1macro_rules! declare_descriptors {
57 (
58 $lt:lifetime;
59 $( $variant:ident = $tag:literal => $($path:ident)::+ $(<$plt:lifetime>)? ),+ $(,)?
60 $( ; @no_dispatch $( $nd_variant:ident => $($nd_path:ident)::+ $(<$nd_plt:lifetime>)? ),+ $(,)? )?
61 ) => {
62 #[derive(Debug)]
69 #[cfg_attr(feature = "serde", derive(serde::Serialize))]
70 #[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
71 #[non_exhaustive]
72 pub enum AnyDescriptor<$lt> {
73 $(
74 #[allow(missing_docs)]
75 $variant($($path)::+ $(<$plt>)?),
76 )+
77 $($(
78 #[allow(missing_docs)]
79 $nd_variant($($nd_path)::+ $(<$nd_plt>)?),
80 )+)?
81 Other {
85 tag: u8,
87 #[cfg_attr(
91 feature = "serde",
92 serde(serialize_with = "crate::descriptors::registry::serialize_erased")
93 )]
94 value: Box<dyn crate::descriptors::registry::DescriptorObject>,
95 },
96 Unknown {
99 tag: u8,
101 body: &$lt [u8],
103 },
104 }
105
106 $(
107 impl<$lt> From<$($path)::+ $(<$plt>)?> for AnyDescriptor<$lt> {
108 fn from(d: $($path)::+ $(<$plt>)?) -> Self {
109 Self::$variant(d)
110 }
111 }
112 )+
113 $($(
114 impl<$lt> From<$($nd_path)::+ $(<$nd_plt>)?> for AnyDescriptor<$lt> {
115 fn from(d: $($nd_path)::+ $(<$nd_plt>)?) -> Self {
116 Self::$nd_variant(d)
117 }
118 }
119 )+)?
120
121 impl<$lt> AnyDescriptor<$lt> {
122 pub const DISPATCHED_TAGS: &'static [u8] = &[$($tag),+];
125
126 pub(crate) fn dispatch(tag: u8, full: &$lt [u8]) -> Option<crate::Result<Self>> {
132 use dvb_common::Parse;
133 match tag {
134 $(
135 $tag => Some(<$($path)::+>::parse(full).map(Self::$variant)),
136 )+
137 _ => None,
138 }
139 }
140 }
141
142 #[cfg(test)]
143 mod macro_drift {
144 #[test]
145 fn tag_literals_match_descriptor_def() {
146 use crate::traits::DescriptorDef;
147 $(
148 assert_eq!(
149 $tag,
150 <$($path)::+ as DescriptorDef>::TAG,
151 concat!("tag literal drift for ", stringify!($variant)),
152 );
153 assert!(
154 !<$($path)::+ as DescriptorDef>::NAME.is_empty(),
155 concat!("empty NAME for ", stringify!($variant)),
156 );
157 )+
158 $($(
159 assert!(
160 !<$($nd_path)::+ as DescriptorDef>::NAME.is_empty(),
161 concat!("empty NAME for ", stringify!($nd_variant)),
162 );
163 )+)?
164 }
165 }
166 };
167}
168
169declare_descriptors! {'a;
170 Registration = 0x05 => crate::descriptors::registration::RegistrationDescriptor<'a>,
172 DataStreamAlignment = 0x06 => crate::descriptors::data_stream_alignment::DataStreamAlignmentDescriptor,
173 Ca = 0x09 => crate::descriptors::ca::CaDescriptor<'a>,
174 Iso639Language = 0x0A => crate::descriptors::iso_639_language::Iso639LanguageDescriptor,
175 PrivateDataIndicator = 0x0F => crate::descriptors::private_data_indicator::PrivateDataIndicatorDescriptor,
176 NetworkName = 0x40 => crate::descriptors::network_name::NetworkNameDescriptor<'a>,
178 ServiceList = 0x41 => crate::descriptors::service_list::ServiceListDescriptor,
179 Stuffing = 0x42 => crate::descriptors::stuffing::StuffingDescriptor<'a>,
180 SatelliteDeliverySystem = 0x43 => crate::descriptors::satellite_delivery_system::SatelliteDeliverySystemDescriptor,
181 CableDeliverySystem = 0x44 => crate::descriptors::cable_delivery_system::CableDeliverySystemDescriptor,
182 VbiData = 0x45 => crate::descriptors::vbi_data::VbiDataDescriptor<'a>,
183 VbiTeletext = 0x46 => crate::descriptors::vbi_teletext::VbiTeletextDescriptor,
184 BouquetName = 0x47 => crate::descriptors::bouquet_name::BouquetNameDescriptor<'a>,
185 Service = 0x48 => crate::descriptors::service::ServiceDescriptor<'a>,
186 CountryAvailability = 0x49 => crate::descriptors::country_availability::CountryAvailabilityDescriptor,
187 Linkage = 0x4A => crate::descriptors::linkage::LinkageDescriptor<'a>,
188 NvodReference = 0x4B => crate::descriptors::nvod_reference::NvodReferenceDescriptor,
189 TimeShiftedService = 0x4C => crate::descriptors::time_shifted_service::TimeShiftedServiceDescriptor,
190 ShortEvent = 0x4D => crate::descriptors::short_event::ShortEventDescriptor<'a>,
191 ExtendedEvent = 0x4E => crate::descriptors::extended_event::ExtendedEventDescriptor<'a>,
192 TimeShiftedEvent = 0x4F => crate::descriptors::time_shifted_event::TimeShiftedEventDescriptor,
193 Component = 0x50 => crate::descriptors::component::ComponentDescriptor<'a>,
194 Mosaic = 0x51 => crate::descriptors::mosaic::MosaicDescriptor,
195 StreamIdentifier = 0x52 => crate::descriptors::stream_identifier::StreamIdentifierDescriptor,
196 CaIdentifier = 0x53 => crate::descriptors::ca_identifier::CaIdentifierDescriptor,
197 Content = 0x54 => crate::descriptors::content::ContentDescriptor,
198 ParentalRating = 0x55 => crate::descriptors::parental_rating::ParentalRatingDescriptor,
199 Teletext = 0x56 => crate::descriptors::teletext::TeletextDescriptor,
200 Telephone = 0x57 => crate::descriptors::telephone::TelephoneDescriptor<'a>,
201 LocalTimeOffset = 0x58 => crate::descriptors::local_time_offset::LocalTimeOffsetDescriptor,
202 Subtitling = 0x59 => crate::descriptors::subtitling::SubtitlingDescriptor,
203 TerrestrialDeliverySystem = 0x5A => crate::descriptors::terrestrial_delivery_system::TerrestrialDeliverySystemDescriptor,
204 MultilingualNetworkName = 0x5B => crate::descriptors::multilingual_network_name::MultilingualNetworkNameDescriptor<'a>,
205 MultilingualBouquetName = 0x5C => crate::descriptors::multilingual_bouquet_name::MultilingualBouquetNameDescriptor<'a>,
206 MultilingualServiceName = 0x5D => crate::descriptors::multilingual_service_name::MultilingualServiceNameDescriptor<'a>,
207 MultilingualComponent = 0x5E => crate::descriptors::multilingual_component::MultilingualComponentDescriptor<'a>,
208 PrivateDataSpecifier = 0x5F => crate::descriptors::private_data_specifier::PrivateDataSpecifierDescriptor,
209 ServiceMove = 0x60 => crate::descriptors::service_move::ServiceMoveDescriptor,
210 ShortSmoothingBuffer = 0x61 => crate::descriptors::short_smoothing_buffer::ShortSmoothingBufferDescriptor<'a>,
211 FrequencyList = 0x62 => crate::descriptors::frequency_list::FrequencyListDescriptor,
212 PartialTransportStream = 0x63 => crate::descriptors::partial_transport_stream::PartialTransportStreamDescriptor,
213 DataBroadcast = 0x64 => crate::descriptors::data_broadcast::DataBroadcastDescriptor<'a>,
214 Scrambling = 0x65 => crate::descriptors::scrambling::ScramblingDescriptor,
215 DataBroadcastId = 0x66 => crate::descriptors::data_broadcast_id::DataBroadcastIdDescriptor<'a>,
216 TransportStream = 0x67 => crate::descriptors::transport_stream::TransportStreamDescriptor<'a>,
217 Dsng = 0x68 => crate::descriptors::dsng::DsngDescriptor<'a>,
218 Pdc = 0x69 => crate::descriptors::pdc::PdcDescriptor,
219 Ac3 = 0x6A => crate::descriptors::ac3::Ac3Descriptor<'a>,
220 AncillaryData = 0x6B => crate::descriptors::ancillary_data::AncillaryDataDescriptor,
221 CellList = 0x6C => crate::descriptors::cell_list::CellListDescriptor,
222 CellFrequencyLink = 0x6D => crate::descriptors::cell_frequency_link::CellFrequencyLinkDescriptor,
223 AnnouncementSupport = 0x6E => crate::descriptors::announcement_support::AnnouncementSupportDescriptor,
224 ApplicationSignalling = 0x6F => crate::descriptors::application_signalling::ApplicationSignallingDescriptor,
225 AdaptationFieldData = 0x70 => crate::descriptors::adaptation_field_data::AdaptationFieldDataDescriptor,
226 ServiceIdentifier = 0x71 => crate::descriptors::service_identifier::ServiceIdentifierDescriptor<'a>,
227 ServiceAvailability = 0x72 => crate::descriptors::service_availability::ServiceAvailabilityDescriptor,
228 DefaultAuthority = 0x73 => crate::descriptors::default_authority::DefaultAuthorityDescriptor<'a>,
229 RelatedContent = 0x74 => crate::descriptors::related_content::RelatedContentDescriptor,
230 TvaId = 0x75 => crate::descriptors::tva_id::TvaIdDescriptor,
231 ContentIdentifier = 0x76 => crate::descriptors::content_identifier::ContentIdentifierDescriptor<'a>,
232 TimeSliceFecIdentifier = 0x77 => crate::descriptors::time_slice_fec_identifier::TimeSliceFecIdentifierDescriptor<'a>,
233 EcmRepetitionRate = 0x78 => crate::descriptors::ecm_repetition_rate::EcmRepetitionRateDescriptor<'a>,
234 S2SatelliteDeliverySystem = 0x79 => crate::descriptors::s2_satellite_delivery_system::S2SatelliteDeliverySystemDescriptor,
235 EnhancedAc3 = 0x7A => crate::descriptors::enhanced_ac3::EnhancedAc3Descriptor<'a>,
236 Dts = 0x7B => crate::descriptors::dts::DtsDescriptor<'a>,
237 Aac = 0x7C => crate::descriptors::aac::AacDescriptor<'a>,
238 XaitLocation = 0x7D => crate::descriptors::xait_location::XaitLocationDescriptor,
239 FtaContentManagement = 0x7E => crate::descriptors::fta_content_management::FtaContentManagementDescriptor,
240 Extension = 0x7F => crate::descriptors::extension::ExtensionDescriptor<'a>;
241 @no_dispatch
245 LogicalChannel => crate::descriptors::logical_channel::LogicalChannelDescriptor,
246}
247
248#[must_use]
255pub fn parse_loop(bytes: &[u8]) -> DescriptorIter<'_> {
256 DescriptorIter {
257 bytes,
258 pos: 0,
259 fused: false,
260 }
261}
262
263#[derive(Debug, Clone)]
265pub struct DescriptorIter<'a> {
266 bytes: &'a [u8],
267 pos: usize,
268 fused: bool,
269}
270
271impl<'a> Iterator for DescriptorIter<'a> {
272 type Item = crate::Result<AnyDescriptor<'a>>;
273
274 fn next(&mut self) -> Option<Self::Item> {
275 if self.fused || self.pos >= self.bytes.len() {
276 return None;
277 }
278 let rem = &self.bytes[self.pos..];
279 if rem.len() < 2 {
280 self.fused = true;
281 return Some(Err(crate::Error::BufferTooShort {
282 need: 2,
283 have: rem.len(),
284 what: "descriptor header in loop",
285 }));
286 }
287 let tag = rem[0];
288 let len = rem[1] as usize;
289 let total = 2 + len;
290 if rem.len() < total {
291 self.fused = true;
292 return Some(Err(crate::Error::BufferTooShort {
293 need: total,
294 have: rem.len(),
295 what: "descriptor body in loop",
296 }));
297 }
298 let full = &rem[..total];
299 self.pos += total;
300 Some(match AnyDescriptor::dispatch(tag, full) {
301 Some(res) => res,
304 None => Ok(AnyDescriptor::Unknown {
305 tag,
306 body: &full[2..],
307 }),
308 })
309 }
310}
311
312impl std::iter::FusedIterator for DescriptorIter<'_> {}
313
314#[cfg(test)]
315mod tests {
316 use super::*;
317
318 #[test]
319 fn unknown_tag_yields_unknown_with_body_sans_header() {
320 let bytes = [0xA7, 0x02, 0xDE, 0xAD];
322 let items: Vec<_> = parse_loop(&bytes).collect();
323 assert_eq!(items.len(), 1);
324 match items[0].as_ref().unwrap() {
325 AnyDescriptor::Unknown { tag, body } => {
326 assert_eq!(*tag, 0xA7);
327 assert_eq!(*body, &[0xDE, 0xAD]);
328 }
329 other => panic!("expected Unknown, got {other:?}"),
330 }
331 }
332
333 #[test]
334 fn empty_loop_yields_nothing() {
335 assert_eq!(parse_loop(&[]).count(), 0);
336 }
337
338 #[test]
339 fn logical_channel_0x83_is_not_dispatched() {
340 let bytes = [0x83, 0x04, 0x00, 0x01, 0xFC, 0x01];
342 let items: Vec<_> = parse_loop(&bytes).collect();
343 assert_eq!(items.len(), 1);
344 assert!(matches!(
345 items[0].as_ref().unwrap(),
346 AnyDescriptor::Unknown { tag: 0x83, .. }
347 ));
348 }
349}