1use crate::error::Result;
7use crate::protocol::header::Header;
8use std::collections::HashMap;
9
10pub trait Message: Sized {
15 fn message_type() -> &'static str;
19
20 fn encode_content(&self) -> Result<Vec<u8>>;
25
26 fn decode_content(data: &[u8]) -> Result<Self>;
34}
35
36#[derive(Debug)]
44pub struct IgtlMessage<T: Message> {
45 pub header: Header,
47 pub extended_header: Option<Vec<u8>>,
49 pub content: T,
51 pub metadata: Option<HashMap<String, String>>,
53}
54
55impl<T: Message> IgtlMessage<T> {
56 pub fn new(content: T, device_name: &str) -> Result<Self> {
65 use crate::protocol::header::{TypeName, DeviceName, Timestamp};
66
67 let timestamp = Timestamp::now();
68
69 let content_bytes = content.encode_content()?;
70 let body_size = content_bytes.len() as u64;
71
72 let header = Header {
73 version: 2, type_name: TypeName::new(T::message_type())?,
75 device_name: DeviceName::new(device_name)?,
76 timestamp,
77 body_size,
78 crc: 0, };
80
81 Ok(IgtlMessage {
82 header,
83 extended_header: None,
84 content,
85 metadata: None,
86 })
87 }
88
89 pub fn set_extended_header(&mut self, data: Vec<u8>) {
104 self.extended_header = Some(data);
105 if self.header.version < 3 {
107 self.header.version = 3;
108 }
109 }
110
111 pub fn get_extended_header(&self) -> Option<&[u8]> {
116 self.extended_header.as_deref()
117 }
118
119 pub fn clear_extended_header(&mut self) {
121 self.extended_header = None;
122 if self.metadata.is_none() && self.header.version == 3 {
124 self.header.version = 2;
125 }
126 }
127
128 pub fn set_metadata(&mut self, metadata: HashMap<String, String>) {
146 self.metadata = Some(metadata);
147 if self.header.version < 3 {
149 self.header.version = 3;
150 }
151 }
152
153 pub fn add_metadata(&mut self, key: String, value: String) {
159 if self.metadata.is_none() {
160 self.metadata = Some(HashMap::new());
161 if self.header.version < 3 {
162 self.header.version = 3;
163 }
164 }
165 self.metadata.as_mut().unwrap().insert(key, value);
166 }
167
168 pub fn get_metadata(&self) -> Option<&HashMap<String, String>> {
173 self.metadata.as_ref()
174 }
175
176 pub fn clear_metadata(&mut self) {
178 self.metadata = None;
179 if self.extended_header.is_none() && self.header.version == 3 {
181 self.header.version = 2;
182 }
183 }
184
185 pub fn encode(&self) -> Result<Vec<u8>> {
201 use crate::protocol::crc::calculate_crc;
202
203 let content_bytes = self.content.encode_content()?;
205
206 let metadata_bytes = if self.header.version >= 3 && self.metadata.is_some() {
208 let metadata = self.metadata.as_ref().unwrap();
209 let mut meta_buf = Vec::new();
210
211 let meta_header_size = (metadata.len() as u16).to_be_bytes();
213 meta_buf.extend_from_slice(&meta_header_size);
214
215 for (key, value) in metadata.iter() {
217 let key_bytes = key.as_bytes();
219 meta_buf.extend_from_slice(&(key_bytes.len() as u16).to_be_bytes());
220 meta_buf.extend_from_slice(key_bytes);
221
222 let value_bytes = value.as_bytes();
224 meta_buf.extend_from_slice(&(value_bytes.len() as u16).to_be_bytes());
225 meta_buf.extend_from_slice(value_bytes);
226 }
227
228 meta_buf
229 } else {
230 Vec::new()
231 };
232
233 let body_bytes = if self.header.version >= 3 && self.extended_header.is_some() {
235 let ext_header = self.extended_header.as_ref().unwrap();
237 let ext_header_size = ext_header.len() as u16;
238
239 let mut body = Vec::with_capacity(
240 2 + ext_header.len() + content_bytes.len() + metadata_bytes.len()
241 );
242 body.extend_from_slice(&ext_header_size.to_be_bytes());
244 body.extend_from_slice(ext_header);
246 body.extend_from_slice(&content_bytes);
248 body.extend_from_slice(&metadata_bytes);
250
251 body
252 } else if self.header.version >= 3 && !metadata_bytes.is_empty() {
253 let mut body = Vec::with_capacity(2 + content_bytes.len() + metadata_bytes.len());
255 body.extend_from_slice(&0u16.to_be_bytes());
257 body.extend_from_slice(&content_bytes);
259 body.extend_from_slice(&metadata_bytes);
261
262 body
263 } else {
264 content_bytes
266 };
267
268 let mut header = self.header.clone();
270 header.body_size = body_bytes.len() as u64;
271 header.crc = calculate_crc(&body_bytes);
272
273 let mut buf = Vec::with_capacity(Header::SIZE + body_bytes.len());
275 buf.extend_from_slice(&header.encode());
276 buf.extend_from_slice(&body_bytes);
277
278 Ok(buf)
279 }
280
281 pub fn decode(data: &[u8]) -> Result<Self> {
291 Self::decode_with_options(data, true)
292 }
293
294 pub fn decode_with_options(data: &[u8], verify_crc: bool) -> Result<Self> {
322 use crate::protocol::crc::calculate_crc;
323 use crate::error::IgtlError;
324
325 if data.len() < Header::SIZE {
326 return Err(IgtlError::InvalidSize {
327 expected: Header::SIZE,
328 actual: data.len(),
329 });
330 }
331
332 let header = Header::decode(&data[..Header::SIZE])?;
334
335 let body_start = Header::SIZE;
337 let body_end = body_start + header.body_size as usize;
338
339 if data.len() < body_end {
340 return Err(IgtlError::InvalidSize {
341 expected: body_end,
342 actual: data.len(),
343 });
344 }
345
346 let body_bytes = &data[body_start..body_end];
347
348 if verify_crc {
350 let calculated_crc = calculate_crc(body_bytes);
351 if calculated_crc != header.crc {
352 return Err(IgtlError::CrcMismatch {
353 expected: header.crc,
354 actual: calculated_crc,
355 });
356 }
357 }
358
359 let (extended_header, remaining_bytes, has_ext_header_field) = if header.version >= 3 && body_bytes.len() >= 2 {
361 let ext_header_size = u16::from_be_bytes([body_bytes[0], body_bytes[1]]) as usize;
363
364 if ext_header_size > 0 && body_bytes.len() >= 2 + ext_header_size {
365 let ext_header_data = body_bytes[2..2 + ext_header_size].to_vec();
367 let content_start = 2 + ext_header_size;
368 (Some(ext_header_data), &body_bytes[content_start..], true)
369 } else if ext_header_size == 0 && body_bytes.len() >= 2 {
370 (Some(Vec::new()), &body_bytes[2..], true)
372 } else {
373 return Err(IgtlError::InvalidSize {
375 expected: 2 + ext_header_size,
376 actual: body_bytes.len(),
377 });
378 }
379 } else {
380 (None, body_bytes, false)
382 };
383
384 let (content_bytes, metadata) = if header.version >= 3 && has_ext_header_field {
386 match T::decode_content(remaining_bytes) {
392 Ok(content) => {
393 let actual_content_size = content.encode_content()?.len();
396
397 if remaining_bytes.len() > actual_content_size {
398 let content_part = &remaining_bytes[..actual_content_size];
400 let metadata_part = &remaining_bytes[actual_content_size..];
401
402 let parsed_metadata = Self::decode_metadata(metadata_part)?;
404 (content_part, parsed_metadata)
405 } else {
406 (remaining_bytes, None)
408 }
409 }
410 Err(IgtlError::InvalidSize { expected, .. }) if remaining_bytes.len() > expected => {
411 let content_part = &remaining_bytes[..expected];
414 let metadata_part = &remaining_bytes[expected..];
415
416 if T::decode_content(content_part).is_ok() {
418 let parsed_metadata = Self::decode_metadata(metadata_part)?;
420 (content_part, parsed_metadata)
421 } else {
422 (remaining_bytes, None)
424 }
425 }
426 Err(_) => {
427 (remaining_bytes, None)
429 }
430 }
431 } else {
432 (remaining_bytes, None)
434 };
435
436 let content = T::decode_content(content_bytes)?;
438
439 Ok(IgtlMessage {
440 header,
441 extended_header,
442 content,
443 metadata,
444 })
445 }
446
447 fn decode_metadata(data: &[u8]) -> Result<Option<HashMap<String, String>>> {
449 use crate::error::IgtlError;
450
451 if data.len() < 2 {
452 return Ok(None);
453 }
454
455 let metadata_count = u16::from_be_bytes([data[0], data[1]]) as usize;
456
457 if metadata_count == 0 {
458 return Ok(None);
459 }
460
461 let mut metadata = HashMap::new();
462 let mut offset = 2;
463
464 for _ in 0..metadata_count {
465 if offset + 2 > data.len() {
467 return Err(IgtlError::InvalidSize {
468 expected: offset + 2,
469 actual: data.len(),
470 });
471 }
472 let key_size = u16::from_be_bytes([data[offset], data[offset + 1]]) as usize;
473 offset += 2;
474
475 if offset + key_size > data.len() {
477 return Err(IgtlError::InvalidSize {
478 expected: offset + key_size,
479 actual: data.len(),
480 });
481 }
482 let key = String::from_utf8(data[offset..offset + key_size].to_vec())?;
483 offset += key_size;
484
485 if offset + 2 > data.len() {
487 return Err(IgtlError::InvalidSize {
488 expected: offset + 2,
489 actual: data.len(),
490 });
491 }
492 let value_size = u16::from_be_bytes([data[offset], data[offset + 1]]) as usize;
493 offset += 2;
494
495 if offset + value_size > data.len() {
497 return Err(IgtlError::InvalidSize {
498 expected: offset + value_size,
499 actual: data.len(),
500 });
501 }
502 let value = String::from_utf8(data[offset..offset + value_size].to_vec())?;
503 offset += value_size;
504
505 metadata.insert(key, value);
506 }
507
508 Ok(Some(metadata))
509 }
510}
511
512#[cfg(test)]
513mod tests {
514 use super::*;
515 use crate::protocol::types::{TransformMessage, StatusMessage, CapabilityMessage};
516
517 struct TestMessage {
519 data: Vec<u8>,
520 }
521
522 impl Message for TestMessage {
523 fn message_type() -> &'static str {
524 "TEST"
525 }
526
527 fn encode_content(&self) -> Result<Vec<u8>> {
528 Ok(self.data.clone())
529 }
530
531 fn decode_content(data: &[u8]) -> Result<Self> {
532 Ok(TestMessage {
533 data: data.to_vec(),
534 })
535 }
536 }
537
538 #[test]
539 fn test_message_trait() {
540 assert_eq!(TestMessage::message_type(), "TEST");
541 }
542
543 #[test]
544 fn test_message_encode_decode() {
545 let original = TestMessage {
546 data: vec![1, 2, 3, 4, 5],
547 };
548
549 let encoded = original.encode_content().unwrap();
550 let decoded = TestMessage::decode_content(&encoded).unwrap();
551
552 assert_eq!(original.data, decoded.data);
553 }
554
555 #[test]
556 fn test_full_message_roundtrip_transform() {
557 let transform = TransformMessage::identity();
558 let msg = IgtlMessage::new(transform.clone(), "TestDevice").unwrap();
559
560 let encoded = msg.encode().unwrap();
561 let decoded = IgtlMessage::<TransformMessage>::decode(&encoded).unwrap();
562
563 assert_eq!(decoded.header.version, 2);
565 assert_eq!(decoded.header.type_name.as_str().unwrap(), "TRANSFORM");
566 assert_eq!(decoded.header.device_name.as_str().unwrap(), "TestDevice");
567 assert_eq!(decoded.header.body_size, 48);
568
569 assert_eq!(decoded.content, transform);
571 }
572
573 #[test]
574 fn test_full_message_roundtrip_status() {
575 let status = StatusMessage::ok("Operation successful");
576 let msg = IgtlMessage::new(status.clone(), "StatusDevice").unwrap();
577
578 let encoded = msg.encode().unwrap();
579 let decoded = IgtlMessage::<StatusMessage>::decode(&encoded).unwrap();
580
581 assert_eq!(decoded.header.type_name.as_str().unwrap(), "STATUS");
582 assert_eq!(decoded.content, status);
583 }
584
585 #[test]
586 fn test_full_message_roundtrip_capability() {
587 let capability = CapabilityMessage::new(vec![
588 "TRANSFORM".to_string(),
589 "STATUS".to_string(),
590 "IMAGE".to_string(),
591 ]);
592 let msg = IgtlMessage::new(capability.clone(), "CapDevice").unwrap();
593
594 let encoded = msg.encode().unwrap();
595 let decoded = IgtlMessage::<CapabilityMessage>::decode(&encoded).unwrap();
596
597 assert_eq!(decoded.header.type_name.as_str().unwrap(), "CAPABILITY");
598 assert_eq!(decoded.content, capability);
599 }
600
601 #[test]
602 fn test_timestamp_reasonable() {
603 let transform = TransformMessage::identity();
604 let msg = IgtlMessage::new(transform, "TestDevice").unwrap();
605
606 let now = std::time::SystemTime::now()
608 .duration_since(std::time::UNIX_EPOCH)
609 .unwrap()
610 .as_secs() as u32;
611
612 let one_year_ago = now - (365 * 24 * 60 * 60);
613
614 assert!(msg.header.timestamp.seconds >= one_year_ago);
615 assert!(msg.header.timestamp.seconds <= now + 1); }
617
618 #[test]
619 fn test_crc_verification() {
620 let transform = TransformMessage::identity();
621 let msg = IgtlMessage::new(transform, "TestDevice").unwrap();
622
623 let mut encoded = msg.encode().unwrap();
624
625 let content_start = Header::SIZE;
627 encoded[content_start] ^= 0xFF;
628
629 let result = IgtlMessage::<TransformMessage>::decode(&encoded);
631 assert!(matches!(result, Err(crate::error::IgtlError::CrcMismatch { .. })));
632 }
633
634 #[test]
635 fn test_message_size_calculation() {
636 let transform = TransformMessage::identity();
637 let msg = IgtlMessage::new(transform, "TestDevice").unwrap();
638
639 let encoded = msg.encode().unwrap();
640
641 assert_eq!(encoded.len(), 106);
643 }
644
645 #[test]
646 fn test_decode_short_buffer() {
647 let short_data = vec![0u8; 30];
648 let result = IgtlMessage::<TransformMessage>::decode(&short_data);
649 assert!(matches!(result, Err(crate::error::IgtlError::InvalidSize { .. })));
650 }
651
652 #[test]
655 fn test_extended_header_set_get() {
656 let transform = TransformMessage::identity();
657 let mut msg = IgtlMessage::new(transform, "TestDevice").unwrap();
658
659 assert_eq!(msg.get_extended_header(), None);
661 assert_eq!(msg.header.version, 2);
662
663 let ext_header = vec![0x01, 0x02, 0x03, 0x04];
665 msg.set_extended_header(ext_header.clone());
666
667 assert_eq!(msg.header.version, 3);
669 assert_eq!(msg.get_extended_header(), Some(ext_header.as_slice()));
670 }
671
672 #[test]
673 fn test_extended_header_clear() {
674 let transform = TransformMessage::identity();
675 let mut msg = IgtlMessage::new(transform, "TestDevice").unwrap();
676
677 msg.set_extended_header(vec![0x01, 0x02, 0x03, 0x04]);
679 assert_eq!(msg.header.version, 3);
680
681 msg.clear_extended_header();
683 assert_eq!(msg.get_extended_header(), None);
684 assert_eq!(msg.header.version, 2);
686 }
687
688 #[test]
689 fn test_version3_encode_decode_with_extended_header() {
690 let transform = TransformMessage::identity();
691 let mut msg = IgtlMessage::new(transform.clone(), "TestDevice").unwrap();
692
693 let ext_header = vec![0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF];
695 msg.set_extended_header(ext_header.clone());
696
697 let encoded = msg.encode().unwrap();
699
700 let decoded = IgtlMessage::<TransformMessage>::decode(&encoded).unwrap();
702
703 assert_eq!(decoded.header.version, 3);
705
706 assert_eq!(decoded.get_extended_header(), Some(ext_header.as_slice()));
708
709 assert_eq!(decoded.content, transform);
711 }
712
713 #[test]
714 fn test_version3_encode_decode_without_extended_header() {
715 let status = StatusMessage::ok("Test message");
716 let msg = IgtlMessage::new(status.clone(), "TestDevice").unwrap();
717
718 let encoded = msg.encode().unwrap();
720
721 let decoded = IgtlMessage::<StatusMessage>::decode(&encoded).unwrap();
723
724 assert_eq!(decoded.header.version, 2);
726 assert_eq!(decoded.get_extended_header(), None);
727 assert_eq!(decoded.content, status);
728 }
729
730 #[test]
731 fn test_extended_header_body_size_calculation() {
732 let transform = TransformMessage::identity();
733 let mut msg = IgtlMessage::new(transform, "TestDevice").unwrap();
734
735 let ext_header = vec![0x01, 0x02, 0x03, 0x04]; msg.set_extended_header(ext_header);
738
739 let encoded = msg.encode().unwrap();
740
741 assert_eq!(encoded.len(), 112);
744
745 let decoded = IgtlMessage::<TransformMessage>::decode(&encoded).unwrap();
747 assert_eq!(decoded.header.body_size, 2 + 4 + 48); }
749
750 #[test]
751 fn test_extended_header_empty() {
752 let transform = TransformMessage::identity();
753 let mut msg = IgtlMessage::new(transform.clone(), "TestDevice").unwrap();
754
755 msg.set_extended_header(vec![]);
757
758 let encoded = msg.encode().unwrap();
759 let decoded = IgtlMessage::<TransformMessage>::decode(&encoded).unwrap();
760
761 assert_eq!(decoded.header.version, 3);
763 assert_eq!(decoded.get_extended_header(), Some(&[] as &[u8]));
765 assert_eq!(decoded.content, transform);
767 }
768
769 #[test]
770 fn test_extended_header_large() {
771 let status = StatusMessage::ok("Test");
772 let mut msg = IgtlMessage::new(status.clone(), "TestDevice").unwrap();
773
774 let ext_header = vec![0xAB; 1024];
776 msg.set_extended_header(ext_header.clone());
777
778 let encoded = msg.encode().unwrap();
779 let decoded = IgtlMessage::<StatusMessage>::decode(&encoded).unwrap();
780
781 assert_eq!(decoded.header.version, 3);
782 assert_eq!(decoded.get_extended_header(), Some(ext_header.as_slice()));
783 assert_eq!(decoded.content, status);
784 }
785
786 #[test]
787 fn test_version3_crc_includes_extended_header() {
788 let transform = TransformMessage::identity();
789 let mut msg = IgtlMessage::new(transform, "TestDevice").unwrap();
790
791 msg.set_extended_header(vec![0x01, 0x02, 0x03, 0x04]);
792
793 let mut encoded = msg.encode().unwrap();
794
795 encoded[Header::SIZE + 2] ^= 0xFF; let result = IgtlMessage::<TransformMessage>::decode(&encoded);
800 assert!(matches!(result, Err(crate::error::IgtlError::CrcMismatch { .. })));
801 }
802
803 #[test]
804 fn test_backward_compatibility_version2() {
805 let capability = CapabilityMessage::new(vec!["TRANSFORM".to_string()]);
807 let msg = IgtlMessage::new(capability.clone(), "Device").unwrap();
808
809 assert_eq!(msg.header.version, 2);
810
811 let encoded = msg.encode().unwrap();
812 let decoded = IgtlMessage::<CapabilityMessage>::decode(&encoded).unwrap();
813
814 assert_eq!(decoded.header.version, 2);
816 assert_eq!(decoded.get_extended_header(), None);
817 assert_eq!(decoded.content, capability);
818 }
819
820 #[test]
823 fn test_metadata_set_get() {
824 let transform = TransformMessage::identity();
825 let mut msg = IgtlMessage::new(transform, "TestDevice").unwrap();
826
827 assert_eq!(msg.get_metadata(), None);
829 assert_eq!(msg.header.version, 2);
830
831 let mut metadata = HashMap::new();
833 metadata.insert("priority".to_string(), "high".to_string());
834 metadata.insert("sequence".to_string(), "42".to_string());
835 msg.set_metadata(metadata.clone());
836
837 assert_eq!(msg.header.version, 3);
839 assert_eq!(msg.get_metadata(), Some(&metadata));
840 }
841
842 #[test]
843 fn test_metadata_add() {
844 let status = StatusMessage::ok("Test");
845 let mut msg = IgtlMessage::new(status, "TestDevice").unwrap();
846
847 assert_eq!(msg.header.version, 2);
848
849 msg.add_metadata("key1".to_string(), "value1".to_string());
851 assert_eq!(msg.header.version, 3);
852
853 msg.add_metadata("key2".to_string(), "value2".to_string());
854
855 let metadata = msg.get_metadata().unwrap();
856 assert_eq!(metadata.get("key1"), Some(&"value1".to_string()));
857 assert_eq!(metadata.get("key2"), Some(&"value2".to_string()));
858 }
859
860 #[test]
861 fn test_metadata_clear() {
862 let transform = TransformMessage::identity();
863 let mut msg = IgtlMessage::new(transform, "TestDevice").unwrap();
864
865 msg.add_metadata("test".to_string(), "value".to_string());
867 assert_eq!(msg.header.version, 3);
868
869 msg.clear_metadata();
871 assert_eq!(msg.get_metadata(), None);
872 assert_eq!(msg.header.version, 2);
874 }
875
876 #[test]
877 fn test_version3_encode_decode_with_metadata() {
878 let transform = TransformMessage::identity();
879 let mut msg = IgtlMessage::new(transform.clone(), "TestDevice").unwrap();
880
881 let mut metadata = HashMap::new();
883 metadata.insert("priority".to_string(), "high".to_string());
884 metadata.insert("timestamp".to_string(), "123456".to_string());
885 msg.set_metadata(metadata.clone());
886
887 let encoded = msg.encode().unwrap();
889
890 let decoded = IgtlMessage::<TransformMessage>::decode(&encoded).unwrap();
892
893 assert_eq!(decoded.header.version, 3);
895
896 let decoded_metadata = decoded.get_metadata().unwrap();
898 assert_eq!(decoded_metadata.get("priority"), Some(&"high".to_string()));
899 assert_eq!(decoded_metadata.get("timestamp"), Some(&"123456".to_string()));
900
901 assert_eq!(decoded.content, transform);
903 }
904
905 #[test]
906 fn test_version3_with_extended_header_and_metadata() {
907 let status = StatusMessage::ok("Test message");
908 let mut msg = IgtlMessage::new(status.clone(), "TestDevice").unwrap();
909
910 msg.set_extended_header(vec![0xAA, 0xBB, 0xCC, 0xDD]);
912 msg.add_metadata("key1".to_string(), "value1".to_string());
913 msg.add_metadata("key2".to_string(), "value2".to_string());
914
915 let encoded = msg.encode().unwrap();
916 let decoded = IgtlMessage::<StatusMessage>::decode(&encoded).unwrap();
917
918 assert_eq!(decoded.header.version, 3);
920
921 let expected_ext_header: &[u8] = &[0xAA, 0xBB, 0xCC, 0xDD];
923 assert_eq!(decoded.get_extended_header(), Some(expected_ext_header));
924
925 let metadata = decoded.get_metadata().unwrap();
927 assert_eq!(metadata.get("key1"), Some(&"value1".to_string()));
928 assert_eq!(metadata.get("key2"), Some(&"value2".to_string()));
929
930 assert_eq!(decoded.content, status);
932 }
933
934 #[test]
935 fn test_metadata_empty() {
936 let transform = TransformMessage::identity();
937 let mut msg = IgtlMessage::new(transform.clone(), "TestDevice").unwrap();
938
939 msg.set_metadata(HashMap::new());
941
942 let encoded = msg.encode().unwrap();
943 let decoded = IgtlMessage::<TransformMessage>::decode(&encoded).unwrap();
944
945 assert_eq!(decoded.get_metadata(), None);
947 assert_eq!(decoded.content, transform);
948 }
949
950 #[test]
951 fn test_metadata_utf8_values() {
952 let status = StatusMessage::ok("Test");
953 let mut msg = IgtlMessage::new(status.clone(), "TestDevice").unwrap();
954
955 msg.add_metadata("name".to_string(), "日本語".to_string());
957 msg.add_metadata("emoji".to_string(), "🎉✨".to_string());
958
959 let encoded = msg.encode().unwrap();
960 let decoded = IgtlMessage::<StatusMessage>::decode(&encoded).unwrap();
961
962 let metadata = decoded.get_metadata().unwrap();
963 assert_eq!(metadata.get("name"), Some(&"日本語".to_string()));
964 assert_eq!(metadata.get("emoji"), Some(&"🎉✨".to_string()));
965 }
966
967 #[test]
970 fn test_decode_with_crc_verification_enabled() {
971 let transform = TransformMessage::identity();
972 let msg = IgtlMessage::new(transform.clone(), "TestDevice").unwrap();
973
974 let encoded = msg.encode().unwrap();
975
976 let decoded = IgtlMessage::<TransformMessage>::decode_with_options(&encoded, true).unwrap();
978 assert_eq!(decoded.content, transform);
979 }
980
981 #[test]
982 fn test_decode_with_crc_verification_disabled() {
983 let transform = TransformMessage::identity();
984 let msg = IgtlMessage::new(transform.clone(), "TestDevice").unwrap();
985
986 let mut encoded = msg.encode().unwrap();
987
988 encoded[Header::SIZE] ^= 0xFF;
990
991 let result_with_crc = IgtlMessage::<TransformMessage>::decode_with_options(&encoded, true);
993 assert!(matches!(result_with_crc, Err(crate::error::IgtlError::CrcMismatch { .. })));
994
995 let result_without_crc = IgtlMessage::<TransformMessage>::decode_with_options(&encoded, false);
997 assert!(result_without_crc.is_ok());
998 }
999
1000 #[test]
1001 fn test_decode_default_uses_crc_verification() {
1002 let transform = TransformMessage::identity();
1003 let msg = IgtlMessage::new(transform, "TestDevice").unwrap();
1004
1005 let mut encoded = msg.encode().unwrap();
1006
1007 encoded[Header::SIZE] ^= 0xFF;
1009
1010 let result = IgtlMessage::<TransformMessage>::decode(&encoded);
1012 assert!(matches!(result, Err(crate::error::IgtlError::CrcMismatch { .. })));
1013 }
1014
1015 #[test]
1016 fn test_crc_skip_performance() {
1017 let status = StatusMessage::ok("Performance test");
1019 let msg = IgtlMessage::new(status.clone(), "TestDevice").unwrap();
1020
1021 let encoded = msg.encode().unwrap();
1022
1023 let decoded_with_crc = IgtlMessage::<StatusMessage>::decode_with_options(&encoded, true).unwrap();
1025 let decoded_without_crc = IgtlMessage::<StatusMessage>::decode_with_options(&encoded, false).unwrap();
1026
1027 assert_eq!(decoded_with_crc.content, decoded_without_crc.content);
1028 assert_eq!(decoded_with_crc.content, status);
1029 }
1030
1031 #[test]
1032 fn test_version3_crc_skip_with_extended_header() {
1033 let transform = TransformMessage::identity();
1034 let mut msg = IgtlMessage::new(transform.clone(), "TestDevice").unwrap();
1035
1036 msg.set_extended_header(vec![0x01, 0x02, 0x03, 0x04]);
1037
1038 let encoded = msg.encode().unwrap();
1039
1040 let decoded = IgtlMessage::<TransformMessage>::decode_with_options(&encoded, false).unwrap();
1042 assert_eq!(decoded.header.version, 3);
1043 let expected: &[u8] = &[0x01, 0x02, 0x03, 0x04];
1044 assert_eq!(decoded.get_extended_header(), Some(expected));
1045 assert_eq!(decoded.content, transform);
1046 }
1047
1048 #[test]
1049 fn test_version3_crc_skip_with_metadata() {
1050 let status = StatusMessage::ok("Test");
1051 let mut msg = IgtlMessage::new(status.clone(), "TestDevice").unwrap();
1052
1053 msg.add_metadata("key1".to_string(), "value1".to_string());
1054 msg.add_metadata("key2".to_string(), "value2".to_string());
1055
1056 let encoded = msg.encode().unwrap();
1057
1058 let decoded = IgtlMessage::<StatusMessage>::decode_with_options(&encoded, false).unwrap();
1060 assert_eq!(decoded.header.version, 3);
1061
1062 let metadata = decoded.get_metadata().unwrap();
1063 assert_eq!(metadata.get("key1"), Some(&"value1".to_string()));
1064 assert_eq!(metadata.get("key2"), Some(&"value2".to_string()));
1065 assert_eq!(decoded.content, status);
1066 }
1067}