muggle_macros 0.1.0

Macros for muggle
Documentation
use heck::ToUpperCamelCase;
use proc_macro::TokenStream;
use quote::{format_ident, quote};
use syn::{parse::Parse, punctuated::Punctuated, Ident, LitStr, Token};

struct Input {
    ident: Ident,
    suffix: Option<LitStr>,
    constants: Punctuated<Ident, Option<Token![,]>>,
}

impl Parse for Input {
    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
        Ok(Input {
            ident: input.parse()?,
            suffix: input.parse()?,
            constants: input.parse_terminated(Ident::parse)?,
        })
    }
}

#[proc_macro]
pub fn gl_enum(tokens: TokenStream) -> TokenStream {
    let Input {
        ident,
        suffix,
        constants,
    } = syn::parse_macro_input!(tokens);

    let mut fields = Vec::new();

    for constant in constants {
        let ident = if let Some(ref suffix) = suffix {
            constant
                .to_string()
                .strip_suffix(&suffix.value())
                .unwrap_or_else(|| {
                    panic!(
                        "Failed to remove suffix {} from constant {constant}",
                        suffix.value()
                    )
                })
                .to_string()
                .to_upper_camel_case()
        } else {
            constant.to_string().to_upper_camel_case()
        };

        let ident = format_ident!("{}", ident.strip_prefix("Gl").unwrap_or(&ident));
        fields.push(quote!(#ident = #constant))
    }

    quote! {
        #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, IntoPrimitive)]
        #[repr(u32)]
        #[non_exhaustive]
        pub enum #ident {
            #(#fields),*
        }
    }
    .into()
}