-
-
Notifications
You must be signed in to change notification settings - Fork 14.5k
Add {Arc, Rc}::{try_}into_unique #150631
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
base: main
Are you sure you want to change the base?
Add {Arc, Rc}::{try_}into_unique #150631
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -396,6 +396,85 @@ impl<T: ?Sized, A: Allocator> Rc<T, A> { | |
| ptr::drop_in_place(&mut (*self.ptr.as_ptr()).value); | ||
| } | ||
| } | ||
|
|
||
| /// Converts an `Rc` into a `UniqueRc` if the `Rc` has exactly one strong | ||
| /// reference. | ||
| /// | ||
| /// Otherwise, returns `None`. If the `Rc` is still needed in the error | ||
| /// case, consider using `try_into_unique` instead | ||
| /// | ||
| /// This will succeed even if there are outstanding weak references. | ||
| /// However, attempting to upgrade those weak references will fail while | ||
| /// this `UniqueRc` exists. | ||
| /// | ||
| /// # Example | ||
| /// | ||
| /// ``` | ||
| /// #![feature(unique_rc_arc)] | ||
| /// | ||
| /// use std::rc::{Rc, UniqueRc}; | ||
| /// | ||
| /// let a = Rc::new(7); | ||
| /// let mut unique_a: UniqueRc<i32> = Rc::into_unique(a).unwrap(); | ||
| /// *unique_a = 5; | ||
| /// ``` | ||
| #[inline] | ||
| #[unstable(feature = "unique_rc_arc", issue = "112566")] | ||
| pub fn into_unique(this: Self) -> Option<UniqueRc<T, A>> { | ||
| // Prevent `Weak` upgrades by decrementing the strong count to zero, | ||
| // or simply decrementing the refcount in the case that other strong | ||
| // owners remain. | ||
| this.inner().dec_strong(); | ||
| if this.inner().strong() != 0 { | ||
| return None; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Doesn't this double-decrement strong? We have the dec_strong above and then Drop for Rc will run here, decrementing it again, right? I think you might want to move the ManuallyDrop up? Maybe related: it's not entirely clear to me why this can't be implemented as I think it'd be good to add tests for the None path (we have a Some path test via doc comment but not the other way around). |
||
| } | ||
| 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) }; | ||
|
|
||
| Some(UniqueRc { ptr: this.ptr, _marker: PhantomData, _marker2: PhantomData, alloc }) | ||
| } | ||
|
|
||
| /// Converts an `Rc` into a `UniqueRc` if the `Rc` has exactly one strong | ||
| /// reference. | ||
| /// | ||
| /// Otherwise, an `Err` is returned containing the original `Rc`. | ||
| /// | ||
| /// This will succeed even if there are outstanding weak references. | ||
| /// However, attempting to upgrade those weak references will fail while | ||
| /// this `UniqueRc` exists. | ||
| /// | ||
| /// # Example | ||
| /// | ||
| /// ``` | ||
| /// #![feature(unique_rc_arc)] | ||
| /// | ||
| /// use std::rc::{Rc, UniqueRc}; | ||
| /// | ||
| /// let a = Rc::new(7); | ||
| /// let mut unique_a: UniqueRc<i32> = Rc::try_into_unique(a).unwrap(); | ||
| /// *unique_a = 5; | ||
| /// ``` | ||
| #[inline] | ||
| #[unstable(feature = "unique_rc_arc", issue = "112566")] | ||
| pub fn try_into_unique(this: Self) -> Result<UniqueRc<T, A>, Self> { | ||
| if Rc::strong_count(&this) != 1 { | ||
| return Err(this); | ||
| } | ||
| let this = ManuallyDrop::new(this); | ||
|
|
||
| // Prevent `Weak` upgrades by setting the strong count to zero. | ||
| this.inner().strong.set(0); | ||
|
|
||
| // 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) }; | ||
|
|
||
| Ok(UniqueRc { ptr: this.ptr, _marker: PhantomData, _marker2: PhantomData, alloc }) | ||
| } | ||
| } | ||
|
|
||
| impl<T> Rc<T> { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.