Skip to main content

simple_someip/protocol/
message_type.rs

1use super::Error;
2
3/// Bit flag in `message_type` field indicating that the message is a SOME/IP TP message.
4pub const MESSAGE_TYPE_TP_FLAG: u8 = 0x20;
5
6///Message types of a SOME/IP message.
7#[derive(Clone, Copy, Debug, Eq, PartialEq)]
8pub enum MessageType {
9    Request,
10    RequestNoReturn,
11    Notification,
12    Response,
13    Error,
14}
15
16impl MessageType {
17    const fn try_from(value: u8) -> Result<Self, Error> {
18        match value & !MESSAGE_TYPE_TP_FLAG {
19            0x00 => Ok(MessageType::Request),
20            0x01 => Ok(MessageType::RequestNoReturn),
21            0x02 => Ok(MessageType::Notification),
22            0x80 => Ok(MessageType::Response),
23            0x81 => Ok(MessageType::Error),
24            _ => Err(Error::InvalidMessageTypeField(value)),
25        }
26    }
27}
28
29impl TryFrom<u8> for MessageType {
30    type Error = Error;
31    fn try_from(value: u8) -> Result<Self, Error> {
32        MessageType::try_from(value)
33    }
34}
35
36/// Newtype for message type field
37/// The field encodes the message type and the TP flag.
38/// The TP flag indicates that the message is a SOME/IP TP message.
39#[derive(Clone, Copy, Debug, Eq, PartialEq)]
40pub struct MessageTypeField(u8);
41
42impl TryFrom<u8> for MessageTypeField {
43    type Error = Error;
44    fn try_from(value: u8) -> Result<Self, Self::Error> {
45        MessageType::try_from(value)?;
46        Ok(MessageTypeField(value))
47    }
48}
49
50impl From<MessageTypeField> for u8 {
51    fn from(message_type_field: MessageTypeField) -> u8 {
52        message_type_field.0
53    }
54}
55
56impl MessageTypeField {
57    #[must_use]
58    pub const fn new(msg_type: MessageType, tp: bool) -> Self {
59        let message_type_byte = if tp {
60            msg_type as u8 | MESSAGE_TYPE_TP_FLAG
61        } else {
62            msg_type as u8
63        };
64        MessageTypeField(message_type_byte)
65    }
66
67    #[must_use]
68    pub const fn new_sd() -> Self {
69        Self::new(MessageType::Notification, false)
70    }
71
72    /// Returns the message type of the message
73    #[must_use]
74    pub fn message_type(&self) -> MessageType {
75        // This unwrap is safe because the private message_type_byte is always a valid MessageType
76        MessageType::try_from(self.0).unwrap()
77    }
78
79    #[must_use]
80    pub const fn is_tp(&self) -> bool {
81        self.0 & MESSAGE_TYPE_TP_FLAG != 0
82    }
83}
84
85#[cfg(test)]
86mod tests {
87
88    use super::*;
89    /// Check that we properly decode and encode hex bytes
90    #[test]
91    fn test_all_u8_values() {
92        let valid_inputs: [u8; 10] = [0x00, 0x01, 0x02, 0x80, 0x81, 0x20, 0x21, 0x22, 0xA0, 0xA1];
93        for i in 0..=255 {
94            let msg_type = MessageTypeField::try_from(i);
95            if valid_inputs.contains(&i) {
96                assert!(msg_type.is_ok());
97                let msg_type = msg_type.unwrap();
98                match i {
99                    0x00 => {
100                        assert_eq!(msg_type.message_type(), MessageType::Request);
101                        assert!(!msg_type.is_tp());
102                    }
103                    0x01 => {
104                        assert_eq!(msg_type.message_type(), MessageType::RequestNoReturn);
105                        assert!(!msg_type.is_tp());
106                    }
107                    0x02 => {
108                        assert_eq!(msg_type.message_type(), MessageType::Notification);
109                        assert!(!msg_type.is_tp());
110                    }
111                    0x80 => {
112                        assert_eq!(msg_type.message_type(), MessageType::Response);
113                        assert!(!msg_type.is_tp());
114                    }
115                    0x81 => {
116                        assert_eq!(msg_type.message_type(), MessageType::Error);
117                        assert!(!msg_type.is_tp());
118                    }
119                    0x20 => {
120                        assert_eq!(msg_type.message_type(), MessageType::Request);
121                        assert!(msg_type.is_tp());
122                    }
123                    0x21 => {
124                        assert_eq!(msg_type.message_type(), MessageType::RequestNoReturn);
125                        assert!(msg_type.is_tp());
126                    }
127                    0x22 => {
128                        assert_eq!(msg_type.message_type(), MessageType::Notification);
129                        assert!(msg_type.is_tp());
130                    }
131                    0xA0 => {
132                        assert_eq!(msg_type.message_type(), MessageType::Response);
133                        assert!(msg_type.is_tp());
134                    }
135                    0xA1 => {
136                        assert_eq!(msg_type.message_type(), MessageType::Error);
137                        assert!(msg_type.is_tp());
138                    }
139
140                    _ => unreachable!("Only valid inputs should have made it to this point"),
141                }
142            } else {
143                assert!(msg_type.is_err());
144            }
145        }
146    }
147}