Make weak_count return an Option<usize>

This commit is contained in:
Jonas Schievink 2019-01-29 21:58:17 +01:00
parent 7e0edb39ba
commit b664341d91
2 changed files with 22 additions and 26 deletions

View File

@ -1300,22 +1300,20 @@ impl<T: ?Sized> Weak<T> {
/// 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
/// If `self` was created using [`Weak::new`], this will return `None`. 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() {
pub fn weak_count(&self) -> Option<usize> {
self.inner().map(|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`,
@ -1658,28 +1656,28 @@ mod tests {
#[test]
fn weak_counts() {
assert_eq!(Weak::weak_count(&Weak::<u64>::new()), 0);
assert_eq!(Weak::weak_count(&Weak::<u64>::new()), None);
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);
assert_eq!(Weak::weak_count(&w), Some(1));
let w2 = w.clone();
assert_eq!(Weak::strong_count(&w), 1);
assert_eq!(Weak::weak_count(&w), 2);
assert_eq!(Weak::weak_count(&w), Some(2));
assert_eq!(Weak::strong_count(&w2), 1);
assert_eq!(Weak::weak_count(&w2), 2);
assert_eq!(Weak::weak_count(&w2), Some(2));
drop(w);
assert_eq!(Weak::strong_count(&w2), 1);
assert_eq!(Weak::weak_count(&w2), 1);
assert_eq!(Weak::weak_count(&w2), Some(1));
let a2 = a.clone();
assert_eq!(Weak::strong_count(&w2), 2);
assert_eq!(Weak::weak_count(&w2), 1);
assert_eq!(Weak::weak_count(&w2), Some(1));
drop(a2);
drop(a);
assert_eq!(Weak::strong_count(&w2), 0);
assert_eq!(Weak::weak_count(&w2), 1);
assert_eq!(Weak::weak_count(&w2), Some(1));
drop(w2);
}

View File

@ -1146,12 +1146,12 @@ impl<T: ?Sized> Weak<T> {
///
/// [`Weak::new`]: #method.new
#[unstable(feature = "weak_counts", issue = "0")]
pub fn weak_count(&self) -> usize {
pub fn weak_count(&self) -> Option<usize> {
// 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. So this version is a bit racy.
if let Some(inner) = self.inner() {
self.inner().map(|inner| {
let strong = inner.strong.load(SeqCst);
let weak = inner.weak.load(SeqCst);
if strong == 0 {
@ -1169,9 +1169,7 @@ impl<T: ?Sized> Weak<T> {
// pointer), we guard against that specifically.
cmp::max(1, weak - 1)
}
} else {
0
}
})
}
/// Return `None` when the pointer is dangling and there is no allocated `ArcInner`,
@ -1695,28 +1693,28 @@ mod tests {
#[test]
fn weak_counts() {
assert_eq!(Weak::weak_count(&Weak::<u64>::new()), 0);
assert_eq!(Weak::weak_count(&Weak::<u64>::new()), None);
assert_eq!(Weak::strong_count(&Weak::<u64>::new()), 0);
let a = Arc::new(0);
let w = Arc::downgrade(&a);
assert_eq!(Weak::strong_count(&w), 1);
assert_eq!(Weak::weak_count(&w), 1);
assert_eq!(Weak::weak_count(&w), Some(1));
let w2 = w.clone();
assert_eq!(Weak::strong_count(&w), 1);
assert_eq!(Weak::weak_count(&w), 2);
assert_eq!(Weak::weak_count(&w), Some(2));
assert_eq!(Weak::strong_count(&w2), 1);
assert_eq!(Weak::weak_count(&w2), 2);
assert_eq!(Weak::weak_count(&w2), Some(2));
drop(w);
assert_eq!(Weak::strong_count(&w2), 1);
assert_eq!(Weak::weak_count(&w2), 1);
assert_eq!(Weak::weak_count(&w2), Some(1));
let a2 = a.clone();
assert_eq!(Weak::strong_count(&w2), 2);
assert_eq!(Weak::weak_count(&w2), 1);
assert_eq!(Weak::weak_count(&w2), Some(1));
drop(a2);
drop(a);
assert_eq!(Weak::strong_count(&w2), 0);
assert_eq!(Weak::weak_count(&w2), 1);
assert_eq!(Weak::weak_count(&w2), Some(1));
drop(w2);
}