1use crate::{MarkdownExt, Share};
2use equt_md_frontmatter::FrontMatter;
3use std::cell::{Ref, RefCell};
4
5enum BeforeState {
6 Origin,
7 Pseudo,
8}
9
10#[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 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 t if (self.before)(&t) => {
68 self.state = BeforeState::Pseudo;
69 self.holded = Some(t);
70
71 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 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 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}