diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index efc779f49..143ac2b6d 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -38,14 +38,3 @@ jobs:
steps:
- name: Mark the job as successful
run: exit 0
-
- end-failure:
- name: bors build finished
- if: "!success()"
- runs-on: ubuntu-latest
- needs: [msrv,stable]
-
- steps:
- - name: Mark the job as a failure
- run: exit 1
-
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 67633ab75..41c4ab037 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,48 @@
# Changelog
+## 0.10.1
+ - Add `Itertools::contains` (#514)
+ - Add `Itertools::counts_by` (#515)
+ - Add `Itertools::partition_result` (#511)
+ - Add `Itertools::all_unique` (#241)
+ - Add `Itertools::duplicates` and `Itertools::duplicates_by` (#502)
+ - Add `chain!` (#525)
+ - Add `Itertools::at_most_one` (#523)
+ - Add `Itertools::flatten_ok` (#527)
+ - Add `EitherOrBoth::or_default` (#583)
+ - Add `Itertools::find_or_last` and `Itertools::find_or_first` (#535)
+ - Implement `FusedIterator` for `FilterOk`, `FilterMapOk`, `InterleaveShortest`, `KMergeBy`, `MergeBy`, `PadUsing`, `Positions`, `Product` , `RcIter`, `TupleWindows`, `Unique`, `UniqueBy`, `Update`, `WhileSome`, `Combinations`, `CombinationsWithReplacement`, `Powerset`, `RepeatN`, and `WithPosition` (#550)
+ - Implement `FusedIterator` for `Interleave`, `IntersperseWith`, and `ZipLongest` (#548)
+
+## 0.10.0
+ - **Increase minimum supported Rust version to 1.32.0**
+ - Improve macro hygiene (#507)
+ - Add `Itertools::powerset` (#335)
+ - Add `Itertools::sorted_unstable`, `Itertools::sorted_unstable_by`, and `Itertools::sorted_unstable_by_key` (#494)
+ - Implement `Error` for `ExactlyOneError` (#484)
+ - Undeprecate `Itertools::fold_while` (#476)
+ - Tuple-related adapters work for tuples of arity up to 12 (#475)
+ - `use_alloc` feature for users who have `alloc`, but not `std` (#474)
+ - Add `Itertools::k_smallest` (#473)
+ - Add `Itertools::into_grouping_map` and `GroupingMap` (#465)
+ - Add `Itertools::into_grouping_map_by` and `GroupingMapBy` (#465)
+ - Add `Itertools::counts` (#468)
+ - Add implementation of `DoubleEndedIterator` for `Unique` (#442)
+ - Add implementation of `DoubleEndedIterator` for `UniqueBy` (#442)
+ - Add implementation of `DoubleEndedIterator` for `Zip` (#346)
+ - Add `Itertools::multipeek` (#435)
+ - Add `Itertools::dedup_with_count` and `DedupWithCount` (#423)
+ - Add `Itertools::dedup_by_with_count` and `DedupByWithCount` (#423)
+ - Add `Itertools::intersperse_with` and `IntersperseWith` (#381)
+ - Add `Itertools::filter_ok` and `FilterOk` (#377)
+ - Add `Itertools::filter_map_ok` and `FilterMapOk` (#377)
+ - Deprecate `Itertools::fold_results`, use `Itertools::fold_ok` instead (#377)
+ - Deprecate `Itertools::map_results`, use `Itertools::map_ok` instead (#377)
+ - Deprecate `FoldResults`, use `FoldOk` instead (#377)
+ - Deprecate `MapResults`, use `MapOk` instead (#377)
+ - Add `Itertools::circular_tuple_windows` and `CircularTupleWindows` (#350)
+ - Add `peek_nth` and `PeekNth` (#303)
+
## 0.9.0
- Fix potential overflow in `MergeJoinBy::size_hint` (#385)
- Add `derive(Clone)` where possible (#382)
@@ -163,7 +206,7 @@
## 0.5.1
- Workaround module/function name clash that made racer crash on completing itertools. Only internal changes needed.
## 0.5.0
- - [Release announcement](http://bluss.github.io/rust/2016/09/26/itertools-0.5.0/)
+ - [Release announcement](https://bluss.github.io/rust/2016/09/26/itertools-0.5.0/)
- Renamed:
- `combinations` is now `tuple_combinations`
- `combinations_n` to `combinations`
@@ -217,7 +260,7 @@
## 0.4.15
- Fixup on top of the workaround in 0.4.14. A function in `itertools::free` was removed by mistake and now it is added back again.
## 0.4.14
- - Workaround an upstream regression in a rust nightly build that broke compilation of of `itertools::free::{interleave, merge}`
+ - Workaround an upstream regression in a Rust nightly build that broke compilation of of `itertools::free::{interleave, merge}`
## 0.4.13
- Add `.minmax()` and `.minmax_by_key()`, iterator methods for finding both minimum and maximum in one scan.
- Add `.format_default()`, a simpler version of `.format()` (lazy formatting for iterators).
@@ -283,9 +326,9 @@
## 0.3.19
- Added `.group_by_lazy()`, a possibly nonallocating group by
- Added `.format()`, a nonallocating formatting helper for iterators
- - Remove uses of `RandomAccessIterator` since it has been deprecated in rust.
+ - Remove uses of `RandomAccessIterator` since it has been deprecated in Rust.
## 0.3.17
- - Added (adopted) `Unfold` from rust
+ - Added (adopted) `Unfold` from Rust
## 0.3.16
- Added adaptors `.unique()`, `.unique_by()`
## 0.3.15
diff --git a/Cargo.toml b/Cargo.toml
index 46b209417..d7f6b231f 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,9 +1,9 @@
[package]
name = "itertools"
-version = "0.10.0"
+version = "0.10.1"
license = "MIT/Apache-2.0"
-repository = "https://github.com/bluss/rust-itertools"
+repository = "https://github.com/rust-itertools/itertools"
documentation = "https://docs.rs/itertools/"
authors = ["bluss"]
@@ -27,8 +27,8 @@ either = { version = "1.0", default-features = false }
[dev-dependencies]
rand = "0.7"
-criterion = "=0" # TODO how could this work with our minimum supported rust version?
-paste = "1.0.0" # Used in test_std to instanciate generic tests
+criterion = "=0" # TODO how could this work with our minimum supported Rust version?
+paste = "1.0.0" # Used in test_std to instantiate generic tests
[dev-dependencies.quickcheck]
version = "0.9"
diff --git a/README.rst b/README.rst
index 4e370072b..aa37f6bb7 100644
--- a/README.rst
+++ b/README.rst
@@ -13,7 +13,7 @@ __ https://docs.rs/itertools/
.. |build_status| image:: https://travis-ci.org/rust-itertools/itertools.svg?branch=master
.. _build_status: https://travis-ci.org/rust-itertools/itertools
-.. |crates| image:: http://meritbadge.herokuapp.com/itertools
+.. |crates| image:: https://meritbadge.herokuapp.com/itertools
.. _crates: https://crates.io/crates/itertools
How to use with cargo:
@@ -21,7 +21,7 @@ How to use with cargo:
.. code:: toml
[dependencies]
- itertools = "0.9"
+ itertools = "0.10.0"
How to use in your crate:
@@ -36,7 +36,7 @@ How to contribute
- Include tests for your new feature, preferably a quickcheck test
- Make a Pull Request
-For new features, please first consider filing a PR to `rust-lang/rust `_,
+For new features, please first consider filing a PR to `rust-lang/rust `_,
adding your new feature to the `Iterator` trait of the standard library, if you believe it is reasonable.
If it isn't accepted there, proposing it for inclusion in ``itertools`` is a good idea.
The reason for doing is this is so that we avoid future breakage as with ``.flatten()``.
@@ -49,7 +49,7 @@ License
Dual-licensed to be compatible with the Rust project.
Licensed under the Apache License, Version 2.0
-http://www.apache.org/licenses/LICENSE-2.0 or the MIT license
-http://opensource.org/licenses/MIT, at your
+https://www.apache.org/licenses/LICENSE-2.0 or the MIT license
+https://opensource.org/licenses/MIT, at your
option. This file may not be copied, modified, or distributed
except according to those terms.
diff --git a/src/adaptors/coalesce.rs b/src/adaptors/coalesce.rs
index 116f688f5..1afbee58f 100644
--- a/src/adaptors/coalesce.rs
+++ b/src/adaptors/coalesce.rs
@@ -40,20 +40,21 @@ where
fn next(&mut self) -> Option {
// this fuses the iterator
- let mut last = match self.last.take() {
- None => return None,
- Some(x) => x,
- };
- for next in &mut self.iter {
- match self.f.coalesce_pair(last, next) {
- Ok(joined) => last = joined,
- Err((last_, next_)) => {
- self.last = Some(next_);
- return Some(last_);
- }
- }
- }
- Some(last)
+ let last = self.last.take()?;
+
+ let self_last = &mut self.last;
+ let self_f = &mut self.f;
+ Some(
+ self.iter
+ .try_fold(last, |last, next| match self_f.coalesce_pair(last, next) {
+ Ok(joined) => Ok(joined),
+ Err((last_, next_)) => {
+ *self_last = Some(next_);
+ Err(last_)
+ }
+ })
+ .unwrap_or_else(|x| x),
+ )
}
fn size_hint(&self) -> (usize, Option) {
@@ -84,7 +85,7 @@ impl, T> FusedIterator for Coalesc
/// An iterator adaptor that may join together adjacent elements.
///
-/// See [`.coalesce()`](../trait.Itertools.html#method.coalesce) for more information.
+/// See [`.coalesce()`](crate::Itertools::coalesce) for more information.
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub type Coalesce = CoalesceBy::Item>;
@@ -111,7 +112,7 @@ where
/// An iterator adaptor that removes repeated duplicates, determining equality using a comparison function.
///
-/// See [`.dedup_by()`](../trait.Itertools.html#method.dedup_by) or [`.dedup()`](../trait.Itertools.html#method.dedup) for more information.
+/// 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 = CoalesceBy, ::Item>;
@@ -165,7 +166,7 @@ where
/// An iterator adaptor that removes repeated duplicates.
///
-/// See [`.dedup()`](../trait.Itertools.html#method.dedup) for more information.
+/// See [`.dedup()`](crate::Itertools::dedup) for more information.
pub type Dedup = DedupBy;
/// Create a new `Dedup`.
@@ -179,8 +180,8 @@ where
/// An iterator adaptor that removes repeated duplicates, while keeping a count of how many
/// repeated elements were present. This will determine equality using a comparison function.
///
-/// See [`.dedup_by_with_count()`](../trait.Itertools.html#method.dedup_by_with_count) or
-/// [`.dedup_with_count()`](../trait.Itertools.html#method.dedup_with_count) for more information.
+/// 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 =
CoalesceBy, (usize, ::Item)>;
@@ -208,7 +209,7 @@ where
/// An iterator adaptor that removes repeated duplicates, while keeping a count of how many
/// repeated elements were present.
///
-/// See [`.dedup_with_count()`](../trait.Itertools.html#method.dedup_with_count) for more information.
+/// See [`.dedup_with_count()`](crate::Itertools::dedup_with_count) for more information.
pub type DedupWithCount = DedupByWithCount;
/// Create a new `DedupByWithCount`.
diff --git a/src/adaptors/map.rs b/src/adaptors/map.rs
index ff377f700..eee5cc35f 100644
--- a/src/adaptors/map.rs
+++ b/src/adaptors/map.rs
@@ -64,10 +64,10 @@ where
/// An iterator adapter to apply a transformation within a nested `Result::Ok`.
///
-/// See [`.map_ok()`](../trait.Itertools.html#method.map_ok) for more information.
+/// See [`.map_ok()`](crate::Itertools::map_ok) for more information.
pub type MapOk = MapSpecialCase>;
-/// See [`MapOk`](struct.MapOk.html).
+/// See [`MapOk`].
#[deprecated(note = "Use MapOk instead", since = "0.10.0")]
pub type MapResults = MapOk;
@@ -98,7 +98,7 @@ where
/// An iterator adapter to apply `Into` conversion to each element.
///
-/// See [`.map_into()`](../trait.Itertools.html#method.map_into) for more information.
+/// See [`.map_into()`](crate::Itertools::map_into) for more information.
pub type MapInto = MapSpecialCase>;
impl, U> MapSpecialCaseFn for MapSpecialCaseFnInto {
@@ -111,7 +111,7 @@ impl, U> MapSpecialCaseFn for MapSpecialCaseFnInto {
#[derive(Clone)]
pub struct MapSpecialCaseFnInto(PhantomData);
-/// Create a new [`MapInto`](struct.MapInto.html) iterator.
+/// Create a new [`MapInto`] iterator.
pub fn map_into(iter: I) -> MapInto {
MapSpecialCase {
iter,
diff --git a/src/adaptors/mod.rs b/src/adaptors/mod.rs
index 8a8697b36..bd0d93a5f 100644
--- a/src/adaptors/mod.rs
+++ b/src/adaptors/mod.rs
@@ -1,6 +1,6 @@
//! Licensed under the Apache License, Version 2.0
-//! http://www.apache.org/licenses/LICENSE-2.0 or the MIT license
-//! http://opensource.org/licenses/MIT, at your
+//! or the MIT license
+//! , at your
//! option. This file may not be copied, modified, or distributed
//! except according to those terms.
@@ -15,7 +15,7 @@ pub use self::map::MapResults;
pub use self::multi_product::*;
use std::fmt;
-use std::iter::{Fuse, Peekable, FromIterator};
+use std::iter::{Fuse, Peekable, FromIterator, FusedIterator};
use std::marker::PhantomData;
use crate::size_hint;
@@ -24,7 +24,7 @@ use crate::size_hint;
///
/// This iterator is *fused*.
///
-/// See [`.interleave()`](../trait.Itertools.html#method.interleave) for more information.
+/// See [`.interleave()`](crate::Itertools::interleave) for more information.
#[derive(Clone, Debug)]
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct Interleave {
@@ -35,9 +35,9 @@ pub struct Interleave {
/// Create an iterator that interleaves elements in `i` and `j`.
///
-/// `IntoIterator` enabled version of `i.interleave(j)`.
+/// [`IntoIterator`] enabled version of `i.interleave(j)`.
///
-/// See [`.interleave()`](trait.Itertools.html#method.interleave) for more information.
+/// See [`.interleave()`](crate::Itertools::interleave) for more information.
pub fn interleave(i: I, j: J) -> Interleave<::IntoIter, ::IntoIter>
where I: IntoIterator,
J: IntoIterator-
@@ -75,12 +75,17 @@ impl Iterator for Interleave
}
}
+impl FusedIterator for Interleave
+ where I: Iterator,
+ J: Iterator
-
+{}
+
/// An iterator adaptor that alternates elements from the two iterators until
/// one of them runs out.
///
/// This iterator is *fused*.
///
-/// See [`.interleave_shortest()`](../trait.Itertools.html#method.interleave_shortest)
+/// See [`.interleave_shortest()`](crate::Itertools::interleave_shortest)
/// for more information.
#[derive(Clone, Debug)]
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
@@ -157,6 +162,11 @@ impl Iterator for InterleaveShortest
}
}
+impl FusedIterator for InterleaveShortest
+ where I: FusedIterator,
+ J: FusedIterator
-
+{}
+
#[derive(Clone, Debug)]
/// An iterator adaptor that allows putting back a single
/// item to the front of the iterator.
@@ -271,7 +281,7 @@ impl Iterator for PutBack
///
/// Iterator element type is `(I::Item, J::Item)`.
///
-/// See [`.cartesian_product()`](../trait.Itertools.html#method.cartesian_product) for more information.
+/// See [`.cartesian_product()`](crate::Itertools::cartesian_product) for more information.
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct Product
where I: Iterator
@@ -361,12 +371,18 @@ impl Iterator for Product
}
}
+impl FusedIterator for Product
+ where I: FusedIterator,
+ J: Clone + FusedIterator,
+ I::Item: Clone
+{}
+
/// A “meta iterator adaptor”. Its closure receives a reference to the iterator
/// and may pick off as many elements as it likes, to produce the next iterator element.
///
/// Iterator element type is *X*, if the return type of `F` is *Option\*.
///
-/// See [`.batching()`](../trait.Itertools.html#method.batching) for more information.
+/// See [`.batching()`](crate::Itertools::batching) for more information.
#[derive(Clone)]
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct Batching {
@@ -400,7 +416,7 @@ impl Iterator for Batching
/// The iterator steps by yielding the next element from the base iterator,
/// then skipping forward *n-1* elements.
///
-/// See [`.step()`](../trait.Itertools.html#method.step) for more information.
+/// See [`.step()`](crate::Itertools::step) for more information.
#[deprecated(note="Use std .step_by() instead", since="0.8.0")]
#[allow(deprecated)]
#[derive(Clone, Debug)]
@@ -475,13 +491,13 @@ impl MergePredicate for MergeLte {
///
/// Iterator element type is `I::Item`.
///
-/// See [`.merge()`](../trait.Itertools.html#method.merge_by) for more information.
+/// See [`.merge()`](crate::Itertools::merge_by) for more information.
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub type Merge = MergeBy;
/// Create an iterator that merges elements in `i` and `j`.
///
-/// `IntoIterator` enabled version of `i.merge(j)`.
+/// [`IntoIterator`] enabled version of [`Itertools::merge`](crate::Itertools::merge).
///
/// ```
/// use itertools::merge;
@@ -503,7 +519,7 @@ pub fn merge(i: I, j: J) -> Merge<::IntoIter,
where I: Iterator,
@@ -588,10 +604,16 @@ impl Iterator for MergeBy
}
}
+impl FusedIterator for MergeBy
+ where I: FusedIterator,
+ J: FusedIterator
- ,
+ F: MergePredicate
+{}
+
/// An iterator adaptor that borrows from a `Clone`-able iterator
/// to only pick off elements while the predicate returns `true`.
///
-/// See [`.take_while_ref()`](../trait.Itertools.html#method.take_while_ref) for more information.
+/// See [`.take_while_ref()`](crate::Itertools::take_while_ref) for more information.
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct TakeWhileRef<'a, I: 'a, F> {
iter: &'a mut I,
@@ -640,7 +662,7 @@ impl<'a, I, F> Iterator for TakeWhileRef<'a, I, F>
/// An iterator adaptor that filters `Option` iterator elements
/// and produces `A`. Stops on the first `None` encountered.
///
-/// See [`.while_some()`](../trait.Itertools.html#method.while_some) for more information.
+/// See [`.while_some()`](crate::Itertools::while_some) for more information.
#[derive(Clone, Debug)]
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct WhileSome {
@@ -672,7 +694,7 @@ impl Iterator for WhileSome
/// An iterator to iterate through all combinations in a `Clone`-able iterator that produces tuples
/// of a specific size.
///
-/// See [`.tuple_combinations()`](../trait.Itertools.html#method.tuple_combinations) for more
+/// See [`.tuple_combinations()`](crate::Itertools::tuple_combinations) for more
/// information.
#[derive(Clone, Debug)]
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
@@ -682,7 +704,6 @@ pub struct TupleCombinations
{
iter: T::Combination,
_mi: PhantomData,
- _mt: PhantomData
}
pub trait HasCombination: Sized {
@@ -698,7 +719,6 @@ pub fn tuple_combinations(iter: I) -> TupleCombinations
TupleCombinations {
iter: T::Combination::from(iter),
_mi: PhantomData,
- _mt: PhantomData,
}
}
@@ -713,6 +733,11 @@ impl Iterator for TupleCombinations
}
}
+impl FusedIterator for TupleCombinations
+ where I: FusedIterator,
+ T: HasCombination,
+{}
+
#[derive(Clone, Debug)]
pub struct Tuple1Combination {
iter: I,
@@ -737,7 +762,7 @@ impl HasCombination for (I::Item,) {
}
macro_rules! impl_tuple_combination {
- ($C:ident $P:ident ; $A:ident, $($I:ident),* ; $($X:ident)*) => (
+ ($C:ident $P:ident ; $($X:ident)*) => (
#[derive(Clone, Debug)]
pub struct $C {
item: Option,
@@ -747,30 +772,25 @@ macro_rules! impl_tuple_combination {
impl From for $C {
fn from(mut iter: I) -> Self {
- $C {
+ Self {
item: iter.next(),
iter: iter.clone(),
- c: $P::from(iter),
+ c: iter.into(),
}
}
}
impl From for $C> {
fn from(iter: I) -> Self {
- let mut iter = iter.fuse();
- $C {
- item: iter.next(),
- iter: iter.clone(),
- c: $P::from(iter),
- }
+ Self::from(iter.fuse())
}
}
- impl Iterator for $C
- where I: Iterator
- + Clone,
+ impl Iterator for $C
+ where I: Iterator
- + Clone,
I::Item: Clone
{
- type Item = ($($I),*);
+ type Item = (A, $(ignore_ident!($X, A)),*);
fn next(&mut self) -> Option {
if let Some(($($X),*,)) = self.c.next() {
@@ -779,15 +799,15 @@ macro_rules! impl_tuple_combination {
} else {
self.item = self.iter.next();
self.item.clone().and_then(|z| {
- self.c = $P::from(self.iter.clone());
+ self.c = self.iter.clone().into();
self.c.next().map(|($($X),*,)| (z, $($X),*))
})
}
}
}
- impl HasCombination for ($($I),*)
- where I: Iterator
- + Clone,
+ impl HasCombination for (A, $(ignore_ident!($X, A)),*)
+ where I: Iterator
- + Clone,
I::Item: Clone
{
type Combination = $C>;
@@ -800,29 +820,28 @@ macro_rules! impl_tuple_combination {
// use itertools::Itertools;
//
// for i in 2..=12 {
-// println!("impl_tuple_combination!(Tuple{arity}Combination Tuple{prev}Combination; {tys}; {idents});",
+// println!("impl_tuple_combination!(Tuple{arity}Combination Tuple{prev}Combination; {idents});",
// arity = i,
// prev = i - 1,
-// tys = iter::repeat("A").take(i + 1).join(", "),
// idents = ('a'..'z').take(i - 1).join(" "),
// );
// }
// It could probably be replaced by a bit more macro cleverness.
-impl_tuple_combination!(Tuple2Combination Tuple1Combination; A, A, A; a);
-impl_tuple_combination!(Tuple3Combination Tuple2Combination; A, A, A, A; a b);
-impl_tuple_combination!(Tuple4Combination Tuple3Combination; A, A, A, A, A; a b c);
-impl_tuple_combination!(Tuple5Combination Tuple4Combination; A, A, A, A, A, A; a b c d);
-impl_tuple_combination!(Tuple6Combination Tuple5Combination; A, A, A, A, A, A, A; a b c d e);
-impl_tuple_combination!(Tuple7Combination Tuple6Combination; A, A, A, A, A, A, A, A; a b c d e f);
-impl_tuple_combination!(Tuple8Combination Tuple7Combination; A, A, A, A, A, A, A, A, A; a b c d e f g);
-impl_tuple_combination!(Tuple9Combination Tuple8Combination; A, A, A, A, A, A, A, A, A, A; a b c d e f g h);
-impl_tuple_combination!(Tuple10Combination Tuple9Combination; A, A, A, A, A, A, A, A, A, A, A; a b c d e f g h i);
-impl_tuple_combination!(Tuple11Combination Tuple10Combination; A, A, A, A, A, A, A, A, A, A, A, A; a b c d e f g h i j);
-impl_tuple_combination!(Tuple12Combination Tuple11Combination; A, A, A, A, A, A, A, A, A, A, A, A, A; a b c d e f g h i j k);
+impl_tuple_combination!(Tuple2Combination Tuple1Combination; a);
+impl_tuple_combination!(Tuple3Combination Tuple2Combination; a b);
+impl_tuple_combination!(Tuple4Combination Tuple3Combination; a b c);
+impl_tuple_combination!(Tuple5Combination Tuple4Combination; a b c d);
+impl_tuple_combination!(Tuple6Combination Tuple5Combination; a b c d e);
+impl_tuple_combination!(Tuple7Combination Tuple6Combination; a b c d e f);
+impl_tuple_combination!(Tuple8Combination Tuple7Combination; a b c d e f g);
+impl_tuple_combination!(Tuple9Combination Tuple8Combination; a b c d e f g h);
+impl_tuple_combination!(Tuple10Combination Tuple9Combination; a b c d e f g h i);
+impl_tuple_combination!(Tuple11Combination Tuple10Combination; a b c d e f g h i j);
+impl_tuple_combination!(Tuple12Combination Tuple11Combination; a b c d e f g h i j k);
/// An iterator adapter to filter values within a nested `Result::Ok`.
///
-/// See [`.filter_ok()`](../trait.Itertools.html#method.filter_ok) for more information.
+/// See [`.filter_ok()`](crate::Itertools::filter_ok) for more information.
#[derive(Clone)]
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct FilterOk {
@@ -884,9 +903,14 @@ impl Iterator for FilterOk
}
}
+impl FusedIterator for FilterOk
+ where I: FusedIterator
- >,
+ F: FnMut(&T) -> bool,
+{}
+
/// An iterator adapter to filter and apply a transformation on values within a nested `Result::Ok`.
///
-/// See [`.filter_map_ok()`](../trait.Itertools.html#method.filter_map_ok) for more information.
+/// See [`.filter_map_ok()`](crate::Itertools::filter_map_ok) for more information.
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct FilterMapOk {
iter: I,
@@ -955,9 +979,14 @@ impl Iterator for FilterMapOk
}
}
+impl FusedIterator for FilterMapOk
+ where I: FusedIterator
- >,
+ F: FnMut(T) -> Option,
+{}
+
/// An iterator adapter to get the positions of each element that matches a predicate.
///
-/// See [`.positions()`](../trait.Itertools.html#method.positions) for more information.
+/// See [`.positions()`](crate::Itertools::positions) for more information.
#[derive(Clone)]
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct Positions {
@@ -1014,9 +1043,14 @@ impl DoubleEndedIterator for Positions
}
}
+impl FusedIterator for Positions
+ where I: FusedIterator,
+ F: FnMut(I::Item) -> bool,
+{}
+
/// An iterator adapter to apply a mutating function to each element before yielding it.
///
-/// See [`.update()`](../trait.Itertools.html#method.update) for more information.
+/// See [`.update()`](crate::Itertools::update) for more information.
#[derive(Clone)]
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct Update {
@@ -1089,3 +1123,9 @@ where
}
}
}
+
+impl FusedIterator for Update
+where
+ I: FusedIterator,
+ F: FnMut(&mut I::Item),
+{}
diff --git a/src/adaptors/multi_product.rs b/src/adaptors/multi_product.rs
index 6938014ce..9708ef4bd 100644
--- a/src/adaptors/multi_product.rs
+++ b/src/adaptors/multi_product.rs
@@ -11,7 +11,7 @@ use alloc::vec::Vec;
///
/// An iterator element type is `Vec`.
///
-/// See [`.multi_cartesian_product()`](../trait.Itertools.html#method.multi_cartesian_product)
+/// See [`.multi_cartesian_product()`](crate::Itertools::multi_cartesian_product)
/// for more information.
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct MultiProduct(Vec>)
diff --git a/src/combinations.rs b/src/combinations.rs
index e6ba4ac29..68a59c5e4 100644
--- a/src/combinations.rs
+++ b/src/combinations.rs
@@ -1,11 +1,12 @@
use std::fmt;
+use std::iter::FusedIterator;
use super::lazy_buffer::LazyBuffer;
use alloc::vec::Vec;
/// An iterator to iterate through all the `k`-length combinations in an iterator.
///
-/// See [`.combinations()`](../trait.Itertools.html#method.combinations) for more information.
+/// See [`.combinations()`](crate::Itertools::combinations) for more information.
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct Combinations {
indices: Vec,
@@ -47,9 +48,7 @@ impl Combinations {
pub fn k(&self) -> usize { self.indices.len() }
/// Returns the (current) length of the pool from which combination elements are
- /// selected. This value can change between invocations of [`next`].
- ///
- /// [`next`]: #method.next
+ /// selected. This value can change between invocations of [`next`](Combinations::next).
#[inline]
pub fn n(&self) -> usize { self.pool.len() }
@@ -122,3 +121,8 @@ impl Iterator for Combinations
Some(self.indices.iter().map(|i| self.pool[*i].clone()).collect())
}
}
+
+impl FusedIterator for Combinations
+ where I: Iterator,
+ I::Item: Clone
+{}
diff --git a/src/combinations_with_replacement.rs b/src/combinations_with_replacement.rs
index 7e7a80223..81b13f130 100644
--- a/src/combinations_with_replacement.rs
+++ b/src/combinations_with_replacement.rs
@@ -1,11 +1,13 @@
use alloc::vec::Vec;
use std::fmt;
+use std::iter::FusedIterator;
use super::lazy_buffer::LazyBuffer;
/// An iterator to iterate through all the `n`-length combinations in an iterator, with replacement.
///
-/// See [`.combinations_with_replacement()`](../trait.Itertools.html#method.combinations_with_replacement) for more information.
+/// See [`.combinations_with_replacement()`](crate::Itertools::combinations_with_replacement)
+/// for more information.
#[derive(Clone)]
pub struct CombinationsWithReplacement
where
@@ -99,3 +101,9 @@ where
}
}
}
+
+impl FusedIterator for CombinationsWithReplacement
+where
+ I: Iterator,
+ I::Item: Clone,
+{}
diff --git a/src/concat_impl.rs b/src/concat_impl.rs
index 0233d01f6..450f7fce1 100644
--- a/src/concat_impl.rs
+++ b/src/concat_impl.rs
@@ -1,8 +1,8 @@
use crate::Itertools;
-/// Combine all an iterator's elements into one element by using `Extend`.
+/// Combine all an iterator's elements into one element by using [`Extend`].
///
-/// `IntoIterator`-enabled version of `.concat()`
+/// [`IntoIterator`]-enabled version of [`Itertools::concat`].
///
/// This combinator will extend the first item with each of the rest of the
/// items of the iterator. If the iterator is empty, the default value of
diff --git a/src/diff.rs b/src/diff.rs
index c196d8d2f..1731f0639 100644
--- a/src/diff.rs
+++ b/src/diff.rs
@@ -1,14 +1,14 @@
//! "Diff"ing iterators for caching elements to sequential collections without requiring the new
//! elements' iterator to be `Clone`.
//!
-//! - [**Diff**](./enum.Diff.html) (produced by the [**diff_with**](./fn.diff_with.html) function)
+//! - [`Diff`] (produced by the [`diff_with`] function)
//! describes the difference between two non-`Clone` iterators `I` and `J` after breaking ASAP from
//! a lock-step comparison.
use crate::free::put_back;
use crate::structs::PutBack;
-/// A type returned by the [`diff_with`](./fn.diff_with.html) function.
+/// A type returned by the [`diff_with`] function.
///
/// `Diff` represents the way in which the elements yielded by the iterator `I` differ to some
/// iterator `J`.
@@ -26,7 +26,7 @@ pub enum Diff
}
/// Compares every element yielded by both `i` and `j` with the given function in lock-step and
-/// returns a `Diff` which describes how `j` differs from `i`.
+/// returns a [`Diff`] which describes how `j` differs from `i`.
///
/// If the number of elements yielded by `j` is less than the number of elements yielded by `i`,
/// the number of `j` elements yielded will be returned along with `i`'s remaining elements as
diff --git a/src/duplicates_impl.rs b/src/duplicates_impl.rs
new file mode 100644
index 000000000..42049df35
--- /dev/null
+++ b/src/duplicates_impl.rs
@@ -0,0 +1,206 @@
+use std::hash::Hash;
+
+mod private {
+ use std::collections::HashMap;
+ use std::hash::Hash;
+ use std::fmt;
+
+ #[derive(Clone)]
+ #[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
+ pub struct DuplicatesBy {
+ pub(crate) iter: I,
+ pub(crate) meta: Meta,
+ }
+
+ impl fmt::Debug for DuplicatesBy
+ where
+ I: Iterator + fmt::Debug,
+ V: fmt::Debug + Hash + Eq,
+ {
+ debug_fmt_fields!(DuplicatesBy, iter, meta.used);
+ }
+
+ impl DuplicatesBy {
+ pub(crate) fn new(iter: I, key_method: F) -> Self {
+ DuplicatesBy {
+ iter,
+ meta: Meta {
+ used: HashMap::new(),
+ pending: 0,
+ key_method,
+ },
+ }
+ }
+ }
+
+ #[derive(Clone)]
+ pub struct Meta {
+ used: HashMap,
+ pending: usize,
+ key_method: F,
+ }
+
+ impl Meta
+ where
+ Key: Eq + Hash,
+ {
+ /// Takes an item and returns it back to the caller if it's the second time we see it.
+ /// Otherwise the item is consumed and None is returned
+ #[inline(always)]
+ fn filter(&mut self, item: I) -> Option
+ where
+ F: KeyMethod,
+ {
+ let kv = self.key_method.make(item);
+ match self.used.get_mut(kv.key_ref()) {
+ None => {
+ self.used.insert(kv.key(), false);
+ self.pending += 1;
+ None
+ }
+ Some(true) => None,
+ Some(produced) => {
+ *produced = true;
+ self.pending -= 1;
+ Some(kv.value())
+ }
+ }
+ }
+ }
+
+ impl Iterator for DuplicatesBy
+ where
+ I: Iterator,
+ Key: Eq + Hash,
+ F: KeyMethod,
+ {
+ type Item = I::Item;
+
+ fn next(&mut self) -> Option {
+ let DuplicatesBy { iter, meta } = self;
+ iter.find_map(|v| meta.filter(v))
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option) {
+ let (_, hi) = self.iter.size_hint();
+ // There are `hi` number of items left in the base iterator. In the best case scenario,
+ // these items are exactly the same as the ones pending (i.e items seen exactly once so
+ // far), plus (hi - pending) / 2 pairs of never seen before items.
+ let hi = hi.map(|hi| {
+ let max_pending = std::cmp::min(self.meta.pending, hi);
+ let max_new = std::cmp::max(hi - self.meta.pending, 0) / 2;
+ max_pending + max_new
+ });
+ // The lower bound is always 0 since we might only get unique items from now on
+ (0, hi)
+ }
+ }
+
+ impl DoubleEndedIterator for DuplicatesBy
+ where
+ I: DoubleEndedIterator,
+ Key: Eq + Hash,
+ F: KeyMethod,
+ {
+ fn next_back(&mut self) -> Option {
+ let DuplicatesBy { iter, meta } = self;
+ iter.rev().find_map(|v| meta.filter(v))
+ }
+ }
+
+ /// A keying method for use with `DuplicatesBy`
+ pub trait KeyMethod {
+ type Container: KeyXorValue;
+
+ fn make(&mut self, value: V) -> Self::Container;
+ }
+
+ /// Apply the identity function to elements before checking them for equality.
+ pub struct ById;
+ impl KeyMethod for ById {
+ type Container = JustValue;
+
+ fn make(&mut self, v: V) -> Self::Container {
+ JustValue(v)
+ }
+ }
+
+ /// Apply a user-supplied function to elements before checking them for equality.
+ pub struct ByFn(pub(crate) F);
+ impl KeyMethod for ByFn
+ where
+ F: FnMut(&V) -> K,
+ {
+ type Container = KeyValue;
+
+ fn make(&mut self, v: V) -> Self::Container {
+ KeyValue((self.0)(&v), v)
+ }
+ }
+
+ // Implementors of this trait can hold onto a key and a value but only give access to one of them
+ // at a time. This allows the key and the value to be the same value internally
+ pub trait KeyXorValue {
+ fn key_ref(&self) -> &K;
+ fn key(self) -> K;
+ fn value(self) -> V;
+ }
+
+ pub struct KeyValue(K, V);
+ impl KeyXorValue for KeyValue {
+ fn key_ref(&self) -> &K {
+ &self.0
+ }
+ fn key(self) -> K {
+ self.0
+ }
+ fn value(self) -> V {
+ self.1
+ }
+ }
+
+ pub struct JustValue(V);
+ impl KeyXorValue for JustValue {
+ fn key_ref(&self) -> &V {
+ &self.0
+ }
+ fn key(self) -> V {
+ self.0
+ }
+ fn value(self) -> V {
+ self.0
+ }
+ }
+}
+
+/// 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 = private::DuplicatesBy>;
+
+/// Create a new `DuplicatesBy` iterator.
+pub fn duplicates_by(iter: I, f: F) -> DuplicatesBy
+where
+ Key: Eq + Hash,
+ F: FnMut(&I::Item) -> Key,
+ I: Iterator,
+{
+ DuplicatesBy::new(iter, private::ByFn(f))
+}
+
+/// An iterator adapter to filter out duplicate elements.
+///
+/// See [`.duplicates()`](crate::Itertools::duplicates) for more information.
+pub type Duplicates = private::DuplicatesBy::Item, private::ById>;
+
+/// Create a new `Duplicates` iterator.
+pub fn duplicates(iter: I) -> Duplicates
+where
+ I: Iterator,
+ I::Item: Eq + Hash,
+{
+ Duplicates::new(iter, private::ById)
+}
+
diff --git a/src/either_or_both.rs b/src/either_or_both.rs
index a03a4f16e..28d1df757 100644
--- a/src/either_or_both.rs
+++ b/src/either_or_both.rs
@@ -25,7 +25,7 @@ impl EitherOrBoth {
}
/// If Left, return true otherwise, return false.
- /// Exclusive version of [`has_left`].
+ /// Exclusive version of [`has_left`](EitherOrBoth::has_left).
pub fn is_left(&self) -> bool {
match *self {
Left(_) => true,
@@ -34,7 +34,7 @@ impl EitherOrBoth {
}
/// If Right, return true otherwise, return false.
- /// Exclusive version of [`has_right`].
+ /// Exclusive version of [`has_right`](EitherOrBoth::has_right).
pub fn is_right(&self) -> bool {
match *self {
Right(_) => true,
@@ -140,7 +140,7 @@ impl EitherOrBoth {
}
}
- /// Apply the function `f` on the value `b` in `Right(b)` or `Both(a, _)` variants if it is
+ /// Apply the function `f` on the value `a` in `Left(a)` or `Both(a, _)` variants if it is
/// present.
pub fn left_and_then(self, f: F) -> EitherOrBoth
where
@@ -152,8 +152,8 @@ impl EitherOrBoth {
}
}
- /// Apply the function `f` on the value `a`
- /// in `Left(a)` or `Both(a, _)` variants if it is present.
+ /// Apply the function `f` on the value `b`
+ /// in `Right(b)` or `Both(_, b)` variants if it is present.
pub fn right_and_then(self, f: F) -> EitherOrBoth
where
F: FnOnce(B) -> EitherOrBoth,
@@ -163,6 +163,21 @@ impl EitherOrBoth {
Right(b) | Both(_, b) => f(b),
}
}
+
+ /// Returns a tuple consisting of the `l` and `r` in `Both(l, r)`, if present.
+ /// Otherwise, returns the wrapped value for the present element, and the [`default`](Default::default)
+ /// for the other.
+ pub fn or_default(self) -> (A, B)
+ where
+ A: Default,
+ B: Default,
+ {
+ match self {
+ EitherOrBoth::Left(l) => (l, B::default()),
+ EitherOrBoth::Right(r) => (A::default(), r),
+ EitherOrBoth::Both(l, r) => (l, r),
+ }
+ }
}
impl EitherOrBoth {
diff --git a/src/flatten_ok.rs b/src/flatten_ok.rs
new file mode 100644
index 000000000..d46bbde4e
--- /dev/null
+++ b/src/flatten_ok.rs
@@ -0,0 +1,166 @@
+use crate::size_hint;
+use std::{
+ fmt,
+ iter::{DoubleEndedIterator, FusedIterator},
+};
+
+pub fn flatten_ok(iter: I) -> FlattenOk
+where
+ I: Iterator
- >,
+ T: IntoIterator,
+{
+ FlattenOk {
+ iter,
+ inner_front: None,
+ inner_back: None,
+ }
+}
+
+/// An iterator adaptor that flattens `Result::Ok` values and
+/// allows `Result::Err` values through unchanged.
+///
+/// See [`.flatten_ok()`](crate::Itertools::flatten_ok) for more information.
+#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
+pub struct FlattenOk
+where
+ I: Iterator
- >,
+ T: IntoIterator,
+{
+ iter: I,
+ inner_front: Option,
+ inner_back: Option,
+}
+
+impl Iterator for FlattenOk
+where
+ I: Iterator
- >,
+ T: IntoIterator,
+{
+ type Item = Result;
+
+ fn next(&mut self) -> Option {
+ loop {
+ // Handle the front inner iterator.
+ 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;
+ }
+ }
+
+ match self.iter.next() {
+ Some(Ok(ok)) => self.inner_front = Some(ok.into_iter()),
+ Some(Err(e)) => return Some(Err(e)),
+ None => {
+ // Handle the back inner iterator.
+ 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;
+ }
+ } else {
+ return None;
+ }
+ }
+ }
+ }
+ }
+
+ fn size_hint(&self) -> (usize, Option) {
+ let inner_hint = |inner: &Option| {
+ inner
+ .as_ref()
+ .map(Iterator::size_hint)
+ .unwrap_or((0, Some(0)))
+ };
+ let inner_front = inner_hint(&self.inner_front);
+ let inner_back = inner_hint(&self.inner_back);
+ // The outer iterator `Ok` case could be (0, None) as we don't know its size_hint yet.
+ let outer = match self.iter.size_hint() {
+ (0, Some(0)) => (0, Some(0)),
+ _ => (0, None),
+ };
+
+ size_hint::add(size_hint::add(inner_front, inner_back), outer)
+ }
+}
+
+impl DoubleEndedIterator for FlattenOk
+where
+ I: DoubleEndedIterator
- >,
+ T: IntoIterator,
+ T::IntoIter: DoubleEndedIterator,
+{
+ fn next_back(&mut self) -> Option {
+ loop {
+ // Handle the back inner iterator.
+ 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;
+ }
+ }
+
+ match self.iter.next_back() {
+ Some(Ok(ok)) => self.inner_back = Some(ok.into_iter()),
+ Some(Err(e)) => return Some(Err(e)),
+ None => {
+ // Handle the front inner iterator.
+ 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;
+ }
+ } else {
+ return None;
+ }
+ }
+ }
+ }
+ }
+}
+
+impl Clone for FlattenOk
+where
+ I: Iterator
- > + Clone,
+ T: IntoIterator,
+ T::IntoIter: Clone,
+{
+ #[inline]
+ clone_fields!(iter, inner_front, inner_back);
+}
+
+impl fmt::Debug for FlattenOk
+where
+ I: Iterator
- > + fmt::Debug,
+ T: IntoIterator,
+ T::IntoIter: fmt::Debug,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("FlattenOk")
+ .field("iter", &self.iter)
+ .field("inner_front", &self.inner_front)
+ .field("inner_back", &self.inner_back)
+ .finish()
+ }
+}
+
+/// Only the iterator being flattened needs to implement [`FusedIterator`].
+impl FusedIterator for FlattenOk
+where
+ I: FusedIterator
- >,
+ T: IntoIterator,
+{
+}
diff --git a/src/format.rs b/src/format.rs
index ec2dc7a7c..d87cee950 100644
--- a/src/format.rs
+++ b/src/format.rs
@@ -6,7 +6,7 @@ use std::cell::RefCell;
/// The format value can only be formatted once, after that the iterator is
/// exhausted.
///
-/// See [`.format_with()`](../trait.Itertools.html#method.format_with) for more information.
+/// See [`.format_with()`](crate::Itertools::format_with) for more information.
#[derive(Clone)]
pub struct FormatWith<'a, I, F> {
sep: &'a str,
@@ -19,7 +19,7 @@ pub struct FormatWith<'a, I, F> {
/// The format value can only be formatted once, after that the iterator is
/// exhausted.
///
-/// See [`.format()`](../trait.Itertools.html#method.format)
+/// See [`.format()`](crate::Itertools::format)
/// for more information.
#[derive(Clone)]
pub struct Format<'a, I> {
diff --git a/src/free.rs b/src/free.rs
index bfc5ab422..c78dc1d02 100644
--- a/src/free.rs
+++ b/src/free.rs
@@ -1,6 +1,6 @@
//! Free functions that create iterator adaptors or call iterator methods.
//!
-//! The benefit of free functions is that they accept any `IntoIterator` as
+//! The benefit of free functions is that they accept any [`IntoIterator`] as
//! argument, so the resulting code may be easier to read.
#[cfg(feature = "use_alloc")]
@@ -37,7 +37,7 @@ pub use crate::rciter_impl::rciter;
/// Iterate `iterable` with a running index.
///
-/// `IntoIterator` enabled version of `.enumerate()`.
+/// [`IntoIterator`] enabled version of [`Iterator::enumerate`].
///
/// ```
/// use itertools::enumerate;
@@ -54,7 +54,7 @@ pub fn enumerate(iterable: I) -> iter::Enumerate
/// Iterate `iterable` in reverse.
///
-/// `IntoIterator` enabled version of `.rev()`.
+/// [`IntoIterator`] enabled version of [`Iterator::rev`].
///
/// ```
/// use itertools::rev;
@@ -72,7 +72,7 @@ pub fn rev(iterable: I) -> iter::Rev
/// Iterate `i` and `j` in lock step.
///
-/// `IntoIterator` enabled version of `i.zip(j)`.
+/// [`IntoIterator`] enabled version of [`Iterator::zip`].
///
/// ```
/// use itertools::zip;
@@ -91,7 +91,7 @@ pub fn zip(i: I, j: J) -> Zip
/// Create an iterator that first iterates `i` and then `j`.
///
-/// `IntoIterator` enabled version of `i.chain(j)`.
+/// [`IntoIterator`] enabled version of [`Iterator::chain`].
///
/// ```
/// use itertools::chain;
@@ -109,7 +109,7 @@ pub fn chain(i: I, j: J) -> iter::Chain<::IntoIter, (iterable: I) -> iter::Cloned
/// Perform a fold operation over the iterable.
///
-/// `IntoIterator` enabled version of `i.fold(init, f)`
+/// [`IntoIterator`] enabled version of [`Iterator::fold`].
///
/// ```
/// use itertools::fold;
@@ -141,7 +141,7 @@ pub fn fold(iterable: I, init: B, f: F) -> B
/// Test whether the predicate holds for all elements in the iterable.
///
-/// `IntoIterator` enabled version of `i.all(f)`
+/// [`IntoIterator`] enabled version of [`Iterator::all`].
///
/// ```
/// use itertools::all;
@@ -157,7 +157,7 @@ pub fn all(iterable: I, f: F) -> bool
/// Test whether the predicate holds for any elements in the iterable.
///
-/// `IntoIterator` enabled version of `i.any(f)`
+/// [`IntoIterator`] enabled version of [`Iterator::any`].
///
/// ```
/// use itertools::any;
@@ -173,7 +173,7 @@ pub fn any(iterable: I, f: F) -> bool
/// Return the maximum value of the iterable.
///
-/// `IntoIterator` enabled version of `i.max()`.
+/// [`IntoIterator`] enabled version of [`Iterator::max`].
///
/// ```
/// use itertools::max;
@@ -189,7 +189,7 @@ pub fn max(iterable: I) -> Option
/// Return the minimum value of the iterable.
///
-/// `IntoIterator` enabled version of `i.min()`.
+/// [`IntoIterator`] enabled version of [`Iterator::min`].
///
/// ```
/// use itertools::min;
@@ -206,7 +206,7 @@ pub fn min(iterable: I) -> Option
/// Combine all iterator elements into one String, seperated by `sep`.
///
-/// `IntoIterator` enabled version of `iterable.join(sep)`.
+/// [`IntoIterator`] enabled version of [`Itertools::join`].
///
/// ```
/// use itertools::join;
@@ -223,9 +223,7 @@ pub fn join(iterable: I, sep: &str) -> String
/// Sort all iterator elements into a new iterator in ascending order.
///
-/// `IntoIterator` enabled version of [`iterable.sorted()`][1].
-///
-/// [1]: trait.Itertools.html#method.sorted
+/// [`IntoIterator`] enabled version of [`Itertools::sorted`].
///
/// ```
/// use itertools::sorted;
diff --git a/src/group_map.rs b/src/group_map.rs
index 4231de074..a2d0ebb2a 100644
--- a/src/group_map.rs
+++ b/src/group_map.rs
@@ -6,7 +6,7 @@ use std::iter::Iterator;
/// Return a `HashMap` of keys mapped to a list of their corresponding values.
///
-/// See [`.into_group_map()`](../trait.Itertools.html#method.into_group_map)
+/// See [`.into_group_map()`](crate::Itertools::into_group_map)
/// for more information.
pub fn into_group_map(iter: I) -> HashMap>
where I: Iterator