Skip to content

Commit 39aa668

Browse files
committed
Added Arc::try_unique
1 parent d754722 commit 39aa668

File tree

1 file changed

+50
-6
lines changed

1 file changed

+50
-6
lines changed

src/liballoc/arc.rs

+50-6
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,38 @@ pub fn weak_count<T>(this: &Arc<T>) -> usize { this.inner().weak.load(SeqCst) -
242242
#[unstable(feature = "alloc")]
243243
pub fn strong_count<T>(this: &Arc<T>) -> usize { this.inner().strong.load(SeqCst) }
244244

245+
246+
/// Try accessing a mutable reference to the contents behind an unique `Arc<T>`.
247+
///
248+
/// The access is granted only if this is the only reference to the object.
249+
/// Otherwise, `None` is returned.
250+
///
251+
/// # Examples
252+
///
253+
/// ```
254+
/// # #![feature(alloc)]
255+
/// use std::alloc::arc;
256+
///
257+
/// let mut four = arc::Arc::new(4);
258+
///
259+
/// arc::unique(&mut four).map(|num| *num = 5);
260+
/// ```
261+
#[inline]
262+
#[unstable(feature = "alloc")]
263+
pub fn unique<T>(this: &mut Arc<T>) -> Option<&mut T> {
264+
if strong_count(this) == 1 && weak_count(this) == 0 {
265+
// This unsafety is ok because we're guaranteed that the pointer
266+
// returned is the *only* pointer that will ever be returned to T. Our
267+
// reference count is guaranteed to be 1 at this point, and we required
268+
// the Arc itself to be `mut`, so we're returning the only possible
269+
// reference to the inner data.
270+
let inner = unsafe { &mut **this._ptr };
271+
Some(&mut inner.data)
272+
}else {
273+
None
274+
}
275+
}
276+
245277
#[stable(feature = "rust1", since = "1.0.0")]
246278
impl<T> Clone for Arc<T> {
247279
/// Makes a clone of the `Arc<T>`.
@@ -312,11 +344,8 @@ impl<T: Send + Sync + Clone> Arc<T> {
312344
self.inner().weak.load(SeqCst) != 1 {
313345
*self = Arc::new((**self).clone())
314346
}
315-
// This unsafety is ok because we're guaranteed that the pointer
316-
// returned is the *only* pointer that will ever be returned to T. Our
317-
// reference count is guaranteed to be 1 at this point, and we required
318-
// the Arc itself to be `mut`, so we're returning the only possible
319-
// reference to the inner data.
347+
// As with `unique()`, the unsafety is ok because our reference was
348+
// either unique to begin with, or became one upon cloning the contents.
320349
let inner = unsafe { &mut **self._ptr };
321350
&mut inner.data
322351
}
@@ -659,7 +688,7 @@ mod tests {
659688
use std::sync::atomic::Ordering::{Acquire, SeqCst};
660689
use std::thread;
661690
use std::vec::Vec;
662-
use super::{Arc, Weak, weak_count, strong_count};
691+
use super::{Arc, Weak, weak_count, strong_count, unique};
663692
use std::sync::Mutex;
664693

665694
struct Canary(*mut atomic::AtomicUsize);
@@ -695,6 +724,21 @@ mod tests {
695724
assert_eq!((*arc_v)[4], 5);
696725
}
697726

727+
#[test]
728+
fn test_arc_unique() {
729+
let mut x = Arc::new(10);
730+
assert!(unique(&mut x).is_some());
731+
{
732+
let y = x.clone();
733+
assert!(unique(&mut x).is_none());
734+
}
735+
{
736+
let z = x.downgrade();
737+
assert!(unique(&mut x).is_none());
738+
}
739+
assert!(unique(&mut x).is_some());
740+
}
741+
698742
#[test]
699743
fn test_cowarc_clone_make_unique() {
700744
let mut cow0 = Arc::new(75);

0 commit comments

Comments
 (0)