Skip to content

Commit d5d5fea

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

File tree

2 files changed

+90
-2
lines changed

2 files changed

+90
-2
lines changed

library/alloc/src/boxed.rs

Lines changed: 89 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,93 @@ 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::<U>().is_multiple_of(align_of::<T>()) {
413+
let ptr = Box::into_raw(this);
414+
unsafe {
415+
ptr.cast::<U>().write(f(ptr.read()));
416+
Box::from_raw(ptr.cast::<U>())
417+
}
418+
} else {
419+
Box::new(f(*this))
420+
}
421+
}
422+
423+
/// Attempts to map the value in a box, reusing the allocation if possible.
424+
///
425+
/// `f` is called on the value in the box, and if the operation succeeds, the result is
426+
/// returned, also boxed.
427+
///
428+
/// Note: this is an associated function, which means that you have
429+
/// to call it as `Box::try_map(b, f)` instead of `b.try_map(f)`. This
430+
/// is so that there is no conflict with a method on the inner type.
431+
///
432+
/// # Examples
433+
///
434+
/// ```
435+
/// #![feature(smart_pointer_try_map)]
436+
///
437+
/// let b = Box::new(7);
438+
/// let new = Box::try_map(b, u32::try_from).unwrap();
439+
/// assert_eq!(*new, 7);
440+
/// ```
441+
#[unstable(feature = "smart_pointer_try_map", issue = "144419")]
442+
pub fn try_map<R>(
443+
this: Self,
444+
f: impl FnOnce(T) -> R,
445+
) -> <R::Residual as Residual<Box<R::Output>>>::TryType
446+
where
447+
R: Try,
448+
R::Residual: Residual<Box<R::Output>>,
449+
{
450+
if size_of::<T>() == size_of::<R::Output>()
451+
&& align_of::<R::Output>().is_multiple_of(align_of::<T>())
452+
{
453+
let ptr = Box::into_raw(this);
454+
unsafe {
455+
match f(ptr.read()).branch() {
456+
ControlFlow::Continue(c) => {
457+
ptr.cast::<R::Output>().write(c);
458+
<R::Residual as Residual<Box<R::Output>>>::TryType::from_output(
459+
Box::from_raw(ptr.cast::<R::Output>()),
460+
)
461+
}
462+
ControlFlow::Break(b) => {
463+
drop(Box::from_raw(ptr));
464+
<R::Residual as Residual<Box<R::Output>>>::TryType::from_residual(b)
465+
}
466+
}
467+
}
468+
} else {
469+
match f(*this).branch() {
470+
ControlFlow::Continue(c) => {
471+
<R::Residual as Residual<Box<R::Output>>>::TryType::from_output(Box::new(c))
472+
}
473+
ControlFlow::Break(b) => {
474+
<R::Residual as Residual<Box<R::Output>>>::TryType::from_residual(b)
475+
}
476+
}
477+
}
478+
}
392479
}
393480

394481
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)