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