use core::fmt;
use core::num::NonZeroU32;
use core::ops::Range;
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct NodeId(NonZeroU32);
impl NodeId {
#[inline]
pub(crate) fn from_index(index: usize) -> Self {
let index = u32::try_from(index).unwrap_or(u32::MAX);
NodeId(NonZeroU32::MIN.saturating_add(index))
}
#[inline]
pub fn index(self) -> usize {
(self.0.get() - 1) as usize
}
}
impl fmt::Debug for NodeId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("NodeId").field(&self.index()).finish()
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) struct Span {
pub(crate) start: u32,
pub(crate) len: u32,
}
impl Span {
pub(crate) const EMPTY: Span = Span { start: 0, len: 0 };
#[inline]
pub(crate) fn range(self) -> Range<usize> {
let start = self.start as usize;
start..start + self.len as usize
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum NodeKind<'a> {
Element {
tag: &'a str,
},
Text(&'a str),
Comment(&'a str),
Doctype(&'a str),
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub(crate) struct AttrRange {
pub(crate) start: u32,
pub(crate) len: u32,
}
impl AttrRange {
#[inline]
pub(crate) fn range(self) -> Range<usize> {
let start = self.start as usize;
start..start + self.len as usize
}
}
#[derive(Clone, Copy)]
pub(crate) enum RawKind {
Element { name: Span, attrs: AttrRange },
Text(Span),
Comment(Span),
Doctype(Span),
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub(crate) struct SrcRange {
start: u32,
end: u32,
}
impl SrcRange {
pub(crate) const NONE: SrcRange = SrcRange {
start: u32::MAX,
end: u32::MAX,
};
#[inline]
pub(crate) fn new(start: u32, end: u32) -> Self {
SrcRange { start, end }
}
#[inline]
pub(crate) fn set_end(&mut self, end: u32) {
if self.start != u32::MAX {
self.end = end;
}
}
pub(crate) fn get(self) -> Option<Range<usize>> {
(self.start != u32::MAX).then_some(self.start as usize..self.end.max(self.start) as usize)
}
}
#[derive(Clone)]
pub(crate) struct Node {
pub(crate) parent: Option<NodeId>,
pub(crate) first_child: Option<NodeId>,
pub(crate) last_child: Option<NodeId>,
pub(crate) next_sibling: Option<NodeId>,
pub(crate) prev_sibling: Option<NodeId>,
pub(crate) detached: bool,
pub(crate) src: SrcRange,
pub(crate) raw: RawKind,
}
impl Node {
pub(crate) fn new(raw: RawKind, src: SrcRange) -> Self {
Node {
parent: None,
first_child: None,
last_child: None,
next_sibling: None,
prev_sibling: None,
detached: false,
src,
raw,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn nodes_stay_small() {
assert_eq!(core::mem::size_of::<Option<NodeId>>(), 4);
assert_eq!(core::mem::size_of::<RawKind>(), 20);
assert!(core::mem::size_of::<Node>() <= 52);
}
#[test]
fn node_id_round_trips_its_index() {
for i in [0, 1, 41, u32::MAX as usize - 1] {
assert_eq!(NodeId::from_index(i).index(), i);
}
assert_eq!(alloc::format!("{:?}", NodeId::from_index(7)), "NodeId(7)");
}
}