@@ -252,9 +252,13 @@ use core::intrinsics::abort;
252252#[ cfg( not( no_global_oom_handling) ) ]
253253use core:: iter;
254254use core:: marker:: { PhantomData , Unsize } ;
255+ #[ cfg( not( no_global_oom_handling) ) ]
256+ use core:: mem:: MaybeUninit ;
255257use core:: mem:: { self , ManuallyDrop , align_of_val_raw} ;
256258use core:: num:: NonZeroUsize ;
257259use core:: ops:: { CoerceUnsized , Deref , DerefMut , DerefPure , DispatchFromDyn , LegacyReceiver } ;
260+ #[ cfg( not( no_global_oom_handling) ) ]
261+ use core:: ops:: { Residual , Try } ;
258262use core:: panic:: { RefUnwindSafe , UnwindSafe } ;
259263#[ cfg( not( no_global_oom_handling) ) ]
260264use core:: pin:: Pin ;
@@ -640,6 +644,93 @@ impl<T> Rc<T> {
640644 pub fn pin ( value : T ) -> Pin < Rc < T > > {
641645 unsafe { Pin :: new_unchecked ( Rc :: new ( value) ) }
642646 }
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+ try { allocation. assume_init ( ) }
729+ }
730+ } else {
731+ try { Rc :: new ( f ( & * this) ?) }
732+ }
733+ }
643734}
644735
645736impl < T , A : Allocator > Rc < T , A > {
0 commit comments