about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2019-06-07 18:26:15 +0000
committerbors <bors@rust-lang.org>2019-06-07 18:26:15 +0000
commitd132f544f9d74e3cc047ef211e57eae60b78e5c5 (patch)
tree791d2fe11b49b7a14bba265fb1cdb41629e81282
parentc8865d8e195813ade6b84434ac9f8850e7112d1a (diff)
parent5a01b547078e45cc1a96a062334d8571f129ddc2 (diff)
downloadrust-d132f544f9d74e3cc047ef211e57eae60b78e5c5.tar.gz
rust-d132f544f9d74e3cc047ef211e57eae60b78e5c5.zip
Auto merge of #61130 - jonhoo:mem-take, r=SimonSapin
Add std::mem::take as suggested in #61129

This PR implements #61129 by adding `std::mem::take`.

The added function is equivalent to:
```rust
std::mem::replace(dest, Default::default())
```

This particular pattern is fairly common, especially when implementing `Future::poll`, where you often need to yield an owned value in `Async::Ready`. This change allows you to write
```rust
return Async::Ready(std::mem::take(self.result));
```
instead of
```rust
return Async::Ready(std::mem::replace(self.result, Vec::new()));
```

EDIT: Changed name from `take` to `swap_default`.
EDIT: Changed name back to `take`.
-rw-r--r--src/libcore/mem/mod.rs55
1 files changed, 55 insertions, 0 deletions
diff --git a/src/libcore/mem/mod.rs b/src/libcore/mem/mod.rs
index b43ba6ac340..770d1ca8e75 100644
--- a/src/libcore/mem/mod.rs
+++ b/src/libcore/mem/mod.rs
@@ -503,6 +503,61 @@ pub fn swap<T>(x: &mut T, y: &mut T) {
     }
 }
 
+/// Replace `dest` with the default value of `T`, and return the previous `dest` value.
+///
+/// # Examples
+///
+/// A simple example:
+///
+/// ```
+/// use std::mem;
+///
+/// let mut v: Vec<i32> = vec![1, 2];
+///
+/// let old_v = mem::take(&mut v);
+/// assert_eq!(vec![1, 2], old_v);
+/// assert!(v.is_empty());
+/// ```
+///
+/// `take` allows taking ownership of a struct field by replacing it with an "empty" value.
+/// Without `take` you can run into issues like these:
+///
+/// ```compile_fail,E0507
+/// struct Buffer<T> { buf: Vec<T> }
+///
+/// impl<T> Buffer<T> {
+///     fn get_and_reset(&mut self) -> Vec<T> {
+///         // error: cannot move out of dereference of `&mut`-pointer
+///         let buf = self.buf;
+///         self.buf = Vec::new();
+///         buf
+///     }
+/// }
+/// ```
+///
+/// Note that `T` does not necessarily implement [`Clone`], so it can't even clone and reset
+/// `self.buf`. But `take` can be used to disassociate the original value of `self.buf` from
+/// `self`, allowing it to be returned:
+///
+/// ```
+/// # #![allow(dead_code)]
+/// use std::mem;
+///
+/// # struct Buffer<T> { buf: Vec<T> }
+/// impl<T> Buffer<T> {
+///     fn get_and_reset(&mut self) -> Vec<T> {
+///         mem::take(&mut self.buf)
+///     }
+/// }
+/// ```
+///
+/// [`Clone`]: ../../std/clone/trait.Clone.html
+#[inline]
+#[unstable(feature = "mem_take", issue = "61129")]
+pub fn take<T: Default>(dest: &mut T) -> T {
+    replace(dest, T::default())
+}
+
 /// Moves `src` into the referenced `dest`, returning the previous `dest` value.
 ///
 /// Neither value is dropped.