enum_dict_derive 0.1.1

Derive macros for enum_dict.
Documentation
#![doc = include_str!("../README.md")]

use proc_macro::TokenStream;
use quote::quote;
use syn::spanned::Spanned;
use syn::{Data, DeriveInput, Error, Fields, LitStr, parse_macro_input};

#[proc_macro_derive(DictKey)]
pub fn derive_dict_key(input: TokenStream) -> TokenStream {
    let input: DeriveInput = parse_macro_input!(input);
    let ident = &input.ident;

    let mut ident_names = vec![];

    match &input.data {
        Data::Enum(data) => {
            for variant in &data.variants {
                let ident = &variant.ident;
                let name = LitStr::new(&ident.to_string(), ident.span());
                ident_names.push(quote! { #name });

                match &variant.fields {
                    Fields::Unit => {}
                    _ => {
                        return Error::new(variant.span(), "DictKey can only be derived for unit variants")
                            .to_compile_error()
                            .into();
                    }
                }
            }
        }
        _ => {
            return Error::new(input.span(), "DictKey can only be derived for enums")
                .to_compile_error()
                .into();
        }
    }

    quote! {
        impl DictKey for #ident {
            const FIELDS: &'static [&'static str] = &[#(#ident_names),*];

            fn into_usize(self) -> usize {
                self as usize
            }
        }
    }
    .into()
}

#[proc_macro_derive(FromStr)]
pub fn derive_from_str(input: TokenStream) -> TokenStream {
    let input: DeriveInput = parse_macro_input!(input);
    let ident = &input.ident;

    let mut match_arms = vec![];

    match &input.data {
        Data::Enum(data) => {
            for variant in &data.variants {
                let ident = &variant.ident;
                let name = LitStr::new(&ident.to_string(), ident.span());
                match_arms.push(quote! { #name => Ok(Self::#ident), });

                match &variant.fields {
                    Fields::Unit => {}
                    _ => {
                        return Error::new(variant.span(), "FromStr can only be derived for unit variants")
                            .to_compile_error()
                            .into();
                    }
                }
            }
        }
        _ => {
            return Error::new(input.span(), "FromStr can only be derived for enums")
                .to_compile_error()
                .into();
        }
    }

    quote! {
        impl FromStr for #ident {
            type Err = ();

            fn from_str(s: &str) -> Result<Self, Self::Err> {
                match s {
                    #(#match_arms)*
                    _ => Err(()),
                }
            }
        }
    }
    .into()
}