@@ -194,8 +194,8 @@ use core::hash::{Hash, Hasher};
194
194
use core:: marker:: { Tuple , Unsize } ;
195
195
use core:: mem:: { self , SizedTypeProperties } ;
196
196
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 ,
199
199
} ;
200
200
use core:: pin:: { Pin , PinCoerceUnsized } ;
201
201
use core:: ptr:: { self , NonNull , Unique } ;
@@ -389,6 +389,113 @@ impl<T> Box<T> {
389
389
pub fn try_new_zeroed ( ) -> Result < Box < mem:: MaybeUninit < T > > , AllocError > {
390
390
Box :: try_new_zeroed_in ( Global )
391
391
}
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
+ }
392
499
}
393
500
394
501
impl < T , A : Allocator > Box < T , A > {
0 commit comments