use std::collections::VecDeque;
use crate::interface;
use crate::Tree;
use crate::tree::{self, NodeId};
pub trait TreeHelper {
fn get_element (&self, node_id : &NodeId) -> &interface::Element;
fn get_element_mut (&mut self, node_id : &NodeId) -> &mut interface::Element;
fn get_parent (&self, child : &NodeId) -> &interface::Element;
fn get_parent_mut (&mut self, child : &NodeId) -> &mut interface::Element;
fn get_parent_id (&self, child : &NodeId) -> &NodeId;
fn splice_subtree (
&mut self,
parent_id : &NodeId,
other : &Tree <interface::Element>,
other_id : &NodeId,
order : interface::CreateOrder
) -> NodeId;
fn write_formatted_names <W : std::fmt::Write> (&self, w : &mut W)
-> std::fmt::Result;
}
pub fn map_tree <T, U, F> (tree : &Tree <T>, f : F) -> Tree <U> where
F : Fn (&T) -> U
{
use tree::{InsertBehavior, Node};
let mut out = Tree::new();
if let Some (root_id) = tree.root_node_id() {
let root = tree.get (root_id).unwrap();
let new_root_id = out
.insert (Node::new (f (root.data())), InsertBehavior::AsRoot).unwrap();
let mut parent_child_ids = root.children().iter()
.map (|child_id| (new_root_id.clone(), child_id.clone()))
.collect::<VecDeque <_>>();
while let Some ((new_parent_id, old_child_id)) =
parent_child_ids.pop_front()
{
let child = tree.get (&old_child_id).unwrap();
let new_child_id = out.insert (
Node::new (f (child.data())),
InsertBehavior::UnderNode (&new_parent_id)
).unwrap();
for child_id in child.children().iter() {
parent_child_ids.push_back ((new_child_id.clone(), child_id.clone()));
}
}
}
out
}
impl TreeHelper for Tree <interface::Element> {
#[inline]
fn get_element (&self, node_id : &NodeId) -> &interface::Element {
self.get (node_id).unwrap().data()
}
#[inline]
fn get_element_mut (&mut self, node_id : &NodeId) -> &mut interface::Element {
self.get_mut (node_id).unwrap().data_mut()
}
#[inline]
fn get_parent (&self, child : &NodeId) -> &interface::Element {
self.get_element (self.get_parent_id (child))
}
#[inline]
fn get_parent_mut (&mut self, child : &NodeId) -> &mut interface::Element {
let parent_id = self.get_parent_id (child).clone();
self.get_element_mut (&parent_id)
}
#[inline]
fn get_parent_id (&self, child : &NodeId) -> &NodeId {
self.get (child).unwrap().parent().unwrap()
}
fn splice_subtree (
&mut self,
parent_id : &NodeId,
other : &Tree <interface::Element>,
other_id : &NodeId,
order : interface::CreateOrder
) -> NodeId {
use tree::Node;
use interface::CreateOrder;
let subtree_root = Node::new (other.get_element (other_id).clone());
let subtree_id = self.insert (
subtree_root, tree::InsertBehavior::UnderNode (parent_id)
).unwrap();
match order {
CreateOrder::Append => {}
CreateOrder::Prepend => {
let _ = self.make_first_sibling (&subtree_id).unwrap();
}
CreateOrder::NthSibling (n) =>
self.make_nth_sibling (&subtree_id, n as usize).unwrap()
}
for child_id in other.children_ids (other_id).unwrap() {
self.splice_subtree (&subtree_id, other, child_id, CreateOrder::Append);
}
subtree_id
}
fn write_formatted_names<W: std::fmt::Write>(&self, w: &mut W)
-> std::fmt::Result
{
if let Some(node_id) = self.root_node_id() {
let childn = 0;
let level = 0;
let last = vec![];
let mut stack = vec![(node_id, childn, level, last)];
while let Some((node_id, childn, level, last)) = stack.pop() {
debug_assert_eq!(
last.len(), level,
"each previous level should indicate whether it has reached the last node"
);
let node = self.get(node_id)
.expect("getting node of existing node ref id");
if childn == 0 {
for i in 1..level {
if last[i - 1] {
write!(w, " ")?;
} else {
write!(w, "│ ")?;
}
}
if level > 0 {
if last[level - 1] {
write!(w, "└── ")?;
} else {
write!(w, "├── ")?;
}
}
let data = node.data();
let state = match data.controller.state {
interface::controller::State::Focused => "*",
interface::controller::State::Enabled => "",
interface::controller::State::Disabled => "†"
};
writeln!(w, "{}{}", data.name, state)?;
}
let mut children = node.children().iter().skip(childn);
if let Some(child_id) = children.next() {
let mut next_last = last.clone();
if children.next().is_some() {
stack.push((node_id, childn + 1, level, last));
next_last.push(false);
} else {
next_last.push(true);
}
stack.push((child_id, 0, level + 1, next_last));
}
}
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use crate::tree::{InsertBehavior, Node};
use super::*;
#[test]
fn map_tree() {
use super::map_tree;
let mut tree = Tree::new();
let root_id = tree.insert (Node::new (0u32), InsertBehavior::AsRoot).unwrap();
let child_id = tree.insert (Node::new (1), InsertBehavior::UnderNode (&root_id))
.unwrap();
tree.insert (Node::new (2), InsertBehavior::UnderNode (&root_id)).unwrap();
tree.insert (Node::new (3), InsertBehavior::UnderNode (&child_id)).unwrap();
tree.insert (Node::new (4), InsertBehavior::UnderNode (&child_id)).unwrap();
let mut s = String::new();
tree.write_formatted (&mut s).unwrap();
println!("old tree:\n{s}");
let new_tree : Tree <String> = map_tree (&tree, |i| (*i).to_string());
let mut s = String::new();
new_tree.write_formatted (&mut s).unwrap();
println!("new tree:\n{s}");
}
}