Skip to content

Commit

Permalink
Improve error messages for the derive macros
Browse files Browse the repository at this point in the history
Closes #346.
  • Loading branch information
shahn committed Jan 5, 2025
1 parent 3531401 commit ac6de09
Show file tree
Hide file tree
Showing 7 changed files with 465 additions and 365 deletions.
61 changes: 27 additions & 34 deletions macros/macros_impl/src/asn_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,68 +3,61 @@ use itertools::Itertools;
use crate::config::*;

pub fn derive_struct_impl(
name: syn::Ident,
mut generics: syn::Generics,
name: &syn::Ident,
generics: syn::Generics,
container: syn::DataStruct,
config: &Config,
) -> proc_macro2::TokenStream {
) -> syn::Result<proc_macro2::TokenStream> {
let crate_root = &config.crate_root;
let tag = config.tag_for_struct(&container.fields);
let field_groups = container
let field_configs = container
.fields
.iter()
.enumerate()
.map(|(i, f)| (i, FieldConfig::new(f, config)));
.map(|(i, f)| FieldConfig::new(f, config, i))
.collect::<Result<Vec<_>, _>>()?;

let field_metadata = field_groups
.clone()
.filter(|(_, field)| field.is_not_extension())
.map(|(i, field)| {
let metadata = field.to_field_metadata(i);
let field_metadata = field_configs
.iter()
.filter(|field| field.is_not_extension())
.map(|field| {
let metadata = field.to_field_metadata();
quote!(#metadata)
})
.collect::<Vec<_>>();

let extension_metadata = field_groups
.clone()
.filter(|(_, field)| field.is_extension())
.map(|(i, field)| {
let metadata = field.to_field_metadata(i);
let extension_metadata = field_configs
.iter()
.filter(|field| field.is_extension())
.map(|field| {
let metadata = field.to_field_metadata();
quote!(#metadata)
})
.collect::<Vec<_>>();
// TODO use partition above?

let all_optional_tags_are_unique: Vec<_> = field_groups
.chunk_by(|(_, config)| config.is_option_or_default_type())
let all_optional_tags_are_unique: Vec<_> = field_configs
.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 \
OPTIONALs are correct.",
name
);

quote!({
let tag_tree = fields.map(|f| f.tag_tree()).collect::<Vec<_>>();

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::<Vec<_>>();

for param in generics.type_params_mut() {
param
.bounds
.push(syn::TypeParamBound::Trait(syn::TraitBound {
paren_token: Some(<_>::default()),
modifier: syn::TraitBoundModifier::None,
lifetimes: None,
path: syn::parse_quote!(#crate_root::AsnType),
}));
}
.collect::<Result<Vec<_>, _>>()?;

let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();

Expand Down Expand Up @@ -101,7 +94,7 @@ pub fn derive_struct_impl(
|id| quote!(const IDENTIFIER: Option<&'static str> = Some(#id);),
);

quote! {
Ok(quote! {
#constructed_impl

#[automatically_derived]
Expand All @@ -114,5 +107,5 @@ pub fn derive_struct_impl(
#alt_identifier
#constraints_def
}
}
})
}
Loading

0 comments on commit ac6de09

Please sign in to comment.