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