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
/// 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
/// 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.
#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub struct DrainFilter<
'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")]
impl<T: fmt::Debug, F> fmt::Debug for DrainFilter<'_, T, F>
where

View File

@ -1005,17 +1005,23 @@ fn drain_filter_drop_panic_leak() {
q.push_front(d1.spawn(Panic::InDrop));
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!(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!(d3.dropped(), 1);
assert_eq!(d4.dropped(), 1);
assert_eq!(d5.dropped(), 1);
assert_eq!(d6.dropped(), 1);
assert_eq!(d7.dropped(), 1);
assert!(q.is_empty());
}
#[test]
@ -1045,7 +1051,7 @@ fn drain_filter_pred_panic_leak() {
q.push_front(D(0));
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();