rust/hg-cpython/src/ref_sharing.rs
changeset 43288 434d7a3e92e3
parent 43287 0df8312463ae
child 43289 8d432d3a2d7c
equal deleted inserted replaced
43287:0df8312463ae 43288:434d7a3e92e3
    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 
    28 
    29 /// Manages the shared state between Python and Rust
    29 /// Manages the shared state between Python and Rust
    30 #[derive(Debug, Default)]
    30 #[derive(Debug, Default)]
    31 pub struct PySharedState {
    31 struct PySharedState {
    32     leak_count: Cell<usize>,
    32     leak_count: Cell<usize>,
    33     mutably_borrowed: Cell<bool>,
    33     mutably_borrowed: Cell<bool>,
    34 }
    34 }
    35 
    35 
    36 // &PySharedState can be Send because any access to inner cells is
    36 // &PySharedState can be Send because any access to inner cells is
    37 // synchronized by the GIL.
    37 // synchronized by the GIL.
    38 unsafe impl Sync for PySharedState {}
    38 unsafe impl Sync for PySharedState {}
    39 
    39 
    40 impl PySharedState {
    40 impl PySharedState {
    41     pub fn borrow_mut<'a, T>(
    41     fn borrow_mut<'a, T>(
    42         &'a self,
    42         &'a self,
    43         py: Python<'a>,
    43         py: Python<'a>,
    44         pyrefmut: RefMut<'a, T>,
    44         pyrefmut: RefMut<'a, T>,
    45     ) -> PyResult<PyRefMut<'a, T>> {
    45     ) -> PyResult<PyRefMut<'a, T>> {
    46         if self.mutably_borrowed.get() {
    46         if self.mutably_borrowed.get() {
    80     ///
    80     ///
    81     /// # Safety
    81     /// # Safety
    82     ///
    82     ///
    83     /// This is highly unsafe since the lifetime of the given data can be
    83     /// This is highly unsafe since the lifetime of the given data can be
    84     /// extended. Do not call this function directly.
    84     /// extended. Do not call this function directly.
    85     pub unsafe fn leak_immutable<T>(
    85     unsafe fn leak_immutable<T>(
    86         &self,
    86         &self,
    87         py: Python,
    87         py: Python,
    88         data: &PySharedRefCell<T>,
    88         data: &PySharedRefCell<T>,
    89     ) -> PyResult<(&'static T, &'static PySharedState)> {
    89     ) -> PyResult<(&'static T, &'static PySharedState)> {
    90         if self.mutably_borrowed.get() {
    90         if self.mutably_borrowed.get() {
   102         Ok((&*ptr, &*state_ptr))
   102         Ok((&*ptr, &*state_ptr))
   103     }
   103     }
   104 
   104 
   105     /// # Safety
   105     /// # Safety
   106     ///
   106     ///
   107     /// It's unsafe to update the reference count without knowing the
   107     /// It's up to you to make sure the reference is about to be deleted
   108     /// reference is deleted. Do not call this function directly.
   108     /// when updating the leak count.
   109     pub unsafe fn decrease_leak_count(&self, _py: Python, mutable: bool) {
   109     fn decrease_leak_count(&self, _py: Python, mutable: bool) {
   110         if mutable {
   110         if mutable {
   111             assert_eq!(self.leak_count.get(), 0);
   111             assert_eq!(self.leak_count.get(), 0);
   112             assert!(self.mutably_borrowed.get());
   112             assert!(self.mutably_borrowed.get());
   113             self.mutably_borrowed.replace(false);
   113             self.mutably_borrowed.replace(false);
   114         } else {
   114         } else {
   119     }
   119     }
   120 }
   120 }
   121 
   121 
   122 /// `RefCell` wrapper to be safely used in conjunction with `PySharedState`.
   122 /// `RefCell` wrapper to be safely used in conjunction with `PySharedState`.
   123 ///
   123 ///
   124 /// Only immutable operation is allowed through this interface.
   124 /// This object can be stored in a `py_class!` object as a data field. Any
       
   125 /// operation is allowed through the `PySharedRef` interface.
   125 #[derive(Debug)]
   126 #[derive(Debug)]
   126 pub struct PySharedRefCell<T> {
   127 pub struct PySharedRefCell<T> {
   127     inner: RefCell<T>,
   128     inner: RefCell<T>,
   128     py_shared_state: PySharedState,
   129     py_shared_state: PySharedState,
   129 }
   130 }
   134             inner: RefCell::new(value),
   135             inner: RefCell::new(value),
   135             py_shared_state: PySharedState::default(),
   136             py_shared_state: PySharedState::default(),
   136         }
   137         }
   137     }
   138     }
   138 
   139 
   139     pub fn borrow<'a>(&'a self, _py: Python<'a>) -> Ref<'a, T> {
   140     fn borrow<'a>(&'a self, _py: Python<'a>) -> Ref<'a, T> {
   140         // py_shared_state isn't involved since
   141         // py_shared_state isn't involved since
   141         // - inner.borrow() would fail if self is mutably borrowed,
   142         // - inner.borrow() would fail if self is mutably borrowed,
   142         // - and inner.borrow_mut() would fail while self is borrowed.
   143         // - and inner.borrow_mut() would fail while self is borrowed.
   143         self.inner.borrow()
   144         self.inner.borrow()
   144     }
   145     }
   145 
   146 
   146     pub fn as_ptr(&self) -> *mut T {
   147     fn as_ptr(&self) -> *mut T {
   147         self.inner.as_ptr()
   148         self.inner.as_ptr()
   148     }
   149     }
   149 
   150 
   150     // TODO: maybe this should be named as try_borrow_mut(), and use
   151     // TODO: maybe this should be named as try_borrow_mut(), and use
   151     // inner.try_borrow_mut(). The current implementation panics if
   152     // inner.try_borrow_mut(). The current implementation panics if
   152     // self.inner has been borrowed, but returns error if py_shared_state
   153     // self.inner has been borrowed, but returns error if py_shared_state
   153     // refuses to borrow.
   154     // refuses to borrow.
   154     pub fn borrow_mut<'a>(
   155     fn borrow_mut<'a>(&'a self, py: Python<'a>) -> PyResult<PyRefMut<'a, T>> {
   155         &'a self,
       
   156         py: Python<'a>,
       
   157     ) -> PyResult<PyRefMut<'a, T>> {
       
   158         self.py_shared_state.borrow_mut(py, self.inner.borrow_mut())
   156         self.py_shared_state.borrow_mut(py, self.inner.borrow_mut())
   159     }
   157     }
   160 }
   158 }
   161 
   159 
   162 /// Sharable data member of type `T` borrowed from the `PyObject`.
   160 /// Sharable data member of type `T` borrowed from the `PyObject`.
   239     }
   237     }
   240 }
   238 }
   241 
   239 
   242 impl<'a, T> Drop for PyRefMut<'a, T> {
   240 impl<'a, T> Drop for PyRefMut<'a, T> {
   243     fn drop(&mut self) {
   241     fn drop(&mut self) {
   244         unsafe {
   242         self.py_shared_state.decrease_leak_count(self.py, true);
   245             self.py_shared_state.decrease_leak_count(self.py, true);
       
   246         }
       
   247     }
   243     }
   248 }
   244 }
   249 
   245 
   250 /// Allows a `py_class!` generated struct to share references to one of its
   246 /// Allows a `py_class!` generated struct to share references to one of its
   251 /// data members with Python.
   247 /// data members with Python.
   322 
   318 
   323 impl<T> PyLeakedRef<T> {
   319 impl<T> PyLeakedRef<T> {
   324     /// # Safety
   320     /// # Safety
   325     ///
   321     ///
   326     /// The `py_shared_state` must be owned by the `inner` Python object.
   322     /// The `py_shared_state` must be owned by the `inner` Python object.
   327     // Marked as unsafe so client code wouldn't construct PyLeakedRef
   323     fn new(
   328     // struct by mistake. Its drop() is unsafe.
       
   329     pub unsafe fn new(
       
   330         py: Python,
   324         py: Python,
   331         inner: &PyObject,
   325         inner: &PyObject,
   332         data: T,
   326         data: T,
   333         py_shared_state: &'static PySharedState,
   327         py_shared_state: &'static PySharedState,
   334     ) -> Self {
   328     ) -> Self {
   389         let gil = Python::acquire_gil();
   383         let gil = Python::acquire_gil();
   390         let py = gil.python();
   384         let py = gil.python();
   391         if self.data.is_none() {
   385         if self.data.is_none() {
   392             return; // moved to another PyLeakedRef
   386             return; // moved to another PyLeakedRef
   393         }
   387         }
   394         unsafe {
   388         self.py_shared_state.decrease_leak_count(py, false);
   395             self.py_shared_state.decrease_leak_count(py, false);
       
   396         }
       
   397     }
   389     }
   398 }
   390 }
   399 
   391 
   400 /// Defines a `py_class!` that acts as a Python iterator over a Rust iterator.
   392 /// Defines a `py_class!` that acts as a Python iterator over a Rust iterator.
   401 ///
   393 ///