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 //! and can be used as replacement for the the pure `ancestor` Python module. |
10 //! and can be used as replacement for the the pure `ancestor` Python module. |
11 //! |
11 //! |
12 //! # Classes visible from Python: |
12 //! # Classes visible from Python: |
13 //! - [`LazyAncestors`] is the Rust implementation of |
13 //! - [`LazyAncestors`] is the Rust implementation of |
14 //! `mercurial.ancestor.lazyancestors`. |
14 //! `mercurial.ancestor.lazyancestors`. The only difference is that it is |
15 //! The only difference is that it is instantiated with a C `parsers.index` |
15 //! instantiated with a C `parsers.index` instance instead of a parents |
16 //! instance instead of a parents function. |
16 //! function. |
17 //! |
17 //! |
18 //! - [`MissingAncestors`] is the Rust implementation of |
18 //! - [`MissingAncestors`] is the Rust implementation of |
19 //! `mercurial.ancestor.incrementalmissingancestors`. |
19 //! `mercurial.ancestor.incrementalmissingancestors`. |
20 //! |
20 //! |
21 //! API differences: |
21 //! API differences: |
25 //! a set-valued attribute. We could return a Python set easily if our |
25 //! a set-valued attribute. We could return a Python set easily if our |
26 //! [PySet PR](https://github.com/dgrunwald/rust-cpython/pull/165) |
26 //! [PySet PR](https://github.com/dgrunwald/rust-cpython/pull/165) |
27 //! is accepted. |
27 //! is accepted. |
28 //! |
28 //! |
29 //! - [`AncestorsIterator`] is the Rust counterpart of the |
29 //! - [`AncestorsIterator`] is the Rust counterpart of the |
30 //! `ancestor._lazyancestorsiter` Python generator. |
30 //! `ancestor._lazyancestorsiter` Python generator. From Python, instances of |
31 //! From Python, instances of this should be mainly obtained by calling |
31 //! this should be mainly obtained by calling `iter()` on a [`LazyAncestors`] |
32 //! `iter()` on a [`LazyAncestors`] instance. |
32 //! instance. |
33 //! |
33 //! |
34 //! [`LazyAncestors`]: struct.LazyAncestors.html |
34 //! [`LazyAncestors`]: struct.LazyAncestors.html |
35 //! [`MissingAncestors`]: struct.MissingAncestors.html |
35 //! [`MissingAncestors`]: struct.MissingAncestors.html |
36 //! [`AncestorsIterator`]: struct.AncestorsIterator.html |
36 //! [`AncestorsIterator`]: struct.AncestorsIterator.html |
37 use crate::conversion::rev_pyiter_collect; |
37 use crate::conversion::rev_pyiter_collect; |
38 use cindex::Index; |
38 use cindex::Index; |
39 use cpython::{ |
39 use cpython::{ |
40 ObjectProtocol, PyClone, PyDict, PyList, PyModule, PyObject, |
40 ObjectProtocol, PyClone, PyDict, PyList, PyModule, PyObject, PyResult, |
41 PyResult, PyTuple, Python, PythonObject, ToPyObject, |
41 PyTuple, Python, PythonObject, ToPyObject, |
42 }; |
42 }; |
43 use exceptions::GraphError; |
43 use exceptions::GraphError; |
44 use hg::Revision; |
44 use hg::Revision; |
45 use hg::{ |
45 use hg::{ |
46 AncestorsIterator as CoreIterator, LazyAncestors as CoreLazy, |
46 AncestorsIterator as CoreIterator, LazyAncestors as CoreLazy, |
88 pub fn from_inner(py: Python, ait: CoreIterator<Index>) -> PyResult<Self> { |
88 pub fn from_inner(py: Python, ait: CoreIterator<Index>) -> PyResult<Self> { |
89 Self::create_instance(py, RefCell::new(Box::new(ait))) |
89 Self::create_instance(py, RefCell::new(Box::new(ait))) |
90 } |
90 } |
91 } |
91 } |
92 |
92 |
|
93 /// Copy and convert an `HashSet<Revision>` in a Python set |
|
94 /// |
|
95 /// This will probably turn useless once `PySet` support lands in |
|
96 /// `rust-cpython`. |
|
97 /// |
|
98 /// This builds a Python tuple, then calls Python's "set()" on it |
|
99 fn py_set(py: Python, set: &HashSet<Revision>) -> PyResult<PyObject> { |
|
100 let as_vec: Vec<PyObject> = set |
|
101 .iter() |
|
102 .map(|rev| rev.to_py_object(py).into_object()) |
|
103 .collect(); |
|
104 let as_pytuple = PyTuple::new(py, as_vec.as_slice()); |
|
105 |
|
106 let locals = PyDict::new(py); |
|
107 locals.set_item(py, "obj", as_pytuple.to_py_object(py))?; |
|
108 py.eval("set(obj)", None, Some(&locals)) |
|
109 } |
|
110 |
93 py_class!(pub class LazyAncestors |py| { |
111 py_class!(pub class LazyAncestors |py| { |
94 data inner: RefCell<Box<CoreLazy<Index>>>; |
112 data inner: RefCell<Box<CoreLazy<Index>>>; |
95 |
113 |
96 def __contains__(&self, rev: Revision) -> PyResult<bool> { |
114 def __contains__(&self, rev: Revision) -> PyResult<bool> { |
97 self.inner(py) |
115 self.inner(py) |
142 // the trait `cpython::ToPyObject` is not implemented for `()` |
160 // the trait `cpython::ToPyObject` is not implemented for `()` |
143 // so let's return an explicit None |
161 // so let's return an explicit None |
144 Ok(py.None()) |
162 Ok(py.None()) |
145 } |
163 } |
146 |
164 |
147 def bases(&self) -> PyResult<PyTuple> { |
165 def bases(&self) -> PyResult<PyObject> { |
148 let inner = self.inner(py).borrow(); |
166 py_set(py, self.inner(py).borrow().get_bases()) |
149 let bases_set = inner.get_bases(); |
|
150 // convert as Python tuple TODO how to return a proper Python set? |
|
151 let mut bases_vec: Vec<PyObject> = Vec::with_capacity( |
|
152 bases_set.len()); |
|
153 for rev in bases_set { |
|
154 bases_vec.push(rev.to_py_object(py).into_object()); |
|
155 } |
|
156 Ok(PyTuple::new(py, bases_vec.as_slice())) |
|
157 } |
167 } |
158 |
168 |
159 def removeancestorsfrom(&self, revs: PyObject) -> PyResult<PyObject> { |
169 def removeancestorsfrom(&self, revs: PyObject) -> PyResult<PyObject> { |
160 let mut inner = self.inner(py).borrow_mut(); |
170 let mut inner = self.inner(py).borrow_mut(); |
161 // this is very lame: we convert to a Rust set, update it in place |
171 // this is very lame: we convert to a Rust set, update it in place |