dvb_si/descriptors/
teletext.rs1use crate::error::{Error, Result};
7use crate::text::LangCode;
8use crate::traits::Descriptor;
9use dvb_common::{Parse, Serialize};
10
11pub const TAG: u8 = 0x56;
13const HEADER_LEN: usize = 2;
14const ENTRY_LEN: usize = 5;
15const LANG_LEN: usize = 3;
16
17#[derive(Debug, Clone, PartialEq, Eq)]
19#[cfg_attr(feature = "serde", derive(serde::Serialize))]
20pub struct TeletextEntry {
21 pub language_code: LangCode,
23 pub teletext_type: u8,
25 pub magazine_number: u8,
27 pub page_number: u8,
29}
30
31#[derive(Debug, Clone, PartialEq, Eq)]
33#[cfg_attr(feature = "serde", derive(serde::Serialize))]
34pub struct TeletextDescriptor {
35 pub entries: Vec<TeletextEntry>,
37}
38
39impl<'a> Parse<'a> for TeletextDescriptor {
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: "TeletextDescriptor header",
47 });
48 }
49 if bytes[0] != TAG {
50 return Err(Error::InvalidDescriptor {
51 tag: bytes[0],
52 reason: "unexpected tag for teletext_descriptor",
53 });
54 }
55 let length = bytes[1] as usize;
56 if bytes.len() < HEADER_LEN + length {
57 return Err(Error::BufferTooShort {
58 need: HEADER_LEN + length,
59 have: bytes.len(),
60 what: "TeletextDescriptor body",
61 });
62 }
63 if length % ENTRY_LEN != 0 {
64 return Err(Error::InvalidDescriptor {
65 tag: TAG,
66 reason: "teletext_descriptor length must be a multiple of 5",
67 });
68 }
69 let body = &bytes[HEADER_LEN..HEADER_LEN + length];
70 let mut entries = Vec::with_capacity(length / ENTRY_LEN);
71 for chunk in body.chunks_exact(ENTRY_LEN) {
72 let language_code = LangCode([chunk[0], chunk[1], chunk[2]]);
73 let type_and_mag = chunk[LANG_LEN];
74 let teletext_type = (type_and_mag >> 3) & 0x1F;
75 let magazine_number = type_and_mag & 0x07;
76 let page_number = chunk[LANG_LEN + 1];
77 entries.push(TeletextEntry {
78 language_code,
79 teletext_type,
80 magazine_number,
81 page_number,
82 });
83 }
84 Ok(Self { entries })
85 }
86}
87
88impl Serialize for TeletextDescriptor {
89 type Error = crate::error::Error;
90 fn serialized_len(&self) -> usize {
91 HEADER_LEN + self.entries.len() * ENTRY_LEN
92 }
93
94 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
95 let len = self.serialized_len();
96 if buf.len() < len {
97 return Err(Error::OutputBufferTooSmall {
98 need: len,
99 have: buf.len(),
100 });
101 }
102 buf[0] = TAG;
103 buf[1] = (self.entries.len() * ENTRY_LEN) as u8;
104 let mut pos = HEADER_LEN;
105 for e in &self.entries {
106 buf[pos..pos + LANG_LEN].copy_from_slice(&e.language_code.0);
107 buf[pos + LANG_LEN] = ((e.teletext_type & 0x1F) << 3) | (e.magazine_number & 0x07);
108 buf[pos + LANG_LEN + 1] = e.page_number;
109 pos += ENTRY_LEN;
110 }
111 Ok(len)
112 }
113}
114
115impl<'a> Descriptor<'a> for TeletextDescriptor {
116 const TAG: u8 = TAG;
117 fn descriptor_length(&self) -> u8 {
118 (self.entries.len() * ENTRY_LEN) as u8
119 }
120}
121
122impl<'a> crate::traits::DescriptorDef<'a> for TeletextDescriptor {
123 const TAG: u8 = TAG;
124 const NAME: &'static str = "TELETEXT";
125}
126
127#[cfg(test)]
128mod tests {
129 use super::*;
130
131 #[test]
132 fn parse_single_entry() {
133 let bytes = [TAG, 5, b'e', b'n', b'g', (1 << 3) | 2, 0x10];
135 let d = TeletextDescriptor::parse(&bytes).unwrap();
136 assert_eq!(d.entries.len(), 1);
137 assert_eq!(d.entries[0].language_code, LangCode(*b"eng"));
138 assert_eq!(d.entries[0].teletext_type, 1);
139 assert_eq!(d.entries[0].magazine_number, 2);
140 assert_eq!(d.entries[0].page_number, 0x10);
141 }
142
143 #[test]
144 fn parse_multiple_entries() {
145 let bytes = [
146 TAG,
147 10,
148 b'e',
149 b'n',
150 b'g',
151 (1 << 3) | 1,
152 0x10,
153 b'f',
154 b'r',
155 b'a',
156 (2 << 3) | 1,
157 0x20,
158 ];
159 let d = TeletextDescriptor::parse(&bytes).unwrap();
160 assert_eq!(d.entries.len(), 2);
161 assert_eq!(d.entries[1].teletext_type, 2);
162 }
163
164 #[test]
165 fn parse_rejects_wrong_tag() {
166 assert!(matches!(
167 TeletextDescriptor::parse(&[0x57, 0]).unwrap_err(),
168 Error::InvalidDescriptor { tag: 0x57, .. }
169 ));
170 }
171
172 #[test]
173 fn parse_rejects_length_not_multiple_of_5() {
174 let bytes = [TAG, 4, 0, 0, 0, 0];
175 assert!(matches!(
176 TeletextDescriptor::parse(&bytes).unwrap_err(),
177 Error::InvalidDescriptor { .. }
178 ));
179 }
180
181 #[test]
182 fn serialize_round_trip() {
183 let d = TeletextDescriptor {
184 entries: vec![TeletextEntry {
185 language_code: LangCode(*b"fra"),
186 teletext_type: 2,
187 magazine_number: 8 & 0x07,
188 page_number: 0x88,
189 }],
190 };
191 let mut buf = vec![0u8; d.serialized_len()];
192 d.serialize_into(&mut buf).unwrap();
193 assert_eq!(TeletextDescriptor::parse(&buf).unwrap(), d);
194 }
195
196 #[test]
197 fn empty_descriptor_valid() {
198 let bytes = [TAG, 0];
199 let d = TeletextDescriptor::parse(&bytes).unwrap();
200 assert_eq!(d.entries.len(), 0);
201 }
202}