1 //! OID Names Database
2 //!
3 //! The contents of this database are generated from the official IANA
4 //! [Object Identifier Descriptors] Registry CSV file and from [RFC 5280].
5 //! If we are missing values you care about, please contribute a patch to
6 //! `oiddbgen` (a subcrate in the source code) to generate the values from
7 //! the relevant standard.
8 //!
9 //! [RFC 5280]: https://datatracker.ietf.org/doc/html/rfc5280
10 //! [Object Identifier Descriptors]: https://www.iana.org/assignments/ldap-parameters/ldap-parameters.xhtml#ldap-parameters-3
11
12 #![allow(clippy::integer_arithmetic, missing_docs)]
13
14 mod gen;
15
16 pub use gen::*;
17
18 use crate::{Error, ObjectIdentifier};
19
20 /// A const implementation of byte equals.
eq(lhs: &[u8], rhs: &[u8]) -> bool21 const fn eq(lhs: &[u8], rhs: &[u8]) -> bool {
22 if lhs.len() != rhs.len() {
23 return false;
24 }
25
26 let mut i = 0usize;
27 while i < lhs.len() {
28 if lhs[i] != rhs[i] {
29 return false;
30 }
31
32 i += 1;
33 }
34
35 true
36 }
37
38 /// A const implementation of case-insensitive ASCII equals.
eq_case(lhs: &[u8], rhs: &[u8]) -> bool39 const fn eq_case(lhs: &[u8], rhs: &[u8]) -> bool {
40 if lhs.len() != rhs.len() {
41 return false;
42 }
43
44 let mut i = 0usize;
45 while i < lhs.len() {
46 if !lhs[i].eq_ignore_ascii_case(&rhs[i]) {
47 return false;
48 }
49
50 i += 1;
51 }
52
53 true
54 }
55
56 /// A query interface for OIDs/Names.
57 #[derive(Copy, Clone)]
58 pub struct Database<'a>(&'a [(&'a ObjectIdentifier, &'a str)]);
59
60 impl<'a> Database<'a> {
61 /// Looks up a name for an OID.
62 ///
63 /// Errors if the input is not a valid OID.
64 /// Returns the input if no name is found.
resolve<'b>(&self, oid: &'b str) -> Result<&'b str, Error> where 'a: 'b,65 pub fn resolve<'b>(&self, oid: &'b str) -> Result<&'b str, Error>
66 where
67 'a: 'b,
68 {
69 Ok(self.by_oid(&oid.parse()?).unwrap_or(oid))
70 }
71
72 /// Finds a named oid by its associated OID.
by_oid(&self, oid: &ObjectIdentifier) -> Option<&'a str>73 pub const fn by_oid(&self, oid: &ObjectIdentifier) -> Option<&'a str> {
74 let mut i = 0;
75
76 while i < self.0.len() {
77 let lhs = self.0[i].0;
78 if lhs.length == oid.length && eq(&lhs.bytes, &oid.bytes) {
79 return Some(self.0[i].1);
80 }
81
82 i += 1;
83 }
84
85 None
86 }
87
88 /// Finds a named oid by its associated name.
by_name(&self, name: &str) -> Option<&'a ObjectIdentifier>89 pub const fn by_name(&self, name: &str) -> Option<&'a ObjectIdentifier> {
90 let mut i = 0;
91
92 while i < self.0.len() {
93 let lhs = self.0[i].1;
94 if eq_case(lhs.as_bytes(), name.as_bytes()) {
95 return Some(self.0[i].0);
96 }
97
98 i += 1;
99 }
100
101 None
102 }
103
104 /// Return the list of matched name for the OID.
find_names_for_oid(&self, oid: ObjectIdentifier) -> Names<'a>105 pub const fn find_names_for_oid(&self, oid: ObjectIdentifier) -> Names<'a> {
106 Names {
107 database: *self,
108 oid,
109 position: 0,
110 }
111 }
112 }
113
114 /// Iterator returning the multiple names that may be associated with an OID.
115 pub struct Names<'a> {
116 database: Database<'a>,
117 oid: ObjectIdentifier,
118 position: usize,
119 }
120
121 impl<'a> Iterator for Names<'a> {
122 type Item = &'a str;
123
next(&mut self) -> Option<&'a str>124 fn next(&mut self) -> Option<&'a str> {
125 let mut i = self.position;
126
127 while i < self.database.0.len() {
128 let lhs = self.database.0[i].0;
129
130 if lhs.as_bytes().eq(self.oid.as_bytes()) {
131 self.position = i + 1;
132 return Some(self.database.0[i].1);
133 }
134
135 i += 1;
136 }
137
138 None
139 }
140 }
141
142 #[cfg(test)]
143 mod tests {
144 use crate::ObjectIdentifier;
145
146 use super::rfc4519::CN;
147
148 #[test]
by_oid()149 fn by_oid() {
150 let cn = super::DB.by_oid(&CN).expect("cn not found");
151 assert_eq!("cn", cn);
152
153 let none = ObjectIdentifier::new_unwrap("0.1.2.3.4.5.6.7.8.9");
154 assert_eq!(None, super::DB.by_oid(&none));
155 }
156
157 #[test]
by_name()158 fn by_name() {
159 let cn = super::DB.by_name("CN").expect("cn not found");
160 assert_eq!(&CN, cn);
161
162 assert_eq!(None, super::DB.by_name("purplePeopleEater"));
163 }
164 }
165