equt_md_ext/
within.rs

1use crate::{MarkdownExt, Share};
2use equt_md_frontmatter::FrontMatter;
3use std::cell::{Ref, RefCell};
4
5enum WithinState {
6    External,
7    Internal,
8}
9
10/// An iterator maps function upon events within two specific events.
11///
12/// This `struct` is created by [`within`] method on [`MarkdownExt`].
13///
14/// [`within`]: trait.MarkdownExt.html#method.within
15/// [`MarkdownExt`]: trait.MarkdownExt.html
16#[derive(new)]
17pub struct Within<I, P, Q, F, T>
18where
19    I: Iterator<Item = T>,
20    P: Fn(&T) -> bool,
21    Q: Fn(&T) -> bool,
22    F: FnMut(Ref<Option<FrontMatter>>, T) -> Option<T>,
23{
24    frontmatter: Share<RefCell<Option<FrontMatter>>>,
25    iter: I,
26    start: P,
27    end: Q,
28    f: F,
29
30    #[new(value = "WithinState::External")]
31    state: WithinState,
32}
33
34impl<I, P, Q, F, T> Iterator for Within<I, P, Q, F, T>
35where
36    I: Iterator<Item = T>,
37    P: Fn(&T) -> bool,
38    Q: Fn(&T) -> bool,
39    F: FnMut(Ref<Option<FrontMatter>>, T) -> Option<T>,
40{
41    type Item = T;
42
43    fn next(&mut self) -> Option<Self::Item> {
44        match self.state {
45            WithinState::External => match self.iter.next() {
46                Some(e) if (self.start)(&e) => {
47                    self.state = WithinState::Internal;
48                    Some(e)
49                }
50                node => node,
51            },
52            WithinState::Internal => match self.iter.next() {
53                Some(e) if (self.end)(&e) => {
54                    self.state = WithinState::External;
55                    Some(e)
56                }
57                Some(e) => match (self.f)(self.frontmatter.upgrade().unwrap().borrow(), e) {
58                    node @ Some(_) => node,
59                    None => self.next(),
60                },
61                node => node,
62            },
63        }
64    }
65}
66
67impl<I, P, Q, F, T> MarkdownExt<T> for Within<I, P, Q, F, T>
68where
69    I: Iterator<Item = T>,
70    P: Fn(&T) -> bool,
71    Q: Fn(&T) -> bool,
72    F: FnMut(Ref<Option<FrontMatter>>, T) -> Option<T>,
73{
74    fn frontmatter(&mut self) -> &mut Share<RefCell<Option<FrontMatter>>> {
75        &mut self.frontmatter
76    }
77}
78
79#[cfg(test)]
80mod test {
81    use super::*;
82    use std::rc::Rc;
83
84    #[test]
85    fn normal() {
86        assert_eq!(
87            Within::new(
88                Rc::new(RefCell::new(None)).into(),
89                1..9,
90                |&n| n == 3,
91                |&n| n == 6,
92                |_, n| Some(n + 1)
93            ).collect::<Vec<_>>(),
94            vec![1, 2, 3, 5, 6, 6, 7, 8]
95        );
96    }
97}