dvb_si/descriptors/
service_list.rs1use super::descriptor_body;
7use crate::error::{Error, Result};
8use dvb_common::{Parse, Serialize};
9
10pub const TAG: u8 = 0x41;
12const HEADER_LEN: usize = 2;
13const ENTRY_LEN: usize = 3;
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq)]
17#[cfg_attr(feature = "serde", derive(serde::Serialize))]
18pub struct ServiceListEntry {
19 pub service_id: u16,
21 pub service_type: u8,
23}
24
25#[derive(Debug, Clone, PartialEq, Eq)]
27#[cfg_attr(feature = "serde", derive(serde::Serialize))]
28pub struct ServiceListDescriptor {
29 pub entries: Vec<ServiceListEntry>,
31}
32
33impl<'a> Parse<'a> for ServiceListDescriptor {
34 type Error = crate::error::Error;
35 fn parse(bytes: &'a [u8]) -> Result<Self> {
36 let body = descriptor_body(
37 bytes,
38 TAG,
39 "ServiceListDescriptor",
40 "unexpected tag for service_list_descriptor",
41 )?;
42 if body.len() % 3 != 0 {
43 return Err(Error::InvalidDescriptor {
44 tag: TAG,
45 reason: "descriptor_length must be a multiple of 3",
46 });
47 }
48 let mut entries = Vec::with_capacity(body.len() / ENTRY_LEN);
49 let mut offset = 0;
50 while offset < body.len() {
51 let service_id = u16::from_be_bytes([body[offset], body[offset + 1]]);
52 let service_type = body[offset + 2];
53 entries.push(ServiceListEntry {
54 service_id,
55 service_type,
56 });
57 offset += ENTRY_LEN;
58 }
59 Ok(Self { entries })
60 }
61}
62
63impl Serialize for ServiceListDescriptor {
64 type Error = crate::error::Error;
65 fn serialized_len(&self) -> usize {
66 HEADER_LEN + ENTRY_LEN * self.entries.len()
67 }
68
69 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
70 let len = self.serialized_len();
71 if buf.len() < len {
72 return Err(Error::OutputBufferTooSmall {
73 need: len,
74 have: buf.len(),
75 });
76 }
77 buf[0] = TAG;
78 buf[1] = (len - HEADER_LEN) as u8;
79 let mut offset = HEADER_LEN;
80 for entry in &self.entries {
81 buf[offset..offset + 2].copy_from_slice(&entry.service_id.to_be_bytes());
82 buf[offset + 2] = entry.service_type;
83 offset += ENTRY_LEN;
84 }
85 Ok(len)
86 }
87}
88impl<'a> crate::traits::DescriptorDef<'a> for ServiceListDescriptor {
89 const TAG: u8 = TAG;
90 const NAME: &'static str = "SERVICE_LIST";
91}
92
93#[cfg(test)]
94mod tests {
95 use super::*;
96
97 #[test]
98 fn parse_single_entry() {
99 let bytes = [TAG, 3, 0x00, 0x01, 0x01];
100 let d = ServiceListDescriptor::parse(&bytes).unwrap();
101 assert_eq!(d.entries.len(), 1);
102 assert_eq!(d.entries[0].service_id, 1);
103 assert_eq!(d.entries[0].service_type, 0x01);
104 }
105
106 #[test]
107 fn parse_multiple_entries_preserves_order() {
108 let bytes = [TAG, 9, 0x00, 0x01, 0x01, 0x00, 0x02, 0x02, 0x00, 0x03, 0x03];
109 let d = ServiceListDescriptor::parse(&bytes).unwrap();
110 assert_eq!(d.entries.len(), 3);
111 assert_eq!(d.entries[0].service_id, 1);
112 assert_eq!(d.entries[0].service_type, 0x01);
113 assert_eq!(d.entries[1].service_id, 2);
114 assert_eq!(d.entries[1].service_type, 0x02);
115 assert_eq!(d.entries[2].service_id, 3);
116 assert_eq!(d.entries[2].service_type, 0x03);
117 }
118
119 #[test]
120 fn parse_rejects_wrong_tag() {
121 let err = ServiceListDescriptor::parse(&[0x42, 3, 0x00, 0x01, 0x01]).unwrap_err();
122 assert!(matches!(err, Error::InvalidDescriptor { tag: 0x42, .. }));
123 }
124
125 #[test]
126 fn parse_rejects_length_not_multiple_of_3() {
127 let bytes = [TAG, 4, 0x00, 0x01, 0x01, 0xFF];
128 let err = ServiceListDescriptor::parse(&bytes).unwrap_err();
129 assert!(matches!(err, Error::InvalidDescriptor { tag: TAG, .. }));
130 }
131
132 #[test]
133 fn parse_rejects_truncated_body() {
134 let bytes = [TAG, 6, 0x00, 0x01];
135 let err = ServiceListDescriptor::parse(&bytes).unwrap_err();
136 assert!(matches!(err, Error::BufferTooShort { .. }));
137 }
138
139 #[test]
140 fn empty_descriptor_valid() {
141 let bytes = [TAG, 0];
142 let d = ServiceListDescriptor::parse(&bytes).unwrap();
143 assert!(d.entries.is_empty());
144 }
145
146 #[test]
147 fn serialize_round_trip() {
148 let d = ServiceListDescriptor {
149 entries: vec![
150 ServiceListEntry {
151 service_id: 1,
152 service_type: 0x01,
153 },
154 ServiceListEntry {
155 service_id: 0x0102,
156 service_type: 0x04,
157 },
158 ],
159 };
160 let mut buf = vec![0u8; d.serialized_len()];
161 d.serialize_into(&mut buf).unwrap();
162 let re = ServiceListDescriptor::parse(&buf).unwrap();
163 assert_eq!(d, re);
164 }
165}