Skip to content

Commit 88ac38e

Browse files
committed
add Unique{Rc,Arc}::(try_)map
1 parent cdb8d49 commit 88ac38e

File tree

2 files changed

+335
-6
lines changed

2 files changed

+335
-6
lines changed

library/alloc/src/rc.rs

Lines changed: 168 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -252,8 +252,6 @@ use core::intrinsics::abort;
252252
#[cfg(not(no_global_oom_handling))]
253253
use core::iter;
254254
use core::marker::{PhantomData, Unsize};
255-
#[cfg(not(no_global_oom_handling))]
256-
use core::mem::MaybeUninit;
257255
use core::mem::{self, ManuallyDrop, align_of_val_raw};
258256
use core::num::NonZeroUsize;
259257
use core::ops::{CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn, LegacyReceiver};
@@ -675,7 +673,7 @@ impl<T> Rc<T> {
675673
unsafe {
676674
let ptr = Rc::into_raw(this);
677675
let value = ptr.read();
678-
let mut allocation = Rc::from_raw(ptr.cast::<MaybeUninit<U>>());
676+
let mut allocation = Rc::from_raw(ptr.cast::<mem::MaybeUninit<U>>());
679677

680678
Rc::get_mut_unchecked(&mut allocation).write(f(&value));
681679
allocation.assume_init()
@@ -687,7 +685,7 @@ impl<T> Rc<T> {
687685

688686
/// Attempts to map the value in an `Rc`, reusing the allocation if possible.
689687
///
690-
/// `f` is called on a reference to the value in the box, and if the operation succeeds, the
688+
/// `f` is called on a reference to the value in the `Rc`, and if the operation succeeds, the
691689
/// result is returned, also in an `Rc`.
692690
///
693691
/// Note: this is an associated function, which means that you have
@@ -722,7 +720,7 @@ impl<T> Rc<T> {
722720
unsafe {
723721
let ptr = Rc::into_raw(this);
724722
let value = ptr.read();
725-
let mut allocation = Rc::from_raw(ptr.cast::<MaybeUninit<R::Output>>());
723+
let mut allocation = Rc::from_raw(ptr.cast::<mem::MaybeUninit<R::Output>>());
726724

727725
Rc::get_mut_unchecked(&mut allocation).write(f(&value)?);
728726
try { allocation.assume_init() }
@@ -4093,6 +4091,129 @@ impl<T> UniqueRc<T> {
40934091
pub fn new(value: T) -> Self {
40944092
Self::new_in(value, Global)
40954093
}
4094+
4095+
/// Maps the value in a `UniqueRc`, reusing the allocation if possible.
4096+
///
4097+
/// `f` is called on a reference to the value in the `UniqueRc`, and the result is returned,
4098+
/// also in a `UniqueRc`.
4099+
///
4100+
/// Note: this is an associated function, which means that you have
4101+
/// to call it as `UniqueRc::map(&u, f)` instead of `u.map(f)`. This
4102+
/// is so that there is no conflict with a method on the inner type.
4103+
///
4104+
/// # Examples
4105+
///
4106+
/// ```
4107+
/// #![feature(smart_pointer_try_map)]
4108+
/// #![feature(unique_rc_arc)]
4109+
///
4110+
/// use std::rc::UniqueRc;
4111+
///
4112+
/// let r = UniqueRc::new(7);
4113+
/// let new = UniqueRc::map(r, |i| i + 7);
4114+
/// assert_eq!(*new, 14);
4115+
/// ```
4116+
#[cfg(not(no_global_oom_handling))]
4117+
#[unstable(feature = "smart_pointer_try_map", issue = "144419")]
4118+
pub fn map<U>(this: Self, f: impl FnOnce(T) -> U) -> UniqueRc<U> {
4119+
if size_of::<T>() == size_of::<U>()
4120+
&& align_of::<T>() == align_of::<U>()
4121+
&& UniqueRc::weak_count(&this) == 0
4122+
{
4123+
unsafe {
4124+
let ptr = UniqueRc::into_raw(this);
4125+
let value = ptr.read();
4126+
let mut allocation = UniqueRc::from_raw(ptr.cast::<mem::MaybeUninit<U>>());
4127+
4128+
allocation.write(f(value));
4129+
allocation.assume_init()
4130+
}
4131+
} else {
4132+
UniqueRc::new(f(UniqueRc::unwrap(this)))
4133+
}
4134+
}
4135+
4136+
/// Attempts to map the value in a `UniqueRc`, reusing the allocation if possible.
4137+
///
4138+
/// `f` is called on a reference to the value in the `UniqueRc`, and if the operation succeeds,
4139+
/// the result is returned, also in a `UniqueRc`.
4140+
///
4141+
/// Note: this is an associated function, which means that you have
4142+
/// to call it as `UniqueRc::try_map(&u, f)` instead of `u.try_map(f)`. This
4143+
/// is so that there is no conflict with a method on the inner type.
4144+
///
4145+
/// # Examples
4146+
///
4147+
/// ```
4148+
/// #![feature(smart_pointer_try_map)]
4149+
/// #![feature(unique_rc_arc)]
4150+
///
4151+
/// use std::rc::UniqueRc;
4152+
///
4153+
/// let b = UniqueRc::new(7);
4154+
/// let new = UniqueRc::try_map(b, u32::try_from).unwrap();
4155+
/// assert_eq!(*new, 7);
4156+
/// ```
4157+
#[cfg(not(no_global_oom_handling))]
4158+
#[unstable(feature = "smart_pointer_try_map", issue = "144419")]
4159+
pub fn try_map<R>(
4160+
this: Self,
4161+
f: impl FnOnce(T) -> R,
4162+
) -> <R::Residual as Residual<UniqueRc<R::Output>>>::TryType
4163+
where
4164+
R: Try,
4165+
R::Residual: Residual<UniqueRc<R::Output>>,
4166+
{
4167+
if size_of::<T>() == size_of::<R::Output>()
4168+
&& align_of::<T>() == align_of::<R::Output>()
4169+
&& UniqueRc::weak_count(&this) == 0
4170+
{
4171+
unsafe {
4172+
let ptr = UniqueRc::into_raw(this);
4173+
let value = ptr.read();
4174+
let mut allocation = UniqueRc::from_raw(ptr.cast::<mem::MaybeUninit<R::Output>>());
4175+
4176+
allocation.write(f(value)?);
4177+
try { allocation.assume_init() }
4178+
}
4179+
} else {
4180+
try { UniqueRc::new(f(UniqueRc::unwrap(this))?) }
4181+
}
4182+
}
4183+
4184+
#[cfg(not(no_global_oom_handling))]
4185+
fn unwrap(this: Self) -> T {
4186+
let this = ManuallyDrop::new(this);
4187+
let val: T = unsafe { ptr::read(&**this) };
4188+
4189+
this.inner().dec_strong();
4190+
let _weak = Weak { ptr: this.ptr, alloc: Global };
4191+
4192+
val
4193+
}
4194+
}
4195+
4196+
impl<T: ?Sized> UniqueRc<T> {
4197+
#[cfg(not(no_global_oom_handling))]
4198+
unsafe fn from_raw(ptr: *const T) -> Self {
4199+
let offset = unsafe { data_offset(ptr) };
4200+
4201+
// Reverse the offset to find the original RcInner.
4202+
let rc_ptr = unsafe { ptr.byte_sub(offset) as *mut RcInner<T> };
4203+
4204+
Self {
4205+
ptr: unsafe { NonNull::new_unchecked(rc_ptr) },
4206+
_marker: PhantomData,
4207+
_marker2: PhantomData,
4208+
alloc: Global,
4209+
}
4210+
}
4211+
4212+
#[cfg(not(no_global_oom_handling))]
4213+
fn into_raw(this: Self) -> *const T {
4214+
let this = ManuallyDrop::new(this);
4215+
Self::as_ptr(&*this)
4216+
}
40964217
}
40974218

40984219
impl<T, A: Allocator> UniqueRc<T, A> {
@@ -4143,6 +4264,40 @@ impl<T: ?Sized, A: Allocator> UniqueRc<T, A> {
41434264
Rc::from_inner_in(this.ptr, alloc)
41444265
}
41454266
}
4267+
4268+
#[cfg(not(no_global_oom_handling))]
4269+
fn weak_count(this: &Self) -> usize {
4270+
this.inner().weak() - 1
4271+
}
4272+
4273+
#[cfg(not(no_global_oom_handling))]
4274+
fn inner(&self) -> &RcInner<T> {
4275+
// SAFETY: while this UniqueRc is alive we're guaranteed that the inner pointer is valid.
4276+
unsafe { self.ptr.as_ref() }
4277+
}
4278+
4279+
#[cfg(not(no_global_oom_handling))]
4280+
fn as_ptr(this: &Self) -> *const T {
4281+
let ptr: *mut RcInner<T> = NonNull::as_ptr(this.ptr);
4282+
4283+
// SAFETY: This cannot go through Deref::deref or UniqueRc::inner because
4284+
// this is required to retain raw/mut provenance such that e.g. `get_mut` can
4285+
// write through the pointer after the Rc is recovered through `from_raw`.
4286+
unsafe { &raw mut (*ptr).value }
4287+
}
4288+
4289+
#[inline]
4290+
#[cfg(not(no_global_oom_handling))]
4291+
fn into_inner_with_allocator(this: Self) -> (NonNull<RcInner<T>>, A) {
4292+
let this = mem::ManuallyDrop::new(this);
4293+
(this.ptr, unsafe { ptr::read(&this.alloc) })
4294+
}
4295+
4296+
#[inline]
4297+
#[cfg(not(no_global_oom_handling))]
4298+
unsafe fn from_inner_in(ptr: NonNull<RcInner<T>>, alloc: A) -> Self {
4299+
Self { ptr, _marker: PhantomData, _marker2: PhantomData, alloc }
4300+
}
41464301
}
41474302

41484303
impl<T: ?Sized, A: Allocator + Clone> UniqueRc<T, A> {
@@ -4161,6 +4316,14 @@ impl<T: ?Sized, A: Allocator + Clone> UniqueRc<T, A> {
41614316
}
41624317
}
41634318

4319+
#[cfg(not(no_global_oom_handling))]
4320+
impl<T, A: Allocator> UniqueRc<mem::MaybeUninit<T>, A> {
4321+
unsafe fn assume_init(self) -> UniqueRc<T, A> {
4322+
let (ptr, alloc) = UniqueRc::into_inner_with_allocator(self);
4323+
unsafe { UniqueRc::from_inner_in(ptr.cast(), alloc) }
4324+
}
4325+
}
4326+
41644327
#[unstable(feature = "unique_rc_arc", issue = "112566")]
41654328
impl<T: ?Sized, A: Allocator> Deref for UniqueRc<T, A> {
41664329
type Target = T;

0 commit comments

Comments
 (0)