diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index 9b37ddc7ab533..5dcdddfafa466 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -242,6 +242,38 @@ pub fn weak_count(this: &Arc) -> usize { this.inner().weak.load(SeqCst) - #[unstable(feature = "alloc")] pub fn strong_count(this: &Arc) -> usize { this.inner().strong.load(SeqCst) } + +/// Try accessing a mutable reference to the contents behind an unique `Arc`. +/// +/// The access is granted only if this is the only reference to the object. +/// Otherwise, `None` is returned. +/// +/// # Examples +/// +/// ``` +/// # #![feature(alloc)] +/// use std::alloc::arc; +/// +/// let mut four = arc::Arc::new(4); +/// +/// arc::unique(&mut four).map(|num| *num = 5); +/// ``` +#[inline] +#[unstable(feature = "alloc")] +pub fn unique(this: &mut Arc) -> Option<&mut T> { + if strong_count(this) == 1 && weak_count(this) == 0 { + // 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 Arc itself to be `mut`, so we're returning the only possible + // reference to the inner data. + let inner = unsafe { &mut **this._ptr }; + Some(&mut inner.data) + }else { + None + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl Clone for Arc { /// Makes a clone of the `Arc`. @@ -312,11 +344,8 @@ impl Arc { self.inner().weak.load(SeqCst) != 1 { *self = Arc::new((**self).clone()) } - // 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 Arc itself to be `mut`, so we're returning the only possible - // reference to the inner data. + // As with `unique()`, the unsafety is ok because our reference was + // either unique to begin with, or became one upon cloning the contents. let inner = unsafe { &mut **self._ptr }; &mut inner.data } @@ -659,7 +688,7 @@ mod tests { use std::sync::atomic::Ordering::{Acquire, SeqCst}; use std::thread; use std::vec::Vec; - use super::{Arc, Weak, weak_count, strong_count}; + use super::{Arc, Weak, weak_count, strong_count, unique}; use std::sync::Mutex; struct Canary(*mut atomic::AtomicUsize); @@ -695,6 +724,21 @@ mod tests { assert_eq!((*arc_v)[4], 5); } + #[test] + fn test_arc_unique() { + let mut x = Arc::new(10); + assert!(unique(&mut x).is_some()); + { + let y = x.clone(); + assert!(unique(&mut x).is_none()); + } + { + let z = x.downgrade(); + assert!(unique(&mut x).is_none()); + } + assert!(unique(&mut x).is_some()); + } + #[test] fn test_cowarc_clone_make_unique() { let mut cow0 = Arc::new(75);