1use crate::ber::{Decoder, EncodeBuf, tag};
6use crate::error::{DecodeErrorKind, Error, Result};
7use crate::format::hex;
8use crate::oid::Oid;
9use bytes::Bytes;
10
11#[derive(Debug, Clone, PartialEq)]
15#[non_exhaustive]
16pub enum Value {
17 Integer(i32),
19
20 OctetString(Bytes),
27
28 Null,
30
31 ObjectIdentifier(Oid),
33
34 IpAddress([u8; 4]),
36
37 Counter32(u32),
39
40 Gauge32(u32),
42
43 TimeTicks(u32),
45
46 Opaque(Bytes),
48
49 Counter64(u64),
59
60 NoSuchObject,
81
82 NoSuchInstance,
97
98 EndOfMibView,
118
119 Unknown { tag: u8, data: Bytes },
121}
122
123impl Value {
124 pub fn as_i32(&self) -> Option<i32> {
144 match self {
145 Value::Integer(v) => Some(*v),
146 _ => None,
147 }
148 }
149
150 pub fn as_u32(&self) -> Option<u32> {
175 match self {
176 Value::Counter32(v) | Value::Gauge32(v) | Value::TimeTicks(v) => Some(*v),
177 Value::Integer(v) if *v >= 0 => Some(*v as u32),
178 _ => None,
179 }
180 }
181
182 pub fn as_u64(&self) -> Option<u64> {
207 match self {
208 Value::Counter64(v) => Some(*v),
209 Value::Counter32(v) | Value::Gauge32(v) | Value::TimeTicks(v) => Some(*v as u64),
210 Value::Integer(v) if *v >= 0 => Some(*v as u64),
211 _ => None,
212 }
213 }
214
215 pub fn as_bytes(&self) -> Option<&[u8]> {
237 match self {
238 Value::OctetString(v) | Value::Opaque(v) => Some(v),
239 _ => None,
240 }
241 }
242
243 pub fn as_str(&self) -> Option<&str> {
267 self.as_bytes().and_then(|b| std::str::from_utf8(b).ok())
268 }
269
270 pub fn as_oid(&self) -> Option<&Oid> {
287 match self {
288 Value::ObjectIdentifier(oid) => Some(oid),
289 _ => None,
290 }
291 }
292
293 pub fn as_ip(&self) -> Option<std::net::Ipv4Addr> {
310 match self {
311 Value::IpAddress(bytes) => Some(std::net::Ipv4Addr::from(*bytes)),
312 _ => None,
313 }
314 }
315
316 pub fn is_exception(&self) -> bool {
318 matches!(
319 self,
320 Value::NoSuchObject | Value::NoSuchInstance | Value::EndOfMibView
321 )
322 }
323
324 pub fn format_with_hint(&self, hint: &str) -> Option<String> {
342 match self {
343 Value::OctetString(bytes) => Some(crate::format::display_hint::apply(hint, bytes)),
344 Value::Opaque(bytes) => Some(crate::format::display_hint::apply(hint, bytes)),
345 _ => None,
346 }
347 }
348
349 pub fn encode(&self, buf: &mut EncodeBuf) {
351 match self {
352 Value::Integer(v) => buf.push_integer(*v),
353 Value::OctetString(data) => buf.push_octet_string(data),
354 Value::Null => buf.push_null(),
355 Value::ObjectIdentifier(oid) => buf.push_oid(oid),
356 Value::IpAddress(addr) => buf.push_ip_address(*addr),
357 Value::Counter32(v) => buf.push_unsigned32(tag::application::COUNTER32, *v),
358 Value::Gauge32(v) => buf.push_unsigned32(tag::application::GAUGE32, *v),
359 Value::TimeTicks(v) => buf.push_unsigned32(tag::application::TIMETICKS, *v),
360 Value::Opaque(data) => {
361 buf.push_bytes(data);
362 buf.push_length(data.len());
363 buf.push_tag(tag::application::OPAQUE);
364 }
365 Value::Counter64(v) => buf.push_integer64(*v),
366 Value::NoSuchObject => {
367 buf.push_length(0);
368 buf.push_tag(tag::context::NO_SUCH_OBJECT);
369 }
370 Value::NoSuchInstance => {
371 buf.push_length(0);
372 buf.push_tag(tag::context::NO_SUCH_INSTANCE);
373 }
374 Value::EndOfMibView => {
375 buf.push_length(0);
376 buf.push_tag(tag::context::END_OF_MIB_VIEW);
377 }
378 Value::Unknown { tag: t, data } => {
379 buf.push_bytes(data);
380 buf.push_length(data.len());
381 buf.push_tag(*t);
382 }
383 }
384 }
385
386 pub fn decode(decoder: &mut Decoder) -> Result<Self> {
388 let tag = decoder.read_tag()?;
389 let len = decoder.read_length()?;
390
391 match tag {
392 tag::universal::INTEGER => {
393 let value = decoder.read_integer_value(len)?;
394 Ok(Value::Integer(value))
395 }
396 tag::universal::OCTET_STRING => {
397 let data = decoder.read_bytes(len)?;
398 Ok(Value::OctetString(data))
399 }
400 tag::universal::NULL => {
401 if len != 0 {
402 return Err(Error::decode(
403 decoder.offset(),
404 DecodeErrorKind::InvalidNull,
405 ));
406 }
407 Ok(Value::Null)
408 }
409 tag::universal::OBJECT_IDENTIFIER => {
410 let oid = decoder.read_oid_value(len)?;
411 Ok(Value::ObjectIdentifier(oid))
412 }
413 tag::application::IP_ADDRESS => {
414 if len != 4 {
415 return Err(Error::decode(
416 decoder.offset(),
417 DecodeErrorKind::InvalidIpAddressLength { length: len },
418 ));
419 }
420 let data = decoder.read_bytes(4)?;
421 Ok(Value::IpAddress([data[0], data[1], data[2], data[3]]))
422 }
423 tag::application::COUNTER32 => {
424 let value = decoder.read_unsigned32_value(len)?;
425 Ok(Value::Counter32(value))
426 }
427 tag::application::GAUGE32 => {
428 let value = decoder.read_unsigned32_value(len)?;
429 Ok(Value::Gauge32(value))
430 }
431 tag::application::TIMETICKS => {
432 let value = decoder.read_unsigned32_value(len)?;
433 Ok(Value::TimeTicks(value))
434 }
435 tag::application::OPAQUE => {
436 let data = decoder.read_bytes(len)?;
437 Ok(Value::Opaque(data))
438 }
439 tag::application::COUNTER64 => {
440 let value = decoder.read_integer64_value(len)?;
441 Ok(Value::Counter64(value))
442 }
443 tag::context::NO_SUCH_OBJECT => {
444 if len != 0 {
445 let _ = decoder.read_bytes(len)?;
446 }
447 Ok(Value::NoSuchObject)
448 }
449 tag::context::NO_SUCH_INSTANCE => {
450 if len != 0 {
451 let _ = decoder.read_bytes(len)?;
452 }
453 Ok(Value::NoSuchInstance)
454 }
455 tag::context::END_OF_MIB_VIEW => {
456 if len != 0 {
457 let _ = decoder.read_bytes(len)?;
458 }
459 Ok(Value::EndOfMibView)
460 }
461 tag::universal::OCTET_STRING_CONSTRUCTED => Err(Error::decode(
464 decoder.offset(),
465 DecodeErrorKind::ConstructedOctetString,
466 )),
467 _ => {
468 let data = decoder.read_bytes(len)?;
470 Ok(Value::Unknown { tag, data })
471 }
472 }
473 }
474}
475
476impl std::fmt::Display for Value {
477 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
478 match self {
479 Value::Integer(v) => write!(f, "{}", v),
480 Value::OctetString(data) => {
481 if let Ok(s) = std::str::from_utf8(data) {
483 write!(f, "{}", s)
484 } else {
485 write!(f, "0x{}", hex::encode(data))
486 }
487 }
488 Value::Null => write!(f, "NULL"),
489 Value::ObjectIdentifier(oid) => write!(f, "{}", oid),
490 Value::IpAddress(addr) => {
491 write!(f, "{}.{}.{}.{}", addr[0], addr[1], addr[2], addr[3])
492 }
493 Value::Counter32(v) => write!(f, "{}", v),
494 Value::Gauge32(v) => write!(f, "{}", v),
495 Value::TimeTicks(v) => {
496 let secs = v / 100;
498 let days = secs / 86400;
499 let hours = (secs % 86400) / 3600;
500 let mins = (secs % 3600) / 60;
501 let s = secs % 60;
502 write!(f, "{}d {}h {}m {}s", days, hours, mins, s)
503 }
504 Value::Opaque(data) => write!(f, "Opaque(0x{})", hex::encode(data)),
505 Value::Counter64(v) => write!(f, "{}", v),
506 Value::NoSuchObject => write!(f, "noSuchObject"),
507 Value::NoSuchInstance => write!(f, "noSuchInstance"),
508 Value::EndOfMibView => write!(f, "endOfMibView"),
509 Value::Unknown { tag, data } => {
510 write!(
511 f,
512 "Unknown(tag=0x{:02X}, data=0x{})",
513 tag,
514 hex::encode(data)
515 )
516 }
517 }
518 }
519}
520
521impl From<i32> for Value {
563 fn from(v: i32) -> Self {
564 Value::Integer(v)
565 }
566}
567
568impl From<&str> for Value {
569 fn from(s: &str) -> Self {
570 Value::OctetString(Bytes::copy_from_slice(s.as_bytes()))
571 }
572}
573
574impl From<String> for Value {
575 fn from(s: String) -> Self {
576 Value::OctetString(Bytes::from(s))
577 }
578}
579
580impl From<&[u8]> for Value {
581 fn from(data: &[u8]) -> Self {
582 Value::OctetString(Bytes::copy_from_slice(data))
583 }
584}
585
586impl From<Oid> for Value {
587 fn from(oid: Oid) -> Self {
588 Value::ObjectIdentifier(oid)
589 }
590}
591
592impl From<std::net::Ipv4Addr> for Value {
593 fn from(addr: std::net::Ipv4Addr) -> Self {
594 Value::IpAddress(addr.octets())
595 }
596}
597
598impl From<Bytes> for Value {
599 fn from(data: Bytes) -> Self {
600 Value::OctetString(data)
601 }
602}
603
604impl From<u64> for Value {
605 fn from(v: u64) -> Self {
606 Value::Counter64(v)
607 }
608}
609
610impl From<[u8; 4]> for Value {
611 fn from(addr: [u8; 4]) -> Self {
612 Value::IpAddress(addr)
613 }
614}
615
616#[cfg(test)]
617mod tests {
618 use super::*;
619
620 #[test]
623 fn test_reject_constructed_octet_string() {
624 let data = bytes::Bytes::from_static(&[0x24, 0x03, 0x04, 0x01, 0x41]);
628 let mut decoder = Decoder::new(data);
629 let result = Value::decode(&mut decoder);
630
631 assert!(
632 result.is_err(),
633 "constructed OCTET STRING (0x24) should be rejected"
634 );
635 let err = result.unwrap_err();
636 let err_msg = format!("{}", err);
637 assert!(
638 err_msg.contains("constructed OCTET STRING"),
639 "error message should mention 'constructed OCTET STRING', got: {}",
640 err_msg
641 );
642 }
643
644 #[test]
645 fn test_primitive_octet_string_accepted() {
646 let data = bytes::Bytes::from_static(&[0x04, 0x03, 0x41, 0x42, 0x43]); let mut decoder = Decoder::new(data);
649 let result = Value::decode(&mut decoder);
650
651 assert!(result.is_ok(), "primitive OCTET STRING should be accepted");
652 let value = result.unwrap();
653 assert_eq!(value.as_bytes(), Some(&b"ABC"[..]));
654 }
655
656 fn roundtrip(value: Value) -> Value {
661 let mut buf = EncodeBuf::new();
662 value.encode(&mut buf);
663 let data = buf.finish();
664 let mut decoder = Decoder::new(data);
665 Value::decode(&mut decoder).unwrap()
666 }
667
668 #[test]
669 fn test_integer_positive() {
670 let value = Value::Integer(42);
671 assert_eq!(roundtrip(value.clone()), value);
672 }
673
674 #[test]
675 fn test_integer_negative() {
676 let value = Value::Integer(-42);
677 assert_eq!(roundtrip(value.clone()), value);
678 }
679
680 #[test]
681 fn test_integer_zero() {
682 let value = Value::Integer(0);
683 assert_eq!(roundtrip(value.clone()), value);
684 }
685
686 #[test]
687 fn test_integer_min() {
688 let value = Value::Integer(i32::MIN);
689 assert_eq!(roundtrip(value.clone()), value);
690 }
691
692 #[test]
693 fn test_integer_max() {
694 let value = Value::Integer(i32::MAX);
695 assert_eq!(roundtrip(value.clone()), value);
696 }
697
698 #[test]
699 fn test_octet_string_ascii() {
700 let value = Value::OctetString(Bytes::from_static(b"hello world"));
701 assert_eq!(roundtrip(value.clone()), value);
702 }
703
704 #[test]
705 fn test_octet_string_binary() {
706 let value = Value::OctetString(Bytes::from_static(&[0x00, 0xFF, 0x80, 0x7F]));
707 assert_eq!(roundtrip(value.clone()), value);
708 }
709
710 #[test]
711 fn test_octet_string_empty() {
712 let value = Value::OctetString(Bytes::new());
713 assert_eq!(roundtrip(value.clone()), value);
714 }
715
716 #[test]
717 fn test_null() {
718 let value = Value::Null;
719 assert_eq!(roundtrip(value.clone()), value);
720 }
721
722 #[test]
723 fn test_object_identifier() {
724 let value = Value::ObjectIdentifier(crate::oid!(1, 3, 6, 1, 2, 1, 1, 1, 0));
725 assert_eq!(roundtrip(value.clone()), value);
726 }
727
728 #[test]
729 fn test_ip_address() {
730 let value = Value::IpAddress([192, 168, 1, 1]);
731 assert_eq!(roundtrip(value.clone()), value);
732 }
733
734 #[test]
735 fn test_ip_address_zero() {
736 let value = Value::IpAddress([0, 0, 0, 0]);
737 assert_eq!(roundtrip(value.clone()), value);
738 }
739
740 #[test]
741 fn test_ip_address_broadcast() {
742 let value = Value::IpAddress([255, 255, 255, 255]);
743 assert_eq!(roundtrip(value.clone()), value);
744 }
745
746 #[test]
747 fn test_counter32() {
748 let value = Value::Counter32(999999);
749 assert_eq!(roundtrip(value.clone()), value);
750 }
751
752 #[test]
753 fn test_counter32_zero() {
754 let value = Value::Counter32(0);
755 assert_eq!(roundtrip(value.clone()), value);
756 }
757
758 #[test]
759 fn test_counter32_max() {
760 let value = Value::Counter32(u32::MAX);
761 assert_eq!(roundtrip(value.clone()), value);
762 }
763
764 #[test]
765 fn test_gauge32() {
766 let value = Value::Gauge32(1000000000);
767 assert_eq!(roundtrip(value.clone()), value);
768 }
769
770 #[test]
771 fn test_gauge32_max() {
772 let value = Value::Gauge32(u32::MAX);
773 assert_eq!(roundtrip(value.clone()), value);
774 }
775
776 #[test]
777 fn test_timeticks() {
778 let value = Value::TimeTicks(123456);
779 assert_eq!(roundtrip(value.clone()), value);
780 }
781
782 #[test]
783 fn test_timeticks_max() {
784 let value = Value::TimeTicks(u32::MAX);
785 assert_eq!(roundtrip(value.clone()), value);
786 }
787
788 #[test]
789 fn test_opaque() {
790 let value = Value::Opaque(Bytes::from_static(&[0xDE, 0xAD, 0xBE, 0xEF]));
791 assert_eq!(roundtrip(value.clone()), value);
792 }
793
794 #[test]
795 fn test_opaque_empty() {
796 let value = Value::Opaque(Bytes::new());
797 assert_eq!(roundtrip(value.clone()), value);
798 }
799
800 #[test]
801 fn test_counter64() {
802 let value = Value::Counter64(123456789012345);
803 assert_eq!(roundtrip(value.clone()), value);
804 }
805
806 #[test]
807 fn test_counter64_zero() {
808 let value = Value::Counter64(0);
809 assert_eq!(roundtrip(value.clone()), value);
810 }
811
812 #[test]
813 fn test_counter64_max() {
814 let value = Value::Counter64(u64::MAX);
815 assert_eq!(roundtrip(value.clone()), value);
816 }
817
818 #[test]
819 fn test_no_such_object() {
820 let value = Value::NoSuchObject;
821 assert_eq!(roundtrip(value.clone()), value);
822 }
823
824 #[test]
825 fn test_no_such_instance() {
826 let value = Value::NoSuchInstance;
827 assert_eq!(roundtrip(value.clone()), value);
828 }
829
830 #[test]
831 fn test_end_of_mib_view() {
832 let value = Value::EndOfMibView;
833 assert_eq!(roundtrip(value.clone()), value);
834 }
835
836 #[test]
837 fn test_unknown_tag_preserved() {
838 let data = Bytes::from_static(&[0x45, 0x03, 0x01, 0x02, 0x03]);
840 let mut decoder = Decoder::new(data);
841 let value = Value::decode(&mut decoder).unwrap();
842
843 match value {
844 Value::Unknown { tag, ref data } => {
845 assert_eq!(tag, 0x45);
846 assert_eq!(data.as_ref(), &[0x01, 0x02, 0x03]);
847 }
848 _ => panic!("expected Unknown variant"),
849 }
850
851 assert_eq!(roundtrip(value.clone()), value);
853 }
854
855 #[test]
860 fn test_as_i32() {
861 assert_eq!(Value::Integer(42).as_i32(), Some(42));
862 assert_eq!(Value::Integer(-42).as_i32(), Some(-42));
863 assert_eq!(Value::Counter32(100).as_i32(), None);
864 assert_eq!(Value::Null.as_i32(), None);
865 }
866
867 #[test]
868 fn test_as_u32() {
869 assert_eq!(Value::Counter32(100).as_u32(), Some(100));
870 assert_eq!(Value::Gauge32(200).as_u32(), Some(200));
871 assert_eq!(Value::TimeTicks(300).as_u32(), Some(300));
872 assert_eq!(Value::Integer(50).as_u32(), Some(50));
873 assert_eq!(Value::Integer(-1).as_u32(), None);
874 assert_eq!(Value::Counter64(100).as_u32(), None);
875 }
876
877 #[test]
878 fn test_as_u64() {
879 assert_eq!(Value::Counter64(100).as_u64(), Some(100));
880 assert_eq!(Value::Counter32(100).as_u64(), Some(100));
881 assert_eq!(Value::Gauge32(200).as_u64(), Some(200));
882 assert_eq!(Value::TimeTicks(300).as_u64(), Some(300));
883 assert_eq!(Value::Integer(50).as_u64(), Some(50));
884 assert_eq!(Value::Integer(-1).as_u64(), None);
885 }
886
887 #[test]
888 fn test_as_bytes() {
889 let s = Value::OctetString(Bytes::from_static(b"test"));
890 assert_eq!(s.as_bytes(), Some(b"test".as_slice()));
891
892 let o = Value::Opaque(Bytes::from_static(b"data"));
893 assert_eq!(o.as_bytes(), Some(b"data".as_slice()));
894
895 assert_eq!(Value::Integer(1).as_bytes(), None);
896 }
897
898 #[test]
899 fn test_as_str() {
900 let s = Value::OctetString(Bytes::from_static(b"hello"));
901 assert_eq!(s.as_str(), Some("hello"));
902
903 let invalid = Value::OctetString(Bytes::from_static(&[0xFF, 0xFE]));
905 assert_eq!(invalid.as_str(), None);
906
907 assert_eq!(Value::Integer(1).as_str(), None);
908 }
909
910 #[test]
911 fn test_as_oid() {
912 let oid = crate::oid!(1, 3, 6, 1);
913 let v = Value::ObjectIdentifier(oid.clone());
914 assert_eq!(v.as_oid(), Some(&oid));
915
916 assert_eq!(Value::Integer(1).as_oid(), None);
917 }
918
919 #[test]
920 fn test_as_ip() {
921 let v = Value::IpAddress([192, 168, 1, 1]);
922 assert_eq!(v.as_ip(), Some(std::net::Ipv4Addr::new(192, 168, 1, 1)));
923
924 assert_eq!(Value::Integer(1).as_ip(), None);
925 }
926
927 #[test]
932 fn test_is_exception() {
933 assert!(Value::NoSuchObject.is_exception());
934 assert!(Value::NoSuchInstance.is_exception());
935 assert!(Value::EndOfMibView.is_exception());
936
937 assert!(!Value::Integer(1).is_exception());
938 assert!(!Value::Null.is_exception());
939 assert!(!Value::OctetString(Bytes::new()).is_exception());
940 }
941
942 #[test]
947 fn test_display_integer() {
948 assert_eq!(format!("{}", Value::Integer(42)), "42");
949 assert_eq!(format!("{}", Value::Integer(-42)), "-42");
950 }
951
952 #[test]
953 fn test_display_octet_string_utf8() {
954 let v = Value::OctetString(Bytes::from_static(b"hello"));
955 assert_eq!(format!("{}", v), "hello");
956 }
957
958 #[test]
959 fn test_display_octet_string_binary() {
960 let v = Value::OctetString(Bytes::from_static(&[0xFF, 0xFE]));
962 assert_eq!(format!("{}", v), "0xfffe");
963 }
964
965 #[test]
966 fn test_display_null() {
967 assert_eq!(format!("{}", Value::Null), "NULL");
968 }
969
970 #[test]
971 fn test_display_ip_address() {
972 let v = Value::IpAddress([192, 168, 1, 1]);
973 assert_eq!(format!("{}", v), "192.168.1.1");
974 }
975
976 #[test]
977 fn test_display_counter32() {
978 assert_eq!(format!("{}", Value::Counter32(999)), "999");
979 }
980
981 #[test]
982 fn test_display_gauge32() {
983 assert_eq!(format!("{}", Value::Gauge32(1000)), "1000");
984 }
985
986 #[test]
987 fn test_display_timeticks() {
988 let v = Value::TimeTicks(123456);
991 assert_eq!(format!("{}", v), "0d 0h 20m 34s");
992 }
993
994 #[test]
995 fn test_display_opaque() {
996 let v = Value::Opaque(Bytes::from_static(&[0xBE, 0xEF]));
997 assert_eq!(format!("{}", v), "Opaque(0xbeef)");
998 }
999
1000 #[test]
1001 fn test_display_counter64() {
1002 assert_eq!(format!("{}", Value::Counter64(12345678)), "12345678");
1003 }
1004
1005 #[test]
1006 fn test_display_exceptions() {
1007 assert_eq!(format!("{}", Value::NoSuchObject), "noSuchObject");
1008 assert_eq!(format!("{}", Value::NoSuchInstance), "noSuchInstance");
1009 assert_eq!(format!("{}", Value::EndOfMibView), "endOfMibView");
1010 }
1011
1012 #[test]
1013 fn test_display_unknown() {
1014 let v = Value::Unknown {
1015 tag: 0x99,
1016 data: Bytes::from_static(&[0x01, 0x02]),
1017 };
1018 assert_eq!(format!("{}", v), "Unknown(tag=0x99, data=0x0102)");
1019 }
1020
1021 #[test]
1026 fn test_from_i32() {
1027 let v: Value = 42i32.into();
1028 assert_eq!(v, Value::Integer(42));
1029 }
1030
1031 #[test]
1032 fn test_from_str() {
1033 let v: Value = "hello".into();
1034 assert_eq!(v.as_str(), Some("hello"));
1035 }
1036
1037 #[test]
1038 fn test_from_string() {
1039 let v: Value = String::from("hello").into();
1040 assert_eq!(v.as_str(), Some("hello"));
1041 }
1042
1043 #[test]
1044 fn test_from_bytes_slice() {
1045 let v: Value = (&[1u8, 2, 3][..]).into();
1046 assert_eq!(v.as_bytes(), Some(&[1u8, 2, 3][..]));
1047 }
1048
1049 #[test]
1050 fn test_from_oid() {
1051 let oid = crate::oid!(1, 3, 6, 1);
1052 let v: Value = oid.clone().into();
1053 assert_eq!(v.as_oid(), Some(&oid));
1054 }
1055
1056 #[test]
1057 fn test_from_ipv4addr() {
1058 let addr = std::net::Ipv4Addr::new(10, 0, 0, 1);
1059 let v: Value = addr.into();
1060 assert_eq!(v, Value::IpAddress([10, 0, 0, 1]));
1061 }
1062
1063 #[test]
1064 fn test_from_bytes() {
1065 let data = Bytes::from_static(b"hello");
1066 let v: Value = data.into();
1067 assert_eq!(v.as_bytes(), Some(b"hello".as_slice()));
1068 }
1069
1070 #[test]
1071 fn test_from_u64() {
1072 let v: Value = 12345678901234u64.into();
1073 assert_eq!(v, Value::Counter64(12345678901234));
1074 }
1075
1076 #[test]
1077 fn test_from_ip_array() {
1078 let v: Value = [192u8, 168, 1, 1].into();
1079 assert_eq!(v, Value::IpAddress([192, 168, 1, 1]));
1080 }
1081
1082 #[test]
1087 fn test_decode_invalid_null_length() {
1088 let data = Bytes::from_static(&[0x05, 0x01, 0x00]); let mut decoder = Decoder::new(data);
1091 let result = Value::decode(&mut decoder);
1092 assert!(result.is_err());
1093 }
1094
1095 #[test]
1096 fn test_decode_invalid_ip_address_length() {
1097 let data = Bytes::from_static(&[0x40, 0x03, 0x01, 0x02, 0x03]); let mut decoder = Decoder::new(data);
1100 let result = Value::decode(&mut decoder);
1101 assert!(result.is_err());
1102 }
1103
1104 #[test]
1105 fn test_decode_exception_with_content_accepted() {
1106 let data = Bytes::from_static(&[0x80, 0x01, 0xFF]); let mut decoder = Decoder::new(data);
1109 let result = Value::decode(&mut decoder);
1110 assert!(result.is_ok());
1111 assert_eq!(result.unwrap(), Value::NoSuchObject);
1112 }
1113}