Skip to content

Commit

Permalink
Add map_and_then method.
Browse files Browse the repository at this point in the history
  • Loading branch information
pthariensflame committed Jul 6, 2020
1 parent 7565519 commit 389acab
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 0 deletions.
50 changes: 50 additions & 0 deletions src/adaptors/mod.rs
Expand Up @@ -1260,6 +1260,56 @@ impl<I, F, T, U, E> Iterator for FilterMapOk<I, F>
}).collect()
}
}

/// An iterator adapter to apply a fallible transformation within a nested `Result`.
///
/// See [`.map_and_then()`](../trait.Itertools.html#method.map_and_then) for more information.
#[derive(Clone)]
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct MapAndThen<I, F> {
iter: I,
f: F
}

/// Create a new `MapAndThen` iterator.
pub fn map_and_then<I, F, T, U, E>(iter: I, f: F) -> MapAndThen<I, F>
where I: Iterator<Item = Result<T, E>>,
F: FnMut(T) -> Result<U, E>
{
MapAndThen {
iter: iter,
f: f,
}
}

impl<I, F, T, U, E> Iterator for MapAndThen<I, F>
where I: Iterator<Item = Result<T, E>>,
F: FnMut(T) -> Result<U, E>
{
type Item = Result<U, E>;

fn next(&mut self) -> Option<Self::Item> {
self.iter.next().map(|v| v.and_then(&mut self.f))
}

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, v.and_then(&mut f)))
}

fn collect<C>(self) -> C
where C: FromIterator<Self::Item>
{
let mut f = self.f;
self.iter.map(move |v| v.and_then(&mut f)).collect()
}
}

/// An iterator adapter to get the positions of each element that matches a predicate.
///
Expand Down
19 changes: 19 additions & 0 deletions src/lib.rs
Expand Up @@ -89,6 +89,7 @@ pub mod structs {
Batching,
MapInto,
MapOk,
MapAndThen,
Merge,
MergeBy,
TakeWhileRef,
Expand Down Expand Up @@ -811,6 +812,24 @@ pub trait Itertools : Iterator {
adaptors::filter_map_ok(self, f)
}

/// Return an iterator adaptor that applies the provided fallible
/// closure to every `Result::Ok` value. `Result::Err` values in
/// the original iterator are unchanged.
///
/// ```
/// use itertools::Itertools;
///
/// let input = vec![Ok(41), Err(false), Ok(i32::max_value())];
/// let it = input.into_iter().map_and_then(|i| i.checked_add(1).ok_or(true));
/// itertools::assert_equal(it, vec![Ok(42), Err(false), Err(true)]);
/// ```
fn map_and_then<F, T, U, E>(self, f: F) -> MapAndThen<Self, F>
where Self: Iterator<Item = Result<T, E>> + Sized,
F: FnMut(T) -> Result<U, E>,
{
adaptors::map_and_then(self, f)
}

/// Return an iterator adaptor that merges the two base iterators in
/// ascending order. If both base iterators are sorted (ascending), the
/// result is sorted.
Expand Down

0 comments on commit 389acab

Please sign in to comment.