diff --git a/tree/src/lib.rs b/tree/src/lib.rs index 8d50e9b..2b9cdc8 100644 --- a/tree/src/lib.rs +++ b/tree/src/lib.rs @@ -60,14 +60,23 @@ impl Tree { None } + /// Convert each node of a tree from type T to type U pub fn map(&self, op: F) -> Tree where - F: FnOnce(&Node) -> Node + Copy, + F: FnOnce(&T) -> U + Copy, { + // A key part of this is to avoid recursion. There is no telling how deep a tree may go (Go + // game records can go hundreds of nodes deep), so we're going to just avoid recursion. match self { Tree::Empty => Tree::Empty, Tree::Root(root) => { - let new_root = op(root); + let new_root = Node::new(op(&root.value())); + + // This queue serves as a work list. Each node in the queue needs to be converted, + // and I've paired the node up with the one that it's supposed to be attached to. + // So, as we look at a node A, we make sure that all of its children gets added to + // the queue, and that the queue knows that the conversion of each child node + // should get attached to A. let mut queue: VecDeque<(Node, Node)> = root .children() .iter() @@ -75,7 +84,7 @@ impl Tree { .collect(); while let Some((source, dest)) = queue.pop_front() { - let res = op(&source); + let res = Node::new(op(&source.value())); dest.add_child_node(res.clone()); for child in source.children().iter() { @@ -174,7 +183,7 @@ mod tests { let n = n.add_child_value(16); let _ = n.add_child_value(17); - let tree2 = tree.map(|v| Node::new(v.value().to_string())); + let tree2 = tree.map(|v| v.to_string()); assert!(tree2.find_bfs(|val| *val == "15").is_some()); assert!(tree2.find_bfs(|val| *val == "16").is_some());