@@ -252,9 +252,11 @@ use core::intrinsics::abort;
252252#[ cfg( not( no_global_oom_handling) ) ]
253253use core:: iter;
254254use 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} ;
256256use core:: num:: NonZeroUsize ;
257- use core:: ops:: { CoerceUnsized , Deref , DerefMut , DerefPure , DispatchFromDyn , LegacyReceiver } ;
257+ use core:: ops:: {
258+ CoerceUnsized , Deref , DerefMut , DerefPure , DispatchFromDyn , LegacyReceiver , Residual , Try ,
259+ } ;
258260use core:: panic:: { RefUnwindSafe , UnwindSafe } ;
259261#[ cfg( not( no_global_oom_handling) ) ]
260262use core:: pin:: Pin ;
@@ -640,6 +642,95 @@ impl<T> Rc<T> {
640642 pub fn pin ( value : T ) -> Pin < Rc < T > > {
641643 unsafe { Pin :: new_unchecked ( Rc :: new ( value) ) }
642644 }
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+ }
643734}
644735
645736impl < T , A : Allocator > Rc < T , A > {
0 commit comments