Skip to content

Commit 0c65df4

Browse files
committed
add Box::(try_)map
1 parent 55b9b4d commit 0c65df4

File tree

2 files changed

+79
-2
lines changed

2 files changed

+79
-2
lines changed

library/alloc/src/boxed.rs

Lines changed: 78 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -192,10 +192,10 @@ use core::fmt;
192192
use core::future::Future;
193193
use core::hash::{Hash, Hasher};
194194
use core::marker::{Tuple, Unsize};
195-
use core::mem::{self, SizedTypeProperties};
195+
use core::mem::{self, MaybeUninit, SizedTypeProperties};
196196
use core::ops::{
197197
AsyncFn, AsyncFnMut, AsyncFnOnce, CoerceUnsized, Coroutine, CoroutineState, Deref, DerefMut,
198-
DerefPure, DispatchFromDyn, LegacyReceiver,
198+
DerefPure, DispatchFromDyn, LegacyReceiver, Residual, Try,
199199
};
200200
use core::pin::{Pin, PinCoerceUnsized};
201201
use core::ptr::{self, NonNull, Unique};
@@ -389,6 +389,82 @@ 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 (allocation, value) = unsafe {
414+
let ptr = Box::into_raw(this);
415+
let value = ptr.read();
416+
let allocation = Box::from_raw(ptr.cast::<MaybeUninit<U>>());
417+
(allocation, value)
418+
};
419+
420+
Box::write(allocation, f(value))
421+
} else {
422+
Box::new(f(*this))
423+
}
424+
}
425+
426+
/// Attempts to map the value in a box, reusing the allocation if possible.
427+
///
428+
/// `f` is called on the value in the box, and if the operation succeeds, the result is
429+
/// returned, also boxed.
430+
///
431+
/// Note: this is an associated function, which means that you have
432+
/// to call it as `Box::try_map(b, f)` instead of `b.try_map(f)`. This
433+
/// is so that there is no conflict with a method on the inner type.
434+
///
435+
/// # Examples
436+
///
437+
/// ```
438+
/// #![feature(smart_pointer_try_map)]
439+
///
440+
/// let b = Box::new(7);
441+
/// let new = Box::try_map(b, u32::try_from).unwrap();
442+
/// assert_eq!(*new, 7);
443+
/// ```
444+
#[unstable(feature = "smart_pointer_try_map", issue = "144419")]
445+
pub fn try_map<R>(
446+
this: Self,
447+
f: impl FnOnce(T) -> R,
448+
) -> <R::Residual as Residual<Box<R::Output>>>::TryType
449+
where
450+
R: Try,
451+
R::Residual: Residual<Box<R::Output>>,
452+
{
453+
if size_of::<T>() == size_of::<R::Output>() && align_of::<T>() == align_of::<R::Output>() {
454+
let (allocation, value) = unsafe {
455+
let ptr = Box::into_raw(this);
456+
let value = ptr.read();
457+
let allocation = Box::from_raw(ptr.cast::<MaybeUninit<R::Output>>());
458+
(allocation, value)
459+
};
460+
<R::Residual as Residual<Box<R::Output>>>::TryType::from_output(Box::write(
461+
allocation,
462+
f(value)?,
463+
))
464+
} else {
465+
<R::Residual as Residual<Box<R::Output>>>::TryType::from_output(Box::new(f(*this)?))
466+
}
467+
}
392468
}
393469

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