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 message_type_byte = if tp {
66 msg_type as u8 | MESSAGE_TYPE_TP_FLAG
67 } else {
68 msg_type as u8
69 };
70 MessageTypeField(message_type_byte)
71 }
72
73 #[must_use]
75 pub const fn new_sd() -> Self {
76 Self::new(MessageType::Notification, false)
77 }
78
79 #[must_use]
85 pub const fn message_type(&self) -> MessageType {
86 match self.0 & !MESSAGE_TYPE_TP_FLAG {
88 0x00 => MessageType::Request,
89 0x01 => MessageType::RequestNoReturn,
90 0x02 => MessageType::Notification,
91 0x80 => MessageType::Response,
92 0x81 => MessageType::Error,
93 _ => unreachable!(),
94 }
95 }
96
97 #[must_use]
99 pub const fn as_u8(self) -> u8 {
100 self.0
101 }
102
103 #[must_use]
105 pub const fn is_tp(&self) -> bool {
106 self.0 & MESSAGE_TYPE_TP_FLAG != 0
107 }
108}
109
110#[cfg(test)]
111mod tests {
112
113 use super::*;
114
115 #[test]
118 fn message_type_trait_try_from() {
119 let mt: Result<MessageType, _> = 0x00u8.try_into();
121 assert_eq!(mt.unwrap(), MessageType::Request);
122 }
123
124 #[test]
127 fn new_with_tp_true() {
128 let field = MessageTypeField::new(MessageType::Request, true);
129 assert_eq!(field.message_type(), MessageType::Request);
130 assert!(field.is_tp());
131 assert_eq!(u8::from(field), 0x20);
132 }
133
134 #[test]
135 fn new_with_tp_false() {
136 let field = MessageTypeField::new(MessageType::Request, false);
137 assert_eq!(field.message_type(), MessageType::Request);
138 assert!(!field.is_tp());
139 assert_eq!(u8::from(field), 0x00);
140 }
141
142 #[test]
145 fn new_sd_is_notification_no_tp() {
146 let field = MessageTypeField::new_sd();
147 assert_eq!(field.message_type(), MessageType::Notification);
148 assert!(!field.is_tp());
149 }
150
151 #[test]
155 fn test_all_u8_values() {
156 let valid_inputs: [u8; 10] = [0x00, 0x01, 0x02, 0x80, 0x81, 0x20, 0x21, 0x22, 0xA0, 0xA1];
157 for i in 0..=255 {
158 let msg_type = MessageTypeField::try_from(i);
159 if valid_inputs.contains(&i) {
160 assert!(msg_type.is_ok());
161 let msg_type = msg_type.unwrap();
162 match i {
163 0x00 => {
164 assert_eq!(msg_type.message_type(), MessageType::Request);
165 assert!(!msg_type.is_tp());
166 }
167 0x01 => {
168 assert_eq!(msg_type.message_type(), MessageType::RequestNoReturn);
169 assert!(!msg_type.is_tp());
170 }
171 0x02 => {
172 assert_eq!(msg_type.message_type(), MessageType::Notification);
173 assert!(!msg_type.is_tp());
174 }
175 0x80 => {
176 assert_eq!(msg_type.message_type(), MessageType::Response);
177 assert!(!msg_type.is_tp());
178 }
179 0x81 => {
180 assert_eq!(msg_type.message_type(), MessageType::Error);
181 assert!(!msg_type.is_tp());
182 }
183 0x20 => {
184 assert_eq!(msg_type.message_type(), MessageType::Request);
185 assert!(msg_type.is_tp());
186 }
187 0x21 => {
188 assert_eq!(msg_type.message_type(), MessageType::RequestNoReturn);
189 assert!(msg_type.is_tp());
190 }
191 0x22 => {
192 assert_eq!(msg_type.message_type(), MessageType::Notification);
193 assert!(msg_type.is_tp());
194 }
195 0xA0 => {
196 assert_eq!(msg_type.message_type(), MessageType::Response);
197 assert!(msg_type.is_tp());
198 }
199 0xA1 => {
200 assert_eq!(msg_type.message_type(), MessageType::Error);
201 assert!(msg_type.is_tp());
202 }
203
204 _ => unreachable!("Only valid inputs should have made it to this point"),
205 }
206 } else {
207 assert!(msg_type.is_err());
208 }
209 }
210 }
211}