1use crate::error::{Error, Result};
8use crate::traits::Descriptor;
9use dvb_common::{Parse, Serialize};
10
11pub const TAG: u8 = 0x83;
13const HEADER_LEN: usize = 2;
14const ENTRY_LEN: usize = 4;
15const VISIBLE_MASK: u8 = 0x80;
16const RESERVED_BITS_MASK: u8 = 0x7C;
17const LCN_HI_MASK: u8 = 0x03;
18
19#[derive(Debug, Clone, Copy, PartialEq, Eq)]
21#[cfg_attr(feature = "serde", derive(serde::Serialize))]
22pub struct LogicalChannelEntry {
23 pub service_id: u16,
25 pub visible_service: bool,
27 pub logical_channel_number: u16,
29}
30
31#[derive(Debug, Clone, PartialEq, Eq)]
33#[cfg_attr(feature = "serde", derive(serde::Serialize))]
34pub struct LogicalChannelDescriptor {
35 pub entries: Vec<LogicalChannelEntry>,
37}
38
39impl<'a> Parse<'a> for LogicalChannelDescriptor {
40 type Error = crate::error::Error;
41 fn parse(bytes: &'a [u8]) -> Result<Self> {
42 if bytes.len() < HEADER_LEN {
43 return Err(Error::BufferTooShort {
44 need: HEADER_LEN,
45 have: bytes.len(),
46 what: "LogicalChannelDescriptor header",
47 });
48 }
49 if bytes[0] != TAG {
50 return Err(Error::InvalidDescriptor {
51 tag: bytes[0],
52 reason: "unexpected tag for logical_channel_descriptor",
53 });
54 }
55 let length = bytes[1] as usize;
56 if length % ENTRY_LEN != 0 {
57 return Err(Error::InvalidDescriptor {
58 tag: TAG,
59 reason: "descriptor_length must be a multiple of 4",
60 });
61 }
62 let body_start = HEADER_LEN;
63 let body_end = body_start + length;
64 if bytes.len() < body_end {
65 return Err(Error::BufferTooShort {
66 need: body_end,
67 have: bytes.len(),
68 what: "LogicalChannelDescriptor body",
69 });
70 }
71 let mut entries = Vec::with_capacity(length / ENTRY_LEN);
72 let mut offset = body_start;
73 while offset < body_end {
74 let service_id = u16::from_be_bytes([bytes[offset], bytes[offset + 1]]);
75 let flags = bytes[offset + 2];
76 let visible_service = flags & VISIBLE_MASK != 0;
84 let lcn = (u16::from(flags & LCN_HI_MASK) << 8) | u16::from(bytes[offset + 3]);
85 entries.push(LogicalChannelEntry {
86 service_id,
87 visible_service,
88 logical_channel_number: lcn,
89 });
90 offset += ENTRY_LEN;
91 }
92 Ok(Self { entries })
93 }
94}
95
96impl Serialize for LogicalChannelDescriptor {
97 type Error = crate::error::Error;
98 fn serialized_len(&self) -> usize {
99 HEADER_LEN + ENTRY_LEN * self.entries.len()
100 }
101
102 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
103 let len = self.serialized_len();
104 if buf.len() < len {
105 return Err(Error::OutputBufferTooSmall {
106 need: len,
107 have: buf.len(),
108 });
109 }
110 buf[0] = TAG;
111 buf[1] = (len - HEADER_LEN) as u8;
112 let mut offset = HEADER_LEN;
113 for entry in &self.entries {
114 buf[offset..offset + 2].copy_from_slice(&entry.service_id.to_be_bytes());
115 let visible_byte = if entry.visible_service {
116 VISIBLE_MASK
117 } else {
118 0
119 };
120 let flags = visible_byte
121 | RESERVED_BITS_MASK
122 | ((entry.logical_channel_number >> 8) as u8 & LCN_HI_MASK);
123 buf[offset + 2] = flags;
124 buf[offset + 3] = (entry.logical_channel_number & 0xFF) as u8;
125 offset += ENTRY_LEN;
126 }
127 Ok(len)
128 }
129}
130
131impl<'a> Descriptor<'a> for LogicalChannelDescriptor {
132 const TAG: u8 = TAG;
133 fn descriptor_length(&self) -> u8 {
134 (self.serialized_len() - HEADER_LEN) as u8
135 }
136}
137
138impl<'a> crate::traits::DescriptorDef<'a> for LogicalChannelDescriptor {
139 const TAG: u8 = TAG;
140 const NAME: &'static str = "LOGICAL_CHANNEL";
141}
142
143#[cfg(test)]
144mod tests {
145 use super::*;
146
147 #[test]
148 fn parse_single_entry() {
149 let bytes = [TAG, 4, 0x00, 0x01, 0xFC, 0x05];
150 let d = LogicalChannelDescriptor::parse(&bytes).unwrap();
151 assert_eq!(d.entries.len(), 1);
152 assert_eq!(d.entries[0].service_id, 1);
153 assert!(d.entries[0].visible_service);
154 assert_eq!(d.entries[0].logical_channel_number, 5);
155 }
156
157 #[test]
158 fn parse_extracts_visible_service_false() {
159 let bytes = [TAG, 4, 0x00, 0x02, 0x7C, 0x0A];
160 let d = LogicalChannelDescriptor::parse(&bytes).unwrap();
161 assert_eq!(d.entries.len(), 1);
162 assert!(!d.entries[0].visible_service);
163 assert_eq!(d.entries[0].service_id, 2);
164 assert_eq!(d.entries[0].logical_channel_number, 10);
165 }
166
167 #[test]
168 fn parse_extracts_logical_channel_number_full_10_bit_range() {
169 let bytes = [TAG, 4, 0x00, 0x03, 0xFF, 0xFF];
170 let d = LogicalChannelDescriptor::parse(&bytes).unwrap();
171 assert_eq!(d.entries.len(), 1);
172 assert_eq!(d.entries[0].logical_channel_number, 1023);
173 assert!(d.entries[0].visible_service);
174 }
175
176 #[test]
177 fn parse_multiple_entries_preserves_order() {
178 let bytes = [
179 TAG, 12, 0x00, 0x01, 0xFC, 0x01, 0x00, 0x02, 0xFC, 0x02, 0x00, 0x03, 0xFC, 0x03,
180 ];
181 let d = LogicalChannelDescriptor::parse(&bytes).unwrap();
182 assert_eq!(d.entries.len(), 3);
183 assert_eq!(d.entries[0].service_id, 1);
184 assert_eq!(d.entries[0].logical_channel_number, 1);
185 assert_eq!(d.entries[1].service_id, 2);
186 assert_eq!(d.entries[1].logical_channel_number, 2);
187 assert_eq!(d.entries[2].service_id, 3);
188 assert_eq!(d.entries[2].logical_channel_number, 3);
189 }
190
191 #[test]
192 fn parse_rejects_wrong_tag() {
193 let err = LogicalChannelDescriptor::parse(&[0x84, 4, 0x00, 0x01, 0xFC, 0x05]).unwrap_err();
194 assert!(matches!(err, Error::InvalidDescriptor { tag: 0x84, .. }));
195 }
196
197 #[test]
198 fn parse_rejects_length_not_multiple_of_4() {
199 let bytes = [TAG, 5, 0x00, 0x01, 0xFC, 0x05, 0xFF];
200 let err = LogicalChannelDescriptor::parse(&bytes).unwrap_err();
201 assert!(matches!(err, Error::InvalidDescriptor { tag: TAG, .. }));
202 }
203
204 #[test]
205 fn parse_tolerates_cleared_reserved_bits() {
206 let bytes = [TAG, 4, 0x00, 0x01, 0x00, 0x05];
215 let d = LogicalChannelDescriptor::parse(&bytes).expect("tolerant parse");
216 assert_eq!(d.entries.len(), 1);
217 assert_eq!(d.entries[0].service_id, 1);
218 assert_eq!(d.entries[0].logical_channel_number, 5);
219 assert!(!d.entries[0].visible_service);
220 }
221
222 #[test]
223 fn empty_descriptor_valid() {
224 let bytes = [TAG, 0];
225 let d = LogicalChannelDescriptor::parse(&bytes).unwrap();
226 assert!(d.entries.is_empty());
227 }
228
229 #[test]
230 fn serialize_round_trip() {
231 let d = LogicalChannelDescriptor {
232 entries: vec![
233 LogicalChannelEntry {
234 service_id: 1,
235 visible_service: true,
236 logical_channel_number: 5,
237 },
238 LogicalChannelEntry {
239 service_id: 0x0102,
240 visible_service: false,
241 logical_channel_number: 1023,
242 },
243 ],
244 };
245 let mut buf = vec![0u8; d.serialized_len()];
246 d.serialize_into(&mut buf).unwrap();
247 let re = LogicalChannelDescriptor::parse(&buf).unwrap();
248 assert_eq!(d, re);
249 }
250}