##// END OF EJS Templates
rust-index: implementation of __getitem__...
Raphaël Gomès -
r52098:002b4990 default
parent child Browse files
Show More
@@ -123,6 +123,10 b' impl IndexData {'
123 }
123 }
124 Ok(())
124 Ok(())
125 }
125 }
126
127 fn is_new(&self) -> bool {
128 self.bytes.is_empty()
129 }
126 }
130 }
127
131
128 impl std::ops::Index<std::ops::Range<usize>> for IndexData {
132 impl std::ops::Index<std::ops::Range<usize>> for IndexData {
@@ -146,6 +150,7 b' impl std::ops::Index<std::ops::Range<usi'
146 }
150 }
147 }
151 }
148
152
153 #[derive(Debug, PartialEq, Eq)]
149 pub struct RevisionDataParams {
154 pub struct RevisionDataParams {
150 pub flags: u16,
155 pub flags: u16,
151 pub data_offset: u64,
156 pub data_offset: u64,
@@ -163,6 +168,27 b' pub struct RevisionDataParams {'
163 pub _rank: i32,
168 pub _rank: i32,
164 }
169 }
165
170
171 impl Default for RevisionDataParams {
172 fn default() -> Self {
173 Self {
174 flags: 0,
175 data_offset: 0,
176 data_compressed_length: 0,
177 data_uncompressed_length: 0,
178 data_delta_base: -1,
179 link_rev: -1,
180 parent_rev_1: -1,
181 parent_rev_2: -1,
182 node_id: [0; NODE_BYTES_LENGTH],
183 _sidedata_offset: 0,
184 _sidedata_compressed_length: 0,
185 data_compression_mode: COMPRESSION_MODE_INLINE,
186 _sidedata_compression_mode: COMPRESSION_MODE_INLINE,
187 _rank: -1,
188 }
189 }
190 }
191
166 #[derive(BytesCast)]
192 #[derive(BytesCast)]
167 #[repr(C)]
193 #[repr(C)]
168 pub struct RevisionDataV1 {
194 pub struct RevisionDataV1 {
@@ -397,6 +423,29 b' impl Index {'
397 })
423 })
398 }
424 }
399
425
426 pub fn entry_as_params(
427 &self,
428 rev: UncheckedRevision,
429 ) -> Option<RevisionDataParams> {
430 let rev = self.check_revision(rev)?;
431 self.get_entry(rev).map(|e| RevisionDataParams {
432 flags: e.flags(),
433 data_offset: if rev.0 == 0 && !self.bytes.is_new() {
434 e.flags() as u64
435 } else {
436 e.raw_offset()
437 },
438 data_compressed_length: e.compressed_len().try_into().unwrap(),
439 data_uncompressed_length: e.uncompressed_len(),
440 data_delta_base: e.base_revision_or_base_of_delta_chain().0,
441 link_rev: e.link_revision().0,
442 parent_rev_1: e.p1().0,
443 parent_rev_2: e.p2().0,
444 node_id: e.hash().as_bytes().try_into().unwrap(),
445 ..Default::default()
446 })
447 }
448
400 fn get_entry_inline(
449 fn get_entry_inline(
401 &self,
450 &self,
402 rev: Revision,
451 rev: Revision,
@@ -519,6 +568,9 b" impl<'a> IndexEntry<'a> {"
519 BigEndian::read_u64(&bytes[..]) as usize
568 BigEndian::read_u64(&bytes[..]) as usize
520 }
569 }
521 }
570 }
571 pub fn raw_offset(&self) -> u64 {
572 BigEndian::read_u64(&self.bytes[0..8])
573 }
522
574
523 pub fn flags(&self) -> u16 {
575 pub fn flags(&self) -> u16 {
524 BigEndian::read_u16(&self.bytes[6..=7])
576 BigEndian::read_u16(&self.bytes[6..=7])
@@ -17,11 +17,10 b' use cpython::{'
17 PyObject, PyResult, PyString, PyTuple, Python, PythonObject, ToPyObject,
17 PyObject, PyResult, PyString, PyTuple, Python, PythonObject, ToPyObject,
18 };
18 };
19 use hg::{
19 use hg::{
20 index::IndexHeader,
20 index::{IndexHeader, RevisionDataParams},
21 index::{RevisionDataParams, COMPRESSION_MODE_INLINE},
22 nodemap::{Block, NodeMapError, NodeTree},
21 nodemap::{Block, NodeMapError, NodeTree},
23 revlog::{nodemap::NodeMap, NodePrefix, RevlogIndex},
22 revlog::{nodemap::NodeMap, NodePrefix, RevlogIndex},
24 BaseRevision, Revision, UncheckedRevision,
23 BaseRevision, Revision, UncheckedRevision, NULL_REVISION,
25 };
24 };
26 use std::cell::RefCell;
25 use std::cell::RefCell;
27
26
@@ -237,11 +236,6 b' py_class!(pub class MixedIndex |py| {'
237 Ok(rust_res)
236 Ok(rust_res)
238 }
237 }
239
238
240 /// get an index entry
241 def get(&self, *args, **kw) -> PyResult<PyObject> {
242 self.call_cindex(py, "get", args, kw)
243 }
244
245 /// compute phases
239 /// compute phases
246 def computephasesmapsets(&self, *args, **kw) -> PyResult<PyObject> {
240 def computephasesmapsets(&self, *args, **kw) -> PyResult<PyObject> {
247 self.call_cindex(py, "computephasesmapsets", args, kw)
241 self.call_cindex(py, "computephasesmapsets", args, kw)
@@ -292,23 +286,32 b' py_class!(pub class MixedIndex |py| {'
292 // Since we call back through the high level Python API,
286 // Since we call back through the high level Python API,
293 // there's no point making a distinction between index_get
287 // there's no point making a distinction between index_get
294 // and index_getitem.
288 // and index_getitem.
289 // gracinet 2023: this above is no longer true for the pure Rust impl
295
290
296 def __len__(&self) -> PyResult<usize> {
291 def __len__(&self) -> PyResult<usize> {
297 self.len(py)
292 self.len(py)
298 }
293 }
299
294
300 def __getitem__(&self, key: PyObject) -> PyResult<PyObject> {
295 def __getitem__(&self, key: PyObject) -> PyResult<PyObject> {
296 let rust_res = self.inner_getitem(py, key.clone_ref(py))?;
297
301 // this conversion seems needless, but that's actually because
298 // this conversion seems needless, but that's actually because
302 // `index_getitem` does not handle conversion from PyLong,
299 // `index_getitem` does not handle conversion from PyLong,
303 // which expressions such as [e for e in index] internally use.
300 // which expressions such as [e for e in index] internally use.
304 // Note that we don't seem to have a direct way to call
301 // Note that we don't seem to have a direct way to call
305 // PySequence_GetItem (does the job), which would possibly be better
302 // PySequence_GetItem (does the job), which would possibly be better
306 // for performance
303 // for performance
307 let key = match key.extract::<i32>(py) {
304 // gracinet 2023: the above comment can be removed when we use
305 // the pure Rust impl only. Note also that `key` can be a binary
306 // node id.
307 let c_key = match key.extract::<BaseRevision>(py) {
308 Ok(rev) => rev.to_py_object(py).into_object(),
308 Ok(rev) => rev.to_py_object(py).into_object(),
309 Err(_) => key,
309 Err(_) => key,
310 };
310 };
311 self.cindex(py).borrow().inner().get_item(py, key)
311 let c_res = self.cindex(py).borrow().inner().get_item(py, c_key)?;
312
313 assert_py_eq(py, "__getitem__", &rust_res, &c_res)?;
314 Ok(rust_res)
312 }
315 }
313
316
314 def __contains__(&self, item: PyObject) -> PyResult<bool> {
317 def __contains__(&self, item: PyObject) -> PyResult<bool> {
@@ -426,13 +429,49 b' fn py_tuple_to_revision_data_params('
426 parent_rev_1: tuple.get_item(py, 5).extract(py)?,
429 parent_rev_1: tuple.get_item(py, 5).extract(py)?,
427 parent_rev_2: tuple.get_item(py, 6).extract(py)?,
430 parent_rev_2: tuple.get_item(py, 6).extract(py)?,
428 node_id,
431 node_id,
429 _sidedata_offset: 0,
432 ..Default::default()
430 _sidedata_compressed_length: 0,
431 data_compression_mode: COMPRESSION_MODE_INLINE,
432 _sidedata_compression_mode: COMPRESSION_MODE_INLINE,
433 _rank: -1,
434 })
433 })
435 }
434 }
435 fn revision_data_params_to_py_tuple(
436 py: Python,
437 params: RevisionDataParams,
438 ) -> PyTuple {
439 PyTuple::new(
440 py,
441 &[
442 params.data_offset.into_py_object(py).into_object(),
443 params
444 .data_compressed_length
445 .into_py_object(py)
446 .into_object(),
447 params
448 .data_uncompressed_length
449 .into_py_object(py)
450 .into_object(),
451 params.data_delta_base.into_py_object(py).into_object(),
452 params.link_rev.into_py_object(py).into_object(),
453 params.parent_rev_1.into_py_object(py).into_object(),
454 params.parent_rev_2.into_py_object(py).into_object(),
455 PyBytes::new(py, &params.node_id)
456 .into_py_object(py)
457 .into_object(),
458 params._sidedata_offset.into_py_object(py).into_object(),
459 params
460 ._sidedata_compressed_length
461 .into_py_object(py)
462 .into_object(),
463 params
464 .data_compression_mode
465 .into_py_object(py)
466 .into_object(),
467 params
468 ._sidedata_compression_mode
469 .into_py_object(py)
470 .into_object(),
471 params._rank.into_py_object(py).into_object(),
472 ],
473 )
474 }
436
475
437 impl MixedIndex {
476 impl MixedIndex {
438 fn new(
477 fn new(
@@ -601,6 +640,34 b' impl MixedIndex {'
601
640
602 Ok(py.None())
641 Ok(py.None())
603 }
642 }
643
644 fn inner_getitem(&self, py: Python, key: PyObject) -> PyResult<PyObject> {
645 let idx = self.index(py).borrow();
646 Ok(match key.extract::<BaseRevision>(py) {
647 Ok(key_as_int) => {
648 let entry_params = if key_as_int == NULL_REVISION.0 {
649 RevisionDataParams::default()
650 } else {
651 let rev = UncheckedRevision(key_as_int);
652 match idx.entry_as_params(rev) {
653 Some(e) => e,
654 None => {
655 return Err(PyErr::new::<IndexError, _>(
656 py,
657 "revlog index out of range",
658 ));
659 }
660 }
661 };
662 revision_data_params_to_py_tuple(py, entry_params)
663 .into_object()
664 }
665 _ => self.get_rev(py, key.extract::<PyBytes>(py)?)?.map_or_else(
666 || py.None(),
667 |py_rev| py_rev.into_py_object(py).into_object(),
668 ),
669 })
670 }
604 }
671 }
605
672
606 fn revlog_error(py: Python) -> PyErr {
673 fn revlog_error(py: Python) -> PyErr {
General Comments 0
You need to be logged in to leave comments. Login now