rust/hg-cpython/src/revlog.rs
changeset 51239 7eea2e4109ae
parent 51235 456e0fe702e8
child 51245 0b81440e2a73
--- a/rust/hg-cpython/src/revlog.rs	Fri Oct 27 23:29:29 2023 +0200
+++ b/rust/hg-cpython/src/revlog.rs	Fri Oct 27 22:11:05 2023 +0200
@@ -16,7 +16,7 @@
     exc::{IndexError, ValueError},
     ObjectProtocol, PyBool, PyBytes, PyClone, PyDict, PyErr, PyInt, PyList,
     PyModule, PyObject, PyResult, PySet, PyString, PyTuple, Python,
-    PythonObject, ToPyObject,
+    PythonObject, ToPyObject, UnsafePyLeaked,
 };
 use hg::{
     errors::HgError,
@@ -25,10 +25,11 @@
         INDEX_ENTRY_SIZE,
     },
     nodemap::{Block, NodeMapError, NodeTree},
-    revlog::{nodemap::NodeMap, NodePrefix, RevlogError, RevlogIndex},
-    BaseRevision, Revision, UncheckedRevision, NULL_REVISION,
+    revlog::{nodemap::NodeMap, Graph, NodePrefix, RevlogError, RevlogIndex},
+    BaseRevision, Node, Revision, UncheckedRevision, NULL_REVISION,
 };
 use std::{cell::RefCell, collections::HashMap};
+use vcsgraph::graph::Graph as VCSGraph;
 
 /// Return a Struct implementing the Graph trait
 pub(crate) fn pyindex_to_graph(
@@ -41,9 +42,64 @@
     }
 }
 
+pub struct PySharedIndex {
+    /// The underlying hg-core index
+    pub(crate) inner: &'static hg::index::Index,
+}
+
+/// Return a Struct implementing the Graph trait
+pub(crate) fn py_rust_index_to_graph(
+    py: Python,
+    index: PyObject,
+) -> PyResult<UnsafePyLeaked<PySharedIndex>> {
+    let midx = index.extract::<MixedIndex>(py)?;
+    let leaked = midx.index(py).leak_immutable();
+    Ok(unsafe { leaked.map(py, |idx| PySharedIndex { inner: idx }) })
+}
+
+impl Clone for PySharedIndex {
+    fn clone(&self) -> Self {
+        Self { inner: self.inner }
+    }
+}
+
+impl Graph for PySharedIndex {
+    fn parents(&self, rev: Revision) -> Result<[Revision; 2], hg::GraphError> {
+        self.inner.parents(rev)
+    }
+}
+
+impl VCSGraph for PySharedIndex {
+    fn parents(
+        &self,
+        rev: BaseRevision,
+    ) -> Result<vcsgraph::graph::Parents, vcsgraph::graph::GraphReadError>
+    {
+        // FIXME This trait should be reworked to decide between Revision
+        // and UncheckedRevision, get better errors names, etc.
+        match Graph::parents(self, Revision(rev)) {
+            Ok(parents) => {
+                Ok(vcsgraph::graph::Parents([parents[0].0, parents[1].0]))
+            }
+            Err(hg::GraphError::ParentOutOfRange(rev)) => {
+                Err(vcsgraph::graph::GraphReadError::KeyedInvalidKey(rev.0))
+            }
+        }
+    }
+}
+
+impl RevlogIndex for PySharedIndex {
+    fn len(&self) -> usize {
+        self.inner.len()
+    }
+    fn node(&self, rev: Revision) -> Option<&Node> {
+        self.inner.node(rev)
+    }
+}
+
 py_class!(pub class MixedIndex |py| {
     data cindex: RefCell<cindex::Index>;
-    data index: RefCell<hg::index::Index>;
+    @shared data index: hg::index::Index;
     data nt: RefCell<Option<NodeTree>>;
     data docket: RefCell<Option<PyObject>>;
     // Holds a reference to the mmap'ed persistent nodemap data
@@ -668,17 +724,15 @@
         Self::create_instance(
             py,
             RefCell::new(cindex::Index::new(py, cindex)?),
-            RefCell::new(
-                hg::index::Index::new(
-                    bytes,
-                    IndexHeader::parse(&header.to_be_bytes())
-                        .expect("default header is broken")
-                        .unwrap(),
-                )
-                .map_err(|e| {
-                    revlog_error_with_msg(py, e.to_string().as_bytes())
-                })?,
-            ),
+            hg::index::Index::new(
+                bytes,
+                IndexHeader::parse(&header.to_be_bytes())
+                    .expect("default header is broken")
+                    .unwrap(),
+            )
+            .map_err(|e| {
+                revlog_error_with_msg(py, e.to_string().as_bytes())
+            })?,
             RefCell::new(None),
             RefCell::new(None),
             RefCell::new(None),