[−][src]Crate flexiber_derive
[−][src]Crate flexiber_derive
Custom derive support for the flexiber crate
With #[tlv(slice)] set, Encodable should work for fields implementing AsRef<[u8]>,
and Decodable should work for fields implementing TryFrom<[u8]>, even if the field
is not Decodable or Encodable.
use proc_macro2::TokenStream; use quote::{quote, ToTokens}; @@ -168,30 +213,48 @@ let field_name = &field.name; let tag = field.tag; - let class = tag.class as u8; - let constructed = tag.constructed; - let tag_number = tag.number; + let field_decoder = match tag { + Tag::Ber(tag) => { + let class = tag.class as u8; + let constructed = tag.constructed; + let tag_number = tag.number; - let field_decoder = if field.slice { - quote! { - let tag = ::flexiber::Tag::from( - flexiber::Class::try_from(#class).unwrap(), - #constructed, - #tag_number - ); - let #field_name = - decoder.decode_tagged_slice(tag)?.try_into().unwrap(); - // .map_err(|_| flexiber::ErrorKind::Length { tag })?; + if field.slice { + quote! { + let tag = ::flexiber::Tag::from( + flexiber::Class::try_from(#class).unwrap(), + #constructed, + #tag_number + ); + let #field_name = + decoder.decode_tagged_slice(tag)?.try_into().unwrap(); + // .map_err(|_| flexiber::ErrorKind::Length { tag })?; + } + } else { + quote! { + let tag = ::flexiber::Tag::from( + flexiber::Class::try_from(#class).unwrap(), + #constructed, + #tag_number + ); + + let #field_name = decoder.decode_tagged_value(tag)?; + } + } } - } else { - quote! { - let tag = ::flexiber::Tag::from( - flexiber::Class::try_from(#class).unwrap(), - #constructed, - #tag_number - ); - - let #field_name = decoder.decode_tagged_value(tag)?; + Tag::Simple(tag) => { + let field_tag = tag.0; + if field.slice { + quote! { let #field_name = + decoder.decode_tagged_slice(::flexiber::SimpleTag::try_from(#field_tag).unwrap())?.try_into() + .map_err(|_| { + use flexiber::TagLike; + flexiber::ErrorKind::Length { tag: flexiber::SimpleTag::try_from(#field_tag).unwrap().embedding() } + })?; + } + } else { + quote! { let #field_name = decoder.decode_tagged_value(::flexiber::SimpleTag::try_from(#field_tag).unwrap())?; } + } } }; field_decoder.to_tokens(&mut self.decode_fields); @@ -208,30 +271,57 @@ if let Some(tag) = tag { - let class = tag.class as u8; - let constructed = tag.constructed; - let tag_number = tag.number; + match tag { + Tag::Ber(tag) => { + let class = tag.class as u8; + let constructed = tag.constructed; + let tag_number = tag.number; - s.gen_impl(quote! { - gen impl<'a> core::convert::TryFrom<flexiber::TaggedSlice<'a>> for @Self { - type Error = flexiber::Error; + s.gen_impl(quote! { + gen impl<'a> core::convert::TryFrom<flexiber::TaggedSlice<'a>> for @Self { + type Error = flexiber::Error; - fn try_from(tagged_slice: flexiber::TaggedSlice<'a>) -> flexiber::Result<Self> { - use core::convert::TryInto; - let tag = ::flexiber::Tag::from( - flexiber::Class::try_from(#class).unwrap(), - #constructed, - #tag_number - ); - tagged_slice.tag().assert_eq(tag)?; - tagged_slice.decode_nested(|decoder| { - #decode_fields + fn try_from(tagged_slice: flexiber::TaggedSlice<'a>) -> flexiber::Result<Self> { + use core::convert::TryInto; + use flexiber::TagLike; + let tag = ::flexiber::Tag::from( + flexiber::Class::try_from(#class).unwrap(), + #constructed, + #tag_number + ); + tagged_slice.tag().assert_eq(tag)?; + tagged_slice.decode_nested(|decoder| { + #decode_fields - Ok(Self { #decode_result }) - }) - } + Ok(Self { #decode_result }) + }) + } + } + }) } - }) + Tag::Simple(tag) => { + let tag = tag.0; + s.gen_impl(quote! { + gen impl<'a> Decodable<'a> for @Self { + fn decode(decoder: &mut Decoder<'a>) -> Result<Self> { + flexiber::TaggedSlice::<'a, flexiber::SimpleTag>::decode(decoder) + .and_then(|tagged_slice| { + use core::convert::TryInto; + use flexiber::TagLike; + tagged_slice.tag().assert_eq(flexiber::SimpleTag::try_from(#tag).unwrap())?; + tagged_slice.decode_nested(|decoder| { + #decode_fields + + Ok(Self { #decode_result }) + }) + }) + .or_else(|e| decoder.error(e.kind())) + } + + } + }) + } + } } else { s.gen_impl(quote! { gen impl<'a> flexiber::Decodable<'a> for @Self { diff --git a/src/flexiber_derive/encodable.rs.html b/src/flexiber_derive/encodable.rs.html index cbf009d..acaf72d 100644 --- a/src/flexiber_derive/encodable.rs.html +++ b/src/flexiber_derive/encodable.rs.html @@ -111,6 +111,43 @@ 108 109 110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147
use proc_macro2::TokenStream; use quote::{quote, ToTokens}; @@ -152,14 +189,26 @@ let field_name = &field.name; let tag = field.tag; - let class = tag.class as u8; - let constructed = tag.constructed; - let tag_number = tag.number; + let field_encoder = match tag { + Tag::Ber(tag) => { + let class = tag.class as u8; + let constructed = tag.constructed; + let tag_number = tag.number; - let field_encoder = if field.slice { - quote! { &(::flexiber::TaggedSlice::from(flexiber::Tag::from(flexiber::Class::try_from(#class).unwrap(), #constructed, #tag_number), &self.#field_name)?), } - } else { - quote! { &(::flexiber::Tag::from(flexiber::Class::try_from(#class).unwrap(), #constructed, #tag_number).with_value(&self.#field_name)), } + if field.slice { + quote! { &(::flexiber::TaggedSlice::from(flexiber::Tag::from(flexiber::Class::try_from(#class).unwrap(), #constructed, #tag_number), &self.#field_name)?), } + } else { + quote! { &(::flexiber::Tag::from(flexiber::Class::try_from(#class).unwrap(), #constructed, #tag_number).with_value(&self.#field_name)), } + } + } + Tag::Simple(tag) => { + let field_tag = tag.0; + if field.slice { + quote! { &(::flexiber::TaggedSlice::from(flexiber::SimpleTag::try_from(#field_tag).unwrap(), &self.#field_name)?), } + } else { + quote! { &(::flexiber::SimpleTag::try_from(#field_tag).unwrap().with_value(&self.#field_name)), } + } + } }; field_encoder.to_tokens(&mut self.encode_fields); } @@ -171,28 +220,53 @@ let encode_fields = self.encode_fields; if let Some(tag) = tag { - let class = tag.class as u8; - let constructed = tag.constructed; - let tag_number = tag.number; - s.gen_impl(quote! { - gen impl flexiber::Tagged for @Self { - fn tag() -> flexiber::Tag { - // TODO(nickray): FIXME FIXME - use core::convert::TryFrom; - flexiber::Tag::from(flexiber::Class::try_from(#class).unwrap(), #constructed, #tag_number) - } - } + match tag { + Tag::Ber(tag) => { + let class = tag.class as u8; + let constructed = tag.constructed; + let tag_number = tag.number; + s.gen_impl(quote! { + gen impl flexiber::Tagged for @Self { + fn tag() -> flexiber::Tag { + // TODO(nickray): FIXME FIXME + use core::convert::TryFrom; + flexiber::Tag::from(flexiber::Class::try_from(#class).unwrap(), #constructed, #tag_number) + } + } - gen impl flexiber::Container for @Self { - fn fields<F, T>(&self, field_encoder: F) -> flexiber::Result<T> - where - F: FnOnce(&[&dyn flexiber::Encodable]) -> flexiber::Result<T>, - { - use core::convert::TryFrom; - field_encoder(&[#encode_fields]) - } + gen impl flexiber::Container for @Self { + fn fields<F, T>(&self, field_encoder: F) -> flexiber::Result<T> + where + F: FnOnce(&[&dyn flexiber::Encodable]) -> flexiber::Result<T>, + { + use core::convert::TryFrom; + field_encoder(&[#encode_fields]) + } + } + }) } - }) + Tag::Simple(tag) => { + let tag = tag.0; + s.gen_impl(quote! { + gen impl flexiber::Tagged for @Self { + fn tag() -> flexiber::Tag { + use core::convert::TryFrom; + flexiber::Tag::try_from(#tag).unwrap() + } + } + + gen impl flexiber::Container for @Self { + fn fields<F, T>(&self, field_encoder: F) -> flexiber::Result<T> + where + F: FnOnce(&[&dyn flexiber::Encodable]) -> flexiber::Result<T>, + { + use core::convert::TryFrom; + field_encoder(&[#encode_fields]) + } + } + }) + } + } } else { s.gen_impl(quote! { gen impl flexiber::Container for @Self { diff --git a/src/flexiber_derive/lib.rs.html b/src/flexiber_derive/lib.rs.html index bddd601..84c4def 100644 --- a/src/flexiber_derive/lib.rs.html +++ b/src/flexiber_derive/lib.rs.html @@ -199,6 +199,88 @@ 196 197 198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273 +274 +275 +276 +277 +278 +279 +280
//! Custom derive support for the `flexiber` crate //! @@ -270,12 +352,39 @@ } #[derive(Clone, Copy, Debug, Default)] -struct Tag { +struct BerTag { class: Class, constructed: bool, number: u16, } +#[derive(Clone, Copy, Debug, Default)] +struct SimpleTag(u8); + +#[derive(Clone, Copy, Debug)] +enum Tag { + Ber(BerTag), + Simple(SimpleTag), +} + +impl From<BerTag> for Tag { + fn from(tag: BerTag) -> Self { + Self::Ber(tag) + } +} + +impl From<SimpleTag> for Tag { + fn from(tag: SimpleTag) -> Self { + Self::Simple(tag) + } +} + +impl Default for Tag { + fn default() -> Self { + Self::Ber(BerTag::default()) + } +} + #[derive(Clone, Copy, Debug)] #[repr(u8)] enum Class { @@ -337,17 +446,53 @@ if path.is_ident("slice") { slice = true; } else if path.is_ident("universal") { - tag.class = Class::Universal; + tag = { + let mut tag = if let Tag::Ber(tag) = tag { + tag + } else { Default::default() }; + tag.class = Class::Universal; + tag.into() + }; } else if path.is_ident("application") { - tag.class = Class::Application; + tag = { + let mut tag = if let Tag::Ber(tag) = tag { + tag + } else { Default::default() }; + tag.class = Class::Application; + tag.into() + }; } else if path.is_ident("context") { - tag.class = Class::Context; + tag = { + let mut tag = if let Tag::Ber(tag) = tag { + tag + } else { Default::default() }; + tag.class = Class::Context; + tag.into() + }; } else if path.is_ident("private") { - tag.class = Class::Private; + tag = { + let mut tag = if let Tag::Ber(tag) = tag { + tag + } else { Default::default() }; + tag.class = Class::Private; + tag.into() + }; } else if path.is_ident("constructed") { - tag.constructed = true; + tag = { + let mut tag = if let Tag::Ber(tag) = tag { + tag + } else { Default::default() }; + tag.constructed = true; + tag.into() + }; } else if path.is_ident("primitive") { - tag.constructed = false; + tag = { + let mut tag = if let Tag::Ber(tag) = tag { + tag + } else { Default::default() }; + tag.constructed = false; + tag.into() + }; } else { panic!("unknown `tlv` attribute for field `{}`: {:?}", name, path); } @@ -358,15 +503,34 @@ .. })) => { // Parse the `type = "..."` attribute - if !path.is_ident("number") { + if path.is_ident("number") { + tag = { + let possibly_with_prefix = lit_str.value(); + let without_prefix = possibly_with_prefix.trim_start_matches("0x"); + let tag_number = u16::from_str_radix(without_prefix, 16).expect("tag values must be between one and 254"); + let mut tag = if let Tag::Ber(tag) = tag { + tag + } else { Default::default() }; + tag.number = tag_number; + tag_number_is_set = true; + tag.into() + } + } else if path.is_ident("simple") { + tag = { + let possibly_with_prefix = lit_str.value(); + let without_prefix = possibly_with_prefix.trim_start_matches("0x"); + let tag_number = u8::from_str_radix(without_prefix, 16).expect("tag values must be between one and 254"); + let mut tag = if let Tag::Simple(tag) = tag { + tag + } else { Default::default() }; + tag.0 = tag_number; + tag_number_is_set = true; + tag.into() + }; + } else { panic!("unknown `tlv` attribute for field `{}`: {:?}", name, path); } - let possibly_with_prefix = lit_str.value(); - let without_prefix = possibly_with_prefix.trim_start_matches("0x"); - let tag_number = u16::from_str_radix(without_prefix, 16).expect("tag values must be between one and 254"); - tag.number = tag_number; - tag_number_is_set = true; } other => panic!( "a malformed `tlv` attribute for field `{}`: {:?}",