ember_plus/tree/
walker.rs1use super::node::{EmberTree, TreeNodeRef};
4
5pub struct TreeWalker<'a> {
7 tree: &'a EmberTree,
8 stack: Vec<(TreeNodeRef, Vec<i32>)>,
9}
10
11impl<'a> TreeWalker<'a> {
12 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 pub fn next(&mut self) -> Option<(TreeNodeRef, Vec<i32>)> {
27 let (node, path) = self.stack.pop()?;
28
29 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
51pub 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
68pub 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); }
129}