rust-index: using `hg::index::Index` in `hg-cpython::dagops`
authorGeorges Racinet <georges.racinet@octobus.net>
Sun, 29 Oct 2023 10:47:54 +0100
changeset 51241 578c049f0408
parent 51240 59d81768ad6d
child 51242 2e2832e00f6c
rust-index: using `hg::index::Index` in `hg-cpython::dagops` Hooking `headrevs` to the Rust index is straightforward as long as we go the `PySharedRef` way. Direct attempts of obtaining a reference to the inner `hg::index::Index` fail for lifetime reasons: the reference is bound to the GIL, yet the `as_set` local variable is considered to be static (the borrow checker clearly does not realize or care that this set only stores `Revision` values). In `rank()`, the chosen solution is the simplest as far as `hg-cpython` is concerned, but it has the defect of removing an implementation that would be easily adaptable if the core index did implement `RankedGraph` (returning the same error as long as only `REVLOGV1` is supported), but that would introduce a direct dependency of `hg-core` on the ``vcsgraph` crate.
rust/hg-cpython/src/dagops.rs
tests/test-rust-ancestor.py
--- a/rust/hg-cpython/src/dagops.rs	Sat Oct 28 22:50:10 2023 +0200
+++ b/rust/hg-cpython/src/dagops.rs	Sun Oct 29 10:47:54 2023 +0100
@@ -15,10 +15,9 @@
 use hg::dagops;
 use hg::Revision;
 use std::collections::HashSet;
-use vcsgraph::ancestors::node_rank;
-use vcsgraph::graph::{Parents, Rank};
+use vcsgraph::graph::Rank;
 
-use crate::revlog::pyindex_to_graph;
+use crate::revlog::py_rust_index_to_graph;
 
 /// Using the the `index`, return heads out of any Python iterable of Revisions
 ///
@@ -28,23 +27,33 @@
     index: PyObject,
     revs: PyObject,
 ) -> PyResult<HashSet<PyRevision>> {
-    let index = pyindex_to_graph(py, index)?;
-    let mut as_set: HashSet<Revision> = rev_pyiter_collect(py, &revs, &index)?;
-    dagops::retain_heads(&index, &mut as_set)
+    let py_leaked = py_rust_index_to_graph(py, index)?;
+    let index = &*unsafe { py_leaked.try_borrow(py)? };
+    let mut as_set: HashSet<Revision> = rev_pyiter_collect(py, &revs, index)?;
+    dagops::retain_heads(index, &mut as_set)
         .map_err(|e| GraphError::pynew(py, e))?;
     Ok(as_set.into_iter().map(Into::into).collect())
 }
 
 /// Computes the rank, i.e. the number of ancestors including itself,
 /// of a node represented by its parents.
+///
+/// Currently, the pure Rust index supports only the REVLOGV1 format, hence
+/// the only possible return value is that the rank is unknown.
+///
+/// References:
+/// - C implementation, function `index_fast_rank()`.
+/// - `impl vcsgraph::graph::RankedGraph for Index` in `crate::cindex`.
 pub fn rank(
     py: Python,
-    index: PyObject,
-    p1r: PyRevision,
-    p2r: PyRevision,
+    _index: PyObject,
+    _p1r: PyRevision,
+    _p2r: PyRevision,
 ) -> PyResult<Rank> {
-    node_rank(&pyindex_to_graph(py, index)?, &Parents([p1r.0, p2r.0]))
-        .map_err(|e| GraphError::pynew_from_vcsgraph(py, e))
+    Err(GraphError::pynew_from_vcsgraph(
+        py,
+        vcsgraph::graph::GraphReadError::InconsistentGraphData,
+    ))
 }
 
 /// Create the module, with `__package__` given from parent
--- a/tests/test-rust-ancestor.py	Sat Oct 28 22:50:10 2023 +0200
+++ b/tests/test-rust-ancestor.py	Sun Oct 29 10:47:54 2023 +0100
@@ -157,7 +157,7 @@
         self.assertEqual(exc.args, ('InvalidRevision', wdirrev))
 
     def testheadrevs(self):
-        idx = self.parseindex()
+        idx = self.parserustindex()
         self.assertEqual(dagop.headrevs(idx, [1, 2, 3]), {3})