field_name 0.2.0

A proc-macro for exposing a struct's field names at runtime.
Documentation
use darling::{ast::Data, FromDeriveInput, FromVariant};
use proc_macro2::TokenStream;
use quote::{quote, ToTokens};
use syn::{Generics, Ident};

#[derive(FromDeriveInput)]
#[darling(attributes(variant_name), supports(enum_any))]
pub(crate) struct Receiver {
    ident: Ident,
    generics: Generics,
    data: Data<ReceiverVariant, ()>,
}

#[derive(FromVariant)]
#[darling(attributes(variant_name))]
struct ReceiverVariant {
    ident: Ident,

    #[darling(default)]
    rename: Option<String>,

    #[darling(default)]
    skip: bool,
}

impl ToTokens for Receiver {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let ident = &self.ident;
        let (impl_generics, ty_generics, where_clause) = self.generics.split_for_impl();

        let variants = self.data
            .as_ref()
            .take_enum()
            .expect("VariantNames only supports enums")
            .into_iter()
            .filter(|v| !v.skip)
            .collect::<Vec<_>>();

        let variant_values: Vec<String> = variants.iter()
            .map(|v| v.rename.clone().unwrap_or_else(|| v.ident.to_string()))
            .collect();

        let individual_consts = variants.iter().map(|v| {
            let variant_ident = &v.ident;

            // Convert variant name to uppercase (Connecting -> CONNECTING)
            let const_name = Ident::new(
                &variant_ident.to_string().to_uppercase(),
                variant_ident.span()
            );

            let const_value = v.rename.clone().unwrap_or_else(|| variant_ident.to_string());

            quote! {
                pub const #const_name: &'static str = #const_value;
            }
        });

        let len = variant_values.len();

        tokens.extend(quote! {
            #[automatically_derived]
            impl #impl_generics #ident #ty_generics #where_clause {
                pub const VARIANTS: [&'static str; #len] = [
                    #(#variant_values),*
                ];

                #(#individual_consts)*
            }
        });
    }
}