1#![allow(clippy::integer_arithmetic, missing_docs)]
13
14mod gen;
15
16pub use gen::*;
17
18use crate::{Error, ObjectIdentifier};
19
20const 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
38const 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#[derive(Copy, Clone)]
58pub struct Database<'a>(&'a [(&'a ObjectIdentifier, &'a str)]);
59
60impl<'a> Database<'a> {
61 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 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 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 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
114pub struct Names<'a> {
116 database: Database<'a>,
117 oid: ObjectIdentifier,
118 position: usize,
119}
120
121impl<'a> Iterator for Names<'a> {
122 type Item = &'a str;
123
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)]
143mod tests {
144 use crate::ObjectIdentifier;
145
146 use super::rfc4519::CN;
147
148 #[test]
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]
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}