use super::{RecordId, RecordTree, TreeRecord};
pub struct TreeWalker<'a, R> {
tree: &'a RecordTree<R>,
stack: Vec<(RecordId, usize)>,
}
impl<'a, R: TreeRecord> TreeWalker<'a, R> {
pub fn new(tree: &'a RecordTree<R>) -> Self {
let stack = tree.roots.iter().rev().map(|&id| (id, 0)).collect();
TreeWalker { tree, stack }
}
pub fn from_node(tree: &'a RecordTree<R>, start: RecordId) -> Self {
let depth = tree.depth(start);
TreeWalker {
tree,
stack: vec![(start, depth)],
}
}
}
impl<'a, R: TreeRecord> Iterator for TreeWalker<'a, R> {
type Item = (RecordId, &'a R, usize);
fn next(&mut self) -> Option<Self::Item> {
let (id, depth) = self.stack.pop()?;
let record = self.tree.get(id)?;
if let Some(children) = self.tree.children.get(&id) {
for &child_id in children.iter().rev() {
self.stack.push((child_id, depth + 1));
}
}
Some((id, record, depth))
}
}
pub struct BreadthFirstWalker<'a, R> {
tree: &'a RecordTree<R>,
queue: std::collections::VecDeque<(RecordId, usize)>,
}
impl<'a, R: TreeRecord> BreadthFirstWalker<'a, R> {
pub fn new(tree: &'a RecordTree<R>) -> Self {
let queue = tree.roots.iter().map(|&id| (id, 0)).collect();
BreadthFirstWalker { tree, queue }
}
pub fn from_node(tree: &'a RecordTree<R>, start: RecordId) -> Self {
let depth = tree.depth(start);
let mut queue = std::collections::VecDeque::new();
queue.push_back((start, depth));
BreadthFirstWalker { tree, queue }
}
}
impl<'a, R: TreeRecord> Iterator for BreadthFirstWalker<'a, R> {
type Item = (RecordId, &'a R, usize);
fn next(&mut self) -> Option<Self::Item> {
let (id, depth) = self.queue.pop_front()?;
let record = self.tree.get(id)?;
if let Some(children) = self.tree.children.get(&id) {
for &child_id in children.iter() {
self.queue.push_back((child_id, depth + 1));
}
}
Some((id, record, depth))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[derive(Debug, Clone, Default)]
struct TestRecord {
owner_index: i32,
name: String,
}
impl TreeRecord for TestRecord {
fn owner_index(&self) -> i32 {
self.owner_index
}
fn set_owner_index(&mut self, index: i32) {
self.owner_index = index;
}
}
#[test]
fn test_depth_first_walk() {
let records = vec![
TestRecord {
owner_index: -1,
name: "root".to_string(),
},
TestRecord {
owner_index: 0,
name: "child1".to_string(),
},
TestRecord {
owner_index: 0,
name: "child2".to_string(),
},
TestRecord {
owner_index: 1,
name: "grandchild".to_string(),
},
];
let tree = RecordTree::from_records(records);
let walked: Vec<_> = tree
.walk_depth_first()
.map(|(_, r, d)| (r.name.clone(), d))
.collect();
assert_eq!(
walked,
vec![
("root".to_string(), 0),
("child1".to_string(), 1),
("grandchild".to_string(), 2),
("child2".to_string(), 1),
]
);
}
#[test]
fn test_breadth_first_walk() {
let records = vec![
TestRecord {
owner_index: -1,
name: "root".to_string(),
},
TestRecord {
owner_index: 0,
name: "child1".to_string(),
},
TestRecord {
owner_index: 0,
name: "child2".to_string(),
},
TestRecord {
owner_index: 1,
name: "grandchild".to_string(),
},
];
let tree = RecordTree::from_records(records);
let walker = BreadthFirstWalker::new(&tree);
let walked: Vec<_> = walker.map(|(_, r, d)| (r.name.clone(), d)).collect();
assert_eq!(
walked,
vec![
("root".to_string(), 0),
("child1".to_string(), 1),
("child2".to_string(), 1),
("grandchild".to_string(), 2),
]
);
}
}