pub mod empty; use is_tree::*; visitor! { pub enum Visitors, VisitorsMut { Root(Library visits [Module, String]), Branches( Module visits [Module, Function, String], Function visits [String], String ) } } #[derive(Debug, Default, IsTree)] #[tree(branches)] pub struct Library { #[tree(path_segment)] pub name: String, pub root_module: Module } 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() }, } } } #[derive(Debug, Default, IsTree)] #[tree(branches)] pub struct Function { #[tree(path_segment)] pub name: String } #[derive(Debug, Default, IsTree)] #[tree(branches)] pub struct Module { #[tree(path_segment)] pub name: String, pub modules: Vec, pub functions: Vec } #[test] fn branches() { let mut library = Library::mock(); library.branches_mut::<&mut String>().for_each(|s| *s = s.to_uppercase()); assert_eq!(library.branches::<&String>().map(|s| s.as_str()).collect::>(), vec!["LIBRARY"]); assert_eq!(library.branches::<&Module>().map(|module| module.name.as_str()).collect::>(), vec!["math"]); assert_eq!(library.root_module.branches::<&String>().map(|s| s.as_str()).collect::>(), vec!["math"]); assert_eq!(library.root_module.branches::<&Module>().map(|module| module.name.as_str()).collect::>(), vec!["geometry", "algebra"]); } #[test] fn get() { let mut library = Library::mock(); assert_eq!(library.branches::<&Module>().map(|branch| branch.name.as_str()).collect::>(), vec!["math"]); if let Some(module) = library.get_mut::<&mut Module>("math") { module.name = module.name.to_uppercase() } assert_eq!(library.get::<&Module>("MATH").unwrap().name, "MATH"); assert_eq!(library.branches::<&Module>().map(|branch| branch.name.as_str()).collect::>(), vec!["MATH"]); assert_eq!(library.root_module.branches::<&Module>().map(|branch| branch.name.as_str()).collect::>(), vec!["geometry", "algebra"]); if let Some(module) = library.root_module.get_mut::<&mut Module>("geometry") { module.name = module.name.to_uppercase() } assert_eq!(library.root_module.branches::<&Module>().map(|branch| branch.name.as_str()).collect::>(), vec!["GEOMETRY", "algebra"]); assert_eq!((library.root_module.get::<&Module>("algebra").unwrap()).branches::<&Function>().map(|branch| branch.name.as_str()).collect::>(), vec!["exponential"]); } #[test] fn visitor() { let mut branch = Library::mock(); let root_visitor = Visitors::from(&branch); assert_eq!(root_visitor.as_library().unwrap().value.name, "library"); assert_eq!(root_visitor.branches().filter_map(|visitor| visitor.into_module().ok()).map(|visitor| &visitor.value.name).collect::>(), vec!["math"]); let iterator: TreeIterator = TreeIterator::new(&branch); assert_eq!(iterator.filter(|visitor| !visitor.is_string()).map(|visitor| visitor.path_segment().clone()).collect::>(), vec!["exponential", "algebra", "shapes", "geometry", "math", "library"]); let mut root_visitor = VisitorsMut::from(&mut branch); root_visitor.branches_mut::().for_each(|mut visitor| { match &mut visitor { VisitorsMut::Library(visitor) => visitor.value.name = visitor.value.name.to_uppercase(), VisitorsMut::Module(visitor) => visitor.value.name = visitor.value.name.to_uppercase(), VisitorsMut::Function(visitor) => visitor.value.name = visitor.value.name.to_uppercase(), VisitorsMut::String(visitor) => *visitor.value = visitor.value.to_uppercase() } }); let root_visitor = Visitors::from(&branch); assert_eq!(root_visitor.as_library().unwrap().value.name, "LIBRARY"); assert_eq!(root_visitor.branches().filter_map(|visitor| visitor.into_module().ok()).map(|visitor| &visitor.value.name).collect::>(), vec!["MATH"]); let iterator: TreeIterator = TreeIterator::new(&branch); assert_eq!(iterator.filter(|visitor| !visitor.is_string()).map(|visitor| visitor.path_segment().clone()).collect::>(), vec!["exponential", "algebra", "shapes", "geometry", "MATH", "LIBRARY"]); let iterator: TreeIterator = TreeIterator::new(&mut branch); iterator.for_each(|mut visitor| { match &mut visitor { VisitorsMut::Library(visitor) => visitor.value.name = visitor.value.name.to_uppercase(), VisitorsMut::Module(visitor) => visitor.value.name = visitor.value.name.to_uppercase(), VisitorsMut::Function(visitor) => visitor.value.name = visitor.value.name.to_uppercase(), VisitorsMut::String(visitor) => *visitor.value = visitor.value.to_uppercase() } }); let iterator: TreeIterator = TreeIterator::new(&branch); assert_eq!(iterator.filter(|visitor| !visitor.is_string()).map(|visitor| visitor.path_segment().clone()).collect::>(), vec!["EXPONENTIAL", "ALGEBRA", "SHAPES", "GEOMETRY", "MATH", "LIBRARY"]); } #[test] fn relative_access() { let branch = Library::mock(); let library_visitor = Visitors::from(&branch); let math_visitor = library_visitor.branches::().next().unwrap(); let geometry_visitor = math_visitor.branches::().next().unwrap(); let shapes_visitor = geometry_visitor.branches::().next().unwrap(); assert_eq!(shapes_visitor.path_segment(), "shapes"); assert_eq!(shapes_visitor.parent().unwrap().path_segment(), "geometry"); assert_eq!(shapes_visitor.parent().unwrap().parent().unwrap().path_segment(), "math"); assert_eq!(shapes_visitor.root().path_segment(), "library"); assert_eq!(math_visitor.get("geometry").unwrap().path_segment(), "geometry"); assert!(library_visitor.relative(vec!["super"]).is_none()); assert_eq!(library_visitor.relative(Vec::::new()).unwrap().path_segment(), "library"); assert_eq!(library_visitor.relative(vec!["self"]).unwrap().path_segment(), "library"); assert_eq!(library_visitor.relative(vec!["root"]).unwrap().path_segment(), "library"); assert_eq!(library_visitor.relative(vec!["math"]).unwrap().path_segment(), "math"); assert_eq!(library_visitor.relative(vec!["math", "geometry", "shapes"]).unwrap().path_segment(), "shapes"); assert_eq!(math_visitor.relative(vec!["super"]).unwrap().path_segment(), "library"); assert_eq!(shapes_visitor.relative(vec!["super", "super"]).unwrap().path_segment(), "math"); assert_eq!(shapes_visitor.relative(vec!["root"]).unwrap().path_segment(), "library"); assert_eq!(library_visitor.relative(vec!["math", "algebra", "exponential"]).unwrap().path_segment(), "exponential"); } #[test] fn unsafe_mutable_relative_access() { let mut branch = Library::mock(); unsafe { let mut root_visitor = VisitorsMut::from(&mut branch); let mut geometry_visitor = root_visitor.branches_mut::().next().unwrap(); let mut shapes_visitor = geometry_visitor.branches_mut::().next().unwrap(); let mut geometry = shapes_visitor.parent_mut().unwrap(); let geometry = geometry.as_module_mut().unwrap(); geometry.value.name = geometry.value.name.to_uppercase(); let mut math = shapes_visitor.root_mut(); let math = math.as_library_mut().unwrap(); math.value.name = math.value.name.to_uppercase(); } let iterator: TreeIterator = TreeIterator::new(&branch); assert_eq!(iterator.filter(|visitor| !visitor.is_string()).map(|visitor| visitor.path_segment().clone()).collect::>(), vec!["exponential", "algebra", "shapes", "geometry", "MATH", "LIBRARY"]); let mut branch = Library::mock(); unsafe { let mut root_visitor = VisitorsMut::from(&mut branch); if let Some(mut visitor) = root_visitor.relative_mut(vec!["math", "geometry", "shapes"]) { let branch_visitor = visitor.as_module_mut().unwrap(); branch_visitor.value.name = branch_visitor.value.name.to_uppercase(); if let Some(mut visitor) = visitor.relative_mut(vec!["root"]) { let visitor = visitor.as_library_mut().unwrap(); visitor.value.name = visitor.value.name.to_uppercase(); } } } let iterator: TreeIterator = TreeIterator::new(&branch); assert_eq!(iterator.filter(|visitor| !visitor.is_string()).map(|visitor| visitor.path_segment().clone()).collect::>(), vec!["exponential", "algebra", "SHAPES", "geometry", "math", "LIBRARY"]); let mut branch = Library::mock(); unsafe { let mut root_visitor = VisitorsMut::from(&mut branch); if let Some(mut visitor) = root_visitor.relative_mut(vec!["self"]) { let branch_visitor = visitor.as_library_mut().unwrap(); branch_visitor.value.name = branch_visitor.value.name.to_uppercase(); if let Some(mut visitor) = visitor.relative_mut(vec!["math", "geometry", "shapes", "super"]) { let visitor = visitor.as_module_mut().unwrap(); visitor.value.name = visitor.value.name.to_uppercase(); } } } let iterator: TreeIterator = TreeIterator::new(&branch); assert_eq!(iterator.filter(|visitor| !visitor.is_string()).map(|visitor| visitor.path_segment().clone()).collect::>(), vec!["exponential", "algebra", "shapes", "GEOMETRY", "math", "LIBRARY"]); } impl From for Module { fn from(name: String) -> Self { Module { name, .. Default::default() } } } impl AddBranch for Module { fn add_branch(&mut self, module: Module) -> &mut Module { self.modules.push(module); self.modules.last_mut().unwrap() } } impl AddBranch for Library { fn add_branch(&mut self, module: Module) -> &mut Module { self.root_module = module; &mut self.root_module } } #[test] fn branch_fn() { let mut root = Library { name: "Root".into(), ..Default::default() }; root.branch("Branch") .branch("Leaf"); assert_eq!(TreeIterator::::new(&root).filter(|visitor| !visitor.is_string()).map(|visitor| visitor.path_segment().clone()).collect::>(), vec!["Leaf", "Branch", "Root"]); } #[test] fn branch_visitor() { // Visitor let mut library: Library = Library::mock(); let visitor: Visitors = Visitors::from(&library); let visitor: Visitor, &Module> = visitor.relative(vec!["math", "geometry"]).unwrap().into_module().unwrap(); assert_eq!((visitor.parent().unwrap() as Visitors).path_segment(), "math"); assert_eq!((visitor.root() as Visitors).path_segment(), "library"); assert_eq!((visitor.get("shapes").unwrap()).path_segment(), "shapes"); unsafe { let mut visitor: VisitorsMut = VisitorsMut::from(&mut library); let mut visitor: Visitor, &mut Module> = visitor.relative_mut(vec!["math", "geometry"]).unwrap().into_module().unwrap(); assert_eq!((visitor.parent().unwrap() as Visitors).path_segment(), "math"); assert_eq!((visitor.root() as Visitors).path_segment(), "library"); assert_eq!((visitor.get("shapes").unwrap()).path_segment(), "shapes"); visitor.parent_mut().unwrap().as_module_mut().unwrap().value.name = visitor.parent_mut().unwrap().as_module_mut().unwrap().value.name.to_uppercase(); visitor.root_mut().as_library_mut().unwrap().value.name = visitor.root().as_library_mut().unwrap().value.name.to_uppercase(); // visitor.get_mut("shapes").unwrap().as_module_mut().unwrap().value.name = visitor.get_mut("shapes").unwrap().as_module_mut().unwrap().value.name.to_uppercase(); assert_eq!((visitor.parent().unwrap() as Visitors).path_segment(), "MATH"); assert_eq!((visitor.root() as Visitors).path_segment(), "LIBRARY"); // assert_eq!((visitor.get("SHAPES").unwrap()).path_segment(), "SHAPES"); // let visitor = visitor.relative(vec!["self"]).unwrap(); // visitor.root_mut().as_library_mut().unwrap().value.name = visitor.root_mut().as_library_mut().unwrap().value.name.to_uppercase(); // assert_eq!(visitor.root().path_segment(), "LIBRARY"); } }