Skip to content

Commit

Permalink
Feat/identifier annotation (#239)
Browse files Browse the repository at this point in the history
  • Loading branch information
6d7a committed Apr 3, 2024
1 parent ff05eb1 commit 285f004
Show file tree
Hide file tree
Showing 13 changed files with 193 additions and 38 deletions.
27 changes: 27 additions & 0 deletions README.md
Expand Up @@ -721,6 +721,33 @@ struct TestTypeA {

```

</td>
</tr>
<tr>
<td>Renaming fields</td>
<td>

```asn
Test-type-a ::= SEQUENCE {
notQuiteRustCase INTEGER
}
```

</td>
<td>

```rust
use rasn::prelude::*;

#[derive(AsnType, Decode, Encode)]
#[rasn(automatic_tags, identifier = "Test-type-a")]
struct TestTypeA {
#[rasn(identifier = "notQuiteRustCase")]
rust_case_indeed: Integer
}

```

</td>
</tr>
<tr>
Expand Down
7 changes: 6 additions & 1 deletion macros/src/asn_type.rs
Expand Up @@ -94,6 +94,11 @@ pub fn derive_struct_impl(

let constraints_def = config.constraints.const_static_def(crate_root);

let alt_identifier = config.identifier.as_ref().map_or(
quote!(),
|id| quote!(const IDENTIFIER: Option<&'static str> = Some(#id);),
);

quote! {
#constructed_impl

Expand All @@ -104,7 +109,7 @@ pub fn derive_struct_impl(

#tag
};

#alt_identifier
#constraints_def
}
}
Expand Down
46 changes: 39 additions & 7 deletions macros/src/config.rs
@@ -1,7 +1,7 @@
use std::ops::Deref;

use quote::ToTokens;
use syn::{Lit, NestedMeta, Path, UnOp};
use syn::{Lit, LitStr, NestedMeta, Path, UnOp};

use crate::{ext::TypeExt, tag::Tag};

Expand Down Expand Up @@ -214,6 +214,7 @@ impl Constraints {
#[derive(Clone, Debug)]
pub struct Config {
pub crate_root: Path,
pub identifier: Option<syn::LitStr>,
pub enumerated: bool,
pub choice: bool,
pub set: bool,
Expand All @@ -229,6 +230,7 @@ impl Config {
let mut choice = false;
let mut set = false;
let mut crate_root = None;
let mut identifier = None;
let mut enumerated = false;
let mut automatic_tags = false;
let mut tag = None;
Expand Down Expand Up @@ -262,6 +264,13 @@ impl Config {
_ => None,
};
}
} else if path.is_ident("identifier") {
if let syn::Meta::NameValue(nv) = item {
identifier = match &nv.lit {
syn::Lit::Str(s) => Some(s.clone()),
_ => None,
};
}
} else if path.is_ident("enumerated") {
enumerated = true;
} else if path.is_ident("choice") {
Expand Down Expand Up @@ -362,6 +371,7 @@ impl Config {
option_type,
set,
tag,
identifier,
constraints: Constraints {
extensible,
from,
Expand Down Expand Up @@ -457,6 +467,7 @@ pub struct VariantConfig<'config> {
container_config: &'config Config,
generics: &'config syn::Generics,
pub tag: Option<Tag>,
pub identifier: Option<LitStr>,
pub extension_addition: bool,
pub constraints: Constraints,
}
Expand All @@ -468,6 +479,7 @@ impl<'config> VariantConfig<'config> {
container_config: &'config Config,
) -> Self {
let mut extensible = false;
let mut identifier = None;
let mut extension_addition = false;
let mut from = None;
let mut size = None;
Expand All @@ -488,6 +500,13 @@ impl<'config> VariantConfig<'config> {
let path = item.path();
if path.is_ident("tag") {
tag = Tag::from_meta(item);
} else if path.is_ident("identifier") {
if let syn::Meta::NameValue(nv) = item {
identifier = match &nv.lit {
syn::Lit::Str(s) => Some(s.clone()),
_ => None,
};
}
} else if path.is_ident("size") {
size = Some(Value::from_meta(item));
} else if path.is_ident("value") {
Expand All @@ -507,6 +526,7 @@ impl<'config> VariantConfig<'config> {
extension_addition,
generics,
tag,
identifier,
variant,
constraints: Constraints {
extensible,
Expand Down Expand Up @@ -709,6 +729,7 @@ pub struct FieldConfig<'a> {
pub field: &'a syn::Field,
pub container_config: &'a Config,
pub tag: Option<Tag>,
pub identifier: Option<LitStr>,
pub default: Option<Option<syn::Path>>,
pub extension_addition: bool,
pub extension_addition_group: bool,
Expand All @@ -726,6 +747,7 @@ impl<'a> FieldConfig<'a> {
let mut default = None;
let mut tag = None;
let mut size = None;
let mut identifier = None;
let mut from = None;
let mut value = None;
let mut extensible = false;
Expand Down Expand Up @@ -753,6 +775,13 @@ impl<'a> FieldConfig<'a> {
},
_ => None,
});
} else if path.is_ident("identifier") {
if let syn::Meta::NameValue(nv) = item {
identifier = match &nv.lit {
syn::Lit::Str(s) => Some(s.clone()),
_ => None,
};
}
} else if path.is_ident("size") {
size = Some(Value::from_meta(item));
} else if path.is_ident("value") {
Expand Down Expand Up @@ -782,6 +811,7 @@ impl<'a> FieldConfig<'a> {
container_config,
default,
field,
identifier,
tag,
extension_addition,
extension_addition_group,
Expand Down Expand Up @@ -1122,12 +1152,14 @@ impl<'a> FieldConfig<'a> {
let tag = self.tag(context);
let tag_tree = self.tag_tree(context);
let name = self
.field
.ident
.as_ref()
.map_or(syn::LitStr::new("", proc_macro2::Span::call_site()), |id| {
syn::LitStr::new(&id.to_string(), proc_macro2::Span::call_site())
});
.identifier
.clone()
.or(self
.field
.ident
.as_ref()
.map(|id| syn::LitStr::new(&id.to_string(), proc_macro2::Span::call_site())))
.unwrap_or(syn::LitStr::new("", proc_macro2::Span::call_site()));

let constructor = quote::format_ident!(
"{}",
Expand Down
35 changes: 18 additions & 17 deletions macros/src/enum.rs
Expand Up @@ -75,7 +75,14 @@ impl Enum {
let identifiers = self
.variants
.iter()
.map(|v| syn::LitStr::new(&v.ident.to_string(), proc_macro2::Span::call_site()))
.map(|v| {
VariantConfig::new(v, &self.generics, &self.config)
.identifier
.unwrap_or(syn::LitStr::new(
&v.ident.to_string(),
proc_macro2::Span::call_site(),
))
})
.collect_vec();

let constraints_def = self.config.constraints.const_static_def(crate_root);
Expand Down Expand Up @@ -128,10 +135,19 @@ impl Enum {

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

const IDENTIFIERS: &'static [&'static str] = &[
#(#identifiers),*
];
}
}
});

let alt_identifier = self.config.identifier.as_ref().map_or(
quote!(),
|id| quote!(const IDENTIFIER: Option<&'static str> = Some(#id);),
);

quote! {
impl #impl_generics #crate_root::AsnType for #name #ty_generics #where_clause {
const TAG: #crate_root::Tag = {
Expand All @@ -143,7 +159,7 @@ impl Enum {
const _: () = assert!(TAG_TREE.is_unique(), #error_message);
#return_val
};

#alt_identifier
#constraints_def
}

Expand Down Expand Up @@ -312,18 +328,6 @@ impl Enum {
fn encode_choice(&self, generics: &syn::Generics) -> proc_macro2::TokenStream {
let crate_root = &self.config.crate_root;

let identifiers = self.variants.iter().map(|v| {
let ident = &v.ident;
let name = &self.name;

let identifier = syn::LitStr::new(&v.ident.to_string(), proc_macro2::Span::call_site());

match &v.fields {
syn::Fields::Named(_) => quote!(#name::#ident { .. } => #identifier),
syn::Fields::Unnamed(_) => quote!(#name::#ident (_) => #identifier),
syn::Fields::Unit => quote!(#name::#ident => #identifier),
}
});
let tags = self.variants.iter().enumerate().map(|(i, v)| {
let ident = &v.ident;
let name = &self.name;
Expand Down Expand Up @@ -413,9 +417,6 @@ impl Enum {
match self {
#(#tags),*
},
match self {
#(#identifiers),*
},
|encoder| match self {
#(#variants),*
}
Expand Down
1 change: 0 additions & 1 deletion src/ber/enc.rs
Expand Up @@ -359,7 +359,6 @@ impl crate::Encoder for Encoder {
&mut self,
_: Constraints,
_t: Tag,
_i: &str,
encode_fn: impl FnOnce(&mut Self) -> Result<Tag, Self::Error>,
) -> Result<Self::Ok, Self::Error> {
(encode_fn)(self).map(drop)
Expand Down
1 change: 0 additions & 1 deletion src/enc.rs
Expand Up @@ -323,7 +323,6 @@ pub trait Encoder {
&mut self,
constraints: Constraints,
tag: Tag,
identifier: &'static str,
encode_fn: impl FnOnce(&mut Self) -> Result<Tag, Self::Error>,
) -> Result<Self::Ok, Self::Error>;

Expand Down
33 changes: 33 additions & 0 deletions src/jer.rs
Expand Up @@ -148,6 +148,25 @@ mod tests {
#[rasn(crate_root = "crate", delegate, size("3", extensible))]
struct ConstrainedBitString(pub BitString);

#[derive(AsnType, Decode, Encode, Debug, PartialEq)]
#[rasn(automatic_tags)]
#[rasn(crate_root = "crate")]
struct Renamed {
#[rasn(identifier = "so-very")]
very: Integer,
#[rasn(identifier = "re_named")]
renamed: Option<bool>,
}

#[derive(AsnType, Decode, Encode, Debug, Clone, PartialEq)]
#[rasn(automatic_tags, choice)]
#[rasn(crate_root = "crate")]
enum Renumed {
#[rasn(identifier = "test-1")]
#[rasn(size("0..3"))]
Test1(Utf8String),
}

#[test]
fn bool() {
round_trip_jer!(bool, true, "true");
Expand Down Expand Up @@ -288,4 +307,18 @@ mod tests {
"{\"a\":{\"very\":{},\"nested\":false}}"
);
}

#[test]
fn with_identifier_annotation() {
round_trip_jer!(
Renamed,
Renamed {
very: 1.into(),
renamed: Some(true),
},
r#"{"so_very":1,"re_named":true}"#
);

round_trip_jer!(Renumed, Renumed::Test1("hel".into()), r#"{"test_1":"hel"}"#);
}
}
8 changes: 4 additions & 4 deletions src/jer/de.rs
Expand Up @@ -101,12 +101,12 @@ impl crate::Decoder for Decoder {
let mut field_names = [D::FIELDS, D::EXTENDED_FIELDS.unwrap_or(Fields::empty())]
.iter()
.flat_map(|f| f.iter())
.map(|f| f.name)
.collect::<alloc::vec::Vec<&str>>();
.map(|f| f.name.replace('-', "_"))
.collect::<alloc::vec::Vec<alloc::string::String>>();
field_names.reverse();
for name in field_names {
self.stack
.push(value_map.remove(name).unwrap_or(JsonValue::Null));
.push(value_map.remove(&name).unwrap_or(JsonValue::Null));
}

(decode_fn)(self)
Expand Down Expand Up @@ -530,7 +530,7 @@ impl Decoder {
D::IDENTIFIERS
.iter()
.enumerate()
.find(|id| id.1.eq_ignore_ascii_case(k))
.find(|id| id.1.replace('-', "_").eq_ignore_ascii_case(k))
.map(|(i, _)| (i, v))
})
.map_or(Tag::EOC, |(i, v)| {
Expand Down

0 comments on commit 285f004

Please sign in to comment.