use super::Pattern;
pub struct Chunks<'a, P>
where
P: Iterator<Item = Pattern>,
{
s: &'a str,
indices: Indices<'a, P>,
}
struct Indices<'a, P>
where
P: Iterator<Item = Pattern>,
{
lines: std::iter::Enumerate<std::str::Lines<'a>>,
patterns: P,
pattern: Pattern,
start: usize,
}
impl<'a, P> Indices<'a, P>
where
P: Iterator<Item = Pattern>,
{
fn new<I>(s: &'a str, patterns: I) -> Option<Self>
where
I: IntoIterator<IntoIter = P, Item = Pattern>,
{
let mut patterns = patterns.into_iter();
let pattern = match patterns.next() {
Some(p) => p,
None => return None,
};
Some(Indices {
lines: s.lines().enumerate(),
patterns,
pattern,
start: 0,
})
}
}
impl<'a, P> Chunks<'a, P>
where
P: Iterator<Item = Pattern>,
{
pub fn new<I>(s: &'a str, patterns: I) -> Option<Self>
where
I: IntoIterator<Item = Pattern, IntoIter = P>,
{
let indices = Indices::new(&s, patterns)?;
Some(Chunks { s, indices })
}
}
impl<'a, P> Iterator for Chunks<'a, P>
where
P: Iterator<Item = Pattern>,
{
type Item = String;
fn next(&mut self) -> Option<Self::Item> {
if let Some((start, end)) = self.indices.next() {
let lines: Vec<&str> = self.s.lines().skip(start).take(end).collect();
Some(lines.join("\n"))
} else {
None
}
}
}
impl<'a, P> Iterator for Indices<'a, P>
where
P: Iterator<Item = Pattern>,
{
type Item = (usize, usize);
fn next(&mut self) -> Option<Self::Item> {
while let Some((i, text)) = self.lines.next() {
if let Some((end, write)) = self.pattern.find(self.start, i, text) {
let start = self.start;
self.start = end;
self.pattern = match &self.pattern {
Pattern::Match { repeat: 0, .. } | Pattern::NLines { repeat: 0, .. } | Pattern::UntilLine(_) => {
match self.patterns.next() {
Some(p) => p,
None => break,
}
},
Pattern::Match {
re,
repeat,
offset,
skip,
} => Pattern::Match {
re: re.clone(),
repeat: repeat - 1,
offset: *offset,
skip: *skip,
},
Pattern::NLines { n, repeat } => Pattern::NLines {
n: *n,
repeat: repeat - 1,
},
};
if write {
return Some((start, end));
} else {
return self.next();
}
};
}
None
}
}