enum_collections_macros/
lib.rs

1use proc_macro::TokenStream;
2use quote::{quote, quote_spanned};
3use syn::{parse_macro_input, spanned::Spanned, DeriveInput};
4
5/// Creates `enum_map::Enumerated` implementation for the underlying Enum.
6/// Also derives Copy and Clone.
7#[proc_macro_derive(Enumerated)]
8pub fn derive_enum_collections(input: TokenStream) -> TokenStream {
9    let input = parse_macro_input!(input as DeriveInput);
10    let generics = &input.generics;
11    let name = &input.ident;
12    let syn::Data::Enum(en) = input.data else {
13        return quote_spanned! {
14            input.span() => compile_error!("The `Enumerated` macro only supports enums.");
15        }
16        .into();
17    };
18
19    let enum_len = en.variants.len();
20    let mut variants = proc_macro2::TokenStream::new();
21    for variant in en.variants {
22        if let Some((_, discriminant)) = variant.discriminant {
23            return quote_spanned! {
24                discriminant.span() => compile_error!("`Enumerated` doesn't support discriminants");
25            }
26            .into();
27        }
28        let variant_name = variant.ident;
29        variants.extend(quote! { Self::#variant_name, });
30    }
31
32    #[cfg(feature = "variants")]
33    return quote! {
34        impl #generics Enumerated for #name #generics {
35
36            fn position(self) -> usize {
37                self as usize
38            }
39
40            const SIZE: usize = #enum_len;
41            const VARIANTS: &'static [Self] = &[#variants];
42        }
43    }
44    .into();
45
46    #[cfg(not(feature = "variants"))]
47    return quote! {
48        impl #generics Enumerated for #name #generics {
49
50            fn position(self) -> usize {
51                self as usize
52            }
53
54            const SIZE: usize = #enum_len;
55        }
56    }
57    .into();
58}