1use crate::protocol::Header;
7#[cfg(feature = "std")]
8use crate::protocol::message::Message;
9#[cfg(all(feature = "alloc", not(feature = "std")))]
10use alloc::vec::Vec;
11
12#[derive(Debug, PartialEq, Eq, Clone, Copy)]
34pub struct PacketRef<'a> {
35 pub header: Header,
37
38 pub data: &'a [u8],
40}
41
42impl<'a> PacketRef<'a> {
43 pub fn from_bytes(bytes: &'a [u8]) -> Option<Self> {
48 if bytes.len() < 10 {
49 return None;
50 }
51
52 let has_timecode = (bytes[0] & 0b00010000) != 0;
54 let header_size = if has_timecode { 14 } else { 10 };
55
56 if bytes.len() < header_size {
57 return None;
58 }
59
60 Some(PacketRef {
61 header: Header::from(&bytes[0..header_size]),
62 data: &bytes[header_size..],
63 })
64 }
65}
66
67#[cfg(feature = "alloc")]
88#[derive(Debug, PartialEq, Clone)]
89pub struct Packet {
90 pub header: Header,
92
93 pub data: Vec<u8>,
95
96 #[cfg(feature = "std")]
100 pub parsed: Option<Message>,
101}
102
103#[cfg(feature = "alloc")]
104impl Packet {
105 pub fn from_data(h: Header, d: &[u8]) -> Packet {
107 Packet {
108 header: h,
109 data: d.to_vec(),
110 #[cfg(feature = "std")]
111 parsed: None,
112 }
113 }
114
115 pub fn from_bytes(bytes: &[u8]) -> Self {
144 let (header, data): (Header, &[u8]) = match PacketRef::from_bytes(bytes) {
146 Some(p) => (p.header, p.data),
147 None => (Header::default(), &[]),
149 };
150
151 Packet {
152 header,
153 data: data.to_vec(),
154 #[cfg(feature = "std")]
155 parsed: Self::parse_message(&header, data),
156 }
157 }
158
159 #[cfg(feature = "std")]
161 fn parse_message(header: &Header, data: &[u8]) -> Option<Message> {
162 if !header.packet_type.reply {
163 return None;
164 }
165
166 match match header.id {
168 crate::protocol::ID::Control => match serde_json::from_slice(data) {
169 Ok(v) => Some(Message::Control(v)),
170 Err(_) => None,
171 },
172 crate::protocol::ID::Config => match serde_json::from_slice(data) {
173 Ok(v) => Some(Message::Config(v)),
174 Err(_) => None,
175 },
176 crate::protocol::ID::Status => match serde_json::from_slice(data) {
177 Ok(v) => Some(Message::Status(v)),
178 Err(_) => None,
179 },
180 _ => None,
181 } {
182 Some(v) => Some(v),
184
185 None => match header.id {
187 crate::protocol::ID::Control
188 | crate::protocol::ID::Config
189 | crate::protocol::ID::Status => match serde_json::from_slice(data) {
190 Ok(v) => Some(Message::Parsed((header.id, v))),
192 Err(_) => match std::str::from_utf8(data) {
194 Ok(v) => Some(Message::Unparsed((header.id, v.to_string()))),
195 Err(_) => None,
197 },
198 },
199 _ => None,
200 },
201 }
202 }
203}
204
205#[cfg(test)]
206mod packet_ref_tests {
207 use super::*;
208
209 #[test]
210 fn parses_header_and_borrows_data() {
211 let bytes = [
212 0x41, 0x01, 0x0D, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0xFF, 0x00, 0x00, 0x00,
213 0xFF, 0x00,
214 ];
215 let p = PacketRef::from_bytes(&bytes).unwrap();
216 assert_eq!(p.header.sequence_number, 1);
217 assert_eq!(p.header.length, 6);
218 assert_eq!(p.data, &[0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00]);
219 }
220
221 #[test]
222 fn handles_timecode_header() {
223 let mut bytes = vec![0x51, 0x01, 0x0D, 0x01, 0, 0, 0, 0, 0, 3];
225 bytes.extend_from_slice(&[0x00, 0x00, 0x30, 0x39]); bytes.extend_from_slice(&[0xAB, 0xCD, 0xEF]); let p = PacketRef::from_bytes(&bytes).unwrap();
228 assert_eq!(p.header.time_code.0, Some(12345));
229 assert_eq!(p.data, &[0xAB, 0xCD, 0xEF]);
230 }
231
232 #[test]
233 fn too_short_returns_none() {
234 assert!(PacketRef::from_bytes(&[0u8; 4]).is_none());
235 }
236}
237
238#[cfg(all(test, feature = "std"))]
239mod tests {
240 use super::*;
241
242 #[test]
243 fn test_json() {
244 {
245 let data = vec![
246 0x44, 0x00, 0x0D, 0xFA, 0x00, 0x00, 0x00, 0x00, 0x01, 0x8E, 0x7b, 0x0a, 0x20, 0x20,
247 0x20, 0x20, 0x22, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x3a, 0x0a, 0x20, 0x20,
248 0x20, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x67,
249 0x77, 0x22, 0x3a, 0x20, 0x22, 0x61, 0x2e, 0x62, 0x2e, 0x63, 0x2e, 0x64, 0x22, 0x2c,
250 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x69, 0x70, 0x22, 0x3a,
251 0x20, 0x22, 0x61, 0x2e, 0x62, 0x2e, 0x63, 0x2e, 0x64, 0x22, 0x2c, 0x0a, 0x20, 0x20,
252 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6e, 0x6d, 0x22, 0x3a, 0x20, 0x22, 0x61,
253 0x2e, 0x62, 0x2e, 0x63, 0x2e, 0x64, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
254 0x20, 0x20, 0x20, 0x22, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x22, 0x3a, 0x0a, 0x20, 0x20,
255 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
256 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
257 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6c, 0x22, 0x3a,
258 0x20, 0x33, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
259 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x6f, 0x72, 0x74, 0x22, 0x3a, 0x20,
260 0x31, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
261 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x73, 0x73, 0x22, 0x3a, 0x20, 0x34, 0x2c, 0x0a,
262 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
263 0x20, 0x20, 0x22, 0x74, 0x73, 0x22, 0x3a, 0x20, 0x32, 0x0a, 0x20, 0x20, 0x20, 0x20,
264 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x2c, 0x0a, 0x20, 0x20, 0x20,
265 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20,
266 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
267 0x6c, 0x22, 0x3a, 0x20, 0x37, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
268 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x6f, 0x72, 0x74,
269 0x22, 0x3a, 0x20, 0x35, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
270 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x73, 0x73, 0x22, 0x3a, 0x20,
271 0x38, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
272 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x73, 0x22, 0x3a, 0x20, 0x36, 0x0a, 0x20,
273 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20,
274 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d,
275 0x0a, 0x7d,
276 ];
277 let packet = Packet::from_bytes(&data);
278
279 assert_eq!(packet.header.length, 398);
280
281 match packet.parsed {
282 Some(p) => match p {
283 Message::Config(c) => {
284 assert_eq!(c.config.gw.unwrap(), "a.b.c.d");
285 assert_eq!(c.config.nm.unwrap(), "a.b.c.d");
286 assert_eq!(c.config.ports.len(), 2);
287 }
288 _ => panic!("not the right packet parsed"),
289 },
290 None => panic!("Packet parsing failed"),
291 }
292 }
293 }
294
295 #[test]
296 fn test_untyped() {
297 {
298 let data = vec![
299 0x44, 0x00, 0x0D, 0xFA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x7B, 0x22, 0x68, 0x65,
300 0x6C, 0x6C, 0x6F, 0x22, 0x3A, 0x20, 0x22, 0x6F, 0x6B, 0x22, 0x7D,
301 ];
302 let packet = Packet::from_bytes(&data);
303
304 match packet.parsed {
305 Some(p) => match p {
306 Message::Parsed((_, p)) => {
307 assert_eq!(p["hello"], "ok");
308 }
309 _ => panic!("not the right packet parsed"),
310 },
311 None => panic!("Packet parsing failed"),
312 }
313 }
314 }
315
316 #[test]
317 fn test_unparsed() {
318 {
319 let data = vec![
320 0x44, 0x00, 0x0D, 0xFA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x53, 0x4C, 0x49, 0x43,
321 0x4B, 0x44, 0x45, 0x4E, 0x49, 0x53, 0x34, 0x30, 0x30, 0x30,
322 ];
323 let packet = Packet::from_bytes(&data);
324
325 match packet.parsed {
326 Some(p) => match p {
327 Message::Unparsed((_, p)) => {
328 assert_eq!(p, "SLICKDENIS4000");
329 }
330 _ => panic!("not the right packet parsed"),
331 },
332 None => panic!("Packet parsing failed"),
333 }
334 }
335 }
336
337 use proptest::prelude::*;
339
340 proptest! {
341 #[test]
342 fn test_packet_header_roundtrip(
343 version in 0u8..4,
344 seq_num in 0u8..=15,
345 pixel_config in 0u8..=255,
346 id in 0u8..=255,
347 offset in 0u32..1000000,
348 length in 0u16..1500,
349 ) {
350 let mut packet_bytes = vec![
352 (version << 6) | 0b00000001, seq_num,
354 pixel_config,
355 id,
356 ];
357 packet_bytes.extend_from_slice(&offset.to_be_bytes());
358 packet_bytes.extend_from_slice(&length.to_be_bytes());
359
360 let data = vec![0u8; length.min(100) as usize];
362 packet_bytes.extend_from_slice(&data);
363
364 let packet = Packet::from_bytes(&packet_bytes);
366
367 prop_assert_eq!(packet.header.sequence_number, seq_num);
369 prop_assert_eq!(packet.header.offset, offset);
370 prop_assert_eq!(packet.header.length, length);
371 }
372
373 #[test]
374 fn test_packet_with_arbitrary_data(
375 data_len in 0usize..500,
376 seq_num in 1u8..=15,
377 ) {
378 let data: Vec<u8> = (0..data_len).map(|i| (i % 256) as u8).collect();
380
381 let mut packet_bytes = vec![
383 0x41, seq_num,
385 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, ];
389 let length = data.len() as u16;
390 packet_bytes.extend_from_slice(&length.to_be_bytes());
391 packet_bytes.extend_from_slice(&data);
392
393 let packet = Packet::from_bytes(&packet_bytes);
395
396 prop_assert_eq!(packet.data, data);
398 prop_assert_eq!(packet.header.sequence_number, seq_num);
399 }
400
401 #[test]
402 fn test_packet_parsing_never_panics(
403 bytes in prop::collection::vec(any::<u8>(), 10..1500)
404 ) {
405 let _ = Packet::from_bytes(&bytes);
408 }
409
410 #[test]
411 fn test_packet_with_timecode_roundtrip(
412 timecode in any::<u32>(),
413 seq_num in 1u8..=15,
414 data_len in 0usize..100,
415 ) {
416 let mut packet_bytes = vec![
418 0x51, seq_num,
420 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, ];
424
425 let data: Vec<u8> = (0..data_len).map(|i| (i % 256) as u8).collect();
426 let length = data.len() as u16;
427 packet_bytes.extend_from_slice(&length.to_be_bytes());
428 packet_bytes.extend_from_slice(&timecode.to_be_bytes());
429 packet_bytes.extend_from_slice(&data);
430
431 let packet = Packet::from_bytes(&packet_bytes);
432
433 prop_assert_eq!(packet.header.time_code.0, Some(timecode));
434 prop_assert_eq!(packet.data, data);
435 }
436
437 #[test]
438 fn test_offset_values_preserved(
439 offset in 0u32..4000000,
440 ) {
441 let mut packet_bytes = vec![
442 0x41, 1, 0x00, 0x01,
443 ];
444 packet_bytes.extend_from_slice(&offset.to_be_bytes());
445 packet_bytes.extend_from_slice(&[0x00, 0x03]); packet_bytes.extend_from_slice(&[255, 0, 0]); let packet = Packet::from_bytes(&packet_bytes);
449 prop_assert_eq!(packet.header.offset, offset);
450 }
451 }
452
453 #[test]
455 fn test_full_packet_roundtrip() {
456 use crate::protocol::{Header, PacketType, PixelConfig, ID, timecode::TimeCode};
457
458 let header = Header {
460 packet_type: PacketType {
461 version: 1,
462 timecode: false,
463 storage: false,
464 reply: false,
465 query: false,
466 push: true,
467 },
468 sequence_number: 5,
469 pixel_config: PixelConfig::default(),
470 id: ID::default(),
471 offset: 0,
472 length: 9,
473 time_code: TimeCode(None),
474 };
475
476 let data = vec![255, 0, 0, 0, 255, 0, 0, 0, 255];
478
479 let header_bytes: [u8; 10] = header.into();
481
482 let mut packet_bytes = header_bytes.to_vec();
484 packet_bytes.extend_from_slice(&data);
485
486 let parsed_packet = Packet::from_bytes(&packet_bytes);
488
489 assert_eq!(parsed_packet.header.sequence_number, 5);
491 assert_eq!(parsed_packet.header.length, 9);
492 assert_eq!(parsed_packet.data, data);
493 }
494
495 #[test]
496 fn test_packet_with_timecode_integration() {
497 use crate::protocol::{Header, PacketType, PixelConfig, ID, timecode::TimeCode};
498
499 let header = Header {
501 packet_type: PacketType {
502 version: 1,
503 timecode: true,
504 storage: false,
505 reply: false,
506 query: false,
507 push: true,
508 },
509 sequence_number: 3,
510 pixel_config: PixelConfig::default(),
511 id: ID::default(),
512 offset: 100,
513 length: 6,
514 time_code: TimeCode(Some(12345)),
515 };
516
517 let data = vec![128, 128, 128, 64, 64, 64];
519
520 let header_bytes: [u8; 14] = header.into();
522
523 let mut packet_bytes = header_bytes.to_vec();
525 packet_bytes.extend_from_slice(&data);
526
527 let parsed_packet = Packet::from_bytes(&packet_bytes);
529
530 assert_eq!(parsed_packet.header.sequence_number, 3);
532 assert_eq!(parsed_packet.header.length, 6);
533 assert_eq!(parsed_packet.header.offset, 100);
534 assert_eq!(parsed_packet.header.time_code.0, Some(12345));
535 assert_eq!(parsed_packet.data, data);
536 }
537
538 #[test]
539 fn test_packet_with_config_message_integration() {
540 use crate::protocol::{Header, PacketType, PixelConfig, ID, timecode::TimeCode};
541
542 let json = r#"{"config":{"gw":"192.168.1.1","ip":"192.168.1.100"}}"#;
543
544 let header = Header {
545 packet_type: PacketType {
546 version: 1,
547 timecode: false,
548 storage: false,
549 reply: true,
550 query: false,
551 push: false,
552 },
553 sequence_number: 1,
554 pixel_config: PixelConfig::default(),
555 id: ID::Config,
556 offset: 0,
557 length: json.len() as u16,
558 time_code: TimeCode(None),
559 };
560
561 let header_bytes: [u8; 10] = header.into();
562 let mut packet_bytes = header_bytes.to_vec();
563 packet_bytes.extend_from_slice(json.as_bytes());
564
565 let parsed_packet = Packet::from_bytes(&packet_bytes);
566
567 assert_eq!(parsed_packet.header.id, ID::Config);
568 assert!(parsed_packet.parsed.is_some());
569 }
570
571 #[test]
572 fn test_multiple_packets_different_sequences_integration() {
573 use crate::protocol::{Header, PacketType, PixelConfig, ID, timecode::TimeCode};
574
575 let test_cases = vec![
577 (1, vec![255, 0, 0]),
578 (5, vec![0, 255, 0]),
579 (10, vec![0, 0, 255]),
580 (15, vec![128, 128, 128]),
581 ];
582
583 for (seq_num, data) in test_cases {
584 let header = Header {
585 packet_type: PacketType {
586 version: 1,
587 timecode: false,
588 storage: false,
589 reply: false,
590 query: false,
591 push: true,
592 },
593 sequence_number: seq_num,
594 pixel_config: PixelConfig::default(),
595 id: ID::default(),
596 offset: 0,
597 length: data.len() as u16,
598 time_code: TimeCode(None),
599 };
600
601 let header_bytes: [u8; 10] = header.into();
602 let mut packet_bytes = header_bytes.to_vec();
603 packet_bytes.extend_from_slice(&data);
604
605 let parsed = Packet::from_bytes(&packet_bytes);
606 assert_eq!(parsed.header.sequence_number, seq_num);
607 assert_eq!(parsed.data, data);
608 }
609 }
610
611 #[test]
612 fn test_large_pixel_data_integration() {
613 use crate::protocol::{Header, PacketType, PixelConfig, ID, timecode::TimeCode};
614
615 let num_pixels = 480; let mut data = Vec::with_capacity(num_pixels * 3);
618
619 for i in 0..num_pixels {
620 data.push((i % 256) as u8);
621 data.push(((i * 2) % 256) as u8);
622 data.push(((i * 3) % 256) as u8);
623 }
624
625 let header = Header {
626 packet_type: PacketType {
627 version: 1,
628 timecode: false,
629 storage: false,
630 reply: false,
631 query: false,
632 push: true,
633 },
634 sequence_number: 1,
635 pixel_config: PixelConfig::default(),
636 id: ID::default(),
637 offset: 0,
638 length: data.len() as u16,
639 time_code: TimeCode(None),
640 };
641
642 let header_bytes: [u8; 10] = header.into();
643 let mut packet_bytes = header_bytes.to_vec();
644 packet_bytes.extend_from_slice(&data);
645
646 let parsed = Packet::from_bytes(&packet_bytes);
647 assert_eq!(parsed.data.len(), data.len());
648 assert_eq!(parsed.data, data);
649 }
650}