From 8ccbe9e6c8a8e5708b128a527da77cdb56acc702 Mon Sep 17 00:00:00 2001 From: Kevin Reid Date: Tue, 11 Jun 2024 15:16:47 -0700 Subject: [PATCH] `UniqueRc`: support allocators and `T: ?Sized`. Added the following (all unstable): * Defaulted type pararameter `A: Allocator`. * `UniqueRc::new_in()`. * `T: ?Sized` where possible. * `impl CoerceUnsized for UniqueRc`. * Drive-by doc polish: links and periods at the end of sentences. These changes are motivated by supporting the implementation of unsized `Rc::make_mut()` (PR #116113), but are also intended to be obvious generalizations of `UniqueRc` to support the things `Rc` does. --- alloc/src/rc.rs | 95 +++++++++++++++++++++++++++++-------------- alloc/src/rc/tests.rs | 26 ++++++++++++ 2 files changed, 91 insertions(+), 30 deletions(-) diff --git a/alloc/src/rc.rs b/alloc/src/rc.rs index f3a4803e0d4a5..336fd52d92fb3 100644 --- a/alloc/src/rc.rs +++ b/alloc/src/rc.rs @@ -3516,7 +3516,7 @@ fn data_offset_align(align: usize) -> usize { layout.size() + layout.padding_needed_for(align) } -/// A uniquely owned `Rc` +/// A uniquely owned [`Rc`]. /// /// This represents an `Rc` 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 @@ -3554,13 +3554,24 @@ fn data_offset_align(align: usize) -> usize { /// including fallible or async constructors. #[unstable(feature = "unique_rc_arc", issue = "112566")] #[derive(Debug)] -pub struct UniqueRc { +pub struct UniqueRc< + T: ?Sized, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { ptr: NonNull>, phantom: PhantomData>, + alloc: A, } +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl, U: ?Sized, A: Allocator> CoerceUnsized> + for UniqueRc +{ +} + +// Depends on A = Global impl UniqueRc { - /// Creates a new `UniqueRc` + /// Creates a new `UniqueRc`. /// /// Weak references to this `UniqueRc` can be created with [`UniqueRc::downgrade`]. Upgrading /// these weak references will fail before the `UniqueRc` has been converted into an [`Rc`]. @@ -3569,34 +3580,36 @@ impl UniqueRc { #[cfg(not(no_global_oom_handling))] #[unstable(feature = "unique_rc_arc", issue = "112566")] pub fn new(value: T) -> Self { - Self { - ptr: Box::leak(Box::new(RcBox { + Self::new_in(value, Global) + } +} + +impl UniqueRc { + /// Creates a new `UniqueRc` in the provided allocator. + /// + /// Weak references to this `UniqueRc` can be created with [`UniqueRc::downgrade`]. Upgrading + /// these weak references will fail before the `UniqueRc` has been converted into an [`Rc`]. + /// After converting the `UniqueRc` into an [`Rc`], any weak references created beforehand will + /// point to the new [`Rc`]. + #[cfg(not(no_global_oom_handling))] + #[unstable(feature = "unique_rc_arc", issue = "112566")] + pub fn new_in(value: T, alloc: A) -> Self { + let (ptr, alloc) = Box::into_unique(Box::new_in( + RcBox { strong: Cell::new(0), // keep one weak reference so if all the weak pointers that are created are dropped // the UniqueRc still stays valid. weak: Cell::new(1), value, - })) - .into(), - phantom: PhantomData, - } - } - - /// Creates a new weak reference to the `UniqueRc` - /// - /// Attempting to upgrade this weak reference will fail before the `UniqueRc` has been converted - /// to a [`Rc`] using [`UniqueRc::into_rc`]. - #[unstable(feature = "unique_rc_arc", issue = "112566")] - pub fn downgrade(this: &Self) -> Weak { - // SAFETY: This pointer was allocated at creation time and we guarantee that we only have - // one strong reference before converting to a regular Rc. - unsafe { - this.ptr.as_ref().inc_weak(); - } - Weak { ptr: this.ptr, alloc: Global } + }, + alloc, + )); + Self { ptr: ptr.into(), phantom: PhantomData, alloc } } +} - /// Converts the `UniqueRc` into a regular [`Rc`] +impl UniqueRc { + /// Converts the `UniqueRc` into a regular [`Rc`]. /// /// This consumes the `UniqueRc` and returns a regular [`Rc`] that contains the `value` that /// is passed to `into_rc`. @@ -3604,19 +3617,41 @@ impl UniqueRc { /// 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_rc(this: Self) -> Rc { + pub fn into_rc(this: Self) -> Rc { let mut 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_mut().strong.set(1); - Rc::from_inner(this.ptr) + Rc::from_inner_in(this.ptr, alloc) + } + } +} + +impl UniqueRc { + /// Creates a new weak reference to the `UniqueRc`. + /// + /// Attempting to upgrade this weak reference will fail before the `UniqueRc` has been converted + /// to a [`Rc`] using [`UniqueRc::into_rc`]. + #[unstable(feature = "unique_rc_arc", issue = "112566")] + pub fn downgrade(this: &Self) -> Weak { + // SAFETY: This pointer was allocated at creation time and we guarantee that we only have + // one strong reference before converting to a regular Rc. + unsafe { + this.ptr.as_ref().inc_weak(); } + Weak { ptr: this.ptr, alloc: this.alloc.clone() } } } #[unstable(feature = "unique_rc_arc", issue = "112566")] -impl Deref for UniqueRc { +impl Deref for UniqueRc { type Target = T; fn deref(&self) -> &T { @@ -3626,7 +3661,7 @@ impl Deref for UniqueRc { } #[unstable(feature = "unique_rc_arc", issue = "112566")] -impl DerefMut for UniqueRc { +impl DerefMut for UniqueRc { 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 @@ -3636,7 +3671,7 @@ impl DerefMut for UniqueRc { } #[unstable(feature = "unique_rc_arc", issue = "112566")] -unsafe impl<#[may_dangle] T> Drop for UniqueRc { +unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for UniqueRc { fn drop(&mut self) { unsafe { // destroy the contained object @@ -3646,7 +3681,7 @@ unsafe impl<#[may_dangle] T> Drop for UniqueRc { self.ptr.as_ref().dec_weak(); if self.ptr.as_ref().weak() == 0 { - Global.deallocate(self.ptr.cast(), Layout::for_value_raw(self.ptr.as_ptr())); + self.alloc.deallocate(self.ptr.cast(), Layout::for_value_raw(self.ptr.as_ptr())); } } } diff --git a/alloc/src/rc/tests.rs b/alloc/src/rc/tests.rs index c8a40603d9db2..0f09be7721fa9 100644 --- a/alloc/src/rc/tests.rs +++ b/alloc/src/rc/tests.rs @@ -606,6 +606,23 @@ fn test_unique_rc_drops_contents() { assert!(dropped); } +/// Exercise the non-default allocator usage. +#[test] +fn test_unique_rc_with_alloc_drops_contents() { + let mut dropped = false; + struct DropMe<'a>(&'a mut bool); + impl Drop for DropMe<'_> { + fn drop(&mut self) { + *self.0 = true; + } + } + { + let rc = UniqueRc::new_in(DropMe(&mut dropped), std::alloc::System); + drop(rc); + } + assert!(dropped); +} + #[test] fn test_unique_rc_weak_clone_holding_ref() { let mut v = UniqueRc::new(0u8); @@ -614,3 +631,12 @@ fn test_unique_rc_weak_clone_holding_ref() { let _ = w.clone(); // touch weak count *r = 123; } + +#[test] +fn test_unique_rc_unsizing_coercion() { + let mut rc: UniqueRc<[u8]> = UniqueRc::new([0u8; 3]); + assert_eq!(rc.len(), 3); + rc[0] = 123; + let rc: Rc<[u8]> = UniqueRc::into_rc(rc); + assert_eq!(*rc, [123, 0, 0]); +}