Initial move to returning results from render calls.
This commit is contained in:
parent
d30749f709
commit
d51392fe8a
@ -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()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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<C>(&self, name: &str, context: &C) -> Result<String, RenderError>
|
||||
pub fn render<C>(&self, name: &str, context: &'a C) -> Result<String, RenderError<'a>>
|
||||
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<C>(&self, body: &Body, context: &C) -> Result<String, RenderError>
|
||||
fn render_body<C>(&self, body: &Body, context: &'a C) -> Result<String, RenderError<'a>>
|
||||
where
|
||||
C: ContextElement,
|
||||
{
|
||||
@ -78,14 +80,14 @@ impl<'a> DustRenderer<'a> {
|
||||
Ok(output)
|
||||
}
|
||||
|
||||
fn render_tag<C>(&self, tag: &DustTag, context: &C) -> Result<String, RenderError>
|
||||
fn render_tag<C>(&self, tag: &DustTag, context: &'a C) -> Result<String, RenderError<'a>>
|
||||
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<I: ContextElement> 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");
|
||||
}
|
||||
}
|
||||
|
@ -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>;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user