equt_md_ext/
before.rs

1use crate::{MarkdownExt, Share};
2use equt_md_frontmatter::FrontMatter;
3use std::cell::{Ref, RefCell};
4
5enum BeforeState {
6    Origin,
7    Pseudo,
8}
9
10/// An iterator places events before the first occurence of certain event.
11///
12/// This `struct` is created by [`before`] method on [`MarkdownExt`].
13///
14/// [`before`]: trait.MarkdownExt.html#method.before
15/// [`MarkdownExt`]: trait.MarkdownExt.html
16#[must_use = "iterators are lazy and do nothing unless consumed"]
17#[derive(new)]
18pub struct Before<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    before: P,
29    // Create pseudo iter
30    f: F,
31
32    #[new(default)]
33    pseudo: Option<S>,
34    #[new(value = "BeforeState::Origin")]
35    state: BeforeState,
36    #[new(default)]
37    holded: Option<I::Item>,
38}
39
40impl<I, S, G, F, P, T> MarkdownExt<T> for Before<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 Before<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            BeforeState::Origin => match self.iter.next()? {
66                // Current item match the predication, hold it and call self.
67                t if (self.before)(&t) => {
68                    self.state = BeforeState::Pseudo;
69                    self.holded = Some(t);
70
71                    // Since we've already hand over to Pseudo, it's safe to call itself.
72                    self.next()
73                }
74                otherwise => Some(otherwise),
75            },
76            BeforeState::Pseudo => match self.pseudo.as_mut() {
77                Some(iter) => match iter.next() {
78                    node @ Some(_) => node,
79                    // We've consumed the pseudo iter, now take the holded value.
80                    None => {
81                        self.state = BeforeState::Origin;
82                        self.holded.take()
83                    }
84                },
85                None => {
86                    self.pseudo = Some(
87                        (self.f)(self.frontmatter.upgrade().unwrap().borrow()).into_iter(),
88                    );
89                    // Unwrap the previous created iter and call next on it.
90                    // NOTE: If that iter is empty, it might caused unexpected
91                    // termination for our iterator.
92                    self.pseudo.as_mut().unwrap().next().or_else(|| {
93                        self.state = BeforeState::Origin;
94                        self.holded.take()
95                    })
96                }
97            },
98        }
99    }
100}
101
102#[cfg(test)]
103mod test {
104    use super::*;
105    use std::iter::{empty, once};
106    use std::rc::Rc;
107
108    #[test]
109    fn only_once() {
110        assert_eq!(
111            Before::new(
112                Rc::new(RefCell::new(None)).into(),
113                1..5,
114                |&n| n % 2 == 0,
115                |_| once(0)
116            )
117            .collect::<Vec<_>>(),
118            vec![1, 0, 2, 3, 4],
119        );
120    }
121
122    #[test]
123    fn empty_pseudo() {
124        assert_eq!(
125            Before::new(
126                Rc::new(RefCell::new(None)).into(),
127                1..5,
128                |&n| n % 2 == 0,
129                |_| empty()
130            )
131            .collect::<Vec<_>>(),
132            vec![1, 2, 3, 4],
133        );
134    }
135
136    #[test]
137    fn never_match() {
138        assert_eq!(
139            Before::new(
140                Rc::new(RefCell::new(None)).into(),
141                1..5,
142                |&n| n % 2 == 5,
143                |_| empty()
144            )
145            .collect::<Vec<_>>(),
146            vec![1, 2, 3, 4],
147        );
148    }
149
150    #[test]
151    fn lazy() {
152        assert!(Before::new(
153            Rc::new(RefCell::new(None)).into(),
154            1..5,
155            |&n| n % 2 == 5,
156            |_| empty()
157        )
158        .pseudo
159        .is_none());
160    }
161}