Skip to content

Commit 14803bd

Browse files
committed
Auto merge of rust-lang#111849 - eholk:uniquearc, r=Mark-Simulacrum
Add `alloc::rc::UniqueRc` This PR implements `UniqueRc` as described in rust-lang/libs-team#90. I've tried to stick to the API proposed there, incorporating the feedback from the ACP review. For now I've just implemented `UniqueRc`, but we'll want `UniqueArc` as well. I wanted to get feedback on this implementation first since the `UniqueArc` version should be mostly a copy/paste/rename job.
2 parents fe7454b + 53003cd commit 14803bd

File tree

2 files changed

+184
-3
lines changed

2 files changed

+184
-3
lines changed

library/alloc/src/rc.rs

+139-3
Original file line numberDiff line numberDiff line change
@@ -258,12 +258,12 @@ use core::iter;
258258
use core::marker::{PhantomData, Unsize};
259259
#[cfg(not(no_global_oom_handling))]
260260
use core::mem::size_of_val;
261-
use core::mem::{self, align_of_val_raw, forget};
262-
use core::ops::{CoerceUnsized, Deref, DispatchFromDyn, Receiver};
261+
use core::mem::{self, align_of_val_raw, forget, ManuallyDrop};
262+
use core::ops::{CoerceUnsized, Deref, DerefMut, DispatchFromDyn, Receiver};
263263
use core::panic::{RefUnwindSafe, UnwindSafe};
264264
#[cfg(not(no_global_oom_handling))]
265265
use core::pin::Pin;
266-
use core::ptr::{self, NonNull};
266+
use core::ptr::{self, drop_in_place, NonNull};
267267
#[cfg(not(no_global_oom_handling))]
268268
use core::slice::from_raw_parts_mut;
269269

@@ -2744,3 +2744,139 @@ fn data_offset_align(align: usize) -> usize {
27442744
let layout = Layout::new::<RcBox<()>>();
27452745
layout.size() + layout.padding_needed_for(align)
27462746
}
2747+
2748+
/// A uniquely owned `Rc`
2749+
///
2750+
/// This represents an `Rc` that is known to be uniquely owned -- that is, have exactly one strong
2751+
/// reference. Multiple weak pointers can be created, but attempts to upgrade those to strong
2752+
/// references will fail unless the `UniqueRc` they point to has been converted into a regular `Rc`.
2753+
///
2754+
/// Because they are uniquely owned, the contents of a `UniqueRc` can be freely mutated. A common
2755+
/// use case is to have an object be mutable during its initialization phase but then have it become
2756+
/// immutable and converted to a normal `Rc`.
2757+
///
2758+
/// This can be used as a flexible way to create cyclic data structures, as in the example below.
2759+
///
2760+
/// ```
2761+
/// #![feature(unique_rc_arc)]
2762+
/// use std::rc::{Rc, Weak, UniqueRc};
2763+
///
2764+
/// struct Gadget {
2765+
/// #[allow(dead_code)]
2766+
/// me: Weak<Gadget>,
2767+
/// }
2768+
///
2769+
/// fn create_gadget() -> Option<Rc<Gadget>> {
2770+
/// let mut rc = UniqueRc::new(Gadget {
2771+
/// me: Weak::new(),
2772+
/// });
2773+
/// rc.me = UniqueRc::downgrade(&rc);
2774+
/// Some(UniqueRc::into_rc(rc))
2775+
/// }
2776+
///
2777+
/// create_gadget().unwrap();
2778+
/// ```
2779+
///
2780+
/// An advantage of using `UniqueRc` over [`Rc::new_cyclic`] to build cyclic data structures is that
2781+
/// [`Rc::new_cyclic`]'s `data_fn` parameter cannot be async or return a [`Result`]. As shown in the
2782+
/// previous example, `UniqueRc` allows for more flexibility in the construction of cyclic data,
2783+
/// including fallible or async constructors.
2784+
#[unstable(feature = "unique_rc_arc", issue = "112566")]
2785+
#[derive(Debug)]
2786+
pub struct UniqueRc<T> {
2787+
ptr: NonNull<RcBox<T>>,
2788+
phantom: PhantomData<RcBox<T>>,
2789+
}
2790+
2791+
impl<T> UniqueRc<T> {
2792+
/// Creates a new `UniqueRc`
2793+
///
2794+
/// Weak references to this `UniqueRc` can be created with [`UniqueRc::downgrade`]. Upgrading
2795+
/// these weak references will fail before the `UniqueRc` has been converted into an [`Rc`].
2796+
/// After converting the `UniqueRc` into an [`Rc`], any weak references created beforehand will
2797+
/// point to the new [`Rc`].
2798+
#[cfg(not(no_global_oom_handling))]
2799+
#[unstable(feature = "unique_rc_arc", issue = "112566")]
2800+
pub fn new(value: T) -> Self {
2801+
Self {
2802+
ptr: Box::leak(Box::new(RcBox {
2803+
strong: Cell::new(0),
2804+
// keep one weak reference so if all the weak pointers that are created are dropped
2805+
// the UniqueRc still stays valid.
2806+
weak: Cell::new(1),
2807+
value,
2808+
}))
2809+
.into(),
2810+
phantom: PhantomData,
2811+
}
2812+
}
2813+
2814+
/// Creates a new weak reference to the `UniqueRc`
2815+
///
2816+
/// Attempting to upgrade this weak reference will fail before the `UniqueRc` has been converted
2817+
/// to a [`Rc`] using [`UniqueRc::into_rc`].
2818+
#[unstable(feature = "unique_rc_arc", issue = "112566")]
2819+
pub fn downgrade(this: &Self) -> Weak<T> {
2820+
// SAFETY: This pointer was allocated at creation time and we guarantee that we only have
2821+
// one strong reference before converting to a regular Rc.
2822+
unsafe {
2823+
this.ptr.as_ref().inc_weak();
2824+
}
2825+
Weak { ptr: this.ptr }
2826+
}
2827+
2828+
/// Converts the `UniqueRc` into a regular [`Rc`]
2829+
///
2830+
/// This consumes the `UniqueRc` and returns a regular [`Rc`] that contains the `value` that
2831+
/// is passed to `into_rc`.
2832+
///
2833+
/// Any weak references created before this method is called can now be upgraded to strong
2834+
/// references.
2835+
#[unstable(feature = "unique_rc_arc", issue = "112566")]
2836+
pub fn into_rc(this: Self) -> Rc<T> {
2837+
let mut this = ManuallyDrop::new(this);
2838+
// SAFETY: This pointer was allocated at creation time so we know it is valid.
2839+
unsafe {
2840+
// Convert our weak reference into a strong reference
2841+
this.ptr.as_mut().strong.set(1);
2842+
Rc::from_inner(this.ptr)
2843+
}
2844+
}
2845+
}
2846+
2847+
#[unstable(feature = "unique_rc_arc", issue = "112566")]
2848+
impl<T> Deref for UniqueRc<T> {
2849+
type Target = T;
2850+
2851+
fn deref(&self) -> &T {
2852+
// SAFETY: This pointer was allocated at creation time so we know it is valid.
2853+
unsafe { &self.ptr.as_ref().value }
2854+
}
2855+
}
2856+
2857+
#[unstable(feature = "unique_rc_arc", issue = "112566")]
2858+
impl<T> DerefMut for UniqueRc<T> {
2859+
fn deref_mut(&mut self) -> &mut T {
2860+
// SAFETY: This pointer was allocated at creation time so we know it is valid. We know we
2861+
// have unique ownership and therefore it's safe to make a mutable reference because
2862+
// `UniqueRc` owns the only strong reference to itself.
2863+
unsafe { &mut (*self.ptr.as_ptr()).value }
2864+
}
2865+
}
2866+
2867+
#[unstable(feature = "unique_rc_arc", issue = "112566")]
2868+
unsafe impl<#[may_dangle] T> Drop for UniqueRc<T> {
2869+
fn drop(&mut self) {
2870+
unsafe {
2871+
// destroy the contained object
2872+
drop_in_place(DerefMut::deref_mut(self));
2873+
2874+
// remove the implicit "strong weak" pointer now that we've destroyed the contents.
2875+
self.ptr.as_ref().dec_weak();
2876+
2877+
if self.ptr.as_ref().weak() == 0 {
2878+
Global.deallocate(self.ptr.cast(), Layout::for_value(self.ptr.as_ref()));
2879+
}
2880+
}
2881+
}
2882+
}

library/alloc/src/rc/tests.rs

+45
Original file line numberDiff line numberDiff line change
@@ -574,3 +574,48 @@ fn test_rc_cyclic_with_two_ref() {
574574
assert_eq!(Rc::strong_count(&two_refs), 3);
575575
assert_eq!(Rc::weak_count(&two_refs), 2);
576576
}
577+
578+
#[test]
579+
fn test_unique_rc_weak() {
580+
let rc = UniqueRc::new(42);
581+
let weak = UniqueRc::downgrade(&rc);
582+
assert!(weak.upgrade().is_none());
583+
584+
let _rc = UniqueRc::into_rc(rc);
585+
assert_eq!(*weak.upgrade().unwrap(), 42);
586+
}
587+
588+
#[test]
589+
fn test_unique_rc_drop_weak() {
590+
let rc = UniqueRc::new(42);
591+
let weak = UniqueRc::downgrade(&rc);
592+
mem::drop(weak);
593+
594+
let rc = UniqueRc::into_rc(rc);
595+
assert_eq!(*rc, 42);
596+
}
597+
598+
#[test]
599+
fn test_unique_rc_drops_contents() {
600+
let mut dropped = false;
601+
struct DropMe<'a>(&'a mut bool);
602+
impl Drop for DropMe<'_> {
603+
fn drop(&mut self) {
604+
*self.0 = true;
605+
}
606+
}
607+
{
608+
let rc = UniqueRc::new(DropMe(&mut dropped));
609+
drop(rc);
610+
}
611+
assert!(dropped);
612+
}
613+
614+
#[test]
615+
fn test_unique_rc_weak_clone_holding_ref() {
616+
let mut v = UniqueRc::new(0u8);
617+
let w = UniqueRc::downgrade(&v);
618+
let r = &mut *v;
619+
let _ = w.clone(); // touch weak count
620+
*r = 123;
621+
}

0 commit comments

Comments
 (0)