someip_rs/
error.rs

1//! Error types for SOME/IP operations.
2
3use crate::types::ReturnCode;
4use std::io;
5use thiserror::Error;
6
7/// Errors that can occur during SOME/IP operations.
8#[derive(Error, Debug)]
9pub enum SomeIpError {
10    /// I/O error during network operations.
11    #[error("I/O error: {0}")]
12    Io(#[from] io::Error),
13
14    /// Invalid message header.
15    #[error("Invalid header: {0}")]
16    InvalidHeader(String),
17
18    /// Unknown message type value.
19    #[error("Unknown message type: 0x{0:02X}")]
20    UnknownMessageType(u8),
21
22    /// Unknown return code value.
23    #[error("Unknown return code: 0x{0:02X}")]
24    UnknownReturnCode(u8),
25
26    /// Wrong protocol version.
27    #[error("Wrong protocol version: expected 0x01, got 0x{0:02X}")]
28    WrongProtocolVersion(u8),
29
30    /// Message too short to contain header.
31    #[error("Message too short: expected at least {expected} bytes, got {actual}")]
32    MessageTooShort { expected: usize, actual: usize },
33
34    /// Message length mismatch.
35    #[error("Message length mismatch: header says {header_length} bytes, got {actual_length}")]
36    LengthMismatch {
37        header_length: u32,
38        actual_length: usize,
39    },
40
41    /// Payload too large.
42    #[error("Payload too large: {size} bytes exceeds maximum of {max} bytes")]
43    PayloadTooLarge { size: usize, max: usize },
44
45    /// Protocol error returned by remote.
46    #[error("Protocol error: {0:?}")]
47    ProtocolError(ReturnCode),
48
49    /// Connection closed unexpectedly.
50    #[error("Connection closed")]
51    ConnectionClosed,
52
53    /// Operation timed out.
54    #[error("Operation timed out")]
55    Timeout,
56
57    /// No response received for request.
58    #[error("No response received for request (client={client_id:04X}, session={session_id:04X})")]
59    NoResponse { client_id: u16, session_id: u16 },
60}
61
62/// Result type alias for SOME/IP operations.
63pub type Result<T> = std::result::Result<T, SomeIpError>;
64
65impl SomeIpError {
66    /// Create a new invalid header error.
67    pub fn invalid_header(msg: impl Into<String>) -> Self {
68        Self::InvalidHeader(msg.into())
69    }
70
71    /// Check if this error is recoverable (transient).
72    pub fn is_recoverable(&self) -> bool {
73        matches!(
74            self,
75            Self::Io(e) if e.kind() == io::ErrorKind::WouldBlock
76                || e.kind() == io::ErrorKind::TimedOut
77                || e.kind() == io::ErrorKind::Interrupted
78        ) || matches!(self, Self::Timeout)
79    }
80}
81
82#[cfg(test)]
83mod tests {
84    use super::*;
85
86    #[test]
87    fn test_error_display() {
88        let err = SomeIpError::UnknownMessageType(0xFF);
89        assert_eq!(format!("{err}"), "Unknown message type: 0xFF");
90
91        let err = SomeIpError::MessageTooShort {
92            expected: 16,
93            actual: 8,
94        };
95        assert_eq!(
96            format!("{err}"),
97            "Message too short: expected at least 16 bytes, got 8"
98        );
99    }
100
101    #[test]
102    fn test_from_io_error() {
103        let io_err = io::Error::new(io::ErrorKind::ConnectionRefused, "test");
104        let err: SomeIpError = io_err.into();
105        assert!(matches!(err, SomeIpError::Io(_)));
106    }
107}