Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
XAMPPRocky committed Apr 30, 2023
1 parent 4eea8b7 commit 09decf7
Show file tree
Hide file tree
Showing 12 changed files with 238 additions and 68 deletions.
2 changes: 1 addition & 1 deletion benches/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ pub struct Bench {
#[derive(AsnType, Decode, Encode)]
pub struct EmptySequence {}

#[derive(AsnType, Clone, Copy, Decode, Encode)]
#[derive(AsnType, Clone, Copy, Decode, Encode, PartialEq)]
#[rasn(enumerated)]
pub enum BenchEnum {
A,
Expand Down
9 changes: 8 additions & 1 deletion macros/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,7 @@ impl OptionalEnum {
}

pub struct VariantConfig<'config> {
variant: &'config syn::Variant,
pub variant: &'config syn::Variant,
container_config: &'config Config,
generics: &'config syn::Generics,
pub tag: Option<Tag>,
Expand Down Expand Up @@ -414,6 +414,13 @@ impl<'config> VariantConfig<'config> {
}
}

pub fn discriminant(&self) -> Option<usize> {
self.variant.discriminant.as_ref().and_then(|(_, expr)| match expr {
syn::Expr::Lit(syn::ExprLit { lit: syn::Lit::Int(int), ..}) => int.base10_parse().ok(),
_ => None,
})
}

pub fn has_explicit_tag(&self) -> bool {
self.tag.as_ref().map_or(false, |tag| tag.is_explicit())
}
Expand Down
58 changes: 39 additions & 19 deletions macros/src/enum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,42 @@ impl Enum {
}
});

let enumerated_impl = self.config.enumerated.then(|| {
let (variants, extended_variants): (Vec<_>, Vec<_>) = self.variants.iter()
.map(|variant| VariantConfig::new(variant, &self.generics, &self.config))
.partition(|config| config.extension_addition);

let discriminants = variants.iter().enumerate().map(|(i, config)| {
let discriminant = config.discriminant().unwrap_or(i) as isize;
let variant = &config.variant.ident;
quote!((Self::#variant, #discriminant))
});
let extended_discriminants = extended_variants.iter().enumerate().map(|(i, config)| {
let discriminant = config.discriminant().unwrap_or(i) as isize;
let variant = &config.variant.ident;
quote!((Self::#variant, #discriminant))
});

let variants = variants.iter().map(|config| config.variant.ident.clone());
let extended_variant_idents = extended_variants.iter().map(|config| config.variant.ident.clone());
let extended_variants = (!extended_variants.is_empty())
.then(|| quote!(Some(&[#(Self::#extended_variant_idents,)*])))
.unwrap_or(quote!(None));
let extended_discriminants = (!extended_variants.is_empty())
.then(|| quote!(Some(&[#(#extended_discriminants,)*])))
.unwrap_or(quote!(None));

quote! {
impl #impl_generics #crate_root::types::Enumerated for #name #ty_generics #where_clause {
const VARIANTS: &'static [Self] = &[#(Self::#variants,)*];
const EXTENDED_VARIANTS: Option<&'static [Self]> = #extended_variants;

const DISCRIMINANTS: &'static [(Self, isize)] = &[#(#discriminants,)*];
const EXTENDED_DISCRIMINANTS: Option<&'static [(Self, isize)]> = #extended_discriminants;
}
}
});

quote! {
impl #impl_generics #crate_root::AsnType for #name #ty_generics #where_clause {
const TAG: #crate_root::Tag = {
Expand All @@ -102,6 +138,7 @@ impl Enum {
}

#choice_impl
#enumerated_impl
}
}

Expand Down Expand Up @@ -129,23 +166,7 @@ impl Enum {
let mut generics = self.generics.clone();
generics.add_trait_bounds(&self.config.crate_root, quote::format_ident!("Decode"));
let decode_with_tag = if self.config.enumerated {
let variants = self.variants.iter().map(|v| {
let ident = &v.ident;
quote!(i if i == #crate_root::types::Integer::from(Self::#ident as isize) => Self::#ident,)
});

quote! {
let integer = decoder.decode_enumerated(
tag,
constraints,
)?;

Ok(match integer {
#(#variants)*
_ => return Err(#crate_root::de::Error::custom("Invalid enumerated disrciminant."))
})

}
quote!(decoder.decode_enumerated(tag))
} else {
quote!(decoder.decode_explicit_prefix(tag))
};
Expand Down Expand Up @@ -244,9 +265,8 @@ impl Enum {
fn encode_with_tag(&self) -> proc_macro2::TokenStream {
let crate_root = &self.config.crate_root;
let operation = if self.config.enumerated {
let variance = self.variants.len();
quote! {
encoder.encode_enumerated(tag, #variance, *self as isize).map(drop)
encoder.encode_enumerated(tag, self).map(drop)
}
} else {
quote! {
Expand Down
6 changes: 3 additions & 3 deletions src/ber/de.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use super::identifier::Identifier;
use crate::{
de::Error as _,
types::{
self,
self, Enumerated,
oid::{MAX_OID_FIRST_OCTET, MAX_OID_SECOND_OCTET},
Constraints, Tag,
},
Expand Down Expand Up @@ -148,8 +148,8 @@ impl<'input> crate::Decoder for Decoder<'input> {
})
}

fn decode_enumerated(&mut self, tag: Tag, constraints: Constraints) -> Result<types::Integer> {
self.decode_integer(tag, constraints)
fn decode_enumerated<E: Enumerated>(&mut self, tag: Tag) -> Result<E> {
E::from_discriminant(self.decode_integer(tag, <_>::default())?.try_into().map_err(|error| Error::custom(error))?).ok_or_else(|| Error::custom("no valid discriminant"))
}

fn decode_integer(&mut self, tag: Tag, _: Constraints) -> Result<types::Integer> {
Expand Down
18 changes: 6 additions & 12 deletions src/ber/enc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ use alloc::{collections::VecDeque, string::ToString, vec::Vec};
use super::Identifier;
use crate::{
types::{
self, constraints,
self,
oid::{MAX_OID_FIRST_OCTET, MAX_OID_SECOND_OCTET},
Constraints, Tag,
Constraints, Tag, Enumerated,
},
Encode,
};
Expand Down Expand Up @@ -279,19 +279,13 @@ impl crate::Encoder for Encoder {
(encode_fn)(self).map(drop)
}

fn encode_enumerated(
fn encode_enumerated<E: Enumerated>(
&mut self,
tag: Tag,
variance: usize,
value: isize,
value: &E,
) -> Result<Self::Ok, Self::Error> {
self.encode_integer(
tag,
Constraints::from(
&[constraints::Size::new(constraints::Bounded::up_to(variance)).into()],
),
&(value.into()),
)
let value = E::discriminant(value);
self.encode_integer(tag, <_>::default(), &value.into())
}

fn encode_integer(
Expand Down
7 changes: 3 additions & 4 deletions src/de.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
use alloc::{boxed::Box, vec::Vec};
use core::convert::TryInto;

use crate::types::{self, AsnType, Constraints, Tag};
use crate::types::{self, AsnType, Constraints, Tag, Enumerated};

pub use nom::Needed;
pub use rasn_derive::Decode;
Expand Down Expand Up @@ -60,11 +60,10 @@ pub trait Decoder: Sized {
/// Decode a `BOOL` identified by `tag` from the available input.
fn decode_bool(&mut self, tag: Tag) -> Result<bool, Self::Error>;
/// Decode an enumerated enum's discriminant identified by `tag` from the available input.
fn decode_enumerated(
fn decode_enumerated<E: Enumerated>(
&mut self,
tag: Tag,
constraints: Constraints,
) -> Result<types::Integer, Self::Error>;
) -> Result<E, Self::Error>;
/// Decode a `INTEGER` identified by `tag` from the available input.
fn decode_integer(
&mut self,
Expand Down
7 changes: 3 additions & 4 deletions src/enc.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Generic ASN.1 encoding framework.

use crate::types::{self, AsnType, Constraints, Tag};
use crate::types::{self, AsnType, Constraints, Tag, Enumerated};

pub use rasn_derive::Encode;

Expand Down Expand Up @@ -63,11 +63,10 @@ pub trait Encoder {
) -> Result<Self::Ok, Self::Error>;

/// Encode a `ENUMERATED` value.
fn encode_enumerated(
fn encode_enumerated<E: Enumerated>(
&mut self,
tag: Tag,
variance: usize,
value: isize,
value: &E,
) -> Result<Self::Ok, Self::Error>;

/// Encode a `OBJECT IDENTIFIER` value.
Expand Down
51 changes: 49 additions & 2 deletions src/per.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,35 @@ mod tests {
round_trip!(aper, Choice, Choice::Medium, &[0x80, 1, 0]);
}

#[test]
fn enumerated() {

#[derive(AsnType, Clone, Copy, Debug, Decode, Encode, PartialEq)]
#[rasn(enumerated, crate_root = "crate")]
enum Enum1 { Green, Red, Blue, }

// round_trip!(uper, Enum1, Enum1::Green, &[0]);
// round_trip!(uper, Enum1, Enum1::Red, &[0x40]);
// round_trip!(uper, Enum1, Enum1::Blue, &[0x80]);

#[derive(AsnType, Clone, Copy, Debug, Decode, Encode, PartialEq)]
#[rasn(enumerated, crate_root = "crate")]
#[non_exhaustive]
enum Enum2 {
Red,
Blue,
Green,
#[rasn(extension_addition)]
Yellow,
#[rasn(extension_addition)]
Purple,
}

// round_trip!(uper, Enum2, Enum2::Red, &[0]);
round_trip!(uper, Enum2, Enum2::Yellow, &[0x80]);
round_trip!(uper, Enum2, Enum2::Purple, &[0x81]);
}

#[test]
fn extension_additions() {
#[derive(AsnType, Clone, Copy, Debug, Decode, Default, Encode, PartialEq)]
Expand Down Expand Up @@ -138,6 +167,23 @@ mod tests {
v2: MySequenceValExtension,
}

let value = MySequenceVal {
item_code: 0,
item_name: None,
urgency: Urgency::High,
v2: MySequenceValExtension {
alternate_item_code: 0,
alternate_item_name: None,
},
};

round_trip!(
uper,
MySequenceVal,
value,
&[0x80, 0x00, 0xa0, 0x40, 0x00, 0x00, 0x0a]
);

let value = MySequenceVal {
item_code: 29,
item_name: Some(Ia5String::try_from("SHERRY").unwrap()),
Expand All @@ -153,8 +199,9 @@ mod tests {
MySequenceVal,
value,
&[
0xc7, 0x5d, 0x39, 0x11, 0x69, 0x52, 0xb2, 0x7, 0x1, 0x80, 0x5, 0x96, 0x9a, 0x13,
0xe9, 0x54
0xc7, 0x5d, 0x39, 0x11, 0x69, 0x52, 0xb2, 0x07, 0x01, 0x80,
0x05, 0x96, 0x9a, 0x13, 0xe9, 0x54

]
);
}
Expand Down
15 changes: 13 additions & 2 deletions src/per/de.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use crate::{
de::Error as _,
types::{
self,
Enumerated,
constraints::{self, Extensible},
fields::{Field, Fields},
strings::StaticPermittedAlphabet,
Expand Down Expand Up @@ -273,8 +274,18 @@ impl<'input> crate::Decoder for Decoder<'input> {
self.parse_one_bit()
}

fn decode_enumerated(&mut self, tag: Tag, constraints: Constraints) -> Result<types::Integer> {
self.decode_integer(tag, constraints)
fn decode_enumerated<E: Enumerated>(&mut self, _: Tag) -> Result<E> {
let extensible = E::EXTENDED_VARIANTS.is_some().then(|| self.parse_one_bit()).transpose()?.unwrap_or_default();

if extensible {
let index: usize = self.parse_normally_small_integer()?.try_into().map_err(Error::custom)?;
E::from_extended_enumeration_index(index)
.ok_or_else(|| Error::custom(format!("Extended index {} not found", index)))
} else {
let index = self.parse_non_negative_binary_integer(E::variance() as i128)?.try_into().map_err(Error::custom)?;
E::from_enumeration_index(index)
.ok_or_else(|| Error::custom(format!("Index {} not found", index)))
}
}

fn decode_integer(&mut self, _: Tag, constraints: Constraints) -> Result<types::Integer> {
Expand Down
Loading

0 comments on commit 09decf7

Please sign in to comment.