1use std::fmt;
2
3use crate::error::{Error, Kind as ErrorKind};
4use crate::pid::PID as TsPID;
5use crate::result::Result;
6use crate::subtable_id::{SubtableID, SubtableIDer};
7
8use super::traits::*;
9
10pub struct PAT<'buf> {
14 buf: &'buf [u8],
15}
16
17impl<'buf> PAT<'buf> {
18 const HEADER_FULL_SZ: usize = HEADER_SZ + SYNTAX_SECTION_SZ;
19
20 #[inline(always)]
21 pub fn new(buf: &'buf [u8]) -> PAT<'buf> {
22 PAT { buf }
23 }
24
25 #[inline(always)]
26 pub fn try_new(buf: &'buf [u8]) -> Result<PAT<'buf>> {
27 let s = Self::new(buf);
28 s.validate()?;
29 Ok(s)
30 }
31
32 #[inline(always)]
33 pub fn validate(&self) -> Result<()> {
34 if self.buf.len() < Self::HEADER_FULL_SZ {
35 Err(Error::new(ErrorKind::Buf(
36 self.buf.len(),
37 Self::HEADER_FULL_SZ,
38 )))
39 } else {
40 Ok(())
41 }
42 }
43
44 #[inline(always)]
46 fn buf_programs(&self) -> &'buf [u8] {
47 let lft = Self::HEADER_FULL_SZ;
48 let mut rght = HEADER_SZ + (self.section_length() as usize);
49
50 if rght >= self.buf.len() {
51 rght = self.buf.len();
52 }
53
54 rght -= CRC32_SZ;
55
56 &self.buf[lft..rght]
57 }
58
59 #[inline(always)]
60 pub fn programs(&self) -> Cursor<'buf, Program> {
61 Cursor::new(self.buf_programs())
62 }
63
64 pub fn first_program_map_pid(&self) -> Option<u16> {
65 self.programs().next().and_then(|res| match res {
66 Ok(p) => match p.pid() {
67 PID::ProgramMap(v) => Some(v),
68 _ => None,
69 },
70 _ => None,
71 })
72 }
73
74 #[inline(always)]
75 pub fn transport_stream_id(&self) -> u16 {
76 self.table_id_extension()
77 }
78}
79
80impl<'buf> Bufer<'buf> for PAT<'buf> {
81 fn buf(&self) -> &'buf [u8] {
82 self.buf
83 }
84}
85
86impl<'buf> WithHeader<'buf> for PAT<'buf> {}
87impl<'buf> WithTableIDExtension<'buf> for PAT<'buf> {}
88impl<'buf> WithSyntaxSection<'buf> for PAT<'buf> {}
89impl<'buf> WithCRC32<'buf> for PAT<'buf> {}
90
91impl<'buf> fmt::Debug for PAT<'buf> {
92 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
93 write!(
94 f,
95 ":PAT (:id {:?} :transport-stream-id {})",
96 self.subtable_id(),
97 self.transport_stream_id(),
98 )?;
99
100 write!(f, "\n :programs")?;
101 for p in self.programs().filter_map(Result::ok) {
102 write!(f, "\n ")?;
103 p.fmt(f)?;
104 }
105
106 Ok(())
107 }
108}
109
110impl<'buf> SubtableIDer for PAT<'buf> {
111 #[inline(always)]
112 fn subtable_id(&self) -> SubtableID {
113 SubtableID::PAT(
114 self.table_id(),
115 self.transport_stream_id(),
116 self.version_number(),
117 )
118 }
119}
120
121#[derive(Debug)]
122pub enum PID {
123 Network(u16),
124
125 ProgramMap(u16),
126}
127
128impl PID {
129 #[inline(always)]
130 pub fn is_program_map(&self) -> bool {
131 match self {
132 PID::ProgramMap(..) => true,
133 _ => false,
134 }
135 }
136}
137
138impl From<PID> for TsPID {
139 fn from(id: PID) -> TsPID {
140 match id {
141 PID::Network(v) => TsPID::Other(v),
142 PID::ProgramMap(v) => TsPID::Other(v),
143 }
144 }
145}
146
147pub struct Program<'buf> {
148 buf: &'buf [u8],
149}
150
151impl<'buf> Program<'buf> {
152 const SZ: usize = 4;
153
154 #[inline(always)]
155 pub fn new(buf: &'buf [u8]) -> Program<'buf> {
156 Program { buf }
157 }
158
159 #[inline(always)]
160 pub fn number(&self) -> u16 {
161 (u16::from(self.buf[0]) << 8) | u16::from(self.buf[1])
162 }
163
164 #[inline(always)]
165 pub fn pid_raw(&self) -> u16 {
166 (u16::from(self.buf[2] & 0b0001_1111) << 8) | u16::from(self.buf[3])
167 }
168
169 #[inline(always)]
170 pub fn pid(&self) -> PID {
171 match self.number() {
172 0 => PID::Network(self.pid_raw()),
173 _ => PID::ProgramMap(self.pid_raw()),
174 }
175 }
176}
177
178impl<'buf> Szer for Program<'buf> {
179 #[inline(always)]
180 fn sz(&self) -> usize {
181 Program::SZ
182 }
183}
184
185impl<'buf> TryNewer<'buf> for Program<'buf> {
186 #[inline(always)]
187 fn try_new(buf: &'buf [u8]) -> Result<Program<'buf>> {
188 let p = Program::new(buf);
189 Ok(p)
190 }
191}
192
193impl<'buf> fmt::Debug for Program<'buf> {
194 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
195 write!(
196 f,
197 ":program (:number {:?} :pid {:?}/0x{:02X})",
198 self.number(),
199 self.pid(),
200 self.pid_raw(),
201 )
202 }
203}