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}