derive_name_macros/
lib.rs

1use proc_macro::TokenStream;
2use quote::quote;
3use syn::{self, parse_quote, Arm, Data};
4
5#[proc_macro_derive(Name)]
6pub fn name(input: TokenStream) -> TokenStream {
7    let ast: syn::DeriveInput = syn::parse_macro_input!(input);
8    let ident = &ast.ident;
9    let gen = quote! {
10        impl derive_name::Name for #ident {
11            fn name() -> &'static str {
12                stringify!(#ident)
13            }
14        }
15    };
16    gen.into()
17}
18
19#[proc_macro_derive(VariantName)]
20pub fn variant(input: TokenStream) -> TokenStream {
21    let ast: syn::DeriveInput = syn::parse_macro_input!(input);
22
23    if let Data::Enum(r#enum) = &ast.data {
24        let ident = &ast.ident;
25        let mut match_arms = Vec::<Arm>::with_capacity(r#enum.variants.len());
26
27        for variant in r#enum.variants.iter() {
28            let variant_ident = &variant.ident;
29            let match_pattern = match &variant.fields {
30                syn::Fields::Named(_) => {
31                    quote!( Self::#variant_ident {..} )
32                }
33                syn::Fields::Unnamed(_) => {
34                    quote!( Self::#variant_ident (..) )
35                }
36                syn::Fields::Unit => quote!( Self::#variant_ident ),
37            };
38
39            match_arms.push(parse_quote! {
40                #match_pattern => stringify!(#variant_ident)
41            });
42        }
43        let gen = quote! {
44            impl derive_name::VariantName for #ident {
45                fn variant_name(&self) -> &'static str {
46                    match self {
47                        #(#match_arms),*
48                    }
49                }
50            }
51        };
52        gen.into()
53    } else {
54        quote!(
55            compile_error!("Can only implement 'VariantName' on a enum");
56        )
57        .into()
58    }
59}