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