@@ -924,3 +924,164 @@ fn test_raw_entry() {
924
924
}
925
925
}
926
926
}
927
+
928
+ mod test_drain_filter {
929
+ use super :: * ;
930
+
931
+ use crate :: panic:: { catch_unwind, AssertUnwindSafe } ;
932
+ use crate :: sync:: atomic:: { AtomicUsize , Ordering } ;
933
+
934
+ trait EqSorted : Iterator {
935
+ fn eq_sorted < I : IntoIterator < Item = Self :: Item > > ( self , other : I ) -> bool ;
936
+ }
937
+
938
+ impl < T : Iterator > EqSorted for T
939
+ where
940
+ T :: Item : Eq + Ord ,
941
+ {
942
+ fn eq_sorted < I : IntoIterator < Item = Self :: Item > > ( self , other : I ) -> bool {
943
+ let mut v: Vec < _ > = self . collect ( ) ;
944
+ v. sort_unstable ( ) ;
945
+ v. into_iter ( ) . eq ( other)
946
+ }
947
+ }
948
+
949
+ #[ test]
950
+ fn empty ( ) {
951
+ let mut map: HashMap < i32 , i32 > = HashMap :: new ( ) ;
952
+ map. drain_filter ( |_, _| unreachable ! ( "there's nothing to decide on" ) ) ;
953
+ assert ! ( map. is_empty( ) ) ;
954
+ }
955
+
956
+ #[ test]
957
+ fn consuming_nothing ( ) {
958
+ let pairs = ( 0 ..3 ) . map ( |i| ( i, i) ) ;
959
+ let mut map: HashMap < _ , _ > = pairs. collect ( ) ;
960
+ assert ! ( map. drain_filter( |_, _| false ) . eq_sorted( crate :: iter:: empty( ) ) ) ;
961
+ assert_eq ! ( map. len( ) , 3 ) ;
962
+ }
963
+
964
+ #[ test]
965
+ fn consuming_all ( ) {
966
+ let pairs = ( 0 ..3 ) . map ( |i| ( i, i) ) ;
967
+ let mut map: HashMap < _ , _ > = pairs. clone ( ) . collect ( ) ;
968
+ assert ! ( map. drain_filter( |_, _| true ) . eq_sorted( pairs) ) ;
969
+ assert ! ( map. is_empty( ) ) ;
970
+ }
971
+
972
+ #[ test]
973
+ fn mutating_and_keeping ( ) {
974
+ let pairs = ( 0 ..3 ) . map ( |i| ( i, i) ) ;
975
+ let mut map: HashMap < _ , _ > = pairs. collect ( ) ;
976
+ assert ! (
977
+ map. drain_filter( |_, v| {
978
+ * v += 6 ;
979
+ false
980
+ } )
981
+ . eq_sorted( crate :: iter:: empty( ) )
982
+ ) ;
983
+ assert ! ( map. keys( ) . copied( ) . eq_sorted( 0 ..3 ) ) ;
984
+ assert ! ( map. values( ) . copied( ) . eq_sorted( 6 ..9 ) ) ;
985
+ }
986
+
987
+ #[ test]
988
+ fn mutating_and_removing ( ) {
989
+ let pairs = ( 0 ..3 ) . map ( |i| ( i, i) ) ;
990
+ let mut map: HashMap < _ , _ > = pairs. collect ( ) ;
991
+ assert ! (
992
+ map. drain_filter( |_, v| {
993
+ * v += 6 ;
994
+ true
995
+ } )
996
+ . eq_sorted( ( 0 ..3 ) . map( |i| ( i, i + 6 ) ) )
997
+ ) ;
998
+ assert ! ( map. is_empty( ) ) ;
999
+ }
1000
+
1001
+ #[ test]
1002
+ fn drop_panic_leak ( ) {
1003
+ static PREDS : AtomicUsize = AtomicUsize :: new ( 0 ) ;
1004
+ static DROPS : AtomicUsize = AtomicUsize :: new ( 0 ) ;
1005
+
1006
+ struct D ;
1007
+ impl Drop for D {
1008
+ fn drop ( & mut self ) {
1009
+ if DROPS . fetch_add ( 1 , Ordering :: SeqCst ) == 1 {
1010
+ panic ! ( "panic in `drop`" ) ;
1011
+ }
1012
+ }
1013
+ }
1014
+
1015
+ let mut map = ( 0 ..3 ) . map ( |i| ( i, D ) ) . collect :: < HashMap < _ , _ > > ( ) ;
1016
+
1017
+ catch_unwind ( move || {
1018
+ drop ( map. drain_filter ( |_, _| {
1019
+ PREDS . fetch_add ( 1 , Ordering :: SeqCst ) ;
1020
+ true
1021
+ } ) )
1022
+ } )
1023
+ . unwrap_err ( ) ;
1024
+
1025
+ assert_eq ! ( PREDS . load( Ordering :: SeqCst ) , 3 ) ;
1026
+ assert_eq ! ( DROPS . load( Ordering :: SeqCst ) , 3 ) ;
1027
+ }
1028
+
1029
+ #[ test]
1030
+ fn pred_panic_leak ( ) {
1031
+ static PREDS : AtomicUsize = AtomicUsize :: new ( 0 ) ;
1032
+ static DROPS : AtomicUsize = AtomicUsize :: new ( 0 ) ;
1033
+
1034
+ struct D ;
1035
+ impl Drop for D {
1036
+ fn drop ( & mut self ) {
1037
+ DROPS . fetch_add ( 1 , Ordering :: SeqCst ) ;
1038
+ }
1039
+ }
1040
+
1041
+ let mut map = ( 0 ..3 ) . map ( |i| ( i, D ) ) . collect :: < HashMap < _ , _ > > ( ) ;
1042
+
1043
+ catch_unwind ( AssertUnwindSafe ( || {
1044
+ drop ( map. drain_filter ( |_, _| match PREDS . fetch_add ( 1 , Ordering :: SeqCst ) {
1045
+ 0 => true ,
1046
+ _ => panic ! ( ) ,
1047
+ } ) )
1048
+ } ) )
1049
+ . unwrap_err ( ) ;
1050
+
1051
+ assert_eq ! ( PREDS . load( Ordering :: SeqCst ) , 2 ) ;
1052
+ assert_eq ! ( DROPS . load( Ordering :: SeqCst ) , 1 ) ;
1053
+ assert_eq ! ( map. len( ) , 2 ) ;
1054
+ }
1055
+
1056
+ // Same as above, but attempt to use the iterator again after the panic in the predicate
1057
+ #[ test]
1058
+ fn pred_panic_reuse ( ) {
1059
+ static PREDS : AtomicUsize = AtomicUsize :: new ( 0 ) ;
1060
+ static DROPS : AtomicUsize = AtomicUsize :: new ( 0 ) ;
1061
+
1062
+ struct D ;
1063
+ impl Drop for D {
1064
+ fn drop ( & mut self ) {
1065
+ DROPS . fetch_add ( 1 , Ordering :: SeqCst ) ;
1066
+ }
1067
+ }
1068
+
1069
+ let mut map = ( 0 ..3 ) . map ( |i| ( i, D ) ) . collect :: < HashMap < _ , _ > > ( ) ;
1070
+
1071
+ {
1072
+ let mut it = map. drain_filter ( |_, _| match PREDS . fetch_add ( 1 , Ordering :: SeqCst ) {
1073
+ 0 => true ,
1074
+ _ => panic ! ( ) ,
1075
+ } ) ;
1076
+ catch_unwind ( AssertUnwindSafe ( || while it. next ( ) . is_some ( ) { } ) ) . unwrap_err ( ) ;
1077
+ // Iterator behaviour after a panic is explicitly unspecified,
1078
+ // so this is just the current implementation:
1079
+ let result = catch_unwind ( AssertUnwindSafe ( || it. next ( ) ) ) ;
1080
+ assert ! ( result. is_err( ) ) ;
1081
+ }
1082
+
1083
+ assert_eq ! ( PREDS . load( Ordering :: SeqCst ) , 3 ) ;
1084
+ assert_eq ! ( DROPS . load( Ordering :: SeqCst ) , 1 ) ;
1085
+ assert_eq ! ( map. len( ) , 2 ) ;
1086
+ }
1087
+ }
0 commit comments