diff options
| author | HampusM <hampus@hampusmat.com> | 2026-06-08 15:11:16 +0200 |
|---|---|---|
| committer | HampusM <hampus@hampusmat.com> | 2026-06-08 15:11:16 +0200 |
| commit | 02b258ae1eefbcc613afbd9fab0f195401a00b35 (patch) | |
| tree | 18b413e8575923b807155aa3477bd2155b08319f | |
| parent | ca33e594edea5e17ec26c760f92804b4e7f653a7 (diff) | |
feat(engine): add visibility reflection
| -rw-r--r-- | engine-macros/src/lib.rs | 81 | ||||
| -rw-r--r-- | engine-reflection/src/lib.rs | 19 |
2 files changed, 98 insertions, 2 deletions
diff --git a/engine-macros/src/lib.rs b/engine-macros/src/lib.rs index 9fe92e5..e7b3772 100644 --- a/engine-macros/src/lib.rs +++ b/engine-macros/src/lib.rs @@ -1,8 +1,19 @@ #![deny(clippy::all, clippy::pedantic)] +use std::fmt::Write; + use proc_macro::TokenStream; use quote::{format_ident, quote, ToTokens}; -use syn::{parse, Fields, Item, ItemEnum, ItemStruct, LitStr, Path as SynPath}; +use syn::{ + parse, + Fields, + Item, + ItemEnum, + ItemStruct, + LitStr, + Path as SynPath, + Visibility as SynVisibility, +}; macro_rules! syn_path { ($first_segment: ident $(::$segment: ident)*) => { @@ -58,6 +69,8 @@ fn generate_struct_reflection_impl(input: ItemStruct) -> TokenStream // since std::any::type_name as const is not stable yet let field_type_name = field_type.to_token_stream().to_string(); + let field_vis = gen_reflection_visibility_path(&field.vis, &engine_crate_path); + quote! { #engine_crate_path::reflection::StructField { name: #field_name, @@ -103,7 +116,8 @@ fn generate_struct_reflection_impl(input: ItemStruct) -> TokenStream (&SpecializationTarget::<#field_type>(std::marker::PhantomData)) .field_type_reflection() - }) + }), + visibility: #field_vis } } }); @@ -197,6 +211,48 @@ fn generate_enum_reflection_impl(input: ItemEnum) -> TokenStream .into() } +fn gen_reflection_visibility_path( + visibility: &SynVisibility, + engine_crate_path: &SynPath, +) -> proc_macro2::TokenStream +{ + match visibility { + SynVisibility::Public(_) => { + quote! { #engine_crate_path::reflection::Visibility::Pub } + } + SynVisibility::Restricted(vis_restricted) => { + let vis_scope = if vis_restricted.in_token.is_some() { + let in_path = syn_path_to_string(&vis_restricted.path); + + quote! { + #engine_crate_path::reflection::VisibilityScope::In( + std::borrow::Cow::Borrowed(#in_path) + ) + } + } else { + let Some(scope) = vis_restricted.path.get_ident() else { + unreachable!(); + }; + + if scope == "crate" { + quote! { #engine_crate_path::reflection::VisibilityScope::Crate } + } else if scope == "super" { + quote! { #engine_crate_path::reflection::VisibilityScope::Super } + } else if scope == "self" { + quote! { #engine_crate_path::reflection::VisibilityScope::SelfModule } + } else { + unreachable!(); + } + }; + + quote! { #engine_crate_path::reflection::Visibility::PubScoped(#vis_scope) } + } + SynVisibility::Inherited => { + quote! { #engine_crate_path::reflection::Visibility::Private } + } + } +} + fn find_engine_crate_path() -> Option<SynPath> { let cargo_crate_name = std::env::var("CARGO_CRATE_NAME").ok()?; @@ -213,3 +269,24 @@ fn find_engine_crate_path() -> Option<SynPath> Some(syn_path!(engine)) } + +fn syn_path_to_string(path: &syn::Path) -> String +{ + let mut output = String::with_capacity(2 + path.segments.len() * 8); + + if let Some(leading_colon) = path.leading_colon { + write!(output, "{}", leading_colon.to_token_stream()).unwrap(); + } + + for (segment, punct) in path.segments.pairs().map(syn::punctuated::Pair::into_tuple) { + let segment_ident = &segment.ident; + + write!(output, "{segment_ident}",).unwrap(); + + if let Some(punct) = punct { + write!(output, "{}", punct.to_token_stream()).unwrap(); + } + } + + output +} diff --git a/engine-reflection/src/lib.rs b/engine-reflection/src/lib.rs index 5122cca..ef705a0 100644 --- a/engine-reflection/src/lib.rs +++ b/engine-reflection/src/lib.rs @@ -1,5 +1,6 @@ use std::alloc::Layout; use std::any::{type_name, TypeId}; +use std::borrow::Cow; use std::fmt::Debug; /// Trait implemented by types that support runtime reflection on them. @@ -81,6 +82,7 @@ pub struct StructField pub type_id: TypeId, pub type_name: &'static str, pub get_type: FnWithDebug<Option<&'static Type>>, + pub visibility: Visibility, } impl StructField @@ -149,6 +151,23 @@ pub enum LiteralType Str, } +#[derive(Debug, Clone)] +pub enum Visibility +{ + Pub, + PubScoped(VisibilityScope), + Private, +} + +#[derive(Debug, Clone)] +pub enum VisibilityScope +{ + Crate, + Super, + SelfModule, + In(Cow<'static, str>), +} + macro_rules! impl_reflection_for_literals { ($(($literal_type: ident, $literal: ty)),*) => { $( |
