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 UInteger32(u32),
225
226 TimeTicks(u32),
228
229 Opaque(Bytes),
231
232 Nsap(Bytes),
240
241 Counter64(u64),
251
252 NoSuchObject,
273
274 NoSuchInstance,
289
290 EndOfMibView,
310
311 Unknown { tag: u8, data: Bytes },
319}
320
321impl Value {
322 pub fn as_i32(&self) -> Option<i32> {
342 match self {
343 Value::Integer(v) => Some(*v),
344 _ => None,
345 }
346 }
347
348 pub fn as_u32(&self) -> Option<u32> {
374 match self {
375 Value::Counter32(v)
376 | Value::Gauge32(v)
377 | Value::UInteger32(v)
378 | Value::TimeTicks(v) => Some(*v),
379 Value::Integer(v) if *v >= 0 => Some(*v as u32),
380 _ => None,
381 }
382 }
383
384 pub fn as_u64(&self) -> Option<u64> {
410 match self {
411 Value::Counter64(v) => Some(*v),
412 Value::Counter32(v)
413 | Value::Gauge32(v)
414 | Value::UInteger32(v)
415 | Value::TimeTicks(v) => Some(u64::from(*v)),
416 Value::Integer(v) if *v >= 0 => Some(*v as u64),
417 _ => None,
418 }
419 }
420
421 pub fn as_bytes(&self) -> Option<&[u8]> {
443 match self {
444 Value::OctetString(v) | Value::Opaque(v) | Value::Nsap(v) => Some(v),
445 _ => None,
446 }
447 }
448
449 pub fn as_str(&self) -> Option<&str> {
474 self.as_bytes().and_then(|b| std::str::from_utf8(b).ok())
475 }
476
477 pub fn as_oid(&self) -> Option<&Oid> {
494 match self {
495 Value::ObjectIdentifier(oid) => Some(oid),
496 _ => None,
497 }
498 }
499
500 pub fn as_ip(&self) -> Option<std::net::Ipv4Addr> {
517 match self {
518 Value::IpAddress(bytes) => Some(std::net::Ipv4Addr::from(*bytes)),
519 _ => None,
520 }
521 }
522
523 #[expect(
539 clippy::cast_precision_loss,
540 reason = "we intentionally bend over backwards to make an f64 available even for 64-bit ints"
541 )]
542 pub fn as_f64(&self) -> Option<f64> {
543 match self {
544 Value::Integer(v) => Some(f64::from(*v)),
545 Value::Counter32(v)
546 | Value::Gauge32(v)
547 | Value::UInteger32(v)
548 | Value::TimeTicks(v) => Some(f64::from(*v)),
549 Value::Counter64(v) => Some(*v as f64),
550 _ => None,
551 }
552 }
553
554 #[expect(
578 clippy::cast_precision_loss,
579 reason = "we intentionally bend over backwards to make an f64 available even for 64-bit ints"
580 )]
581 pub fn as_f64_wrapped(&self) -> Option<f64> {
582 const MANTISSA_LIMIT: u64 = 1 << 53;
583 match self {
584 Value::Counter64(v) => Some((*v % MANTISSA_LIMIT) as f64),
585 _ => self.as_f64(),
586 }
587 }
588
589 pub fn as_decimal(&self, places: u8) -> Option<f64> {
617 let divisor = 10f64.powi(i32::from(places));
618 self.as_f64().map(|v| v / divisor)
619 }
620
621 pub fn as_duration(&self) -> Option<std::time::Duration> {
642 match self {
643 Value::TimeTicks(v) => Some(std::time::Duration::from_millis(u64::from(*v) * 10)),
644 _ => None,
645 }
646 }
647
648 pub fn as_opaque_float(&self) -> Option<f32> {
674 match self {
675 Value::Opaque(data)
676 if data.len() >= 7
677 && data[0] == 0x9f && data[1] == 0x78 && data[2] == 0x04 =>
680 {
681 let bytes: [u8; 4] = data[3..7].try_into().ok()?;
683 Some(f32::from_be_bytes(bytes))
684 }
685 _ => None,
686 }
687 }
688
689 pub fn as_opaque_double(&self) -> Option<f64> {
711 match self {
712 Value::Opaque(data)
713 if data.len() >= 11
714 && data[0] == 0x9f && data[1] == 0x79 && data[2] == 0x08 =>
717 {
718 let bytes: [u8; 8] = data[3..11].try_into().ok()?;
720 Some(f64::from_be_bytes(bytes))
721 }
722 _ => None,
723 }
724 }
725
726 pub fn as_opaque_counter64(&self) -> Option<u64> {
747 self.as_opaque_unsigned(0x76)
748 }
749
750 pub fn as_opaque_i64(&self) -> Option<i64> {
769 match self {
770 Value::Opaque(data)
771 if data.len() >= 4
772 && data[0] == 0x9f && data[1] == 0x7a =>
774 {
775 let len = data[2] as usize;
777 if data.len() < 3 + len || len == 0 || len > 8 {
778 return None;
779 }
780 let bytes = &data[3..3 + len];
781 let is_negative = bytes[0] & 0x80 != 0;
783 let mut value: i64 = if is_negative { -1 } else { 0 };
784 for &byte in bytes {
785 value = (value << 8) | i64::from(byte);
786 }
787 Some(value)
788 }
789 _ => None,
790 }
791 }
792
793 pub fn as_opaque_u64(&self) -> Option<u64> {
812 self.as_opaque_unsigned(0x7b)
813 }
814
815 fn as_opaque_unsigned(&self, expected_type: u8) -> Option<u64> {
817 match self {
818 Value::Opaque(data)
819 if data.len() >= 4
820 && data[0] == 0x9f && data[1] == expected_type =>
822 {
823 let len = data[2] as usize;
824 if data.len() < 3 + len || len == 0 || len > 8 {
825 return None;
826 }
827 let bytes = &data[3..3 + len];
828 let mut value: u64 = 0;
829 for &byte in bytes {
830 value = (value << 8) | u64::from(byte);
831 }
832 Some(value)
833 }
834 _ => None,
835 }
836 }
837
838 pub fn as_truth_value(&self) -> Option<bool> {
857 match self {
858 Value::Integer(1) => Some(true),
859 Value::Integer(2) => Some(false),
860 _ => None,
861 }
862 }
863
864 pub fn as_row_status(&self) -> Option<RowStatus> {
882 match self {
883 Value::Integer(v) => RowStatus::from_i32(*v),
884 _ => None,
885 }
886 }
887
888 pub fn as_storage_type(&self) -> Option<StorageType> {
906 match self {
907 Value::Integer(v) => StorageType::from_i32(*v),
908 _ => None,
909 }
910 }
911
912 pub fn is_exception(&self) -> bool {
914 matches!(
915 self,
916 Value::NoSuchObject | Value::NoSuchInstance | Value::EndOfMibView
917 )
918 }
919
920 pub(crate) fn ber_encoded_size(&self) -> usize {
922 use crate::ber::{
923 integer_content_len, length_encoded_len, unsigned32_content_len, unsigned64_content_len,
924 };
925
926 match self {
927 Value::Integer(v) => {
928 let content_len = integer_content_len(*v);
929 1 + length_encoded_len(content_len) + content_len
930 }
931 Value::OctetString(data)
932 | Value::Opaque(data)
933 | Value::Nsap(data)
934 | Value::Unknown { data, .. } => {
935 let content_len = data.len();
936 1 + length_encoded_len(content_len) + content_len
937 }
938 Value::Null | Value::NoSuchObject | Value::NoSuchInstance | Value::EndOfMibView => 2, Value::ObjectIdentifier(oid) => oid.ber_encoded_size(),
940 Value::IpAddress(_) => 6, Value::Counter32(v)
942 | Value::Gauge32(v)
943 | Value::UInteger32(v)
944 | Value::TimeTicks(v) => {
945 let content_len = unsigned32_content_len(*v);
946 1 + length_encoded_len(content_len) + content_len
947 }
948 Value::Counter64(v) => {
949 let content_len = unsigned64_content_len(*v);
950 1 + length_encoded_len(content_len) + content_len
951 }
952 }
953 }
954
955 pub fn format_with_hint(&self, hint: &str) -> Option<String> {
982 match self {
983 Value::OctetString(bytes) | Value::Opaque(bytes) | Value::Nsap(bytes) => {
984 Some(crate::format::display_hint::apply(hint, bytes))
985 }
986 Value::Integer(v) => crate::format::display_hint::apply_integer(hint, *v),
987 _ => None,
988 }
989 }
990
991 pub fn encode(&self, buf: &mut EncodeBuf) {
993 match self {
994 Value::Integer(v) => buf.push_integer(*v),
995 Value::OctetString(data) => buf.push_octet_string(data),
996 Value::Null => buf.push_null(),
997 Value::ObjectIdentifier(oid) => buf.push_oid(oid),
998 Value::IpAddress(addr) => buf.push_ip_address(*addr),
999 Value::Counter32(v) => buf.push_unsigned32(tag::application::COUNTER32, *v),
1000 Value::Gauge32(v) => buf.push_unsigned32(tag::application::GAUGE32, *v),
1001 Value::UInteger32(v) => buf.push_unsigned32(tag::application::UINTEGER32, *v),
1002 Value::TimeTicks(v) => buf.push_unsigned32(tag::application::TIMETICKS, *v),
1003 Value::Opaque(data) => {
1004 buf.push_bytes(data);
1005 buf.push_length(data.len());
1006 buf.push_tag(tag::application::OPAQUE);
1007 }
1008 Value::Nsap(data) => {
1009 buf.push_bytes(data);
1010 buf.push_length(data.len());
1011 buf.push_tag(tag::application::NSAP);
1012 }
1013 Value::Counter64(v) => buf.push_integer64(*v),
1014 Value::NoSuchObject => {
1015 buf.push_length(0);
1016 buf.push_tag(tag::context::NO_SUCH_OBJECT);
1017 }
1018 Value::NoSuchInstance => {
1019 buf.push_length(0);
1020 buf.push_tag(tag::context::NO_SUCH_INSTANCE);
1021 }
1022 Value::EndOfMibView => {
1023 buf.push_length(0);
1024 buf.push_tag(tag::context::END_OF_MIB_VIEW);
1025 }
1026 Value::Unknown { tag: t, data } => {
1027 buf.push_bytes(data);
1028 buf.push_length(data.len());
1029 buf.push_tag(*t);
1030 }
1031 }
1032 }
1033
1034 pub fn decode(decoder: &mut Decoder) -> Result<Self> {
1036 let tag = decoder.read_tag()?;
1037 let len = decoder.read_length()?;
1038
1039 match tag {
1040 tag::universal::INTEGER => {
1041 let value = decoder.read_integer_value(len)?;
1042 Ok(Value::Integer(value))
1043 }
1044 tag::universal::OCTET_STRING => {
1045 let available = decoder.remaining();
1046 let len = if len > available {
1047 tracing::warn!(
1052 target: "async_snmp::value",
1053 { snmp.offset = %decoder.offset(), declared = len, available },
1054 "OctetString length exceeds varbind SEQUENCE boundary, clamping to available bytes"
1055 );
1056 available
1057 } else {
1058 len
1059 };
1060 let data = decoder.read_bytes(len)?;
1061 Ok(Value::OctetString(data))
1062 }
1063 tag::universal::NULL => {
1064 if len != 0 {
1065 tracing::debug!(target: "async_snmp::value", { offset = decoder.offset(), kind = %DecodeErrorKind::InvalidNull }, "decode error");
1066 return Err(Error::MalformedResponse {
1067 target: UNKNOWN_TARGET,
1068 }
1069 .boxed());
1070 }
1071 Ok(Value::Null)
1072 }
1073 tag::universal::OBJECT_IDENTIFIER => {
1074 let oid = decoder.read_oid_value(len)?;
1075 Ok(Value::ObjectIdentifier(oid))
1076 }
1077 tag::application::IP_ADDRESS => {
1078 if len != 4 {
1079 tracing::debug!(target: "async_snmp::value", { offset = decoder.offset(), length = len, kind = %DecodeErrorKind::InvalidIpAddressLength { length: len } }, "decode error");
1080 return Err(Error::MalformedResponse {
1081 target: UNKNOWN_TARGET,
1082 }
1083 .boxed());
1084 }
1085 let data = decoder.read_bytes(4)?;
1086 Ok(Value::IpAddress([data[0], data[1], data[2], data[3]]))
1087 }
1088 tag::application::COUNTER32 => {
1089 let value = decoder.read_unsigned32_value(len)?;
1090 Ok(Value::Counter32(value))
1091 }
1092 tag::application::GAUGE32 => {
1093 let value = decoder.read_unsigned32_value(len)?;
1094 Ok(Value::Gauge32(value))
1095 }
1096 tag::application::TIMETICKS => {
1097 let value = decoder.read_unsigned32_value(len)?;
1098 Ok(Value::TimeTicks(value))
1099 }
1100 tag::application::OPAQUE => {
1101 let available = decoder.remaining();
1102 let len = if len > available {
1103 tracing::warn!(
1104 target: "async_snmp::value",
1105 { snmp.offset = %decoder.offset(), declared = len, available },
1106 "Opaque length exceeds varbind SEQUENCE boundary, clamping to available bytes"
1107 );
1108 available
1109 } else {
1110 len
1111 };
1112 let data = decoder.read_bytes(len)?;
1113 Ok(Value::Opaque(data))
1114 }
1115 tag::application::NSAP => {
1116 let data = decoder.read_bytes(len)?;
1117 Ok(Value::Nsap(data))
1118 }
1119 tag::application::COUNTER64 => {
1120 let value = decoder.read_integer64_value(len)?;
1121 Ok(Value::Counter64(value))
1122 }
1123 tag::application::UINTEGER32 => {
1124 let value = decoder.read_unsigned32_value(len)?;
1125 Ok(Value::UInteger32(value))
1126 }
1127 tag::context::NO_SUCH_OBJECT => {
1128 if len != 0 {
1129 let _ = decoder.read_bytes(len)?;
1130 }
1131 Ok(Value::NoSuchObject)
1132 }
1133 tag::context::NO_SUCH_INSTANCE => {
1134 if len != 0 {
1135 let _ = decoder.read_bytes(len)?;
1136 }
1137 Ok(Value::NoSuchInstance)
1138 }
1139 tag::context::END_OF_MIB_VIEW => {
1140 if len != 0 {
1141 let _ = decoder.read_bytes(len)?;
1142 }
1143 Ok(Value::EndOfMibView)
1144 }
1145 tag::universal::OCTET_STRING_CONSTRUCTED => {
1148 tracing::debug!(target: "async_snmp::value", { offset = decoder.offset(), kind = %DecodeErrorKind::ConstructedOctetString }, "decode error");
1149 Err(Error::MalformedResponse {
1150 target: UNKNOWN_TARGET,
1151 }
1152 .boxed())
1153 }
1154 _ => {
1155 let data = decoder.read_bytes(len)?;
1157 Ok(Value::Unknown { tag, data })
1158 }
1159 }
1160 }
1161}
1162
1163impl std::fmt::Display for Value {
1164 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1165 match self {
1166 Value::Integer(v) => write!(f, "{v}"),
1167 Value::OctetString(data) => {
1168 if let Ok(s) = std::str::from_utf8(data) {
1170 write!(f, "{s}")
1171 } else {
1172 write!(f, "0x{}", hex::encode(data))
1173 }
1174 }
1175 Value::Null => write!(f, "NULL"),
1176 Value::ObjectIdentifier(oid) => write!(f, "{oid}"),
1177 Value::IpAddress(addr) => {
1178 write!(f, "{}.{}.{}.{}", addr[0], addr[1], addr[2], addr[3])
1179 }
1180 Value::Counter32(v) => write!(f, "{v}"),
1181 Value::Gauge32(v) => write!(f, "{v}"),
1182 Value::UInteger32(v) => write!(f, "{v}"),
1183 Value::TimeTicks(v) => {
1184 write!(f, "{}", crate::format::format_timeticks(*v))
1185 }
1186 Value::Opaque(data) => write!(f, "Opaque(0x{})", hex::encode(data)),
1187 Value::Nsap(data) => write!(f, "0x{}", hex::encode(data)),
1189 Value::Counter64(v) => write!(f, "{v}"),
1190 Value::NoSuchObject => write!(f, "noSuchObject"),
1191 Value::NoSuchInstance => write!(f, "noSuchInstance"),
1192 Value::EndOfMibView => write!(f, "endOfMibView"),
1193 Value::Unknown { tag, data } => {
1194 write!(
1195 f,
1196 "Unknown(tag=0x{:02X}, data=0x{})",
1197 tag,
1198 hex::encode(data)
1199 )
1200 }
1201 }
1202 }
1203}
1204
1205impl From<i32> for Value {
1247 fn from(v: i32) -> Self {
1248 Value::Integer(v)
1249 }
1250}
1251
1252impl From<&str> for Value {
1253 fn from(s: &str) -> Self {
1254 Value::OctetString(Bytes::copy_from_slice(s.as_bytes()))
1255 }
1256}
1257
1258impl From<String> for Value {
1259 fn from(s: String) -> Self {
1260 Value::OctetString(Bytes::from(s))
1261 }
1262}
1263
1264impl From<&[u8]> for Value {
1265 fn from(data: &[u8]) -> Self {
1266 Value::OctetString(Bytes::copy_from_slice(data))
1267 }
1268}
1269
1270impl From<Oid> for Value {
1271 fn from(oid: Oid) -> Self {
1272 Value::ObjectIdentifier(oid)
1273 }
1274}
1275
1276impl From<std::net::Ipv4Addr> for Value {
1277 fn from(addr: std::net::Ipv4Addr) -> Self {
1278 Value::IpAddress(addr.octets())
1279 }
1280}
1281
1282impl From<Bytes> for Value {
1283 fn from(data: Bytes) -> Self {
1284 Value::OctetString(data)
1285 }
1286}
1287
1288impl From<u64> for Value {
1289 fn from(v: u64) -> Self {
1290 Value::Counter64(v)
1291 }
1292}
1293
1294impl From<[u8; 4]> for Value {
1300 fn from(addr: [u8; 4]) -> Self {
1301 Value::IpAddress(addr)
1302 }
1303}
1304
1305#[cfg(test)]
1306mod tests {
1307 use super::*;
1308
1309 #[test]
1312 fn test_reject_constructed_octet_string() {
1313 let data = bytes::Bytes::from_static(&[0x24, 0x03, 0x04, 0x01, 0x41]);
1317 let mut decoder = Decoder::new(data);
1318 let result = Value::decode(&mut decoder);
1319
1320 assert!(
1321 result.is_err(),
1322 "constructed OCTET STRING (0x24) should be rejected"
1323 );
1324 let err = result.unwrap_err();
1326 assert!(
1327 matches!(&*err, crate::Error::MalformedResponse { .. }),
1328 "expected MalformedResponse error, got: {err:?}"
1329 );
1330 }
1331
1332 #[test]
1333 fn test_primitive_octet_string_accepted() {
1334 let data = bytes::Bytes::from_static(&[0x04, 0x03, 0x41, 0x42, 0x43]); let mut decoder = Decoder::new(data);
1337 let result = Value::decode(&mut decoder);
1338
1339 assert!(result.is_ok(), "primitive OCTET STRING should be accepted");
1340 let value = result.unwrap();
1341 assert_eq!(value.as_bytes(), Some(&b"ABC"[..]));
1342 }
1343
1344 fn roundtrip(value: &Value) -> Value {
1349 let mut buf = EncodeBuf::new();
1350 value.encode(&mut buf);
1351 let data = buf.finish();
1352 let mut decoder = Decoder::new(data);
1353 Value::decode(&mut decoder).unwrap()
1354 }
1355
1356 #[test]
1357 fn test_integer_positive() {
1358 let value = Value::Integer(42);
1359 assert_eq!(roundtrip(&value), value);
1360 }
1361
1362 #[test]
1363 fn test_integer_negative() {
1364 let value = Value::Integer(-42);
1365 assert_eq!(roundtrip(&value), value);
1366 }
1367
1368 #[test]
1369 fn test_integer_zero() {
1370 let value = Value::Integer(0);
1371 assert_eq!(roundtrip(&value), value);
1372 }
1373
1374 #[test]
1375 fn test_integer_min() {
1376 let value = Value::Integer(i32::MIN);
1377 assert_eq!(roundtrip(&value), value);
1378 }
1379
1380 #[test]
1381 fn test_integer_max() {
1382 let value = Value::Integer(i32::MAX);
1383 assert_eq!(roundtrip(&value), value);
1384 }
1385
1386 #[test]
1387 fn test_octet_string_ascii() {
1388 let value = Value::OctetString(Bytes::from_static(b"hello world"));
1389 assert_eq!(roundtrip(&value), value);
1390 }
1391
1392 #[test]
1393 fn test_octet_string_binary() {
1394 let value = Value::OctetString(Bytes::from_static(&[0x00, 0xFF, 0x80, 0x7F]));
1395 assert_eq!(roundtrip(&value), value);
1396 }
1397
1398 #[test]
1399 fn test_octet_string_empty() {
1400 let value = Value::OctetString(Bytes::new());
1401 assert_eq!(roundtrip(&value), value);
1402 }
1403
1404 #[test]
1405 fn test_null() {
1406 let value = Value::Null;
1407 assert_eq!(roundtrip(&value), value);
1408 }
1409
1410 #[test]
1411 fn test_object_identifier() {
1412 let value = Value::ObjectIdentifier(crate::oid!(1, 3, 6, 1, 2, 1, 1, 1, 0));
1413 assert_eq!(roundtrip(&value), value);
1414 }
1415
1416 #[test]
1417 fn test_ip_address() {
1418 let value = Value::IpAddress([192, 168, 1, 1]);
1419 assert_eq!(roundtrip(&value), value);
1420 }
1421
1422 #[test]
1423 fn test_ip_address_zero() {
1424 let value = Value::IpAddress([0, 0, 0, 0]);
1425 assert_eq!(roundtrip(&value), value);
1426 }
1427
1428 #[test]
1429 fn test_ip_address_broadcast() {
1430 let value = Value::IpAddress([255, 255, 255, 255]);
1431 assert_eq!(roundtrip(&value), value);
1432 }
1433
1434 #[test]
1435 fn test_counter32() {
1436 let value = Value::Counter32(999_999);
1437 assert_eq!(roundtrip(&value), value);
1438 }
1439
1440 #[test]
1441 fn test_counter32_zero() {
1442 let value = Value::Counter32(0);
1443 assert_eq!(roundtrip(&value), value);
1444 }
1445
1446 #[test]
1447 fn test_counter32_max() {
1448 let value = Value::Counter32(u32::MAX);
1449 assert_eq!(roundtrip(&value), value);
1450 }
1451
1452 #[test]
1453 fn test_gauge32() {
1454 let value = Value::Gauge32(1_000_000_000);
1455 assert_eq!(roundtrip(&value), value);
1456 }
1457
1458 #[test]
1459 fn test_gauge32_max() {
1460 let value = Value::Gauge32(u32::MAX);
1461 assert_eq!(roundtrip(&value), value);
1462 }
1463
1464 #[test]
1465 fn test_timeticks() {
1466 let value = Value::TimeTicks(123_456);
1467 assert_eq!(roundtrip(&value), value);
1468 }
1469
1470 #[test]
1471 fn test_timeticks_max() {
1472 let value = Value::TimeTicks(u32::MAX);
1473 assert_eq!(roundtrip(&value), value);
1474 }
1475
1476 #[test]
1477 fn test_opaque() {
1478 let value = Value::Opaque(Bytes::from_static(&[0xDE, 0xAD, 0xBE, 0xEF]));
1479 assert_eq!(roundtrip(&value), value);
1480 }
1481
1482 #[test]
1483 fn test_opaque_empty() {
1484 let value = Value::Opaque(Bytes::new());
1485 assert_eq!(roundtrip(&value), value);
1486 }
1487
1488 #[test]
1489 fn test_counter64() {
1490 let value = Value::Counter64(123_456_789_012_345);
1491 assert_eq!(roundtrip(&value), value);
1492 }
1493
1494 #[test]
1495 fn test_counter64_zero() {
1496 let value = Value::Counter64(0);
1497 assert_eq!(roundtrip(&value), value);
1498 }
1499
1500 #[test]
1501 fn test_counter64_max() {
1502 let value = Value::Counter64(u64::MAX);
1503 assert_eq!(roundtrip(&value), value);
1504 }
1505
1506 #[test]
1507 fn test_no_such_object() {
1508 let value = Value::NoSuchObject;
1509 assert_eq!(roundtrip(&value), value);
1510 }
1511
1512 #[test]
1513 fn test_no_such_instance() {
1514 let value = Value::NoSuchInstance;
1515 assert_eq!(roundtrip(&value), value);
1516 }
1517
1518 #[test]
1519 fn test_end_of_mib_view() {
1520 let value = Value::EndOfMibView;
1521 assert_eq!(roundtrip(&value), value);
1522 }
1523
1524 #[test]
1525 fn test_unknown_tag_preserved() {
1526 let data = Bytes::from_static(&[0x48, 0x03, 0x01, 0x02, 0x03]);
1528 let mut decoder = Decoder::new(data);
1529 let value = Value::decode(&mut decoder).unwrap();
1530
1531 match value {
1532 Value::Unknown { tag, ref data } => {
1533 assert_eq!(tag, 0x48);
1534 assert_eq!(data.as_ref(), &[0x01, 0x02, 0x03]);
1535 }
1536 _ => panic!("expected Unknown variant"),
1537 }
1538
1539 assert_eq!(roundtrip(&value), value);
1541 }
1542
1543 #[test]
1544 fn test_nsap_decodes_as_nsap() {
1545 let data = Bytes::from_static(&[0x45, 0x03, 0x01, 0x02, 0x03]);
1547 let mut decoder = Decoder::new(data);
1548 let value = Value::decode(&mut decoder).unwrap();
1549 assert_eq!(value, Value::Nsap(Bytes::from_static(&[0x01, 0x02, 0x03])));
1550 }
1551
1552 #[test]
1553 fn test_uinteger32_decodes_as_uinteger32() {
1554 let data = Bytes::from_static(&[0x47, 0x01, 0x2a]);
1556 let mut decoder = Decoder::new(data);
1557 let value = Value::decode(&mut decoder).unwrap();
1558 assert_eq!(value, Value::UInteger32(42));
1559 }
1560
1561 #[test]
1562 fn test_nsap_roundtrip_preserves_tag() {
1563 let bytes = Bytes::from_static(&[0x45, 0x03, 0x01, 0x02, 0x03]);
1565 let mut decoder = Decoder::new(bytes.clone());
1566 let value = Value::decode(&mut decoder).unwrap();
1567 assert_eq!(value, Value::Nsap(Bytes::from_static(&[0x01, 0x02, 0x03])));
1568 let mut buf = EncodeBuf::new();
1569 value.encode(&mut buf);
1570 assert_eq!(&buf.finish()[..], &bytes[..]);
1571 }
1572
1573 #[test]
1574 fn test_uinteger32_roundtrip_preserves_tag() {
1575 let bytes = Bytes::from_static(&[0x47, 0x01, 0x2a]);
1577 let mut decoder = Decoder::new(bytes.clone());
1578 let value = Value::decode(&mut decoder).unwrap();
1579 assert_eq!(value, Value::UInteger32(42));
1580 let mut buf = EncodeBuf::new();
1581 value.encode(&mut buf);
1582 assert_eq!(&buf.finish()[..], &bytes[..]);
1583 }
1584
1585 #[test]
1590 fn test_as_i32() {
1591 assert_eq!(Value::Integer(42).as_i32(), Some(42));
1592 assert_eq!(Value::Integer(-42).as_i32(), Some(-42));
1593 assert_eq!(Value::Counter32(100).as_i32(), None);
1594 assert_eq!(Value::Null.as_i32(), None);
1595 }
1596
1597 #[test]
1598 fn test_as_u32() {
1599 assert_eq!(Value::Counter32(100).as_u32(), Some(100));
1600 assert_eq!(Value::Gauge32(200).as_u32(), Some(200));
1601 assert_eq!(Value::TimeTicks(300).as_u32(), Some(300));
1602 assert_eq!(Value::Integer(50).as_u32(), Some(50));
1603 assert_eq!(Value::Integer(-1).as_u32(), None);
1604 assert_eq!(Value::Counter64(100).as_u32(), None);
1605 }
1606
1607 #[test]
1608 fn test_as_u64() {
1609 assert_eq!(Value::Counter64(100).as_u64(), Some(100));
1610 assert_eq!(Value::Counter32(100).as_u64(), Some(100));
1611 assert_eq!(Value::Gauge32(200).as_u64(), Some(200));
1612 assert_eq!(Value::TimeTicks(300).as_u64(), Some(300));
1613 assert_eq!(Value::Integer(50).as_u64(), Some(50));
1614 assert_eq!(Value::Integer(-1).as_u64(), None);
1615 }
1616
1617 #[test]
1618 fn test_as_bytes() {
1619 let s = Value::OctetString(Bytes::from_static(b"test"));
1620 assert_eq!(s.as_bytes(), Some(b"test".as_slice()));
1621
1622 let o = Value::Opaque(Bytes::from_static(b"data"));
1623 assert_eq!(o.as_bytes(), Some(b"data".as_slice()));
1624
1625 assert_eq!(Value::Integer(1).as_bytes(), None);
1626 }
1627
1628 #[test]
1629 fn test_as_str() {
1630 let s = Value::OctetString(Bytes::from_static(b"hello"));
1631 assert_eq!(s.as_str(), Some("hello"));
1632
1633 let invalid = Value::OctetString(Bytes::from_static(&[0xFF, 0xFE]));
1635 assert_eq!(invalid.as_str(), None);
1636
1637 assert_eq!(Value::Integer(1).as_str(), None);
1638 }
1639
1640 #[test]
1641 fn test_as_oid() {
1642 let oid = crate::oid!(1, 3, 6, 1);
1643 let v = Value::ObjectIdentifier(oid.clone());
1644 assert_eq!(v.as_oid(), Some(&oid));
1645
1646 assert_eq!(Value::Integer(1).as_oid(), None);
1647 }
1648
1649 #[test]
1650 fn test_as_ip() {
1651 let v = Value::IpAddress([192, 168, 1, 1]);
1652 assert_eq!(v.as_ip(), Some(std::net::Ipv4Addr::new(192, 168, 1, 1)));
1653
1654 assert_eq!(Value::Integer(1).as_ip(), None);
1655 }
1656
1657 #[test]
1662 fn test_is_exception() {
1663 assert!(Value::NoSuchObject.is_exception());
1664 assert!(Value::NoSuchInstance.is_exception());
1665 assert!(Value::EndOfMibView.is_exception());
1666
1667 assert!(!Value::Integer(1).is_exception());
1668 assert!(!Value::Null.is_exception());
1669 assert!(!Value::OctetString(Bytes::new()).is_exception());
1670 }
1671
1672 #[test]
1677 fn test_display_integer() {
1678 assert_eq!(format!("{}", Value::Integer(42)), "42");
1679 assert_eq!(format!("{}", Value::Integer(-42)), "-42");
1680 }
1681
1682 #[test]
1683 fn test_display_octet_string_utf8() {
1684 let v = Value::OctetString(Bytes::from_static(b"hello"));
1685 assert_eq!(format!("{v}"), "hello");
1686 }
1687
1688 #[test]
1689 fn test_display_octet_string_binary() {
1690 let v = Value::OctetString(Bytes::from_static(&[0xFF, 0xFE]));
1692 assert_eq!(format!("{v}"), "0xfffe");
1693 }
1694
1695 #[test]
1696 fn test_display_null() {
1697 assert_eq!(format!("{}", Value::Null), "NULL");
1698 }
1699
1700 #[test]
1701 fn test_display_ip_address() {
1702 let v = Value::IpAddress([192, 168, 1, 1]);
1703 assert_eq!(format!("{v}"), "192.168.1.1");
1704 }
1705
1706 #[test]
1707 fn test_display_counter32() {
1708 assert_eq!(format!("{}", Value::Counter32(999)), "999");
1709 }
1710
1711 #[test]
1712 fn test_display_gauge32() {
1713 assert_eq!(format!("{}", Value::Gauge32(1000)), "1000");
1714 }
1715
1716 #[test]
1717 fn test_display_timeticks() {
1718 let v = Value::TimeTicks(123_456);
1720 assert_eq!(format!("{v}"), "00:20:34.56");
1721 }
1722
1723 #[test]
1724 fn test_display_opaque() {
1725 let v = Value::Opaque(Bytes::from_static(&[0xBE, 0xEF]));
1726 assert_eq!(format!("{v}"), "Opaque(0xbeef)");
1727 }
1728
1729 #[test]
1730 fn test_display_nsap_always_hex() {
1731 let v = Value::Nsap(Bytes::from_static(b"90abc"));
1733 assert_eq!(format!("{v}"), "0x3930616263");
1734 }
1735
1736 #[test]
1737 fn test_display_counter64() {
1738 assert_eq!(format!("{}", Value::Counter64(1234_5678)), "12345678");
1739 }
1740
1741 #[test]
1742 fn test_display_exceptions() {
1743 assert_eq!(format!("{}", Value::NoSuchObject), "noSuchObject");
1744 assert_eq!(format!("{}", Value::NoSuchInstance), "noSuchInstance");
1745 assert_eq!(format!("{}", Value::EndOfMibView), "endOfMibView");
1746 }
1747
1748 #[test]
1749 fn test_display_unknown() {
1750 let v = Value::Unknown {
1751 tag: 0x99,
1752 data: Bytes::from_static(&[0x01, 0x02]),
1753 };
1754 assert_eq!(format!("{v}"), "Unknown(tag=0x99, data=0x0102)");
1755 }
1756
1757 #[test]
1762 fn test_from_i32() {
1763 let v: Value = 42i32.into();
1764 assert_eq!(v, Value::Integer(42));
1765 }
1766
1767 #[test]
1768 fn test_from_str() {
1769 let v: Value = "hello".into();
1770 assert_eq!(v.as_str(), Some("hello"));
1771 }
1772
1773 #[test]
1774 fn test_from_string() {
1775 let v: Value = String::from("hello").into();
1776 assert_eq!(v.as_str(), Some("hello"));
1777 }
1778
1779 #[test]
1780 fn test_from_bytes_slice() {
1781 let v: Value = (&[1u8, 2, 3][..]).into();
1782 assert_eq!(v.as_bytes(), Some(&[1u8, 2, 3][..]));
1783 }
1784
1785 #[test]
1786 fn test_from_oid() {
1787 let oid = crate::oid!(1, 3, 6, 1);
1788 let v: Value = oid.clone().into();
1789 assert_eq!(v.as_oid(), Some(&oid));
1790 }
1791
1792 #[test]
1793 fn test_from_ipv4addr() {
1794 let addr = std::net::Ipv4Addr::new(10, 0, 0, 1);
1795 let v: Value = addr.into();
1796 assert_eq!(v, Value::IpAddress([10, 0, 0, 1]));
1797 }
1798
1799 #[test]
1800 fn test_from_bytes() {
1801 let data = Bytes::from_static(b"hello");
1802 let v: Value = data.into();
1803 assert_eq!(v.as_bytes(), Some(b"hello".as_slice()));
1804 }
1805
1806 #[test]
1807 fn test_from_u64() {
1808 let v: Value = 12_345_678_901_234_u64.into();
1809 assert_eq!(v, Value::Counter64(12_345_678_901_234));
1810 }
1811
1812 #[test]
1813 fn test_from_ip_array() {
1814 let v: Value = [192u8, 168, 1, 1].into();
1815 assert_eq!(v, Value::IpAddress([192, 168, 1, 1]));
1816 }
1817
1818 #[test]
1823 fn test_value_eq_and_hash() {
1824 use std::collections::HashSet;
1825
1826 let mut set = HashSet::new();
1827 set.insert(Value::Integer(42));
1828 set.insert(Value::Integer(42)); set.insert(Value::Integer(100));
1830
1831 assert_eq!(set.len(), 2);
1832 assert!(set.contains(&Value::Integer(42)));
1833 assert!(set.contains(&Value::Integer(100)));
1834 }
1835
1836 #[test]
1841 fn test_decode_invalid_null_length() {
1842 let data = Bytes::from_static(&[0x05, 0x01, 0x00]); let mut decoder = Decoder::new(data);
1845 let result = Value::decode(&mut decoder);
1846 assert!(result.is_err());
1847 }
1848
1849 #[test]
1850 fn test_decode_invalid_ip_address_length() {
1851 let data = Bytes::from_static(&[0x40, 0x03, 0x01, 0x02, 0x03]); let mut decoder = Decoder::new(data);
1854 let result = Value::decode(&mut decoder);
1855 assert!(result.is_err());
1856 }
1857
1858 #[test]
1859 fn test_decode_exception_with_content_accepted() {
1860 let data = Bytes::from_static(&[0x80, 0x01, 0xFF]); let mut decoder = Decoder::new(data);
1863 let result = Value::decode(&mut decoder);
1864 assert!(result.is_ok());
1865 assert_eq!(result.unwrap(), Value::NoSuchObject);
1866 }
1867
1868 #[test]
1873 fn test_as_f64() {
1874 assert_eq!(Value::Integer(42).as_f64(), Some(42.0));
1875 assert_eq!(Value::Integer(-42).as_f64(), Some(-42.0));
1876 assert_eq!(Value::Counter32(1000).as_f64(), Some(1000.0));
1877 assert_eq!(Value::Gauge32(2000).as_f64(), Some(2000.0));
1878 assert_eq!(Value::TimeTicks(3000).as_f64(), Some(3000.0));
1879 assert_eq!(
1880 Value::Counter64(10_000_000_000).as_f64(),
1881 Some(10_000_000_000.0)
1882 );
1883 assert_eq!(Value::Null.as_f64(), None);
1884 assert_eq!(
1885 Value::OctetString(Bytes::from_static(b"test")).as_f64(),
1886 None
1887 );
1888 }
1889
1890 #[test]
1891 fn test_as_f64_wrapped() {
1892 assert_eq!(Value::Counter64(1000).as_f64_wrapped(), Some(1000.0));
1894 assert_eq!(Value::Counter32(1000).as_f64_wrapped(), Some(1000.0));
1895 assert_eq!(Value::Integer(42).as_f64_wrapped(), Some(42.0));
1896
1897 let mantissa_limit = 1u64 << 53;
1899 assert_eq!(Value::Counter64(mantissa_limit).as_f64_wrapped(), Some(0.0));
1900 assert_eq!(
1901 Value::Counter64(mantissa_limit + 1).as_f64_wrapped(),
1902 Some(1.0)
1903 );
1904 }
1905
1906 #[test]
1907 fn test_as_decimal() {
1908 assert_eq!(Value::Integer(2350).as_decimal(2), Some(23.50));
1909 assert_eq!(Value::Integer(9999).as_decimal(2), Some(99.99));
1910 assert_eq!(Value::Integer(12500).as_decimal(3), Some(12.5));
1911 assert_eq!(Value::Integer(-500).as_decimal(2), Some(-5.0));
1912 assert_eq!(Value::Counter32(1000).as_decimal(1), Some(100.0));
1913 assert_eq!(Value::Null.as_decimal(2), None);
1914 }
1915
1916 #[test]
1917 fn test_as_duration() {
1918 use std::time::Duration;
1919
1920 assert_eq!(
1922 Value::TimeTicks(100).as_duration(),
1923 Some(Duration::from_secs(1))
1924 );
1925 assert_eq!(
1927 Value::TimeTicks(360_000).as_duration(),
1928 Some(Duration::from_secs(3600))
1929 );
1930 assert_eq!(
1932 Value::TimeTicks(1).as_duration(),
1933 Some(Duration::from_millis(10))
1934 );
1935
1936 assert_eq!(Value::Integer(100).as_duration(), None);
1938 assert_eq!(Value::Counter32(100).as_duration(), None);
1939 }
1940
1941 #[test]
1946 fn test_as_opaque_float() {
1947 let data = Bytes::from_static(&[0x9f, 0x78, 0x04, 0x40, 0x49, 0x0f, 0xdb]);
1950 let value = Value::Opaque(data);
1951 let pi = value.as_opaque_float().unwrap();
1952 assert!((pi - std::f32::consts::PI).abs() < 0.0001);
1953
1954 assert_eq!(Value::Integer(42).as_opaque_float(), None);
1956
1957 let wrong_type = Bytes::from_static(&[0x9f, 0x79, 0x04, 0x40, 0x49, 0x0f, 0xdb]);
1959 assert_eq!(Value::Opaque(wrong_type).as_opaque_float(), None);
1960
1961 let short = Bytes::from_static(&[0x9f, 0x78, 0x04, 0x40, 0x49]);
1963 assert_eq!(Value::Opaque(short).as_opaque_float(), None);
1964 }
1965
1966 #[test]
1967 fn test_as_opaque_double() {
1968 let data = Bytes::from_static(&[
1971 0x9f, 0x79, 0x08, 0x40, 0x09, 0x21, 0xfb, 0x54, 0x44, 0x2d, 0x18,
1972 ]);
1973 let value = Value::Opaque(data);
1974 let pi = value.as_opaque_double().unwrap();
1975 assert!((pi - std::f64::consts::PI).abs() < 1e-10);
1976
1977 assert_eq!(Value::Integer(42).as_opaque_double(), None);
1979 }
1980
1981 #[test]
1982 fn test_as_opaque_counter64() {
1983 let data = Bytes::from_static(&[
1985 0x9f, 0x76, 0x08, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
1986 ]);
1987 let value = Value::Opaque(data);
1988 assert_eq!(value.as_opaque_counter64(), Some(0x0123_4567_89AB_CDEF));
1989
1990 let small = Bytes::from_static(&[0x9f, 0x76, 0x01, 0x42]);
1992 assert_eq!(Value::Opaque(small).as_opaque_counter64(), Some(0x42));
1993
1994 let zero = Bytes::from_static(&[0x9f, 0x76, 0x01, 0x00]);
1996 assert_eq!(Value::Opaque(zero).as_opaque_counter64(), Some(0));
1997 }
1998
1999 #[test]
2000 fn test_as_opaque_i64() {
2001 let positive = Bytes::from_static(&[0x9f, 0x7a, 0x02, 0x01, 0x00]);
2003 assert_eq!(Value::Opaque(positive).as_opaque_i64(), Some(256));
2004
2005 let minus_one = Bytes::from_static(&[0x9f, 0x7a, 0x01, 0xFF]);
2007 assert_eq!(Value::Opaque(minus_one).as_opaque_i64(), Some(-1));
2008
2009 let full_neg = Bytes::from_static(&[
2011 0x9f, 0x7a, 0x08, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
2012 ]);
2013 assert_eq!(Value::Opaque(full_neg).as_opaque_i64(), Some(-1));
2014
2015 let min = Bytes::from_static(&[
2017 0x9f, 0x7a, 0x08, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2018 ]);
2019 assert_eq!(Value::Opaque(min).as_opaque_i64(), Some(i64::MIN));
2020 }
2021
2022 #[test]
2023 fn test_as_opaque_u64() {
2024 let data = Bytes::from_static(&[
2026 0x9f, 0x7b, 0x08, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
2027 ]);
2028 let value = Value::Opaque(data);
2029 assert_eq!(value.as_opaque_u64(), Some(0x0123_4567_89AB_CDEF));
2030
2031 let max = Bytes::from_static(&[
2033 0x9f, 0x7b, 0x08, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
2034 ]);
2035 assert_eq!(Value::Opaque(max).as_opaque_u64(), Some(u64::MAX));
2036 }
2037
2038 #[test]
2039 fn test_format_with_hint_integer() {
2040 assert_eq!(
2042 Value::Integer(2350).format_with_hint("d-2"),
2043 Some("23.50".into())
2044 );
2045 assert_eq!(
2046 Value::Integer(-500).format_with_hint("d-2"),
2047 Some("-5.00".into())
2048 );
2049
2050 assert_eq!(Value::Integer(255).format_with_hint("x"), Some("ff".into()));
2052 assert_eq!(Value::Integer(8).format_with_hint("o"), Some("10".into()));
2053 assert_eq!(Value::Integer(5).format_with_hint("b"), Some("101".into()));
2054 assert_eq!(Value::Integer(42).format_with_hint("d"), Some("42".into()));
2055
2056 assert_eq!(Value::Integer(42).format_with_hint("invalid"), None);
2058
2059 assert_eq!(Value::Counter32(42).format_with_hint("d-2"), None);
2061 }
2062
2063 #[test]
2064 fn test_as_truth_value() {
2065 assert_eq!(Value::Integer(1).as_truth_value(), Some(true));
2067 assert_eq!(Value::Integer(2).as_truth_value(), Some(false));
2068
2069 assert_eq!(Value::Integer(0).as_truth_value(), None);
2071 assert_eq!(Value::Integer(3).as_truth_value(), None);
2072 assert_eq!(Value::Integer(-1).as_truth_value(), None);
2073
2074 assert_eq!(Value::Null.as_truth_value(), None);
2076 assert_eq!(Value::Counter32(1).as_truth_value(), None);
2077 assert_eq!(Value::Gauge32(1).as_truth_value(), None);
2078 }
2079
2080 #[test]
2085 fn test_row_status_from_i32() {
2086 assert_eq!(RowStatus::from_i32(1), Some(RowStatus::Active));
2087 assert_eq!(RowStatus::from_i32(2), Some(RowStatus::NotInService));
2088 assert_eq!(RowStatus::from_i32(3), Some(RowStatus::NotReady));
2089 assert_eq!(RowStatus::from_i32(4), Some(RowStatus::CreateAndGo));
2090 assert_eq!(RowStatus::from_i32(5), Some(RowStatus::CreateAndWait));
2091 assert_eq!(RowStatus::from_i32(6), Some(RowStatus::Destroy));
2092
2093 assert_eq!(RowStatus::from_i32(0), None);
2095 assert_eq!(RowStatus::from_i32(7), None);
2096 assert_eq!(RowStatus::from_i32(-1), None);
2097 }
2098
2099 #[test]
2100 fn test_row_status_try_from() {
2101 assert_eq!(RowStatus::try_from(1), Ok(RowStatus::Active));
2102 assert_eq!(RowStatus::try_from(6), Ok(RowStatus::Destroy));
2103 assert_eq!(RowStatus::try_from(0), Err(0));
2104 assert_eq!(RowStatus::try_from(7), Err(7));
2105 assert_eq!(RowStatus::try_from(-1), Err(-1));
2106 }
2107
2108 #[test]
2109 fn test_row_status_into_value() {
2110 let v: Value = RowStatus::Active.into();
2111 assert_eq!(v, Value::Integer(1));
2112
2113 let v: Value = RowStatus::Destroy.into();
2114 assert_eq!(v, Value::Integer(6));
2115 }
2116
2117 #[test]
2118 fn test_row_status_display() {
2119 assert_eq!(format!("{}", RowStatus::Active), "active");
2120 assert_eq!(format!("{}", RowStatus::NotInService), "notInService");
2121 assert_eq!(format!("{}", RowStatus::NotReady), "notReady");
2122 assert_eq!(format!("{}", RowStatus::CreateAndGo), "createAndGo");
2123 assert_eq!(format!("{}", RowStatus::CreateAndWait), "createAndWait");
2124 assert_eq!(format!("{}", RowStatus::Destroy), "destroy");
2125 }
2126
2127 #[test]
2128 fn test_as_row_status() {
2129 assert_eq!(Value::Integer(1).as_row_status(), Some(RowStatus::Active));
2131 assert_eq!(Value::Integer(6).as_row_status(), Some(RowStatus::Destroy));
2132
2133 assert_eq!(Value::Integer(0).as_row_status(), None);
2135 assert_eq!(Value::Integer(7).as_row_status(), None);
2136
2137 assert_eq!(Value::Null.as_row_status(), None);
2139 assert_eq!(Value::Counter32(1).as_row_status(), None);
2140 }
2141
2142 #[test]
2147 fn test_storage_type_from_i32() {
2148 assert_eq!(StorageType::from_i32(1), Some(StorageType::Other));
2149 assert_eq!(StorageType::from_i32(2), Some(StorageType::Volatile));
2150 assert_eq!(StorageType::from_i32(3), Some(StorageType::NonVolatile));
2151 assert_eq!(StorageType::from_i32(4), Some(StorageType::Permanent));
2152 assert_eq!(StorageType::from_i32(5), Some(StorageType::ReadOnly));
2153
2154 assert_eq!(StorageType::from_i32(0), None);
2156 assert_eq!(StorageType::from_i32(6), None);
2157 assert_eq!(StorageType::from_i32(-1), None);
2158 }
2159
2160 #[test]
2161 fn test_storage_type_try_from() {
2162 assert_eq!(StorageType::try_from(1), Ok(StorageType::Other));
2163 assert_eq!(StorageType::try_from(5), Ok(StorageType::ReadOnly));
2164 assert_eq!(StorageType::try_from(0), Err(0));
2165 assert_eq!(StorageType::try_from(6), Err(6));
2166 assert_eq!(StorageType::try_from(-1), Err(-1));
2167 }
2168
2169 #[test]
2170 fn test_storage_type_into_value() {
2171 let v: Value = StorageType::Volatile.into();
2172 assert_eq!(v, Value::Integer(2));
2173
2174 let v: Value = StorageType::NonVolatile.into();
2175 assert_eq!(v, Value::Integer(3));
2176 }
2177
2178 #[test]
2179 fn test_storage_type_display() {
2180 assert_eq!(format!("{}", StorageType::Other), "other");
2181 assert_eq!(format!("{}", StorageType::Volatile), "volatile");
2182 assert_eq!(format!("{}", StorageType::NonVolatile), "nonVolatile");
2183 assert_eq!(format!("{}", StorageType::Permanent), "permanent");
2184 assert_eq!(format!("{}", StorageType::ReadOnly), "readOnly");
2185 }
2186
2187 #[test]
2188 fn test_as_storage_type() {
2189 assert_eq!(
2191 Value::Integer(2).as_storage_type(),
2192 Some(StorageType::Volatile)
2193 );
2194 assert_eq!(
2195 Value::Integer(3).as_storage_type(),
2196 Some(StorageType::NonVolatile)
2197 );
2198
2199 assert_eq!(Value::Integer(0).as_storage_type(), None);
2201 assert_eq!(Value::Integer(6).as_storage_type(), None);
2202
2203 assert_eq!(Value::Null.as_storage_type(), None);
2205 assert_eq!(Value::Counter32(1).as_storage_type(), None);
2206 }
2207}