summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock3
-rw-r--r--engine-macros/src/reflection/enum_impl.rs90
-rw-r--r--engine-reflection/Cargo.toml2
-rw-r--r--engine-reflection/src/lib.rs21
4 files changed, 116 insertions, 0 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 23c697c..c806536 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -664,6 +664,9 @@ dependencies = [
[[package]]
name = "engine-reflection"
version = "0.1.0"
+dependencies = [
+ "thiserror 1.0.69",
+]
[[package]]
name = "equivalent"
diff --git a/engine-macros/src/reflection/enum_impl.rs b/engine-macros/src/reflection/enum_impl.rs
index ea83681..baf1732 100644
--- a/engine-macros/src/reflection/enum_impl.rs
+++ b/engine-macros/src/reflection/enum_impl.rs
@@ -331,12 +331,102 @@ fn generate_variants<'a>(
}
};
+ let variant_field_vars = variant.fields.iter().enumerate().map(
+ |(variant_field_index, variant_field)| {
+ let var_ident = match variant_field.ident.as_ref() {
+ Some(field_ident) => format_ident!("field_{field_ident}"),
+ None => format_ident!("field_{}", variant_field_index),
+ };
+
+ let field_type = &variant_field.ty;
+
+ quote! {
+ let #var_ident = fields
+ .next()
+ .ok_or(EnumVariantWriteNewToError::TooFewFields)?
+ .downcast::<#field_type>()
+ .map_err(|_| EnumVariantWriteNewToError::WrongFieldType)?;
+ }
+ },
+ );
+
+ let variant_construction =
+ match &variant.fields {
+ syn::Fields::Unit => {
+ let variant_ident = &variant.ident;
+
+ quote! {
+ Self::#variant_ident
+ }
+ }
+ syn::Fields::Named(named_fields) => {
+ let variant_ident = &variant.ident;
+
+ let fields = named_fields.named.iter().map(|field| {
+ let Some(field_ident) = field.ident.as_ref() else {
+ unreachable!();
+ };
+
+ let field_var_ident = format_ident!("field_{field_ident}");
+
+ quote! {
+ #field_ident: *#field_var_ident
+ }
+ });
+
+ quote! {
+ Self::#variant_ident {
+ #(#fields),*
+ }
+ }
+ }
+ syn::Fields::Unnamed(unnamed_fields) => {
+ let variant_ident = &variant.ident;
+
+ let fields = unnamed_fields.unnamed.iter().enumerate().map(
+ |(field_index, _)| {
+ let field_var_ident = format_ident!("field_{field_index}");
+
+ quote! {
+ *#field_var_ident
+ }
+ },
+ );
+
+ quote! {
+ Self::#variant_ident(
+ #(#fields),*
+ )
+ }
+ }
+ };
+
quote! {
#engine_crate_path::reflection::EnumVariant {
name: #variant_name,
fields: #fields,
discriminant: #engine_crate_path::reflection::EnumDiscriminant {
buf: { #discriminant }
+ },
+ try_write_new_to: |dst, fields| {
+ use std::any::Any;
+ use #engine_crate_path::reflection::EnumVariantWriteNewToError;
+
+ let dst = dst
+ .downcast_mut()
+ .ok_or(EnumVariantWriteNewToError::WrongDstType)?;
+
+ #(#variant_field_vars)*;
+
+ let created = #variant_construction;
+
+ if fields.next().is_some() {
+ return Err(EnumVariantWriteNewToError::TooManyFields);
+ }
+
+ *dst = created;
+
+ Ok(())
}
}
}
diff --git a/engine-reflection/Cargo.toml b/engine-reflection/Cargo.toml
index 8e13728..2f90841 100644
--- a/engine-reflection/Cargo.toml
+++ b/engine-reflection/Cargo.toml
@@ -4,3 +4,5 @@ version = "0.1.0"
edition = "2021"
[dependencies]
+thiserror = "1.0.49"
+
diff --git a/engine-reflection/src/lib.rs b/engine-reflection/src/lib.rs
index 9f347fa..3451442 100644
--- a/engine-reflection/src/lib.rs
+++ b/engine-reflection/src/lib.rs
@@ -177,6 +177,27 @@ pub struct EnumVariant
pub fields: Option<EnumVariantFields>,
pub discriminant: EnumDiscriminant,
+
+ pub try_write_new_to: fn(
+ dst: &mut dyn Any,
+ fields: &mut dyn Iterator<Item = Box<dyn Any>>,
+ ) -> Result<(), EnumVariantWriteNewToError>,
+}
+
+#[derive(Debug, thiserror::Error)]
+pub enum EnumVariantWriteNewToError
+{
+ #[error("Destination must be the same type as the variant's enum")]
+ WrongDstType,
+
+ #[error("Too few fields are specified")]
+ TooFewFields,
+
+ #[error("Too many fields are specified")]
+ TooManyFields,
+
+ #[error("A field has the wrong type")]
+ WrongFieldType,
}
#[derive(Debug, Clone)]