about summary refs log tree commit diff
path: root/src/libcore
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2017-02-03 03:23:35 +0000
committerbors <bors@rust-lang.org>2017-02-03 03:23:35 +0000
commit5de2a24b2ebfa42db8eadab911a107b4a67fabdb (patch)
tree801d474d204637340ba30ed2521d68f2c9abdf63 /src/libcore
parent7f294e4c186b461ee8fc28c75d4216822a535d7a (diff)
parent8b947a37c8bf396cf80c3790f68253c97d435250 (diff)
downloadrust-5de2a24b2ebfa42db8eadab911a107b4a67fabdb.tar.gz
rust-5de2a24b2ebfa42db8eadab911a107b4a67fabdb.zip
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?
Diffstat (limited to 'src/libcore')
-rw-r--r--src/libcore/cell.rs149
1 files changed, 108 insertions, 41 deletions
diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs
index c3f862e7c54..ab44342ebf0 100644
--- a/src/libcore/cell.rs
+++ b/src/libcore/cell.rs
@@ -15,10 +15,18 @@
 //! references. We say that `Cell<T>` and `RefCell<T>` provide 'interior mutability', in contrast
 //! with typical Rust types that exhibit 'inherited mutability'.
 //!
-//! Cell types come in two flavors: `Cell<T>` and `RefCell<T>`. `Cell<T>` provides `get` and `set`
-//! methods that change the interior value with a single method call. `Cell<T>` though is only
-//! compatible with types that implement `Copy`. For other types, one must use the `RefCell<T>`
-//! type, acquiring a write lock before mutating.
+//! Cell types come in two flavors: `Cell<T>` and `RefCell<T>`. `Cell<T>` implements interior
+//! mutability by moving values in and out of the `Cell<T>`. To use references instead of values,
+//! one must use the `RefCell<T>` type, acquiring a write lock before mutating. `Cell<T>` provides
+//! methods to retrieve and change the current interior value:
+//!
+//!  - For types that implement `Copy`, the `get` method retrieves the current interior value.
+//!  - For types that implement `Default`, the `take` method replaces the current interior value
+//!    with `Default::default()` and returns the replaced value.
+//!  - For all types, the `replace` method replaces the current interior value and returns the
+//!    replaced value and the `into_inner` method consumes the `Cell<T>` and returns the interior
+//!    value. Additionally, the `set` method replaces the interior value, dropping the replaced
+//!    value.
 //!
 //! `RefCell<T>` uses Rust's lifetimes to implement 'dynamic borrowing', a process whereby one can
 //! claim temporary, exclusive, mutable access to the inner value. Borrows for `RefCell<T>`s are
@@ -176,9 +184,10 @@
 use cmp::Ordering;
 use fmt::{self, Debug, Display};
 use marker::Unsize;
+use mem;
 use ops::{Deref, DerefMut, CoerceUnsized};
 
-/// A mutable memory location that admits only `Copy` data.
+/// A mutable memory location.
 ///
 /// See the [module-level documentation](index.html) for more.
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -187,23 +196,6 @@ pub struct Cell<T> {
 }
 
 impl<T:Copy> Cell<T> {
-    /// Creates a new `Cell` containing the given value.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::cell::Cell;
-    ///
-    /// let c = Cell::new(5);
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    #[inline]
-    pub const fn new(value: T) -> Cell<T> {
-        Cell {
-            value: UnsafeCell::new(value),
-        }
-    }
-
     /// Returns a copy of the contained value.
     ///
     /// # Examples
@@ -221,25 +213,6 @@ impl<T:Copy> Cell<T> {
         unsafe{ *self.value.get() }
     }
 
-    /// Sets the contained value.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::cell::Cell;
-    ///
-    /// let c = Cell::new(5);
-    ///
-    /// c.set(10);
-    /// ```
-    #[inline]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn set(&self, value: T) {
-        unsafe {
-            *self.value.get() = value;
-        }
-    }
-
     /// Returns a reference to the underlying `UnsafeCell`.
     ///
     /// # Examples
@@ -378,6 +351,100 @@ impl<T: Copy> From<T> for Cell<T> {
     }
 }
 
+impl<T> Cell<T> {
+    /// Creates a new `Cell` containing the given value.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::cell::Cell;
+    ///
+    /// let c = Cell::new(5);
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    #[inline]
+    pub const fn new(value: T) -> Cell<T> {
+        Cell {
+            value: UnsafeCell::new(value),
+        }
+    }
+
+    /// Sets the contained value.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::cell::Cell;
+    ///
+    /// let c = Cell::new(5);
+    ///
+    /// c.set(10);
+    /// ```
+    #[inline]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn set(&self, val: T) {
+        let old = self.replace(val);
+        drop(old);
+    }
+
+    /// Replaces the contained value.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(move_cell)]
+    /// use std::cell::Cell;
+    ///
+    /// let c = Cell::new(5);
+    /// let old = c.replace(10);
+    ///
+    /// assert_eq!(5, old);
+    /// ```
+    #[unstable(feature = "move_cell", issue = "39264")]
+    pub fn replace(&self, val: T) -> T {
+        mem::replace(unsafe { &mut *self.value.get() }, val)
+    }
+
+    /// Unwraps the value.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(move_cell)]
+    /// use std::cell::Cell;
+    ///
+    /// let c = Cell::new(5);
+    /// let five = c.into_inner();
+    ///
+    /// assert_eq!(five, 5);
+    /// ```
+    #[unstable(feature = "move_cell", issue = "39264")]
+    pub fn into_inner(self) -> T {
+        unsafe { self.value.into_inner() }
+    }
+}
+
+impl<T: Default> Cell<T> {
+    /// Takes the value of the cell, leaving `Default::default()` in its place.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(move_cell)]
+    /// use std::cell::Cell;
+    ///
+    /// let c = Cell::new(5);
+    /// let five = c.take();
+    ///
+    /// assert_eq!(five, 5);
+    /// assert_eq!(c.into_inner(), 0);
+    /// ```
+    #[unstable(feature = "move_cell", issue = "39264")]
+    pub fn take(&self) -> T {
+        self.replace(Default::default())
+    }
+}
+
 #[unstable(feature = "coerce_unsized", issue = "27732")]
 impl<T: CoerceUnsized<U>, U> CoerceUnsized<Cell<U>> for Cell<T> {}