const_oid/
arcs.rs

1//! Arcs are integer values which exist within an OID's hierarchy.
2
3use crate::{Error, ObjectIdentifier, Result};
4use core::mem;
5
6/// Type used to represent an "arc" (i.e. integer identifier value).
7pub type Arc = u32;
8
9/// Maximum value of the first arc in an OID.
10pub(crate) const ARC_MAX_FIRST: Arc = 2;
11
12/// Maximum value of the second arc in an OID.
13pub(crate) const ARC_MAX_SECOND: Arc = 39;
14
15/// Maximum number of bytes supported in an arc.
16pub(crate) const ARC_MAX_BYTES: usize = mem::size_of::<Arc>();
17
18/// Maximum value of the last byte in an arc.
19pub(crate) const ARC_MAX_LAST_OCTET: u8 = 0b11110000; // Max bytes of leading 1-bits
20
21/// [`Iterator`] over arcs (a.k.a. nodes) in an [`ObjectIdentifier`].
22///
23/// This iterates over all arcs in an OID, including the root.
24pub struct Arcs<'a> {
25    /// OID we're iterating over
26    oid: &'a ObjectIdentifier,
27
28    /// Current position within the serialized DER bytes of this OID
29    cursor: Option<usize>,
30}
31
32impl<'a> Arcs<'a> {
33    /// Create a new iterator over the arcs of this OID
34    pub(crate) fn new(oid: &'a ObjectIdentifier) -> Self {
35        Self { oid, cursor: None }
36    }
37}
38
39impl<'a> Iterator for Arcs<'a> {
40    type Item = Arc;
41
42    fn next(&mut self) -> Option<Arc> {
43        match self.cursor {
44            // Indicates we're on the root OID
45            None => {
46                let root = RootArcs(self.oid.as_bytes()[0]);
47                self.cursor = Some(0);
48                Some(root.first_arc())
49            }
50            Some(0) => {
51                let root = RootArcs(self.oid.as_bytes()[0]);
52                self.cursor = Some(1);
53                Some(root.second_arc())
54            }
55            Some(offset) => {
56                let mut result = 0;
57                let mut arc_bytes = 0;
58
59                // TODO(tarcieri): consolidate this with `ObjectIdentifier::from_bytes`?
60                loop {
61                    match self.oid.as_bytes().get(offset + arc_bytes).cloned() {
62                        Some(byte) => {
63                            arc_bytes += 1;
64                            debug_assert!(
65                                arc_bytes <= ARC_MAX_BYTES || byte & ARC_MAX_LAST_OCTET == 0,
66                                "OID arc overflowed"
67                            );
68                            result = result << 7 | (byte & 0b1111111) as Arc;
69
70                            if byte & 0b10000000 == 0 {
71                                self.cursor = Some(offset + arc_bytes);
72                                return Some(result);
73                            }
74                        }
75                        None => {
76                            debug_assert_eq!(arc_bytes, 0, "truncated OID");
77                            return None;
78                        }
79                    }
80                }
81            }
82        }
83    }
84}
85
86/// Byte containing the first and second arcs of an OID.
87///
88/// This is represented this way in order to reduce the overall size of the
89/// [`ObjectIdentifier`] struct.
90#[derive(Copy, Clone, Debug, Eq, PartialEq)]
91pub(crate) struct RootArcs(u8);
92
93impl RootArcs {
94    /// Create [`RootArcs`] from the first and second arc values represented
95    /// as `Arc` integers.
96    pub(crate) fn new(first_arc: Arc, second_arc: Arc) -> Result<Self> {
97        if first_arc > ARC_MAX_FIRST || second_arc > ARC_MAX_SECOND {
98            return Err(Error);
99        }
100
101        let byte = (first_arc * (ARC_MAX_SECOND + 1)) as u8 + second_arc as u8;
102        Ok(Self(byte))
103    }
104
105    /// Get the value of the first arc
106    pub(crate) fn first_arc(self) -> Arc {
107        self.0 as Arc / (ARC_MAX_SECOND + 1)
108    }
109
110    /// Get the value of the second arc
111    pub(crate) fn second_arc(self) -> Arc {
112        self.0 as Arc % (ARC_MAX_SECOND + 1)
113    }
114}
115
116impl TryFrom<u8> for RootArcs {
117    type Error = Error;
118
119    fn try_from(octet: u8) -> Result<Self> {
120        let first = octet as Arc / (ARC_MAX_SECOND + 1);
121        let second = octet as Arc % (ARC_MAX_SECOND + 1);
122        let result = Self::new(first, second)?;
123        debug_assert_eq!(octet, result.0);
124        Ok(result)
125    }
126}
127
128impl From<RootArcs> for u8 {
129    fn from(root_arcs: RootArcs) -> u8 {
130        root_arcs.0
131    }
132}