@@ -670,7 +670,6 @@ impl<'a, T: ?Sized> Ref<'a, T> {
670670 {
671671 // Avoid decrementing the borrow flag on Drop.
672672 let orig = ManuallyDrop :: new ( orig) ;
673-
674673 Ref {
675674 value : NonNull :: from ( f ( & * orig) ) ,
676675 state : orig. state ,
@@ -679,6 +678,27 @@ impl<'a, T: ?Sized> Ref<'a, T> {
679678 }
680679 }
681680
681+ /// Tries to makes a new `Ref` for a component of the borrowed data.
682+ /// On failure, the original guard is returned alongside with the error
683+ /// returned by the closure.
684+ #[ inline]
685+ pub fn try_map < U : ?Sized , E > (
686+ orig : Ref < ' a , T > ,
687+ f : impl FnOnce ( & T ) -> Result < & U , E > ,
688+ ) -> Result < Ref < ' a , U > , ( Self , E ) > {
689+ // Avoid decrementing the borrow flag on Drop.
690+ let orig = ManuallyDrop :: new ( orig) ;
691+ match f ( & * orig) {
692+ Ok ( value) => Ok ( Ref {
693+ value : NonNull :: from ( value) ,
694+ state : orig. state ,
695+ borrow_shift : orig. borrow_shift ,
696+ marker : PhantomData ,
697+ } ) ,
698+ Err ( e) => Err ( ( ManuallyDrop :: into_inner ( orig) , e) ) ,
699+ }
700+ }
701+
682702 /// Filters and maps a reference to a new type.
683703 #[ inline]
684704 pub fn filter_map < U : ?Sized , F > ( orig : Ref < ' a , T > , f : F ) -> Result < Ref < ' a , U > , Self >
@@ -742,7 +762,6 @@ impl<'a, T: ?Sized> RefMut<'a, T> {
742762 {
743763 // Avoid decrementing the borrow flag on Drop.
744764 let mut orig = ManuallyDrop :: new ( orig) ;
745-
746765 RefMut {
747766 value : NonNull :: from ( f ( & mut * orig) ) ,
748767 state : orig. state ,
@@ -751,6 +770,27 @@ impl<'a, T: ?Sized> RefMut<'a, T> {
751770 }
752771 }
753772
773+ /// Tries to makes a new `RefMut` for a component of the borrowed data.
774+ /// On failure, the original guard is returned alongside with the error
775+ /// returned by the closure.
776+ #[ inline]
777+ pub fn try_map < U : ?Sized , E > (
778+ orig : RefMut < ' a , T > ,
779+ f : impl FnOnce ( & mut T ) -> Result < & mut U , E > ,
780+ ) -> Result < RefMut < ' a , U > , ( Self , E ) > {
781+ // Avoid decrementing the borrow flag on Drop.
782+ let mut orig = ManuallyDrop :: new ( orig) ;
783+ match f ( & mut * orig) {
784+ Ok ( value) => Ok ( RefMut {
785+ value : NonNull :: from ( value) ,
786+ state : orig. state ,
787+ borrow_bitmask : orig. borrow_bitmask ,
788+ marker : PhantomData ,
789+ } ) ,
790+ Err ( e) => Err ( ( ManuallyDrop :: into_inner ( orig) , e) ) ,
791+ }
792+ }
793+
754794 /// Filters and maps a mutable reference to a new type.
755795 #[ inline]
756796 pub fn filter_map < U : ?Sized , F > ( orig : RefMut < ' a , T > , f : F ) -> Result < RefMut < ' a , U > , Self >
@@ -759,17 +799,13 @@ impl<'a, T: ?Sized> RefMut<'a, T> {
759799 {
760800 // Avoid decrementing the mutable borrow flag on Drop.
761801 let mut orig = ManuallyDrop :: new ( orig) ;
762-
763802 match f ( & mut * orig) {
764- Some ( value) => {
765- let value = NonNull :: from ( value) ;
766- Ok ( RefMut {
767- value,
768- state : orig. state ,
769- borrow_bitmask : orig. borrow_bitmask ,
770- marker : PhantomData ,
771- } )
772- }
803+ Some ( value) => Ok ( RefMut {
804+ value : NonNull :: from ( value) ,
805+ state : orig. state ,
806+ borrow_bitmask : orig. borrow_bitmask ,
807+ marker : PhantomData ,
808+ } ) ,
773809 None => Err ( ManuallyDrop :: into_inner ( orig) ) ,
774810 }
775811 }
@@ -827,6 +863,19 @@ mod tests {
827863 assert_eq ! ( state, NOT_BORROWED - ( 1 << DATA_BORROW_SHIFT ) ) ;
828864 assert_eq ! ( * new_ref, 3 ) ;
829865
866+ let Ok ( new_ref) = Ref :: try_map :: < _ , u8 > ( new_ref, |_| Ok ( & 4 ) ) else {
867+ unreachable ! ( )
868+ } ;
869+
870+ assert_eq ! ( state, NOT_BORROWED - ( 1 << DATA_BORROW_SHIFT ) ) ;
871+ assert_eq ! ( * new_ref, 4 ) ;
872+
873+ let ( new_ref, err) = Ref :: try_map :: < u8 , u8 > ( new_ref, |_| Err ( 5 ) ) . unwrap_err ( ) ;
874+ assert_eq ! ( state, NOT_BORROWED - ( 1 << DATA_BORROW_SHIFT ) ) ;
875+ assert_eq ! ( err, 5 ) ;
876+ // Unchanged
877+ assert_eq ! ( * new_ref, 4 ) ;
878+
830879 let new_ref = Ref :: filter_map ( new_ref, |_| Option :: < & u8 > :: None ) ;
831880
832881 assert_eq ! ( state, NOT_BORROWED - ( 1 << DATA_BORROW_SHIFT ) ) ;
0 commit comments