Skip to content

Commit 5de2a24

Browse files
committed
Auto merge of #39287 - wesleywiser:move_cell, r=aturon
Extend Cell to work with non-Copy types I'm not sure that I did this right but all of the tests pass. I also had to move the `new()` function so that `Cell`s with non-`Copy` `T`s could be created. That wasn't in the RFC but I assume it needed to be done?
2 parents 7f294e4 + 8b947a3 commit 5de2a24

File tree

4 files changed

+147
-46
lines changed

4 files changed

+147
-46
lines changed

src/doc/book/choosing-your-guarantees.md

+7-5
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,8 @@ These types are _generally_ found in struct fields, but they may be found elsewh
118118

119119
## `Cell<T>`
120120

121-
[`Cell<T>`][cell] is a type that provides zero-cost interior mutability, but only for `Copy` types.
121+
[`Cell<T>`][cell] is a type that provides zero-cost interior mutability by moving data in and
122+
out of the cell.
122123
Since the compiler knows that all the data owned by the contained value is on the stack, there's
123124
no worry of leaking any data behind references (or worse!) by simply replacing the data.
124125

@@ -160,24 +161,25 @@ This relaxes the &ldquo;no aliasing with mutability&rdquo; restriction in places
160161
unnecessary. However, this also relaxes the guarantees that the restriction provides; so if your
161162
invariants depend on data stored within `Cell`, you should be careful.
162163

163-
This is useful for mutating primitives and other `Copy` types when there is no easy way of
164+
This is useful for mutating primitives and other types when there is no easy way of
164165
doing it in line with the static rules of `&` and `&mut`.
165166

166167
`Cell` does not let you obtain interior references to the data, which makes it safe to freely
167168
mutate.
168169

169170
#### Cost
170171

171-
There is no runtime cost to using `Cell<T>`, however if you are using it to wrap larger (`Copy`)
172+
There is no runtime cost to using `Cell<T>`, however if you are using it to wrap larger
172173
structs, it might be worthwhile to instead wrap individual fields in `Cell<T>` since each write is
173174
otherwise a full copy of the struct.
174175

175176

176177
## `RefCell<T>`
177178

178-
[`RefCell<T>`][refcell] also provides interior mutability, but isn't restricted to `Copy` types.
179+
[`RefCell<T>`][refcell] also provides interior mutability, but doesn't move data in and out of the
180+
cell.
179181

180-
Instead, it has a runtime cost. `RefCell<T>` enforces the read-write lock pattern at runtime (it's
182+
However, it has a runtime cost. `RefCell<T>` enforces the read-write lock pattern at runtime (it's
181183
like a single-threaded mutex), unlike `&T`/`&mut T` which do so at compile time. This is done by the
182184
`borrow()` and `borrow_mut()` functions, which modify an internal reference count and return smart
183185
pointers which can be dereferenced immutably and mutably respectively. The refcount is restored when

src/libcore/cell.rs

+108-41
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,18 @@
1515
//! references. We say that `Cell<T>` and `RefCell<T>` provide 'interior mutability', in contrast
1616
//! with typical Rust types that exhibit 'inherited mutability'.
1717
//!
18-
//! Cell types come in two flavors: `Cell<T>` and `RefCell<T>`. `Cell<T>` provides `get` and `set`
19-
//! methods that change the interior value with a single method call. `Cell<T>` though is only
20-
//! compatible with types that implement `Copy`. For other types, one must use the `RefCell<T>`
21-
//! type, acquiring a write lock before mutating.
18+
//! Cell types come in two flavors: `Cell<T>` and `RefCell<T>`. `Cell<T>` implements interior
19+
//! mutability by moving values in and out of the `Cell<T>`. To use references instead of values,
20+
//! one must use the `RefCell<T>` type, acquiring a write lock before mutating. `Cell<T>` provides
21+
//! methods to retrieve and change the current interior value:
22+
//!
23+
//! - For types that implement `Copy`, the `get` method retrieves the current interior value.
24+
//! - For types that implement `Default`, the `take` method replaces the current interior value
25+
//! with `Default::default()` and returns the replaced value.
26+
//! - For all types, the `replace` method replaces the current interior value and returns the
27+
//! replaced value and the `into_inner` method consumes the `Cell<T>` and returns the interior
28+
//! value. Additionally, the `set` method replaces the interior value, dropping the replaced
29+
//! value.
2230
//!
2331
//! `RefCell<T>` uses Rust's lifetimes to implement 'dynamic borrowing', a process whereby one can
2432
//! claim temporary, exclusive, mutable access to the inner value. Borrows for `RefCell<T>`s are
@@ -176,9 +184,10 @@
176184
use cmp::Ordering;
177185
use fmt::{self, Debug, Display};
178186
use marker::Unsize;
187+
use mem;
179188
use ops::{Deref, DerefMut, CoerceUnsized};
180189

181-
/// A mutable memory location that admits only `Copy` data.
190+
/// A mutable memory location.
182191
///
183192
/// See the [module-level documentation](index.html) for more.
184193
#[stable(feature = "rust1", since = "1.0.0")]
@@ -187,23 +196,6 @@ pub struct Cell<T> {
187196
}
188197

189198
impl<T:Copy> Cell<T> {
190-
/// Creates a new `Cell` containing the given value.
191-
///
192-
/// # Examples
193-
///
194-
/// ```
195-
/// use std::cell::Cell;
196-
///
197-
/// let c = Cell::new(5);
198-
/// ```
199-
#[stable(feature = "rust1", since = "1.0.0")]
200-
#[inline]
201-
pub const fn new(value: T) -> Cell<T> {
202-
Cell {
203-
value: UnsafeCell::new(value),
204-
}
205-
}
206-
207199
/// Returns a copy of the contained value.
208200
///
209201
/// # Examples
@@ -221,25 +213,6 @@ impl<T:Copy> Cell<T> {
221213
unsafe{ *self.value.get() }
222214
}
223215

224-
/// Sets the contained value.
225-
///
226-
/// # Examples
227-
///
228-
/// ```
229-
/// use std::cell::Cell;
230-
///
231-
/// let c = Cell::new(5);
232-
///
233-
/// c.set(10);
234-
/// ```
235-
#[inline]
236-
#[stable(feature = "rust1", since = "1.0.0")]
237-
pub fn set(&self, value: T) {
238-
unsafe {
239-
*self.value.get() = value;
240-
}
241-
}
242-
243216
/// Returns a reference to the underlying `UnsafeCell`.
244217
///
245218
/// # Examples
@@ -378,6 +351,100 @@ impl<T: Copy> From<T> for Cell<T> {
378351
}
379352
}
380353

354+
impl<T> Cell<T> {
355+
/// Creates a new `Cell` containing the given value.
356+
///
357+
/// # Examples
358+
///
359+
/// ```
360+
/// use std::cell::Cell;
361+
///
362+
/// let c = Cell::new(5);
363+
/// ```
364+
#[stable(feature = "rust1", since = "1.0.0")]
365+
#[inline]
366+
pub const fn new(value: T) -> Cell<T> {
367+
Cell {
368+
value: UnsafeCell::new(value),
369+
}
370+
}
371+
372+
/// Sets the contained value.
373+
///
374+
/// # Examples
375+
///
376+
/// ```
377+
/// use std::cell::Cell;
378+
///
379+
/// let c = Cell::new(5);
380+
///
381+
/// c.set(10);
382+
/// ```
383+
#[inline]
384+
#[stable(feature = "rust1", since = "1.0.0")]
385+
pub fn set(&self, val: T) {
386+
let old = self.replace(val);
387+
drop(old);
388+
}
389+
390+
/// Replaces the contained value.
391+
///
392+
/// # Examples
393+
///
394+
/// ```
395+
/// #![feature(move_cell)]
396+
/// use std::cell::Cell;
397+
///
398+
/// let c = Cell::new(5);
399+
/// let old = c.replace(10);
400+
///
401+
/// assert_eq!(5, old);
402+
/// ```
403+
#[unstable(feature = "move_cell", issue = "39264")]
404+
pub fn replace(&self, val: T) -> T {
405+
mem::replace(unsafe { &mut *self.value.get() }, val)
406+
}
407+
408+
/// Unwraps the value.
409+
///
410+
/// # Examples
411+
///
412+
/// ```
413+
/// #![feature(move_cell)]
414+
/// use std::cell::Cell;
415+
///
416+
/// let c = Cell::new(5);
417+
/// let five = c.into_inner();
418+
///
419+
/// assert_eq!(five, 5);
420+
/// ```
421+
#[unstable(feature = "move_cell", issue = "39264")]
422+
pub fn into_inner(self) -> T {
423+
unsafe { self.value.into_inner() }
424+
}
425+
}
426+
427+
impl<T: Default> Cell<T> {
428+
/// Takes the value of the cell, leaving `Default::default()` in its place.
429+
///
430+
/// # Examples
431+
///
432+
/// ```
433+
/// #![feature(move_cell)]
434+
/// use std::cell::Cell;
435+
///
436+
/// let c = Cell::new(5);
437+
/// let five = c.take();
438+
///
439+
/// assert_eq!(five, 5);
440+
/// assert_eq!(c.into_inner(), 0);
441+
/// ```
442+
#[unstable(feature = "move_cell", issue = "39264")]
443+
pub fn take(&self) -> T {
444+
self.replace(Default::default())
445+
}
446+
}
447+
381448
#[unstable(feature = "coerce_unsized", issue = "27732")]
382449
impl<T: CoerceUnsized<U>, U> CoerceUnsized<Cell<U>> for Cell<T> {}
383450

src/libcoretest/cell.rs

+31
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,37 @@ fn cell_default() {
209209
assert_eq!(0, cell.get());
210210
}
211211

212+
#[test]
213+
fn cell_set() {
214+
let cell = Cell::new(10);
215+
cell.set(20);
216+
assert_eq!(20, cell.get());
217+
218+
let cell = Cell::new("Hello".to_owned());
219+
cell.set("World".to_owned());
220+
assert_eq!("World".to_owned(), cell.into_inner());
221+
}
222+
223+
#[test]
224+
fn cell_replace() {
225+
let cell = Cell::new(10);
226+
assert_eq!(10, cell.replace(20));
227+
assert_eq!(20, cell.get());
228+
229+
let cell = Cell::new("Hello".to_owned());
230+
assert_eq!("Hello".to_owned(), cell.replace("World".to_owned()));
231+
assert_eq!("World".to_owned(), cell.into_inner());
232+
}
233+
234+
#[test]
235+
fn cell_into_inner() {
236+
let cell = Cell::new(10);
237+
assert_eq!(10, cell.into_inner());
238+
239+
let cell = Cell::new("Hello world".to_owned());
240+
assert_eq!("Hello world".to_owned(), cell.into_inner());
241+
}
242+
212243
#[test]
213244
fn refcell_default() {
214245
let cell: RefCell<u64> = Default::default();

src/libcoretest/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#![feature(unique)]
3434
#![feature(ordering_chaining)]
3535
#![feature(ptr_unaligned)]
36+
#![feature(move_cell)]
3637

3738
extern crate core;
3839
extern crate test;

0 commit comments

Comments
 (0)