itertools/
process_results_impl.rs

1#[cfg(doc)]
2use crate::Itertools;
3
4/// An iterator that produces only the `T` values as long as the
5/// inner iterator produces `Ok(T)`.
6///
7/// Used by [`process_results`](crate::process_results), see its docs
8/// for more information.
9#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
10#[derive(Debug)]
11pub struct ProcessResults<'a, I, E: 'a> {
12    error: &'a mut Result<(), E>,
13    iter: I,
14}
15
16impl<I, E> ProcessResults<'_, I, E> {
17    #[inline(always)]
18    fn next_body<T>(&mut self, item: Option<Result<T, E>>) -> Option<T> {
19        match item {
20            Some(Ok(x)) => Some(x),
21            Some(Err(e)) => {
22                *self.error = Err(e);
23                None
24            }
25            None => None,
26        }
27    }
28}
29
30impl<I, T, E> Iterator for ProcessResults<'_, I, E>
31where
32    I: Iterator<Item = Result<T, E>>,
33{
34    type Item = T;
35
36    fn next(&mut self) -> Option<Self::Item> {
37        let item = self.iter.next();
38        self.next_body(item)
39    }
40
41    fn size_hint(&self) -> (usize, Option<usize>) {
42        (0, self.iter.size_hint().1)
43    }
44
45    fn fold<B, F>(mut self, init: B, mut f: F) -> B
46    where
47        Self: Sized,
48        F: FnMut(B, Self::Item) -> B,
49    {
50        let error = self.error;
51        self.iter
52            .try_fold(init, |acc, opt| match opt {
53                Ok(x) => Ok(f(acc, x)),
54                Err(e) => {
55                    *error = Err(e);
56                    Err(acc)
57                }
58            })
59            .unwrap_or_else(|e| e)
60    }
61}
62
63impl<I, T, E> DoubleEndedIterator for ProcessResults<'_, I, E>
64where
65    I: Iterator<Item = Result<T, E>>,
66    I: DoubleEndedIterator,
67{
68    fn next_back(&mut self) -> Option<Self::Item> {
69        let item = self.iter.next_back();
70        self.next_body(item)
71    }
72
73    fn rfold<B, F>(mut self, init: B, mut f: F) -> B
74    where
75        F: FnMut(B, Self::Item) -> B,
76    {
77        let error = self.error;
78        self.iter
79            .try_rfold(init, |acc, opt| match opt {
80                Ok(x) => Ok(f(acc, x)),
81                Err(e) => {
82                    *error = Err(e);
83                    Err(acc)
84                }
85            })
86            .unwrap_or_else(|e| e)
87    }
88}
89
90/// “Lift” a function of the values of an iterator so that it can process
91/// an iterator of `Result` values instead.
92///
93/// [`IntoIterator`] enabled version of [`Itertools::process_results`].
94pub fn process_results<I, F, T, E, R>(iterable: I, processor: F) -> Result<R, E>
95where
96    I: IntoIterator<Item = Result<T, E>>,
97    F: FnOnce(ProcessResults<I::IntoIter, E>) -> R,
98{
99    let iter = iterable.into_iter();
100    let mut error = Ok(());
101
102    let result = processor(ProcessResults {
103        error: &mut error,
104        iter,
105    });
106
107    error.map(|_| result)
108}