rust/hg-cpython/src/ref_sharing.rs
changeset 43423 945d4dba5e78
parent 43422 b9f791090211
child 43424 0836efe4967b
equal deleted inserted replaced
43422:b9f791090211 43423:945d4dba5e78
    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();