1use std::convert::Into;
2use std::error::Error as StdError;
3use std::fmt;
4
5#[derive(Debug)]
7#[allow(clippy::manual_non_exhaustive)] pub enum ErrorKind {
9 Msg(String),
11 CircularExtend {
13 tpl: String,
15 inheritance_chain: Vec<String>,
17 },
18 MissingParent {
20 current: String,
22 parent: String,
24 },
25 TemplateNotFound(String),
27 FilterNotFound(String),
29 TestNotFound(String),
31 InvalidMacroDefinition(String),
33 FunctionNotFound(String),
35 Json(serde_json::Error),
37 CallFunction(String),
39 CallFilter(String),
41 CallTest(String),
43 Io(std::io::ErrorKind),
45 Utf8Conversion {
49 context: String,
51 },
52 #[doc(hidden)]
56 __Nonexhaustive,
57}
58
59#[derive(Debug)]
61pub struct Error {
62 pub kind: ErrorKind,
64 source: Option<Box<dyn StdError + Sync + Send>>,
65}
66
67impl fmt::Display for Error {
68 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
69 match self.kind {
70 ErrorKind::Msg(ref message) => write!(f, "{}", message),
71 ErrorKind::CircularExtend { ref tpl, ref inheritance_chain } => write!(
72 f,
73 "Circular extend detected for template '{}'. Inheritance chain: `{:?}`",
74 tpl, inheritance_chain
75 ),
76 ErrorKind::MissingParent { ref current, ref parent } => write!(
77 f,
78 "Template '{}' is inheriting from '{}', which doesn't exist or isn't loaded.",
79 current, parent
80 ),
81 ErrorKind::TemplateNotFound(ref name) => write!(f, "Template '{}' not found", name),
82 ErrorKind::FilterNotFound(ref name) => write!(f, "Filter '{}' not found", name),
83 ErrorKind::TestNotFound(ref name) => write!(f, "Test '{}' not found", name),
84 ErrorKind::FunctionNotFound(ref name) => write!(f, "Function '{}' not found", name),
85 ErrorKind::InvalidMacroDefinition(ref info) => {
86 write!(f, "Invalid macro definition: `{}`", info)
87 }
88 ErrorKind::Json(ref e) => write!(f, "{}", e),
89 ErrorKind::CallFunction(ref name) => write!(f, "Function call '{}' failed", name),
90 ErrorKind::CallFilter(ref name) => write!(f, "Filter call '{}' failed", name),
91 ErrorKind::CallTest(ref name) => write!(f, "Test call '{}' failed", name),
92 ErrorKind::Io(ref io_error) => {
93 write!(f, "Io error while writing rendered value to output: {:?}", io_error)
94 }
95 ErrorKind::Utf8Conversion { ref context } => {
96 write!(f, "UTF-8 conversion error occured while rendering template: {}", context)
97 }
98 ErrorKind::__Nonexhaustive => write!(f, "Nonexhaustive"),
99 }
100 }
101}
102
103impl StdError for Error {
104 fn source(&self) -> Option<&(dyn StdError + 'static)> {
105 self.source.as_ref().map(|c| &**c as &(dyn StdError + 'static))
106 }
107}
108
109impl Error {
110 pub fn msg(value: impl ToString) -> Self {
112 Self { kind: ErrorKind::Msg(value.to_string()), source: None }
113 }
114
115 pub fn circular_extend(tpl: impl ToString, inheritance_chain: Vec<String>) -> Self {
117 Self {
118 kind: ErrorKind::CircularExtend { tpl: tpl.to_string(), inheritance_chain },
119 source: None,
120 }
121 }
122
123 pub fn missing_parent(current: impl ToString, parent: impl ToString) -> Self {
125 Self {
126 kind: ErrorKind::MissingParent {
127 current: current.to_string(),
128 parent: parent.to_string(),
129 },
130 source: None,
131 }
132 }
133
134 pub fn template_not_found(tpl: impl ToString) -> Self {
136 Self { kind: ErrorKind::TemplateNotFound(tpl.to_string()), source: None }
137 }
138
139 pub fn filter_not_found(name: impl ToString) -> Self {
141 Self { kind: ErrorKind::FilterNotFound(name.to_string()), source: None }
142 }
143
144 pub fn test_not_found(name: impl ToString) -> Self {
146 Self { kind: ErrorKind::TestNotFound(name.to_string()), source: None }
147 }
148
149 pub fn function_not_found(name: impl ToString) -> Self {
151 Self { kind: ErrorKind::FunctionNotFound(name.to_string()), source: None }
152 }
153
154 pub fn chain(value: impl ToString, source: impl Into<Box<dyn StdError + Send + Sync>>) -> Self {
156 Self { kind: ErrorKind::Msg(value.to_string()), source: Some(source.into()) }
157 }
158
159 pub fn call_function(
161 name: impl ToString,
162 source: impl Into<Box<dyn StdError + Send + Sync>>,
163 ) -> Self {
164 Self { kind: ErrorKind::CallFunction(name.to_string()), source: Some(source.into()) }
165 }
166
167 pub fn call_filter(
169 name: impl ToString,
170 source: impl Into<Box<dyn StdError + Send + Sync>>,
171 ) -> Self {
172 Self { kind: ErrorKind::CallFilter(name.to_string()), source: Some(source.into()) }
173 }
174
175 pub fn call_test(
177 name: impl ToString,
178 source: impl Into<Box<dyn StdError + Send + Sync>>,
179 ) -> Self {
180 Self { kind: ErrorKind::CallTest(name.to_string()), source: Some(source.into()) }
181 }
182
183 pub fn json(value: serde_json::Error) -> Self {
185 Self { kind: ErrorKind::Json(value), source: None }
186 }
187
188 pub fn invalid_macro_def(name: impl ToString) -> Self {
190 Self { kind: ErrorKind::InvalidMacroDefinition(name.to_string()), source: None }
191 }
192
193 pub fn io_error(error: std::io::Error) -> Self {
195 Self { kind: ErrorKind::Io(error.kind()), source: Some(Box::new(error)) }
196 }
197
198 pub fn utf8_conversion_error(error: std::string::FromUtf8Error, context: String) -> Self {
200 Self { kind: ErrorKind::Utf8Conversion { context }, source: Some(Box::new(error)) }
201 }
202}
203
204impl From<std::io::Error> for Error {
205 fn from(error: std::io::Error) -> Self {
206 Self::io_error(error)
207 }
208}
209impl From<&str> for Error {
210 fn from(e: &str) -> Self {
211 Self::msg(e)
212 }
213}
214impl From<String> for Error {
215 fn from(e: String) -> Self {
216 Self::msg(e)
217 }
218}
219impl From<serde_json::Error> for Error {
220 fn from(e: serde_json::Error) -> Self {
221 Self::json(e)
222 }
223}
224pub type Result<T> = ::std::result::Result<T, Error>;
226
227#[cfg(test)]
228mod tests {
229 #[test]
230 fn test_error_is_send_and_sync() {
231 fn test_send_sync<T: Send + Sync>() {}
232
233 test_send_sync::<super::Error>();
234 }
235}