use crate::{MarkdownExt, Share};
use equt_md_frontmatter::FrontMatter;
use std::cell::{Ref, RefCell};
enum BeforeState {
Origin,
Pseudo,
}
#[must_use = "iterators are lazy and do nothing unless consumed"]
#[derive(new)]
pub struct Before<I, S, G, F, P, T>
where
I: Iterator<Item = T>,
S: Iterator<Item = T>,
G: IntoIterator<Item = T, IntoIter = S>,
F: Fn(Ref<Option<FrontMatter>>) -> G,
P: Fn(&T) -> bool,
{
frontmatter: Share<RefCell<Option<FrontMatter>>>,
iter: I,
before: P,
f: F,
#[new(default)]
pseudo: Option<S>,
#[new(value = "BeforeState::Origin")]
state: BeforeState,
#[new(default)]
holded: Option<I::Item>,
}
impl<I, S, G, F, P, T> MarkdownExt<T> for Before<I, S, G, F, P, T>
where
I: Iterator<Item = T>,
S: Iterator<Item = T>,
G: IntoIterator<Item = T, IntoIter = S>,
F: Fn(Ref<Option<FrontMatter>>) -> G,
P: Fn(&T) -> bool,
{
fn frontmatter(&mut self) -> &mut Share<RefCell<Option<FrontMatter>>> {
&mut self.frontmatter
}
}
impl<I, S, G, F, P, T> Iterator for Before<I, S, G, F, P, T>
where
I: Iterator<Item = T>,
S: Iterator<Item = T>,
G: IntoIterator<Item = T, IntoIter = S>,
F: Fn(Ref<Option<FrontMatter>>) -> G,
P: Fn(&T) -> bool,
{
type Item = I::Item;
fn next(&mut self) -> Option<Self::Item> {
match self.state {
BeforeState::Origin => match self.iter.next()? {
t if (self.before)(&t) => {
self.state = BeforeState::Pseudo;
self.holded = Some(t);
self.next()
}
otherwise => Some(otherwise),
},
BeforeState::Pseudo => match self.pseudo.as_mut() {
Some(iter) => match iter.next() {
node @ Some(_) => node,
None => {
self.state = BeforeState::Origin;
self.holded.take()
}
},
None => {
self.pseudo = Some(
(self.f)(self.frontmatter.upgrade().unwrap().borrow()).into_iter(),
);
self.pseudo.as_mut().unwrap().next().or_else(|| {
self.state = BeforeState::Origin;
self.holded.take()
})
}
},
}
}
}
#[cfg(test)]
mod test {
use super::*;
use std::iter::{empty, once};
use std::rc::Rc;
#[test]
fn only_once() {
assert_eq!(
Before::new(
Rc::new(RefCell::new(None)).into(),
1..5,
|&n| n % 2 == 0,
|_| once(0)
)
.collect::<Vec<_>>(),
vec![1, 0, 2, 3, 4],
);
}
#[test]
fn empty_pseudo() {
assert_eq!(
Before::new(
Rc::new(RefCell::new(None)).into(),
1..5,
|&n| n % 2 == 0,
|_| empty()
)
.collect::<Vec<_>>(),
vec![1, 2, 3, 4],
);
}
#[test]
fn never_match() {
assert_eq!(
Before::new(
Rc::new(RefCell::new(None)).into(),
1..5,
|&n| n % 2 == 5,
|_| empty()
)
.collect::<Vec<_>>(),
vec![1, 2, 3, 4],
);
}
#[test]
fn lazy() {
assert!(Before::new(
Rc::new(RefCell::new(None)).into(),
1..5,
|&n| n % 2 == 5,
|_| empty()
)
.pseudo
.is_none());
}
}