use std::any::{type_name, Any}; use std::fmt::Debug; use seq_macro::seq; use crate::event::component::{ Added as ComponentAddedEvent, Kind as ComponentEventKind, Removed as ComponentRemovedEvent, }; use crate::lock::{Error as LockError, Lock, ReadGuard, WriteGuard}; use crate::system::Input as SystemInput; use crate::type_name::TypeName; use crate::uid::Uid; use crate::util::Array; use crate::World; pub mod local; pub(crate) mod storage; pub trait Component: SystemInput + Any + TypeName { /// The component type in question. Will usually be `Self` type Component: Component where Self: Sized; type RefMut<'component>: FromOptionalMut<'component> + FromLockedOptional<'component> where Self: Sized; type Ref<'component>: FromOptional<'component> + FromLockedOptional<'component> where Self: Sized; /// Returns the ID of this component. fn id() -> Uid where Self: Sized; /// Returns the component UID of a component event for this component. fn get_event_uid(&self, event_kind: ComponentEventKind) -> Uid; #[doc(hidden)] fn as_any_mut(&mut self) -> &mut dyn Any; #[doc(hidden)] fn as_any(&self) -> &dyn Any; /// Returns whether the component `self` is optional. fn self_is_optional(&self) -> bool { false } /// Returns whether this component is optional. #[must_use] fn is_optional() -> bool where Self: Sized, { false } } impl dyn Component { pub fn downcast_mut<Real: 'static>(&mut self) -> Option<&mut Real> { self.as_any_mut().downcast_mut() } pub fn downcast_ref<Real: 'static>(&self) -> Option<&Real> { self.as_any().downcast_ref() } pub fn is<Other: 'static>(&self) -> bool { self.as_any().is::<Other>() } } impl Debug for dyn Component { fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { formatter.debug_struct("Component").finish_non_exhaustive() } } impl TypeName for Box<dyn Component> { fn type_name(&self) -> &'static str { self.as_ref().type_name() } } impl<ComponentT> Component for Option<ComponentT> where ComponentT: Component, for<'a> Option<ComponentT::Ref<'a>>: FromOptional<'a> + FromLockedOptional<'a>, for<'a> Option<ComponentT::RefMut<'a>>: FromOptionalMut<'a> + FromLockedOptional<'a>, { type Component = ComponentT; type Ref<'component> = Option<ComponentT::Ref<'component>>; type RefMut<'component> = Option<ComponentT::RefMut<'component>>; fn id() -> Uid { ComponentT::id() } fn get_event_uid(&self, event_kind: ComponentEventKind) -> Uid { match event_kind { ComponentEventKind::Removed => ComponentRemovedEvent::<Self>::id(), } } fn as_any_mut(&mut self) -> &mut dyn Any { self } fn as_any(&self) -> &dyn Any { self } fn self_is_optional(&self) -> bool { true } fn is_optional() -> bool { true } } impl<ComponentT> TypeName for Option<ComponentT> where ComponentT: Component, { fn type_name(&self) -> &'static str { type_name::<Self>() } } impl<ComponentT> SystemInput for Option<ComponentT> where ComponentT: Component {} /// A sequence of components. pub trait Sequence { /// The number of components in this component sequence. const COUNT: usize; type Array: Array<(Uid, Box<dyn Component>)>; fn into_array(self) -> Self::Array; fn metadata() -> impl Array<Metadata>; fn added_event_ids() -> Vec<Uid>; fn removed_event_ids() -> Vec<Uid>; } /// A mutable or immutable reference to a component. pub trait Ref { type Component: Component; type Handle<'component>: FromLockedOptional<'component>; } impl<ComponentT> Ref for &ComponentT where ComponentT: Component, { type Component = ComponentT; type Handle<'component> = ComponentT::Ref<'component>; } impl<ComponentT> Ref for &mut ComponentT where ComponentT: Component, { type Component = ComponentT; type Handle<'component> = ComponentT::RefMut<'component>; } /// [`Component`] metadata. #[derive(Debug, Clone)] #[non_exhaustive] pub struct Metadata { pub id: Uid, pub is_optional: bool, } impl Metadata { #[must_use] pub fn new_non_optional(id: Uid) -> Self { Self { id, is_optional: false } } #[must_use] pub fn of<ComponentT: Component>() -> Self { Self { id: ComponentT::id(), is_optional: ComponentT::is_optional(), } } } pub trait FromOptionalMut<'comp> { fn from_optional_mut_component( optional_component: Option<WriteGuard<'comp, Box<dyn Component>>>, world: &'comp World, ) -> Self; } pub trait FromOptional<'comp> { fn from_optional_component( optional_component: Option<ReadGuard<'comp, Box<dyn Component>>>, world: &'comp World, ) -> Self; } pub trait FromLockedOptional<'comp>: Sized { /// Converts a reference to a optional locked boxed component to a instance of `Self`. /// /// # Errors /// Returns `Err` if taking the lock (in a non-blocking way) fails. fn from_locked_optional_component( optional_component: Option<&'comp Lock<Box<dyn Component>>>, world: &'comp World, ) -> Result<Self, LockError>; } macro_rules! inner { ($c: tt) => { seq!(I in 0..=$c { impl<#(IntoComp~I,)*> Sequence for (#(IntoComp~I,)*) where #( for<'comp> IntoComp~I: Into< Component: Component< RefMut<'comp>: FromOptionalMut<'comp>, Ref<'comp>: FromOptional<'comp> > >, )* { const COUNT: usize = $c + 1; type Array = [(Uid, Box<dyn Component>); $c + 1]; fn into_array(self) -> Self::Array { [#({ let (id, component) = self.I.into_component(); (id, Box::new(component)) },)*] } fn metadata() -> impl Array<Metadata> { [ #( Metadata { id: IntoComp~I::Component::id(), is_optional: IntoComp~I::Component::is_optional(), }, )* ] } fn added_event_ids() -> Vec<Uid> { vec![ #(ComponentAddedEvent::<IntoComp~I::Component>::id(),)* ] } fn removed_event_ids() -> Vec<Uid> { vec![ #(ComponentRemovedEvent::<IntoComp~I::Component>::id(),)* ] } } }); }; } seq!(C in 0..=16 { inner!(C); }); impl Sequence for () { type Array = [(Uid, Box<dyn Component>); 0]; const COUNT: usize = 0; fn into_array(self) -> Self::Array { [] } fn metadata() -> impl Array<Metadata> { [] } fn added_event_ids() -> Vec<Uid> { Vec::new() } fn removed_event_ids() -> Vec<Uid> { Vec::new() } } pub trait Into { type Component; fn into_component(self) -> (Uid, Self::Component); } impl<ComponentT> Into for ComponentT where ComponentT: Component, { type Component = Self; fn into_component(self) -> (Uid, Self::Component) { (Self::id(), self) } }