Skip to main content

ember_plus/tree/
walker.rs

1//! Tree traversal utilities.
2
3use super::node::{EmberTree, TreeNodeRef};
4
5/// A walker for traversing the Ember+ tree.
6pub struct TreeWalker<'a> {
7    tree: &'a EmberTree,
8    stack: Vec<(TreeNodeRef, Vec<i32>)>,
9}
10
11impl<'a> TreeWalker<'a> {
12    /// Create a new walker starting from the root.
13    pub fn new(tree: &'a EmberTree) -> Self {
14        let stack: Vec<(TreeNodeRef, Vec<i32>)> = tree
15            .children()
16            .map(|node| {
17                let number = node.read().number();
18                (std::sync::Arc::clone(node), vec![number])
19            })
20            .collect();
21        
22        TreeWalker { tree, stack }
23    }
24
25    /// Get the next node and its path.
26    pub fn next(&mut self) -> Option<(TreeNodeRef, Vec<i32>)> {
27        let (node, path) = self.stack.pop()?;
28        
29        // Add children to stack
30        let node_guard = node.read();
31        for child in node_guard.children() {
32            let child_number = child.read().number();
33            let mut child_path = path.clone();
34            child_path.push(child_number);
35            self.stack.push((std::sync::Arc::clone(child), child_path));
36        }
37        drop(node_guard);
38        
39        Some((node, path))
40    }
41}
42
43impl<'a> Iterator for TreeWalker<'a> {
44    type Item = (TreeNodeRef, Vec<i32>);
45
46    fn next(&mut self) -> Option<Self::Item> {
47        TreeWalker::next(self)
48    }
49}
50
51/// Find nodes by identifier.
52pub fn find_by_identifier(tree: &EmberTree, identifier: &str) -> Vec<(TreeNodeRef, Vec<i32>)> {
53    let mut results = Vec::new();
54    
55    for (node, path) in TreeWalker::new(tree) {
56        let matches = {
57            let guard = node.read();
58            guard.identifier() == Some(identifier)
59        };
60        if matches {
61            results.push((node, path));
62        }
63    }
64    
65    results
66}
67
68/// Find nodes by path pattern (supports wildcards).
69pub fn find_by_pattern(tree: &EmberTree, pattern: &str) -> Vec<(TreeNodeRef, Vec<i32>)> {
70    let parts: Vec<&str> = pattern.split('.').collect();
71    let mut results = Vec::new();
72    
73    fn matches(path: &[i32], pattern: &[&str]) -> bool {
74        if path.len() != pattern.len() {
75            return false;
76        }
77        
78        for (num, pat) in path.iter().zip(pattern.iter()) {
79            if *pat != "*" {
80                if let Ok(expected) = pat.parse::<i32>() {
81                    if *num != expected {
82                        return false;
83                    }
84                } else {
85                    return false;
86                }
87            }
88        }
89        
90        true
91    }
92    
93    for (node, path) in TreeWalker::new(tree) {
94        let path_strs: Vec<String> = path.iter().map(|n| n.to_string()).collect();
95        let path_refs: Vec<&str> = path_strs.iter().map(|s| s.as_str()).collect();
96        
97        if matches(&path, &parts) {
98            results.push((node, path));
99        }
100    }
101    
102    results
103}
104
105#[cfg(test)]
106mod tests {
107    use super::*;
108    use crate::tree::node::TreeNode;
109
110    #[test]
111    fn test_walker() {
112        let mut tree = EmberTree::new();
113        
114        let mut root = TreeNode::new_node(0);
115        let child1 = std::sync::Arc::new(parking_lot::RwLock::new(TreeNode::new_node(1)));
116        let child2 = std::sync::Arc::new(parking_lot::RwLock::new(TreeNode::new_node(2)));
117        root.add_child(child1);
118        root.add_child(child2);
119        
120        tree.add_root_child(root);
121        
122        let mut count = 0;
123        for _ in TreeWalker::new(&tree) {
124            count += 1;
125        }
126        
127        assert_eq!(count, 3); // root + 2 children
128    }
129}