simple_someip/protocol/
message.rs1use crate::{
2 protocol::{Error, Header, MessageType, ReturnCode, header::HeaderView, sd::SdHeaderView},
3 traits::{PayloadWireFormat, WireFormat},
4};
5
6#[derive(Clone, Debug, Eq, PartialEq)]
8pub struct Message<PayloadDefinition> {
9 header: Header,
10 payload: PayloadDefinition,
11}
12
13impl<PayloadDefinition: PayloadWireFormat> Message<PayloadDefinition> {
14 pub const fn new(header: Header, payload: PayloadDefinition) -> Self {
16 Self { header, payload }
17 }
18
19 #[must_use]
21 pub fn new_sd(
22 request_id: u32,
23 sd_header: &<PayloadDefinition as PayloadWireFormat>::SdHeader,
24 ) -> Self {
25 let sd_header_size = sd_header.required_size();
26 Self::new(
27 Header::new_sd(request_id, sd_header_size),
28 PayloadDefinition::new_sd_payload(sd_header),
29 )
30 }
31
32 pub const fn header(&self) -> &Header {
34 &self.header
35 }
36
37 pub const fn is_sd(&self) -> bool {
39 self.header.is_sd()
40 }
41
42 pub const fn set_request_id(&mut self, request_id: u32) {
44 self.header.set_request_id(request_id);
45 }
46
47 pub fn sd_header(&self) -> Option<&<PayloadDefinition as PayloadWireFormat>::SdHeader> {
49 if !self.header().message_id().is_sd() || self.header().message_type().is_tp() {
50 return None;
51 }
52 self.payload.as_sd_header()
53 }
54
55 pub const fn payload(&self) -> &PayloadDefinition {
57 &self.payload
58 }
59
60 pub const fn payload_mut(&mut self) -> &mut PayloadDefinition {
62 &mut self.payload
63 }
64}
65
66#[derive(Clone, Copy, Debug)]
68pub struct MessageView<'a> {
69 header: HeaderView<'a>,
70 payload: &'a [u8],
71}
72
73impl<'a> MessageView<'a> {
74 pub fn parse(buf: &'a [u8]) -> Result<Self, Error> {
84 let (header, remaining) = HeaderView::parse(buf)?;
85 let payload_size = header.payload_size();
86
87 if remaining.len() < payload_size {
88 return Err(Error::UnexpectedEof);
89 }
90
91 if header.is_sd() {
93 if payload_size < 12 {
94 return Err(
95 crate::protocol::sd::Error::InvalidMessage("SD message too short").into(),
96 );
97 }
98 if header.interface_version() != 0x01 {
99 return Err(crate::protocol::sd::Error::InvalidMessage(
100 "SD interface version mismatch",
101 )
102 .into());
103 }
104 if header.message_type().message_type() != MessageType::Notification {
105 return Err(
106 crate::protocol::sd::Error::InvalidMessage("SD message type mismatch").into(),
107 );
108 }
109 if header.return_code() != ReturnCode::Ok {
110 return Err(
111 crate::protocol::sd::Error::InvalidMessage("SD return code mismatch").into(),
112 );
113 }
114 }
115
116 let payload = &remaining[..payload_size];
117 Ok(Self { header, payload })
118 }
119
120 #[must_use]
122 pub fn header(&self) -> HeaderView<'a> {
123 self.header
124 }
125
126 #[must_use]
128 pub fn payload_bytes(&self) -> &'a [u8] {
129 self.payload
130 }
131
132 #[must_use]
134 pub fn is_sd(&self) -> bool {
135 self.header.is_sd()
136 }
137
138 pub fn sd_header(&self) -> Result<SdHeaderView<'a>, Error> {
147 if !self.is_sd() {
148 return Err(crate::protocol::sd::Error::InvalidMessage("Not an SD message").into());
149 }
150 SdHeaderView::parse(self.payload)
151 }
152}
153
154impl<PayloadDefinition: PayloadWireFormat> WireFormat for Message<PayloadDefinition> {
155 fn required_size(&self) -> usize {
156 self.header.required_size() + self.payload.required_size()
157 }
158
159 fn encode<W: embedded_io::Write>(&self, writer: &mut W) -> Result<usize, Error> {
160 Ok(self.header.encode(writer)? + self.payload.encode(writer)?)
161 }
162}
163
164#[cfg(test)]
165mod tests {
166 use super::*;
167 use crate::protocol::sd::test_support::{TestPayload, TestSdHeader, empty_sd_header};
168 use crate::protocol::{MessageId, sd};
169
170 type Msg = Message<TestPayload>;
171
172 fn minimal_sd_header() -> TestSdHeader {
173 empty_sd_header()
174 }
175
176 fn make_sd_message() -> Msg {
177 Msg::new_sd(0x0000_0001, &minimal_sd_header())
178 }
179
180 #[test]
183 fn new_stores_header_and_payload() {
184 let header = Header::new_sd(0x42, 12);
185 let payload = TestPayload::new_sd_payload(&minimal_sd_header());
186 let msg = Msg::new(header.clone(), payload.clone());
187 assert_eq!(*msg.header(), header);
188 assert_eq!(*msg.payload(), payload);
189 }
190
191 #[test]
194 fn new_sd_creates_valid_message() {
195 let msg = make_sd_message();
196 assert!(msg.is_sd());
197 assert_eq!(msg.header().message_id(), MessageId::SD);
198 }
199
200 #[test]
203 fn header_returns_reference() {
204 let msg = make_sd_message();
205 assert_eq!(msg.header().protocol_version(), 0x01);
206 }
207
208 #[test]
209 fn payload_returns_reference() {
210 let sd_hdr = minimal_sd_header();
211 let msg = make_sd_message();
212 assert_eq!(msg.payload().as_sd_header().unwrap(), &sd_hdr);
213 }
214
215 #[test]
216 fn payload_mut_allows_modification() {
217 let mut msg = make_sd_message();
218 let _p = msg.payload_mut();
219 }
221
222 #[test]
225 fn is_sd_true_for_sd_message() {
226 assert!(make_sd_message().is_sd());
227 }
228
229 #[test]
232 fn set_request_id_updates_header() {
233 let mut msg = make_sd_message();
234 msg.set_request_id(0xDEAD_BEEF);
235 assert_eq!(msg.header().request_id(), 0xDEAD_BEEF);
236 }
237
238 #[test]
241 fn get_sd_header_returns_some_for_sd() {
242 let sd_hdr = minimal_sd_header();
243 let msg = make_sd_message();
244 assert_eq!(msg.sd_header().unwrap(), &sd_hdr);
245 }
246
247 #[test]
250 fn required_size_is_header_plus_payload() {
251 let msg = make_sd_message();
252 let expected = msg.header().required_size() + msg.payload().required_size();
253 assert_eq!(msg.required_size(), expected);
254 }
255
256 #[test]
259 fn encode_parse_round_trip() {
260 let msg = make_sd_message();
261 let mut buf = [0u8; 64];
262 let n = msg.encode(&mut buf.as_mut_slice()).unwrap();
263 assert_eq!(n, msg.required_size());
264 let view = MessageView::parse(&buf[..n]).unwrap();
265 assert!(view.is_sd());
266 assert_eq!(view.header().to_owned(), *msg.header());
267 }
268
269 #[test]
270 fn encode_parse_with_entries() {
271 let mut entries = heapless::Vec::<sd::Entry, 4>::new();
272 entries
273 .push(sd::Entry::FindService(sd::ServiceEntry::find(0xABCD)))
274 .unwrap();
275 let sd_hdr = TestSdHeader {
276 flags: sd::Flags::new_sd(true),
277 entries,
278 options: heapless::Vec::new(),
279 };
280 let msg = Msg::new_sd(0x42, &sd_hdr);
281 let mut buf = [0u8; 64];
282 let n = msg.encode(&mut buf.as_mut_slice()).unwrap();
283 let view = MessageView::parse(&buf[..n]).unwrap();
284 let sd_view = view.sd_header().unwrap();
285 assert_eq!(sd_view.entry_count(), 1);
286 let entry = sd_view.entries().next().unwrap();
287 assert_eq!(entry.service_id(), 0xABCD);
288 }
289
290 #[test]
293 fn parse_exact_size_slice_succeeds() {
294 let msg = make_sd_message();
295 let mut buf = [0u8; 64];
296 let n = msg.encode(&mut buf.as_mut_slice()).unwrap();
297 let view = MessageView::parse(&buf[..n]).unwrap();
299 assert!(view.is_sd());
300 assert_eq!(view.header().to_owned(), *msg.header());
301 }
302
303 #[test]
306 fn parse_truncated_returns_eof() {
307 let buf: [u8; 4] = [0; 4];
308 assert!(matches!(
309 MessageView::parse(&buf[..]),
310 Err(Error::UnexpectedEof)
311 ));
312 }
313
314 #[test]
317 fn parse_sd_payload_too_short_returns_error() {
318 let msg = make_sd_message();
319 let mut buf = [0u8; 64];
320 msg.encode(&mut buf.as_mut_slice()).unwrap();
321 let bad_len: u32 = 19;
324 buf[4..8].copy_from_slice(&bad_len.to_be_bytes());
325 assert!(matches!(
326 MessageView::parse(&buf[..]),
327 Err(Error::Sd(crate::protocol::sd::Error::InvalidMessage(
328 "SD message too short"
329 )))
330 ));
331 }
332
333 #[test]
334 fn parse_sd_wrong_interface_version_returns_error() {
335 let msg = make_sd_message();
336 let mut buf = [0u8; 64];
337 let n = msg.encode(&mut buf.as_mut_slice()).unwrap();
338 buf[13] = 0x02; assert!(matches!(
340 MessageView::parse(&buf[..n]),
341 Err(Error::Sd(crate::protocol::sd::Error::InvalidMessage(
342 "SD interface version mismatch"
343 )))
344 ));
345 }
346
347 #[test]
348 fn parse_sd_wrong_message_type_returns_error() {
349 let msg = make_sd_message();
350 let mut buf = [0u8; 64];
351 let n = msg.encode(&mut buf.as_mut_slice()).unwrap();
352 buf[14] = 0x00; assert!(matches!(
354 MessageView::parse(&buf[..n]),
355 Err(Error::Sd(crate::protocol::sd::Error::InvalidMessage(
356 "SD message type mismatch"
357 )))
358 ));
359 }
360
361 #[test]
362 fn parse_sd_wrong_return_code_returns_error() {
363 let msg = make_sd_message();
364 let mut buf = [0u8; 64];
365 let n = msg.encode(&mut buf.as_mut_slice()).unwrap();
366 buf[15] = 0x01; assert!(matches!(
368 MessageView::parse(&buf[..n]),
369 Err(Error::Sd(crate::protocol::sd::Error::InvalidMessage(
370 "SD return code mismatch"
371 )))
372 ));
373 }
374
375 #[test]
378 fn message_view_payload_bytes() {
379 let msg = make_sd_message();
380 let mut buf = [0u8; 64];
381 let n = msg.encode(&mut buf.as_mut_slice()).unwrap();
382 let view = MessageView::parse(&buf[..n]).unwrap();
383 assert_eq!(view.payload_bytes().len(), msg.header().payload_size());
384 }
385
386 #[test]
387 fn message_view_sd_header_on_non_sd_returns_error() {
388 let header = Header::new(
390 MessageId::new_from_service_and_method(0x1234, 0x0001),
391 0x0001,
392 0x01,
393 0x01,
394 crate::protocol::MessageTypeField::try_from(0x00).unwrap(),
395 ReturnCode::Ok,
396 0,
397 );
398 let mut buf = [0u8; 16];
399 header.encode(&mut buf.as_mut_slice()).unwrap();
400 let view = MessageView::parse(&buf).unwrap();
401 assert!(matches!(
402 view.sd_header(),
403 Err(Error::Sd(crate::protocol::sd::Error::InvalidMessage(
404 "Not an SD message"
405 )))
406 ));
407 }
408}