use crate::templating::TemplatePart;
#[derive(Default)]
pub struct TemplateIter {
current: usize,
parts: Vec<TemplatePart>,
}
impl TemplateIter {
pub fn new(parts: Vec<TemplatePart>) -> Self {
Self { current: 0, parts }
}
}
impl Iterator for TemplateIter {
type Item = &'static str;
fn next(&mut self) -> Option<Self::Item> {
let next = match self.parts.get_mut(self.current) {
None => return None,
Some(p) => match p {
TemplatePart::Str(s) => {
self.current += 1;
*s
}
#[allow(clippy::single_match_else)]
TemplatePart::Iter(i) => match i.next() {
Some(s) => s,
None => {
self.current += 1;
return self.next();
}
},
},
};
Some(next)
}
}
impl<T, const N: usize> From<[T; N]> for TemplateIter
where
T: Into<TemplatePart>,
{
fn from(value: [T; N]) -> Self {
Self::new(value.into_iter().map(Into::into).collect())
}
}
impl<T> From<Vec<T>> for TemplateIter
where
T: Into<TemplatePart>,
{
fn from(value: Vec<T>) -> Self {
Self::new(value.into_iter().map(Into::into).collect())
}
}
impl From<&'static str> for TemplateIter {
fn from(value: &'static str) -> Self {
Self::new(vec![value.into()])
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn next_handles_flat_parts() {
let iter: TemplateIter = ["1", "2", "3"].into();
let expected = vec!["1", "2", "3"];
let actual: Vec<&str> = iter.collect();
assert_eq!(actual, expected);
}
#[test]
fn next_handles_nested_parts() {
let iter = TemplateIter::new(vec![
"1".into(),
TemplatePart::Iter(["2", "3"].into()),
"4".into(),
TemplatePart::Iter(["5", "6"].into()),
"7".into(),
]);
let expected = vec!["1", "2", "3", "4", "5", "6", "7"];
let actual: Vec<&str> = iter.collect();
assert_eq!(actual, expected);
}
#[test]
fn next_is_safe_to_call_after_done() {
let mut iter: TemplateIter = ["1", "2", "3"].into();
for _ in iter.by_ref() {}
assert_eq!(iter.next(), None);
assert_eq!(iter.next(), None);
}
}