use crate::reflection::options_attr::OptionsAttr; mod default_value; mod enum_impl; mod field; mod options_attr; mod struct_impl; mod visibility; pub fn derive(input: proc_macro2::TokenStream) -> proc_macro2::TokenStream { let input = syn::parse2::(input).unwrap(); let options = get_options(&input); match input { syn::Item::Struct(input) => struct_impl::generate(input, options), syn::Item::Enum(input) => enum_impl::generate(input, options), _ => panic!("Invalid input"), } } pub fn get_options(input: &syn::Item) -> OptionsAttr { let (attrs, generic_params) = match &input { syn::Item::Struct(input) => (input.attrs.as_slice(), &input.generics.params), syn::Item::Enum(input) => (input.attrs.as_slice(), &input.generics.params), _ => ( const { &[] }.as_slice(), &syn::punctuated::Punctuated::::new(), ), }; if attrs .iter() .filter(|attr| attr.path().is_ident("reflection")) .count() > 1 { panic!("Multiple 'reflection' attributes are not allowed"); } let options = match attrs .iter() .find_map(|attr| { if attr.path().is_ident("reflection") { return Some(attr.parse_args::()); } None }) .transpose() { Ok(attr) => attr.unwrap_or_default(), Err(err) => { panic!("{err}"); } }; if options.impl_with_generics.is_empty() && !generic_params.is_empty() { panic!(concat!( "Generic types deriving Reflection must specify which ", "generics to use in the generated impl(s) using the 'reflection' attribute\n", "For example: #[reflection(impl_with_generics(, ))]" )); } if !options.impl_with_generics.is_empty() && generic_params.is_empty() { panic!("Specifying 'impl_with_generics' for non-generic types is not allowed"); } options }