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, ¶ms.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