1use convert_case::{Case, Casing};
2use proc_macro::{self, TokenStream};
3use proc_macro2::Span;
4use proc_macro_crate::{crate_name, FoundCrate};
5use quote::quote;
6use syn::{parse_macro_input, Ident, ItemEnum};
7
8#[allow(dead_code)]
9fn import_crate() -> Ident {
10 let found_crate =
11 crate_name("serde-dot-case").expect("serde-dot-case is present in `Cargo.toml`");
12 match found_crate {
13 FoundCrate::Itself => Ident::new("crate", Span::call_site()),
14 FoundCrate::Name(name) => Ident::new(&name, Span::call_site()),
15 }
16}
17
18#[proc_macro_attribute]
19pub fn serde_dot_case(_attr: TokenStream, item: TokenStream) -> TokenStream {
20 let ItemEnum {
21 attrs,
22 vis,
23 enum_token,
24 ident,
25 generics,
26 brace_token: _,
27 variants,
28 } = parse_macro_input!(item);
29 let variants = variants.iter().map(|v| {
30 let name = v.ident.to_string().to_case(Case::Snake).replace('_', ".");
31 quote! {
32 #[serde(rename = #name)]
33 #v
34 }
35 });
36 quote! {
37 #(#attrs)*
38 #vis #enum_token #ident #generics {
39 #(#variants,)*
40 }
41 }
42 .into()
43}