1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
//! Versioned storage for the nodes of the DOM tree.
use std::ops::{Index, IndexMut};
use blitz_traits::node_id::NodeId;
use slotmap::{Key as _, KeyData, SlotMap};
use crate::Node;
slotmap::new_key_type! {
/// The internal [`slotmap`] key for node storage. Only used at the
/// storage boundary: all public APIs use [`NodeId`].
struct NodeKey;
}
#[inline(always)]
fn to_key(id: NodeId) -> NodeKey {
NodeKey::from(KeyData::from_ffi(id.as_u64()))
}
#[inline(always)]
fn to_id(key: NodeKey) -> NodeId {
NodeId::from_u64(key.data().as_ffi())
}
/// The versioned map in which the nodes of the DOM tree are stored, backed by
/// a [`slotmap::SlotMap`].
///
/// Nodes are addressed by [`NodeId`], which carries the slot's version in
/// addition to its index: when a node is dropped and its slot reused, ids
/// referring to the dropped node no longer resolve ([`NodeTree::get`] returns
/// `None`, and indexing panics) instead of aliasing the new occupant.
pub struct NodeTree(SlotMap<NodeKey, Node>);
impl NodeTree {
pub(crate) fn new() -> Self {
Self(SlotMap::with_key())
}
/// The number of live nodes in the map.
pub fn len(&self) -> usize {
self.0.len()
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
/// Whether `id` resolves to a live node.
pub fn contains_key(&self, id: NodeId) -> bool {
self.0.contains_key(to_key(id))
}
/// Get a reference to the node with the given id, if it is still live.
pub fn get(&self, id: NodeId) -> Option<&Node> {
self.0.get(to_key(id))
}
/// Get a mutable reference to the node with the given id, if it is still live.
pub fn get_mut(&mut self, id: NodeId) -> Option<&mut Node> {
self.0.get_mut(to_key(id))
}
/// Insert a node constructed with knowledge of its own id.
pub(crate) fn insert_with_key(&mut self, f: impl FnOnce(NodeId) -> Node) -> NodeId {
to_id(self.0.insert_with_key(|key| f(to_id(key))))
}
/// Remove the node with the given id, returning it if it was still live.
pub(crate) fn remove(&mut self, id: NodeId) -> Option<Node> {
self.0.remove(to_key(id))
}
/// Iterate over all live `(NodeId, &Node)` pairs.
pub fn iter(&self) -> impl Iterator<Item = (NodeId, &Node)> {
self.0.iter().map(|(key, node)| (to_id(key), node))
}
/// Iterate over all live `(NodeId, &mut Node)` pairs.
pub fn iter_mut(&mut self) -> impl Iterator<Item = (NodeId, &mut Node)> {
self.0.iter_mut().map(|(key, node)| (to_id(key), node))
}
}
impl Index<NodeId> for NodeTree {
type Output = Node;
#[track_caller]
#[inline]
fn index(&self, id: NodeId) -> &Node {
&self.0[to_key(id)]
}
}
impl IndexMut<NodeId> for NodeTree {
#[track_caller]
#[inline]
fn index_mut(&mut self, id: NodeId) -> &mut Node {
&mut self.0[to_key(id)]
}
}