Skip to main content

orx_parallel/infallible/
xap_iter.rs

1use crate::infallible::Xap;
2use core::iter::Fuse;
3
4/// Iterator that applies an [`Xap`] to each input and yields its output values.
5///
6/// This is equivalent to `iter.flat_map(|i| xap.xap(i))` while keeping the
7/// transformation as a named iterator.
8#[must_use = "iterators are lazy and do nothing unless consumed"]
9pub struct XapIter<I, X>
10where
11    I: Iterator,
12    X: Xap<I = I::Item>,
13{
14    iter: Fuse<I>,
15    xap: X,
16    values: Option<<X::Values as IntoIterator>::IntoIter>,
17}
18
19impl<I, X> XapIter<I, X>
20where
21    I: Iterator,
22    X: Xap<I = I::Item>,
23{
24    /// Creates an iterator over the values produced by `xap` for each item in `iter`.
25    pub fn new(iter: I, xap: X) -> Self {
26        Self {
27            iter: iter.fuse(),
28            xap,
29            values: None,
30        }
31    }
32}
33
34impl<I, X> Iterator for XapIter<I, X>
35where
36    I: Iterator,
37    X: Xap<I = I::Item>,
38{
39    type Item = X::O;
40
41    #[inline]
42    fn next(&mut self) -> Option<Self::Item> {
43        loop {
44            if let Some(values) = &mut self.values
45                && let Some(value) = values.next()
46            {
47                return Some(value);
48            }
49
50            self.values = None;
51
52            let input = self.iter.next()?;
53            self.values = Some(self.xap.xap(input).into_iter());
54        }
55    }
56
57    #[inline]
58    fn size_hint(&self) -> (usize, Option<usize>) {
59        let (values_lower, values_upper) = self
60            .values
61            .as_ref()
62            .map_or((0, Some(0)), Iterator::size_hint);
63        let (iter_lower, iter_upper) = self.iter.size_hint();
64        let (transformed_lower, transformed_upper) =
65            <X::Size as crate::sizes::Size>::transformed_size_hint((iter_lower, iter_upper));
66
67        let lower = values_lower.saturating_add(transformed_lower);
68        let upper = values_upper.and_then(|values_upper| {
69            transformed_upper
70                .and_then(|transformed_upper| values_upper.checked_add(transformed_upper))
71        });
72        (lower, upper)
73    }
74
75    #[inline]
76    fn fold<B, F>(self, init: B, mut f: F) -> B
77    where
78        F: FnMut(B, Self::Item) -> B,
79    {
80        let mut result = init;
81        if let Some(values) = self.values {
82            result = values.fold(result, &mut f);
83        }
84        for input in self.iter {
85            result = self.xap.xap(input).into_iter().fold(result, &mut f);
86        }
87        result
88    }
89}