From c79f7883c099f1624f9666fb8691ffc5022c1bf5 Mon Sep 17 00:00:00 2001 From: HampusM Date: Tue, 16 Jun 2026 19:07:36 +0200 Subject: feat(engine): add default value retrieval to type reflection --- engine-macros/src/reflection.rs | 1 + engine-macros/src/reflection/default_value.rs | 42 +++++++++++++++ engine-macros/src/reflection/enum_impl.rs | 8 ++- engine-macros/src/reflection/struct_impl.rs | 8 ++- engine-reflection/src/lib.rs | 78 ++++++++++++++++++++++++++- 5 files changed, 133 insertions(+), 4 deletions(-) create mode 100644 engine-macros/src/reflection/default_value.rs diff --git a/engine-macros/src/reflection.rs b/engine-macros/src/reflection.rs index 825094b..5d40e0c 100644 --- a/engine-macros/src/reflection.rs +++ b/engine-macros/src/reflection.rs @@ -1,3 +1,4 @@ +mod default_value; mod enum_impl; mod field; mod struct_impl; diff --git a/engine-macros/src/reflection/default_value.rs b/engine-macros/src/reflection/default_value.rs new file mode 100644 index 0000000..567c3b1 --- /dev/null +++ b/engine-macros/src/reflection/default_value.rs @@ -0,0 +1,42 @@ +use quote::quote; + +pub fn gen_get_default_value_fn( + type_ident: &proc_macro2::Ident, + type_generics: &syn::TypeGenerics, +) -> proc_macro2::TokenStream +{ + quote! { + struct SpecializationTarget(std::marker::PhantomData); + + trait HasDefaultValue + { + fn default_value_fn(&self) -> Option Box>; + } + + trait NoDefaultValue + { + fn default_value_fn(&self) -> Option Box>; + } + + impl NoDefaultValue for &SpecializationTarget + { + fn default_value_fn(&self) -> Option Box> + { + None + } + } + + impl HasDefaultValue for SpecializationTarget + where + T: std::default::Default + 'static + { + fn default_value_fn(&self) -> Option Box> + { + Some(|| Box::new(T::default())) + } + } + + (&SpecializationTarget::<#type_ident #type_generics>(std::marker::PhantomData)) + .default_value_fn() + } +} diff --git a/engine-macros/src/reflection/enum_impl.rs b/engine-macros/src/reflection/enum_impl.rs index 14142bf..611da6d 100644 --- a/engine-macros/src/reflection/enum_impl.rs +++ b/engine-macros/src/reflection/enum_impl.rs @@ -1,5 +1,6 @@ use quote::{format_ident, quote, ToTokens}; +use crate::reflection::default_value::gen_get_default_value_fn; use crate::reflection::field::{generate as generate_field, ReflectionFieldGenOptions}; use crate::util::{find_engine_crate_path, syn_path, SynPathExt}; @@ -238,6 +239,8 @@ pub fn generate(input: syn::ItemEnum) -> proc_macro2::TokenStream } }; + let get_default_value_fn = gen_get_default_value_fn(&input_ident, &type_generics); + quote! { #[doc(hidden)] mod #mod_name { @@ -254,7 +257,10 @@ pub fn generate(input: syn::ItemEnum) -> proc_macro2::TokenStream variants: &[#(#variants),*], is_unit_only: #is_unit_only, discriminant_layout: #discriminant_layout, - fields_layout: #fields_layout + fields_layout: #fields_layout, + get_default_value: || { + #get_default_value_fn + } } ) }; diff --git a/engine-macros/src/reflection/struct_impl.rs b/engine-macros/src/reflection/struct_impl.rs index b1adea5..ce1086b 100644 --- a/engine-macros/src/reflection/struct_impl.rs +++ b/engine-macros/src/reflection/struct_impl.rs @@ -1,5 +1,6 @@ use quote::quote; +use crate::reflection::default_value::gen_get_default_value_fn; use crate::reflection::field::{generate as generate_field, ReflectionFieldGenOptions}; use crate::util::{find_engine_crate_path, syn_path, SynPathExt}; @@ -49,6 +50,8 @@ pub fn generate(input: syn::ItemStruct) -> proc_macro2::TokenStream ) }); + let get_default_value_fn = gen_get_default_value_fn(&input_ident, &type_generics); + quote! { unsafe impl #impl_generics #engine_crate_path::reflection::Reflection for #input_ident #type_generics #where_clause @@ -59,7 +62,10 @@ pub fn generate(input: syn::ItemStruct) -> proc_macro2::TokenStream #engine_crate_path::reflection::Struct { fields: &[ #(#fields),* - ] + ], + get_default_value: || { + #get_default_value_fn + } } ) }; diff --git a/engine-reflection/src/lib.rs b/engine-reflection/src/lib.rs index c8b0004..4e5e8d8 100644 --- a/engine-reflection/src/lib.rs +++ b/engine-reflection/src/lib.rs @@ -1,5 +1,5 @@ use std::alloc::Layout; -use std::any::{type_name, TypeId}; +use std::any::{type_name, Any, TypeId}; use std::borrow::Cow; use std::fmt::Debug; @@ -64,12 +64,50 @@ impl Type _ => None, } } + + #[inline] + pub fn default_value(&self) -> Option> + { + match self { + Self::Struct(struct_type) => struct_type.default_value(), + Self::Enum(enum_type) => enum_type.default_value(), + Self::Literal(literal_type) => literal_type.default_value(), + Self::Array(_) | Self::Slice(_) => None, + } + } + + #[inline] + pub fn has_default_value(&self) -> bool + { + match self { + Self::Struct(struct_type) => struct_type.has_default_value(), + Self::Enum(enum_type) => enum_type.has_default_value(), + Self::Literal(literal_type) => literal_type.has_default_value(), + Self::Array(_) | Self::Slice(_) => false, + } + } } #[derive(Debug, Clone)] pub struct Struct { pub fields: &'static [Field], + pub get_default_value: fn() -> Option, +} + +impl Struct +{ + #[inline] + pub fn default_value(&self) -> Option> + { + Some((self.get_default_value)()?()) + } + + #[inline] + pub fn has_default_value(&self) -> bool + { + (self.get_default_value)().is_some() + } } #[derive(Debug, Clone)] @@ -83,6 +121,23 @@ pub struct Enum pub discriminant_layout: Layout, pub fields_layout: Option, + + pub get_default_value: fn() -> Option, +} + +impl Enum +{ + #[inline] + pub fn default_value(&self) -> Option> + { + Some((self.get_default_value)()?()) + } + + #[inline] + pub fn has_default_value(&self) -> bool + { + (self.get_default_value)().is_some() + } } #[derive(Debug, Clone)] @@ -169,6 +224,22 @@ pub struct Literal pub type_id: TypeId, pub ty: LiteralType, pub type_name: fn() -> &'static str, + pub get_default_value: fn() -> Option, +} + +impl Literal +{ + #[inline] + pub fn default_value(&self) -> Option> + { + Some((self.get_default_value)()?()) + } + + #[inline] + pub fn has_default_value(&self) -> bool + { + (self.get_default_value)().is_some() + } } #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -219,7 +290,8 @@ macro_rules! impl_reflection_for_literals { layout: Layout::new::<$literal>(), type_id: TypeId::of::<$literal>(), ty: LiteralType::$literal_type, - type_name: || type_name::<$literal>() + type_name: || type_name::<$literal>(), + get_default_value: || Some(|| Box::new(Self::default())) }); } )* @@ -288,3 +360,5 @@ impl Debug for FnWithDebug .finish() } } + +type DefaultValueFn = fn() -> Box; -- cgit v1.2.3-18-g5258