Skip to content

Commit

Permalink
Add try_filter_map_results method.
Browse files Browse the repository at this point in the history
  • Loading branch information
gin-ahirsch committed Oct 29, 2019
1 parent 95342cb commit f9a21a4
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 0 deletions.
65 changes: 65 additions & 0 deletions src/adaptors/mod.rs
Expand Up @@ -1208,6 +1208,71 @@ impl<I, F, T, U, E> Iterator for TryMapResults<I, F>
}
}

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

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

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

fn next(&mut self) -> Option<Self::Item> {
loop {
match self.iter.next() {
Some(Ok(v)) => {
if let Some(v) = (self.f)(v).transpose() {
return Some(v);
}
},
Some(Err(e)) => return Some(Err(e)),
None => return None,
}
}
}

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| {
if let Some(v) = v.and_then(&mut f).transpose() {
fold_f(acc, v)
} else {
acc
}
})
}

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

/// An iterator adapter to get the positions of each element that matches a predicate.
///
/// See [`.positions()`](../trait.Itertools.html#method.positions) for more information.
Expand Down
19 changes: 19 additions & 0 deletions src/lib.rs
Expand Up @@ -59,6 +59,7 @@ pub mod structs {
Batching,
Step,
MapResults,
TryFilterMapResults,
TryMapResults,
Merge,
MergeBy,
Expand Down Expand Up @@ -654,6 +655,24 @@ pub trait Itertools : Iterator {
adaptors::try_map_results(self, f)
}

/// Return an iterator adaptor that filters and transforms every
/// `Result::Ok` value with the provided fallible closure.
/// `Result::Err` values in the original iterator are unchanged.
///
/// ```
/// use itertools::Itertools;
///
/// let input = vec![Ok(11), Ok(41), Err(false), Ok(i32::max_value())];
/// let it = input.into_iter().try_filter_map_results(|i| if i > 20 { Some(i.checked_add(1).ok_or(true)).transpose() } else { Ok(None) });
/// itertools::assert_equal(it, vec![Ok(42), Err(false), Err(true)]);
/// ```
fn try_filter_map_results<F, T, U, E>(self, f: F) -> TryFilterMapResults<Self, F>
where Self: Iterator<Item = Result<T, E>> + Sized,
F: FnMut(T) -> Result<Option<U>, E>,
{
adaptors::try_filter_map_results(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 f9a21a4

Please sign in to comment.