Skip to main content

altium_format/tree/
walker.rs

1//! Depth-first tree walker iterator.
2
3use super::{RecordId, RecordTree, TreeRecord};
4
5/// Depth-first iterator over tree nodes.
6///
7/// Yields (RecordId, &Record, depth) tuples in pre-order traversal.
8pub struct TreeWalker<'a, R> {
9    tree: &'a RecordTree<R>,
10    /// Stack of (RecordId, depth) pairs to visit.
11    stack: Vec<(RecordId, usize)>,
12}
13
14impl<'a, R: TreeRecord> TreeWalker<'a, R> {
15    /// Create a new walker starting from all roots.
16    pub fn new(tree: &'a RecordTree<R>) -> Self {
17        // Push roots in reverse order so first root is processed first
18        let stack = tree.roots.iter().rev().map(|&id| (id, 0)).collect();
19
20        TreeWalker { tree, stack }
21    }
22
23    /// Create a walker starting from a specific node.
24    pub fn from_node(tree: &'a RecordTree<R>, start: RecordId) -> Self {
25        let depth = tree.depth(start);
26        TreeWalker {
27            tree,
28            stack: vec![(start, depth)],
29        }
30    }
31}
32
33impl<'a, R: TreeRecord> Iterator for TreeWalker<'a, R> {
34    type Item = (RecordId, &'a R, usize);
35
36    fn next(&mut self) -> Option<Self::Item> {
37        let (id, depth) = self.stack.pop()?;
38
39        // Get the record
40        let record = self.tree.get(id)?;
41
42        // Push children in reverse order for correct traversal order
43        if let Some(children) = self.tree.children.get(&id) {
44            for &child_id in children.iter().rev() {
45                self.stack.push((child_id, depth + 1));
46            }
47        }
48
49        Some((id, record, depth))
50    }
51}
52
53/// Breadth-first iterator over tree nodes.
54///
55/// Yields (RecordId, &Record, depth) tuples level by level.
56pub struct BreadthFirstWalker<'a, R> {
57    tree: &'a RecordTree<R>,
58    /// Queue of (RecordId, depth) pairs to visit.
59    queue: std::collections::VecDeque<(RecordId, usize)>,
60}
61
62impl<'a, R: TreeRecord> BreadthFirstWalker<'a, R> {
63    /// Create a new breadth-first walker starting from all roots.
64    pub fn new(tree: &'a RecordTree<R>) -> Self {
65        let queue = tree.roots.iter().map(|&id| (id, 0)).collect();
66
67        BreadthFirstWalker { tree, queue }
68    }
69
70    /// Create a walker starting from a specific node.
71    pub fn from_node(tree: &'a RecordTree<R>, start: RecordId) -> Self {
72        let depth = tree.depth(start);
73        let mut queue = std::collections::VecDeque::new();
74        queue.push_back((start, depth));
75        BreadthFirstWalker { tree, queue }
76    }
77}
78
79impl<'a, R: TreeRecord> Iterator for BreadthFirstWalker<'a, R> {
80    type Item = (RecordId, &'a R, usize);
81
82    fn next(&mut self) -> Option<Self::Item> {
83        let (id, depth) = self.queue.pop_front()?;
84
85        // Get the record
86        let record = self.tree.get(id)?;
87
88        // Add children to the back of the queue
89        if let Some(children) = self.tree.children.get(&id) {
90            for &child_id in children.iter() {
91                self.queue.push_back((child_id, depth + 1));
92            }
93        }
94
95        Some((id, record, depth))
96    }
97}
98
99#[cfg(test)]
100mod tests {
101    use super::*;
102
103    #[derive(Debug, Clone, Default)]
104    struct TestRecord {
105        owner_index: i32,
106        name: String,
107    }
108
109    impl TreeRecord for TestRecord {
110        fn owner_index(&self) -> i32 {
111            self.owner_index
112        }
113
114        fn set_owner_index(&mut self, index: i32) {
115            self.owner_index = index;
116        }
117    }
118
119    #[test]
120    fn test_depth_first_walk() {
121        // Build a tree:
122        //   0 (root)
123        //   ├── 1
124        //   │   └── 3
125        //   └── 2
126        let records = vec![
127            TestRecord {
128                owner_index: -1,
129                name: "root".to_string(),
130            },
131            TestRecord {
132                owner_index: 0,
133                name: "child1".to_string(),
134            },
135            TestRecord {
136                owner_index: 0,
137                name: "child2".to_string(),
138            },
139            TestRecord {
140                owner_index: 1,
141                name: "grandchild".to_string(),
142            },
143        ];
144
145        let tree = RecordTree::from_records(records);
146        let walked: Vec<_> = tree
147            .walk_depth_first()
148            .map(|(_, r, d)| (r.name.clone(), d))
149            .collect();
150
151        // Depth-first: root, child1, grandchild, child2
152        assert_eq!(
153            walked,
154            vec![
155                ("root".to_string(), 0),
156                ("child1".to_string(), 1),
157                ("grandchild".to_string(), 2),
158                ("child2".to_string(), 1),
159            ]
160        );
161    }
162
163    #[test]
164    fn test_breadth_first_walk() {
165        let records = vec![
166            TestRecord {
167                owner_index: -1,
168                name: "root".to_string(),
169            },
170            TestRecord {
171                owner_index: 0,
172                name: "child1".to_string(),
173            },
174            TestRecord {
175                owner_index: 0,
176                name: "child2".to_string(),
177            },
178            TestRecord {
179                owner_index: 1,
180                name: "grandchild".to_string(),
181            },
182        ];
183
184        let tree = RecordTree::from_records(records);
185        let walker = BreadthFirstWalker::new(&tree);
186        let walked: Vec<_> = walker.map(|(_, r, d)| (r.name.clone(), d)).collect();
187
188        // Breadth-first: root, child1, child2, grandchild
189        assert_eq!(
190            walked,
191            vec![
192                ("root".to_string(), 0),
193                ("child1".to_string(), 1),
194                ("child2".to_string(), 1),
195                ("grandchild".to_string(), 2),
196            ]
197        );
198    }
199}