about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJosh Triplett <josh@joshtriplett.org>2023-03-11 11:19:25 -0800
committerJosh Triplett <josh@joshtriplett.org>2023-03-11 12:47:12 -0800
commita2341fbbc2f9b35292473f139d17316a55d9e3d0 (patch)
treec8fc198c21ce3cb8849763dff862f5318b5675ab
parentd7948c843de94245c794e8c63dd4301a78bb5ba3 (diff)
downloadrust-a2341fbbc2f9b35292473f139d17316a55d9e3d0.tar.gz
rust-a2341fbbc2f9b35292473f139d17316a55d9e3d0.zip
Introduce `Rc::into_inner`, as a parallel to `Arc::into_inner`
Unlike `Arc`, `Rc` doesn't have the same race condition to avoid, but
maintaining an equivalent API still makes it easier to work with both
`Rc` and `Arc`.
-rw-r--r--library/alloc/src/rc.rs18
-rw-r--r--library/alloc/src/rc/tests.rs16
2 files changed, 34 insertions, 0 deletions
diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs
index c9aa23fc4af..0e0cf145a99 100644
--- a/library/alloc/src/rc.rs
+++ b/library/alloc/src/rc.rs
@@ -681,6 +681,24 @@ impl<T> Rc<T> {
             Err(this)
         }
     }
+
+    /// Returns the inner value, if the `Rc` has exactly one strong reference.
+    ///
+    /// Otherwise, [`None`] is returned and the `Rc` is dropped.
+    ///
+    /// This will succeed even if there are outstanding weak references.
+    ///
+    /// If `Rc::into_inner` is called on every clone of this `Rc`,
+    /// it is guaranteed that exactly one of the calls returns the inner value.
+    /// This means in particular that the inner value is not dropped.
+    ///
+    /// This is equivalent to `Rc::try_unwrap(...).ok()`. (Note that these are not equivalent for
+    /// `Arc`, due to race conditions that do not apply to `Rc`.)
+    #[inline]
+    #[unstable(feature = "rc_into_inner", issue = "106894")]
+    pub fn into_inner(this: Self) -> Option<T> {
+        Rc::try_unwrap(this).ok()
+    }
 }
 
 impl<T> Rc<[T]> {
diff --git a/library/alloc/src/rc/tests.rs b/library/alloc/src/rc/tests.rs
index 32433cfbdcf..342dc686fa3 100644
--- a/library/alloc/src/rc/tests.rs
+++ b/library/alloc/src/rc/tests.rs
@@ -152,6 +152,22 @@ fn try_unwrap() {
 }
 
 #[test]
+fn into_inner() {
+    let x = Rc::new(3);
+    assert_eq!(Rc::into_inner(x), Some(3));
+
+    let x = Rc::new(4);
+    let y = Rc::clone(&x);
+    assert_eq!(Rc::into_inner(x), None);
+    assert_eq!(Rc::into_inner(y), Some(4));
+
+    let x = Rc::new(5);
+    let _w = Rc::downgrade(&x);
+    assert_eq!(Rc::into_inner(x), Some(5));
+}
+
+
+#[test]
 fn into_from_raw() {
     let x = Rc::new(Box::new("hello"));
     let y = x.clone();