23 //! Macros for use in the `hg-cpython` bridge library. |
23 //! Macros for use in the `hg-cpython` bridge library. |
24 |
24 |
25 use crate::exceptions::AlreadyBorrowed; |
25 use crate::exceptions::AlreadyBorrowed; |
26 use cpython::{PyClone, PyObject, PyResult, Python}; |
26 use cpython::{PyClone, PyObject, PyResult, Python}; |
27 use std::cell::{Cell, Ref, RefCell, RefMut}; |
27 use std::cell::{Cell, Ref, RefCell, RefMut}; |
|
28 use std::ops::{Deref, DerefMut}; |
28 |
29 |
29 /// Manages the shared state between Python and Rust |
30 /// Manages the shared state between Python and Rust |
30 #[derive(Debug, Default)] |
31 #[derive(Debug, Default)] |
31 struct PySharedState { |
32 struct PySharedState { |
32 leak_count: Cell<usize>, |
33 leak_count: Cell<usize>, |
331 data: Some(data), |
332 data: Some(data), |
332 py_shared_state, |
333 py_shared_state, |
333 } |
334 } |
334 } |
335 } |
335 |
336 |
336 /// Returns an immutable reference to the inner value. |
337 /// Immutably borrows the wrapped value. |
337 pub fn get_ref<'a>(&'a self, _py: Python<'a>) -> &'a T { |
338 pub fn try_borrow<'a>( |
338 self.data.as_ref().unwrap() |
339 &'a self, |
339 } |
340 py: Python<'a>, |
340 |
341 ) -> PyResult<PyLeakedRef<'a, T>> { |
341 /// Returns a mutable reference to the inner value. |
342 Ok(PyLeakedRef { |
|
343 _py: py, |
|
344 data: self.data.as_ref().unwrap(), |
|
345 }) |
|
346 } |
|
347 |
|
348 /// Mutably borrows the wrapped value. |
342 /// |
349 /// |
343 /// Typically `T` is an iterator. If `T` is an immutable reference, |
350 /// Typically `T` is an iterator. If `T` is an immutable reference, |
344 /// `get_mut()` is useless since the inner value can't be mutated. |
351 /// `get_mut()` is useless since the inner value can't be mutated. |
345 pub fn get_mut<'a>(&'a mut self, _py: Python<'a>) -> &'a mut T { |
352 pub fn try_borrow_mut<'a>( |
346 self.data.as_mut().unwrap() |
353 &'a mut self, |
|
354 py: Python<'a>, |
|
355 ) -> PyResult<PyLeakedRefMut<'a, T>> { |
|
356 Ok(PyLeakedRefMut { |
|
357 _py: py, |
|
358 data: self.data.as_mut().unwrap(), |
|
359 }) |
347 } |
360 } |
348 |
361 |
349 /// Converts the inner value by the given function. |
362 /// Converts the inner value by the given function. |
350 /// |
363 /// |
351 /// Typically `T` is a static reference to a container, and `U` is an |
364 /// Typically `T` is a static reference to a container, and `U` is an |
387 } |
400 } |
388 self.py_shared_state.decrease_leak_count(py, false); |
401 self.py_shared_state.decrease_leak_count(py, false); |
389 } |
402 } |
390 } |
403 } |
391 |
404 |
|
405 /// Immutably borrowed reference to a leaked value. |
|
406 pub struct PyLeakedRef<'a, T> { |
|
407 _py: Python<'a>, |
|
408 data: &'a T, |
|
409 } |
|
410 |
|
411 impl<T> Deref for PyLeakedRef<'_, T> { |
|
412 type Target = T; |
|
413 |
|
414 fn deref(&self) -> &T { |
|
415 self.data |
|
416 } |
|
417 } |
|
418 |
|
419 /// Mutably borrowed reference to a leaked value. |
|
420 pub struct PyLeakedRefMut<'a, T> { |
|
421 _py: Python<'a>, |
|
422 data: &'a mut T, |
|
423 } |
|
424 |
|
425 impl<T> Deref for PyLeakedRefMut<'_, T> { |
|
426 type Target = T; |
|
427 |
|
428 fn deref(&self) -> &T { |
|
429 self.data |
|
430 } |
|
431 } |
|
432 |
|
433 impl<T> DerefMut for PyLeakedRefMut<'_, T> { |
|
434 fn deref_mut(&mut self) -> &mut T { |
|
435 self.data |
|
436 } |
|
437 } |
|
438 |
392 /// Defines a `py_class!` that acts as a Python iterator over a Rust iterator. |
439 /// Defines a `py_class!` that acts as a Python iterator over a Rust iterator. |
393 /// |
440 /// |
394 /// TODO: this is a bit awkward to use, and a better (more complicated) |
441 /// TODO: this is a bit awkward to use, and a better (more complicated) |
395 /// procedural macro would simplify the interface a lot. |
442 /// procedural macro would simplify the interface a lot. |
396 /// |
443 /// |
455 data inner: RefCell<Option<$leaked>>; |
502 data inner: RefCell<Option<$leaked>>; |
456 |
503 |
457 def __next__(&self) -> PyResult<$success_type> { |
504 def __next__(&self) -> PyResult<$success_type> { |
458 let mut inner_opt = self.inner(py).borrow_mut(); |
505 let mut inner_opt = self.inner(py).borrow_mut(); |
459 if let Some(leaked) = inner_opt.as_mut() { |
506 if let Some(leaked) = inner_opt.as_mut() { |
460 match leaked.get_mut(py).next() { |
507 let mut iter = leaked.try_borrow_mut(py)?; |
|
508 match iter.next() { |
461 None => { |
509 None => { |
462 // replace Some(inner) by None, drop $leaked |
510 // replace Some(inner) by None, drop $leaked |
463 inner_opt.take(); |
511 inner_opt.take(); |
464 Ok(None) |
512 Ok(None) |
465 } |
513 } |
510 .unwrap(); |
558 .unwrap(); |
511 (gil, owner) |
559 (gil, owner) |
512 } |
560 } |
513 |
561 |
514 #[test] |
562 #[test] |
|
563 fn test_leaked_borrow() { |
|
564 let (gil, owner) = prepare_env(); |
|
565 let py = gil.python(); |
|
566 let leaked = owner.string_shared(py).leak_immutable().unwrap(); |
|
567 let leaked_ref = leaked.try_borrow(py).unwrap(); |
|
568 assert_eq!(*leaked_ref, "new"); |
|
569 } |
|
570 |
|
571 #[test] |
|
572 fn test_leaked_borrow_mut() { |
|
573 let (gil, owner) = prepare_env(); |
|
574 let py = gil.python(); |
|
575 let leaked = owner.string_shared(py).leak_immutable().unwrap(); |
|
576 let mut leaked_iter = unsafe { leaked.map(py, |s| s.chars()) }; |
|
577 let mut leaked_ref = leaked_iter.try_borrow_mut(py).unwrap(); |
|
578 assert_eq!(leaked_ref.next(), Some('n')); |
|
579 assert_eq!(leaked_ref.next(), Some('e')); |
|
580 assert_eq!(leaked_ref.next(), Some('w')); |
|
581 assert_eq!(leaked_ref.next(), None); |
|
582 } |
|
583 |
|
584 #[test] |
515 fn test_borrow_mut_while_leaked() { |
585 fn test_borrow_mut_while_leaked() { |
516 let (gil, owner) = prepare_env(); |
586 let (gil, owner) = prepare_env(); |
517 let py = gil.python(); |
587 let py = gil.python(); |
518 assert!(owner.string_shared(py).borrow_mut().is_ok()); |
588 assert!(owner.string_shared(py).borrow_mut().is_ok()); |
519 let _leaked = owner.string_shared(py).leak_immutable().unwrap(); |
589 let _leaked = owner.string_shared(py).leak_immutable().unwrap(); |