errcode_derive 0.1.0-alpha.1

An internal helper crate for errcode. Not public API.
Documentation
use crate::enum_info::EnumInfo;
use proc_macro2::{Ident, Span, TokenStream};
use quote::quote;

pub fn generate(info: EnumInfo) -> TokenStream {
    let errcode = quote!(errcode);
    let internal = quote!(#errcode::__macro_export);
    let core = quote!(#errcode::__macro_export::core);

    let ty = &info.name;
    let ty_name = ty.to_string();

    let error_code_info_ident: Vec<_> = (0..info.variants.len())
        .map(|x| Ident::new(&format!("ERROR_CODE_INFO_{x}"), Span::call_site()))
        .collect();
    let static_info_ident: Vec<_> = (0..info.variants.len())
        .map(|x| Ident::new(&format!("STATIC_INFO_{x}"), Span::call_site()))
        .collect();

    let ids: Vec<_> = info.variants.iter().map(|x| x.repr).collect();
    let variant_names: Vec<_> = info.variants.iter().map(|x| x.name.to_string()).collect();
    let variant: Vec<_> = info.variants.iter().map(|x| &x.name).collect();
    let message_data: Vec<_> = info
        .variants
        .iter()
        .map(|x| match &x.message {
            None => quote! { #internal::None },
            Some(msg) => quote! { #internal::Some(#msg) },
        })
        .collect();

    quote! {
        #[automatically_derived]
        const _: () = {
            const TYPE_ID: #core::any::TypeId = #core::any::TypeId::of::<#ty>();
            #(
                static #error_code_info_ident: #internal::ErrorCodeInfo = #internal::ErrorCodeInfo {
                    tid: TYPE_ID,
                    value: #ids,
                    type_name: #ty_name,
                    variant_name: #variant_names,
                    message: #message_data,
                };
                static #static_info_ident: #internal::ErrorInfoImpl =
                    #internal::wrap_code(&#error_code_info_ident);
            )*

            pub struct ConstHelperType;
            impl ConstHelperType {
                pub const fn info(&self, value: #ty) -> &'static #internal::ErrorCodeInfo {
                    match value {
                        #(#ty::#variant => &#error_code_info_ident,)*
                    }
                }
            }

            impl #internal::ErrorCodePrivate for #ty {
                type ConstHelper = ConstHelperType;
                const CONST_HELPER_INSTANCE: ConstHelperType = ConstHelperType;

                fn error_source(self) -> &'static #internal::ErrorInfoImpl {
                    match self {
                        #(#ty::#variant => &#static_info_ident,)*
                    }
                }
                fn is_value(self, value: u32) -> bool {
                    match value {
                        #(#ids => #core::matches!(self, #ty::#variant),)*
                        _ => false,
                    }
                }
                fn from_value(value: u32) -> Self {
                    match value {
                        #(#ids => #ty::#variant,)*
                        _ => #core::panic!("unknown value: {value}"),
                    }
                }
            }
            impl #errcode::ErrorCode for #ty {}
        };
    }
}