diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index 414262fcf5ab1..67b6c79b7e32f 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -874,6 +874,38 @@ pub const fn replace(dest: &mut T, src: T) -> T { } } +/// Replaces the value in `dest` by the value returned by `f`. +/// +/// `f` receives the current referenced value of `dest` as its argument. +/// +/// * If you want to replace the values of two variables, see [`swap`]. +/// * If you want to replace with a default value, see [`take`]. +/// * If you want replace without the function, see [`replace`]. +/// +/// # Examples +/// +/// A simple example: +/// +/// ``` +/// use std::mem; +/// +/// let mut v: Vec = vec![1, 2]; +/// +/// mem::replace(&mut v, |mut v| { v.push(3); v }); +/// assert_eq!(vec![1, 2, 3], v); +/// ``` +#[inline] +#[unstable(feature = "mem_reshape", issue = "130848")] +pub fn reshape(dest: &mut T, f: impl FnOnce(T) -> T) { + // SAFETY: We read from `dest` but directly write to 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, f(result)); + } +} + /// Disposes of a value. /// /// This does so by calling the argument's implementation of [`Drop`][drop]. diff --git a/library/core/tests/mem.rs b/library/core/tests/mem.rs index f3b4387f6a898..5e2bdfda3700e 100644 --- a/library/core/tests/mem.rs +++ b/library/core/tests/mem.rs @@ -110,6 +110,17 @@ fn test_replace() { assert!(y.is_some()); } +#[test] +fn test_reshape() { + let mut x = Some("test".to_string()); + reshape(&mut x, |_| None); + assert!(x.is_none()); + + let mut y = "test".to_string(); + reshape(&mut y, |y| y + "test"); + assert_eq!(y, "testtest"); +} + #[test] fn test_transmute_copy() { assert_eq!(1, unsafe { transmute_copy(&1) });