1use crate::error::{Error, Result};
7use crate::traits::Descriptor;
8use dvb_common::{Parse, Serialize};
9
10pub const TAG: u8 = 0x4A;
12const HEADER_LEN: usize = 2;
13const FIXED_FIELDS_LEN: usize = 7;
14
15#[derive(Debug, Clone, PartialEq, Eq)]
17#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
18pub struct LinkageDescriptor<'a> {
19 pub transport_stream_id: u16,
21 pub original_network_id: u16,
23 pub service_id: u16,
26 pub linkage_type: u8,
30 #[cfg_attr(feature = "serde", serde(borrow))]
32 pub private_data: &'a [u8],
33}
34
35impl<'a> Parse<'a> for LinkageDescriptor<'a> {
36 type Error = crate::error::Error;
37 fn parse(bytes: &'a [u8]) -> Result<Self> {
38 if bytes.len() < HEADER_LEN {
39 return Err(Error::BufferTooShort {
40 need: HEADER_LEN,
41 have: bytes.len(),
42 what: "LinkageDescriptor header",
43 });
44 }
45 if bytes[0] != TAG {
46 return Err(Error::InvalidDescriptor {
47 tag: bytes[0],
48 reason: "unexpected tag for linkage_descriptor",
49 });
50 }
51 let length = bytes[1] as usize;
52 let end = HEADER_LEN + length;
53 if bytes.len() < end {
54 return Err(Error::BufferTooShort {
55 need: end,
56 have: bytes.len(),
57 what: "LinkageDescriptor body",
58 });
59 }
60 if length < FIXED_FIELDS_LEN {
61 return Err(Error::InvalidDescriptor {
62 tag: TAG,
63 reason: "linkage_descriptor body shorter than minimum 7 bytes",
64 });
65 }
66 let body_start = HEADER_LEN;
67 let transport_stream_id = u16::from_be_bytes([bytes[body_start], bytes[body_start + 1]]);
68 let original_network_id =
69 u16::from_be_bytes([bytes[body_start + 2], bytes[body_start + 3]]);
70 let service_id = u16::from_be_bytes([bytes[body_start + 4], bytes[body_start + 5]]);
71 let linkage_type = bytes[body_start + 6];
72 let private_data = &bytes[body_start + FIXED_FIELDS_LEN..end];
73 Ok(Self {
74 transport_stream_id,
75 original_network_id,
76 service_id,
77 linkage_type,
78 private_data,
79 })
80 }
81}
82
83impl Serialize for LinkageDescriptor<'_> {
84 type Error = crate::error::Error;
85 fn serialized_len(&self) -> usize {
86 HEADER_LEN + FIXED_FIELDS_LEN + self.private_data.len()
87 }
88
89 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
90 let len = self.serialized_len();
91 if buf.len() < len {
92 return Err(Error::OutputBufferTooSmall {
93 need: len,
94 have: buf.len(),
95 });
96 }
97 buf[0] = TAG;
98 buf[1] = (FIXED_FIELDS_LEN + self.private_data.len()) as u8;
99 let body_start = HEADER_LEN;
100 buf[body_start..body_start + 2].copy_from_slice(&self.transport_stream_id.to_be_bytes());
101 buf[body_start + 2..body_start + 4]
102 .copy_from_slice(&self.original_network_id.to_be_bytes());
103 buf[body_start + 4..body_start + 6].copy_from_slice(&self.service_id.to_be_bytes());
104 buf[body_start + 6] = self.linkage_type;
105 if !self.private_data.is_empty() {
106 let private_start = body_start + FIXED_FIELDS_LEN;
107 buf[private_start..private_start + self.private_data.len()]
108 .copy_from_slice(self.private_data);
109 }
110 Ok(len)
111 }
112}
113
114impl<'a> Descriptor<'a> for LinkageDescriptor<'a> {
115 const TAG: u8 = TAG;
116
117 fn descriptor_length(&self) -> u8 {
118 (FIXED_FIELDS_LEN + self.private_data.len()) as u8
119 }
120}
121
122impl<'a> crate::traits::DescriptorDef<'a> for LinkageDescriptor<'a> {
123 const TAG: u8 = TAG;
124 const NAME: &'static str = "LINKAGE";
125}
126
127#[cfg(test)]
128mod tests {
129 use super::*;
130
131 #[test]
132 fn parse_extracts_tsid_onid_sid() {
133 let bytes = [
134 TAG, 0x09, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x05, 0xAA, 0xBB,
135 ];
136 let d = LinkageDescriptor::parse(&bytes).unwrap();
137 assert_eq!(d.transport_stream_id, 0x0001);
138 assert_eq!(d.original_network_id, 0x0002);
139 assert_eq!(d.service_id, 0x0003);
140 }
141
142 #[test]
143 fn parse_extracts_linkage_type() {
144 let bytes = [TAG, 0x07, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x06];
145 let d = LinkageDescriptor::parse(&bytes).unwrap();
146 assert_eq!(d.linkage_type, 0x06);
147 }
148
149 #[test]
150 fn parse_preserves_raw_private_data() {
151 let bytes = [
152 TAG, 0x0A, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x05, 0xAA, 0xBB, 0xCC,
153 ];
154 let d = LinkageDescriptor::parse(&bytes).unwrap();
155 assert_eq!(d.private_data, &[0xAA, 0xBB, 0xCC]);
156 }
157
158 #[test]
159 fn parse_accepts_empty_private_data() {
160 let bytes = [TAG, 0x07, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x05];
161 let d = LinkageDescriptor::parse(&bytes).unwrap();
162 assert!(d.private_data.is_empty());
163 }
164
165 #[test]
166 fn parse_rejects_wrong_tag() {
167 let err = LinkageDescriptor::parse(&[0x4B, 0x07, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x05])
168 .unwrap_err();
169 assert!(matches!(err, Error::InvalidDescriptor { tag: 0x4B, .. }));
170 }
171
172 #[test]
173 fn parse_rejects_body_shorter_than_seven() {
174 let bytes = [TAG, 0x05, 0x00, 0x01, 0x00, 0x02, 0x00];
175 let err = LinkageDescriptor::parse(&bytes).unwrap_err();
176 assert!(matches!(err, Error::InvalidDescriptor { tag: TAG, .. }));
177 }
178
179 #[test]
180 fn parse_rejects_truncated_buffer() {
181 let err = LinkageDescriptor::parse(&[TAG]).unwrap_err();
182 assert!(matches!(err, Error::BufferTooShort { .. }));
183 }
184
185 #[test]
186 fn serialize_round_trip_no_private_data() {
187 let d = LinkageDescriptor {
188 transport_stream_id: 0x1234,
189 original_network_id: 0x5678,
190 service_id: 0xABCD,
191 linkage_type: 0x02,
192 private_data: &[],
193 };
194 let mut buf = vec![0u8; d.serialized_len()];
195 d.serialize_into(&mut buf).unwrap();
196 let re = LinkageDescriptor::parse(&buf).unwrap();
197 assert_eq!(d, re);
198 }
199
200 #[test]
201 fn serialize_round_trip_with_private_data() {
202 let private = [0xDE, 0xAD, 0xBE, 0xEF];
203 let d = LinkageDescriptor {
204 transport_stream_id: 0x0001,
205 original_network_id: 0x0002,
206 service_id: 0x0003,
207 linkage_type: 0x05,
208 private_data: &private,
209 };
210 let mut buf = vec![0u8; d.serialized_len()];
211 d.serialize_into(&mut buf).unwrap();
212 let re = LinkageDescriptor::parse(&buf).unwrap();
213 assert_eq!(d, re);
214 }
215}