summaryrefslogtreecommitdiff
path: root/engine-macros/src/reflection/field.rs
diff options
context:
space:
mode:
Diffstat (limited to 'engine-macros/src/reflection/field.rs')
-rw-r--r--engine-macros/src/reflection/field.rs120
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>())
+ }
+}