enum_rename/
lib.rs

1use proc_macro::TokenStream;
2use quote::quote;
3use syn::{DeriveInput, Meta, Token, parse_macro_input, punctuated::Punctuated};
4
5#[proc_macro_derive(EnumRenames, attributes(serde))]
6pub fn enum_renames(input: TokenStream) -> TokenStream {
7    let ast = parse_macro_input!(input as DeriveInput);
8    let name = &ast.ident;
9
10    let mut match_arms = Vec::new();
11    let mut variant_renames = Vec::new();
12
13    if let syn::Data::Enum(data_enum) = ast.data {
14        for variant in data_enum.variants {
15            let ident = &variant.ident;
16            let mut rename = ident.to_string();
17            for attr in variant.attrs {
18                if attr.path().is_ident("serde") {
19                    if let Ok(nested) = attr.parse_args_with(Punctuated::<Meta, Token![,]>::parse_terminated) {
20                        for meta in nested {
21                            if let Meta::NameValue(nv) = meta {
22                                if nv.path.is_ident("rename") {
23                                    if let syn::Expr::Lit(expr_lit) = &nv.value {
24                                        if let syn::Lit::Str(lit_str) = &expr_lit.lit {
25                                            rename = lit_str.value();
26                                        }
27                                    }
28                                }
29                            }
30                        }
31                    }
32                }
33            }
34            // clone here to avoid move
35            variant_renames.push(rename.clone());
36
37            let pat = match &variant.fields {
38                syn::Fields::Unit => quote! { Self::#ident },
39                syn::Fields::Unnamed(_) => quote! { Self::#ident (..) },
40                syn::Fields::Named(_) => quote! { Self::#ident { .. } },
41            };
42            match_arms.push(quote! { #pat => #rename });
43        }
44    }
45
46    let expanded = quote! {
47        impl #name {
48            pub fn renames() -> &'static [&'static str] {
49                &[#(#variant_renames),*]
50            }
51            pub fn rename(&self) -> &'static str {
52                match self {
53                    #(#match_arms,)*
54                }
55            }
56        }
57    };
58
59    expanded.into()
60}
61#[cfg(test)]
62mod tests {
63    use super::*;
64    #[test]
65    fn test_case() {
66        assert!(false);
67    }
68}