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