equt_md_ext/
after.rs

1use crate::{MarkdownExt, Share};
2use equt_md_frontmatter::FrontMatter;
3use std::cell::{Ref, RefCell};
4
5enum AfterState {
6    Origin,
7    Pseudo,
8}
9
10/// An iterator places events after the first occurrence of certain event.
11///
12/// This `struct` is created by [`after`] method on [`MarkdownExt`].
13///
14/// [`after`]: trait.MarkdownExt.html#method.after
15/// [`MarkdownExt`]: trait.MarkdownExt.html
16#[must_use = "iterators are lazy and do nothing unless consumed"]
17#[derive(new)]
18pub struct After<I, S, G, F, P, T>
19where
20    I: Iterator<Item = T>,
21    S: Iterator<Item = T>,
22    G: IntoIterator<Item = T, IntoIter = S>,
23    F: Fn(Ref<Option<FrontMatter>>) -> G,
24    P: Fn(&T) -> bool,
25{
26    frontmatter: Share<RefCell<Option<FrontMatter>>>,
27    iter: I,
28    after: P,
29
30    // Create pseudo iter
31    f: F,
32
33    // Delay its construction until needed
34    #[new(default)]
35    pseudo: Option<S>,
36    #[new(value = "AfterState::Origin")]
37    state: AfterState,
38}
39
40impl<I, S, G, F, P, T> MarkdownExt<T> for After<I, S, G, F, P, T>
41where
42    I: Iterator<Item = T>,
43    S: Iterator<Item = T>,
44    G: IntoIterator<Item = T, IntoIter = S>,
45    F: Fn(Ref<Option<FrontMatter>>) -> G,
46    P: Fn(&T) -> bool,
47{
48    fn frontmatter(&mut self) -> &mut Share<RefCell<Option<FrontMatter>>> {
49        &mut self.frontmatter
50    }
51}
52
53impl<I, S, G, F, P, T> Iterator for After<I, S, G, F, P, T>
54where
55    I: Iterator<Item = T>,
56    S: Iterator<Item = T>,
57    G: IntoIterator<Item = T, IntoIter = S>,
58    F: Fn(Ref<Option<FrontMatter>>) -> G,
59    P: Fn(&T) -> bool,
60{
61    type Item = I::Item;
62
63    fn next(&mut self) -> Option<Self::Item> {
64        match self.state {
65            AfterState::Origin => match self.iter.next() {
66                // If current item match the predication, return it and switch to
67                // pseudo iterator.
68                Some(t) if (self.after)(&t) => {
69                    self.state = AfterState::Pseudo;
70                    Some(t)
71                }
72                otherwise => otherwise,
73            },
74            // We need to check if the pseudo iterator has been created or not.
75            AfterState::Pseudo => match self.pseudo.as_mut() {
76                Some(iter) => match iter.next() {
77                    node @ Some(_) => node,
78                    // The whole pseudo iterator has been consumed, hand back to
79                    // the original iterator.
80                    None => {
81                        self.state = AfterState::Origin;
82                        self.iter.next()
83                    }
84                },
85                None => {
86                    self.pseudo = Some(
87                        (self.f)(self.frontmatter.upgrade().unwrap().borrow()).into_iter(),
88                    );
89
90                    // Since we've written something into self.pseudo, it would definitely
91                    // go to the Some arm above
92                    self.next()
93                }
94            },
95        }
96    }
97}
98
99#[cfg(test)]
100mod test {
101    use super::*;
102    use std::iter::{empty, once};
103    use std::rc::Rc;
104
105    #[test]
106    fn only_once() {
107        assert_eq!(
108            After::new(
109                Rc::new(RefCell::new(None)).into(),
110                1..5,
111                |&n| n % 2 == 0,
112                |_| once(0)
113            )
114            .collect::<Vec<_>>(),
115            vec![1, 2, 0, 3, 4]
116        );
117    }
118
119    #[test]
120    fn empty_pseudo() {
121        assert_eq!(
122            After::new(
123                Rc::new(RefCell::new(None)).into(),
124                1..5,
125                |&n| n % 2 == 0,
126                |_| empty()
127            )
128            .collect::<Vec<_>>(),
129            vec![1, 2, 3, 4]
130        );
131    }
132
133    #[test]
134    fn never_match() {
135        assert_eq!(
136            After::new(
137                Rc::new(RefCell::new(None)).into(),
138                1..5,
139                |&n| n % 2 == 5,
140                |_| once(0)
141            )
142            .collect::<Vec<_>>(),
143            vec![1, 2, 3, 4]
144        );
145    }
146
147    #[test]
148    fn lazy() {
149        assert!(After::new(
150                Rc::new(RefCell::new(None)).into(),
151            1..5,
152            |&n| n % 10 == 0,
153            |_| once(0)
154        )
155        .pseudo
156        .is_none());
157    }
158}