1use crate::{
2 protocol::{Error, Header, MessageType, ReturnCode, header::HeaderView, sd::SdHeaderView},
3 traits::PayloadWireFormat,
4};
5use automotive_wire_codec::{Decode, Encode};
6
7#[derive(Clone, Debug, Eq, PartialEq)]
9pub struct Message<PayloadDefinition> {
10 header: Header,
11 payload: PayloadDefinition,
12}
13
14impl<PayloadDefinition: PayloadWireFormat> Message<PayloadDefinition> {
15 pub const fn new(header: Header, payload: PayloadDefinition) -> Self {
17 Self { header, payload }
18 }
19
20 pub fn new_sd(
29 request_id: u32,
30 sd_header: &<PayloadDefinition as PayloadWireFormat>::SdHeader,
31 ) -> Result<Self, Error> {
32 let sd_header_size = sd_header.encoded_size()?;
38 Ok(Self::new(
39 Header::new_sd(request_id, sd_header_size),
40 PayloadDefinition::new_sd_payload(sd_header),
41 ))
42 }
43
44 pub const fn header(&self) -> &Header {
46 &self.header
47 }
48
49 pub const fn is_sd(&self) -> bool {
51 self.header.is_sd()
52 }
53
54 pub const fn set_request_id(&mut self, request_id: u32) {
56 self.header.set_request_id(request_id);
57 }
58
59 pub fn sd_header(&self) -> Option<&<PayloadDefinition as PayloadWireFormat>::SdHeader> {
61 if !self.header().message_id().is_sd() || self.header().message_type().is_tp() {
62 return None;
63 }
64 self.payload.as_sd_header()
65 }
66
67 pub const fn payload(&self) -> &PayloadDefinition {
69 &self.payload
70 }
71
72 pub const fn payload_mut(&mut self) -> &mut PayloadDefinition {
74 &mut self.payload
75 }
76}
77
78#[derive(Clone, Copy, Debug)]
80pub struct MessageView<'a> {
81 header: HeaderView<'a>,
82 payload: &'a [u8],
83}
84
85impl<'a> MessageView<'a> {
86 pub fn parse(buf: &'a [u8]) -> Result<Self, Error> {
104 Ok(Self::decode(buf)?.0)
105 }
106
107 #[must_use]
109 pub fn header(&self) -> HeaderView<'a> {
110 self.header
111 }
112
113 #[must_use]
115 pub fn payload_bytes(&self) -> &'a [u8] {
116 self.payload
117 }
118
119 #[must_use]
121 pub fn is_sd(&self) -> bool {
122 self.header.is_sd()
123 }
124
125 pub fn sd_header(&self) -> Result<SdHeaderView<'a>, Error> {
134 if !self.is_sd() {
135 return Err(crate::protocol::sd::Error::InvalidMessage("Not an SD message").into());
136 }
137 SdHeaderView::parse(self.payload)
138 }
139}
140
141impl<'a> Decode<'a> for MessageView<'a> {
142 type Error = Error;
143
144 fn decode(buf: &'a [u8]) -> Result<(Self, &'a [u8]), Error> {
157 let (header, remaining) = HeaderView::decode(buf)?;
158 if header.length() < 8 {
159 return Err(Error::InvalidLength(header.length()));
160 }
161 let payload_size = header.payload_size();
162
163 if remaining.len() < payload_size {
164 return Err(automotive_wire_codec::Incomplete {
165 needed: payload_size,
166 available: remaining.len(),
167 }
168 .into());
169 }
170
171 if header.is_sd() {
173 if payload_size < 12 {
174 return Err(
175 crate::protocol::sd::Error::InvalidMessage("SD message too short").into(),
176 );
177 }
178 if header.interface_version() != 0x01 {
179 return Err(crate::protocol::sd::Error::InvalidMessage(
180 "SD interface version mismatch",
181 )
182 .into());
183 }
184 if header.message_type().message_type() != MessageType::Notification {
185 return Err(
186 crate::protocol::sd::Error::InvalidMessage("SD message type mismatch").into(),
187 );
188 }
189 if header.return_code() != ReturnCode::Ok {
190 return Err(
191 crate::protocol::sd::Error::InvalidMessage("SD return code mismatch").into(),
192 );
193 }
194 }
195
196 let payload = &remaining[..payload_size];
197 let rest = &remaining[payload_size..];
198 Ok((Self { header, payload }, rest))
199 }
200}
201
202impl<PayloadDefinition: PayloadWireFormat> Encode for Message<PayloadDefinition> {
203 type Error = Error;
204
205 fn encoded_size(&self) -> Result<usize, Self::Error> {
206 Ok(self.header.encoded_size()? + self.payload.encoded_size()?)
207 }
208
209 fn encode(&self, writer: &mut impl embedded_io::Write) -> Result<usize, Error> {
210 Ok(self.header.encode(writer)? + self.payload.encode(writer)?)
211 }
212}
213
214#[cfg(test)]
215mod tests {
216 use super::*;
217 use crate::protocol::sd::test_support::{TestPayload, TestSdHeader, empty_sd_header};
218 use crate::protocol::{MessageId, sd, sd::RebootFlag};
219
220 type Msg = Message<TestPayload>;
221
222 fn minimal_sd_header() -> TestSdHeader {
223 empty_sd_header()
224 }
225
226 fn make_sd_message() -> Msg {
227 Msg::new_sd(0x0000_0001, &minimal_sd_header()).expect("in-tree SdHeader cannot fail")
228 }
229
230 #[test]
238 fn new_sd_surfaces_a_failing_sd_header_size() {
239 use crate::protocol::sd::test_support::{FailingPayload, FailingSdHeader};
240
241 assert!(
242 FailingSdHeader.encoded_size().is_err(),
243 "fixture must actually fail, or this test proves nothing",
244 );
245 assert!(Message::<FailingPayload>::new_sd(0x1, &FailingSdHeader).is_err());
246 }
247
248 #[test]
251 fn new_stores_header_and_payload() {
252 let header = Header::new_sd(0x42, 12);
253 let payload = TestPayload::new_sd_payload(&minimal_sd_header());
254 let msg = Msg::new(header.clone(), payload.clone());
255 assert_eq!(*msg.header(), header);
256 assert_eq!(*msg.payload(), payload);
257 }
258
259 #[test]
262 fn new_sd_creates_valid_message() {
263 let msg = make_sd_message();
264 assert!(msg.is_sd());
265 assert_eq!(msg.header().message_id(), MessageId::SD);
266 }
267
268 #[test]
271 fn header_returns_reference() {
272 let msg = make_sd_message();
273 assert_eq!(msg.header().protocol_version(), 0x01);
274 }
275
276 #[test]
277 fn payload_returns_reference() {
278 let sd_hdr = minimal_sd_header();
279 let msg = make_sd_message();
280 assert_eq!(msg.payload().as_sd_header().unwrap(), &sd_hdr);
281 }
282
283 #[test]
284 fn payload_mut_allows_modification() {
285 let mut msg = make_sd_message();
286 let _p = msg.payload_mut();
287 }
289
290 #[test]
293 fn is_sd_true_for_sd_message() {
294 assert!(make_sd_message().is_sd());
295 }
296
297 #[test]
300 fn set_request_id_updates_header() {
301 let mut msg = make_sd_message();
302 msg.set_request_id(0xDEAD_BEEF);
303 assert_eq!(msg.header().request_id(), 0xDEAD_BEEF);
304 }
305
306 #[test]
309 fn get_sd_header_returns_some_for_sd() {
310 let sd_hdr = minimal_sd_header();
311 let msg = make_sd_message();
312 assert_eq!(msg.sd_header().unwrap(), &sd_hdr);
313 }
314
315 #[test]
318 fn required_size_is_header_plus_payload() {
319 let msg = make_sd_message();
320 let expected = msg.header().encoded_size().unwrap() + msg.payload().encoded_size().unwrap();
321 assert_eq!(msg.encoded_size().unwrap(), expected);
322 }
323
324 #[test]
327 fn encode_parse_round_trip() {
328 let msg = make_sd_message();
329 let mut buf = [0u8; 64];
330 let n = msg.encode(&mut buf.as_mut_slice()).unwrap();
331 assert_eq!(n, msg.encoded_size().unwrap());
332 let view = MessageView::parse(&buf[..n]).unwrap();
333 assert!(view.is_sd());
334 assert_eq!(view.header().to_owned(), *msg.header());
335 }
336
337 #[test]
338 fn encode_parse_with_entries() {
339 let mut entries = heapless::Vec::<sd::Entry, 4>::new();
340 entries
341 .push(sd::Entry::FindService(sd::ServiceEntry::find(0xABCD)))
342 .unwrap();
343 let sd_hdr = TestSdHeader {
344 flags: sd::Flags::new_sd(RebootFlag::RecentlyRebooted),
345 entries,
346 options: heapless::Vec::new(),
347 };
348 let msg = Msg::new_sd(0x42, &sd_hdr).expect("in-tree SdHeader cannot fail");
349 let mut buf = [0u8; 64];
350 let n = msg.encode(&mut buf.as_mut_slice()).unwrap();
351 let view = MessageView::parse(&buf[..n]).unwrap();
352 let sd_view = view.sd_header().unwrap();
353 assert_eq!(sd_view.entry_count(), 1);
354 let entry = sd_view.entries().next().unwrap();
355 assert_eq!(entry.service_id(), 0xABCD);
356 }
357
358 #[test]
361 fn decode_returns_trailing_bytes_as_remainder() {
362 let msg = make_sd_message();
363 let mut buf = [0u8; 128];
364 let n = msg.encode(&mut buf.as_mut_slice()).unwrap();
365 for (i, b) in [0xDE, 0xAD, 0xBE, 0xEF, 0x42].into_iter().enumerate() {
367 buf[n + i] = b;
368 }
369 let (view, rest) = MessageView::decode(&buf[..n + 5]).unwrap();
370 assert_eq!(view.header().to_owned(), *msg.header());
371 assert_eq!(rest, &[0xDE, 0xAD, 0xBE, 0xEF, 0x42]);
372 }
373
374 #[test]
375 fn parse_silently_discards_trailing_bytes() {
376 let msg = make_sd_message();
377 let mut buf = [0u8; 128];
378 let n = msg.encode(&mut buf.as_mut_slice()).unwrap();
379 buf[n] = 0xFF;
380 let view = MessageView::parse(&buf[..=n]).unwrap();
382 assert_eq!(view.header().to_owned(), *msg.header());
383 }
384
385 #[test]
386 fn decode_exact_rejects_trailing_bytes() {
387 let msg = make_sd_message();
388 let mut buf = [0u8; 128];
389 let n = msg.encode(&mut buf.as_mut_slice()).unwrap();
390 buf[n] = 0xFF;
391 assert!(matches!(
392 MessageView::decode_exact(&buf[..=n]),
393 Err(Error::Trailing(_))
394 ));
395 assert!(MessageView::decode_exact(&buf[..n]).is_ok());
397 }
398
399 #[test]
402 fn parse_exact_size_slice_succeeds() {
403 let msg = make_sd_message();
404 let mut buf = [0u8; 64];
405 let n = msg.encode(&mut buf.as_mut_slice()).unwrap();
406 let view = MessageView::parse(&buf[..n]).unwrap();
408 assert!(view.is_sd());
409 assert_eq!(view.header().to_owned(), *msg.header());
410 }
411
412 #[test]
415 fn parse_truncated_returns_eof() {
416 let buf: [u8; 4] = [0; 4];
417 assert!(matches!(
418 MessageView::parse(&buf[..]),
419 Err(Error::Incomplete(automotive_wire_codec::Incomplete {
420 needed: 16,
421 available: 4,
422 }))
423 ));
424 }
425
426 #[test]
427 fn parse_payload_truncated_reports_needed_and_available() {
428 let msg = make_sd_message();
429 let mut buf = [0u8; 64];
430 let n = msg.encode(&mut buf.as_mut_slice()).unwrap();
431 let payload_size = msg.header().payload_size();
432 let short = &buf[..n - 1];
434 assert!(matches!(
435 MessageView::parse(short),
436 Err(Error::Incomplete(automotive_wire_codec::Incomplete {
437 needed,
438 available,
439 })) if needed == payload_size && available == payload_size - 1
440 ));
441 }
442
443 #[test]
444 fn decode_rejects_length_below_8() {
445 let msg = make_sd_message();
446 let mut buf = [0u8; 64];
447 msg.encode(&mut buf.as_mut_slice()).unwrap();
448 let bad_len: u32 = 4;
451 buf[4..8].copy_from_slice(&bad_len.to_be_bytes());
452 assert!(matches!(
453 MessageView::decode(&buf[..]),
454 Err(Error::InvalidLength(4))
455 ));
456 assert!(matches!(
457 MessageView::decode_exact(&buf[..16]),
458 Err(Error::InvalidLength(4))
459 ));
460 }
461
462 #[test]
465 fn parse_sd_payload_too_short_returns_error() {
466 let msg = make_sd_message();
467 let mut buf = [0u8; 64];
468 msg.encode(&mut buf.as_mut_slice()).unwrap();
469 let bad_len: u32 = 19;
472 buf[4..8].copy_from_slice(&bad_len.to_be_bytes());
473 assert!(matches!(
474 MessageView::parse(&buf[..]),
475 Err(Error::Sd(crate::protocol::sd::Error::InvalidMessage(
476 "SD message too short"
477 )))
478 ));
479 }
480
481 #[test]
482 fn parse_sd_wrong_interface_version_returns_error() {
483 let msg = make_sd_message();
484 let mut buf = [0u8; 64];
485 let n = msg.encode(&mut buf.as_mut_slice()).unwrap();
486 buf[13] = 0x02; assert!(matches!(
488 MessageView::parse(&buf[..n]),
489 Err(Error::Sd(crate::protocol::sd::Error::InvalidMessage(
490 "SD interface version mismatch"
491 )))
492 ));
493 }
494
495 #[test]
496 fn parse_sd_wrong_message_type_returns_error() {
497 let msg = make_sd_message();
498 let mut buf = [0u8; 64];
499 let n = msg.encode(&mut buf.as_mut_slice()).unwrap();
500 buf[14] = 0x00; assert!(matches!(
502 MessageView::parse(&buf[..n]),
503 Err(Error::Sd(crate::protocol::sd::Error::InvalidMessage(
504 "SD message type mismatch"
505 )))
506 ));
507 }
508
509 #[test]
510 fn parse_sd_wrong_return_code_returns_error() {
511 let msg = make_sd_message();
512 let mut buf = [0u8; 64];
513 let n = msg.encode(&mut buf.as_mut_slice()).unwrap();
514 buf[15] = 0x01; assert!(matches!(
516 MessageView::parse(&buf[..n]),
517 Err(Error::Sd(crate::protocol::sd::Error::InvalidMessage(
518 "SD return code mismatch"
519 )))
520 ));
521 }
522
523 #[test]
526 fn message_view_payload_bytes() {
527 let msg = make_sd_message();
528 let mut buf = [0u8; 64];
529 let n = msg.encode(&mut buf.as_mut_slice()).unwrap();
530 let view = MessageView::parse(&buf[..n]).unwrap();
531 assert_eq!(view.payload_bytes().len(), msg.header().payload_size());
532 }
533
534 #[test]
535 fn message_view_sd_header_on_non_sd_returns_error() {
536 let header = Header::new(
538 MessageId::new_from_service_and_method(0x1234, 0x0001),
539 0x0001,
540 0x01,
541 0x01,
542 crate::protocol::MessageTypeField::try_from(0x00).unwrap(),
543 ReturnCode::Ok,
544 0,
545 );
546 let mut buf = [0u8; 16];
547 header.encode(&mut buf.as_mut_slice()).unwrap();
548 let view = MessageView::parse(&buf).unwrap();
549 assert!(matches!(
550 view.sd_header(),
551 Err(Error::Sd(crate::protocol::sd::Error::InvalidMessage(
552 "Not an SD message"
553 )))
554 ));
555 }
556}