1use core::{convert::From, fmt};
2
3#[cfg(any(feature = "alloc", feature = "kernel"))]
5use core::num::ParseIntError;
6
7#[cfg(feature = "kernel")]
10use crate::kernel::alloc::string::String as ErrorString;
11#[cfg(all(feature = "alloc", not(feature = "kernel")))]
12use alloc::string::String as ErrorString;
13
14#[cfg(feature = "kernel")]
16pub(crate) fn str_to_error_string(s: &str) -> ErrorString {
17 crate::kernel::alloc::string::String::from_str(s)
18}
19
20#[cfg(all(feature = "alloc", not(feature = "kernel")))]
21pub(crate) fn str_to_error_string(s: &str) -> ErrorString {
22 alloc::string::String::from(s)
23}
24
25pub mod lang;
26
27#[derive(Debug, PartialEq)]
32pub enum Error {
33 #[cfg(any(feature = "alloc", feature = "kernel"))]
35 InvalidData(ErrorString),
36
37 #[cfg(any(feature = "alloc", feature = "kernel"))]
39 Signal(ErrorString),
40
41 #[cfg(any(feature = "alloc", feature = "kernel"))]
43 Message(ErrorString),
44
45 #[cfg(any(feature = "alloc", feature = "kernel"))]
47 Dbc(ErrorString),
48
49 #[cfg(any(feature = "alloc", feature = "kernel"))]
51 Version(ErrorString),
52
53 #[cfg(any(feature = "alloc", feature = "kernel"))]
55 Nodes(ErrorString),
56
57 ParseError(ParseError),
59}
60
61#[derive(Debug, PartialEq, Clone, Copy)]
65pub enum ParseError {
66 UnexpectedEof,
68
69 Expected(&'static str),
71
72 InvalidChar(char),
74
75 MaxStrLength(u16),
77
78 Version(&'static str),
80
81 Message(&'static str),
83
84 Receivers(&'static str),
86
87 Nodes(&'static str),
89
90 Signal(&'static str),
92}
93
94impl fmt::Display for ParseError {
95 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
96 match self {
97 ParseError::UnexpectedEof => write!(f, "Unexpected end of input"),
98 ParseError::Expected(msg) => write!(f, "Expected {}", msg),
99 ParseError::InvalidChar(c) => write!(f, "Invalid character: {}", c),
100 ParseError::MaxStrLength(max) => write!(f, "String length exceeds maximum: {}", max),
101 ParseError::Version(msg) => write!(f, "Version error: {}", msg),
102 ParseError::Message(msg) => write!(f, "Message error: {}", msg),
103 ParseError::Receivers(msg) => write!(f, "Receivers error: {}", msg),
104 ParseError::Nodes(msg) => write!(f, "Nodes error: {}", msg),
105 ParseError::Signal(msg) => write!(f, "Signal error: {}", msg),
106 }
107 }
108}
109
110pub type Result<T> = core::result::Result<T, Error>;
112
113pub type ParseResult<T> = core::result::Result<T, ParseError>;
115
116#[cfg(any(feature = "alloc", feature = "kernel"))]
118impl Error {
119 pub(crate) fn signal(msg: &'static str) -> Self {
120 Error::Signal(str_to_error_string(msg))
121 }
122
123 pub(crate) fn message(msg: &'static str) -> Self {
124 Error::Message(str_to_error_string(msg))
125 }
126
127 pub(crate) fn dbc(msg: &'static str) -> Self {
128 Error::Dbc(str_to_error_string(msg))
129 }
130
131 pub(crate) fn version(msg: &'static str) -> Self {
132 Error::Version(str_to_error_string(msg))
133 }
134
135 pub(crate) fn nodes(msg: &'static str) -> Self {
136 Error::Nodes(str_to_error_string(msg))
137 }
138}
139
140#[cfg(any(feature = "alloc", feature = "kernel"))]
142impl fmt::Display for Error {
143 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
144 match self {
145 Error::InvalidData(msg) => write!(f, "{}: {}", lang::INVALID_DATA_CATEGORY, msg),
146 Error::Signal(msg) => write!(f, "{}: {}", lang::SIGNAL_ERROR_CATEGORY, msg),
147 Error::Message(msg) => write!(f, "{}: {}", lang::MESSAGE_ERROR_CATEGORY, msg),
148 Error::Dbc(msg) => write!(f, "{}: {}", lang::DBC_ERROR_CATEGORY, msg),
149 Error::Version(msg) => write!(f, "{}: {}", lang::VERSION_ERROR_CATEGORY, msg),
150 Error::Nodes(msg) => write!(f, "{}: {}", lang::NODES_ERROR_CATEGORY, msg),
151 Error::ParseError(msg) => write!(f, "Parse Error: {}", msg),
152 }
153 }
154}
155
156#[cfg(any(feature = "alloc", feature = "kernel"))]
158impl From<ParseIntError> for Error {
159 fn from(_err: ParseIntError) -> Self {
160 Error::InvalidData(str_to_error_string(lang::PARSE_NUMBER_FAILED))
161 }
162}
163
164#[cfg(not(any(feature = "alloc", feature = "kernel")))]
165impl From<core::num::ParseIntError> for Error {
166 fn from(_err: core::num::ParseIntError) -> Self {
167 Error::ParseError(ParseError::Expected("Invalid number format"))
170 }
171}
172
173impl From<ParseError> for Error {
174 fn from(err: ParseError) -> Self {
175 Error::ParseError(err)
176 }
177}
178
179#[cfg(all(feature = "std", feature = "alloc", not(feature = "kernel")))]
182impl std::error::Error for Error {
183 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
184 None
185 }
186}
187
188#[cfg(test)]
189mod tests {
190 #![allow(clippy::float_cmp)]
191
192 #[cfg(any(feature = "alloc", feature = "kernel"))]
194 mod tests_with_alloc {
195 use crate::error::{Error, lang};
196
197 #[test]
198 fn test_from_parse_int_error() {
199 let parse_error = "invalid".parse::<u32>().unwrap_err();
201 let error: Error = parse_error.into();
202
203 match error {
204 Error::InvalidData(msg) => {
205 assert!(msg.contains(lang::PARSE_NUMBER_FAILED));
206 }
207 _ => panic!("Expected InvalidData error"),
208 }
209 }
210
211 #[test]
212 fn test_display_invalid_data() {
213 use crate::compat::{display_to_string, str_to_string};
214 let error = Error::InvalidData(str_to_string("Test error message"));
215 let display = display_to_string(error);
216 assert!(display.starts_with(lang::INVALID_DATA_CATEGORY));
217 assert!(display.contains("Test error message"));
218 }
219
220 #[test]
221 fn test_display_signal_error() {
222 use crate::compat::{display_to_string, str_to_string};
223 let error = Error::Signal(str_to_string("Test signal error"));
224 let display = display_to_string(error);
225 assert!(display.starts_with(lang::SIGNAL_ERROR_CATEGORY));
226 assert!(display.contains("Test signal error"));
227 }
228
229 #[test]
230 fn test_display_formatting() {
231 use crate::compat::{display_to_string, str_to_string};
232 let error = Error::InvalidData(str_to_string(
234 "Duplicate message ID: 256 (messages 'EngineData' and 'BrakeData')",
235 ));
236 let display = display_to_string(error);
237 assert!(display.starts_with(lang::INVALID_DATA_CATEGORY));
238 assert!(display.contains("256"));
239 assert!(display.contains("EngineData"));
240 assert!(display.contains("BrakeData"));
241 }
242
243 #[test]
244 fn test_display_parse_error() {
245 use crate::compat::display_to_string;
246 let parse_error = "not_a_number".parse::<u32>().unwrap_err();
247 let error: Error = parse_error.into();
248 let display = display_to_string(error);
249
250 assert!(display.starts_with(lang::INVALID_DATA_CATEGORY));
251 assert!(display.contains(lang::PARSE_NUMBER_FAILED));
252 }
253 }
254
255 #[cfg(all(feature = "std", feature = "alloc", not(feature = "kernel")))]
258 mod tests_std {
259 use crate::error::Error;
260 use std::error::Error as StdError;
261
262 #[test]
263 fn test_std_error_trait() {
264 use crate::compat::str_to_string;
265 let error = Error::InvalidData(str_to_string("Test"));
266 let _: &dyn StdError = &error;
268
269 assert!(error.source().is_none());
271 }
272 }
273}