diff --git a/macros/macros_impl/src/asn_type.rs b/macros/macros_impl/src/asn_type.rs index a4cf7303..eafb975a 100644 --- a/macros/macros_impl/src/asn_type.rs +++ b/macros/macros_impl/src/asn_type.rs @@ -7,39 +7,42 @@ pub fn derive_struct_impl( mut generics: syn::Generics, container: syn::DataStruct, config: &Config, -) -> proc_macro2::TokenStream { +) -> syn::Result { let crate_root = &config.crate_root; let tag = config.tag_for_struct(&container.fields); let field_groups = container .fields .iter() .enumerate() - .map(|(i, f)| (i, FieldConfig::new(f, config))); + .map(|(i, f)| FieldConfig::new(f, config).map(|f| (i, f))) + .collect::, _>>()?; let field_metadata = field_groups - .clone() + .iter() .filter(|(_, field)| field.is_not_extension()) .map(|(i, field)| { - let metadata = field.to_field_metadata(i); - quote!(#metadata) + field + .to_field_metadata(*i) + .map(|metadata| quote!(#metadata)) }) - .collect::>(); + .collect::, _>>()?; let extension_metadata = field_groups - .clone() + .iter() .filter(|(_, field)| field.is_extension()) .map(|(i, field)| { - let metadata = field.to_field_metadata(i); - quote!(#metadata) + field + .to_field_metadata(*i) + .map(|metadata| quote!(#metadata)) }) - .collect::>(); + .collect::, _>>()?; let all_optional_tags_are_unique: Vec<_> = field_groups + .iter() .chunk_by(|(_, config)| config.is_option_or_default_type()) .into_iter() .filter_map(|(key, fields)| key.then_some(fields)) .map(|fields| { - let tag_tree = fields.map(|(i, f)| f.tag_tree(i)); let error_message = format!( "{}'s fields is not a valid \ order of ASN.1 tags, ensure that your field's tags and \ @@ -47,13 +50,15 @@ pub fn derive_struct_impl( name ); - quote!({ + let tag_tree = fields.map(|(i, f)| f.tag_tree(*i)).collect::, _>>()?; + + Ok::<_, syn::Error>(quote!({ const LIST: &'static [#crate_root::types::TagTree] = &[#(#tag_tree),*]; const TAG_TREE: #crate_root::types::TagTree = #crate_root::types::TagTree::Choice(LIST); const _: () = assert!(TAG_TREE.is_unique(), #error_message); - }) + })) }) - .collect::>(); + .collect::, _>>()?; for param in generics.type_params_mut() { param @@ -101,7 +106,7 @@ pub fn derive_struct_impl( |id| quote!(const IDENTIFIER: Option<&'static str> = Some(#id);), ); - quote! { + Ok(quote! { #constructed_impl #[automatically_derived] @@ -114,5 +119,5 @@ pub fn derive_struct_impl( #alt_identifier #constraints_def } - } + }) } diff --git a/macros/macros_impl/src/config.rs b/macros/macros_impl/src/config.rs index c8b5a853..5417d24e 100644 --- a/macros/macros_impl/src/config.rs +++ b/macros/macros_impl/src/config.rs @@ -1,10 +1,9 @@ -use std::ops::Deref; - +use crate::{ext::TypeExt, tag::Tag}; use quote::ToTokens; +use std::ops::Deref; +use syn::spanned::Spanned; use syn::{parenthesized, Ident, LitStr, Path, Token, Type, UnOp}; -use crate::{ext::TypeExt, tag::Tag}; - #[derive(Clone, Debug, Default)] pub struct Constraints { pub extensible: bool, @@ -224,7 +223,7 @@ pub struct Config { } impl Config { - pub fn from_attributes(input: &syn::DeriveInput) -> Self { + pub fn from_attributes(input: &syn::DeriveInput) -> syn::Result { let mut choice = false; let mut set = false; let mut crate_root = None; @@ -274,24 +273,33 @@ impl Config { } else if path.is_ident("value") { value = Some(Value::from_meta(&meta)?); } else { - panic!("unknown input provided: {}", path.to_token_stream()); + return Err(meta.error(format!( + "unknown input provided: {}", + path.to_token_stream() + ))); } Ok(()) - }) - .unwrap() + })? } } let is_enum = matches!(input.data, syn::Data::Enum(_)); if !is_enum && (choice || enumerated) { - panic!("Structs cannot be annotated with `#[rasn(choice)]` or `#[rasn(enumerated)]`."); + return Err(syn::Error::new( + input.ident.span(), + "Structs cannot be annotated with `#[rasn(choice)]` or `#[rasn(enumerated)]`.", + )); } else if is_enum && set { - panic!("Enums cannot be annotated with `#[rasn(set)]`."); + return Err(syn::Error::new( + input.ident.span(), + "Enums cannot be annotated with `#[rasn(set)]`.", + )); } else if is_enum && ((choice && enumerated) || (!choice && !enumerated)) { - panic!( - "Enums must be annotated with either `#[rasn(choice)]` OR `#[rasn(enumerated)]`." - ) + return Err(syn::Error::new( + input.ident.span(), + "Enums must be annotated with either `#[rasn(choice)]` OR `#[rasn(enumerated)]`.", + )); } let mut invalid_delegate = false; @@ -305,10 +313,13 @@ impl Config { } if invalid_delegate { - panic!("`#[rasn(delegate)]` is only valid on single-unit structs."); + return Err(syn::Error::new( + input.ident.span(), + "`#[rasn(delegate)]` is only valid on single-unit structs.", + )); } - Self { + Ok(Self { automatic_tags, choice, delegate, @@ -327,7 +338,7 @@ impl Config { .parse() .unwrap() }), - } + }) } fn tag_tree_for_ty(&self, ty: &syn::Type) -> proc_macro2::TokenStream { @@ -414,7 +425,7 @@ impl<'config> VariantConfig<'config> { variant: &'config syn::Variant, generics: &'config syn::Generics, container_config: &'config Config, - ) -> Self { + ) -> syn::Result { let mut extensible = false; let mut identifier = None; let mut extension_addition = false; @@ -430,16 +441,16 @@ impl<'config> VariantConfig<'config> { attr.parse_nested_meta(|meta| { let path = &meta.path; if path.is_ident("tag") { - tag = Some(Tag::from_meta(&meta).unwrap()); + tag = Some(Tag::from_meta(&meta)?); } else if path.is_ident("identifier") { let value = meta.value()?; identifier = Some(value.parse()?); } else if path.is_ident("size") { - size = Some(Value::from_meta(&meta).unwrap()); + size = Some(Value::from_meta(&meta)?); } else if path.is_ident("value") { - value = Some(Value::from_meta(&meta).unwrap()); + value = Some(Value::from_meta(&meta)?); } else if path.is_ident("from") { - from = Some(StringValue::from_meta(&meta).unwrap()); + from = Some(StringValue::from_meta(&meta)?); } else if path.is_ident("extensible") { extensible = true; } else if path.is_ident("extension_addition") { @@ -447,11 +458,10 @@ impl<'config> VariantConfig<'config> { } Ok(()) - }) - .unwrap(); + })?; } - Self { + Ok(Self { container_config, extension_addition, generics, @@ -464,7 +474,7 @@ impl<'config> VariantConfig<'config> { size, value, }, - } + }) } pub fn discriminant(&self) -> Option { @@ -499,9 +509,13 @@ impl<'config> VariantConfig<'config> { self.tag.as_ref().is_some_and(|tag| tag.is_explicit()) } - pub fn decode(&self, name: &syn::Ident, context: usize) -> proc_macro2::TokenStream { + pub fn decode( + &self, + name: &syn::Ident, + context: usize, + ) -> syn::Result { let crate_root = &self.container_config.crate_root; - let tag_tree = self.tag_tree(context); + let tag_tree = self.tag_tree(context)?; let ident = &self.variant.ident; let is_explicit = self.has_explicit_tag(); let constraint_name = format_ident!("DECODE_CONSTRAINT_{}", context); @@ -519,7 +533,10 @@ impl<'config> VariantConfig<'config> { } syn::Fields::Unnamed(_) => { if self.variant.fields.len() != 1 { - panic!("Tuple struct variants should contain only a single element."); + return Err(syn::Error::new( + self.variant.fields.span(), + "Tuple struct variants should contain only a single element.", + )); } let constraints = self .constraints @@ -528,7 +545,7 @@ impl<'config> VariantConfig<'config> { let field = FieldConfig::new( self.variant.fields.iter().next().unwrap(), self.container_config, - ); + )?; let decode_operation = if is_explicit { quote!(decoder.decode_explicit_prefix(tag)) } else if self.container_config.automatic_tags || self.tag.is_some() { @@ -592,16 +609,16 @@ impl<'config> VariantConfig<'config> { } }; - quote! { + Ok(quote! { if #crate_root::types::TagTree::tag_contains(&tag, &[#tag_tree]) { #const_constraint return #decode_op } - } + }) } - pub fn tag(&self, context: usize) -> crate::tag::Tag { - if let Some(tag) = &self.tag { + pub fn tag(&self, context: usize) -> syn::Result { + Ok(if let Some(tag) = &self.tag { tag.clone() } else if self.container_config.automatic_tags { Tag::Value { @@ -611,25 +628,30 @@ impl<'config> VariantConfig<'config> { explicit: false, } } else { - Tag::from_fields(&self.variant.fields) - } + Tag::from_fields(&self.variant.fields)? + }) } - pub fn tag_tree(&self, context: usize) -> proc_macro2::TokenStream { + pub fn tag_tree(&self, context: usize) -> syn::Result { let crate_root = &self.container_config.crate_root; if self.tag.is_some() || self.container_config.automatic_tags { - let tag = self.tag(context).to_tokens(crate_root); - quote!(#crate_root::types::TagTree::Leaf(#tag)) + let tag = self.tag(context)?.to_tokens(crate_root); + Ok(quote!(#crate_root::types::TagTree::Leaf(#tag))) } else { - let field_tags = self + let field_configs = self .variant .fields + .iter() + .map(|f| FieldConfig::new(f, self.container_config)) + .collect::, _>>()?; + + let field_tags = field_configs .iter() .enumerate() - .filter(|(_, f)| FieldConfig::new(f, self.container_config).is_option_type()) - .map(|(i, f)| FieldConfig::new(f, self.container_config).tag_tree(i)); + .filter(|(_, f)| f.is_option_type()) + .map(|(i, f)| f.tag_tree(i).unwrap()); - match self.variant.fields { + Ok(match self.variant.fields { syn::Fields::Unit => { quote!(#crate_root::types::TagTree::Leaf(<() as #crate_root::AsnType>::TAG)) } @@ -650,7 +672,8 @@ impl<'config> VariantConfig<'config> { } syn::Fields::Unnamed(_) => { if self.variant.fields.iter().count() != 1 { - panic!("Tuple-style enum variants must contain only a single field, switch to struct-style variants for multiple fields."); + return Err(syn::Error::new(self.variant.fields.span(), "Tuple-style enum variants must contain only a single field, switch to struct-style variants for multiple fields.")); + //panic!("Tuple-style enum variants must contain only a single field, switch to struct-style variants for multiple fields."); } else { let mut ty = self.variant.fields.iter().next().unwrap().ty.clone(); ty.strip_lifetimes(); @@ -658,7 +681,7 @@ impl<'config> VariantConfig<'config> { quote!(<#ty as #crate_root::AsnType>::TAG_TREE) } } - } + }) } } } @@ -682,7 +705,7 @@ pub enum FieldType { } impl<'a> FieldConfig<'a> { - pub fn new(field: &'a syn::Field, container_config: &'a Config) -> Self { + pub fn new(field: &'a syn::Field, container_config: &'a Config) -> syn::Result { let mut default = None; let mut tag = None; let mut size = None; @@ -692,6 +715,9 @@ impl<'a> FieldConfig<'a> { let mut extensible = false; let mut extension_addition = false; let mut extension_addition_group = false; + /*if !field.attrs.is_empty() { + panic!("{:?}", field) + }*/ for attr in &field.attrs { if !attr.path().is_ident(crate::CRATE_NAME) { @@ -700,7 +726,12 @@ impl<'a> FieldConfig<'a> { attr.parse_nested_meta(|meta| { let path = &meta.path; if path.is_ident("tag") { - tag = Some(Tag::from_meta(&meta).unwrap()); + if container_config.automatic_tags { + return Err(meta.error( + "You can't use the `#[rasn(tag)]` with `#[rasn(automatic_tags)]`", + )); + } + tag = Some(Tag::from_meta(&meta)?); } else if path.is_ident("default") { if meta.input.is_empty() || meta.input.peek(Token![,]) { default = Some(None); @@ -713,11 +744,11 @@ impl<'a> FieldConfig<'a> { let value = meta.value()?; identifier = Some(value.parse()?); } else if path.is_ident("size") { - size = Some(Value::from_meta(&meta).unwrap()); + size = Some(Value::from_meta(&meta)?); } else if path.is_ident("value") { - value = Some(Value::from_meta(&meta).unwrap()); + value = Some(Value::from_meta(&meta)?); } else if path.is_ident("from") { - from = Some(StringValue::from_meta(&meta).unwrap()); + from = Some(StringValue::from_meta(&meta)?); } else if path.is_ident("extensible") { extensible = true; } else if path.is_ident("extension_addition") { @@ -725,21 +756,20 @@ impl<'a> FieldConfig<'a> { } else if path.is_ident("extension_addition_group") { extension_addition_group = true; } else { - panic!( + return Err(meta.error(format!( "unknown field tag {:?}", path.get_ident().map(ToString::to_string) - ); + ))); } Ok(()) - }) - .unwrap(); + })?; } if extension_addition && extension_addition_group { - panic!("field cannot be both `extension_addition` and `extension_addition_group`, choose one"); + return Err(syn::Error::new(field.span(), "field cannot be both `extension_addition` and `extension_addition_group`, choose one")); } - Self { + Ok(Self { container_config, default, field, @@ -753,7 +783,7 @@ impl<'a> FieldConfig<'a> { size, value, }, - } + }) } pub fn encode( @@ -761,7 +791,7 @@ impl<'a> FieldConfig<'a> { context: usize, use_self: bool, type_params: &[Ident], - ) -> proc_macro2::TokenStream { + ) -> syn::Result { let this = use_self.then(|| quote!(self.)); let tag = self.tag(context); let i = syn::Index::from(context); @@ -887,9 +917,9 @@ impl<'a> FieldConfig<'a> { } }; - quote! { + Ok(quote! { #encode - } + }) } pub fn decode_field_def( @@ -897,10 +927,10 @@ impl<'a> FieldConfig<'a> { name: &syn::Ident, context: usize, type_params: &[Ident], - ) -> proc_macro2::TokenStream { + ) -> syn::Result { let lhs = self.field.ident.as_ref().map(|i| quote!(#i :)); - let decode_op = self.decode(name, context, type_params); - quote!(#lhs #decode_op) + let decode_op = self.decode(name, context, type_params)?; + Ok(quote!(#lhs #decode_op)) } pub fn decode( @@ -908,7 +938,7 @@ impl<'a> FieldConfig<'a> { name: &syn::Ident, context: usize, type_params: &[Ident], - ) -> proc_macro2::TokenStream { + ) -> syn::Result { let crate_root = &self.container_config.crate_root; let ty = &self.field.ty; let ident = format!( @@ -1038,7 +1068,7 @@ impl<'a> FieldConfig<'a> { } }; - if self.extension_addition { + Ok(if self.extension_addition { match ( (self.tag.is_some() || self.container_config.automatic_tags) .then(|| self.tag.as_ref().is_some_and(|tag| tag.is_explicit())), @@ -1136,7 +1166,7 @@ impl<'a> FieldConfig<'a> { quote!({ #decode }) - } + }) } pub fn default_fn(&self) -> Option { @@ -1149,10 +1179,6 @@ impl<'a> FieldConfig<'a> { pub fn tag_derive(&self, context: usize) -> proc_macro2::TokenStream { if let Some(tag) = &self.tag { - if self.container_config.automatic_tags { - panic!("You can't use the `#[rasn(tag)]` with `#[rasn(automatic_tags)]`") - } - tag.to_attribute_tokens() } else if self.container_config.automatic_tags { let context = syn::Index::from(context); @@ -1165,9 +1191,6 @@ impl<'a> FieldConfig<'a> { pub fn tag(&self, context: usize) -> proc_macro2::TokenStream { let crate_root = &self.container_config.crate_root; if let Some(tag) = &self.tag { - if self.container_config.automatic_tags { - panic!("You can't use the `#[rasn(tag)]` with `#[rasn(automatic_tags)]`") - } let tag = tag.to_tokens(crate_root); quote!(#tag) } else if self.container_config.automatic_tags { @@ -1179,22 +1202,24 @@ impl<'a> FieldConfig<'a> { } } - pub fn tag_tree(&self, context: usize) -> proc_macro2::TokenStream { + pub fn tag_tree(&self, context: usize) -> syn::Result { let crate_root = &self.container_config.crate_root; let ty = &self.field.ty; - if self.tag.is_some() || self.container_config.automatic_tags { - let tag = self.tag(context); - quote!(#crate_root::types::TagTree::Leaf(#tag)) - } else { - self.container_config.tag_tree_for_ty(ty) - } + Ok( + if self.tag.is_some() || self.container_config.automatic_tags { + let tag = self.tag(context); + quote!(#crate_root::types::TagTree::Leaf(#tag)) + } else { + self.container_config.tag_tree_for_ty(ty) + }, + ) } - pub fn to_field_metadata(&self, context: usize) -> proc_macro2::TokenStream { + pub fn to_field_metadata(&self, context: usize) -> syn::Result { let crate_root = &self.container_config.crate_root; let tag = self.tag(context); - let tag_tree = self.tag_tree(context); + let tag_tree = self.tag_tree(context)?; let name = self .identifier .clone() @@ -1214,7 +1239,9 @@ impl<'a> FieldConfig<'a> { } ); - quote!({ #crate_root::types::fields::Field::#constructor(#context, #tag, #tag_tree, #name) }) + Ok( + quote!({ #crate_root::types::fields::Field::#constructor(#context, #tag, #tag_tree, #name) }), + ) } pub fn field_type(&self) -> FieldType { @@ -1287,34 +1314,37 @@ impl StringValue { let content; parenthesized!(content in item.input); while !content.is_empty() { - if content.peek(Token![,]) { - let _: Token![,] = content.parse()?; - } - let string = if content.peek(syn::LitStr) { - content.parse::()?.value() + let (span, string) = if content.peek(syn::LitStr) { + let str: syn::LitStr = content.parse()?; + + (str.span(), str.value()) } else if content.peek(syn::Ident) { let path: syn::Path = content.parse()?; - path.require_ident()?.to_string() + (path.span(), path.require_ident()?.to_string()) } else { - panic!("StringValue Unsupported meta item: {:?}", content); + return Err(content.error(format!("Unsupported meta item: {:?}", content))); }; - if string == "extensible" { extensible = Some(Vec::new()); + skip_comma(&content); continue; } if string.len() == 1 { values.push(parse_character(&string).map(StringRange::Single).unwrap()); + skip_comma(&content); continue; } let Some((start, mut end)) = string.split_once("..") else { - panic!("unknown format: {string}, must be a single character or range of characters (`..`, `..=`)") + return Err(syn::Error::new(span, format!("unknown format: {string}, must be a single character or range of characters (`..`, `..=`)"))); }; let Some(start) = parse_character(start) else { - panic!("start of range was an invalid character: {start}") + return Err(syn::Error::new( + span, + format!("start of range was an invalid character: {start}"), + )); }; let is_inclusive = end.starts_with('='); @@ -1323,7 +1353,10 @@ impl StringValue { } let Some(end) = parse_character(end) else { - panic!("end of range was an invalid character: {end}") + return Err(syn::Error::new( + span, + format!("end of range was an invalid character: {end}"), + )); }; if let Some(extensible_values) = extensible.as_mut() { @@ -1331,6 +1364,7 @@ impl StringValue { } else { values.push(StringRange::Range(start, end + is_inclusive as u32)); } + skip_comma(&content); } let into_flat_set = |constraints: Vec<_>| { let mut set = constraints @@ -1369,26 +1403,28 @@ impl Value { let content; parenthesized!(content in item.input); + if content.is_empty() { + return Err(content.error("Missing content inside `value()`")); + } while !content.is_empty() { - if content.peek(Token![,]) { - let _: Token![,] = content.parse()?; - continue; - } - let string = if content.peek(syn::LitStr) { - content.parse::()?.value() + let (span, string) = if content.peek(syn::LitStr) { + let str: syn::LitStr = content.parse()?; + (str.span(), str.value()) } else if content.peek(syn::Ident) { - let path: syn::Path = content.parse()?; - path.get_ident().unwrap().to_string() + let ident: syn::Ident = content.parse()?; + (ident.span(), ident.to_string()) } else if content.peek(syn::LitInt) { let int: syn::LitInt = content.parse()?; - constraint = Some(int.base10_parse().map(Value::Single).unwrap()); + constraint = Some(int.base10_parse().map(Value::Single)?); + skip_comma(&content); continue; } else { - panic!("Value Unsupported meta item: {:?}", content); + return Err(content.error(format!("Value Unsupported meta item: {:?}", content))); }; if string == "extensible" { extensible = Some(Vec::new()); + skip_comma(&content); continue; } @@ -1396,7 +1432,7 @@ impl Value { Value::Single(number) } else { let Some((start, mut end)) = string.split_once("..") else { - panic!("unknown format: {string}, must be a single character or range of characters (`..`, `..=`)") + return Err(syn::Error::new(span, format!("unknown format: {string}, must be a single character or range of characters (`..`, `..=`)"))); }; let start = parse_character(start); @@ -1414,8 +1450,12 @@ impl Value { } else if constraint.is_none() { constraint = Some(value); } else { - panic!("Multiple non-extensible value constraints are not permitted."); + return Err(syn::Error::new( + span, + "Multiple non-extensible value constraints are not permitted.", + )); } + skip_comma(&content); } Ok(Constraint { @@ -1424,3 +1464,9 @@ impl Value { }) } } + +fn skip_comma(content: &syn::parse::ParseBuffer) { + if content.peek(Token![,]) { + let _: Token![,] = content.parse().unwrap(); + } +} diff --git a/macros/macros_impl/src/decode.rs b/macros/macros_impl/src/decode.rs index 63b5602b..80c2fa82 100644 --- a/macros/macros_impl/src/decode.rs +++ b/macros/macros_impl/src/decode.rs @@ -1,6 +1,5 @@ -use syn::Fields; - use crate::{config::*, ext::GenericsExt}; +use syn::Fields; #[allow(clippy::too_many_lines)] pub fn derive_struct_impl( @@ -8,12 +7,18 @@ pub fn derive_struct_impl( mut generics: syn::Generics, container: syn::DataStruct, config: &Config, -) -> proc_macro2::TokenStream { +) -> syn::Result { let mut list = vec![]; let crate_root = &config.crate_root; generics.add_trait_bounds(crate_root, quote::format_ident!("Decode")); let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); + let field_configs = container + .fields + .iter() + .map(|field| FieldConfig::new(field, config)) + .collect::, _>>()?; + let decode_impl = if config.delegate { let ty = &container.fields.iter().next().unwrap().ty; @@ -58,25 +63,28 @@ pub fn derive_struct_impl( } } } else if config.set { - if container.fields.is_empty() { - panic!("`struct`s without any fields are not currently supported as `set`s.") + if field_configs.is_empty() { + return Err(syn::Error::new( + name.span(), + "struct without fields not allowed to be a `set`", + )); } - let field_names = container.fields.iter().map(|field| field.ident.clone()); + let field_names = field_configs + .iter() + .map(|config| config.field.ident.clone()); let field_names2 = field_names.clone(); let mut count_extended_fields: usize = 0; let mut count_root_fields: usize = 0; - let required_field_names = container - .fields + let required_field_names = field_configs .iter() - .filter(|field| !FieldConfig::new(field, config).is_option_type()) - .map(|field| field.ident.clone()); - let (field_type_names, field_type_defs): (Vec<_>, Vec<_>) = container - .fields + .filter(|config| !config.is_option_type()) + .map(|config| config.field.ident.clone()); + + let (field_type_names, field_type_defs): (Vec<_>, Vec<_>) = field_configs .iter() .enumerate() - .map(|(i, field)| { - let ty = map_to_inner_type(&field.ty).unwrap_or(&field.ty); - let config = FieldConfig::new(field, config); + .map(|(i, config)| { + let ty = map_to_inner_type(&config.field.ty).unwrap_or(&config.field.ty); let tag_attr = config.tag_derive(i); let constraints = config.constraints.attribute_tokens(); let name = quote::format_ident!("Field{}", i); @@ -117,12 +125,11 @@ pub fn derive_struct_impl( syn::Fields::Named(_) => quote!({ #(#field_names2),* }), }; - let (field_const_defs, field_match_arms, field_set_arms): (Vec<_>, Vec<_>, Vec<_>) = itertools::multiunzip(container.fields + let (field_const_defs, field_match_arms, field_set_arms): (Vec<_>, Vec<_>, Vec<_>) = itertools::multiunzip(field_configs .iter() .enumerate() .zip(field_type_names) - .map(|((context, field), field_name)| { - let config = FieldConfig::new(field, config); + .map(|((context, config), field_name)| { let tag = config.tag(context); let const_name = quote::format_ident!("{}Const", field_name); let decode_impl = if config.extension_addition { @@ -132,7 +139,7 @@ pub fn derive_struct_impl( } else { quote!(<_>::decode(decoder)?) }; - let ident = &field.ident; + let ident = &config.field.ident; let set_field_impl = if config.extension_addition || config.extension_addition_group { quote! { @@ -190,7 +197,7 @@ pub fn derive_struct_impl( let mut count_root_fields: usize = 0; let mut count_extended_fields: usize = 0; for (i, field) in container.fields.iter().enumerate() { - let field_config = FieldConfig::new(field, config); + let field_config = FieldConfig::new(field, config)?; if !field_config.is_option_or_default_type() { all_fields_optional_or_default = false; @@ -212,7 +219,7 @@ pub fn derive_struct_impl( } }) .collect(); - list.push(field_config.decode_field_def(&name, i, &type_params)); + list.push(field_config.decode_field_def(&name, i, &type_params)?); } let fields = match container.fields { @@ -224,21 +231,17 @@ pub fn derive_struct_impl( let initializer_fn = if all_fields_optional_or_default { let fields = match container.fields { Fields::Named(_) => { - let init_fields = container.fields.iter().map(|field| { - let default_fn = FieldConfig::new(field, config) - .default_fn() - .unwrap_or(quote!(<_>::default)); - let name = &field.ident; + let init_fields = field_configs.iter().map(|config| { + let default_fn = config.default_fn().unwrap_or(quote!(<_>::default)); + let name = &config.field.ident; quote!(#name : #default_fn ()) }); quote!({ #(#init_fields),* }) } Fields::Unnamed(_) => { - let init_fields = container.fields.iter().map(|field| { - let default_fn = FieldConfig::new(field, config) - .default_fn() - .unwrap_or(quote!(<_>::default)); + let init_fields = field_configs.iter().map(|config| { + let default_fn = config.default_fn().unwrap_or(quote!(<_>::default)); quote!(#default_fn ()) }); quote!(( #(#init_fields),* )) @@ -278,13 +281,13 @@ pub fn derive_struct_impl( decode_impl }; - quote! { + Ok(quote! { impl #impl_generics #crate_root::Decode for #name #ty_generics #where_clause { fn decode_with_tag_and_constraints(decoder: &mut D, tag: #crate_root::types::Tag, constraints: #crate_root::types::Constraints) -> core::result::Result { #decode_impl } } - } + }) } #[allow(clippy::too_many_arguments)] diff --git a/macros/macros_impl/src/encode.rs b/macros/macros_impl/src/encode.rs index 0d3aac9e..c2c42620 100644 --- a/macros/macros_impl/src/encode.rs +++ b/macros/macros_impl/src/encode.rs @@ -5,7 +5,7 @@ pub fn derive_struct_impl( mut generics: syn::Generics, container: syn::DataStruct, config: &Config, -) -> proc_macro2::TokenStream { +) -> syn::Result { let crate_root = &config.crate_root; let mut field_encodings = Vec::with_capacity(container.fields.len()); @@ -25,8 +25,8 @@ pub fn derive_struct_impl( // Count the number of root and extended fields so that encoder can know the number of fields in advance for (i, field) in container.fields.iter().enumerate() { - let field_config = FieldConfig::new(field, config); - let field_encoding = field_config.encode(i, true, &type_params); + let field_config = FieldConfig::new(field, config)?; + let field_encoding = field_config.encode(i, true, &type_params)?; if field_config.is_extension() { number_extended_fields += 1; @@ -106,7 +106,7 @@ pub fn derive_struct_impl( }; let vars = fields_as_vars(&container.fields); - quote! { + Ok(quote! { #[allow(clippy::mutable_key_type)] impl #impl_generics #crate_root::Encode for #name #ty_generics #where_clause { fn encode_with_tag_and_constraints<'encoder, EN: #crate_root::Encoder<'encoder>>(&self, encoder: &mut EN, tag: #crate_root::types::Tag, constraints: #crate_root::types::Constraints) -> core::result::Result<(), EN::Error> { @@ -115,7 +115,7 @@ pub fn derive_struct_impl( #encode_impl } } - } + }) } pub fn map_to_inner_type( diff --git a/macros/macros_impl/src/enum.rs b/macros/macros_impl/src/enum.rs index f080c009..375c9ce3 100644 --- a/macros/macros_impl/src/enum.rs +++ b/macros/macros_impl/src/enum.rs @@ -12,7 +12,7 @@ pub struct Enum { impl Enum { #[allow(clippy::too_many_lines)] - pub fn impl_asntype(&self) -> proc_macro2::TokenStream { + pub fn impl_asntype(&self) -> syn::Result { let crate_root = &self.config.crate_root; let tag = self.config.tag.as_ref().map_or_else( @@ -30,13 +30,23 @@ impl Enum { self.name ); - let tag_tree = if self.config.choice { - let field_tags = self - .variants + let variant_configs: Vec<_> = self + .variants + .iter() + .map(|v| VariantConfig::new(v, &self.generics, &self.config)) + .collect::, _>>()?; + + let field_tags = if self.config.choice { + variant_configs .iter() .enumerate() - .map(|(i, v)| VariantConfig::new(v, &self.generics, &self.config).tag_tree(i)); + .map(|(i, config)| config.tag_tree(i)) + .collect::, _>>()? + } else { + Vec::new() + }; + let tag_tree = if self.config.choice { quote! { { let variant_list: &'static [#crate_root::types::TagTree] = const { &[#(#field_tags),*] }; @@ -69,34 +79,28 @@ impl Enum { .then(|| quote!(#crate_root::types::TagTree::Leaf(Self::TAG))) .unwrap_or_else(|| quote!(tag_tree)); - let (base_variants, extended_variants): (Vec<_>, Vec<_>) = self - .variants - .iter() - .enumerate() - .partition_map(|(i, variant)| { - let config = VariantConfig::new(variant, &self.generics, &self.config); - let tag_tree = config.tag_tree(i); - if config.extension_addition { - either::Right(tag_tree) - } else { - either::Left(tag_tree) - } - }); - - let identifiers = self - .variants + let identifiers = variant_configs .iter() .map(|v| { - VariantConfig::new(v, &self.generics, &self.config) - .identifier - .unwrap_or(syn::LitStr::new( - &v.ident.to_string(), - proc_macro2::Span::call_site(), - )) + v.identifier.clone().unwrap_or_else(|| { + syn::LitStr::new(&v.variant.ident.to_string(), proc_macro2::Span::call_site()) + }) }) .collect_vec(); let constraints_def = self.config.constraints.const_static_def(crate_root); + + let (base_variants, extended_variants): (Vec<_>, Vec<_>) = variant_configs + .iter() + .zip(field_tags) + .partition_map(|(config, field_tag)| { + if config.extension_addition { + either::Right(field_tag) + } else { + either::Left(field_tag) + } + }); + let extensible = self.config.constraints.extensible; let extended_const_variants = extensible .then(|| quote!(Some(&[#(#extended_variants),*]))) @@ -136,8 +140,7 @@ 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)) + let (variants, extended_variants): (Vec<_>, Vec<_>) = variant_configs.iter() .partition(|config| !config.extension_addition); let discriminants = variants.iter().enumerate().map(|(i, config)| { @@ -180,7 +183,7 @@ impl Enum { |id| quote!(const IDENTIFIER: Option<&'static str> = Some(#id);), ); - quote! { + Ok(quote! { impl #impl_generics #crate_root::AsnType for #name #ty_generics #where_clause { const TAG: #crate_root::types::Tag = { #tag @@ -199,7 +202,7 @@ impl Enum { #choice_impl #enumerated_impl - } + }) } pub fn impl_encode(&self) -> proc_macro2::TokenStream { @@ -221,7 +224,7 @@ impl Enum { } } - pub fn impl_decode(&self) -> proc_macro2::TokenStream { + pub fn impl_decode(&self) -> syn::Result { let crate_root = &self.config.crate_root; let mut generics = self.generics.clone(); generics.add_trait_bounds(&self.config.crate_root, quote::format_ident!("Decode")); @@ -295,10 +298,16 @@ impl Enum { let name = &self.name; let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); - let decode_choice_impl = self.config.choice.then(|| { - let decode_ops = self.variants.iter() + let decode_choice_impl = if self.config.choice { + let decode_ops: Vec = self + .variants + .iter() .enumerate() - .map(|(i, v)| VariantConfig::new(v, &generics, &self.config).decode(&self.name, i)); + .map(|(i, v)| { + VariantConfig::new(v, &generics, &self.config) + .map(|config| config.decode(&self.name, i)) + }) + .collect::, _>, _>>()??; let str_name = syn::LitStr::new(&self.name.to_string(), proc_macro2::Span::call_site()); let from_tag = quote! { @@ -306,7 +315,7 @@ impl Enum { Err(#crate_root::de::Error::no_valid_choice(#str_name, decoder.codec())) }; - quote! { + Some(quote! { #[automatically_derived] impl #impl_generics #crate_root::types::DecodeChoice for #name #ty_generics #where_clause { fn from_tag(decoder: &mut D, tag: #crate_root::types::Tag) -> core::result::Result { @@ -314,10 +323,12 @@ impl Enum { #from_tag } } - } - }); + }) + } else { + None + }; - quote! { + Ok(quote! { #decode_choice_impl #[automatically_derived] @@ -328,7 +339,7 @@ impl Enum { #decode_impl } - } + }) } fn encode_with_tag(&self) -> proc_macro2::TokenStream { @@ -365,8 +376,8 @@ impl Enum { let tags = self.variants.iter().enumerate().map(|(i, v)| { let ident = &v.ident; let name = &self.name; - let variant_config = VariantConfig::new(v, generics, &self.config); - let variant_tag = variant_config.tag(i); + let variant_config = VariantConfig::new(v, generics, &self.config).unwrap(); + let variant_tag = variant_config.tag(i).unwrap(); let tag_tokens = variant_tag.to_tokens(crate_root); match &v.fields { @@ -379,8 +390,8 @@ impl Enum { let variants = self.variants.iter().enumerate().map(|(i, v)| { let ident = &v.ident; let name = &self.name; - let variant_config = VariantConfig::new(v, generics, &self.config); - let variant_tag = variant_config.tag(i); + let variant_config = VariantConfig::new(v, generics, &self.config).unwrap(); + let variant_tag = variant_config.tag(i).unwrap(); match &v.fields { syn::Fields::Named(_) => { diff --git a/macros/macros_impl/src/lib.rs b/macros/macros_impl/src/lib.rs index 9f71cf85..dbcd2ff0 100644 --- a/macros/macros_impl/src/lib.rs +++ b/macros/macros_impl/src/lib.rs @@ -18,17 +18,17 @@ pub fn decode_derive_inner( input: proc_macro2::TokenStream, ) -> syn::Result { let input = syn::parse2(input)?; - let config = Config::from_attributes(&input); + let config = Config::from_attributes(&input)?; let name = input.ident; let generics = input.generics; let crate_root = &config.crate_root; - Ok(match input.data { + match input.data { // Unit structs are treated as ASN.1 NULL values. syn::Data::Struct(DataStruct { fields: syn::Fields::Unit, .. - }) => quote! { + }) => Ok(quote! { impl #crate_root::Decode for #name { fn decode_with_tag_and_constraints( decoder: &mut D, @@ -38,7 +38,7 @@ pub fn decode_derive_inner( decoder.decode_null(tag).map(|_| #name) } } - }, + }), syn::Data::Struct(v) => decode::derive_struct_impl(name, generics, v, &config), syn::Data::Enum(syn::DataEnum { variants, .. }) => r#enum::Enum { name, @@ -47,14 +47,17 @@ pub fn decode_derive_inner( config, } .impl_decode(), - _ => panic!("Union types are not supported."), - }) + _ => Err(syn::Error::new( + name.span(), + "Union types are not supported.", + )), + } } pub fn encode_derive_inner( input: proc_macro2::TokenStream, ) -> syn::Result { let input = syn::parse2(input)?; - let config = Config::from_attributes(&input); + let config = Config::from_attributes(&input)?; let name = input.ident; let generics = input.generics; let crate_root = &config.crate_root; @@ -76,7 +79,7 @@ pub fn encode_derive_inner( } } }, - syn::Data::Struct(v) => encode::derive_struct_impl(name, generics, v, &config), + syn::Data::Struct(v) => encode::derive_struct_impl(name, generics, v, &config)?, syn::Data::Enum(syn::DataEnum { variants, .. }) => r#enum::Enum { name, generics, @@ -84,7 +87,12 @@ pub fn encode_derive_inner( config, } .impl_encode(), - _ => panic!("Union types are not supported."), + _ => { + return Err(syn::Error::new( + name.span(), + "Union types are not supported.", + )) + } }) } @@ -92,19 +100,24 @@ pub fn asn_type_derive_inner( input: proc_macro2::TokenStream, ) -> syn::Result { let input = syn::parse2(input)?; - let config = Config::from_attributes(&input); + let config = Config::from_attributes(&input)?; let name = input.ident; let generics = input.generics; Ok(match input.data { - syn::Data::Struct(v) => asn_type::derive_struct_impl(name, generics, v, &config), + syn::Data::Struct(v) => asn_type::derive_struct_impl(name, generics, v, &config)?, syn::Data::Enum(syn::DataEnum { variants, .. }) => r#enum::Enum { name, generics, variants, config, } - .impl_asntype(), - _ => panic!("Union types are not supported."), + .impl_asntype()?, + _ => { + return Err(syn::Error::new( + name.span(), + "Union types are not supported.", + )) + } }) } diff --git a/macros/macros_impl/src/tag.rs b/macros/macros_impl/src/tag.rs index d08a8eb9..ba33764d 100644 --- a/macros/macros_impl/src/tag.rs +++ b/macros/macros_impl/src/tag.rs @@ -1,3 +1,4 @@ +use syn::spanned::Spanned; use syn::{parenthesized, Token}; #[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug)] @@ -9,17 +10,22 @@ pub enum Class { } impl Class { - fn from_ident(ident: &syn::Ident) -> Self { - match &*ident.to_string().to_lowercase() { + fn from_ident(ident: &syn::Ident) -> syn::Result { + Ok(match &*ident.to_string().to_lowercase() { "universal" => Class::Universal, "application" => Class::Application, "context" => Class::Context, "private" => Class::Private, - s => panic!( - "Class MUST BE `universal`, `application`, `context`, or `private`. Found: {}", - s - ), - } + s => { + return Err(syn::Error::new( + ident.span(), + format!( + "Class MUST BE `universal`, `application`, `context`, or `private`. Found: {}", + s + ), + )) + } + }) } pub fn to_ident(self) -> syn::Ident { @@ -70,7 +76,7 @@ impl Tag { let ident: syn::Ident = content.parse()?; if content.peek(syn::token::Paren) { if ident != syn::Ident::new("explicit", proc_macro2::Span::call_site()) { - panic!("Invalid attribute literal provided to `rasn`, expected `rasn(tag(explicit(...)))`."); + return Err(syn::Error::new(ident.span(), "Invalid attribute literal provided to `rasn`, expected `rasn(tag(explicit(...)))`.")); } let explicit_content; parenthesized!(explicit_content in &content); @@ -78,13 +84,12 @@ impl Tag { && explicit_content.peek2(Token![,]) && explicit_content.peek3(syn::Lit) { - let path: syn::Path = explicit_content.parse()?; + let ident = explicit_content.parse()?; let _ = explicit_content.parse::()?; let lit: syn::Lit = explicit_content.parse()?; - let class = - Class::from_ident(path.get_ident().expect("Path must be a valid ident.")); + let class = Class::from_ident(&ident)?; explicit = true; tag = (class, lit); } else if explicit_content.peek(syn::Lit) { @@ -92,24 +97,27 @@ impl Tag { explicit = true; tag = (Class::Context, lit); } else { - panic!("Expected meta items inside `explicit`") + return Err(explicit_content.error("Expected meta items inside `explicit`")); } if !explicit_content.is_empty() { - panic!("The `#[rasn(tag)]`attribute takes a maximum of two arguments.") + return Err(explicit_content + .error("The `#[rasn(tag)]`attribute takes a maximum of two arguments.")); } } else if content.peek(Token![,]) { let _: Token![,] = content.parse()?; let lit: syn::Lit = content.parse()?; - let class = Class::from_ident(&ident); + let class = Class::from_ident(&ident)?; tag = (class, lit); } else { - panic!("The `#[rasn(tag)]`attribute must be a list.") + return Err(content.error("The `#[rasn(tag)]`attribute must be a list.")); } } else { - panic!("The `#[rasn(tag)]`attribute must be a list.") + return Err(content.error("The `#[rasn(tag)]`attribute must be a list.")); } if !content.is_empty() { - panic!("The `#[rasn(tag)]`attribute takes a maximum of two arguments.") + return Err( + content.error("The `#[rasn(tag)]`attribute takes a maximum of two arguments.") + ); } Ok(Self::Value { @@ -119,8 +127,8 @@ impl Tag { }) } - pub fn from_fields(fields: &syn::Fields) -> Self { - match fields { + pub fn from_fields(fields: &syn::Fields) -> syn::Result { + Ok(match fields { syn::Fields::Unit => Self::Delegate { ty: syn::TypeTuple { paren_token: <_>::default(), @@ -131,14 +139,17 @@ impl Tag { syn::Fields::Named(_) => Self::SEQUENCE(), syn::Fields::Unnamed(_) => { if fields.iter().count() != 1 { - panic!("Tuple-style enum variants must contain only a single field, switch to struct-style variants for multiple fields."); + return Err(syn::Error::new( + fields.span(), + "Unnamed fields are not supported.", + )); } else { let ty = fields.iter().next().cloned().unwrap().ty; Self::Delegate { ty } } } - } + }) } pub fn is_explicit(&self) -> bool {