simple_someip/protocol/
message_type.rs1use super::Error;
2
3pub const MESSAGE_TYPE_TP_FLAG: u8 = 0x20;
5
6#[derive(Clone, Copy, Debug, Eq, PartialEq)]
8pub enum MessageType {
9 Request,
11 RequestNoReturn,
13 Notification,
15 Response,
17 Error,
19}
20
21impl MessageType {
22 const fn try_from(value: u8) -> Result<Self, Error> {
23 match value & !MESSAGE_TYPE_TP_FLAG {
24 0x00 => Ok(MessageType::Request),
25 0x01 => Ok(MessageType::RequestNoReturn),
26 0x02 => Ok(MessageType::Notification),
27 0x80 => Ok(MessageType::Response),
28 0x81 => Ok(MessageType::Error),
29 _ => Err(Error::InvalidMessageTypeField(value)),
30 }
31 }
32}
33
34impl TryFrom<u8> for MessageType {
35 type Error = Error;
36 fn try_from(value: u8) -> Result<Self, Error> {
37 MessageType::try_from(value)
38 }
39}
40
41#[derive(Clone, Copy, Debug, Eq, PartialEq)]
45pub struct MessageTypeField(u8);
46
47impl TryFrom<u8> for MessageTypeField {
48 type Error = Error;
49 fn try_from(value: u8) -> Result<Self, Self::Error> {
50 MessageType::try_from(value)?;
51 Ok(MessageTypeField(value))
52 }
53}
54
55impl From<MessageTypeField> for u8 {
56 fn from(message_type_field: MessageTypeField) -> u8 {
57 message_type_field.0
58 }
59}
60
61impl MessageTypeField {
62 #[must_use]
64 pub const fn new(msg_type: MessageType, tp: bool) -> Self {
65 let base = match msg_type {
70 MessageType::Request => 0x00,
71 MessageType::RequestNoReturn => 0x01,
72 MessageType::Notification => 0x02,
73 MessageType::Response => 0x80,
74 MessageType::Error => 0x81,
75 };
76 let message_type_byte = if tp {
77 base | MESSAGE_TYPE_TP_FLAG
78 } else {
79 base
80 };
81 MessageTypeField(message_type_byte)
82 }
83
84 #[must_use]
86 pub const fn new_sd() -> Self {
87 Self::new(MessageType::Notification, false)
88 }
89
90 #[must_use]
96 pub const fn message_type(&self) -> MessageType {
97 match self.0 & !MESSAGE_TYPE_TP_FLAG {
99 0x00 => MessageType::Request,
100 0x01 => MessageType::RequestNoReturn,
101 0x02 => MessageType::Notification,
102 0x80 => MessageType::Response,
103 0x81 => MessageType::Error,
104 _ => unreachable!(),
105 }
106 }
107
108 #[must_use]
110 pub const fn as_u8(self) -> u8 {
111 self.0
112 }
113
114 #[must_use]
116 pub const fn is_tp(&self) -> bool {
117 self.0 & MESSAGE_TYPE_TP_FLAG != 0
118 }
119}
120
121#[cfg(test)]
122mod tests {
123
124 use super::*;
125
126 #[test]
129 fn message_type_trait_try_from() {
130 let mt: Result<MessageType, _> = 0x00u8.try_into();
132 assert_eq!(mt.unwrap(), MessageType::Request);
133 }
134
135 #[test]
138 fn new_with_tp_true() {
139 let field = MessageTypeField::new(MessageType::Request, true);
140 assert_eq!(field.message_type(), MessageType::Request);
141 assert!(field.is_tp());
142 assert_eq!(u8::from(field), 0x20);
143 }
144
145 #[test]
146 fn new_with_tp_false() {
147 let field = MessageTypeField::new(MessageType::Request, false);
148 assert_eq!(field.message_type(), MessageType::Request);
149 assert!(!field.is_tp());
150 assert_eq!(u8::from(field), 0x00);
151 }
152
153 #[test]
156 fn new_sd_is_notification_no_tp() {
157 let field = MessageTypeField::new_sd();
158 assert_eq!(field.message_type(), MessageType::Notification);
159 assert!(!field.is_tp());
160 }
161
162 #[test]
166 fn new_emits_wire_byte_for_all_variants() {
167 for (mt, wire) in [
168 (MessageType::Request, 0x00u8),
169 (MessageType::RequestNoReturn, 0x01),
170 (MessageType::Notification, 0x02),
171 (MessageType::Response, 0x80),
172 (MessageType::Error, 0x81),
173 ] {
174 let field = MessageTypeField::new(mt, false);
175 assert_eq!(u8::from(field), wire, "wire byte for {mt:?}");
176 assert_eq!(field.message_type(), mt, "round-trips back to {mt:?}");
177 let tp = MessageTypeField::new(mt, true);
178 assert_eq!(
179 u8::from(tp),
180 wire | MESSAGE_TYPE_TP_FLAG,
181 "wire byte for {mt:?} with TP flag"
182 );
183 assert_eq!(tp.message_type(), mt, "TP variant round-trips for {mt:?}");
184 }
185 }
186
187 #[test]
191 fn test_all_u8_values() {
192 let valid_inputs: [u8; 10] = [0x00, 0x01, 0x02, 0x80, 0x81, 0x20, 0x21, 0x22, 0xA0, 0xA1];
193 for i in 0..=255 {
194 let msg_type = MessageTypeField::try_from(i);
195 if valid_inputs.contains(&i) {
196 assert!(msg_type.is_ok());
197 let msg_type = msg_type.unwrap();
198 match i {
199 0x00 => {
200 assert_eq!(msg_type.message_type(), MessageType::Request);
201 assert!(!msg_type.is_tp());
202 }
203 0x01 => {
204 assert_eq!(msg_type.message_type(), MessageType::RequestNoReturn);
205 assert!(!msg_type.is_tp());
206 }
207 0x02 => {
208 assert_eq!(msg_type.message_type(), MessageType::Notification);
209 assert!(!msg_type.is_tp());
210 }
211 0x80 => {
212 assert_eq!(msg_type.message_type(), MessageType::Response);
213 assert!(!msg_type.is_tp());
214 }
215 0x81 => {
216 assert_eq!(msg_type.message_type(), MessageType::Error);
217 assert!(!msg_type.is_tp());
218 }
219 0x20 => {
220 assert_eq!(msg_type.message_type(), MessageType::Request);
221 assert!(msg_type.is_tp());
222 }
223 0x21 => {
224 assert_eq!(msg_type.message_type(), MessageType::RequestNoReturn);
225 assert!(msg_type.is_tp());
226 }
227 0x22 => {
228 assert_eq!(msg_type.message_type(), MessageType::Notification);
229 assert!(msg_type.is_tp());
230 }
231 0xA0 => {
232 assert_eq!(msg_type.message_type(), MessageType::Response);
233 assert!(msg_type.is_tp());
234 }
235 0xA1 => {
236 assert_eq!(msg_type.message_type(), MessageType::Error);
237 assert!(msg_type.is_tp());
238 }
239
240 _ => unreachable!("Only valid inputs should have made it to this point"),
241 }
242 } else {
243 assert!(msg_type.is_err());
244 }
245 }
246 }
247}