use alloc::borrow::Cow;
use alloc::collections::VecDeque;
use alloc::vec::Vec;
use core::iter::FusedIterator;
use core::ops::Range;
use crate::builder::{Sink, TreeBuilder, lower};
use crate::entities;
use crate::error::ParseError;
use crate::tokenizer::Tokenizer;
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Event<'a> {
Start {
name: Cow<'a, str>,
attrs: Vec<(Cow<'a, str>, Cow<'a, str>)>,
},
End {
name: Cow<'a, str>,
implied: bool,
},
Text(Cow<'a, str>),
Comment(&'a str),
Doctype(&'a str),
}
pub struct Events<'a> {
tokenizer: Tokenizer<'a>,
builder: TreeBuilder<'a, Queue<'a>>,
len: usize,
done: bool,
}
impl<'a> Events<'a> {
pub(crate) fn new(src: &'a str) -> Self {
Events {
tokenizer: Tokenizer::new(src),
builder: TreeBuilder::new(
Queue {
events: VecDeque::new(),
attrs: Vec::new(),
},
src,
),
len: src.len(),
done: false,
}
}
pub fn errors(&self) -> &[ParseError] {
&self.builder.errors
}
}
impl<'a> Iterator for Events<'a> {
type Item = (Event<'a>, Range<usize>);
fn next(&mut self) -> Option<Self::Item> {
loop {
if let Some(event) = self.builder.sink.events.pop_front() {
return Some(event);
}
if self.done {
return None;
}
match self.tokenizer.next_token() {
Some((tok, pos)) => {
let end = self.tokenizer.offset();
self.builder.token(tok, self.tokenizer.attrs(), pos, end);
}
None => {
self.builder.finish(self.len, &mut self.tokenizer.errors);
self.done = true;
}
}
}
}
}
impl FusedIterator for Events<'_> {}
struct Queue<'a> {
events: VecDeque<(Event<'a>, Range<usize>)>,
attrs: Vec<(Cow<'a, str>, Cow<'a, str>)>,
}
impl<'a> Sink<'a> for Queue<'a> {
type Open = Cow<'a, str>;
fn name<'s>(&'s self, open: &'s Cow<'a, str>) -> &'s str {
open
}
fn attr(&mut self, name: &'a str, value: &'a str) -> Option<usize> {
let (value, unknown) = entities::decode(value, true);
self.attrs.push((lower(name), value));
unknown
}
fn start(
&mut self,
_parent: Option<&Cow<'a, str>>,
name: Cow<'a, str>,
_attrs: usize,
start: usize,
end: usize,
) -> Cow<'a, str> {
let attrs = core::mem::take(&mut self.attrs);
let event = Event::Start {
name: name.clone(),
attrs,
};
self.events.push_back((event, start..end));
name
}
fn end(&mut self, name: Cow<'a, str>, start: usize, end: usize, implied: bool) {
self.events
.push_back((Event::End { name, implied }, start..end));
}
fn text(
&mut self,
_parent: Option<&Cow<'a, str>>,
text: &'a str,
decode: bool,
start: usize,
end: usize,
) -> Option<usize> {
let (text, unknown) = if decode {
entities::decode(text, false)
} else {
(Cow::Borrowed(text), None)
};
self.events.push_back((Event::Text(text), start..end));
unknown
}
fn comment(&mut self, _parent: Option<&Cow<'a, str>>, text: &'a str, start: usize, end: usize) {
self.events.push_back((Event::Comment(text), start..end));
}
fn doctype(&mut self, _parent: Option<&Cow<'a, str>>, text: &'a str, start: usize, end: usize) {
self.events.push_back((Event::Doctype(text), start..end));
}
}