Mercurial > hg
comparison rust/hg-cpython/src/ref_sharing.rs @ 43177:5cb8867c9e2b
rust-cpython: move $leaked struct out of macro
It wasn't easy to hack the $leaked struct since errors in macro would
generate lots of compile errors. Let's make it a plain struct so we can
easily extend it.
PyLeakedRef keeps a more generic PyObject instead of the $name struct
since it no longer has to call any specific methods implemented by
the $name class. $leaked parameter in py_shared_iterator!() is kept
for future change.
author | Yuya Nishihara <yuya@tcha.org> |
---|---|
date | Sun, 08 Sep 2019 20:26:55 +0900 |
parents | aaec70a5f9a8 |
children | 1b2200bd06b6 |
comparison
equal
deleted
inserted
replaced
43176:aaec70a5f9a8 | 43177:5cb8867c9e2b |
---|---|
21 // IN THE SOFTWARE. | 21 // IN THE SOFTWARE. |
22 | 22 |
23 //! Macros for use in the `hg-cpython` bridge library. | 23 //! Macros for use in the `hg-cpython` bridge library. |
24 | 24 |
25 use crate::exceptions::AlreadyBorrowed; | 25 use crate::exceptions::AlreadyBorrowed; |
26 use cpython::{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 pub struct PySharedState { |
217 /// | 217 /// |
218 /// * `$name` is the same identifier used in for `py_class!` macro call. | 218 /// * `$name` is the same identifier used in for `py_class!` macro call. |
219 /// * `$inner_struct` is the identifier of the underlying Rust struct | 219 /// * `$inner_struct` is the identifier of the underlying Rust struct |
220 /// * `$data_member` is the identifier of the data member of `$inner_struct` | 220 /// * `$data_member` is the identifier of the data member of `$inner_struct` |
221 /// that will be shared. | 221 /// that will be shared. |
222 /// * `$leaked` is the identifier to give to the struct that will manage | |
223 /// references to `$name`, to be used for example in other macros like | |
224 /// `py_shared_iterator`. | |
225 /// | 222 /// |
226 /// # Example | 223 /// # Example |
227 /// | 224 /// |
228 /// ``` | 225 /// ``` |
229 /// struct MyStruct { | 226 /// struct MyStruct { |
232 /// | 229 /// |
233 /// py_class!(pub class MyType |py| { | 230 /// py_class!(pub class MyType |py| { |
234 /// data inner: PySharedRefCell<MyStruct>; | 231 /// data inner: PySharedRefCell<MyStruct>; |
235 /// }); | 232 /// }); |
236 /// | 233 /// |
237 /// py_shared_ref!(MyType, MyStruct, inner, MyTypeLeakedRef); | 234 /// py_shared_ref!(MyType, MyStruct, inner); |
238 /// ``` | 235 /// ``` |
239 macro_rules! py_shared_ref { | 236 macro_rules! py_shared_ref { |
240 ( | 237 ( |
241 $name: ident, | 238 $name: ident, |
242 $inner_struct: ident, | 239 $inner_struct: ident, |
243 $data_member: ident, | 240 $data_member: ident |
244 $leaked: ident, | |
245 ) => { | 241 ) => { |
246 impl $name { | 242 impl $name { |
247 // TODO: remove this function in favor of inner(py).borrow_mut() | 243 // TODO: remove this function in favor of inner(py).borrow_mut() |
248 fn borrow_mut<'a>( | 244 fn borrow_mut<'a>( |
249 &'a self, | 245 &'a self, |
264 /// longer than the leaked reference. Otherwise, you'll get a | 260 /// longer than the leaked reference. Otherwise, you'll get a |
265 /// dangling reference. | 261 /// dangling reference. |
266 unsafe fn leak_immutable<'a>( | 262 unsafe fn leak_immutable<'a>( |
267 &'a self, | 263 &'a self, |
268 py: Python<'a>, | 264 py: Python<'a>, |
269 ) -> PyResult<($leaked, &'static $inner_struct)> { | 265 ) -> PyResult<(PyLeakedRef, &'static $inner_struct)> { |
266 use cpython::PythonObject; | |
270 // assert $data_member type | 267 // assert $data_member type |
271 use crate::ref_sharing::PySharedRefCell; | 268 use crate::ref_sharing::PySharedRefCell; |
272 let data: &PySharedRefCell<_> = self.$data_member(py); | 269 let data: &PySharedRefCell<_> = self.$data_member(py); |
273 let (static_ref, static_state_ref) = | 270 let (static_ref, static_state_ref) = |
274 data.py_shared_state.leak_immutable(py, data)?; | 271 data.py_shared_state.leak_immutable(py, data)?; |
275 let leak_handle = $leaked::new(py, self, static_state_ref); | 272 let leak_handle = |
273 PyLeakedRef::new(py, self.as_object(), static_state_ref); | |
276 Ok((leak_handle, static_ref)) | 274 Ok((leak_handle, static_ref)) |
277 } | 275 } |
278 } | 276 } |
279 | |
280 /// Manage immutable references to `$name` leaked into Python | |
281 /// iterators. | |
282 /// | |
283 /// In truth, this does not represent leaked references themselves; | |
284 /// it is instead useful alongside them to manage them. | |
285 pub struct $leaked { | |
286 _inner: $name, | |
287 py_shared_state: &'static crate::ref_sharing::PySharedState, | |
288 } | |
289 | |
290 impl $leaked { | |
291 /// # Safety | |
292 /// | |
293 /// The `py_shared_state` must be owned by the `inner` Python | |
294 /// object. | |
295 // Marked as unsafe so client code wouldn't construct $leaked | |
296 // struct by mistake. Its drop() is unsafe. | |
297 unsafe fn new( | |
298 py: Python, | |
299 inner: &$name, | |
300 py_shared_state: &'static crate::ref_sharing::PySharedState, | |
301 ) -> Self { | |
302 Self { | |
303 _inner: inner.clone_ref(py), | |
304 py_shared_state, | |
305 } | |
306 } | |
307 } | |
308 | |
309 impl Drop for $leaked { | |
310 fn drop(&mut self) { | |
311 // py_shared_state should be alive since we do have | |
312 // a Python reference to the owner object. Taking GIL makes | |
313 // sure that the state is only accessed by this thread. | |
314 let gil = Python::acquire_gil(); | |
315 let py = gil.python(); | |
316 unsafe { | |
317 self.py_shared_state.decrease_leak_count(py, false); | |
318 } | |
319 } | |
320 } | |
321 }; | 277 }; |
278 } | |
279 | |
280 /// Manage immutable references to `PyObject` leaked into Python iterators. | |
281 /// | |
282 /// In truth, this does not represent leaked references themselves; | |
283 /// it is instead useful alongside them to manage them. | |
284 pub struct PyLeakedRef { | |
285 _inner: PyObject, | |
286 py_shared_state: &'static PySharedState, | |
287 } | |
288 | |
289 impl PyLeakedRef { | |
290 /// # Safety | |
291 /// | |
292 /// The `py_shared_state` must be owned by the `inner` Python object. | |
293 // Marked as unsafe so client code wouldn't construct PyLeakedRef | |
294 // struct by mistake. Its drop() is unsafe. | |
295 pub unsafe fn new( | |
296 py: Python, | |
297 inner: &PyObject, | |
298 py_shared_state: &'static PySharedState, | |
299 ) -> Self { | |
300 Self { | |
301 _inner: inner.clone_ref(py), | |
302 py_shared_state, | |
303 } | |
304 } | |
305 } | |
306 | |
307 impl Drop for PyLeakedRef { | |
308 fn drop(&mut self) { | |
309 // py_shared_state should be alive since we do have | |
310 // a Python reference to the owner object. Taking GIL makes | |
311 // sure that the state is only accessed by this thread. | |
312 let gil = Python::acquire_gil(); | |
313 let py = gil.python(); | |
314 unsafe { | |
315 self.py_shared_state.decrease_leak_count(py, false); | |
316 } | |
317 } | |
322 } | 318 } |
323 | 319 |
324 /// Defines a `py_class!` that acts as a Python iterator over a Rust iterator. | 320 /// Defines a `py_class!` that acts as a Python iterator over a Rust iterator. |
325 /// | 321 /// |
326 /// TODO: this is a bit awkward to use, and a better (more complicated) | 322 /// TODO: this is a bit awkward to use, and a better (more complicated) |
370 /// | 366 /// |
371 /// py_shared_ref!(MyType, MyStruct, inner, MyTypeLeakedRef); | 367 /// py_shared_ref!(MyType, MyStruct, inner, MyTypeLeakedRef); |
372 /// | 368 /// |
373 /// py_shared_iterator!( | 369 /// py_shared_iterator!( |
374 /// MyTypeItemsIterator, | 370 /// MyTypeItemsIterator, |
375 /// MyTypeLeakedRef, | 371 /// PyLeakedRef, |
376 /// HashMap<'static, Vec<u8>, Vec<u8>>, | 372 /// HashMap<'static, Vec<u8>, Vec<u8>>, |
377 /// MyType::translate_key_value, | 373 /// MyType::translate_key_value, |
378 /// Option<(PyBytes, PyBytes)> | 374 /// Option<(PyBytes, PyBytes)> |
379 /// ); | 375 /// ); |
380 /// ``` | 376 /// ``` |
381 macro_rules! py_shared_iterator { | 377 macro_rules! py_shared_iterator { |
382 ( | 378 ( |
383 $name: ident, | 379 $name: ident, |
384 $leaked: ident, | 380 $leaked: ty, |
385 $iterator_type: ty, | 381 $iterator_type: ty, |
386 $success_func: expr, | 382 $success_func: expr, |
387 $success_type: ty | 383 $success_type: ty |
388 ) => { | 384 ) => { |
389 py_class!(pub class $name |py| { | 385 py_class!(pub class $name |py| { |