From 93274fa4d819e9037e2dc424ce2e1b82d4809280 Mon Sep 17 00:00:00 2001 From: HampusM Date: Sat, 6 Jun 2026 19:57:32 +0200 Subject: feat: add engine-reflection crate --- Cargo.lock | 4 + Cargo.toml | 1 + engine-reflection/Cargo.toml | 6 ++ engine-reflection/src/lib.rs | 203 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 214 insertions(+) create mode 100644 engine-reflection/Cargo.toml create mode 100644 engine-reflection/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 9ee8565..52504ce 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -701,6 +701,10 @@ dependencies = [ "syn 2.0.100", ] +[[package]] +name = "engine-reflection" +version = "0.1.0" + [[package]] name = "equivalent" version = "1.0.2" diff --git a/Cargo.toml b/Cargo.toml index ba5027d..dce43ca 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,7 @@ engine = { path = "engine" } engine-macros = { path = "engine-macros" } engine-ecs = { path = "engine-ecs" } engine-ecs-macros = { path = "engine-ecs-macros" } +engine-reflection = { path = "engine-reflection" } util-macros= { path = "util-macros" } opengl-bindings = { path = "opengl-bindings" } diff --git a/engine-reflection/Cargo.toml b/engine-reflection/Cargo.toml new file mode 100644 index 0000000..e2dacff --- /dev/null +++ b/engine-reflection/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "engine-reflection" +version = "0.1.0" +edition = "2024" + +[dependencies] diff --git a/engine-reflection/src/lib.rs b/engine-reflection/src/lib.rs new file mode 100644 index 0000000..5561c9a --- /dev/null +++ b/engine-reflection/src/lib.rs @@ -0,0 +1,203 @@ +use std::alloc::Layout; +use std::any::{type_name, TypeId}; +use std::fmt::Debug; + +/// Trait implemented by types that support runtime reflection on them. +/// +/// # Safety +/// Implementors of this trait must provide accurate reflection information in the +/// `TYPE_REFLECTION` associated constant and the `type_reflection` and +/// `get_type_reflection` methods. +pub unsafe trait Reflection: 'static +{ + const TYPE_REFLECTION: &Type; + + fn type_reflection() -> &'static Type + where + Self: Sized, + { + Self::TYPE_REFLECTION + } + + fn get_type_reflection(&self) -> &'static Type + { + Self::TYPE_REFLECTION + } +} + +/// Trait implemented by enums that support runtime reflection on them. +/// +/// # Safety +/// Implementors of this trait must provide accurate reflection information in the +/// `get_variant_reflection` method. +pub unsafe trait EnumReflectionExt: Reflection +{ + fn get_variant_reflection(&self) -> &'static EnumVariant; +} + +#[derive(Debug)] +#[non_exhaustive] +pub enum Type +{ + Struct(Struct), + Enum(Enum), + Array(Array), + Slice(Slice), + Literal(Literal), +} + +impl Type +{ + pub const fn as_struct(&self) -> Option<&Struct> + { + match self { + Self::Struct(struct_reflection) => Some(struct_reflection), + _ => None, + } + } + + pub const fn as_enum(&self) -> Option<&Enum> + { + match self { + Self::Enum(enum_reflection) => Some(enum_reflection), + _ => None, + } + } +} + +#[derive(Debug, Clone)] +pub struct Struct +{ + pub fields: &'static [StructField], +} + +#[derive(Debug, Clone)] +pub struct StructField +{ + pub name: &'static str, + pub index: usize, + pub layout: Layout, + pub byte_offset: usize, + pub type_id: TypeId, + pub type_name: &'static str, + pub get_type: FnWithDebug>, +} + +impl StructField +{ + pub fn type_reflection(&self) -> Option<&'static Type> + { + self.get_type.get() + } +} + +#[derive(Debug, Clone)] +pub struct Enum +{ + /// Enum variants in the same order as in the enum definition. + pub variants: &'static [EnumVariant], +} + +#[derive(Debug, Clone)] +pub struct EnumVariant +{ + pub name: &'static str, +} + +#[derive(Debug, Clone)] +pub struct Array +{ + pub item_reflection: &'static Type, + pub length: usize, +} + +#[derive(Debug, Clone)] +pub struct Slice +{ + pub item_reflection: &'static Type, +} + +#[derive(Debug)] +pub struct Literal +{ + pub layout: Layout, + pub type_id: TypeId, + pub type_name: fn() -> &'static str, +} + +macro_rules! impl_with_for_literals { + ($($literal: ty),*) => { + $( + unsafe impl Reflection for $literal + { + const TYPE_REFLECTION: &Type = &Type::Literal(Literal { + layout: Layout::new::<$literal>(), + type_id: TypeId::of::<$literal>(), + type_name: || type_name::<$literal>() + }); + } + )* + }; +} + +impl_with_for_literals!( + u8, + i8, + u16, + i16, + u32, + i32, + u64, + i64, + u128, + i128, + f32, + f64, + usize, + isize, + &'static str +); + +unsafe impl Reflection for [T; LEN] +{ + const TYPE_REFLECTION: &Type = &Type::Array(Array { + item_reflection: T::TYPE_REFLECTION, + length: LEN, + }); +} + +unsafe impl Reflection for &'static [T] +{ + const TYPE_REFLECTION: &Type = + &Type::Slice(Slice { item_reflection: T::TYPE_REFLECTION }); +} + +#[derive(Clone)] +pub struct FnWithDebug +{ + 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 + { + formatter + .debug_tuple("FnWithDebug") + .field(&self.get()) + .finish() + } +} -- cgit v1.2.3-18-g5258