Skip to content

Commit

Permalink
Support Complex type composition (like an ENUMERATED in a SEQUENCE) #11
Browse files Browse the repository at this point in the history
  • Loading branch information
kellerkindt committed Apr 30, 2020
1 parent cce4c27 commit faeb91c
Show file tree
Hide file tree
Showing 5 changed files with 120 additions and 1 deletion.
10 changes: 9 additions & 1 deletion asn1rs-macros/src/ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,14 @@ pub(crate) fn parse(attr: TokenStream, item: TokenStream) -> TokenStream {
let parsed = asn1rs_model::model::Asn {
tag: asn.tag,
r#type: match asn.r#type {
Some(some) => some,
Some(some) => {
if let Type::TypeReference(_) = some {
let ty = field.ty.clone();
Type::TypeReference(quote! { #ty }.to_string())
} else {
some
}
}
None => {
return TokenStream::from(
syn::Error::new(field.span(), "Missing ASN-Type")
Expand Down Expand Up @@ -163,6 +170,7 @@ impl Parse for Asn {
let range = MaybeRanged::parse(input)?;
asn.r#type = Some(Type::Integer(range.0.map(|(min, max)| Range(min, max))));
}
"complex" if first => asn.r#type = Some(Type::TypeReference(String::default())),
"tag" if !first => {
let tag = AttrTag::parse(input)?;
asn.tag = Some(tag.0);
Expand Down
38 changes: 38 additions & 0 deletions src/syn/complex.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
use crate::syn::{Readable, ReadableType, Reader, Writable, WritableType, Writer};
use core::marker::PhantomData;

pub struct Complex<V, T: Constraint = NoConstraint>(PhantomData<T>, PhantomData<V>);

impl<V, T: Constraint> Default for Complex<V, T> {
fn default() -> Self {
Complex(Default::default(), Default::default())
}
}

pub trait Constraint {}

#[derive(Default)]
pub struct NoConstraint;

impl Constraint for NoConstraint {}

impl<V: Writable, C: Constraint> WritableType for Complex<V, C> {
type Type = V;

#[inline]
fn write_value<W: Writer>(
writer: &mut W,
value: &Self::Type,
) -> Result<(), <W as Writer>::Error> {
value.write(writer)
}
}

impl<V: Readable, C: Constraint> ReadableType for Complex<V, C> {
type Type = V;

#[inline]
fn read_value<R: Reader>(reader: &mut R) -> Result<Self::Type, <R as Reader>::Error> {
V::read(reader)
}
}
14 changes: 14 additions & 0 deletions src/syn/io/uper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,16 @@ impl UperWriter {
pub const fn bit_len(&self) -> usize {
self.buffer.bit_len()
}

pub fn into_bytes_vec(self) -> Vec<u8> {
self.buffer.into()
}

pub fn into_reader(self) -> UperReader {
let bits = self.bit_len();
let bytes = self.into_bytes_vec();
UperReader::from_bits(bytes, bits)
}
}

impl Writer for UperWriter {
Expand Down Expand Up @@ -106,6 +116,10 @@ impl UperReader {
optionals: Vec::default(),
}
}

pub fn bits_remaining(&self) -> usize {
self.buffer.write_position - self.buffer.read_position
}
}

impl Reader for UperReader {
Expand Down
2 changes: 2 additions & 0 deletions src/syn/mod.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
use std::marker::PhantomData;

pub mod complex;
pub mod enumerated;
pub mod io;
pub mod numbers;
pub mod optional;
pub mod sequence;
pub mod utf8string;

pub use complex::Complex;
pub use enumerated::Enumerated;
pub use numbers::Integer;
pub use sequence::Sequence;
Expand Down
57 changes: 57 additions & 0 deletions tests/basic_proc_macro_attribute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,3 +94,60 @@ fn topping_test_deserialize_with_uper() {
assert_eq!(Topping::EvenLessPineapple, uper.read::<Topping>().unwrap());
assert_eq!(Topping::NoPineappleAtAll, uper.read::<Topping>().unwrap());
}

#[asn(sequence)]
#[derive(Debug, PartialOrd, PartialEq)]
pub struct Pizza {
#[asn(integer(1..4))]
size: u8,
#[asn(complex)]
topping: Topping,
}

#[test]
fn pizza_test_uper_1() {
let mut uper = UperWriter::default();
let pizza = Pizza {
size: 2,
topping: Topping::NotPineapple,
};
uper.write(&pizza).unwrap();
// https://asn1.io/asn1playground/
assert_eq!(&[0x40], uper.byte_content());
assert_eq!(4, uper.bit_len());
let mut uper = uper.into_reader();
assert_eq!(pizza, uper.read::<Pizza>().unwrap());
assert_eq!(0, uper.bits_remaining());
}

#[test]
fn pizza_test_uper_2() {
let mut uper = UperWriter::default();
let pizza = Pizza {
size: 1,
topping: Topping::NoPineappleAtAll,
};
uper.write(&pizza).unwrap();
// https://asn1.io/asn1playground/
assert_eq!(&[0x20], uper.byte_content());
assert_eq!(4, uper.bit_len());
let mut uper = uper.into_reader();
assert_eq!(pizza, uper.read::<Pizza>().unwrap());
assert_eq!(0, uper.bits_remaining());
}

#[test]
fn pizza_test_uper_3() {
let mut uper = UperWriter::default();
let pizza = Pizza {
size: 3,
topping: Topping::EvenLessPineapple,
};
uper.write(&pizza).unwrap();
// https://asn1.io/asn1playground/
assert_eq!(&[0x90], uper.byte_content());
assert_eq!(4, uper.bit_len());
let mut uper = uper.into_reader();
assert_eq!(pizza, uper.read::<Pizza>().unwrap());
assert_eq!(0, uper.bits_remaining());
}

0 comments on commit faeb91c

Please sign in to comment.