about summary refs log tree commit diff
path: root/src/liballoc
diff options
context:
space:
mode:
authorJonas Schievink <jonasschievink@gmail.com>2018-12-11 00:40:39 +0100
committerJonas Schievink <jonasschievink@gmail.com>2019-01-29 21:07:35 +0100
commit2fe3b3b486b3b5e1ec1e6ad259d8840b88b7c77a (patch)
treea76eb8020a512e355281b1932ac36557cfc0ff62 /src/liballoc
parent74256630117fedf479edbd1145cac47c88036aec (diff)
Implement Weak::{strong_count, weak_count}
Diffstat (limited to 'src/liballoc')
-rw-r--r--src/liballoc/rc.rs61
-rw-r--r--src/liballoc/sync.rs19
2 files changed, 80 insertions, 0 deletions
diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs
index c0dc010fe59..7ee05eaff91 100644
--- a/src/liballoc/rc.rs
+++ b/src/liballoc/rc.rs
@@ -1284,6 +1284,40 @@ impl<T: ?Sized> Weak<T> {
         }
     }
 
+    /// Gets the number of strong (`Rc`) pointers pointing to this value.
+    ///
+    /// If `self` was created using [`Weak::new`], this will return 0.
+    ///
+    /// [`Weak::new`]: #method.new
+    #[unstable(feature = "weak_counts", issue = "0")]
+    pub fn strong_count(&self) -> usize {
+        if let Some(inner) = self.inner() {
+            inner.strong()
+        } else {
+            0
+        }
+    }
+
+    /// Gets the number of `Weak` pointers pointing to this value.
+    ///
+    /// If `self` was created using [`Weak::new`], this will return 0. If not,
+    /// the returned value is at least 1, since `self` still points to the
+    /// value.
+    ///
+    /// [`Weak::new`]: #method.new
+    #[unstable(feature = "weak_counts", issue = "0")]
+    pub fn weak_count(&self) -> usize {
+        if let Some(inner) = self.inner() {
+            if inner.strong() > 0 {
+                inner.weak() - 1  // subtract the implicit weak ptr
+            } else {
+                inner.weak()
+            }
+        } else {
+            0
+        }
+    }
+
     /// Return `None` when the pointer is dangling and there is no allocated `RcBox`,
     /// i.e., this `Weak` was created by `Weak::new`
     #[inline]
@@ -1623,6 +1657,33 @@ mod tests {
     }
 
     #[test]
+    fn weak_counts() {
+        assert_eq!(Weak::weak_count(&Weak::<u64>::new()), 0);
+        assert_eq!(Weak::strong_count(&Weak::<u64>::new()), 0);
+
+        let a = Rc::new(0);
+        let w = Rc::downgrade(&a);
+        assert_eq!(Weak::strong_count(&w), 1);
+        assert_eq!(Weak::weak_count(&w), 1);
+        let w2 = w.clone();
+        assert_eq!(Weak::strong_count(&w), 1);
+        assert_eq!(Weak::weak_count(&w), 2);
+        assert_eq!(Weak::strong_count(&w2), 1);
+        assert_eq!(Weak::weak_count(&w2), 2);
+        drop(w);
+        assert_eq!(Weak::strong_count(&w2), 1);
+        assert_eq!(Weak::weak_count(&w2), 1);
+        let a2 = a.clone();
+        assert_eq!(Weak::strong_count(&w2), 2);
+        assert_eq!(Weak::weak_count(&w2), 1);
+        drop(a2);
+        drop(a);
+        assert_eq!(Weak::strong_count(&w2), 0);
+        assert_eq!(Weak::weak_count(&w2), 1);
+        drop(w2);
+    }
+
+    #[test]
     fn try_unwrap() {
         let x = Rc::new(3);
         assert_eq!(Rc::try_unwrap(x), Ok(3));
diff --git a/src/liballoc/sync.rs b/src/liballoc/sync.rs
index 390a0791650..fd3519dee18 100644
--- a/src/liballoc/sync.rs
+++ b/src/liballoc/sync.rs
@@ -1117,6 +1117,25 @@ impl<T: ?Sized> Weak<T> {
         }
     }
 
+    /// Gets the number of strong (`Arc`) pointers pointing to this value.
+    ///
+    /// If `self` was created using [`Weak::new`], this will return 0.
+    ///
+    /// [`Weak::new`]: #method.new
+    #[unstable(feature = "weak_counts", issue = "0")]
+    pub fn strong_count(&self) -> usize {
+        if let Some(inner) = self.inner() {
+            inner.strong.load(SeqCst)
+        } else {
+            0
+        }
+    }
+
+    // Due to the implicit weak pointer added when any strong pointers are
+    // around, we cannot implement `weak_count` correctly since it necessarily
+    // requires accessing the strong count and weak count in an unsynchronized
+    // fashion.
+
     /// Return `None` when the pointer is dangling and there is no allocated `ArcInner`,
     /// i.e., this `Weak` was created by `Weak::new`
     #[inline]