@@ -2152,6 +2152,7 @@ impl<T> Vec<T> {
2152
2152
del : 0 ,
2153
2153
old_len,
2154
2154
pred : filter,
2155
+ panic_flag : false ,
2155
2156
}
2156
2157
}
2157
2158
}
@@ -2779,10 +2780,20 @@ pub struct DrainFilter<'a, T, F>
2779
2780
where F : FnMut ( & mut T ) -> bool ,
2780
2781
{
2781
2782
vec : & ' a mut Vec < T > ,
2783
+ /// The index of the item that will be inspected by the next call to `next`.
2782
2784
idx : usize ,
2785
+ /// The number of items that have been drained (removed) thus far.
2783
2786
del : usize ,
2787
+ /// The original length of `vec` prior to draining.
2784
2788
old_len : usize ,
2789
+ /// The filter test predicate.
2785
2790
pred : F ,
2791
+ /// A flag that indicates a panic has occured in the filter test prodicate.
2792
+ /// This is used as a hint in the drop implmentation to prevent consumption
2793
+ /// of the remainder of the `DrainFilter`. Any unprocessed items will be
2794
+ /// backshifted in the `vec`, but no further items will be dropped or
2795
+ /// tested by the filter predicate.
2796
+ panic_flag : bool ,
2786
2797
}
2787
2798
2788
2799
#[ unstable( feature = "drain_filter" , reason = "recently added" , issue = "43244" ) ]
@@ -2793,20 +2804,23 @@ impl<T, F> Iterator for DrainFilter<'_, T, F>
2793
2804
2794
2805
fn next ( & mut self ) -> Option < T > {
2795
2806
unsafe {
2796
- while self . idx != self . old_len {
2807
+ while self . idx < self . old_len {
2797
2808
let i = self . idx ;
2798
- self . idx += 1 ;
2799
2809
let v = slice:: from_raw_parts_mut ( self . vec . as_mut_ptr ( ) , self . old_len ) ;
2800
- if ( self . pred ) ( & mut v[ i] ) {
2810
+ self . panic_flag = true ;
2811
+ let drained = ( self . pred ) ( & mut v[ i] ) ;
2812
+ self . panic_flag = false ;
2813
+ // Update the index *after* the predicate is called. If the index
2814
+ // is updated prior and the predicate panics, the element at this
2815
+ // index would be leaked.
2816
+ self . idx += 1 ;
2817
+ if drained {
2801
2818
self . del += 1 ;
2802
2819
return Some ( ptr:: read ( & v[ i] ) ) ;
2803
2820
} else if self . del > 0 {
2804
2821
let del = self . del ;
2805
2822
let src: * const T = & v[ i] ;
2806
2823
let dst: * mut T = & mut v[ i - del] ;
2807
- // This is safe because self.vec has length 0
2808
- // thus its elements will not have Drop::drop
2809
- // called on them in the event of a panic.
2810
2824
ptr:: copy_nonoverlapping ( src, dst, 1 ) ;
2811
2825
}
2812
2826
}
@@ -2824,9 +2838,46 @@ impl<T, F> Drop for DrainFilter<'_, T, F>
2824
2838
where F : FnMut ( & mut T ) -> bool ,
2825
2839
{
2826
2840
fn drop ( & mut self ) {
2827
- self . for_each ( drop) ;
2828
- unsafe {
2829
- self . vec . set_len ( self . old_len - self . del ) ;
2841
+ struct BackshiftOnDrop < ' a , ' b , T , F >
2842
+ where
2843
+ F : FnMut ( & mut T ) -> bool ,
2844
+ {
2845
+ drain : & ' b mut DrainFilter < ' a , T , F > ,
2846
+ }
2847
+
2848
+ impl < ' a , ' b , T , F > Drop for BackshiftOnDrop < ' a , ' b , T , F >
2849
+ where
2850
+ F : FnMut ( & mut T ) -> bool
2851
+ {
2852
+ fn drop ( & mut self ) {
2853
+ unsafe {
2854
+ if self . drain . idx < self . drain . old_len && self . drain . del > 0 {
2855
+ // This is a pretty messed up state, and there isn't really an
2856
+ // obviously right thing to do. We don't want to keep trying
2857
+ // to execute `pred`, so we just backshift all the unprocessed
2858
+ // elements and tell the vec that they still exist. The backshift
2859
+ // is required to prevent a double-drop of the last successfully
2860
+ // drained item prior to a panic in the predicate.
2861
+ let ptr = self . drain . vec . as_mut_ptr ( ) ;
2862
+ let src = ptr. add ( self . drain . idx ) ;
2863
+ let dst = src. sub ( self . drain . del ) ;
2864
+ let tail_len = self . drain . old_len - self . drain . idx ;
2865
+ src. copy_to ( dst, tail_len) ;
2866
+ }
2867
+ self . drain . vec . set_len ( self . drain . old_len - self . drain . del ) ;
2868
+ }
2869
+ }
2870
+ }
2871
+
2872
+ let backshift = BackshiftOnDrop {
2873
+ drain : self
2874
+ } ;
2875
+
2876
+ // Attempt to consume any remaining elements if the filter predicate
2877
+ // has not yet panicked. We'll backshift any remaining elements
2878
+ // whether we've already panicked or if the consumption here panics.
2879
+ if !backshift. drain . panic_flag {
2880
+ backshift. drain . for_each ( drop) ;
2830
2881
}
2831
2882
}
2832
2883
}
0 commit comments