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    pub const SIGNAL_OVERLAP: &'static str = lang::SIGNAL_OVERLAP;
74    pub const SIGNAL_EXTENDS_BEYOND_MESSAGE: &'static str = lang::SIGNAL_EXTENDS_BEYOND_MESSAGE;
75    pub const SIGNAL_EXTENDS_BEYOND_DATA: &'static str = lang::SIGNAL_EXTENDS_BEYOND_DATA;
76    pub const SIGNAL_RECEIVERS_TOO_MANY: &'static str = lang::SIGNAL_RECEIVERS_TOO_MANY;
77
78    // Validation and decoding error constants
79    pub const NODES_DUPLICATE_NAME: &'static str = lang::NODES_DUPLICATE_NAME;
80    pub const NODES_TOO_MANY: &'static str = lang::NODES_TOO_MANY;
81    pub const DUPLICATE_MESSAGE_ID: &'static str = lang::DUPLICATE_MESSAGE_ID;
82    pub const SENDER_NOT_IN_NODES: &'static str = lang::SENDER_NOT_IN_NODES;
83    pub const INVALID_RANGE: &'static str = lang::INVALID_RANGE;
84    pub const MESSAGE_TOO_MANY_SIGNALS: &'static str = lang::MESSAGE_TOO_MANY_SIGNALS;
85    pub const MESSAGE_NAME_EMPTY: &'static str = lang::MESSAGE_NAME_EMPTY;
86    pub const MESSAGE_SENDER_EMPTY: &'static str = lang::MESSAGE_SENDER_EMPTY;
87    pub const MESSAGE_DLC_TOO_SMALL: &'static str = lang::MESSAGE_DLC_TOO_SMALL;
88    pub const MESSAGE_DLC_TOO_LARGE: &'static str = lang::MESSAGE_DLC_TOO_LARGE;
89    #[cfg(feature = "std")]
90    pub const MESSAGE_DLC_REQUIRED: &'static str = lang::MESSAGE_DLC_REQUIRED;
91    pub const MESSAGE_ID_OUT_OF_RANGE: &'static str = lang::MESSAGE_ID_OUT_OF_RANGE;
92    #[cfg(feature = "std")]
93    pub const MESSAGE_ID_REQUIRED: &'static str = lang::MESSAGE_ID_REQUIRED;
94    pub const MESSAGE_INVALID_ID: &'static str = lang::MESSAGE_INVALID_ID;
95    pub const MESSAGE_INVALID_DLC: &'static str = lang::MESSAGE_INVALID_DLC;
96    pub const MESSAGE_NOT_FOUND: &'static str = lang::MESSAGE_NOT_FOUND;
97    pub const PAYLOAD_LENGTH_MISMATCH: &'static str = lang::PAYLOAD_LENGTH_MISMATCH;
98    #[cfg(feature = "std")]
99    pub const RECEIVERS_DUPLICATE_NAME: &'static str = lang::RECEIVERS_DUPLICATE_NAME;
100    #[cfg(feature = "std")]
101    pub const VALUE_DESCRIPTION_MESSAGE_NOT_FOUND: &'static str =
102        lang::VALUE_DESCRIPTION_MESSAGE_NOT_FOUND;
103    #[cfg(feature = "std")]
104    pub const VALUE_DESCRIPTION_SIGNAL_NOT_FOUND: &'static str =
105        lang::VALUE_DESCRIPTION_SIGNAL_NOT_FOUND;
106    #[cfg(feature = "std")]
107    pub const VALUE_DESCRIPTIONS_TOO_MANY: &'static str = lang::VALUE_DESCRIPTIONS_TOO_MANY;
108}
109
110impl fmt::Display for Error {
111    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
112        match self {
113            Error::UnexpectedEof => write!(f, "{}", Error::UNEXPECTED_EOF),
114            Error::Expected(msg) => write!(f, "Expected {}", msg),
115            Error::InvalidChar(c) => write!(f, "{}: {}", Error::INVALID_CHARACTER, c),
116            Error::MaxStrLength(max) => {
117                write!(f, "{}: {}", Error::STRING_LENGTH_EXCEEDS_MAX, max)
118            }
119            Error::Version(msg) => write!(f, "{}: {}", Error::VERSION_ERROR_PREFIX, msg),
120            Error::Message(msg) => write!(f, "{}: {}", Error::MESSAGE_ERROR_PREFIX, msg),
121            Error::Receivers(msg) => {
122                write!(f, "{}: {}", Error::RECEIVERS_ERROR_PREFIX, msg)
123            }
124            Error::Nodes(msg) => write!(f, "{}: {}", Error::NODES_ERROR_PREFIX, msg),
125            Error::Signal(msg) => write!(f, "{}: {}", Error::SIGNAL_ERROR_PREFIX, msg),
126            Error::Decoding(msg) => write!(f, "{}: {}", Error::DECODING_ERROR_PREFIX, msg),
127            Error::Validation(msg) => write!(f, "{}: {}", Error::VALIDATION_ERROR_PREFIX, msg),
128        }
129    }
130}
131
132impl From<core::num::ParseIntError> for Error {
133    fn from(_err: core::num::ParseIntError) -> Self {
134        Error::Expected(Error::PARSE_NUMBER_FAILED)
135    }
136}
137
138// std::error::Error is only available with std feature
139#[cfg(feature = "std")]
140impl std::error::Error for Error {
141    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
142        None
143    }
144}
145
146#[cfg(test)]
147mod tests {
148    #![allow(clippy::float_cmp)]
149
150    // Tests that require std feature (for Display/ToString)
151    #[cfg(feature = "std")]
152    mod tests_with_std {
153        use crate::Error;
154
155        #[test]
156        fn test_from_parse_int_error() {
157            // Create a ParseIntError by trying to parse an invalid string
158            let parse_error = "invalid".parse::<u32>().unwrap_err();
159            let error: Error = parse_error.into();
160
161            match error {
162                Error::Expected(msg) => {
163                    assert_eq!(msg, Error::PARSE_NUMBER_FAILED);
164                }
165                _ => panic!("Expected Error::Expected(Error::PARSE_NUMBER_FAILED)"),
166            }
167        }
168
169        #[test]
170        fn test_display_decoding_error() {
171            let error = Error::Decoding("Test error message");
172            let display = error.to_string();
173            assert!(display.starts_with(Error::DECODING_ERROR_PREFIX));
174            assert!(display.contains("Test error message"));
175        }
176
177        #[test]
178        fn test_display_signal_error() {
179            let error = Error::Signal("Test signal error");
180            let display = error.to_string();
181            assert!(display.starts_with(Error::SIGNAL_ERROR_PREFIX));
182            assert!(display.contains("Test signal error"));
183        }
184
185        #[test]
186        fn test_display_formatting() {
187            // Test that Display properly formats complex error messages
188            let error = Error::Decoding(
189                "Duplicate message ID: 256 (messages 'EngineData' and 'BrakeData')",
190            );
191            let display = error.to_string();
192            assert!(display.starts_with(Error::DECODING_ERROR_PREFIX));
193            assert!(display.contains("256"));
194            assert!(display.contains("EngineData"));
195            assert!(display.contains("BrakeData"));
196        }
197
198        #[test]
199        fn test_display_from_parse_int_error() {
200            let int_error = "not_a_number".parse::<u32>().unwrap_err();
201            let error: Error = int_error.into();
202            let display = error.to_string();
203
204            assert!(display.contains(Error::PARSE_NUMBER_FAILED));
205        }
206    }
207
208    // Tests that require std feature (for std::error::Error trait)
209    // Only available when std is enabled
210    #[cfg(feature = "std")]
211    mod tests_std {
212        use super::super::Error;
213        use std::error::Error as StdError;
214
215        #[test]
216        fn test_std_error_trait() {
217            let error = Error::Decoding("Test");
218            // Verify it implements std::error::Error
219            let _: &dyn StdError = &error;
220
221            // Verify source() returns None (no underlying error)
222            assert!(error.source().is_none());
223        }
224    }
225}