Skip to content

Commit 5016467

Browse files
committed
Implement UniqueArc
1 parent 2a1c8be commit 5016467

File tree

3 files changed

+187
-2
lines changed

3 files changed

+187
-2
lines changed

library/alloc/src/sync.rs

+181-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use core::iter;
2020
use core::marker::{PhantomData, Unsize};
2121
use core::mem::{self, ManuallyDrop, align_of_val_raw};
2222
use core::num::NonZeroUsize;
23-
use core::ops::{CoerceUnsized, Deref, DerefPure, DispatchFromDyn, LegacyReceiver};
23+
use core::ops::{CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn, LegacyReceiver};
2424
use core::panic::{RefUnwindSafe, UnwindSafe};
2525
use core::pin::{Pin, PinCoerceUnsized};
2626
use core::ptr::{self, NonNull};
@@ -4066,3 +4066,183 @@ impl<T: core::error::Error + ?Sized> core::error::Error for Arc<T> {
40664066
core::error::Error::provide(&**self, req);
40674067
}
40684068
}
4069+
4070+
/// A uniquely owned [`Arc`].
4071+
///
4072+
/// This represents an `Arc` that is known to be uniquely owned -- that is, have exactly one strong
4073+
/// reference. Multiple weak pointers can be created, but attempts to upgrade those to strong
4074+
/// references will fail unless the `UniqueArc` they point to has been converted into a regular `Arc`.
4075+
///
4076+
/// Because they are uniquely owned, the contents of a `UniqueArc` can be freely mutated. A common
4077+
/// use case is to have an object be mutable during its initialization phase but then have it become
4078+
/// immutable and converted to a normal `Arc`.
4079+
///
4080+
/// This can be used as a flexible way to create cyclic data structures, as in the example below.
4081+
///
4082+
/// ```
4083+
/// #![feature(unique_rc_arc)]
4084+
/// use std::sync::{Arc, Weak, UniqueArc};
4085+
///
4086+
/// struct Gadget {
4087+
/// #[allow(dead_code)]
4088+
/// me: Weak<Gadget>,
4089+
/// }
4090+
///
4091+
/// fn create_gadget() -> Option<Arc<Gadget>> {
4092+
/// let mut rc = UniqueArc::new(Gadget {
4093+
/// me: Weak::new(),
4094+
/// });
4095+
/// rc.me = UniqueArc::downgrade(&rc);
4096+
/// Some(UniqueArc::into_arc(rc))
4097+
/// }
4098+
///
4099+
/// create_gadget().unwrap();
4100+
/// ```
4101+
///
4102+
/// An advantage of using `UniqueArc` over [`Arc::new_cyclic`] to build cyclic data structures is that
4103+
/// [`Arc::new_cyclic`]'s `data_fn` parameter cannot be async or return a [`Result`]. As shown in the
4104+
/// previous example, `UniqueArc` allows for more flexibility in the construction of cyclic data,
4105+
/// including fallible or async constructors.
4106+
#[unstable(feature = "unique_rc_arc", issue = "112566")]
4107+
#[derive(Debug)]
4108+
pub struct UniqueArc<
4109+
T: ?Sized,
4110+
#[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
4111+
> {
4112+
ptr: NonNull<ArcInner<T>>,
4113+
phantom: PhantomData<ArcInner<T>>,
4114+
alloc: A,
4115+
}
4116+
4117+
#[unstable(feature = "unique_rc_arc", issue = "112566")]
4118+
impl<T: ?Sized + Unsize<U>, U: ?Sized, A: Allocator> CoerceUnsized<UniqueArc<U, A>>
4119+
for UniqueArc<T, A>
4120+
{
4121+
}
4122+
4123+
// Depends on A = Global
4124+
impl<T> UniqueArc<T> {
4125+
/// Creates a new `UniqueArc`.
4126+
///
4127+
/// Weak references to this `UniqueArc` can be created with [`UniqueArc::downgrade`]. Upgrading
4128+
/// these weak references will fail before the `UniqueArc` has been converted into an [`Arc`].
4129+
/// After converting the `UniqueArc` into an [`Arc`], any weak references created beforehand will
4130+
/// point to the new [`Arc`].
4131+
#[cfg(not(no_global_oom_handling))]
4132+
#[unstable(feature = "unique_rc_arc", issue = "112566")]
4133+
pub fn new(value: T) -> Self {
4134+
Self::new_in(value, Global)
4135+
}
4136+
}
4137+
4138+
impl<T, A: Allocator> UniqueArc<T, A> {
4139+
/// Creates a new `UniqueArc` in the provided allocator.
4140+
///
4141+
/// Weak references to this `UniqueArc` can be created with [`UniqueArc::downgrade`]. Upgrading
4142+
/// these weak references will fail before the `UniqueArc` has been converted into an [`Arc`].
4143+
/// After converting the `UniqueArc` into an [`Arc`], any weak references created beforehand will
4144+
/// point to the new [`Arc`].
4145+
#[cfg(not(no_global_oom_handling))]
4146+
#[unstable(feature = "unique_rc_arc", issue = "112566")]
4147+
pub fn new_in(data: T, alloc: A) -> Self {
4148+
let (ptr, alloc) = Box::into_unique(Box::new_in(
4149+
ArcInner {
4150+
strong: atomic::AtomicUsize::new(0),
4151+
// keep one weak reference so if all the weak pointers that are created are dropped
4152+
// the UniqueArc still stays valid.
4153+
weak: atomic::AtomicUsize::new(1),
4154+
data,
4155+
},
4156+
alloc,
4157+
));
4158+
Self { ptr: ptr.into(), phantom: PhantomData, alloc }
4159+
}
4160+
}
4161+
4162+
impl<T: ?Sized, A: Allocator> UniqueArc<T, A> {
4163+
/// Converts the `UniqueArc` into a regular [`Arc`].
4164+
///
4165+
/// This consumes the `UniqueArc` and returns a regular [`Arc`] that contains the `value` that
4166+
/// is passed to `into_arc`.
4167+
///
4168+
/// Any weak references created before this method is called can now be upgraded to strong
4169+
/// references.
4170+
#[unstable(feature = "unique_rc_arc", issue = "112566")]
4171+
pub fn into_arc(this: Self) -> Arc<T, A> {
4172+
let this = ManuallyDrop::new(this);
4173+
4174+
// Move the allocator out.
4175+
// SAFETY: `this.alloc` will not be accessed again, nor dropped because it is in
4176+
// a `ManuallyDrop`.
4177+
let alloc: A = unsafe { ptr::read(&this.alloc) };
4178+
4179+
// SAFETY: This pointer was allocated at creation time so we know it is valid.
4180+
unsafe {
4181+
// Convert our weak reference into a strong reference
4182+
(*this.ptr.as_ptr()).strong.store(1, Release);
4183+
Arc::from_inner_in(this.ptr, alloc)
4184+
}
4185+
}
4186+
}
4187+
4188+
impl<T: ?Sized, A: Allocator + Clone> UniqueArc<T, A> {
4189+
/// Creates a new weak reference to the `UniqueArc`.
4190+
///
4191+
/// Attempting to upgrade this weak reference will fail before the `UniqueArc` has been converted
4192+
/// to a [`Arc`] using [`UniqueArc::into_arc`].
4193+
#[unstable(feature = "unique_rc_arc", issue = "112566")]
4194+
pub fn downgrade(this: &Self) -> Weak<T, A> {
4195+
// Using a relaxed ordering is alright here, as knowledge of the
4196+
// original reference prevents other threads from erroneously deleting
4197+
// the object or converting the object to a normal `Arc<T, A>`.
4198+
//
4199+
// Note that we don't need to test if the weak counter is locked because there
4200+
// are no such operations like `Arc::get_mut` or `Arc::make_mut` that will lock
4201+
// the weak counter.
4202+
//
4203+
// SAFETY: This pointer was allocated at creation time so we know it is valid.
4204+
let old_size = unsafe { (*this.ptr.as_ptr()).weak.fetch_add(1, Relaxed) };
4205+
4206+
// See comments in Arc::clone() for why we do this (for mem::forget).
4207+
if old_size > MAX_REFCOUNT {
4208+
abort();
4209+
}
4210+
4211+
Weak { ptr: this.ptr, alloc: this.alloc.clone() }
4212+
}
4213+
}
4214+
4215+
#[unstable(feature = "unique_rc_arc", issue = "112566")]
4216+
impl<T: ?Sized, A: Allocator> Deref for UniqueArc<T, A> {
4217+
type Target = T;
4218+
4219+
fn deref(&self) -> &T {
4220+
// SAFETY: This pointer was allocated at creation time so we know it is valid.
4221+
unsafe { &self.ptr.as_ref().data }
4222+
}
4223+
}
4224+
4225+
// #[unstable(feature = "unique_rc_arc", issue = "112566")]
4226+
#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")]
4227+
unsafe impl<T: ?Sized> PinCoerceUnsized for UniqueArc<T> {}
4228+
4229+
#[unstable(feature = "unique_rc_arc", issue = "112566")]
4230+
impl<T: ?Sized, A: Allocator> DerefMut for UniqueArc<T, A> {
4231+
fn deref_mut(&mut self) -> &mut T {
4232+
// SAFETY: This pointer was allocated at creation time so we know it is valid. We know we
4233+
// have unique ownership and therefore it's safe to make a mutable reference because
4234+
// `UniqueArc` owns the only strong reference to itself.
4235+
unsafe { &mut (*self.ptr.as_ptr()).data }
4236+
}
4237+
}
4238+
4239+
#[unstable(feature = "unique_rc_arc", issue = "112566")]
4240+
unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for UniqueArc<T, A> {
4241+
fn drop(&mut self) {
4242+
// See `Arc::drop_slow` which drops an `Arc` with a strong count of 0.
4243+
// SAFETY: This pointer was allocated at creation time so we know it is valid.
4244+
let _weak = Weak { ptr: self.ptr, alloc: &self.alloc };
4245+
4246+
unsafe { ptr::drop_in_place(&mut (*self.ptr.as_ptr()).data) };
4247+
}
4248+
}

library/alloctests/tests/arc.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,7 @@ fn make_mut_unsized() {
265265

266266
#[allow(unused)]
267267
mod pin_coerce_unsized {
268-
use alloc::sync::Arc;
268+
use alloc::sync::{Arc, UniqueArc};
269269
use core::pin::Pin;
270270

271271
pub trait MyTrait {}
@@ -275,4 +275,7 @@ mod pin_coerce_unsized {
275275
pub fn pin_arc(arg: Pin<Arc<String>>) -> Pin<Arc<dyn MyTrait>> {
276276
arg
277277
}
278+
pub fn pin_unique_arc(arg: Pin<UniqueArc<String>>) -> Pin<UniqueArc<dyn MyTrait>> {
279+
arg
280+
}
278281
}

library/std/src/sync/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,8 @@ pub use core::sync::Exclusive;
176176
#[stable(feature = "rust1", since = "1.0.0")]
177177
pub use core::sync::atomic;
178178

179+
#[unstable(feature = "unique_rc_arc", issue = "112566")]
180+
pub use alloc_crate::sync::UniqueArc;
179181
#[stable(feature = "rust1", since = "1.0.0")]
180182
pub use alloc_crate::sync::{Arc, Weak};
181183

0 commit comments

Comments
 (0)