summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHampusM <hampus@hampusmat.com>2026-07-16 20:17:51 +0200
committerHampusM <hampus@hampusmat.com>2026-07-16 20:17:51 +0200
commit8dc188fbe6224155f6a48f8908402e98b169d0a6 (patch)
tree66a379450e9154c14d5c6ab56d520eddc8b9bc54
parent8a45d32a7e66f2fc2be641f272bbe214b42d2960 (diff)
feat(engine): add try_get_* fns to struct, array & slice reflection
-rw-r--r--engine-macros/src/reflection/enum_impl.rs8
-rw-r--r--engine-macros/src/reflection/struct_impl.rs72
-rw-r--r--engine-reflection/src/lib.rs51
3 files changed, 109 insertions, 22 deletions
diff --git a/engine-macros/src/reflection/enum_impl.rs b/engine-macros/src/reflection/enum_impl.rs
index b637d9f..37abc34 100644
--- a/engine-macros/src/reflection/enum_impl.rs
+++ b/engine-macros/src/reflection/enum_impl.rs
@@ -356,20 +356,20 @@ fn generate_variants<'a>(
#![allow(unreachable_code)]
use std::any::Any;
- use #engine_crate_path::reflection::EnumVariantGetFieldError;
+ use #engine_crate_path::reflection::GetError;
let target = target
.downcast_mut::<Self>()
- .ok_or(EnumVariantGetFieldError::WrongTargetType)?;
+ .ok_or(GetError::WrongTargetType)?;
let #variant_pattern = target else {
- return Err(EnumVariantGetFieldError::WrongTargetVariant);
+ return Err(GetError::WrongTargetEnumVariant);
};
let field: &mut dyn Any = match field_index {
#field_index_match_arms
_ => {
- return Err(EnumVariantGetFieldError::FieldIndexOutOfBounds);
+ return Err(GetError::IndexOutOfBounds);
}
};
diff --git a/engine-macros/src/reflection/struct_impl.rs b/engine-macros/src/reflection/struct_impl.rs
index 4fbf88b..8617874 100644
--- a/engine-macros/src/reflection/struct_impl.rs
+++ b/engine-macros/src/reflection/struct_impl.rs
@@ -1,4 +1,4 @@
-use quote::quote;
+use quote::{format_ident, quote};
use crate::reflection::default_value::gen_get_default_value_fn;
use crate::reflection::field::{generate as generate_field, ReflectionFieldGenOptions};
@@ -73,12 +73,64 @@ fn gen_impl(
}
});
+ let struct_pattern = match &input.fields {
+ syn::Fields::Unit => quote! { Self },
+ 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 { #(#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(#(#field_idents),*) }
+ }
+ };
+
+ let field_index_match_arms = match &input.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! {
unsafe impl #engine_crate_path::reflection::Reflection for
#input_ident #generic_args
{
const TYPE_REFLECTION: &#engine_crate_path::reflection::Type =
&const {
+ use std::any::Any;
+
+ use #engine_crate_path::reflection::GetError;
+
#(#generics_type_aliases)*
#engine_crate_path::reflection::Type::Struct(
@@ -89,7 +141,23 @@ fn gen_impl(
get_default_value: || {
#get_default_value_fn
},
- cast_dyn_any: |ptr| ptr.cast::<Self>()
+ cast_dyn_any: |ptr| ptr.cast::<Self>(),
+ try_get_field_mut: |target, field_index| {
+ let target = target
+ .downcast_mut::<Self>()
+ .ok_or(GetError::WrongTargetType)?;
+
+ let #struct_pattern = target;
+
+ let field: &mut dyn Any = match field_index {
+ #field_index_match_arms
+ _ => {
+ return Err(GetError::IndexOutOfBounds);
+ }
+ };
+
+ Ok(field)
+ },
}
)
};
diff --git a/engine-reflection/src/lib.rs b/engine-reflection/src/lib.rs
index 79a7417..4ef688c 100644
--- a/engine-reflection/src/lib.rs
+++ b/engine-reflection/src/lib.rs
@@ -109,6 +109,8 @@ pub struct Struct
pub fields: &'static [Field],
pub get_default_value: fn() -> Option<DefaultValueFn>,
pub cast_dyn_any: CastDynAnyFn,
+ pub try_get_field_mut:
+ fn(target: &mut dyn Any, field_index: usize) -> Result<&mut dyn Any, GetError>,
}
impl Struct
@@ -169,10 +171,8 @@ pub struct EnumVariant
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>,
+ pub try_get_field_mut:
+ fn(target: &mut dyn Any, field_index: usize) -> Result<&mut dyn Any, GetError>,
}
#[derive(Debug, thiserror::Error)]
@@ -192,16 +192,16 @@ pub enum EnumVariantWriteNewToError
}
#[derive(Debug, thiserror::Error)]
-pub enum EnumVariantGetFieldError
+pub enum GetError
{
- #[error("Target is not the same type as the variant's enum")]
+ #[error("Target is not the correct type")]
WrongTargetType,
- #[error("Target is not the correct variant")]
- WrongTargetVariant,
+ #[error("Target is not the correct enum variant")]
+ WrongTargetEnumVariant,
- #[error("Field index is out of bounds")]
- FieldIndexOutOfBounds,
+ #[error("Index is out of bounds")]
+ IndexOutOfBounds,
}
#[derive(Debug, Clone)]
@@ -288,6 +288,8 @@ pub struct Array
pub get_item_type_name: FnWithDebug<&'static str>,
pub length: usize,
pub cast_dyn_any: CastDynAnyFn,
+ pub try_get_item_mut:
+ fn(target: &mut dyn Any, index: usize) -> Result<&mut dyn Any, GetError>,
}
impl Array
@@ -304,6 +306,7 @@ pub struct Slice
pub item_type: &'static Type,
pub item_layout: Layout,
pub get_item_type_name: FnWithDebug<&'static str>,
+ pub try_get_item: fn(target: &dyn Any, index: usize) -> Result<&dyn Any, GetError>,
}
impl Slice
@@ -432,6 +435,15 @@ unsafe impl<T: Reflection, const LEN: usize> Reflection for [T; LEN]
get_item_type_name: FnWithDebug::new(|| type_name::<T>()),
length: LEN,
cast_dyn_any: |ptr| ptr.cast::<Self>(),
+ try_get_item_mut: |target, index| {
+ let target = target
+ .downcast_mut::<Self>()
+ .ok_or(GetError::WrongTargetType)?;
+
+ let item = target.get_mut(index).ok_or(GetError::IndexOutOfBounds)?;
+
+ Ok(item)
+ },
});
}
@@ -441,6 +453,15 @@ unsafe impl<T: Reflection> Reflection for &'static [T]
item_type: T::TYPE_REFLECTION,
item_layout: Layout::new::<T>(),
get_item_type_name: FnWithDebug::new(|| type_name::<T>()),
+ try_get_item: |target, index| {
+ let target = target
+ .downcast_ref::<Self>()
+ .ok_or(GetError::WrongTargetType)?;
+
+ let item = target.get(index).ok_or(GetError::IndexOutOfBounds)?;
+
+ Ok(item)
+ },
});
}
@@ -488,15 +509,15 @@ unsafe impl<T: Reflection> Reflection for Option<T>
},
try_get_field_mut: |target, field_index| {
if field_index != 0 {
- return Err(EnumVariantGetFieldError::FieldIndexOutOfBounds);
+ return Err(GetError::IndexOutOfBounds);
}
let target = target
.downcast_mut::<Self>()
- .ok_or(EnumVariantGetFieldError::WrongTargetType)?;
+ .ok_or(GetError::WrongTargetType)?;
let Some(value_field) = target else {
- return Err(EnumVariantGetFieldError::WrongTargetVariant);
+ return Err(GetError::WrongTargetEnumVariant);
};
Ok(value_field)
@@ -518,9 +539,7 @@ unsafe impl<T: Reflection> Reflection for Option<T>
Ok(())
},
- try_get_field_mut: |_, _| {
- Err(EnumVariantGetFieldError::FieldIndexOutOfBounds)
- },
+ try_get_field_mut: |_, _| Err(GetError::IndexOutOfBounds),
},
],
is_unit_only: false,