about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2021-03-12 23:27:23 +0000
committerbors <bors@rust-lang.org>2021-03-12 23:27:23 +0000
commit46a934a1dc789b9441e5fb5cd043287baddcc5c7 (patch)
treee05f0ddb8a326faa2f523509471bf1564fb59988
parentb3e19a221e63dcffdef87e12eadf1f36a8b90295 (diff)
parentbf27819f37fb7cbe5fb67972d874ab285b741538 (diff)
downloadrust-46a934a1dc789b9441e5fb5cd043287baddcc5c7.tar.gz
rust-46a934a1dc789b9441e5fb5cd043287baddcc5c7.zip
Auto merge of #83022 - m-ou-se:mem-replace-no-swap, r=nagisa
Don't implement mem::replace with mem::swap.

`swap` is a complicated operation, so this changes the implementation of `replace` to use `read` and `write` instead.

See https://github.com/rust-lang/rust/pull/83019.

I wrote there:

> Implementing the simpler operation (replace) with the much more complicated operation (swap) doesn't make a whole lot of sense. `replace` is just read+write, and the primitive for moving out of a `&mut`. `swap` is for doing that to *two* `&mut` at the same time, which is both more niche and more complicated (as shown by `swap_nonoverlapping_bytes`).

This could be especially interesting for `Option<VeryLargeStruct>::take()`, since swapping such a large structure with `swap_nonoverlapping_bytes` is going to be much less efficient than `ptr::write()`'ing a `None`.

But also for small values where `swap` just reads/writes using temporary variable, this makes a `replace` or `take` operation simpler:
![image](https://user-images.githubusercontent.com/783247/110839393-c7e6bd80-82a3-11eb-97b7-28acb14deffd.png)
-rw-r--r--library/core/src/mem/mod.rs12
1 files changed, 9 insertions, 3 deletions
diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs
index afce6e55b8f..84edbd30a5d 100644
--- a/library/core/src/mem/mod.rs
+++ b/library/core/src/mem/mod.rs
@@ -812,9 +812,15 @@ pub fn take<T: Default>(dest: &mut T) -> T {
 #[inline]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[must_use = "if you don't need the old value, you can just assign the new value directly"]
-pub fn replace<T>(dest: &mut T, mut src: T) -> T {
-    swap(dest, &mut src);
-    src
+pub fn replace<T>(dest: &mut T, src: T) -> T {
+    // SAFETY: We read from `dest` but directly write `src` into it afterwards,
+    // such that the old value is not duplicated. Nothing is dropped and
+    // nothing here can panic.
+    unsafe {
+        let result = ptr::read(dest);
+        ptr::write(dest, src);
+        result
+    }
 }
 
 /// Disposes of a value.