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}"); } }; assert!( !options.impl_with_generics.is_empty() || generic_params.is_empty(), 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(, ))]" ) ); assert!( options.impl_with_generics.is_empty() || !generic_params.is_empty(), "Specifying 'impl_with_generics' for non-generic types is not allowed" ); options }