Skip to main content

altium_format/tree/
mod.rs

1//! Tree structure support for Altium record hierarchies.
2//!
3//! Altium records form tree structures where parent-child relationships are
4//! encoded via the OWNERINDEX parameter. This module provides:
5//!
6//! - [`RecordTree`] - Generic tree structure with navigation methods
7//! - [`RecordId`] - Unique identifier for records within a tree
8//! - [`TreeWalker`] - Depth-first iterator over tree nodes
9//!
10//! # Example
11//!
12//! ```ignore
13//! use altium_format::tree::RecordTree;
14//! use altium_format::records::sch::SchRecord;
15//!
16//! // Build tree from flat record list
17//! let tree = RecordTree::from_records(records);
18//!
19//! // Navigate the tree
20//! for (id, record) in tree.roots() {
21//!     println!("Root: {:?}", record);
22//!     for (child_id, child) in tree.children(id) {
23//!         println!("  Child: {:?}", child);
24//!     }
25//! }
26//!
27//! // Walk entire tree depth-first
28//! for (id, record, depth) in tree.walk_depth_first() {
29//!     println!("{:indent$}{:?}", "", record, indent = depth * 2);
30//! }
31//! ```
32
33mod node;
34mod walker;
35
36pub use node::{ParentRef, RecordId};
37pub use walker::{BreadthFirstWalker, TreeWalker};
38
39use std::collections::HashMap;
40
41/// A trait for records that can participate in a tree structure.
42///
43/// Records must provide their owner index (parent reference) to build
44/// the tree relationships.
45pub trait TreeRecord {
46    /// Get the owner index (parent reference).
47    /// Returns the index of the parent record, or a negative value for root records.
48    fn owner_index(&self) -> i32;
49
50    /// Set the owner index.
51    fn set_owner_index(&mut self, index: i32);
52}
53
54/// Generic tree structure for Altium records.
55///
56/// Provides efficient navigation of parent-child relationships that are
57/// encoded via OWNERINDEX in the original flat record list.
58#[derive(Debug, Clone)]
59pub struct RecordTree<R> {
60    /// All records in the tree (indexed by RecordId).
61    records: Vec<R>,
62    /// Parent lookup: child_id -> parent_id
63    parents: HashMap<RecordId, RecordId>,
64    /// Children lookup: parent_id -> [child_ids]
65    children: HashMap<RecordId, Vec<RecordId>>,
66    /// Root records (no parent or invalid OWNERINDEX).
67    roots: Vec<RecordId>,
68}
69
70impl<R: TreeRecord> RecordTree<R> {
71    /// Build a tree from a flat list of records using OWNERINDEX relationships.
72    ///
73    /// Records with OWNERINDEX < 0 or >= len are treated as roots.
74    pub fn from_records(records: Vec<R>) -> Self {
75        let mut tree = RecordTree {
76            records,
77            parents: HashMap::new(),
78            children: HashMap::new(),
79            roots: Vec::new(),
80        };
81        tree.rebuild_relationships();
82        tree
83    }
84
85    /// Rebuild parent-child relationships from OWNERINDEX values.
86    fn rebuild_relationships(&mut self) {
87        self.parents.clear();
88        self.children.clear();
89        self.roots.clear();
90
91        let len = self.records.len();
92
93        for (idx, record) in self.records.iter().enumerate() {
94            let child_id = RecordId::new(idx as u32);
95            let owner_index = record.owner_index();
96
97            // Check if this is a root (invalid owner index)
98            if owner_index < 0 || (owner_index as usize) >= len {
99                self.roots.push(child_id);
100            } else {
101                let parent_id = RecordId::new(owner_index as u32);
102                self.parents.insert(child_id, parent_id);
103                self.children.entry(parent_id).or_default().push(child_id);
104            }
105        }
106    }
107
108    /// Get the number of records in the tree.
109    pub fn len(&self) -> usize {
110        self.records.len()
111    }
112
113    /// Check if the tree is empty.
114    pub fn is_empty(&self) -> bool {
115        self.records.is_empty()
116    }
117
118    /// Get a record by ID.
119    pub fn get(&self, id: RecordId) -> Option<&R> {
120        self.records.get(id.index() as usize)
121    }
122
123    /// Get a mutable record by ID.
124    pub fn get_mut(&mut self, id: RecordId) -> Option<&mut R> {
125        self.records.get_mut(id.index() as usize)
126    }
127
128    /// Get the record at a specific index.
129    pub fn get_by_index(&self, index: usize) -> Option<&R> {
130        self.records.get(index)
131    }
132
133    /// Iterate over all records with their IDs.
134    pub fn iter(&self) -> impl Iterator<Item = (RecordId, &R)> {
135        self.records
136            .iter()
137            .enumerate()
138            .map(|(i, r)| (RecordId::new(i as u32), r))
139    }
140
141    /// Iterate over all records mutably with their IDs.
142    pub fn iter_mut(&mut self) -> impl Iterator<Item = (RecordId, &mut R)> {
143        self.records
144            .iter_mut()
145            .enumerate()
146            .map(|(i, r)| (RecordId::new(i as u32), r))
147    }
148
149    /// Get root records (records with no valid parent).
150    pub fn roots(&self) -> impl Iterator<Item = (RecordId, &R)> {
151        self.roots
152            .iter()
153            .filter_map(move |&id| self.records.get(id.index() as usize).map(|r| (id, r)))
154    }
155
156    /// Get the number of root records.
157    pub fn root_count(&self) -> usize {
158        self.roots.len()
159    }
160
161    /// Check if a record is a root.
162    pub fn is_root(&self, id: RecordId) -> bool {
163        self.roots.contains(&id)
164    }
165
166    /// Get the parent of a record.
167    pub fn parent(&self, id: RecordId) -> Option<(RecordId, &R)> {
168        self.parents.get(&id).and_then(|&parent_id| {
169            self.records
170                .get(parent_id.index() as usize)
171                .map(|r| (parent_id, r))
172        })
173    }
174
175    /// Get the parent ID of a record (without the record itself).
176    pub fn parent_id(&self, id: RecordId) -> Option<RecordId> {
177        self.parents.get(&id).copied()
178    }
179
180    /// Get children of a record.
181    pub fn children(&self, id: RecordId) -> impl Iterator<Item = (RecordId, &R)> {
182        self.children
183            .get(&id)
184            .map(|ids| ids.as_slice())
185            .unwrap_or(&[])
186            .iter()
187            .filter_map(move |&child_id| {
188                self.records
189                    .get(child_id.index() as usize)
190                    .map(|r| (child_id, r))
191            })
192    }
193
194    /// Get the number of children for a record.
195    pub fn child_count(&self, id: RecordId) -> usize {
196        self.children.get(&id).map(|c| c.len()).unwrap_or(0)
197    }
198
199    /// Check if a record has children.
200    pub fn has_children(&self, id: RecordId) -> bool {
201        self.children
202            .get(&id)
203            .map(|c| !c.is_empty())
204            .unwrap_or(false)
205    }
206
207    /// Get all ancestors of a record (parent, grandparent, etc.).
208    pub fn ancestors(&self, id: RecordId) -> impl Iterator<Item = (RecordId, &R)> {
209        AncestorIterator {
210            tree: self,
211            current: self.parent_id(id),
212        }
213    }
214
215    /// Get all descendants of a record (children, grandchildren, etc.).
216    pub fn descendants(&self, id: RecordId) -> impl Iterator<Item = (RecordId, &R)> {
217        DescendantIterator {
218            tree: self,
219            stack: self.children.get(&id).cloned().unwrap_or_default(),
220        }
221    }
222
223    /// Get the depth of a record (0 for roots).
224    pub fn depth(&self, id: RecordId) -> usize {
225        let mut depth = 0;
226        let mut current = id;
227        while let Some(parent_id) = self.parent_id(current) {
228            depth += 1;
229            current = parent_id;
230        }
231        depth
232    }
233
234    /// Walk the tree depth-first starting from roots.
235    pub fn walk_depth_first(&self) -> TreeWalker<'_, R> {
236        TreeWalker::new(self)
237    }
238
239    /// Walk the tree depth-first starting from a specific node.
240    pub fn walk_from(&self, id: RecordId) -> TreeWalker<'_, R> {
241        TreeWalker::from_node(self, id)
242    }
243
244    /// Find records matching a predicate.
245    pub fn find<F>(&self, predicate: F) -> impl Iterator<Item = (RecordId, &R)>
246    where
247        F: Fn(&R) -> bool,
248    {
249        self.records
250            .iter()
251            .enumerate()
252            .filter(move |(_, r)| predicate(r))
253            .map(|(i, r)| (RecordId::new(i as u32), r))
254    }
255
256    /// Find the first record matching a predicate.
257    pub fn find_first<F>(&self, predicate: F) -> Option<(RecordId, &R)>
258    where
259        F: Fn(&R) -> bool,
260    {
261        self.records
262            .iter()
263            .enumerate()
264            .find(|(_, r)| predicate(r))
265            .map(|(i, r)| (RecordId::new(i as u32), r))
266    }
267
268    /// Get the path from a record to the root (inclusive).
269    pub fn path_to_root(&self, id: RecordId) -> Vec<RecordId> {
270        let mut path = vec![id];
271        let mut current = id;
272        while let Some(parent_id) = self.parent_id(current) {
273            path.push(parent_id);
274            current = parent_id;
275        }
276        path
277    }
278
279    /// Consume the tree and return the underlying records.
280    pub fn into_records(self) -> Vec<R> {
281        self.records
282    }
283
284    /// Get a reference to the underlying records slice.
285    pub fn as_slice(&self) -> &[R] {
286        &self.records
287    }
288
289    /// Add a record to the tree.
290    ///
291    /// Returns the ID of the newly added record.
292    pub fn add(&mut self, record: R) -> RecordId {
293        let id = RecordId::new(self.records.len() as u32);
294        let owner_index = record.owner_index();
295
296        self.records.push(record);
297
298        // Update relationships
299        if owner_index < 0 || (owner_index as usize) >= self.records.len() - 1 {
300            self.roots.push(id);
301        } else {
302            let parent_id = RecordId::new(owner_index as u32);
303            self.parents.insert(id, parent_id);
304            self.children.entry(parent_id).or_default().push(id);
305        }
306
307        id
308    }
309
310    /// Remove a record from the tree by ID.
311    ///
312    /// Note: This invalidates all RecordIds after the removed record.
313    /// Consider using a different approach for frequent removals.
314    pub fn remove(&mut self, id: RecordId) -> Option<R> {
315        let index = id.index() as usize;
316        if index >= self.records.len() {
317            return None;
318        }
319
320        let record = self.records.remove(index);
321
322        // Rebuild all relationships (IDs have changed)
323        self.rebuild_relationships();
324
325        Some(record)
326    }
327
328    /// Move a record to a new parent.
329    pub fn reparent(&mut self, id: RecordId, new_parent: Option<RecordId>) {
330        // Remove from old parent's children
331        if let Some(old_parent_id) = self.parents.remove(&id) {
332            if let Some(siblings) = self.children.get_mut(&old_parent_id) {
333                siblings.retain(|&child_id| child_id != id);
334            }
335        }
336
337        // Remove from roots if it was a root
338        self.roots.retain(|&root_id| root_id != id);
339
340        // Add to new parent
341        if let Some(parent_id) = new_parent {
342            self.parents.insert(id, parent_id);
343            self.children.entry(parent_id).or_default().push(id);
344
345            // Update the record's owner_index
346            if let Some(record) = self.records.get_mut(id.index() as usize) {
347                record.set_owner_index(parent_id.index() as i32);
348            }
349        } else {
350            // Make it a root
351            self.roots.push(id);
352            if let Some(record) = self.records.get_mut(id.index() as usize) {
353                record.set_owner_index(-1);
354            }
355        }
356    }
357}
358
359impl<R> Default for RecordTree<R> {
360    fn default() -> Self {
361        RecordTree {
362            records: Vec::new(),
363            parents: HashMap::new(),
364            children: HashMap::new(),
365            roots: Vec::new(),
366        }
367    }
368}
369
370/// Iterator over ancestors of a record.
371struct AncestorIterator<'a, R: TreeRecord> {
372    tree: &'a RecordTree<R>,
373    current: Option<RecordId>,
374}
375
376impl<'a, R: TreeRecord> Iterator for AncestorIterator<'a, R> {
377    type Item = (RecordId, &'a R);
378
379    fn next(&mut self) -> Option<Self::Item> {
380        let id = self.current?;
381        self.current = self.tree.parent_id(id);
382        self.tree.get(id).map(|r| (id, r))
383    }
384}
385
386/// Iterator over descendants of a record.
387struct DescendantIterator<'a, R: TreeRecord> {
388    tree: &'a RecordTree<R>,
389    stack: Vec<RecordId>,
390}
391
392impl<'a, R: TreeRecord> Iterator for DescendantIterator<'a, R> {
393    type Item = (RecordId, &'a R);
394
395    fn next(&mut self) -> Option<Self::Item> {
396        let id = self.stack.pop()?;
397
398        // Add children to stack for further iteration
399        if let Some(children) = self.tree.children.get(&id) {
400            self.stack.extend(children.iter().rev());
401        }
402
403        self.tree.get(id).map(|r| (id, r))
404    }
405}
406
407#[cfg(test)]
408mod tests {
409    use super::*;
410
411    #[derive(Debug, Clone, Default)]
412    struct TestRecord {
413        owner_index: i32,
414        value: String,
415    }
416
417    impl TreeRecord for TestRecord {
418        fn owner_index(&self) -> i32 {
419            self.owner_index
420        }
421
422        fn set_owner_index(&mut self, index: i32) {
423            self.owner_index = index;
424        }
425    }
426
427    #[test]
428    fn test_build_tree() {
429        let records = vec![
430            TestRecord {
431                owner_index: -1,
432                value: "root".to_string(),
433            },
434            TestRecord {
435                owner_index: 0,
436                value: "child1".to_string(),
437            },
438            TestRecord {
439                owner_index: 0,
440                value: "child2".to_string(),
441            },
442            TestRecord {
443                owner_index: 1,
444                value: "grandchild".to_string(),
445            },
446        ];
447
448        let tree = RecordTree::from_records(records);
449
450        assert_eq!(tree.len(), 4);
451        assert_eq!(tree.root_count(), 1);
452    }
453
454    #[test]
455    fn test_navigation() {
456        let records = vec![
457            TestRecord {
458                owner_index: -1,
459                value: "root".to_string(),
460            },
461            TestRecord {
462                owner_index: 0,
463                value: "child1".to_string(),
464            },
465            TestRecord {
466                owner_index: 0,
467                value: "child2".to_string(),
468            },
469            TestRecord {
470                owner_index: 1,
471                value: "grandchild".to_string(),
472            },
473        ];
474
475        let tree = RecordTree::from_records(records);
476
477        // Test roots
478        let roots: Vec<_> = tree.roots().collect();
479        assert_eq!(roots.len(), 1);
480        assert_eq!(roots[0].1.value, "root");
481
482        // Test children
483        let root_id = RecordId::new(0);
484        let children: Vec<_> = tree.children(root_id).collect();
485        assert_eq!(children.len(), 2);
486
487        // Test parent
488        let child_id = RecordId::new(1);
489        let parent = tree.parent(child_id);
490        assert!(parent.is_some());
491        assert_eq!(parent.unwrap().1.value, "root");
492
493        // Test depth
494        assert_eq!(tree.depth(RecordId::new(0)), 0);
495        assert_eq!(tree.depth(RecordId::new(1)), 1);
496        assert_eq!(tree.depth(RecordId::new(3)), 2);
497    }
498
499    #[test]
500    fn test_walk_depth_first() {
501        let records = vec![
502            TestRecord {
503                owner_index: -1,
504                value: "root".to_string(),
505            },
506            TestRecord {
507                owner_index: 0,
508                value: "child1".to_string(),
509            },
510            TestRecord {
511                owner_index: 0,
512                value: "child2".to_string(),
513            },
514            TestRecord {
515                owner_index: 1,
516                value: "grandchild".to_string(),
517            },
518        ];
519
520        let tree = RecordTree::from_records(records);
521
522        let walked: Vec<_> = tree.walk_depth_first().collect();
523        assert_eq!(walked.len(), 4);
524
525        // First should be root at depth 0
526        assert_eq!(walked[0].1.value, "root");
527        assert_eq!(walked[0].2, 0);
528    }
529
530    #[test]
531    fn test_ancestors() {
532        let records = vec![
533            TestRecord {
534                owner_index: -1,
535                value: "root".to_string(),
536            },
537            TestRecord {
538                owner_index: 0,
539                value: "child".to_string(),
540            },
541            TestRecord {
542                owner_index: 1,
543                value: "grandchild".to_string(),
544            },
545        ];
546
547        let tree = RecordTree::from_records(records);
548
549        let ancestors: Vec<_> = tree.ancestors(RecordId::new(2)).collect();
550        assert_eq!(ancestors.len(), 2);
551        assert_eq!(ancestors[0].1.value, "child");
552        assert_eq!(ancestors[1].1.value, "root");
553    }
554}