comparison rust/hg-cpython/src/ancestors.rs @ 51240:59d81768ad6d

rust-index: using `hg::index::Index` in MissingAncestors With this, the whole `hg-cpython::ancestors` module can now work without the C index.
author Georges Racinet on incendie.racinet.fr <georges@racinet.fr>
date Sat, 28 Oct 2023 22:50:10 +0200
parents 7eea2e4109ae
children 24d3298189d7
comparison
equal deleted inserted replaced
51239:7eea2e4109ae 51240:59d81768ad6d
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::{py_rust_index_to_graph, pyindex_to_graph}; 37 use crate::revlog::py_rust_index_to_graph;
38 use crate::PyRevision; 38 use crate::PyRevision;
39 use crate::{ 39 use crate::{
40 cindex::Index, conversion::rev_pyiter_collect, exceptions::GraphError, 40 conversion::rev_pyiter_collect, exceptions::GraphError,
41 revlog::PySharedIndex, 41 revlog::PySharedIndex,
42 }; 42 };
43 use cpython::{ 43 use cpython::{
44 ObjectProtocol, PyClone, PyDict, PyErr, PyList, PyModule, PyObject, 44 ObjectProtocol, PyClone, PyDict, PyErr, PyList, PyModule, PyObject,
45 PyResult, Python, PythonObject, ToPyObject, UnsafePyLeaked, 45 PyResult, Python, PythonObject, ToPyObject, UnsafePyLeaked,
221 } 221 }
222 222
223 }); 223 });
224 224
225 py_class!(pub class MissingAncestors |py| { 225 py_class!(pub class MissingAncestors |py| {
226 data inner: RefCell<Box<CoreMissing<Index>>>; 226 data inner: RefCell<UnsafePyLeaked<
227 data index: RefCell<Index>; 227 CoreMissing<PySharedIndex>
228 >>;
229 data index: PyObject;
228 230
229 def __new__( 231 def __new__(
230 _cls, 232 _cls,
231 index: PyObject, 233 index: PyObject,
232 bases: PyObject 234 bases: PyObject
233 ) 235 )
234 -> PyResult<MissingAncestors> { 236 -> PyResult<MissingAncestors> {
235 let index = pyindex_to_graph(py, index)?; 237 let cloned_index = index.clone_ref(py);
236 let bases_vec: Vec<_> = rev_pyiter_collect(py, &bases, &index)?; 238 let inner_index = py_rust_index_to_graph(py, index)?;
237 239 let bases_vec: Vec<_> = {
238 let inner = CoreMissing::new(index.clone_ref(py), bases_vec); 240 let borrowed_idx = unsafe { inner_index.try_borrow(py)? };
241 rev_pyiter_collect(py, &bases, &*borrowed_idx)?
242 };
243
244 let inner = unsafe {
245 inner_index.map(py, |idx| CoreMissing::new(idx, bases_vec))
246 };
239 MissingAncestors::create_instance( 247 MissingAncestors::create_instance(
240 py, 248 py,
241 RefCell::new(Box::new(inner)), 249 RefCell::new(inner),
242 RefCell::new(index) 250 cloned_index,
243 ) 251 )
244 } 252 }
245 253
246 def hasbases(&self) -> PyResult<bool> { 254 def hasbases(&self) -> PyResult<bool> {
247 Ok(self.inner(py).borrow().has_bases()) 255 let leaked = self.inner(py).borrow();
256 let inner: &CoreMissing<PySharedIndex> =
257 &*unsafe { leaked.try_borrow(py)? };
258 Ok(inner.has_bases())
248 } 259 }
249 260
250 def addbases(&self, bases: PyObject) -> PyResult<PyObject> { 261 def addbases(&self, bases: PyObject) -> PyResult<PyObject> {
251 let index = self.index(py).borrow(); 262 let bases_vec: Vec<_> = {
252 let bases_vec: Vec<_> = rev_pyiter_collect(py, &bases, &*index)?; 263 let leaked = py_rust_index_to_graph(py,
253 let mut inner = self.inner(py).borrow_mut(); 264 self.index(py).clone_ref(py))?;
265 let index = &*unsafe { leaked.try_borrow(py)? };
266 rev_pyiter_collect(py, &bases, index)?
267 };
268
269 let mut leaked = self.inner(py).borrow_mut();
270 let inner: &mut CoreMissing<PySharedIndex> =
271 &mut *unsafe { leaked.try_borrow_mut(py)? };
272
254 inner.add_bases(bases_vec); 273 inner.add_bases(bases_vec);
255 // cpython doc has examples with PyResult<()> but this gives me 274 // cpython doc has examples with PyResult<()> but this gives me
256 // the trait `cpython::ToPyObject` is not implemented for `()` 275 // the trait `cpython::ToPyObject` is not implemented for `()`
257 // so let's return an explicit None 276 // so let's return an explicit None
258 Ok(py.None()) 277 Ok(py.None())
259 } 278 }
260 279
261 def bases(&self) -> PyResult<HashSet<PyRevision>> { 280 def bases(&self) -> PyResult<HashSet<PyRevision>> {
262 Ok( 281 let leaked = self.inner(py).borrow();
263 self.inner(py) 282 let inner: &CoreMissing<PySharedIndex> =
264 .borrow() 283 &*unsafe { leaked.try_borrow(py)? };
265 .get_bases() 284 Ok(inner.get_bases()
266 .iter() 285 .iter()
267 .map(|r| PyRevision(r.0)) 286 .map(|r| PyRevision(r.0))
268 .collect() 287 .collect()
269 ) 288 )
270 } 289 }
271 290
272 def basesheads(&self) -> PyResult<HashSet<PyRevision>> { 291 def basesheads(&self) -> PyResult<HashSet<PyRevision>> {
273 let inner = self.inner(py).borrow(); 292 let leaked = self.inner(py).borrow();
293 let inner: &CoreMissing<PySharedIndex> =
294 &*unsafe { leaked.try_borrow(py)? };
274 Ok( 295 Ok(
275 inner 296 inner
276 .bases_heads() 297 .bases_heads()
277 .map_err(|e| GraphError::pynew(py, e))? 298 .map_err(|e| GraphError::pynew(py, e))?
278 .into_iter() 299 .into_iter()
280 .collect() 301 .collect()
281 ) 302 )
282 } 303 }
283 304
284 def removeancestorsfrom(&self, revs: PyObject) -> PyResult<PyObject> { 305 def removeancestorsfrom(&self, revs: PyObject) -> PyResult<PyObject> {
285 let index = self.index(py).borrow(); 306 let mut revs_pyset: HashSet<Revision> = {
286 // this is very lame: we convert to a Rust set, update it in place 307 // this is very lame: we convert to a Rust set, update it in place
287 // and then convert back to Python, only to have Python remove the 308 // and then convert back to Python, only to have Python remove the
288 // excess (thankfully, Python is happy with a list or even an iterator) 309 // excess (thankfully, Python is happy with a list or even an
289 // Leads to improve this: 310 // iterator)
290 // - have the CoreMissing instead do something emit revisions to 311 // Leads to improve this:
291 // discard 312 // - have the CoreMissing instead do something emit revisions to
292 // - define a trait for sets of revisions in the core and implement 313 // discard
293 // it for a Python set rewrapped with the GIL marker 314 // - define a trait for sets of revisions in the core and
294 let mut revs_pyset: HashSet<Revision> = rev_pyiter_collect( 315 // implement it for a Python set rewrapped with the GIL marker
295 py, &revs, &*index 316 let leaked = py_rust_index_to_graph(py,
296 )?; 317 self.index(py).clone_ref(py))?;
297 let mut inner = self.inner(py).borrow_mut(); 318 let index = &*unsafe { leaked.try_borrow(py)? };
319 rev_pyiter_collect(py, &revs, &*index)?
320 };
321
322 let mut leaked = self.inner(py).borrow_mut();
323 let inner: &mut CoreMissing<PySharedIndex> =
324 &mut *unsafe { leaked.try_borrow_mut(py)? };
325
298 inner.remove_ancestors_from(&mut revs_pyset) 326 inner.remove_ancestors_from(&mut revs_pyset)
299 .map_err(|e| GraphError::pynew(py, e))?; 327 .map_err(|e| GraphError::pynew(py, e))?;
300 328
301 // convert as Python list 329 // convert as Python list
302 let mut remaining_pyint_vec: Vec<PyObject> = Vec::with_capacity( 330 let mut remaining_pyint_vec: Vec<PyObject> = Vec::with_capacity(
309 let remaining_pylist = PyList::new(py, remaining_pyint_vec.as_slice()); 337 let remaining_pylist = PyList::new(py, remaining_pyint_vec.as_slice());
310 revs.call_method(py, "intersection_update", (remaining_pylist, ), None) 338 revs.call_method(py, "intersection_update", (remaining_pylist, ), None)
311 } 339 }
312 340
313 def missingancestors(&self, revs: PyObject) -> PyResult<PyList> { 341 def missingancestors(&self, revs: PyObject) -> PyResult<PyList> {
314 let index = self.index(py).borrow(); 342 let revs_vec: Vec<Revision> = {
315 let revs_vec: Vec<Revision> = rev_pyiter_collect(py, &revs, &*index)?; 343 let leaked = py_rust_index_to_graph(py,
316 344 self.index(py).clone_ref(py))?;
317 let mut inner = self.inner(py).borrow_mut(); 345 let index = &*unsafe { leaked.try_borrow(py)? };
346 rev_pyiter_collect(py, &revs, index)?
347 };
348
349 let mut leaked = self.inner(py).borrow_mut();
350 let inner: &mut CoreMissing<PySharedIndex> =
351 &mut *unsafe { leaked.try_borrow_mut(py)? };
352
318 let missing_vec = match inner.missing_ancestors(revs_vec) { 353 let missing_vec = match inner.missing_ancestors(revs_vec) {
319 Ok(missing) => missing, 354 Ok(missing) => missing,
320 Err(e) => { 355 Err(e) => {
321 return Err(GraphError::pynew(py, e)); 356 return Err(GraphError::pynew(py, e));
322 } 357 }