Show More
@@ -13,7 +13,6 b' use std::cell::RefCell;' | |||
|
13 | 13 | |
|
14 | 14 | use crate::dirstate::dirstate_map::DirstateMap; |
|
15 | 15 | use crate::ref_sharing::PyLeakedRef; |
|
16 | use hg::DirstateMap as RustDirstateMap; | |
|
17 | 16 | use hg::{utils::hg_path::HgPathBuf, CopyMapIter}; |
|
18 | 17 | |
|
19 | 18 | py_class!(pub class CopyMap |py| { |
@@ -105,16 +104,14 b' impl CopyMap {' | |||
|
105 | 104 | |
|
106 | 105 | py_shared_iterator!( |
|
107 | 106 | CopyMapKeysIterator, |
|
108 |
PyLeakedRef< |
|
|
109 | CopyMapIter<'static>, | |
|
107 | PyLeakedRef<CopyMapIter<'static>>, | |
|
110 | 108 | CopyMap::translate_key, |
|
111 | 109 | Option<PyBytes> |
|
112 | 110 | ); |
|
113 | 111 | |
|
114 | 112 | py_shared_iterator!( |
|
115 | 113 | CopyMapItemsIterator, |
|
116 |
PyLeakedRef< |
|
|
117 | CopyMapIter<'static>, | |
|
114 | PyLeakedRef<CopyMapIter<'static>>, | |
|
118 | 115 | CopyMap::translate_key_value, |
|
119 | 116 | Option<(PyBytes, PyBytes)> |
|
120 | 117 | ); |
@@ -92,13 +92,10 b' py_class!(pub class Dirs |py| {' | |||
|
92 | 92 | }) |
|
93 | 93 | } |
|
94 | 94 | def __iter__(&self) -> PyResult<DirsMultisetKeysIterator> { |
|
95 | let mut leak_handle = | |
|
96 | unsafe { self.inner_shared(py).leak_immutable()? }; | |
|
97 | let leaked_ref = leak_handle.data.take().unwrap(); | |
|
95 | let leaked_ref = self.inner_shared(py).leak_immutable()?; | |
|
98 | 96 | DirsMultisetKeysIterator::from_inner( |
|
99 | 97 | py, |
|
100 | leak_handle, | |
|
101 | leaked_ref.iter(), | |
|
98 | unsafe { leaked_ref.map(py, |o| o.iter()) }, | |
|
102 | 99 | ) |
|
103 | 100 | } |
|
104 | 101 | |
@@ -126,8 +123,7 b' impl Dirs {' | |||
|
126 | 123 | |
|
127 | 124 | py_shared_iterator!( |
|
128 | 125 | DirsMultisetKeysIterator, |
|
129 |
PyLeakedRef< |
|
|
130 | DirsMultisetIter<'static>, | |
|
126 | PyLeakedRef<DirsMultisetIter<'static>>, | |
|
131 | 127 | Dirs::translate_key, |
|
132 | 128 | Option<PyBytes> |
|
133 | 129 | ); |
@@ -304,35 +304,26 b' py_class!(pub class DirstateMap |py| {' | |||
|
304 | 304 | } |
|
305 | 305 | |
|
306 | 306 | def keys(&self) -> PyResult<DirstateMapKeysIterator> { |
|
307 | let mut leak_handle = | |
|
308 | unsafe { self.inner_shared(py).leak_immutable()? }; | |
|
309 | let leaked_ref = leak_handle.data.take().unwrap(); | |
|
307 | let leaked_ref = self.inner_shared(py).leak_immutable()?; | |
|
310 | 308 | DirstateMapKeysIterator::from_inner( |
|
311 | 309 | py, |
|
312 | leak_handle, | |
|
313 | leaked_ref.iter(), | |
|
310 | unsafe { leaked_ref.map(py, |o| o.iter()) }, | |
|
314 | 311 | ) |
|
315 | 312 | } |
|
316 | 313 | |
|
317 | 314 | def items(&self) -> PyResult<DirstateMapItemsIterator> { |
|
318 | let mut leak_handle = | |
|
319 | unsafe { self.inner_shared(py).leak_immutable()? }; | |
|
320 | let leaked_ref = leak_handle.data.take().unwrap(); | |
|
315 | let leaked_ref = self.inner_shared(py).leak_immutable()?; | |
|
321 | 316 | DirstateMapItemsIterator::from_inner( |
|
322 | 317 | py, |
|
323 | leak_handle, | |
|
324 | leaked_ref.iter(), | |
|
318 | unsafe { leaked_ref.map(py, |o| o.iter()) }, | |
|
325 | 319 | ) |
|
326 | 320 | } |
|
327 | 321 | |
|
328 | 322 | def __iter__(&self) -> PyResult<DirstateMapKeysIterator> { |
|
329 | let mut leak_handle = | |
|
330 | unsafe { self.inner_shared(py).leak_immutable()? }; | |
|
331 | let leaked_ref = leak_handle.data.take().unwrap(); | |
|
323 | let leaked_ref = self.inner_shared(py).leak_immutable()?; | |
|
332 | 324 | DirstateMapKeysIterator::from_inner( |
|
333 | 325 | py, |
|
334 | leak_handle, | |
|
335 | leaked_ref.iter(), | |
|
326 | unsafe { leaked_ref.map(py, |o| o.iter()) }, | |
|
336 | 327 | ) |
|
337 | 328 | } |
|
338 | 329 | |
@@ -446,24 +437,18 b' py_class!(pub class DirstateMap |py| {' | |||
|
446 | 437 | } |
|
447 | 438 | |
|
448 | 439 | def copymapiter(&self) -> PyResult<CopyMapKeysIterator> { |
|
449 | let mut leak_handle = | |
|
450 | unsafe { self.inner_shared(py).leak_immutable()? }; | |
|
451 | let leaked_ref = leak_handle.data.take().unwrap(); | |
|
440 | let leaked_ref = self.inner_shared(py).leak_immutable()?; | |
|
452 | 441 | CopyMapKeysIterator::from_inner( |
|
453 | 442 | py, |
|
454 | leak_handle, | |
|
455 | leaked_ref.copy_map.iter(), | |
|
443 | unsafe { leaked_ref.map(py, |o| o.copy_map.iter()) }, | |
|
456 | 444 | ) |
|
457 | 445 | } |
|
458 | 446 | |
|
459 | 447 | def copymapitemsiter(&self) -> PyResult<CopyMapItemsIterator> { |
|
460 | let mut leak_handle = | |
|
461 | unsafe { self.inner_shared(py).leak_immutable()? }; | |
|
462 | let leaked_ref = leak_handle.data.take().unwrap(); | |
|
448 | let leaked_ref = self.inner_shared(py).leak_immutable()?; | |
|
463 | 449 | CopyMapItemsIterator::from_inner( |
|
464 | 450 | py, |
|
465 | leak_handle, | |
|
466 | leaked_ref.copy_map.iter(), | |
|
451 | unsafe { leaked_ref.map(py, |o| o.copy_map.iter()) }, | |
|
467 | 452 | ) |
|
468 | 453 | } |
|
469 | 454 | |
@@ -498,16 +483,14 b' py_shared_ref!(DirstateMap, RustDirstate' | |||
|
498 | 483 | |
|
499 | 484 | py_shared_iterator!( |
|
500 | 485 | DirstateMapKeysIterator, |
|
501 |
PyLeakedRef< |
|
|
502 | StateMapIter<'static>, | |
|
486 | PyLeakedRef<StateMapIter<'static>>, | |
|
503 | 487 | DirstateMap::translate_key, |
|
504 | 488 | Option<PyBytes> |
|
505 | 489 | ); |
|
506 | 490 | |
|
507 | 491 | py_shared_iterator!( |
|
508 | 492 | DirstateMapItemsIterator, |
|
509 |
PyLeakedRef< |
|
|
510 | StateMapIter<'static>, | |
|
493 | PyLeakedRef<StateMapIter<'static>>, | |
|
511 | 494 | DirstateMap::translate_key_value, |
|
512 | 495 | Option<(PyBytes, PyObject)> |
|
513 | 496 | ); |
@@ -187,24 +187,19 b" impl<'a, T> PySharedRef<'a, T> {" | |||
|
187 | 187 | self.data.borrow_mut(self.py) |
|
188 | 188 | } |
|
189 | 189 | |
|
190 |
/// Returns a leaked reference |
|
|
191 | /// | |
|
192 | /// # Safety | |
|
193 | /// | |
|
194 | /// It's up to you to make sure that the management object lives | |
|
195 | /// longer than the leaked reference. Otherwise, you'll get a | |
|
196 | /// dangling reference. | |
|
197 | pub unsafe fn leak_immutable(&self) -> PyResult<PyLeakedRef<&'static T>> { | |
|
198 | let (static_ref, static_state_ref) = self | |
|
199 |
|
|
|
200 |
|
|
|
201 | .leak_immutable(self.py, self.data)?; | |
|
202 | Ok(PyLeakedRef::new( | |
|
203 | self.py, | |
|
204 | self.owner, | |
|
205 | static_ref, | |
|
206 | static_state_ref, | |
|
207 | )) | |
|
190 | /// Returns a leaked reference. | |
|
191 | pub fn leak_immutable(&self) -> PyResult<PyLeakedRef<&'static T>> { | |
|
192 | let state = &self.data.py_shared_state; | |
|
193 | unsafe { | |
|
194 | let (static_ref, static_state_ref) = | |
|
195 | state.leak_immutable(self.py, self.data)?; | |
|
196 | Ok(PyLeakedRef::new( | |
|
197 | self.py, | |
|
198 | self.owner, | |
|
199 | static_ref, | |
|
200 | static_state_ref, | |
|
201 | )) | |
|
202 | } | |
|
208 | 203 | } |
|
209 | 204 | } |
|
210 | 205 | |
@@ -316,15 +311,15 b' macro_rules! py_shared_ref {' | |||
|
316 | 311 | } |
|
317 | 312 | |
|
318 | 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 | 314 | pub struct PyLeakedRef<T> { |
|
323 |
|
|
|
324 |
|
|
|
315 | inner: PyObject, | |
|
316 | data: Option<T>, | |
|
325 | 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 | 323 | impl<T> PyLeakedRef<T> { |
|
329 | 324 | /// # Safety |
|
330 | 325 | /// |
@@ -338,11 +333,52 b' impl<T> PyLeakedRef<T> {' | |||
|
338 | 333 | py_shared_state: &'static PySharedState, |
|
339 | 334 | ) -> Self { |
|
340 | 335 | Self { |
|
341 |
|
|
|
336 | inner: inner.clone_ref(py), | |
|
342 | 337 | data: Some(data), |
|
343 | 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 | 384 | impl<T> Drop for PyLeakedRef<T> { |
@@ -352,6 +388,9 b' impl<T> Drop for PyLeakedRef<T> {' | |||
|
352 | 388 | // sure that the state is only accessed by this thread. |
|
353 | 389 | let gil = Python::acquire_gil(); |
|
354 | 390 | let py = gil.python(); |
|
391 | if self.data.is_none() { | |
|
392 | return; // moved to another PyLeakedRef | |
|
393 | } | |
|
355 | 394 | unsafe { |
|
356 | 395 | self.py_shared_state.decrease_leak_count(py, false); |
|
357 | 396 | } |
@@ -383,13 +422,10 b' impl<T> Drop for PyLeakedRef<T> {' | |||
|
383 | 422 | /// data inner: PySharedRefCell<MyStruct>; |
|
384 | 423 | /// |
|
385 | 424 | /// def __iter__(&self) -> PyResult<MyTypeItemsIterator> { |
|
386 | /// let mut leak_handle = | |
|
387 | /// unsafe { self.inner_shared(py).leak_immutable()? }; | |
|
388 | /// let leaked_ref = leak_handle.data.take().unwrap(); | |
|
425 | /// let leaked_ref = self.inner_shared(py).leak_immutable()?; | |
|
389 | 426 | /// MyTypeItemsIterator::from_inner( |
|
390 | 427 | /// py, |
|
391 | /// leak_handle, | |
|
392 | /// leaked_ref.iter(), | |
|
428 | /// unsafe { leaked_ref.map(py, |o| o.iter()) }, | |
|
393 | 429 | /// ) |
|
394 | 430 | /// } |
|
395 | 431 | /// }); |
@@ -411,8 +447,7 b' impl<T> Drop for PyLeakedRef<T> {' | |||
|
411 | 447 | /// |
|
412 | 448 | /// py_shared_iterator!( |
|
413 | 449 | /// MyTypeItemsIterator, |
|
414 |
/// PyLeakedRef< |
|
|
415 | /// HashMap<'static, Vec<u8>, Vec<u8>>, | |
|
450 | /// PyLeakedRef<HashMap<'static, Vec<u8>, Vec<u8>>>, | |
|
416 | 451 | /// MyType::translate_key_value, |
|
417 | 452 | /// Option<(PyBytes, PyBytes)> |
|
418 | 453 | /// ); |
@@ -421,18 +456,16 b' macro_rules! py_shared_iterator {' | |||
|
421 | 456 | ( |
|
422 | 457 | $name: ident, |
|
423 | 458 | $leaked: ty, |
|
424 | $iterator_type: ty, | |
|
425 | 459 | $success_func: expr, |
|
426 | 460 | $success_type: ty |
|
427 | 461 | ) => { |
|
428 | 462 | py_class!(pub class $name |py| { |
|
429 | 463 | data inner: RefCell<Option<$leaked>>; |
|
430 | data it: RefCell<$iterator_type>; | |
|
431 | 464 | |
|
432 | 465 | def __next__(&self) -> PyResult<$success_type> { |
|
433 | 466 | let mut inner_opt = self.inner(py).borrow_mut(); |
|
434 |
if inner_opt. |
|
|
435 |
match |
|
|
467 | if let Some(leaked) = inner_opt.as_mut() { | |
|
468 | match leaked.get_mut(py).next() { | |
|
436 | 469 | None => { |
|
437 | 470 | // replace Some(inner) by None, drop $leaked |
|
438 | 471 | inner_opt.take(); |
@@ -456,12 +489,10 b' macro_rules! py_shared_iterator {' | |||
|
456 | 489 | pub fn from_inner( |
|
457 | 490 | py: Python, |
|
458 | 491 | leaked: $leaked, |
|
459 | it: $iterator_type | |
|
460 | 492 | ) -> PyResult<Self> { |
|
461 | 493 | Self::create_instance( |
|
462 | 494 | py, |
|
463 | 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