use std::any::Any; use std::convert::Infallible; use std::fmt::Debug; use std::ptr::addr_of_mut; use seq_macro::seq; use crate::component::Component; use crate::system::util::check_params_are_compatible; use crate::tuple::{FilterElement as TupleFilterElement, With as TupleWith}; use crate::ComponentStorage; pub mod stateful; mod util; pub trait System: 'static { type Input; #[must_use] fn initialize(self, input: Self::Input) -> Self; fn run(&mut self, component_storage: &mut ComponentStorage); fn into_type_erased(self) -> TypeErased; fn get_local_component_mut( &mut self, ) -> Option<&mut LocalComponent>; fn set_local_component( &mut self, local_component: LocalComponent, ); } macro_rules! impl_system { ($c: tt) => { seq!(I in 0..=$c { impl<'world, Func, #(TParam~I,)*> System for Func where Func: Fn(#(TParam~I,)*) + Copy + 'static, #(TParam~I: Param<'world, Flags = NoInitParamFlag>,)* { type Input = Infallible; fn initialize(self, _input: Self::Input) -> Self { self } fn run(&mut self, component_storage: &mut ComponentStorage) { #( check_params_are_compatible!(I, TParam~I, $c); )* let func = *self; func(#({ // SAFETY: All parameters are compatible so this is fine let this = unsafe { &mut *addr_of_mut!(*self) }; // SAFETY: All parameters are compatible so this is fine let component_storage = unsafe { &mut *addr_of_mut!(*component_storage) }; TParam~I::new(this, component_storage) },)*); } fn into_type_erased(self) -> TypeErased { TypeErased { data: Box::new(self), func: Box::new(|data, component_storage| { let me = data.downcast_mut::().unwrap(); me.run(component_storage); }), } } fn get_local_component_mut( &mut self, ) -> Option<&mut LocalComponent> { panic!("System does not have any local components"); } fn set_local_component( &mut self, _local_component: LocalComponent, ) { panic!("System does not have any local components"); } } }); }; } seq!(C in 0..=4 { impl_system!(C); }); pub trait Into { type System; fn into_system(self) -> Self::System; } pub struct TypeErased { data: Box, func: Box, } impl TypeErased { pub fn run(&mut self, component_storage: &mut ComponentStorage) { (self.func)(self.data.as_mut(), component_storage); } } impl Debug for TypeErased { fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { formatter.debug_struct("TypeErased").finish_non_exhaustive() } } /// Function in [`TypeErased`] used to run the system. type TypeErasedFunc = dyn Fn(&mut dyn Any, &mut ComponentStorage); /// A parameter to a [`System`]. /// /// # Safety /// The `is_compatible` function is used for safety so it must be implemented properly. pub unsafe trait Param<'world> { type Input; type Flags; fn initialize(system: &mut impl System, input: Self::Input); fn new( system: &'world mut impl System, component_storage: &'world mut ComponentStorage, ) -> Self; fn is_compatible>() -> bool; fn get_comparable() -> Box; } pub struct NoInitParamFlag {} /// A type which can be used as input to a [`System`]. pub trait Input: 'static {} impl TupleFilterElement for InputT where Tup: TupleWith, { type Tuple = Tup::With; }