simple_someip/protocol/error.rs
1use thiserror::Error;
2
3/// Errors that can occur when encoding, decoding, or validating SOME/IP messages.
4#[derive(Error, Debug)]
5#[non_exhaustive]
6pub enum Error {
7 /// An I/O error occurred while reading or writing bytes.
8 #[error("I/O error: {0:?}")]
9 Io(embedded_io::ErrorKind),
10 /// Input ended before the expected number of bytes could be read.
11 #[error("incomplete: need {} bytes, have {}", .0.needed, .0.available)]
12 Incomplete(#[from] automotive_wire_codec::Incomplete),
13 /// Bytes remained after a value that should have consumed the whole buffer.
14 #[error("trailing bytes: {} left over", .0.0)]
15 Trailing(#[from] automotive_wire_codec::TrailingBytes),
16 /// An output slice was too small for the bytes an encode needed to write.
17 #[error("insufficient buffer: need {} bytes, have {}", .0.needed, .0.available)]
18 InsufficientBuffer(#[from] automotive_wire_codec::InsufficientBuffer),
19 /// The protocol version field contains an unsupported value.
20 #[error("Invalid protocol version: {0:X}")]
21 InvalidProtocolVersion(u8),
22 /// The message type field contains an unrecognized value.
23 #[error("Invalid value in MessageType field: {0:X}")]
24 InvalidMessageTypeField(u8),
25 /// The return code field contains an unrecognized value.
26 #[error("Invalid value in ReturnCode field: {0:X}")]
27 InvalidReturnCode(u8),
28 /// The SOME/IP length field was smaller than the 8-byte minimum (`request_id..return_code`).
29 #[error("Invalid SOME/IP length field: {0} (minimum 8)")]
30 InvalidLength(u32),
31 /// The message ID is not supported by the payload implementation.
32 #[error("Unsupported MessageID {0:X?}")]
33 UnsupportedMessageID(super::MessageId),
34 /// A service discovery (SD) error occurred.
35 #[error(transparent)]
36 Sd(#[from] super::sd::Error),
37}
38
39impl From<embedded_io::ErrorKind> for Error {
40 fn from(k: embedded_io::ErrorKind) -> Self {
41 Error::Io(k)
42 }
43}
44
45impl From<automotive_wire_codec::EncodeToSliceError<Error>> for Error {
46 fn from(e: automotive_wire_codec::EncodeToSliceError<Error>) -> Self {
47 use automotive_wire_codec::EncodeToSliceError::{Encode, InsufficientBuffer};
48 match e {
49 InsufficientBuffer(ib) => Error::InsufficientBuffer(ib),
50 Encode(inner) => inner,
51 }
52 }
53}
54
55/// Bridges [`crate::e2e::Error`] onto `protocol::Error` so E2E failures can be
56/// reported through the same error type as the rest of the wire path.
57///
58/// E2E deliberately does **not** implement `Encode`/`Decode` (see the
59/// `src/e2e` module docs), so it keeps its own `Error` type. This impl only
60/// aligns the *shape* of that error with `protocol::Error` for callers that
61/// want a single error type to propagate; it does not change E2E's
62/// protect/check behavior or on-wire bytes.
63///
64/// # Mapping
65///
66/// `e2e::Error` currently has exactly one variant:
67///
68/// - [`crate::e2e::Error::BufferTooSmall`] `{ needed, actual }` → maps to
69/// [`Error::InsufficientBuffer`], **not** [`Error::Incomplete`]. Although
70/// `Incomplete { needed, available }` has the identical field shape, its
71/// semantics are decode-direction ("input ended before enough bytes could
72/// be *read*"). `BufferTooSmall` instead means an output slice was too
73/// small to hold the bytes E2E `protect` needed to *write* — the same
74/// direction as `automotive_wire_codec::InsufficientBuffer` ("An output
75/// slice was too small for the bytes an encode needed to write"). That is
76/// the semantically correct counterpart, so `needed`/`actual` map directly
77/// onto `InsufficientBuffer`'s `needed`/`available` fields.
78impl From<crate::e2e::Error> for Error {
79 fn from(err: crate::e2e::Error) -> Self {
80 match err {
81 crate::e2e::Error::BufferTooSmall { needed, actual } => {
82 Error::InsufficientBuffer(automotive_wire_codec::InsufficientBuffer {
83 needed,
84 available: actual,
85 })
86 }
87 }
88 }
89}
90
91#[cfg(test)]
92mod e2e_bridge_tests {
93 use super::Error;
94
95 #[test]
96 fn buffer_too_small_maps_to_insufficient_buffer() {
97 let e2e_err = crate::e2e::Error::BufferTooSmall {
98 needed: 16,
99 actual: 10,
100 };
101 let mapped: Error = e2e_err.into();
102 match mapped {
103 Error::InsufficientBuffer(ib) => {
104 assert_eq!(ib.needed, 16);
105 assert_eq!(ib.available, 10);
106 }
107 other => panic!("expected Error::InsufficientBuffer, got {other:?}"),
108 }
109 }
110}