diff options
Diffstat (limited to 'engine-reflection/src/lib.rs')
| -rw-r--r-- | engine-reflection/src/lib.rs | 290 |
1 files changed, 290 insertions, 0 deletions
diff --git a/engine-reflection/src/lib.rs b/engine-reflection/src/lib.rs new file mode 100644 index 0000000..c8b0004 --- /dev/null +++ b/engine-reflection/src/lib.rs @@ -0,0 +1,290 @@ +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. +/// +/// # 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 [Field], +} + +#[derive(Debug, Clone)] +pub struct Enum +{ + /// Enum variants in the same order as in the enum definition. + pub variants: &'static [EnumVariant], + + /// The enum only contains unit variants. + pub is_unit_only: bool, + + pub discriminant_layout: Layout, + pub fields_layout: Option<Layout>, +} + +#[derive(Debug, Clone)] +pub struct EnumVariant +{ + pub name: &'static str, + + /// The fields of this variant. If `None`, this variant is a unit variant. + pub fields: Option<EnumVariantFields>, + + pub discriminant: EnumDiscriminant, +} + +#[derive(Debug, Clone)] +pub enum EnumVariantFields +{ + Named + { + fields: &'static [Field] + }, + Unnamed + { + fields: &'static [Field] + }, +} + +/// The discriminant of a enum variant. +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct EnumDiscriminant +{ + /// This buffer is the size of a u128/i128 because they are the largest possible enum + /// discriminant representations. + pub buf: [u8; size_of::<u128>()], +} + +#[derive(Debug, Clone)] +pub struct Field +{ + pub name: Option<&'static str>, + pub index: usize, + pub layout: Layout, + + /// Byte offset to the field relative to the start of the type containing it. If the + /// type containing the field is a enum, this offset will include the enum tag + pub byte_offset: usize, + + pub type_id: TypeId, + pub get_type_name: FnWithDebug<&'static str>, + pub get_type: FnWithDebug<Option<&'static Type>>, + pub visibility: Visibility, +} + +impl Field +{ + pub fn type_name(&self) -> &'static str + { + self.get_type_name.get() + } + + 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)] +#[non_exhaustive] +pub struct Literal +{ + pub layout: Layout, + pub type_id: TypeId, + pub ty: LiteralType, + pub type_name: fn() -> &'static str, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[non_exhaustive] +pub enum LiteralType +{ + U8, + I8, + U16, + I16, + U32, + I32, + U64, + I64, + U128, + I128, + F32, + F64, + Usize, + Isize, + Bool, + 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)),*) => { + $( + unsafe impl Reflection for $literal + { + const TYPE_REFLECTION: &Type = &Type::Literal(Literal { + layout: Layout::new::<$literal>(), + type_id: TypeId::of::<$literal>(), + ty: LiteralType::$literal_type, + type_name: || type_name::<$literal>() + }); + } + )* + }; +} + +impl_reflection_for_literals!( + (U8, u8), + (I8, i8), + (U16, u16), + (I16, i16), + (U32, u32), + (I32, i32), + (U64, u64), + (I64, i64), + (U128, u128), + (I128, i128), + (F32, f32), + (F64, f64), + (Usize, usize), + (Isize, isize), + (Bool, bool), + (Str, &'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() + } +} |
