summaryrefslogtreecommitdiff
path: root/engine-macros/src/reflection/enum_impl.rs
diff options
context:
space:
mode:
Diffstat (limited to 'engine-macros/src/reflection/enum_impl.rs')
-rw-r--r--engine-macros/src/reflection/enum_impl.rs125
1 files changed, 125 insertions, 0 deletions
diff --git a/engine-macros/src/reflection/enum_impl.rs b/engine-macros/src/reflection/enum_impl.rs
new file mode 100644
index 0000000..0d9ff8b
--- /dev/null
+++ b/engine-macros/src/reflection/enum_impl.rs
@@ -0,0 +1,125 @@
+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 {
+ <Self as #engine_crate_path::reflection::Reflection>::TYPE_REFLECTION
+ .as_enum()
+ .unwrap_unchecked()
+ };
+
+ match self {
+ #(#variant_lookup_match_arms),*
+ }
+ }
+ }
+ }
+}