diff options
| author | Matthias Krüger <matthias.krueger@famsik.de> | 2022-02-04 18:42:13 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-02-04 18:42:13 +0100 |
| commit | 6f03bd09ff6ef6402b68b32485f0d25e7f6c0c01 (patch) | |
| tree | d63552075a2c9c2962cfea48482bf25911a20696 | |
| parent | 2fe9a32ed209b93ddd08cab174dfffefc1409a9c (diff) | |
| parent | f5e6d16d000e0aa73833de909de44e8dcc8589ed (diff) | |
| download | rust-6f03bd09ff6ef6402b68b32485f0d25e7f6c0c01.tar.gz rust-6f03bd09ff6ef6402b68b32485f0d25e7f6c0c01.zip | |
Rollup merge of #91589 - derekdreery:arc_unwrap_or_clone, r=m-ou-se
impl `Arc::unwrap_or_clone` The function gets the inner value, cloning only if necessary. The conversation started on [`irlo`](https://internals.rust-lang.org/t/arc-into-inner/15707). If the reviewer think the PR has potential to be merged, and does not need an RFC, then I will create the corresponding tracking issues and update the PR. ## Alternative names - `into_inner` - `make_owned` - `make_unique` - `take_*` (`take_inner`?)
| -rw-r--r-- | library/alloc/src/rc.rs | 35 | ||||
| -rw-r--r-- | library/alloc/src/sync.rs | 35 |
2 files changed, 70 insertions, 0 deletions
diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 78bf28c843c..3065169e5e2 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -1203,6 +1203,41 @@ impl<T: Clone> Rc<T> { // reference to the allocation. unsafe { &mut this.ptr.as_mut().value } } + + /// If we have the only reference to `T` then unwrap it. Otherwise, clone `T` and return the + /// clone. + /// + /// Assuming `rc_t` is of type `Rc<T>`, this function is functionally equivalent to + /// `(*rc_t).clone()`, but will avoid cloning the inner value where possible. + /// + /// # Examples + /// + /// ``` + /// #![feature(arc_unwrap_or_clone)] + /// # use std::{ptr, rc::Rc}; + /// let inner = String::from("test"); + /// let ptr = inner.as_ptr(); + /// + /// let rc = Rc::new(inner); + /// let inner = Rc::unwrap_or_clone(rc); + /// // The inner value was not cloned + /// assert!(ptr::eq(ptr, inner.as_ptr())); + /// + /// let rc = Rc::new(inner); + /// let rc2 = rc.clone(); + /// let inner = Rc::unwrap_or_clone(rc); + /// // Because there were 2 references, we had to clone the inner value. + /// assert!(!ptr::eq(ptr, inner.as_ptr())); + /// // `rc2` is the last reference, so when we unwrap it we get back + /// // the original `String`. + /// let inner = Rc::unwrap_or_clone(rc2); + /// assert!(ptr::eq(ptr, inner.as_ptr())); + /// ``` + #[inline] + #[unstable(feature = "arc_unwrap_or_clone", issue = "93610")] + pub fn unwrap_or_clone(this: Self) -> T { + Rc::try_unwrap(this).unwrap_or_else(|rc| (*rc).clone()) + } } impl Rc<dyn Any> { diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 64f21d087da..7e7670aad64 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 = "93610")] + pub fn unwrap_or_clone(this: Self) -> T { + Arc::try_unwrap(this).unwrap_or_else(|arc| (*arc).clone()) + } } impl<T: ?Sized> Arc<T> { |
