use std::any::{type_name, Any, TypeId}; use std::fmt::Debug; use seq_macro::seq; use crate::lock::WriteGuard; use crate::system::{ComponentRefMut, Input as SystemInput}; use crate::type_name::TypeName; use crate::EntityComponent; pub mod local; pub trait Component: SystemInput + Any + TypeName { /// The component type in question. Will usually be `Self` type Component where Self: Sized; type RefMut<'component> where Self: Sized; #[doc(hidden)] fn as_any_mut(&mut self) -> &mut dyn Any; #[doc(hidden)] fn as_any(&self) -> &dyn Any; } impl dyn Component { pub fn downcast_mut(&mut self) -> Option<&mut Real> { self.as_any_mut().downcast_mut() } pub fn downcast_ref(&self) -> Option<&Real> { self.as_any().downcast_ref() } pub fn is(&self) -> bool { self.as_any().is::() } } 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 { fn type_name(&self) -> &'static str { self.as_ref().type_name() } } impl Component for Option where ComponentT: Component, { type Component = ComponentT; type RefMut<'component> = Option>; fn as_any_mut(&mut self) -> &mut dyn Any { self } fn as_any(&self) -> &dyn Any { self } } impl TypeName for Option where ComponentT: Component, { fn type_name(&self) -> &'static str { type_name::() } } impl SystemInput for Option where ComponentT: Component {} /// A sequence of components. pub trait Sequence { type Refs<'component> where Self: 'component; fn into_vec(self) -> Vec>; fn type_ids() -> Vec<(TypeId, IsOptional)>; fn from_components<'component>( components: impl Iterator, ) -> Self::Refs<'component>; } /// Whether or not a `Component` is optional. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum IsOptional { Yes, No, } impl From for IsOptional { fn from(is_optional: bool) -> Self { if is_optional { return IsOptional::Yes; } IsOptional::No } } /// Returns whether the given component type is a optional component. /// /// Will return `true` if the component is a [`Option`]. pub fn is_optional() -> bool { if TypeId::of::() == TypeId::of::>() { return true; } false } pub trait FromOptionalComponent<'comp> { fn from_optional_component( optional_component: Option>>, ) -> Self; } macro_rules! inner { ($c: tt) => { seq!(I in 0..=$c { impl<#(Comp~I: Component,)*> Sequence for (#(Comp~I,)*) where #(for<'comp> Comp~I::RefMut<'comp>: FromOptionalComponent<'comp>,)* { type Refs<'component> = (#(Comp~I::RefMut<'component>,)*) where Self: 'component; fn into_vec(self) -> Vec> { Vec::from_iter([#(Box::new(self.I) as Box,)*]) } fn type_ids() -> Vec<(TypeId, IsOptional)> { vec![ #( (TypeId::of::(), is_optional::().into()), )* ] } fn from_components<'component>( components: impl Iterator, ) -> Self::Refs<'component> { #( let mut comp_~I: Option>> = None; )* for comp in components { #( if comp.id == TypeId::of::() { comp_~I = Some(lock_component(comp)); continue; } )* } (#( Comp~I::RefMut::from_optional_component(comp_~I), )*) } } }); }; } seq!(C in 0..=64 { inner!(C); }); fn lock_component( entity_component: &EntityComponent, ) -> WriteGuard<'_, Box> { entity_component .component .write_nonblock() .unwrap_or_else(|_| { panic!( "Failed to acquire read-write lock to component {}", entity_component.name ); }) }