#![allow(clippy::arithmetic_side_effects, missing_docs)]
mod gen;
pub use gen::*;
use crate::{Error, ObjectIdentifier};
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
}
#[derive(Copy, Clone)]
pub struct Database<'a>(&'a [(&'a ObjectIdentifier, &'a str)]);
impl<'a> Database<'a> {
pub fn resolve<'b>(&self, oid: &'b str) -> Result<&'b str, Error>
where
'a: 'b,
{
Ok(self.by_oid(&oid.parse()?).unwrap_or(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.ber.eq(&oid.ber) {
return Some(self.0[i].1);
}
i += 1;
}
None
}
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
}
pub const fn find_names_for_oid(&self, oid: ObjectIdentifier) -> Names<'a> {
Names {
database: *self,
oid,
position: 0,
}
}
}
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.ber.eq(&self.oid.ber) {
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"));
}
}