@@ -252,9 +252,11 @@ use core::intrinsics::abort;
252
252
#[ cfg( not( no_global_oom_handling) ) ]
253
253
use core:: iter;
254
254
use core:: marker:: { PhantomData , Unsize } ;
255
- use core:: mem:: { self , ManuallyDrop , align_of_val_raw} ;
255
+ use core:: mem:: { self , ManuallyDrop , MaybeUninit , align_of_val_raw} ;
256
256
use core:: num:: NonZeroUsize ;
257
257
use core:: ops:: { CoerceUnsized , Deref , DerefMut , DerefPure , DispatchFromDyn , LegacyReceiver } ;
258
+ #[ cfg( not( no_global_oom_handling) ) ]
259
+ use core:: ops:: { Residual , Try } ;
258
260
use core:: panic:: { RefUnwindSafe , UnwindSafe } ;
259
261
#[ cfg( not( no_global_oom_handling) ) ]
260
262
use core:: pin:: Pin ;
@@ -640,6 +642,95 @@ impl<T> Rc<T> {
640
642
pub fn pin ( value : T ) -> Pin < Rc < T > > {
641
643
unsafe { Pin :: new_unchecked ( Rc :: new ( value) ) }
642
644
}
645
+
646
+ /// Maps the value in an `Rc`, reusing the allocation if possible.
647
+ ///
648
+ /// `f` is called on a reference to the value in the `Rc`, and the result is returned, also in
649
+ /// an `Rc`.
650
+ ///
651
+ /// Note: this is an associated function, which means that you have
652
+ /// to call it as `Rc::map(&r, f)` instead of `r.map(f)`. This
653
+ /// is so that there is no conflict with a method on the inner type.
654
+ ///
655
+ /// # Examples
656
+ ///
657
+ /// ```
658
+ /// #![feature(smart_pointer_try_map)]
659
+ ///
660
+ /// use std::rc::Rc;
661
+ ///
662
+ /// let r = Rc::new(7);
663
+ /// let new = Rc::map(r, |i| i + 7);
664
+ /// assert_eq!(*new, 14);
665
+ /// ```
666
+ #[ cfg( not( no_global_oom_handling) ) ]
667
+ #[ unstable( feature = "smart_pointer_try_map" , issue = "144419" ) ]
668
+ pub fn map < U > ( this : Self , f : impl FnOnce ( & T ) -> U ) -> Rc < U > {
669
+ if size_of :: < T > ( ) == size_of :: < U > ( )
670
+ && align_of :: < T > ( ) == align_of :: < U > ( )
671
+ && Rc :: is_unique ( & this)
672
+ {
673
+ unsafe {
674
+ let ptr = Rc :: into_raw ( this) ;
675
+ let value = ptr. read ( ) ;
676
+ let mut allocation = Rc :: from_raw ( ptr. cast :: < MaybeUninit < U > > ( ) ) ;
677
+
678
+ Rc :: get_mut_unchecked ( & mut allocation) . write ( f ( & value) ) ;
679
+ allocation. assume_init ( )
680
+ }
681
+ } else {
682
+ Rc :: new ( f ( & * this) )
683
+ }
684
+ }
685
+
686
+ /// Attempts to map the value in an `Rc`, reusing the allocation if possible.
687
+ ///
688
+ /// `f` is called on a reference to the value in the box, and if the operation succeeds, the
689
+ /// result is returned, also in an `Rc`.
690
+ ///
691
+ /// Note: this is an associated function, which means that you have
692
+ /// to call it as `Rc::try_map(&r, f)` instead of `r.try_map(f)`. This
693
+ /// is so that there is no conflict with a method on the inner type.
694
+ ///
695
+ /// # Examples
696
+ ///
697
+ /// ```
698
+ /// #![feature(smart_pointer_try_map)]
699
+ ///
700
+ /// use std::rc::Rc;
701
+ ///
702
+ /// let b = Rc::new(7);
703
+ /// let new = Rc::try_map(b, |&i| u32::try_from(i)).unwrap();
704
+ /// assert_eq!(*new, 7);
705
+ /// ```
706
+ #[ cfg( not( no_global_oom_handling) ) ]
707
+ #[ unstable( feature = "smart_pointer_try_map" , issue = "144419" ) ]
708
+ pub fn try_map < R > (
709
+ this : Self ,
710
+ f : impl FnOnce ( & T ) -> R ,
711
+ ) -> <R :: Residual as Residual < Rc < R :: Output > > >:: TryType
712
+ where
713
+ R : Try ,
714
+ R :: Residual : Residual < Rc < R :: Output > > ,
715
+ {
716
+ if size_of :: < T > ( ) == size_of :: < R :: Output > ( )
717
+ && align_of :: < T > ( ) == align_of :: < R :: Output > ( )
718
+ && Rc :: is_unique ( & this)
719
+ {
720
+ unsafe {
721
+ let ptr = Rc :: into_raw ( this) ;
722
+ let value = ptr. read ( ) ;
723
+ let mut allocation = Rc :: from_raw ( ptr. cast :: < MaybeUninit < R :: Output > > ( ) ) ;
724
+
725
+ Rc :: get_mut_unchecked ( & mut allocation) . write ( f ( & value) ?) ;
726
+ <R :: Residual as Residual < Rc < R :: Output > > >:: TryType :: from_output (
727
+ allocation. assume_init ( ) ,
728
+ )
729
+ }
730
+ } else {
731
+ <R :: Residual as Residual < Rc < R :: Output > > >:: TryType :: from_output ( Rc :: new ( f ( & * this) ?) )
732
+ }
733
+ }
643
734
}
644
735
645
736
impl < T , A : Allocator > Rc < T , A > {
0 commit comments