endex_derive 0.1.0

get index of enum variant by enum value
Documentation
use proc_macro::TokenStream;
use syn::{parse_macro_input, ItemEnum};

#[proc_macro_derive(VariantIndex)]
pub fn variant_index(input: TokenStream) -> TokenStream {
    let item_enum = parse_macro_input!(input as ItemEnum);
    let enum_name = &item_enum.ident;
    let enum_generic_params = &item_enum.generics.params.iter().collect::<Vec<_>>();
    let enum_generic_where_clause = &item_enum.generics.where_clause;
    let enum_generic_params_without_bounds = &item_enum
        .generics
        .params
        .iter()
        .map(|param| match param {
            syn::GenericParam::Lifetime(lifetime_param) => &lifetime_param.lifetime.ident,
            syn::GenericParam::Type(type_param) => &type_param.ident,
            syn::GenericParam::Const(const_param) => &const_param.ident,
        })
        .collect::<Vec<_>>();
    let mut last_index: proc_macro2::TokenStream = quote::quote! {0};
    let match_branches = item_enum
        .variants
        .iter()
        .map(|variant| {
            let index = if let Some(discriminant) = &variant.discriminant {
                let index = &discriminant.1;
                last_index = quote::quote! { #index };
                last_index.clone()
            } else {
                last_index = quote::quote! {(#last_index) + 1};
                last_index.clone()
            };

            let variant_name = &variant.ident;
            let fields = match variant.fields {
                syn::Fields::Named(_) => quote::quote! { {..} },
                syn::Fields::Unnamed(_) => quote::quote! { (..) },
                syn::Fields::Unit => quote::quote! {},
            };
            quote::quote! {
                #enum_name::#variant_name #fields => #index
            }
        })
        .collect::<Vec<_>>();
    quote::quote! {
    impl<#(#enum_generic_params),*> endex::VariantIndex
        for #enum_name<#(#enum_generic_params_without_bounds),*> #enum_generic_where_clause {

            fn variant_index(&self) -> usize {
                match self {
                    #(#match_branches),*
                }
            }
        }
    }
    .into()
}