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