1pub mod packet_type;
24pub use packet_type::*;
25
26pub mod pixel_config;
27pub use pixel_config::{DataType, PixelConfig, PixelFormat};
28
29pub mod id;
30pub use id::ID;
31
32pub mod message;
33
34pub mod timecode;
35use timecode::TimeCode;
36
37#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy, Default)]
61pub struct Header {
62 pub packet_type: PacketType,
64
65 pub sequence_number: u8,
67
68 pub pixel_config: PixelConfig,
70
71 pub id: ID,
73
74 pub offset: u32,
76
77 pub length: u16,
79
80 pub time_code: TimeCode,
82}
83
84impl Into<[u8; 10]> for Header {
85 fn into(self) -> [u8; 10] {
86 let mut buffer: [u8; 10] = [0u8; 10];
88
89 let packet_type_byte: u8 = self.packet_type.into();
92 buffer[0] = packet_type_byte;
93
94 buffer[1] = self.sequence_number;
96
97 buffer[2] = self.pixel_config.into();
99
100 buffer[3] = self.id.into();
102
103 let offset_bytes = self.offset.to_be_bytes();
105 buffer[4..8].copy_from_slice(&offset_bytes);
106
107 let length_bytes = self.length.to_be_bytes();
109 buffer[8..10].copy_from_slice(&length_bytes);
110
111 buffer
113 }
114}
115impl Into<[u8; 14]> for Header {
116 fn into(self) -> [u8; 14] {
117 let mut buffer = [0u8; 14];
119
120 let packet_type_byte: u8 = self.packet_type.into();
123 buffer[0] = packet_type_byte;
124
125 buffer[1] = self.sequence_number;
127
128 buffer[2] = self.pixel_config.into();
130
131 buffer[3] = self.id.into();
133
134 let offset_bytes: [u8; 4] = self.offset.to_be_bytes();
136 buffer[4..8].copy_from_slice(&offset_bytes);
137
138 let length_bytes: [u8; 2] = self.length.to_be_bytes();
140 buffer[8..10].copy_from_slice(&length_bytes);
141
142 let time_code: [u8; 4] = self.time_code.to_bytes();
143 buffer[10..14].copy_from_slice(&time_code);
144
145 buffer
147 }
148}
149
150impl<'a> From<&'a [u8]> for Header {
151 fn from(bytes: &'a [u8]) -> Self {
152 let packet_type = PacketType::from(bytes[0]);
154
155 let sequence_number = bytes[1];
157
158 let pixel_config = PixelConfig::from(bytes[2]);
160
161 let id = ID::from(bytes[3]);
163
164 let offset = u32::from_be_bytes([bytes[4], bytes[5], bytes[6], bytes[7]]);
166
167 let length = u16::from_be_bytes([bytes[8], bytes[9]]);
169
170 if packet_type.timecode && bytes.len() >= 14 {
171 let time_code = TimeCode::from_4_bytes([bytes[10], bytes[11], bytes[12], bytes[13]]);
172
173 Header {
174 packet_type,
175 sequence_number,
176 pixel_config,
177 id,
178 offset,
179 length,
180 time_code,
181 }
182 } else {
183 Header {
184 packet_type,
185 sequence_number,
186 pixel_config,
187 id,
188 offset,
189 length,
190 time_code: TimeCode(None),
191 }
192 }
193 }
194}
195
196#[cfg(test)]
197mod tests {
198 use super::*;
199
200 #[test]
201 fn test_parsing() {
202 {
204 let data: [u8; 10] = [65, 6, 10, 1, 0, 0, 0, 0, 0, 3];
205 let header = Header::from(&data[..]);
206
207 assert_eq!(
208 header.packet_type,
209 PacketType {
210 version: 1,
211 timecode: false,
212 storage: false,
213 reply: false,
214 query: false,
215 push: true
216 }
217 );
218 assert_eq!(header.sequence_number, 6);
219 assert_eq!(header.length, 3);
220 assert_eq!(header.offset, 0);
221 }
222
223 {
225 let data: [u8; 10] = [255, 12, 13, 1, 0, 0, 0x99, 0xd5, 0x01, 0x19];
226 let header = Header::from(&data[..]);
227
228 assert_eq!(
229 header.packet_type,
230 PacketType {
231 version: 3,
232 timecode: true,
233 storage: true,
234 reply: true,
235 query: true,
236 push: true
237 }
238 );
239
240 assert_eq!(header.sequence_number, 12);
241 assert_eq!(
242 header.pixel_config,
243 PixelConfig {
244 data_type: pixel_config::DataType::RGB,
245 data_size: PixelFormat::Pixel24Bits,
246 customer_defined: false
247 }
248 );
249 assert_eq!(header.length, 281);
250 assert_eq!(header.offset, 39381);
251 }
252 }
253
254 use proptest::prelude::*;
256
257 proptest! {
258 #[test]
259 fn test_header_10_byte_roundtrip(
260 packet_type_byte in any::<u8>(),
261 seq_num in any::<u8>(),
262 pixel_config in any::<u8>(),
263 id in any::<u8>(),
264 offset in any::<u32>(),
265 length in any::<u16>(),
266 ) {
267 let mut bytes = vec![packet_type_byte, seq_num, pixel_config, id];
269 bytes.extend_from_slice(&offset.to_be_bytes());
270 bytes.extend_from_slice(&length.to_be_bytes());
271
272 let header = Header::from(&bytes[..]);
274
275 let roundtrip_bytes: [u8; 10] = header.into();
277
278 prop_assert_eq!(header.sequence_number, seq_num);
280 prop_assert_eq!(header.offset, offset);
281 prop_assert_eq!(header.length, length);
282
283 let roundtrip_header = Header::from(&roundtrip_bytes[..]);
285 prop_assert_eq!(header.sequence_number, roundtrip_header.sequence_number);
286 prop_assert_eq!(header.offset, roundtrip_header.offset);
287 prop_assert_eq!(header.length, roundtrip_header.length);
288 }
289
290 #[test]
291 fn test_header_14_byte_with_timecode_roundtrip(
292 seq_num in any::<u8>(),
293 pixel_config in any::<u8>(),
294 id in any::<u8>(),
295 offset in any::<u32>(),
296 length in any::<u16>(),
297 timecode in any::<u32>(),
298 ) {
299 let packet_type_byte = 0b01010000u8; let mut bytes = vec![packet_type_byte, seq_num, pixel_config, id];
302 bytes.extend_from_slice(&offset.to_be_bytes());
303 bytes.extend_from_slice(&length.to_be_bytes());
304 bytes.extend_from_slice(&timecode.to_be_bytes());
305
306 let header = Header::from(&bytes[..]);
308
309 prop_assert_eq!(header.time_code.0, Some(timecode));
311 prop_assert_eq!(header.sequence_number, seq_num);
312 prop_assert_eq!(header.offset, offset);
313 prop_assert_eq!(header.length, length);
314 prop_assert!(header.packet_type.timecode);
315
316 let roundtrip_bytes: [u8; 14] = header.into();
318
319 let roundtrip_header = Header::from(&roundtrip_bytes[..]);
321 prop_assert_eq!(header.time_code, roundtrip_header.time_code);
322 prop_assert_eq!(header.sequence_number, roundtrip_header.sequence_number);
323 }
324
325 #[test]
326 fn test_header_parsing_never_panics(
327 bytes in prop::collection::vec(any::<u8>(), 10..20)
328 ) {
329 let _ = Header::from(&bytes[..]);
331 }
332
333 #[test]
334 fn test_header_offset_range(
335 offset in 0u32..=0xFFFFFFFF,
336 ) {
337 let mut header = Header::default();
338 header.offset = offset;
339
340 let bytes: [u8; 10] = header.into();
341 let parsed = Header::from(&bytes[..]);
342
343 prop_assert_eq!(parsed.offset, offset);
344 }
345
346 #[test]
347 fn test_header_length_range(
348 length in 0u16..=1500,
349 ) {
350 let mut header = Header::default();
351 header.length = length;
352
353 let bytes: [u8; 10] = header.into();
354 let parsed = Header::from(&bytes[..]);
355
356 prop_assert_eq!(parsed.length, length);
357 }
358 }
359}