use std::alloc::Layout; use std::any::{type_name, Any, TypeId}; use std::borrow::Cow; use std::ffi::c_void; 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), Reference(Reference), } 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, } } #[inline] pub fn default_value(&self) -> Option> { match self { Self::Struct(struct_type) => struct_type.default_value(), Self::Enum(enum_type) => enum_type.default_value(), Self::Literal(literal_type) => literal_type.default_value(), Self::Array(_) | Self::Slice(_) | Self::Reference(_) => None, } } #[inline] pub fn has_default_value(&self) -> bool { match self { Self::Struct(struct_type) => struct_type.has_default_value(), Self::Enum(enum_type) => enum_type.has_default_value(), Self::Literal(literal_type) => literal_type.has_default_value(), Self::Array(_) | Self::Slice(_) | Self::Reference(_) => false, } } #[inline] pub fn cast_dyn_any(&self, ptr: *mut c_void) -> Option<*mut dyn Any> { match self { Self::Struct(struct_type) => Some((struct_type.cast_dyn_any)(ptr)), Self::Enum(enum_type) => Some((enum_type.cast_dyn_any)(ptr)), Self::Literal(literal_type) => Some((literal_type.cast_dyn_any)(ptr)), Self::Array(array_type) => Some((array_type.cast_dyn_any)(ptr)), Self::Reference(ref_type) => Some((ref_type.cast_dyn_any)(ptr)), Self::Slice(_) => None, } } } #[derive(Debug, Clone)] pub struct Struct { pub fields: &'static [Field], pub get_default_value: fn() -> Option, pub cast_dyn_any: CastDynAnyFn, } impl Struct { #[inline] pub fn default_value(&self) -> Option> { Some((self.get_default_value)()?()) } #[inline] pub fn has_default_value(&self) -> bool { (self.get_default_value)().is_some() } } #[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 get_default_value: fn() -> Option, pub cast_dyn_any: CastDynAnyFn, pub get_variant_index: fn(&dyn Any) -> Option, } impl Enum { #[inline] pub fn default_value(&self) -> Option> { Some((self.get_default_value)()?()) } #[inline] pub fn has_default_value(&self) -> bool { (self.get_default_value)().is_some() } } #[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, pub try_write_new_to: fn( dst: &mut dyn Any, fields: &mut dyn Iterator>, ) -> Result<(), EnumVariantWriteNewToError>, pub try_get_field_mut: fn( target: &mut dyn Any, field_index: usize, ) -> Result<&mut dyn Any, EnumVariantGetFieldError>, } #[derive(Debug, thiserror::Error)] pub enum EnumVariantWriteNewToError { #[error("Destination must have the same type as the variant's enum")] WrongDstType, #[error("Too few fields are specified")] TooFewFields, #[error("Too many fields are specified")] TooManyFields, #[error("A field has the wrong type")] WrongFieldType, } #[derive(Debug, thiserror::Error)] pub enum EnumVariantGetFieldError { #[error("Target is not the same type as the variant's enum")] WrongTargetType, #[error("Target is not the correct variant")] WrongTargetVariant, #[error("Field index is out of bounds")] FieldIndexOutOfBounds, } #[derive(Debug, Clone)] pub enum EnumVariantFields { Named { fields: &'static [EnumVariantField] }, Unnamed { fields: &'static [EnumVariantField] }, } impl EnumVariantFields { pub fn fields(&self) -> &'static [EnumVariantField] { match self { Self::Named { fields } => fields, Self::Unnamed { fields } => fields, } } } #[derive(Debug, Clone)] pub struct EnumVariantField { pub name: Option<&'static str>, pub index: usize, pub type_id: TypeId, pub get_type_name: FnWithDebug<&'static str>, pub get_type: FnWithDebug>, } impl EnumVariantField { 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 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. pub byte_offset: usize, pub type_id: TypeId, pub get_type_name: FnWithDebug<&'static str>, pub get_type: FnWithDebug>, 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_type: &'static Type, pub item_layout: Layout, pub get_item_type_name: FnWithDebug<&'static str>, pub length: usize, pub cast_dyn_any: CastDynAnyFn, } impl Array { pub fn item_type_name(&self) -> &'static str { self.get_item_type_name.get() } } #[derive(Debug, Clone)] pub struct Slice { pub item_type: &'static Type, pub item_layout: Layout, pub get_item_type_name: FnWithDebug<&'static str>, } impl Slice { pub fn item_type_name(&self) -> &'static str { self.get_item_type_name.get() } } #[derive(Debug)] #[non_exhaustive] pub struct Literal { pub layout: Layout, pub type_id: TypeId, pub ty: LiteralType, pub type_name: fn() -> &'static str, pub get_default_value: fn() -> Option, pub cast_dyn_any: CastDynAnyFn, } impl Literal { #[inline] pub fn default_value(&self) -> Option> { Some((self.get_default_value)()?()) } #[inline] pub fn has_default_value(&self) -> bool { (self.get_default_value)().is_some() } } #[derive(Debug)] pub struct Reference { pub ty: &'static Type, pub cast_dyn_any: CastDynAnyFn, } #[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>(), get_default_value: || Some(|| Box::new(Self::default())), cast_dyn_any: |ptr| ptr.cast::() }); } )* }; } 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_type: T::TYPE_REFLECTION, item_layout: Layout::new::(), get_item_type_name: FnWithDebug::new(|| type_name::()), length: LEN, cast_dyn_any: |ptr| ptr.cast::(), }); } unsafe impl Reflection for &'static [T] { const TYPE_REFLECTION: &Type = &Type::Slice(Slice { item_type: T::TYPE_REFLECTION, item_layout: Layout::new::(), get_item_type_name: FnWithDebug::new(|| type_name::()), }); } unsafe impl Reflection for &'static T { const TYPE_REFLECTION: &Type = &Type::Reference(Reference { ty: T::TYPE_REFLECTION, cast_dyn_any: |ptr| ptr.cast::(), }); } unsafe impl Reflection for Option { const TYPE_REFLECTION: &Type = &Type::Enum(Enum { variants: &[ EnumVariant { name: "Some", fields: Some(EnumVariantFields::Unnamed { fields: &[EnumVariantField { name: None, index: 0, type_id: TypeId::of::(), get_type_name: FnWithDebug::new(|| type_name::()), get_type: FnWithDebug::new(|| Some(T::type_reflection())), }], }), try_write_new_to: |dst, fields| { let dst = dst .downcast_mut::() .ok_or(EnumVariantWriteNewToError::WrongDstType)?; let value_field = fields .next() .ok_or(EnumVariantWriteNewToError::TooFewFields)? .downcast::() .map_err(|_| EnumVariantWriteNewToError::WrongFieldType)?; if fields.next().is_some() { return Err(EnumVariantWriteNewToError::TooManyFields); } *dst = Some(*value_field); Ok(()) }, try_get_field_mut: |target, field_index| { if field_index != 0 { return Err(EnumVariantGetFieldError::FieldIndexOutOfBounds); } let target = target .downcast_mut::() .ok_or(EnumVariantGetFieldError::WrongTargetType)?; let Some(value_field) = target else { return Err(EnumVariantGetFieldError::WrongTargetVariant); }; Ok(value_field) }, }, EnumVariant { name: "None", fields: None, try_write_new_to: |dst, fields| { let dst = dst .downcast_mut::() .ok_or(EnumVariantWriteNewToError::WrongDstType)?; if fields.next().is_some() { return Err(EnumVariantWriteNewToError::TooManyFields); } *dst = None; Ok(()) }, try_get_field_mut: |_, _| { Err(EnumVariantGetFieldError::FieldIndexOutOfBounds) }, }, ], is_unit_only: false, get_default_value: || Some(|| Box::new(Option::::None)), cast_dyn_any: |ptr| ptr.cast::(), get_variant_index: |target| { let target = target.downcast_ref::()?; Some(match target { Some(_) => 0, None => 1, }) }, }); } unsafe impl EnumReflectionExt for Option { fn get_variant_reflection(&self) -> &'static EnumVariant { let ty = unsafe { Self::type_reflection().as_enum().unwrap_unchecked() }; match self { Some(_) => &ty.variants[0], None => &ty.variants[1], } } } #[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() } } type DefaultValueFn = fn() -> Box; type CastDynAnyFn = fn(*mut c_void) -> *mut dyn Any;