15 exc::{IndexError, ValueError}, |
15 exc::{IndexError, ValueError}, |
16 ObjectProtocol, PyBool, PyBytes, PyClone, PyDict, PyErr, PyInt, PyModule, |
16 ObjectProtocol, PyBool, PyBytes, PyClone, PyDict, PyErr, PyInt, PyModule, |
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 |
28 /// Return a Struct implementing the Graph trait |
27 /// Return a Struct implementing the Graph trait |
29 pub(crate) fn pyindex_to_graph( |
28 pub(crate) fn pyindex_to_graph( |
235 let c_res = self.call_cindex(py, "pack_header", args, kw)?; |
234 let c_res = self.call_cindex(py, "pack_header", args, kw)?; |
236 assert_py_eq(py, "pack_header", &rust_res, &c_res)?; |
235 assert_py_eq(py, "pack_header", &rust_res, &c_res)?; |
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) |
248 } |
242 } |
249 |
243 |
290 // index_sequence_methods and index_mapping_methods. |
284 // index_sequence_methods and index_mapping_methods. |
291 // |
285 // |
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> { |
315 // ObjectProtocol does not seem to provide contains(), so |
318 // ObjectProtocol does not seem to provide contains(), so |
316 // this is an equivalent implementation of the index_contains() |
319 // this is an equivalent implementation of the index_contains() |
424 data_delta_base: tuple.get_item(py, 3).extract(py)?, |
427 data_delta_base: tuple.get_item(py, 3).extract(py)?, |
425 link_rev: tuple.get_item(py, 4).extract(py)?, |
428 link_rev: tuple.get_item(py, 4).extract(py)?, |
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 }) |
|
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 ) |
435 } |
474 } |
436 |
475 |
437 impl MixedIndex { |
476 impl MixedIndex { |
438 fn new( |
477 fn new( |
439 py: Python, |
478 py: Python, |
598 } |
637 } |
599 |
638 |
600 *self.nt(py).borrow_mut() = Some(nt); |
639 *self.nt(py).borrow_mut() = Some(nt); |
601 |
640 |
602 Ok(py.None()) |
641 Ok(py.None()) |
|
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 }) |
603 } |
670 } |
604 } |
671 } |
605 |
672 |
606 fn revlog_error(py: Python) -> PyErr { |
673 fn revlog_error(py: Python) -> PyErr { |
607 match py |
674 match py |