From 942df064017258a92eee1a14cd613c6aec983dc8 Mon Sep 17 00:00:00 2001 From: HampusM Date: Mon, 6 Apr 2026 18:50:04 +0200 Subject: feat(engine): make reflection of reflected struct fields optional --- engine-macros/src/lib.rs | 94 ++++++++++------------------- engine/src/reflection.rs | 43 ++++++++++--- engine/src/renderer/opengl/graphics_mesh.rs | 6 +- 3 files changed, 71 insertions(+), 72 deletions(-) diff --git a/engine-macros/src/lib.rs b/engine-macros/src/lib.rs index ad6c15f..b87acf8 100644 --- a/engine-macros/src/lib.rs +++ b/engine-macros/src/lib.rs @@ -2,19 +2,7 @@ use proc_macro::TokenStream; use quote::{ToTokens, format_ident, quote}; -use syn::punctuated::Punctuated; -use syn::{ - Item, - LitStr, - Path as SynPath, - PredicateType, - Token, - TraitBound, - TypeParamBound, - WhereClause, - WherePredicate, - parse, -}; +use syn::{Item, LitStr, Path as SynPath, parse}; macro_rules! syn_path { ($first_segment: ident $(::$segment: ident)*) => { @@ -57,29 +45,6 @@ pub fn reflection_derive(input: TokenStream) -> TokenStream let (impl_generics, type_generics, where_clause) = input.generics.split_for_impl(); - let mut where_clause = where_clause.cloned().unwrap_or_else(|| WhereClause { - where_token: ::default(), - predicates: Punctuated::new(), - }); - - where_clause - .predicates - .extend(input.fields.iter().map(|field| { - WherePredicate::Type(PredicateType { - lifetimes: None, - bounded_ty: field.ty.clone(), - colon_token: ::default(), - bounds: [TypeParamBound::Trait(TraitBound { - paren_token: None, - modifier: syn::TraitBoundModifier::None, - lifetimes: None, - path: engine_crate_path.join(syn_path!(reflection::With)), - })] - .into_iter() - .collect(), - }) - })); - let fields = input.fields.into_iter().enumerate().map(|(index, field)| { let field_ident = field.ident.unwrap_or_else(|| format_ident!("{index}")); @@ -98,10 +63,38 @@ pub fn reflection_derive(input: TokenStream) -> TokenStream byte_offset: std::mem::offset_of!(Self, #field_ident), type_id: std::any::TypeId::of::<#field_type>(), type_name: #field_type_name, - reflection: - #engine_crate_path::reflection::__private::get_type_reflection::< - #field_type - >() + get_reflection: #engine_crate_path::reflection::FnWithDebug::new(|| { + struct SpecializationTarget(std::marker::PhantomData); + + trait FieldHasReflection + { + fn field_reflection(&self) -> Option<&'static #engine_crate_path::reflection::Reflection>; + } + + trait FieldDoesNotHaveReflection + { + fn field_reflection(&self) -> Option<&'static #engine_crate_path::reflection::Reflection>; + } + + impl FieldDoesNotHaveReflection for &SpecializationTarget + { + fn field_reflection(&self) -> Option<&'static #engine_crate_path::reflection::Reflection> + { + None + } + } + + impl FieldHasReflection for SpecializationTarget + { + fn field_reflection(&self) -> Option<&'static #engine_crate_path::reflection::Reflection> + { + Some(Field::reflection()) + } + } + + (&SpecializationTarget::<#field_type>(std::marker::PhantomData)) + .field_reflection() + }) } } }); @@ -151,24 +144,3 @@ fn find_engine_crate_path() -> Option Some(syn_path!(engine)) } - -trait SynPathExt -{ - fn join(&self, other: Self) -> Self; -} - -impl SynPathExt for SynPath -{ - fn join(&self, other: Self) -> Self - { - Self { - leading_colon: self.leading_colon.clone(), - segments: self - .segments - .iter() - .chain(&other.segments) - .cloned() - .collect(), - } - } -} diff --git a/engine/src/reflection.rs b/engine/src/reflection.rs index 3ce424e..7c5ee5c 100644 --- a/engine/src/reflection.rs +++ b/engine/src/reflection.rs @@ -1,5 +1,6 @@ use std::alloc::Layout; use std::any::{TypeId, type_name}; +use std::fmt::Debug; pub use engine_macros::Reflection; @@ -50,7 +51,15 @@ pub struct StructField pub byte_offset: usize, pub type_id: TypeId, pub type_name: &'static str, - pub reflection: &'static Reflection, + pub get_reflection: FnWithDebug>, +} + +impl StructField +{ + pub fn reflection(&self) -> Option<&'static Reflection> + { + self.get_reflection.get() + } } #[derive(Debug, Clone)] @@ -157,14 +166,32 @@ impl With for &'static [T] } } -// Used by the Reflection derive macro -#[doc(hidden)] -pub mod __private +#[derive(Clone)] +pub struct FnWithDebug { - pub const fn get_type_reflection() -> &'static super::Reflection - where - T: super::With, + func: fn() -> Value, +} + +impl FnWithDebug +{ + pub const fn new(func: fn() -> Value) -> Self + { + Self { func } + } + + pub fn get(&self) -> Value + { + (self.func)() + } +} + +impl Debug for FnWithDebug +{ + fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - T::REFLECTION + formatter + .debug_tuple("FnWithDebug") + .field(&self.get()) + .finish() } } diff --git a/engine/src/renderer/opengl/graphics_mesh.rs b/engine/src/renderer/opengl/graphics_mesh.rs index 5d081c7..d62cd3e 100644 --- a/engine/src/renderer/opengl/graphics_mesh.rs +++ b/engine/src/renderer/opengl/graphics_mesh.rs @@ -105,8 +105,8 @@ impl GraphicsMesh vertex_arr.set_attrib_format( current_context, attrib_index, - match vertex_subset_field.reflection.reflection { - Reflection::Literal(_) => { + match vertex_subset_field.reflection.reflection() { + Some(Reflection::Literal(_)) => { if vertex_subset_field.reflection.type_id != TypeId::of::() { panic!("Unsupported vertex field data type"); } @@ -118,7 +118,7 @@ impl GraphicsMesh offset: vertex_subset_field.offset.try_into().unwrap(), } } - Reflection::Array(array_vertex_field) => { + Some(Reflection::Array(array_vertex_field)) => { let Reflection::Literal(array_vertex_field_item) = array_vertex_field.item_reflection else { -- cgit v1.2.3-18-g5258