changeset 43284:ce6dd1cee4c8

rust-cpython: put leaked reference in PyLeakedRef The next patch will make PyLeakedRef manage the lifetime of the underlying object. leak_handle.data.take() will be removed soon.
author Yuya Nishihara <yuya@tcha.org>
date Sun, 15 Sep 2019 22:06:19 +0900
parents 96eb9ef777a8
children ffc1fbd7d1f5
files 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
diffstat 4 files changed, 35 insertions(+), 23 deletions(-) [+]
line wrap: on
line diff
--- a/rust/hg-cpython/src/dirstate/copymap.rs	Thu Oct 17 20:40:12 2019 -0700
+++ b/rust/hg-cpython/src/dirstate/copymap.rs	Sun Sep 15 22:06:19 2019 +0900
@@ -13,6 +13,7 @@
 
 use crate::dirstate::dirstate_map::DirstateMap;
 use crate::ref_sharing::PyLeakedRef;
+use hg::DirstateMap as RustDirstateMap;
 use hg::{utils::hg_path::HgPathBuf, CopyMapIter};
 
 py_class!(pub class CopyMap |py| {
@@ -104,7 +105,7 @@
 
 py_shared_iterator!(
     CopyMapKeysIterator,
-    PyLeakedRef,
+    PyLeakedRef<&'static RustDirstateMap>,
     CopyMapIter<'static>,
     CopyMap::translate_key,
     Option<PyBytes>
@@ -112,7 +113,7 @@
 
 py_shared_iterator!(
     CopyMapItemsIterator,
-    PyLeakedRef,
+    PyLeakedRef<&'static RustDirstateMap>,
     CopyMapIter<'static>,
     CopyMap::translate_key_value,
     Option<(PyBytes, PyBytes)>
--- a/rust/hg-cpython/src/dirstate/dirs_multiset.rs	Thu Oct 17 20:40:12 2019 -0700
+++ b/rust/hg-cpython/src/dirstate/dirs_multiset.rs	Sun Sep 15 22:06:19 2019 +0900
@@ -92,8 +92,9 @@
             })
     }
     def __iter__(&self) -> PyResult<DirsMultisetKeysIterator> {
-        let (leak_handle, leaked_ref) =
+        let mut leak_handle =
             unsafe { self.inner_shared(py).leak_immutable()? };
+        let leaked_ref = leak_handle.data.take().unwrap();
         DirsMultisetKeysIterator::from_inner(
             py,
             leak_handle,
@@ -125,7 +126,7 @@
 
 py_shared_iterator!(
     DirsMultisetKeysIterator,
-    PyLeakedRef,
+    PyLeakedRef<&'static DirsMultiset>,
     DirsMultisetIter<'static>,
     Dirs::translate_key,
     Option<PyBytes>
--- a/rust/hg-cpython/src/dirstate/dirstate_map.rs	Thu Oct 17 20:40:12 2019 -0700
+++ b/rust/hg-cpython/src/dirstate/dirstate_map.rs	Sun Sep 15 22:06:19 2019 +0900
@@ -304,8 +304,9 @@
     }
 
     def keys(&self) -> PyResult<DirstateMapKeysIterator> {
-        let (leak_handle, leaked_ref) =
+        let mut leak_handle =
             unsafe { self.inner_shared(py).leak_immutable()? };
+        let leaked_ref = leak_handle.data.take().unwrap();
         DirstateMapKeysIterator::from_inner(
             py,
             leak_handle,
@@ -314,8 +315,9 @@
     }
 
     def items(&self) -> PyResult<DirstateMapItemsIterator> {
-        let (leak_handle, leaked_ref) =
+        let mut leak_handle =
             unsafe { self.inner_shared(py).leak_immutable()? };
+        let leaked_ref = leak_handle.data.take().unwrap();
         DirstateMapItemsIterator::from_inner(
             py,
             leak_handle,
@@ -324,8 +326,9 @@
     }
 
     def __iter__(&self) -> PyResult<DirstateMapKeysIterator> {
-        let (leak_handle, leaked_ref) =
+        let mut leak_handle =
             unsafe { self.inner_shared(py).leak_immutable()? };
+        let leaked_ref = leak_handle.data.take().unwrap();
         DirstateMapKeysIterator::from_inner(
             py,
             leak_handle,
@@ -443,8 +446,9 @@
     }
 
     def copymapiter(&self) -> PyResult<CopyMapKeysIterator> {
-        let (leak_handle, leaked_ref) =
+        let mut leak_handle =
             unsafe { self.inner_shared(py).leak_immutable()? };
+        let leaked_ref = leak_handle.data.take().unwrap();
         CopyMapKeysIterator::from_inner(
             py,
             leak_handle,
@@ -453,8 +457,9 @@
     }
 
     def copymapitemsiter(&self) -> PyResult<CopyMapItemsIterator> {
-        let (leak_handle, leaked_ref) =
+        let mut leak_handle =
             unsafe { self.inner_shared(py).leak_immutable()? };
+        let leaked_ref = leak_handle.data.take().unwrap();
         CopyMapItemsIterator::from_inner(
             py,
             leak_handle,
@@ -493,7 +498,7 @@
 
 py_shared_iterator!(
     DirstateMapKeysIterator,
-    PyLeakedRef,
+    PyLeakedRef<&'static RustDirstateMap>,
     StateMapIter<'static>,
     DirstateMap::translate_key,
     Option<PyBytes>
@@ -501,7 +506,7 @@
 
 py_shared_iterator!(
     DirstateMapItemsIterator,
-    PyLeakedRef,
+    PyLeakedRef<&'static RustDirstateMap>,
     StateMapIter<'static>,
     DirstateMap::translate_key_value,
     Option<(PyBytes, PyObject)>
--- a/rust/hg-cpython/src/ref_sharing.rs	Thu Oct 17 20:40:12 2019 -0700
+++ b/rust/hg-cpython/src/ref_sharing.rs	Sun Sep 15 22:06:19 2019 +0900
@@ -187,23 +187,24 @@
         self.data.borrow_mut(self.py)
     }
 
-    /// Returns a leaked reference and its management object.
+    /// Returns a leaked reference temporarily held by its management object.
     ///
     /// # Safety
     ///
     /// It's up to you to make sure that the management object lives
     /// longer than the leaked reference. Otherwise, you'll get a
     /// dangling reference.
-    pub unsafe fn leak_immutable(
-        &self,
-    ) -> PyResult<(PyLeakedRef, &'static T)> {
+    pub unsafe fn leak_immutable(&self) -> PyResult<PyLeakedRef<&'static T>> {
         let (static_ref, static_state_ref) = self
             .data
             .py_shared_state
             .leak_immutable(self.py, self.data)?;
-        let leak_handle =
-            PyLeakedRef::new(self.py, self.owner, static_state_ref);
-        Ok((leak_handle, static_ref))
+        Ok(PyLeakedRef::new(
+            self.py,
+            self.owner,
+            static_ref,
+            static_state_ref,
+        ))
     }
 }
 
@@ -318,12 +319,13 @@
 ///
 /// In truth, this does not represent leaked references themselves;
 /// it is instead useful alongside them to manage them.
-pub struct PyLeakedRef {
+pub struct PyLeakedRef<T> {
     _inner: PyObject,
+    pub data: Option<T>, // TODO: remove pub
     py_shared_state: &'static PySharedState,
 }
 
-impl PyLeakedRef {
+impl<T> PyLeakedRef<T> {
     /// # Safety
     ///
     /// The `py_shared_state` must be owned by the `inner` Python object.
@@ -332,16 +334,18 @@
     pub unsafe fn new(
         py: Python,
         inner: &PyObject,
+        data: T,
         py_shared_state: &'static PySharedState,
     ) -> Self {
         Self {
             _inner: inner.clone_ref(py),
+            data: Some(data),
             py_shared_state,
         }
     }
 }
 
-impl Drop for PyLeakedRef {
+impl<T> Drop for PyLeakedRef<T> {
     fn drop(&mut self) {
         // py_shared_state should be alive since we do have
         // a Python reference to the owner object. Taking GIL makes
@@ -379,8 +383,9 @@
 ///     data inner: PySharedRefCell<MyStruct>;
 ///
 ///     def __iter__(&self) -> PyResult<MyTypeItemsIterator> {
-///         let (leak_handle, leaked_ref) =
+///         let mut leak_handle =
 ///             unsafe { self.inner_shared(py).leak_immutable()? };
+///         let leaked_ref = leak_handle.data.take().unwrap();
 ///         MyTypeItemsIterator::from_inner(
 ///             py,
 ///             leak_handle,
@@ -406,7 +411,7 @@
 ///
 /// py_shared_iterator!(
 ///     MyTypeItemsIterator,
-///     PyLeakedRef,
+///     PyLeakedRef<&'static MyStruct>,
 ///     HashMap<'static, Vec<u8>, Vec<u8>>,
 ///     MyType::translate_key_value,
 ///     Option<(PyBytes, PyBytes)>