process_results/
raw_iter.rs

1use crate::errors::{ControlFlow, ErrorCollector};
2use crate::IterResult;
3
4/// An iterator adaptor wrapping an iterator with [`Result<T, E>`] elements and implements
5/// `Iterator<Item=T>`. Used only in [`Fallible::process`][`crate::Fallible::process`] and
6/// [`Fallible::process_no_discard`][crate::Fallible::process_no_discard].
7#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
8#[derive(Debug)]
9pub struct RawIter<'c, I, C> {
10    pub(crate) iter: I,
11    pub(crate) errors: &'c mut C,
12}
13
14impl<I, C> Iterator for RawIter<'_, I, C>
15where
16    I: IterResult,
17    C: ErrorCollector<I::Error>,
18{
19    type Item = I::Ok;
20
21    #[inline]
22    fn next(&mut self) -> Option<Self::Item> {
23        loop {
24            match self.iter.next() {
25                Some(Ok(item)) => {
26                    break item.into();
27                }
28                Some(Err(err)) => {
29                    if let ControlFlow::Break = self.errors.push_err(err) {
30                        break None;
31                    }
32                }
33                None => {
34                    break None;
35                }
36            }
37        }
38    }
39
40    #[inline]
41    fn fold<B, F>(self, init: B, f: F) -> B
42    where
43        Self: Sized,
44        F: FnMut(B, Self::Item) -> B,
45    {
46        let mut f = f; // to appease the IntelliJ Rust
47        let Self { mut iter, errors } = self;
48        let res = iter.try_fold(init, |acc, item| match item {
49            Ok(ok) => Ok(f(acc, ok)),
50            Err(err) => {
51                if let ControlFlow::Break = errors.push_err(err) {
52                    Err(acc)
53                } else {
54                    Ok(acc)
55                }
56            }
57        });
58        match res {
59            Ok(inner) => inner,
60            Err(inner) => inner,
61        }
62    }
63}
64
65#[cfg(test)]
66mod tests {
67    use crate::raw_iter::RawIter;
68    use arrayvec::ArrayVec;
69    use std::ops::Add;
70
71    #[test]
72    fn test() {
73        let v = vec![
74            Ok(1i64),
75            Err("Error1"),
76            Ok(4),
77            Err("Error2"),
78            Ok(-3),
79            Err("Error3"),
80            Ok(10),
81        ];
82        let mut col = ArrayVec::<&str, 2>::new();
83        let iter = RawIter {
84            iter: v.into_iter(),
85            errors: &mut col,
86        };
87        assert_eq!(iter.collect::<Vec<_>>(), vec![1, 4, -3]);
88        assert_eq!(col.into_inner().unwrap(), ["Error1", "Error2"]);
89    }
90
91    #[test]
92    fn test_fold() {
93        let v = vec![
94            Ok(1i64),
95            Err("Error1"),
96            Ok(4),
97            Err("Error2"),
98            Ok(-3),
99            Err("Error3"),
100            Ok(10),
101        ];
102        let mut col = ArrayVec::<&str, 2>::new();
103        let iter = RawIter {
104            iter: v.into_iter(),
105            errors: &mut col,
106        };
107        assert_eq!(iter.fold(0, i64::add), 2);
108        assert_eq!(col.into_inner().unwrap(), ["Error1", "Error2"]);
109    }
110}