equal
deleted
inserted
replaced
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, |