summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engine-macros/src/lib.rs231
-rw-r--r--engine-reflection/src/lib.rs53
2 files changed, 201 insertions, 83 deletions
diff --git a/engine-macros/src/lib.rs b/engine-macros/src/lib.rs
index e7b3772..3eecab3 100644
--- a/engine-macros/src/lib.rs
+++ b/engine-macros/src/lib.rs
@@ -3,9 +3,10 @@
use std::fmt::Write;
use proc_macro::TokenStream;
-use quote::{format_ident, quote, ToTokens};
+use quote::{quote, ToTokens};
use syn::{
parse,
+ Field as SynField,
Fields,
Item,
ItemEnum,
@@ -59,68 +60,21 @@ fn generate_struct_reflection_impl(input: ItemStruct) -> TokenStream
let (impl_generics, type_generics, where_clause) = input.generics.split_for_impl();
- let fields = input.fields.into_iter().enumerate().map(|(index, field)| {
- let field_ident = field.ident.unwrap_or_else(|| format_ident!("{index}"));
-
- let field_type = &field.ty;
-
- let field_name = LitStr::new(&field_ident.to_string(), field_ident.span());
-
- // since std::any::type_name as const is not stable yet
- let field_type_name = field_type.to_token_stream().to_string();
-
- let field_vis = gen_reflection_visibility_path(&field.vis, &engine_crate_path);
-
- quote! {
- #engine_crate_path::reflection::StructField {
- name: #field_name,
- index: #index,
- layout: std::alloc::Layout::new::<#field_type>(),
- byte_offset: std::mem::offset_of!(Self, #field_ident),
- type_id: std::any::TypeId::of::<#field_type>(),
- type_name: #field_type_name,
- get_type: #engine_crate_path::reflection::FnWithDebug::new(|| {
- 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()
- }),
- visibility: #field_vis
- }
- }
- });
+ let fields = input
+ .fields
+ .into_iter()
+ .enumerate()
+ .map(|(field_index, field)| {
+ gen_reflection_field(
+ &field,
+ field_index,
+ &engine_crate_path,
+ ReflectionFieldGenOptions {
+ field_vis_override: None,
+ include_byte_offset: true,
+ },
+ )
+ });
quote! {
unsafe impl #impl_generics #engine_crate_path::reflection::Reflection for
@@ -152,9 +106,56 @@ fn generate_enum_reflection_impl(input: ItemEnum) -> TokenStream
let variants = input.variants.iter().map(|variant| {
let variant_name = LitStr::new(&variant.ident.to_string(), variant.ident.span());
+ let fields = match &variant.fields {
+ Fields::Unit => quote! { None },
+ Fields::Named(named_fields) => {
+ let fields = named_fields.named.iter().enumerate().map(
+ |(variant_field_index, variant_field)| {
+ gen_reflection_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),*]
+ })
+ }
+ }
+ Fields::Unnamed(unnamed_fields) => {
+ let fields = unnamed_fields.unnamed.iter().enumerate().map(
+ |(variant_field_index, variant_field)| {
+ gen_reflection_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
}
}
});
@@ -174,6 +175,11 @@ fn generate_enum_reflection_impl(input: ItemEnum) -> TokenStream
}
});
+ let is_unit_only = input
+ .variants
+ .iter()
+ .all(|variant| matches!(variant.fields, Fields::Unit));
+
quote! {
unsafe impl #impl_generics #engine_crate_path::reflection::Reflection for
#input_ident #type_generics #where_clause
@@ -182,9 +188,8 @@ fn generate_enum_reflection_impl(input: ItemEnum) -> TokenStream
&const {
#engine_crate_path::reflection::Type::Enum(
#engine_crate_path::reflection::Enum {
- variants: &[
- #(#variants),*
- ]
+ variants: &[#(#variants),*],
+ is_unit_only: #is_unit_only
}
)
};
@@ -211,6 +216,100 @@ fn generate_enum_reflection_impl(input: ItemEnum) -> TokenStream
.into()
}
+struct ReflectionFieldGenOptions
+{
+ field_vis_override: Option<SynVisibility>,
+ include_byte_offset: bool,
+}
+
+fn gen_reflection_field(
+ field: &SynField,
+ field_index: usize,
+ engine_crate_path: &SynPath,
+ 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 = LitStr::new(&field_ident.to_string(), field_ident.span());
+
+ quote! { Some(#field_name) }
+ } else {
+ quote! { None }
+ };
+
+ let field_byte_offset = if options.include_byte_offset {
+ if let Some(field_ident) = field_ident {
+ quote! { Some(std::mem::offset_of!(Self, #field_ident)) }
+ } else {
+ quote! { Some(std::mem::offset_of!(Self, #field_index)) }
+ }
+ } else {
+ quote! { None }
+ };
+
+ // since std::any::type_name as const is not stable yet
+ let field_type_name = field_type.to_token_stream().to_string();
+
+ let field_vis = options.field_vis_override.as_ref().unwrap_or(&field.vis);
+
+ let field_reflection_vis =
+ gen_reflection_visibility_path(field_vis, &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>(),
+ type_name: #field_type_name,
+ get_type: #engine_crate_path::reflection::FnWithDebug::new(|| {
+ 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()
+ }),
+ visibility: #field_reflection_vis
+ }
+ }
+}
+
fn gen_reflection_visibility_path(
visibility: &SynVisibility,
engine_crate_path: &SynPath,
diff --git a/engine-reflection/src/lib.rs b/engine-reflection/src/lib.rs
index ef705a0..53aa953 100644
--- a/engine-reflection/src/lib.rs
+++ b/engine-reflection/src/lib.rs
@@ -69,23 +69,55 @@ impl Type
#[derive(Debug, Clone)]
pub struct Struct
{
- pub fields: &'static [StructField],
+ pub fields: &'static [Field],
}
#[derive(Debug, Clone)]
-pub struct StructField
+pub struct Enum
+{
+ /// Enum variants in the same order as in the enum definition.
+ pub variants: &'static [EnumVariant],
+
+ /// The enum only contains unit variants.
+ pub is_unit_only: bool,
+}
+
+#[derive(Debug, Clone)]
+pub struct EnumVariant
{
pub name: &'static str,
+
+ /// The fields of this variant. If `None`, this variant is a unit variant.
+ pub fields: Option<EnumVariantFields>,
+}
+
+#[derive(Debug, Clone)]
+pub enum EnumVariantFields
+{
+ Named
+ {
+ fields: &'static [Field]
+ },
+ Unnamed
+ {
+ fields: &'static [Field]
+ },
+}
+
+#[derive(Debug, Clone)]
+pub struct Field
+{
+ pub name: Option<&'static str>,
pub index: usize,
pub layout: Layout,
- pub byte_offset: usize,
+ pub byte_offset: Option<usize>,
pub type_id: TypeId,
pub type_name: &'static str,
pub get_type: FnWithDebug<Option<&'static Type>>,
pub visibility: Visibility,
}
-impl StructField
+impl Field
{
pub fn type_reflection(&self) -> Option<&'static Type>
{
@@ -94,19 +126,6 @@ impl StructField
}
#[derive(Debug, Clone)]
-pub struct Enum
-{
- /// Enum variants in the same order as in the enum definition.
- pub variants: &'static [EnumVariant],
-}
-
-#[derive(Debug, Clone)]
-pub struct EnumVariant
-{
- pub name: &'static str,
-}
-
-#[derive(Debug, Clone)]
pub struct Array
{
pub item_reflection: &'static Type,