Skip to main content

tiptap_rusty_parser/
query.rs

1//! Traversal and querying via predicate closures.
2//!
3//! All traversal is depth-first pre-order (a node is visited before its
4//! children). Iterators are stack-based (no recursion) to stay cheap and avoid
5//! blowing the call stack on deep documents.
6
7use crate::node::Node;
8
9impl Node {
10    /// Visit `self` and every descendant, pre-order.
11    ///
12    /// ```
13    /// use tiptap_rusty_parser::Document;
14    /// let doc = Document::from_json_str(r#"{"type":"doc","content":[{"type":"paragraph"}]}"#).unwrap();
15    /// let mut n = 0;
16    /// doc.root().walk(&mut |_| n += 1);
17    /// assert_eq!(n, 2);
18    /// ```
19    pub fn walk(&self, f: &mut impl FnMut(&Node)) {
20        f(self);
21        if let Some(children) = &self.content {
22            for child in children {
23                child.walk(f);
24            }
25        }
26    }
27
28    /// Mutable pre-order visit of `self` and every descendant.
29    pub fn walk_mut(&mut self, f: &mut impl FnMut(&mut Node)) {
30        f(self);
31        if let Some(children) = &mut self.content {
32            for child in children {
33                child.walk_mut(f);
34            }
35        }
36    }
37
38    /// First node (incl. `self`) matching `pred`, pre-order.
39    pub fn find(&self, mut pred: impl FnMut(&Node) -> bool) -> Option<&Node> {
40        self.descendants().find(|n| pred(n))
41    }
42
43    /// Mutable variant of [`Node::find`].
44    pub fn find_mut(&mut self, mut pred: impl FnMut(&Node) -> bool) -> Option<&mut Node> {
45        if pred(self) {
46            return Some(self);
47        }
48        let children = self.content.as_mut()?;
49        for child in children {
50            if let Some(found) = child.find_mut(&mut pred) {
51                return Some(found);
52            }
53        }
54        None
55    }
56
57    /// All nodes (incl. `self`) matching `pred`, pre-order.
58    pub fn find_all(&self, mut pred: impl FnMut(&Node) -> bool) -> Vec<&Node> {
59        self.descendants().filter(|n| pred(n)).collect()
60    }
61
62    /// Mutable variant of [`Node::find_all`]. Collects matching `&mut Node`.
63    pub fn find_all_mut(&mut self, pred: &mut impl FnMut(&Node) -> bool) -> Vec<&mut Node> {
64        let mut out = Vec::new();
65        self.collect_mut(pred, &mut out);
66        out
67    }
68
69    fn collect_mut<'a>(
70        &'a mut self,
71        pred: &mut impl FnMut(&Node) -> bool,
72        out: &mut Vec<&'a mut Node>,
73    ) {
74        let matched = pred(self);
75        // Split borrow: push self, then recurse into children.
76        let children_ptr = self.content.as_mut().map(|c| c as *mut Vec<Node>);
77        if matched {
78            out.push(self);
79        }
80        // SAFETY: `content` is disjoint from the `&mut Node` pushed above
81        // (different field), and we never alias the same node twice.
82        if let Some(ptr) = children_ptr {
83            let children = unsafe { &mut *ptr };
84            for child in children {
85                child.collect_mut(pred, out);
86            }
87        }
88    }
89
90    /// Lazy pre-order iterator over `self` and all descendants.
91    #[inline]
92    pub fn descendants(&self) -> Descendants<'_> {
93        Descendants { stack: vec![self] }
94    }
95}
96
97/// Pre-order descendant iterator. See [`Node::descendants`].
98pub struct Descendants<'a> {
99    stack: Vec<&'a Node>,
100}
101
102impl<'a> Iterator for Descendants<'a> {
103    type Item = &'a Node;
104
105    fn next(&mut self) -> Option<&'a Node> {
106        let node = self.stack.pop()?;
107        if let Some(children) = &node.content {
108            // Push in reverse so children pop in document order.
109            self.stack.extend(children.iter().rev());
110        }
111        Some(node)
112    }
113}