Skip to content

Commit a8a35fb

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

File tree

2 files changed

+336
-10
lines changed

2 files changed

+336
-10
lines changed

library/alloc/src/rc.rs

Lines changed: 169 additions & 7 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};
@@ -651,7 +649,7 @@ impl<T> Rc<T> {
651649
/// an `Rc`.
652650
///
653651
/// Note: this is an associated function, which means that you have
654-
/// to call it as `Rc::map(&r, f)` instead of `r.map(f)`. This
652+
/// to call it as `Rc::map(r, f)` instead of `r.map(f)`. This
655653
/// is so that there is no conflict with a method on the inner type.
656654
///
657655
/// # Examples
@@ -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,11 +685,11 @@ 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
694-
/// to call it as `Rc::try_map(&r, f)` instead of `r.try_map(f)`. This
692+
/// to call it as `Rc::try_map(r, f)` instead of `r.try_map(f)`. This
695693
/// is so that there is no conflict with a method on the inner type.
696694
///
697695
/// # Examples
@@ -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,128 @@ 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+
let _weak = Weak { ptr: this.ptr, alloc: Global };
4190+
4191+
val
4192+
}
4193+
}
4194+
4195+
impl<T: ?Sized> UniqueRc<T> {
4196+
#[cfg(not(no_global_oom_handling))]
4197+
unsafe fn from_raw(ptr: *const T) -> Self {
4198+
let offset = unsafe { data_offset(ptr) };
4199+
4200+
// Reverse the offset to find the original RcInner.
4201+
let rc_ptr = unsafe { ptr.byte_sub(offset) as *mut RcInner<T> };
4202+
4203+
Self {
4204+
ptr: unsafe { NonNull::new_unchecked(rc_ptr) },
4205+
_marker: PhantomData,
4206+
_marker2: PhantomData,
4207+
alloc: Global,
4208+
}
4209+
}
4210+
4211+
#[cfg(not(no_global_oom_handling))]
4212+
fn into_raw(this: Self) -> *const T {
4213+
let this = ManuallyDrop::new(this);
4214+
Self::as_ptr(&*this)
4215+
}
40964216
}
40974217

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

41484302
impl<T: ?Sized, A: Allocator + Clone> UniqueRc<T, A> {
@@ -4161,6 +4315,14 @@ impl<T: ?Sized, A: Allocator + Clone> UniqueRc<T, A> {
41614315
}
41624316
}
41634317

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

0 commit comments

Comments
 (0)