Skip to content

Commit 14999dd

Browse files
committed
Add methods to leak RefCell borrows to references
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 and composing with both borrow and try_borrow without additional method combinations.
1 parent 698fcd3 commit 14999dd

File tree

1 file changed

+63
-0
lines changed

1 file changed

+63
-0
lines changed

src/libcore/cell.rs

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1245,6 +1245,38 @@ impl<'b, T: ?Sized> Ref<'b, T> {
12451245
let borrow = orig.borrow.clone();
12461246
(Ref { value: a, borrow }, Ref { value: b, borrow: orig.borrow })
12471247
}
1248+
1249+
/// Convert into a reference to the underlying data.
1250+
///
1251+
/// The underlying `RefCell` can never be mutably borrowed from again and will always appear
1252+
/// already immutably borrowed. It can still be immutably borrowed until more than `isize::MAX`
1253+
/// `Ref`s of this `RefCell` have been leaked, through this function or another leak, in total.
1254+
///
1255+
/// This is an associated function that needs to be used as
1256+
/// `Ref::leak(...)`. A method would interfere with methods of the
1257+
/// same name on the contents of a `RefCell` used through `Deref`.
1258+
///
1259+
/// # Examples
1260+
///
1261+
/// ```
1262+
/// #![feature(cell_leak)]
1263+
/// use std::cell::{RefCell, Ref};
1264+
/// let cell = RefCell::new(0);
1265+
///
1266+
/// let value = Ref::leak(cell.borrow());
1267+
/// assert_eq!(*value, 0);
1268+
///
1269+
/// assert!(cell.try_borrow().is_ok());
1270+
/// assert!(cell.try_borrow_mut().is_err());
1271+
/// ```
1272+
#[unstable(feature = "cell_leak", issue = "none")]
1273+
pub fn leak(orig: Ref<'b, T>) -> &'b T {
1274+
// By forgetting this BorrowRefMut we ensure that the borrow counter in the RefCell never
1275+
// goes back to UNUSED again. No further references can be created from the original cell,
1276+
// making the current borrow the only reference for the remaining lifetime.
1277+
mem::forget(orig.borrow);
1278+
orig.value
1279+
}
12481280
}
12491281

12501282
#[unstable(feature = "coerce_unsized", issue = "27732")]
@@ -1330,6 +1362,37 @@ impl<'b, T: ?Sized> RefMut<'b, T> {
13301362
let borrow = orig.borrow.clone();
13311363
(RefMut { value: a, borrow }, RefMut { value: b, borrow: orig.borrow })
13321364
}
1365+
1366+
/// Convert into a mutable reference to the underlying data.
1367+
///
1368+
/// The underlying `RefCell` can not be borrowed from again and will always appear already
1369+
/// mutably borrowed, making the returned reference the only to the interior.
1370+
///
1371+
/// This is an associated function that needs to be used as
1372+
/// `RefMut::leak(...)`. A method would interfere with methods of the
1373+
/// same name on the contents of a `RefCell` used through `Deref`.
1374+
///
1375+
/// # Examples
1376+
///
1377+
/// ```
1378+
/// #![feature(cell_leak)]
1379+
/// use std::cell::{RefCell, RefMut};
1380+
/// let cell = RefCell::new(0);
1381+
///
1382+
/// let value = RefMut::leak(cell.borrow_mut());
1383+
/// assert_eq!(*value, 0);
1384+
/// *value = 1;
1385+
///
1386+
/// assert!(cell.try_borrow_mut().is_err());
1387+
/// ```
1388+
#[unstable(feature = "cell_leak", issue = "none")]
1389+
pub fn leak(orig: RefMut<'b, T>) -> &'b mut T {
1390+
// By forgetting this BorrowRefMut we ensure that the borrow counter in the RefCell never
1391+
// goes back to UNUSED again. No further references can be created from the original cell,
1392+
// making the current borrow the only reference for the remaining lifetime.
1393+
mem::forget(orig.borrow);
1394+
orig.value
1395+
}
13331396
}
13341397

13351398
struct BorrowRefMut<'b> {

0 commit comments

Comments
 (0)