##// END OF EJS Templates
rust-format: cleanup ancestors.rs to make rustfmt happy...
Raphaël Gomès -
r44927:b24721e7 stable
parent child Browse files
Show More
@@ -1,222 +1,227 b''
1 // ancestors.rs
1 // ancestors.rs
2 //
2 //
3 // Copyright 2018 Georges Racinet <gracinet@anybox.fr>
3 // Copyright 2018 Georges Racinet <gracinet@anybox.fr>
4 //
4 //
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 //! 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`. The only difference is that it is
14 //! `mercurial.ancestor.lazyancestors`. The only difference is that it is
15 //! instantiated with a C `parsers.index` instance instead of a parents
15 //! instantiated with a C `parsers.index` instance instead of a parents
16 //! 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:
22 //! + it is instantiated with a C `parsers.index`
22 //! + it is instantiated with a C `parsers.index`
23 //! instance instead of a parents function.
23 //! instance instead of a parents function.
24 //! + `MissingAncestors.bases` is a method returning a tuple instead of
24 //! + `MissingAncestors.bases` is a method returning a tuple instead of
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. From Python, instances of
30 //! `ancestor._lazyancestorsiter` Python generator. From Python, instances of
31 //! this should be mainly obtained by calling `iter()` on a [`LazyAncestors`]
31 //! this should be mainly obtained by calling `iter()` on a [`LazyAncestors`]
32 //! 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::revlog::pyindex_to_graph;
37 use crate::revlog::pyindex_to_graph;
38 use crate::{
38 use crate::{
39 cindex::Index, conversion::rev_pyiter_collect, exceptions::GraphError,
39 cindex::Index, conversion::rev_pyiter_collect, exceptions::GraphError,
40 };
40 };
41 use cpython::{
41 use cpython::{
42 ObjectProtocol, PyClone, PyDict, PyList, PyModule, PyObject, PyResult,
42 ObjectProtocol, PyClone, PyDict, PyList, PyModule, PyObject, PyResult,
43 Python, PythonObject, ToPyObject,
43 Python, PythonObject, ToPyObject,
44 };
44 };
45 use hg::Revision;
45 use hg::Revision;
46 use hg::{
46 use hg::{
47 AncestorsIterator as CoreIterator, LazyAncestors as CoreLazy,
47 AncestorsIterator as CoreIterator, LazyAncestors as CoreLazy,
48 MissingAncestors as CoreMissing,
48 MissingAncestors as CoreMissing,
49 };
49 };
50 use std::cell::RefCell;
50 use std::cell::RefCell;
51 use std::collections::HashSet;
51 use std::collections::HashSet;
52
52
53 py_class!(pub class AncestorsIterator |py| {
53 py_class!(pub class AncestorsIterator |py| {
54 data inner: RefCell<Box<CoreIterator<Index>>>;
54 data inner: RefCell<Box<CoreIterator<Index>>>;
55
55
56 def __next__(&self) -> PyResult<Option<Revision>> {
56 def __next__(&self) -> PyResult<Option<Revision>> {
57 match self.inner(py).borrow_mut().next() {
57 match self.inner(py).borrow_mut().next() {
58 Some(Err(e)) => Err(GraphError::pynew(py, e)),
58 Some(Err(e)) => Err(GraphError::pynew(py, e)),
59 None => Ok(None),
59 None => Ok(None),
60 Some(Ok(r)) => Ok(Some(r)),
60 Some(Ok(r)) => Ok(Some(r)),
61 }
61 }
62 }
62 }
63
63
64 def __contains__(&self, rev: Revision) -> PyResult<bool> {
64 def __contains__(&self, rev: Revision) -> PyResult<bool> {
65 self.inner(py).borrow_mut().contains(rev)
65 self.inner(py).borrow_mut().contains(rev)
66 .map_err(|e| GraphError::pynew(py, e))
66 .map_err(|e| GraphError::pynew(py, e))
67 }
67 }
68
68
69 def __iter__(&self) -> PyResult<Self> {
69 def __iter__(&self) -> PyResult<Self> {
70 Ok(self.clone_ref(py))
70 Ok(self.clone_ref(py))
71 }
71 }
72
72
73 def __new__(_cls, index: PyObject, initrevs: PyObject, stoprev: Revision,
73 def __new__(_cls, index: PyObject, initrevs: PyObject, stoprev: Revision,
74 inclusive: bool) -> PyResult<AncestorsIterator> {
74 inclusive: bool) -> PyResult<AncestorsIterator> {
75 let initvec: Vec<Revision> = rev_pyiter_collect(py, &initrevs)?;
75 let initvec: Vec<Revision> = rev_pyiter_collect(py, &initrevs)?;
76 let ait = CoreIterator::new(
76 let ait = CoreIterator::new(
77 pyindex_to_graph(py, index)?,
77 pyindex_to_graph(py, index)?,
78 initvec,
78 initvec,
79 stoprev,
79 stoprev,
80 inclusive,
80 inclusive,
81 )
81 )
82 .map_err(|e| GraphError::pynew(py, e))?;
82 .map_err(|e| GraphError::pynew(py, e))?;
83 AncestorsIterator::from_inner(py, ait)
83 AncestorsIterator::from_inner(py, ait)
84 }
84 }
85
85
86 });
86 });
87
87
88 impl AncestorsIterator {
88 impl AncestorsIterator {
89 pub fn from_inner(py: Python, ait: CoreIterator<Index>) -> PyResult<Self> {
89 pub fn from_inner(py: Python, ait: CoreIterator<Index>) -> PyResult<Self> {
90 Self::create_instance(py, RefCell::new(Box::new(ait)))
90 Self::create_instance(py, RefCell::new(Box::new(ait)))
91 }
91 }
92 }
92 }
93
93
94 py_class!(pub class LazyAncestors |py| {
94 py_class!(pub class LazyAncestors |py| {
95 data inner: RefCell<Box<CoreLazy<Index>>>;
95 data inner: RefCell<Box<CoreLazy<Index>>>;
96
96
97 def __contains__(&self, rev: Revision) -> PyResult<bool> {
97 def __contains__(&self, rev: Revision) -> PyResult<bool> {
98 self.inner(py)
98 self.inner(py)
99 .borrow_mut()
99 .borrow_mut()
100 .contains(rev)
100 .contains(rev)
101 .map_err(|e| GraphError::pynew(py, e))
101 .map_err(|e| GraphError::pynew(py, e))
102 }
102 }
103
103
104 def __iter__(&self) -> PyResult<AncestorsIterator> {
104 def __iter__(&self) -> PyResult<AncestorsIterator> {
105 AncestorsIterator::from_inner(py, self.inner(py).borrow().iter())
105 AncestorsIterator::from_inner(py, self.inner(py).borrow().iter())
106 }
106 }
107
107
108 def __bool__(&self) -> PyResult<bool> {
108 def __bool__(&self) -> PyResult<bool> {
109 Ok(!self.inner(py).borrow().is_empty())
109 Ok(!self.inner(py).borrow().is_empty())
110 }
110 }
111
111
112 def __new__(_cls, index: PyObject, initrevs: PyObject, stoprev: Revision,
112 def __new__(_cls, index: PyObject, initrevs: PyObject, stoprev: Revision,
113 inclusive: bool) -> PyResult<Self> {
113 inclusive: bool) -> PyResult<Self> {
114 let initvec: Vec<Revision> = rev_pyiter_collect(py, &initrevs)?;
114 let initvec: Vec<Revision> = rev_pyiter_collect(py, &initrevs)?;
115
115
116 let lazy =
116 let lazy =
117 CoreLazy::new(pyindex_to_graph(py, index)?,
117 CoreLazy::new(pyindex_to_graph(py, index)?,
118 initvec, stoprev, inclusive)
118 initvec, stoprev, inclusive)
119 .map_err(|e| GraphError::pynew(py, e))?;
119 .map_err(|e| GraphError::pynew(py, e))?;
120
120
121 Self::create_instance(py, RefCell::new(Box::new(lazy)))
121 Self::create_instance(py, RefCell::new(Box::new(lazy)))
122 }
122 }
123
123
124 });
124 });
125
125
126 py_class!(pub class MissingAncestors |py| {
126 py_class!(pub class MissingAncestors |py| {
127 data inner: RefCell<Box<CoreMissing<Index>>>;
127 data inner: RefCell<Box<CoreMissing<Index>>>;
128
128
129 def __new__(_cls, index: PyObject, bases: PyObject) -> PyResult<MissingAncestors> {
129 def __new__(
130 _cls,
131 index: PyObject,
132 bases: PyObject
133 )
134 -> PyResult<MissingAncestors> {
130 let bases_vec: Vec<Revision> = rev_pyiter_collect(py, &bases)?;
135 let bases_vec: Vec<Revision> = rev_pyiter_collect(py, &bases)?;
131 let inner = CoreMissing::new(pyindex_to_graph(py, index)?, bases_vec);
136 let inner = CoreMissing::new(pyindex_to_graph(py, index)?, bases_vec);
132 MissingAncestors::create_instance(py, RefCell::new(Box::new(inner)))
137 MissingAncestors::create_instance(py, RefCell::new(Box::new(inner)))
133 }
138 }
134
139
135 def hasbases(&self) -> PyResult<bool> {
140 def hasbases(&self) -> PyResult<bool> {
136 Ok(self.inner(py).borrow().has_bases())
141 Ok(self.inner(py).borrow().has_bases())
137 }
142 }
138
143
139 def addbases(&self, bases: PyObject) -> PyResult<PyObject> {
144 def addbases(&self, bases: PyObject) -> PyResult<PyObject> {
140 let mut inner = self.inner(py).borrow_mut();
145 let mut inner = self.inner(py).borrow_mut();
141 let bases_vec: Vec<Revision> = rev_pyiter_collect(py, &bases)?;
146 let bases_vec: Vec<Revision> = rev_pyiter_collect(py, &bases)?;
142 inner.add_bases(bases_vec);
147 inner.add_bases(bases_vec);
143 // cpython doc has examples with PyResult<()> but this gives me
148 // cpython doc has examples with PyResult<()> but this gives me
144 // the trait `cpython::ToPyObject` is not implemented for `()`
149 // the trait `cpython::ToPyObject` is not implemented for `()`
145 // so let's return an explicit None
150 // so let's return an explicit None
146 Ok(py.None())
151 Ok(py.None())
147 }
152 }
148
153
149 def bases(&self) -> PyResult<HashSet<Revision>> {
154 def bases(&self) -> PyResult<HashSet<Revision>> {
150 Ok(self.inner(py).borrow().get_bases().clone())
155 Ok(self.inner(py).borrow().get_bases().clone())
151 }
156 }
152
157
153 def basesheads(&self) -> PyResult<HashSet<Revision>> {
158 def basesheads(&self) -> PyResult<HashSet<Revision>> {
154 let inner = self.inner(py).borrow();
159 let inner = self.inner(py).borrow();
155 inner.bases_heads().map_err(|e| GraphError::pynew(py, e))
160 inner.bases_heads().map_err(|e| GraphError::pynew(py, e))
156 }
161 }
157
162
158 def removeancestorsfrom(&self, revs: PyObject) -> PyResult<PyObject> {
163 def removeancestorsfrom(&self, revs: PyObject) -> PyResult<PyObject> {
159 let mut inner = self.inner(py).borrow_mut();
164 let mut inner = self.inner(py).borrow_mut();
160 // this is very lame: we convert to a Rust set, update it in place
165 // this is very lame: we convert to a Rust set, update it in place
161 // and then convert back to Python, only to have Python remove the
166 // and then convert back to Python, only to have Python remove the
162 // excess (thankfully, Python is happy with a list or even an iterator)
167 // excess (thankfully, Python is happy with a list or even an iterator)
163 // Leads to improve this:
168 // Leads to improve this:
164 // - have the CoreMissing instead do something emit revisions to
169 // - have the CoreMissing instead do something emit revisions to
165 // discard
170 // discard
166 // - define a trait for sets of revisions in the core and implement
171 // - define a trait for sets of revisions in the core and implement
167 // it for a Python set rewrapped with the GIL marker
172 // it for a Python set rewrapped with the GIL marker
168 let mut revs_pyset: HashSet<Revision> = rev_pyiter_collect(py, &revs)?;
173 let mut revs_pyset: HashSet<Revision> = rev_pyiter_collect(py, &revs)?;
169 inner.remove_ancestors_from(&mut revs_pyset)
174 inner.remove_ancestors_from(&mut revs_pyset)
170 .map_err(|e| GraphError::pynew(py, e))?;
175 .map_err(|e| GraphError::pynew(py, e))?;
171
176
172 // convert as Python list
177 // convert as Python list
173 let mut remaining_pyint_vec: Vec<PyObject> = Vec::with_capacity(
178 let mut remaining_pyint_vec: Vec<PyObject> = Vec::with_capacity(
174 revs_pyset.len());
179 revs_pyset.len());
175 for rev in revs_pyset {
180 for rev in revs_pyset {
176 remaining_pyint_vec.push(rev.to_py_object(py).into_object());
181 remaining_pyint_vec.push(rev.to_py_object(py).into_object());
177 }
182 }
178 let remaining_pylist = PyList::new(py, remaining_pyint_vec.as_slice());
183 let remaining_pylist = PyList::new(py, remaining_pyint_vec.as_slice());
179 revs.call_method(py, "intersection_update", (remaining_pylist, ), None)
184 revs.call_method(py, "intersection_update", (remaining_pylist, ), None)
180 }
185 }
181
186
182 def missingancestors(&self, revs: PyObject) -> PyResult<PyList> {
187 def missingancestors(&self, revs: PyObject) -> PyResult<PyList> {
183 let mut inner = self.inner(py).borrow_mut();
188 let mut inner = self.inner(py).borrow_mut();
184 let revs_vec: Vec<Revision> = rev_pyiter_collect(py, &revs)?;
189 let revs_vec: Vec<Revision> = rev_pyiter_collect(py, &revs)?;
185 let missing_vec = match inner.missing_ancestors(revs_vec) {
190 let missing_vec = match inner.missing_ancestors(revs_vec) {
186 Ok(missing) => missing,
191 Ok(missing) => missing,
187 Err(e) => {
192 Err(e) => {
188 return Err(GraphError::pynew(py, e));
193 return Err(GraphError::pynew(py, e));
189 }
194 }
190 };
195 };
191 // convert as Python list
196 // convert as Python list
192 let mut missing_pyint_vec: Vec<PyObject> = Vec::with_capacity(
197 let mut missing_pyint_vec: Vec<PyObject> = Vec::with_capacity(
193 missing_vec.len());
198 missing_vec.len());
194 for rev in missing_vec {
199 for rev in missing_vec {
195 missing_pyint_vec.push(rev.to_py_object(py).into_object());
200 missing_pyint_vec.push(rev.to_py_object(py).into_object());
196 }
201 }
197 Ok(PyList::new(py, missing_pyint_vec.as_slice()))
202 Ok(PyList::new(py, missing_pyint_vec.as_slice()))
198 }
203 }
199 });
204 });
200
205
201 /// Create the module, with __package__ given from parent
206 /// Create the module, with __package__ given from parent
202 pub fn init_module(py: Python, package: &str) -> PyResult<PyModule> {
207 pub fn init_module(py: Python, package: &str) -> PyResult<PyModule> {
203 let dotted_name = &format!("{}.ancestor", package);
208 let dotted_name = &format!("{}.ancestor", package);
204 let m = PyModule::new(py, dotted_name)?;
209 let m = PyModule::new(py, dotted_name)?;
205 m.add(py, "__package__", package)?;
210 m.add(py, "__package__", package)?;
206 m.add(
211 m.add(
207 py,
212 py,
208 "__doc__",
213 "__doc__",
209 "Generic DAG ancestor algorithms - Rust implementation",
214 "Generic DAG ancestor algorithms - Rust implementation",
210 )?;
215 )?;
211 m.add_class::<AncestorsIterator>(py)?;
216 m.add_class::<AncestorsIterator>(py)?;
212 m.add_class::<LazyAncestors>(py)?;
217 m.add_class::<LazyAncestors>(py)?;
213 m.add_class::<MissingAncestors>(py)?;
218 m.add_class::<MissingAncestors>(py)?;
214
219
215 let sys = PyModule::import(py, "sys")?;
220 let sys = PyModule::import(py, "sys")?;
216 let sys_modules: PyDict = sys.get(py, "modules")?.extract(py)?;
221 let sys_modules: PyDict = sys.get(py, "modules")?.extract(py)?;
217 sys_modules.set_item(py, dotted_name, &m)?;
222 sys_modules.set_item(py, dotted_name, &m)?;
218 // Example C code (see pyexpat.c and import.c) will "give away the
223 // Example C code (see pyexpat.c and import.c) will "give away the
219 // reference", but we won't because it will be consumed once the
224 // reference", but we won't because it will be consumed once the
220 // Rust PyObject is dropped.
225 // Rust PyObject is dropped.
221 Ok(m)
226 Ok(m)
222 }
227 }
General Comments 0
You need to be logged in to leave comments. Login now