Skip to content

Commit 929d326

Browse files
committed
add Box::(try_)map
1 parent fc5af18 commit 929d326

File tree

2 files changed

+92
-2
lines changed

2 files changed

+92
-2
lines changed

library/alloc/src/boxed.rs

Lines changed: 91 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -194,8 +194,8 @@ use core::hash::{Hash, Hasher};
194194
use core::marker::{Tuple, Unsize};
195195
use core::mem::{self, SizedTypeProperties};
196196
use core::ops::{
197-
AsyncFn, AsyncFnMut, AsyncFnOnce, CoerceUnsized, Coroutine, CoroutineState, Deref, DerefMut,
198-
DerefPure, DispatchFromDyn, LegacyReceiver,
197+
AsyncFn, AsyncFnMut, AsyncFnOnce, CoerceUnsized, ControlFlow, Coroutine, CoroutineState, Deref,
198+
DerefMut, DerefPure, DispatchFromDyn, FromResidual, LegacyReceiver, Residual, Try,
199199
};
200200
use core::pin::{Pin, PinCoerceUnsized};
201201
use core::ptr::{self, NonNull, Unique};
@@ -389,6 +389,95 @@ impl<T> Box<T> {
389389
pub fn try_new_zeroed() -> Result<Box<mem::MaybeUninit<T>>, AllocError> {
390390
Box::try_new_zeroed_in(Global)
391391
}
392+
393+
/// Maps the value in a box, reusing the allocation if possible.
394+
///
395+
/// `f` is called on the value in the box, and the result is returned, also boxed.
396+
///
397+
/// Note: this is an associated function, which means that you have
398+
/// to call it as `Box::map(b, f)` instead of `b.map(f)`. This
399+
/// is so that there is no conflict with a method on the inner type.
400+
///
401+
/// # Examples
402+
///
403+
/// ```
404+
/// #![feature(smart_pointer_try_map)]
405+
///
406+
/// let b = Box::new(7);
407+
/// let new = Box::map(b, |i| i + 7);
408+
/// assert_eq!(*new, 14);
409+
/// ```
410+
#[unstable(feature = "smart_pointer_try_map", issue = "144419")]
411+
pub fn map<U>(this: Self, f: impl FnOnce(T) -> U) -> Box<U> {
412+
if size_of::<T>() == size_of::<U>() && align_of::<T>() == align_of::<U>() {
413+
let ptr = &raw const *this;
414+
unsafe {
415+
let new = f(ptr.read());
416+
let ptr = Box::into_raw(this);
417+
ptr.cast::<U>().write(new);
418+
Box::from_raw(ptr.cast::<U>())
419+
}
420+
} else {
421+
Box::new(f(*this))
422+
}
423+
}
424+
425+
/// Attempts to map the value in a box, reusing the allocation if possible.
426+
///
427+
/// `f` is called on the value in the box, and if the operation succeeds, the result is
428+
/// returned, also boxed.
429+
///
430+
/// Note: this is an associated function, which means that you have
431+
/// to call it as `Box::try_map(b, f)` instead of `b.try_map(f)`. This
432+
/// is so that there is no conflict with a method on the inner type.
433+
///
434+
/// # Examples
435+
///
436+
/// ```
437+
/// #![feature(smart_pointer_try_map)]
438+
///
439+
/// let b = Box::new(7);
440+
/// let new = Box::try_map(b, u32::try_from).unwrap();
441+
/// assert_eq!(*new, 7);
442+
/// ```
443+
#[unstable(feature = "smart_pointer_try_map", issue = "144419")]
444+
pub fn try_map<R>(
445+
this: Self,
446+
f: impl FnOnce(T) -> R,
447+
) -> <R::Residual as Residual<Box<R::Output>>>::TryType
448+
where
449+
R: Try,
450+
R::Residual: Residual<Box<R::Output>>,
451+
{
452+
if size_of::<T>() == size_of::<R::Output>() && align_of::<T>() == align_of::<R::Output>() {
453+
let ptr = &raw const *this;
454+
unsafe {
455+
let new = f(ptr.read());
456+
let ptr = Box::into_raw(this);
457+
match new.branch() {
458+
ControlFlow::Continue(c) => {
459+
ptr.cast::<R::Output>().write(c);
460+
<R::Residual as Residual<Box<R::Output>>>::TryType::from_output(
461+
Box::from_raw(ptr.cast::<R::Output>()),
462+
)
463+
}
464+
ControlFlow::Break(b) => {
465+
drop(Box::from_raw(ptr));
466+
<R::Residual as Residual<Box<R::Output>>>::TryType::from_residual(b)
467+
}
468+
}
469+
}
470+
} else {
471+
match f(*this).branch() {
472+
ControlFlow::Continue(c) => {
473+
<R::Residual as Residual<Box<R::Output>>>::TryType::from_output(Box::new(c))
474+
}
475+
ControlFlow::Break(b) => {
476+
<R::Residual as Residual<Box<R::Output>>>::TryType::from_residual(b)
477+
}
478+
}
479+
}
480+
}
392481
}
393482

394483
impl<T, A: Allocator> Box<T, A> {

library/alloc/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@
153153
#![feature(trusted_len)]
154154
#![feature(trusted_random_access)]
155155
#![feature(try_trait_v2)]
156+
#![feature(try_trait_v2_residual)]
156157
#![feature(try_with_capacity)]
157158
#![feature(tuple_trait)]
158159
#![feature(ub_checks)]

0 commit comments

Comments
 (0)