Skip to content

Commit

Permalink
const-oid: make ObjectIdentifier's size const generic
Browse files Browse the repository at this point in the history
Previously the v0.10-pre release series has attempted to make
`ObjectIdentifier` generic around a backing buffer containing the BER
encoding and bounded on `AsRef<[u8]>`.

This approach has a drawback though: we can't use derived
`PartialEq`/`Eq`, which means it isn't possible to use in `match`
expressions anymore, an ergonomics drawback noted in #1293, with the
implementation reverted in #1299.

An alternative way to go for what it was trying to implement: an
`ObjectIdentifierRef` backed by a `&[u8]` is to use a separate struct.
With that approach, there could be overlapping `PartialEq`/`Eq` impls
that would allow the two to be compared.

As a start towards going that route, this gets rid of the generic
backing buffer and opts instead to make the struct const generic around
its size with a default.
  • Loading branch information
tarcieri committed Jan 4, 2024
1 parent afe505d commit 43cee88
Showing 1 changed file with 9 additions and 25 deletions.
34 changes: 9 additions & 25 deletions const-oid/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ use core::{fmt, str::FromStr};
/// Default maximum size.
///
/// Makes `ObjectIdentifier` 40-bytes total w\ 1-byte length.
const MAX_SIZE: usize = 39;
const DEFAULT_MAX_SIZE: usize = 39;

/// A trait which associates an OID with a type.
pub trait AssociatedOid {
Expand Down Expand Up @@ -85,15 +85,15 @@ impl<T: AssociatedOid> DynAssociatedOid for T {
/// - The second arc MUST be within the range 0-39
/// - The BER/DER encoding of the OID MUST be shorter than
/// [`ObjectIdentifier::MAX_SIZE`]
#[derive(Copy, Clone, Eq, Hash, PartialEq, PartialOrd, Ord)]
pub struct ObjectIdentifier<B: AsRef<[u8]> = Buffer<MAX_SIZE>> {
#[derive(Clone, Copy, Eq, Hash, PartialEq, PartialOrd, Ord)]
pub struct ObjectIdentifier<const MAX_SIZE: usize = DEFAULT_MAX_SIZE> {
/// Buffer containing BER/DER-serialized bytes (sans ASN.1 tag/length)
buffer: B,
buffer: Buffer<MAX_SIZE>,
}

impl ObjectIdentifier {
/// Maximum size of a BER/DER-encoded OID in bytes.
pub const MAX_SIZE: usize = MAX_SIZE;
pub const MAX_SIZE: usize = DEFAULT_MAX_SIZE;

/// Parse an [`ObjectIdentifier`] from the dot-delimited string form,
/// panicking on parse errors.
Expand Down Expand Up @@ -203,20 +203,7 @@ impl ObjectIdentifier {
}
}

impl<'a> ObjectIdentifier<&'a [u8]> {
/// Initialize OID from a byte slice without validating that it contains
/// a well-formed BER-encoded OID.
///
/// Use with care, e.g. to define compact constants.
pub const fn from_bytes_unchecked(buffer: &'a [u8]) -> Self {
Self { buffer }
}
}

impl<B> ObjectIdentifier<B>
where
B: AsRef<[u8]>,
{
impl<const MAX_SIZE: usize> ObjectIdentifier<MAX_SIZE> {
/// Get the BER/DER serialization of this OID as bytes.
///
/// Note that this encoding omits the tag/length, and only contains the
Expand All @@ -243,10 +230,7 @@ where
}
}

impl<B> AsRef<[u8]> for ObjectIdentifier<B>
where
B: AsRef<[u8]>,
{
impl<const MAX_SIZE: usize> AsRef<[u8]> for ObjectIdentifier<MAX_SIZE> {
fn as_ref(&self) -> &[u8] {
self.as_bytes()
}
Expand All @@ -268,13 +252,13 @@ impl TryFrom<&[u8]> for ObjectIdentifier {
}
}

impl fmt::Debug for ObjectIdentifier {
impl<const MAX_SIZE: usize> fmt::Debug for ObjectIdentifier<MAX_SIZE> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "ObjectIdentifier({})", self)
}
}

impl fmt::Display for ObjectIdentifier {
impl<const MAX_SIZE: usize> fmt::Display for ObjectIdentifier<MAX_SIZE> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let len = self.arcs().count();

Expand Down

0 comments on commit 43cee88

Please sign in to comment.