##// 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 124 Ok(())
125 125 }
126
127 fn is_new(&self) -> bool {
128 self.bytes.is_empty()
129 }
126 130 }
127 131
128 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 154 pub struct RevisionDataParams {
150 155 pub flags: u16,
151 156 pub data_offset: u64,
@@ -163,6 +168,27 b' pub struct RevisionDataParams {'
163 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 192 #[derive(BytesCast)]
167 193 #[repr(C)]
168 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 449 fn get_entry_inline(
401 450 &self,
402 451 rev: Revision,
@@ -519,6 +568,9 b" impl<'a> IndexEntry<'a> {"
519 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 575 pub fn flags(&self) -> u16 {
524 576 BigEndian::read_u16(&self.bytes[6..=7])
@@ -17,11 +17,10 b' use cpython::{'
17 17 PyObject, PyResult, PyString, PyTuple, Python, PythonObject, ToPyObject,
18 18 };
19 19 use hg::{
20 index::IndexHeader,
21 index::{RevisionDataParams, COMPRESSION_MODE_INLINE},
20 index::{IndexHeader, RevisionDataParams},
22 21 nodemap::{Block, NodeMapError, NodeTree},
23 22 revlog::{nodemap::NodeMap, NodePrefix, RevlogIndex},
24 BaseRevision, Revision, UncheckedRevision,
23 BaseRevision, Revision, UncheckedRevision, NULL_REVISION,
25 24 };
26 25 use std::cell::RefCell;
27 26
@@ -237,11 +236,6 b' py_class!(pub class MixedIndex |py| {'
237 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 239 /// compute phases
246 240 def computephasesmapsets(&self, *args, **kw) -> PyResult<PyObject> {
247 241 self.call_cindex(py, "computephasesmapsets", args, kw)
@@ -292,23 +286,32 b' py_class!(pub class MixedIndex |py| {'
292 286 // Since we call back through the high level Python API,
293 287 // there's no point making a distinction between index_get
294 288 // and index_getitem.
289 // gracinet 2023: this above is no longer true for the pure Rust impl
295 290
296 291 def __len__(&self) -> PyResult<usize> {
297 292 self.len(py)
298 293 }
299 294
300 295 def __getitem__(&self, key: PyObject) -> PyResult<PyObject> {
296 let rust_res = self.inner_getitem(py, key.clone_ref(py))?;
297
301 298 // this conversion seems needless, but that's actually because
302 299 // `index_getitem` does not handle conversion from PyLong,
303 300 // which expressions such as [e for e in index] internally use.
304 301 // Note that we don't seem to have a direct way to call
305 302 // PySequence_GetItem (does the job), which would possibly be better
306 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 308 Ok(rev) => rev.to_py_object(py).into_object(),
309 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 317 def __contains__(&self, item: PyObject) -> PyResult<bool> {
@@ -426,13 +429,49 b' fn py_tuple_to_revision_data_params('
426 429 parent_rev_1: tuple.get_item(py, 5).extract(py)?,
427 430 parent_rev_2: tuple.get_item(py, 6).extract(py)?,
428 431 node_id,
429 _sidedata_offset: 0,
430 _sidedata_compressed_length: 0,
431 data_compression_mode: COMPRESSION_MODE_INLINE,
432 _sidedata_compression_mode: COMPRESSION_MODE_INLINE,
433 _rank: -1,
432 ..Default::default()
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 476 impl MixedIndex {
438 477 fn new(
@@ -601,6 +640,34 b' impl MixedIndex {'
601 640
602 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 673 fn revlog_error(py: Python) -> PyErr {
General Comments 0
You need to be logged in to leave comments. Login now