changeset 44189:4a4c3b9fd91b

rust-cpython: make sure PySharedRef::borrow_mut() never panics Since it returns a Result, it shouldn't panic depending on where the borrowing fails. PySharedRef::borrow_mut() will be renamed to try_borrow_mut() by the next patch.
author Yuya Nishihara <yuya@tcha.org>
date Sat, 21 Sep 2019 17:27:14 +0900
parents 1f9e6fbdd3e6
children 5de70f798ea7
files rust/hg-cpython/src/ref_sharing.rs
diffstat 1 files changed, 20 insertions(+), 9 deletions(-) [+]
line wrap: on
line diff
--- a/rust/hg-cpython/src/ref_sharing.rs	Tue Oct 22 11:38:43 2019 +0900
+++ b/rust/hg-cpython/src/ref_sharing.rs	Sat Sep 21 17:27:14 2019 +0900
@@ -57,7 +57,7 @@
 }
 
 impl PySharedState {
-    fn borrow_mut<'a, T>(
+    fn try_borrow_mut<'a, T>(
         &'a self,
         py: Python<'a>,
         pyrefmut: RefMut<'a, T>,
@@ -162,16 +162,19 @@
     fn borrow<'a>(&'a self, _py: Python<'a>) -> Ref<'a, T> {
         // py_shared_state isn't involved since
         // - inner.borrow() would fail if self is mutably borrowed,
-        // - and inner.borrow_mut() would fail while self is borrowed.
+        // - and inner.try_borrow_mut() would fail while self is borrowed.
         self.inner.borrow()
     }
 
-    // TODO: maybe this should be named as try_borrow_mut(), and use
-    // inner.try_borrow_mut(). The current implementation panics if
-    // self.inner has been borrowed, but returns error if py_shared_state
-    // refuses to borrow.
-    fn borrow_mut<'a>(&'a self, py: Python<'a>) -> PyResult<RefMut<'a, T>> {
-        self.py_shared_state.borrow_mut(py, self.inner.borrow_mut())
+    fn try_borrow_mut<'a>(
+        &'a self,
+        py: Python<'a>,
+    ) -> PyResult<RefMut<'a, T>> {
+        let inner_ref = self
+            .inner
+            .try_borrow_mut()
+            .map_err(|e| AlreadyBorrowed::new(py, e.to_string()))?;
+        self.py_shared_state.try_borrow_mut(py, inner_ref)
     }
 }
 
@@ -200,7 +203,7 @@
     }
 
     pub fn borrow_mut(&self) -> PyResult<RefMut<'a, T>> {
-        self.data.borrow_mut(self.py)
+        self.data.try_borrow_mut(self.py)
     }
 
     /// Returns a leaked reference.
@@ -633,4 +636,12 @@
         let _mut_ref = owner.string_shared(py).borrow_mut();
         owner.string_shared(py).leak_immutable();
     }
+
+    #[test]
+    fn test_borrow_mut_while_borrow() {
+        let (gil, owner) = prepare_env();
+        let py = gil.python();
+        let _ref = owner.string_shared(py).borrow();
+        assert!(owner.string_shared(py).borrow_mut().is_err());
+    }
 }