From c7f36fa43e6c70d863386749f48293b1b46db6e9 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Sat, 3 Feb 2024 10:15:15 -0800 Subject: [PATCH 1/2] Add map and set `extract_if` --- src/map.rs | 43 +++++++++++++++++- src/map/core.rs | 3 ++ src/map/core/extract.rs | 96 +++++++++++++++++++++++++++++++++++++++++ src/map/iter.rs | 56 +++++++++++++++++++++++- src/set.rs | 37 +++++++++++++++- src/set/iter.rs | 52 ++++++++++++++++++++++ tests/quick.rs | 41 ++++++++++++++++++ 7 files changed, 323 insertions(+), 5 deletions(-) create mode 100644 src/map/core/extract.rs diff --git a/src/map.rs b/src/map.rs index 347649f8..b47381c8 100644 --- a/src/map.rs +++ b/src/map.rs @@ -16,7 +16,8 @@ mod tests; pub use self::core::raw_entry_v1::{self, RawEntryApiV1}; pub use self::core::{Entry, IndexedEntry, OccupiedEntry, VacantEntry}; pub use self::iter::{ - Drain, IntoIter, IntoKeys, IntoValues, Iter, IterMut, IterMut2, Keys, Splice, Values, ValuesMut, + Drain, ExtractIf, IntoIter, IntoKeys, IntoValues, Iter, IterMut, IterMut2, Keys, Splice, + Values, ValuesMut, }; pub use self::mutable::MutableEntryKey; pub use self::mutable::MutableKeys; @@ -36,7 +37,7 @@ use alloc::vec::Vec; #[cfg(feature = "std")] use std::collections::hash_map::RandomState; -use self::core::IndexMapCore; +pub(crate) use self::core::{ExtractCore, IndexMapCore}; use crate::util::{third, try_simplify_range}; use crate::{Bucket, Entries, Equivalent, HashValue, TryReserveError}; @@ -307,6 +308,44 @@ impl IndexMap { Drain::new(self.core.drain(range)) } + /// Creates an iterator which uses a closure to determine if an element should be removed. + /// + /// If the closure returns true, the element is removed from the map and yielded. + /// If the closure returns false, or panics, the element remains in the map and will not be + /// yielded. + /// + /// Note that `extract_if` lets you mutate every value in the filter closure, regardless of + /// whether you choose to keep or remove it. + /// + /// If the returned `ExtractIf` is not exhausted, e.g. because it is dropped without iterating + /// or the iteration short-circuits, then the remaining elements will be retained. + /// Use [`retain`] with a negated predicate if you do not need the returned iterator. + /// + /// [`retain`]: IndexMap::retain + /// + /// # Examples + /// + /// Splitting a map into even and odd keys, reusing the original map: + /// + /// ``` + /// use indexmap::IndexMap; + /// + /// let mut map: IndexMap = (0..8).map(|x| (x, x)).collect(); + /// let extracted: IndexMap = map.extract_if(|k, _v| k % 2 == 0).collect(); + /// + /// let evens = extracted.keys().copied().collect::>(); + /// let odds = map.keys().copied().collect::>(); + /// + /// assert_eq!(evens, vec![0, 2, 4, 6]); + /// assert_eq!(odds, vec![1, 3, 5, 7]); + /// ``` + pub fn extract_if(&mut self, pred: F) -> ExtractIf<'_, K, V, F> + where + F: FnMut(&K, &mut V) -> bool, + { + ExtractIf::new(&mut self.core, pred) + } + /// Splits the collection into two at the given index. /// /// Returns a newly allocated map containing the elements in the range diff --git a/src/map/core.rs b/src/map/core.rs index 9022c8ee..e904544f 100644 --- a/src/map/core.rs +++ b/src/map/core.rs @@ -8,6 +8,7 @@ //! However, we should probably not let this show in the public API or docs. mod entry; +mod extract; pub mod raw_entry_v1; @@ -25,6 +26,7 @@ type Indices = hash_table::HashTable; type Entries = Vec>; pub use entry::{Entry, IndexedEntry, OccupiedEntry, VacantEntry}; +pub(crate) use extract::ExtractCore; /// Core of the map that does not depend on S #[derive(Debug)] @@ -163,6 +165,7 @@ impl IndexMapCore { #[inline] pub(crate) fn len(&self) -> usize { + debug_assert_eq!(self.entries.len(), self.indices.len()); self.indices.len() } diff --git a/src/map/core/extract.rs b/src/map/core/extract.rs new file mode 100644 index 00000000..db35d96d --- /dev/null +++ b/src/map/core/extract.rs @@ -0,0 +1,96 @@ +#![allow(unsafe_code)] + +use super::{Bucket, IndexMapCore}; + +impl IndexMapCore { + pub(crate) fn extract(&mut self) -> ExtractCore<'_, K, V> { + // SAFETY: We must have consistent lengths to start, so that's a hard assertion. + // Then the worst `set_len(0)` can do is leak items if `ExtractCore` doesn't drop. + assert_eq!(self.entries.len(), self.indices.len()); + unsafe { + self.entries.set_len(0); + } + ExtractCore { + map: self, + current: 0, + new_len: 0, + } + } +} + +pub(crate) struct ExtractCore<'a, K, V> { + map: &'a mut IndexMapCore, + current: usize, + new_len: usize, +} + +impl Drop for ExtractCore<'_, K, V> { + fn drop(&mut self) { + let old_len = self.map.indices.len(); + let mut new_len = self.new_len; + debug_assert!(new_len <= self.current); + debug_assert!(self.current <= old_len); + debug_assert!(old_len <= self.map.entries.capacity()); + + // SAFETY: We assume `new_len` and `current` were correctly maintained by the iterator. + // So `entries[new_len..current]` were extracted, but the rest before and after are valid. + unsafe { + if new_len == self.current { + // Nothing was extracted, so any remaining items can be left in place. + new_len = old_len; + } else if self.current < old_len { + // Need to shift the remaining items down. + let tail_len = old_len - self.current; + let base = self.map.entries.as_mut_ptr(); + let src = base.add(self.current); + let dest = base.add(new_len); + src.copy_to(dest, tail_len); + new_len += tail_len; + } + self.map.entries.set_len(new_len); + } + + if new_len != old_len { + // We don't keep track of *which* items were extracted, so reindex everything. + self.map.rebuild_hash_table(); + } + } +} + +impl ExtractCore<'_, K, V> { + pub(crate) fn extract_if(&mut self, mut pred: F) -> Option> + where + F: FnMut(&mut Bucket) -> bool, + { + let old_len = self.map.indices.len(); + debug_assert!(old_len <= self.map.entries.capacity()); + + let base = self.map.entries.as_mut_ptr(); + while self.current < old_len { + // SAFETY: We're maintaining both indices within bounds of the original entries, so + // 0..new_len and current..old_len are always valid items for our Drop to keep. + unsafe { + let item = base.add(self.current); + if pred(&mut *item) { + // Extract it! + self.current += 1; + return Some(item.read()); + } else { + // Keep it, shifting it down if needed. + if self.new_len != self.current { + debug_assert!(self.new_len < self.current); + let dest = base.add(self.new_len); + item.copy_to_nonoverlapping(dest, 1); + } + self.current += 1; + self.new_len += 1; + } + } + } + None + } + + pub(crate) fn remaining(&self) -> usize { + self.map.indices.len() - self.current + } +} diff --git a/src/map/iter.rs b/src/map/iter.rs index e343b8a3..42ee48bc 100644 --- a/src/map/iter.rs +++ b/src/map/iter.rs @@ -1,5 +1,4 @@ -use super::core::IndexMapCore; -use super::{Bucket, Entries, IndexMap, Slice}; +use super::{Bucket, Entries, ExtractCore, IndexMap, IndexMapCore, Slice}; use alloc::vec::{self, Vec}; use core::fmt; @@ -774,3 +773,56 @@ where .finish() } } + +/// An extracting iterator for `IndexMap`. +/// +/// This `struct` is created by [`IndexMap::extract_if()`]. +/// See its documentation for more. +pub struct ExtractIf<'a, K, V, F> +where + F: FnMut(&K, &mut V) -> bool, +{ + inner: ExtractCore<'a, K, V>, + pred: F, +} + +impl ExtractIf<'_, K, V, F> +where + F: FnMut(&K, &mut V) -> bool, +{ + pub(super) fn new(core: &mut IndexMapCore, pred: F) -> ExtractIf<'_, K, V, F> { + ExtractIf { + inner: core.extract(), + pred, + } + } +} + +impl Iterator for ExtractIf<'_, K, V, F> +where + F: FnMut(&K, &mut V) -> bool, +{ + type Item = (K, V); + + fn next(&mut self) -> Option { + self.inner + .extract_if(|bucket| { + let (key, value) = bucket.ref_mut(); + (self.pred)(key, value) + }) + .map(Bucket::key_value) + } + + fn size_hint(&self) -> (usize, Option) { + (0, Some(self.inner.remaining())) + } +} + +impl<'a, K, V, F> fmt::Debug for ExtractIf<'a, K, V, F> +where + F: FnMut(&K, &mut V) -> bool, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("ExtractIf").finish_non_exhaustive() + } +} diff --git a/src/set.rs b/src/set.rs index 1be248eb..a4ff8f38 100644 --- a/src/set.rs +++ b/src/set.rs @@ -8,7 +8,7 @@ mod slice; mod tests; pub use self::iter::{ - Difference, Drain, Intersection, IntoIter, Iter, Splice, SymmetricDifference, Union, + Difference, Drain, ExtractIf, Intersection, IntoIter, Iter, Splice, SymmetricDifference, Union, }; pub use self::mutable::MutableValues; pub use self::slice::Slice; @@ -258,6 +258,41 @@ impl IndexSet { Drain::new(self.map.core.drain(range)) } + /// Creates an iterator which uses a closure to determine if a value should be removed. + /// + /// If the closure returns true, then the value is removed and yielded. + /// If the closure returns false, the value will remain in the list and will not be yielded + /// by the iterator. + /// + /// If the returned `ExtractIf` is not exhausted, e.g. because it is dropped without iterating + /// or the iteration short-circuits, then the remaining elements will be retained. + /// Use [`retain`] with a negated predicate if you do not need the returned iterator. + /// + /// [`retain`]: IndexSet::retain + /// + /// # Examples + /// + /// Splitting a set into even and odd values, reusing the original set: + /// + /// ``` + /// use indexmap::IndexSet; + /// + /// let mut set: IndexSet = (0..8).collect(); + /// let extracted: IndexSet = set.extract_if(|v| v % 2 == 0).collect(); + /// + /// let evens = extracted.into_iter().collect::>(); + /// let odds = set.into_iter().collect::>(); + /// + /// assert_eq!(evens, vec![0, 2, 4, 6]); + /// assert_eq!(odds, vec![1, 3, 5, 7]); + /// ``` + pub fn extract_if(&mut self, pred: F) -> ExtractIf<'_, T, F> + where + F: FnMut(&T) -> bool, + { + ExtractIf::new(&mut self.map.core, pred) + } + /// Splits the collection into two at the given index. /// /// Returns a newly allocated set containing the elements in the range diff --git a/src/set/iter.rs b/src/set/iter.rs index 34433164..a00c743e 100644 --- a/src/set/iter.rs +++ b/src/set/iter.rs @@ -1,3 +1,5 @@ +use crate::map::{ExtractCore, IndexMapCore}; + use super::{Bucket, Entries, IndexSet, Slice}; use alloc::vec::{self, Vec}; @@ -626,3 +628,53 @@ impl fmt::Debug for UnitValue { fmt::Debug::fmt(&self.0, f) } } + +/// An extracting iterator for `IndexSet`. +/// +/// This `struct` is created by [`IndexSet::extract_if()`]. +/// See its documentation for more. +pub struct ExtractIf<'a, T, F> +where + F: FnMut(&T) -> bool, +{ + inner: ExtractCore<'a, T, ()>, + pred: F, +} + +impl ExtractIf<'_, T, F> +where + F: FnMut(&T) -> bool, +{ + pub(super) fn new(core: &mut IndexMapCore, pred: F) -> ExtractIf<'_, T, F> { + ExtractIf { + inner: core.extract(), + pred, + } + } +} + +impl Iterator for ExtractIf<'_, T, F> +where + F: FnMut(&T) -> bool, +{ + type Item = T; + + fn next(&mut self) -> Option { + self.inner + .extract_if(|bucket| (self.pred)(bucket.key_ref())) + .map(Bucket::key) + } + + fn size_hint(&self) -> (usize, Option) { + (0, Some(self.inner.remaining())) + } +} + +impl<'a, T, F> fmt::Debug for ExtractIf<'a, T, F> +where + F: FnMut(&T) -> bool, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("ExtractIf").finish_non_exhaustive() + } +} diff --git a/tests/quick.rs b/tests/quick.rs index 56afee72..9394a4a4 100644 --- a/tests/quick.rs +++ b/tests/quick.rs @@ -191,6 +191,47 @@ quickcheck_limit! { } } + fn extract_if_odd(insert: Vec) -> bool { + let mut map = IndexMap::new(); + for &x in &insert { + map.insert(x, x.to_string()); + } + + let (odd, even): (Vec<_>, Vec<_>) = map.keys().copied().partition(|k| k % 2 == 1); + + let extracted: Vec<_> = map + .extract_if(|k, _| k % 2 == 1) + .map(|(k, _)| k) + .collect(); + + even.iter().all(|k| map.contains_key(k)) + && map.keys().eq(&even) + && extracted == odd + } + + fn extract_if_odd_limit(insert: Vec, limit: usize) -> bool { + let mut map = IndexMap::new(); + for &x in &insert { + map.insert(x, x.to_string()); + } + let limit = limit % (map.len() + 1); + + let mut i = 0; + let (odd, other): (Vec<_>, Vec<_>) = map.keys().copied().partition(|k| { + k % 2 == 1 && i < limit && { i += 1; true } + }); + + let extracted: Vec<_> = map + .extract_if(|k, _| k % 2 == 1) + .map(|(k, _)| k) + .take(limit) + .collect(); + + other.iter().all(|k| map.contains_key(k)) + && map.keys().eq(&other) + && extracted == odd + } + fn shift_remove(insert: Vec, remove: Vec) -> bool { let mut map = IndexMap::new(); for &key in &insert { From 25310504d2a683b2531b2e1aa2ef2a26bb32421d Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Tue, 19 Nov 2024 17:48:49 -0800 Subject: [PATCH 2/2] Add range support to `extract_if` --- src/map.rs | 15 +++++++++++---- src/map/core/extract.rs | 33 ++++++++++++++++++++++----------- src/map/iter.rs | 23 +++++++++-------------- src/set.rs | 15 +++++++++++---- src/set/iter.rs | 23 +++++++++-------------- tests/quick.rs | 4 ++-- 6 files changed, 64 insertions(+), 49 deletions(-) diff --git a/src/map.rs b/src/map.rs index b47381c8..78c3c557 100644 --- a/src/map.rs +++ b/src/map.rs @@ -308,7 +308,8 @@ impl IndexMap { Drain::new(self.core.drain(range)) } - /// Creates an iterator which uses a closure to determine if an element should be removed. + /// Creates an iterator which uses a closure to determine if an element should be removed, + /// for all elements in the given range. /// /// If the closure returns true, the element is removed from the map and yielded. /// If the closure returns false, or panics, the element remains in the map and will not be @@ -317,6 +318,11 @@ impl IndexMap { /// Note that `extract_if` lets you mutate every value in the filter closure, regardless of /// whether you choose to keep or remove it. /// + /// The range may be any type that implements [`RangeBounds`], + /// including all of the `std::ops::Range*` types, or even a tuple pair of + /// `Bound` start and end values. To check the entire map, use `RangeFull` + /// like `map.extract_if(.., predicate)`. + /// /// If the returned `ExtractIf` is not exhausted, e.g. because it is dropped without iterating /// or the iteration short-circuits, then the remaining elements will be retained. /// Use [`retain`] with a negated predicate if you do not need the returned iterator. @@ -331,7 +337,7 @@ impl IndexMap { /// use indexmap::IndexMap; /// /// let mut map: IndexMap = (0..8).map(|x| (x, x)).collect(); - /// let extracted: IndexMap = map.extract_if(|k, _v| k % 2 == 0).collect(); + /// let extracted: IndexMap = map.extract_if(.., |k, _v| k % 2 == 0).collect(); /// /// let evens = extracted.keys().copied().collect::>(); /// let odds = map.keys().copied().collect::>(); @@ -339,11 +345,12 @@ impl IndexMap { /// assert_eq!(evens, vec![0, 2, 4, 6]); /// assert_eq!(odds, vec![1, 3, 5, 7]); /// ``` - pub fn extract_if(&mut self, pred: F) -> ExtractIf<'_, K, V, F> + pub fn extract_if(&mut self, range: R, pred: F) -> ExtractIf<'_, K, V, F> where F: FnMut(&K, &mut V) -> bool, + R: RangeBounds, { - ExtractIf::new(&mut self.core, pred) + ExtractIf::new(&mut self.core, range, pred) } /// Splits the collection into two at the given index. diff --git a/src/map/core/extract.rs b/src/map/core/extract.rs index db35d96d..ab7aa64d 100644 --- a/src/map/core/extract.rs +++ b/src/map/core/extract.rs @@ -1,34 +1,46 @@ #![allow(unsafe_code)] use super::{Bucket, IndexMapCore}; +use crate::util::simplify_range; + +use core::ops::RangeBounds; impl IndexMapCore { - pub(crate) fn extract(&mut self) -> ExtractCore<'_, K, V> { + pub(crate) fn extract(&mut self, range: R) -> ExtractCore<'_, K, V> + where + R: RangeBounds, + { + let range = simplify_range(range, self.entries.len()); + // SAFETY: We must have consistent lengths to start, so that's a hard assertion. - // Then the worst `set_len(0)` can do is leak items if `ExtractCore` doesn't drop. + // Then the worst `set_len` can do is leak items if `ExtractCore` doesn't drop. assert_eq!(self.entries.len(), self.indices.len()); unsafe { - self.entries.set_len(0); + self.entries.set_len(range.start); } ExtractCore { map: self, - current: 0, - new_len: 0, + new_len: range.start, + current: range.start, + end: range.end, } } } pub(crate) struct ExtractCore<'a, K, V> { map: &'a mut IndexMapCore, - current: usize, new_len: usize, + current: usize, + end: usize, } impl Drop for ExtractCore<'_, K, V> { fn drop(&mut self) { let old_len = self.map.indices.len(); let mut new_len = self.new_len; + debug_assert!(new_len <= self.current); + debug_assert!(self.current <= self.end); debug_assert!(self.current <= old_len); debug_assert!(old_len <= self.map.entries.capacity()); @@ -62,13 +74,12 @@ impl ExtractCore<'_, K, V> { where F: FnMut(&mut Bucket) -> bool, { - let old_len = self.map.indices.len(); - debug_assert!(old_len <= self.map.entries.capacity()); + debug_assert!(self.end <= self.map.entries.capacity()); let base = self.map.entries.as_mut_ptr(); - while self.current < old_len { + while self.current < self.end { // SAFETY: We're maintaining both indices within bounds of the original entries, so - // 0..new_len and current..old_len are always valid items for our Drop to keep. + // 0..new_len and current..indices.len() are always valid items for our Drop to keep. unsafe { let item = base.add(self.current); if pred(&mut *item) { @@ -91,6 +102,6 @@ impl ExtractCore<'_, K, V> { } pub(crate) fn remaining(&self) -> usize { - self.map.indices.len() - self.current + self.end - self.current } } diff --git a/src/map/iter.rs b/src/map/iter.rs index 42ee48bc..6bba162d 100644 --- a/src/map/iter.rs +++ b/src/map/iter.rs @@ -778,21 +778,19 @@ where /// /// This `struct` is created by [`IndexMap::extract_if()`]. /// See its documentation for more. -pub struct ExtractIf<'a, K, V, F> -where - F: FnMut(&K, &mut V) -> bool, -{ +pub struct ExtractIf<'a, K, V, F> { inner: ExtractCore<'a, K, V>, pred: F, } -impl ExtractIf<'_, K, V, F> -where - F: FnMut(&K, &mut V) -> bool, -{ - pub(super) fn new(core: &mut IndexMapCore, pred: F) -> ExtractIf<'_, K, V, F> { +impl ExtractIf<'_, K, V, F> { + pub(super) fn new(core: &mut IndexMapCore, range: R, pred: F) -> ExtractIf<'_, K, V, F> + where + R: RangeBounds, + F: FnMut(&K, &mut V) -> bool, + { ExtractIf { - inner: core.extract(), + inner: core.extract(range), pred, } } @@ -818,10 +816,7 @@ where } } -impl<'a, K, V, F> fmt::Debug for ExtractIf<'a, K, V, F> -where - F: FnMut(&K, &mut V) -> bool, -{ +impl<'a, K, V, F> fmt::Debug for ExtractIf<'a, K, V, F> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("ExtractIf").finish_non_exhaustive() } diff --git a/src/set.rs b/src/set.rs index a4ff8f38..a5ad9451 100644 --- a/src/set.rs +++ b/src/set.rs @@ -258,12 +258,18 @@ impl IndexSet { Drain::new(self.map.core.drain(range)) } - /// Creates an iterator which uses a closure to determine if a value should be removed. + /// Creates an iterator which uses a closure to determine if a value should be removed, + /// for all values in the given range. /// /// If the closure returns true, then the value is removed and yielded. /// If the closure returns false, the value will remain in the list and will not be yielded /// by the iterator. /// + /// The range may be any type that implements [`RangeBounds`], + /// including all of the `std::ops::Range*` types, or even a tuple pair of + /// `Bound` start and end values. To check the entire set, use `RangeFull` + /// like `set.extract_if(.., predicate)`. + /// /// If the returned `ExtractIf` is not exhausted, e.g. because it is dropped without iterating /// or the iteration short-circuits, then the remaining elements will be retained. /// Use [`retain`] with a negated predicate if you do not need the returned iterator. @@ -278,7 +284,7 @@ impl IndexSet { /// use indexmap::IndexSet; /// /// let mut set: IndexSet = (0..8).collect(); - /// let extracted: IndexSet = set.extract_if(|v| v % 2 == 0).collect(); + /// let extracted: IndexSet = set.extract_if(.., |v| v % 2 == 0).collect(); /// /// let evens = extracted.into_iter().collect::>(); /// let odds = set.into_iter().collect::>(); @@ -286,11 +292,12 @@ impl IndexSet { /// assert_eq!(evens, vec![0, 2, 4, 6]); /// assert_eq!(odds, vec![1, 3, 5, 7]); /// ``` - pub fn extract_if(&mut self, pred: F) -> ExtractIf<'_, T, F> + pub fn extract_if(&mut self, range: R, pred: F) -> ExtractIf<'_, T, F> where F: FnMut(&T) -> bool, + R: RangeBounds, { - ExtractIf::new(&mut self.map.core, pred) + ExtractIf::new(&mut self.map.core, range, pred) } /// Splits the collection into two at the given index. diff --git a/src/set/iter.rs b/src/set/iter.rs index a00c743e..2786888c 100644 --- a/src/set/iter.rs +++ b/src/set/iter.rs @@ -633,21 +633,19 @@ impl fmt::Debug for UnitValue { /// /// This `struct` is created by [`IndexSet::extract_if()`]. /// See its documentation for more. -pub struct ExtractIf<'a, T, F> -where - F: FnMut(&T) -> bool, -{ +pub struct ExtractIf<'a, T, F> { inner: ExtractCore<'a, T, ()>, pred: F, } -impl ExtractIf<'_, T, F> -where - F: FnMut(&T) -> bool, -{ - pub(super) fn new(core: &mut IndexMapCore, pred: F) -> ExtractIf<'_, T, F> { +impl ExtractIf<'_, T, F> { + pub(super) fn new(core: &mut IndexMapCore, range: R, pred: F) -> ExtractIf<'_, T, F> + where + R: RangeBounds, + F: FnMut(&T) -> bool, + { ExtractIf { - inner: core.extract(), + inner: core.extract(range), pred, } } @@ -670,10 +668,7 @@ where } } -impl<'a, T, F> fmt::Debug for ExtractIf<'a, T, F> -where - F: FnMut(&T) -> bool, -{ +impl<'a, T, F> fmt::Debug for ExtractIf<'a, T, F> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("ExtractIf").finish_non_exhaustive() } diff --git a/tests/quick.rs b/tests/quick.rs index 9394a4a4..e9682115 100644 --- a/tests/quick.rs +++ b/tests/quick.rs @@ -200,7 +200,7 @@ quickcheck_limit! { let (odd, even): (Vec<_>, Vec<_>) = map.keys().copied().partition(|k| k % 2 == 1); let extracted: Vec<_> = map - .extract_if(|k, _| k % 2 == 1) + .extract_if(.., |k, _| k % 2 == 1) .map(|(k, _)| k) .collect(); @@ -222,7 +222,7 @@ quickcheck_limit! { }); let extracted: Vec<_> = map - .extract_if(|k, _| k % 2 == 1) + .extract_if(.., |k, _| k % 2 == 1) .map(|(k, _)| k) .take(limit) .collect();