diff options
Diffstat (limited to 'engine/src/reflection.rs')
| -rw-r--r-- | engine/src/reflection.rs | 173 |
1 files changed, 173 insertions, 0 deletions
diff --git a/engine/src/reflection.rs b/engine/src/reflection.rs new file mode 100644 index 0000000..83bc636 --- /dev/null +++ b/engine/src/reflection.rs @@ -0,0 +1,173 @@ +use std::alloc::Layout; +use std::any::{TypeId, type_name}; +use std::fmt::Debug; + +pub use engine_macros::Reflection; + +/// 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 + } +} + +#[derive(Debug)] +#[non_exhaustive] +pub enum Type +{ + Struct(Struct), + 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, + } + } +} + +#[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<Option<&'static Type>>, +} + +impl StructField +{ + pub fn type_reflection(&self) -> Option<&'static Type> + { + self.get_type.get() + } +} + +#[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<T: Reflection, const LEN: usize> Reflection for [T; LEN] +{ + const TYPE_REFLECTION: &Type = &Type::Array(Array { + item_reflection: T::TYPE_REFLECTION, + length: LEN, + }); +} + +unsafe impl<T: Reflection> Reflection for &'static [T] +{ + const TYPE_REFLECTION: &Type = + &Type::Slice(Slice { item_reflection: T::TYPE_REFLECTION }); +} + +#[derive(Clone)] +pub struct FnWithDebug<Value> +{ + func: fn() -> Value, +} + +impl<Value> FnWithDebug<Value> +{ + pub const fn new(func: fn() -> Value) -> Self + { + Self { func } + } + + pub fn get(&self) -> Value + { + (self.func)() + } +} + +impl<Value: Debug> Debug for FnWithDebug<Value> +{ + fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result + { + formatter + .debug_tuple("FnWithDebug") + .field(&self.get()) + .finish() + } +} |
