1use super::Error;
2
3#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
5pub enum ReturnCode {
6 Ok,
8 NotOk,
10 UnknownService,
12 UnknownMethod,
14 NotReady,
16 NotReachable,
18 Timeout,
20 WrongProtocolVersion,
22 WrongInterfaceVersion,
24 MalformedMessage,
26 WrongMessageType,
28 E2ERepeated,
30 E2EWrongSequence,
32 E2E,
34 E2ENotAvailable,
36 E2ENoNewData,
38 GenericError(u8),
40 InterfaceError(u8),
42}
43
44impl ReturnCode {
45 #[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 #[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 #[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 #[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 #[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 #[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}