Convert everything into a tree structure that supports multi-type visitors for tree iterators and relative access.
use is_tree::*;
visitor! {
pub enum Visitors, VisitorsMut {
Root(Library visits [Module]),
Branches(
Module visits [Module, Function],
Function
)
}
}
#[derive(Debug, IsTree)]
pub struct Library {
#[tree(path_segment)] // Any ToString can go here.
pub name: String,
#[tree(branch)] // If we want only this to be a branch.
pub root_module: Module
}
#[derive(Debug, Default, IsTree)]
#[tree(branches)] // This will make all fields branches.
pub struct Module {
#[tree(path_segment)]
pub name: String,
pub modules: Vec<Module>,
pub functions: Vec<Function>
}
#[derive(Debug, Default, IsTree)]
#[tree(branches)]
pub struct Function {
#[tree(path_segment)]
pub name: String
}
impl Library {
pub fn mock() -> Self {
Library {
name: String::from("library"),
root_module: Module {
name: String::from("math"),
modules: vec![
Module {
name: String::from("geometry"),
modules: vec![Module { name: String::from("shapes"), .. Default::default() }],
.. Default::default()
},
Module {
name: String::from("algebra"),
functions: vec![Function { name: String::from("exponential") }],
.. Default::default()
},
],
.. Default::default()
},
}
}
}
fn main() {
let mut library = Library::mock();
// Getting the Module branches of the structure.
library.branches_mut::<&mut Module>().for_each(|module| module.name = module.name.to_uppercase());
library.branches::<&Module>().for_each(|module| println!("{}", module.name));
// Getting a Module of the structure.
library.get_mut::<&mut Module>("MATH").unwrap().name.push_str("EMATICS");
println!("{}", library.get::<&Module>("MATHEMATICS").unwrap().name);
// Getting an mutable tree visitor.
let iterator: TreeIterator<VisitorsMut> = TreeIterator::new(&mut library);
iterator.for_each(|mut visitor| {
match &mut visitor {
VisitorsMut::Library(visitor) => visitor.value.name = visitor.value.name.to_lowercase(),
VisitorsMut::Module(visitor) => visitor.value.name = visitor.value.name.to_lowercase(),
VisitorsMut::Function(visitor) => visitor.value.name = visitor.value.name.to_lowercase()
}
});
// Getting a constant tree visitor.
let iterator: TreeIterator<Visitors> = TreeIterator::new(&library);
iterator.for_each(|visitor| println!("{}", visitor.path_segment()));
// Getting the root visitor.
let root_visitor = Visitors::from(&library);
// Root don't have a parent.
assert!(root_visitor.parent().is_none());
// Root is the root of the structure.
assert_eq!(root_visitor.root().as_library().unwrap().value.name, "library");
// "self", "super" amd "root" are special path segments.
assert_eq!(root_visitor.relative(vec!["self"]).unwrap().path(), Path::from(vec!["library"]));
// Accessing Module structure.
assert_eq!(root_visitor.relative(vec!["mathematics"]).unwrap().as_module().unwrap().value.name, "mathematics");
// Using "super".
assert_eq!(root_visitor.relative(vec!["mathematics", "algebra", "super"]).unwrap().as_module().unwrap().value.name, "mathematics");
// Access a Function structure.
assert_eq!(root_visitor.relative(vec!["mathematics", "algebra", "exponential"]).unwrap().as_function().unwrap().value.name, "exponential");
// This is allowed.
assert_eq!(root_visitor.relative(vec!["mathematics", "algebra", "exponential", "root"]).unwrap().as_library().unwrap().value.name, "library");
// Mutably accessing the visitor's parent is unsafe because it allows you to get two mutable references to the same object.
unsafe {
let mut root_visitor = VisitorsMut::from(&mut library);
assert!(root_visitor.parent_mut().is_none());
root_visitor.root_mut().as_library_mut().unwrap().value.name = "LIBRARY".into();
root_visitor.relative_mut(vec!["mathematics"]).unwrap().as_module_mut().unwrap().value.name = "MATHEMATICS".into();
}
}