diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index 6d0c041..13d2ede 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -4,6 +4,7 @@ mod context_element; mod errors; mod parameters_context; mod renderer; +mod walking; pub use context_element::ContextElement; pub use context_element::Loopable; diff --git a/src/renderer/parameters_context.rs b/src/renderer/parameters_context.rs index 562933a..c2aa6d0 100644 --- a/src/renderer/parameters_context.rs +++ b/src/renderer/parameters_context.rs @@ -1,6 +1,7 @@ use crate::parser::KVPair; use crate::parser::{Filter, RValue}; use crate::renderer::context_element::ContextElement; +use crate::renderer::walking::walk_path; use crate::renderer::Loopable; use crate::renderer::RenderError; use crate::renderer::Renderable; @@ -34,20 +35,52 @@ impl<'a> ContextElement for ParametersContext<'a> {} impl<'a> Renderable for ParametersContext<'a> { fn render(&self, _filters: &Vec) -> Result { + // TODO: Would this even ever be called? Won't matter, but I'd + // like to know. Since it is injected 1 above the current + // context, we wouldn't be able to access it with `{.}`. Ok("[object Object]".to_owned()) } } impl<'a> Loopable for ParametersContext<'a> { fn get_loop_elements(&self) -> Vec<&dyn ContextElement> { - // TODO: Would this even ever be called? Won't matter, but I'd like to know. + // TODO: Would this even ever be called? Won't matter, but I'd + // like to know. Since it is injected 1 above the current + // context, we wouldn't be able to access it with `{.}`. vec![self] } } impl<'a> Walkable for ParametersContext<'a> { fn walk(&self, segment: &str) -> Result<&dyn ContextElement, WalkError> { - // TODO: Actually implement + let rval = self.params.get(segment).ok_or(WalkError::CantWalk)?; + match rval { + RValue::RVPath(path) => walk_path(self.breadcrumbs, &path.keys), + RValue::RVString(text) => Ok(text), + } + } +} + +impl ContextElement for String {} + +impl Renderable for String { + fn render(&self, _filters: &Vec) -> Result { + Ok(self.clone()) + } +} + +impl Loopable for String { + fn get_loop_elements(&self) -> Vec<&dyn ContextElement> { + if self.is_empty() { + Vec::new() + } else { + vec![self] + } + } +} + +impl Walkable for String { + fn walk(&self, segment: &str) -> Result<&dyn ContextElement, WalkError> { Err(WalkError::CantWalk) } } diff --git a/src/renderer/renderer.rs b/src/renderer/renderer.rs index 1b4314b..5a4f18e 100644 --- a/src/renderer/renderer.rs +++ b/src/renderer/renderer.rs @@ -9,6 +9,7 @@ use crate::renderer::errors::CompileError; use crate::renderer::errors::RenderError; use crate::renderer::errors::WalkError; use crate::renderer::parameters_context::ParametersContext; +use crate::renderer::walking::walk_path; use std::collections::HashMap; #[derive(Clone, Debug)] @@ -202,57 +203,6 @@ impl<'a> DustRenderer<'a> { } } -enum WalkResult<'a> { - NoWalk, - PartialWalk, - FullyWalked(&'a dyn ContextElement), -} - -fn walk_path_from_single_level<'a>( - context: &'a dyn ContextElement, - path: &Vec<&str>, -) -> WalkResult<'a> { - if path.is_empty() { - return WalkResult::FullyWalked(context); - } - - let mut walk_failure = WalkResult::NoWalk; - let mut output = context; - for elem in path.iter() { - let new_val = output.walk(elem); - match output.walk(elem) { - Err(WalkError::CantWalk { .. }) => { - return walk_failure; - } - Ok(new_val) => { - walk_failure = WalkResult::PartialWalk; - output = new_val; - } - } - } - - WalkResult::FullyWalked(output) -} - -fn walk_path<'a>( - breadcrumbs: &Vec<&'a dyn ContextElement>, - path: &'a Vec<&str>, -) -> Result<&'a dyn ContextElement, WalkError> { - for context in breadcrumbs.iter().rev() { - match walk_path_from_single_level(*context, path) { - // If no walking was done at all, keep looping - WalkResult::NoWalk => {} - // If we partially walked then stop trying to find - // anything - WalkResult::PartialWalk => { - return Err(WalkError::CantWalk); - } - WalkResult::FullyWalked(new_context) => return Ok(new_context), - } - } - Err(WalkError::CantWalk) -} - #[cfg(test)] mod tests { use super::*;