1use super::descriptor_body;
8use crate::error::{Error, Result};
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 let body = descriptor_body(
43 bytes,
44 TAG,
45 "LogicalChannelDescriptor",
46 "unexpected tag for logical_channel_descriptor",
47 )?;
48 if body.len() % ENTRY_LEN != 0 {
49 return Err(Error::InvalidDescriptor {
50 tag: TAG,
51 reason: "descriptor_length must be a multiple of 4",
52 });
53 }
54 let mut entries = Vec::with_capacity(body.len() / ENTRY_LEN);
55 let mut offset = 0;
56 while offset < body.len() {
57 let service_id = u16::from_be_bytes([body[offset], body[offset + 1]]);
58 let flags = body[offset + 2];
59 let visible_service = flags & VISIBLE_MASK != 0;
60 let lcn = (u16::from(flags & LCN_HI_MASK) << 8) | u16::from(body[offset + 3]);
61 entries.push(LogicalChannelEntry {
62 service_id,
63 visible_service,
64 logical_channel_number: lcn,
65 });
66 offset += ENTRY_LEN;
67 }
68 Ok(Self { entries })
69 }
70}
71
72impl Serialize for LogicalChannelDescriptor {
73 type Error = crate::error::Error;
74 fn serialized_len(&self) -> usize {
75 HEADER_LEN + ENTRY_LEN * self.entries.len()
76 }
77
78 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
79 let len = self.serialized_len();
80 if buf.len() < len {
81 return Err(Error::OutputBufferTooSmall {
82 need: len,
83 have: buf.len(),
84 });
85 }
86 buf[0] = TAG;
87 buf[1] = (len - HEADER_LEN) as u8;
88 let mut offset = HEADER_LEN;
89 for entry in &self.entries {
90 buf[offset..offset + 2].copy_from_slice(&entry.service_id.to_be_bytes());
91 let visible_byte = if entry.visible_service {
92 VISIBLE_MASK
93 } else {
94 0
95 };
96 let flags = visible_byte
97 | RESERVED_BITS_MASK
98 | ((entry.logical_channel_number >> 8) as u8 & LCN_HI_MASK);
99 buf[offset + 2] = flags;
100 buf[offset + 3] = (entry.logical_channel_number & 0xFF) as u8;
101 offset += ENTRY_LEN;
102 }
103 Ok(len)
104 }
105}
106impl<'a> crate::traits::DescriptorDef<'a> for LogicalChannelDescriptor {
107 const TAG: u8 = TAG;
108 const NAME: &'static str = "LOGICAL_CHANNEL";
109}
110
111#[cfg(test)]
112mod tests {
113 use super::*;
114
115 #[test]
116 fn parse_single_entry() {
117 let bytes = [TAG, 4, 0x00, 0x01, 0xFC, 0x05];
118 let d = LogicalChannelDescriptor::parse(&bytes).unwrap();
119 assert_eq!(d.entries.len(), 1);
120 assert_eq!(d.entries[0].service_id, 1);
121 assert!(d.entries[0].visible_service);
122 assert_eq!(d.entries[0].logical_channel_number, 5);
123 }
124
125 #[test]
126 fn parse_extracts_visible_service_false() {
127 let bytes = [TAG, 4, 0x00, 0x02, 0x7C, 0x0A];
128 let d = LogicalChannelDescriptor::parse(&bytes).unwrap();
129 assert_eq!(d.entries.len(), 1);
130 assert!(!d.entries[0].visible_service);
131 assert_eq!(d.entries[0].service_id, 2);
132 assert_eq!(d.entries[0].logical_channel_number, 10);
133 }
134
135 #[test]
136 fn parse_extracts_logical_channel_number_full_10_bit_range() {
137 let bytes = [TAG, 4, 0x00, 0x03, 0xFF, 0xFF];
138 let d = LogicalChannelDescriptor::parse(&bytes).unwrap();
139 assert_eq!(d.entries.len(), 1);
140 assert_eq!(d.entries[0].logical_channel_number, 1023);
141 assert!(d.entries[0].visible_service);
142 }
143
144 #[test]
145 fn parse_multiple_entries_preserves_order() {
146 let bytes = [
147 TAG, 12, 0x00, 0x01, 0xFC, 0x01, 0x00, 0x02, 0xFC, 0x02, 0x00, 0x03, 0xFC, 0x03,
148 ];
149 let d = LogicalChannelDescriptor::parse(&bytes).unwrap();
150 assert_eq!(d.entries.len(), 3);
151 assert_eq!(d.entries[0].service_id, 1);
152 assert_eq!(d.entries[0].logical_channel_number, 1);
153 assert_eq!(d.entries[1].service_id, 2);
154 assert_eq!(d.entries[1].logical_channel_number, 2);
155 assert_eq!(d.entries[2].service_id, 3);
156 assert_eq!(d.entries[2].logical_channel_number, 3);
157 }
158
159 #[test]
160 fn parse_rejects_wrong_tag() {
161 let err = LogicalChannelDescriptor::parse(&[0x84, 4, 0x00, 0x01, 0xFC, 0x05]).unwrap_err();
162 assert!(matches!(err, Error::InvalidDescriptor { tag: 0x84, .. }));
163 }
164
165 #[test]
166 fn parse_rejects_length_not_multiple_of_4() {
167 let bytes = [TAG, 5, 0x00, 0x01, 0xFC, 0x05, 0xFF];
168 let err = LogicalChannelDescriptor::parse(&bytes).unwrap_err();
169 assert!(matches!(err, Error::InvalidDescriptor { tag: TAG, .. }));
170 }
171
172 #[test]
173 fn parse_tolerates_cleared_reserved_bits() {
174 let bytes = [TAG, 4, 0x00, 0x01, 0x00, 0x05];
183 let d = LogicalChannelDescriptor::parse(&bytes).expect("tolerant parse");
184 assert_eq!(d.entries.len(), 1);
185 assert_eq!(d.entries[0].service_id, 1);
186 assert_eq!(d.entries[0].logical_channel_number, 5);
187 assert!(!d.entries[0].visible_service);
188 }
189
190 #[test]
191 fn empty_descriptor_valid() {
192 let bytes = [TAG, 0];
193 let d = LogicalChannelDescriptor::parse(&bytes).unwrap();
194 assert!(d.entries.is_empty());
195 }
196
197 #[test]
198 fn serialize_round_trip() {
199 let d = LogicalChannelDescriptor {
200 entries: vec![
201 LogicalChannelEntry {
202 service_id: 1,
203 visible_service: true,
204 logical_channel_number: 5,
205 },
206 LogicalChannelEntry {
207 service_id: 0x0102,
208 visible_service: false,
209 logical_channel_number: 1023,
210 },
211 ],
212 };
213 let mut buf = vec![0u8; d.serialized_len()];
214 d.serialize_into(&mut buf).unwrap();
215 let re = LogicalChannelDescriptor::parse(&buf).unwrap();
216 assert_eq!(d, re);
217 }
218}