diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index 6f91eb7..c80f1a5 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -3,8 +3,11 @@ mod errors; mod renderable; mod renderer; +mod walkable; pub use renderable::Renderable; pub use renderer::compile_template; pub use renderer::CompiledTemplate; pub use renderer::DustRenderer; +pub use walkable::ContextElement; +pub use walkable::Walkable; diff --git a/src/renderer/renderer.rs b/src/renderer/renderer.rs index 99f3aba..f40ecdc 100644 --- a/src/renderer/renderer.rs +++ b/src/renderer/renderer.rs @@ -5,6 +5,8 @@ use crate::parser::TemplateElement; use crate::renderer::errors::CompileError; use crate::renderer::errors::RenderError; use crate::renderer::renderable::Renderable; +use crate::renderer::walkable::ContextElement; +use crate::renderer::walkable::Walkable; use std::collections::HashMap; use std::ops::Index; @@ -93,3 +95,85 @@ impl<'a> DustRenderer<'a> { Ok("".to_owned()) } } + +fn walk_path<'a>(context: &'a dyn ContextElement, path: &Vec<&str>) -> &'a dyn ContextElement { + let mut output = context; + + for elem in path.iter() { + output = output.walk(elem); + } + + output +} + +#[cfg(test)] +mod tests { + use super::*; + + impl ContextElement for u32 {} + impl ContextElement for &str {} + impl ContextElement for HashMap<&str, I> {} + + impl Renderable for u32 { + fn render(&self) -> std::string::String { + self.to_string() + } + } + + impl Renderable for &str { + fn render(&self) -> std::string::String { + self.to_string() + } + } + + impl Renderable for HashMap<&str, I> { + fn render(&self) -> std::string::String { + panic!("Attempted to render a hashmap"); + } + } + + impl Walkable for HashMap<&str, I> { + fn walk(&self, segment: &str) -> &dyn ContextElement { + self.get(segment).unwrap() + } + } + + impl Walkable for &str { + fn walk(&self, _segment: &str) -> &dyn ContextElement { + panic!("Tried to walk down a str"); + } + } + + impl Walkable for u32 { + fn walk(&self, _segment: &str) -> &dyn ContextElement { + panic!("Tried to walk down a str"); + } + } + + #[test] + fn test_walk_path() { + let context: HashMap<&str, &str> = + [("cat", "kitty"), ("dog", "doggy"), ("tiger", "murderkitty")] + .iter() + .cloned() + .collect(); + let number_context: HashMap<&str, u32> = [("cat", 1), ("dog", 2), ("tiger", 3)] + .iter() + .cloned() + .collect(); + let deep_context: HashMap<&str, HashMap<&str, &str>> = [ + ("cat", [("food", "meat")].iter().cloned().collect()), + ("dog", [("food", "meat")].iter().cloned().collect()), + ("tiger", [("food", "people")].iter().cloned().collect()), + ] + .iter() + .cloned() + .collect(); + assert_eq!(walk_path(&context, &vec!["cat"]).render(), "kitty"); + assert_eq!(walk_path(&number_context, &vec!["tiger"]).render(), "3"); + assert_eq!( + walk_path(&deep_context, &vec!["tiger", "food"]).render(), + "people" + ); + } +} diff --git a/src/renderer/walkable.rs b/src/renderer/walkable.rs new file mode 100644 index 0000000..b861deb --- /dev/null +++ b/src/renderer/walkable.rs @@ -0,0 +1,8 @@ +use super::renderable::Renderable; +use std::fmt::Debug; + +pub trait ContextElement: Walkable + Renderable + Debug {} + +pub trait Walkable { + fn walk(&self, segment: &str) -> &dyn ContextElement; +}