@@ -16,7 +16,7 @@ use std::cmp::Ordering;
1616use std:: fmt:: { self , Debug , Display } ;
1717use std:: hash:: { Hash , Hasher } ;
1818use std:: marker:: PhantomData ;
19- use std:: mem;
19+ use std:: mem:: { self , ManuallyDrop } ;
2020use std:: ops:: { Deref , DerefMut } ;
2121use std:: ptr:: { self , NonNull } ;
2222use std:: rc:: Rc ;
@@ -194,9 +194,7 @@ impl<T: ?Sized> Gc<T> {
194194 /// unsafe { Gc::from_raw(x_ptr) };
195195 /// ```
196196 pub fn into_raw ( this : Self ) -> * const T {
197- let ptr: * const T = GcBox :: value_ptr ( this. inner_ptr ( ) ) ;
198- mem:: forget ( this) ;
199- ptr
197+ GcBox :: value_ptr ( ManuallyDrop :: new ( this) . inner_ptr ( ) )
200198 }
201199
202200 /// Constructs an `Gc` from a raw pointer.
@@ -747,7 +745,7 @@ impl<'a, T: ?Sized> GcCellRef<'a, T> {
747745 }
748746 }
749747
750- /// Makes a new `GcCellRef` from a component of the borrowed data.
748+ /// Makes a new `GcCellRef` for a component of the borrowed data.
751749 ///
752750 /// The `GcCell` is already immutably borrowed, so this cannot fail.
753751 ///
@@ -763,24 +761,65 @@ impl<'a, T: ?Sized> GcCellRef<'a, T> {
763761 /// let c = GcCell::new((5, 'b'));
764762 /// let b1: GcCellRef<(u32, char)> = c.borrow();
765763 /// let b2: GcCellRef<u32> = GcCellRef::map(b1, |t| &t.0);
766- /// // assert_eq!(b2, 5);
764+ /// assert_eq!(* b2, 5);
767765 /// ```
768766 #[ inline]
769767 pub fn map < U , F > ( orig : Self , f : F ) -> GcCellRef < ' a , U >
770768 where
771769 U : ?Sized ,
772770 F : FnOnce ( & T ) -> & U ,
773771 {
774- let ret = GcCellRef {
775- flags : orig. flags ,
776- value : f ( orig. value ) ,
777- } ;
772+ let value = f ( orig. value ) ;
778773
779774 // We have to tell the compiler not to call the destructor of GcCellRef,
780775 // because it will update the borrow flags.
781- std :: mem :: forget ( orig) ;
776+ let orig = ManuallyDrop :: new ( orig) ;
782777
783- ret
778+ GcCellRef {
779+ flags : orig. flags ,
780+ value,
781+ }
782+ }
783+
784+ /// Makes a new `GcCellRef` for an optional component of the borrowed data.
785+ /// The original guard is returned as an `Err(..)` if the closure returns
786+ /// `None`.
787+ ///
788+ /// The `GcCell` is already immutably borrowed, so this cannot fail.
789+ ///
790+ /// This is an associated function that needs to be used as
791+ /// `GcCellRef::filter_map(...)`. A method would interfere with methods of
792+ /// the same name on the contents of a `GcCellRef` used through `Deref`.
793+ ///
794+ /// # Examples
795+ ///
796+ /// ```
797+ /// use gc::{GcCell, GcCellRef};
798+ ///
799+ /// let c = GcCell::new(vec![1, 2, 3]);
800+ /// let b1: GcCellRef<Vec<u32>> = c.borrow();
801+ /// let b2: Result<GcCellRef<u32>, _> = GcCellRef::filter_map(b1, |v| v.get(1));
802+ /// assert_eq!(*b2.unwrap(), 2);
803+ /// ```
804+ #[ inline]
805+ pub fn filter_map < U , F > ( orig : Self , f : F ) -> Result < GcCellRef < ' a , U > , Self >
806+ where
807+ U : ?Sized ,
808+ F : FnOnce ( & T ) -> Option < & U > ,
809+ {
810+ match f ( orig. value ) {
811+ None => Err ( orig) ,
812+ Some ( value) => {
813+ // We have to tell the compiler not to call the destructor of GcCellRef,
814+ // because it will update the borrow flags.
815+ let orig = ManuallyDrop :: new ( orig) ;
816+
817+ Ok ( GcCellRef {
818+ flags : orig. flags ,
819+ value,
820+ } )
821+ }
822+ }
784823 }
785824
786825 /// Splits a `GcCellRef` into multiple `GcCellRef`s for different components of the borrowed data.
@@ -812,7 +851,11 @@ impl<'a, T: ?Sized> GcCellRef<'a, T> {
812851
813852 orig. flags . set ( orig. flags . get ( ) . add_reading ( ) ) ;
814853
815- let ret = (
854+ // We have to tell the compiler not to call the destructor of GcCellRef,
855+ // because it will update the borrow flags.
856+ let orig = ManuallyDrop :: new ( orig) ;
857+
858+ (
816859 GcCellRef {
817860 flags : orig. flags ,
818861 value : a,
@@ -821,13 +864,7 @@ impl<'a, T: ?Sized> GcCellRef<'a, T> {
821864 flags : orig. flags ,
822865 value : b,
823866 } ,
824- ) ;
825-
826- // We have to tell the compiler not to call the destructor of GcCellRef,
827- // because it will update the borrow flags.
828- std:: mem:: forget ( orig) ;
829-
830- ret
867+ )
831868 }
832869}
833870
@@ -869,7 +906,7 @@ impl<'a, T: Trace + ?Sized, U: ?Sized> GcCellRefMut<'a, T, U> {
869906 /// Makes a new `GcCellRefMut` for a component of the borrowed data, e.g., an enum
870907 /// variant.
871908 ///
872- /// The `GcCellRefMut ` is already mutably borrowed, so this cannot fail.
909+ /// The `GcCell ` is already mutably borrowed, so this cannot fail.
873910 ///
874911 /// This is an associated function that needs to be used as
875912 /// `GcCellRefMut::map(...)`. A method would interfere with methods of the same
@@ -909,6 +946,55 @@ impl<'a, T: Trace + ?Sized, U: ?Sized> GcCellRefMut<'a, T, U> {
909946 value : f ( value) ,
910947 }
911948 }
949+
950+ /// Makes a new `GcCellRefMut` for an optional component of the borrowed
951+ /// data. The original guard is returned as an `Err(..)` if the closure
952+ /// returns `None`.
953+ ///
954+ /// The `GcCell` is already mutably borrowed, so this cannot fail.
955+ ///
956+ /// This is an associated function that needs to be used as
957+ /// `GcCellRefMut::filter_map(...)`. A method would interfere with methods
958+ /// of the same name on the contents of a `GcCell` used through `Deref`.
959+ ///
960+ /// # Examples
961+ ///
962+ /// ```
963+ /// use gc::{GcCell, GcCellRefMut};
964+ ///
965+ /// let c = GcCell::new(vec![1, 2, 3]);
966+ ///
967+ /// {
968+ /// let b1: GcCellRefMut<Vec<u32>> = c.borrow_mut();
969+ /// let mut b2: Result<GcCellRefMut<Vec<u32>, u32>, _> = GcCellRefMut::filter_map(b1, |v| v.get_mut(1));
970+ ///
971+ /// if let Ok(mut b2) = b2 {
972+ /// *b2 += 2;
973+ /// }
974+ /// }
975+ ///
976+ /// assert_eq!(*c.borrow(), vec![1, 4, 3]);
977+ /// ```
978+ #[ inline]
979+ pub fn filter_map < V , F > ( orig : Self , f : F ) -> Result < GcCellRefMut < ' a , T , V > , Self >
980+ where
981+ V : ?Sized ,
982+ F : FnOnce ( & mut U ) -> Option < & mut V > ,
983+ {
984+ let gc_cell = orig. gc_cell ;
985+
986+ // Use MaybeUninit to avoid calling the destructor of
987+ // GcCellRefMut (which would update the borrow flags) and to
988+ // avoid duplicating the mutable reference orig.value (which
989+ // would be UB).
990+ let orig = mem:: MaybeUninit :: new ( orig) ;
991+ let value = unsafe { ptr:: addr_of!( ( * orig. as_ptr( ) ) . value) . read ( ) } ;
992+
993+ match f ( value) {
994+ None => Err ( unsafe { orig. assume_init ( ) } ) ,
995+ Some ( value) => Ok ( GcCellRefMut { gc_cell, value } ) ,
996+ }
997+ }
912998}
913999
9141000impl < ' a , T : Trace + ?Sized , U : ?Sized > Deref for GcCellRefMut < ' a , T , U > {
0 commit comments