async_snmp/format/hints.rs
1//! Pre-defined DISPLAY-HINT constants for common SNMP types.
2//!
3//! These constants can be used with [`Value::format_with_hint()`](crate::Value::format_with_hint)
4//! to format values according to their MIB definitions without looking up hints.
5//!
6//! # Example
7//!
8//! ```
9//! use async_snmp::format::hints;
10//! use async_snmp::Value;
11//! use bytes::Bytes;
12//!
13//! let mac = Value::OctetString(Bytes::from_static(&[0x00, 0x1a, 0x2b, 0x3c, 0x4d, 0x5e]));
14//! assert_eq!(mac.format_with_hint(hints::MAC_ADDRESS), Some("00:1a:2b:3c:4d:5e".to_string()));
15//! ```
16
17/// MAC address: "1x:" - each byte as hex separated by colons.
18///
19/// Used by `SNMPv2-TC::MacAddress` and many physical address fields.
20pub const MAC_ADDRESS: &str = "1x:";
21
22/// Display string (UTF-8): "255a" - up to 255 ASCII/UTF-8 characters.
23///
24/// Used by `SNMPv2-TC::DisplayString`, `SNMPv2-MIB::sysDescr`, etc.
25pub const DISPLAY_STRING: &str = "255a";
26
27/// Date and time: "2d-1d-1d,1d:1d:1d.1d,1a1d:1d".
28///
29/// Used by `SNMPv2-TC::DateAndTime` (8 or 11 bytes).
30/// Format: YYYY-MM-DD,HH:MM:SS.d,+/-HH:MM
31pub const DATE_AND_TIME: &str = "2d-1d-1d,1d:1d:1d.1d,1a1d:1d";
32
33/// Hexadecimal string: "1x" - each byte as two hex digits.
34///
35/// Common format for binary data that should display as hex.
36pub const HEX_STRING: &str = "1x";
37
38/// Hexadecimal with spaces: "1x " - each byte as hex separated by spaces.
39///
40/// Alternative hex format sometimes used for readability.
41pub const HEX_STRING_SPACED: &str = "1x ";
42
43/// Dotted decimal: "1d." - each byte as decimal separated by dots.
44///
45/// Used for IP addresses and similar dotted notations.
46pub const DOTTED_DECIMAL: &str = "1d.";
47
48/// UTF-8 string: "255t" - up to 255 UTF-8 encoded characters.
49///
50/// For explicitly UTF-8 encoded strings.
51pub const UTF8_STRING: &str = "255t";
52
53/// Integer as hex: "x" - integer value in lowercase hexadecimal.
54pub const INTEGER_HEX: &str = "x";
55
56/// Integer with 1 decimal place: "d-1".
57///
58/// Common for tenths (e.g., temperatures in 0.1 degree units).
59pub const DECIMAL_1: &str = "d-1";
60
61/// Integer with 2 decimal places: "d-2".
62///
63/// Common for hundredths (e.g., percentages as 0-10000).
64pub const DECIMAL_2: &str = "d-2";
65
66/// Integer with 3 decimal places: "d-3".
67///
68/// Common for thousandths (e.g., voltages in millivolts).
69pub const DECIMAL_3: &str = "d-3";
70
71#[cfg(test)]
72mod tests {
73 use super::*;
74 use crate::Value;
75 use bytes::Bytes;
76
77 #[test]
78 fn test_mac_address_hint() {
79 let mac = Value::OctetString(Bytes::from_static(&[0x00, 0x1a, 0x2b, 0x3c, 0x4d, 0x5e]));
80 assert_eq!(
81 mac.format_with_hint(MAC_ADDRESS),
82 Some("00:1a:2b:3c:4d:5e".to_string())
83 );
84 }
85
86 #[test]
87 fn test_display_string_hint() {
88 let desc = Value::OctetString(Bytes::from_static(b"Hello World"));
89 assert_eq!(
90 desc.format_with_hint(DISPLAY_STRING),
91 Some("Hello World".to_string())
92 );
93 }
94
95 #[test]
96 fn test_hex_string_hint() {
97 let data = Value::OctetString(Bytes::from_static(&[0xDE, 0xAD, 0xBE, 0xEF]));
98 assert_eq!(
99 data.format_with_hint(HEX_STRING),
100 Some("deadbeef".to_string())
101 );
102 }
103
104 #[test]
105 fn test_dotted_decimal_hint() {
106 let ip = Value::OctetString(Bytes::from_static(&[192, 168, 1, 1]));
107 assert_eq!(
108 ip.format_with_hint(DOTTED_DECIMAL),
109 Some("192.168.1.1".to_string())
110 );
111 }
112
113 #[test]
114 fn test_integer_decimal_hints() {
115 assert_eq!(
116 Value::Integer(2350).format_with_hint(DECIMAL_2),
117 Some("23.50".to_string())
118 );
119 assert_eq!(
120 Value::Integer(1234).format_with_hint(DECIMAL_1),
121 Some("123.4".to_string())
122 );
123 assert_eq!(
124 Value::Integer(12500).format_with_hint(DECIMAL_3),
125 Some("12.500".to_string())
126 );
127 }
128
129 #[test]
130 fn test_integer_hex_hint() {
131 assert_eq!(
132 Value::Integer(255).format_with_hint(INTEGER_HEX),
133 Some("ff".to_string())
134 );
135 }
136
137 #[test]
138 fn test_hex_string_hint_displays_as_hex() {
139 // HEX_STRING uses "1x" which is valid RFC 2579
140 let data = Value::OctetString(Bytes::from_static(&[0x0f, 0xff]));
141 assert_eq!(data.format_with_hint(HEX_STRING), Some("0fff".to_string()));
142 }
143
144 #[test]
145 fn test_utf8_string_multibyte() {
146 // UTF8_STRING uses "255t" and must decode multi-byte UTF-8 correctly
147 let data = Value::OctetString(Bytes::from("café".as_bytes()));
148 assert_eq!(data.format_with_hint(UTF8_STRING), Some("café".to_string()));
149 }
150
151 #[test]
152 fn test_date_and_time_hint_with_timezone() {
153 // RFC 2579 3.1(7) worked example: Tuesday May 26, 1992 at 1:30:15 PM EDT
154 // (references/rfc2579.txt:1058) -> "1992-5-26,13:30:15.0,-4:0"
155 let dt = Value::OctetString(Bytes::from_static(&[
156 0x07, 0xC8, // year 1992
157 5, // month
158 26, // day
159 13, // hour
160 30, // minutes
161 15, // seconds
162 0, // deci-seconds
163 b'-', // direction from UTC
164 4, // hours from UTC
165 0, // minutes from UTC
166 ]));
167 assert_eq!(
168 dt.format_with_hint(DATE_AND_TIME),
169 Some("1992-5-26,13:30:15.0,-4:0".to_string())
170 );
171 }
172
173 #[test]
174 fn test_date_and_time_hint_without_timezone() {
175 // 8-octet form: same date/time, no timezone tail. The trailing
176 // ",1a1d:1d" specs receive no data and are not emitted.
177 let dt = Value::OctetString(Bytes::from_static(&[
178 0x07, 0xC8, // year 1992
179 5, // month
180 26, // day
181 13, // hour
182 30, // minutes
183 15, // seconds
184 0, // deci-seconds
185 ]));
186 assert_eq!(
187 dt.format_with_hint(DATE_AND_TIME),
188 Some("1992-5-26,13:30:15.0".to_string())
189 );
190 }
191
192 #[test]
193 fn test_date_and_time_hint_positive_offset() {
194 // 11-octet form with a '+' direction (e.g. UTC+10:30), covering the
195 // positive-offset branch of the `1a` direction character.
196 let dt = Value::OctetString(Bytes::from_static(&[
197 0x07, 0xC8, // year 1992
198 5, // month
199 26, // day
200 13, // hour
201 30, // minutes
202 15, // seconds
203 0, // deci-seconds
204 b'+', // direction from UTC
205 10, // hours from UTC
206 30, // minutes from UTC
207 ]));
208 assert_eq!(
209 dt.format_with_hint(DATE_AND_TIME),
210 Some("1992-5-26,13:30:15.0,+10:30".to_string())
211 );
212 }
213}