1use core::fmt;
2
3use super::Error;
4
5impl Error {
6 #[inline]
12 pub fn unexpected_eof() -> Self {
13 Error::UnexpectedEof { line: None }
14 }
15
16 #[inline]
18 pub fn unexpected_eof_at(line: usize) -> Self {
19 Error::UnexpectedEof { line: Some(line) }
20 }
21
22 #[inline]
24 pub fn expected(msg: &'static str) -> Self {
25 Error::Expected { msg, line: None }
26 }
27
28 #[inline]
30 pub fn expected_at(msg: &'static str, line: usize) -> Self {
31 Error::Expected {
32 msg,
33 line: Some(line),
34 }
35 }
36
37 #[inline]
39 pub fn invalid_char(char: char) -> Self {
40 Error::InvalidChar { char, line: None }
41 }
42
43 #[inline]
45 pub fn invalid_char_at(char: char, line: usize) -> Self {
46 Error::InvalidChar {
47 char,
48 line: Some(line),
49 }
50 }
51
52 #[inline]
54 pub fn max_str_length(max: usize) -> Self {
55 Error::MaxStrLength { max, line: None }
56 }
57
58 #[inline]
60 pub fn max_str_length_at(max: usize, line: usize) -> Self {
61 Error::MaxStrLength {
62 max,
63 line: Some(line),
64 }
65 }
66
67 #[inline]
69 pub fn version(msg: &'static str) -> Self {
70 Error::Version { msg, line: None }
71 }
72
73 #[inline]
75 pub fn version_at(msg: &'static str, line: usize) -> Self {
76 Error::Version {
77 msg,
78 line: Some(line),
79 }
80 }
81
82 #[inline]
84 pub fn message(msg: &'static str) -> Self {
85 Error::Message { msg, line: None }
86 }
87
88 #[inline]
90 pub fn message_at(msg: &'static str, line: usize) -> Self {
91 Error::Message {
92 msg,
93 line: Some(line),
94 }
95 }
96
97 #[inline]
99 pub fn receivers(msg: &'static str) -> Self {
100 Error::Receivers { msg, line: None }
101 }
102
103 #[inline]
105 pub fn receivers_at(msg: &'static str, line: usize) -> Self {
106 Error::Receivers {
107 msg,
108 line: Some(line),
109 }
110 }
111
112 #[inline]
114 pub fn nodes(msg: &'static str) -> Self {
115 Error::Nodes { msg, line: None }
116 }
117
118 #[inline]
120 pub fn nodes_at(msg: &'static str, line: usize) -> Self {
121 Error::Nodes {
122 msg,
123 line: Some(line),
124 }
125 }
126
127 #[inline]
129 pub fn signal(msg: &'static str) -> Self {
130 Error::Signal { msg, line: None }
131 }
132
133 #[inline]
135 pub fn signal_at(msg: &'static str, line: usize) -> Self {
136 Error::Signal {
137 msg,
138 line: Some(line),
139 }
140 }
141
142 #[inline]
148 pub fn line(&self) -> Option<usize> {
149 match self {
150 Error::UnexpectedEof { line } => *line,
151 Error::Expected { line, .. } => *line,
152 Error::InvalidChar { line, .. } => *line,
153 Error::MaxStrLength { line, .. } => *line,
154 Error::Version { line, .. } => *line,
155 Error::Message { line, .. } => *line,
156 Error::Receivers { line, .. } => *line,
157 Error::Nodes { line, .. } => *line,
158 Error::Signal { line, .. } => *line,
159 Error::Decoding(_) | Error::Encoding(_) | Error::Validation(_) => None,
160 #[cfg(feature = "std")]
161 Error::Io(_) => None,
162 }
163 }
164
165 #[inline]
168 pub fn with_line(self, line: usize) -> Self {
169 match self {
170 Error::UnexpectedEof { line: None } => Error::UnexpectedEof { line: Some(line) },
171 Error::Expected { msg, line: None } => Error::Expected {
172 msg,
173 line: Some(line),
174 },
175 Error::InvalidChar { char, line: None } => Error::InvalidChar {
176 char,
177 line: Some(line),
178 },
179 Error::MaxStrLength { max, line: None } => Error::MaxStrLength {
180 max,
181 line: Some(line),
182 },
183 Error::Version { msg, line: None } => Error::Version {
184 msg,
185 line: Some(line),
186 },
187 Error::Message { msg, line: None } => Error::Message {
188 msg,
189 line: Some(line),
190 },
191 Error::Receivers { msg, line: None } => Error::Receivers {
192 msg,
193 line: Some(line),
194 },
195 Error::Nodes { msg, line: None } => Error::Nodes {
196 msg,
197 line: Some(line),
198 },
199 Error::Signal { msg, line: None } => Error::Signal {
200 msg,
201 line: Some(line),
202 },
203 other => other,
205 }
206 }
207}
208
209impl fmt::Display for Error {
210 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
211 match self {
212 Error::UnexpectedEof { line } => {
213 if let Some(line) = line {
214 write!(f, "line {}: {}", line, Error::UNEXPECTED_EOF)
215 } else {
216 write!(f, "{}", Error::UNEXPECTED_EOF)
217 }
218 }
219 Error::Expected { msg, line } => {
220 if let Some(line) = line {
221 write!(f, "line {}: {}", line, msg)
222 } else {
223 write!(f, "{}", msg)
224 }
225 }
226 Error::InvalidChar { char, line } => {
227 if let Some(line) = line {
228 write!(
229 f,
230 "line {}: {}: {}",
231 line,
232 Error::INVALID_CHARACTER,
233 char.escape_debug()
234 )
235 } else {
236 write!(f, "{}: {}", Error::INVALID_CHARACTER, char.escape_debug())
237 }
238 }
239 Error::MaxStrLength { max, line } => {
240 if let Some(line) = line {
241 write!(
242 f,
243 "line {}: {}: {}",
244 line,
245 Error::STRING_LENGTH_EXCEEDS_MAX,
246 max
247 )
248 } else {
249 write!(f, "{}: {}", Error::STRING_LENGTH_EXCEEDS_MAX, max)
250 }
251 }
252 Error::Version { msg, line } => {
253 if let Some(line) = line {
254 write!(f, "line {}: {}: {}", line, Error::VERSION_ERROR_PREFIX, msg)
255 } else {
256 write!(f, "{}: {}", Error::VERSION_ERROR_PREFIX, msg)
257 }
258 }
259 Error::Message { msg, line } => {
260 if let Some(line) = line {
261 write!(f, "line {}: {}: {}", line, Error::MESSAGE_ERROR_PREFIX, msg)
262 } else {
263 write!(f, "{}: {}", Error::MESSAGE_ERROR_PREFIX, msg)
264 }
265 }
266 Error::Receivers { msg, line } => {
267 if let Some(line) = line {
268 write!(
269 f,
270 "line {}: {}: {}",
271 line,
272 Error::RECEIVERS_ERROR_PREFIX,
273 msg
274 )
275 } else {
276 write!(f, "{}: {}", Error::RECEIVERS_ERROR_PREFIX, msg)
277 }
278 }
279 Error::Nodes { msg, line } => {
280 if let Some(line) = line {
281 write!(f, "line {}: {}: {}", line, Error::NODES_ERROR_PREFIX, msg)
282 } else {
283 write!(f, "{}: {}", Error::NODES_ERROR_PREFIX, msg)
284 }
285 }
286 Error::Signal { msg, line } => {
287 if let Some(line) = line {
288 write!(f, "line {}: {}: {}", line, Error::SIGNAL_ERROR_PREFIX, msg)
289 } else {
290 write!(f, "{}: {}", Error::SIGNAL_ERROR_PREFIX, msg)
291 }
292 }
293 Error::Decoding(msg) => {
294 write!(f, "{}: {}", Error::DECODING_ERROR_PREFIX, msg)
295 }
296 Error::Encoding(msg) => {
297 write!(f, "{}: {}", Error::ENCODING_ERROR_PREFIX, msg)
298 }
299 Error::Validation(msg) => {
300 write!(f, "{}: {}", Error::VALIDATION_ERROR_PREFIX, msg)
301 }
302 #[cfg(feature = "std")]
303 Error::Io(msg) => {
304 write!(f, "I/O error: {}", msg)
305 }
306 }
307 }
308}
309
310#[cfg(feature = "std")]
311impl From<std::io::Error> for Error {
312 fn from(err: std::io::Error) -> Self {
313 Error::Io(err.to_string())
314 }
315}
316
317impl From<core::num::ParseIntError> for Error {
318 fn from(_err: core::num::ParseIntError) -> Self {
319 Error::expected(Error::PARSE_NUMBER_FAILED)
320 }
321}
322
323#[cfg(feature = "std")]
325impl std::error::Error for Error {}
326
327#[cfg(test)]
328mod tests {
329 #![allow(clippy::float_cmp)]
330
331 #[cfg(feature = "std")]
333 mod tests_with_std {
334 use crate::Error;
335
336 #[test]
337 fn test_from_parse_int_error() {
338 let parse_error = "invalid".parse::<u32>().unwrap_err();
340 let error: Error = parse_error.into();
341
342 match error {
343 Error::Expected { msg, line } => {
344 assert_eq!(msg, Error::PARSE_NUMBER_FAILED);
345 assert_eq!(line, None);
346 }
347 _ => panic!("Expected Error::Expected"),
348 }
349 }
350
351 #[test]
352 fn test_display_decoding_error() {
353 let error = Error::Decoding("Test error message");
354 let display = error.to_string();
355 assert!(display.starts_with(Error::DECODING_ERROR_PREFIX));
356 assert!(display.contains("Test error message"));
357 }
358
359 #[test]
360 fn test_display_signal_error() {
361 let error = Error::signal("Test signal error");
362 let display = error.to_string();
363 assert!(display.starts_with(Error::SIGNAL_ERROR_PREFIX));
364 assert!(display.contains("Test signal error"));
365 }
366
367 #[test]
368 fn test_display_formatting() {
369 let error = Error::Decoding(
371 "Duplicate message ID: 256 (messages 'EngineData' and 'BrakeData')",
372 );
373 let display = error.to_string();
374 assert!(display.starts_with(Error::DECODING_ERROR_PREFIX));
375 assert!(display.contains("256"));
376 assert!(display.contains("EngineData"));
377 assert!(display.contains("BrakeData"));
378 }
379
380 #[test]
381 fn test_display_from_parse_int_error() {
382 let int_error = "not_a_number".parse::<u32>().unwrap_err();
383 let error: Error = int_error.into();
384 let display = error.to_string();
385
386 assert!(display.contains(Error::PARSE_NUMBER_FAILED));
387 }
388
389 #[test]
390 fn test_error_with_line_number() {
391 let error = Error::expected_at("Expected identifier", 42);
392 let display = error.to_string();
393 assert!(display.contains("line 42"));
394 assert!(display.contains("Expected identifier"));
395 }
396
397 #[test]
398 fn test_error_without_line_number() {
399 let error = Error::expected("Expected identifier");
400 let display = error.to_string();
401 assert!(!display.contains("line"));
402 assert!(display.contains("Expected identifier"));
403 }
404
405 #[test]
406 fn test_with_line_adds_line_info() {
407 let error = Error::expected("Expected whitespace");
408 assert_eq!(error.line(), None);
409
410 let error_with_line = error.with_line(10);
411 assert_eq!(error_with_line.line(), Some(10));
412 }
413
414 #[test]
415 fn test_with_line_preserves_existing_line() {
416 let error = Error::expected_at("Expected whitespace", 5);
417 let error_with_line = error.with_line(10);
418 assert_eq!(error_with_line.line(), Some(5));
420 }
421
422 #[test]
423 fn test_invalid_char_display() {
424 let error = Error::invalid_char_at('\t', 15);
425 let display = error.to_string();
426 assert!(display.contains("line 15"));
427 assert!(display.contains("\\t"));
428 }
429
430 #[test]
431 fn test_max_str_length_display() {
432 let error = Error::max_str_length_at(256, 20);
433 let display = error.to_string();
434 assert!(display.contains("line 20"));
435 assert!(display.contains("256"));
436 }
437 }
438
439 #[cfg(feature = "std")]
442 mod tests_std {
443 use super::super::Error;
444 use std::error::Error as StdError;
445
446 #[test]
447 fn test_std_error_trait() {
448 let error = Error::Decoding("Test");
449 let _: &dyn StdError = &error;
451
452 assert!(error.source().is_none());
454 }
455 }
456}