use std::borrow::Cow;
use super::super::decode_entities;
use super::name::LocalNameHash;
use super::tag::HtmlTag;
fn decode_lossy(bytes: &[u8]) -> Cow<'_, str> {
match String::from_utf8_lossy(bytes) {
Cow::Borrowed(s) => decode_entities(s),
Cow::Owned(s) => Cow::Owned(decode_entities(&s).into_owned()),
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) struct Span {
pub(crate) start: usize,
pub(crate) end: usize,
}
impl Span {
pub(crate) const fn new(start: usize, end: usize) -> Self {
Self { start, end }
}
pub(crate) const fn empty(at: usize) -> Self {
Self { start: at, end: at }
}
fn slice(self, input: &[u8]) -> &[u8] {
input.get(self.start..self.end).unwrap_or(&[])
}
}
#[derive(Debug, Clone, Copy)]
pub(crate) struct AttrRange {
pub(crate) name: Span,
pub(crate) value: Span,
pub(crate) has_value: bool,
}
#[derive(Debug)]
pub struct StartTag<'i> {
pub(crate) input: &'i [u8],
pub(crate) raw: Span,
pub(crate) name: Span,
pub(crate) name_hash: LocalNameHash,
pub(crate) attributes: &'i [AttrRange],
pub(crate) self_closing: bool,
}
impl<'i> StartTag<'i> {
#[must_use]
pub fn tag(&self) -> HtmlTag<'i> {
HtmlTag::classify(self.name_hash, self.name())
}
pub(crate) fn name(&self) -> &'i [u8] {
self.name.slice(self.input)
}
#[must_use]
pub fn name_hash(&self) -> LocalNameHash {
self.name_hash
}
#[must_use]
pub fn is_self_closing(&self) -> bool {
self.self_closing
}
#[must_use]
pub fn attributes(&self) -> Attributes<'i> {
Attributes {
input: self.input,
ranges: self.attributes.iter(),
}
}
#[must_use]
pub fn raw(&self) -> &'i [u8] {
self.raw.slice(self.input)
}
}
#[derive(Debug, Clone)]
pub struct Attributes<'i> {
input: &'i [u8],
ranges: std::slice::Iter<'i, AttrRange>,
}
impl<'i> Iterator for Attributes<'i> {
type Item = Attribute<'i>;
fn next(&mut self) -> Option<Self::Item> {
let range = self.ranges.next()?;
Some(Attribute {
name: range.name.slice(self.input),
value: range.value.slice(self.input),
has_value: range.has_value,
})
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.ranges.size_hint()
}
}
impl ExactSizeIterator for Attributes<'_> {}
#[derive(Debug, Clone, Copy)]
pub struct Attribute<'i> {
name: &'i [u8],
value: &'i [u8],
has_value: bool,
}
impl<'i> Attribute<'i> {
#[must_use]
pub fn name(&self) -> &'i [u8] {
self.name
}
#[must_use]
pub fn value(&self) -> &'i [u8] {
self.value
}
#[must_use]
pub fn value_decoded(&self) -> Cow<'i, str> {
decode_lossy(self.value)
}
#[must_use]
pub fn has_value(&self) -> bool {
self.has_value
}
}
#[derive(Debug)]
pub struct EndTag<'i> {
pub(crate) input: &'i [u8],
pub(crate) raw: Span,
pub(crate) name: Span,
pub(crate) name_hash: LocalNameHash,
}
impl<'i> EndTag<'i> {
#[must_use]
pub fn tag(&self) -> HtmlTag<'i> {
HtmlTag::classify(self.name_hash, self.name())
}
pub(crate) fn name(&self) -> &'i [u8] {
self.name.slice(self.input)
}
#[must_use]
pub fn name_hash(&self) -> LocalNameHash {
self.name_hash
}
#[must_use]
pub fn raw(&self) -> &'i [u8] {
self.raw.slice(self.input)
}
}
#[derive(Debug)]
pub struct Text<'i> {
pub(crate) input: &'i [u8],
pub(crate) raw: Span,
}
impl<'i> Text<'i> {
#[must_use]
pub fn as_bytes(&self) -> &'i [u8] {
self.raw.slice(self.input)
}
#[must_use]
pub fn decoded(&self) -> Cow<'i, str> {
decode_lossy(self.raw.slice(self.input))
}
#[must_use]
pub fn raw(&self) -> &'i [u8] {
self.raw.slice(self.input)
}
}
#[derive(Debug)]
pub struct Comment<'i> {
pub(crate) input: &'i [u8],
pub(crate) raw: Span,
pub(crate) data: Span,
}
impl<'i> Comment<'i> {
#[must_use]
pub fn data(&self) -> &'i [u8] {
self.data.slice(self.input)
}
#[must_use]
pub fn raw(&self) -> &'i [u8] {
self.raw.slice(self.input)
}
}
#[derive(Debug)]
pub struct Cdata<'i> {
pub(crate) input: &'i [u8],
pub(crate) raw: Span,
pub(crate) data: Span,
}
impl<'i> Cdata<'i> {
#[must_use]
pub fn data(&self) -> &'i [u8] {
self.data.slice(self.input)
}
#[must_use]
pub fn raw(&self) -> &'i [u8] {
self.raw.slice(self.input)
}
}
#[derive(Debug)]
pub struct Doctype<'i> {
pub(crate) input: &'i [u8],
pub(crate) raw: Span,
pub(crate) name: Option<Span>,
}
impl<'i> Doctype<'i> {
#[must_use]
pub fn name(&self) -> Option<&'i [u8]> {
self.name.map(|span| span.slice(self.input))
}
#[must_use]
pub fn raw(&self) -> &'i [u8] {
self.raw.slice(self.input)
}
}