Rollup merge of #68712 - HeroicKatora:finalize-ref-cell, r=dtolnay
Add methods to 'leak' RefCell borrows as references with the lifetime of the original reference
Usually, references to the interior are only created by the `Deref` and
`DerefMut` impl of the guards `Ref` and `RefMut`. Note that `RefCell`
already has to cope with leaks of such guards which, when it occurs,
effectively makes it impossible to ever acquire a mutable guard or any
guard for `Ref` and `RefMut` respectively. It is already safe to use
this to create a reference to the inner of the ref cell that lives as
long as the reference to the `RefCell` itself, e.g.
```rust
fn leak(r: &RefCell<usize>) -> Option<&usize> {
let guard = r.try_borrow().ok()?;
let leaked = Box::leak(Box::new(guard));
Some(&*leaked)
}
```
The newly added methods allow the same reference conversion without an
indirection over a leaked allocation. It's placed on the `Ref`/`RefMut` to
compose with both borrow and try_borrow directly.
This commit is contained in:
commit
86b9377dd6
1 changed files with 63 additions and 0 deletions
|
|
@ -1245,6 +1245,38 @@ impl<'b, T: ?Sized> Ref<'b, T> {
|
|||
let borrow = orig.borrow.clone();
|
||||
(Ref { value: a, borrow }, Ref { value: b, borrow: orig.borrow })
|
||||
}
|
||||
|
||||
/// Convert into a reference to the underlying data.
|
||||
///
|
||||
/// The underlying `RefCell` can never be mutably borrowed from again and will always appear
|
||||
/// already immutably borrowed. It is not a good idea to leak more than a constant number of
|
||||
/// references. The `RefCell` can be immutably borrowed again if only a smaller number of leaks
|
||||
/// have occurred in total.
|
||||
///
|
||||
/// This is an associated function that needs to be used as
|
||||
/// `Ref::leak(...)`. A method would interfere with methods of the
|
||||
/// same name on the contents of a `RefCell` used through `Deref`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(cell_leak)]
|
||||
/// use std::cell::{RefCell, Ref};
|
||||
/// let cell = RefCell::new(0);
|
||||
///
|
||||
/// let value = Ref::leak(cell.borrow());
|
||||
/// assert_eq!(*value, 0);
|
||||
///
|
||||
/// assert!(cell.try_borrow().is_ok());
|
||||
/// assert!(cell.try_borrow_mut().is_err());
|
||||
/// ```
|
||||
#[unstable(feature = "cell_leak", issue = "69099")]
|
||||
pub fn leak(orig: Ref<'b, T>) -> &'b T {
|
||||
// By forgetting this Ref we ensure that the borrow counter in the RefCell never goes back
|
||||
// to UNUSED again. No further mutable references can be created from the original cell.
|
||||
mem::forget(orig.borrow);
|
||||
orig.value
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "coerce_unsized", issue = "27732")]
|
||||
|
|
@ -1330,6 +1362,37 @@ impl<'b, T: ?Sized> RefMut<'b, T> {
|
|||
let borrow = orig.borrow.clone();
|
||||
(RefMut { value: a, borrow }, RefMut { value: b, borrow: orig.borrow })
|
||||
}
|
||||
|
||||
/// Convert into a mutable reference to the underlying data.
|
||||
///
|
||||
/// The underlying `RefCell` can not be borrowed from again and will always appear already
|
||||
/// mutably borrowed, making the returned reference the only to the interior.
|
||||
///
|
||||
/// This is an associated function that needs to be used as
|
||||
/// `RefMut::leak(...)`. A method would interfere with methods of the
|
||||
/// same name on the contents of a `RefCell` used through `Deref`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(cell_leak)]
|
||||
/// use std::cell::{RefCell, RefMut};
|
||||
/// let cell = RefCell::new(0);
|
||||
///
|
||||
/// let value = RefMut::leak(cell.borrow_mut());
|
||||
/// assert_eq!(*value, 0);
|
||||
/// *value = 1;
|
||||
///
|
||||
/// assert!(cell.try_borrow_mut().is_err());
|
||||
/// ```
|
||||
#[unstable(feature = "cell_leak", issue = "69099")]
|
||||
pub fn leak(orig: RefMut<'b, T>) -> &'b mut T {
|
||||
// By forgetting this BorrowRefMut we ensure that the borrow counter in the RefCell never
|
||||
// goes back to UNUSED again. No further references can be created from the original cell,
|
||||
// making the current borrow the only reference for the remaining lifetime.
|
||||
mem::forget(orig.borrow);
|
||||
orig.value
|
||||
}
|
||||
}
|
||||
|
||||
struct BorrowRefMut<'b> {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue