annotate rust/hg-cpython/src/dagops.rs @ 52167:7be39c5110c9

hg-core: add a complete VFS This will be used from Python in a later change. More changes are needed in hg-core and rhg to properly clean up the APIs of the old VFS implementation but it can be done when the dust settles and we start adding more functionality to the pure Rust VFS.
author Rapha?l Gom?s <rgomes@octobus.net>
date Mon, 29 Jul 2024 20:47:43 +0200
parents 24d3298189d7
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
41694
0c7b353ce100 rust-cpython: binding for headrevs()
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
1 // dagops.rs
0c7b353ce100 rust-cpython: binding for headrevs()
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
2 //
0c7b353ce100 rust-cpython: binding for headrevs()
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
3 // Copyright 2019 Georges Racinet <georges.racinet@octobus.net>
0c7b353ce100 rust-cpython: binding for headrevs()
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
4 //
0c7b353ce100 rust-cpython: binding for headrevs()
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
5 // This software may be used and distributed according to the terms of the
0c7b353ce100 rust-cpython: binding for headrevs()
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
6 // GNU General Public License version 2 or any later version.
0c7b353ce100 rust-cpython: binding for headrevs()
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
7
0c7b353ce100 rust-cpython: binding for headrevs()
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
8 //! Bindings for the `hg::dagops` module provided by the
0c7b353ce100 rust-cpython: binding for headrevs()
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
9 //! `hg-core` package.
0c7b353ce100 rust-cpython: binding for headrevs()
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
10 //!
0c7b353ce100 rust-cpython: binding for headrevs()
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
11 //! From Python, this will be seen as `mercurial.rustext.dagop`
50976
4c5f6e95df84 rust: make `Revision` a newtype
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48854
diff changeset
12 use crate::PyRevision;
43945
f98f0e3ddaa1 rust-index: add a function to convert PyObject index for hg-core
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43269
diff changeset
13 use crate::{conversion::rev_pyiter_collect, exceptions::GraphError};
41694
0c7b353ce100 rust-cpython: binding for headrevs()
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
14 use cpython::{PyDict, PyModule, PyObject, PyResult, Python};
0c7b353ce100 rust-cpython: binding for headrevs()
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
15 use hg::dagops;
0c7b353ce100 rust-cpython: binding for headrevs()
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
16 use hg::Revision;
0c7b353ce100 rust-cpython: binding for headrevs()
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
17 use std::collections::HashSet;
51238
578c049f0408 rust-index: using `hg::index::Index` in `hg-cpython::dagops`
Georges Racinet <georges.racinet@octobus.net>
parents: 50976
diff changeset
18 use vcsgraph::graph::Rank;
41694
0c7b353ce100 rust-cpython: binding for headrevs()
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
19
51238
578c049f0408 rust-index: using `hg::index::Index` in `hg-cpython::dagops`
Georges Racinet <georges.racinet@octobus.net>
parents: 50976
diff changeset
20 use crate::revlog::py_rust_index_to_graph;
43945
f98f0e3ddaa1 rust-index: add a function to convert PyObject index for hg-core
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 43269
diff changeset
21
41694
0c7b353ce100 rust-cpython: binding for headrevs()
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
22 /// Using the the `index`, return heads out of any Python iterable of Revisions
0c7b353ce100 rust-cpython: binding for headrevs()
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
23 ///
0c7b353ce100 rust-cpython: binding for headrevs()
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
24 /// This is the Rust counterpart for `mercurial.dagop.headrevs`
0c7b353ce100 rust-cpython: binding for headrevs()
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
25 pub fn headrevs(
0c7b353ce100 rust-cpython: binding for headrevs()
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
26 py: Python,
0c7b353ce100 rust-cpython: binding for headrevs()
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
27 index: PyObject,
0c7b353ce100 rust-cpython: binding for headrevs()
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
28 revs: PyObject,
50976
4c5f6e95df84 rust: make `Revision` a newtype
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48854
diff changeset
29 ) -> PyResult<HashSet<PyRevision>> {
51238
578c049f0408 rust-index: using `hg::index::Index` in `hg-cpython::dagops`
Georges Racinet <georges.racinet@octobus.net>
parents: 50976
diff changeset
30 let py_leaked = py_rust_index_to_graph(py, index)?;
51252
24d3298189d7 rust-index: document safety invariants being upheld for every `unsafe` block
Rapha?l Gom?s <rgomes@octobus.net>
parents: 51238
diff changeset
31 // Safety: we don't leak the "faked" reference out of `UnsafePyLeaked`
51238
578c049f0408 rust-index: using `hg::index::Index` in `hg-cpython::dagops`
Georges Racinet <georges.racinet@octobus.net>
parents: 50976
diff changeset
32 let index = &*unsafe { py_leaked.try_borrow(py)? };
578c049f0408 rust-index: using `hg::index::Index` in `hg-cpython::dagops`
Georges Racinet <georges.racinet@octobus.net>
parents: 50976
diff changeset
33 let mut as_set: HashSet<Revision> = rev_pyiter_collect(py, &revs, index)?;
578c049f0408 rust-index: using `hg::index::Index` in `hg-cpython::dagops`
Georges Racinet <georges.racinet@octobus.net>
parents: 50976
diff changeset
34 dagops::retain_heads(index, &mut as_set)
41694
0c7b353ce100 rust-cpython: binding for headrevs()
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
35 .map_err(|e| GraphError::pynew(py, e))?;
50976
4c5f6e95df84 rust: make `Revision` a newtype
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48854
diff changeset
36 Ok(as_set.into_iter().map(Into::into).collect())
41694
0c7b353ce100 rust-cpython: binding for headrevs()
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
37 }
0c7b353ce100 rust-cpython: binding for headrevs()
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
38
48854
8b8054b8e5a7 rust: expose rank computation function to python
pacien <pacien.trangirard@pacien.net>
parents: 43945
diff changeset
39 /// Computes the rank, i.e. the number of ancestors including itself,
8b8054b8e5a7 rust: expose rank computation function to python
pacien <pacien.trangirard@pacien.net>
parents: 43945
diff changeset
40 /// of a node represented by its parents.
51238
578c049f0408 rust-index: using `hg::index::Index` in `hg-cpython::dagops`
Georges Racinet <georges.racinet@octobus.net>
parents: 50976
diff changeset
41 ///
578c049f0408 rust-index: using `hg::index::Index` in `hg-cpython::dagops`
Georges Racinet <georges.racinet@octobus.net>
parents: 50976
diff changeset
42 /// Currently, the pure Rust index supports only the REVLOGV1 format, hence
578c049f0408 rust-index: using `hg::index::Index` in `hg-cpython::dagops`
Georges Racinet <georges.racinet@octobus.net>
parents: 50976
diff changeset
43 /// the only possible return value is that the rank is unknown.
578c049f0408 rust-index: using `hg::index::Index` in `hg-cpython::dagops`
Georges Racinet <georges.racinet@octobus.net>
parents: 50976
diff changeset
44 ///
578c049f0408 rust-index: using `hg::index::Index` in `hg-cpython::dagops`
Georges Racinet <georges.racinet@octobus.net>
parents: 50976
diff changeset
45 /// References:
578c049f0408 rust-index: using `hg::index::Index` in `hg-cpython::dagops`
Georges Racinet <georges.racinet@octobus.net>
parents: 50976
diff changeset
46 /// - C implementation, function `index_fast_rank()`.
578c049f0408 rust-index: using `hg::index::Index` in `hg-cpython::dagops`
Georges Racinet <georges.racinet@octobus.net>
parents: 50976
diff changeset
47 /// - `impl vcsgraph::graph::RankedGraph for Index` in `crate::cindex`.
48854
8b8054b8e5a7 rust: expose rank computation function to python
pacien <pacien.trangirard@pacien.net>
parents: 43945
diff changeset
48 pub fn rank(
8b8054b8e5a7 rust: expose rank computation function to python
pacien <pacien.trangirard@pacien.net>
parents: 43945
diff changeset
49 py: Python,
51238
578c049f0408 rust-index: using `hg::index::Index` in `hg-cpython::dagops`
Georges Racinet <georges.racinet@octobus.net>
parents: 50976
diff changeset
50 _index: PyObject,
578c049f0408 rust-index: using `hg::index::Index` in `hg-cpython::dagops`
Georges Racinet <georges.racinet@octobus.net>
parents: 50976
diff changeset
51 _p1r: PyRevision,
578c049f0408 rust-index: using `hg::index::Index` in `hg-cpython::dagops`
Georges Racinet <georges.racinet@octobus.net>
parents: 50976
diff changeset
52 _p2r: PyRevision,
48854
8b8054b8e5a7 rust: expose rank computation function to python
pacien <pacien.trangirard@pacien.net>
parents: 43945
diff changeset
53 ) -> PyResult<Rank> {
51238
578c049f0408 rust-index: using `hg::index::Index` in `hg-cpython::dagops`
Georges Racinet <georges.racinet@octobus.net>
parents: 50976
diff changeset
54 Err(GraphError::pynew_from_vcsgraph(
578c049f0408 rust-index: using `hg::index::Index` in `hg-cpython::dagops`
Georges Racinet <georges.racinet@octobus.net>
parents: 50976
diff changeset
55 py,
578c049f0408 rust-index: using `hg::index::Index` in `hg-cpython::dagops`
Georges Racinet <georges.racinet@octobus.net>
parents: 50976
diff changeset
56 vcsgraph::graph::GraphReadError::InconsistentGraphData,
578c049f0408 rust-index: using `hg::index::Index` in `hg-cpython::dagops`
Georges Racinet <georges.racinet@octobus.net>
parents: 50976
diff changeset
57 ))
48854
8b8054b8e5a7 rust: expose rank computation function to python
pacien <pacien.trangirard@pacien.net>
parents: 43945
diff changeset
58 }
8b8054b8e5a7 rust: expose rank computation function to python
pacien <pacien.trangirard@pacien.net>
parents: 43945
diff changeset
59
41694
0c7b353ce100 rust-cpython: binding for headrevs()
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
60 /// Create the module, with `__package__` given from parent
0c7b353ce100 rust-cpython: binding for headrevs()
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
61 pub fn init_module(py: Python, package: &str) -> PyResult<PyModule> {
0c7b353ce100 rust-cpython: binding for headrevs()
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
62 let dotted_name = &format!("{}.dagop", package);
0c7b353ce100 rust-cpython: binding for headrevs()
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
63 let m = PyModule::new(py, dotted_name)?;
0c7b353ce100 rust-cpython: binding for headrevs()
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
64 m.add(py, "__package__", package)?;
0c7b353ce100 rust-cpython: binding for headrevs()
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
65 m.add(py, "__doc__", "DAG operations - Rust implementation")?;
0c7b353ce100 rust-cpython: binding for headrevs()
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
66 m.add(
0c7b353ce100 rust-cpython: binding for headrevs()
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
67 py,
0c7b353ce100 rust-cpython: binding for headrevs()
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
68 "headrevs",
0c7b353ce100 rust-cpython: binding for headrevs()
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
69 py_fn!(py, headrevs(index: PyObject, revs: PyObject)),
0c7b353ce100 rust-cpython: binding for headrevs()
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
70 )?;
48854
8b8054b8e5a7 rust: expose rank computation function to python
pacien <pacien.trangirard@pacien.net>
parents: 43945
diff changeset
71 m.add(
8b8054b8e5a7 rust: expose rank computation function to python
pacien <pacien.trangirard@pacien.net>
parents: 43945
diff changeset
72 py,
8b8054b8e5a7 rust: expose rank computation function to python
pacien <pacien.trangirard@pacien.net>
parents: 43945
diff changeset
73 "rank",
50976
4c5f6e95df84 rust: make `Revision` a newtype
Rapha?l Gom?s <rgomes@octobus.net>
parents: 48854
diff changeset
74 py_fn!(py, rank(index: PyObject, p1r: PyRevision, p2r: PyRevision)),
48854
8b8054b8e5a7 rust: expose rank computation function to python
pacien <pacien.trangirard@pacien.net>
parents: 43945
diff changeset
75 )?;
41694
0c7b353ce100 rust-cpython: binding for headrevs()
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
76
0c7b353ce100 rust-cpython: binding for headrevs()
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
77 let sys = PyModule::import(py, "sys")?;
0c7b353ce100 rust-cpython: binding for headrevs()
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
78 let sys_modules: PyDict = sys.get(py, "modules")?.extract(py)?;
0c7b353ce100 rust-cpython: binding for headrevs()
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
79 sys_modules.set_item(py, dotted_name, &m)?;
0c7b353ce100 rust-cpython: binding for headrevs()
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
80 // Example C code (see pyexpat.c and import.c) will "give away the
0c7b353ce100 rust-cpython: binding for headrevs()
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
81 // reference", but we won't because it will be consumed once the
0c7b353ce100 rust-cpython: binding for headrevs()
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
82 // Rust PyObject is dropped.
0c7b353ce100 rust-cpython: binding for headrevs()
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
83 Ok(m)
0c7b353ce100 rust-cpython: binding for headrevs()
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
84 }