archetect_core/vendor/tera/
errors.rs

1use std::convert::Into;
2use std::error::Error as StdError;
3use std::fmt;
4
5/// The kind of an error (non-exhaustive)
6#[derive(Debug)]
7pub enum ErrorKind {
8    /// Generic error
9    Msg(String),
10    /// A loop was found while looking up the inheritance chain
11    CircularExtend {
12        /// Name of the template with the loop
13        tpl: String,
14        /// All the parents templates we found so far
15        inheritance_chain: Vec<String>,
16    },
17    /// A template is extending a template that wasn't found in the Tera instance
18    MissingParent {
19        /// The template we are currently looking at
20        current: String,
21        /// The missing template
22        parent: String,
23    },
24    /// A template was missing (more generic version of MissingParent)
25    TemplateNotFound(String),
26    /// A filter wasn't found
27    FilterNotFound(String),
28    /// A test wasn't found
29    TestNotFound(String),
30    /// A macro was defined in the middle of a template
31    InvalidMacroDefinition(String),
32    /// A function wasn't found
33    FunctionNotFound(String),
34    /// An error happened while serializing JSON
35    Json(serde_json::Error),
36    /// An error occured while executing a function.
37    CallFunction(String),
38    /// An error occured while executing a filter.
39    CallFilter(String),
40    /// An error occured while executing a test.
41    CallTest(String),
42    /// An IO error occured
43    Io(std::io::ErrorKind),
44    /// UTF-8 conversion error
45    ///
46    /// This should not occur unless invalid UTF8 chars are rendered
47    Utf8Conversion {
48        /// The context that indicates where the error occurs in the rendering process
49        context: String,
50    },
51    /// This enum may grow additional variants, so this makes sure clients
52    /// don't count on exhaustive matching. (Otherwise, adding a new variant
53    /// could break existing code.)
54    #[doc(hidden)]
55    __Nonexhaustive,
56}
57
58/// The Error type
59#[derive(Debug)]
60pub struct Error {
61    /// Kind of error
62    pub kind: ErrorKind,
63    source: Option<Box<dyn StdError + Sync + Send>>,
64}
65
66impl fmt::Display for Error {
67    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
68        match self.kind {
69            ErrorKind::Msg(ref message) => write!(f, "{}", message),
70            ErrorKind::CircularExtend { ref tpl, ref inheritance_chain } => write!(
71                f,
72                "Circular extend detected for template '{}'. Inheritance chain: `{:?}`",
73                tpl, inheritance_chain
74            ),
75            ErrorKind::MissingParent { ref current, ref parent } => write!(
76                f,
77                "Template '{}' is inheriting from '{}', which doesn't exist or isn't loaded.",
78                current, parent
79            ),
80            ErrorKind::TemplateNotFound(ref name) => write!(f, "Template '{}' not found", name),
81            ErrorKind::FilterNotFound(ref name) => write!(f, "Filter '{}' not found", name),
82            ErrorKind::TestNotFound(ref name) => write!(f, "Test '{}' not found", name),
83            ErrorKind::FunctionNotFound(ref name) => write!(f, "Function '{}' not found", name),
84            ErrorKind::InvalidMacroDefinition(ref info) => {
85                write!(f, "Invalid macro definition: `{}`", info)
86            }
87            ErrorKind::Json(ref e) => write!(f, "{}", e),
88            ErrorKind::CallFunction(ref name) => write!(f, "Function call '{}' failed", name),
89            ErrorKind::CallFilter(ref name) => write!(f, "Filter call '{}' failed", name),
90            ErrorKind::CallTest(ref name) => write!(f, "Test call '{}' failed", name),
91            ErrorKind::Io(ref io_error) => {
92                write!(f, "Io error while writing rendered value to output: {:?}", io_error)
93            }
94            ErrorKind::Utf8Conversion { ref context } => {
95                write!(f, "UTF-8 conversion error occured while rendering template: {}", context)
96            }
97            ErrorKind::__Nonexhaustive => write!(f, "Nonexhaustive"),
98        }
99    }
100}
101
102impl StdError for Error {
103    fn source(&self) -> Option<&(dyn StdError + 'static)> {
104        self.source.as_ref().map(|c| &**c as &(dyn StdError + 'static))
105    }
106}
107
108impl Error {
109    /// Creates generic error
110    pub fn msg(value: impl ToString) -> Self {
111        Self { kind: ErrorKind::Msg(value.to_string()), source: None }
112    }
113
114    /// Creates a circular extend error
115    pub fn circular_extend(tpl: impl ToString, inheritance_chain: Vec<String>) -> Self {
116        Self {
117            kind: ErrorKind::CircularExtend { tpl: tpl.to_string(), inheritance_chain },
118            source: None,
119        }
120    }
121
122    /// Creates a missing parent error
123    pub fn missing_parent(current: impl ToString, parent: impl ToString) -> Self {
124        Self {
125            kind: ErrorKind::MissingParent {
126                current: current.to_string(),
127                parent: parent.to_string(),
128            },
129            source: None,
130        }
131    }
132
133    /// Creates a template not found error
134    pub fn template_not_found(tpl: impl ToString) -> Self {
135        Self { kind: ErrorKind::TemplateNotFound(tpl.to_string()), source: None }
136    }
137
138    /// Creates a filter not found error
139    pub fn filter_not_found(name: impl ToString) -> Self {
140        Self { kind: ErrorKind::FilterNotFound(name.to_string()), source: None }
141    }
142
143    /// Creates a test not found error
144    pub fn test_not_found(name: impl ToString) -> Self {
145        Self { kind: ErrorKind::TestNotFound(name.to_string()), source: None }
146    }
147
148    /// Creates a function not found error
149    pub fn function_not_found(name: impl ToString) -> Self {
150        Self { kind: ErrorKind::FunctionNotFound(name.to_string()), source: None }
151    }
152
153    /// Creates generic error with a source
154    pub fn chain(value: impl ToString, source: impl Into<Box<dyn StdError + Send + Sync>>) -> Self {
155        Self { kind: ErrorKind::Msg(value.to_string()), source: Some(source.into()) }
156    }
157
158    /// Creates an error wrapping a failed function call.
159    pub fn call_function(
160        name: impl ToString,
161        source: impl Into<Box<dyn StdError + Send + Sync>>,
162    ) -> Self {
163        Self { kind: ErrorKind::CallFunction(name.to_string()), source: Some(source.into()) }
164    }
165
166    /// Creates an error wrapping a failed filter call.
167    pub fn call_filter(
168        name: impl ToString,
169        source: impl Into<Box<dyn StdError + Send + Sync>>,
170    ) -> Self {
171        Self { kind: ErrorKind::CallFilter(name.to_string()), source: Some(source.into()) }
172    }
173
174    /// Creates an error wrapping a failed test call.
175    pub fn call_test(
176        name: impl ToString,
177        source: impl Into<Box<dyn StdError + Send + Sync>>,
178    ) -> Self {
179        Self { kind: ErrorKind::CallTest(name.to_string()), source: Some(source.into()) }
180    }
181
182    /// Creates JSON error
183    pub fn json(value: serde_json::Error) -> Self {
184        Self { kind: ErrorKind::Json(value), source: None }
185    }
186
187    /// Creates an invalid macro definition error
188    pub fn invalid_macro_def(name: impl ToString) -> Self {
189        Self { kind: ErrorKind::InvalidMacroDefinition(name.to_string()), source: None }
190    }
191
192    /// Creates an IO error
193    pub fn io_error(error: std::io::Error) -> Self {
194        Self { kind: ErrorKind::Io(error.kind()), source: Some(Box::new(error)) }
195    }
196
197    /// Creates an utf8 conversion error
198    pub fn utf8_conversion_error(error: std::string::FromUtf8Error, context: String) -> Self {
199        Self { kind: ErrorKind::Utf8Conversion { context }, source: Some(Box::new(error)) }
200    }
201}
202
203impl From<std::io::Error> for Error {
204    fn from(error: std::io::Error) -> Self {
205        Self::io_error(error)
206    }
207}
208impl From<&str> for Error {
209    fn from(e: &str) -> Self {
210        Self::msg(e)
211    }
212}
213impl From<String> for Error {
214    fn from(e: String) -> Self {
215        Self::msg(e)
216    }
217}
218impl From<serde_json::Error> for Error {
219    fn from(e: serde_json::Error) -> Self {
220        Self::json(e)
221    }
222}
223/// Convenient wrapper around std::Result.
224pub type Result<T> = ::std::result::Result<T, Error>;
225
226#[cfg(test)]
227mod tests {
228    #[test]
229    fn test_error_is_send_and_sync() {
230        fn test_send_sync<T: Send + Sync>() {}
231
232        test_send_sync::<super::Error>();
233    }
234}