use quote::quote; use crate::reflection::field::{generate as generate_field, ReflectionFieldGenOptions}; use crate::util::find_engine_crate_path; pub fn generate(input: syn::ItemEnum) -> proc_macro2::TokenStream { let engine_crate_path = find_engine_crate_path().unwrap(); let input_ident = input.ident; let (impl_generics, type_generics, where_clause) = input.generics.split_for_impl(); let variants = input.variants.iter().map(|variant| { let variant_name = syn::LitStr::new(&variant.ident.to_string(), variant.ident.span()); let fields = match &variant.fields { syn::Fields::Unit => quote! { None }, syn::Fields::Named(named_fields) => { let fields = named_fields.named.iter().enumerate().map( |(variant_field_index, variant_field)| { generate_field( variant_field, variant_field_index, &engine_crate_path, ReflectionFieldGenOptions { field_vis_override: None, include_byte_offset: false, }, ) }, ); quote! { Some(#engine_crate_path::reflection::EnumVariantFields::Named { fields: &[#(#fields),*] }) } } syn::Fields::Unnamed(unnamed_fields) => { let fields = unnamed_fields.unnamed.iter().enumerate().map( |(variant_field_index, variant_field)| { generate_field( variant_field, variant_field_index, &engine_crate_path, ReflectionFieldGenOptions { field_vis_override: None, include_byte_offset: false, }, ) }, ); quote! { Some(#engine_crate_path::reflection::EnumVariantFields::Unnamed { fields: &[#(#fields),*] }) } } }; quote! { #engine_crate_path::reflection::EnumVariant { name: #variant_name, fields: #fields } } }); let variant_lookup_match_arms = input.variants.iter().enumerate().map(|(index, variant)| { let variant_ident = &variant.ident; let pattern = match variant.fields { syn::Fields::Unit => quote! { Self::#variant_ident }, syn::Fields::Named(_) => quote! { Self::#variant_ident { .. } }, syn::Fields::Unnamed(_) => quote! { Self::#variant_ident(..) }, }; quote! { #pattern => &enum_reflection.variants[#index] } }); let is_unit_only = input .variants .iter() .all(|variant| matches!(variant.fields, syn::Fields::Unit)); quote! { unsafe impl #impl_generics #engine_crate_path::reflection::Reflection for #input_ident #type_generics #where_clause { const TYPE_REFLECTION: &#engine_crate_path::reflection::Type = &const { #engine_crate_path::reflection::Type::Enum( #engine_crate_path::reflection::Enum { variants: &[#(#variants),*], is_unit_only: #is_unit_only } ) }; } unsafe impl #impl_generics #engine_crate_path::reflection::EnumReflectionExt for #input_ident #type_generics #where_clause { fn get_variant_reflection(&self) -> &'static #engine_crate_path::reflection::EnumVariant { let enum_reflection = unsafe { ::TYPE_REFLECTION .as_enum() .unwrap_unchecked() }; match self { #(#variant_lookup_match_arms),* } } } } }