]> git.lizzy.rs Git - rust.git/commitdiff
Rework Rc for FCP of #27718
authorAlexis Beingessner <a.beingessner@gmail.com>
Wed, 12 Aug 2015 19:00:46 +0000 (12:00 -0700)
committerAlexis Beingessner <a.beingessner@gmail.com>
Wed, 19 Aug 2015 22:52:12 +0000 (15:52 -0700)
* Add `Rc::would_unwrap(&Self) -> bool` to introspect whether try_unwrap would succeed,
  because it's destructive (unlike get_mut).
* Move `rc.downgrade()` to `Rc::downgrade(&Self)` per conventions.
* Deprecate `Rc::weak_count` and `Rc::strong_count` for questionable utility.
* Deprecate `Rc::is_unique` for questionable semantics (there are two kinds of
  uniqueness with Weak pointers in play).
* Rename `rc.make_unique()` to `Rc::make_mut(&mut Self)` per conventions, to
  avoid uniqueness terminology, and to clarify the relation to `Rc::get_mut`.

src/liballoc/rc.rs

index c2d7febf98e5e25d1399870dcd164375e3ec8ee1..e0ff3a1bca0306a30c13b53928cb5a4831927e4b 100644 (file)
@@ -8,6 +8,9 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// FIXME(27718): rc_counts stuff is useful internally, but was previously public
+#![allow(deprecated)]
+
 //! Thread-local reference-counted boxes (the `Rc<T>` type).
 //!
 //! The `Rc<T>` type provides shared ownership of an immutable value.
 //!
 //!     // Add the Gadgets to their Owner. To do this we mutably borrow from
 //!     // the RefCell holding the Owner's Gadgets.
-//!     gadget_owner.gadgets.borrow_mut().push(gadget1.clone().downgrade());
-//!     gadget_owner.gadgets.borrow_mut().push(gadget2.clone().downgrade());
+//!     gadget_owner.gadgets.borrow_mut().push(Rc::downgrade(&gadget1));
+//!     gadget_owner.gadgets.borrow_mut().push(Rc::downgrade(&gadget2));
 //!
 //!     // Iterate over our Gadgets, printing their details out
 //!     for gadget_opt in gadget_owner.gadgets.borrow().iter() {
 use core::hash::{Hasher, Hash};
 use core::intrinsics::{assume, drop_in_place, abort};
 use core::marker::{self, Unsize};
-use core::mem::{self, align_of, size_of, align_of_val, size_of_val, forget};
+use core::mem::{self, align_of_val, size_of_val, forget};
 use core::nonzero::NonZero;
 use core::ops::{CoerceUnsized, Deref};
 use core::ptr;
@@ -218,10 +221,10 @@ pub fn new(value: T) -> Rc<T> {
         }
     }
 
-    /// Unwraps the contained value if the `Rc<T>` is unique.
+    /// Unwraps the contained value if the `Rc<T>` has only one strong reference.
+    /// This will succeed even if there are outstanding weak references.
     ///
-    /// If the `Rc<T>` is not unique, an `Err` is returned with the same
-    /// `Rc<T>`.
+    /// Otherwise, an `Err` is returned with the same `Rc<T>`.
     ///
     /// # Examples
     ///
@@ -238,22 +241,32 @@ pub fn new(value: T) -> Rc<T> {
     /// assert_eq!(Rc::try_unwrap(x), Err(Rc::new(4)));
     /// ```
     #[inline]
-    #[unstable(feature = "rc_unique", issue = "27718")]
-    pub fn try_unwrap(rc: Rc<T>) -> Result<T, Rc<T>> {
-        if Rc::is_unique(&rc) {
+    #[unstable(feature = "rc_unique", reason=  "needs FCP", issue = "27718")]
+    pub fn try_unwrap(this: Self) -> Result<T, Self> {
+        if Rc::would_unwrap(&this) {
             unsafe {
-                let val = ptr::read(&*rc); // copy the contained object
-                // destruct the box and skip our Drop
-                // we can ignore the refcounts because we know we're unique
-                deallocate(*rc._ptr as *mut u8, size_of::<RcBox<T>>(),
-                            align_of::<RcBox<T>>());
-                forget(rc);
+                let val = ptr::read(&*this); // copy the contained object
+
+                // Indicate to Weaks that they can't be promoted by decrememting
+                // the strong count, and then remove the implicit "strong weak"
+                // pointer while also handling drop logic by just crafting a
+                // fake Weak.
+                this.dec_strong();
+                let _weak = Weak { _ptr: this._ptr };
+                forget(this);
                 Ok(val)
             }
         } else {
-            Err(rc)
+            Err(this)
         }
     }
+
+    /// Checks if `Rc::try_unwrap` would return `Ok`.
+    #[unstable(feature = "rc_would_unwrap", reason = "just added for niche usecase",
+               issue = "27718")]
+    pub fn would_unwrap(this: &Self) -> bool {
+        Rc::strong_count(&this) == 1
+    }
 }
 
 impl<T: ?Sized> Rc<T> {
@@ -268,25 +281,25 @@ impl<T: ?Sized> Rc<T> {
     ///
     /// let five = Rc::new(5);
     ///
-    /// let weak_five = five.downgrade();
+    /// let weak_five = Rc::downgrade(&five);
     /// ```
-    #[unstable(feature = "rc_weak",
-               reason = "Weak pointers may not belong in this module",
-               issue = "27718")]
-    pub fn downgrade(&self) -> Weak<T> {
-        self.inc_weak();
-        Weak { _ptr: self._ptr }
+    #[unstable(feature = "rc_weak", reason = "needs FCP", issue = "27718")]
+    pub fn downgrade(this: &Self) -> Weak<T> {
+        this.inc_weak();
+        Weak { _ptr: this._ptr }
     }
 
     /// Get the number of weak references to this value.
     #[inline]
-    #[unstable(feature = "rc_counts", issue = "27718")]
-    pub fn weak_count(this: &Rc<T>) -> usize { this.weak() - 1 }
+    #[unstable(feature = "rc_counts", reason = "not clearly useful", issue = "27718")]
+    #[deprecated(since = "1.4.0", reason = "not clearly useful")]
+    pub fn weak_count(this: &Self) -> usize { this.weak() - 1 }
 
     /// Get the number of strong references to this value.
     #[inline]
-    #[unstable(feature = "rc_counts", issue= "27718")]
-    pub fn strong_count(this: &Rc<T>) -> usize { this.strong() }
+    #[unstable(feature = "rc_counts", reason = "not clearly useful", issue = "27718")]
+    #[deprecated(since = "1.4.0", reason = "not clearly useful")]
+    pub fn strong_count(this: &Self) -> usize { this.strong() }
 
     /// Returns true if there are no other `Rc` or `Weak<T>` values that share
     /// the same inner value.
@@ -294,7 +307,7 @@ pub fn strong_count(this: &Rc<T>) -> usize { this.strong() }
     /// # Examples
     ///
     /// ```
-    /// #![feature(rc_unique)]
+    /// #![feature(rc_counts)]
     ///
     /// use std::rc::Rc;
     ///
@@ -303,13 +316,14 @@ pub fn strong_count(this: &Rc<T>) -> usize { this.strong() }
     /// assert!(Rc::is_unique(&five));
     /// ```
     #[inline]
-    #[unstable(feature = "rc_unique", issue = "27718")]
-    pub fn is_unique(rc: &Rc<T>) -> bool {
-        Rc::weak_count(rc) == 0 && Rc::strong_count(rc) == 1
+    #[unstable(feature = "rc_counts", reason = "uniqueness has unclear meaning", issue = "27718")]
+    #[deprecated(since = "1.4.0", reason = "uniqueness has unclear meaning")]
+    pub fn is_unique(this: &Self) -> bool {
+        Rc::weak_count(this) == 0 && Rc::strong_count(this) == 1
     }
 
-    /// Returns a mutable reference to the contained value if the `Rc<T>` is
-    /// unique.
+    /// Returns a mutable reference to the contained value if the `Rc<T>` has
+    /// one strong reference and no weak references.
     ///
     /// Returns `None` if the `Rc<T>` is not unique.
     ///
@@ -328,10 +342,10 @@ pub fn is_unique(rc: &Rc<T>) -> bool {
     /// assert!(Rc::get_mut(&mut x).is_none());
     /// ```
     #[inline]
-    #[unstable(feature = "rc_unique", issue = "27718")]
-    pub fn get_mut(rc: &mut Rc<T>) -> Option<&mut T> {
-        if Rc::is_unique(rc) {
-            let inner = unsafe { &mut **rc._ptr };
+    #[unstable(feature = "rc_unique", reason = "needs FCP", issue = "27718")]
+    pub fn get_mut(this: &mut Self) -> Option<&mut T> {
+        if Rc::is_unique(this) {
+            let inner = unsafe { &mut **this._ptr };
             Some(&mut inner.value)
         } else {
             None
@@ -340,34 +354,62 @@ pub fn get_mut(rc: &mut Rc<T>) -> Option<&mut T> {
 }
 
 impl<T: Clone> Rc<T> {
-    /// Make a mutable reference from the given `Rc<T>`.
+    #[inline]
+    #[unstable(feature = "rc_unique", reason = "renamed to Rc::make_mut", issue = "27718")]
+    #[deprecated(since = "1.4.0", reason = "renamed to Rc::make_mut")]
+    pub fn make_unique(&mut self) -> &mut T {
+        Rc::make_mut(self)
+    }
+
+    /// Make a mutable reference into the given `Rc<T>` by cloning the inner
+    /// data if the `Rc<T>` doesn't have one strong reference and no weak
+    /// references.
     ///
-    /// This is also referred to as a copy-on-write operation because the inner
-    /// data is cloned if the reference count is greater than one.
+    /// This is also referred to as a copy-on-write.
     ///
     /// # Examples
     ///
     /// ```
     /// #![feature(rc_unique)]
-    ///
     /// use std::rc::Rc;
     ///
-    /// let mut five = Rc::new(5);
+    /// let mut data = Rc::new(5);
+    ///
+    /// *Rc::make_mut(&mut data) += 1;             // Won't clone anything
+    /// let mut other_data = data.clone(); // Won't clone inner data
+    /// *Rc::make_mut(&mut data) += 1;             // Clones inner data
+    /// *Rc::make_mut(&mut data) += 1;             // Won't clone anything
+    /// *Rc::make_mut(&mut other_data) *= 2;       // Won't clone anything
+    ///
+    /// // Note: data and other_data now point to different numbers
+    /// assert_eq!(*data, 8);
+    /// assert_eq!(*other_data, 12);
     ///
-    /// let mut_five = five.make_unique();
     /// ```
     #[inline]
-    #[unstable(feature = "rc_unique", issue = "27718")]
-    pub fn make_unique(&mut self) -> &mut T {
-        if !Rc::is_unique(self) {
-            *self = Rc::new((**self).clone())
+    #[unstable(feature = "rc_unique", reason = "needs FCP", issue = "27718")]
+    pub fn make_mut(this: &mut Self) -> &mut T {
+        if Rc::strong_count(this) != 1 {
+            // Gotta clone the data, there are other Rcs
+            *this = Rc::new((**this).clone())
+        } else if Rc::weak_count(this) != 0 {
+            // Can just steal the data, all that's left is Weaks
+            unsafe {
+                let mut swap = Rc::new(ptr::read(&(**this._ptr).value));
+                mem::swap(this, &mut swap);
+                swap.dec_strong();
+                // Remove implicit strong-weak ref (no need to craft a fake
+                // Weak here -- we know other Weaks can clean up for us)
+                swap.dec_weak();
+                forget(swap);
+            }
         }
         // This unsafety is ok because we're guaranteed that the pointer
         // returned is the *only* pointer that will ever be returned to T. Our
         // reference count is guaranteed to be 1 at this point, and we required
         // the `Rc<T>` itself to be `mut`, so we're returning the only possible
         // reference to the inner value.
-        let inner = unsafe { &mut **self._ptr };
+        let inner = unsafe { &mut **this._ptr };
         &mut inner.value
     }
 }
@@ -413,7 +455,7 @@ fn drop(&mut self) {
         unsafe {
             let ptr = *self._ptr;
             if !(*(&ptr as *const _ as *const *const ())).is_null() &&
-               ptr as *const () as usize != mem::POST_DROP_USIZE {
+                ptr as *const () as usize != mem::POST_DROP_USIZE {
                 self.dec_strong();
                 if self.strong() == 0 {
                     // destroy the contained object
@@ -653,9 +695,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 ///
 /// See the [module level documentation](./index.html) for more.
 #[unsafe_no_drop_flag]
-#[unstable(feature = "rc_weak",
-           reason = "Weak pointers may not belong in this module.",
-           issue = "27718")]
+#[unstable(feature = "rc_weak", reason = "needs FCP", issue = "27718")]
 pub struct Weak<T: ?Sized> {
     // FIXME #12808: strange names to try to avoid interfering with
     // field accesses of the contained type via Deref
@@ -667,11 +707,7 @@ impl<T: ?Sized> !marker::Sync for Weak<T> {}
 
 impl<T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<Weak<U>> for Weak<T> {}
 
-#[unstable(feature = "rc_weak",
-           reason = "Weak pointers may not belong in this module.",
-           issue = "27718")]
 impl<T: ?Sized> Weak<T> {
-
     /// Upgrades a weak reference to a strong reference.
     ///
     /// Upgrades the `Weak<T>` reference to an `Rc<T>`, if possible.
@@ -688,10 +724,11 @@ impl<T: ?Sized> Weak<T> {
     ///
     /// let five = Rc::new(5);
     ///
-    /// let weak_five = five.downgrade();
+    /// let weak_five = Rc::downgrade(&five);
     ///
     /// let strong_five: Option<Rc<_>> = weak_five.upgrade();
     /// ```
+    #[unstable(feature = "rc_weak", reason = "needs FCP", issue = "27718")]
     pub fn upgrade(&self) -> Option<Rc<T>> {
         if self.strong() == 0 {
             None
@@ -717,7 +754,7 @@ impl<T: ?Sized> Drop for Weak<T> {
     ///
     /// {
     ///     let five = Rc::new(5);
-    ///     let weak_five = five.downgrade();
+    ///     let weak_five = Rc::downgrade(&five);
     ///
     ///     // stuff
     ///
@@ -725,7 +762,7 @@ impl<T: ?Sized> Drop for Weak<T> {
     /// }
     /// {
     ///     let five = Rc::new(5);
-    ///     let weak_five = five.downgrade();
+    ///     let weak_five = Rc::downgrade(&five);
     ///
     ///     // stuff
     ///
@@ -735,7 +772,7 @@ fn drop(&mut self) {
         unsafe {
             let ptr = *self._ptr;
             if !(*(&ptr as *const _ as *const *const ())).is_null() &&
-               ptr as *const () as usize != mem::POST_DROP_USIZE {
+                ptr as *const () as usize != mem::POST_DROP_USIZE {
                 self.dec_weak();
                 // the weak count starts at 1, and will only go to zero if all
                 // the strong pointers have disappeared.
@@ -748,9 +785,7 @@ fn drop(&mut self) {
     }
 }
 
-#[unstable(feature = "rc_weak",
-           reason = "Weak pointers may not belong in this module.",
-           issue = "27718")]
+#[unstable(feature = "rc_weak", reason = "needs FCP", issue = "27718")]
 impl<T: ?Sized> Clone for Weak<T> {
 
     /// Makes a clone of the `Weak<T>`.
@@ -764,7 +799,7 @@ impl<T: ?Sized> Clone for Weak<T> {
     ///
     /// use std::rc::Rc;
     ///
-    /// let weak_five = Rc::new(5).downgrade();
+    /// let weak_five = Rc::downgrade(&Rc::new(5));
     ///
     /// weak_five.clone();
     /// ```
@@ -888,14 +923,14 @@ fn test_destructor() {
     #[test]
     fn test_live() {
         let x = Rc::new(5);
-        let y = x.downgrade();
+        let y = Rc::downgrade(&x);
         assert!(y.upgrade().is_some());
     }
 
     #[test]
     fn test_dead() {
         let x = Rc::new(5);
-        let y = x.downgrade();
+        let y = Rc::downgrade(&x);
         drop(x);
         assert!(y.upgrade().is_none());
     }
@@ -907,7 +942,7 @@ struct Cycle {
         }
 
         let a = Rc::new(Cycle { x: RefCell::new(None) });
-        let b = a.clone().downgrade();
+        let b = Rc::downgrade(&a.clone());
         *a.x.borrow_mut() = Some(b);
 
         // hopefully we don't double-free (or leak)...
@@ -921,7 +956,7 @@ fn is_unique() {
         assert!(!Rc::is_unique(&x));
         drop(y);
         assert!(Rc::is_unique(&x));
-        let w = x.downgrade();
+        let w = Rc::downgrade(&x);
         assert!(!Rc::is_unique(&x));
         drop(w);
         assert!(Rc::is_unique(&x));
@@ -931,7 +966,7 @@ fn is_unique() {
     fn test_strong_count() {
         let a = Rc::new(0u32);
         assert!(Rc::strong_count(&a) == 1);
-        let w = a.downgrade();
+        let w = Rc::downgrade(&a);
         assert!(Rc::strong_count(&a) == 1);
         let b = w.upgrade().expect("upgrade of live rc failed");
         assert!(Rc::strong_count(&b) == 2);
@@ -949,7 +984,7 @@ fn test_weak_count() {
         let a = Rc::new(0u32);
         assert!(Rc::strong_count(&a) == 1);
         assert!(Rc::weak_count(&a) == 0);
-        let w = a.downgrade();
+        let w = Rc::downgrade(&a);
         assert!(Rc::strong_count(&a) == 1);
         assert!(Rc::weak_count(&a) == 1);
         drop(w);
@@ -969,8 +1004,8 @@ fn try_unwrap() {
         let _y = x.clone();
         assert_eq!(Rc::try_unwrap(x), Err(Rc::new(4)));
         let x = Rc::new(5);
-        let _w = x.downgrade();
-        assert_eq!(Rc::try_unwrap(x), Err(Rc::new(5)));
+        let _w = Rc::downgrade(&x);
+        assert_eq!(Rc::try_unwrap(x), Ok(5));
     }
 
     #[test]
@@ -982,7 +1017,7 @@ fn get_mut() {
         assert!(Rc::get_mut(&mut x).is_none());
         drop(y);
         assert!(Rc::get_mut(&mut x).is_some());
-        let _w = x.downgrade();
+        let _w = Rc::downgrade(&x);
         assert!(Rc::get_mut(&mut x).is_none());
     }
 
@@ -992,13 +1027,13 @@ fn test_cowrc_clone_make_unique() {
         let mut cow1 = cow0.clone();
         let mut cow2 = cow1.clone();
 
-        assert!(75 == *cow0.make_unique());
-        assert!(75 == *cow1.make_unique());
-        assert!(75 == *cow2.make_unique());
+        assert!(75 == *Rc::make_mut(&mut cow0));
+        assert!(75 == *Rc::make_mut(&mut cow1));
+        assert!(75 == *Rc::make_mut(&mut cow2));
 
-        *cow0.make_unique() += 1;
-        *cow1.make_unique() += 2;
-        *cow2.make_unique() += 3;
+        *Rc::make_mut(&mut cow0) += 1;
+        *Rc::make_mut(&mut cow1) += 2;
+        *Rc::make_mut(&mut cow2) += 3;
 
         assert!(76 == *cow0);
         assert!(77 == *cow1);
@@ -1020,7 +1055,7 @@ fn test_cowrc_clone_unique2() {
         assert!(75 == *cow1);
         assert!(75 == *cow2);
 
-        *cow0.make_unique() += 1;
+        *Rc::make_mut(&mut cow0) += 1;
 
         assert!(76 == *cow0);
         assert!(75 == *cow1);
@@ -1036,12 +1071,12 @@ fn test_cowrc_clone_unique2() {
     #[test]
     fn test_cowrc_clone_weak() {
         let mut cow0 = Rc::new(75);
-        let cow1_weak = cow0.downgrade();
+        let cow1_weak = Rc::downgrade(&cow0);
 
         assert!(75 == *cow0);
         assert!(75 == *cow1_weak.upgrade().unwrap());
 
-        *cow0.make_unique() += 1;
+        *Rc::make_mut(&mut cow0) += 1;
 
         assert!(76 == *cow0);
         assert!(cow1_weak.upgrade().is_none());