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