@@ -194,8 +194,8 @@ use core::hash::{Hash, Hasher};
194194use core:: marker:: { Tuple , Unsize } ;
195195use core:: mem:: { self , SizedTypeProperties } ;
196196use 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} ;
200200use core:: pin:: { Pin , PinCoerceUnsized } ;
201201use core:: ptr:: { self , NonNull , Unique } ;
@@ -389,6 +389,113 @@ 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+ struct Guard < T > ( * mut T ) ;
413+
414+ impl < T > Drop for Guard < T > {
415+ fn drop ( & mut self ) {
416+ let _box = unsafe { Box :: from_raw ( self . 0 ) } ;
417+ }
418+ }
419+
420+ if size_of :: < T > ( ) == size_of :: < U > ( ) && align_of :: < T > ( ) == align_of :: < U > ( ) {
421+ let guard = Guard ( Box :: into_raw ( this) ) ;
422+ unsafe {
423+ let new = f ( guard. 0 . read ( ) ) ;
424+ let ptr = guard. 0 ;
425+ mem:: forget ( guard) ;
426+ ptr. cast :: < U > ( ) . write ( new) ;
427+ Box :: from_raw ( ptr. cast :: < U > ( ) )
428+ }
429+ } else {
430+ Box :: new ( f ( * this) )
431+ }
432+ }
433+
434+ /// Attempts to map the value in a box, reusing the allocation if possible.
435+ ///
436+ /// `f` is called on the value in the box, and if the operation succeeds, the result is
437+ /// returned, also boxed.
438+ ///
439+ /// Note: this is an associated function, which means that you have
440+ /// to call it as `Box::try_map(b, f)` instead of `b.try_map(f)`. This
441+ /// is so that there is no conflict with a method on the inner type.
442+ ///
443+ /// # Examples
444+ ///
445+ /// ```
446+ /// #![feature(smart_pointer_try_map)]
447+ ///
448+ /// let b = Box::new(7);
449+ /// let new = Box::try_map(b, u32::try_from).unwrap();
450+ /// assert_eq!(*new, 7);
451+ /// ```
452+ #[ unstable( feature = "smart_pointer_try_map" , issue = "144419" ) ]
453+ pub fn try_map < R > (
454+ this : Self ,
455+ f : impl FnOnce ( T ) -> R ,
456+ ) -> <R :: Residual as Residual < Box < R :: Output > > >:: TryType
457+ where
458+ R : Try ,
459+ R :: Residual : Residual < Box < R :: Output > > ,
460+ {
461+ struct Guard < T > ( * mut T ) ;
462+
463+ impl < T > Drop for Guard < T > {
464+ fn drop ( & mut self ) {
465+ let _box = unsafe { Box :: from_raw ( self . 0 ) } ;
466+ }
467+ }
468+
469+ if size_of :: < T > ( ) == size_of :: < R :: Output > ( ) && align_of :: < T > ( ) == align_of :: < R :: Output > ( ) {
470+ let guard = Guard ( Box :: into_raw ( this) ) ;
471+ unsafe {
472+ let new = f ( guard. 0 . read ( ) ) ;
473+ let ptr = guard. 0 ;
474+ mem:: forget ( guard) ;
475+ match new. branch ( ) {
476+ ControlFlow :: Continue ( c) => {
477+ ptr. cast :: < R :: Output > ( ) . write ( c) ;
478+ <R :: Residual as Residual < Box < R :: Output > > >:: TryType :: from_output (
479+ Box :: from_raw ( ptr. cast :: < R :: Output > ( ) ) ,
480+ )
481+ }
482+ ControlFlow :: Break ( b) => {
483+ drop ( Box :: from_raw ( ptr) ) ;
484+ <R :: Residual as Residual < Box < R :: Output > > >:: TryType :: from_residual ( b)
485+ }
486+ }
487+ }
488+ } else {
489+ match f ( * this) . branch ( ) {
490+ ControlFlow :: Continue ( c) => {
491+ <R :: Residual as Residual < Box < R :: Output > > >:: TryType :: from_output ( Box :: new ( c) )
492+ }
493+ ControlFlow :: Break ( b) => {
494+ <R :: Residual as Residual < Box < R :: Output > > >:: TryType :: from_residual ( b)
495+ }
496+ }
497+ }
498+ }
392499}
393500
394501impl < T , A : Allocator > Box < T , A > {
0 commit comments