Upgrade itertools to 0.10.5

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

Test: TreeHugger
Change-Id: I04ecd1d5827d6d1822997f324e6bac8e8bd8ea83
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,