diff options
Diffstat (limited to 'engine-macros/src/reflection/field.rs')
| -rw-r--r-- | engine-macros/src/reflection/field.rs | 120 |
1 files changed, 120 insertions, 0 deletions
diff --git a/engine-macros/src/reflection/field.rs b/engine-macros/src/reflection/field.rs new file mode 100644 index 0000000..95671c3 --- /dev/null +++ b/engine-macros/src/reflection/field.rs @@ -0,0 +1,120 @@ +use quote::quote; + +use crate::reflection::visibility::generate as generate_visibility; + +pub struct ReflectionFieldGenOptions<'a> +{ + pub field_vis_override: Option<syn::Visibility>, + 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<Field>(std::marker::PhantomData<Field>); + + 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<Field> FieldDoesNotHaveReflection for &SpecializationTarget<Field> + { + fn field_type_reflection(&self) + -> Option<&'static #engine_crate_path::reflection::Type> + { + None + } + } + + impl<Field> FieldHasReflection for SpecializationTarget<Field> + 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<T: #engine_crate_path::reflection::Reflection>() + -> &'static #engine_crate_path::reflection::Type + { + T::type_reflection() + } + + Some(field_type_reflection::<#field_type>()) + } +} |
