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]) {
71 buf.push_sequence(|buf| {
72 for vb in varbinds.iter().rev() {
74 vb.encode(buf);
75 }
76 });
77}
78
79pub fn decode_varbind_list(decoder: &mut Decoder) -> Result<Vec<VarBind>> {
83 let mut seq = decoder.read_sequence()?;
84 let mut varbinds = Vec::new();
85
86 while !seq.is_empty() {
87 varbinds.push(VarBind::decode(&mut seq)?);
88 }
89
90 Ok(varbinds)
91}
92
93pub fn encode_null_varbinds(buf: &mut EncodeBuf, oids: &[Oid]) {
98 buf.push_sequence(|buf| {
99 for oid in oids.iter().rev() {
100 buf.push_sequence(|buf| {
101 buf.push_null();
102 buf.push_oid(oid);
103 });
104 }
105 });
106}
107
108#[cfg(test)]
109mod tests {
110 use super::*;
111 use crate::oid;
112 use bytes::Bytes;
113
114 #[test]
115 fn test_varbind_roundtrip() {
116 let vb = VarBind::new(oid!(1, 3, 6, 1), Value::Integer(42));
117
118 let mut buf = EncodeBuf::new();
119 vb.encode(&mut buf);
120 let bytes = buf.finish();
121
122 let mut decoder = Decoder::new(bytes);
123 let decoded = VarBind::decode(&mut decoder).unwrap();
124
125 assert_eq!(vb, decoded);
126 }
127
128 #[test]
129 fn test_varbind_list_roundtrip() {
130 let varbinds = vec![
131 VarBind::new(oid!(1, 3, 6, 1), Value::Integer(1)),
132 VarBind::new(oid!(1, 3, 6, 2), Value::Integer(2)),
133 ];
134
135 let mut buf = EncodeBuf::new();
136 encode_varbind_list(&mut buf, &varbinds);
137 let bytes = buf.finish();
138
139 let mut decoder = Decoder::new(bytes);
140 let decoded = decode_varbind_list(&mut decoder).unwrap();
141
142 assert_eq!(varbinds, decoded);
143 }
144
145 #[test]
150 fn test_varbind_no_such_object() {
151 let vb = VarBind::new(oid!(1, 3, 6, 1, 2, 1, 1, 1, 0), Value::NoSuchObject);
152
153 let mut buf = EncodeBuf::new();
154 vb.encode(&mut buf);
155 let bytes = buf.finish();
156
157 let mut decoder = Decoder::new(bytes);
158 let decoded = VarBind::decode(&mut decoder).unwrap();
159
160 assert_eq!(vb, decoded);
161 assert!(decoded.value.is_exception());
162 }
163
164 #[test]
165 fn test_varbind_no_such_instance() {
166 let vb = VarBind::new(oid!(1, 3, 6, 1, 2, 1, 1, 1, 0), Value::NoSuchInstance);
167
168 let mut buf = EncodeBuf::new();
169 vb.encode(&mut buf);
170 let bytes = buf.finish();
171
172 let mut decoder = Decoder::new(bytes);
173 let decoded = VarBind::decode(&mut decoder).unwrap();
174
175 assert_eq!(vb, decoded);
176 assert!(decoded.value.is_exception());
177 }
178
179 #[test]
180 fn test_varbind_end_of_mib_view() {
181 let vb = VarBind::new(oid!(1, 3, 6, 1, 2, 1, 1, 1, 0), Value::EndOfMibView);
182
183 let mut buf = EncodeBuf::new();
184 vb.encode(&mut buf);
185 let bytes = buf.finish();
186
187 let mut decoder = Decoder::new(bytes);
188 let decoded = VarBind::decode(&mut decoder).unwrap();
189
190 assert_eq!(vb, decoded);
191 assert!(decoded.value.is_exception());
192 }
193
194 #[test]
199 fn test_varbind_list_empty() {
200 let varbinds: Vec<VarBind> = vec![];
201
202 let mut buf = EncodeBuf::new();
203 encode_varbind_list(&mut buf, &varbinds);
204 let bytes = buf.finish();
205
206 let mut decoder = Decoder::new(bytes);
207 let decoded = decode_varbind_list(&mut decoder).unwrap();
208
209 assert!(decoded.is_empty());
210 }
211
212 #[test]
213 fn test_varbind_list_single() {
214 let varbinds = vec![VarBind::new(oid!(1, 3, 6, 1), Value::Integer(42))];
215
216 let mut buf = EncodeBuf::new();
217 encode_varbind_list(&mut buf, &varbinds);
218 let bytes = buf.finish();
219
220 let mut decoder = Decoder::new(bytes);
221 let decoded = decode_varbind_list(&mut decoder).unwrap();
222
223 assert_eq!(varbinds, decoded);
224 }
225
226 #[test]
227 fn test_varbind_list_with_exceptions() {
228 let varbinds = vec![
229 VarBind::new(
230 oid!(1, 3, 6, 1, 2, 1, 1, 1, 0),
231 Value::OctetString(Bytes::from_static(b"Linux router")),
232 ),
233 VarBind::new(oid!(1, 3, 6, 1, 2, 1, 1, 99, 0), Value::NoSuchObject),
234 VarBind::new(oid!(1, 3, 6, 1, 2, 1, 1, 3, 0), Value::TimeTicks(123456)),
235 VarBind::new(oid!(1, 3, 6, 1, 2, 1, 1, 100, 0), Value::NoSuchInstance),
236 ];
237
238 let mut buf = EncodeBuf::new();
239 encode_varbind_list(&mut buf, &varbinds);
240 let bytes = buf.finish();
241
242 let mut decoder = Decoder::new(bytes);
243 let decoded = decode_varbind_list(&mut decoder).unwrap();
244
245 assert_eq!(varbinds, decoded);
246 assert!(!decoded[0].value.is_exception());
247 assert!(decoded[1].value.is_exception());
248 assert!(!decoded[2].value.is_exception());
249 assert!(decoded[3].value.is_exception());
250 }
251
252 #[test]
253 fn test_varbind_list_all_exceptions() {
254 let varbinds = vec![
255 VarBind::new(oid!(1, 3, 6, 1, 2, 1, 1, 1, 0), Value::NoSuchObject),
256 VarBind::new(oid!(1, 3, 6, 1, 2, 1, 1, 2, 0), Value::NoSuchInstance),
257 VarBind::new(oid!(1, 3, 6, 1, 2, 1, 1, 3, 0), Value::EndOfMibView),
258 ];
259
260 let mut buf = EncodeBuf::new();
261 encode_varbind_list(&mut buf, &varbinds);
262 let bytes = buf.finish();
263
264 let mut decoder = Decoder::new(bytes);
265 let decoded = decode_varbind_list(&mut decoder).unwrap();
266
267 assert_eq!(varbinds, decoded);
268 assert!(decoded.iter().all(|vb| vb.value.is_exception()));
269 }
270
271 #[test]
272 fn test_varbind_list_mixed_value_types() {
273 let varbinds = vec![
274 VarBind::new(
275 oid!(1, 3, 6, 1, 2, 1, 1, 1, 0),
276 Value::OctetString(Bytes::from_static(b"test")),
277 ),
278 VarBind::new(oid!(1, 3, 6, 1, 2, 1, 1, 2, 0), Value::Integer(42)),
279 VarBind::new(oid!(1, 3, 6, 1, 2, 1, 1, 3, 0), Value::Counter32(1000)),
280 VarBind::new(oid!(1, 3, 6, 1, 2, 1, 1, 4, 0), Value::Gauge32(500)),
281 VarBind::new(oid!(1, 3, 6, 1, 2, 1, 1, 5, 0), Value::TimeTicks(99999)),
282 VarBind::new(
283 oid!(1, 3, 6, 1, 2, 1, 1, 6, 0),
284 Value::IpAddress([192, 168, 1, 1]),
285 ),
286 VarBind::new(oid!(1, 3, 6, 1, 2, 1, 1, 7, 0), Value::Counter64(u64::MAX)),
287 VarBind::new(
288 oid!(1, 3, 6, 1, 2, 1, 1, 8, 0),
289 Value::ObjectIdentifier(oid!(1, 3, 6, 1, 4)),
290 ),
291 VarBind::new(oid!(1, 3, 6, 1, 2, 1, 1, 9, 0), Value::Null),
292 ];
293
294 let mut buf = EncodeBuf::new();
295 encode_varbind_list(&mut buf, &varbinds);
296 let bytes = buf.finish();
297
298 let mut decoder = Decoder::new(bytes);
299 let decoded = decode_varbind_list(&mut decoder).unwrap();
300
301 assert_eq!(varbinds, decoded);
302 }
303
304 #[test]
305 fn test_null_varbinds_encoding() {
306 let oids = vec![
307 oid!(1, 3, 6, 1, 2, 1, 1, 1, 0),
308 oid!(1, 3, 6, 1, 2, 1, 1, 3, 0),
309 oid!(1, 3, 6, 1, 2, 1, 1, 5, 0),
310 ];
311
312 let mut buf = EncodeBuf::new();
313 encode_null_varbinds(&mut buf, &oids);
314 let bytes = buf.finish();
315
316 let mut decoder = Decoder::new(bytes);
317 let decoded = decode_varbind_list(&mut decoder).unwrap();
318
319 assert_eq!(decoded.len(), 3);
320 for (i, vb) in decoded.iter().enumerate() {
321 assert_eq!(vb.oid, oids[i]);
322 assert_eq!(vb.value, Value::Null);
323 }
324 }
325
326 #[test]
327 fn test_null_varbinds_empty() {
328 let oids: Vec<Oid> = vec![];
329
330 let mut buf = EncodeBuf::new();
331 encode_null_varbinds(&mut buf, &oids);
332 let bytes = buf.finish();
333
334 let mut decoder = Decoder::new(bytes);
335 let decoded = decode_varbind_list(&mut decoder).unwrap();
336
337 assert!(decoded.is_empty());
338 }
339
340 #[test]
345 fn test_varbind_display() {
346 let vb = VarBind::new(oid!(1, 3, 6, 1, 2, 1, 1, 1, 0), Value::Integer(42));
347 let display = format!("{}", vb);
348 assert!(display.contains("1.3.6.1.2.1.1.1.0"));
349 assert!(display.contains("42"));
350 }
351
352 #[test]
353 fn test_varbind_display_exception() {
354 let vb = VarBind::new(oid!(1, 3, 6, 1), Value::NoSuchObject);
355 let display = format!("{}", vb);
356 assert!(display.contains("noSuchObject"));
357 }
358
359 #[test]
364 fn test_varbind_null_constructor() {
365 let vb = VarBind::null(oid!(1, 3, 6, 1, 2, 1, 1, 1, 0));
366 assert_eq!(vb.oid, oid!(1, 3, 6, 1, 2, 1, 1, 1, 0));
367 assert_eq!(vb.value, Value::Null);
368 }
369}