Mercurial > hg
comparison rust/hg-cpython/src/ancestors.rs @ 41053:d9f439fcdb4c
rust-cpython: binding for AncestorsIterator
It's now reachable from Python as
rustext.ancestor.AncestorsIterator
Tests are provided in the previously introduced
Python testcase: this is much more convenient
that writing lengthy Rust code to call into Python.
Differential Revision: https://phab.mercurial-scm.org/D5439
author | Georges Racinet <gracinet@anybox.fr> |
---|---|
date | Thu, 06 Dec 2018 20:01:21 +0100 |
parents | 5532823e8c18 |
children | b31a41f24864 |
comparison
equal
deleted
inserted
replaced
41052:4c25038c112c | 41053:d9f439fcdb4c |
---|---|
5 // This software may be used and distributed according to the terms of the | 5 // This software may be used and distributed according to the terms of the |
6 // GNU General Public License version 2 or any later version. | 6 // GNU General Public License version 2 or any later version. |
7 | 7 |
8 //! Bindings for the hg::ancestors module provided by the | 8 //! Bindings for the hg::ancestors module provided by the |
9 //! `hg-core` crate. From Python, this will be seen as `rustext.ancestor` | 9 //! `hg-core` crate. From Python, this will be seen as `rustext.ancestor` |
10 use cpython::{PyDict, PyModule, PyResult, Python}; | 10 use cindex::Index; |
11 use cpython::{ | |
12 ObjectProtocol, PyClone, PyDict, PyModule, PyObject, PyResult, Python, | |
13 }; | |
14 use exceptions::GraphError; | |
15 use hg; | |
16 use hg::AncestorsIterator as CoreIterator; | |
17 use hg::Revision; | |
18 use std::cell::RefCell; | |
19 | |
20 /// Utility function to convert a Python iterable into a Vec<Revision> | |
21 /// | |
22 /// We need this to feed to AncestorIterators constructors because | |
23 /// a PyErr can arise at each step of iteration, whereas our inner objects | |
24 /// expect iterables over Revision, not over some Result<Revision, PyErr> | |
25 fn reviter_to_revvec(py: Python, revs: PyObject) -> PyResult<Vec<Revision>> { | |
26 revs.iter(py)? | |
27 .map(|r| r.and_then(|o| o.extract::<Revision>(py))) | |
28 .collect() | |
29 } | |
30 | |
31 py_class!(class AncestorsIterator |py| { | |
32 // TODO RW lock ? | |
33 data inner: RefCell<Box<CoreIterator<Index>>>; | |
34 | |
35 def __next__(&self) -> PyResult<Option<Revision>> { | |
36 match self.inner(py).borrow_mut().next() { | |
37 Some(Err(e)) => Err(GraphError::pynew(py, e)), | |
38 None => Ok(None), | |
39 Some(Ok(r)) => Ok(Some(r)), | |
40 } | |
41 } | |
42 | |
43 def __contains__(&self, rev: Revision) -> PyResult<bool> { | |
44 self.inner(py).borrow_mut().contains(rev).map_err(|e| GraphError::pynew(py, e)) | |
45 } | |
46 | |
47 def __iter__(&self) -> PyResult<Self> { | |
48 Ok(self.clone_ref(py)) | |
49 } | |
50 | |
51 def __new__(_cls, index: PyObject, initrevs: PyObject, stoprev: Revision, | |
52 inclusive: bool) -> PyResult<AncestorsIterator> { | |
53 let initvec = reviter_to_revvec(py, initrevs)?; | |
54 let ait = match hg::AncestorsIterator::new(Index::new(py, index)?, | |
55 initvec, stoprev, | |
56 inclusive) { | |
57 Ok(ait) => ait, | |
58 Err(e) => { | |
59 return Err(GraphError::pynew(py, e)); | |
60 } | |
61 }; | |
62 AncestorsIterator::from_inner(py, ait) | |
63 } | |
64 | |
65 }); | |
66 | |
67 impl AncestorsIterator { | |
68 pub fn from_inner(py: Python, ait: CoreIterator<Index>) -> PyResult<Self> { | |
69 Self::create_instance(py, RefCell::new(Box::new(ait))) | |
70 } | |
71 } | |
11 | 72 |
12 /// Create the module, with __package__ given from parent | 73 /// Create the module, with __package__ given from parent |
13 pub fn init_module(py: Python, package: &str) -> PyResult<PyModule> { | 74 pub fn init_module(py: Python, package: &str) -> PyResult<PyModule> { |
14 let dotted_name = &format!("{}.ancestor", package); | 75 let dotted_name = &format!("{}.ancestor", package); |
15 let m = PyModule::new(py, dotted_name)?; | 76 let m = PyModule::new(py, dotted_name)?; |
17 m.add( | 78 m.add( |
18 py, | 79 py, |
19 "__doc__", | 80 "__doc__", |
20 "Generic DAG ancestor algorithms - Rust implementation", | 81 "Generic DAG ancestor algorithms - Rust implementation", |
21 )?; | 82 )?; |
83 m.add_class::<AncestorsIterator>(py)?; | |
22 | 84 |
23 let sys = PyModule::import(py, "sys")?; | 85 let sys = PyModule::import(py, "sys")?; |
24 let sys_modules: PyDict = sys.get(py, "modules")?.extract(py)?; | 86 let sys_modules: PyDict = sys.get(py, "modules")?.extract(py)?; |
25 sys_modules.set_item(py, dotted_name, &m)?; | 87 sys_modules.set_item(py, dotted_name, &m)?; |
26 // Example C code (see pyexpat.c and import.c) will "give away the | 88 // Example C code (see pyexpat.c and import.c) will "give away the |