aboutsummaryrefslogtreecommitdiff
path: root/src/adaptors/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/adaptors/mod.rs')
-rw-r--r--src/adaptors/mod.rs421
1 files changed, 126 insertions, 295 deletions
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()
}
}