Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement alloc::sync::UniqueArc #133572

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
182 changes: 181 additions & 1 deletion library/alloc/src/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use core::intrinsics::abort;
use core::iter;
use core::marker::{PhantomData, Unsize};
use core::mem::{self, ManuallyDrop, align_of_val_raw};
use core::ops::{CoerceUnsized, Deref, DerefPure, DispatchFromDyn, LegacyReceiver};
use core::ops::{CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn, LegacyReceiver};
use core::panic::{RefUnwindSafe, UnwindSafe};
use core::pin::{Pin, PinCoerceUnsized};
use core::ptr::{self, NonNull};
Expand Down Expand Up @@ -4012,3 +4012,183 @@ impl<T: core::error::Error + ?Sized> core::error::Error for Arc<T> {
core::error::Error::provide(&**self, req);
}
}

/// A uniquely owned [`Arc`].
///
/// This represents an `Arc` that is known to be uniquely owned -- that is, have exactly one strong
/// reference. Multiple weak pointers can be created, but attempts to upgrade those to strong
/// references will fail unless the `UniqueArc` they point to has been converted into a regular `Arc`.
///
/// Because they are uniquely owned, the contents of a `UniqueArc` can be freely mutated. A common
/// use case is to have an object be mutable during its initialization phase but then have it become
/// immutable and converted to a normal `Arc`.
///
/// This can be used as a flexible way to create cyclic data structures, as in the example below.
///
/// ```
/// #![feature(unique_rc_arc)]
/// use std::sync::{Arc, Weak, UniqueArc};
///
/// struct Gadget {
/// #[allow(dead_code)]
/// me: Weak<Gadget>,
/// }
///
/// fn create_gadget() -> Option<Arc<Gadget>> {
/// let mut rc = UniqueArc::new(Gadget {
/// me: Weak::new(),
/// });
/// rc.me = UniqueArc::downgrade(&rc);
/// Some(UniqueArc::into_arc(rc))
/// }
///
/// create_gadget().unwrap();
/// ```
///
/// An advantage of using `UniqueArc` over [`Arc::new_cyclic`] to build cyclic data structures is that
/// [`Arc::new_cyclic`]'s `data_fn` parameter cannot be async or return a [`Result`]. As shown in the
/// previous example, `UniqueArc` allows for more flexibility in the construction of cyclic data,
/// including fallible or async constructors.
#[unstable(feature = "unique_rc_arc", issue = "112566")]
#[derive(Debug)]
pub struct UniqueArc<
T: ?Sized,
#[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
> {
ptr: NonNull<ArcInner<T>>,
phantom: PhantomData<ArcInner<T>>,
alloc: A,
}

#[unstable(feature = "unique_rc_arc", issue = "112566")]
impl<T: ?Sized + Unsize<U>, U: ?Sized, A: Allocator> CoerceUnsized<UniqueArc<U, A>>
for UniqueArc<T, A>
{
}

// Depends on A = Global
impl<T> UniqueArc<T> {
/// Creates a new `UniqueArc`.
///
/// Weak references to this `UniqueArc` can be created with [`UniqueArc::downgrade`]. Upgrading
/// these weak references will fail before the `UniqueArc` has been converted into an [`Arc`].
/// After converting the `UniqueArc` into an [`Arc`], any weak references created beforehand will
/// point to the new [`Arc`].
#[cfg(not(no_global_oom_handling))]
#[unstable(feature = "unique_rc_arc", issue = "112566")]
pub fn new(value: T) -> Self {
Self::new_in(value, Global)
}
}

impl<T, A: Allocator> UniqueArc<T, A> {
/// Creates a new `UniqueArc` in the provided allocator.
///
/// Weak references to this `UniqueArc` can be created with [`UniqueArc::downgrade`]. Upgrading
/// these weak references will fail before the `UniqueArc` has been converted into an [`Arc`].
/// After converting the `UniqueArc` into an [`Arc`], any weak references created beforehand will
/// point to the new [`Arc`].
#[cfg(not(no_global_oom_handling))]
#[unstable(feature = "unique_rc_arc", issue = "112566")]
pub fn new_in(data: T, alloc: A) -> Self {
let (ptr, alloc) = Box::into_unique(Box::new_in(
ArcInner {
strong: atomic::AtomicUsize::new(0),
// keep one weak reference so if all the weak pointers that are created are dropped
// the UniqueArc still stays valid.
weak: atomic::AtomicUsize::new(1),
data,
},
alloc,
));
Self { ptr: ptr.into(), phantom: PhantomData, alloc }
}
}

impl<T: ?Sized, A: Allocator> UniqueArc<T, A> {
/// Converts the `UniqueArc` into a regular [`Arc`].
///
/// This consumes the `UniqueArc` and returns a regular [`Arc`] that contains the `value` that
/// is passed to `into_arc`.
///
/// Any weak references created before this method is called can now be upgraded to strong
/// references.
#[unstable(feature = "unique_rc_arc", issue = "112566")]
pub fn into_arc(this: Self) -> Arc<T, A> {
let this = ManuallyDrop::new(this);

// Move the allocator out.
// SAFETY: `this.alloc` will not be accessed again, nor dropped because it is in
// a `ManuallyDrop`.
let alloc: A = unsafe { ptr::read(&this.alloc) };

// SAFETY: This pointer was allocated at creation time so we know it is valid.
unsafe {
// Convert our weak reference into a strong reference
(*this.ptr.as_ptr()).strong.store(1, Release);
Arc::from_inner_in(this.ptr, alloc)
}
}
}

impl<T: ?Sized, A: Allocator + Clone> UniqueArc<T, A> {
/// Creates a new weak reference to the `UniqueArc`.
///
/// Attempting to upgrade this weak reference will fail before the `UniqueArc` has been converted
/// to a [`Arc`] using [`UniqueArc::into_arc`].
#[unstable(feature = "unique_rc_arc", issue = "112566")]
pub fn downgrade(this: &Self) -> Weak<T, A> {
// Using a relaxed ordering is alright here, as knowledge of the
// original reference prevents other threads from erroneously deleting
// the object or converting the object to a normal `Arc<T, A>`.
//
// Note that we don't need to test if the weak counter is locked because there
// are no such operations like `Arc::get_mut` or `Arc::make_mut` that will lock
// the weak counter.
//
// SAFETY: This pointer was allocated at creation time so we know it is valid.
let old_size = unsafe { (*this.ptr.as_ptr()).weak.fetch_add(1, Relaxed) };

// See comments in Arc::clone() for why we do this (for mem::forget).
if old_size > MAX_REFCOUNT {
abort();
}

Weak { ptr: this.ptr, alloc: this.alloc.clone() }
}
}

#[unstable(feature = "unique_rc_arc", issue = "112566")]
impl<T: ?Sized, A: Allocator> Deref for UniqueArc<T, A> {
type Target = T;

fn deref(&self) -> &T {
// SAFETY: This pointer was allocated at creation time so we know it is valid.
unsafe { &self.ptr.as_ref().data }
}
}

// #[unstable(feature = "unique_rc_arc", issue = "112566")]
#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")]
unsafe impl<T: ?Sized> PinCoerceUnsized for UniqueArc<T> {}

#[unstable(feature = "unique_rc_arc", issue = "112566")]
impl<T: ?Sized, A: Allocator> DerefMut for UniqueArc<T, A> {
fn deref_mut(&mut self) -> &mut T {
// SAFETY: This pointer was allocated at creation time so we know it is valid. We know we
// have unique ownership and therefore it's safe to make a mutable reference because
// `UniqueArc` owns the only strong reference to itself.
unsafe { &mut (*self.ptr.as_ptr()).data }
}
}

#[unstable(feature = "unique_rc_arc", issue = "112566")]
unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for UniqueArc<T, A> {
fn drop(&mut self) {
// See `Arc::drop_slow` which drops an `Arc` with a strong count of 0.
// SAFETY: This pointer was allocated at creation time so we know it is valid.
let _weak = Weak { ptr: self.ptr, alloc: &self.alloc };

unsafe { ptr::drop_in_place(&mut (*self.ptr.as_ptr()).data) };
}
}
5 changes: 4 additions & 1 deletion library/alloc/tests/arc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ fn make_mut_unsized() {

#[allow(unused)]
mod pin_coerce_unsized {
use alloc::sync::Arc;
use alloc::sync::{Arc, UniqueArc};
use core::pin::Pin;

pub trait MyTrait {}
Expand All @@ -276,4 +276,7 @@ mod pin_coerce_unsized {
pub fn pin_arc(arg: Pin<Arc<String>>) -> Pin<Arc<dyn MyTrait>> {
arg
}
pub fn pin_unique_arc(arg: Pin<UniqueArc<String>>) -> Pin<UniqueArc<dyn MyTrait>> {
arg
}
}
2 changes: 2 additions & 0 deletions library/std/src/sync/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,8 @@ pub use core::sync::Exclusive;
#[stable(feature = "rust1", since = "1.0.0")]
pub use core::sync::atomic;

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

Expand Down
Loading