Skip to content

Commit

Permalink
Fix derive codegen
Browse files Browse the repository at this point in the history
  • Loading branch information
XAMPPRocky committed Aug 21, 2021
1 parent 6a47efb commit 3d94b96
Show file tree
Hide file tree
Showing 10 changed files with 144 additions and 155 deletions.
30 changes: 14 additions & 16 deletions macros/src/decode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,26 +132,23 @@ pub fn derive_enum_impl(
let variant_tag = variant_config.tag(i);
let ident = &v.ident;
match &v.fields {
syn::Fields::Unit => quote!(if let Ok(()) = decoder.decode_null(#variant_tag) { return Ok(#name::#ident) }),
syn::Fields::Unit => quote!(if let Ok(()) = <()>::decode_with_tag(decoder, #variant_tag) { return Ok(#name::#ident) }),
syn::Fields::Unnamed(_) => {
if v.fields.len() != 1 {
panic!("Tuple struct variants should contain only a single element.");
}
if config.automatic_tags || variant_config.tag.is_some() {
let ty = v.fields.iter().next().unwrap();
quote! {
let result = if <#ty as #crate_root::AsnType>::TAG.const_eq(&#crate_root::Tag::EOC) {
decoder.decode_explicit_prefix(#variant_tag).map(#name::#ident)
} else {
<_>::decode_with_tag(decoder, #variant_tag).map(#name::#ident)
};

if let Ok(value) = result {
return Ok(value)
}
}

let decode_operation = if config.automatic_tags || variant_config.tag.is_some() {
quote!(<_>::decode_with_tag(decoder, #variant_tag))
} else {
quote!(if let Ok(value) = <_>::decode(decoder).map(#name::#ident) { return Ok(value) })
quote!(<_>::decode(decoder))
};

quote!{
match #decode_operation.map(#name::#ident) {
Ok(value) => return Ok(value),
_ => {}
}
}
},
syn::Fields::Named(_) => {
Expand Down Expand Up @@ -182,9 +179,10 @@ pub fn derive_enum_impl(
"Decoding field of type `{}`: Invalid `CHOICE` discriminant.",
name.to_string(),
);

Some(quote! {
fn decode<D: #crate_root::Decoder>(decoder: &mut D) -> Result<Self, D::Error> {
#(#variants)*
#(#variants);*
Err(#crate_root::de::Error::custom(#match_fail_error))
}
})
Expand Down
21 changes: 9 additions & 12 deletions macros/src/encode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,19 +137,16 @@ pub fn derive_enum_impl(
if v.fields.iter().count() != 1 {
panic!("Tuple variants must contain only a single element.");
}
if variant_config.tag.is_some() || config.automatic_tags {
let ty = v.fields.iter().next().unwrap();
quote! {
#name::#ident(value) => {
if <#ty as #crate_root::AsnType>::TAG.is_choice() {
encoder.encode_explicit_prefix(#variant_tag, value).map(drop)
} else {
#crate_root::Encode::encode_with_tag(value, encoder, #variant_tag).map(drop)
}
}
}
let encode_operation = if variant_config.tag.is_some() || config.automatic_tags {
quote!(#crate_root::Encode::encode_with_tag(value, encoder, #variant_tag))
} else {
quote!(#name::#ident(value) => { #crate_root::Encode::encode(value, encoder).map(drop) })
quote!(#crate_root::Encode::encode(value, encoder))
};

quote! {
#name::#ident(value) => {
#encode_operation.map(drop)
}
}
}
syn::Fields::Unit => quote!(#name::#ident => { encoder.encode_null(#variant_tag).map(drop) }),
Expand Down
12 changes: 0 additions & 12 deletions src/ber.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,18 +173,6 @@ mod tests {
assert_eq!(new_int, decode(&encode(&new_int).unwrap()).unwrap());
}

#[test]
fn explicit_empty_tag() {
use crate::types::Explicit;
type EmptyTag = Explicit<C0, Option<()>>;

let value = EmptyTag::new(None::<()>);
let data = &[0x80, 0][..];

assert_eq!(data, &*crate::ber::encode(&value).unwrap());
assert_eq!(value, crate::ber::decode::<EmptyTag>(data).unwrap());
}

#[test]
fn implicit_tagged_constructed() {
use crate::types::Implicit;
Expand Down
10 changes: 0 additions & 10 deletions src/ber/de.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,21 +57,11 @@ impl<'input> Decoder<'input> {
None => error::IndefiniteLengthNotAllowed.fail(),
}
}

pub(crate) fn peek_identifier(&self) -> Result<Identifier> {
let (_, identifier) =
self::parser::parse_identifier_octet(self.input).map_err(error::map_nom_err)?;
Ok(identifier)
}
}

impl<'input> crate::Decoder for Decoder<'input> {
type Error = Error;

fn peek_tag(&self) -> Result<Tag> {
Ok(self.peek_identifier()?.tag)
}

fn decode_any(&mut self, tag: Tag) -> Result<Vec<u8>> {
let (input, (_, contents)) = self::parser::parse_value(&self.config, self.input, tag)?;
self.input = input;
Expand Down
13 changes: 5 additions & 8 deletions src/de.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,6 @@ pub trait Decode: Sized + AsnType {
pub trait Decoder: Sized {
type Error: Error;

/// Peek at the next available tag.
fn peek_tag(&self) -> Result<Tag, Self::Error>;

/// Decode a unknown ASN.1 value identified by `tag` from the available input.
fn decode_any(&mut self, tag: Tag) -> Result<Vec<u8>, Self::Error>;
/// Decode a `BIT STRING` identified by `tag` from the available input.
Expand Down Expand Up @@ -99,12 +96,12 @@ impl Decode for () {
}

impl<D: Decode> Decode for Option<D> {
fn decode<DE: Decoder>(decoder: &mut DE) -> Result<Self, DE::Error> {
D::decode(decoder).map(Some)
}

fn decode_with_tag<DE: Decoder>(decoder: &mut DE, tag: Tag) -> Result<Self, DE::Error> {
if decoder.peek_tag().map_or(false, |t| t == tag) {
D::decode_with_tag(decoder, tag).map(Some)
} else {
Ok(None)
}
D::decode_with_tag(decoder, tag).map(Some)
}
}

Expand Down
24 changes: 20 additions & 4 deletions src/enc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,11 +106,17 @@ impl Encode for () {
}

impl<E: Encode> Encode for Option<E> {
fn encode<EN: Encoder>(&self, encoder: &mut EN) -> Result<(), EN::Error> {
match self {
Some(value) => E::encode(&value, encoder),
None => Ok(()),
}
}

fn encode_with_tag<EN: Encoder>(&self, encoder: &mut EN, tag: Tag) -> Result<(), EN::Error> {
if let Some(inner) = &self {
Ok(Encode::encode_with_tag(inner, encoder, tag)?)
} else {
Ok(())
match self {
Some(value) => E::encode_with_tag(&value, encoder, tag),
None => Ok(()),
}
}
}
Expand Down Expand Up @@ -202,6 +208,16 @@ impl Encode for types::GeneralizedTime {
}
}

impl<E: Encode> Encode for alloc::boxed::Box<E> {
fn encode<EN: Encoder>(&self, encoder: &mut EN) -> Result<(), EN::Error> {
E::encode(&*self, encoder)
}

fn encode_with_tag<EN: Encoder>(&self, encoder: &mut EN, tag: Tag) -> Result<(), EN::Error> {
E::encode_with_tag(&*self, encoder, tag)
}
}

impl<E: Encode> Encode for alloc::vec::Vec<E> {
fn encode_with_tag<EN: Encoder>(&self, encoder: &mut EN, tag: Tag) -> Result<(), EN::Error> {
encoder.encode_sequence_of(tag, self).map(drop)
Expand Down
2 changes: 2 additions & 0 deletions src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ asn_type! {

impl<T: AsnType> AsnType for Box<T> {
const TAG: Tag = T::TAG;
const TAG_TREE: TagTree = T::TAG_TREE;
}

impl<T: AsnType> AsnType for alloc::vec::Vec<T> {
Expand All @@ -104,6 +105,7 @@ impl<T: AsnType> AsnType for alloc::vec::Vec<T> {

impl<T: AsnType> AsnType for Option<T> {
const TAG: Tag = T::TAG;
const TAG_TREE: TagTree = T::TAG_TREE;
}

impl<T> AsnType for SetOf<T> {
Expand Down
96 changes: 4 additions & 92 deletions src/types/open.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
use super::*;
use crate::{Decode, Encode};

/// An "open" type representing any valid ASN.1 type.
#[derive(Debug, Clone, PartialEq)]
#[derive(AsnType, Debug, Clone, PartialEq, Decode, Encode)]
#[rasn(crate_root="crate")]
#[rasn(choice)]
pub enum Open {
BitString(BitString),
BmpString(BmpString),
Expand All @@ -16,95 +19,4 @@ pub enum Open {
UtcTime(UtcTime),
VisibleString(VisibleString),
InstanceOf(alloc::boxed::Box<InstanceOf<Open>>),
Unknown {
tag: Tag,
value: alloc::vec::Vec<u8>,
},
}

impl Open {
/// Returns the tag of the variant.
pub fn tag(&self) -> Tag {
match self {
Self::BitString(_) => BitString::TAG,
Self::BmpString(_) => BmpString::TAG,
Self::Bool(_) => bool::TAG,
Self::GeneralizedTime(_) => GeneralizedTime::TAG,
Self::IA5String(_) => IA5String::TAG,
Self::InstanceOf(_) => <InstanceOf<Open>>::TAG,
Self::Integer(_) => Integer::TAG,
Self::Null => <()>::TAG,
Self::OctetString(_) => OctetString::TAG,
Self::PrintableString(_) => PrintableString::TAG,
Self::UniversalString(_) => UniversalString::TAG,
Self::UtcTime(_) => UtcTime::TAG,
Self::VisibleString(_) => VisibleString::TAG,
Self::Unknown { tag, .. } => *tag,
}
}
}

impl crate::AsnType for Open {
const TAG: Tag = Tag::EOC;
}

impl crate::Decode for Open {
fn decode_with_tag<D: crate::Decoder>(_: &mut D, _: Tag) -> Result<Self, D::Error> {
Err(crate::de::Error::custom(
"`CHOICE`-style enums cannot be implicitly tagged.",
))
}
fn decode<D: crate::Decoder>(decoder: &mut D) -> Result<Self, D::Error> {
Ok(match decoder.peek_tag()? {
Tag::EOC => return Err(crate::de::Error::custom("Invalid ASN.1 Type")),
Tag::BIT_STRING => Open::BitString(<_>::decode(decoder)?),
Tag::BMP_STRING => Open::BmpString(<_>::decode(decoder)?),
Tag::BOOL => Open::Bool(<_>::decode(decoder)?),
Tag::IA5_STRING => Open::IA5String(<_>::decode(decoder)?),
Tag::INTEGER => Open::Integer(<_>::decode(decoder)?),
Tag::OCTET_STRING => Open::OctetString(<_>::decode(decoder)?),
Tag::PRINTABLE_STRING => Open::PrintableString(<_>::decode(decoder)?),
Tag::UNIVERSAL_STRING => Open::UniversalString(<_>::decode(decoder)?),
Tag::VISIBLE_STRING => Open::VisibleString(<_>::decode(decoder)?),
Tag::UTC_TIME => Open::UtcTime(<_>::decode(decoder)?),
Tag::EXTERNAL => Open::InstanceOf(alloc::boxed::Box::new(<_>::decode(decoder)?)),
Tag::GENERALIZED_TIME => Open::GeneralizedTime(<_>::decode(decoder)?),
Tag::NULL => {
decoder.decode_null(<()>::TAG)?;
Open::Null
}
tag => Open::Unknown {
tag,
value: decoder.decode_any(tag)?,
},
})
}
}

impl crate::Encode for Open {
fn encode_with_tag<EN: crate::Encoder>(&self, _: &mut EN, _: Tag) -> Result<(), EN::Error> {
Err(crate::enc::Error::custom(
"CHOICE-style enums do not allow implicit tagging.",
))
}

fn encode<E: crate::Encoder>(&self, encoder: &mut E) -> Result<(), E::Error> {
match self {
Open::BitString(value) => value.encode(encoder),
Open::BmpString(value) => crate::Encode::encode(value, encoder),
Open::Bool(value) => crate::Encode::encode(value, encoder),
Open::GeneralizedTime(value) => crate::Encode::encode(value, encoder),
Open::IA5String(value) => crate::Encode::encode(value, encoder),
Open::InstanceOf(value) => crate::Encode::encode(&**value, encoder),
Open::Integer(value) => crate::Encode::encode(value, encoder),
Open::Null => ().encode(encoder),
Open::OctetString(value) => crate::Encode::encode(value, encoder),
Open::PrintableString(value) => crate::Encode::encode(value, encoder),
Open::UniversalString(value) => crate::Encode::encode(value, encoder),
Open::UtcTime(value) => crate::Encode::encode(value, encoder),
Open::VisibleString(value) => crate::Encode::encode(value, encoder),
Open::Unknown { tag, value } => encoder.encode_any(*tag, value).map(drop),
}
.map(drop)
}
}
2 changes: 1 addition & 1 deletion src/types/tag.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ impl TagTree {
}

/// Whether `needle` matches any `Leaf`s in `nodes`.
const fn tag_contains(needle: &Tag, nodes: &'static [TagTree]) -> bool {
pub(crate) const fn tag_contains(needle: &Tag, nodes: &'static [TagTree]) -> bool {
let mut index = 0;

while index < nodes.len() {
Expand Down
Loading

0 comments on commit 3d94b96

Please sign in to comment.