Mercurial > hg
changeset 41694:0c7b353ce100
rust-cpython: binding for headrevs()
This uses the core `dagops::retain_heads` to give a Rust implementation
to `mercurial.dagop.headrevs`.
Testing happens for now from `test-rust-ancestors.py`
(for quick and minimal change), but it'd made more sense to put the binary
index data elsewhere and to create a new test python module
author | Georges Racinet <georges.racinet@octobus.net> |
---|---|
date | Thu, 10 Jan 2019 18:25:18 +0100 |
parents | 060c030c9993 |
children | e37bd7ccfee3 |
files | rust/hg-cpython/src/dagops.rs rust/hg-cpython/src/lib.rs tests/test-rust-ancestor.py |
diffstat | 3 files changed, 60 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rust/hg-cpython/src/dagops.rs Thu Jan 10 18:25:18 2019 +0100 @@ -0,0 +1,53 @@ +// dagops.rs +// +// Copyright 2019 Georges Racinet <georges.racinet@octobus.net> +// +// This software may be used and distributed according to the terms of the +// GNU General Public License version 2 or any later version. + +//! Bindings for the `hg::dagops` module provided by the +//! `hg-core` package. +//! +//! From Python, this will be seen as `mercurial.rustext.dagop` +use cindex::Index; +use cpython::{PyDict, PyModule, PyObject, PyResult, Python}; +use crate::conversion::{py_set, rev_pyiter_collect}; +use exceptions::GraphError; +use hg::dagops; +use hg::Revision; +use std::collections::HashSet; + +/// Using the the `index`, return heads out of any Python iterable of Revisions +/// +/// This is the Rust counterpart for `mercurial.dagop.headrevs` +pub fn headrevs( + py: Python, + index: PyObject, + revs: PyObject, +) -> PyResult<PyObject> { + let mut as_set: HashSet<Revision> = rev_pyiter_collect(py, &revs)?; + dagops::retain_heads(&Index::new(py, index)?, &mut as_set) + .map_err(|e| GraphError::pynew(py, e))?; + py_set(py, &as_set) +} + +/// Create the module, with `__package__` given from parent +pub fn init_module(py: Python, package: &str) -> PyResult<PyModule> { + let dotted_name = &format!("{}.dagop", package); + let m = PyModule::new(py, dotted_name)?; + m.add(py, "__package__", package)?; + m.add(py, "__doc__", "DAG operations - Rust implementation")?; + m.add( + py, + "headrevs", + py_fn!(py, headrevs(index: PyObject, revs: PyObject)), + )?; + + let sys = PyModule::import(py, "sys")?; + let sys_modules: PyDict = sys.get(py, "modules")?.extract(py)?; + sys_modules.set_item(py, dotted_name, &m)?; + // Example C code (see pyexpat.c and import.c) will "give away the + // reference", but we won't because it will be consumed once the + // Rust PyObject is dropped. + Ok(m) +}
--- a/rust/hg-cpython/src/lib.rs Wed Jan 16 16:05:27 2019 +0100 +++ b/rust/hg-cpython/src/lib.rs Thu Jan 10 18:25:18 2019 +0100 @@ -27,6 +27,7 @@ pub mod ancestors; mod cindex; mod conversion; +pub mod dagops; pub mod exceptions; py_module_initializer!(rustext, initrustext, PyInit_rustext, |py, m| { @@ -38,6 +39,7 @@ let dotted_name: String = m.get(py, "__name__")?.extract(py)?; m.add(py, "ancestor", ancestors::init_module(py, &dotted_name)?)?; + m.add(py, "dagop", dagops::init_module(py, &dotted_name)?)?; m.add(py, "GraphError", py.get_type::<exceptions::GraphError>())?; Ok(()) });
--- a/tests/test-rust-ancestor.py Wed Jan 16 16:05:27 2019 +0100 +++ b/tests/test-rust-ancestor.py Thu Jan 10 18:25:18 2019 +0100 @@ -19,6 +19,7 @@ LazyAncestors, MissingAncestors, ) + from mercurial.rustext import dagop try: from mercurial.cext import parsers as cparsers @@ -165,6 +166,10 @@ with self.assertRaises(error.WdirUnsupported): list(AncestorsIterator(idx, [node.wdirrev], -1, False)) + def testheadrevs(self): + idx = self.parseindex() + self.assertEqual(dagop.headrevs(idx, [1, 2, 3]), {3}) + if __name__ == '__main__': import silenttestrunner silenttestrunner.main(__name__)