/rust/registry/src/index.crates.io-1949cf8c6b5b557f/tinytemplate-1.2.1/src/error.rs
Line | Count | Source |
1 | | //! Module containing the error type returned by TinyTemplate if an error occurs. |
2 | | |
3 | | use instruction::{path_to_str, PathSlice}; |
4 | | use serde_json::Error as SerdeJsonError; |
5 | | use serde_json::Value; |
6 | | use std::error::Error as StdError; |
7 | | use std::fmt; |
8 | | |
9 | | /// Enum representing the potential errors that TinyTemplate can encounter. |
10 | | #[derive(Debug)] |
11 | | pub enum Error { |
12 | | ParseError { |
13 | | msg: String, |
14 | | line: usize, |
15 | | column: usize, |
16 | | }, |
17 | | RenderError { |
18 | | msg: String, |
19 | | line: usize, |
20 | | column: usize, |
21 | | }, |
22 | | SerdeError { |
23 | | err: SerdeJsonError, |
24 | | }, |
25 | | GenericError { |
26 | | msg: String, |
27 | | }, |
28 | | StdFormatError { |
29 | | err: fmt::Error, |
30 | | }, |
31 | | CalledTemplateError { |
32 | | name: String, |
33 | | err: Box<Error>, |
34 | | line: usize, |
35 | | column: usize, |
36 | | }, |
37 | | CalledFormatterError { |
38 | | name: String, |
39 | | err: Box<Error>, |
40 | | line: usize, |
41 | | column: usize, |
42 | | }, |
43 | | |
44 | | #[doc(hidden)] |
45 | | __NonExhaustive, |
46 | | } |
47 | | impl From<SerdeJsonError> for Error { |
48 | 0 | fn from(err: SerdeJsonError) -> Error { |
49 | 0 | Error::SerdeError { err } |
50 | 0 | } |
51 | | } |
52 | | impl From<fmt::Error> for Error { |
53 | 0 | fn from(err: fmt::Error) -> Error { |
54 | 0 | Error::StdFormatError { err } |
55 | 0 | } |
56 | | } |
57 | | impl fmt::Display for Error { |
58 | 0 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
59 | 0 | match self { |
60 | 0 | Error::ParseError { msg, line, column } => write!( |
61 | 0 | f, |
62 | 0 | "Failed to parse the template (line {}, column {}). Reason: {}", |
63 | | line, column, msg |
64 | | ), |
65 | 0 | Error::RenderError { msg, line, column } => { |
66 | 0 | write!( |
67 | 0 | f, |
68 | 0 | "Encountered rendering error on line {}, column {}. Reason: {}", |
69 | | line, column, msg |
70 | | ) |
71 | | } |
72 | 0 | Error::SerdeError { err } => { |
73 | 0 | write!(f, "Unexpected serde error while converting the context to a serde_json::Value. Error: {}", err) |
74 | | } |
75 | 0 | Error::GenericError { msg } => { |
76 | 0 | write!(f, "{}", msg) |
77 | | } |
78 | 0 | Error::StdFormatError { err } => { |
79 | 0 | write!(f, "Unexpected formatting error: {}", err) |
80 | | } |
81 | | Error::CalledTemplateError { |
82 | 0 | name, |
83 | 0 | err, |
84 | 0 | line, |
85 | 0 | column, |
86 | | } => { |
87 | 0 | write!( |
88 | 0 | f, |
89 | 0 | "Call to sub-template \"{}\" on line {}, column {} failed. Reason: {}", |
90 | | name, line, column, err |
91 | | ) |
92 | | } |
93 | | Error::CalledFormatterError { |
94 | 0 | name, |
95 | 0 | err, |
96 | 0 | line, |
97 | 0 | column, |
98 | | } => { |
99 | 0 | write!( |
100 | 0 | f, |
101 | 0 | "Call to value formatter \"{}\" on line {}, column {} failed. Reason: {}", |
102 | | name, line, column, err |
103 | | ) |
104 | | } |
105 | 0 | Error::__NonExhaustive => unreachable!(), |
106 | | } |
107 | 0 | } |
108 | | } |
109 | | impl StdError for Error { |
110 | 0 | fn description(&self) -> &str { |
111 | 0 | match self { |
112 | 0 | Error::ParseError { .. } => "ParseError", |
113 | 0 | Error::RenderError { .. } => "RenderError", |
114 | 0 | Error::SerdeError { .. } => "SerdeError", |
115 | 0 | Error::GenericError { msg } => &msg, |
116 | 0 | Error::StdFormatError { .. } => "StdFormatError", |
117 | 0 | Error::CalledTemplateError { .. } => "CalledTemplateError", |
118 | 0 | Error::CalledFormatterError { .. } => "CalledFormatterError", |
119 | 0 | Error::__NonExhaustive => unreachable!(), |
120 | | } |
121 | 0 | } |
122 | | } |
123 | | |
124 | | pub type Result<T> = ::std::result::Result<T, Error>; |
125 | | |
126 | 0 | pub(crate) fn lookup_error(source: &str, step: &str, path: PathSlice, current: &Value) -> Error { |
127 | 0 | let avail_str = if let Value::Object(object_map) = current { |
128 | 0 | let mut avail_str = " Available values at this level are ".to_string(); |
129 | 0 | for (i, key) in object_map.keys().enumerate() { |
130 | 0 | if i > 0 { |
131 | 0 | avail_str.push_str(", "); |
132 | 0 | } |
133 | 0 | avail_str.push('\''); |
134 | 0 | avail_str.push_str(key); |
135 | 0 | avail_str.push('\''); |
136 | | } |
137 | 0 | avail_str |
138 | | } else { |
139 | 0 | "".to_string() |
140 | | }; |
141 | | |
142 | 0 | let (line, column) = get_offset(source, step); |
143 | | |
144 | 0 | Error::RenderError { |
145 | 0 | msg: format!( |
146 | 0 | "Failed to find value '{}' from path '{}'.{}", |
147 | 0 | step, |
148 | 0 | path_to_str(path), |
149 | 0 | avail_str |
150 | 0 | ), |
151 | 0 | line, |
152 | 0 | column, |
153 | 0 | } |
154 | 0 | } |
155 | | |
156 | 0 | pub(crate) fn truthiness_error(source: &str, path: PathSlice) -> Error { |
157 | 0 | let (line, column) = get_offset(source, path.last().unwrap()); |
158 | 0 | Error::RenderError { |
159 | 0 | msg: format!( |
160 | 0 | "Path '{}' produced a value which could not be checked for truthiness.", |
161 | 0 | path_to_str(path) |
162 | 0 | ), |
163 | 0 | line, |
164 | 0 | column, |
165 | 0 | } |
166 | 0 | } |
167 | | |
168 | 0 | pub(crate) fn unprintable_error() -> Error { |
169 | 0 | Error::GenericError { |
170 | 0 | msg: "Expected a printable value but found array or object.".to_string(), |
171 | 0 | } |
172 | 0 | } |
173 | | |
174 | 0 | pub(crate) fn not_iterable_error(source: &str, path: PathSlice) -> Error { |
175 | 0 | let (line, column) = get_offset(source, path.last().unwrap()); |
176 | 0 | Error::RenderError { |
177 | 0 | msg: format!( |
178 | 0 | "Expected an array for path '{}' but found a non-iterable value.", |
179 | 0 | path_to_str(path) |
180 | 0 | ), |
181 | 0 | line, |
182 | 0 | column, |
183 | 0 | } |
184 | 0 | } |
185 | | |
186 | 0 | pub(crate) fn unknown_template(source: &str, name: &str) -> Error { |
187 | 0 | let (line, column) = get_offset(source, name); |
188 | 0 | Error::RenderError { |
189 | 0 | msg: format!("Tried to call an unknown template '{}'", name), |
190 | 0 | line, |
191 | 0 | column, |
192 | 0 | } |
193 | 0 | } |
194 | | |
195 | 0 | pub(crate) fn unknown_formatter(source: &str, name: &str) -> Error { |
196 | 0 | let (line, column) = get_offset(source, name); |
197 | 0 | Error::RenderError { |
198 | 0 | msg: format!("Tried to call an unknown formatter '{}'", name), |
199 | 0 | line, |
200 | 0 | column, |
201 | 0 | } |
202 | 0 | } |
203 | | |
204 | 0 | pub(crate) fn called_template_error(source: &str, template_name: &str, err: Error) -> Error { |
205 | 0 | let (line, column) = get_offset(source, template_name); |
206 | 0 | Error::CalledTemplateError { |
207 | 0 | name: template_name.to_string(), |
208 | 0 | err: Box::new(err), |
209 | 0 | line, |
210 | 0 | column, |
211 | 0 | } |
212 | 0 | } |
213 | | |
214 | 0 | pub(crate) fn called_formatter_error(source: &str, formatter_name: &str, err: Error) -> Error { |
215 | 0 | let (line, column) = get_offset(source, formatter_name); |
216 | 0 | Error::CalledFormatterError { |
217 | 0 | name: formatter_name.to_string(), |
218 | 0 | err: Box::new(err), |
219 | 0 | line, |
220 | 0 | column, |
221 | 0 | } |
222 | 0 | } |
223 | | |
224 | | /// Find the line number and column of the target string within the source string. Will panic if |
225 | | /// target is not a substring of source. |
226 | 0 | pub(crate) fn get_offset(source: &str, target: &str) -> (usize, usize) { |
227 | 0 | let offset = target.as_ptr() as isize - source.as_ptr() as isize; |
228 | 0 | let to_scan = &source[0..(offset as usize)]; |
229 | | |
230 | 0 | let mut line = 1; |
231 | 0 | let mut column = 0; |
232 | | |
233 | 0 | for byte in to_scan.bytes() { |
234 | 0 | match byte as char { |
235 | 0 | '\n' => { |
236 | 0 | line += 1; |
237 | 0 | column = 0; |
238 | 0 | } |
239 | 0 | _ => { |
240 | 0 | column += 1; |
241 | 0 | } |
242 | | } |
243 | | } |
244 | | |
245 | 0 | (line, column) |
246 | 0 | } |