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 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}