1use crate::error::{DecodeErrorKind, Error, OidErrorKind, Result};
6use smallvec::SmallVec;
7use std::fmt;
8
9pub const MAX_OID_LEN: usize = 128;
18
19#[derive(Clone, PartialEq, Eq, Hash)]
24pub struct Oid {
25 arcs: SmallVec<[u32; 16]>,
26}
27
28impl Oid {
29 pub fn empty() -> Self {
31 Self {
32 arcs: SmallVec::new(),
33 }
34 }
35
36 pub fn new(arcs: impl IntoIterator<Item = u32>) -> Self {
38 Self {
39 arcs: arcs.into_iter().collect(),
40 }
41 }
42
43 pub fn from_slice(arcs: &[u32]) -> Self {
45 Self {
46 arcs: SmallVec::from_slice(arcs),
47 }
48 }
49
50 pub fn parse(s: &str) -> Result<Self> {
75 if s.is_empty() {
76 return Ok(Self::empty());
77 }
78
79 let mut arcs = SmallVec::new();
80
81 for part in s.split('.') {
82 if part.is_empty() {
83 continue;
84 }
85
86 let arc: u32 = part.parse().map_err(|_| {
87 Error::invalid_oid_with_input(OidErrorKind::InvalidArc, s.to_string())
88 })?;
89
90 arcs.push(arc);
91 }
92
93 Ok(Self { arcs })
94 }
95
96 pub fn arcs(&self) -> &[u32] {
98 &self.arcs
99 }
100
101 pub fn len(&self) -> usize {
103 self.arcs.len()
104 }
105
106 pub fn is_empty(&self) -> bool {
108 self.arcs.is_empty()
109 }
110
111 pub fn starts_with(&self, other: &Oid) -> bool {
113 self.arcs.len() >= other.arcs.len() && self.arcs[..other.arcs.len()] == other.arcs[..]
114 }
115
116 pub fn parent(&self) -> Option<Oid> {
118 if self.arcs.is_empty() {
119 None
120 } else {
121 Some(Oid {
122 arcs: SmallVec::from_slice(&self.arcs[..self.arcs.len() - 1]),
123 })
124 }
125 }
126
127 pub fn child(&self, arc: u32) -> Oid {
129 let mut arcs = self.arcs.clone();
130 arcs.push(arc);
131 Oid { arcs }
132 }
133
134 pub fn validate(&self) -> Result<()> {
140 if self.arcs.is_empty() {
141 return Ok(());
142 }
143
144 let arc1 = self.arcs[0];
145
146 if arc1 > 2 {
148 return Err(Error::invalid_oid(OidErrorKind::InvalidFirstArc(arc1)));
149 }
150
151 if self.arcs.len() >= 2 {
153 let arc2 = self.arcs[1];
154 if arc1 < 2 && arc2 >= 40 {
155 return Err(Error::invalid_oid(OidErrorKind::InvalidSecondArc {
156 first: arc1,
157 second: arc2,
158 }));
159 }
160 }
161
162 Ok(())
163 }
164
165 pub fn validate_length(&self) -> Result<()> {
184 if self.arcs.len() > MAX_OID_LEN {
185 return Err(Error::invalid_oid(OidErrorKind::TooManyArcs {
186 count: self.arcs.len(),
187 max: MAX_OID_LEN,
188 }));
189 }
190 Ok(())
191 }
192
193 pub fn validate_all(&self) -> Result<()> {
197 self.validate()?;
198 self.validate_length()
199 }
200
201 pub fn to_ber_smallvec(&self) -> SmallVec<[u8; 64]> {
210 let mut bytes = SmallVec::new();
211
212 if self.arcs.is_empty() {
213 return bytes;
214 }
215
216 if self.arcs.len() >= 2 {
219 let first_subid = self.arcs[0] * 40 + self.arcs[1];
220 encode_subidentifier_smallvec(&mut bytes, first_subid);
221 } else if self.arcs.len() == 1 {
222 let first_subid = self.arcs[0] * 40;
223 encode_subidentifier_smallvec(&mut bytes, first_subid);
224 }
225
226 if self.arcs.len() > 2 {
228 for &arc in &self.arcs[2..] {
229 encode_subidentifier_smallvec(&mut bytes, arc);
230 }
231 }
232
233 bytes
234 }
235
236 pub fn to_ber(&self) -> Vec<u8> {
253 self.to_ber_smallvec().to_vec()
254 }
255
256 pub fn to_ber_checked(&self) -> Result<Vec<u8>> {
260 self.validate()?;
261 Ok(self.to_ber())
262 }
263
264 pub fn from_ber(data: &[u8]) -> Result<Self> {
266 if data.is_empty() {
267 return Ok(Self::empty());
268 }
269
270 let mut arcs = SmallVec::new();
271
272 let (first_subid, consumed) = decode_subidentifier(data)?;
275
276 if first_subid < 40 {
278 arcs.push(0);
279 arcs.push(first_subid);
280 } else if first_subid < 80 {
281 arcs.push(1);
282 arcs.push(first_subid - 40);
283 } else {
284 arcs.push(2);
285 arcs.push(first_subid - 80);
286 }
287
288 let mut i = consumed;
290 while i < data.len() {
291 let (arc, bytes_consumed) = decode_subidentifier(&data[i..])?;
292 arcs.push(arc);
293 i += bytes_consumed;
294 }
295
296 Ok(Self { arcs })
297 }
298}
299
300#[inline]
302fn encode_subidentifier_smallvec(bytes: &mut SmallVec<[u8; 64]>, value: u32) {
303 if value == 0 {
304 bytes.push(0);
305 return;
306 }
307
308 let mut temp = value;
310 let mut count = 0;
311 while temp > 0 {
312 count += 1;
313 temp >>= 7;
314 }
315
316 for i in (0..count).rev() {
318 let mut byte = ((value >> (i * 7)) & 0x7F) as u8;
319 if i > 0 {
320 byte |= 0x80; }
322 bytes.push(byte);
323 }
324}
325
326fn decode_subidentifier(data: &[u8]) -> Result<(u32, usize)> {
328 let mut value: u32 = 0;
329 let mut i = 0;
330
331 loop {
332 if i >= data.len() {
333 return Err(Error::decode(i, DecodeErrorKind::TruncatedData));
334 }
335
336 let byte = data[i];
337 i += 1;
338
339 if value > (u32::MAX >> 7) {
341 return Err(Error::decode(i, DecodeErrorKind::IntegerOverflow));
342 }
343
344 value = (value << 7) | ((byte & 0x7F) as u32);
345
346 if byte & 0x80 == 0 {
347 break;
349 }
350 }
351
352 Ok((value, i))
353}
354
355impl fmt::Debug for Oid {
356 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
357 write!(f, "Oid({})", self)
358 }
359}
360
361impl fmt::Display for Oid {
362 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
363 let mut first = true;
364 for arc in &self.arcs {
365 if !first {
366 write!(f, ".")?;
367 }
368 write!(f, "{}", arc)?;
369 first = false;
370 }
371 Ok(())
372 }
373}
374
375impl std::str::FromStr for Oid {
376 type Err = crate::error::Error;
377
378 fn from_str(s: &str) -> Result<Self> {
379 Self::parse(s)
380 }
381}
382
383impl From<&[u32]> for Oid {
384 fn from(arcs: &[u32]) -> Self {
385 Self::from_slice(arcs)
386 }
387}
388
389impl<const N: usize> From<[u32; N]> for Oid {
390 fn from(arcs: [u32; N]) -> Self {
391 Self::new(arcs)
392 }
393}
394
395impl PartialOrd for Oid {
396 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
397 Some(self.cmp(other))
398 }
399}
400
401impl Ord for Oid {
402 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
403 self.arcs.cmp(&other.arcs)
404 }
405}
406
407#[macro_export]
417macro_rules! oid {
418 ($($arc:expr),* $(,)?) => {
419 $crate::oid::Oid::from_slice(&[$($arc),*])
420 };
421}
422
423#[cfg(test)]
424mod tests {
425 use super::*;
426
427 #[test]
428 fn test_parse() {
429 let oid = Oid::parse("1.3.6.1.2.1.1.1.0").unwrap();
430 assert_eq!(oid.arcs(), &[1, 3, 6, 1, 2, 1, 1, 1, 0]);
431 }
432
433 #[test]
434 fn test_display() {
435 let oid = Oid::from_slice(&[1, 3, 6, 1, 2, 1, 1, 1, 0]);
436 assert_eq!(oid.to_string(), "1.3.6.1.2.1.1.1.0");
437 }
438
439 #[test]
440 fn test_starts_with() {
441 let oid = Oid::parse("1.3.6.1.2.1.1.1.0").unwrap();
442 let prefix = Oid::parse("1.3.6.1").unwrap();
443 assert!(oid.starts_with(&prefix));
444 assert!(!prefix.starts_with(&oid));
445 }
446
447 #[test]
448 fn test_ber_roundtrip() {
449 let oid = Oid::parse("1.3.6.1.2.1.1.1.0").unwrap();
450 let ber = oid.to_ber();
451 let decoded = Oid::from_ber(&ber).unwrap();
452 assert_eq!(oid, decoded);
453 }
454
455 #[test]
456 fn test_ber_encoding() {
457 let oid = Oid::parse("1.3.6.1").unwrap();
459 assert_eq!(oid.to_ber(), vec![0x2B, 0x06, 0x01]);
460 }
461
462 #[test]
463 fn test_macro() {
464 let oid = oid!(1, 3, 6, 1);
465 assert_eq!(oid.arcs(), &[1, 3, 6, 1]);
466 }
467
468 #[test]
471 fn test_validate_arc1_must_be_0_1_or_2() {
472 let oid = Oid::from_slice(&[3, 0]);
474 let result = oid.validate();
475 assert!(result.is_err(), "arc1=3 should be invalid");
476 }
477
478 #[test]
479 fn test_validate_arc2_limit_when_arc1_is_0() {
480 let oid = Oid::from_slice(&[0, 40]);
482 let result = oid.validate();
483 assert!(result.is_err(), "arc2=40 with arc1=0 should be invalid");
484
485 let oid = Oid::from_slice(&[0, 39]);
487 assert!(
488 oid.validate().is_ok(),
489 "arc2=39 with arc1=0 should be valid"
490 );
491 }
492
493 #[test]
494 fn test_validate_arc2_limit_when_arc1_is_1() {
495 let oid = Oid::from_slice(&[1, 40]);
497 let result = oid.validate();
498 assert!(result.is_err(), "arc2=40 with arc1=1 should be invalid");
499
500 let oid = Oid::from_slice(&[1, 39]);
502 assert!(
503 oid.validate().is_ok(),
504 "arc2=39 with arc1=1 should be valid"
505 );
506 }
507
508 #[test]
509 fn test_validate_arc2_no_limit_when_arc1_is_2() {
510 let oid = Oid::from_slice(&[2, 999]);
512 assert!(
513 oid.validate().is_ok(),
514 "arc2=999 with arc1=2 should be valid"
515 );
516 }
517
518 #[test]
519 fn test_to_ber_validates_arcs() {
520 let oid = Oid::from_slice(&[3, 0]); let result = oid.to_ber_checked();
523 assert!(
524 result.is_err(),
525 "to_ber_checked should fail for invalid arc1"
526 );
527 }
528
529 #[test]
532 fn test_ber_encoding_large_arc2() {
533 let oid = Oid::from_slice(&[2, 999, 3]);
536 let ber = oid.to_ber();
537 assert_eq!(
541 ber[0], 0x88,
542 "first byte should be 0x88 (8 with continuation)"
543 );
544 assert_eq!(
545 ber[1], 0x37,
546 "second byte should be 0x37 (55, no continuation)"
547 );
548 assert_eq!(ber[2], 0x03, "third byte should be 0x03 (arc 3)");
549 assert_eq!(ber.len(), 3, "OID 2.999.3 should encode to 3 bytes");
550 }
551
552 #[test]
553 fn test_ber_roundtrip_large_arc2() {
554 let oid = Oid::from_slice(&[2, 999, 3]);
556 let ber = oid.to_ber();
557 let decoded = Oid::from_ber(&ber).unwrap();
558 assert_eq!(oid, decoded, "roundtrip should preserve OID 2.999.3");
559 }
560
561 #[test]
562 fn test_ber_encoding_arc2_equals_80() {
563 let oid = Oid::from_slice(&[2, 0]);
565 let ber = oid.to_ber();
566 assert_eq!(ber, vec![80], "OID 2.0 should encode to [80]");
567 }
568
569 #[test]
570 fn test_ber_encoding_arc2_equals_127() {
571 let oid = Oid::from_slice(&[2, 47]);
573 let ber = oid.to_ber();
574 assert_eq!(ber, vec![127], "OID 2.47 should encode to [127]");
575 }
576
577 #[test]
578 fn test_ber_encoding_arc2_equals_128_needs_2_bytes() {
579 let oid = Oid::from_slice(&[2, 48]);
581 let ber = oid.to_ber();
582 assert_eq!(
584 ber,
585 vec![0x81, 0x00],
586 "OID 2.48 should encode to [0x81, 0x00]"
587 );
588 }
589
590 #[test]
591 fn test_oid_non_minimal_subidentifier() {
592 let result = Oid::from_ber(&[0x2B, 0x80, 0x01]);
596 assert!(
597 result.is_ok(),
598 "should accept non-minimal subidentifier 0x80 0x01"
599 );
600 let oid = result.unwrap();
601 assert_eq!(oid.arcs(), &[1, 3, 1]);
602
603 let result = Oid::from_ber(&[0x2B, 0x80, 0x80, 0x01]);
605 assert!(
606 result.is_ok(),
607 "should accept non-minimal subidentifier 0x80 0x80 0x01"
608 );
609 let oid = result.unwrap();
610 assert_eq!(oid.arcs(), &[1, 3, 1]);
611
612 let result = Oid::from_ber(&[0x2B, 0x80, 0x00]);
614 assert!(
615 result.is_ok(),
616 "should accept non-minimal subidentifier 0x80 0x00"
617 );
618 let oid = result.unwrap();
619 assert_eq!(oid.arcs(), &[1, 3, 0]);
620 }
621
622 #[test]
624 fn test_validate_length_within_limit() {
625 let arcs: Vec<u32> = (0..MAX_OID_LEN as u32).collect();
627 let oid = Oid::new(arcs);
628 assert!(
629 oid.validate_length().is_ok(),
630 "OID with exactly MAX_OID_LEN arcs should be valid"
631 );
632 }
633
634 #[test]
635 fn test_validate_length_exceeds_limit() {
636 let arcs: Vec<u32> = (0..(MAX_OID_LEN + 1) as u32).collect();
638 let oid = Oid::new(arcs);
639 let result = oid.validate_length();
640 assert!(
641 result.is_err(),
642 "OID exceeding MAX_OID_LEN should fail validation"
643 );
644 }
645
646 #[test]
647 fn test_validate_all_combines_checks() {
648 let oid = Oid::from_slice(&[1, 3, 6, 1]);
650 assert!(oid.validate_all().is_ok());
651
652 let oid = Oid::from_slice(&[3, 0]);
654 assert!(oid.validate_all().is_err());
655
656 let arcs: Vec<u32> = (0..(MAX_OID_LEN + 1) as u32).collect();
658 let oid = Oid::new(arcs);
659 assert!(oid.validate_all().is_err());
660 }
661
662 #[test]
663 fn test_oid_fromstr() {
664 let oid: Oid = "1.3.6.1.2.1.1.1.0".parse().unwrap();
666 assert_eq!(oid, oid!(1, 3, 6, 1, 2, 1, 1, 1, 0));
667
668 let empty: Oid = "".parse().unwrap();
670 assert!(empty.is_empty());
671
672 let single: Oid = "1".parse().unwrap();
674 assert_eq!(single.arcs(), &[1]);
675
676 let original = oid!(1, 3, 6, 1, 4, 1, 9, 9, 42);
678 let displayed = original.to_string();
679 let parsed: Oid = displayed.parse().unwrap();
680 assert_eq!(original, parsed);
681 }
682
683 #[test]
684 fn test_oid_fromstr_invalid() {
685 assert!("1.3.abc.1".parse::<Oid>().is_err());
687
688 assert!("1.3.-6.1".parse::<Oid>().is_err());
690 }
691}