domtree/node.rs
1//! Node types stored in the [`Dom`](crate::Dom) arena.
2//!
3//! Strings (tag names, attribute names/values, text) are **not** stored inline
4//! on each node. They live in a single growable buffer on the [`Dom`](crate::Dom)
5//! and nodes reference them by [`Span`] (a byte range). This replaces thousands
6//! of tiny per-node allocations with appends to one buffer — the main reason
7//! parsing is fast despite producing an owned tree.
8
9use alloc::vec::Vec;
10use core::ops::Range;
11
12/// A handle to a node inside a [`Dom`](crate::Dom). Cheap (`Copy`) and stable
13/// for the lifetime of the tree.
14#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
15pub struct NodeId(pub(crate) u32);
16
17impl NodeId {
18 /// The node's position in the arena.
19 #[inline]
20 pub fn index(self) -> usize {
21 self.0 as usize
22 }
23}
24
25/// A byte range into the [`Dom`](crate::Dom)'s string arena.
26#[derive(Clone, Copy)]
27pub(crate) struct Span {
28 pub(crate) start: u32,
29 pub(crate) len: u32,
30}
31
32impl Span {
33 pub(crate) const EMPTY: Span = Span { start: 0, len: 0 };
34
35 #[inline]
36 pub(crate) fn range(self) -> Range<usize> {
37 let start = self.start as usize;
38 start..start + self.len as usize
39 }
40}
41
42/// What a node is — a borrowed, `Copy` view returned by
43/// [`NodeRef::kind`](crate::NodeRef::kind).
44///
45/// For elements, the tag name is included here; read attributes via the
46/// [`NodeRef`](crate::NodeRef) accessors (`attr`, `attributes`, `classes`, …).
47#[derive(Clone, Copy, Debug, PartialEq, Eq)]
48pub enum NodeKind<'a> {
49 /// An element, with its lower-cased tag name.
50 Element {
51 /// The lower-cased tag name (e.g. `"div"`).
52 tag: &'a str,
53 },
54 /// A run of text (already entity-decoded, except inside `<script>`/`<style>`).
55 Text(&'a str),
56 /// The body of an HTML comment.
57 Comment(&'a str),
58 /// The body of a `<!doctype …>` declaration.
59 Doctype(&'a str),
60}
61
62/// The internal, span-based node kind (not exposed; see [`NodeKind`]).
63#[derive(Clone)]
64pub(crate) enum RawKind {
65 Element {
66 name: Span,
67 attrs: Vec<(Span, Span)>,
68 },
69 Text(Span),
70 Comment(Span),
71 Doctype(Span),
72}
73
74/// The internal arena record: tree links plus the node's kind.
75#[derive(Clone)]
76pub(crate) struct Node {
77 pub(crate) parent: Option<NodeId>,
78 pub(crate) first_child: Option<NodeId>,
79 pub(crate) last_child: Option<NodeId>,
80 pub(crate) next_sibling: Option<NodeId>,
81 pub(crate) prev_sibling: Option<NodeId>,
82 pub(crate) raw: RawKind,
83}
84
85impl Node {
86 pub(crate) fn new(raw: RawKind) -> Self {
87 Node {
88 parent: None,
89 first_child: None,
90 last_child: None,
91 next_sibling: None,
92 prev_sibling: None,
93 raw,
94 }
95 }
96}