Skip to main content

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}