dbc_rs/error/
error.rs

1use core::fmt;
2
3use crate::error::lang;
4
5/// Error type for DBC operations.
6///
7/// This enum represents all possible errors that can occur when working with DBC files.
8#[derive(Debug, PartialEq, Clone)]
9pub enum Error {
10    /// Unexpected end of input encountered.
11    UnexpectedEof,
12    /// Expected a specific token or value.
13    Expected(&'static str),
14    /// Invalid character encountered.
15    InvalidChar(char),
16    /// String length exceeds the maximum allowed length.
17    MaxStrLength(usize),
18    /// Version-related error.
19    Version(&'static str),
20    /// Message-related error.
21    Message(&'static str),
22    /// Receivers-related error.
23    Receivers(&'static str),
24    /// Nodes-related error.
25    Nodes(&'static str),
26    /// Signal-related error.
27    Signal(&'static str),
28    /// Decoding-related error.
29    Decoding(&'static str),
30    /// Validation-related error.
31    Validation(&'static str),
32}
33
34impl Error {
35    // Error message constants
36    pub const UNEXPECTED_EOF: &'static str = lang::UNEXPECTED_EOF;
37    pub const EXPECTED_WHITESPACE: &'static str = lang::EXPECTED_WHITESPACE;
38    pub const EXPECTED_PATTERN: &'static str = lang::EXPECTED_PATTERN;
39    pub const EXPECTED_KEYWORD: &'static str = lang::EXPECTED_KEYWORD;
40    pub const EXPECTED_NUMBER: &'static str = lang::EXPECTED_NUMBER;
41    pub const EXPECTED_IDENTIFIER: &'static str = lang::EXPECTED_IDENTIFIER;
42    pub const INVALID_UTF8: &'static str = lang::INVALID_UTF8;
43    pub const INVALID_NUMBER_FORMAT: &'static str = lang::INVALID_NUMBER_FORMAT;
44    pub const PARSE_NUMBER_FAILED: &'static str = lang::PARSE_NUMBER_FAILED;
45    pub const INVALID_CHARACTER: &'static str = lang::INVALID_CHARACTER;
46    pub const STRING_LENGTH_EXCEEDS_MAX: &'static str = lang::STRING_LENGTH_EXCEEDS_MAX;
47    pub const MAX_NAME_SIZE_EXCEEDED: &'static str = lang::MAX_NAME_SIZE_EXCEEDED;
48
49    // Error prefix constants (used in Display impl)
50    pub const DECODING_ERROR_PREFIX: &'static str = lang::DECODING_ERROR_PREFIX;
51    pub const VALIDATION_ERROR_PREFIX: &'static str = lang::VALIDATION_ERROR_PREFIX;
52    pub const VERSION_ERROR_PREFIX: &'static str = lang::VERSION_ERROR_PREFIX;
53    pub const MESSAGE_ERROR_PREFIX: &'static str = lang::MESSAGE_ERROR_PREFIX;
54    pub const RECEIVERS_ERROR_PREFIX: &'static str = lang::RECEIVERS_ERROR_PREFIX;
55    pub const NODES_ERROR_PREFIX: &'static str = lang::NODES_ERROR_PREFIX;
56    pub const SIGNAL_ERROR_PREFIX: &'static str = lang::SIGNAL_ERROR_PREFIX;
57
58    // Signal error constants
59    pub const SIGNAL_PARSE_INVALID_START_BIT: &'static str = lang::SIGNAL_PARSE_INVALID_START_BIT;
60    pub const SIGNAL_PARSE_INVALID_LENGTH: &'static str = lang::SIGNAL_PARSE_INVALID_LENGTH;
61    pub const SIGNAL_PARSE_INVALID_FACTOR: &'static str = lang::SIGNAL_PARSE_INVALID_FACTOR;
62    pub const SIGNAL_PARSE_INVALID_OFFSET: &'static str = lang::SIGNAL_PARSE_INVALID_OFFSET;
63    pub const SIGNAL_PARSE_INVALID_MIN: &'static str = lang::SIGNAL_PARSE_INVALID_MIN;
64    pub const SIGNAL_PARSE_INVALID_MAX: &'static str = lang::SIGNAL_PARSE_INVALID_MAX;
65    pub const SIGNAL_PARSE_UNIT_TOO_LONG: &'static str = lang::SIGNAL_PARSE_UNIT_TOO_LONG;
66    pub const SIGNAL_NAME_EMPTY: &'static str = lang::SIGNAL_NAME_EMPTY;
67    pub const SIGNAL_LENGTH_TOO_SMALL: &'static str = lang::SIGNAL_LENGTH_TOO_SMALL;
68    pub const SIGNAL_LENGTH_TOO_LARGE: &'static str = lang::SIGNAL_LENGTH_TOO_LARGE;
69    #[cfg(feature = "std")]
70    pub const SIGNAL_LENGTH_REQUIRED: &'static str = lang::SIGNAL_LENGTH_REQUIRED;
71    #[cfg(feature = "std")]
72    pub const SIGNAL_START_BIT_REQUIRED: &'static str = lang::SIGNAL_START_BIT_REQUIRED;
73    #[cfg(feature = "std")]
74    pub const SIGNAL_BYTE_ORDER_REQUIRED: &'static str = lang::SIGNAL_BYTE_ORDER_REQUIRED;
75    #[cfg(feature = "std")]
76    pub const SIGNAL_UNSIGNED_REQUIRED: &'static str = lang::SIGNAL_UNSIGNED_REQUIRED;
77    #[cfg(feature = "std")]
78    pub const SIGNAL_FACTOR_REQUIRED: &'static str = lang::SIGNAL_FACTOR_REQUIRED;
79    #[cfg(feature = "std")]
80    pub const SIGNAL_OFFSET_REQUIRED: &'static str = lang::SIGNAL_OFFSET_REQUIRED;
81    #[cfg(feature = "std")]
82    pub const SIGNAL_MIN_REQUIRED: &'static str = lang::SIGNAL_MIN_REQUIRED;
83    #[cfg(feature = "std")]
84    pub const SIGNAL_MAX_REQUIRED: &'static str = lang::SIGNAL_MAX_REQUIRED;
85    pub const SIGNAL_OVERLAP: &'static str = lang::SIGNAL_OVERLAP;
86    pub const SIGNAL_EXTENDS_BEYOND_MESSAGE: &'static str = lang::SIGNAL_EXTENDS_BEYOND_MESSAGE;
87    pub const SIGNAL_EXTENDS_BEYOND_DATA: &'static str = lang::SIGNAL_EXTENDS_BEYOND_DATA;
88    pub const SIGNAL_RECEIVERS_TOO_MANY: &'static str = lang::SIGNAL_RECEIVERS_TOO_MANY;
89
90    // Validation and decoding error constants
91    pub const NODES_DUPLICATE_NAME: &'static str = lang::NODES_DUPLICATE_NAME;
92    pub const NODES_TOO_MANY: &'static str = lang::NODES_TOO_MANY;
93    pub const DUPLICATE_MESSAGE_ID: &'static str = lang::DUPLICATE_MESSAGE_ID;
94    pub const SENDER_NOT_IN_NODES: &'static str = lang::SENDER_NOT_IN_NODES;
95    pub const INVALID_RANGE: &'static str = lang::INVALID_RANGE;
96    pub const MESSAGE_TOO_MANY_SIGNALS: &'static str = lang::MESSAGE_TOO_MANY_SIGNALS;
97    pub const EXTENDED_MULTIPLEXING_TOO_MANY: &'static str = lang::EXTENDED_MULTIPLEXING_TOO_MANY;
98    pub const MESSAGE_NAME_EMPTY: &'static str = lang::MESSAGE_NAME_EMPTY;
99    pub const MESSAGE_SENDER_EMPTY: &'static str = lang::MESSAGE_SENDER_EMPTY;
100    pub const MESSAGE_DLC_TOO_SMALL: &'static str = lang::MESSAGE_DLC_TOO_SMALL;
101    pub const MESSAGE_DLC_TOO_LARGE: &'static str = lang::MESSAGE_DLC_TOO_LARGE;
102    #[cfg(feature = "std")]
103    pub const MESSAGE_DLC_REQUIRED: &'static str = lang::MESSAGE_DLC_REQUIRED;
104    pub const MESSAGE_ID_OUT_OF_RANGE: &'static str = lang::MESSAGE_ID_OUT_OF_RANGE;
105    #[cfg(feature = "std")]
106    pub const MESSAGE_ID_REQUIRED: &'static str = lang::MESSAGE_ID_REQUIRED;
107    pub const MESSAGE_INVALID_ID: &'static str = lang::MESSAGE_INVALID_ID;
108    pub const MESSAGE_INVALID_DLC: &'static str = lang::MESSAGE_INVALID_DLC;
109    pub const MESSAGE_NOT_FOUND: &'static str = lang::MESSAGE_NOT_FOUND;
110    pub const PAYLOAD_LENGTH_MISMATCH: &'static str = lang::PAYLOAD_LENGTH_MISMATCH;
111    pub const MULTIPLEXER_SWITCH_NEGATIVE: &'static str = lang::MULTIPLEXER_SWITCH_NEGATIVE;
112    #[cfg(feature = "std")]
113    pub const RECEIVERS_DUPLICATE_NAME: &'static str = lang::RECEIVERS_DUPLICATE_NAME;
114    #[cfg(feature = "std")]
115    pub const VALUE_DESCRIPTION_MESSAGE_NOT_FOUND: &'static str =
116        lang::VALUE_DESCRIPTION_MESSAGE_NOT_FOUND;
117    #[cfg(feature = "std")]
118    pub const VALUE_DESCRIPTION_SIGNAL_NOT_FOUND: &'static str =
119        lang::VALUE_DESCRIPTION_SIGNAL_NOT_FOUND;
120    #[cfg(feature = "std")]
121    pub const VALUE_DESCRIPTIONS_TOO_MANY: &'static str = lang::VALUE_DESCRIPTIONS_TOO_MANY;
122}
123
124impl fmt::Display for Error {
125    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
126        match self {
127            Error::UnexpectedEof => write!(f, "{}", Error::UNEXPECTED_EOF),
128            Error::Expected(msg) => write!(f, "Expected {}", msg),
129            Error::InvalidChar(c) => write!(f, "{}: {}", Error::INVALID_CHARACTER, c),
130            Error::MaxStrLength(max) => {
131                write!(f, "{}: {}", Error::STRING_LENGTH_EXCEEDS_MAX, max)
132            }
133            Error::Version(msg) => write!(f, "{}: {}", Error::VERSION_ERROR_PREFIX, msg),
134            Error::Message(msg) => write!(f, "{}: {}", Error::MESSAGE_ERROR_PREFIX, msg),
135            Error::Receivers(msg) => {
136                write!(f, "{}: {}", Error::RECEIVERS_ERROR_PREFIX, msg)
137            }
138            Error::Nodes(msg) => write!(f, "{}: {}", Error::NODES_ERROR_PREFIX, msg),
139            Error::Signal(msg) => write!(f, "{}: {}", Error::SIGNAL_ERROR_PREFIX, msg),
140            Error::Decoding(msg) => write!(f, "{}: {}", Error::DECODING_ERROR_PREFIX, msg),
141            Error::Validation(msg) => write!(f, "{}: {}", Error::VALIDATION_ERROR_PREFIX, msg),
142        }
143    }
144}
145
146impl From<core::num::ParseIntError> for Error {
147    fn from(_err: core::num::ParseIntError) -> Self {
148        Error::Expected(Error::PARSE_NUMBER_FAILED)
149    }
150}
151
152// std::error::Error is only available with std feature
153#[cfg(feature = "std")]
154impl std::error::Error for Error {
155    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
156        None
157    }
158}
159
160#[cfg(test)]
161mod tests {
162    #![allow(clippy::float_cmp)]
163
164    // Tests that require std feature (for Display/ToString)
165    #[cfg(feature = "std")]
166    mod tests_with_std {
167        use crate::Error;
168
169        #[test]
170        fn test_from_parse_int_error() {
171            // Create a ParseIntError by trying to parse an invalid string
172            let parse_error = "invalid".parse::<u32>().unwrap_err();
173            let error: Error = parse_error.into();
174
175            match error {
176                Error::Expected(msg) => {
177                    assert_eq!(msg, Error::PARSE_NUMBER_FAILED);
178                }
179                _ => panic!("Expected Error::Expected(Error::PARSE_NUMBER_FAILED)"),
180            }
181        }
182
183        #[test]
184        fn test_display_decoding_error() {
185            let error = Error::Decoding("Test error message");
186            let display = error.to_string();
187            assert!(display.starts_with(Error::DECODING_ERROR_PREFIX));
188            assert!(display.contains("Test error message"));
189        }
190
191        #[test]
192        fn test_display_signal_error() {
193            let error = Error::Signal("Test signal error");
194            let display = error.to_string();
195            assert!(display.starts_with(Error::SIGNAL_ERROR_PREFIX));
196            assert!(display.contains("Test signal error"));
197        }
198
199        #[test]
200        fn test_display_formatting() {
201            // Test that Display properly formats complex error messages
202            let error = Error::Decoding(
203                "Duplicate message ID: 256 (messages 'EngineData' and 'BrakeData')",
204            );
205            let display = error.to_string();
206            assert!(display.starts_with(Error::DECODING_ERROR_PREFIX));
207            assert!(display.contains("256"));
208            assert!(display.contains("EngineData"));
209            assert!(display.contains("BrakeData"));
210        }
211
212        #[test]
213        fn test_display_from_parse_int_error() {
214            let int_error = "not_a_number".parse::<u32>().unwrap_err();
215            let error: Error = int_error.into();
216            let display = error.to_string();
217
218            assert!(display.contains(Error::PARSE_NUMBER_FAILED));
219        }
220    }
221
222    // Tests that require std feature (for std::error::Error trait)
223    // Only available when std is enabled
224    #[cfg(feature = "std")]
225    mod tests_std {
226        use super::super::Error;
227        use std::error::Error as StdError;
228
229        #[test]
230        fn test_std_error_trait() {
231            let error = Error::Decoding("Test");
232            // Verify it implements std::error::Error
233            let _: &dyn StdError = &error;
234
235            // Verify source() returns None (no underlying error)
236            assert!(error.source().is_none());
237        }
238    }
239}