@@ -16,7 +16,7 @@ use std::cmp::Ordering;
16
16
use std:: fmt:: { self , Debug , Display } ;
17
17
use std:: hash:: { Hash , Hasher } ;
18
18
use std:: marker:: PhantomData ;
19
- use std:: mem;
19
+ use std:: mem:: { self , ManuallyDrop } ;
20
20
use std:: ops:: { Deref , DerefMut } ;
21
21
use std:: ptr:: { self , NonNull } ;
22
22
use std:: rc:: Rc ;
@@ -194,9 +194,7 @@ impl<T: ?Sized> Gc<T> {
194
194
/// unsafe { Gc::from_raw(x_ptr) };
195
195
/// ```
196
196
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 ( ) )
200
198
}
201
199
202
200
/// Constructs an `Gc` from a raw pointer.
@@ -747,7 +745,7 @@ impl<'a, T: ?Sized> GcCellRef<'a, T> {
747
745
}
748
746
}
749
747
750
- /// Makes a new `GcCellRef` from a component of the borrowed data.
748
+ /// Makes a new `GcCellRef` for a component of the borrowed data.
751
749
///
752
750
/// The `GcCell` is already immutably borrowed, so this cannot fail.
753
751
///
@@ -763,24 +761,65 @@ impl<'a, T: ?Sized> GcCellRef<'a, T> {
763
761
/// let c = GcCell::new((5, 'b'));
764
762
/// let b1: GcCellRef<(u32, char)> = c.borrow();
765
763
/// let b2: GcCellRef<u32> = GcCellRef::map(b1, |t| &t.0);
766
- /// // assert_eq!(b2, 5);
764
+ /// assert_eq!(* b2, 5);
767
765
/// ```
768
766
#[ inline]
769
767
pub fn map < U , F > ( orig : Self , f : F ) -> GcCellRef < ' a , U >
770
768
where
771
769
U : ?Sized ,
772
770
F : FnOnce ( & T ) -> & U ,
773
771
{
774
- let ret = GcCellRef {
775
- flags : orig. flags ,
776
- value : f ( orig. value ) ,
777
- } ;
772
+ let value = f ( orig. value ) ;
778
773
779
774
// We have to tell the compiler not to call the destructor of GcCellRef,
780
775
// because it will update the borrow flags.
781
- std :: mem :: forget ( orig) ;
776
+ let orig = ManuallyDrop :: new ( orig) ;
782
777
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
+ }
784
823
}
785
824
786
825
/// 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> {
812
851
813
852
orig. flags . set ( orig. flags . get ( ) . add_reading ( ) ) ;
814
853
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
+ (
816
859
GcCellRef {
817
860
flags : orig. flags ,
818
861
value : a,
@@ -821,13 +864,7 @@ impl<'a, T: ?Sized> GcCellRef<'a, T> {
821
864
flags : orig. flags ,
822
865
value : b,
823
866
} ,
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
+ )
831
868
}
832
869
}
833
870
@@ -869,7 +906,7 @@ impl<'a, T: Trace + ?Sized, U: ?Sized> GcCellRefMut<'a, T, U> {
869
906
/// Makes a new `GcCellRefMut` for a component of the borrowed data, e.g., an enum
870
907
/// variant.
871
908
///
872
- /// The `GcCellRefMut ` is already mutably borrowed, so this cannot fail.
909
+ /// The `GcCell ` is already mutably borrowed, so this cannot fail.
873
910
///
874
911
/// This is an associated function that needs to be used as
875
912
/// `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> {
909
946
value : f ( value) ,
910
947
}
911
948
}
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
+ }
912
998
}
913
999
914
1000
impl < ' a , T : Trace + ?Sized , U : ?Sized > Deref for GcCellRefMut < ' a , T , U > {
0 commit comments