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. |
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 /// |