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