@@ -924,3 +924,164 @@ fn test_raw_entry() {
924924 }
925925 }
926926}
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