--- a/rust/hg-cpython/src/ref_sharing.rs Sat Oct 19 17:01:28 2019 +0900
+++ b/rust/hg-cpython/src/ref_sharing.rs Tue Oct 22 16:04:34 2019 +0900
@@ -294,7 +294,13 @@
/// Immutably borrows the wrapped value.
///
/// Borrowing fails if the underlying reference has been invalidated.
- pub fn try_borrow<'a>(
+ ///
+ /// # Safety
+ ///
+ /// The lifetime of the innermost object is cheated. Do not obtain and
+ /// copy it out of the borrow scope. See the example of `try_borrow_mut()`
+ /// for details.
+ pub unsafe fn try_borrow<'a>(
&'a self,
py: Python<'a>,
) -> PyResult<PyLeakedRef<'a, T>> {
@@ -311,7 +317,24 @@
///
/// Typically `T` is an iterator. If `T` is an immutable reference,
/// `get_mut()` is useless since the inner value can't be mutated.
- pub fn try_borrow_mut<'a>(
+ ///
+ /// # Safety
+ ///
+ /// The lifetime of the innermost object is cheated. Do not obtain and
+ /// copy it out of the borrow scope. For example, the following code
+ /// is unsafe:
+ ///
+ /// ```compile_fail
+ /// let slice;
+ /// {
+ /// let iter = leaked.try_borrow_mut(py);
+ /// // slice can outlive since the iterator is of Iter<'static, T>
+ /// // type, but it shouldn't.
+ /// slice = iter.as_slice();
+ /// }
+ /// println!("{:?}", slice);
+ /// ```
+ pub unsafe fn try_borrow_mut<'a>(
&'a mut self,
py: Python<'a>,
) -> PyResult<PyLeakedRefMut<'a, T>> {
@@ -423,6 +446,11 @@
/// tuple on iteration success, turning it into something Python understands.
/// * `$success_func` is the return type of `$success_func`
///
+/// # Safety
+///
+/// `$success_func` may take a reference, but it's lifetime may be cheated.
+/// Do not copy it out of the function call.
+///
/// # Example
///
/// ```
@@ -476,9 +504,10 @@
def __next__(&self) -> PyResult<$success_type> {
let mut leaked = self.inner(py).borrow_mut();
- let mut iter = leaked.try_borrow_mut(py)?;
+ let mut iter = unsafe { leaked.try_borrow_mut(py)? };
match iter.next() {
None => Ok(None),
+ // res may be a reference of cheated 'static lifetime
Some(res) => $success_func(py, res),
}
}
@@ -527,7 +556,7 @@
let (gil, owner) = prepare_env();
let py = gil.python();
let leaked = owner.string_shared(py).leak_immutable();
- let leaked_ref = leaked.try_borrow(py).unwrap();
+ let leaked_ref = unsafe { leaked.try_borrow(py) }.unwrap();
assert_eq!(*leaked_ref, "new");
}
@@ -537,7 +566,8 @@
let py = gil.python();
let leaked = owner.string_shared(py).leak_immutable();
let mut leaked_iter = unsafe { leaked.map(py, |s| s.chars()) };
- let mut leaked_ref = leaked_iter.try_borrow_mut(py).unwrap();
+ let mut leaked_ref =
+ unsafe { leaked_iter.try_borrow_mut(py) }.unwrap();
assert_eq!(leaked_ref.next(), Some('n'));
assert_eq!(leaked_ref.next(), Some('e'));
assert_eq!(leaked_ref.next(), Some('w'));
@@ -550,7 +580,7 @@
let py = gil.python();
let leaked = owner.string_shared(py).leak_immutable();
owner.string_shared(py).borrow_mut().clear();
- assert!(leaked.try_borrow(py).is_err());
+ assert!(unsafe { leaked.try_borrow(py) }.is_err());
}
#[test]
@@ -560,7 +590,7 @@
let leaked = owner.string_shared(py).leak_immutable();
let mut leaked_iter = unsafe { leaked.map(py, |s| s.chars()) };
owner.string_shared(py).borrow_mut().clear();
- assert!(leaked_iter.try_borrow_mut(py).is_err());
+ assert!(unsafe { leaked_iter.try_borrow_mut(py) }.is_err());
}
#[test]
@@ -580,10 +610,10 @@
assert!(owner.string_shared(py).try_borrow_mut().is_ok());
let leaked = owner.string_shared(py).leak_immutable();
{
- let _leaked_ref = leaked.try_borrow(py).unwrap();
+ let _leaked_ref = unsafe { leaked.try_borrow(py) }.unwrap();
assert!(owner.string_shared(py).try_borrow_mut().is_err());
{
- let _leaked_ref2 = leaked.try_borrow(py).unwrap();
+ let _leaked_ref2 = unsafe { leaked.try_borrow(py) }.unwrap();
assert!(owner.string_shared(py).try_borrow_mut().is_err());
}
assert!(owner.string_shared(py).try_borrow_mut().is_err());
@@ -599,7 +629,8 @@
let leaked = owner.string_shared(py).leak_immutable();
let mut leaked_iter = unsafe { leaked.map(py, |s| s.chars()) };
{
- let _leaked_ref = leaked_iter.try_borrow_mut(py).unwrap();
+ let _leaked_ref =
+ unsafe { leaked_iter.try_borrow_mut(py) }.unwrap();
assert!(owner.string_shared(py).try_borrow_mut().is_err());
}
assert!(owner.string_shared(py).try_borrow_mut().is_ok());