Skip to content

Commit 389acab

Browse files
Add map_and_then method.
1 parent 7565519 commit 389acab

File tree

2 files changed

+69
-0
lines changed

2 files changed

+69
-0
lines changed

src/adaptors/mod.rs

+50
Original file line numberDiff line numberDiff line change
@@ -1260,6 +1260,56 @@ impl<I, F, T, U, E> Iterator for FilterMapOk<I, F>
12601260
}).collect()
12611261
}
12621262
}
1263+
1264+
/// An iterator adapter to apply a fallible transformation within a nested `Result`.
1265+
///
1266+
/// See [`.map_and_then()`](../trait.Itertools.html#method.map_and_then) for more information.
1267+
#[derive(Clone)]
1268+
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
1269+
pub struct MapAndThen<I, F> {
1270+
iter: I,
1271+
f: F
1272+
}
1273+
1274+
/// Create a new `MapAndThen` iterator.
1275+
pub fn map_and_then<I, F, T, U, E>(iter: I, f: F) -> MapAndThen<I, F>
1276+
where I: Iterator<Item = Result<T, E>>,
1277+
F: FnMut(T) -> Result<U, E>
1278+
{
1279+
MapAndThen {
1280+
iter: iter,
1281+
f: f,
1282+
}
1283+
}
1284+
1285+
impl<I, F, T, U, E> Iterator for MapAndThen<I, F>
1286+
where I: Iterator<Item = Result<T, E>>,
1287+
F: FnMut(T) -> Result<U, E>
1288+
{
1289+
type Item = Result<U, E>;
1290+
1291+
fn next(&mut self) -> Option<Self::Item> {
1292+
self.iter.next().map(|v| v.and_then(&mut self.f))
1293+
}
1294+
1295+
fn size_hint(&self) -> (usize, Option<usize>) {
1296+
self.iter.size_hint()
1297+
}
1298+
1299+
fn fold<Acc, Fold>(self, init: Acc, mut fold_f: Fold) -> Acc
1300+
where Fold: FnMut(Acc, Self::Item) -> Acc,
1301+
{
1302+
let mut f = self.f;
1303+
self.iter.fold(init, move |acc, v| fold_f(acc, v.and_then(&mut f)))
1304+
}
1305+
1306+
fn collect<C>(self) -> C
1307+
where C: FromIterator<Self::Item>
1308+
{
1309+
let mut f = self.f;
1310+
self.iter.map(move |v| v.and_then(&mut f)).collect()
1311+
}
1312+
}
12631313

12641314
/// An iterator adapter to get the positions of each element that matches a predicate.
12651315
///

src/lib.rs

+19
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ pub mod structs {
8989
Batching,
9090
MapInto,
9191
MapOk,
92+
MapAndThen,
9293
Merge,
9394
MergeBy,
9495
TakeWhileRef,
@@ -811,6 +812,24 @@ pub trait Itertools : Iterator {
811812
adaptors::filter_map_ok(self, f)
812813
}
813814

815+
/// Return an iterator adaptor that applies the provided fallible
816+
/// closure to every `Result::Ok` value. `Result::Err` values in
817+
/// the original iterator are unchanged.
818+
///
819+
/// ```
820+
/// use itertools::Itertools;
821+
///
822+
/// let input = vec![Ok(41), Err(false), Ok(i32::max_value())];
823+
/// let it = input.into_iter().map_and_then(|i| i.checked_add(1).ok_or(true));
824+
/// itertools::assert_equal(it, vec![Ok(42), Err(false), Err(true)]);
825+
/// ```
826+
fn map_and_then<F, T, U, E>(self, f: F) -> MapAndThen<Self, F>
827+
where Self: Iterator<Item = Result<T, E>> + Sized,
828+
F: FnMut(T) -> Result<U, E>,
829+
{
830+
adaptors::map_and_then(self, f)
831+
}
832+
814833
/// Return an iterator adaptor that merges the two base iterators in
815834
/// ascending order. If both base iterators are sorted (ascending), the
816835
/// result is sorted.

0 commit comments

Comments
 (0)