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.
--- 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})