about summary refs log tree commit diff
path: root/src/liballoc
diff options
context:
space:
mode:
authorDzmitry Malyshau <kvarkus@gmail.com>2015-03-29 17:38:05 -0400
committerDzmitry Malyshau <kvarkus@gmail.com>2015-03-31 23:44:23 -0400
commit39aa668a01fb671cff382a8237ec3993c9cc4c33 (patch)
tree01b941eed547c19bf950fa0f269180c26102006b /src/liballoc
parentd754722a04b99fdcae0fd97fa2a4395521145ef2 (diff)
downloadrust-39aa668a01fb671cff382a8237ec3993c9cc4c33.tar.gz
rust-39aa668a01fb671cff382a8237ec3993c9cc4c33.zip
Added Arc::try_unique
Diffstat (limited to 'src/liballoc')
-rw-r--r--src/liballoc/arc.rs56
1 files changed, 50 insertions, 6 deletions
diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs
index 9b37ddc7ab5..5dcdddfafa4 100644
--- a/src/liballoc/arc.rs
+++ b/src/liballoc/arc.rs
@@ -242,6 +242,38 @@ pub fn weak_count<T>(this: &Arc<T>) -> usize { this.inner().weak.load(SeqCst) -
 #[unstable(feature = "alloc")]
 pub fn strong_count<T>(this: &Arc<T>) -> usize { this.inner().strong.load(SeqCst) }
 
+
+/// Try accessing a mutable reference to the contents behind an unique `Arc<T>`.
+///
+/// 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<T>(this: &mut Arc<T>) -> 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<T> Clone for Arc<T> {
     /// Makes a clone of the `Arc<T>`.
@@ -312,11 +344,8 @@ impl<T: Send + Sync + Clone> Arc<T> {
            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);
@@ -696,6 +725,21 @@ mod tests {
     }
 
     #[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);
         let mut cow1 = cow0.clone();