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
29 NetworkInformationActual = 0x40,
31 NetworkInformationOther = 0x41,
32 ServiceDescriptionActual = 0x42,
33 ServiceDescriptionOther = 0x46,
34 BouquetAssociation = 0x4A,
35 UpdateNotification = 0x4B,
36 IpMacNotification = 0x4C,
37 SatelliteAccess = 0x4D,
38 EventInformationPfActual = 0x4E,
39 EventInformationPfOther = 0x4F,
40
41 TimeAndDate = 0x70,
45 RunningStatus = 0x71,
46 Stuffing = 0x72,
47 TimeOffset = 0x73,
48 ApplicationInformation = 0x74,
49 Container = 0x75,
50 RelatedContent = 0x76,
51 ContentIdentifier = 0x77,
52 MpeFec = 0x78,
53 ResolutionNotification = 0x79,
54 MpeIfec = 0x7A,
55 ProtectionMessage = 0x7B,
56 DownloadableFontInfo = 0x7C,
57 DiscontinuityInformation = 0x7E,
58 SelectionInformation = 0x7F,
59}
60
61impl TableId {
62 #[must_use]
65 pub const fn eit_schedule_actual_segment(v: u8) -> Option<u8> {
66 if v >= 0x50 && v <= 0x5F {
67 Some(v - 0x50)
68 } else {
69 None
70 }
71 }
72
73 #[must_use]
76 pub const fn eit_schedule_other_segment(v: u8) -> Option<u8> {
77 if v >= 0x60 && v <= 0x6F {
78 Some(v - 0x60)
79 } else {
80 None
81 }
82 }
83}
84
85#[cfg(test)]
86mod tests {
87 use super::*;
88
89 #[test]
90 fn known_values_round_trip() {
91 for id in [
92 TableId::Pat,
93 TableId::NetworkInformationActual,
94 TableId::ServiceDescriptionActual,
95 TableId::EventInformationPfActual,
96 TableId::TimeAndDate,
97 TableId::SelectionInformation,
98 ] {
99 let byte = id as u8;
100 assert_eq!(TableId::try_from(byte), Ok(id));
101 }
102 }
103
104 #[test]
105 fn eit_schedule_actual_segment_range() {
106 assert_eq!(TableId::eit_schedule_actual_segment(0x4F), None);
107 assert_eq!(TableId::eit_schedule_actual_segment(0x50), Some(0));
108 assert_eq!(TableId::eit_schedule_actual_segment(0x5F), Some(0x0F));
109 assert_eq!(TableId::eit_schedule_actual_segment(0x60), None);
110 }
111
112 #[test]
113 fn eit_schedule_other_segment_range() {
114 assert_eq!(TableId::eit_schedule_other_segment(0x5F), None);
115 assert_eq!(TableId::eit_schedule_other_segment(0x60), Some(0));
116 assert_eq!(TableId::eit_schedule_other_segment(0x6F), Some(0x0F));
117 assert_eq!(TableId::eit_schedule_other_segment(0x70), None);
118 }
119
120 #[test]
121 fn unknown_value_rejected() {
122 assert!(TableId::try_from(0x99).is_err());
123 }
124
125 #[test]
126 fn exhaustive_byte_sweep() {
127 let mut matched = 0u16;
128 for byte in 0u8..=0xFF {
129 if let Ok(id) = TableId::try_from(byte) {
130 assert_eq!(id as u8, byte, "round-trip failed for {byte:#04x}");
131 matched += 1;
132 }
133 }
134 assert_eq!(matched, 29, "expected 29 matched variants");
136 }
137}