Skip to content

Commit b13ae65

Browse files
committed
Refactor DrainFilter::next and update comments
1 parent 53d46ae commit b13ae65

File tree

1 file changed

+13
-16
lines changed

1 file changed

+13
-16
lines changed

src/liballoc/vec.rs

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2762,26 +2762,17 @@ impl<T, F> Iterator for DrainFilter<'_, T, F>
27622762
type Item = T;
27632763

27642764
fn next(&mut self) -> Option<T> {
2765-
struct SetIdxOnDrop<'a> {
2766-
idx: &'a mut usize,
2767-
new_idx: usize,
2768-
}
2769-
2770-
impl<'a> Drop for SetIdxOnDrop<'a> {
2771-
fn drop(&mut self) {
2772-
*self.idx = self.new_idx;
2773-
}
2774-
}
2775-
27762765
unsafe {
27772766
while self.idx < self.old_len {
27782767
let i = self.idx;
27792768
let v = slice::from_raw_parts_mut(self.vec.as_mut_ptr(), self.old_len);
2780-
let mut set_idx = SetIdxOnDrop { new_idx: self.idx, idx: &mut self.idx };
27812769
self.panic_flag = true;
27822770
let drained = (self.pred)(&mut v[i]);
27832771
self.panic_flag = false;
2784-
set_idx.new_idx += 1;
2772+
// Update the index *after* the predicate is called. If the index
2773+
// is updated prior and the predicate panics, the element at this
2774+
// index would be leaked.
2775+
self.idx += 1;
27852776
if drained {
27862777
self.del += 1;
27872778
return Some(ptr::read(&v[i]));
@@ -2806,9 +2797,6 @@ impl<T, F> Drop for DrainFilter<'_, T, F>
28062797
where F: FnMut(&mut T) -> bool,
28072798
{
28082799
fn drop(&mut self) {
2809-
// If the predicate panics, we still need to backshift everything
2810-
// down after the last successfully drained element, but no additional
2811-
// elements are drained or checked.
28122800
struct BackshiftOnDrop<'a, 'b, T, F>
28132801
where
28142802
F: FnMut(&mut T) -> bool,
@@ -2822,6 +2810,12 @@ impl<T, F> Drop for DrainFilter<'_, T, F>
28222810
{
28232811
fn drop(&mut self) {
28242812
unsafe {
2813+
// Backshift any unprocessed elements, preventing double-drop
2814+
// of any element that *should* have been previously overwritten
2815+
// but was not due to a panic in the filter predicate. This is
2816+
// implemented via drop so that it's guaranteed to run even in
2817+
// the event of a panic while consuming the remainder of the
2818+
// DrainFilter.
28252819
while self.drain.idx < self.drain.old_len {
28262820
let i = self.drain.idx;
28272821
self.drain.idx += 1;
@@ -2845,6 +2839,9 @@ impl<T, F> Drop for DrainFilter<'_, T, F>
28452839
drain: self
28462840
};
28472841

2842+
// Attempt to consume any remaining elements if the filter predicate
2843+
// has not yet panicked. We'll backshift any remaining elements
2844+
// whether we've already panicked or if the consumption here panics.
28482845
if !backshift.drain.panic_flag {
28492846
backshift.drain.for_each(drop);
28502847
}

0 commit comments

Comments
 (0)