1use proc_macro2::TokenStream;
2use quote::quote;
3use syn::Data;
4use syn::Result;
5use syn::{DeriveInput, parse_macro_input};
6
7#[proc_macro_derive(Enumable)]
8pub fn derive_enumable(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
9 derive_enumable_internal(parse_macro_input!(input as DeriveInput))
10 .unwrap_or_else(syn::Error::into_compile_error)
11 .into()
12}
13
14fn derive_enumable_internal(input: DeriveInput) -> Result<TokenStream> {
15 let Data::Enum(data_enum) = input.data else {
16 return Err(syn::Error::new_spanned(
17 &input,
18 "Enumable can only be derived for enums",
19 ));
20 };
21
22 let variant_idents = data_enum
23 .variants
24 .iter()
25 .map(|v| {
26 if !matches!(v.fields, syn::Fields::Unit) {
27 return Err(syn::Error::new_spanned(
28 &v.fields,
29 "Enumable can only be derived for unit variants",
30 ));
31 }
32 Ok(&v.ident)
33 })
34 .collect::<Result<Vec<_>>>()?;
35
36 let ident = &input.ident;
37 let expanded = quote! {
38 impl enum_table::Enumable for #ident {
39 const VARIANTS: &'static [#ident] = &enum_table::__private::sort_variants([#(Self::#variant_idents),*]);
40 }
41 };
42
43 Ok(expanded)
44}