dvb_si/descriptors/
pdc.rs1use crate::error::{Error, Result};
9use crate::traits::Descriptor;
10use dvb_common::{Parse, Serialize};
11
12pub const TAG: u8 = 0x69;
14pub const HEADER_LEN: usize = 2;
16pub const BODY_LEN: usize = 3;
18pub const PIL_MASK: u32 = 0x000F_FFFF;
20pub const RESERVED_BITS: u32 = 0x00F0_0000;
23
24#[derive(Debug, Clone, Copy, PartialEq, Eq)]
26#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
27pub struct PdcDescriptor {
28 pub programme_identification_label: u32,
30}
31
32impl<'a> Parse<'a> for PdcDescriptor {
33 type Error = crate::error::Error;
34 fn parse(bytes: &'a [u8]) -> Result<Self> {
35 if bytes.len() < HEADER_LEN {
36 return Err(Error::BufferTooShort {
37 need: HEADER_LEN,
38 have: bytes.len(),
39 what: "PdcDescriptor header",
40 });
41 }
42 if bytes[0] != TAG {
43 return Err(Error::InvalidDescriptor {
44 tag: bytes[0],
45 reason: "unexpected tag for PDC_descriptor",
46 });
47 }
48 let length = bytes[1] as usize;
49 if length != BODY_LEN {
50 return Err(Error::InvalidDescriptor {
51 tag: TAG,
52 reason: "PDC_descriptor length must be exactly 3",
53 });
54 }
55 let end = HEADER_LEN + length;
56 if bytes.len() < end {
57 return Err(Error::BufferTooShort {
58 need: end,
59 have: bytes.len(),
60 what: "PdcDescriptor body",
61 });
62 }
63 let raw = (u32::from(bytes[HEADER_LEN]) << 16)
65 | (u32::from(bytes[HEADER_LEN + 1]) << 8)
66 | u32::from(bytes[HEADER_LEN + 2]);
67 Ok(Self {
68 programme_identification_label: raw & PIL_MASK,
69 })
70 }
71}
72
73impl Serialize for PdcDescriptor {
74 type Error = crate::error::Error;
75 fn serialized_len(&self) -> usize {
76 HEADER_LEN + BODY_LEN
77 }
78
79 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
80 if self.programme_identification_label > PIL_MASK {
81 return Err(Error::InvalidDescriptor {
82 tag: TAG,
83 reason: "programme_identification_label exceeds 20 bits",
84 });
85 }
86 let len = self.serialized_len();
87 if buf.len() < len {
88 return Err(Error::OutputBufferTooSmall {
89 need: len,
90 have: buf.len(),
91 });
92 }
93 buf[0] = TAG;
94 buf[1] = BODY_LEN as u8;
95 let raw = RESERVED_BITS | (self.programme_identification_label & PIL_MASK);
97 buf[HEADER_LEN] = (raw >> 16) as u8;
98 buf[HEADER_LEN + 1] = (raw >> 8) as u8;
99 buf[HEADER_LEN + 2] = raw as u8;
100 Ok(len)
101 }
102}
103
104impl<'a> Descriptor<'a> for PdcDescriptor {
105 const TAG: u8 = TAG;
106 fn descriptor_length(&self) -> u8 {
107 BODY_LEN as u8
108 }
109}
110
111impl<'a> crate::traits::DescriptorDef<'a> for PdcDescriptor {
112 const TAG: u8 = TAG;
113 const NAME: &'static str = "PDC";
114}
115
116#[cfg(test)]
117mod tests {
118 use super::*;
119
120 #[test]
121 fn parse_extracts_pil() {
122 let bytes = [TAG, 3, 0x0A, 0xBC, 0xDE];
124 let d = PdcDescriptor::parse(&bytes).unwrap();
125 assert_eq!(d.programme_identification_label, 0x0A_BCDE);
126 }
127
128 #[test]
129 fn parse_ignores_reserved_bits() {
130 let bytes = [TAG, 3, 0xFA, 0xBC, 0xDE];
132 let d = PdcDescriptor::parse(&bytes).unwrap();
133 assert_eq!(d.programme_identification_label, 0x0A_BCDE);
134 }
135
136 #[test]
137 fn parse_rejects_wrong_tag() {
138 assert!(matches!(
139 PdcDescriptor::parse(&[0x6A, 3, 0, 0, 0]).unwrap_err(),
140 Error::InvalidDescriptor { tag: 0x6A, .. }
141 ));
142 }
143
144 #[test]
145 fn parse_rejects_wrong_length() {
146 assert!(matches!(
147 PdcDescriptor::parse(&[TAG, 2, 0, 0]).unwrap_err(),
148 Error::InvalidDescriptor { tag: TAG, .. }
149 ));
150 }
151
152 #[test]
153 fn parse_rejects_short_body() {
154 assert!(matches!(
155 PdcDescriptor::parse(&[TAG, 3, 0, 0]).unwrap_err(),
156 Error::BufferTooShort { .. }
157 ));
158 }
159
160 #[test]
161 fn serialize_round_trip() {
162 let d = PdcDescriptor {
163 programme_identification_label: 0x0A_BCDE,
164 };
165 let mut buf = vec![0u8; d.serialized_len()];
166 d.serialize_into(&mut buf).unwrap();
167 assert_eq!(buf, [TAG, 3, 0xFA, 0xBC, 0xDE]);
169 assert_eq!(PdcDescriptor::parse(&buf).unwrap(), d);
170 }
171
172 #[test]
173 fn serialize_rejects_too_small_buffer() {
174 let d = PdcDescriptor {
175 programme_identification_label: 0,
176 };
177 let mut buf = vec![0u8; 2];
178 assert!(matches!(
179 d.serialize_into(&mut buf).unwrap_err(),
180 Error::OutputBufferTooSmall { .. }
181 ));
182 }
183
184 #[test]
185 fn serialize_rejects_over_range_pil() {
186 let d = PdcDescriptor {
187 programme_identification_label: 0x10_0000, };
189 let mut buf = vec![0u8; d.serialized_len()];
190 assert!(matches!(
191 d.serialize_into(&mut buf).unwrap_err(),
192 Error::InvalidDescriptor { tag: TAG, .. }
193 ));
194 }
195
196 #[cfg(feature = "serde")]
197 #[test]
198 fn serde_round_trip() {
199 let d = PdcDescriptor {
200 programme_identification_label: 0x0A_BCDE,
201 };
202 let json = serde_json::to_string(&d).unwrap();
203 let back: PdcDescriptor = serde_json::from_str(&json).unwrap();
204 assert_eq!(back, d);
205 }
206}