aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-07-07 04:44:13 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-07-07 04:44:13 +0000
commitca465cbb5441ee5bd3ffcf0401c803ac96ee4573 (patch)
tree8f35d3645086169c660d74ad03160565694afc51
parentc6a2b7582bd139f450e5a57ffe5e1bb9a899fde9 (diff)
parentcacbffa61ab459e4c3f2caf4bfd4208641a0b0fb (diff)
downloaditertools-android14-mainline-adservices-release.tar.gz
Change-Id: If78e17fb37b7e433793931fc2ee0e8fe7c1eeb00
-rw-r--r--.cargo_vcs_info.json2
-rw-r--r--Android.bp9
-rw-r--r--CHANGELOG.md7
-rw-r--r--Cargo.toml4
-rw-r--r--Cargo.toml.orig4
-rw-r--r--METADATA12
-rw-r--r--README.md2
-rw-r--r--TEST_MAPPING14
-rw-r--r--benches/extra/zipslices.rs2
-rw-r--r--clippy.toml1
-rw-r--r--src/adaptors/coalesce.rs4
-rw-r--r--src/adaptors/mod.rs14
-rw-r--r--src/adaptors/multi_product.rs4
-rw-r--r--src/combinations_with_replacement.rs4
-rw-r--r--src/concat_impl.rs3
-rw-r--r--src/duplicates_impl.rs1
-rw-r--r--src/either_or_both.rs49
-rw-r--r--src/exactly_one_err.rs4
-rw-r--r--src/extrema_set.rs48
-rw-r--r--src/flatten_ok.rs33
-rw-r--r--src/free.rs26
-rw-r--r--src/groupbylazy.rs12
-rw-r--r--src/grouping_map.rs7
-rw-r--r--src/impl_macros.rs1
-rw-r--r--src/intersperse.rs5
-rw-r--r--src/kmerge_impl.rs8
-rw-r--r--src/lazy_buffer.rs20
-rw-r--r--src/lib.rs230
-rw-r--r--src/merge_join.rs4
-rw-r--r--src/multipeek_impl.rs10
-rw-r--r--src/pad_tail.rs2
-rw-r--r--src/peeking_take_while.rs2
-rw-r--r--src/permutations.rs7
-rw-r--r--src/rciter_impl.rs1
-rw-r--r--src/size_hint.rs16
-rw-r--r--src/tuple_impl.rs2
-rw-r--r--src/unique_impl.rs7
-rw-r--r--src/unziptuple.rs8
-rw-r--r--src/ziptuple.rs1
-rw-r--r--tests/adaptors_no_collect.rs11
-rw-r--r--tests/quick.rs116
-rw-r--r--tests/specializations.rs4
-rw-r--r--tests/test_core.rs15
-rw-r--r--tests/test_std.rs80
-rw-r--r--tests/zip.rs8
45 files changed, 597 insertions, 227 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
index 5b491ea..5513313 100644
--- a/.cargo_vcs_info.json
+++ b/.cargo_vcs_info.json
@@ -1,5 +1,5 @@
{
"git": {
- "sha1": "3003c2a968f144cbccb63c768d2fec2e83a69ca4"
+ "sha1": "d61d12e808c8691eb0a672d3f9b65560be970a44"
}
}
diff --git a/Android.bp b/Android.bp
index 09dfee1..0d022a8 100644
--- a/Android.bp
+++ b/Android.bp
@@ -39,11 +39,10 @@ license {
rust_library {
name: "libitertools",
- // has rustc warnings
host_supported: true,
crate_name: "itertools",
cargo_env_compat: true,
- cargo_pkg_version: "0.10.3",
+ cargo_pkg_version: "0.10.5",
srcs: ["src/lib.rs"],
edition: "2018",
features: [
@@ -54,4 +53,10 @@ rust_library {
rustlibs: [
"libeither",
],
+ apex_available: [
+ "//apex_available:platform",
+ "//apex_available:anyapex",
+ ],
+ product_available: true,
+ vendor_available: true,
}
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5e2032c..d2b40b5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,12 @@
# Changelog
+## 0.10.4
+ - Add `EitherOrBoth::or` and `EitherOrBoth::or_else` (#593)
+ - Add `min_set`, `max_set` et al. (#613, #323)
+ - Use `either/use_std` (#628)
+ - Documentation fixes (#612, #625, #632, #633, #634, #638)
+ - Code maintenance (#623, #624, #627, #630)
+
## 0.10.2
- Add `Itertools::multiunzip` (#362, #565)
- Add `intersperse` and `intersperse_with` free functions (#555)
diff --git a/Cargo.toml b/Cargo.toml
index 525cae5..40be7e4 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -13,7 +13,7 @@
[package]
edition = "2018"
name = "itertools"
-version = "0.10.3"
+version = "0.10.5"
authors = ["bluss"]
exclude = ["/bors.toml"]
description = "Extra iterator adaptors, iterator methods, free functions, and macros."
@@ -85,4 +85,4 @@ version = "0.7"
[features]
default = ["use_std"]
use_alloc = []
-use_std = ["use_alloc"]
+use_std = ["use_alloc", "either/use_std"]
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
index 22a08a8..afe2ed6 100644
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -1,6 +1,6 @@
[package]
name = "itertools"
-version = "0.10.3"
+version = "0.10.5"
license = "MIT/Apache-2.0"
repository = "https://github.com/rust-itertools/itertools"
@@ -40,7 +40,7 @@ version = "0.2"
[features]
default = ["use_std"]
-use_std = ["use_alloc"]
+use_std = ["use_alloc", "either/use_std"]
use_alloc = []
[profile]
diff --git a/METADATA b/METADATA
index ca38654..bac5c1b 100644
--- a/METADATA
+++ b/METADATA
@@ -1,3 +1,7 @@
+# This project was upgraded with external_updater.
+# Usage: tools/external_updater/updater.sh update rust/crates/itertools
+# For more info, check https://cs.android.com/android/platform/superproject/+/master:tools/external_updater/README.md
+
name: "itertools"
description: "Extra iterator adaptors, iterator methods, free functions, and macros."
third_party {
@@ -7,13 +11,13 @@ third_party {
}
url {
type: ARCHIVE
- value: "https://static.crates.io/crates/itertools/itertools-0.10.3.crate"
+ value: "https://static.crates.io/crates/itertools/itertools-0.10.5.crate"
}
- version: "0.10.3"
+ version: "0.10.5"
license_type: NOTICE
last_upgrade_date {
year: 2022
- month: 3
- day: 1
+ month: 12
+ day: 12
}
}
diff --git a/README.md b/README.md
index 4cc3f8f..a911127 100644
--- a/README.md
+++ b/README.md
@@ -11,7 +11,7 @@ How to use with Cargo:
```toml
[dependencies]
-itertools = "0.10.2"
+itertools = "0.10.5"
```
How to use in your crate:
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 86d1024..0651001 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -12,22 +12,12 @@
},
{
"path": "external/rust/crates/unicode-xid"
- }
- ],
- "presubmit": [
- {
- "name": "apkdmverity.test"
},
{
- "name": "microdroid_manager_test"
- }
- ],
- "presubmit-rust": [
- {
- "name": "apkdmverity.test"
+ "path": "packages/modules/Virtualization/apkdmverity"
},
{
- "name": "microdroid_manager_test"
+ "path": "packages/modules/Virtualization/microdroid_manager"
}
]
}
diff --git a/benches/extra/zipslices.rs b/benches/extra/zipslices.rs
index 8bf3967..633be59 100644
--- a/benches/extra/zipslices.rs
+++ b/benches/extra/zipslices.rs
@@ -3,7 +3,7 @@ use std::cmp;
// Note: There are different ways to implement ZipSlices.
// This version performed the best in benchmarks.
//
-// I also implemented a version with three pointes (tptr, tend, uptr),
+// I also implemented a version with three pointers (tptr, tend, uptr),
// that mimiced slice::Iter and only checked bounds by using tptr == tend,
// but that was inferior to this solution.
diff --git a/clippy.toml b/clippy.toml
new file mode 100644
index 0000000..0a54853
--- /dev/null
+++ b/clippy.toml
@@ -0,0 +1 @@
+msrv = "1.36.0"
diff --git a/src/adaptors/coalesce.rs b/src/adaptors/coalesce.rs
index b1aff6e..3df7cc5 100644
--- a/src/adaptors/coalesce.rs
+++ b/src/adaptors/coalesce.rs
@@ -3,6 +3,7 @@ use std::iter::FusedIterator;
use crate::size_hint;
+#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct CoalesceBy<I, F, T>
where
I: Iterator,
@@ -86,7 +87,6 @@ impl<I: Iterator, F: CoalescePredicate<I::Item, T>, T> FusedIterator for Coalesc
/// An iterator adaptor that may join together adjacent elements.
///
/// See [`.coalesce()`](crate::Itertools::coalesce) for more information.
-#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub type Coalesce<I, F> = CoalesceBy<I, F, <I as Iterator>::Item>;
impl<F, Item, T> CoalescePredicate<Item, T> for F
@@ -113,7 +113,6 @@ where
/// An iterator adaptor that removes repeated duplicates, determining equality using a comparison function.
///
/// See [`.dedup_by()`](crate::Itertools::dedup_by) or [`.dedup()`](crate::Itertools::dedup) for more information.
-#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub type DedupBy<I, Pred> = CoalesceBy<I, DedupPred2CoalescePred<Pred>, <I as Iterator>::Item>;
#[derive(Clone)]
@@ -186,7 +185,6 @@ where
///
/// See [`.dedup_by_with_count()`](crate::Itertools::dedup_by_with_count) or
/// [`.dedup_with_count()`](crate::Itertools::dedup_with_count) for more information.
-#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub type DedupByWithCount<I, Pred> =
CoalesceBy<I, DedupPredWithCount2CoalescePred<Pred>, (usize, <I as Iterator>::Item)>;
diff --git a/src/adaptors/mod.rs b/src/adaptors/mod.rs
index 2010f53..1695bbd 100644
--- a/src/adaptors/mod.rs
+++ b/src/adaptors/mod.rs
@@ -35,9 +35,7 @@ pub struct Interleave<I, J> {
/// Create an iterator that interleaves elements in `i` and `j`.
///
-/// [`IntoIterator`] enabled version of `i.interleave(j)`.
-///
-/// See [`.interleave()`](crate::Itertools::interleave) for more information.
+/// [`IntoIterator`] enabled version of `[Itertools::interleave]`.
pub fn interleave<I, J>(i: I, j: J) -> Interleave<<I as IntoIterator>::IntoIter, <J as IntoIterator>::IntoIter>
where I: IntoIterator,
J: IntoIterator<Item = I::Item>
@@ -210,7 +208,7 @@ impl<I> PutBack<I>
/// If a value is already in the put back slot, it is overwritten.
#[inline]
pub fn put_back(&mut self, x: I::Item) {
- self.top = Some(x)
+ self.top = Some(x);
}
}
@@ -329,12 +327,7 @@ impl<I, J> Iterator for Product<I, J>
}
Some(x) => x
};
- match self.a_cur {
- None => None,
- Some(ref a) => {
- Some((a.clone(), elt_b))
- }
- }
+ self.a_cur.as_ref().map(|a| (a.clone(), elt_b))
}
fn size_hint(&self) -> (usize, Option<usize>) {
@@ -492,7 +485,6 @@ impl<T: PartialOrd> MergePredicate<T> for MergeLte {
/// Iterator element type is `I::Item`.
///
/// See [`.merge()`](crate::Itertools::merge_by) for more information.
-#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub type Merge<I, J> = MergeBy<I, J, MergeLte>;
/// Create an iterator that merges elements in `i` and `j`.
diff --git a/src/adaptors/multi_product.rs b/src/adaptors/multi_product.rs
index 30650ed..0b38406 100644
--- a/src/adaptors/multi_product.rs
+++ b/src/adaptors/multi_product.rs
@@ -40,7 +40,7 @@ pub fn multi_cartesian_product<H>(iters: H) -> MultiProduct<<H::Item as IntoIter
}
#[derive(Clone, Debug)]
-/// Holds the state of a single iterator within a MultiProduct.
+/// Holds the state of a single iterator within a `MultiProduct`.
struct MultiProductIter<I>
where I: Iterator + Clone,
I::Item: Clone
@@ -50,7 +50,7 @@ struct MultiProductIter<I>
iter_orig: I,
}
-/// Holds the current state during an iteration of a MultiProduct.
+/// Holds the current state during an iteration of a `MultiProduct`.
#[derive(Debug)]
enum MultiProductIterState {
StartOfIter,
diff --git a/src/combinations_with_replacement.rs b/src/combinations_with_replacement.rs
index 81b13f1..0fec967 100644
--- a/src/combinations_with_replacement.rs
+++ b/src/combinations_with_replacement.rs
@@ -64,7 +64,7 @@ where
// If this is the first iteration, return early
if self.first {
// In empty edge cases, stop iterating immediately
- return if self.indices.len() != 0 && !self.pool.get_next() {
+ return if !(self.indices.is_empty() || self.pool.get_next()) {
None
// Otherwise, yield the initial state
} else {
@@ -92,7 +92,7 @@ where
// We need to update the rightmost non-max value
// and all those to the right
for indices_index in increment_from..self.indices.len() {
- self.indices[indices_index] = increment_value
+ self.indices[indices_index] = increment_value;
}
Some(self.current())
}
diff --git a/src/concat_impl.rs b/src/concat_impl.rs
index 450f7fc..f022ec9 100644
--- a/src/concat_impl.rs
+++ b/src/concat_impl.rs
@@ -18,5 +18,6 @@ pub fn concat<I>(iterable: I) -> I::Item
where I: IntoIterator,
I::Item: Extend<<<I as IntoIterator>::Item as IntoIterator>::Item> + IntoIterator + Default
{
- iterable.into_iter().fold1(|mut a, b| { a.extend(b); a }).unwrap_or_else(<_>::default)
+ #[allow(deprecated)] //TODO: once msrv hits 1.51. replace `fold1` with `reduce`
+ iterable.into_iter().fold1(|mut a, b| { a.extend(b); a }).unwrap_or_default()
}
diff --git a/src/duplicates_impl.rs b/src/duplicates_impl.rs
index 640d481..28eda44 100644
--- a/src/duplicates_impl.rs
+++ b/src/duplicates_impl.rs
@@ -188,7 +188,6 @@ mod private {
/// An iterator adapter to filter for duplicate elements.
///
/// See [`.duplicates_by()`](crate::Itertools::duplicates_by) for more information.
-#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub type DuplicatesBy<I, V, F> = private::DuplicatesBy<I, V, private::ByFn<F>>;
/// Create a new `DuplicatesBy` iterator.
diff --git a/src/either_or_both.rs b/src/either_or_both.rs
index 28d1df7..ef3985f 100644
--- a/src/either_or_both.rs
+++ b/src/either_or_both.rs
@@ -165,6 +165,33 @@ impl<A, B> EitherOrBoth<A, B> {
}
/// Returns a tuple consisting of the `l` and `r` in `Both(l, r)`, if present.
+ /// Otherwise, returns the wrapped value for the present element, and the supplied
+ /// value for the other. The first (`l`) argument is used for a missing `Left`
+ /// value. The second (`r`) argument is used for a missing `Right` value.
+ ///
+ /// Arguments passed to `or` are eagerly evaluated; if you are passing
+ /// the result of a function call, it is recommended to use [`or_else`],
+ /// which is lazily evaluated.
+ ///
+ /// [`or_else`]: EitherOrBoth::or_else
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # use itertools::EitherOrBoth;
+ /// assert_eq!(EitherOrBoth::Both("tree", 1).or("stone", 5), ("tree", 1));
+ /// assert_eq!(EitherOrBoth::Left("tree").or("stone", 5), ("tree", 5));
+ /// assert_eq!(EitherOrBoth::Right(1).or("stone", 5), ("stone", 1));
+ /// ```
+ pub fn or(self, l: A, r: B) -> (A, B) {
+ match self {
+ Left(inner_l) => (inner_l, r),
+ Right(inner_r) => (l, inner_r),
+ Both(inner_l, inner_r) => (inner_l, inner_r),
+ }
+ }
+
+ /// Returns a tuple consisting of the `l` and `r` in `Both(l, r)`, if present.
/// Otherwise, returns the wrapped value for the present element, and the [`default`](Default::default)
/// for the other.
pub fn or_default(self) -> (A, B)
@@ -178,6 +205,28 @@ impl<A, B> EitherOrBoth<A, B> {
EitherOrBoth::Both(l, r) => (l, r),
}
}
+
+ /// Returns a tuple consisting of the `l` and `r` in `Both(l, r)`, if present.
+ /// Otherwise, returns the wrapped value for the present element, and computes the
+ /// missing value with the supplied closure. The first argument (`l`) is used for a
+ /// missing `Left` value. The second argument (`r`) is used for a missing `Right` value.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # use itertools::EitherOrBoth;
+ /// let k = 10;
+ /// assert_eq!(EitherOrBoth::Both("tree", 1).or_else(|| "stone", || 2 * k), ("tree", 1));
+ /// assert_eq!(EitherOrBoth::Left("tree").or_else(|| "stone", || 2 * k), ("tree", 20));
+ /// assert_eq!(EitherOrBoth::Right(1).or_else(|| "stone", || 2 * k), ("stone", 1));
+ /// ```
+ pub fn or_else<L: FnOnce() -> A, R: FnOnce() -> B>(self, l: L, r: R) -> (A, B) {
+ match self {
+ Left(inner_l) => (inner_l, r()),
+ Right(inner_r) => (l(), inner_r),
+ Both(inner_l, inner_r) => (inner_l, inner_r),
+ }
+ }
}
impl<T> EitherOrBoth<T, T> {
diff --git a/src/exactly_one_err.rs b/src/exactly_one_err.rs
index 63485c9..c54ae77 100644
--- a/src/exactly_one_err.rs
+++ b/src/exactly_one_err.rs
@@ -11,10 +11,10 @@ use crate::size_hint;
/// Iterator returned for the error case of `IterTools::exactly_one()`
/// This iterator yields exactly the same elements as the input iterator.
///
-/// During the execution of exactly_one the iterator must be mutated. This wrapper
+/// During the execution of `exactly_one` the iterator must be mutated. This wrapper
/// effectively "restores" the state of the input iterator when it's handed back.
///
-/// This is very similar to PutBackN except this iterator only supports 0-2 elements and does not
+/// This is very similar to `PutBackN` except this iterator only supports 0-2 elements and does not
/// use a `Vec`.
#[derive(Clone)]
pub struct ExactlyOneError<I>
diff --git a/src/extrema_set.rs b/src/extrema_set.rs
new file mode 100644
index 0000000..ae12836
--- /dev/null
+++ b/src/extrema_set.rs
@@ -0,0 +1,48 @@
+use std::cmp::Ordering;
+
+/// Implementation guts for `min_set`, `min_set_by`, and `min_set_by_key`.
+pub fn min_set_impl<I, K, F, Compare>(
+ mut it: I,
+ mut key_for: F,
+ mut compare: Compare,
+) -> Vec<I::Item>
+where
+ I: Iterator,
+ F: FnMut(&I::Item) -> K,
+ Compare: FnMut(&I::Item, &I::Item, &K, &K) -> Ordering,
+{
+ match it.next() {
+ None => Vec::new(),
+ Some(element) => {
+ let mut current_key = key_for(&element);
+ let mut result = vec![element];
+ it.for_each(|element| {
+ let key = key_for(&element);
+ match compare(&element, &result[0], &key, &current_key) {
+ Ordering::Less => {
+ result.clear();
+ result.push(element);
+ current_key = key;
+ }
+ Ordering::Equal => {
+ result.push(element);
+ }
+ Ordering::Greater => {}
+ }
+ });
+ result
+ }
+ }
+}
+
+/// Implementation guts for `ax_set`, `max_set_by`, and `max_set_by_key`.
+pub fn max_set_impl<I, K, F, Compare>(it: I, key_for: F, mut compare: Compare) -> Vec<I::Item>
+where
+ I: Iterator,
+ F: FnMut(&I::Item) -> K,
+ Compare: FnMut(&I::Item, &I::Item, &K, &K) -> Ordering,
+{
+ min_set_impl(it, key_for, |it1, it2, key1, key2| {
+ compare(it2, it1, key2, key1)
+ })
+}
diff --git a/src/flatten_ok.rs b/src/flatten_ok.rs
index d46bbde..21ae1f7 100644
--- a/src/flatten_ok.rs
+++ b/src/flatten_ok.rs
@@ -44,11 +44,11 @@ where
if let Some(inner) = &mut self.inner_front {
if let Some(item) = inner.next() {
return Some(Ok(item));
- } else {
- // This is necessary for the iterator to implement `FusedIterator`
- // with only the orginal iterator being fused.
- self.inner_front = None;
}
+
+ // This is necessary for the iterator to implement `FusedIterator`
+ // with only the original iterator being fused.
+ self.inner_front = None;
}
match self.iter.next() {
@@ -59,11 +59,11 @@ where
if let Some(inner) = &mut self.inner_back {
if let Some(item) = inner.next() {
return Some(Ok(item));
- } else {
- // This is necessary for the iterator to implement `FusedIterator`
- // with only the orginal iterator being fused.
- self.inner_back = None;
}
+
+ // This is necessary for the iterator to implement `FusedIterator`
+ // with only the original iterator being fused.
+ self.inner_back = None;
} else {
return None;
}
@@ -103,11 +103,11 @@ where
if let Some(inner) = &mut self.inner_back {
if let Some(item) = inner.next_back() {
return Some(Ok(item));
- } else {
- // This is necessary for the iterator to implement `FusedIterator`
- // with only the orginal iterator being fused.
- self.inner_back = None;
}
+
+ // This is necessary for the iterator to implement `FusedIterator`
+ // with only the original iterator being fused.
+ self.inner_back = None;
}
match self.iter.next_back() {
@@ -118,11 +118,11 @@ where
if let Some(inner) = &mut self.inner_front {
if let Some(item) = inner.next_back() {
return Some(Ok(item));
- } else {
- // This is necessary for the iterator to implement `FusedIterator`
- // with only the orginal iterator being fused.
- self.inner_front = None;
}
+
+ // This is necessary for the iterator to implement `FusedIterator`
+ // with only the original iterator being fused.
+ self.inner_front = None;
} else {
return None;
}
@@ -138,7 +138,6 @@ where
T: IntoIterator,
T::IntoIter: Clone,
{
- #[inline]
clone_fields!(iter, inner_front, inner_back);
}
diff --git a/src/free.rs b/src/free.rs
index 6674030..19e3e28 100644
--- a/src/free.rs
+++ b/src/free.rs
@@ -105,18 +105,23 @@ pub fn rev<I>(iterable: I) -> iter::Rev<I::IntoIter>
iterable.into_iter().rev()
}
-/// Iterate `i` and `j` in lock step.
+/// Converts the arguments to iterators and zips them.
///
/// [`IntoIterator`] enabled version of [`Iterator::zip`].
+///
+/// ## Example
///
/// ```
/// use itertools::zip;
///
-/// let data = [1, 2, 3, 4, 5];
-/// for (a, b) in zip(&data, &data[1..]) {
-/// /* loop body */
+/// let mut result: Vec<(i32, char)> = Vec::new();
+///
+/// for (a, b) in zip(&[1, 2, 3, 4, 5], &['a', 'b', 'c']) {
+/// result.push((*a, *b));
/// }
+/// assert_eq!(result, vec![(1, 'a'),(2, 'b'),(3, 'c')]);
/// ```
+#[deprecated(note="Use [std::iter::zip](https://doc.rust-lang.org/std/iter/fn.zip.html) instead", since="0.10.4")]
pub fn zip<I, J>(i: I, j: J) -> Zip<I::IntoIter, J::IntoIter>
where I: IntoIterator,
J: IntoIterator
@@ -124,16 +129,21 @@ pub fn zip<I, J>(i: I, j: J) -> Zip<I::IntoIter, J::IntoIter>
i.into_iter().zip(j)
}
-/// Create an iterator that first iterates `i` and then `j`.
+
+/// Takes two iterables and creates a new iterator over both in sequence.
///
/// [`IntoIterator`] enabled version of [`Iterator::chain`].
///
+/// ## Example
/// ```
/// use itertools::chain;
+///
+/// let mut result:Vec<i32> = Vec::new();
///
-/// for elt in chain(&[1, 2, 3], &[4]) {
-/// /* loop body */
+/// for element in chain(&[1, 2, 3], &[4]) {
+/// result.push(*element);
/// }
+/// assert_eq!(result, vec![1, 2, 3, 4]);
/// ```
pub fn chain<I, J>(i: I, j: J) -> iter::Chain<<I as IntoIterator>::IntoIter, <J as IntoIterator>::IntoIter>
where I: IntoIterator,
@@ -239,7 +249,7 @@ pub fn min<I>(iterable: I) -> Option<I::Item>
}
-/// Combine all iterator elements into one String, seperated by `sep`.
+/// Combine all iterator elements into one String, separated by `sep`.
///
/// [`IntoIterator`] enabled version of [`Itertools::join`].
///
diff --git a/src/groupbylazy.rs b/src/groupbylazy.rs
index 91c52ea..a5a321d 100644
--- a/src/groupbylazy.rs
+++ b/src/groupbylazy.rs
@@ -1,13 +1,13 @@
use std::cell::{Cell, RefCell};
use alloc::vec::{self, Vec};
-/// A trait to unify FnMut for GroupBy with the chunk key in IntoChunks
+/// A trait to unify `FnMut` for `GroupBy` with the chunk key in `IntoChunks`
trait KeyFunction<A> {
type Key;
fn call_mut(&mut self, arg: A) -> Self::Key;
}
-impl<'a, A, K, F: ?Sized> KeyFunction<A> for F
+impl<A, K, F: ?Sized> KeyFunction<A> for F
where F: FnMut(A) -> K
{
type Key = K;
@@ -18,7 +18,7 @@ impl<'a, A, K, F: ?Sized> KeyFunction<A> for F
}
-/// ChunkIndex acts like the grouping key function for IntoChunks
+/// `ChunkIndex` acts like the grouping key function for `IntoChunks`
#[derive(Debug)]
struct ChunkIndex {
size: usize,
@@ -37,7 +37,7 @@ impl ChunkIndex {
}
}
-impl<'a, A> KeyFunction<A> for ChunkIndex {
+impl<A> KeyFunction<A> for ChunkIndex {
type Key = usize;
#[inline(always)]
fn call_mut(&mut self, _arg: A) -> Self::Key {
@@ -330,7 +330,7 @@ impl<K, I, F> GroupBy<K, I, F>
/// `client`: Index of group
fn drop_group(&self, client: usize) {
- self.inner.borrow_mut().drop_group(client)
+ self.inner.borrow_mut().drop_group(client);
}
}
@@ -482,7 +482,7 @@ impl<I> IntoChunks<I>
/// `client`: Index of chunk
fn drop_group(&self, client: usize) {
- self.inner.borrow_mut().drop_group(client)
+ self.inner.borrow_mut().drop_group(client);
}
}
diff --git a/src/grouping_map.rs b/src/grouping_map.rs
index be22ec8..bb5b582 100644
--- a/src/grouping_map.rs
+++ b/src/grouping_map.rs
@@ -39,7 +39,6 @@ pub fn new<I, K, V>(iter: I) -> GroupingMap<I>
/// `GroupingMapBy` is an intermediate struct for efficient group-and-fold operations.
///
/// See [`GroupingMap`] for more informations.
-#[must_use = "GroupingMapBy is lazy and do nothing unless consumed"]
pub type GroupingMapBy<I, F> = GroupingMap<MapForGrouping<I, F>>;
/// `GroupingMap` is an intermediate struct for efficient group-and-fold operations.
@@ -290,7 +289,7 @@ impl<I, K, V> GroupingMap<I>
where F: FnMut(&K, &V) -> CK,
CK: Ord,
{
- self.max_by(|key, v1, v2| f(key, &v1).cmp(&f(key, &v2)))
+ self.max_by(|key, v1, v2| f(key, v1).cmp(&f(key, v2)))
}
/// Groups elements from the `GroupingMap` source by key and finds the minimum of each group.
@@ -368,7 +367,7 @@ impl<I, K, V> GroupingMap<I>
where F: FnMut(&K, &V) -> CK,
CK: Ord,
{
- self.min_by(|key, v1, v2| f(key, &v1).cmp(&f(key, &v2)))
+ self.min_by(|key, v1, v2| f(key, v1).cmp(&f(key, v2)))
}
/// Groups elements from the `GroupingMap` source by key and find the maximum and minimum of
@@ -481,7 +480,7 @@ impl<I, K, V> GroupingMap<I>
where F: FnMut(&K, &V) -> CK,
CK: Ord,
{
- self.minmax_by(|key, v1, v2| f(key, &v1).cmp(&f(key, &v2)))
+ self.minmax_by(|key, v1, v2| f(key, v1).cmp(&f(key, v2)))
}
/// Groups elements from the `GroupingMap` source by key and sums them.
diff --git a/src/impl_macros.rs b/src/impl_macros.rs
index 5772bae..a029843 100644
--- a/src/impl_macros.rs
+++ b/src/impl_macros.rs
@@ -15,6 +15,7 @@ macro_rules! debug_fmt_fields {
macro_rules! clone_fields {
($($field:ident),*) => {
+ #[inline] // TODO is this sensible?
fn clone(&self) -> Self {
Self {
$($field: self.$field.clone(),)*
diff --git a/src/intersperse.rs b/src/intersperse.rs
index 2c660d4..10a3a53 100644
--- a/src/intersperse.rs
+++ b/src/intersperse.rs
@@ -55,7 +55,7 @@ pub struct IntersperseWith<I, ElemF>
peek: Option<I::Item>,
}
-/// Create a new IntersperseWith iterator
+/// Create a new `IntersperseWith` iterator
pub fn intersperse_with<I, ElemF>(iter: I, elt: ElemF) -> IntersperseWith<I, ElemF>
where I: Iterator,
{
@@ -107,8 +107,7 @@ impl<I, ElemF> Iterator for IntersperseWith<I, ElemF>
self.iter.fold(accum,
|accum, x| {
let accum = f(accum, element.generate());
- let accum = f(accum, x);
- accum
+ f(accum, x)
})
}
}
diff --git a/src/kmerge_impl.rs b/src/kmerge_impl.rs
index bd56b03..509d5fc 100644
--- a/src/kmerge_impl.rs
+++ b/src/kmerge_impl.rs
@@ -80,7 +80,7 @@ fn sift_down<T, S>(heap: &mut [T], index: usize, mut less_than: S)
// that wouldn't be predicted if present
while child + 1 < heap.len() {
// pick the smaller of the two children
- // use aritmethic to avoid an unpredictable branch
+ // use arithmetic to avoid an unpredictable branch
child += less_than(&heap[child+1], &heap[child]) as usize;
// sift down is done if we are already in order
@@ -104,7 +104,6 @@ fn sift_down<T, S>(heap: &mut [T], index: usize, mut less_than: S)
/// Iterator element type is `I::Item`.
///
/// See [`.kmerge()`](crate::Itertools::kmerge) for more information.
-#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub type KMerge<I> = KMergeBy<I, KMergeByLt>;
pub trait KMergePredicate<T> {
@@ -129,7 +128,7 @@ impl<T, F: FnMut(&T, &T)->bool> KMergePredicate<T> for F {
/// Create an iterator that merges elements of the contained iterators using
/// the ordering function.
///
-/// Equivalent to `iterable.into_iter().kmerge()`.
+/// [`IntoIterator`] enabled version of [`Itertools::kmerge`].
///
/// ```
/// use itertools::kmerge;
@@ -170,7 +169,7 @@ impl<I, F> fmt::Debug for KMergeBy<I, F>
/// Create an iterator that merges elements of the contained iterators.
///
-/// Equivalent to `iterable.into_iter().kmerge_by(less_than)`.
+/// [`IntoIterator`] enabled version of [`Itertools::kmerge_by`].
pub fn kmerge_by<I, F>(iterable: I, mut less_than: F)
-> KMergeBy<<I::Item as IntoIterator>::IntoIter, F>
where I: IntoIterator,
@@ -214,6 +213,7 @@ impl<I, F> Iterator for KMergeBy<I, F>
}
fn size_hint(&self) -> (usize, Option<usize>) {
+ #[allow(deprecated)] //TODO: once msrv hits 1.51. replace `fold1` with `reduce`
self.heap.iter()
.map(|i| i.size_hint())
.fold1(size_hint::add)
diff --git a/src/lazy_buffer.rs b/src/lazy_buffer.rs
index fa514ec..ca24062 100644
--- a/src/lazy_buffer.rs
+++ b/src/lazy_buffer.rs
@@ -28,16 +28,12 @@ where
if self.done {
return false;
}
- let next_item = self.it.next();
- match next_item {
- Some(x) => {
- self.buffer.push(x);
- true
- }
- None => {
- self.done = true;
- false
- }
+ if let Some(x) = self.it.next() {
+ self.buffer.push(x);
+ true
+ } else {
+ self.done = true;
+ false
}
}
@@ -61,7 +57,7 @@ where
{
type Output = <Vec<I::Item> as Index<J>>::Output;
- fn index(&self, _index: J) -> &Self::Output {
- self.buffer.index(_index)
+ fn index(&self, index: J) -> &Self::Output {
+ self.buffer.index(index)
}
}
diff --git a/src/lib.rs b/src/lib.rs
index df95e19..f919688 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -197,6 +197,8 @@ mod combinations_with_replacement;
mod exactly_one_err;
mod diff;
mod flatten_ok;
+#[cfg(feature = "use_std")]
+mod extrema_set;
mod format;
#[cfg(feature = "use_std")]
mod grouping_map;
@@ -387,7 +389,7 @@ macro_rules! izip {
/// let with_macro: Chain<Chain<Once<_>, Take<Repeat<_>>>, slice::Iter<_>> =
/// chain![once(&0), repeat(&1).take(2), &[2, 3, 5],];
///
-/// // ...is equivalant to this:
+/// // ...is equivalent to this:
/// let with_method: Chain<Chain<Once<_>, Take<Repeat<_>>>, slice::Iter<_>> =
/// once(&0)
/// .chain(repeat(&1).take(2))
@@ -778,7 +780,7 @@ pub trait Itertools : Iterator {
/// the original iterator.
///
/// **Note:** If the iterator is clonable, prefer using that instead
- /// of using this method. It is likely to be more efficient.
+ /// of using this method. Cloning is likely to be more efficient.
///
/// Iterator element type is `Self::Item`.
///
@@ -904,7 +906,7 @@ pub trait Itertools : Iterator {
/// a series of `Result::Ok` values. `Result::Err` values are unchanged.
///
/// This is useful when you have some common error type for your crate and
- /// need to propogate it upwards, but the `Result::Ok` case needs to be flattened.
+ /// need to propagate it upwards, but the `Result::Ok` case needs to be flattened.
///
/// ```
/// use itertools::Itertools;
@@ -913,7 +915,7 @@ pub trait Itertools : Iterator {
/// let it = input.iter().cloned().flatten_ok();
/// itertools::assert_equal(it.clone(), vec![Ok(0), Ok(1), Err(false), Ok(2), Ok(3)]);
///
- /// // This can also be used to propogate errors when collecting.
+ /// // This can also be used to propagate errors when collecting.
/// let output_result: Result<Vec<i32>, bool> = it.collect();
/// assert_eq!(output_result, Err(false));
/// ```
@@ -1109,7 +1111,7 @@ pub trait Itertools : Iterator {
/// ```
#[cfg(feature = "use_alloc")]
fn multi_cartesian_product(self) -> MultiProduct<<Self::Item as IntoIterator>::IntoIter>
- where Self: Iterator + Sized,
+ where Self: Sized,
Self::Item: IntoIterator,
<Self::Item as IntoIterator>::IntoIter: Clone,
<Self::Item as IntoIterator>::Item: Clone
@@ -1746,12 +1748,10 @@ pub trait Itertools : Iterator {
fn find_position<P>(&mut self, mut pred: P) -> Option<(usize, Self::Item)>
where P: FnMut(&Self::Item) -> bool
{
- let mut index = 0usize;
- for elt in self {
+ for (index, elt) in self.enumerate() {
if pred(&elt) {
return Some((index, elt));
}
- index += 1;
}
None
}
@@ -1795,7 +1795,7 @@ pub trait Itertools : Iterator {
Some(if predicate(&first) {
first
} else {
- self.find(|x| predicate(&x)).unwrap_or(first)
+ self.find(|x| predicate(x)).unwrap_or(first)
})
}
/// Returns `true` if the given item is present in this iterator.
@@ -1953,7 +1953,7 @@ pub trait Itertools : Iterator {
where F: FnMut(Self::Item),
Self: Sized,
{
- self.for_each(f)
+ self.for_each(f);
}
/// Combine all an iterator's elements into one element by using [`Extend`].
@@ -2271,7 +2271,7 @@ pub trait Itertools : Iterator {
/// ```
///
/// Which, for non-associative functions, will typically produce a different
- /// result than the linear call tree used by `fold1`:
+ /// result than the linear call tree used by [`Iterator::reduce`]:
///
/// ```text
/// 1 2 3 4 5 6 7
@@ -2279,7 +2279,7 @@ pub trait Itertools : Iterator {
/// └─f─f─f─f─f─f
/// ```
///
- /// If `f` is associative, prefer the normal `fold1` instead.
+ /// If `f` is associative, prefer the normal [`Iterator::reduce`] instead.
///
/// ```
/// use itertools::Itertools;
@@ -2692,7 +2692,6 @@ pub trait Itertools : Iterator {
/// itertools::assert_equal(oldest_people_first,
/// vec!["Jill", "Jack", "Jane", "John"]);
/// ```
- /// ```
#[cfg(feature = "use_alloc")]
fn sorted_by_cached_key<K, F>(self, f: F) -> VecIntoIter<Self::Item>
where
@@ -2902,6 +2901,194 @@ pub trait Itertools : Iterator {
grouping_map::new(grouping_map::MapForGrouping::new(self, key_mapper))
}
+ /// Return all minimum elements of an iterator.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use itertools::Itertools;
+ ///
+ /// let a: [i32; 0] = [];
+ /// assert_eq!(a.iter().min_set(), Vec::<&i32>::new());
+ ///
+ /// let a = [1];
+ /// assert_eq!(a.iter().min_set(), vec![&1]);
+ ///
+ /// let a = [1, 2, 3, 4, 5];
+ /// assert_eq!(a.iter().min_set(), vec![&1]);
+ ///
+ /// let a = [1, 1, 1, 1];
+ /// assert_eq!(a.iter().min_set(), vec![&1, &1, &1, &1]);
+ /// ```
+ ///
+ /// The elements can be floats but no particular result is guaranteed
+ /// if an element is NaN.
+ #[cfg(feature = "use_std")]
+ fn min_set(self) -> Vec<Self::Item>
+ where Self: Sized, Self::Item: Ord
+ {
+ extrema_set::min_set_impl(self, |_| (), |x, y, _, _| x.cmp(y))
+ }
+
+ /// Return all minimum elements of an iterator, as determined by
+ /// the specified function.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # use std::cmp::Ordering;
+ /// use itertools::Itertools;
+ ///
+ /// let a: [(i32, i32); 0] = [];
+ /// assert_eq!(a.iter().min_set_by(|_, _| Ordering::Equal), Vec::<&(i32, i32)>::new());
+ ///
+ /// let a = [(1, 2)];
+ /// assert_eq!(a.iter().min_set_by(|&&(k1,_), &&(k2, _)| k1.cmp(&k2)), vec![&(1, 2)]);
+ ///
+ /// let a = [(1, 2), (2, 2), (3, 9), (4, 8), (5, 9)];
+ /// assert_eq!(a.iter().min_set_by(|&&(_,k1), &&(_,k2)| k1.cmp(&k2)), vec![&(1, 2), &(2, 2)]);
+ ///
+ /// let a = [(1, 2), (1, 3), (1, 4), (1, 5)];
+ /// assert_eq!(a.iter().min_set_by(|&&(k1,_), &&(k2, _)| k1.cmp(&k2)), vec![&(1, 2), &(1, 3), &(1, 4), &(1, 5)]);
+ /// ```
+ ///
+ /// The elements can be floats but no particular result is guaranteed
+ /// if an element is NaN.
+ #[cfg(feature = "use_std")]
+ fn min_set_by<F>(self, mut compare: F) -> Vec<Self::Item>
+ where Self: Sized, F: FnMut(&Self::Item, &Self::Item) -> Ordering
+ {
+ extrema_set::min_set_impl(
+ self,
+ |_| (),
+ |x, y, _, _| compare(x, y)
+ )
+ }
+
+ /// Return all minimum elements of an iterator, as determined by
+ /// the specified function.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use itertools::Itertools;
+ ///
+ /// let a: [(i32, i32); 0] = [];
+ /// assert_eq!(a.iter().min_set_by_key(|_| ()), Vec::<&(i32, i32)>::new());
+ ///
+ /// let a = [(1, 2)];
+ /// assert_eq!(a.iter().min_set_by_key(|&&(k,_)| k), vec![&(1, 2)]);
+ ///
+ /// let a = [(1, 2), (2, 2), (3, 9), (4, 8), (5, 9)];
+ /// assert_eq!(a.iter().min_set_by_key(|&&(_, k)| k), vec![&(1, 2), &(2, 2)]);
+ ///
+ /// let a = [(1, 2), (1, 3), (1, 4), (1, 5)];
+ /// assert_eq!(a.iter().min_set_by_key(|&&(k, _)| k), vec![&(1, 2), &(1, 3), &(1, 4), &(1, 5)]);
+ /// ```
+ ///
+ /// The elements can be floats but no particular result is guaranteed
+ /// if an element is NaN.
+ #[cfg(feature = "use_std")]
+ fn min_set_by_key<K, F>(self, key: F) -> Vec<Self::Item>
+ where Self: Sized, K: Ord, F: FnMut(&Self::Item) -> K
+ {
+ extrema_set::min_set_impl(self, key, |_, _, kx, ky| kx.cmp(ky))
+ }
+
+ /// Return all maximum elements of an iterator.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use itertools::Itertools;
+ ///
+ /// let a: [i32; 0] = [];
+ /// assert_eq!(a.iter().max_set(), Vec::<&i32>::new());
+ ///
+ /// let a = [1];
+ /// assert_eq!(a.iter().max_set(), vec![&1]);
+ ///
+ /// let a = [1, 2, 3, 4, 5];
+ /// assert_eq!(a.iter().max_set(), vec![&5]);
+ ///
+ /// let a = [1, 1, 1, 1];
+ /// assert_eq!(a.iter().max_set(), vec![&1, &1, &1, &1]);
+ /// ```
+ ///
+ /// The elements can be floats but no particular result is guaranteed
+ /// if an element is NaN.
+ #[cfg(feature = "use_std")]
+ fn max_set(self) -> Vec<Self::Item>
+ where Self: Sized, Self::Item: Ord
+ {
+ extrema_set::max_set_impl(self, |_| (), |x, y, _, _| x.cmp(y))
+ }
+
+ /// Return all maximum elements of an iterator, as determined by
+ /// the specified function.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # use std::cmp::Ordering;
+ /// use itertools::Itertools;
+ ///
+ /// let a: [(i32, i32); 0] = [];
+ /// assert_eq!(a.iter().max_set_by(|_, _| Ordering::Equal), Vec::<&(i32, i32)>::new());
+ ///
+ /// let a = [(1, 2)];
+ /// assert_eq!(a.iter().max_set_by(|&&(k1,_), &&(k2, _)| k1.cmp(&k2)), vec![&(1, 2)]);
+ ///
+ /// let a = [(1, 2), (2, 2), (3, 9), (4, 8), (5, 9)];
+ /// assert_eq!(a.iter().max_set_by(|&&(_,k1), &&(_,k2)| k1.cmp(&k2)), vec![&(3, 9), &(5, 9)]);
+ ///
+ /// let a = [(1, 2), (1, 3), (1, 4), (1, 5)];
+ /// assert_eq!(a.iter().max_set_by(|&&(k1,_), &&(k2, _)| k1.cmp(&k2)), vec![&(1, 2), &(1, 3), &(1, 4), &(1, 5)]);
+ /// ```
+ ///
+ /// The elements can be floats but no particular result is guaranteed
+ /// if an element is NaN.
+ #[cfg(feature = "use_std")]
+ fn max_set_by<F>(self, mut compare: F) -> Vec<Self::Item>
+ where Self: Sized, F: FnMut(&Self::Item, &Self::Item) -> Ordering
+ {
+ extrema_set::max_set_impl(
+ self,
+ |_| (),
+ |x, y, _, _| compare(x, y)
+ )
+ }
+
+ /// Return all minimum elements of an iterator, as determined by
+ /// the specified function.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use itertools::Itertools;
+ ///
+ /// let a: [(i32, i32); 0] = [];
+ /// assert_eq!(a.iter().max_set_by_key(|_| ()), Vec::<&(i32, i32)>::new());
+ ///
+ /// let a = [(1, 2)];
+ /// assert_eq!(a.iter().max_set_by_key(|&&(k,_)| k), vec![&(1, 2)]);
+ ///
+ /// let a = [(1, 2), (2, 2), (3, 9), (4, 8), (5, 9)];
+ /// assert_eq!(a.iter().max_set_by_key(|&&(_, k)| k), vec![&(3, 9), &(5, 9)]);
+ ///
+ /// let a = [(1, 2), (1, 3), (1, 4), (1, 5)];
+ /// assert_eq!(a.iter().max_set_by_key(|&&(k, _)| k), vec![&(1, 2), &(1, 3), &(1, 4), &(1, 5)]);
+ /// ```
+ ///
+ /// The elements can be floats but no particular result is guaranteed
+ /// if an element is NaN.
+ #[cfg(feature = "use_std")]
+ fn max_set_by_key<K, F>(self, key: F) -> Vec<Self::Item>
+ where Self: Sized, K: Ord, F: FnMut(&Self::Item) -> K
+ {
+ extrema_set::max_set_impl(self, key, |_, _, kx, ky| kx.cmp(ky))
+ }
+
/// Return the minimum and maximum elements in the iterator.
///
/// The return type `MinMaxResult` is an enum of three variants:
@@ -3157,7 +3344,7 @@ pub trait Itertools : Iterator {
/// be equal to `ypos`.
///
/// On an iterator of length `n`, `position_minmax` does `1.5 * n`
- /// comparisons, and so is faster than calling `positon_min` and
+ /// comparisons, and so is faster than calling `position_min` and
/// `position_max` separately which does `2 * n` comparisons.
///
/// For the minimum, if several elements are equally minimum, the
@@ -3478,8 +3665,7 @@ impl<T: ?Sized> Itertools for T where T: Iterator { }
/// (elements pairwise equal and sequences of the same length),
/// `false` otherwise.
///
-/// This is an [`IntoIterator`] enabled function that is similar to the standard
-/// library method [`Iterator::eq`].
+/// [`IntoIterator`] enabled version of [`Iterator::eq`].
///
/// ```
/// assert!(itertools::equal(vec![1, 2, 3], 1..4));
@@ -3490,17 +3676,7 @@ pub fn equal<I, J>(a: I, b: J) -> bool
J: IntoIterator,
I::Item: PartialEq<J::Item>
{
- let mut ia = a.into_iter();
- let mut ib = b.into_iter();
- loop {
- match ia.next() {
- Some(x) => match ib.next() {
- Some(y) => if x != y { return false; },
- None => return false,
- },
- None => return ib.next().is_none()
- }
- }
+ a.into_iter().eq(b)
}
/// Assert that two iterables produce equal sequences, with the same
diff --git a/src/merge_join.rs b/src/merge_join.rs
index 4c0048f..f2fbdea 100644
--- a/src/merge_join.rs
+++ b/src/merge_join.rs
@@ -4,10 +4,12 @@ use std::fmt;
use super::adaptors::{PutBack, put_back};
use crate::either_or_both::EitherOrBoth;
+#[cfg(doc)]
+use crate::Itertools;
/// Return an iterator adaptor that merge-joins items from the two base iterators in ascending order.
///
-/// See [`.merge_join_by()`](crate::Itertools::merge_join_by) for more information.
+/// [`IntoIterator`] enabled version of [`Itertools::merge_join_by`].
pub fn merge_join_by<I, J, F>(left: I, right: J, cmp_fn: F)
-> MergeJoinBy<I::IntoIter, J::IntoIter, F>
where I: IntoIterator,
diff --git a/src/multipeek_impl.rs b/src/multipeek_impl.rs
index 5917681..8b49c69 100644
--- a/src/multipeek_impl.rs
+++ b/src/multipeek_impl.rs
@@ -2,6 +2,8 @@ use std::iter::Fuse;
use alloc::collections::VecDeque;
use crate::size_hint;
use crate::PeekingNext;
+#[cfg(doc)]
+use crate::Itertools;
/// See [`multipeek()`] for more information.
#[derive(Clone, Debug)]
@@ -15,6 +17,8 @@ pub struct MultiPeek<I>
/// An iterator adaptor that allows the user to peek at multiple `.next()`
/// values without advancing the base iterator.
+///
+/// [`IntoIterator`] enabled version of [`Itertools::multipeek`].
pub fn multipeek<I>(iterable: I) -> MultiPeek<I::IntoIter>
where I: IntoIterator
{
@@ -67,10 +71,8 @@ impl<I> PeekingNext for MultiPeek<I>
if let Some(r) = self.peek() {
if !accept(r) { return None }
}
- } else {
- if let Some(r) = self.buf.get(0) {
- if !accept(r) { return None }
- }
+ } else if let Some(r) = self.buf.get(0) {
+ if !accept(r) { return None }
}
self.next()
}
diff --git a/src/pad_tail.rs b/src/pad_tail.rs
index de57ee4..248a432 100644
--- a/src/pad_tail.rs
+++ b/src/pad_tail.rs
@@ -23,7 +23,7 @@ where
debug_fmt_fields!(PadUsing, iter, min, pos);
}
-/// Create a new **PadUsing** iterator.
+/// Create a new `PadUsing` iterator.
pub fn pad_using<I, F>(iter: I, min: usize, filler: F) -> PadUsing<I, F>
where I: Iterator,
F: FnMut(usize) -> I::Item
diff --git a/src/peeking_take_while.rs b/src/peeking_take_while.rs
index cd0945a..b3a9c5c 100644
--- a/src/peeking_take_while.rs
+++ b/src/peeking_take_while.rs
@@ -90,7 +90,7 @@ where
debug_fmt_fields!(PeekingTakeWhile, iter);
}
-/// Create a PeekingTakeWhile
+/// Create a `PeekingTakeWhile`
pub fn peeking_take_while<I, F>(iter: &mut I, f: F) -> PeekingTakeWhile<I, F>
where I: Iterator,
{
diff --git a/src/permutations.rs b/src/permutations.rs
index 3080f9d..d03b852 100644
--- a/src/permutations.rs
+++ b/src/permutations.rs
@@ -113,19 +113,15 @@ where
Some(indices.map(|i| vals[i].clone()).collect())
}
- PermutationState::Complete(CompleteState::Start { .. }) => None,
PermutationState::Complete(CompleteState::Ongoing { ref indices, ref cycles }) => {
let k = cycles.len();
-
Some(indices[0..k].iter().map(|&i| vals[i].clone()).collect())
},
- PermutationState::Empty => None
+ PermutationState::Complete(CompleteState::Start { .. }) | PermutationState::Empty => None
}
}
fn count(self) -> usize {
- let Permutations { vals, state } = self;
-
fn from_complete(complete_state: CompleteState) -> usize {
match complete_state.remaining() {
CompleteStateRemaining::Known(count) => count,
@@ -135,6 +131,7 @@ where
}
}
+ let Permutations { vals, state } = self;
match state {
PermutationState::StartUnknownLen { k } => {
let n = vals.len() + vals.it.count();
diff --git a/src/rciter_impl.rs b/src/rciter_impl.rs
index 782908e..7298350 100644
--- a/src/rciter_impl.rs
+++ b/src/rciter_impl.rs
@@ -51,7 +51,6 @@ pub fn rciter<I>(iterable: I) -> RcIter<I::IntoIter>
}
impl<I> Clone for RcIter<I> {
- #[inline]
clone_fields!(rciter);
}
diff --git a/src/size_hint.rs b/src/size_hint.rs
index 1168eca..71ea141 100644
--- a/src/size_hint.rs
+++ b/src/size_hint.rs
@@ -1,14 +1,14 @@
-//! Arithmetic on **Iterator** *.size_hint()* values.
+//! Arithmetic on `Iterator.size_hint()` values.
//!
use std::usize;
use std::cmp;
use std::u32;
-/// **SizeHint** is the return type of **Iterator::size_hint()**.
+/// `SizeHint` is the return type of `Iterator::size_hint()`.
pub type SizeHint = (usize, Option<usize>);
-/// Add **SizeHint** correctly.
+/// Add `SizeHint` correctly.
#[inline]
pub fn add(a: SizeHint, b: SizeHint) -> SizeHint {
let min = a.0.saturating_add(b.0);
@@ -20,7 +20,7 @@ pub fn add(a: SizeHint, b: SizeHint) -> SizeHint {
(min, max)
}
-/// Add **x** correctly to a **SizeHint**.
+/// Add `x` correctly to a `SizeHint`.
#[inline]
pub fn add_scalar(sh: SizeHint, x: usize) -> SizeHint {
let (mut low, mut hi) = sh;
@@ -29,7 +29,7 @@ pub fn add_scalar(sh: SizeHint, x: usize) -> SizeHint {
(low, hi)
}
-/// Sbb **x** correctly to a **SizeHint**.
+/// Subtract `x` correctly from a `SizeHint`.
#[inline]
#[allow(dead_code)]
pub fn sub_scalar(sh: SizeHint, x: usize) -> SizeHint {
@@ -40,7 +40,7 @@ pub fn sub_scalar(sh: SizeHint, x: usize) -> SizeHint {
}
-/// Multiply **SizeHint** correctly
+/// Multiply `SizeHint` correctly
///
/// ```ignore
/// use std::usize;
@@ -66,7 +66,7 @@ pub fn mul(a: SizeHint, b: SizeHint) -> SizeHint {
(low, hi)
}
-/// Multiply **x** correctly with a **SizeHint**.
+/// Multiply `x` correctly with a `SizeHint`.
#[inline]
pub fn mul_scalar(sh: SizeHint, x: usize) -> SizeHint {
let (mut low, mut hi) = sh;
@@ -75,7 +75,7 @@ pub fn mul_scalar(sh: SizeHint, x: usize) -> SizeHint {
(low, hi)
}
-/// Raise `base` correctly by a **`SizeHint`** exponent.
+/// Raise `base` correctly by a `SizeHint` exponent.
#[inline]
pub fn pow_scalar_base(base: usize, exp: SizeHint) -> SizeHint {
let exp_low = cmp::min(exp.0, u32::MAX as usize) as u32;
diff --git a/src/tuple_impl.rs b/src/tuple_impl.rs
index d914e03..06b5c13 100644
--- a/src/tuple_impl.rs
+++ b/src/tuple_impl.rs
@@ -162,8 +162,8 @@ pub fn tuple_windows<I, T>(mut iter: I) -> TupleWindows<I, T>
}
TupleWindows {
- last,
iter,
+ last,
}
}
diff --git a/src/unique_impl.rs b/src/unique_impl.rs
index 2240f36..4e81e78 100644
--- a/src/unique_impl.rs
+++ b/src/unique_impl.rs
@@ -1,6 +1,5 @@
-
use std::collections::HashMap;
-use std::collections::hash_map::{Entry};
+use std::collections::hash_map::Entry;
use std::hash::Hash;
use std::fmt;
use std::iter::FusedIterator;
@@ -12,7 +11,9 @@ use std::iter::FusedIterator;
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct UniqueBy<I: Iterator, V, F> {
iter: I,
- // Use a hashmap for the entry API
+ // Use a Hashmap for the Entry API in order to prevent hashing twice.
+ // This can maybe be replaced with a HashSet once `get_or_insert_with`
+ // or a proper Entry API for Hashset is stable and meets this msrv
used: HashMap<V, ()>,
f: F,
}
diff --git a/src/unziptuple.rs b/src/unziptuple.rs
index f468f05..7af29ec 100644
--- a/src/unziptuple.rs
+++ b/src/unziptuple.rs
@@ -39,11 +39,11 @@ macro_rules! impl_unzip_iter {
#[allow(non_snake_case)]
impl<IT: Iterator<Item = ($($T,)*)>, $($T, $FromT: Default + Extend<$T>),* > MultiUnzip<($($FromT,)*)> for IT {
fn multiunzip(self) -> ($($FromT,)*) {
- // This implementation mirrors the logic of Iterator::unzip as close as possible.
- // Unfortunately a lot of the used api there is still unstable represented by
- // the commented out parts that follow.
+ // This implementation mirrors the logic of Iterator::unzip resp. Extend for (A, B) as close as possible.
+ // Unfortunately a lot of the used api there is still unstable (https://github.com/rust-lang/rust/issues/72631).
//
- // https://doc.rust-lang.org/src/core/iter/traits/iterator.rs.html#2816-2844
+ // Iterator::unzip: https://doc.rust-lang.org/src/core/iter/traits/iterator.rs.html#2825-2865
+ // Extend for (A, B): https://doc.rust-lang.org/src/core/iter/traits/collect.rs.html#370-411
let mut res = ($($FromT::default(),)*);
let ($($FromT,)*) = &mut res;
diff --git a/src/ziptuple.rs b/src/ziptuple.rs
index b7902ae..6d3a584 100644
--- a/src/ziptuple.rs
+++ b/src/ziptuple.rs
@@ -36,6 +36,7 @@ pub struct Zip<T> {
///
/// assert_eq!(results, [0 + 3, 10 + 7, 29, 36]);
/// ```
+/// [`izip!()`]: crate::izip
pub fn multizip<T, U>(t: U) -> Zip<T>
where Zip<T>: From<U>,
Zip<T>: Iterator,
diff --git a/tests/adaptors_no_collect.rs b/tests/adaptors_no_collect.rs
index a47f906..103db23 100644
--- a/tests/adaptors_no_collect.rs
+++ b/tests/adaptors_no_collect.rs
@@ -11,12 +11,11 @@ impl Iterator for PanickingCounter {
fn next(&mut self) -> Option<Self::Item> {
self.curr += 1;
- if self.curr == self.max {
- panic!(
- "Input iterator reached maximum of {} suggesting collection by adaptor",
- self.max
- );
- }
+ assert_ne!(
+ self.curr, self.max,
+ "Input iterator reached maximum of {} suggesting collection by adaptor",
+ self.max
+ );
Some(())
}
diff --git a/tests/quick.rs b/tests/quick.rs
index 7e222a6..0adcf1a 100644
--- a/tests/quick.rs
+++ b/tests/quick.rs
@@ -258,12 +258,13 @@ where
let mut it = get_it();
for _ in 0..(counts.len() - 1) {
- if let None = it.next() {
+ #[allow(clippy::manual_assert)]
+ if it.next().is_none() {
panic!("Iterator shouldn't be finished, may not be deterministic");
}
}
- if let None = it.next() {
+ if it.next().is_none() {
break 'outer;
}
@@ -438,7 +439,7 @@ quickcheck! {
}
assert_eq!(answer, actual);
- assert_eq!(answer.into_iter().last(), a.clone().multi_cartesian_product().last());
+ assert_eq!(answer.into_iter().last(), a.multi_cartesian_product().last());
}
#[allow(deprecated)]
@@ -498,15 +499,13 @@ quickcheck! {
exact_size(it)
}
- fn equal_merge(a: Vec<i16>, b: Vec<i16>) -> bool {
- let mut sa = a.clone();
- let mut sb = b.clone();
- sa.sort();
- sb.sort();
- let mut merged = sa.clone();
- merged.extend(sb.iter().cloned());
+ fn equal_merge(mut a: Vec<i16>, mut b: Vec<i16>) -> bool {
+ a.sort();
+ b.sort();
+ let mut merged = a.clone();
+ merged.extend(b.iter().cloned());
merged.sort();
- itertools::equal(&merged, sa.iter().merge(&sb))
+ itertools::equal(&merged, a.iter().merge(&b))
}
fn size_merge(a: Iter<u16>, b: Iter<u16>) -> bool {
correct_size_hint(a.merge(b))
@@ -517,7 +516,7 @@ quickcheck! {
exact_size(multizip((a, b, c)))
}
fn size_zip_rc(a: Iter<i16>, b: Iter<i16>) -> bool {
- let rc = rciter(a.clone());
+ let rc = rciter(a);
correct_size_hint(multizip((&rc, &rc, b)))
}
@@ -526,19 +525,16 @@ quickcheck! {
correct_size_hint(izip!(filt, b.clone(), c.clone())) &&
exact_size(izip!(a, b, c))
}
- fn equal_kmerge(a: Vec<i16>, b: Vec<i16>, c: Vec<i16>) -> bool {
+ fn equal_kmerge(mut a: Vec<i16>, mut b: Vec<i16>, mut c: Vec<i16>) -> bool {
use itertools::free::kmerge;
- let mut sa = a.clone();
- let mut sb = b.clone();
- let mut sc = c.clone();
- sa.sort();
- sb.sort();
- sc.sort();
- let mut merged = sa.clone();
- merged.extend(sb.iter().cloned());
- merged.extend(sc.iter().cloned());
+ a.sort();
+ b.sort();
+ c.sort();
+ let mut merged = a.clone();
+ merged.extend(b.iter().cloned());
+ merged.extend(c.iter().cloned());
merged.sort();
- itertools::equal(merged.into_iter(), kmerge(vec![sa, sb, sc]))
+ itertools::equal(merged.into_iter(), kmerge(vec![a, b, c]))
}
// Any number of input iterators
@@ -610,7 +606,7 @@ quickcheck! {
fn size_2_zip_longest(a: Iter<i16>, b: Iter<i16>) -> bool {
let it = a.clone().zip_longest(b.clone());
let jt = a.clone().zip_longest(b.clone());
- itertools::equal(a.clone(),
+ itertools::equal(a,
it.filter_map(|elt| match elt {
EitherOrBoth::Both(x, _) => Some(x),
EitherOrBoth::Left(x) => Some(x),
@@ -618,7 +614,7 @@ quickcheck! {
}
))
&&
- itertools::equal(b.clone(),
+ itertools::equal(b,
jt.filter_map(|elt| match elt {
EitherOrBoth::Both(_, y) => Some(y),
EitherOrBoth::Right(y) => Some(y),
@@ -721,7 +717,7 @@ quickcheck! {
assert_eq!(expected_first, curr_perm);
- while let Some(next_perm) = perms.next() {
+ for next_perm in perms {
assert!(
next_perm > curr_perm,
"next perm isn't greater-than current; next_perm={:?} curr_perm={:?} n={}",
@@ -943,8 +939,7 @@ quickcheck! {
fn fuzz_group_by_lazy_1(it: Iter<u8>) -> bool {
let jt = it.clone();
let groups = it.group_by(|k| *k);
- let res = itertools::equal(jt, groups.into_iter().flat_map(|(_, x)| x));
- res
+ itertools::equal(jt, groups.into_iter().flat_map(|(_, x)| x))
}
}
@@ -1286,7 +1281,7 @@ quickcheck! {
.map(|i| (i % modulo, i))
.into_group_map()
.into_iter()
- .map(|(key, vals)| (key, vals.into_iter().fold(0u64, |acc, val| acc + val)))
+ .map(|(key, vals)| (key, vals.into_iter().sum()))
.collect::<HashMap<_,_>>();
assert_eq!(lookup, group_map_lookup);
@@ -1551,10 +1546,10 @@ quickcheck! {
}
quickcheck! {
- #[test]
fn counts(nums: Vec<isize>) -> TestResult {
let counts = nums.iter().counts();
for (&item, &count) in counts.iter() {
+ #[allow(clippy::absurd_extreme_comparisons)]
if count <= 0 {
return TestResult::failed();
}
@@ -1602,7 +1597,7 @@ quickcheck! {
fn is_fused<I: Iterator>(mut it: I) -> bool
{
- while let Some(_) = it.next() {}
+ for _ in it.by_ref() {}
for _ in 0..10{
if it.next().is_some(){
return false;
@@ -1693,3 +1688,62 @@ quickcheck! {
}
}
+quickcheck! {
+ fn min_set_contains_min(a: Vec<(usize, char)>) -> bool {
+ let result_set = a.iter().min_set();
+ if let Some(result_element) = a.iter().min() {
+ result_set.contains(&result_element)
+ } else {
+ result_set.is_empty()
+ }
+ }
+
+ fn min_set_by_contains_min(a: Vec<(usize, char)>) -> bool {
+ let compare = |x: &&(usize, char), y: &&(usize, char)| x.1.cmp(&y.1);
+ let result_set = a.iter().min_set_by(compare);
+ if let Some(result_element) = a.iter().min_by(compare) {
+ result_set.contains(&result_element)
+ } else {
+ result_set.is_empty()
+ }
+ }
+
+ fn min_set_by_key_contains_min(a: Vec<(usize, char)>) -> bool {
+ let key = |x: &&(usize, char)| x.1;
+ let result_set = a.iter().min_set_by_key(&key);
+ if let Some(result_element) = a.iter().min_by_key(&key) {
+ result_set.contains(&result_element)
+ } else {
+ result_set.is_empty()
+ }
+ }
+
+ fn max_set_contains_max(a: Vec<(usize, char)>) -> bool {
+ let result_set = a.iter().max_set();
+ if let Some(result_element) = a.iter().max() {
+ result_set.contains(&result_element)
+ } else {
+ result_set.is_empty()
+ }
+ }
+
+ fn max_set_by_contains_max(a: Vec<(usize, char)>) -> bool {
+ let compare = |x: &&(usize, char), y: &&(usize, char)| x.1.cmp(&y.1);
+ let result_set = a.iter().max_set_by(compare);
+ if let Some(result_element) = a.iter().max_by(compare) {
+ result_set.contains(&result_element)
+ } else {
+ result_set.is_empty()
+ }
+ }
+
+ fn max_set_by_key_contains_max(a: Vec<(usize, char)>) -> bool {
+ let key = |x: &&(usize, char)| x.1;
+ let result_set = a.iter().max_set_by_key(&key);
+ if let Some(result_element) = a.iter().max_by_key(&key) {
+ result_set.contains(&result_element)
+ } else {
+ result_set.is_empty()
+ }
+ }
+}
diff --git a/tests/specializations.rs b/tests/specializations.rs
index 199cf56..057e11c 100644
--- a/tests/specializations.rs
+++ b/tests/specializations.rs
@@ -129,7 +129,7 @@ quickcheck! {
check_results_specialized!(it, |i| {
let mut parameters_from_fold = vec![];
let fold_result = i.fold(vec![], |mut acc, v| {
- parameters_from_fold.push((acc.clone(), v.clone()));
+ parameters_from_fold.push((acc.clone(), v));
acc.push(v);
acc
});
@@ -139,7 +139,7 @@ quickcheck! {
let mut parameters_from_all = vec![];
let first = i.next();
let all_result = i.all(|x| {
- parameters_from_all.push(x.clone());
+ parameters_from_all.push(x);
Some(x)==first
});
(parameters_from_all, all_result)
diff --git a/tests/test_core.rs b/tests/test_core.rs
index a7b7449..df94eb6 100644
--- a/tests/test_core.rs
+++ b/tests/test_core.rs
@@ -116,7 +116,7 @@ fn chain2() {
fn write_to() {
let xs = [7, 9, 8];
let mut ys = [0; 5];
- let cnt = ys.iter_mut().set_from(xs.iter().map(|x| *x));
+ let cnt = ys.iter_mut().set_from(xs.iter().copied());
assert!(cnt == xs.len());
assert!(ys == [7, 9, 8, 0, 0]);
@@ -180,15 +180,10 @@ fn batching() {
let ys = [(0, 1), (2, 1)];
// An iterator that gathers elements up in pairs
- let pit = xs.iter().cloned().batching(|it| {
- match it.next() {
- None => None,
- Some(x) => match it.next() {
- None => None,
- Some(y) => Some((x, y)),
- }
- }
- });
+ let pit = xs
+ .iter()
+ .cloned()
+ .batching(|it| it.next().and_then(|x| it.next().map(|y| (x, y))));
it::assert_equal(pit, ys.iter().cloned());
}
diff --git a/tests/test_std.rs b/tests/test_std.rs
index 2049d15..f590342 100644
--- a/tests/test_std.rs
+++ b/tests/test_std.rs
@@ -1,5 +1,3 @@
-use paste;
-use permutohedron;
use quickcheck as qc;
use rand::{distributions::{Distribution, Standard}, Rng, SeedableRng, rngs::StdRng};
use rand::{seq::SliceRandom, thread_rng};
@@ -123,12 +121,12 @@ fn unique() {
#[test]
fn intersperse() {
let xs = ["a", "", "b", "c"];
- let v: Vec<&str> = xs.iter().map(|x| x.clone()).intersperse(", ").collect();
+ let v: Vec<&str> = xs.iter().cloned().intersperse(", ").collect();
let text: String = v.concat();
assert_eq!(text, "a, , b, c".to_string());
let ys = [0, 1, 2, 3];
- let mut it = ys[..0].iter().map(|x| *x).intersperse(1);
+ let mut it = ys[..0].iter().copied().intersperse(1);
assert!(it.next() == None);
}
@@ -474,7 +472,7 @@ impl<T: Clone + Send, R: Clone + Rng + SeedableRng + Send> qc::Arbitrary for Ran
// Check that taking the k smallest is the same as
// sorting then taking the k first elements
-fn k_smallest_sort<I>(i: I, k: u16) -> ()
+fn k_smallest_sort<I>(i: I, k: u16)
where
I: Iterator + Clone,
I::Item: Ord + Debug,
@@ -538,10 +536,10 @@ fn sorted_by_cached_key() {
fn test_multipeek() {
let nums = vec![1u8,2,3,4,5];
- let mp = multipeek(nums.iter().map(|&x| x));
+ let mp = multipeek(nums.iter().copied());
assert_eq!(nums, mp.collect::<Vec<_>>());
- let mut mp = multipeek(nums.iter().map(|&x| x));
+ let mut mp = multipeek(nums.iter().copied());
assert_eq!(mp.peek(), Some(&1));
assert_eq!(mp.next(), Some(1));
assert_eq!(mp.peek(), Some(&2));
@@ -579,7 +577,7 @@ fn test_multipeek_peeking_next() {
use crate::it::PeekingNext;
let nums = vec![1u8,2,3,4,5,6,7];
- let mut mp = multipeek(nums.iter().map(|&x| x));
+ let mut mp = multipeek(nums.iter().copied());
assert_eq!(mp.peeking_next(|&x| x != 0), Some(1));
assert_eq!(mp.next(), Some(2));
assert_eq!(mp.peek(), Some(&3));
@@ -604,10 +602,10 @@ fn test_multipeek_peeking_next() {
fn test_peek_nth() {
let nums = vec![1u8,2,3,4,5];
- let iter = peek_nth(nums.iter().map(|&x| x));
+ let iter = peek_nth(nums.iter().copied());
assert_eq!(nums, iter.collect::<Vec<_>>());
- let mut iter = peek_nth(nums.iter().map(|&x| x));
+ let mut iter = peek_nth(nums.iter().copied());
assert_eq!(iter.peek_nth(0), Some(&1));
assert_eq!(iter.peek_nth(0), Some(&1));
@@ -638,7 +636,7 @@ fn test_peek_nth() {
fn test_peek_nth_peeking_next() {
use it::PeekingNext;
let nums = vec![1u8,2,3,4,5,6,7];
- let mut iter = peek_nth(nums.iter().map(|&x| x));
+ let mut iter = peek_nth(nums.iter().copied());
assert_eq!(iter.peeking_next(|&x| x != 0), Some(1));
assert_eq!(iter.next(), Some(2));
@@ -694,7 +692,7 @@ fn group_by() {
}
}
- let toupper = |ch: &char| ch.to_uppercase().nth(0).unwrap();
+ let toupper = |ch: &char| ch.to_uppercase().next().unwrap();
// try all possible orderings
for indices in permutohedron::Heap::new(&mut [0, 1, 2, 3]) {
@@ -993,6 +991,54 @@ fn diff_shorter() {
}
#[test]
+fn extrema_set() {
+ use std::cmp::Ordering;
+
+ // A peculiar type: Equality compares both tuple items, but ordering only the
+ // first item. Used to distinguish equal elements.
+ #[derive(Clone, Debug, PartialEq, Eq)]
+ struct Val(u32, u32);
+
+ impl PartialOrd<Val> for Val {
+ fn partial_cmp(&self, other: &Val) -> Option<Ordering> {
+ self.0.partial_cmp(&other.0)
+ }
+ }
+
+ impl Ord for Val {
+ fn cmp(&self, other: &Val) -> Ordering {
+ self.0.cmp(&other.0)
+ }
+ }
+
+ assert_eq!(None::<u32>.iter().min_set(), Vec::<&u32>::new());
+ assert_eq!(None::<u32>.iter().max_set(), Vec::<&u32>::new());
+
+ assert_eq!(Some(1u32).iter().min_set(), vec![&1]);
+ assert_eq!(Some(1u32).iter().max_set(), vec![&1]);
+
+ let data = vec![Val(0, 1), Val(2, 0), Val(0, 2), Val(1, 0), Val(2, 1)];
+
+ let min_set = data.iter().min_set();
+ assert_eq!(min_set, vec![&Val(0, 1), &Val(0, 2)]);
+
+ let min_set_by_key = data.iter().min_set_by_key(|v| v.1);
+ assert_eq!(min_set_by_key, vec![&Val(2, 0), &Val(1, 0)]);
+
+ let min_set_by = data.iter().min_set_by(|x, y| x.1.cmp(&y.1));
+ assert_eq!(min_set_by, vec![&Val(2, 0), &Val(1, 0)]);
+
+ let max_set = data.iter().max_set();
+ assert_eq!(max_set, vec![&Val(2, 0), &Val(2, 1)]);
+
+ let max_set_by_key = data.iter().max_set_by_key(|v| v.1);
+ assert_eq!(max_set_by_key, vec![&Val(0, 2)]);
+
+ let max_set_by = data.iter().max_set_by(|x, y| x.1.cmp(&y.1));
+ assert_eq!(max_set_by, vec![&Val(0, 2)]);
+}
+
+#[test]
fn minmax() {
use std::cmp::Ordering;
use crate::it::MinMaxResult;
@@ -1043,9 +1089,9 @@ fn format() {
let t2 = format!("{:?}", data.iter().format("--"));
assert_eq!(t2, ans2);
- let dataf = [1.1, 2.71828, -22.];
+ let dataf = [1.1, 5.71828, -22.];
let t3 = format!("{:.2e}", dataf.iter().format(", "));
- assert_eq!(t3, "1.10e0, 2.72e0, -2.20e1");
+ assert_eq!(t3, "1.10e0, 5.72e0, -2.20e1");
}
#[test]
@@ -1062,7 +1108,7 @@ fn fold_while() {
let vec = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let sum = vec.into_iter().fold_while(0, |acc, item| {
iterations += 1;
- let new_sum = acc.clone() + item;
+ let new_sum = acc + item;
if new_sum <= 20 {
FoldWhile::Continue(new_sum)
} else {
@@ -1095,7 +1141,7 @@ fn tree_fold1() {
"0 1 x 2 3 x x 4 5 x 6 7 x x x 8 9 x 10 11 x x 12 13 x 14 15 x x x x",
];
for (i, &s) in x.iter().enumerate() {
- let expected = if s == "" { None } else { Some(s.to_string()) };
+ let expected = if s.is_empty() { None } else { Some(s.to_string()) };
let num_strings = (0..i).map(|x| x.to_string());
let actual = num_strings.tree_fold1(|a, b| format!("{} {} x", a, b));
assert_eq!(actual, expected);
@@ -1119,4 +1165,4 @@ fn multiunzip() {
let (): () = [(), (), ()].iter().cloned().multiunzip();
let t: (Vec<_>, Vec<_>, Vec<_>, Vec<_>, Vec<_>, Vec<_>, Vec<_>, Vec<_>, Vec<_>, Vec<_>, Vec<_>, Vec<_>) = [(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11)].iter().cloned().multiunzip();
assert_eq!(t, (vec![0], vec![1], vec![2], vec![3], vec![4], vec![5], vec![6], vec![7], vec![8], vec![9], vec![10], vec![11]));
-} \ No newline at end of file
+}
diff --git a/tests/zip.rs b/tests/zip.rs
index 5801b42..75157d3 100644
--- a/tests/zip.rs
+++ b/tests/zip.rs
@@ -29,8 +29,8 @@ fn test_zip_longest_size_hint() {
fn test_double_ended_zip_longest() {
let xs = [1, 2, 3, 4, 5, 6];
let ys = [1, 2, 3, 7];
- let a = xs.iter().map(|&x| x);
- let b = ys.iter().map(|&x| x);
+ let a = xs.iter().copied();
+ let b = ys.iter().copied();
let mut it = a.zip_longest(b);
assert_eq!(it.next(), Some(Both(1, 1)));
assert_eq!(it.next(), Some(Both(2, 2)));
@@ -45,8 +45,8 @@ fn test_double_ended_zip_longest() {
fn test_double_ended_zip() {
let xs = [1, 2, 3, 4, 5, 6];
let ys = [1, 2, 3, 7];
- let a = xs.iter().map(|&x| x);
- let b = ys.iter().map(|&x| x);
+ let a = xs.iter().copied();
+ let b = ys.iter().copied();
let mut it = multizip((a, b));
assert_eq!(it.next_back(), Some((4, 7)));
assert_eq!(it.next_back(), Some((3, 3)));