Skip to content

Commit a39a2e7

Browse files
committed
Add 'take', 'replace', 'replace_with' from std::cell::RefCell
This changeset also clarifies the language around mutable borrows. The message accountable_refcell paniced with when trying to take a mutable borrow was not entirely accurate ("RefCell is already immutably borrowed"), as panics can also occur when trying to mutably borrow a RefCell that is already mutably borrowed. Technically, at the time of this writing, the `take` method is not in stable Rust, but will be in the next version (1.49) rust-lang/rust#71395 A rust-toolchain file has been added codifying the expectation that this crate targets stable Rust.
1 parent be1ad50 commit a39a2e7

File tree

2 files changed

+84
-5
lines changed

2 files changed

+84
-5
lines changed

rust-toolchain

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
stable

src/lib.rs

Lines changed: 83 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use backtrace::Backtrace;
88
use std::cell::{
99
BorrowError, BorrowMutError, Ref as StdRef, RefCell as StdRefCell, RefMut as StdRefMut,
1010
};
11-
use std::env;
11+
use std::{env, mem};
1212
use std::fmt::{Debug, Display, Error, Formatter};
1313
use std::ops::{Deref, DerefMut};
1414

@@ -203,8 +203,8 @@ impl<T: ?Sized> RefCell<T> {
203203
})
204204
}
205205

206-
/// Borrow the value stored in this cell mutably. Panics if any outstanding immutable
207-
/// borrows of the same cell exist.
206+
/// Borrow the value stored in this cell mutably. Panics if there are any other outstanding
207+
/// borrows of this cell (mutable borrows are unique, i.e. there can only be one).
208208
pub fn borrow_mut(&self) -> RefMut<T> {
209209
if let Ok(r) = self.inner.try_borrow_mut() {
210210
let id = self.borrows.borrow_mut().record();
@@ -225,7 +225,7 @@ impl<T: ?Sized> RefCell<T> {
225225
}
226226
}
227227
}
228-
panic!("RefCell is already immutably borrowed.");
228+
panic!("RefCell is already borrowed.");
229229
}
230230
}
231231

@@ -251,6 +251,20 @@ impl<T: ?Sized> RefCell<T> {
251251
}
252252
}
253253

254+
impl <T> RefCell<T> {
255+
/// Corresponds to https://doc.rust-lang.org/std/cell/struct.RefCell.html#method.replace.
256+
pub fn replace(&self, t: T) -> T {
257+
mem::replace(&mut *self.borrow_mut(), t)
258+
}
259+
260+
/// Corresponds to https://doc.rust-lang.org/std/cell/struct.RefCell.html#method.replace_with.
261+
pub fn replace_with<F: FnOnce(&mut T) -> T>(&self, f: F) -> T {
262+
let mut_borrow = &mut *self.borrow_mut();
263+
let replacement = f(mut_borrow);
264+
mem::replace(mut_borrow, replacement)
265+
}
266+
}
267+
254268
/// Print a backtrace without any frames from the backtrace library.
255269
fn print_filtered_backtrace(backtrace: &Backtrace) {
256270
let mut idx = 1;
@@ -284,6 +298,13 @@ impl<T: Clone> Clone for RefCell<T> {
284298
}
285299
}
286300

301+
impl <T: Default> RefCell<T> {
302+
/// Corresponds to https://doc.rust-lang.org/std/cell/struct.RefCell.html#method.take.
303+
pub fn take(&self) -> T {
304+
self.replace(Default::default())
305+
}
306+
}
307+
287308
impl<T: Default> Default for RefCell<T> {
288309
fn default() -> RefCell<T> {
289310
RefCell::new(Default::default())
@@ -319,7 +340,7 @@ mod tests {
319340
use super::{Ref, RefCell};
320341

321342
#[test]
322-
#[should_panic(expected = "RefCell is already immutably borrowed")]
343+
#[should_panic(expected = "RefCell is already borrowed")]
323344
fn cannot_borrow_mutably() {
324345
let c = RefCell::new(5);
325346
let _b = c.borrow();
@@ -358,4 +379,61 @@ mod tests {
358379
};
359380
let _b2 = c.borrow_mut();
360381
}
382+
383+
#[test]
384+
#[should_panic(expected = "RefCell is already borrowed")]
385+
fn cannot_take_borrowed_refcell() {
386+
let c = RefCell::new(5);
387+
let _b = c.borrow();
388+
c.take();
389+
}
390+
391+
#[test]
392+
#[should_panic(expected = "RefCell is already borrowed")]
393+
fn cannot_take_mut_borrowed_refcell() {
394+
let c = RefCell::new(5);
395+
let _b = c.borrow_mut();
396+
c.take();
397+
}
398+
399+
#[test]
400+
#[should_panic(expected = "RefCell is already borrowed")]
401+
fn cannot_replace_borrowed_refcell() {
402+
let c = RefCell::new(5);
403+
let _b = c.borrow();
404+
c.replace(12);
405+
}
406+
407+
#[test]
408+
#[should_panic(expected = "RefCell is already borrowed")]
409+
fn cannot_replace_mut_borrowed_refcell() {
410+
let c = RefCell::new(5);
411+
let _b = c.borrow_mut();
412+
c.replace(12);
413+
}
414+
415+
416+
#[test]
417+
#[should_panic(expected = "RefCell is already borrowed")]
418+
fn cannot_replace_with_borrowed_refcell() {
419+
let c = RefCell::new(5);
420+
let _b = c.borrow();
421+
c.replace_with(|&mut old_val| { old_val + 1 });
422+
}
423+
424+
#[test]
425+
#[should_panic(expected = "RefCell is already borrowed")]
426+
fn cannot_replace_with_mut_borrowed_refcell() {
427+
let c = RefCell::new(5);
428+
let _b = c.borrow_mut();
429+
c.replace_with(|&mut old_val| { old_val + 1 });
430+
}
431+
432+
#[test]
433+
#[should_panic(expected = "RefCell is already borrowed")]
434+
fn test() {
435+
let c = RefCell::new(5);
436+
let _b = c.borrow_mut();
437+
let _b2 = c.borrow_mut();
438+
}
361439
}

0 commit comments

Comments
 (0)