use std::convert::Into;
use std::error::Error as StdError;
use std::fmt;
#[derive(Debug)]
#[allow(clippy::manual_non_exhaustive)] pub enum ErrorKind {
Msg(String),
CircularExtend {
tpl: String,
inheritance_chain: Vec<String>,
},
MissingParent {
current: String,
parent: String,
},
TemplateNotFound(String),
FilterNotFound(String),
TestNotFound(String),
InvalidMacroDefinition(String),
FunctionNotFound(String),
Json(serde_json::Error),
CallFunction(String),
CallFilter(String),
CallTest(String),
Io(std::io::ErrorKind),
Utf8Conversion {
context: String,
},
#[doc(hidden)]
__Nonexhaustive,
}
#[derive(Debug)]
pub struct Error {
pub kind: ErrorKind,
source: Option<Box<dyn StdError + Sync + Send>>,
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.kind {
ErrorKind::Msg(ref message) => write!(f, "{}", message),
ErrorKind::CircularExtend { ref tpl, ref inheritance_chain } => write!(
f,
"Circular extend detected for template '{}'. Inheritance chain: `{:?}`",
tpl, inheritance_chain
),
ErrorKind::MissingParent { ref current, ref parent } => write!(
f,
"Template '{}' is inheriting from '{}', which doesn't exist or isn't loaded.",
current, parent
),
ErrorKind::TemplateNotFound(ref name) => write!(f, "Template '{}' not found", name),
ErrorKind::FilterNotFound(ref name) => write!(f, "Filter '{}' not found", name),
ErrorKind::TestNotFound(ref name) => write!(f, "Test '{}' not found", name),
ErrorKind::FunctionNotFound(ref name) => write!(f, "Function '{}' not found", name),
ErrorKind::InvalidMacroDefinition(ref info) => {
write!(f, "Invalid macro definition: `{}`", info)
}
ErrorKind::Json(ref e) => write!(f, "{}", e),
ErrorKind::CallFunction(ref name) => write!(f, "Function call '{}' failed", name),
ErrorKind::CallFilter(ref name) => write!(f, "Filter call '{}' failed", name),
ErrorKind::CallTest(ref name) => write!(f, "Test call '{}' failed", name),
ErrorKind::Io(ref io_error) => {
write!(f, "Io error while writing rendered value to output: {:?}", io_error)
}
ErrorKind::Utf8Conversion { ref context } => {
write!(f, "UTF-8 conversion error occured while rendering template: {}", context)
}
ErrorKind::__Nonexhaustive => write!(f, "Nonexhaustive"),
}
}
}
impl StdError for Error {
fn source(&self) -> Option<&(dyn StdError + 'static)> {
self.source.as_ref().map(|c| &**c as &(dyn StdError + 'static))
}
}
impl Error {
pub fn msg(value: impl ToString) -> Self {
Self { kind: ErrorKind::Msg(value.to_string()), source: None }
}
pub fn circular_extend(tpl: impl ToString, inheritance_chain: Vec<String>) -> Self {
Self {
kind: ErrorKind::CircularExtend { tpl: tpl.to_string(), inheritance_chain },
source: None,
}
}
pub fn missing_parent(current: impl ToString, parent: impl ToString) -> Self {
Self {
kind: ErrorKind::MissingParent {
current: current.to_string(),
parent: parent.to_string(),
},
source: None,
}
}
pub fn template_not_found(tpl: impl ToString) -> Self {
Self { kind: ErrorKind::TemplateNotFound(tpl.to_string()), source: None }
}
pub fn filter_not_found(name: impl ToString) -> Self {
Self { kind: ErrorKind::FilterNotFound(name.to_string()), source: None }
}
pub fn test_not_found(name: impl ToString) -> Self {
Self { kind: ErrorKind::TestNotFound(name.to_string()), source: None }
}
pub fn function_not_found(name: impl ToString) -> Self {
Self { kind: ErrorKind::FunctionNotFound(name.to_string()), source: None }
}
pub fn chain(value: impl ToString, source: impl Into<Box<dyn StdError + Send + Sync>>) -> Self {
Self { kind: ErrorKind::Msg(value.to_string()), source: Some(source.into()) }
}
pub fn call_function(
name: impl ToString,
source: impl Into<Box<dyn StdError + Send + Sync>>,
) -> Self {
Self { kind: ErrorKind::CallFunction(name.to_string()), source: Some(source.into()) }
}
pub fn call_filter(
name: impl ToString,
source: impl Into<Box<dyn StdError + Send + Sync>>,
) -> Self {
Self { kind: ErrorKind::CallFilter(name.to_string()), source: Some(source.into()) }
}
pub fn call_test(
name: impl ToString,
source: impl Into<Box<dyn StdError + Send + Sync>>,
) -> Self {
Self { kind: ErrorKind::CallTest(name.to_string()), source: Some(source.into()) }
}
pub fn json(value: serde_json::Error) -> Self {
Self { kind: ErrorKind::Json(value), source: None }
}
pub fn invalid_macro_def(name: impl ToString) -> Self {
Self { kind: ErrorKind::InvalidMacroDefinition(name.to_string()), source: None }
}
pub fn io_error(error: std::io::Error) -> Self {
Self { kind: ErrorKind::Io(error.kind()), source: Some(Box::new(error)) }
}
pub fn utf8_conversion_error(error: std::string::FromUtf8Error, context: String) -> Self {
Self { kind: ErrorKind::Utf8Conversion { context }, source: Some(Box::new(error)) }
}
}
impl From<std::io::Error> for Error {
fn from(error: std::io::Error) -> Self {
Self::io_error(error)
}
}
impl From<&str> for Error {
fn from(e: &str) -> Self {
Self::msg(e)
}
}
impl From<String> for Error {
fn from(e: String) -> Self {
Self::msg(e)
}
}
impl From<serde_json::Error> for Error {
fn from(e: serde_json::Error) -> Self {
Self::json(e)
}
}
pub type Result<T> = ::std::result::Result<T, Error>;
#[cfg(test)]
mod tests {
#[test]
fn test_error_is_send_and_sync() {
fn test_send_sync<T: Send + Sync>() {}
test_send_sync::<super::Error>();
}
}