diff --git a/src/bin.rs b/src/bin.rs index 0e9bd5f..d334aef 100644 --- a/src/bin.rs +++ b/src/bin.rs @@ -4,6 +4,7 @@ use renderer::compile_template; use renderer::CompiledTemplate; use renderer::ContextElement; use renderer::DustRenderer; +use renderer::RenderError; use renderer::Renderable; use renderer::Walkable; use std::env; @@ -85,7 +86,7 @@ impl Renderable for serde_json::Value { } impl Walkable for serde_json::Value { - fn walk(&self, segment: &str) -> &dyn ContextElement { + fn walk(&self, segment: &str) -> Result<&dyn ContextElement, RenderError> { match self { serde_json::Value::Null => panic!("Attempted to walk to {} on a null value", segment), serde_json::Value::Bool(_boolean) => { @@ -98,7 +99,8 @@ impl Walkable for serde_json::Value { panic!("Attempted to walk to {} on a string value", segment) } serde_json::Value::Array(_arr) => todo!("Arrays not supported yet"), - serde_json::Value::Object(obj) => obj.get(segment).unwrap(), + // TODO: Handle this error better + serde_json::Value::Object(obj) => Ok(obj.get(segment).unwrap()), } } } diff --git a/src/renderer/errors.rs b/src/renderer/errors.rs index b324484..57804e9 100644 --- a/src/renderer/errors.rs +++ b/src/renderer/errors.rs @@ -1,9 +1,19 @@ +use crate::renderer::walkable::ContextElement; use std::error; use std::fmt; -#[derive(Clone)] -pub struct RenderError { - pub message: String, +pub enum RenderError<'a> { + Generic(String), + /// For when walking is absolutely impossible + CantWalk { + segment: String, + elem: &'a dyn ContextElement, + }, + /// For when walking fails (example, a missing key on a map) + WontWalk { + segment: String, + elem: &'a dyn ContextElement, + }, } #[derive(Clone)] @@ -11,19 +21,35 @@ pub struct CompileError { pub message: String, } -impl fmt::Display for RenderError { +impl fmt::Display for RenderError<'_> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Error rendering: {}", self.message) + match self { + RenderError::Generic(msg) => write!(f, "{}", msg), + RenderError::CantWalk { segment, elem } => { + write!(f, "Tried to walk to {} from {:?}", segment, elem) + } + RenderError::WontWalk { segment, elem } => { + write!(f, "Failed to walk to {} from {:?}", segment, elem) + } + } } } -impl fmt::Debug for RenderError { +impl fmt::Debug for RenderError<'_> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Error rendering: {}", self.message) + match self { + RenderError::Generic(msg) => write!(f, "{}", msg), + RenderError::CantWalk { segment, elem } => { + write!(f, "Tried to walk to {} from {:?}", segment, elem) + } + RenderError::WontWalk { segment, elem } => { + write!(f, "Failed to walk to {} from {:?}", segment, elem) + } + } } } -impl error::Error for RenderError { +impl error::Error for RenderError<'_> { fn source(&self) -> Option<&(dyn error::Error + 'static)> { None } diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index c80f1a5..8b536f9 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -5,6 +5,8 @@ mod renderable; mod renderer; mod walkable; +pub use errors::CompileError; +pub use errors::RenderError; pub use renderable::Renderable; pub use renderer::compile_template; pub use renderer::CompiledTemplate; diff --git a/src/renderer/renderer.rs b/src/renderer/renderer.rs index ac664a8..b6e4b6e 100644 --- a/src/renderer/renderer.rs +++ b/src/renderer/renderer.rs @@ -9,6 +9,7 @@ use crate::renderer::renderable::Renderable; use crate::renderer::walkable::ContextElement; use crate::renderer::walkable::Walkable; use std::collections::HashMap; +use std::error::Error; use std::ops::Index; #[derive(Clone, Debug)] @@ -47,22 +48,23 @@ impl<'a> DustRenderer<'a> { .insert(template.name.clone(), &template.template); } - pub fn render(&self, name: &str, context: &C) -> Result + pub fn render(&self, name: &str, context: &'a C) -> Result> where C: ContextElement, { let main_template = match self.templates.get(name) { Some(tmpl) => tmpl, None => { - return Err(RenderError { - message: format!("No template named {} in context", name), - }); + return Err(RenderError::Generic(format!( + "No template named {} in context", + name + ))); } }; self.render_body(&main_template.contents, context) } - fn render_body(&self, body: &Body, context: &C) -> Result + fn render_body(&self, body: &Body, context: &'a C) -> Result> where C: ContextElement, { @@ -78,14 +80,14 @@ impl<'a> DustRenderer<'a> { Ok(output) } - fn render_tag(&self, tag: &DustTag, context: &C) -> Result + fn render_tag(&self, tag: &DustTag, context: &'a C) -> Result> where C: ContextElement, { match tag { DustTag::DTComment(comment) => (), DustTag::DTReference(reference) => { - let val = walk_path(context, &reference.path.keys); + let val = walk_path(context, &reference.path.keys)?; return Ok(val.render()); } _ => (), // TODO: Implement the rest @@ -94,14 +96,17 @@ impl<'a> DustRenderer<'a> { } } -fn walk_path<'a>(context: &'a dyn ContextElement, path: &Vec<&str>) -> &'a dyn ContextElement { +fn walk_path<'a>( + context: &'a dyn ContextElement, + path: &Vec<&str>, +) -> Result<&'a dyn ContextElement, RenderError<'a>> { let mut output = context; for elem in path.iter() { - output = output.walk(elem); + output = output.walk(elem)?; } - output + Ok(output) } #[cfg(test)] @@ -133,19 +138,24 @@ mod tests { } impl Walkable for HashMap<&str, I> { - fn walk(&self, segment: &str) -> &dyn ContextElement { - self.get(segment).unwrap() + fn walk(&self, segment: &str) -> Result<&dyn ContextElement, RenderError> { + Ok(self.get(segment).unwrap()) + // TODO: Handle error here better + // self.get(segment).ok_or(RenderError::WontWalk { + // segment: segment.to_string(), + // elem: self, + // }) } } impl Walkable for &str { - fn walk(&self, _segment: &str) -> &dyn ContextElement { + fn walk(&self, _segment: &str) -> Result<&dyn ContextElement, RenderError> { panic!("Tried to walk down a str"); } } impl Walkable for u32 { - fn walk(&self, _segment: &str) -> &dyn ContextElement { + fn walk(&self, _segment: &str) -> Result<&dyn ContextElement, RenderError> { panic!("Tried to walk down a str"); } } diff --git a/src/renderer/walkable.rs b/src/renderer/walkable.rs index b861deb..d2ae81f 100644 --- a/src/renderer/walkable.rs +++ b/src/renderer/walkable.rs @@ -1,8 +1,9 @@ use super::renderable::Renderable; +use crate::renderer::errors::RenderError; use std::fmt::Debug; pub trait ContextElement: Walkable + Renderable + Debug {} pub trait Walkable { - fn walk(&self, segment: &str) -> &dyn ContextElement; + fn walk(&self, segment: &str) -> Result<&dyn ContextElement, RenderError>; }