Show More
@@ -13,7 +13,6 b' use std::cell::RefCell;' | |||||
13 |
|
13 | |||
14 | use crate::dirstate::dirstate_map::DirstateMap; |
|
14 | use crate::dirstate::dirstate_map::DirstateMap; | |
15 | use crate::ref_sharing::PyLeakedRef; |
|
15 | use crate::ref_sharing::PyLeakedRef; | |
16 | use hg::DirstateMap as RustDirstateMap; |
|
|||
17 | use hg::{utils::hg_path::HgPathBuf, CopyMapIter}; |
|
16 | use hg::{utils::hg_path::HgPathBuf, CopyMapIter}; | |
18 |
|
17 | |||
19 | py_class!(pub class CopyMap |py| { |
|
18 | py_class!(pub class CopyMap |py| { | |
@@ -105,16 +104,14 b' impl CopyMap {' | |||||
105 |
|
104 | |||
106 | py_shared_iterator!( |
|
105 | py_shared_iterator!( | |
107 | CopyMapKeysIterator, |
|
106 | CopyMapKeysIterator, | |
108 |
PyLeakedRef< |
|
107 | PyLeakedRef<CopyMapIter<'static>>, | |
109 | CopyMapIter<'static>, |
|
|||
110 | CopyMap::translate_key, |
|
108 | CopyMap::translate_key, | |
111 | Option<PyBytes> |
|
109 | Option<PyBytes> | |
112 | ); |
|
110 | ); | |
113 |
|
111 | |||
114 | py_shared_iterator!( |
|
112 | py_shared_iterator!( | |
115 | CopyMapItemsIterator, |
|
113 | CopyMapItemsIterator, | |
116 |
PyLeakedRef< |
|
114 | PyLeakedRef<CopyMapIter<'static>>, | |
117 | CopyMapIter<'static>, |
|
|||
118 | CopyMap::translate_key_value, |
|
115 | CopyMap::translate_key_value, | |
119 | Option<(PyBytes, PyBytes)> |
|
116 | Option<(PyBytes, PyBytes)> | |
120 | ); |
|
117 | ); |
@@ -92,13 +92,10 b' py_class!(pub class Dirs |py| {' | |||||
92 | }) |
|
92 | }) | |
93 | } |
|
93 | } | |
94 | def __iter__(&self) -> PyResult<DirsMultisetKeysIterator> { |
|
94 | def __iter__(&self) -> PyResult<DirsMultisetKeysIterator> { | |
95 | let mut leak_handle = |
|
95 | let leaked_ref = self.inner_shared(py).leak_immutable()?; | |
96 | unsafe { self.inner_shared(py).leak_immutable()? }; |
|
|||
97 | let leaked_ref = leak_handle.data.take().unwrap(); |
|
|||
98 | DirsMultisetKeysIterator::from_inner( |
|
96 | DirsMultisetKeysIterator::from_inner( | |
99 | py, |
|
97 | py, | |
100 | leak_handle, |
|
98 | unsafe { leaked_ref.map(py, |o| o.iter()) }, | |
101 | leaked_ref.iter(), |
|
|||
102 | ) |
|
99 | ) | |
103 | } |
|
100 | } | |
104 |
|
101 | |||
@@ -126,8 +123,7 b' impl Dirs {' | |||||
126 |
|
123 | |||
127 | py_shared_iterator!( |
|
124 | py_shared_iterator!( | |
128 | DirsMultisetKeysIterator, |
|
125 | DirsMultisetKeysIterator, | |
129 |
PyLeakedRef< |
|
126 | PyLeakedRef<DirsMultisetIter<'static>>, | |
130 | DirsMultisetIter<'static>, |
|
|||
131 | Dirs::translate_key, |
|
127 | Dirs::translate_key, | |
132 | Option<PyBytes> |
|
128 | Option<PyBytes> | |
133 | ); |
|
129 | ); |
@@ -304,35 +304,26 b' py_class!(pub class DirstateMap |py| {' | |||||
304 | } |
|
304 | } | |
305 |
|
305 | |||
306 | def keys(&self) -> PyResult<DirstateMapKeysIterator> { |
|
306 | def keys(&self) -> PyResult<DirstateMapKeysIterator> { | |
307 | let mut leak_handle = |
|
307 | let leaked_ref = self.inner_shared(py).leak_immutable()?; | |
308 | unsafe { self.inner_shared(py).leak_immutable()? }; |
|
|||
309 | let leaked_ref = leak_handle.data.take().unwrap(); |
|
|||
310 | DirstateMapKeysIterator::from_inner( |
|
308 | DirstateMapKeysIterator::from_inner( | |
311 | py, |
|
309 | py, | |
312 | leak_handle, |
|
310 | unsafe { leaked_ref.map(py, |o| o.iter()) }, | |
313 | leaked_ref.iter(), |
|
|||
314 | ) |
|
311 | ) | |
315 | } |
|
312 | } | |
316 |
|
313 | |||
317 | def items(&self) -> PyResult<DirstateMapItemsIterator> { |
|
314 | def items(&self) -> PyResult<DirstateMapItemsIterator> { | |
318 | let mut leak_handle = |
|
315 | let leaked_ref = self.inner_shared(py).leak_immutable()?; | |
319 | unsafe { self.inner_shared(py).leak_immutable()? }; |
|
|||
320 | let leaked_ref = leak_handle.data.take().unwrap(); |
|
|||
321 | DirstateMapItemsIterator::from_inner( |
|
316 | DirstateMapItemsIterator::from_inner( | |
322 | py, |
|
317 | py, | |
323 | leak_handle, |
|
318 | unsafe { leaked_ref.map(py, |o| o.iter()) }, | |
324 | leaked_ref.iter(), |
|
|||
325 | ) |
|
319 | ) | |
326 | } |
|
320 | } | |
327 |
|
321 | |||
328 | def __iter__(&self) -> PyResult<DirstateMapKeysIterator> { |
|
322 | def __iter__(&self) -> PyResult<DirstateMapKeysIterator> { | |
329 | let mut leak_handle = |
|
323 | let leaked_ref = self.inner_shared(py).leak_immutable()?; | |
330 | unsafe { self.inner_shared(py).leak_immutable()? }; |
|
|||
331 | let leaked_ref = leak_handle.data.take().unwrap(); |
|
|||
332 | DirstateMapKeysIterator::from_inner( |
|
324 | DirstateMapKeysIterator::from_inner( | |
333 | py, |
|
325 | py, | |
334 | leak_handle, |
|
326 | unsafe { leaked_ref.map(py, |o| o.iter()) }, | |
335 | leaked_ref.iter(), |
|
|||
336 | ) |
|
327 | ) | |
337 | } |
|
328 | } | |
338 |
|
329 | |||
@@ -446,24 +437,18 b' py_class!(pub class DirstateMap |py| {' | |||||
446 | } |
|
437 | } | |
447 |
|
438 | |||
448 | def copymapiter(&self) -> PyResult<CopyMapKeysIterator> { |
|
439 | def copymapiter(&self) -> PyResult<CopyMapKeysIterator> { | |
449 | let mut leak_handle = |
|
440 | let leaked_ref = self.inner_shared(py).leak_immutable()?; | |
450 | unsafe { self.inner_shared(py).leak_immutable()? }; |
|
|||
451 | let leaked_ref = leak_handle.data.take().unwrap(); |
|
|||
452 | CopyMapKeysIterator::from_inner( |
|
441 | CopyMapKeysIterator::from_inner( | |
453 | py, |
|
442 | py, | |
454 | leak_handle, |
|
443 | unsafe { leaked_ref.map(py, |o| o.copy_map.iter()) }, | |
455 | leaked_ref.copy_map.iter(), |
|
|||
456 | ) |
|
444 | ) | |
457 | } |
|
445 | } | |
458 |
|
446 | |||
459 | def copymapitemsiter(&self) -> PyResult<CopyMapItemsIterator> { |
|
447 | def copymapitemsiter(&self) -> PyResult<CopyMapItemsIterator> { | |
460 | let mut leak_handle = |
|
448 | let leaked_ref = self.inner_shared(py).leak_immutable()?; | |
461 | unsafe { self.inner_shared(py).leak_immutable()? }; |
|
|||
462 | let leaked_ref = leak_handle.data.take().unwrap(); |
|
|||
463 | CopyMapItemsIterator::from_inner( |
|
449 | CopyMapItemsIterator::from_inner( | |
464 | py, |
|
450 | py, | |
465 | leak_handle, |
|
451 | unsafe { leaked_ref.map(py, |o| o.copy_map.iter()) }, | |
466 | leaked_ref.copy_map.iter(), |
|
|||
467 | ) |
|
452 | ) | |
468 | } |
|
453 | } | |
469 |
|
454 | |||
@@ -498,16 +483,14 b' py_shared_ref!(DirstateMap, RustDirstate' | |||||
498 |
|
483 | |||
499 | py_shared_iterator!( |
|
484 | py_shared_iterator!( | |
500 | DirstateMapKeysIterator, |
|
485 | DirstateMapKeysIterator, | |
501 |
PyLeakedRef< |
|
486 | PyLeakedRef<StateMapIter<'static>>, | |
502 | StateMapIter<'static>, |
|
|||
503 | DirstateMap::translate_key, |
|
487 | DirstateMap::translate_key, | |
504 | Option<PyBytes> |
|
488 | Option<PyBytes> | |
505 | ); |
|
489 | ); | |
506 |
|
490 | |||
507 | py_shared_iterator!( |
|
491 | py_shared_iterator!( | |
508 | DirstateMapItemsIterator, |
|
492 | DirstateMapItemsIterator, | |
509 |
PyLeakedRef< |
|
493 | PyLeakedRef<StateMapIter<'static>>, | |
510 | StateMapIter<'static>, |
|
|||
511 | DirstateMap::translate_key_value, |
|
494 | DirstateMap::translate_key_value, | |
512 | Option<(PyBytes, PyObject)> |
|
495 | Option<(PyBytes, PyObject)> | |
513 | ); |
|
496 | ); |
@@ -187,24 +187,19 b" impl<'a, T> PySharedRef<'a, T> {" | |||||
187 | self.data.borrow_mut(self.py) |
|
187 | self.data.borrow_mut(self.py) | |
188 | } |
|
188 | } | |
189 |
|
189 | |||
190 |
/// Returns a leaked reference |
|
190 | /// Returns a leaked reference. | |
191 | /// |
|
191 | pub fn leak_immutable(&self) -> PyResult<PyLeakedRef<&'static T>> { | |
192 | /// # Safety |
|
192 | let state = &self.data.py_shared_state; | |
193 | /// |
|
193 | unsafe { | |
194 | /// It's up to you to make sure that the management object lives |
|
194 | let (static_ref, static_state_ref) = | |
195 | /// longer than the leaked reference. Otherwise, you'll get a |
|
195 | state.leak_immutable(self.py, self.data)?; | |
196 | /// dangling reference. |
|
196 | Ok(PyLeakedRef::new( | |
197 | pub unsafe fn leak_immutable(&self) -> PyResult<PyLeakedRef<&'static T>> { |
|
197 | self.py, | |
198 | let (static_ref, static_state_ref) = self |
|
198 | self.owner, | |
199 |
|
|
199 | static_ref, | |
200 |
|
|
200 | static_state_ref, | |
201 | .leak_immutable(self.py, self.data)?; |
|
201 | )) | |
202 | Ok(PyLeakedRef::new( |
|
202 | } | |
203 | self.py, |
|
|||
204 | self.owner, |
|
|||
205 | static_ref, |
|
|||
206 | static_state_ref, |
|
|||
207 | )) |
|
|||
208 | } |
|
203 | } | |
209 | } |
|
204 | } | |
210 |
|
205 | |||
@@ -316,15 +311,15 b' macro_rules! py_shared_ref {' | |||||
316 | } |
|
311 | } | |
317 |
|
312 | |||
318 | /// Manage immutable references to `PyObject` leaked into Python iterators. |
|
313 | /// Manage immutable references to `PyObject` leaked into Python iterators. | |
319 | /// |
|
|||
320 | /// In truth, this does not represent leaked references themselves; |
|
|||
321 | /// it is instead useful alongside them to manage them. |
|
|||
322 | pub struct PyLeakedRef<T> { |
|
314 | pub struct PyLeakedRef<T> { | |
323 |
|
|
315 | inner: PyObject, | |
324 |
|
|
316 | data: Option<T>, | |
325 | py_shared_state: &'static PySharedState, |
|
317 | py_shared_state: &'static PySharedState, | |
326 | } |
|
318 | } | |
327 |
|
319 | |||
|
320 | // DO NOT implement Deref for PyLeakedRef<T>! Dereferencing PyLeakedRef | |||
|
321 | // without taking Python GIL wouldn't be safe. | |||
|
322 | ||||
328 | impl<T> PyLeakedRef<T> { |
|
323 | impl<T> PyLeakedRef<T> { | |
329 | /// # Safety |
|
324 | /// # Safety | |
330 | /// |
|
325 | /// | |
@@ -338,11 +333,52 b' impl<T> PyLeakedRef<T> {' | |||||
338 | py_shared_state: &'static PySharedState, |
|
333 | py_shared_state: &'static PySharedState, | |
339 | ) -> Self { |
|
334 | ) -> Self { | |
340 | Self { |
|
335 | Self { | |
341 |
|
|
336 | inner: inner.clone_ref(py), | |
342 | data: Some(data), |
|
337 | data: Some(data), | |
343 | py_shared_state, |
|
338 | py_shared_state, | |
344 | } |
|
339 | } | |
345 | } |
|
340 | } | |
|
341 | ||||
|
342 | /// Returns an immutable reference to the inner value. | |||
|
343 | pub fn get_ref<'a>(&'a self, _py: Python<'a>) -> &'a T { | |||
|
344 | self.data.as_ref().unwrap() | |||
|
345 | } | |||
|
346 | ||||
|
347 | /// Returns a mutable reference to the inner value. | |||
|
348 | /// | |||
|
349 | /// Typically `T` is an iterator. If `T` is an immutable reference, | |||
|
350 | /// `get_mut()` is useless since the inner value can't be mutated. | |||
|
351 | pub fn get_mut<'a>(&'a mut self, _py: Python<'a>) -> &'a mut T { | |||
|
352 | self.data.as_mut().unwrap() | |||
|
353 | } | |||
|
354 | ||||
|
355 | /// Converts the inner value by the given function. | |||
|
356 | /// | |||
|
357 | /// Typically `T` is a static reference to a container, and `U` is an | |||
|
358 | /// iterator of that container. | |||
|
359 | /// | |||
|
360 | /// # Safety | |||
|
361 | /// | |||
|
362 | /// The lifetime of the object passed in to the function `f` is cheated. | |||
|
363 | /// It's typically a static reference, but is valid only while the | |||
|
364 | /// corresponding `PyLeakedRef` is alive. Do not copy it out of the | |||
|
365 | /// function call. | |||
|
366 | pub unsafe fn map<U>( | |||
|
367 | mut self, | |||
|
368 | py: Python, | |||
|
369 | f: impl FnOnce(T) -> U, | |||
|
370 | ) -> PyLeakedRef<U> { | |||
|
371 | // f() could make the self.data outlive. That's why map() is unsafe. | |||
|
372 | // In order to make this function safe, maybe we'll need a way to | |||
|
373 | // temporarily restrict the lifetime of self.data and translate the | |||
|
374 | // returned object back to Something<'static>. | |||
|
375 | let new_data = f(self.data.take().unwrap()); | |||
|
376 | PyLeakedRef { | |||
|
377 | inner: self.inner.clone_ref(py), | |||
|
378 | data: Some(new_data), | |||
|
379 | py_shared_state: self.py_shared_state, | |||
|
380 | } | |||
|
381 | } | |||
346 | } |
|
382 | } | |
347 |
|
383 | |||
348 | impl<T> Drop for PyLeakedRef<T> { |
|
384 | impl<T> Drop for PyLeakedRef<T> { | |
@@ -352,6 +388,9 b' impl<T> Drop for PyLeakedRef<T> {' | |||||
352 | // sure that the state is only accessed by this thread. |
|
388 | // sure that the state is only accessed by this thread. | |
353 | let gil = Python::acquire_gil(); |
|
389 | let gil = Python::acquire_gil(); | |
354 | let py = gil.python(); |
|
390 | let py = gil.python(); | |
|
391 | if self.data.is_none() { | |||
|
392 | return; // moved to another PyLeakedRef | |||
|
393 | } | |||
355 | unsafe { |
|
394 | unsafe { | |
356 | self.py_shared_state.decrease_leak_count(py, false); |
|
395 | self.py_shared_state.decrease_leak_count(py, false); | |
357 | } |
|
396 | } | |
@@ -383,13 +422,10 b' impl<T> Drop for PyLeakedRef<T> {' | |||||
383 | /// data inner: PySharedRefCell<MyStruct>; |
|
422 | /// data inner: PySharedRefCell<MyStruct>; | |
384 | /// |
|
423 | /// | |
385 | /// def __iter__(&self) -> PyResult<MyTypeItemsIterator> { |
|
424 | /// def __iter__(&self) -> PyResult<MyTypeItemsIterator> { | |
386 | /// let mut leak_handle = |
|
425 | /// let leaked_ref = self.inner_shared(py).leak_immutable()?; | |
387 | /// unsafe { self.inner_shared(py).leak_immutable()? }; |
|
|||
388 | /// let leaked_ref = leak_handle.data.take().unwrap(); |
|
|||
389 | /// MyTypeItemsIterator::from_inner( |
|
426 | /// MyTypeItemsIterator::from_inner( | |
390 | /// py, |
|
427 | /// py, | |
391 | /// leak_handle, |
|
428 | /// unsafe { leaked_ref.map(py, |o| o.iter()) }, | |
392 | /// leaked_ref.iter(), |
|
|||
393 | /// ) |
|
429 | /// ) | |
394 | /// } |
|
430 | /// } | |
395 | /// }); |
|
431 | /// }); | |
@@ -411,8 +447,7 b' impl<T> Drop for PyLeakedRef<T> {' | |||||
411 | /// |
|
447 | /// | |
412 | /// py_shared_iterator!( |
|
448 | /// py_shared_iterator!( | |
413 | /// MyTypeItemsIterator, |
|
449 | /// MyTypeItemsIterator, | |
414 |
/// PyLeakedRef< |
|
450 | /// PyLeakedRef<HashMap<'static, Vec<u8>, Vec<u8>>>, | |
415 | /// HashMap<'static, Vec<u8>, Vec<u8>>, |
|
|||
416 | /// MyType::translate_key_value, |
|
451 | /// MyType::translate_key_value, | |
417 | /// Option<(PyBytes, PyBytes)> |
|
452 | /// Option<(PyBytes, PyBytes)> | |
418 | /// ); |
|
453 | /// ); | |
@@ -421,18 +456,16 b' macro_rules! py_shared_iterator {' | |||||
421 | ( |
|
456 | ( | |
422 | $name: ident, |
|
457 | $name: ident, | |
423 | $leaked: ty, |
|
458 | $leaked: ty, | |
424 | $iterator_type: ty, |
|
|||
425 | $success_func: expr, |
|
459 | $success_func: expr, | |
426 | $success_type: ty |
|
460 | $success_type: ty | |
427 | ) => { |
|
461 | ) => { | |
428 | py_class!(pub class $name |py| { |
|
462 | py_class!(pub class $name |py| { | |
429 | data inner: RefCell<Option<$leaked>>; |
|
463 | data inner: RefCell<Option<$leaked>>; | |
430 | data it: RefCell<$iterator_type>; |
|
|||
431 |
|
464 | |||
432 | def __next__(&self) -> PyResult<$success_type> { |
|
465 | def __next__(&self) -> PyResult<$success_type> { | |
433 | let mut inner_opt = self.inner(py).borrow_mut(); |
|
466 | let mut inner_opt = self.inner(py).borrow_mut(); | |
434 |
if inner_opt. |
|
467 | if let Some(leaked) = inner_opt.as_mut() { | |
435 |
match |
|
468 | match leaked.get_mut(py).next() { | |
436 | None => { |
|
469 | None => { | |
437 | // replace Some(inner) by None, drop $leaked |
|
470 | // replace Some(inner) by None, drop $leaked | |
438 | inner_opt.take(); |
|
471 | inner_opt.take(); | |
@@ -456,12 +489,10 b' macro_rules! py_shared_iterator {' | |||||
456 | pub fn from_inner( |
|
489 | pub fn from_inner( | |
457 | py: Python, |
|
490 | py: Python, | |
458 | leaked: $leaked, |
|
491 | leaked: $leaked, | |
459 | it: $iterator_type |
|
|||
460 | ) -> PyResult<Self> { |
|
492 | ) -> PyResult<Self> { | |
461 | Self::create_instance( |
|
493 | Self::create_instance( | |
462 | py, |
|
494 | py, | |
463 | RefCell::new(Some(leaked)), |
|
495 | RefCell::new(Some(leaked)), | |
464 | RefCell::new(it) |
|
|||
465 | ) |
|
496 | ) | |
466 | } |
|
497 | } | |
467 | } |
|
498 | } |
General Comments 0
You need to be logged in to leave comments.
Login now