Skip to content

Commit

Permalink
Implement ValueOrd in more places (#723)
Browse files Browse the repository at this point in the history
Implements `ValueOrd` for the following:

- `FlagSet<T>`
- `UIntRef`
- x509-cert `Version`

Allows deriving `ValueOrd` on `Choice` enums.

Derives `ValueOrd` for a bunch of structs.
  • Loading branch information
roblabla authored Nov 26, 2022
1 parent 2deb3a4 commit be9e7ca
Show file tree
Hide file tree
Showing 17 changed files with 135 additions and 67 deletions.
107 changes: 74 additions & 33 deletions der/derive/src/value_ord.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ pub(crate) struct DeriveValueOrd {

/// Fields of structs or enum variants.
fields: Vec<ValueField>,

is_enum: bool,
}

impl DeriveValueOrd {
Expand All @@ -36,17 +38,21 @@ impl DeriveValueOrd {
.next()
.map(|lt| lt.lifetime.clone());

let fields = match input.data {
syn::Data::Enum(data) => data
.variants
.into_iter()
.map(|variant| ValueField::new_enum(variant, &type_attrs))
.collect(),
syn::Data::Struct(data) => data
.fields
.into_iter()
.map(|field| ValueField::new_struct(field, &type_attrs))
.collect(),
let (fields, is_enum) = match input.data {
syn::Data::Enum(data) => (
data.variants
.into_iter()
.map(|variant| ValueField::new_enum(variant, &type_attrs))
.collect(),
true,
),
syn::Data::Struct(data) => (
data.fields
.into_iter()
.map(|field| ValueField::new_struct(field, &type_attrs))
.collect(),
false,
),
_ => abort!(
ident,
"can't derive `ValueOrd` on this type: \
Expand All @@ -58,6 +64,7 @@ impl DeriveValueOrd {
ident,
lifetime,
fields,
is_enum,
}
}

Expand All @@ -79,15 +86,30 @@ impl DeriveValueOrd {
body.push(field.to_tokens());
}

let body = if self.is_enum {
quote! {
#[allow(unused_imports)]
use ::der::ValueOrd;
match (self, other) {
#(#body)*
_ => unreachable!(),
}
}
} else {
quote! {
#[allow(unused_imports)]
use ::der::{DerOrd, ValueOrd};

#(#body)*

Ok(::core::cmp::Ordering::Equal)
}
};

quote! {
impl<#(#lt_params)*> ::der::ValueOrd for #ident<#(#lt_params)*> {
fn value_cmp(&self, other: &Self) -> ::der::Result<::core::cmp::Ordering> {
#[allow(unused_imports)]
use ::der::DerOrd;

#(#body)*

Ok(::core::cmp::Ordering::Equal)
#body
}
}
}
Expand All @@ -100,15 +122,21 @@ struct ValueField {

/// Field-level attributes.
attrs: FieldAttrs,

is_enum: bool,
}

impl ValueField {
/// Create from an `enum` variant.
fn new_enum(variant: Variant, _: &TypeAttrs) -> Self {
abort!(
variant,
"deriving `ValueOrd` only presently supported for structs"
);
fn new_enum(variant: Variant, type_attrs: &TypeAttrs) -> Self {
let ident = variant.ident;

let attrs = FieldAttrs::parse(&variant.attrs, type_attrs);
Self {
ident,
attrs,
is_enum: true,
}
}

/// Create from a `struct` field.
Expand All @@ -120,24 +148,37 @@ impl ValueField {
.unwrap_or_else(|| abort!(&field, "tuple structs are not supported"));

let attrs = FieldAttrs::parse(&field.attrs, type_attrs);
Self { ident, attrs }
Self {
ident,
attrs,
is_enum: false,
}
}

/// Lower to [`TokenStream`].
fn to_tokens(&self) -> TokenStream {
let ident = &self.ident;
let mut binding1 = quote!(self.#ident);
let mut binding2 = quote!(other.#ident);

if let Some(ty) = &self.attrs.asn1_type {
binding1 = ty.encoder(&binding1);
binding2 = ty.encoder(&binding2);
}
if self.is_enum {
let binding1 = quote!(Self::#ident(this));
let binding2 = quote!(Self::#ident(other));
quote! {
(#binding1, #binding2) => this.value_cmp(other),
}
} else {
let mut binding1 = quote!(self.#ident);
let mut binding2 = quote!(other.#ident);

quote! {
match #binding1.der_cmp(&#binding2)? {
::core::cmp::Ordering::Equal => (),
other => return Ok(other),
if let Some(ty) = &self.attrs.asn1_type {
binding1 = ty.encoder(&binding1);
binding2 = ty.encoder(&binding2);
}

quote! {
match #binding1.der_cmp(&#binding2)? {
::core::cmp::Ordering::Equal => (),
other => return Ok(other),
}
}
}
}
Expand Down
11 changes: 11 additions & 0 deletions der/src/asn1/bit_string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,17 @@ impl<T: flagset::Flags> FixedTag for flagset::FlagSet<T> {
const TAG: Tag = BitStringRef::TAG;
}

#[cfg(feature = "flagset")]
impl<T> ValueOrd for flagset::FlagSet<T>
where
T: flagset::Flags,
T::Type: Ord,
{
fn value_cmp(&self, other: &Self) -> Result<Ordering> {
Ok(self.bits().cmp(&other.bits()))
}
}

#[cfg(feature = "flagset")]
#[allow(clippy::integer_arithmetic)]
impl<'a, T> DecodeValue<'a> for flagset::FlagSet<T>
Expand Down
8 changes: 5 additions & 3 deletions der/src/asn1/integer/bigint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

use super::uint;
use crate::{
asn1::AnyRef, ByteSlice, DecodeValue, EncodeValue, Error, ErrorKind, FixedTag, Header, Length,
Reader, Result, Tag, Writer,
asn1::AnyRef, ord::OrdIsValueOrd, ByteSlice, DecodeValue, EncodeValue, Error, ErrorKind,
FixedTag, Header, Length, Reader, Result, Tag, Writer,
};

/// "Big" unsigned ASN.1 `INTEGER` type.
Expand All @@ -13,7 +13,7 @@ use crate::{
///
/// Intended for use cases like very large integers that are used in
/// cryptographic applications (e.g. keys, signatures).
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub struct UIntRef<'a> {
/// Inner value
inner: ByteSlice<'a>,
Expand Down Expand Up @@ -92,6 +92,8 @@ impl<'a> FixedTag for UIntRef<'a> {
const TAG: Tag = Tag::Integer;
}

impl<'a> OrdIsValueOrd for UIntRef<'a> {}

#[cfg(test)]
mod tests {
use super::UIntRef;
Expand Down
13 changes: 10 additions & 3 deletions x509-cert/src/certificate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
use crate::{name::Name, time::Validity};

use alloc::vec::Vec;
use core::cmp::Ordering;

use const_oid::AssociatedOid;
use der::asn1::{BitStringRef, UIntRef};
use der::{Decode, Enumerated, Error, ErrorKind, Sequence};
use der::{Decode, Enumerated, Error, ErrorKind, Sequence, ValueOrd};
use spki::{AlgorithmIdentifier, SubjectPublicKeyInfo};

#[cfg(feature = "pem")]
Expand All @@ -33,6 +34,12 @@ pub enum Version {
V3 = 2,
}

impl ValueOrd for Version {
fn value_cmp(&self, other: &Self) -> der::Result<Ordering> {
(&(*self as u8)).value_cmp(&(*other as u8))
}
}

impl Default for Version {
fn default() -> Self {
Self::V1
Expand Down Expand Up @@ -64,7 +71,7 @@ impl Default for Version {
/// ```
///
/// [RFC 5280 Section 4.1]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1
#[derive(Clone, Debug, Eq, PartialEq, Sequence)]
#[derive(Clone, Debug, Eq, PartialEq, Sequence, ValueOrd)]
#[allow(missing_docs)]
pub struct TbsCertificate<'a> {
/// The certificate version
Expand Down Expand Up @@ -138,7 +145,7 @@ impl<'a> TbsCertificate<'a> {
/// ```
///
/// [RFC 5280 Section 4.1]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1
#[derive(Clone, Debug, Eq, PartialEq, Sequence)]
#[derive(Clone, Debug, Eq, PartialEq, Sequence, ValueOrd)]
#[allow(missing_docs)]
pub struct Certificate<'a> {
pub tbs_certificate: TbsCertificate<'a>,
Expand Down
8 changes: 4 additions & 4 deletions x509-cert/src/crl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::Version;
use alloc::vec::Vec;

use der::asn1::{BitStringRef, UIntRef};
use der::Sequence;
use der::{Sequence, ValueOrd};
use spki::AlgorithmIdentifier;

/// `CertificateList` as defined in [RFC 5280 Section 5.1].
Expand All @@ -22,7 +22,7 @@ use spki::AlgorithmIdentifier;
/// ```
///
/// [RFC 5280 Section 5.1]: https://datatracker.ietf.org/doc/html/rfc5280#section-5.1
#[derive(Clone, Debug, Eq, PartialEq, Sequence)]
#[derive(Clone, Debug, Eq, PartialEq, Sequence, ValueOrd)]
#[allow(missing_docs)]
pub struct CertificateList<'a> {
pub tbs_cert_list: TbsCertList<'a>,
Expand All @@ -44,7 +44,7 @@ pub struct CertificateList<'a> {
/// ```
///
/// [RFC 5280 Section 5.1]: https://datatracker.ietf.org/doc/html/rfc5280#section-5.1
#[derive(Clone, Debug, Eq, PartialEq, Sequence)]
#[derive(Clone, Debug, Eq, PartialEq, Sequence, ValueOrd)]
#[allow(missing_docs)]
pub struct RevokedCert<'a> {
pub serial_number: UIntRef<'a>,
Expand All @@ -71,7 +71,7 @@ pub struct RevokedCert<'a> {
/// ```
///
/// [RFC 5280 Section 5.1]: https://datatracker.ietf.org/doc/html/rfc5280#section-5.1
#[derive(Clone, Debug, Eq, PartialEq, Sequence)]
#[derive(Clone, Debug, Eq, PartialEq, Sequence, ValueOrd)]
#[allow(missing_docs)]
pub struct TbsCertList<'a> {
pub version: Version,
Expand Down
4 changes: 2 additions & 2 deletions x509-cert/src/ext.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Standardized X.509 Certificate Extensions

use der::Sequence;
use der::{Sequence, ValueOrd};
use spki::ObjectIdentifier;

pub mod pkix;
Expand All @@ -22,7 +22,7 @@ pub mod pkix;
/// ```
///
/// [RFC 5280 Section 4.1.2.9]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.9
#[derive(Clone, Debug, Eq, PartialEq, Sequence)]
#[derive(Clone, Debug, Eq, PartialEq, Sequence, ValueOrd)]
#[allow(missing_docs)]
pub struct Extension<'a> {
pub extn_id: ObjectIdentifier,
Expand Down
4 changes: 2 additions & 2 deletions x509-cert/src/ext/pkix/access.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use const_oid::{
db::rfc5280::{ID_PE_AUTHORITY_INFO_ACCESS, ID_PE_SUBJECT_INFO_ACCESS},
AssociatedOid,
};
use der::{asn1::ObjectIdentifier, Sequence};
use der::{asn1::ObjectIdentifier, Sequence, ValueOrd};

/// AuthorityInfoAccessSyntax as defined in [RFC 5280 Section 4.2.2.1].
///
Expand Down Expand Up @@ -50,7 +50,7 @@ impl_newtype!(SubjectInfoAccessSyntax<'a>, Vec<AccessDescription<'a>>);
/// ```
///
/// [RFC 5280 Section 4.2.2.1]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.2.1
#[derive(Clone, Debug, Eq, PartialEq, Sequence)]
#[derive(Clone, Debug, Eq, PartialEq, Sequence, ValueOrd)]
#[allow(missing_docs)]
pub struct AccessDescription<'a> {
pub access_method: ObjectIdentifier,
Expand Down
6 changes: 3 additions & 3 deletions x509-cert/src/ext/pkix/certpolicy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use alloc::vec::Vec;
use const_oid::db::rfc5912::ID_CE_CERTIFICATE_POLICIES;
use const_oid::AssociatedOid;
use der::asn1::{GeneralizedTime, Ia5StringRef, ObjectIdentifier, UIntRef, Utf8StringRef};
use der::{AnyRef, Choice, Sequence};
use der::{AnyRef, Choice, Sequence, ValueOrd};

/// CertificatePolicies as defined in [RFC 5280 Section 4.2.1.4].
///
Expand Down Expand Up @@ -35,7 +35,7 @@ impl_newtype!(CertificatePolicies<'a>, Vec<PolicyInformation<'a>>);
/// ```
///
/// [RFC 5280 Section 4.2.1.4]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.4
#[derive(Clone, Debug, Eq, PartialEq, Sequence)]
#[derive(Clone, Debug, Eq, PartialEq, Sequence, ValueOrd)]
#[allow(missing_docs)]
pub struct PolicyInformation<'a> {
pub policy_identifier: ObjectIdentifier,
Expand All @@ -52,7 +52,7 @@ pub struct PolicyInformation<'a> {
/// ```
///
/// [RFC 5280 Section 4.2.1.4]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.4
#[derive(Clone, Debug, Eq, PartialEq, Sequence)]
#[derive(Clone, Debug, Eq, PartialEq, Sequence, ValueOrd)]
#[allow(missing_docs)]
pub struct PolicyQualifierInfo<'a> {
pub policy_qualifier_id: ObjectIdentifier,
Expand Down
4 changes: 2 additions & 2 deletions x509-cert/src/ext/pkix/crl/dp.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! PKIX distribution point types

use const_oid::{db::rfc5280::ID_PE_SUBJECT_INFO_ACCESS, AssociatedOid, ObjectIdentifier};
use der::Sequence;
use der::{Sequence, ValueOrd};
use flagset::{flags, FlagSet};

use crate::ext::pkix::name::{DistributionPointName, GeneralNames};
Expand Down Expand Up @@ -74,7 +74,7 @@ impl<'a> AssociatedOid for IssuingDistributionPoint<'a> {
/// ```
///
/// [RFC 5280 Section 4.2.1.13]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.13
#[derive(Clone, Debug, PartialEq, Eq, Sequence)]
#[derive(Clone, Debug, PartialEq, Eq, Sequence, ValueOrd)]
#[allow(missing_docs)]
pub struct DistributionPoint<'a> {
#[asn1(context_specific = "0", tag_mode = "EXPLICIT", optional = "true")]
Expand Down
4 changes: 2 additions & 2 deletions x509-cert/src/ext/pkix/name/dirstr.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use der::asn1::{PrintableStringRef, TeletexStringRef, Utf8StringRef};
use der::Choice;
use der::{Choice, ValueOrd};

/// DirectoryString as defined in [RFC 5280 Section 4.2.1.4].
///
Expand Down Expand Up @@ -38,7 +38,7 @@ use der::Choice;
/// the need arises, we only support `PrintableString` and `UTF8String`.
///
/// [RFC 5280 Section 4.2.1.4]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.4
#[derive(Clone, Debug, Eq, PartialEq, Choice)]
#[derive(Clone, Debug, Eq, PartialEq, Choice, ValueOrd)]
#[allow(missing_docs)]
pub enum DirectoryString<'a> {
#[asn1(type = "PrintableString")]
Expand Down
Loading

0 comments on commit be9e7ca

Please sign in to comment.