use pulldown_cmark::{Event, Tag};
use std::collections::VecDeque;
pub struct InlineImages<'a, I: Iterator<Item = Event<'a>>> {
parser: I,
buffer: VecDeque<Event<'a>>,
}
impl<'a, I: Iterator<Item = Event<'a>>> InlineImages<'a, I> {
pub fn new(parser: I) -> Self {
InlineImages {
parser,
buffer: VecDeque::new(),
}
}
fn buffer_until_image_end(&mut self) {
loop {
let event = self
.parser
.next()
.expect("parser ended with unclosed image");
if let Event::End(Tag::Image(..)) = event {
self.buffer.push_back(event);
break;
}
self.buffer.push_back(event);
}
}
fn on_paragraph_start(&mut self) -> Event<'a> {
let event = self
.parser
.next()
.expect("parser ended with unclosed paragraph");
if let Event::Start(Tag::Image(..)) = event {
self.buffer.push_back(event);
self.buffer_until_image_end();
let next = self
.parser
.next()
.expect("parser ended with unclosed paragraph");
if !matches!(next, Event::End(Tag::Paragraph)) {
self.buffer.push_front(Event::Start(Tag::Paragraph));
self.buffer.push_back(next);
}
self.buffer.pop_front().expect("buffer not to be empty")
} else {
self.buffer.push_back(event);
Event::Start(Tag::Paragraph)
}
}
}
impl<'a, I: Iterator<Item = Event<'a>>> Iterator for InlineImages<'a, I> {
type Item = Event<'a>;
fn next(&mut self) -> Option<Event<'a>> {
self.buffer.pop_front().or_else(|| {
let event = self.parser.next()?;
if event == Event::Start(Tag::Paragraph) {
Some(self.on_paragraph_start())
} else {
Some(event)
}
})
}
}