1
Fork 0

remove drain-on-drop behavior from linked_list::DrainFilter and add #[must_use]

This commit is contained in:
The 8472 2022-11-15 19:51:49 +01:00
parent b687e84aeb
commit b7ce7edd87
2 changed files with 14 additions and 30 deletions

View file

@ -1030,6 +1030,10 @@ impl<T, A: Allocator> LinkedList<T, A> {
/// If the closure returns false, the element will remain in the list and will not be yielded /// If the closure returns false, the element will remain in the list and will not be yielded
/// by the iterator. /// by the iterator.
/// ///
/// If the returned `DrainFilter` is not exhausted, e.g. because it is dropped without iterating
/// or the iteration short-circuits, then the remaining elements will be retained.
/// Use `drain_filter().for_each(drop)` if you do not need the returned iterator.
///
/// Note that `drain_filter` lets you mutate every element in the filter closure, regardless of /// Note that `drain_filter` lets you mutate every element in the filter closure, regardless of
/// whether you choose to keep or remove it. /// whether you choose to keep or remove it.
/// ///
@ -1805,6 +1809,7 @@ impl<'a, T, A: Allocator> CursorMut<'a, T, A> {
/// An iterator produced by calling `drain_filter` on LinkedList. /// An iterator produced by calling `drain_filter` on LinkedList.
#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] #[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub struct DrainFilter< pub struct DrainFilter<
'a, 'a,
T: 'a, T: 'a,
@ -1849,33 +1854,6 @@ where
} }
} }
#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
impl<T, F, A: Allocator> Drop for DrainFilter<'_, T, F, A>
where
F: FnMut(&mut T) -> bool,
{
fn drop(&mut self) {
struct DropGuard<'r, 'a, T, F, A: Allocator>(&'r mut DrainFilter<'a, T, F, A>)
where
F: FnMut(&mut T) -> bool;
impl<'r, 'a, T, F, A: Allocator> Drop for DropGuard<'r, 'a, T, F, A>
where
F: FnMut(&mut T) -> bool,
{
fn drop(&mut self) {
self.0.for_each(drop);
}
}
while let Some(item) = self.next() {
let guard = DropGuard(self);
drop(item);
mem::forget(guard);
}
}
}
#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] #[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
impl<T: fmt::Debug, F> fmt::Debug for DrainFilter<'_, T, F> impl<T: fmt::Debug, F> fmt::Debug for DrainFilter<'_, T, F>
where where

View file

@ -1005,17 +1005,23 @@ fn drain_filter_drop_panic_leak() {
q.push_front(d1.spawn(Panic::InDrop)); q.push_front(d1.spawn(Panic::InDrop));
q.push_front(d0.spawn(Panic::Never)); q.push_front(d0.spawn(Panic::Never));
catch_unwind(AssertUnwindSafe(|| drop(q.drain_filter(|_| true)))).unwrap_err(); catch_unwind(AssertUnwindSafe(|| q.drain_filter(|_| true).for_each(drop))).unwrap_err();
assert_eq!(d0.dropped(), 1); assert_eq!(d0.dropped(), 1);
assert_eq!(d1.dropped(), 1); assert_eq!(d1.dropped(), 1);
assert_eq!(d2.dropped(), 0);
assert_eq!(d3.dropped(), 0);
assert_eq!(d4.dropped(), 0);
assert_eq!(d5.dropped(), 0);
assert_eq!(d6.dropped(), 0);
assert_eq!(d7.dropped(), 0);
drop(q);
assert_eq!(d2.dropped(), 1); assert_eq!(d2.dropped(), 1);
assert_eq!(d3.dropped(), 1); assert_eq!(d3.dropped(), 1);
assert_eq!(d4.dropped(), 1); assert_eq!(d4.dropped(), 1);
assert_eq!(d5.dropped(), 1); assert_eq!(d5.dropped(), 1);
assert_eq!(d6.dropped(), 1); assert_eq!(d6.dropped(), 1);
assert_eq!(d7.dropped(), 1); assert_eq!(d7.dropped(), 1);
assert!(q.is_empty());
} }
#[test] #[test]
@ -1045,7 +1051,7 @@ fn drain_filter_pred_panic_leak() {
q.push_front(D(0)); q.push_front(D(0));
catch_unwind(AssertUnwindSafe(|| { catch_unwind(AssertUnwindSafe(|| {
drop(q.drain_filter(|item| if item.0 >= 2 { panic!() } else { true })) q.drain_filter(|item| if item.0 >= 2 { panic!() } else { true }).for_each(drop)
})) }))
.ok(); .ok();