Skip to main content

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}