14 use cpython::{ |
14 use cpython::{ |
15 buffer::{Element, PyBuffer}, |
15 buffer::{Element, PyBuffer}, |
16 exc::{IndexError, ValueError}, |
16 exc::{IndexError, ValueError}, |
17 ObjectProtocol, PyBool, PyBytes, PyClone, PyDict, PyErr, PyInt, PyList, |
17 ObjectProtocol, PyBool, PyBytes, PyClone, PyDict, PyErr, PyInt, PyList, |
18 PyModule, PyObject, PyResult, PySet, PyString, PyTuple, Python, |
18 PyModule, PyObject, PyResult, PySet, PyString, PyTuple, Python, |
19 PythonObject, ToPyObject, |
19 PythonObject, ToPyObject, UnsafePyLeaked, |
20 }; |
20 }; |
21 use hg::{ |
21 use hg::{ |
22 errors::HgError, |
22 errors::HgError, |
23 index::{ |
23 index::{ |
24 IndexHeader, Phase, RevisionDataParams, SnapshotsCache, |
24 IndexHeader, Phase, RevisionDataParams, SnapshotsCache, |
25 INDEX_ENTRY_SIZE, |
25 INDEX_ENTRY_SIZE, |
26 }, |
26 }, |
27 nodemap::{Block, NodeMapError, NodeTree}, |
27 nodemap::{Block, NodeMapError, NodeTree}, |
28 revlog::{nodemap::NodeMap, NodePrefix, RevlogError, RevlogIndex}, |
28 revlog::{nodemap::NodeMap, Graph, NodePrefix, RevlogError, RevlogIndex}, |
29 BaseRevision, Revision, UncheckedRevision, NULL_REVISION, |
29 BaseRevision, Node, Revision, UncheckedRevision, NULL_REVISION, |
30 }; |
30 }; |
31 use std::{cell::RefCell, collections::HashMap}; |
31 use std::{cell::RefCell, collections::HashMap}; |
|
32 use vcsgraph::graph::Graph as VCSGraph; |
32 |
33 |
33 /// Return a Struct implementing the Graph trait |
34 /// Return a Struct implementing the Graph trait |
34 pub(crate) fn pyindex_to_graph( |
35 pub(crate) fn pyindex_to_graph( |
35 py: Python, |
36 py: Python, |
36 index: PyObject, |
37 index: PyObject, |
39 Ok(midx) => Ok(midx.clone_cindex(py)), |
40 Ok(midx) => Ok(midx.clone_cindex(py)), |
40 Err(_) => cindex::Index::new(py, index), |
41 Err(_) => cindex::Index::new(py, index), |
41 } |
42 } |
42 } |
43 } |
43 |
44 |
|
45 pub struct PySharedIndex { |
|
46 /// The underlying hg-core index |
|
47 pub(crate) inner: &'static hg::index::Index, |
|
48 } |
|
49 |
|
50 /// Return a Struct implementing the Graph trait |
|
51 pub(crate) fn py_rust_index_to_graph( |
|
52 py: Python, |
|
53 index: PyObject, |
|
54 ) -> PyResult<UnsafePyLeaked<PySharedIndex>> { |
|
55 let midx = index.extract::<MixedIndex>(py)?; |
|
56 let leaked = midx.index(py).leak_immutable(); |
|
57 Ok(unsafe { leaked.map(py, |idx| PySharedIndex { inner: idx }) }) |
|
58 } |
|
59 |
|
60 impl Clone for PySharedIndex { |
|
61 fn clone(&self) -> Self { |
|
62 Self { inner: self.inner } |
|
63 } |
|
64 } |
|
65 |
|
66 impl Graph for PySharedIndex { |
|
67 fn parents(&self, rev: Revision) -> Result<[Revision; 2], hg::GraphError> { |
|
68 self.inner.parents(rev) |
|
69 } |
|
70 } |
|
71 |
|
72 impl VCSGraph for PySharedIndex { |
|
73 fn parents( |
|
74 &self, |
|
75 rev: BaseRevision, |
|
76 ) -> Result<vcsgraph::graph::Parents, vcsgraph::graph::GraphReadError> |
|
77 { |
|
78 // FIXME This trait should be reworked to decide between Revision |
|
79 // and UncheckedRevision, get better errors names, etc. |
|
80 match Graph::parents(self, Revision(rev)) { |
|
81 Ok(parents) => { |
|
82 Ok(vcsgraph::graph::Parents([parents[0].0, parents[1].0])) |
|
83 } |
|
84 Err(hg::GraphError::ParentOutOfRange(rev)) => { |
|
85 Err(vcsgraph::graph::GraphReadError::KeyedInvalidKey(rev.0)) |
|
86 } |
|
87 } |
|
88 } |
|
89 } |
|
90 |
|
91 impl RevlogIndex for PySharedIndex { |
|
92 fn len(&self) -> usize { |
|
93 self.inner.len() |
|
94 } |
|
95 fn node(&self, rev: Revision) -> Option<&Node> { |
|
96 self.inner.node(rev) |
|
97 } |
|
98 } |
|
99 |
44 py_class!(pub class MixedIndex |py| { |
100 py_class!(pub class MixedIndex |py| { |
45 data cindex: RefCell<cindex::Index>; |
101 data cindex: RefCell<cindex::Index>; |
46 data index: RefCell<hg::index::Index>; |
102 @shared data index: hg::index::Index; |
47 data nt: RefCell<Option<NodeTree>>; |
103 data nt: RefCell<Option<NodeTree>>; |
48 data docket: RefCell<Option<PyObject>>; |
104 data docket: RefCell<Option<PyObject>>; |
49 // Holds a reference to the mmap'ed persistent nodemap data |
105 // Holds a reference to the mmap'ed persistent nodemap data |
50 data nodemap_mmap: RefCell<Option<PyBuffer>>; |
106 data nodemap_mmap: RefCell<Option<PyBuffer>>; |
51 // Holds a reference to the mmap'ed persistent index data |
107 // Holds a reference to the mmap'ed persistent index data |
666 let (buf, bytes) = unsafe { mmap_keeparound(py, data)? }; |
722 let (buf, bytes) = unsafe { mmap_keeparound(py, data)? }; |
667 |
723 |
668 Self::create_instance( |
724 Self::create_instance( |
669 py, |
725 py, |
670 RefCell::new(cindex::Index::new(py, cindex)?), |
726 RefCell::new(cindex::Index::new(py, cindex)?), |
671 RefCell::new( |
727 hg::index::Index::new( |
672 hg::index::Index::new( |
728 bytes, |
673 bytes, |
729 IndexHeader::parse(&header.to_be_bytes()) |
674 IndexHeader::parse(&header.to_be_bytes()) |
730 .expect("default header is broken") |
675 .expect("default header is broken") |
731 .unwrap(), |
676 .unwrap(), |
732 ) |
677 ) |
733 .map_err(|e| { |
678 .map_err(|e| { |
734 revlog_error_with_msg(py, e.to_string().as_bytes()) |
679 revlog_error_with_msg(py, e.to_string().as_bytes()) |
735 })?, |
680 })?, |
|
681 ), |
|
682 RefCell::new(None), |
736 RefCell::new(None), |
683 RefCell::new(None), |
737 RefCell::new(None), |
684 RefCell::new(None), |
738 RefCell::new(None), |
685 RefCell::new(Some(buf)), |
739 RefCell::new(Some(buf)), |
686 ) |
740 ) |