diff options
Diffstat (limited to 'src/adaptors')
-rw-r--r-- | src/adaptors/coalesce.rs | 232 | ||||
-rw-r--r-- | src/adaptors/map.rs | 120 | ||||
-rw-r--r-- | src/adaptors/mod.rs | 421 | ||||
-rw-r--r-- | src/adaptors/multi_product.rs | 8 |
4 files changed, 483 insertions, 298 deletions
diff --git a/src/adaptors/coalesce.rs b/src/adaptors/coalesce.rs new file mode 100644 index 0000000..116f688 --- /dev/null +++ b/src/adaptors/coalesce.rs @@ -0,0 +1,232 @@ +use std::fmt; +use std::iter::FusedIterator; + +use crate::size_hint; + +pub struct CoalesceBy<I, F, T> +where + I: Iterator, +{ + iter: I, + last: Option<T>, + f: F, +} + +impl<I: Clone, F: Clone, T: Clone> Clone for CoalesceBy<I, F, T> +where + I: Iterator, +{ + clone_fields!(last, iter, f); +} + +impl<I, F, T> fmt::Debug for CoalesceBy<I, F, T> +where + I: Iterator + fmt::Debug, + T: fmt::Debug, +{ + debug_fmt_fields!(CoalesceBy, iter); +} + +pub trait CoalescePredicate<Item, T> { + fn coalesce_pair(&mut self, t: T, item: Item) -> Result<T, (T, T)>; +} + +impl<I, F, T> Iterator for CoalesceBy<I, F, T> +where + I: Iterator, + F: CoalescePredicate<I::Item, T>, +{ + type Item = T; + + fn next(&mut self) -> Option<Self::Item> { + // 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) + } + + fn size_hint(&self) -> (usize, Option<usize>) { + let (low, hi) = size_hint::add_scalar(self.iter.size_hint(), self.last.is_some() as usize); + ((low > 0) as usize, hi) + } + + fn fold<Acc, FnAcc>(self, acc: Acc, mut fn_acc: FnAcc) -> Acc + where + FnAcc: FnMut(Acc, Self::Item) -> Acc, + { + if let Some(last) = self.last { + let mut f = self.f; + let (last, acc) = self.iter.fold((last, acc), |(last, acc), elt| { + match f.coalesce_pair(last, elt) { + Ok(joined) => (joined, acc), + Err((last_, next_)) => (next_, fn_acc(acc, last_)), + } + }); + fn_acc(acc, last) + } else { + acc + } + } +} + +impl<I: Iterator, F: CoalescePredicate<I::Item, T>, T> FusedIterator for CoalesceBy<I, F, T> {} + +/// An iterator adaptor that may join together adjacent elements. +/// +/// See [`.coalesce()`](../trait.Itertools.html#method.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 +where + F: FnMut(T, Item) -> Result<T, (T, T)>, +{ + fn coalesce_pair(&mut self, t: T, item: Item) -> Result<T, (T, T)> { + self(t, item) + } +} + +/// Create a new `Coalesce`. +pub fn coalesce<I, F>(mut iter: I, f: F) -> Coalesce<I, F> +where + I: Iterator, +{ + Coalesce { + last: iter.next(), + iter, + f, + } +} + +/// 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. +#[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)] +pub struct DedupPred2CoalescePred<DP>(DP); + +pub trait DedupPredicate<T> { + // TODO replace by Fn(&T, &T)->bool once Rust supports it + fn dedup_pair(&mut self, a: &T, b: &T) -> bool; +} + +impl<DP, T> CoalescePredicate<T, T> for DedupPred2CoalescePred<DP> +where + DP: DedupPredicate<T>, +{ + fn coalesce_pair(&mut self, t: T, item: T) -> Result<T, (T, T)> { + if self.0.dedup_pair(&t, &item) { + Ok(t) + } else { + Err((t, item)) + } + } +} + +#[derive(Clone)] +pub struct DedupEq; + +impl<T: PartialEq> DedupPredicate<T> for DedupEq { + fn dedup_pair(&mut self, a: &T, b: &T) -> bool { + a == b + } +} + +impl<T, F: FnMut(&T, &T) -> bool> DedupPredicate<T> for F { + fn dedup_pair(&mut self, a: &T, b: &T) -> bool { + self(a, b) + } +} + +/// Create a new `DedupBy`. +pub fn dedup_by<I, Pred>(mut iter: I, dedup_pred: Pred) -> DedupBy<I, Pred> +where + I: Iterator, +{ + DedupBy { + last: iter.next(), + iter, + f: DedupPred2CoalescePred(dedup_pred), + } +} + +/// An iterator adaptor that removes repeated duplicates. +/// +/// See [`.dedup()`](../trait.Itertools.html#method.dedup) for more information. +pub type Dedup<I> = DedupBy<I, DedupEq>; + +/// Create a new `Dedup`. +pub fn dedup<I>(iter: I) -> Dedup<I> +where + I: Iterator, +{ + dedup_by(iter, DedupEq) +} + +/// 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. +#[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)>; + +#[derive(Clone)] +pub struct DedupPredWithCount2CoalescePred<DP>(DP); + +impl<DP, T> CoalescePredicate<T, (usize, T)> for DedupPredWithCount2CoalescePred<DP> +where + DP: DedupPredicate<T>, +{ + fn coalesce_pair( + &mut self, + (c, t): (usize, T), + item: T, + ) -> Result<(usize, T), ((usize, T), (usize, T))> { + if self.0.dedup_pair(&t, &item) { + Ok((c + 1, t)) + } else { + Err(((c, t), (1, item))) + } + } +} + +/// 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. +pub type DedupWithCount<I> = DedupByWithCount<I, DedupEq>; + +/// Create a new `DedupByWithCount`. +pub fn dedup_by_with_count<I, Pred>(mut iter: I, dedup_pred: Pred) -> DedupByWithCount<I, Pred> +where + I: Iterator, +{ + DedupByWithCount { + last: iter.next().map(|v| (1, v)), + iter, + f: DedupPredWithCount2CoalescePred(dedup_pred), + } +} + +/// Create a new `DedupWithCount`. +pub fn dedup_with_count<I>(iter: I) -> DedupWithCount<I> +where + I: Iterator, +{ + dedup_by_with_count(iter, DedupEq) +} diff --git a/src/adaptors/map.rs b/src/adaptors/map.rs new file mode 100644 index 0000000..ff377f7 --- /dev/null +++ b/src/adaptors/map.rs @@ -0,0 +1,120 @@ +use std::iter::FromIterator; +use std::marker::PhantomData; + +#[derive(Clone)] +#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] +pub struct MapSpecialCase<I, F> { + iter: I, + f: F, +} + +pub trait MapSpecialCaseFn<T> { + type Out; + fn call(&mut self, t: T) -> Self::Out; +} + +impl<I, R> Iterator for MapSpecialCase<I, R> +where + I: Iterator, + R: MapSpecialCaseFn<I::Item>, +{ + type Item = R::Out; + + fn next(&mut self) -> Option<Self::Item> { + self.iter.next().map(|i| self.f.call(i)) + } + + fn size_hint(&self) -> (usize, Option<usize>) { + self.iter.size_hint() + } + + fn fold<Acc, Fold>(self, init: Acc, mut fold_f: Fold) -> Acc + where + Fold: FnMut(Acc, Self::Item) -> Acc, + { + let mut f = self.f; + self.iter.fold(init, move |acc, v| fold_f(acc, f.call(v))) + } + + fn collect<C>(self) -> C + where + C: FromIterator<Self::Item>, + { + let mut f = self.f; + self.iter.map(move |v| f.call(v)).collect() + } +} + +impl<I, R> DoubleEndedIterator for MapSpecialCase<I, R> +where + I: DoubleEndedIterator, + R: MapSpecialCaseFn<I::Item>, +{ + fn next_back(&mut self) -> Option<Self::Item> { + self.iter.next_back().map(|i| self.f.call(i)) + } +} + +impl<I, R> ExactSizeIterator for MapSpecialCase<I, R> +where + I: ExactSizeIterator, + R: MapSpecialCaseFn<I::Item>, +{ +} + +/// An iterator adapter to apply a transformation within a nested `Result::Ok`. +/// +/// See [`.map_ok()`](../trait.Itertools.html#method.map_ok) for more information. +pub type MapOk<I, F> = MapSpecialCase<I, MapSpecialCaseFnOk<F>>; + +/// See [`MapOk`](struct.MapOk.html). +#[deprecated(note = "Use MapOk instead", since = "0.10.0")] +pub type MapResults<I, F> = MapOk<I, F>; + +impl<F, T, U, E> MapSpecialCaseFn<Result<T, E>> for MapSpecialCaseFnOk<F> +where + F: FnMut(T) -> U, +{ + type Out = Result<U, E>; + fn call(&mut self, t: Result<T, E>) -> Self::Out { + t.map(|v| self.0(v)) + } +} + +#[derive(Clone)] +pub struct MapSpecialCaseFnOk<F>(F); + +/// Create a new `MapOk` iterator. +pub fn map_ok<I, F, T, U, E>(iter: I, f: F) -> MapOk<I, F> +where + I: Iterator<Item = Result<T, E>>, + F: FnMut(T) -> U, +{ + MapSpecialCase { + iter, + f: MapSpecialCaseFnOk(f), + } +} + +/// An iterator adapter to apply `Into` conversion to each element. +/// +/// See [`.map_into()`](../trait.Itertools.html#method.map_into) for more information. +pub type MapInto<I, R> = MapSpecialCase<I, MapSpecialCaseFnInto<R>>; + +impl<T: Into<U>, U> MapSpecialCaseFn<T> for MapSpecialCaseFnInto<U> { + type Out = U; + fn call(&mut self, t: T) -> Self::Out { + t.into() + } +} + +#[derive(Clone)] +pub struct MapSpecialCaseFnInto<U>(PhantomData<U>); + +/// Create a new [`MapInto`](struct.MapInto.html) iterator. +pub fn map_into<I, R>(iter: I) -> MapInto<I, R> { + MapSpecialCase { + iter, + f: MapSpecialCaseFnInto(PhantomData), + } +} diff --git a/src/adaptors/mod.rs b/src/adaptors/mod.rs index 7d61f11..8a8697b 100644 --- a/src/adaptors/mod.rs +++ b/src/adaptors/mod.rs @@ -4,12 +4,17 @@ //! option. This file may not be copied, modified, or distributed //! except according to those terms. +mod coalesce; +mod map; mod multi_product; -#[cfg(feature = "use_std")] +pub use self::coalesce::*; +pub use self::map::{map_into, map_ok, MapInto, MapOk}; +#[allow(deprecated)] +pub use self::map::MapResults; +#[cfg(feature = "use_alloc")] pub use self::multi_product::*; use std::fmt; -use std::mem::replace; use std::iter::{Fuse, Peekable, FromIterator}; use std::marker::PhantomData; use crate::size_hint; @@ -32,13 +37,7 @@ pub struct Interleave<I, J> { /// /// `IntoIterator` enabled version of `i.interleave(j)`. /// -/// ``` -/// use itertools::interleave; -/// -/// for elt in interleave(&[1, 2, 3], &[2, 3, 4]) { -/// /* loop body */ -/// } -/// ``` +/// See [`.interleave()`](trait.Itertools.html#method.interleave) for more information. 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> @@ -56,7 +55,7 @@ impl<I, J> Iterator for Interleave<I, J> { type Item = I::Item; #[inline] - fn next(&mut self) -> Option<I::Item> { + fn next(&mut self) -> Option<Self::Item> { self.flag = !self.flag; if self.flag { match self.a.next() { @@ -113,23 +112,12 @@ impl<I, J> Iterator for InterleaveShortest<I, J> type Item = I::Item; #[inline] - fn next(&mut self) -> Option<I::Item> { - match self.phase { - false => match self.it0.next() { - None => None, - e => { - self.phase = true; - e - } - }, - true => match self.it1.next() { - None => None, - e => { - self.phase = false; - e - } - }, + fn next(&mut self) -> Option<Self::Item> { + let e = if self.phase { self.it1.next() } else { self.it0.next() }; + if e.is_some() { + self.phase = !self.phase; } + e } #[inline] @@ -221,7 +209,7 @@ impl<I> Iterator for PutBack<I> { type Item = I::Item; #[inline] - fn next(&mut self) -> Option<I::Item> { + fn next(&mut self) -> Option<Self::Item> { match self.top { None => self.iter.next(), ref mut some => some.take(), @@ -310,14 +298,14 @@ pub fn cartesian_product<I, J>(mut i: I, j: J) -> Product<I, J> } } - impl<I, J> Iterator for Product<I, J> where I: Iterator, J: Clone + Iterator, I::Item: Clone { type Item = (I::Item, J::Item); - fn next(&mut self) -> Option<(I::Item, J::Item)> { + + fn next(&mut self) -> Option<Self::Item> { let elt_b = match self.b.next() { None => { self.b = self.b_orig.clone(); @@ -401,15 +389,9 @@ impl<B, F, I> Iterator for Batching<I, F> { type Item = B; #[inline] - fn next(&mut self) -> Option<B> { + fn next(&mut self) -> Option<Self::Item> { (self.f)(&mut self.iter) } - - #[inline] - fn size_hint(&self) -> (usize, Option<usize>) { - // No information about closue behavior - (0, None) - } } /// An iterator adaptor that steps a number elements in the base iterator @@ -419,7 +401,7 @@ impl<B, F, I> Iterator for Batching<I, F> /// then skipping forward *n-1* elements. /// /// See [`.step()`](../trait.Itertools.html#method.step) for more information. -#[deprecated(note="Use std .step_by() instead", since="0.8")] +#[deprecated(note="Use std .step_by() instead", since="0.8.0")] #[allow(deprecated)] #[derive(Clone, Debug)] #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] @@ -448,7 +430,7 @@ impl<I> Iterator for Step<I> { type Item = I::Item; #[inline] - fn next(&mut self) -> Option<I::Item> { + fn next(&mut self) -> Option<Self::Item> { let elt = self.iter.next(); if self.skip > 0 { self.iter.nth(self.skip - 1); @@ -577,7 +559,7 @@ impl<I, J, F> Iterator for MergeBy<I, J, F> { type Item = I::Item; - fn next(&mut self) -> Option<I::Item> { + fn next(&mut self) -> Option<Self::Item> { let less_than = match self.fused { Some(lt) => lt, None => match (self.a.peek(), self.b.peek()) { @@ -606,203 +588,6 @@ impl<I, J, F> Iterator for MergeBy<I, J, F> } } -#[derive(Clone, Debug)] -pub struct CoalesceCore<I> - where I: Iterator -{ - iter: I, - last: Option<I::Item>, -} - -impl<I> CoalesceCore<I> - where I: Iterator -{ - fn next_with<F>(&mut self, mut f: F) -> Option<I::Item> - where F: FnMut(I::Item, I::Item) -> Result<I::Item, (I::Item, I::Item)> - { - // this fuses the iterator - let mut last = match self.last.take() { - None => return None, - Some(x) => x, - }; - for next in &mut self.iter { - match f(last, next) { - Ok(joined) => last = joined, - Err((last_, next_)) => { - self.last = Some(next_); - return Some(last_); - } - } - } - - Some(last) - } - - fn size_hint(&self) -> (usize, Option<usize>) { - let (low, hi) = size_hint::add_scalar(self.iter.size_hint(), - self.last.is_some() as usize); - ((low > 0) as usize, hi) - } -} - -/// An iterator adaptor that may join together adjacent elements. -/// -/// See [`.coalesce()`](../trait.Itertools.html#method.coalesce) for more information. -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct Coalesce<I, F> - where I: Iterator -{ - iter: CoalesceCore<I>, - f: F, -} - -impl<I: Clone, F: Clone> Clone for Coalesce<I, F> - where I: Iterator, - I::Item: Clone -{ - clone_fields!(iter, f); -} - -impl<I, F> fmt::Debug for Coalesce<I, F> - where I: Iterator + fmt::Debug, - I::Item: fmt::Debug, -{ - debug_fmt_fields!(Coalesce, iter); -} - -/// Create a new `Coalesce`. -pub fn coalesce<I, F>(mut iter: I, f: F) -> Coalesce<I, F> - where I: Iterator -{ - Coalesce { - iter: CoalesceCore { - last: iter.next(), - iter, - }, - f, - } -} - -impl<I, F> Iterator for Coalesce<I, F> - where I: Iterator, - F: FnMut(I::Item, I::Item) -> Result<I::Item, (I::Item, I::Item)> -{ - type Item = I::Item; - - fn next(&mut self) -> Option<I::Item> { - self.iter.next_with(&mut self.f) - } - - fn size_hint(&self) -> (usize, Option<usize>) { - self.iter.size_hint() - } -} - -/// 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. -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct DedupBy<I, Pred> - where I: Iterator -{ - iter: CoalesceCore<I>, - dedup_pred: Pred, -} - -pub trait DedupPredicate<T> { // TODO replace by Fn(&T, &T)->bool once Rust supports it - fn dedup_pair(&mut self, a: &T, b: &T) -> bool; -} - -#[derive(Clone)] -pub struct DedupEq; - -impl<T: PartialEq> DedupPredicate<T> for DedupEq { - fn dedup_pair(&mut self, a: &T, b: &T) -> bool { - a==b - } -} - -impl<T, F: FnMut(&T, &T)->bool> DedupPredicate<T> for F { - fn dedup_pair(&mut self, a: &T, b: &T) -> bool { - self(a, b) - } -} - -/// An iterator adaptor that removes repeated duplicates. -/// -/// See [`.dedup()`](../trait.Itertools.html#method.dedup) for more information. -pub type Dedup<I>=DedupBy<I, DedupEq>; - -impl<I: Clone, Pred: Clone> Clone for DedupBy<I, Pred> - where I: Iterator, - I::Item: Clone, -{ - clone_fields!(iter, dedup_pred); -} - -/// Create a new `DedupBy`. -pub fn dedup_by<I, Pred>(mut iter: I, dedup_pred: Pred) -> DedupBy<I, Pred> - where I: Iterator, -{ - DedupBy { - iter: CoalesceCore { - last: iter.next(), - iter, - }, - dedup_pred, - } -} - -/// Create a new `Dedup`. -pub fn dedup<I>(iter: I) -> Dedup<I> - where I: Iterator -{ - dedup_by(iter, DedupEq) -} - -impl<I, Pred> fmt::Debug for DedupBy<I, Pred> - where I: Iterator + fmt::Debug, - I::Item: fmt::Debug, -{ - debug_fmt_fields!(Dedup, iter); -} - -impl<I, Pred> Iterator for DedupBy<I, Pred> - where I: Iterator, - Pred: DedupPredicate<I::Item>, -{ - type Item = I::Item; - - fn next(&mut self) -> Option<I::Item> { - let ref mut dedup_pred = self.dedup_pred; - self.iter.next_with(|x, y| { - if dedup_pred.dedup_pair(&x, &y) { Ok(x) } else { Err((x, y)) } - }) - } - - fn size_hint(&self) -> (usize, Option<usize>) { - self.iter.size_hint() - } - - fn fold<Acc, G>(self, mut accum: Acc, mut f: G) -> Acc - where G: FnMut(Acc, Self::Item) -> Acc, - { - if let Some(mut last) = self.iter.last { - let mut dedup_pred = self.dedup_pred; - accum = self.iter.iter.fold(accum, |acc, elt| { - if dedup_pred.dedup_pair(&elt, &last) { - acc - } else { - f(acc, replace(&mut last, elt)) - } - }); - f(accum, last) - } else { - accum - } - } -} - /// An iterator adaptor that borrows from a `Clone`-able iterator /// to only pick off elements while the predicate returns `true`. /// @@ -832,7 +617,7 @@ impl<'a, I, F> Iterator for TakeWhileRef<'a, I, F> { type Item = I::Item; - fn next(&mut self) -> Option<I::Item> { + fn next(&mut self) -> Option<Self::Item> { let old = self.iter.clone(); match self.iter.next() { None => None, @@ -848,8 +633,7 @@ impl<'a, I, F> Iterator for TakeWhileRef<'a, I, F> } fn size_hint(&self) -> (usize, Option<usize>) { - let (_, hi) = self.iter.size_hint(); - (0, hi) + (0, self.iter.size_hint().1) } } @@ -873,7 +657,7 @@ impl<I, A> Iterator for WhileSome<I> { type Item = A; - fn next(&mut self) -> Option<A> { + fn next(&mut self) -> Option<Self::Item> { match self.iter.next() { None | Some(None) => None, Some(elt) => elt, @@ -881,8 +665,7 @@ impl<I, A> Iterator for WhileSome<I> } fn size_hint(&self) -> (usize, Option<usize>) { - let sh = self.iter.size_hint(); - (0, sh.1) + (0, self.iter.size_hint().1) } } @@ -1012,115 +795,163 @@ macro_rules! impl_tuple_combination { ) } -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); - -/// An iterator adapter to apply `Into` conversion to each element. +// This snippet generates the twelve `impl_tuple_combination!` invocations: +// use core::iter; +// use itertools::Itertools; +// +// for i in 2..=12 { +// println!("impl_tuple_combination!(Tuple{arity}Combination Tuple{prev}Combination; {tys}; {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); + +/// An iterator adapter to filter values within a nested `Result::Ok`. /// -/// See [`.map_into()`](../trait.Itertools.html#method.map_into) for more information. +/// See [`.filter_ok()`](../trait.Itertools.html#method.filter_ok) for more information. #[derive(Clone)] #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct MapInto<I, R> { +pub struct FilterOk<I, F> { iter: I, - _res: PhantomData<fn() -> R>, + f: F } -/// Create a new [`MapInto`](struct.MapInto.html) iterator. -pub fn map_into<I, R>(iter: I) -> MapInto<I, R> { - MapInto { +/// Create a new `FilterOk` iterator. +pub fn filter_ok<I, F, T, E>(iter: I, f: F) -> FilterOk<I, F> + where I: Iterator<Item = Result<T, E>>, + F: FnMut(&T) -> bool, +{ + FilterOk { iter, - _res: PhantomData, + f, } } -impl<I, R> Iterator for MapInto<I, R> - where I: Iterator, - I::Item: Into<R>, +impl<I, F, T, E> Iterator for FilterOk<I, F> + where I: Iterator<Item = Result<T, E>>, + F: FnMut(&T) -> bool, { - type Item = R; + type Item = Result<T, E>; - fn next(&mut self) -> Option<R> { - self.iter - .next() - .map(|i| i.into()) + fn next(&mut self) -> Option<Self::Item> { + loop { + match self.iter.next() { + Some(Ok(v)) => { + if (self.f)(&v) { + return Some(Ok(v)); + } + }, + Some(Err(e)) => return Some(Err(e)), + None => return None, + } + } } fn size_hint(&self) -> (usize, Option<usize>) { - self.iter.size_hint() + (0, self.iter.size_hint().1) } - fn fold<Acc, Fold>(self, init: Acc, mut fold_f: Fold) -> Acc + fn fold<Acc, Fold>(self, init: Acc, fold_f: Fold) -> Acc where Fold: FnMut(Acc, Self::Item) -> Acc, { - self.iter.fold(init, move |acc, v| fold_f(acc, v.into())) + let mut f = self.f; + self.iter.filter(|v| { + v.as_ref().map(&mut f).unwrap_or(true) + }).fold(init, fold_f) } -} -impl<I, R> DoubleEndedIterator for MapInto<I, R> - where I: DoubleEndedIterator, - I::Item: Into<R>, -{ - fn next_back(&mut self) -> Option<Self::Item> { - self.iter - .next_back() - .map(|i| i.into()) + fn collect<C>(self) -> C + where C: FromIterator<Self::Item> + { + let mut f = self.f; + self.iter.filter(|v| { + v.as_ref().map(&mut f).unwrap_or(true) + }).collect() } } -impl<I, R> ExactSizeIterator for MapInto<I, R> -where - I: ExactSizeIterator, - I::Item: Into<R>, -{} - -/// An iterator adapter to apply a transformation within a nested `Result`. +/// An iterator adapter to filter and apply a transformation on values within a nested `Result::Ok`. /// -/// See [`.map_results()`](../trait.Itertools.html#method.map_results) for more information. -#[derive(Clone)] +/// See [`.filter_map_ok()`](../trait.Itertools.html#method.filter_map_ok) for more information. #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct MapResults<I, F> { +pub struct FilterMapOk<I, F> { iter: I, f: F } -/// Create a new `MapResults` iterator. -pub fn map_results<I, F, T, U, E>(iter: I, f: F) -> MapResults<I, F> +fn transpose_result<T, E>(result: Result<Option<T>, E>) -> Option<Result<T, E>> { + match result { + Ok(Some(v)) => Some(Ok(v)), + Ok(None) => None, + Err(e) => Some(Err(e)), + } +} + +/// Create a new `FilterOk` iterator. +pub fn filter_map_ok<I, F, T, U, E>(iter: I, f: F) -> FilterMapOk<I, F> where I: Iterator<Item = Result<T, E>>, - F: FnMut(T) -> U, + F: FnMut(T) -> Option<U>, { - MapResults { + FilterMapOk { iter, f, } } -impl<I, F, T, U, E> Iterator for MapResults<I, F> +impl<I, F, T, U, E> Iterator for FilterMapOk<I, F> where I: Iterator<Item = Result<T, E>>, - F: FnMut(T) -> U, + F: FnMut(T) -> Option<U>, { type Item = Result<U, E>; fn next(&mut self) -> Option<Self::Item> { - self.iter.next().map(|v| v.map(&mut self.f)) + loop { + match self.iter.next() { + Some(Ok(v)) => { + if let Some(v) = (self.f)(v) { + return Some(Ok(v)); + } + }, + Some(Err(e)) => return Some(Err(e)), + None => return None, + } + } } fn size_hint(&self) -> (usize, Option<usize>) { - self.iter.size_hint() + (0, self.iter.size_hint().1) } - fn fold<Acc, Fold>(self, init: Acc, mut fold_f: Fold) -> Acc + fn fold<Acc, Fold>(self, init: Acc, fold_f: Fold) -> Acc where Fold: FnMut(Acc, Self::Item) -> Acc, { let mut f = self.f; - self.iter.fold(init, move |acc, v| fold_f(acc, v.map(&mut f))) + self.iter.filter_map(|v| { + transpose_result(v.map(&mut f)) + }).fold(init, fold_f) } fn collect<C>(self) -> C where C: FromIterator<Self::Item> { let mut f = self.f; - self.iter.map(move |v| v.map(&mut f)).collect() + self.iter.filter_map(|v| { + transpose_result(v.map(&mut f)) + }).collect() } } diff --git a/src/adaptors/multi_product.rs b/src/adaptors/multi_product.rs index 4a31713..6938014 100644 --- a/src/adaptors/multi_product.rs +++ b/src/adaptors/multi_product.rs @@ -1,8 +1,10 @@ -#![cfg(feature = "use_std")] +#![cfg(feature = "use_alloc")] use crate::size_hint; use crate::Itertools; +use alloc::vec::Vec; + #[derive(Clone)] /// An iterator adaptor that iterates over the cartesian product of /// multiple iterators of type `I`. @@ -161,7 +163,7 @@ impl<I> Iterator for MultiProduct<I> } fn count(self) -> usize { - if self.0.len() == 0 { + if self.0.is_empty() { return 0; } @@ -183,7 +185,7 @@ impl<I> Iterator for MultiProduct<I> fn size_hint(&self) -> (usize, Option<usize>) { // Not ExactSizeIterator because size may be larger than usize - if self.0.len() == 0 { + if self.0.is_empty() { return (0, Some(0)); } |