use proc_macro::TokenStream; use syn::{spanned::Spanned, Data, Fields}; #[proc_macro_derive(Extract)] pub fn extract(input: TokenStream) -> TokenStream { let ast = syn::parse_macro_input!(input); impl_extract(&ast) } fn impl_extract(ast: &syn::DeriveInput) -> TokenStream { let name = &ast.ident; match &ast.data { Data::Struct(st) => match &st.fields { Fields::Named(fields) => { let extracted = fields.named.iter().map(|field| { let ident = &field.ident; let ty = &field.ty; quote::quote_spanned! {field.span()=> #ident : crate::utils::extract_arg!(ctx, #ident, #ty) } }); TokenStream::from(quote::quote! { impl Extract for #name { fn extract(ctx: crate::ApplicationContext) -> Self { Self { #(#extracted,)* } } } }) } Fields::Unit => TokenStream::from(quote::quote! { impl Extract for #name { fn extract(ctx: crate::ApplicationContext) -> Self { Self {} } } }), _ => { panic!("Only named/unit structs can derive Extract"); } }, _ => { panic!("Only structs can derive Extract"); } } }