1use crate::ber::{Decoder, EncodeBuf};
6use crate::error::Result;
7use crate::oid::Oid;
8use crate::value::Value;
9
10#[derive(Debug, Clone, PartialEq)]
12pub struct VarBind {
13 pub oid: Oid,
15 pub value: Value,
17}
18
19impl VarBind {
20 pub fn new(oid: Oid, value: Value) -> Self {
22 Self { oid, value }
23 }
24
25 pub fn null(oid: Oid) -> Self {
27 Self {
28 oid,
29 value: Value::Null,
30 }
31 }
32
33 pub fn encode(&self, buf: &mut EncodeBuf) {
35 buf.push_sequence(|buf| {
36 self.value.encode(buf);
37 buf.push_oid(&self.oid);
38 });
39 }
40
41 pub fn encoded_size(&self) -> usize {
46 let mut buf = EncodeBuf::new();
47 self.encode(&mut buf);
48 buf.len()
49 }
50
51 pub fn decode(decoder: &mut Decoder) -> Result<Self> {
53 let mut seq = decoder.read_sequence()?;
54 let oid = seq.read_oid()?;
55 let value = Value::decode(&mut seq)?;
56 Ok(VarBind { oid, value })
57 }
58}
59
60impl std::fmt::Display for VarBind {
61 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
62 write!(f, "{} = {}", self.oid, self.value)
63 }
64}
65
66pub fn encode_varbind_list(buf: &mut EncodeBuf, varbinds: &[VarBind]) {
68 buf.push_sequence(|buf| {
69 for vb in varbinds.iter().rev() {
71 vb.encode(buf);
72 }
73 });
74}
75
76pub fn decode_varbind_list(decoder: &mut Decoder) -> Result<Vec<VarBind>> {
78 let mut seq = decoder.read_sequence()?;
79 let mut varbinds = Vec::new();
80
81 while !seq.is_empty() {
82 varbinds.push(VarBind::decode(&mut seq)?);
83 }
84
85 Ok(varbinds)
86}
87
88pub fn encode_null_varbinds(buf: &mut EncodeBuf, oids: &[Oid]) {
90 buf.push_sequence(|buf| {
91 for oid in oids.iter().rev() {
92 buf.push_sequence(|buf| {
93 buf.push_null();
94 buf.push_oid(oid);
95 });
96 }
97 });
98}
99
100#[cfg(test)]
101mod tests {
102 use super::*;
103 use crate::oid;
104 use bytes::Bytes;
105
106 #[test]
107 fn test_varbind_roundtrip() {
108 let vb = VarBind::new(oid!(1, 3, 6, 1), Value::Integer(42));
109
110 let mut buf = EncodeBuf::new();
111 vb.encode(&mut buf);
112 let bytes = buf.finish();
113
114 let mut decoder = Decoder::new(bytes);
115 let decoded = VarBind::decode(&mut decoder).unwrap();
116
117 assert_eq!(vb, decoded);
118 }
119
120 #[test]
121 fn test_varbind_list_roundtrip() {
122 let varbinds = vec![
123 VarBind::new(oid!(1, 3, 6, 1), Value::Integer(1)),
124 VarBind::new(oid!(1, 3, 6, 2), Value::Integer(2)),
125 ];
126
127 let mut buf = EncodeBuf::new();
128 encode_varbind_list(&mut buf, &varbinds);
129 let bytes = buf.finish();
130
131 let mut decoder = Decoder::new(bytes);
132 let decoded = decode_varbind_list(&mut decoder).unwrap();
133
134 assert_eq!(varbinds, decoded);
135 }
136
137 #[test]
142 fn test_varbind_no_such_object() {
143 let vb = VarBind::new(oid!(1, 3, 6, 1, 2, 1, 1, 1, 0), Value::NoSuchObject);
144
145 let mut buf = EncodeBuf::new();
146 vb.encode(&mut buf);
147 let bytes = buf.finish();
148
149 let mut decoder = Decoder::new(bytes);
150 let decoded = VarBind::decode(&mut decoder).unwrap();
151
152 assert_eq!(vb, decoded);
153 assert!(decoded.value.is_exception());
154 }
155
156 #[test]
157 fn test_varbind_no_such_instance() {
158 let vb = VarBind::new(oid!(1, 3, 6, 1, 2, 1, 1, 1, 0), Value::NoSuchInstance);
159
160 let mut buf = EncodeBuf::new();
161 vb.encode(&mut buf);
162 let bytes = buf.finish();
163
164 let mut decoder = Decoder::new(bytes);
165 let decoded = VarBind::decode(&mut decoder).unwrap();
166
167 assert_eq!(vb, decoded);
168 assert!(decoded.value.is_exception());
169 }
170
171 #[test]
172 fn test_varbind_end_of_mib_view() {
173 let vb = VarBind::new(oid!(1, 3, 6, 1, 2, 1, 1, 1, 0), Value::EndOfMibView);
174
175 let mut buf = EncodeBuf::new();
176 vb.encode(&mut buf);
177 let bytes = buf.finish();
178
179 let mut decoder = Decoder::new(bytes);
180 let decoded = VarBind::decode(&mut decoder).unwrap();
181
182 assert_eq!(vb, decoded);
183 assert!(decoded.value.is_exception());
184 }
185
186 #[test]
191 fn test_varbind_list_empty() {
192 let varbinds: Vec<VarBind> = vec![];
193
194 let mut buf = EncodeBuf::new();
195 encode_varbind_list(&mut buf, &varbinds);
196 let bytes = buf.finish();
197
198 let mut decoder = Decoder::new(bytes);
199 let decoded = decode_varbind_list(&mut decoder).unwrap();
200
201 assert!(decoded.is_empty());
202 }
203
204 #[test]
205 fn test_varbind_list_single() {
206 let varbinds = vec![VarBind::new(oid!(1, 3, 6, 1), Value::Integer(42))];
207
208 let mut buf = EncodeBuf::new();
209 encode_varbind_list(&mut buf, &varbinds);
210 let bytes = buf.finish();
211
212 let mut decoder = Decoder::new(bytes);
213 let decoded = decode_varbind_list(&mut decoder).unwrap();
214
215 assert_eq!(varbinds, decoded);
216 }
217
218 #[test]
219 fn test_varbind_list_with_exceptions() {
220 let varbinds = vec![
221 VarBind::new(
222 oid!(1, 3, 6, 1, 2, 1, 1, 1, 0),
223 Value::OctetString(Bytes::from_static(b"Linux router")),
224 ),
225 VarBind::new(oid!(1, 3, 6, 1, 2, 1, 1, 99, 0), Value::NoSuchObject),
226 VarBind::new(oid!(1, 3, 6, 1, 2, 1, 1, 3, 0), Value::TimeTicks(123456)),
227 VarBind::new(oid!(1, 3, 6, 1, 2, 1, 1, 100, 0), Value::NoSuchInstance),
228 ];
229
230 let mut buf = EncodeBuf::new();
231 encode_varbind_list(&mut buf, &varbinds);
232 let bytes = buf.finish();
233
234 let mut decoder = Decoder::new(bytes);
235 let decoded = decode_varbind_list(&mut decoder).unwrap();
236
237 assert_eq!(varbinds, decoded);
238 assert!(!decoded[0].value.is_exception());
239 assert!(decoded[1].value.is_exception());
240 assert!(!decoded[2].value.is_exception());
241 assert!(decoded[3].value.is_exception());
242 }
243
244 #[test]
245 fn test_varbind_list_all_exceptions() {
246 let varbinds = vec![
247 VarBind::new(oid!(1, 3, 6, 1, 2, 1, 1, 1, 0), Value::NoSuchObject),
248 VarBind::new(oid!(1, 3, 6, 1, 2, 1, 1, 2, 0), Value::NoSuchInstance),
249 VarBind::new(oid!(1, 3, 6, 1, 2, 1, 1, 3, 0), Value::EndOfMibView),
250 ];
251
252 let mut buf = EncodeBuf::new();
253 encode_varbind_list(&mut buf, &varbinds);
254 let bytes = buf.finish();
255
256 let mut decoder = Decoder::new(bytes);
257 let decoded = decode_varbind_list(&mut decoder).unwrap();
258
259 assert_eq!(varbinds, decoded);
260 assert!(decoded.iter().all(|vb| vb.value.is_exception()));
261 }
262
263 #[test]
264 fn test_varbind_list_mixed_value_types() {
265 let varbinds = vec![
266 VarBind::new(
267 oid!(1, 3, 6, 1, 2, 1, 1, 1, 0),
268 Value::OctetString(Bytes::from_static(b"test")),
269 ),
270 VarBind::new(oid!(1, 3, 6, 1, 2, 1, 1, 2, 0), Value::Integer(42)),
271 VarBind::new(oid!(1, 3, 6, 1, 2, 1, 1, 3, 0), Value::Counter32(1000)),
272 VarBind::new(oid!(1, 3, 6, 1, 2, 1, 1, 4, 0), Value::Gauge32(500)),
273 VarBind::new(oid!(1, 3, 6, 1, 2, 1, 1, 5, 0), Value::TimeTicks(99999)),
274 VarBind::new(
275 oid!(1, 3, 6, 1, 2, 1, 1, 6, 0),
276 Value::IpAddress([192, 168, 1, 1]),
277 ),
278 VarBind::new(oid!(1, 3, 6, 1, 2, 1, 1, 7, 0), Value::Counter64(u64::MAX)),
279 VarBind::new(
280 oid!(1, 3, 6, 1, 2, 1, 1, 8, 0),
281 Value::ObjectIdentifier(oid!(1, 3, 6, 1, 4)),
282 ),
283 VarBind::new(oid!(1, 3, 6, 1, 2, 1, 1, 9, 0), Value::Null),
284 ];
285
286 let mut buf = EncodeBuf::new();
287 encode_varbind_list(&mut buf, &varbinds);
288 let bytes = buf.finish();
289
290 let mut decoder = Decoder::new(bytes);
291 let decoded = decode_varbind_list(&mut decoder).unwrap();
292
293 assert_eq!(varbinds, decoded);
294 }
295
296 #[test]
297 fn test_null_varbinds_encoding() {
298 let oids = vec![
299 oid!(1, 3, 6, 1, 2, 1, 1, 1, 0),
300 oid!(1, 3, 6, 1, 2, 1, 1, 3, 0),
301 oid!(1, 3, 6, 1, 2, 1, 1, 5, 0),
302 ];
303
304 let mut buf = EncodeBuf::new();
305 encode_null_varbinds(&mut buf, &oids);
306 let bytes = buf.finish();
307
308 let mut decoder = Decoder::new(bytes);
309 let decoded = decode_varbind_list(&mut decoder).unwrap();
310
311 assert_eq!(decoded.len(), 3);
312 for (i, vb) in decoded.iter().enumerate() {
313 assert_eq!(vb.oid, oids[i]);
314 assert_eq!(vb.value, Value::Null);
315 }
316 }
317
318 #[test]
319 fn test_null_varbinds_empty() {
320 let oids: Vec<Oid> = vec![];
321
322 let mut buf = EncodeBuf::new();
323 encode_null_varbinds(&mut buf, &oids);
324 let bytes = buf.finish();
325
326 let mut decoder = Decoder::new(bytes);
327 let decoded = decode_varbind_list(&mut decoder).unwrap();
328
329 assert!(decoded.is_empty());
330 }
331
332 #[test]
337 fn test_varbind_display() {
338 let vb = VarBind::new(oid!(1, 3, 6, 1, 2, 1, 1, 1, 0), Value::Integer(42));
339 let display = format!("{}", vb);
340 assert!(display.contains("1.3.6.1.2.1.1.1.0"));
341 assert!(display.contains("42"));
342 }
343
344 #[test]
345 fn test_varbind_display_exception() {
346 let vb = VarBind::new(oid!(1, 3, 6, 1), Value::NoSuchObject);
347 let display = format!("{}", vb);
348 assert!(display.contains("noSuchObject"));
349 }
350
351 #[test]
356 fn test_varbind_null_constructor() {
357 let vb = VarBind::null(oid!(1, 3, 6, 1, 2, 1, 1, 1, 0));
358 assert_eq!(vb.oid, oid!(1, 3, 6, 1, 2, 1, 1, 1, 0));
359 assert_eq!(vb.value, Value::Null);
360 }
361}