#![feature(trait_upcasting)] use std::{any::TypeId, any::Any, cell::{Ref, RefMut}}; use lyra_ecs::{AtomicRef, AtomicRefMut, World}; extern crate self as lyra_reflect; pub use lyra_reflect_derive::*; #[allow(unused_imports)] pub(crate) mod lyra_engine { pub(crate) mod reflect { pub use super::super::*; } } pub mod reflected_struct; pub use reflected_struct::*; pub mod reflected_enum; pub use reflected_enum::*; pub mod reflected_tuple; pub use reflected_tuple::*; pub mod reflected_array; pub use reflected_array::*; pub mod reflected_list; pub use reflected_list::*; pub mod dynamic_tuple; pub use dynamic_tuple::*; pub mod reflected_hashmap; pub use reflected_hashmap::*; pub mod component; pub use component::*; pub mod resource; pub use resource::*; pub mod util; pub mod field; pub use field::*; pub mod method; pub use method::*; pub mod registry; pub use registry::*; pub mod impls; pub trait Reflect: Any { fn name(&self) -> String; fn type_id(&self) -> TypeId; fn as_any(&self) -> &dyn Any; fn as_any_mut(&mut self) -> &mut dyn Any; fn as_boxed_any(self: Box) -> Box; /// Apply a value to this object. /// /// # Panics /// /// The method panics if /// * the type of `val` is not the same type as `self` // TODO: instead of taking as reference, it would make more sense to take a Box. fn apply(&mut self, val: &dyn Reflect); /// Clone self into a [`Box`] fn clone_inner(&self) -> Box; /// Returns a reflected reference of the value of `self` fn reflect_ref(&self) -> ReflectRef; /// Returns a reflected mutable reference of the value of `self` fn reflect_mut(&mut self) -> ReflectMut; fn reflect_val(&self) -> &dyn Reflect; fn reflect_val_mut(&mut self) -> &mut dyn Reflect; /// Returns a boolean indicating if this reflected object is `other_typeid` /// /// I can't use a generic here because this trait needs to be object safe fn is(&self, other_typeid: TypeId) -> bool { TypeId::of::() == other_typeid } } pub enum ReflectRef<'a> { Struct(&'a dyn Struct), Enum(&'a dyn Enum), Tuple(&'a dyn Tuple), Array(&'a dyn Array), List(&'a dyn List), Value(&'a dyn Reflect), Map(&'a dyn ReflectedMap), } impl<'a> ReflectRef<'a> { /// Gets the reflected reference as a struct. /// /// # Safety /// * If `self` is not a `Struct` variant, this will panic pub fn as_struct(&self) -> &dyn Struct { match self { ReflectRef::Struct(s) => *s, _ => panic!("`self` is not a struct variant!"), } } } pub enum ReflectMut<'a> { Struct(&'a mut dyn Struct), Enum(&'a mut dyn Enum), Tuple(&'a mut dyn Tuple), Array(&'a mut dyn Array), List(&'a mut dyn List), Value(&'a mut dyn Reflect), Map(&'a dyn ReflectedMap), } impl<'a> ReflectMut<'a> { /// Retrieves self as a [`ReflectRef`]. pub fn as_ref(&self) -> ReflectRef { match self { ReflectMut::Struct(v) => ReflectRef::Struct(*v), ReflectMut::Enum(v) => ReflectRef::Enum(*v), ReflectMut::Tuple(v) => ReflectRef::Tuple(*v), ReflectMut::Array(v) => ReflectRef::Array(*v), ReflectMut::List(v) => ReflectRef::List(*v), ReflectMut::Value(v) => ReflectRef::Value(*v), ReflectMut::Map(v) => ReflectRef::Map(*v), } } /// Gets the reflected reference as a struct. /// /// # Safety /// * If `self` is not a `Struct` variant, this will panic pub fn as_struct(&self) -> &dyn Struct { match self { ReflectMut::Struct(s) => *s, _ => panic!("`self` is not a struct variant!"), } } /// Gets the reflected reference mutable as a struct. /// /// # Safety /// * If `self` is not a `Struct` variant, this will panic pub fn as_struct_mut(&mut self) -> &mut dyn Struct { match self { ReflectMut::Struct(s) => *s, _ => panic!("`self` is not a struct variant!"), } } } pub enum ReflectEither<'a> { Ref(ReflectRef<'a>), Mut(ReflectMut<'a>), } impl<'a> ReflectEither<'a> { /// Converts `self` into a [`ReflectRef`]. Both variants can be retrieved as a reference. /* pub fn into_ref(self) -> ReflectRef<'a> { match self { Self::Ref(v) => v, Self::Mut(v) => v.as_ref() } } */ /// Attempts to get `self` as a [`ReflectMut`]. /// /// If `self` is a `Ref`, `None` will be returned pub fn try_into_mut(self) -> Option> { match self { Self::Mut(v) => Some(v), Self::Ref(_) => None } } /* pub fn as_ref(&self) -> &ReflectRef<'a> { match self { Self::Ref(v) => v, Self::Mut(v) => &v.as_ref() } } */ pub fn is_mut(&self) -> bool { match self { ReflectEither::Ref(_) => false, ReflectEither::Mut(_) => true, } } } #[allow(dead_code)] pub struct Value { inner: Box, type_id: TypeId, ref_type_id: TypeId, } impl Value { pub fn new(val: T) -> Self { Self { inner: Box::new(val), type_id: TypeId::of::(), ref_type_id: TypeId::of::<&T>(), } } /// Remove the stored object from Value pub fn take(self) -> Option { (self.inner as Box).downcast::().ok().map(|v| *v) } pub fn get(&self) -> Option<&T> { self.inner.as_any().downcast_ref::() } pub fn get_mut(&mut self) -> Option<&mut T> { self.inner.as_any_mut().downcast_mut::() } } pub trait IntoValue { fn into_value(self) -> Value; fn type_id() -> TypeId; } impl IntoValue for T { fn into_value(self) -> Value { Value::new(self) } fn type_id() -> TypeId { TypeId::of::() } } pub trait FromType { fn from_type() -> Self; } pub trait ReflectWorldExt { /// Retrieves the type registry from the world. fn get_type_registry(&self) -> AtomicRef; /// Retrieves the type registry mutably from the world. fn get_type_registry_mut(&self) -> AtomicRefMut; /// Get a registered type from the type registry. Returns `None` if the type is not registered fn get_type(&self, type_id: TypeId) -> Option>; /// Get a mutable registered type from the type registry in the world. returns `None` if the type is not registered. fn get_type_mut(&self, type_id: TypeId) -> Option>; /// Get a registered type, or register a new type and return it. fn get_type_or_default(&self, type_id: TypeId) -> AtomicRefMut; } impl ReflectWorldExt for World { fn get_type_registry(&self) -> AtomicRef { self.get_resource::() } fn get_type_registry_mut(&self) -> AtomicRefMut { self.get_resource_mut::() } fn get_type(&self, type_id: TypeId) -> Option> { let r = self.get_resource::(); if r.has_type(type_id) { Some(AtomicRef::map(r, |tr| tr.get_type(type_id).unwrap())) } else { None } } fn get_type_mut(&self, type_id: TypeId) -> Option> { let r = self.get_resource_mut::(); if r.has_type(type_id) { Some(AtomicRefMut::map(r, |tr| tr.get_type_mut(type_id).unwrap())) } else { None } } fn get_type_or_default(&self, type_id: TypeId) -> AtomicRefMut { let r = self.get_resource_mut::(); AtomicRefMut::map(r, |tr| tr.get_type_or_default(type_id)) } }