#![allow(clippy::manual_non_exhaustive)]
use std::{borrow::Cow, fmt, ops::Deref};
use markup5ever::{
local_name, namespace_url, ns, tendril::StrTendril, LocalName, Namespace, Prefix,
};
pub use self::NodeOrText::{AppendNode, AppendText};
#[derive(Eq, PartialOrd, Ord, Clone)]
pub enum YName {
Local(LocalName),
Expr(StrTendril),
}
impl PartialEq for YName {
fn eq(&self, other: &Self) -> bool {
use YName::*;
match (self, other) {
(Local(a), Local(b)) => a == b,
(Expr(_), Expr(_)) => true,
_ => false,
}
}
}
impl Deref for YName {
type Target = str;
fn deref(&self) -> &Self::Target {
match self {
YName::Local(l) => &**l,
YName::Expr(l) => &*l,
}
}
}
#[macro_export]
macro_rules! y_name {
($local:tt) => {
YName::Local(local_name!($local))
};
(e $local:tt) => {
YName::Expr(StrTrendril::from($local))
};
}
impl fmt::Debug for YName {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
YName::Local(local) => fmt::Display::fmt(local, f),
YName::Expr(local) => fmt::Display::fmt(local, f),
}
}
}
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Debug)]
pub struct Attribute {
pub name: QualName,
pub value: StrTendril,
}
#[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Clone)]
pub struct QualName {
pub prefix: Option<Prefix>,
pub ns: Namespace,
pub local: YName,
}
impl QualName {
#[inline]
pub fn new(prefix: Option<Prefix>, ns: Namespace, local: YName) -> QualName {
QualName { prefix, ns, local }
}
#[inline]
pub fn expanded(&self) -> ExpandedName {
ExpandedName {
ns: &self.ns,
local: &self.local,
}
}
}
#[derive(Copy, Clone, Eq)]
pub struct ExpandedName<'a> {
pub ns: &'a Namespace,
pub local: &'a YName,
}
impl<'a, 'b> PartialEq<ExpandedName<'a>> for ExpandedName<'b> {
fn eq(&self, other: &ExpandedName<'a>) -> bool {
self.ns == other.ns && self.local == other.local
}
}
impl<'a> fmt::Debug for ExpandedName<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.ns.is_empty() {
write!(f, "{:?}", self.local)
} else {
write!(f, "{{{}}}:{:?}", self.ns, self.local)
}
}
}
#[macro_export]
macro_rules! expanded_name {
("", $local:tt) => {
$crate::interface::ExpandedName {
ns: &ns!(),
local: &$crate::interface::YName::Local(local_name!($local)),
}
};
($ns: ident $local:tt) => {
$crate::interface::ExpandedName {
ns: &ns!($ns),
local: &$crate::interface::YName::Local(local_name!($local)),
}
};
}
pub enum NodeOrText<Handle> {
AppendNode(Handle),
AppendText(StrTendril),
}
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
pub enum NextParserState {
Suspend,
Continue,
}
#[derive(Default)]
pub struct ElementFlags {
pub template: bool,
pub mathml_annotation_xml_integration_point: bool,
_private: (),
}
pub fn create_element<Sink>(sink: &mut Sink, name: QualName, attrs: Vec<Attribute>) -> Sink::Handle
where
Sink: TreeSink,
{
let mut flags = ElementFlags::default();
match name.expanded() {
expanded_name!(html "template") => flags.template = true,
expanded_name!(mathml "annotation-xml") => {
flags.mathml_annotation_xml_integration_point = attrs.iter().any(|attr| {
attr.name.expanded() == expanded_name!("", "encoding")
&& (attr.value.eq_ignore_ascii_case("text/html")
|| attr.value.eq_ignore_ascii_case("application/xhtml+xml"))
})
}
_ => {}
}
sink.create_element(name, attrs, flags)
}
pub trait TreeSink {
type Handle: Clone;
type Output;
fn finish(self) -> Self::Output;
fn parse_error(&mut self, msg: Cow<'static, str>);
fn get_document(&mut self) -> Self::Handle;
fn elem_name<'a>(&'a self, target: &'a Self::Handle) -> ExpandedName<'a>;
fn create_element(
&mut self,
name: QualName,
attrs: Vec<Attribute>,
flags: ElementFlags,
) -> Self::Handle;
fn append(&mut self, parent: &Self::Handle, child: NodeOrText<Self::Handle>);
fn append_doctype_to_document(
&mut self,
name: StrTendril,
public_id: StrTendril,
system_id: StrTendril,
);
fn mark_script_already_started(&mut self, _node: &Self::Handle) {}
fn pop(&mut self, _node: &Self::Handle) {}
fn get_template_contents(&mut self, target: &Self::Handle) -> Self::Handle;
fn same_node(&self, x: &Self::Handle, y: &Self::Handle) -> bool;
fn is_mathml_annotation_xml_integration_point(&self, _handle: &Self::Handle) -> bool {
false
}
fn set_current_line(&mut self, _line_number: u64) {}
fn complete_script(&mut self, _node: &Self::Handle) -> NextParserState {
NextParserState::Continue
}
}