about summary refs log tree commit diff
path: root/library/alloc/src
diff options
context:
space:
mode:
authorRichard Dodd <richard.o.dodd@gmail.com>2021-12-06 11:25:42 +0000
committerRichard Dodd <richard.o.dodd@gmail.com>2022-02-03 09:16:04 +0000
commit0602fb0c6e445f75c598f79ee2f77fe8e2019dd0 (patch)
tree92918904c76d7105012e14b6d18db5cbc08760df /library/alloc/src
parent1be5c8f90912c446ecbdc405cbc4a89f9acd20fd (diff)
downloadrust-0602fb0c6e445f75c598f79ee2f77fe8e2019dd0.tar.gz
rust-0602fb0c6e445f75c598f79ee2f77fe8e2019dd0.zip
impl `Arc::unwrap_or_clone`
The function gets the inner value, cloning only if necessary.
Diffstat (limited to 'library/alloc/src')
-rw-r--r--library/alloc/src/sync.rs35
1 files changed, 35 insertions, 0 deletions
diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs
index 64f21d087da..3d132484b2f 100644
--- a/library/alloc/src/sync.rs
+++ b/library/alloc/src/sync.rs
@@ -1477,6 +1477,41 @@ impl<T: Clone> Arc<T> {
         // either unique to begin with, or became one upon cloning the contents.
         unsafe { Self::get_mut_unchecked(this) }
     }
+
+    /// If we have the only reference to `T` then unwrap it. Otherwise, clone `T` and return the
+    /// clone.
+    ///
+    /// Assuming `arc_t` is of type `Arc<T>`, this function is functionally equivalent to
+    /// `(*arc_t).clone()`, but will avoid cloning the inner value where possible.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(arc_unwrap_or_clone)]
+    /// # use std::{ptr, sync::Arc};
+    /// let inner = String::from("test");
+    /// let ptr = inner.as_ptr();
+    ///
+    /// let arc = Arc::new(inner);
+    /// let inner = Arc::unwrap_or_clone(arc);
+    /// // The inner value was not cloned
+    /// assert!(ptr::eq(ptr, inner.as_ptr()));
+    ///
+    /// let arc = Arc::new(inner);
+    /// let arc2 = arc.clone();
+    /// let inner = Arc::unwrap_or_clone(arc);
+    /// // Because there were 2 references, we had to clone the inner value.
+    /// assert!(!ptr::eq(ptr, inner.as_ptr()));
+    /// // `arc2` is the last reference, so when we unwrap it we get back
+    /// // the original `String`.
+    /// let inner = Arc::unwrap_or_clone(arc2);
+    /// assert!(ptr::eq(ptr, inner.as_ptr()));
+    /// ```
+    #[inline]
+    #[unstable(feature = "arc_unwrap_or_clone", issue = "none")]
+    pub fn unwrap_or_clone(this: Self) -> T {
+        Arc::try_unwrap(this).unwrap_or_else(|arc| (*arc).clone())
+    }
 }
 
 impl<T: ?Sized> Arc<T> {