1use num_enum::TryFromPrimitive;
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, TryFromPrimitive)]
17#[cfg_attr(feature = "serde", derive(serde::Serialize))]
18#[repr(u8)]
19#[allow(missing_docs)]
20#[non_exhaustive]
21#[rustfmt::skip] pub enum TableId {
23 Pat = 0x00,
25 Cat = 0x01,
26 Pmt = 0x02,
27 TransportStreamDescription = 0x03,
28 Iso14496SceneDescription = 0x04,
29 Iso14496ObjectDescriptor = 0x05,
30 Metadata = 0x06,
31 Iso14496 = 0x08,
32 GreenAccessUnit = 0x09,
33
34 NetworkInformationActual = 0x40,
36 NetworkInformationOther = 0x41,
37 ServiceDescriptionActual = 0x42,
38 ServiceDescriptionOther = 0x46,
39 BouquetAssociation = 0x4A,
40 UpdateNotification = 0x4B,
41 IpMacNotification = 0x4C,
42 SatelliteAccess = 0x4D,
43 EventInformationPfActual = 0x4E,
44 EventInformationPfOther = 0x4F,
45
46 TimeAndDate = 0x70,
50 RunningStatus = 0x71,
51 Stuffing = 0x72,
52 TimeOffset = 0x73,
53 ApplicationInformation = 0x74,
54 Container = 0x75,
55 RelatedContent = 0x76,
56 ContentIdentifier = 0x77,
57 MpeFec = 0x78,
58 ResolutionNotification = 0x79,
59 MpeIfec = 0x7A,
60 ProtectionMessage = 0x7B,
61 DownloadableFontInfo = 0x7C,
62 DiscontinuityInformation = 0x7E,
63 SelectionInformation = 0x7F,
64}
65
66impl TableId {
67 #[must_use]
70 pub const fn eit_schedule_actual_segment(v: u8) -> Option<u8> {
71 if v >= 0x50 && v <= 0x5F {
72 Some(v - 0x50)
73 } else {
74 None
75 }
76 }
77
78 #[must_use]
81 pub const fn eit_schedule_other_segment(v: u8) -> Option<u8> {
82 if v >= 0x60 && v <= 0x6F {
83 Some(v - 0x60)
84 } else {
85 None
86 }
87 }
88}
89
90#[cfg(test)]
91mod tests {
92 use super::*;
93
94 #[test]
95 fn known_values_round_trip() {
96 for id in [
97 TableId::Pat,
98 TableId::NetworkInformationActual,
99 TableId::ServiceDescriptionActual,
100 TableId::EventInformationPfActual,
101 TableId::TimeAndDate,
102 TableId::SelectionInformation,
103 ] {
104 let byte = id as u8;
105 assert_eq!(TableId::try_from(byte), Ok(id));
106 }
107 }
108
109 #[test]
110 fn eit_schedule_actual_segment_range() {
111 assert_eq!(TableId::eit_schedule_actual_segment(0x4F), None);
112 assert_eq!(TableId::eit_schedule_actual_segment(0x50), Some(0));
113 assert_eq!(TableId::eit_schedule_actual_segment(0x5F), Some(0x0F));
114 assert_eq!(TableId::eit_schedule_actual_segment(0x60), None);
115 }
116
117 #[test]
118 fn eit_schedule_other_segment_range() {
119 assert_eq!(TableId::eit_schedule_other_segment(0x5F), None);
120 assert_eq!(TableId::eit_schedule_other_segment(0x60), Some(0));
121 assert_eq!(TableId::eit_schedule_other_segment(0x6F), Some(0x0F));
122 assert_eq!(TableId::eit_schedule_other_segment(0x70), None);
123 }
124
125 #[test]
126 fn unknown_value_rejected() {
127 assert!(TableId::try_from(0x99).is_err());
128 }
129
130 #[test]
131 fn exhaustive_byte_sweep() {
132 let mut matched = 0u16;
133 for byte in 0u8..=0xFF {
134 if let Ok(id) = TableId::try_from(byte) {
135 assert_eq!(id as u8, byte, "round-trip failed for {byte:#04x}");
136 matched += 1;
137 }
138 }
139 assert_eq!(matched, 34, "expected 34 matched variants");
141 }
142}