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 [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>, pub visibility: Visibility, } 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)] #[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 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() } }