summaryrefslogtreecommitdiff
path: root/engine/src/reflection.rs
diff options
context:
space:
mode:
Diffstat (limited to 'engine/src/reflection.rs')
-rw-r--r--engine/src/reflection.rs173
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()
+ }
+}