Snap for 10453938 from cacbffa61ab459e4c3f2caf4bfd4208641a0b0fb to mainline-odp-release

Change-Id: I8085c98d8a00d44d26d6d63d2346ca627a0bef07
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 @@
 
 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 @@
     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 @@
 [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 @@
 
 [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 @@
   }
   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 @@
 
 ```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 @@
 // 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 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 @@
 /// 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 @@
 /// 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 @@
 ///
 /// 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 @@
 
 /// 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 @@
     /// 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 @@
             }
             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 @@
 /// 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 @@
 }
 
 #[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 @@
     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 @@
         // 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 @@
                 // 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 @@
     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 @@
 /// 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 @@
     }
 
     /// 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 @@
             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 @@
 /// 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 @@
             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 @@
                     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 @@
             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 @@
                     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 @@
     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 @@
     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 @@
     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 @@
 }
 
 
-/// 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 @@
 }
 
 
-/// 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<'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 @@
 
     /// `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 @@
 
     /// `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 @@
 /// `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 @@
         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 @@
         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 @@
         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! 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 @@
     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 @@
         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 @@
     // 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 @@
 /// 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 @@
 /// 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 @@
 
 /// 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 @@
     }
 
     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 @@
         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 @@
 {
     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 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 @@
 /// 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 @@
     /// 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 @@
     /// 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 @@
     /// 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 @@
     /// ```
     #[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 @@
     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 @@
         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 @@
         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 @@
     /// ```
     ///
     /// 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 @@
     /// └─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 @@
     /// 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 @@
         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 @@
     ///    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 @@
 /// (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 @@
           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 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 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 @@
 
 /// 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 @@
             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 @@
     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 @@
     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 @@
 
                 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 @@
             }
         }
 
+        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 @@
 }
 
 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 @@
     (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 @@
     (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 @@
 }
 
 
-/// Multiply **SizeHint** correctly
+/// Multiply `SizeHint` correctly
 ///
 /// ```ignore
 /// use std::usize;
@@ -66,7 +66,7 @@
     (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 @@
     (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 @@
     }
 
     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 @@
 #[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 @@
         #[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 @@
 ///
 /// 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 @@
     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 @@
         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 @@
         }
         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 @@
         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 @@
             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 @@
         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 @@
     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 @@
                          }
                          ))
             &&
-        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 @@
 
         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 @@
     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 @@
             .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! {
-    #[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 @@
 
 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! {
+    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 @@
             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 @@
                 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 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 @@
     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 @@
 #[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 @@
 
 // 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 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 @@
     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_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_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 @@
         }
     }
 
-    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 @@
 }
 
 #[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 @@
     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 @@
     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 @@
         "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 @@
     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_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() {
     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)));