Skip to content

Commit e0b9347

Browse files
committed
Implement UniqueArc
1 parent 30508fa commit e0b9347

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

library/alloc/tests/arc.rs

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

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

272272
pub trait MyTrait {}
@@ -276,4 +276,7 @@ mod pin_coerce_unsized {
276276
pub fn pin_arc(arg: Pin<Arc<String>>) -> Pin<Arc<dyn MyTrait>> {
277277
arg
278278
}
279+
pub fn pin_unique_arc(arg: Pin<UniqueArc<String>>) -> Pin<UniqueArc<dyn MyTrait>> {
280+
arg
281+
}
279282
}

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)