use crate::node;
use std::collections::BTreeMap;
#[derive(Debug, Default)]
pub(crate) struct RoseTree<T> {
pub(crate) elem: T,
nested: BTreeMap<node::Id, RoseTree<T>>,
}
impl<T> RoseTree<T> {
pub(crate) fn tree(&self, path: &[node::Id]) -> Option<&Self> {
let n_id = match path.first() {
None => return Some(self),
Some(&n_id) => n_id,
};
let tree = self.nested.get(&n_id)?;
tree.tree(&path[..path.len() - 1])
}
pub(crate) fn tree_mut(&mut self, path: &[node::Id]) -> &mut Self
where
T: Default,
{
let n_id = match path.first() {
None => return self,
Some(&n_id) => n_id,
};
let tree = self.nested.entry(n_id).or_default();
tree.tree_mut(&path[..path.len() - 1])
}
pub(crate) fn _map<U>(self, f: &mut impl FnMut(T) -> U) -> RoseTree<U> {
let Self { elem, nested } = self;
let elem = f(elem);
let nested = nested.into_iter().map(|(k, r)| (k, r._map(f))).collect();
RoseTree { elem, nested }
}
pub(crate) fn map_ref<'a, U>(&'a self, f: &mut impl FnMut(&'a T) -> U) -> RoseTree<U> {
let Self { elem, nested } = self;
let elem = f(elem);
let nested = nested
.into_iter()
.map(|(&k, r)| (k, r.map_ref(f)))
.collect();
RoseTree { elem, nested }
}
pub(crate) fn try_map_ref<'a, U, E>(
&'a self,
f: &mut impl FnMut(&'a T) -> Result<U, E>,
) -> Result<RoseTree<U>, E> {
let Self { elem, nested } = self;
let elem = f(elem)?;
let nested = nested
.into_iter()
.map(|(&k, r)| r.try_map_ref(f).map(|r| (k, r)))
.collect::<Result<_, _>>()?;
Ok(RoseTree { elem, nested })
}
pub(crate) fn _visit(&self, path: &[node::Id], f: &mut impl FnMut(&[node::Id], &T)) {
f(path, &self.elem);
let mut path = path.to_vec();
for (&id, tree) in &self.nested {
path.push(id);
tree._visit(&path, f);
path.pop();
}
}
pub(crate) fn try_visit<E>(
&self,
path: &[node::Id],
f: &mut impl FnMut(&[node::Id], &T) -> Result<(), E>,
) -> Result<(), E> {
f(path, &self.elem)?;
let mut path = path.to_vec();
for (&id, tree) in &self.nested {
path.push(id);
tree.try_visit(&path, f)?;
path.pop();
}
Ok(())
}
}