From 0d30e2d5c2f3e03e4fd8da92a89b807895a3ae70 Mon Sep 17 00:00:00 2001 From: Ning Sun Date: Sun, 31 Dec 2023 17:27:29 +0800 Subject: [PATCH 1/6] refactor: move more errors types into RenderErrorReason --- examples/error.rs | 20 +++++------ src/context.rs | 9 +++-- src/error.rs | 72 ++++++++++++++++++---------------------- src/helpers/scripting.rs | 12 ++++--- src/registry.rs | 13 ++++---- src/render.rs | 3 +- 6 files changed, 63 insertions(+), 66 deletions(-) diff --git a/examples/error.rs b/examples/error.rs index 672c4bc1d..a213d9901 100644 --- a/examples/error.rs +++ b/examples/error.rs @@ -30,14 +30,8 @@ pub fn error_helper( .param(0) .ok_or(RenderErrorReason::ParamNotFoundForIndex("error", 0))?; match param.value().as_str() { - Some("db") => Err(RenderError::from_error( - "helper error", - HelperError::DbError, - )), - Some("api") => Err(RenderError::from_error( - "helper error", - HelperError::ApiError, - )), + Some("db") => Err(RenderErrorReason::NestedError(Box::new(HelperError::DbError)).into()), + Some("api") => Err(RenderErrorReason::NestedError(Box::new(HelperError::ApiError)).into()), _ => Ok(()), } } @@ -76,10 +70,12 @@ fn main() -> Result<(), Box> { let e2 = handlebars .render_template("{{err \"db\"}}", &json!({})) .unwrap_err(); - // down-casting the error to user defined type - match e2.source().and_then(|e| e.downcast_ref::()) { - Some(HelperError::DbError) => { - println!("Detected error from helper: db error",) + // get nested error to from `RenderError` + match e2.reason() { + Some(RenderErrorReason::NestedError(e)) => { + if let Some(HelperError::DbError) = e.downcast_ref::() { + println!("Detected error from helper: db error",) + } } _ => {} } diff --git a/src/context.rs b/src/context.rs index 6b5cfffba..957d19ef5 100644 --- a/src/context.rs +++ b/src/context.rs @@ -4,7 +4,7 @@ use serde::Serialize; use serde_json::value::{to_value, Map, Value as Json}; use crate::block::{BlockContext, BlockParamHolder}; -use crate::error::RenderError; +use crate::error::{RenderError, RenderErrorReason}; use crate::grammar::Rule; use crate::json::path::*; use crate::json::value::ScopedJson; @@ -116,7 +116,10 @@ fn parse_json_visitor<'a>( fn get_data<'a>(d: Option<&'a Json>, p: &str) -> Result, RenderError> { let result = match d { - Some(Json::Array(l)) => p.parse::().map(|idx_u| l.get(idx_u))?, + Some(Json::Array(l)) => p + .parse::() + .map(|idx_u| l.get(idx_u)) + .map_err(|_| RenderErrorReason::InvalidJsonIndex(p.to_owned()))?, Some(Json::Object(m)) => m.get(p), Some(_) => None, None => None, @@ -160,7 +163,7 @@ impl Context { /// Create a context with given data pub fn wraps(e: T) -> Result { to_value(e) - .map_err(RenderError::from) + .map_err(|e| RenderErrorReason::SerdeError(e).into()) .map(|d| Context { data: d }) } diff --git a/src/error.rs b/src/error.rs index 97de3f94d..69edb8e85 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,7 +1,6 @@ use std::error::Error as StdError; use std::fmt::{self, Write}; use std::io::Error as IOError; -use std::num::ParseIntError; use std::string::FromUtf8Error; use serde_json::error::Error as SerdeError; @@ -21,7 +20,7 @@ pub struct RenderError { pub line_no: Option, pub column_no: Option, #[source] - cause: Option>, + cause: Option, unimplemented: bool, // backtrace: Backtrace, } @@ -44,31 +43,13 @@ impl fmt::Display for RenderError { impl From for RenderError { fn from(e: IOError) -> RenderError { - RenderError::from_error("Cannot generate output.", e) - } -} - -impl From for RenderError { - fn from(e: SerdeError) -> RenderError { - RenderError::from_error("Failed to access JSON data.", e) + RenderErrorReason::IOError(e).into() } } impl From for RenderError { - fn from(e: FromUtf8Error) -> RenderError { - RenderError::from_error("Failed to generate bytes.", e) - } -} - -impl From for RenderError { - fn from(e: ParseIntError) -> RenderError { - RenderError::from_error("Cannot access array/vector with string index.", e) - } -} - -impl From for RenderError { - fn from(e: TemplateError) -> RenderError { - RenderError::from_error("Failed to parse template.", e) + fn from(e: FromUtf8Error) -> Self { + RenderErrorReason::Utf8Error(e).into() } } @@ -77,6 +58,8 @@ impl From for RenderError { pub enum RenderErrorReason { #[error("Template not found {0}")] TemplateNotFound(String), + #[error("Failed to parse template {0}")] + TemplateError(#[from] TemplateError), #[error("Failed to access variable in strict mode {0:?}")] MissingVariable(Option), #[error("Partial not found {0}")] @@ -103,27 +86,33 @@ pub enum RenderErrorReason { BlockContentRequired, #[error("Invalid json path {0}")] InvalidJsonPath(String), + #[error("Cannot access array/vector with string index, {0}")] + InvalidJsonIndex(String), + #[error("Failed to access JSON data: {0}")] + SerdeError(#[from] SerdeError), + #[error("IO Error: {0}")] + IOError(#[from] IOError), + #[error("FromUtf8Error: {0}")] + Utf8Error(#[from] FromUtf8Error), + #[error("Nested error: {0}")] + NestedError(Box), + #[cfg(feature = "script_helper")] + #[error("Cannot convert data to Rhai dynamic: {0}")] + ScriptValueError(#[from] Box), + #[cfg(feature = "script_helper")] + #[error("Failed to load rhai script: {0}")] + ScriptLoadError(#[from] ScriptError), #[error("{0}")] Other(String), } impl From for RenderError { fn from(e: RenderErrorReason) -> RenderError { - RenderError::from_error(&e.to_string(), e) - } -} - -#[cfg(feature = "script_helper")] -impl From> for RenderError { - fn from(e: Box) -> RenderError { - RenderError::from_error("Cannot convert data to Rhai dynamic", e) - } -} - -#[cfg(feature = "script_helper")] -impl From for RenderError { - fn from(e: ScriptError) -> RenderError { - RenderError::from_error("Failed to load rhai script", e) + RenderError { + desc: e.to_string(), + cause: Some(e), + ..Default::default() + } } } @@ -147,13 +136,14 @@ impl RenderError { RenderErrorReason::MissingVariable(path.map(|p| p.to_owned())).into() } + #[deprecated(since = "5.0.0", note = "Use RenderErrorReason::NestedError instead")] pub fn from_error(error_info: &str, cause: E) -> RenderError where E: StdError + Send + Sync + 'static, { RenderError { desc: error_info.to_owned(), - cause: Some(Box::new(cause)), + cause: Some(RenderErrorReason::NestedError(Box::new(cause))), ..Default::default() } } @@ -162,6 +152,10 @@ impl RenderError { pub(crate) fn is_unimplemented(&self) -> bool { self.unimplemented } + + pub fn reason(&self) -> Option<&RenderErrorReason> { + self.cause.as_ref() + } } /// Template parsing error diff --git a/src/helpers/scripting.rs b/src/helpers/scripting.rs index 28ce927fd..dc901cf98 100644 --- a/src/helpers/scripting.rs +++ b/src/helpers/scripting.rs @@ -1,7 +1,7 @@ use std::collections::{BTreeMap, HashMap}; use crate::context::Context; -use crate::error::RenderError; +use crate::error::{RenderError, RenderErrorReason}; use crate::helpers::HelperDef; use crate::json::value::{PathAndJson, ScopedJson}; use crate::registry::Registry; @@ -23,13 +23,15 @@ fn call_script_helper<'reg: 'rc, 'rc>( engine: &Engine, script: &AST, ) -> Result, RenderError> { - let params: Dynamic = to_dynamic(params.iter().map(|p| p.value()).collect::>())?; + let params: Dynamic = to_dynamic(params.iter().map(|p| p.value()).collect::>()) + .map_err(RenderErrorReason::from)?; let hash: Dynamic = to_dynamic( hash.iter() .map(|(k, v)| ((*k).to_owned(), v.value())) .collect::>(), - )?; + ) + .map_err(RenderErrorReason::from)?; let mut scope = Scope::new(); scope.push_dynamic("params", params); @@ -37,9 +39,9 @@ fn call_script_helper<'reg: 'rc, 'rc>( let result = engine .eval_ast_with_scope::(&mut scope, script) - .map_err(RenderError::from)?; + .map_err(RenderErrorReason::from)?; - let result_json: Json = from_dynamic(&result)?; + let result_json: Json = from_dynamic(&result).map_err(RenderErrorReason::from)?; Ok(ScopedJson::Derived(result_json)) } diff --git a/src/registry.rs b/src/registry.rs index 4ea050e4d..4ad66eccc 100644 --- a/src/registry.rs +++ b/src/registry.rs @@ -11,14 +11,13 @@ use crate::context::Context; use crate::decorators::{self, DecoratorDef}; #[cfg(feature = "script_helper")] use crate::error::ScriptError; -use crate::error::{RenderError, TemplateError}; +use crate::error::{RenderError, RenderErrorReason, TemplateError}; use crate::helpers::{self, HelperDef}; use crate::output::{Output, StringOutput, WriteOutput}; use crate::render::{RenderContext, Renderable}; use crate::sources::{FileSource, Source}; use crate::support::str::{self, StringWriter}; use crate::template::{Template, TemplateOptions}; -use crate::RenderErrorReason; #[cfg(feature = "dir_source")] use walkdir::WalkDir; @@ -597,7 +596,7 @@ impl<'reg> Registry<'reg> { ) }) .map(Cow::Owned) - .map_err(RenderError::from); + .map_err(|e| RenderErrorReason::from(e).into()); Some(r) } else { self.templates.get(name).map(|t| Ok(Cow::Borrowed(t))) @@ -633,7 +632,7 @@ impl<'reg> Registry<'reg> { }) as Box; Ok(Some(helper.into())) }) - .map_err(RenderError::from); + .map_err(|e| RenderError::from(RenderErrorReason::from(e))); } Ok(self.helpers.get(name).cloned()) @@ -755,7 +754,8 @@ impl<'reg> Registry<'reg> { prevent_indent: self.prevent_indent, ..Default::default() }, - )?; + ) + .map_err(RenderErrorReason::from)?; let mut out = StringOutput::new(); { @@ -783,7 +783,8 @@ impl<'reg> Registry<'reg> { prevent_indent: self.prevent_indent, ..Default::default() }, - )?; + ) + .map_err(RenderErrorReason::from)?; let mut render_context = RenderContext::new(None); let mut out = WriteOutput::new(writer); tpl.render(self, ctx, &mut render_context, &mut out) diff --git a/src/render.rs b/src/render.rs index 518e1aeef..4216dd4e7 100644 --- a/src/render.rs +++ b/src/render.rs @@ -542,7 +542,8 @@ pub trait Renderable { ) -> Result { let mut so = StringOutput::new(); self.render(registry, ctx, rc, &mut so)?; - so.into_string().map_err(RenderError::from) + so.into_string() + .map_err(|e| RenderErrorReason::from(e).into()) } } From d06e07120c22a6e4a5ceab0433a503bf25beeb46 Mon Sep 17 00:00:00 2001 From: Ning Sun Date: Sun, 31 Dec 2023 17:38:27 +0800 Subject: [PATCH 2/6] refactor: improve access to nested error in RenderError --- examples/error.rs | 8 +++----- src/error.rs | 52 +++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 46 insertions(+), 14 deletions(-) diff --git a/examples/error.rs b/examples/error.rs index a213d9901..0ea8f0e4b 100644 --- a/examples/error.rs +++ b/examples/error.rs @@ -71,11 +71,9 @@ fn main() -> Result<(), Box> { .render_template("{{err \"db\"}}", &json!({})) .unwrap_err(); // get nested error to from `RenderError` - match e2.reason() { - Some(RenderErrorReason::NestedError(e)) => { - if let Some(HelperError::DbError) = e.downcast_ref::() { - println!("Detected error from helper: db error",) - } + match e2.source().and_then(|e| e.downcast_ref::()) { + Some(HelperError::DbError) => { + println!("Detected error from helper: db error",) } _ => {} } diff --git a/src/error.rs b/src/error.rs index 69edb8e85..294a4fdc1 100644 --- a/src/error.rs +++ b/src/error.rs @@ -13,13 +13,12 @@ use walkdir::Error as WalkdirError; use rhai::{EvalAltResult, ParseError}; /// Error when rendering data on template. -#[derive(Debug, Default, Error)] +#[derive(Debug, Default)] pub struct RenderError { pub desc: String, pub template_name: Option, pub line_no: Option, pub column_no: Option, - #[source] cause: Option, unimplemented: bool, // backtrace: Backtrace, @@ -59,7 +58,11 @@ pub enum RenderErrorReason { #[error("Template not found {0}")] TemplateNotFound(String), #[error("Failed to parse template {0}")] - TemplateError(#[from] TemplateError), + TemplateError( + #[from] + #[source] + TemplateError, + ), #[error("Failed to access variable in strict mode {0:?}")] MissingVariable(Option), #[error("Partial not found {0}")] @@ -89,19 +92,39 @@ pub enum RenderErrorReason { #[error("Cannot access array/vector with string index, {0}")] InvalidJsonIndex(String), #[error("Failed to access JSON data: {0}")] - SerdeError(#[from] SerdeError), + SerdeError( + #[from] + #[source] + SerdeError, + ), #[error("IO Error: {0}")] - IOError(#[from] IOError), + IOError( + #[from] + #[source] + IOError, + ), #[error("FromUtf8Error: {0}")] - Utf8Error(#[from] FromUtf8Error), + Utf8Error( + #[from] + #[source] + FromUtf8Error, + ), #[error("Nested error: {0}")] - NestedError(Box), + NestedError(#[source] Box), #[cfg(feature = "script_helper")] #[error("Cannot convert data to Rhai dynamic: {0}")] - ScriptValueError(#[from] Box), + ScriptValueError( + #[from] + #[source] + Box, + ), #[cfg(feature = "script_helper")] #[error("Failed to load rhai script: {0}")] - ScriptLoadError(#[from] ScriptError), + ScriptLoadError( + #[from] + #[source] + ScriptError, + ), #[error("{0}")] Other(String), } @@ -153,11 +176,22 @@ impl RenderError { self.unimplemented } + /// Get `RenderErrorReason` for this error pub fn reason(&self) -> Option<&RenderErrorReason> { self.cause.as_ref() } } +impl StdError for RenderError { + fn description(&self) -> &str { + &self.desc + } + + fn source(&self) -> Option<&(dyn StdError + 'static)> { + self.reason().and_then(|e| e.source()) + } +} + /// Template parsing error #[derive(Debug, Error)] pub enum TemplateErrorReason { From 9c14b322a982b3c5e126623234611c5afe20e5de Mon Sep 17 00:00:00 2001 From: Ning Sun Date: Sun, 31 Dec 2023 18:04:30 +0800 Subject: [PATCH 3/6] refactor: resolve lint issue on error size --- src/error.rs | 37 +++++++++++++++++++------------------ src/registry.rs | 6 +++--- 2 files changed, 22 insertions(+), 21 deletions(-) diff --git a/src/error.rs b/src/error.rs index 294a4fdc1..12b273669 100644 --- a/src/error.rs +++ b/src/error.rs @@ -15,17 +15,21 @@ use rhai::{EvalAltResult, ParseError}; /// Error when rendering data on template. #[derive(Debug, Default)] pub struct RenderError { - pub desc: String, pub template_name: Option, pub line_no: Option, pub column_no: Option, - cause: Option, + cause: Option>, unimplemented: bool, // backtrace: Backtrace, } impl fmt::Display for RenderError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + let desc = self + .cause + .as_ref() + .map(|e| e.to_string()) + .unwrap_or_else(|| "".to_owned()); match (self.line_no, self.column_no) { (Some(line), Some(col)) => write!( f, @@ -33,9 +37,9 @@ impl fmt::Display for RenderError { self.template_name.as_deref().unwrap_or("Unnamed template"), line, col, - self.desc + desc ), - _ => write!(f, "{}", self.desc), + _ => write!(f, "{}", desc), } } } @@ -52,6 +56,12 @@ impl From for RenderError { } } +impl From for RenderError { + fn from(e: TemplateError) -> Self { + RenderErrorReason::TemplateError(e).into() + } +} + /// Template rendering error #[derive(Debug, Error)] pub enum RenderErrorReason { @@ -132,8 +142,7 @@ pub enum RenderErrorReason { impl From for RenderError { fn from(e: RenderErrorReason) -> RenderError { RenderError { - desc: e.to_string(), - cause: Some(e), + cause: Some(Box::new(e)), ..Default::default() } } @@ -142,10 +151,7 @@ impl From for RenderError { impl RenderError { #[deprecated(since = "5.0.0", note = "Use RenderErrorReason instead")] pub fn new>(desc: T) -> RenderError { - RenderError { - desc: desc.as_ref().to_owned(), - ..Default::default() - } + RenderErrorReason::Other(desc.as_ref().to_string()).into() } pub(crate) fn unimplemented() -> RenderError { @@ -160,13 +166,12 @@ impl RenderError { } #[deprecated(since = "5.0.0", note = "Use RenderErrorReason::NestedError instead")] - pub fn from_error(error_info: &str, cause: E) -> RenderError + pub fn from_error(_error_info: &str, cause: E) -> RenderError where E: StdError + Send + Sync + 'static, { RenderError { - desc: error_info.to_owned(), - cause: Some(RenderErrorReason::NestedError(Box::new(cause))), + cause: Some(Box::new(RenderErrorReason::NestedError(Box::new(cause)))), ..Default::default() } } @@ -178,15 +183,11 @@ impl RenderError { /// Get `RenderErrorReason` for this error pub fn reason(&self) -> Option<&RenderErrorReason> { - self.cause.as_ref() + self.cause.as_ref().map(|e| e.as_ref()) } } impl StdError for RenderError { - fn description(&self) -> &str { - &self.desc - } - fn source(&self) -> Option<&(dyn StdError + 'static)> { self.reason().and_then(|e| e.source()) } diff --git a/src/registry.rs b/src/registry.rs index 4ad66eccc..b3204947c 100644 --- a/src/registry.rs +++ b/src/registry.rs @@ -596,7 +596,7 @@ impl<'reg> Registry<'reg> { ) }) .map(Cow::Owned) - .map_err(|e| RenderErrorReason::from(e).into()); + .map_err(RenderError::from); Some(r) } else { self.templates.get(name).map(|t| Ok(Cow::Borrowed(t))) @@ -755,7 +755,7 @@ impl<'reg> Registry<'reg> { ..Default::default() }, ) - .map_err(RenderErrorReason::from)?; + .map_err(RenderError::from)?; let mut out = StringOutput::new(); { @@ -784,7 +784,7 @@ impl<'reg> Registry<'reg> { ..Default::default() }, ) - .map_err(RenderErrorReason::from)?; + .map_err(RenderError::from)?; let mut render_context = RenderContext::new(None); let mut out = WriteOutput::new(writer); tpl.render(self, ctx, &mut render_context, &mut out) From b7fabb40ba907c1e5cfc7282069071297ccb300c Mon Sep 17 00:00:00 2001 From: Ning Sun Date: Sun, 31 Dec 2023 18:14:28 +0800 Subject: [PATCH 4/6] test: update tests for accessing to reason --- src/helpers/string_helpers/mod.rs | 7 ++----- src/registry.rs | 7 ++----- tests/subexpression.rs | 7 +------ 3 files changed, 5 insertions(+), 16 deletions(-) diff --git a/src/helpers/string_helpers/mod.rs b/src/helpers/string_helpers/mod.rs index 25621ee9b..e31b6d3e3 100644 --- a/src/helpers/string_helpers/mod.rs +++ b/src/helpers/string_helpers/mod.rs @@ -117,7 +117,7 @@ mod tests { define_case_helpers_test_cases!("trainCase", test_train_case, ("train case", "Train-Case"),); #[test] - fn test_invlaid_input() { + fn test_invalid_input() { use crate::error::RenderErrorReason; use std::error::Error; @@ -126,10 +126,7 @@ mod tests { .render_template("{{snakeCase 1}}", &json!({})) .unwrap_err(); assert!(matches!( - err.source() - .unwrap() - .downcast_ref::() - .unwrap(), + err.reason().unwrap(), RenderErrorReason::ParamTypeMismatchForName(_, _, _) )); } diff --git a/src/registry.rs b/src/registry.rs index b3204947c..b229ba49d 100644 --- a/src/registry.rs +++ b/src/registry.rs @@ -834,7 +834,6 @@ mod test { use crate::render::{Helper, RenderContext, Renderable}; use crate::support::str::StringWriter; use crate::template::Template; - use std::error::Error; use std::fs::File; use std::io::Write; use tempfile::tempdir; @@ -1161,8 +1160,7 @@ mod test { assert_eq!(render_error.column_no.unwrap(), 26); assert_eq!( render_error - .source() - .and_then(|e| e.downcast_ref::()) + .reason() .and_then(|e| match e { RenderErrorReason::MissingVariable(path) => path.to_owned(), _ => unreachable!(), @@ -1184,8 +1182,7 @@ mod test { assert_eq!(render_error2.column_no.unwrap(), 31); assert_eq!( render_error2 - .source() - .and_then(|e| e.downcast_ref::()) + .reason() .and_then(|e| match e { RenderErrorReason::MissingVariable(path) => path.to_owned(), _ => unreachable!(), diff --git a/tests/subexpression.rs b/tests/subexpression.rs index bcd4baa0d..8c3b6acf1 100644 --- a/tests/subexpression.rs +++ b/tests/subexpression.rs @@ -2,7 +2,6 @@ extern crate handlebars; #[macro_use] extern crate serde_json; -use std::error::Error; use std::sync::atomic::{AtomicU16, Ordering}; use std::sync::Arc; @@ -82,11 +81,7 @@ fn invalid_json_path() { let hbs = Handlebars::new(); let error = hbs.render_template("{{x[]@this}}", &data).unwrap_err(); - let cause = error - .source() - .unwrap() - .downcast_ref::() - .unwrap(); + let cause = error.reason().unwrap(); assert!(matches!(cause, RenderErrorReason::HelperNotFound(_))); } From 4cf48a9b44083c16c81ea90795e77bc4b708a520 Mon Sep 17 00:00:00 2001 From: Ning Sun Date: Sun, 31 Dec 2023 18:25:37 +0800 Subject: [PATCH 5/6] refactor: remove option on RenderErrorReason --- src/error.rs | 40 +++++++++++++------------------ src/helpers/mod.rs | 4 ++-- src/helpers/string_helpers/mod.rs | 3 +-- src/registry.rs | 22 +++++++---------- tests/subexpression.rs | 2 +- 5 files changed, 28 insertions(+), 43 deletions(-) diff --git a/src/error.rs b/src/error.rs index 12b273669..b99b03e23 100644 --- a/src/error.rs +++ b/src/error.rs @@ -13,23 +13,20 @@ use walkdir::Error as WalkdirError; use rhai::{EvalAltResult, ParseError}; /// Error when rendering data on template. -#[derive(Debug, Default)] +#[derive(Debug)] pub struct RenderError { pub template_name: Option, pub line_no: Option, pub column_no: Option, - cause: Option>, + cause: Box, unimplemented: bool, // backtrace: Backtrace, } impl fmt::Display for RenderError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { - let desc = self - .cause - .as_ref() - .map(|e| e.to_string()) - .unwrap_or_else(|| "".to_owned()); + let desc = self.cause.to_string(); + match (self.line_no, self.column_no) { (Some(line), Some(col)) => write!( f, @@ -135,6 +132,8 @@ pub enum RenderErrorReason { #[source] ScriptError, ), + #[error("Unimplemented")] + Unimplemented, #[error("{0}")] Other(String), } @@ -142,8 +141,11 @@ pub enum RenderErrorReason { impl From for RenderError { fn from(e: RenderErrorReason) -> RenderError { RenderError { - cause: Some(Box::new(e)), - ..Default::default() + template_name: None, + line_no: None, + column_no: None, + cause: Box::new(e), + unimplemented: false, } } } @@ -154,13 +156,6 @@ impl RenderError { RenderErrorReason::Other(desc.as_ref().to_string()).into() } - pub(crate) fn unimplemented() -> RenderError { - RenderError { - unimplemented: true, - ..Default::default() - } - } - pub fn strict_error(path: Option<&String>) -> RenderError { RenderErrorReason::MissingVariable(path.map(|p| p.to_owned())).into() } @@ -170,26 +165,23 @@ impl RenderError { where E: StdError + Send + Sync + 'static, { - RenderError { - cause: Some(Box::new(RenderErrorReason::NestedError(Box::new(cause)))), - ..Default::default() - } + RenderErrorReason::NestedError(Box::new(cause)).into() } #[inline] pub(crate) fn is_unimplemented(&self) -> bool { - self.unimplemented + matches!(*self.cause, RenderErrorReason::Unimplemented) } /// Get `RenderErrorReason` for this error - pub fn reason(&self) -> Option<&RenderErrorReason> { - self.cause.as_ref().map(|e| e.as_ref()) + pub fn reason(&self) -> &RenderErrorReason { + self.cause.as_ref() } } impl StdError for RenderError { fn source(&self) -> Option<&(dyn StdError + 'static)> { - self.reason().and_then(|e| e.source()) + Some(self.reason()) } } diff --git a/src/helpers/mod.rs b/src/helpers/mod.rs index aae1b5192..de69e20e7 100644 --- a/src/helpers/mod.rs +++ b/src/helpers/mod.rs @@ -1,5 +1,5 @@ use crate::context::Context; -use crate::error::RenderError; +use crate::error::{RenderError, RenderErrorReason}; use crate::json::value::ScopedJson; use crate::output::Output; use crate::registry::Registry; @@ -95,7 +95,7 @@ pub trait HelperDef { _: &'rc Context, _: &mut RenderContext<'reg, 'rc>, ) -> Result, RenderError> { - Err(RenderError::unimplemented()) + Err(RenderErrorReason::Unimplemented.into()) } /// A complex version of helper interface. diff --git a/src/helpers/string_helpers/mod.rs b/src/helpers/string_helpers/mod.rs index e31b6d3e3..5b289a31d 100644 --- a/src/helpers/string_helpers/mod.rs +++ b/src/helpers/string_helpers/mod.rs @@ -119,14 +119,13 @@ mod tests { #[test] fn test_invalid_input() { use crate::error::RenderErrorReason; - use std::error::Error; let hbs = crate::registry::Registry::new(); let err = hbs .render_template("{{snakeCase 1}}", &json!({})) .unwrap_err(); assert!(matches!( - err.reason().unwrap(), + err.reason(), RenderErrorReason::ParamTypeMismatchForName(_, _, _) )); } diff --git a/src/registry.rs b/src/registry.rs index b229ba49d..1f4feab63 100644 --- a/src/registry.rs +++ b/src/registry.rs @@ -1159,13 +1159,10 @@ mod test { .unwrap_err(); assert_eq!(render_error.column_no.unwrap(), 26); assert_eq!( - render_error - .reason() - .and_then(|e| match e { - RenderErrorReason::MissingVariable(path) => path.to_owned(), - _ => unreachable!(), - }) - .unwrap(), + match render_error.reason() { + RenderErrorReason::MissingVariable(path) => path.as_ref().unwrap(), + _ => unreachable!(), + }, "the_key_never_exists" ); @@ -1181,13 +1178,10 @@ mod test { .unwrap_err(); assert_eq!(render_error2.column_no.unwrap(), 31); assert_eq!( - render_error2 - .reason() - .and_then(|e| match e { - RenderErrorReason::MissingVariable(path) => path.to_owned(), - _ => unreachable!(), - }) - .unwrap(), + match render_error2.reason() { + RenderErrorReason::MissingVariable(path) => path.as_ref().unwrap(), + _ => unreachable!(), + }, "this.[3]" ) } diff --git a/tests/subexpression.rs b/tests/subexpression.rs index 8c3b6acf1..766fe0f90 100644 --- a/tests/subexpression.rs +++ b/tests/subexpression.rs @@ -81,7 +81,7 @@ fn invalid_json_path() { let hbs = Handlebars::new(); let error = hbs.render_template("{{x[]@this}}", &data).unwrap_err(); - let cause = error.reason().unwrap(); + let cause = error.reason(); assert!(matches!(cause, RenderErrorReason::HelperNotFound(_))); } From 0ad81718ddb7d484dc563242e7138c06bf08b59a Mon Sep 17 00:00:00 2001 From: Ning Sun Date: Sun, 31 Dec 2023 18:26:38 +0800 Subject: [PATCH 6/6] refactor: rename casue to reason in RenderError --- src/error.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/error.rs b/src/error.rs index b99b03e23..fec90d1fa 100644 --- a/src/error.rs +++ b/src/error.rs @@ -18,14 +18,14 @@ pub struct RenderError { pub template_name: Option, pub line_no: Option, pub column_no: Option, - cause: Box, + reason: Box, unimplemented: bool, // backtrace: Backtrace, } impl fmt::Display for RenderError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { - let desc = self.cause.to_string(); + let desc = self.reason.to_string(); match (self.line_no, self.column_no) { (Some(line), Some(col)) => write!( @@ -144,7 +144,7 @@ impl From for RenderError { template_name: None, line_no: None, column_no: None, - cause: Box::new(e), + reason: Box::new(e), unimplemented: false, } } @@ -170,12 +170,12 @@ impl RenderError { #[inline] pub(crate) fn is_unimplemented(&self) -> bool { - matches!(*self.cause, RenderErrorReason::Unimplemented) + matches!(*self.reason, RenderErrorReason::Unimplemented) } /// Get `RenderErrorReason` for this error pub fn reason(&self) -> &RenderErrorReason { - self.cause.as_ref() + self.reason.as_ref() } }