1use core::{convert::From, fmt};
2
3#[cfg(any(feature = "alloc", feature = "kernel"))]
7#[allow(unused_imports)]
8use core::num::ParseIntError;
9
10#[cfg(all(feature = "kernel", not(feature = "alloc")))]
12use crate::kernel::alloc::string::String as ErrorString;
13#[cfg(all(feature = "alloc", not(feature = "kernel")))]
14use alloc::string::String as ErrorString;
15
16#[cfg(all(feature = "kernel", not(feature = "alloc")))]
18pub(crate) fn str_to_error_string(s: &str) -> ErrorString {
19 ErrorString::from_str(s)
20}
21
22#[cfg(all(feature = "alloc", not(feature = "kernel")))]
23pub(crate) fn str_to_error_string(s: &str) -> ErrorString {
24 ErrorString::from(s)
25}
26
27pub mod lang;
28pub(crate) mod messages;
29
30#[derive(Debug, PartialEq)]
35pub enum Error {
36 #[cfg(any(feature = "alloc", feature = "kernel"))]
38 InvalidData(ErrorString),
39
40 #[cfg(any(feature = "alloc", feature = "kernel"))]
42 Signal(ErrorString),
43
44 #[cfg(any(feature = "alloc", feature = "kernel"))]
46 Message(ErrorString),
47
48 #[cfg(any(feature = "alloc", feature = "kernel"))]
50 Dbc(ErrorString),
51
52 #[cfg(any(feature = "alloc", feature = "kernel"))]
54 Version(ErrorString),
55
56 #[cfg(any(feature = "alloc", feature = "kernel"))]
58 Nodes(ErrorString),
59
60 ParseError(ParseError),
62}
63
64#[derive(Debug, PartialEq, Clone, Copy)]
68pub enum ParseError {
69 UnexpectedEof,
71
72 Expected(&'static str),
74
75 InvalidChar(char),
77
78 MaxStrLength(u16),
80
81 Version(&'static str),
83}
84
85impl fmt::Display for ParseError {
86 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
87 match self {
88 ParseError::UnexpectedEof => write!(f, "Unexpected end of input"),
89 ParseError::Expected(msg) => write!(f, "Expected {}", msg),
90 ParseError::InvalidChar(c) => write!(f, "Invalid character: {}", c),
91 ParseError::MaxStrLength(max) => write!(f, "String length exceeds maximum: {}", max),
92 ParseError::Version(msg) => write!(f, "Version error: {}", msg),
93 }
94 }
95}
96
97pub type Result<T> = core::result::Result<T, Error>;
99
100pub type ParseResult<T> = core::result::Result<T, ParseError>;
102
103#[cfg(feature = "alloc")]
127pub(crate) fn version_error_from_string(msg: ErrorString) -> ParseError {
128 use alloc::boxed::Box;
129 ParseError::Version(Box::leak(msg.into_boxed_str()))
130}
131
132#[cfg(all(feature = "alloc", not(feature = "kernel")))]
134impl fmt::Display for Error {
135 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
136 match self {
137 Error::InvalidData(msg) => write!(f, "{}", messages::format_invalid_data(msg)),
138 Error::Signal(msg) => write!(f, "{}", messages::format_signal_error(msg)),
139 Error::Message(msg) => write!(f, "{}", messages::format_message_error(msg)),
140 Error::Dbc(msg) => write!(f, "{}", messages::format_dbc_error(msg)),
141 Error::Version(msg) => write!(f, "{}", messages::format_version_error(msg)),
142 Error::Nodes(msg) => write!(f, "{}", messages::format_nodes_error(msg)),
143 Error::ParseError(msg) => write!(f, "Parse Error: {}", msg),
144 }
145 }
146}
147
148#[cfg(all(feature = "kernel", not(feature = "alloc")))]
149impl fmt::Display for Error {
150 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
151 match self {
152 Error::InvalidData(msg) => {
153 let formatted = messages::format_invalid_data(msg);
154 write!(f, "{}", formatted)
155 }
156 Error::Signal(msg) => {
157 let formatted = messages::format_signal_error(msg);
158 write!(f, "{}", formatted)
159 }
160 Error::Message(msg) => {
161 let formatted = messages::format_message_error(msg);
162 write!(f, "{}", formatted)
163 }
164 Error::Dbc(msg) => {
165 let formatted = messages::format_dbc_error(msg);
166 write!(f, "{}", formatted)
167 }
168 Error::Version(msg) => {
169 let formatted = messages::format_version_error(msg);
170 write!(f, "{}", formatted)
171 }
172 Error::Nodes(msg) => {
173 let formatted = messages::format_nodes_error(msg);
174 write!(f, "{}", formatted)
175 }
176 Error::ParseError(msg) => write!(f, "Parse Error: {}", msg),
177 }
178 }
179}
180
181#[cfg(all(feature = "alloc", not(feature = "kernel")))]
183impl From<ParseIntError> for Error {
184 fn from(err: ParseIntError) -> Self {
185 Error::InvalidData(messages::parse_number_failed(err))
186 }
187}
188
189#[cfg(all(feature = "kernel", not(feature = "alloc")))]
190impl From<ParseIntError> for Error {
191 fn from(err: ParseIntError) -> Self {
192 Error::InvalidData(messages::parse_number_failed(err))
194 }
195}
196
197#[cfg(not(any(feature = "alloc", feature = "kernel")))]
198impl From<core::num::ParseIntError> for Error {
199 fn from(_err: core::num::ParseIntError) -> Self {
200 Error::ParseError(ParseError::Expected("Invalid number format"))
203 }
204}
205
206impl From<ParseError> for Error {
207 fn from(err: ParseError) -> Self {
208 Error::ParseError(err)
209 }
210}
211
212#[cfg(all(feature = "std", feature = "alloc", not(feature = "kernel")))]
215impl std::error::Error for Error {
216 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
217 None
218 }
219}
220
221#[cfg(test)]
222mod tests {
223 #![allow(clippy::float_cmp)]
224
225 #[cfg(any(feature = "alloc", feature = "kernel"))]
227 mod tests_with_alloc {
228 use crate::error::{Error, lang};
229
230 #[test]
231 fn test_from_parse_int_error() {
232 let parse_error = "invalid".parse::<u32>().unwrap_err();
234 let error: Error = parse_error.into();
235
236 match error {
237 Error::InvalidData(msg) => {
238 assert!(
239 msg.contains(lang::FORMAT_PARSE_NUMBER_FAILED.split(':').next().unwrap())
240 );
241 }
242 _ => panic!("Expected InvalidData error"),
243 }
244 }
245
246 #[test]
247 fn test_display_invalid_data() {
248 use crate::compat::{display_to_string, str_to_string};
249 let error = Error::InvalidData(str_to_string("Test error message"));
250 let display = display_to_string(error);
251 assert!(display.starts_with(lang::INVALID_DATA_CATEGORY));
252 assert!(display.contains("Test error message"));
253 }
254
255 #[test]
256 fn test_display_signal_error() {
257 use crate::compat::{display_to_string, str_to_string};
258 let error = Error::Signal(str_to_string("Test signal error"));
259 let display = display_to_string(error);
260 assert!(display.starts_with(lang::SIGNAL_ERROR_CATEGORY));
261 assert!(display.contains("Test signal error"));
262 }
263
264 #[test]
265 fn test_display_formatting() {
266 use crate::compat::{display_to_string, str_to_string};
267 let error = Error::InvalidData(str_to_string(
269 "Duplicate message ID: 256 (messages 'EngineData' and 'BrakeData')",
270 ));
271 let display = display_to_string(error);
272 assert!(display.starts_with(lang::INVALID_DATA_CATEGORY));
273 assert!(display.contains("256"));
274 assert!(display.contains("EngineData"));
275 assert!(display.contains("BrakeData"));
276 }
277
278 #[test]
279 fn test_display_parse_error() {
280 use crate::compat::display_to_string;
281 let parse_error = "not_a_number".parse::<u32>().unwrap_err();
282 let error: Error = parse_error.into();
283 let display = display_to_string(error);
284
285 assert!(display.starts_with(lang::INVALID_DATA_CATEGORY));
286 assert!(display.contains(lang::FORMAT_PARSE_NUMBER_FAILED.split(':').next().unwrap()));
287 }
288 }
289
290 #[cfg(feature = "std")]
292 mod tests_std {
293 use crate::error::Error;
294 use std::error::Error as StdError;
295
296 #[test]
297 fn test_std_error_trait() {
298 use crate::compat::str_to_string;
299 let error = Error::InvalidData(str_to_string("Test"));
300 let _: &dyn StdError = &error;
302
303 assert!(error.source().is_none());
305 }
306 }
307}