//! A simple tree implementation which tries to not allocate all over the place. use std::ops; use la_arena::Arena; #[derive(Default)] pub(crate) struct Tree { nodes: Arena>, current_path: Vec<(Idx, Option>)>, } pub(crate) type Idx = la_arena::Idx>; impl Tree { pub(crate) fn start(&mut self) where T: Default, { let me = self.nodes.alloc(Node::new(T::default())); if let Some((parent, last_child)) = self.current_path.last_mut() { let slot = match *last_child { Some(last_child) => &mut self.nodes[last_child].next_sibling, None => &mut self.nodes[*parent].first_child, }; let prev = slot.replace(me); assert!(prev.is_none()); *last_child = Some(me); } self.current_path.push((me, None)); } pub(crate) fn finish(&mut self, data: T) { let (me, _last_child) = self.current_path.pop().unwrap(); self.nodes[me].data = data; } pub(crate) fn root(&self) -> Option> { self.nodes.iter().next().map(|(idx, _)| idx) } pub(crate) fn children(&self, idx: Idx) -> impl Iterator> + '_ { NodeIter { nodes: &self.nodes, next: self.nodes[idx].first_child } } pub(crate) fn clear(&mut self) { self.nodes.clear(); self.current_path.clear(); } } impl ops::Index> for Tree { type Output = T; fn index(&self, index: Idx) -> &T { &self.nodes[index].data } } pub(crate) struct Node { data: T, first_child: Option>, next_sibling: Option>, } impl Node { fn new(data: T) -> Node { Node { data, first_child: None, next_sibling: None } } } struct NodeIter<'a, T> { nodes: &'a Arena>, next: Option>, } impl<'a, T> Iterator for NodeIter<'a, T> { type Item = Idx; fn next(&mut self) -> Option> { self.next.map(|next| { self.next = self.nodes[next].next_sibling; next }) } }