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