blitz_dom/
traversal.rs

1use style::dom::TNode as _;
2
3use crate::{BaseDocument, Node};
4
5#[derive(Clone)]
6/// An pre-order tree traverser for a [BaseDocument](crate::document::BaseDocument).
7pub struct TreeTraverser<'a> {
8    doc: &'a BaseDocument,
9    stack: Vec<usize>,
10}
11
12impl<'a> TreeTraverser<'a> {
13    /// Creates a new tree traverser for the given document which starts at the root node.
14    pub fn new(doc: &'a BaseDocument) -> Self {
15        Self::new_with_root(doc, 0)
16    }
17
18    /// Creates a new tree traverser for the given document which starts at the specified node.
19    pub fn new_with_root(doc: &'a BaseDocument, root: usize) -> Self {
20        let mut stack = Vec::with_capacity(32);
21        stack.push(root);
22        TreeTraverser { doc, stack }
23    }
24}
25impl Iterator for TreeTraverser<'_> {
26    type Item = usize;
27
28    fn next(&mut self) -> Option<Self::Item> {
29        let id = self.stack.pop()?;
30        let node = self.doc.get_node(id)?;
31        self.stack.extend(node.children.iter().rev());
32        Some(id)
33    }
34}
35
36#[derive(Clone)]
37/// An ancestor traverser for a [BaseDocument](crate::document::BaseDocument).
38pub struct AncestorTraverser<'a> {
39    doc: &'a BaseDocument,
40    current: usize,
41}
42impl<'a> AncestorTraverser<'a> {
43    /// Creates a new ancestor traverser for the given document and node ID.
44    pub fn new(doc: &'a BaseDocument, node_id: usize) -> Self {
45        AncestorTraverser {
46            doc,
47            current: node_id,
48        }
49    }
50}
51impl Iterator for AncestorTraverser<'_> {
52    type Item = usize;
53
54    fn next(&mut self) -> Option<Self::Item> {
55        let current_node = self.doc.get_node(self.current)?;
56        self.current = current_node.parent?;
57        Some(self.current)
58    }
59}
60
61impl BaseDocument {
62    /// Collect the nodes into a chain by traversing upwards
63    pub fn node_chain(&self, node_id: usize) -> Vec<usize> {
64        let mut chain = Vec::with_capacity(16);
65        chain.push(node_id);
66        chain.extend(
67            AncestorTraverser::new(self, node_id).filter(|id| self.nodes[*id].is_element()),
68        );
69        chain
70    }
71
72    pub fn visit<F>(&self, mut visit: F)
73    where
74        F: FnMut(usize, &Node),
75    {
76        TreeTraverser::new(self).for_each(|node_id| visit(node_id, &self.nodes[node_id]));
77    }
78
79    /// If the node is non-anonymous then returns the node's id
80    /// Else find's the first non-anonymous ancester of the node
81    pub fn non_anon_ancestor_if_anon(&self, mut node_id: usize) -> usize {
82        loop {
83            let node = &self.nodes[node_id];
84
85            if !node.is_anonymous() {
86                return node.id;
87            }
88
89            let Some(parent_id) = node.layout_parent.get() else {
90                // Shouldn't be reachable unless invalid node_id is passed
91                // as root node is always non-anonymous
92                panic!("Node does not exist or does not have a non-anonymous parent");
93            };
94
95            node_id = parent_id;
96        }
97    }
98
99    pub fn iter_children_mut(
100        &mut self,
101        node_id: usize,
102        mut cb: impl FnMut(usize, &mut BaseDocument),
103    ) {
104        let children = std::mem::take(&mut self.nodes[node_id].children);
105        for child_id in children.iter().cloned() {
106            cb(child_id, self);
107        }
108        self.nodes[node_id].children = children;
109    }
110
111    pub fn iter_subtree_mut(
112        &mut self,
113        node_id: usize,
114        mut cb: impl FnMut(usize, &mut BaseDocument),
115    ) {
116        cb(node_id, self);
117        iter_subtree_mut_inner(self, node_id, &mut cb);
118        fn iter_subtree_mut_inner(
119            doc: &mut BaseDocument,
120            node_id: usize,
121            cb: &mut impl FnMut(usize, &mut BaseDocument),
122        ) {
123            let children = std::mem::take(&mut doc.nodes[node_id].children);
124            for child_id in children.iter().cloned() {
125                cb(child_id, doc);
126                iter_subtree_mut_inner(doc, child_id, cb);
127            }
128            doc.nodes[node_id].children = children;
129        }
130    }
131
132    pub fn iter_children_and_pseudos_mut(
133        &mut self,
134        node_id: usize,
135        mut cb: impl FnMut(usize, &mut BaseDocument),
136    ) {
137        let before = self.nodes[node_id].before.take();
138        if let Some(before_node_id) = before {
139            cb(before_node_id, self)
140        }
141        self.nodes[node_id].before = before;
142
143        self.iter_children_mut(node_id, &mut cb);
144
145        let after = self.nodes[node_id].after.take();
146        if let Some(after_node_id) = after {
147            cb(after_node_id, self)
148        }
149        self.nodes[node_id].after = after;
150    }
151
152    pub fn next_node(&self, start: &Node, mut filter: impl FnMut(&Node) -> bool) -> Option<usize> {
153        let start_id = start.id;
154        let mut node = start;
155        let mut look_in_children = true;
156        loop {
157            // Next is first child
158            let next = if look_in_children && !node.children.is_empty() {
159                let node_id = node.children[0];
160                &self.nodes[node_id]
161            }
162            // Next is next sibling or parent
163            else if let Some(parent) = node.parent_node() {
164                let self_idx = parent
165                    .children
166                    .iter()
167                    .position(|id| *id == node.id)
168                    .unwrap();
169                // Next is next sibling
170                if let Some(sibling_id) = parent.children.get(self_idx + 1) {
171                    look_in_children = true;
172                    &self.nodes[*sibling_id]
173                }
174                // Next is parent
175                else {
176                    look_in_children = false;
177                    node = parent;
178                    continue;
179                }
180            }
181            // Continue search from the root
182            else {
183                look_in_children = true;
184                self.root_node()
185            };
186
187            if filter(next) {
188                return Some(next.id);
189            } else if next.id == start_id {
190                return None;
191            }
192
193            node = next;
194        }
195    }
196
197    pub fn node_layout_ancestors(&self, node_id: usize) -> Vec<usize> {
198        let mut ancestors = Vec::with_capacity(12);
199        let mut maybe_id = Some(node_id);
200        while let Some(id) = maybe_id {
201            ancestors.push(id);
202            maybe_id = self.nodes[id].layout_parent.get();
203        }
204        ancestors.reverse();
205        ancestors
206    }
207
208    pub fn maybe_node_layout_ancestors(&self, node_id: Option<usize>) -> Vec<usize> {
209        node_id
210            .map(|id| self.node_layout_ancestors(id))
211            .unwrap_or_default()
212    }
213}