1use crate::ber::{Decoder, EncodeBuf, tag};
6use crate::error::internal::DecodeErrorKind;
7use crate::error::{Error, Result, UNKNOWN_TARGET};
8use crate::format::hex;
9use crate::oid::Oid;
10use bytes::Bytes;
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
42pub enum RowStatus {
43 Active = 1,
45 NotInService = 2,
47 NotReady = 3,
49 CreateAndGo = 4,
51 CreateAndWait = 5,
53 Destroy = 6,
55}
56
57impl TryFrom<i32> for RowStatus {
58 type Error = i32;
59
60 fn try_from(value: i32) -> std::result::Result<Self, i32> {
61 match value {
62 1 => Ok(Self::Active),
63 2 => Ok(Self::NotInService),
64 3 => Ok(Self::NotReady),
65 4 => Ok(Self::CreateAndGo),
66 5 => Ok(Self::CreateAndWait),
67 6 => Ok(Self::Destroy),
68 _ => Err(value),
69 }
70 }
71}
72
73impl RowStatus {
74 #[must_use]
78 pub fn from_i32(value: i32) -> Option<Self> {
79 Self::try_from(value).ok()
80 }
81}
82
83impl From<RowStatus> for Value {
84 fn from(status: RowStatus) -> Self {
85 Value::Integer(status as i32)
86 }
87}
88
89impl std::fmt::Display for RowStatus {
90 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
91 match self {
92 Self::Active => write!(f, "active"),
93 Self::NotInService => write!(f, "notInService"),
94 Self::NotReady => write!(f, "notReady"),
95 Self::CreateAndGo => write!(f, "createAndGo"),
96 Self::CreateAndWait => write!(f, "createAndWait"),
97 Self::Destroy => write!(f, "destroy"),
98 }
99 }
100}
101
102#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
130pub enum StorageType {
131 Other = 1,
133 Volatile = 2,
135 NonVolatile = 3,
137 Permanent = 4,
139 ReadOnly = 5,
141}
142
143impl TryFrom<i32> for StorageType {
144 type Error = i32;
145
146 fn try_from(value: i32) -> std::result::Result<Self, i32> {
147 match value {
148 1 => Ok(Self::Other),
149 2 => Ok(Self::Volatile),
150 3 => Ok(Self::NonVolatile),
151 4 => Ok(Self::Permanent),
152 5 => Ok(Self::ReadOnly),
153 _ => Err(value),
154 }
155 }
156}
157
158impl StorageType {
159 #[must_use]
163 pub fn from_i32(value: i32) -> Option<Self> {
164 Self::try_from(value).ok()
165 }
166}
167
168impl From<StorageType> for Value {
169 fn from(storage: StorageType) -> Self {
170 Value::Integer(storage as i32)
171 }
172}
173
174impl std::fmt::Display for StorageType {
175 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
176 match self {
177 Self::Other => write!(f, "other"),
178 Self::Volatile => write!(f, "volatile"),
179 Self::NonVolatile => write!(f, "nonVolatile"),
180 Self::Permanent => write!(f, "permanent"),
181 Self::ReadOnly => write!(f, "readOnly"),
182 }
183 }
184}
185
186#[derive(Debug, Clone, PartialEq, Eq, Hash)]
190#[non_exhaustive]
191pub enum Value {
192 Integer(i32),
194
195 OctetString(Bytes),
202
203 Null,
205
206 ObjectIdentifier(Oid),
208
209 IpAddress([u8; 4]),
211
212 Counter32(u32),
214
215 Gauge32(u32),
217
218 TimeTicks(u32),
220
221 Opaque(Bytes),
223
224 Counter64(u64),
234
235 NoSuchObject,
256
257 NoSuchInstance,
272
273 EndOfMibView,
293
294 Unknown { tag: u8, data: Bytes },
296}
297
298impl Value {
299 pub fn as_i32(&self) -> Option<i32> {
319 match self {
320 Value::Integer(v) => Some(*v),
321 _ => None,
322 }
323 }
324
325 pub fn as_u32(&self) -> Option<u32> {
350 match self {
351 Value::Counter32(v) | Value::Gauge32(v) | Value::TimeTicks(v) => Some(*v),
352 Value::Integer(v) if *v >= 0 => Some(*v as u32),
353 _ => None,
354 }
355 }
356
357 pub fn as_u64(&self) -> Option<u64> {
382 match self {
383 Value::Counter64(v) => Some(*v),
384 Value::Counter32(v) | Value::Gauge32(v) | Value::TimeTicks(v) => Some(u64::from(*v)),
385 Value::Integer(v) if *v >= 0 => Some(*v as u64),
386 _ => None,
387 }
388 }
389
390 pub fn as_bytes(&self) -> Option<&[u8]> {
412 match self {
413 Value::OctetString(v) | Value::Opaque(v) => Some(v),
414 _ => None,
415 }
416 }
417
418 pub fn as_str(&self) -> Option<&str> {
442 self.as_bytes().and_then(|b| std::str::from_utf8(b).ok())
443 }
444
445 pub fn as_oid(&self) -> Option<&Oid> {
462 match self {
463 Value::ObjectIdentifier(oid) => Some(oid),
464 _ => None,
465 }
466 }
467
468 pub fn as_ip(&self) -> Option<std::net::Ipv4Addr> {
485 match self {
486 Value::IpAddress(bytes) => Some(std::net::Ipv4Addr::from(*bytes)),
487 _ => None,
488 }
489 }
490
491 #[expect(
507 clippy::cast_precision_loss,
508 reason = "we intentionally bend over backwards to make an f64 available even for 64-bit ints"
509 )]
510 pub fn as_f64(&self) -> Option<f64> {
511 match self {
512 Value::Integer(v) => Some(f64::from(*v)),
513 Value::Counter32(v) | Value::Gauge32(v) | Value::TimeTicks(v) => Some(f64::from(*v)),
514 Value::Counter64(v) => Some(*v as f64),
515 _ => None,
516 }
517 }
518
519 #[expect(
543 clippy::cast_precision_loss,
544 reason = "we intentionally bend over backwards to make an f64 available even for 64-bit ints"
545 )]
546 pub fn as_f64_wrapped(&self) -> Option<f64> {
547 const MANTISSA_LIMIT: u64 = 1 << 53;
548 match self {
549 Value::Counter64(v) => Some((*v % MANTISSA_LIMIT) as f64),
550 _ => self.as_f64(),
551 }
552 }
553
554 pub fn as_decimal(&self, places: u8) -> Option<f64> {
582 let divisor = 10f64.powi(i32::from(places));
583 self.as_f64().map(|v| v / divisor)
584 }
585
586 pub fn as_duration(&self) -> Option<std::time::Duration> {
607 match self {
608 Value::TimeTicks(v) => Some(std::time::Duration::from_millis(u64::from(*v) * 10)),
609 _ => None,
610 }
611 }
612
613 pub fn as_opaque_float(&self) -> Option<f32> {
639 match self {
640 Value::Opaque(data)
641 if data.len() >= 7
642 && data[0] == 0x9f && data[1] == 0x78 && data[2] == 0x04 =>
645 {
646 let bytes: [u8; 4] = data[3..7].try_into().ok()?;
648 Some(f32::from_be_bytes(bytes))
649 }
650 _ => None,
651 }
652 }
653
654 pub fn as_opaque_double(&self) -> Option<f64> {
676 match self {
677 Value::Opaque(data)
678 if data.len() >= 11
679 && data[0] == 0x9f && data[1] == 0x79 && data[2] == 0x08 =>
682 {
683 let bytes: [u8; 8] = data[3..11].try_into().ok()?;
685 Some(f64::from_be_bytes(bytes))
686 }
687 _ => None,
688 }
689 }
690
691 pub fn as_opaque_counter64(&self) -> Option<u64> {
712 self.as_opaque_unsigned(0x76)
713 }
714
715 pub fn as_opaque_i64(&self) -> Option<i64> {
734 match self {
735 Value::Opaque(data)
736 if data.len() >= 4
737 && data[0] == 0x9f && data[1] == 0x7a =>
739 {
740 let len = data[2] as usize;
742 if data.len() < 3 + len || len == 0 || len > 8 {
743 return None;
744 }
745 let bytes = &data[3..3 + len];
746 let is_negative = bytes[0] & 0x80 != 0;
748 let mut value: i64 = if is_negative { -1 } else { 0 };
749 for &byte in bytes {
750 value = (value << 8) | i64::from(byte);
751 }
752 Some(value)
753 }
754 _ => None,
755 }
756 }
757
758 pub fn as_opaque_u64(&self) -> Option<u64> {
777 self.as_opaque_unsigned(0x7b)
778 }
779
780 fn as_opaque_unsigned(&self, expected_type: u8) -> Option<u64> {
782 match self {
783 Value::Opaque(data)
784 if data.len() >= 4
785 && data[0] == 0x9f && data[1] == expected_type =>
787 {
788 let len = data[2] as usize;
789 if data.len() < 3 + len || len == 0 || len > 8 {
790 return None;
791 }
792 let bytes = &data[3..3 + len];
793 let mut value: u64 = 0;
794 for &byte in bytes {
795 value = (value << 8) | u64::from(byte);
796 }
797 Some(value)
798 }
799 _ => None,
800 }
801 }
802
803 pub fn as_truth_value(&self) -> Option<bool> {
822 match self {
823 Value::Integer(1) => Some(true),
824 Value::Integer(2) => Some(false),
825 _ => None,
826 }
827 }
828
829 pub fn as_row_status(&self) -> Option<RowStatus> {
847 match self {
848 Value::Integer(v) => RowStatus::from_i32(*v),
849 _ => None,
850 }
851 }
852
853 pub fn as_storage_type(&self) -> Option<StorageType> {
871 match self {
872 Value::Integer(v) => StorageType::from_i32(*v),
873 _ => None,
874 }
875 }
876
877 pub fn is_exception(&self) -> bool {
879 matches!(
880 self,
881 Value::NoSuchObject | Value::NoSuchInstance | Value::EndOfMibView
882 )
883 }
884
885 pub(crate) fn ber_encoded_size(&self) -> usize {
887 use crate::ber::{
888 integer_content_len, length_encoded_len, unsigned32_content_len, unsigned64_content_len,
889 };
890
891 match self {
892 Value::Integer(v) => {
893 let content_len = integer_content_len(*v);
894 1 + length_encoded_len(content_len) + content_len
895 }
896 Value::OctetString(data) | Value::Opaque(data) | Value::Unknown { data, .. } => {
897 let content_len = data.len();
898 1 + length_encoded_len(content_len) + content_len
899 }
900 Value::Null | Value::NoSuchObject | Value::NoSuchInstance | Value::EndOfMibView => 2, Value::ObjectIdentifier(oid) => oid.ber_encoded_size(),
902 Value::IpAddress(_) => 6, Value::Counter32(v) | Value::Gauge32(v) | Value::TimeTicks(v) => {
904 let content_len = unsigned32_content_len(*v);
905 1 + length_encoded_len(content_len) + content_len
906 }
907 Value::Counter64(v) => {
908 let content_len = unsigned64_content_len(*v);
909 1 + length_encoded_len(content_len) + content_len
910 }
911 }
912 }
913
914 pub fn format_with_hint(&self, hint: &str) -> Option<String> {
941 match self {
942 Value::OctetString(bytes) => Some(crate::format::display_hint::apply(hint, bytes)),
943 Value::Opaque(bytes) => Some(crate::format::display_hint::apply(hint, bytes)),
944 Value::Integer(v) => crate::format::display_hint::apply_integer(hint, *v),
945 _ => None,
946 }
947 }
948
949 pub fn encode(&self, buf: &mut EncodeBuf) {
951 match self {
952 Value::Integer(v) => buf.push_integer(*v),
953 Value::OctetString(data) => buf.push_octet_string(data),
954 Value::Null => buf.push_null(),
955 Value::ObjectIdentifier(oid) => buf.push_oid(oid),
956 Value::IpAddress(addr) => buf.push_ip_address(*addr),
957 Value::Counter32(v) => buf.push_unsigned32(tag::application::COUNTER32, *v),
958 Value::Gauge32(v) => buf.push_unsigned32(tag::application::GAUGE32, *v),
959 Value::TimeTicks(v) => buf.push_unsigned32(tag::application::TIMETICKS, *v),
960 Value::Opaque(data) => {
961 buf.push_bytes(data);
962 buf.push_length(data.len());
963 buf.push_tag(tag::application::OPAQUE);
964 }
965 Value::Counter64(v) => buf.push_integer64(*v),
966 Value::NoSuchObject => {
967 buf.push_length(0);
968 buf.push_tag(tag::context::NO_SUCH_OBJECT);
969 }
970 Value::NoSuchInstance => {
971 buf.push_length(0);
972 buf.push_tag(tag::context::NO_SUCH_INSTANCE);
973 }
974 Value::EndOfMibView => {
975 buf.push_length(0);
976 buf.push_tag(tag::context::END_OF_MIB_VIEW);
977 }
978 Value::Unknown { tag: t, data } => {
979 buf.push_bytes(data);
980 buf.push_length(data.len());
981 buf.push_tag(*t);
982 }
983 }
984 }
985
986 pub fn decode(decoder: &mut Decoder) -> Result<Self> {
988 let tag = decoder.read_tag()?;
989 let len = decoder.read_length()?;
990
991 match tag {
992 tag::universal::INTEGER => {
993 let value = decoder.read_integer_value(len)?;
994 Ok(Value::Integer(value))
995 }
996 tag::universal::OCTET_STRING => {
997 let available = decoder.remaining();
998 let len = if len > available {
999 tracing::warn!(
1004 target: "async_snmp::value",
1005 { snmp.offset = %decoder.offset(), declared = len, available },
1006 "OctetString length exceeds varbind SEQUENCE boundary, clamping to available bytes"
1007 );
1008 available
1009 } else {
1010 len
1011 };
1012 let data = decoder.read_bytes(len)?;
1013 Ok(Value::OctetString(data))
1014 }
1015 tag::universal::NULL => {
1016 if len != 0 {
1017 tracing::debug!(target: "async_snmp::value", { offset = decoder.offset(), kind = %DecodeErrorKind::InvalidNull }, "decode error");
1018 return Err(Error::MalformedResponse {
1019 target: UNKNOWN_TARGET,
1020 }
1021 .boxed());
1022 }
1023 Ok(Value::Null)
1024 }
1025 tag::universal::OBJECT_IDENTIFIER => {
1026 let oid = decoder.read_oid_value(len)?;
1027 Ok(Value::ObjectIdentifier(oid))
1028 }
1029 tag::application::IP_ADDRESS => {
1030 if len != 4 {
1031 tracing::debug!(target: "async_snmp::value", { offset = decoder.offset(), length = len, kind = %DecodeErrorKind::InvalidIpAddressLength { length: len } }, "decode error");
1032 return Err(Error::MalformedResponse {
1033 target: UNKNOWN_TARGET,
1034 }
1035 .boxed());
1036 }
1037 let data = decoder.read_bytes(4)?;
1038 Ok(Value::IpAddress([data[0], data[1], data[2], data[3]]))
1039 }
1040 tag::application::COUNTER32 => {
1041 let value = decoder.read_unsigned32_value(len)?;
1042 Ok(Value::Counter32(value))
1043 }
1044 tag::application::GAUGE32 => {
1045 let value = decoder.read_unsigned32_value(len)?;
1046 Ok(Value::Gauge32(value))
1047 }
1048 tag::application::TIMETICKS => {
1049 let value = decoder.read_unsigned32_value(len)?;
1050 Ok(Value::TimeTicks(value))
1051 }
1052 tag::application::OPAQUE => {
1053 let available = decoder.remaining();
1054 let len = if len > available {
1055 tracing::warn!(
1056 target: "async_snmp::value",
1057 { snmp.offset = %decoder.offset(), declared = len, available },
1058 "Opaque length exceeds varbind SEQUENCE boundary, clamping to available bytes"
1059 );
1060 available
1061 } else {
1062 len
1063 };
1064 let data = decoder.read_bytes(len)?;
1065 Ok(Value::Opaque(data))
1066 }
1067 tag::application::NSAP => {
1068 let data = decoder.read_bytes(len)?;
1069 Ok(Value::OctetString(data))
1070 }
1071 tag::application::COUNTER64 => {
1072 let value = decoder.read_integer64_value(len)?;
1073 Ok(Value::Counter64(value))
1074 }
1075 tag::application::UINTEGER32 => {
1076 let value = decoder.read_unsigned32_value(len)?;
1077 Ok(Value::Gauge32(value))
1078 }
1079 tag::context::NO_SUCH_OBJECT => {
1080 if len != 0 {
1081 let _ = decoder.read_bytes(len)?;
1082 }
1083 Ok(Value::NoSuchObject)
1084 }
1085 tag::context::NO_SUCH_INSTANCE => {
1086 if len != 0 {
1087 let _ = decoder.read_bytes(len)?;
1088 }
1089 Ok(Value::NoSuchInstance)
1090 }
1091 tag::context::END_OF_MIB_VIEW => {
1092 if len != 0 {
1093 let _ = decoder.read_bytes(len)?;
1094 }
1095 Ok(Value::EndOfMibView)
1096 }
1097 tag::universal::OCTET_STRING_CONSTRUCTED => {
1100 tracing::debug!(target: "async_snmp::value", { offset = decoder.offset(), kind = %DecodeErrorKind::ConstructedOctetString }, "decode error");
1101 Err(Error::MalformedResponse {
1102 target: UNKNOWN_TARGET,
1103 }
1104 .boxed())
1105 }
1106 _ => {
1107 let data = decoder.read_bytes(len)?;
1109 Ok(Value::Unknown { tag, data })
1110 }
1111 }
1112 }
1113}
1114
1115impl std::fmt::Display for Value {
1116 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1117 match self {
1118 Value::Integer(v) => write!(f, "{v}"),
1119 Value::OctetString(data) => {
1120 if let Ok(s) = std::str::from_utf8(data) {
1122 write!(f, "{s}")
1123 } else {
1124 write!(f, "0x{}", hex::encode(data))
1125 }
1126 }
1127 Value::Null => write!(f, "NULL"),
1128 Value::ObjectIdentifier(oid) => write!(f, "{oid}"),
1129 Value::IpAddress(addr) => {
1130 write!(f, "{}.{}.{}.{}", addr[0], addr[1], addr[2], addr[3])
1131 }
1132 Value::Counter32(v) => write!(f, "{v}"),
1133 Value::Gauge32(v) => write!(f, "{v}"),
1134 Value::TimeTicks(v) => {
1135 write!(f, "{}", crate::format::format_timeticks(*v))
1136 }
1137 Value::Opaque(data) => write!(f, "Opaque(0x{})", hex::encode(data)),
1138 Value::Counter64(v) => write!(f, "{v}"),
1139 Value::NoSuchObject => write!(f, "noSuchObject"),
1140 Value::NoSuchInstance => write!(f, "noSuchInstance"),
1141 Value::EndOfMibView => write!(f, "endOfMibView"),
1142 Value::Unknown { tag, data } => {
1143 write!(
1144 f,
1145 "Unknown(tag=0x{:02X}, data=0x{})",
1146 tag,
1147 hex::encode(data)
1148 )
1149 }
1150 }
1151 }
1152}
1153
1154impl From<i32> for Value {
1196 fn from(v: i32) -> Self {
1197 Value::Integer(v)
1198 }
1199}
1200
1201impl From<&str> for Value {
1202 fn from(s: &str) -> Self {
1203 Value::OctetString(Bytes::copy_from_slice(s.as_bytes()))
1204 }
1205}
1206
1207impl From<String> for Value {
1208 fn from(s: String) -> Self {
1209 Value::OctetString(Bytes::from(s))
1210 }
1211}
1212
1213impl From<&[u8]> for Value {
1214 fn from(data: &[u8]) -> Self {
1215 Value::OctetString(Bytes::copy_from_slice(data))
1216 }
1217}
1218
1219impl From<Oid> for Value {
1220 fn from(oid: Oid) -> Self {
1221 Value::ObjectIdentifier(oid)
1222 }
1223}
1224
1225impl From<std::net::Ipv4Addr> for Value {
1226 fn from(addr: std::net::Ipv4Addr) -> Self {
1227 Value::IpAddress(addr.octets())
1228 }
1229}
1230
1231impl From<Bytes> for Value {
1232 fn from(data: Bytes) -> Self {
1233 Value::OctetString(data)
1234 }
1235}
1236
1237impl From<u64> for Value {
1238 fn from(v: u64) -> Self {
1239 Value::Counter64(v)
1240 }
1241}
1242
1243impl From<[u8; 4]> for Value {
1249 fn from(addr: [u8; 4]) -> Self {
1250 Value::IpAddress(addr)
1251 }
1252}
1253
1254#[cfg(test)]
1255mod tests {
1256 use super::*;
1257
1258 #[test]
1261 fn test_reject_constructed_octet_string() {
1262 let data = bytes::Bytes::from_static(&[0x24, 0x03, 0x04, 0x01, 0x41]);
1266 let mut decoder = Decoder::new(data);
1267 let result = Value::decode(&mut decoder);
1268
1269 assert!(
1270 result.is_err(),
1271 "constructed OCTET STRING (0x24) should be rejected"
1272 );
1273 let err = result.unwrap_err();
1275 assert!(
1276 matches!(&*err, crate::Error::MalformedResponse { .. }),
1277 "expected MalformedResponse error, got: {err:?}"
1278 );
1279 }
1280
1281 #[test]
1282 fn test_primitive_octet_string_accepted() {
1283 let data = bytes::Bytes::from_static(&[0x04, 0x03, 0x41, 0x42, 0x43]); let mut decoder = Decoder::new(data);
1286 let result = Value::decode(&mut decoder);
1287
1288 assert!(result.is_ok(), "primitive OCTET STRING should be accepted");
1289 let value = result.unwrap();
1290 assert_eq!(value.as_bytes(), Some(&b"ABC"[..]));
1291 }
1292
1293 fn roundtrip(value: &Value) -> Value {
1298 let mut buf = EncodeBuf::new();
1299 value.encode(&mut buf);
1300 let data = buf.finish();
1301 let mut decoder = Decoder::new(data);
1302 Value::decode(&mut decoder).unwrap()
1303 }
1304
1305 #[test]
1306 fn test_integer_positive() {
1307 let value = Value::Integer(42);
1308 assert_eq!(roundtrip(&value), value);
1309 }
1310
1311 #[test]
1312 fn test_integer_negative() {
1313 let value = Value::Integer(-42);
1314 assert_eq!(roundtrip(&value), value);
1315 }
1316
1317 #[test]
1318 fn test_integer_zero() {
1319 let value = Value::Integer(0);
1320 assert_eq!(roundtrip(&value), value);
1321 }
1322
1323 #[test]
1324 fn test_integer_min() {
1325 let value = Value::Integer(i32::MIN);
1326 assert_eq!(roundtrip(&value), value);
1327 }
1328
1329 #[test]
1330 fn test_integer_max() {
1331 let value = Value::Integer(i32::MAX);
1332 assert_eq!(roundtrip(&value), value);
1333 }
1334
1335 #[test]
1336 fn test_octet_string_ascii() {
1337 let value = Value::OctetString(Bytes::from_static(b"hello world"));
1338 assert_eq!(roundtrip(&value), value);
1339 }
1340
1341 #[test]
1342 fn test_octet_string_binary() {
1343 let value = Value::OctetString(Bytes::from_static(&[0x00, 0xFF, 0x80, 0x7F]));
1344 assert_eq!(roundtrip(&value), value);
1345 }
1346
1347 #[test]
1348 fn test_octet_string_empty() {
1349 let value = Value::OctetString(Bytes::new());
1350 assert_eq!(roundtrip(&value), value);
1351 }
1352
1353 #[test]
1354 fn test_null() {
1355 let value = Value::Null;
1356 assert_eq!(roundtrip(&value), value);
1357 }
1358
1359 #[test]
1360 fn test_object_identifier() {
1361 let value = Value::ObjectIdentifier(crate::oid!(1, 3, 6, 1, 2, 1, 1, 1, 0));
1362 assert_eq!(roundtrip(&value), value);
1363 }
1364
1365 #[test]
1366 fn test_ip_address() {
1367 let value = Value::IpAddress([192, 168, 1, 1]);
1368 assert_eq!(roundtrip(&value), value);
1369 }
1370
1371 #[test]
1372 fn test_ip_address_zero() {
1373 let value = Value::IpAddress([0, 0, 0, 0]);
1374 assert_eq!(roundtrip(&value), value);
1375 }
1376
1377 #[test]
1378 fn test_ip_address_broadcast() {
1379 let value = Value::IpAddress([255, 255, 255, 255]);
1380 assert_eq!(roundtrip(&value), value);
1381 }
1382
1383 #[test]
1384 fn test_counter32() {
1385 let value = Value::Counter32(999_999);
1386 assert_eq!(roundtrip(&value), value);
1387 }
1388
1389 #[test]
1390 fn test_counter32_zero() {
1391 let value = Value::Counter32(0);
1392 assert_eq!(roundtrip(&value), value);
1393 }
1394
1395 #[test]
1396 fn test_counter32_max() {
1397 let value = Value::Counter32(u32::MAX);
1398 assert_eq!(roundtrip(&value), value);
1399 }
1400
1401 #[test]
1402 fn test_gauge32() {
1403 let value = Value::Gauge32(1_000_000_000);
1404 assert_eq!(roundtrip(&value), value);
1405 }
1406
1407 #[test]
1408 fn test_gauge32_max() {
1409 let value = Value::Gauge32(u32::MAX);
1410 assert_eq!(roundtrip(&value), value);
1411 }
1412
1413 #[test]
1414 fn test_timeticks() {
1415 let value = Value::TimeTicks(123_456);
1416 assert_eq!(roundtrip(&value), value);
1417 }
1418
1419 #[test]
1420 fn test_timeticks_max() {
1421 let value = Value::TimeTicks(u32::MAX);
1422 assert_eq!(roundtrip(&value), value);
1423 }
1424
1425 #[test]
1426 fn test_opaque() {
1427 let value = Value::Opaque(Bytes::from_static(&[0xDE, 0xAD, 0xBE, 0xEF]));
1428 assert_eq!(roundtrip(&value), value);
1429 }
1430
1431 #[test]
1432 fn test_opaque_empty() {
1433 let value = Value::Opaque(Bytes::new());
1434 assert_eq!(roundtrip(&value), value);
1435 }
1436
1437 #[test]
1438 fn test_counter64() {
1439 let value = Value::Counter64(123_456_789_012_345);
1440 assert_eq!(roundtrip(&value), value);
1441 }
1442
1443 #[test]
1444 fn test_counter64_zero() {
1445 let value = Value::Counter64(0);
1446 assert_eq!(roundtrip(&value), value);
1447 }
1448
1449 #[test]
1450 fn test_counter64_max() {
1451 let value = Value::Counter64(u64::MAX);
1452 assert_eq!(roundtrip(&value), value);
1453 }
1454
1455 #[test]
1456 fn test_no_such_object() {
1457 let value = Value::NoSuchObject;
1458 assert_eq!(roundtrip(&value), value);
1459 }
1460
1461 #[test]
1462 fn test_no_such_instance() {
1463 let value = Value::NoSuchInstance;
1464 assert_eq!(roundtrip(&value), value);
1465 }
1466
1467 #[test]
1468 fn test_end_of_mib_view() {
1469 let value = Value::EndOfMibView;
1470 assert_eq!(roundtrip(&value), value);
1471 }
1472
1473 #[test]
1474 fn test_unknown_tag_preserved() {
1475 let data = Bytes::from_static(&[0x48, 0x03, 0x01, 0x02, 0x03]);
1477 let mut decoder = Decoder::new(data);
1478 let value = Value::decode(&mut decoder).unwrap();
1479
1480 match value {
1481 Value::Unknown { tag, ref data } => {
1482 assert_eq!(tag, 0x48);
1483 assert_eq!(data.as_ref(), &[0x01, 0x02, 0x03]);
1484 }
1485 _ => panic!("expected Unknown variant"),
1486 }
1487
1488 assert_eq!(roundtrip(&value), value);
1490 }
1491
1492 #[test]
1493 fn test_nsap_decodes_as_octet_string() {
1494 let data = Bytes::from_static(&[0x45, 0x03, 0x01, 0x02, 0x03]);
1496 let mut decoder = Decoder::new(data);
1497 let value = Value::decode(&mut decoder).unwrap();
1498 assert_eq!(
1499 value,
1500 Value::OctetString(Bytes::from_static(&[0x01, 0x02, 0x03]))
1501 );
1502 }
1503
1504 #[test]
1505 fn test_uinteger32_decodes_as_gauge32() {
1506 let data = Bytes::from_static(&[0x47, 0x01, 0x2a]);
1508 let mut decoder = Decoder::new(data);
1509 let value = Value::decode(&mut decoder).unwrap();
1510 assert_eq!(value, Value::Gauge32(42));
1511 }
1512
1513 #[test]
1518 fn test_as_i32() {
1519 assert_eq!(Value::Integer(42).as_i32(), Some(42));
1520 assert_eq!(Value::Integer(-42).as_i32(), Some(-42));
1521 assert_eq!(Value::Counter32(100).as_i32(), None);
1522 assert_eq!(Value::Null.as_i32(), None);
1523 }
1524
1525 #[test]
1526 fn test_as_u32() {
1527 assert_eq!(Value::Counter32(100).as_u32(), Some(100));
1528 assert_eq!(Value::Gauge32(200).as_u32(), Some(200));
1529 assert_eq!(Value::TimeTicks(300).as_u32(), Some(300));
1530 assert_eq!(Value::Integer(50).as_u32(), Some(50));
1531 assert_eq!(Value::Integer(-1).as_u32(), None);
1532 assert_eq!(Value::Counter64(100).as_u32(), None);
1533 }
1534
1535 #[test]
1536 fn test_as_u64() {
1537 assert_eq!(Value::Counter64(100).as_u64(), Some(100));
1538 assert_eq!(Value::Counter32(100).as_u64(), Some(100));
1539 assert_eq!(Value::Gauge32(200).as_u64(), Some(200));
1540 assert_eq!(Value::TimeTicks(300).as_u64(), Some(300));
1541 assert_eq!(Value::Integer(50).as_u64(), Some(50));
1542 assert_eq!(Value::Integer(-1).as_u64(), None);
1543 }
1544
1545 #[test]
1546 fn test_as_bytes() {
1547 let s = Value::OctetString(Bytes::from_static(b"test"));
1548 assert_eq!(s.as_bytes(), Some(b"test".as_slice()));
1549
1550 let o = Value::Opaque(Bytes::from_static(b"data"));
1551 assert_eq!(o.as_bytes(), Some(b"data".as_slice()));
1552
1553 assert_eq!(Value::Integer(1).as_bytes(), None);
1554 }
1555
1556 #[test]
1557 fn test_as_str() {
1558 let s = Value::OctetString(Bytes::from_static(b"hello"));
1559 assert_eq!(s.as_str(), Some("hello"));
1560
1561 let invalid = Value::OctetString(Bytes::from_static(&[0xFF, 0xFE]));
1563 assert_eq!(invalid.as_str(), None);
1564
1565 assert_eq!(Value::Integer(1).as_str(), None);
1566 }
1567
1568 #[test]
1569 fn test_as_oid() {
1570 let oid = crate::oid!(1, 3, 6, 1);
1571 let v = Value::ObjectIdentifier(oid.clone());
1572 assert_eq!(v.as_oid(), Some(&oid));
1573
1574 assert_eq!(Value::Integer(1).as_oid(), None);
1575 }
1576
1577 #[test]
1578 fn test_as_ip() {
1579 let v = Value::IpAddress([192, 168, 1, 1]);
1580 assert_eq!(v.as_ip(), Some(std::net::Ipv4Addr::new(192, 168, 1, 1)));
1581
1582 assert_eq!(Value::Integer(1).as_ip(), None);
1583 }
1584
1585 #[test]
1590 fn test_is_exception() {
1591 assert!(Value::NoSuchObject.is_exception());
1592 assert!(Value::NoSuchInstance.is_exception());
1593 assert!(Value::EndOfMibView.is_exception());
1594
1595 assert!(!Value::Integer(1).is_exception());
1596 assert!(!Value::Null.is_exception());
1597 assert!(!Value::OctetString(Bytes::new()).is_exception());
1598 }
1599
1600 #[test]
1605 fn test_display_integer() {
1606 assert_eq!(format!("{}", Value::Integer(42)), "42");
1607 assert_eq!(format!("{}", Value::Integer(-42)), "-42");
1608 }
1609
1610 #[test]
1611 fn test_display_octet_string_utf8() {
1612 let v = Value::OctetString(Bytes::from_static(b"hello"));
1613 assert_eq!(format!("{v}"), "hello");
1614 }
1615
1616 #[test]
1617 fn test_display_octet_string_binary() {
1618 let v = Value::OctetString(Bytes::from_static(&[0xFF, 0xFE]));
1620 assert_eq!(format!("{v}"), "0xfffe");
1621 }
1622
1623 #[test]
1624 fn test_display_null() {
1625 assert_eq!(format!("{}", Value::Null), "NULL");
1626 }
1627
1628 #[test]
1629 fn test_display_ip_address() {
1630 let v = Value::IpAddress([192, 168, 1, 1]);
1631 assert_eq!(format!("{v}"), "192.168.1.1");
1632 }
1633
1634 #[test]
1635 fn test_display_counter32() {
1636 assert_eq!(format!("{}", Value::Counter32(999)), "999");
1637 }
1638
1639 #[test]
1640 fn test_display_gauge32() {
1641 assert_eq!(format!("{}", Value::Gauge32(1000)), "1000");
1642 }
1643
1644 #[test]
1645 fn test_display_timeticks() {
1646 let v = Value::TimeTicks(123_456);
1648 assert_eq!(format!("{v}"), "00:20:34.56");
1649 }
1650
1651 #[test]
1652 fn test_display_opaque() {
1653 let v = Value::Opaque(Bytes::from_static(&[0xBE, 0xEF]));
1654 assert_eq!(format!("{v}"), "Opaque(0xbeef)");
1655 }
1656
1657 #[test]
1658 fn test_display_counter64() {
1659 assert_eq!(format!("{}", Value::Counter64(1234_5678)), "12345678");
1660 }
1661
1662 #[test]
1663 fn test_display_exceptions() {
1664 assert_eq!(format!("{}", Value::NoSuchObject), "noSuchObject");
1665 assert_eq!(format!("{}", Value::NoSuchInstance), "noSuchInstance");
1666 assert_eq!(format!("{}", Value::EndOfMibView), "endOfMibView");
1667 }
1668
1669 #[test]
1670 fn test_display_unknown() {
1671 let v = Value::Unknown {
1672 tag: 0x99,
1673 data: Bytes::from_static(&[0x01, 0x02]),
1674 };
1675 assert_eq!(format!("{v}"), "Unknown(tag=0x99, data=0x0102)");
1676 }
1677
1678 #[test]
1683 fn test_from_i32() {
1684 let v: Value = 42i32.into();
1685 assert_eq!(v, Value::Integer(42));
1686 }
1687
1688 #[test]
1689 fn test_from_str() {
1690 let v: Value = "hello".into();
1691 assert_eq!(v.as_str(), Some("hello"));
1692 }
1693
1694 #[test]
1695 fn test_from_string() {
1696 let v: Value = String::from("hello").into();
1697 assert_eq!(v.as_str(), Some("hello"));
1698 }
1699
1700 #[test]
1701 fn test_from_bytes_slice() {
1702 let v: Value = (&[1u8, 2, 3][..]).into();
1703 assert_eq!(v.as_bytes(), Some(&[1u8, 2, 3][..]));
1704 }
1705
1706 #[test]
1707 fn test_from_oid() {
1708 let oid = crate::oid!(1, 3, 6, 1);
1709 let v: Value = oid.clone().into();
1710 assert_eq!(v.as_oid(), Some(&oid));
1711 }
1712
1713 #[test]
1714 fn test_from_ipv4addr() {
1715 let addr = std::net::Ipv4Addr::new(10, 0, 0, 1);
1716 let v: Value = addr.into();
1717 assert_eq!(v, Value::IpAddress([10, 0, 0, 1]));
1718 }
1719
1720 #[test]
1721 fn test_from_bytes() {
1722 let data = Bytes::from_static(b"hello");
1723 let v: Value = data.into();
1724 assert_eq!(v.as_bytes(), Some(b"hello".as_slice()));
1725 }
1726
1727 #[test]
1728 fn test_from_u64() {
1729 let v: Value = 12_345_678_901_234_u64.into();
1730 assert_eq!(v, Value::Counter64(12_345_678_901_234));
1731 }
1732
1733 #[test]
1734 fn test_from_ip_array() {
1735 let v: Value = [192u8, 168, 1, 1].into();
1736 assert_eq!(v, Value::IpAddress([192, 168, 1, 1]));
1737 }
1738
1739 #[test]
1744 fn test_value_eq_and_hash() {
1745 use std::collections::HashSet;
1746
1747 let mut set = HashSet::new();
1748 set.insert(Value::Integer(42));
1749 set.insert(Value::Integer(42)); set.insert(Value::Integer(100));
1751
1752 assert_eq!(set.len(), 2);
1753 assert!(set.contains(&Value::Integer(42)));
1754 assert!(set.contains(&Value::Integer(100)));
1755 }
1756
1757 #[test]
1762 fn test_decode_invalid_null_length() {
1763 let data = Bytes::from_static(&[0x05, 0x01, 0x00]); let mut decoder = Decoder::new(data);
1766 let result = Value::decode(&mut decoder);
1767 assert!(result.is_err());
1768 }
1769
1770 #[test]
1771 fn test_decode_invalid_ip_address_length() {
1772 let data = Bytes::from_static(&[0x40, 0x03, 0x01, 0x02, 0x03]); let mut decoder = Decoder::new(data);
1775 let result = Value::decode(&mut decoder);
1776 assert!(result.is_err());
1777 }
1778
1779 #[test]
1780 fn test_decode_exception_with_content_accepted() {
1781 let data = Bytes::from_static(&[0x80, 0x01, 0xFF]); let mut decoder = Decoder::new(data);
1784 let result = Value::decode(&mut decoder);
1785 assert!(result.is_ok());
1786 assert_eq!(result.unwrap(), Value::NoSuchObject);
1787 }
1788
1789 #[test]
1794 fn test_as_f64() {
1795 assert_eq!(Value::Integer(42).as_f64(), Some(42.0));
1796 assert_eq!(Value::Integer(-42).as_f64(), Some(-42.0));
1797 assert_eq!(Value::Counter32(1000).as_f64(), Some(1000.0));
1798 assert_eq!(Value::Gauge32(2000).as_f64(), Some(2000.0));
1799 assert_eq!(Value::TimeTicks(3000).as_f64(), Some(3000.0));
1800 assert_eq!(
1801 Value::Counter64(10_000_000_000).as_f64(),
1802 Some(10_000_000_000.0)
1803 );
1804 assert_eq!(Value::Null.as_f64(), None);
1805 assert_eq!(
1806 Value::OctetString(Bytes::from_static(b"test")).as_f64(),
1807 None
1808 );
1809 }
1810
1811 #[test]
1812 fn test_as_f64_wrapped() {
1813 assert_eq!(Value::Counter64(1000).as_f64_wrapped(), Some(1000.0));
1815 assert_eq!(Value::Counter32(1000).as_f64_wrapped(), Some(1000.0));
1816 assert_eq!(Value::Integer(42).as_f64_wrapped(), Some(42.0));
1817
1818 let mantissa_limit = 1u64 << 53;
1820 assert_eq!(Value::Counter64(mantissa_limit).as_f64_wrapped(), Some(0.0));
1821 assert_eq!(
1822 Value::Counter64(mantissa_limit + 1).as_f64_wrapped(),
1823 Some(1.0)
1824 );
1825 }
1826
1827 #[test]
1828 fn test_as_decimal() {
1829 assert_eq!(Value::Integer(2350).as_decimal(2), Some(23.50));
1830 assert_eq!(Value::Integer(9999).as_decimal(2), Some(99.99));
1831 assert_eq!(Value::Integer(12500).as_decimal(3), Some(12.5));
1832 assert_eq!(Value::Integer(-500).as_decimal(2), Some(-5.0));
1833 assert_eq!(Value::Counter32(1000).as_decimal(1), Some(100.0));
1834 assert_eq!(Value::Null.as_decimal(2), None);
1835 }
1836
1837 #[test]
1838 fn test_as_duration() {
1839 use std::time::Duration;
1840
1841 assert_eq!(
1843 Value::TimeTicks(100).as_duration(),
1844 Some(Duration::from_secs(1))
1845 );
1846 assert_eq!(
1848 Value::TimeTicks(360_000).as_duration(),
1849 Some(Duration::from_secs(3600))
1850 );
1851 assert_eq!(
1853 Value::TimeTicks(1).as_duration(),
1854 Some(Duration::from_millis(10))
1855 );
1856
1857 assert_eq!(Value::Integer(100).as_duration(), None);
1859 assert_eq!(Value::Counter32(100).as_duration(), None);
1860 }
1861
1862 #[test]
1867 fn test_as_opaque_float() {
1868 let data = Bytes::from_static(&[0x9f, 0x78, 0x04, 0x40, 0x49, 0x0f, 0xdb]);
1871 let value = Value::Opaque(data);
1872 let pi = value.as_opaque_float().unwrap();
1873 assert!((pi - std::f32::consts::PI).abs() < 0.0001);
1874
1875 assert_eq!(Value::Integer(42).as_opaque_float(), None);
1877
1878 let wrong_type = Bytes::from_static(&[0x9f, 0x79, 0x04, 0x40, 0x49, 0x0f, 0xdb]);
1880 assert_eq!(Value::Opaque(wrong_type).as_opaque_float(), None);
1881
1882 let short = Bytes::from_static(&[0x9f, 0x78, 0x04, 0x40, 0x49]);
1884 assert_eq!(Value::Opaque(short).as_opaque_float(), None);
1885 }
1886
1887 #[test]
1888 fn test_as_opaque_double() {
1889 let data = Bytes::from_static(&[
1892 0x9f, 0x79, 0x08, 0x40, 0x09, 0x21, 0xfb, 0x54, 0x44, 0x2d, 0x18,
1893 ]);
1894 let value = Value::Opaque(data);
1895 let pi = value.as_opaque_double().unwrap();
1896 assert!((pi - std::f64::consts::PI).abs() < 1e-10);
1897
1898 assert_eq!(Value::Integer(42).as_opaque_double(), None);
1900 }
1901
1902 #[test]
1903 fn test_as_opaque_counter64() {
1904 let data = Bytes::from_static(&[
1906 0x9f, 0x76, 0x08, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
1907 ]);
1908 let value = Value::Opaque(data);
1909 assert_eq!(value.as_opaque_counter64(), Some(0x0123_4567_89AB_CDEF));
1910
1911 let small = Bytes::from_static(&[0x9f, 0x76, 0x01, 0x42]);
1913 assert_eq!(Value::Opaque(small).as_opaque_counter64(), Some(0x42));
1914
1915 let zero = Bytes::from_static(&[0x9f, 0x76, 0x01, 0x00]);
1917 assert_eq!(Value::Opaque(zero).as_opaque_counter64(), Some(0));
1918 }
1919
1920 #[test]
1921 fn test_as_opaque_i64() {
1922 let positive = Bytes::from_static(&[0x9f, 0x7a, 0x02, 0x01, 0x00]);
1924 assert_eq!(Value::Opaque(positive).as_opaque_i64(), Some(256));
1925
1926 let minus_one = Bytes::from_static(&[0x9f, 0x7a, 0x01, 0xFF]);
1928 assert_eq!(Value::Opaque(minus_one).as_opaque_i64(), Some(-1));
1929
1930 let full_neg = Bytes::from_static(&[
1932 0x9f, 0x7a, 0x08, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
1933 ]);
1934 assert_eq!(Value::Opaque(full_neg).as_opaque_i64(), Some(-1));
1935
1936 let min = Bytes::from_static(&[
1938 0x9f, 0x7a, 0x08, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1939 ]);
1940 assert_eq!(Value::Opaque(min).as_opaque_i64(), Some(i64::MIN));
1941 }
1942
1943 #[test]
1944 fn test_as_opaque_u64() {
1945 let data = Bytes::from_static(&[
1947 0x9f, 0x7b, 0x08, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
1948 ]);
1949 let value = Value::Opaque(data);
1950 assert_eq!(value.as_opaque_u64(), Some(0x0123_4567_89AB_CDEF));
1951
1952 let max = Bytes::from_static(&[
1954 0x9f, 0x7b, 0x08, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
1955 ]);
1956 assert_eq!(Value::Opaque(max).as_opaque_u64(), Some(u64::MAX));
1957 }
1958
1959 #[test]
1960 fn test_format_with_hint_integer() {
1961 assert_eq!(
1963 Value::Integer(2350).format_with_hint("d-2"),
1964 Some("23.50".into())
1965 );
1966 assert_eq!(
1967 Value::Integer(-500).format_with_hint("d-2"),
1968 Some("-5.00".into())
1969 );
1970
1971 assert_eq!(Value::Integer(255).format_with_hint("x"), Some("ff".into()));
1973 assert_eq!(Value::Integer(8).format_with_hint("o"), Some("10".into()));
1974 assert_eq!(Value::Integer(5).format_with_hint("b"), Some("101".into()));
1975 assert_eq!(Value::Integer(42).format_with_hint("d"), Some("42".into()));
1976
1977 assert_eq!(Value::Integer(42).format_with_hint("invalid"), None);
1979
1980 assert_eq!(Value::Counter32(42).format_with_hint("d-2"), None);
1982 }
1983
1984 #[test]
1985 fn test_as_truth_value() {
1986 assert_eq!(Value::Integer(1).as_truth_value(), Some(true));
1988 assert_eq!(Value::Integer(2).as_truth_value(), Some(false));
1989
1990 assert_eq!(Value::Integer(0).as_truth_value(), None);
1992 assert_eq!(Value::Integer(3).as_truth_value(), None);
1993 assert_eq!(Value::Integer(-1).as_truth_value(), None);
1994
1995 assert_eq!(Value::Null.as_truth_value(), None);
1997 assert_eq!(Value::Counter32(1).as_truth_value(), None);
1998 assert_eq!(Value::Gauge32(1).as_truth_value(), None);
1999 }
2000
2001 #[test]
2006 fn test_row_status_from_i32() {
2007 assert_eq!(RowStatus::from_i32(1), Some(RowStatus::Active));
2008 assert_eq!(RowStatus::from_i32(2), Some(RowStatus::NotInService));
2009 assert_eq!(RowStatus::from_i32(3), Some(RowStatus::NotReady));
2010 assert_eq!(RowStatus::from_i32(4), Some(RowStatus::CreateAndGo));
2011 assert_eq!(RowStatus::from_i32(5), Some(RowStatus::CreateAndWait));
2012 assert_eq!(RowStatus::from_i32(6), Some(RowStatus::Destroy));
2013
2014 assert_eq!(RowStatus::from_i32(0), None);
2016 assert_eq!(RowStatus::from_i32(7), None);
2017 assert_eq!(RowStatus::from_i32(-1), None);
2018 }
2019
2020 #[test]
2021 fn test_row_status_try_from() {
2022 assert_eq!(RowStatus::try_from(1), Ok(RowStatus::Active));
2023 assert_eq!(RowStatus::try_from(6), Ok(RowStatus::Destroy));
2024 assert_eq!(RowStatus::try_from(0), Err(0));
2025 assert_eq!(RowStatus::try_from(7), Err(7));
2026 assert_eq!(RowStatus::try_from(-1), Err(-1));
2027 }
2028
2029 #[test]
2030 fn test_row_status_into_value() {
2031 let v: Value = RowStatus::Active.into();
2032 assert_eq!(v, Value::Integer(1));
2033
2034 let v: Value = RowStatus::Destroy.into();
2035 assert_eq!(v, Value::Integer(6));
2036 }
2037
2038 #[test]
2039 fn test_row_status_display() {
2040 assert_eq!(format!("{}", RowStatus::Active), "active");
2041 assert_eq!(format!("{}", RowStatus::NotInService), "notInService");
2042 assert_eq!(format!("{}", RowStatus::NotReady), "notReady");
2043 assert_eq!(format!("{}", RowStatus::CreateAndGo), "createAndGo");
2044 assert_eq!(format!("{}", RowStatus::CreateAndWait), "createAndWait");
2045 assert_eq!(format!("{}", RowStatus::Destroy), "destroy");
2046 }
2047
2048 #[test]
2049 fn test_as_row_status() {
2050 assert_eq!(Value::Integer(1).as_row_status(), Some(RowStatus::Active));
2052 assert_eq!(Value::Integer(6).as_row_status(), Some(RowStatus::Destroy));
2053
2054 assert_eq!(Value::Integer(0).as_row_status(), None);
2056 assert_eq!(Value::Integer(7).as_row_status(), None);
2057
2058 assert_eq!(Value::Null.as_row_status(), None);
2060 assert_eq!(Value::Counter32(1).as_row_status(), None);
2061 }
2062
2063 #[test]
2068 fn test_storage_type_from_i32() {
2069 assert_eq!(StorageType::from_i32(1), Some(StorageType::Other));
2070 assert_eq!(StorageType::from_i32(2), Some(StorageType::Volatile));
2071 assert_eq!(StorageType::from_i32(3), Some(StorageType::NonVolatile));
2072 assert_eq!(StorageType::from_i32(4), Some(StorageType::Permanent));
2073 assert_eq!(StorageType::from_i32(5), Some(StorageType::ReadOnly));
2074
2075 assert_eq!(StorageType::from_i32(0), None);
2077 assert_eq!(StorageType::from_i32(6), None);
2078 assert_eq!(StorageType::from_i32(-1), None);
2079 }
2080
2081 #[test]
2082 fn test_storage_type_try_from() {
2083 assert_eq!(StorageType::try_from(1), Ok(StorageType::Other));
2084 assert_eq!(StorageType::try_from(5), Ok(StorageType::ReadOnly));
2085 assert_eq!(StorageType::try_from(0), Err(0));
2086 assert_eq!(StorageType::try_from(6), Err(6));
2087 assert_eq!(StorageType::try_from(-1), Err(-1));
2088 }
2089
2090 #[test]
2091 fn test_storage_type_into_value() {
2092 let v: Value = StorageType::Volatile.into();
2093 assert_eq!(v, Value::Integer(2));
2094
2095 let v: Value = StorageType::NonVolatile.into();
2096 assert_eq!(v, Value::Integer(3));
2097 }
2098
2099 #[test]
2100 fn test_storage_type_display() {
2101 assert_eq!(format!("{}", StorageType::Other), "other");
2102 assert_eq!(format!("{}", StorageType::Volatile), "volatile");
2103 assert_eq!(format!("{}", StorageType::NonVolatile), "nonVolatile");
2104 assert_eq!(format!("{}", StorageType::Permanent), "permanent");
2105 assert_eq!(format!("{}", StorageType::ReadOnly), "readOnly");
2106 }
2107
2108 #[test]
2109 fn test_as_storage_type() {
2110 assert_eq!(
2112 Value::Integer(2).as_storage_type(),
2113 Some(StorageType::Volatile)
2114 );
2115 assert_eq!(
2116 Value::Integer(3).as_storage_type(),
2117 Some(StorageType::NonVolatile)
2118 );
2119
2120 assert_eq!(Value::Integer(0).as_storage_type(), None);
2122 assert_eq!(Value::Integer(6).as_storage_type(), None);
2123
2124 assert_eq!(Value::Null.as_storage_type(), None);
2126 assert_eq!(Value::Counter32(1).as_storage_type(), None);
2127 }
2128}