1use super::Error;
2use crate::protocol::byte_order::WriteBytesExt;
3use automotive_wire_codec::{Decode, DecodeIter, Encode, take};
4
5pub const ENTRY_SIZE: usize = 16;
6
7#[derive(Clone, Copy, Debug, Eq, PartialEq)]
9pub enum EntryType {
10 FindService,
12 OfferService,
14 StopOfferService,
16 Subscribe,
18 SubscribeAck,
20}
21
22impl TryFrom<u8> for EntryType {
23 type Error = Error;
24 fn try_from(value: u8) -> Result<Self, Error> {
25 match value {
26 0x00 => Ok(EntryType::FindService),
27 0x01 => Ok(EntryType::OfferService),
28 0x02 => Ok(EntryType::StopOfferService),
29 0x06 => Ok(EntryType::Subscribe),
30 0x07 => Ok(EntryType::SubscribeAck),
31 _ => Err(Error::InvalidEntryType(value)),
32 }
33 }
34}
35
36impl From<EntryType> for u8 {
37 fn from(service_entry_type: EntryType) -> u8 {
38 match service_entry_type {
39 EntryType::FindService => 0x00,
40 EntryType::OfferService => 0x01,
41 EntryType::StopOfferService => 0x02,
42 EntryType::Subscribe => 0x06,
43 EntryType::SubscribeAck => 0x07,
44 }
45 }
46}
47
48#[derive(Clone, Copy, Debug, Eq, PartialEq)]
50pub struct OptionsCount {
51 pub first_options_count: u8,
53 pub second_options_count: u8,
55}
56
57impl From<u8> for OptionsCount {
58 fn from(value: u8) -> Self {
59 let first_options_count = (value & 0xf0) >> 4;
60 let second_options_count = value & 0x0f;
61
62 Self {
63 first_options_count,
64 second_options_count,
65 }
66 }
67}
68
69impl From<OptionsCount> for u8 {
70 fn from(options_count: OptionsCount) -> u8 {
71 ((options_count.first_options_count << 4) & 0xf0)
72 | (options_count.second_options_count & 0x0f)
73 }
74}
75
76impl OptionsCount {
77 #[must_use]
80 pub const fn new(first_options_count: u8, second_options_count: u8) -> Self {
81 assert!(first_options_count < 16);
82 assert!(second_options_count < 16);
83 OptionsCount {
84 first_options_count,
85 second_options_count,
86 }
87 }
88}
89
90#[derive(Clone, Debug, Eq, PartialEq)]
92pub struct EventGroupEntry {
93 pub index_first_options_run: u8,
95 pub index_second_options_run: u8,
97 pub options_count: OptionsCount,
99 pub service_id: u16,
101 pub instance_id: u16,
103 pub major_version: u8,
105 pub ttl: u32,
107 pub counter: u16,
109 pub event_group_id: u16,
111}
112
113impl EventGroupEntry {
114 #[must_use]
116 pub const fn new(
117 service_id: u16,
118 instance_id: u16,
119 major_version: u8,
120 ttl: u32,
121 event_group_id: u16,
122 ) -> Self {
123 Self {
124 index_first_options_run: 0,
125 index_second_options_run: 0,
126 options_count: OptionsCount::new(1, 0),
127 service_id,
128 instance_id,
129 major_version,
130 ttl,
131 counter: 0,
132 event_group_id,
133 }
134 }
135}
136
137impl Encode for EventGroupEntry {
138 type Error = crate::protocol::Error;
139
140 fn encoded_size(&self) -> Result<usize, Self::Error> {
141 Ok(15)
142 }
143
144 fn encode(&self, writer: &mut impl embedded_io::Write) -> Result<usize, Self::Error> {
145 writer.write_u8(self.index_first_options_run)?;
146 writer.write_u8(self.index_second_options_run)?;
147 writer.write_u8(u8::from(self.options_count))?;
148 writer.write_u16_be(self.service_id)?;
149 writer.write_u16_be(self.instance_id)?;
150 writer.write_u8(self.major_version)?;
151 writer.write_u24_be(self.ttl)?;
152 writer.write_u16_be(self.counter)?;
153 writer.write_u16_be(self.event_group_id)?;
154 Ok(15)
155 }
156}
157
158#[derive(Clone, Debug, Eq, PartialEq)]
160pub struct ServiceEntry {
161 pub index_first_options_run: u8,
163 pub index_second_options_run: u8,
165 pub options_count: OptionsCount,
167 pub service_id: u16,
169 pub instance_id: u16,
171 pub major_version: u8,
173 pub ttl: u32,
175 pub minor_version: u32,
177}
178
179impl ServiceEntry {
180 #[must_use]
182 pub const fn find(service_id: u16) -> Self {
183 Self {
184 index_first_options_run: 0,
185 index_second_options_run: 0,
186 options_count: OptionsCount::new(1, 0),
187 service_id,
188 instance_id: 0xFFFF,
189 major_version: 0xFF,
190 ttl: 0x00FF_FFFF,
191 minor_version: 0xFFFF_FFFF,
192 }
193 }
194}
195
196impl Encode for ServiceEntry {
197 type Error = crate::protocol::Error;
198
199 fn encoded_size(&self) -> Result<usize, Self::Error> {
200 Ok(15)
201 }
202
203 fn encode(&self, writer: &mut impl embedded_io::Write) -> Result<usize, Self::Error> {
204 writer.write_u8(self.index_first_options_run)?;
205 writer.write_u8(self.index_second_options_run)?;
206 writer.write_u8(u8::from(self.options_count))?;
207 writer.write_u16_be(self.service_id)?;
208 writer.write_u16_be(self.instance_id)?;
209 writer.write_u8(self.major_version)?;
210 writer.write_u24_be(self.ttl)?;
211 writer.write_u32_be(self.minor_version)?;
212 Ok(15)
213 }
214}
215
216#[derive(Clone, Debug, Eq, PartialEq)]
218pub enum Entry {
219 FindService(ServiceEntry),
221 OfferService(ServiceEntry),
223 StopOfferService(ServiceEntry),
225 SubscribeEventGroup(EventGroupEntry),
227 SubscribeAckEventGroup(EventGroupEntry),
229}
230
231impl Entry {
232 #[must_use]
234 pub fn first_options_count(&self) -> u8 {
235 match self {
236 Entry::FindService(service_entry)
237 | Entry::OfferService(service_entry)
238 | Entry::StopOfferService(service_entry) => {
239 service_entry.options_count.first_options_count
240 }
241 Entry::SubscribeEventGroup(event_group_entry)
242 | Entry::SubscribeAckEventGroup(event_group_entry) => {
243 event_group_entry.options_count.first_options_count
244 }
245 }
246 }
247
248 #[must_use]
250 pub fn second_options_count(&self) -> u8 {
251 match self {
252 Entry::FindService(service_entry)
253 | Entry::OfferService(service_entry)
254 | Entry::StopOfferService(service_entry) => {
255 service_entry.options_count.second_options_count
256 }
257 Entry::SubscribeEventGroup(event_group_entry)
258 | Entry::SubscribeAckEventGroup(event_group_entry) => {
259 event_group_entry.options_count.second_options_count
260 }
261 }
262 }
263
264 #[must_use]
266 pub fn total_options_count(&self) -> u8 {
267 self.first_options_count() + self.second_options_count()
268 }
269}
270
271impl Encode for Entry {
272 type Error = crate::protocol::Error;
273
274 fn encoded_size(&self) -> Result<usize, Self::Error> {
275 Ok(ENTRY_SIZE)
277 }
278
279 fn encode(&self, writer: &mut impl embedded_io::Write) -> Result<usize, Self::Error> {
280 let body = match self {
281 Entry::FindService(service_entry) => {
282 writer.write_u8(u8::from(EntryType::FindService))?;
283 service_entry.encode(writer)?
284 }
285 Entry::OfferService(service_entry) => {
286 writer.write_u8(u8::from(EntryType::OfferService))?;
287 service_entry.encode(writer)?
288 }
289 Entry::StopOfferService(service_entry) => {
290 writer.write_u8(u8::from(EntryType::StopOfferService))?;
291 service_entry.encode(writer)?
292 }
293 Entry::SubscribeEventGroup(event_group_entry) => {
294 writer.write_u8(u8::from(EntryType::Subscribe))?;
295 event_group_entry.encode(writer)?
296 }
297 Entry::SubscribeAckEventGroup(event_group_entry) => {
298 writer.write_u8(u8::from(EntryType::SubscribeAck))?;
299 event_group_entry.encode(writer)?
300 }
301 };
302 Ok(1 + body)
304 }
305}
306
307#[derive(Clone, Copy, Debug)]
323pub struct EntryView<'a>(&'a [u8; ENTRY_SIZE]);
324
325impl EntryView<'_> {
326 pub fn entry_type(&self) -> Result<EntryType, Error> {
332 EntryType::try_from(self.0[0])
333 }
334
335 #[must_use]
337 pub fn index_first_options_run(&self) -> u8 {
338 self.0[1]
339 }
340
341 #[must_use]
343 pub fn index_second_options_run(&self) -> u8 {
344 self.0[2]
345 }
346
347 #[must_use]
349 pub fn options_count(&self) -> OptionsCount {
350 OptionsCount::from(self.0[3])
351 }
352
353 #[must_use]
355 pub fn service_id(&self) -> u16 {
356 u16::from_be_bytes([self.0[4], self.0[5]])
357 }
358
359 #[must_use]
361 pub fn instance_id(&self) -> u16 {
362 u16::from_be_bytes([self.0[6], self.0[7]])
363 }
364
365 #[must_use]
367 pub fn major_version(&self) -> u8 {
368 self.0[8]
369 }
370
371 #[must_use]
373 pub fn ttl(&self) -> u32 {
374 u32::from_be_bytes([0, self.0[9], self.0[10], self.0[11]])
375 }
376
377 #[must_use]
379 pub fn minor_version(&self) -> u32 {
380 u32::from_be_bytes([self.0[12], self.0[13], self.0[14], self.0[15]])
381 }
382
383 #[must_use]
385 pub fn counter(&self) -> u16 {
386 u16::from_be_bytes([self.0[12], self.0[13]]) & 0x000f
387 }
388
389 #[must_use]
391 pub fn event_group_id(&self) -> u16 {
392 u16::from_be_bytes([self.0[14], self.0[15]])
393 }
394
395 pub fn to_owned(&self) -> Result<Entry, Error> {
401 let entry_type = self.entry_type()?;
402 match entry_type {
403 EntryType::FindService => Ok(Entry::FindService(self.to_service_entry())),
404 EntryType::OfferService => Ok(Entry::OfferService(self.to_service_entry())),
405 EntryType::StopOfferService => Ok(Entry::StopOfferService(self.to_service_entry())),
406 EntryType::Subscribe => Ok(Entry::SubscribeEventGroup(self.to_event_group_entry())),
407 EntryType::SubscribeAck => {
408 Ok(Entry::SubscribeAckEventGroup(self.to_event_group_entry()))
409 }
410 }
411 }
412
413 fn to_service_entry(self) -> ServiceEntry {
414 ServiceEntry {
415 index_first_options_run: self.index_first_options_run(),
416 index_second_options_run: self.index_second_options_run(),
417 options_count: self.options_count(),
418 service_id: self.service_id(),
419 instance_id: self.instance_id(),
420 major_version: self.major_version(),
421 ttl: self.ttl(),
422 minor_version: self.minor_version(),
423 }
424 }
425
426 fn to_event_group_entry(self) -> EventGroupEntry {
427 EventGroupEntry {
428 index_first_options_run: self.index_first_options_run(),
429 index_second_options_run: self.index_second_options_run(),
430 options_count: self.options_count(),
431 service_id: self.service_id(),
432 instance_id: self.instance_id(),
433 major_version: self.major_version(),
434 ttl: self.ttl(),
435 counter: self.counter(),
436 event_group_id: self.event_group_id(),
437 }
438 }
439}
440
441impl<'a> Decode<'a> for EntryView<'a> {
442 type Error = crate::protocol::Error;
443
444 fn decode(buf: &'a [u8]) -> Result<(Self, &'a [u8]), Self::Error> {
460 let (head, rest) = take(buf, ENTRY_SIZE)?;
461 let entry_bytes: &'a [u8; ENTRY_SIZE] =
462 head.try_into().expect("take guarantees ENTRY_SIZE bytes");
463 Ok((EntryView(entry_bytes), rest))
464 }
465}
466
467impl<'a> DecodeIter<'a> for EntryView<'a> {
468 type Error = crate::protocol::Error;
469
470 const WIRE_SIZE: Option<usize> = Some(ENTRY_SIZE);
473
474 fn decode_next(buf: &'a [u8]) -> Result<Option<(Self, &'a [u8])>, Self::Error> {
484 if buf.is_empty() {
485 return Ok(None);
486 }
487 Self::decode(buf).map(Some)
488 }
489}
490
491pub struct EntryIter<'a> {
494 remaining: &'a [u8],
495}
496
497impl<'a> EntryIter<'a> {
498 pub(crate) fn new(buf: &'a [u8]) -> Self {
499 Self { remaining: buf }
500 }
501}
502
503impl<'a> Iterator for EntryIter<'a> {
504 type Item = EntryView<'a>;
505
506 fn next(&mut self) -> Option<Self::Item> {
507 if self.remaining.len() < ENTRY_SIZE {
508 return None;
509 }
510 let entry_bytes: &[u8; ENTRY_SIZE] = self.remaining[..ENTRY_SIZE]
511 .try_into()
512 .expect("length checked above");
513 self.remaining = &self.remaining[ENTRY_SIZE..];
514 Some(EntryView(entry_bytes))
515 }
516
517 fn size_hint(&self) -> (usize, Option<usize>) {
518 let n = self.remaining.len() / ENTRY_SIZE;
519 (n, Some(n))
520 }
521}
522
523impl ExactSizeIterator for EntryIter<'_> {}
524
525#[cfg(test)]
526mod tests {
527 use super::*;
528
529 fn encode_entry(entry: &Entry) -> [u8; 17] {
530 let mut buf = [0u8; 17];
531 entry.encode(&mut buf.as_mut_slice()).unwrap();
532 buf
533 }
534
535 fn make_service_entry() -> ServiceEntry {
536 ServiceEntry {
537 index_first_options_run: 1,
538 index_second_options_run: 2,
539 options_count: OptionsCount::new(3, 4),
540 service_id: 0x1234,
541 instance_id: 0x5678,
542 major_version: 0x01,
543 ttl: 0x0000_00FF,
544 minor_version: 0x0000_0002,
545 }
546 }
547
548 fn make_event_group_entry() -> EventGroupEntry {
549 EventGroupEntry {
550 index_first_options_run: 1,
551 index_second_options_run: 2,
552 options_count: OptionsCount::new(3, 4),
553 service_id: 0xABCD,
554 instance_id: 0x0001,
555 major_version: 0x02,
556 ttl: 0x0000_0064,
557 counter: 0x0003,
558 event_group_id: 0x0010,
559 }
560 }
561
562 #[test]
565 fn entry_type_try_from_all_valid_values() {
566 assert_eq!(EntryType::try_from(0x00).unwrap(), EntryType::FindService);
567 assert_eq!(EntryType::try_from(0x01).unwrap(), EntryType::OfferService);
568 assert_eq!(
569 EntryType::try_from(0x02).unwrap(),
570 EntryType::StopOfferService
571 );
572 assert_eq!(EntryType::try_from(0x06).unwrap(), EntryType::Subscribe);
573 assert_eq!(EntryType::try_from(0x07).unwrap(), EntryType::SubscribeAck);
574 }
575
576 #[test]
577 fn entry_type_try_from_invalid_returns_error() {
578 assert!(matches!(
579 EntryType::try_from(0x03),
580 Err(Error::InvalidEntryType(0x03))
581 ));
582 }
583
584 #[test]
585 fn entry_type_into_u8_all_variants() {
586 assert_eq!(u8::from(EntryType::FindService), 0x00);
587 assert_eq!(u8::from(EntryType::OfferService), 0x01);
588 assert_eq!(u8::from(EntryType::StopOfferService), 0x02);
589 assert_eq!(u8::from(EntryType::Subscribe), 0x06);
590 assert_eq!(u8::from(EntryType::SubscribeAck), 0x07);
591 }
592
593 #[test]
596 fn options_count_round_trip() {
597 let oc = OptionsCount::new(3, 7);
598 let byte = u8::from(oc);
599 let decoded = OptionsCount::from(byte);
600 assert_eq!(decoded.first_options_count, 3);
601 assert_eq!(decoded.second_options_count, 7);
602 }
603
604 #[test]
607 fn service_entry_encoded_size() {
608 assert_eq!(make_service_entry().encoded_size().unwrap(), 15);
610 }
611
612 #[test]
613 fn event_group_entry_encoded_size() {
614 assert_eq!(make_event_group_entry().encoded_size().unwrap(), 15);
615 }
616
617 #[test]
618 fn entry_encoded_size_all_variants() {
619 assert_eq!(
621 Entry::FindService(make_service_entry())
622 .encoded_size()
623 .unwrap(),
624 16
625 );
626 assert_eq!(
627 Entry::OfferService(make_service_entry())
628 .encoded_size()
629 .unwrap(),
630 16
631 );
632 assert_eq!(
633 Entry::StopOfferService(make_service_entry())
634 .encoded_size()
635 .unwrap(),
636 16
637 );
638 assert_eq!(
639 Entry::SubscribeEventGroup(make_event_group_entry())
640 .encoded_size()
641 .unwrap(),
642 16
643 );
644 assert_eq!(
645 Entry::SubscribeAckEventGroup(make_event_group_entry())
646 .encoded_size()
647 .unwrap(),
648 16
649 );
650 }
651
652 #[test]
655 fn entry_options_count_service_variants() {
656 let se = make_service_entry(); for entry in [
658 Entry::FindService(se),
659 Entry::OfferService(make_service_entry()),
660 Entry::StopOfferService(make_service_entry()),
661 ] {
662 assert_eq!(entry.first_options_count(), 3);
663 assert_eq!(entry.second_options_count(), 4);
664 assert_eq!(entry.total_options_count(), 7);
665 }
666 }
667
668 #[test]
669 fn entry_options_count_event_group_variants() {
670 let eg = make_event_group_entry(); for entry in [
672 Entry::SubscribeEventGroup(eg.clone()),
673 Entry::SubscribeAckEventGroup(eg),
674 ] {
675 assert_eq!(entry.first_options_count(), 3);
676 assert_eq!(entry.second_options_count(), 4);
677 assert_eq!(entry.total_options_count(), 7);
678 }
679 }
680
681 #[test]
684 fn find_service_entry_round_trips() {
685 let entry = Entry::FindService(make_service_entry());
686 let buf = encode_entry(&entry);
687 let entry_bytes: &[u8; ENTRY_SIZE] = buf[..ENTRY_SIZE].try_into().unwrap();
690 let view = EntryView(entry_bytes);
691 assert_eq!(view.to_owned().unwrap(), entry);
692 }
693
694 #[test]
695 fn offer_service_entry_round_trips() {
696 let entry = Entry::OfferService(make_service_entry());
697 let buf = encode_entry(&entry);
698 let entry_bytes: &[u8; ENTRY_SIZE] = buf[..ENTRY_SIZE].try_into().unwrap();
699 let view = EntryView(entry_bytes);
700 assert_eq!(view.to_owned().unwrap(), entry);
701 }
702
703 #[test]
704 fn stop_offer_service_entry_round_trips() {
705 let entry = Entry::StopOfferService(make_service_entry());
706 let buf = encode_entry(&entry);
707 let entry_bytes: &[u8; ENTRY_SIZE] = buf[..ENTRY_SIZE].try_into().unwrap();
708 let view = EntryView(entry_bytes);
709 assert_eq!(view.to_owned().unwrap(), entry);
710 }
711
712 #[test]
713 fn subscribe_event_group_entry_round_trips() {
714 let entry = Entry::SubscribeEventGroup(make_event_group_entry());
715 let buf = encode_entry(&entry);
716 let entry_bytes: &[u8; ENTRY_SIZE] = buf[..ENTRY_SIZE].try_into().unwrap();
717 let view = EntryView(entry_bytes);
718 assert_eq!(view.to_owned().unwrap(), entry);
719 }
720
721 #[test]
722 fn subscribe_ack_event_group_entry_round_trips() {
723 let entry = Entry::SubscribeAckEventGroup(make_event_group_entry());
724 let buf = encode_entry(&entry);
725 let entry_bytes: &[u8; ENTRY_SIZE] = buf[..ENTRY_SIZE].try_into().unwrap();
726 let view = EntryView(entry_bytes);
727 assert_eq!(view.to_owned().unwrap(), entry);
728 }
729
730 #[test]
731 fn entry_view_invalid_type_returns_error() {
732 let buf: [u8; ENTRY_SIZE] = [0x03; ENTRY_SIZE]; let view = EntryView(&buf);
734 assert!(matches!(
735 view.to_owned(),
736 Err(Error::InvalidEntryType(0x03))
737 ));
738 }
739
740 #[test]
743 fn entry_iter_empty() {
744 let iter = EntryIter::new(&[]);
745 assert_eq!(iter.len(), 0);
746 }
747
748 #[test]
749 fn entry_iter_two_entries() {
750 let e1 = Entry::FindService(make_service_entry());
751 let e2 = Entry::SubscribeEventGroup(make_event_group_entry());
752 let buf1 = encode_entry(&e1);
753 let buf2 = encode_entry(&e2);
754 let mut combined = [0u8; 32];
756 combined[..16].copy_from_slice(&buf1[..16]);
757 combined[16..32].copy_from_slice(&buf2[..16]);
758
759 let mut iter = EntryIter::new(&combined);
760 assert_eq!(iter.len(), 2);
761 assert_eq!(iter.next().unwrap().to_owned().unwrap(), e1);
762 assert_eq!(iter.next().unwrap().to_owned().unwrap(), e2);
763 assert!(iter.next().is_none());
764 }
765
766 fn two_entry_buf(e1: &Entry, e2: &Entry) -> [u8; 32] {
769 let b1 = encode_entry(e1);
770 let b2 = encode_entry(e2);
771 let mut combined = [0u8; 32];
772 combined[..16].copy_from_slice(&b1[..16]);
773 combined[16..32].copy_from_slice(&b2[..16]);
774 combined
775 }
776
777 #[test]
778 fn decode_yields_entry_and_remainder() {
779 let e1 = Entry::FindService(make_service_entry());
780 let e2 = Entry::SubscribeEventGroup(make_event_group_entry());
781 let buf = two_entry_buf(&e1, &e2);
782 let (view, rest) = EntryView::decode(&buf).unwrap();
783 assert_eq!(view.to_owned().unwrap(), e1);
784 assert_eq!(rest.len(), 16);
785 let (view2, rest2) = EntryView::decode(rest).unwrap();
786 assert_eq!(view2.to_owned().unwrap(), e2);
787 assert!(rest2.is_empty());
788 }
789
790 #[test]
791 fn decode_truncated_is_incomplete() {
792 let e1 = Entry::FindService(make_service_entry());
793 let buf = encode_entry(&e1);
794 assert!(matches!(
795 EntryView::decode(&buf[..15]),
796 Err(crate::protocol::Error::Incomplete(
797 automotive_wire_codec::Incomplete {
798 needed: 16,
799 available: 15,
800 }
801 ))
802 ));
803 }
804
805 #[test]
806 fn decode_exact_rejects_trailing() {
807 let e1 = Entry::FindService(make_service_entry());
808 let e2 = Entry::OfferService(make_service_entry());
809 let buf = two_entry_buf(&e1, &e2);
810 assert!(matches!(
811 EntryView::decode_exact(&buf),
812 Err(crate::protocol::Error::Trailing(_))
813 ));
814 assert!(EntryView::decode_exact(&buf[..16]).is_ok());
816 }
817
818 #[test]
819 fn decode_iter_yields_all_then_none() {
820 let e1 = Entry::FindService(make_service_entry());
821 let e2 = Entry::SubscribeEventGroup(make_event_group_entry());
822 let buf = two_entry_buf(&e1, &e2);
823 let mut iter = EntryView::iter(&buf);
824 assert_eq!(iter.next().unwrap().unwrap().to_owned().unwrap(), e1);
825 assert_eq!(iter.next().unwrap().unwrap().to_owned().unwrap(), e2);
826 assert!(iter.next().is_none());
827 }
828
829 #[test]
830 fn decode_iter_surfaces_truncated_tail_as_err() {
831 let e1 = Entry::FindService(make_service_entry());
832 let buf = two_entry_buf(&e1, &Entry::OfferService(make_service_entry()));
833 let mut iter = EntryView::iter(&buf[..24]);
835 assert!(matches!(iter.next(), Some(Ok(_))));
836 assert!(matches!(
837 iter.next(),
838 Some(Err(crate::protocol::Error::Incomplete(_)))
839 ));
840 assert!(iter.next().is_none());
842 }
843
844 #[test]
845 fn decode_iter_empty_is_immediately_none() {
846 let mut iter = EntryView::iter(&[]);
847 assert!(iter.next().is_none());
848 }
849
850 #[test]
851 fn decode_iter_remaining_len_counts_entries() {
852 let e1 = Entry::FindService(make_service_entry());
853 let e2 = Entry::SubscribeEventGroup(make_event_group_entry());
854 let buf = two_entry_buf(&e1, &e2);
855 let mut iter = EntryView::iter(&buf);
856 assert_eq!(iter.remaining_len(), Some(2));
857 iter.next();
858 assert_eq!(iter.remaining_len(), Some(1));
859 iter.next();
860 iter.next(); assert_eq!(iter.remaining_len(), Some(0));
862 }
863
864 #[test]
865 fn decode_iter_does_not_validate_entry_type() {
866 let buf = [0x03u8; ENTRY_SIZE];
869 let mut iter = EntryView::iter(&buf);
870 let view = iter.next().unwrap().unwrap();
871 assert!(matches!(
872 view.to_owned(),
873 Err(Error::InvalidEntryType(0x03))
874 ));
875 }
876
877 #[test]
880 fn entry_encoded_size_matches_bytes_written() {
881 use automotive_wire_codec::CountingSink;
882 for entry in [
883 Entry::FindService(make_service_entry()),
884 Entry::SubscribeEventGroup(make_event_group_entry()),
885 ] {
886 let mut sink = CountingSink::new();
887 let written = entry.encode(&mut sink).unwrap();
888 assert_eq!(written, entry.encoded_size().unwrap());
889 assert_eq!(written, sink.count());
890 }
891 }
892
893 #[test]
894 fn service_entry_encoded_size_matches_bytes_written() {
895 use automotive_wire_codec::CountingSink;
896 let se = make_service_entry();
897 let mut sink = CountingSink::new();
898 let written = se.encode(&mut sink).unwrap();
899 assert_eq!(written, se.encoded_size().unwrap());
900 assert_eq!(written, sink.count());
901
902 let eg = make_event_group_entry();
903 let mut sink = CountingSink::new();
904 let written = eg.encode(&mut sink).unwrap();
905 assert_eq!(written, eg.encoded_size().unwrap());
906 assert_eq!(written, sink.count());
907 }
908
909 #[test]
910 fn entry_encode_to_slice_too_small_yields_insufficient_buffer() {
911 use automotive_wire_codec::{EncodeToSliceError, InsufficientBuffer};
912 let entry = Entry::FindService(make_service_entry());
913 let mut buf = [0u8; 4]; let err = entry.encode_to_slice(&mut buf).unwrap_err();
915 assert!(matches!(
916 err,
917 EncodeToSliceError::InsufficientBuffer(InsufficientBuffer {
918 needed: 16,
919 available: 4,
920 })
921 ));
922 }
923}