Skip to main content

fluent_iterable/ops/
fallback.rs

1//! Adapters for the fallback operations.
2
3/// Fallback adapter behind [`FluentIter::when_empty`].
4#[derive(Debug)]
5pub struct WhenEmpty<I, F>
6where
7    I: Iterator,
8    F: IntoIterator<Item = I::Item>,
9{
10    pub(crate) phase: WhenEmptyPhase<I, F::IntoIter>,
11    pub(crate) fallback: Option<F>,
12}
13
14#[derive(Debug)]
15pub(crate) enum WhenEmptyPhase<S, T> {
16    /// Still pulling from the source; flag remembers whether it yielded yet.
17    Source(S, bool),
18    /// Source ran out without yielding: draining the fallback.
19    Fallback(T),
20    /// Done — `Iterator::next` must keep returning `None`.
21    Done,
22}
23
24impl<I, F> Iterator for WhenEmpty<I, F>
25where
26    I: Iterator,
27    F: IntoIterator<Item = I::Item>,
28{
29    type Item = I::Item;
30
31    fn next(&mut self) -> Option<I::Item> {
32        match &mut self.phase {
33            WhenEmptyPhase::Source(source, yielded) => match source.next() {
34                Some(item) => {
35                    *yielded = true;
36                    Some(item)
37                }
38                None => {
39                    if *yielded {
40                        self.phase = WhenEmptyPhase::Done;
41                        return None;
42                    }
43                    match self.fallback.take() {
44                        Some(fallback) => {
45                            let mut iter = fallback.into_iter();
46                            let item = iter.next();
47                            self.phase = WhenEmptyPhase::Fallback(iter);
48                            item
49                        }
50                        None => {
51                            self.phase = WhenEmptyPhase::Done;
52                            None
53                        }
54                    }
55                }
56            },
57            WhenEmptyPhase::Fallback(iter) => iter.next(),
58            WhenEmptyPhase::Done => None,
59        }
60    }
61}
62/// Finite repetition adapter behind [`FluentIter::repeat`].
63///
64/// The first pass streams the source while caching; passes 2..=n replay the
65/// cache. With `times == 0` the source is never consumed at all.
66#[derive(Debug)]
67pub struct Repeat<I: Iterator>
68where
69    I::Item: Clone,
70{
71    pub(crate) source: I,
72    pub(crate) cache: Vec<I::Item>,
73    pub(crate) times: usize,
74    /// 0 while streaming the first pass, then the replay round index.
75    pub(crate) round: usize,
76    pub(crate) pos: usize,
77}
78
79impl<I> Iterator for Repeat<I>
80where
81    I: Iterator,
82    I::Item: Clone,
83{
84    type Item = I::Item;
85
86    fn next(&mut self) -> Option<I::Item> {
87        if self.times == 0 {
88            return None;
89        }
90        loop {
91            if self.round == 0 {
92                if let Some(item) = self.source.next() {
93                    self.cache.push(item.clone());
94                    return Some(item);
95                }
96                self.round = 1;
97                self.pos = 0;
98            }
99            if self.round >= self.times {
100                return None;
101            }
102            if let Some(item) = self.cache.get(self.pos) {
103                self.pos += 1;
104                return Some(item.clone());
105            }
106            self.round += 1;
107            self.pos = 0;
108        }
109    }
110}