1use crate::{MarkdownExt, Share};
2use equt_md_frontmatter::FrontMatter;
3use std::cell::{Ref, RefCell};
4
5enum AfterState {
6 Origin,
7 Pseudo,
8}
9
10#[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 f: F,
32
33 #[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 Some(t) if (self.after)(&t) => {
69 self.state = AfterState::Pseudo;
70 Some(t)
71 }
72 otherwise => otherwise,
73 },
74 AfterState::Pseudo => match self.pseudo.as_mut() {
76 Some(iter) => match iter.next() {
77 node @ Some(_) => node,
78 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 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}