rust/hg-cpython/src/ref_sharing.rs
changeset 43173 070a38737334
parent 43082 fdfe5cfb3723
child 43174 1c675c5fe5fe
equal deleted inserted replaced
43172:9145abd8b96d 43173:070a38737334
    25 use crate::exceptions::AlreadyBorrowed;
    25 use crate::exceptions::AlreadyBorrowed;
    26 use cpython::{PyResult, Python};
    26 use cpython::{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(Default)]
    30 #[derive(Debug, Default)]
    31 pub struct PySharedState {
    31 pub 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 
   116 ///
   116 ///
   117 /// Only immutable operation is allowed through this interface.
   117 /// Only immutable operation is allowed through this interface.
   118 #[derive(Debug)]
   118 #[derive(Debug)]
   119 pub struct PySharedRefCell<T> {
   119 pub struct PySharedRefCell<T> {
   120     inner: RefCell<T>,
   120     inner: RefCell<T>,
       
   121     pub py_shared_state: PySharedState, // TODO: remove pub
   121 }
   122 }
   122 
   123 
   123 impl<T> PySharedRefCell<T> {
   124 impl<T> PySharedRefCell<T> {
   124     pub const fn new(value: T) -> PySharedRefCell<T> {
   125     pub fn new(value: T) -> PySharedRefCell<T> {
   125         Self {
   126         Self {
   126             inner: RefCell::new(value),
   127             inner: RefCell::new(value),
       
   128             py_shared_state: PySharedState::default(),
   127         }
   129         }
   128     }
   130     }
   129 
   131 
   130     pub fn borrow(&self) -> Ref<T> {
   132     pub fn borrow(&self) -> Ref<T> {
   131         // py_shared_state isn't involved since
   133         // py_shared_state isn't involved since
   191 /// Allows a `py_class!` generated struct to share references to one of its
   193 /// Allows a `py_class!` generated struct to share references to one of its
   192 /// data members with Python.
   194 /// data members with Python.
   193 ///
   195 ///
   194 /// # Warning
   196 /// # Warning
   195 ///
   197 ///
   196 /// The targeted `py_class!` needs to have the
       
   197 /// `data py_shared_state: PySharedState;` data attribute to compile.
       
   198 /// A better, more complicated macro is needed to automatically insert it,
       
   199 /// but this one is not yet really battle tested (what happens when
       
   200 /// multiple references are needed?). See the example below.
       
   201 ///
       
   202 /// TODO allow Python container types: for now, integration with the garbage
   198 /// TODO allow Python container types: for now, integration with the garbage
   203 ///     collector does not extend to Rust structs holding references to Python
   199 ///     collector does not extend to Rust structs holding references to Python
   204 ///     objects. Should the need surface, `__traverse__` and `__clear__` will
   200 ///     objects. Should the need surface, `__traverse__` and `__clear__` will
   205 ///     need to be written as per the `rust-cpython` docs on GC integration.
   201 ///     need to be written as per the `rust-cpython` docs on GC integration.
   206 ///
   202 ///
   221 ///     inner: Vec<u32>;
   217 ///     inner: Vec<u32>;
   222 /// }
   218 /// }
   223 ///
   219 ///
   224 /// py_class!(pub class MyType |py| {
   220 /// py_class!(pub class MyType |py| {
   225 ///     data inner: PySharedRefCell<MyStruct>;
   221 ///     data inner: PySharedRefCell<MyStruct>;
   226 ///     data py_shared_state: PySharedState;
       
   227 /// });
   222 /// });
   228 ///
   223 ///
   229 /// py_shared_ref!(MyType, MyStruct, inner, MyTypeLeakedRef);
   224 /// py_shared_ref!(MyType, MyStruct, inner, MyTypeLeakedRef);
   230 /// ```
   225 /// ```
   231 macro_rules! py_shared_ref {
   226 macro_rules! py_shared_ref {
   242             ) -> PyResult<crate::ref_sharing::PyRefMut<'a, $inner_struct>>
   237             ) -> PyResult<crate::ref_sharing::PyRefMut<'a, $inner_struct>>
   243             {
   238             {
   244                 // assert $data_member type
   239                 // assert $data_member type
   245                 use crate::ref_sharing::PySharedRefCell;
   240                 use crate::ref_sharing::PySharedRefCell;
   246                 let data: &PySharedRefCell<_> = self.$data_member(py);
   241                 let data: &PySharedRefCell<_> = self.$data_member(py);
   247                 self.py_shared_state(py)
   242                 data.py_shared_state
   248                     .borrow_mut(py, unsafe { data.borrow_mut() })
   243                     .borrow_mut(py, unsafe { data.borrow_mut() })
   249             }
   244             }
   250 
   245 
   251             /// Returns a leaked reference and its management object.
   246             /// Returns a leaked reference and its management object.
   252             ///
   247             ///
   261             ) -> PyResult<($leaked, &'static $inner_struct)> {
   256             ) -> PyResult<($leaked, &'static $inner_struct)> {
   262                 // assert $data_member type
   257                 // assert $data_member type
   263                 use crate::ref_sharing::PySharedRefCell;
   258                 use crate::ref_sharing::PySharedRefCell;
   264                 let data: &PySharedRefCell<_> = self.$data_member(py);
   259                 let data: &PySharedRefCell<_> = self.$data_member(py);
   265                 let static_ref =
   260                 let static_ref =
   266                     self.py_shared_state(py).leak_immutable(py, data)?;
   261                     data.py_shared_state.leak_immutable(py, data)?;
   267                 let leak_handle = $leaked::new(py, self);
   262                 let leak_handle = $leaked::new(py, self);
   268                 Ok((leak_handle, static_ref))
   263                 Ok((leak_handle, static_ref))
   269             }
   264             }
   270         }
   265         }
   271 
   266 
   290 
   285 
   291         impl Drop for $leaked {
   286         impl Drop for $leaked {
   292             fn drop(&mut self) {
   287             fn drop(&mut self) {
   293                 let gil = Python::acquire_gil();
   288                 let gil = Python::acquire_gil();
   294                 let py = gil.python();
   289                 let py = gil.python();
   295                 let state = self.inner.py_shared_state(py);
   290                 let state = &self.inner.$data_member(py).py_shared_state;
   296                 unsafe {
   291                 unsafe {
   297                     state.decrease_leak_count(py, false);
   292                     state.decrease_leak_count(py, false);
   298                 }
   293                 }
   299             }
   294             }
   300         }
   295         }
   322 ///     inner: HashMap<Vec<u8>, Vec<u8>>;
   317 ///     inner: HashMap<Vec<u8>, Vec<u8>>;
   323 /// }
   318 /// }
   324 ///
   319 ///
   325 /// py_class!(pub class MyType |py| {
   320 /// py_class!(pub class MyType |py| {
   326 ///     data inner: PySharedRefCell<MyStruct>;
   321 ///     data inner: PySharedRefCell<MyStruct>;
   327 ///     data py_shared_state: PySharedState;
       
   328 ///
   322 ///
   329 ///     def __iter__(&self) -> PyResult<MyTypeItemsIterator> {
   323 ///     def __iter__(&self) -> PyResult<MyTypeItemsIterator> {
   330 ///         let (leak_handle, leaked_ref) = unsafe { self.leak_immutable(py)? };
   324 ///         let (leak_handle, leaked_ref) = unsafe { self.leak_immutable(py)? };
   331 ///         MyTypeItemsIterator::from_inner(
   325 ///         MyTypeItemsIterator::from_inner(
   332 ///             py,
   326 ///             py,