rust-cpython: move $leaked struct out of macro
authorYuya Nishihara <yuya@tcha.org>
Sun, 08 Sep 2019 20:26:55 +0900
changeset 43177 5cb8867c9e2b
parent 43176 aaec70a5f9a8
child 43178 1b2200bd06b6
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.
rust/hg-cpython/src/dirstate/copymap.rs
rust/hg-cpython/src/dirstate/dirs_multiset.rs
rust/hg-cpython/src/dirstate/dirstate_map.rs
rust/hg-cpython/src/ref_sharing.rs
--- a/rust/hg-cpython/src/dirstate/copymap.rs	Sun Sep 15 16:04:45 2019 +0900
+++ b/rust/hg-cpython/src/dirstate/copymap.rs	Sun Sep 08 20:26:55 2019 +0900
@@ -11,7 +11,8 @@
 use cpython::{PyBytes, PyClone, PyDict, PyObject, PyResult, Python};
 use std::cell::RefCell;
 
-use crate::dirstate::dirstate_map::{DirstateMap, DirstateMapLeakedRef};
+use crate::dirstate::dirstate_map::DirstateMap;
+use crate::ref_sharing::PyLeakedRef;
 use hg::{utils::hg_path::HgPathBuf, CopyMapIter};
 
 py_class!(pub class CopyMap |py| {
@@ -103,7 +104,7 @@
 
 py_shared_iterator!(
     CopyMapKeysIterator,
-    DirstateMapLeakedRef,
+    PyLeakedRef,
     CopyMapIter<'static>,
     CopyMap::translate_key,
     Option<PyBytes>
@@ -111,7 +112,7 @@
 
 py_shared_iterator!(
     CopyMapItemsIterator,
-    DirstateMapLeakedRef,
+    PyLeakedRef,
     CopyMapIter<'static>,
     CopyMap::translate_key_value,
     Option<(PyBytes, PyBytes)>
--- a/rust/hg-cpython/src/dirstate/dirs_multiset.rs	Sun Sep 15 16:04:45 2019 +0900
+++ b/rust/hg-cpython/src/dirstate/dirs_multiset.rs	Sun Sep 08 20:26:55 2019 +0900
@@ -16,7 +16,8 @@
     Python,
 };
 
-use crate::{dirstate::extract_dirstate, ref_sharing::PySharedRefCell};
+use crate::dirstate::extract_dirstate;
+use crate::ref_sharing::{PyLeakedRef, PySharedRefCell};
 use hg::{
     utils::hg_path::{HgPath, HgPathBuf},
     DirsMultiset, DirsMultisetIter, DirstateMapError, DirstateParseError,
@@ -106,7 +107,7 @@
     }
 });
 
-py_shared_ref!(Dirs, DirsMultiset, inner, DirsMultisetLeakedRef,);
+py_shared_ref!(Dirs, DirsMultiset, inner);
 
 impl Dirs {
     pub fn from_inner(py: Python, d: DirsMultiset) -> PyResult<Self> {
@@ -123,7 +124,7 @@
 
 py_shared_iterator!(
     DirsMultisetKeysIterator,
-    DirsMultisetLeakedRef,
+    PyLeakedRef,
     DirsMultisetIter<'static>,
     Dirs::translate_key,
     Option<PyBytes>
--- a/rust/hg-cpython/src/dirstate/dirstate_map.rs	Sun Sep 15 16:04:45 2019 +0900
+++ b/rust/hg-cpython/src/dirstate/dirstate_map.rs	Sun Sep 08 20:26:55 2019 +0900
@@ -21,7 +21,7 @@
 use crate::{
     dirstate::copymap::{CopyMap, CopyMapItemsIterator, CopyMapKeysIterator},
     dirstate::{decapsule_make_dirstate_tuple, dirs_multiset::Dirs},
-    ref_sharing::PySharedRefCell,
+    ref_sharing::{PyLeakedRef, PySharedRefCell},
 };
 use hg::{
     utils::hg_path::{HgPath, HgPathBuf},
@@ -501,11 +501,11 @@
     }
 }
 
-py_shared_ref!(DirstateMap, RustDirstateMap, inner, DirstateMapLeakedRef,);
+py_shared_ref!(DirstateMap, RustDirstateMap, inner);
 
 py_shared_iterator!(
     DirstateMapKeysIterator,
-    DirstateMapLeakedRef,
+    PyLeakedRef,
     StateMapIter<'static>,
     DirstateMap::translate_key,
     Option<PyBytes>
@@ -513,7 +513,7 @@
 
 py_shared_iterator!(
     DirstateMapItemsIterator,
-    DirstateMapLeakedRef,
+    PyLeakedRef,
     StateMapIter<'static>,
     DirstateMap::translate_key_value,
     Option<(PyBytes, PyObject)>
--- a/rust/hg-cpython/src/ref_sharing.rs	Sun Sep 15 16:04:45 2019 +0900
+++ b/rust/hg-cpython/src/ref_sharing.rs	Sun Sep 08 20:26:55 2019 +0900
@@ -23,7 +23,7 @@
 //! Macros for use in the `hg-cpython` bridge library.
 
 use crate::exceptions::AlreadyBorrowed;
-use cpython::{PyResult, Python};
+use cpython::{PyClone, PyObject, PyResult, Python};
 use std::cell::{Cell, Ref, RefCell, RefMut};
 
 /// Manages the shared state between Python and Rust
@@ -219,9 +219,6 @@
 /// * `$inner_struct` is the identifier of the underlying Rust struct
 /// * `$data_member` is the identifier of the data member of `$inner_struct`
 /// that will be shared.
-/// * `$leaked` is the identifier to give to the struct that will manage
-/// references to `$name`, to be used for example in other macros like
-/// `py_shared_iterator`.
 ///
 /// # Example
 ///
@@ -234,14 +231,13 @@
 ///     data inner: PySharedRefCell<MyStruct>;
 /// });
 ///
-/// py_shared_ref!(MyType, MyStruct, inner, MyTypeLeakedRef);
+/// py_shared_ref!(MyType, MyStruct, inner);
 /// ```
 macro_rules! py_shared_ref {
     (
         $name: ident,
         $inner_struct: ident,
-        $data_member: ident,
-        $leaked: ident,
+        $data_member: ident
     ) => {
         impl $name {
             // TODO: remove this function in favor of inner(py).borrow_mut()
@@ -266,59 +262,59 @@
             unsafe fn leak_immutable<'a>(
                 &'a self,
                 py: Python<'a>,
-            ) -> PyResult<($leaked, &'static $inner_struct)> {
+            ) -> PyResult<(PyLeakedRef, &'static $inner_struct)> {
+                use cpython::PythonObject;
                 // assert $data_member type
                 use crate::ref_sharing::PySharedRefCell;
                 let data: &PySharedRefCell<_> = self.$data_member(py);
                 let (static_ref, static_state_ref) =
                     data.py_shared_state.leak_immutable(py, data)?;
-                let leak_handle = $leaked::new(py, self, static_state_ref);
+                let leak_handle =
+                    PyLeakedRef::new(py, self.as_object(), static_state_ref);
                 Ok((leak_handle, static_ref))
             }
         }
+    };
+}
 
-        /// Manage immutable references to `$name` leaked into Python
-        /// iterators.
-        ///
-        /// In truth, this does not represent leaked references themselves;
-        /// it is instead useful alongside them to manage them.
-        pub struct $leaked {
-            _inner: $name,
-            py_shared_state: &'static crate::ref_sharing::PySharedState,
-        }
+/// Manage immutable references to `PyObject` leaked into Python iterators.
+///
+/// In truth, this does not represent leaked references themselves;
+/// it is instead useful alongside them to manage them.
+pub struct PyLeakedRef {
+    _inner: PyObject,
+    py_shared_state: &'static PySharedState,
+}
 
-        impl $leaked {
-            /// # Safety
-            ///
-            /// The `py_shared_state` must be owned by the `inner` Python
-            /// object.
-            // Marked as unsafe so client code wouldn't construct $leaked
-            // struct by mistake. Its drop() is unsafe.
-            unsafe fn new(
-                py: Python,
-                inner: &$name,
-                py_shared_state: &'static crate::ref_sharing::PySharedState,
-            ) -> Self {
-                Self {
-                    _inner: inner.clone_ref(py),
-                    py_shared_state,
-                }
-            }
+impl PyLeakedRef {
+    /// # Safety
+    ///
+    /// The `py_shared_state` must be owned by the `inner` Python object.
+    // Marked as unsafe so client code wouldn't construct PyLeakedRef
+    // struct by mistake. Its drop() is unsafe.
+    pub unsafe fn new(
+        py: Python,
+        inner: &PyObject,
+        py_shared_state: &'static PySharedState,
+    ) -> Self {
+        Self {
+            _inner: inner.clone_ref(py),
+            py_shared_state,
         }
+    }
+}
 
-        impl Drop for $leaked {
-            fn drop(&mut self) {
-                // py_shared_state should be alive since we do have
-                // a Python reference to the owner object. Taking GIL makes
-                // sure that the state is only accessed by this thread.
-                let gil = Python::acquire_gil();
-                let py = gil.python();
-                unsafe {
-                    self.py_shared_state.decrease_leak_count(py, false);
-                }
-            }
+impl Drop for PyLeakedRef {
+    fn drop(&mut self) {
+        // py_shared_state should be alive since we do have
+        // a Python reference to the owner object. Taking GIL makes
+        // sure that the state is only accessed by this thread.
+        let gil = Python::acquire_gil();
+        let py = gil.python();
+        unsafe {
+            self.py_shared_state.decrease_leak_count(py, false);
         }
-    };
+    }
 }
 
 /// Defines a `py_class!` that acts as a Python iterator over a Rust iterator.
@@ -372,7 +368,7 @@
 ///
 /// py_shared_iterator!(
 ///     MyTypeItemsIterator,
-///     MyTypeLeakedRef,
+///     PyLeakedRef,
 ///     HashMap<'static, Vec<u8>, Vec<u8>>,
 ///     MyType::translate_key_value,
 ///     Option<(PyBytes, PyBytes)>
@@ -381,7 +377,7 @@
 macro_rules! py_shared_iterator {
     (
         $name: ident,
-        $leaked: ident,
+        $leaked: ty,
         $iterator_type: ty,
         $success_func: expr,
         $success_type: ty