Skip to content

Commit 86b9377

Browse files
authored
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.
2 parents 3a0d106 + 329022d commit 86b9377

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 is not a good idea to leak more than a constant number of
1253+
/// references. The `RefCell` can be immutably borrowed again if only a smaller number of leaks
1254+
/// have occurred in total.
1255+
///
1256+
/// This is an associated function that needs to be used as
1257+
/// `Ref::leak(...)`. A method would interfere with methods of the
1258+
/// same name on the contents of a `RefCell` used through `Deref`.
1259+
///
1260+
/// # Examples
1261+
///
1262+
/// ```
1263+
/// #![feature(cell_leak)]
1264+
/// use std::cell::{RefCell, Ref};
1265+
/// let cell = RefCell::new(0);
1266+
///
1267+
/// let value = Ref::leak(cell.borrow());
1268+
/// assert_eq!(*value, 0);
1269+
///
1270+
/// assert!(cell.try_borrow().is_ok());
1271+
/// assert!(cell.try_borrow_mut().is_err());
1272+
/// ```
1273+
#[unstable(feature = "cell_leak", issue = "69099")]
1274+
pub fn leak(orig: Ref<'b, T>) -> &'b T {
1275+
// By forgetting this Ref we ensure that the borrow counter in the RefCell never goes back
1276+
// to UNUSED again. No further mutable references can be created from the original cell.
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 = "69099")]
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)