use quote::quote; use crate::reflection::visibility::generate as generate_visibility; pub struct ReflectionFieldGenOptions<'a> { pub field_vis_override: Option, pub gen_get_byte_offset: &'a dyn Fn(&syn::Field) -> proc_macro2::TokenStream, pub type_reflection_optional: bool, } pub fn generate( field: &syn::Field, field_index: usize, engine_crate_path: &syn::Path, options: ReflectionFieldGenOptions<'_>, ) -> proc_macro2::TokenStream { let field_ident = &field.ident; let field_type = &field.ty; let field_name = if let Some(field_ident) = field_ident { let field_name = syn::LitStr::new(&field_ident.to_string(), field_ident.span()); quote! { Some(#field_name) } } else { quote! { None } }; let field_byte_offset = (options.gen_get_byte_offset)(field); let field_vis = options.field_vis_override.as_ref().unwrap_or(&field.vis); let field_reflection_vis = generate_visibility(field_vis, &engine_crate_path); let get_type_fn_body = if options.type_reflection_optional { gen_get_optional_type_reflection(field_type, engine_crate_path) } else { gen_get_mandatory_type_reflection(field_type, engine_crate_path) }; quote! { #engine_crate_path::reflection::Field { name: #field_name, index: #field_index, layout: std::alloc::Layout::new::<#field_type>(), byte_offset: #field_byte_offset, type_id: std::any::TypeId::of::<#field_type>(), get_type_name: #engine_crate_path::reflection::FnWithDebug::new(|| { std::any::type_name::<#field_type>() }), get_type: #engine_crate_path::reflection::FnWithDebug::new(|| { #get_type_fn_body }), visibility: #field_reflection_vis } } } fn gen_get_optional_type_reflection( field_type: &syn::Type, engine_crate_path: &syn::Path, ) -> proc_macro2::TokenStream { quote! { struct SpecializationTarget(std::marker::PhantomData); trait FieldHasReflection { fn field_type_reflection(&self) -> Option<&'static #engine_crate_path::reflection::Type>; } trait FieldDoesNotHaveReflection { fn field_type_reflection(&self) -> Option<&'static #engine_crate_path::reflection::Type>; } impl FieldDoesNotHaveReflection for &SpecializationTarget { fn field_type_reflection(&self) -> Option<&'static #engine_crate_path::reflection::Type> { None } } impl FieldHasReflection for SpecializationTarget where Field: #engine_crate_path::reflection::Reflection { fn field_type_reflection(&self) -> Option<&'static #engine_crate_path::reflection::Type> { Some(Field::type_reflection()) } } (&SpecializationTarget::<#field_type>(std::marker::PhantomData)) .field_type_reflection() } } fn gen_get_mandatory_type_reflection( field_type: &syn::Type, engine_crate_path: &syn::Path, ) -> proc_macro2::TokenStream { quote! { fn field_type_reflection() -> &'static #engine_crate_path::reflection::Type { T::type_reflection() } Some(field_type_reflection::<#field_type>()) } }