diff options
| author | HampusM <hampus@hampusmat.com> | 2026-07-08 00:42:44 +0200 |
|---|---|---|
| committer | HampusM <hampus@hampusmat.com> | 2026-07-08 00:42:44 +0200 |
| commit | 548cfe53130537dfee33d143e8a563879e30e1a2 (patch) | |
| tree | 584804acd078416cd6dac51a6278f8a9cc3a4903 | |
| parent | 28686c9359da2c2c46d12ae8aaada14ece17246f (diff) | |
feat(engine): add try_get_field_mut fn to enum variant reflection
| -rw-r--r-- | engine-macros/src/reflection/enum_impl.rs | 80 | ||||
| -rw-r--r-- | engine-reflection/src/lib.rs | 38 |
2 files changed, 116 insertions, 2 deletions
diff --git a/engine-macros/src/reflection/enum_impl.rs b/engine-macros/src/reflection/enum_impl.rs index 4e27c2b..b637d9f 100644 --- a/engine-macros/src/reflection/enum_impl.rs +++ b/engine-macros/src/reflection/enum_impl.rs @@ -273,6 +273,61 @@ fn generate_variants<'a>( } }; + let variant_ident = &variant.ident; + + let variant_pattern = match &variant.fields { + syn::Fields::Unit => quote! { Self::#variant_ident }, + syn::Fields::Named(syn::FieldsNamed { named: named_fields, .. }) => { + let field_idents = named_fields.iter().map(|field| { + let Some(field_ident) = &field.ident else { + unreachable!(); + }; + + field_ident + }); + + quote! { Self::#variant_ident { #(#field_idents),* } } + } + syn::Fields::Unnamed(syn::FieldsUnnamed { + unnamed: unnamed_fields, .. + }) => { + let field_idents = unnamed_fields + .iter() + .enumerate() + .map(|(field_index, _)| format_ident!("field_{field_index}")); + + quote! { Self::#variant_ident(#(#field_idents),*) } + } + }; + + let field_index_match_arms = match &variant.fields { + syn::Fields::Unit => quote! {}, + syn::Fields::Named(syn::FieldsNamed { named: named_fields, .. }) => { + let match_arms = + named_fields.iter().enumerate().map(|(field_index, field)| { + let Some(field_ident) = &field.ident else { + unreachable!(); + }; + + quote! { #field_index => { #field_ident } } + }); + + quote! { #(#match_arms)* } + } + syn::Fields::Unnamed(syn::FieldsUnnamed { + unnamed: unnamed_fields, .. + }) => { + let match_arms = + unnamed_fields.iter().enumerate().map(|(field_index, _)| { + let field_ident = format_ident!("field_{field_index}"); + + quote! { #field_index => { #field_ident } } + }); + + quote! { #(#match_arms)* } + } + }; + quote! { #engine_crate_path::reflection::EnumVariant { name: #variant_name, @@ -296,7 +351,30 @@ fn generate_variants<'a>( *dst = created; Ok(()) - } + }, + try_get_field_mut: |target, field_index| { { + #![allow(unreachable_code)] + + use std::any::Any; + use #engine_crate_path::reflection::EnumVariantGetFieldError; + + let target = target + .downcast_mut::<Self>() + .ok_or(EnumVariantGetFieldError::WrongTargetType)?; + + let #variant_pattern = target else { + return Err(EnumVariantGetFieldError::WrongTargetVariant); + }; + + let field: &mut dyn Any = match field_index { + #field_index_match_arms + _ => { + return Err(EnumVariantGetFieldError::FieldIndexOutOfBounds); + } + }; + + Ok(field) + } }, } } }) diff --git a/engine-reflection/src/lib.rs b/engine-reflection/src/lib.rs index a31fef0..79a7417 100644 --- a/engine-reflection/src/lib.rs +++ b/engine-reflection/src/lib.rs @@ -168,12 +168,17 @@ pub struct EnumVariant dst: &mut dyn Any, fields: &mut dyn Iterator<Item = Box<dyn Any>>, ) -> Result<(), EnumVariantWriteNewToError>, + + pub try_get_field_mut: fn( + target: &mut dyn Any, + field_index: usize, + ) -> Result<&mut dyn Any, EnumVariantGetFieldError>, } #[derive(Debug, thiserror::Error)] pub enum EnumVariantWriteNewToError { - #[error("Destination must be the same type as the variant's enum")] + #[error("Destination must have the same type as the variant's enum")] WrongDstType, #[error("Too few fields are specified")] @@ -186,6 +191,19 @@ pub enum EnumVariantWriteNewToError WrongFieldType, } +#[derive(Debug, thiserror::Error)] +pub enum EnumVariantGetFieldError +{ + #[error("Target is not the same type as the variant's enum")] + WrongTargetType, + + #[error("Target is not the correct variant")] + WrongTargetVariant, + + #[error("Field index is out of bounds")] + FieldIndexOutOfBounds, +} + #[derive(Debug, Clone)] pub enum EnumVariantFields { @@ -468,6 +486,21 @@ unsafe impl<T: Reflection> Reflection for Option<T> Ok(()) }, + try_get_field_mut: |target, field_index| { + if field_index != 0 { + return Err(EnumVariantGetFieldError::FieldIndexOutOfBounds); + } + + let target = target + .downcast_mut::<Self>() + .ok_or(EnumVariantGetFieldError::WrongTargetType)?; + + let Some(value_field) = target else { + return Err(EnumVariantGetFieldError::WrongTargetVariant); + }; + + Ok(value_field) + }, }, EnumVariant { name: "None", @@ -485,6 +518,9 @@ unsafe impl<T: Reflection> Reflection for Option<T> Ok(()) }, + try_get_field_mut: |_, _| { + Err(EnumVariantGetFieldError::FieldIndexOutOfBounds) + }, }, ], is_unit_only: false, |
