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