use crate::{
BrokenLinkCallback, CowStr, DefaultBrokenLinkCallback, Event, OffsetIter, Options, Parser,
};
use std::{iter::Peekable, ops::Range};
#[derive(Debug)]
pub struct TextMergeStream<'a, I> {
iter: I,
last_event: Option<Event<'a>>,
}
impl<'a, I> TextMergeStream<'a, I>
where
I: Iterator<Item = Event<'a>>,
{
pub fn new(iter: I) -> Self {
Self {
iter,
last_event: None,
}
}
}
impl<'a, I> Iterator for TextMergeStream<'a, I>
where
I: Iterator<Item = Event<'a>>,
{
type Item = Event<'a>;
fn next(&mut self) -> Option<Self::Item> {
match (self.last_event.take(), self.iter.next()) {
(Some(Event::Text(last_text)), Some(Event::Text(next_text))) => {
let mut string_buf: String = last_text.into_string();
string_buf.push_str(&next_text);
loop {
match self.iter.next() {
Some(Event::Text(next_text)) => {
string_buf.push_str(&next_text);
}
next_event => {
self.last_event = next_event;
if string_buf.is_empty() {
break self.next();
} else {
break Some(Event::Text(CowStr::Boxed(
string_buf.into_boxed_str(),
)));
}
}
}
}
}
(None, Some(next_event)) => {
self.last_event = Some(next_event);
self.next()
}
(None, None) => {
None
}
(last_event, next_event) => {
self.last_event = next_event;
last_event
}
}
}
}
#[derive(Debug)]
pub struct TextMergeWithOffset<'input, F = DefaultBrokenLinkCallback>
where
F: BrokenLinkCallback<'input>,
{
source: &'input str,
parser: Peekable<OffsetIter<'input, F>>,
}
impl<'input, F> TextMergeWithOffset<'input, F>
where
F: BrokenLinkCallback<'input>,
{
pub fn new_ext(source: &'input str, options: Options) -> Self {
Self {
source,
parser: Parser::new_with_broken_link_callback(source, options, None)
.into_offset_iter()
.peekable(),
}
}
pub fn new_ext_with_broken_link_callback(
source: &'input str,
options: Options,
callback: Option<F>,
) -> Self {
Self {
source,
parser: Parser::new_with_broken_link_callback(source, options, callback)
.into_offset_iter()
.peekable(),
}
}
}
impl<'input, F> Iterator for TextMergeWithOffset<'input, F>
where
F: BrokenLinkCallback<'input>,
{
type Item = (Event<'input>, Range<usize>);
fn next(&mut self) -> Option<Self::Item> {
let is_empty_text = |x: Option<&(Event<'input>, Range<usize>)>| match x {
Some(e) => matches!(&e.0, Event::Text(t) if t.is_empty()),
None => false,
};
while is_empty_text(self.parser.peek()) {
self.parser.next();
}
match self.parser.peek()? {
(Event::Text(_), range) => {
let start = range.start;
let mut end = range.end;
while let Some((Event::Text(_), _)) = self.parser.peek() {
end = self.parser.next().unwrap().1.end;
}
Some((Event::Text(self.source[start..end].into()), start..end))
}
_ => self.parser.next(),
}
}
}