Skip to main content

simple_someip/protocol/
return_code.rs

1use super::Error;
2
3///Return code contained in a SOME/IP header.
4#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
5pub enum ReturnCode {
6    /// No error (0x00).
7    Ok,
8    /// An unspecified error occurred (0x01).
9    NotOk,
10    /// The requested service is unknown (0x02).
11    UnknownService,
12    /// The requested method is unknown (0x03).
13    UnknownMethod,
14    /// The service is not ready (0x04).
15    NotReady,
16    /// The service is not reachable (0x05).
17    NotReachable,
18    /// A timeout occurred (0x06).
19    Timeout,
20    /// The protocol version is not supported (0x07).
21    WrongProtocolVersion,
22    /// The interface version is not supported (0x08).
23    WrongInterfaceVersion,
24    /// The message is malformed (0x09).
25    MalformedMessage,
26    /// The message type is wrong for the context (0x0A).
27    WrongMessageType,
28    /// E2E: repeated message detected (0x0B).
29    E2ERepeated,
30    /// E2E: wrong sequence counter (0x0C).
31    E2EWrongSequence,
32    /// E2E: unspecified E2E error (0x0D).
33    E2E,
34    /// E2E: protection not available (0x0E).
35    E2ENotAvailable,
36    /// E2E: no new data (0x0F).
37    E2ENoNewData,
38    /// A generic error in the range 0x10..=0x1F.
39    GenericError(u8),
40    /// An interface-specific error in the range 0x20..=0x5E.
41    InterfaceError(u8),
42}
43
44impl ReturnCode {
45    /// Returns the raw byte value of the return code.
46    #[must_use]
47    pub const fn as_u8(self) -> u8 {
48        match self {
49            ReturnCode::Ok => 0x00,
50            ReturnCode::NotOk => 0x01,
51            ReturnCode::UnknownService => 0x02,
52            ReturnCode::UnknownMethod => 0x03,
53            ReturnCode::NotReady => 0x04,
54            ReturnCode::NotReachable => 0x05,
55            ReturnCode::Timeout => 0x06,
56            ReturnCode::WrongProtocolVersion => 0x07,
57            ReturnCode::WrongInterfaceVersion => 0x08,
58            ReturnCode::MalformedMessage => 0x09,
59            ReturnCode::WrongMessageType => 0x0a,
60            ReturnCode::E2ERepeated => 0x0b,
61            ReturnCode::E2EWrongSequence => 0x0c,
62            ReturnCode::E2E => 0x0d,
63            ReturnCode::E2ENotAvailable => 0x0e,
64            ReturnCode::E2ENoNewData => 0x0f,
65            ReturnCode::GenericError(value) | ReturnCode::InterfaceError(value) => value,
66        }
67    }
68}
69
70impl TryFrom<u8> for ReturnCode {
71    type Error = Error;
72    fn try_from(value: u8) -> Result<Self, Error> {
73        match value {
74            0x00 => Ok(ReturnCode::Ok),
75            0x01 => Ok(ReturnCode::NotOk),
76            0x02 => Ok(ReturnCode::UnknownService),
77            0x03 => Ok(ReturnCode::UnknownMethod),
78            0x04 => Ok(ReturnCode::NotReady),
79            0x05 => Ok(ReturnCode::NotReachable),
80            0x06 => Ok(ReturnCode::Timeout),
81            0x07 => Ok(ReturnCode::WrongProtocolVersion),
82            0x08 => Ok(ReturnCode::WrongInterfaceVersion),
83            0x09 => Ok(ReturnCode::MalformedMessage),
84            0x0a => Ok(ReturnCode::WrongMessageType),
85            0x0b => Ok(ReturnCode::E2ERepeated),
86            0x0c => Ok(ReturnCode::E2EWrongSequence),
87            0x0d => Ok(ReturnCode::E2E),
88            0x0e => Ok(ReturnCode::E2ENotAvailable),
89            0x0f => Ok(ReturnCode::E2ENoNewData),
90            0x10..=0x1f => Ok(ReturnCode::GenericError(value)),
91            0x20..=0x5e => Ok(ReturnCode::InterfaceError(value)),
92            _ => Err(Error::InvalidReturnCode(value)),
93        }
94    }
95}
96
97impl From<ReturnCode> for u8 {
98    fn from(return_code: ReturnCode) -> u8 {
99        match return_code {
100            ReturnCode::Ok => 0x00,
101            ReturnCode::NotOk => 0x01,
102            ReturnCode::UnknownService => 0x02,
103            ReturnCode::UnknownMethod => 0x03,
104            ReturnCode::NotReady => 0x04,
105            ReturnCode::NotReachable => 0x05,
106            ReturnCode::Timeout => 0x06,
107            ReturnCode::WrongProtocolVersion => 0x07,
108            ReturnCode::WrongInterfaceVersion => 0x08,
109            ReturnCode::MalformedMessage => 0x09,
110            ReturnCode::WrongMessageType => 0x0a,
111            ReturnCode::E2ERepeated => 0x0b,
112            ReturnCode::E2EWrongSequence => 0x0c,
113            ReturnCode::E2E => 0x0d,
114            ReturnCode::E2ENotAvailable => 0x0e,
115            ReturnCode::E2ENoNewData => 0x0f,
116            ReturnCode::GenericError(value) | ReturnCode::InterfaceError(value) => value,
117        }
118    }
119}
120
121#[cfg(test)]
122mod tests {
123    use super::*;
124
125    // Every valid u8 should round-trip: TryFrom then From gives back the same byte.
126    // Invalid bytes (0x5f..=0xff) must return an error.
127    #[test]
128    fn all_valid_u8_values_round_trip() {
129        for byte in 0x00u8..=0xffu8 {
130            match ReturnCode::try_from(byte) {
131                Ok(code) => {
132                    assert!(
133                        byte < 0x5f,
134                        "0x{byte:02X} should be invalid but decoded successfully"
135                    );
136                    assert_eq!(u8::from(code), byte, "round-trip failed for 0x{byte:02X}");
137                }
138                Err(_) => {
139                    assert!(
140                        byte >= 0x5f,
141                        "0x{byte:02X} should be valid but failed to decode"
142                    );
143                }
144            }
145        }
146    }
147
148    // Named variants
149    #[test]
150    fn named_variants_decode_correctly() {
151        let cases = [
152            (0x00, ReturnCode::Ok),
153            (0x01, ReturnCode::NotOk),
154            (0x02, ReturnCode::UnknownService),
155            (0x03, ReturnCode::UnknownMethod),
156            (0x04, ReturnCode::NotReady),
157            (0x05, ReturnCode::NotReachable),
158            (0x06, ReturnCode::Timeout),
159            (0x07, ReturnCode::WrongProtocolVersion),
160            (0x08, ReturnCode::WrongInterfaceVersion),
161            (0x09, ReturnCode::MalformedMessage),
162            (0x0a, ReturnCode::WrongMessageType),
163            (0x0b, ReturnCode::E2ERepeated),
164            (0x0c, ReturnCode::E2EWrongSequence),
165            (0x0d, ReturnCode::E2E),
166            (0x0e, ReturnCode::E2ENotAvailable),
167            (0x0f, ReturnCode::E2ENoNewData),
168        ];
169        for (byte, expected) in cases {
170            assert_eq!(ReturnCode::try_from(byte).unwrap(), expected);
171        }
172    }
173
174    // GenericError range: 0x10..=0x1f
175    #[test]
176    fn generic_error_range_decodes_and_preserves_value() {
177        for byte in 0x10u8..=0x1f {
178            assert_eq!(
179                ReturnCode::try_from(byte).unwrap(),
180                ReturnCode::GenericError(byte)
181            );
182        }
183    }
184
185    // InterfaceError range: 0x20..=0x5e
186    #[test]
187    fn interface_error_range_decodes_and_preserves_value() {
188        for byte in 0x20u8..=0x5e {
189            assert_eq!(
190                ReturnCode::try_from(byte).unwrap(),
191                ReturnCode::InterfaceError(byte)
192            );
193        }
194    }
195
196    // Invalid values
197    #[test]
198    fn invalid_values_return_error() {
199        for byte in [0x5f, 0x60, 0xff] {
200            assert!(
201                ReturnCode::try_from(byte).is_err(),
202                "0x{byte:02X} should be invalid"
203            );
204        }
205    }
206
207    #[test]
208    fn generic_error_as_u8_preserves_value() {
209        for byte in 0x10u8..=0x1f {
210            assert_eq!(ReturnCode::GenericError(byte).as_u8(), byte);
211        }
212    }
213
214    #[test]
215    fn interface_error_as_u8_preserves_value() {
216        for byte in 0x20u8..=0x5e {
217            assert_eq!(ReturnCode::InterfaceError(byte).as_u8(), byte);
218        }
219    }
220
221    #[test]
222    fn from_u8_for_generic_and_interface_errors() {
223        assert_eq!(u8::from(ReturnCode::GenericError(0x15)), 0x15);
224        assert_eq!(u8::from(ReturnCode::InterfaceError(0x30)), 0x30);
225    }
226
227    #[test]
228    fn as_u8_all_named_variants() {
229        assert_eq!(ReturnCode::Ok.as_u8(), 0x00);
230        assert_eq!(ReturnCode::NotOk.as_u8(), 0x01);
231        assert_eq!(ReturnCode::UnknownService.as_u8(), 0x02);
232        assert_eq!(ReturnCode::UnknownMethod.as_u8(), 0x03);
233        assert_eq!(ReturnCode::NotReady.as_u8(), 0x04);
234        assert_eq!(ReturnCode::NotReachable.as_u8(), 0x05);
235        assert_eq!(ReturnCode::Timeout.as_u8(), 0x06);
236        assert_eq!(ReturnCode::WrongProtocolVersion.as_u8(), 0x07);
237        assert_eq!(ReturnCode::WrongInterfaceVersion.as_u8(), 0x08);
238        assert_eq!(ReturnCode::MalformedMessage.as_u8(), 0x09);
239        assert_eq!(ReturnCode::WrongMessageType.as_u8(), 0x0a);
240        assert_eq!(ReturnCode::E2ERepeated.as_u8(), 0x0b);
241        assert_eq!(ReturnCode::E2EWrongSequence.as_u8(), 0x0c);
242        assert_eq!(ReturnCode::E2E.as_u8(), 0x0d);
243        assert_eq!(ReturnCode::E2ENotAvailable.as_u8(), 0x0e);
244        assert_eq!(ReturnCode::E2ENoNewData.as_u8(), 0x0f);
245    }
246}