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
327impl From<sigma_bounded::Error> for Error {
328 #[inline]
329 fn from(e: sigma_bounded::Error) -> Self {
330 match e {
331 sigma_bounded::Error::CapacityExceeded => {
332 Self::Validation(Self::MAX_NAME_SIZE_EXCEEDED)
333 }
334 sigma_bounded::Error::InvalidUtf8 => Self::expected(Self::INVALID_UTF8),
335 _ => Self::Validation(Self::MAX_NAME_SIZE_EXCEEDED),
336 }
337 }
338}
339
340#[cfg(test)]
341mod tests {
342 #![allow(clippy::float_cmp)]
343
344 #[cfg(feature = "std")]
346 mod tests_with_std {
347 use crate::Error;
348
349 #[test]
350 fn test_from_parse_int_error() {
351 let parse_error = "invalid".parse::<u32>().unwrap_err();
353 let error: Error = parse_error.into();
354
355 match error {
356 Error::Expected { msg, line } => {
357 assert_eq!(msg, Error::PARSE_NUMBER_FAILED);
358 assert_eq!(line, None);
359 }
360 _ => panic!("Expected Error::Expected"),
361 }
362 }
363
364 #[test]
365 fn test_display_decoding_error() {
366 let error = Error::Decoding("Test error message");
367 let display = error.to_string();
368 assert!(display.starts_with(Error::DECODING_ERROR_PREFIX));
369 assert!(display.contains("Test error message"));
370 }
371
372 #[test]
373 fn test_display_signal_error() {
374 let error = Error::signal("Test signal error");
375 let display = error.to_string();
376 assert!(display.starts_with(Error::SIGNAL_ERROR_PREFIX));
377 assert!(display.contains("Test signal error"));
378 }
379
380 #[test]
381 fn test_display_formatting() {
382 let error = Error::Decoding(
384 "Duplicate message ID: 256 (messages 'EngineData' and 'BrakeData')",
385 );
386 let display = error.to_string();
387 assert!(display.starts_with(Error::DECODING_ERROR_PREFIX));
388 assert!(display.contains("256"));
389 assert!(display.contains("EngineData"));
390 assert!(display.contains("BrakeData"));
391 }
392
393 #[test]
394 fn test_display_from_parse_int_error() {
395 let int_error = "not_a_number".parse::<u32>().unwrap_err();
396 let error: Error = int_error.into();
397 let display = error.to_string();
398
399 assert!(display.contains(Error::PARSE_NUMBER_FAILED));
400 }
401
402 #[test]
403 fn test_error_with_line_number() {
404 let error = Error::expected_at("Expected identifier", 42);
405 let display = error.to_string();
406 assert!(display.contains("line 42"));
407 assert!(display.contains("Expected identifier"));
408 }
409
410 #[test]
411 fn test_error_without_line_number() {
412 let error = Error::expected("Expected identifier");
413 let display = error.to_string();
414 assert!(!display.contains("line"));
415 assert!(display.contains("Expected identifier"));
416 }
417
418 #[test]
419 fn test_with_line_adds_line_info() {
420 let error = Error::expected("Expected whitespace");
421 assert_eq!(error.line(), None);
422
423 let error_with_line = error.with_line(10);
424 assert_eq!(error_with_line.line(), Some(10));
425 }
426
427 #[test]
428 fn test_with_line_preserves_existing_line() {
429 let error = Error::expected_at("Expected whitespace", 5);
430 let error_with_line = error.with_line(10);
431 assert_eq!(error_with_line.line(), Some(5));
433 }
434
435 #[test]
436 fn test_invalid_char_display() {
437 let error = Error::invalid_char_at('\t', 15);
438 let display = error.to_string();
439 assert!(display.contains("line 15"));
440 assert!(display.contains("\\t"));
441 }
442
443 #[test]
444 fn test_max_str_length_display() {
445 let error = Error::max_str_length_at(256, 20);
446 let display = error.to_string();
447 assert!(display.contains("line 20"));
448 assert!(display.contains("256"));
449 }
450 }
451
452 #[cfg(feature = "std")]
455 mod tests_std {
456 use super::super::Error;
457 use std::error::Error as StdError;
458
459 #[test]
460 fn test_std_error_trait() {
461 let error = Error::Decoding("Test");
462 let _: &dyn StdError = &error;
464
465 assert!(error.source().is_none());
467 }
468 }
469}