summaryrefslogtreecommitdiffstats
path: root/vendor/const-oid/src/db.rs
blob: 971990de004b3b3c52fee4f9842b2ce4ffebc4fd (plain)
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
//! 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.
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
    }
}

#[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"));
    }
}