Skip to content

Commit

Permalink
const-oid: add ObjectIdentifierRef; use for db (#1212)
Browse files Browse the repository at this point in the history
Adds a type alias for `ObjectIdentifier<&[u8]>` for OIDs whose backing
storage is a byte slice.

Changes the `db` to use OIDs backed by `'static` byte slices, which
makes them smaller than if they use a fixed-size buffer.

Also makes more methods generic so e.g. `Eq`/`PartialEq` work between
`ObjectIdentifier` and `ObjectIdentifierRef`.
  • Loading branch information
tarcieri authored Sep 4, 2023
1 parent 2c1d801 commit 2f6303b
Show file tree
Hide file tree
Showing 11 changed files with 6,850 additions and 3,654 deletions.
27 changes: 16 additions & 11 deletions const-oid/oiddbgen/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions const-oid/oiddbgen/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ edition = "2021"

[dependencies]
convert_case = "0.5.0"
const-oid = { path = ".." }
proc-macro2 = "1.0.36"
quote = "1.0.15"
regex = "1.5.5"
Expand Down
2 changes: 1 addition & 1 deletion const-oid/oiddbgen/ldap-parameters-3.csv
Original file line number Diff line number Diff line change
Expand Up @@ -660,7 +660,7 @@ uddiv3ExpiresAfter,A,1.3.6.1.1.10.4.42,[RFC4403]
uddiv3MaxEntities,A,1.3.6.1.1.10.4.41,[RFC4403]
uddiv3NodeId,A,1.3.6.1.1.10.4.36,[RFC4403]
uddiv3NotificationInterval,A,1.3.6.1.1.10.4.40,[RFC4403]
uddiv3ServiceKey,A,1.3.6.1.1. 10.4.32,[RFC4403]
uddiv3ServiceKey,A,1.3.6.1.1.10.4.32,[RFC4403]
uddiv3Subscription,O,1.3.6.1.1.10.6.9,[RFC4403]
uddiv3SubscriptionFilter,A,1.3.6.1.1.10.4.39,[RFC4403]
uddiv3SubscriptionKey,A,1.3.6.1.1.10.4.38,[RFC4403]
Expand Down
10 changes: 5 additions & 5 deletions const-oid/oiddbgen/src/ldap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,19 @@ impl<'a> LdapParser<'a> {
self.0.lines().filter_map(|line| {
let (name, next) = line.split_at(line.find(',').unwrap());
let (.., next) = next[1..].split_at(next[1..].find(',').unwrap());
let (obid, spec) = next[1..].split_at(next[1..].find(',').unwrap());
let (oid, spec) = next[1..].split_at(next[1..].find(',').unwrap());

let indx = obid.find('.')?;
obid.split_at(indx).0.parse::<usize>().ok()?;
let indx = oid.find('.')?;
oid.split_at(indx).0.parse::<usize>().ok()?;

if !spec.trim().starts_with(",[RFC") {
return None;
}

let spec = spec[2..][..spec.len() - 3].to_ascii_lowercase();
let name = name.trim().to_string();
let obid = obid.trim().to_string();
Some((spec, name, obid))
let oid = oid.trim().to_string();
Some((spec, name, oid))
})
}
}
9 changes: 0 additions & 9 deletions const-oid/oiddbgen/src/lib.rs

This file was deleted.

22 changes: 15 additions & 7 deletions const-oid/oiddbgen/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
use oiddbgen::{Asn1Parser, LdapParser, Root};
mod asn1;
mod ldap;
mod node;
mod root;
mod spec;

pub use asn1::Asn1Parser;
pub use ldap::LdapParser;
pub use root::Root;

// Update this database by downloading the CSV file here:
// https://www.iana.org/assignments/ldap-parameters/ldap-parameters.xhtml#ldap-parameters-3
Expand Down Expand Up @@ -32,19 +40,19 @@ const NO_BASES: &[(&str, &str)] = &[("", "")];
fn main() {
let mut root = Root::default();

for (spec, name, obid) in LdapParser::new(LDAP).iter() {
root.add(&spec, &name, &obid);
for (spec, name, oid) in LdapParser::new(LDAP).iter() {
root.add(&spec, &name, &oid);
}

for (spec, body) in RFCS {
for (name, obid) in Asn1Parser::new(body, BASES).iter() {
root.add(spec, &name, &obid);
for (name, oid) in Asn1Parser::new(body, BASES).iter() {
root.add(spec, &name, &oid);
}
}

for (spec, body) in MDS {
for (name, obid) in Asn1Parser::new(body, NO_BASES).iter() {
root.add(spec, &name, &obid);
for (name, oid) in Asn1Parser::new(body, NO_BASES).iter() {
root.add(spec, &name, &oid);
}
}

Expand Down
41 changes: 15 additions & 26 deletions const-oid/oiddbgen/src/node.rs
Original file line number Diff line number Diff line change
@@ -1,36 +1,17 @@
use std::cmp::Ordering;

use const_oid::ObjectIdentifier;
use convert_case::{Case, Casing};
use proc_macro2::{Ident, Span, TokenStream};
use quote::quote;

#[derive(Clone, Debug, PartialEq, Eq)]
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub struct Node {
obid: String,
oid: ObjectIdentifier,
name: String,
symb: Ident,
}

impl Ord for Node {
fn cmp(&self, other: &Self) -> Ordering {
match self.obid.cmp(&other.obid) {
Ordering::Equal => match self.name.len().cmp(&other.name.len()) {
Ordering::Equal => self.name.cmp(&other.name),
o => o,
},
o => o,
}
}
}

impl PartialOrd for Node {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}

impl Node {
pub fn new(obid: String, name: String) -> Self {
pub fn new(oid: ObjectIdentifier, name: String) -> Self {
// Raise the first letter in the beginning or after a hyphen.
// This produces more natural UpperSnake conversions below.
let mut upper = true;
Expand All @@ -51,7 +32,7 @@ impl Node {
let symb = symb.to_case(Case::UpperSnake);
let symb = Ident::new(&symb, Span::call_site());

Self { obid, name, symb }
Self { oid, name, symb }
}

pub fn name(&self) -> &str {
Expand All @@ -63,11 +44,19 @@ impl Node {
}

pub fn definition(&self) -> TokenStream {
let obid = self.obid.replace(' ', ""); // Fix a typo.
let symb = &self.symb;
let oid = self.oid.to_string();
let doc = format!("#[doc=\"{}: {}\"]", &self.oid, &self.name)
.parse::<TokenStream>()
.expect("malformed doc comment");

let bytes = format!("&{:?}", oid.as_bytes())
.parse::<TokenStream>()
.expect("malformed byte slice literal");

quote! {
pub const #symb: crate::ObjectIdentifier = crate::ObjectIdentifier::new_unwrap(#obid);
#doc
pub const #symb: crate::ObjectIdentifierRef<'static> = crate::ObjectIdentifierRef::from_bytes_unchecked(#bytes);
}
}
}
13 changes: 6 additions & 7 deletions const-oid/oiddbgen/src/root.rs
Original file line number Diff line number Diff line change
@@ -1,24 +1,23 @@
use crate::{node::Node, spec::Spec};

use std::collections::BTreeMap;

use const_oid::ObjectIdentifier;
use proc_macro2::{Ident, Span, TokenStream};
use quote::quote;
use std::collections::BTreeMap;

#[derive(Clone, Debug, Default)]
pub struct Root(BTreeMap<Ident, Spec>);

impl Root {
pub fn add(&mut self, spec: &str, name: &str, obid: &str) {
pub fn add(&mut self, spec: &str, name: &str, oid: &str) {
let name = name.trim().to_string();
let obid = obid.trim().to_string();
let oid = oid.trim().parse::<ObjectIdentifier>().expect("invalid OID");
let spec = spec.trim().to_ascii_lowercase();
let spec = Ident::new(&spec, Span::call_site());

self.0
.entry(spec)
.or_insert_with(Spec::default)
.insert(Node::new(obid, name));
.insert(Node::new(oid, name));
}

pub fn module(&self) -> TokenStream {
Expand All @@ -27,7 +26,7 @@ impl Root {

for (spec, s) in &self.0 {
mods.extend(s.module(spec));
recs.extend(s.records(quote! { &#spec }));
recs.extend(s.records(quote! { #spec }));
}

quote! {
Expand Down
21 changes: 11 additions & 10 deletions const-oid/src/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ mod gen;

pub use gen::*;

use crate::{Error, ObjectIdentifier};
use crate::{Error, ObjectIdentifier, ObjectIdentifierRef};

/// A const implementation of case-insensitive ASCII equals.
const fn eq_case(lhs: &[u8], rhs: &[u8]) -> bool {
Expand All @@ -37,7 +37,7 @@ const fn eq_case(lhs: &[u8], rhs: &[u8]) -> bool {

/// A query interface for OIDs/Names.
#[derive(Copy, Clone)]
pub struct Database<'a>(&'a [(&'a ObjectIdentifier, &'a str)]);
pub struct Database<'a>(&'a [(ObjectIdentifierRef<'a>, &'a str)]);

impl<'a> Database<'a> {
/// Looks up a name for an OID.
Expand All @@ -52,13 +52,14 @@ impl<'a> Database<'a> {
}

/// Finds a named oid by its associated OID.
pub const fn by_oid(&self, oid: &ObjectIdentifier) -> Option<&'a str> {
pub fn by_oid<B>(&self, oid: &ObjectIdentifier<B>) -> Option<&'a str>
where
B: AsRef<[u8]>,
{
let mut i = 0;

while i < self.0.len() {
let lhs = self.0[i].0;

if lhs.buffer.eq(&oid.buffer) {
if oid == &self.0[i].0 {
return Some(self.0[i].1);
}

Expand All @@ -69,7 +70,7 @@ impl<'a> Database<'a> {
}

/// Finds a named oid by its associated name.
pub const fn by_name(&self, name: &str) -> Option<&'a ObjectIdentifier> {
pub const fn by_name(&self, name: &str) -> Option<ObjectIdentifierRef<'a>> {
let mut i = 0;

while i < self.0.len() {
Expand All @@ -85,7 +86,7 @@ impl<'a> Database<'a> {
}

/// Return the list of matched name for the OID.
pub const fn find_names_for_oid(&self, oid: ObjectIdentifier) -> Names<'a> {
pub fn find_names_for_oid(&self, oid: ObjectIdentifier) -> Names<'a> {
Names {
database: *self,
oid,
Expand All @@ -110,7 +111,7 @@ impl<'a> Iterator for Names<'a> {
while i < self.database.0.len() {
let lhs = self.database.0[i].0;

if lhs.buffer.eq(&self.oid.buffer) {
if lhs.eq(&self.oid) {
self.position = i + 1;
return Some(self.database.0[i].1);
}
Expand Down Expand Up @@ -140,7 +141,7 @@ mod tests {
#[test]
fn by_name() {
let cn = super::DB.by_name("CN").expect("cn not found");
assert_eq!(&CN, cn);
assert_eq!(CN, cn);

assert_eq!(None, super::DB.by_name("purplePeopleEater"));
}
Expand Down
Loading

0 comments on commit 2f6303b

Please sign in to comment.