Skip to content

Commit fee500a

Browse files
committed
add Arc::try_unwrap
1 parent d66c0b0 commit fee500a

File tree

1 file changed

+51
-0
lines changed

1 file changed

+51
-0
lines changed

src/liballoc/arc.rs

+51
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,45 @@ impl<T> Arc<T> {
191191
};
192192
Arc { _ptr: unsafe { NonZero::new(Box::into_raw(x)) } }
193193
}
194+
195+
/// Unwraps the contained value if the `Arc<T>` has only one strong reference.
196+
/// This will succeed even if there are outstanding weak references.
197+
///
198+
/// Otherwise, an `Err` is returned with the same `Arc<T>`.
199+
///
200+
/// # Examples
201+
///
202+
/// ```
203+
/// use std::sync::Arc;
204+
///
205+
/// let x = Arc::new(3);
206+
/// assert_eq!(Arc::try_unwrap(x), Ok(3));
207+
///
208+
/// let x = Arc::new(4);
209+
/// let _y = x.clone();
210+
/// assert_eq!(Arc::try_unwrap(x), Err(Arc::new(4)));
211+
/// ```
212+
#[inline]
213+
#[unstable(feature = "arc_unwrap", reason = "was missing, so is technically new")]
214+
pub fn try_unwrap(this: Arc<T>) -> Result<T, Arc<T>> {
215+
// See `drop` for impl details
216+
if self.inner().strong.compare_and_swap(1, 0, Release) != 1 { return Err(self) }
217+
218+
// ~~ magic ~~
219+
atomic::fence(Acquire);
220+
221+
unsafe {
222+
let ptr = *self._ptr;
223+
224+
let elem = ptr::read(&(*ptr).data);
225+
226+
if self.inner().weak.fetch_sub(1, Release) == 1 {
227+
atomic::fence(Acquire);
228+
deallocate(ptr as *mut u8, size_of_val(&*ptr), align_of_val(&*ptr))
229+
}
230+
Ok(elem)
231+
}
232+
}
194233
}
195234

196235
impl<T: ?Sized> Arc<T> {
@@ -885,6 +924,18 @@ mod tests {
885924
assert!(Arc::get_mut(&mut x).is_none());
886925
}
887926

927+
#[test]
928+
fn try_unwrap() {
929+
let x = Arc::new(3);
930+
assert_eq!(Arc::try_unwrap(x), Ok(3));
931+
let x = Arc::new(4);
932+
let _y = x.clone();
933+
assert_eq!(Arc::try_unwrap(x), Err(Arc::new(4)));
934+
let x = Arc::new(5);
935+
let _w = x.downgrade();
936+
assert_eq!(Arc::try_unwrap(x), Ok(5));
937+
}
938+
888939
#[test]
889940
fn test_cowarc_clone_make_mut() {
890941
let mut cow0 = Arc::new(75);

0 commit comments

Comments
 (0)