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