1use crate::protocol::{Error, MessageId, MessageTypeField, ReturnCode, byte_order::WriteBytesExt};
2use automotive_wire_codec::Decode;
3
4#[derive(Clone, Debug, Eq, PartialEq)]
6pub struct Header {
7 message_id: MessageId,
9 length: u32,
12 request_id: u32,
14 protocol_version: u8,
15 interface_version: u8,
16 message_type: MessageTypeField,
17 return_code: ReturnCode,
18}
19
20impl Header {
21 #[must_use]
23 pub const fn message_id(&self) -> MessageId {
24 self.message_id
25 }
26
27 #[must_use]
29 pub const fn length(&self) -> u32 {
30 self.length
31 }
32
33 #[must_use]
35 pub const fn request_id(&self) -> u32 {
36 self.request_id
37 }
38
39 #[must_use]
41 pub const fn protocol_version(&self) -> u8 {
42 self.protocol_version
43 }
44
45 #[must_use]
47 pub const fn interface_version(&self) -> u8 {
48 self.interface_version
49 }
50
51 #[must_use]
53 pub const fn message_type(&self) -> MessageTypeField {
54 self.message_type
55 }
56
57 #[must_use]
59 pub const fn return_code(&self) -> ReturnCode {
60 self.return_code
61 }
62
63 #[must_use]
71 pub const fn upper_header_bytes(&self) -> [u8; 8] {
72 let rid = self.request_id.to_be_bytes();
73 [
74 rid[0],
75 rid[1],
76 rid[2],
77 rid[3],
78 self.protocol_version,
79 self.interface_version,
80 self.message_type.as_u8(),
81 self.return_code.as_u8(),
82 ]
83 }
84
85 #[must_use]
92 pub const fn from_fields(
93 message_id: MessageId,
94 length: u32,
95 request_id: u32,
96 protocol_version: u8,
97 interface_version: u8,
98 message_type: MessageTypeField,
99 return_code: ReturnCode,
100 ) -> Self {
101 Self {
102 message_id,
103 length,
104 request_id,
105 protocol_version,
106 interface_version,
107 message_type,
108 return_code,
109 }
110 }
111
112 #[must_use]
118 #[allow(clippy::cast_possible_truncation)]
119 pub const fn new(
120 message_id: MessageId,
121 request_id: u32,
122 protocol_version: u8,
123 interface_version: u8,
124 message_type: MessageTypeField,
125 return_code: ReturnCode,
126 payload_len: usize,
127 ) -> Self {
128 assert!(payload_len <= u32::MAX as usize - 8);
129 Self {
130 message_id,
131 length: 8 + payload_len as u32,
132 request_id,
133 protocol_version,
134 interface_version,
135 message_type,
136 return_code,
137 }
138 }
139
140 #[must_use]
146 #[allow(clippy::cast_possible_truncation)]
147 pub const fn new_sd(request_id: u32, sd_header_size: usize) -> Self {
148 assert!(sd_header_size <= u32::MAX as usize - 8);
149 Self {
150 message_id: MessageId::SD,
151 length: 8 + sd_header_size as u32,
152 request_id,
153 protocol_version: 0x01,
154 interface_version: 0x01,
155 message_type: MessageTypeField::new_sd(),
156 return_code: ReturnCode::Ok,
157 }
158 }
159
160 #[must_use]
166 #[allow(clippy::cast_possible_truncation)]
167 pub const fn new_event(
168 service_id: u16,
169 event_id: u16,
170 request_id: u32,
171 protocol_version: u8,
172 interface_version: u8,
173 payload_len: usize,
174 ) -> Self {
175 assert!(payload_len <= u32::MAX as usize - 8);
176 Self {
177 message_id: MessageId::new_from_service_and_method(service_id, event_id),
178 length: 8 + payload_len as u32,
179 request_id,
180 protocol_version,
181 interface_version,
182 message_type: MessageTypeField::new(crate::protocol::MessageType::Notification, false),
183 return_code: ReturnCode::Ok,
184 }
185 }
186
187 #[must_use]
189 pub const fn is_sd(&self) -> bool {
190 self.message_id.is_sd()
191 }
192
193 #[must_use]
195 pub const fn payload_size(&self) -> usize {
196 (self.length as usize).saturating_sub(8)
197 }
198
199 pub const fn set_request_id(&mut self, request_id: u32) {
201 self.request_id = request_id;
202 }
203}
204
205#[derive(Clone, Copy, Debug)]
207pub struct HeaderView<'a>(&'a [u8; 16]);
208
209impl<'a> HeaderView<'a> {
210 pub fn parse(buf: &'a [u8]) -> Result<(Self, &'a [u8]), Error> {
225 Self::decode(buf)
226 }
227
228 #[must_use]
230 pub fn message_id(&self) -> MessageId {
231 MessageId::from(u32::from_be_bytes([
232 self.0[0], self.0[1], self.0[2], self.0[3],
233 ]))
234 }
235
236 #[must_use]
238 pub fn length(&self) -> u32 {
239 u32::from_be_bytes([self.0[4], self.0[5], self.0[6], self.0[7]])
240 }
241
242 #[must_use]
244 pub fn request_id(&self) -> u32 {
245 u32::from_be_bytes([self.0[8], self.0[9], self.0[10], self.0[11]])
246 }
247
248 #[must_use]
250 pub fn payload_size(&self) -> usize {
251 (self.length() as usize).saturating_sub(8)
252 }
253
254 #[must_use]
258 pub const fn upper_header_bytes(&self) -> [u8; 8] {
259 [
260 self.0[8], self.0[9], self.0[10], self.0[11], self.0[12], self.0[13], self.0[14],
261 self.0[15],
262 ]
263 }
264
265 #[must_use]
267 pub fn protocol_version(&self) -> u8 {
268 self.0[12]
269 }
270
271 #[must_use]
273 pub fn interface_version(&self) -> u8 {
274 self.0[13]
275 }
276
277 #[must_use]
283 pub fn message_type(&self) -> MessageTypeField {
284 MessageTypeField::try_from(self.0[14]).expect("validated in parse")
286 }
287
288 #[must_use]
294 pub fn return_code(&self) -> ReturnCode {
295 ReturnCode::try_from(self.0[15]).expect("validated in parse")
297 }
298
299 #[must_use]
301 pub fn is_sd(&self) -> bool {
302 self.message_id().is_sd()
303 }
304
305 #[must_use]
307 pub fn to_owned(&self) -> Header {
308 Header {
309 message_id: self.message_id(),
310 length: self.length(),
311 request_id: self.request_id(),
312 protocol_version: self.protocol_version(),
313 interface_version: self.interface_version(),
314 message_type: self.message_type(),
315 return_code: self.return_code(),
316 }
317 }
318}
319
320impl<'a> Decode<'a> for HeaderView<'a> {
321 type Error = Error;
322
323 fn decode(buf: &'a [u8]) -> Result<(Self, &'a [u8]), Error> {
336 if buf.len() < 16 {
337 return Err(automotive_wire_codec::Incomplete {
338 needed: 16,
339 available: buf.len(),
340 }
341 .into());
342 }
343 let header_bytes: &[u8; 16] = buf[..16].try_into().expect("length checked above");
344 let view = Self(header_bytes);
345
346 let pv = view.protocol_version();
348 if pv != 0x01 {
349 return Err(Error::InvalidProtocolVersion(pv));
350 }
351 MessageTypeField::try_from(header_bytes[14])?;
353 ReturnCode::try_from(header_bytes[15])?;
355
356 Ok((view, &buf[16..]))
357 }
358}
359
360impl automotive_wire_codec::Encode for Header {
361 type Error = Error;
362
363 fn encoded_size(&self) -> Result<usize, Self::Error> {
364 Ok(16)
365 }
366
367 fn encode(&self, writer: &mut impl embedded_io::Write) -> Result<usize, Error> {
368 writer.write_u32_be(self.message_id.message_id())?;
369 writer.write_u32_be(self.length)?;
370 writer.write_u32_be(self.request_id)?;
371 writer.write_u8(self.protocol_version)?;
372 writer.write_u8(self.interface_version)?;
373 writer.write_u8(u8::from(self.message_type))?;
374 writer.write_u8(u8::from(self.return_code))?;
375 Ok(16)
376 }
377}
378
379#[cfg(test)]
380mod tests {
381 use super::*;
382 use crate::protocol::{Error, MessageId, MessageTypeField, ReturnCode};
383 use crate::traits::EncodeExt;
384 use automotive_wire_codec::Encode;
385
386 fn make_header() -> Header {
387 Header {
388 message_id: MessageId::new_from_service_and_method(0x1234, 0x0001),
389 length: 16,
390 request_id: 0xABCD_0042,
391 protocol_version: 0x01,
392 interface_version: 0x03,
393 message_type: MessageTypeField::try_from(0x00).unwrap(), return_code: ReturnCode::Ok,
395 }
396 }
397
398 fn encode_header(h: &Header) -> [u8; 16] {
399 let mut buf = [0u8; 16];
400 h.encode(&mut buf.as_mut_slice()).unwrap();
401 buf
402 }
403
404 #[test]
407 fn upper_header_bytes_layout() {
408 let h = make_header();
409 let ub = h.upper_header_bytes();
410 let rid = h.request_id().to_be_bytes();
411 assert_eq!(ub[0..4], rid);
412 assert_eq!(ub[4], h.protocol_version());
413 assert_eq!(ub[5], h.interface_version());
414 assert_eq!(ub[6], u8::from(h.message_type()));
415 assert_eq!(ub[7], u8::from(h.return_code()));
416 }
417
418 #[test]
421 fn new_sd_fields() {
422 let h = Header::new_sd(0x0000_0001, 28);
423 assert_eq!(h.message_id(), MessageId::SD);
424 assert_eq!(h.length(), 8 + 28);
425 assert_eq!(h.request_id(), 0x0000_0001);
426 assert_eq!(h.protocol_version(), 0x01);
427 assert_eq!(h.interface_version(), 0x01);
428 assert_eq!(h.return_code(), ReturnCode::Ok);
429 }
430
431 #[test]
434 fn is_sd_true_for_sd_header() {
435 let h = Header::new_sd(0, 12);
436 assert!(h.is_sd());
437 }
438
439 #[test]
440 fn is_sd_false_for_non_sd_header() {
441 let h = make_header();
442 assert!(!h.is_sd());
443 }
444
445 #[test]
448 fn payload_size_returns_length_minus_8() {
449 let h = Header {
450 length: 24,
451 ..make_header()
452 };
453 assert_eq!(h.payload_size(), 16);
454 }
455
456 #[test]
459 fn set_request_id_updates_value() {
460 let mut h = make_header();
461 h.set_request_id(0xDEAD_BEEF);
462 assert_eq!(h.request_id(), 0xDEAD_BEEF);
463 }
464
465 #[test]
468 fn required_size_is_16() {
469 assert_eq!(make_header().encoded_size().unwrap(), 16);
470 }
471
472 #[test]
475 fn encode_parse_round_trip() {
476 let h = make_header();
477 let buf = encode_header(&h);
478 let (view, remaining) = HeaderView::parse(&buf[..]).unwrap();
479 assert_eq!(view.to_owned(), h);
480 assert!(remaining.is_empty());
481 }
482
483 #[test]
484 fn encode_returns_16() {
485 let h = make_header();
486 let mut buf = [0u8; 16];
487 let n = h.encode(&mut buf.as_mut_slice()).unwrap();
488 assert_eq!(n, 16);
489 }
490
491 #[test]
492 fn sd_header_round_trips() {
493 let h = Header::new_sd(0x0000_0042, 28);
494 let buf = encode_header(&h);
495 let (view, _) = HeaderView::parse(&buf[..]).unwrap();
496 assert_eq!(view.to_owned(), h);
497 }
498
499 #[test]
502 fn parse_exact_size_slice_returns_empty_remainder() {
503 let h = make_header();
504 let buf = encode_header(&h);
505 let (view, remaining) = HeaderView::parse(&buf).unwrap();
507 assert_eq!(view.to_owned(), h);
508 assert!(remaining.is_empty());
509 }
510
511 #[test]
514 fn parse_invalid_protocol_version_returns_error() {
515 let mut h = make_header();
516 h.protocol_version = 0x02;
517 let mid = h.message_id.message_id().to_be_bytes();
519 let len = h.length.to_be_bytes();
520 let rid = h.request_id.to_be_bytes();
521 let buf: [u8; 16] = [
522 mid[0], mid[1], mid[2], mid[3], len[0], len[1], len[2], len[3], rid[0], rid[1], rid[2],
523 rid[3], 0x02, 0x03, 0x00, 0x00,
525 ];
526 assert!(matches!(
527 HeaderView::parse(&buf[..]),
528 Err(Error::InvalidProtocolVersion(0x02))
529 ));
530 }
531
532 #[test]
533 fn parse_invalid_message_type_returns_error() {
534 let h = make_header();
535 let mut buf = encode_header(&h);
536 buf[14] = 0xFF; assert!(matches!(
538 HeaderView::parse(&buf[..]),
539 Err(Error::InvalidMessageTypeField(0xFF))
540 ));
541 }
542
543 #[test]
544 fn parse_invalid_return_code_returns_error() {
545 let h = make_header();
546 let mut buf = encode_header(&h);
547 buf[15] = 0x5F; assert!(matches!(
549 HeaderView::parse(&buf[..]),
550 Err(Error::InvalidReturnCode(0x5F))
551 ));
552 }
553
554 #[test]
555 fn parse_truncated_input_returns_eof() {
556 let buf: [u8; 4] = [0x00, 0x00, 0x00, 0x00];
557 assert!(matches!(
558 HeaderView::parse(&buf[..]),
559 Err(Error::Incomplete(automotive_wire_codec::Incomplete {
560 needed: 16,
561 available: 4,
562 }))
563 ));
564 }
565
566 #[test]
569 fn decode_returns_header_and_remainder() {
570 use automotive_wire_codec::Decode;
571 let h = make_header();
572 let mut buf = [0u8; 20];
573 buf[..16].copy_from_slice(&encode_header(&h));
574 buf[16..].copy_from_slice(&[0xAA, 0xBB, 0xCC, 0xDD]);
575 let (view, rest) = HeaderView::decode(&buf).unwrap();
576 assert_eq!(view.to_owned(), h);
577 assert_eq!(rest, &[0xAA, 0xBB, 0xCC, 0xDD]);
578 }
579
580 #[test]
581 fn decode_exact_rejects_trailing() {
582 use automotive_wire_codec::Decode;
583 let h = make_header();
584 let mut buf = [0u8; 17];
585 buf[..16].copy_from_slice(&encode_header(&h));
586 assert!(matches!(
587 HeaderView::decode_exact(&buf),
588 Err(Error::Trailing(_))
589 ));
590 assert!(HeaderView::decode_exact(&buf[..16]).is_ok());
591 }
592
593 #[test]
596 fn from_fields_round_trip() {
597 let h = make_header();
598 let h2 = Header::from_fields(
599 h.message_id(),
600 h.length(),
601 h.request_id(),
602 h.protocol_version(),
603 h.interface_version(),
604 h.message_type(),
605 h.return_code(),
606 );
607 assert_eq!(h, h2);
608 }
609
610 #[test]
613 fn new_event_fields() {
614 let h = Header::new_event(0x5B, 0x8001, 0x0001, 0x01, 0x03, 10);
615 assert_eq!(h.message_id().service_id(), 0x5B);
616 assert_eq!(h.message_id().method_id(), 0x8001);
617 assert_eq!(h.request_id(), 0x0001);
618 assert_eq!(h.protocol_version(), 0x01);
619 assert_eq!(h.interface_version(), 0x03);
620 assert_eq!(h.length(), 18); assert_eq!(h.return_code(), ReturnCode::Ok);
622 }
623
624 #[test]
627 fn new_constructor_sets_length() {
628 let h = Header::new(
629 MessageId::new_from_service_and_method(0x1234, 0x0001),
630 0x0001,
631 0x01,
632 0x01,
633 MessageTypeField::try_from(0x00).unwrap(),
634 ReturnCode::Ok,
635 100,
636 );
637 assert_eq!(h.length(), 108); assert_eq!(h.payload_size(), 100);
639 }
640
641 #[test]
644 fn header_view_accessors() {
645 let h = make_header();
646 let buf = encode_header(&h);
647 let (view, _) = HeaderView::parse(&buf[..]).unwrap();
648 assert_eq!(view.message_id(), h.message_id());
649 assert_eq!(view.length(), h.length());
650 assert_eq!(view.request_id(), h.request_id());
651 assert_eq!(view.payload_size(), h.payload_size());
652 assert_eq!(view.protocol_version(), h.protocol_version());
653 assert_eq!(view.interface_version(), h.interface_version());
654 assert_eq!(view.message_type(), h.message_type());
655 assert_eq!(view.return_code(), h.return_code());
656 assert_eq!(view.is_sd(), h.is_sd());
657 }
658
659 #[test]
662 fn encode_to_slice_works() {
663 let h = make_header();
664 let mut buf = [0u8; 16];
665 let n = h.encode_to_slice(&mut buf).unwrap();
666 assert_eq!(n, 16);
667 let (view, _) = HeaderView::parse(&buf).unwrap();
668 assert_eq!(view.to_owned(), h);
669 }
670
671 #[cfg(feature = "std")]
672 #[test]
673 fn encode_to_vec_works() {
674 let h = make_header();
675 let buf = h.encode_to_vec().unwrap();
676 assert_eq!(buf.len(), 16);
677 let (view, _) = HeaderView::parse(&buf).unwrap();
678 assert_eq!(view.to_owned(), h);
679 }
680
681 #[test]
684 fn encoded_size_matches_bytes_written() {
685 use automotive_wire_codec::CountingSink;
686 let h = make_header();
687 let mut sink = CountingSink::new();
688 let written = h.encode(&mut sink).unwrap();
689 assert_eq!(written, h.encoded_size().unwrap());
690 assert_eq!(written, sink.count());
691 }
692
693 #[test]
694 fn encode_to_slice_too_small_yields_insufficient_buffer() {
695 use automotive_wire_codec::{EncodeToSliceError, InsufficientBuffer};
696 let h = make_header();
697 let mut buf = [0u8; 4];
698 let err = h.encode_to_slice(&mut buf).unwrap_err();
699 assert!(matches!(
700 err,
701 EncodeToSliceError::InsufficientBuffer(InsufficientBuffer {
702 needed: 16,
703 available: 4,
704 })
705 ));
706 }
707}