comparison rust/hg-cpython/src/ref_sharing.rs @ 43178:1b2200bd06b6

rust-cpython: add safe wrapper representing shared data borrowed from PyObject PySharedRef is a tempoary wrapper around PySharedRefCell. It provides safe functions for each shared data. $shared_accessor implements a safe method to construct PySharedRefCell. This allows us to add more than once PySharedRefCell to a Python object.
author Yuya Nishihara <yuya@tcha.org>
date Sun, 15 Sep 2019 16:50:48 +0900
parents 5cb8867c9e2b
children 7d6758f2d50c
comparison
equal deleted inserted replaced
43177:5cb8867c9e2b 43178:1b2200bd06b6
123 /// 123 ///
124 /// Only immutable operation is allowed through this interface. 124 /// Only immutable operation is allowed through this interface.
125 #[derive(Debug)] 125 #[derive(Debug)]
126 pub struct PySharedRefCell<T> { 126 pub struct PySharedRefCell<T> {
127 inner: RefCell<T>, 127 inner: RefCell<T>,
128 pub py_shared_state: PySharedState, // TODO: remove pub 128 py_shared_state: PySharedState,
129 } 129 }
130 130
131 impl<T> PySharedRefCell<T> { 131 impl<T> PySharedRefCell<T> {
132 pub fn new(value: T) -> PySharedRefCell<T> { 132 pub fn new(value: T) -> PySharedRefCell<T> {
133 Self { 133 Self {
154 pub fn borrow_mut<'a>( 154 pub fn borrow_mut<'a>(
155 &'a self, 155 &'a self,
156 py: Python<'a>, 156 py: Python<'a>,
157 ) -> PyResult<PyRefMut<'a, T>> { 157 ) -> PyResult<PyRefMut<'a, T>> {
158 self.py_shared_state.borrow_mut(py, self.inner.borrow_mut()) 158 self.py_shared_state.borrow_mut(py, self.inner.borrow_mut())
159 }
160 }
161
162 /// Sharable data member of type `T` borrowed from the `PyObject`.
163 pub struct PySharedRef<'a, T> {
164 py: Python<'a>,
165 owner: &'a PyObject,
166 data: &'a PySharedRefCell<T>,
167 }
168
169 impl<'a, T> PySharedRef<'a, T> {
170 /// # Safety
171 ///
172 /// The `data` must be owned by the `owner`. Otherwise, the leak count
173 /// would get wrong.
174 pub unsafe fn new(
175 py: Python<'a>,
176 owner: &'a PyObject,
177 data: &'a PySharedRefCell<T>,
178 ) -> Self {
179 Self { py, owner, data }
180 }
181
182 pub fn borrow(&self) -> Ref<T> {
183 self.data.borrow()
184 }
185
186 pub fn borrow_mut(&self) -> PyResult<PyRefMut<'a, T>> {
187 self.data.borrow_mut(self.py)
188 }
189
190 /// Returns a leaked reference and its management object.
191 ///
192 /// # Safety
193 ///
194 /// It's up to you to make sure that the management object lives
195 /// longer than the leaked reference. Otherwise, you'll get a
196 /// dangling reference.
197 pub unsafe fn leak_immutable(
198 &self,
199 ) -> PyResult<(PyLeakedRef, &'static T)> {
200 let (static_ref, static_state_ref) = self
201 .data
202 .py_shared_state
203 .leak_immutable(self.py, self.data)?;
204 let leak_handle =
205 PyLeakedRef::new(self.py, self.owner, static_state_ref);
206 Ok((leak_handle, static_ref))
159 } 207 }
160 } 208 }
161 209
162 /// Holds a mutable reference to data shared between Python and Rust. 210 /// Holds a mutable reference to data shared between Python and Rust.
163 pub struct PyRefMut<'a, T> { 211 pub struct PyRefMut<'a, T> {
217 /// 265 ///
218 /// * `$name` is the same identifier used in for `py_class!` macro call. 266 /// * `$name` is the same identifier used in for `py_class!` macro call.
219 /// * `$inner_struct` is the identifier of the underlying Rust struct 267 /// * `$inner_struct` is the identifier of the underlying Rust struct
220 /// * `$data_member` is the identifier of the data member of `$inner_struct` 268 /// * `$data_member` is the identifier of the data member of `$inner_struct`
221 /// that will be shared. 269 /// that will be shared.
270 /// * `$shared_accessor` is the function name to be generated, which allows
271 /// safe access to the data member.
272 ///
273 /// # Safety
274 ///
275 /// `$data_member` must persist while the `$name` object is alive. In other
276 /// words, it must be an accessor to a data field of the Python object.
222 /// 277 ///
223 /// # Example 278 /// # Example
224 /// 279 ///
225 /// ``` 280 /// ```
226 /// struct MyStruct { 281 /// struct MyStruct {
229 /// 284 ///
230 /// py_class!(pub class MyType |py| { 285 /// py_class!(pub class MyType |py| {
231 /// data inner: PySharedRefCell<MyStruct>; 286 /// data inner: PySharedRefCell<MyStruct>;
232 /// }); 287 /// });
233 /// 288 ///
234 /// py_shared_ref!(MyType, MyStruct, inner); 289 /// py_shared_ref!(MyType, MyStruct, inner, inner_shared);
235 /// ``` 290 /// ```
236 macro_rules! py_shared_ref { 291 macro_rules! py_shared_ref {
237 ( 292 (
238 $name: ident, 293 $name: ident,
239 $inner_struct: ident, 294 $inner_struct: ident,
240 $data_member: ident 295 $data_member: ident,
296 $shared_accessor: ident
241 ) => { 297 ) => {
242 impl $name { 298 impl $name {
243 // TODO: remove this function in favor of inner(py).borrow_mut() 299 /// Returns a safe reference to the shared `$data_member`.
300 ///
301 /// This function guarantees that `PySharedRef` is created with
302 /// the valid `self` and `self.$data_member(py)` pair.
303 fn $shared_accessor<'a>(
304 &'a self,
305 py: Python<'a>,
306 ) -> $crate::ref_sharing::PySharedRef<'a, $inner_struct> {
307 use cpython::PythonObject;
308 use $crate::ref_sharing::PySharedRef;
309 let owner = self.as_object();
310 let data = self.$data_member(py);
311 unsafe { PySharedRef::new(py, owner, data) }
312 }
313
314 // TODO: remove this function in favor of $shared_accessor(py)
244 fn borrow_mut<'a>( 315 fn borrow_mut<'a>(
245 &'a self, 316 &'a self,
246 py: Python<'a>, 317 py: Python<'a>,
247 ) -> PyResult<crate::ref_sharing::PyRefMut<'a, $inner_struct>> 318 ) -> PyResult<crate::ref_sharing::PyRefMut<'a, $inner_struct>>
248 { 319 {
249 // assert $data_member type 320 self.$shared_accessor(py).borrow_mut()
250 use crate::ref_sharing::PySharedRefCell; 321 }
251 let data: &PySharedRefCell<_> = self.$data_member(py); 322
252 data.borrow_mut(py) 323 // TODO: remove this function in favor of $shared_accessor(py)
253 }
254
255 /// Returns a leaked reference and its management object.
256 ///
257 /// # Safety
258 ///
259 /// It's up to you to make sure that the management object lives
260 /// longer than the leaked reference. Otherwise, you'll get a
261 /// dangling reference.
262 unsafe fn leak_immutable<'a>( 324 unsafe fn leak_immutable<'a>(
263 &'a self, 325 &'a self,
264 py: Python<'a>, 326 py: Python<'a>,
265 ) -> PyResult<(PyLeakedRef, &'static $inner_struct)> { 327 ) -> PyResult<(PyLeakedRef, &'static $inner_struct)> {
266 use cpython::PythonObject; 328 self.$shared_accessor(py).leak_immutable()
267 // assert $data_member type
268 use crate::ref_sharing::PySharedRefCell;
269 let data: &PySharedRefCell<_> = self.$data_member(py);
270 let (static_ref, static_state_ref) =
271 data.py_shared_state.leak_immutable(py, data)?;
272 let leak_handle =
273 PyLeakedRef::new(py, self.as_object(), static_state_ref);
274 Ok((leak_handle, static_ref))
275 } 329 }
276 } 330 }
277 }; 331 };
278 } 332 }
279 333