use std::any::{type_name, Any}; use std::convert::Infallible; use std::fmt::Debug; use std::marker::PhantomData; use std::ops::{Deref, DerefMut}; use std::panic::{RefUnwindSafe, UnwindSafe}; use seq_macro::seq; use crate::component::{Component, FromOptional as FromOptionalComponent}; use crate::lock::WriteGuard; use crate::system::util::check_params_are_compatible; use crate::tuple::{ReduceElement as TupleReduceElement, With as TupleWith}; use crate::WorldData; pub mod stateful; mod util; pub trait System<'world, Impl>: 'static { type Input; #[must_use] fn initialize(self, input: Self::Input) -> Self; fn prepare(&self, world_data: &WorldData); fn run<'this>(&'this self, world_data: &'world WorldData) where 'this: 'world; fn into_type_erased(self) -> TypeErased; fn get_local_component_mut( &self, ) -> Option>; 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<'world, fn(#(TParam~I,)*)> for Func where Func: Fn(#(TParam~I,)*) + Copy + RefUnwindSafe + UnwindSafe + 'static, #(TParam~I: Param<'world, Flags = NoInitParamFlag>,)* { type Input = Infallible; fn initialize(self, _input: Self::Input) -> Self { self } fn prepare(&self, world_data: &WorldData) { #( TParam~I::handle_pre_run(world_data); )* } fn run<'this>(&'this self, world_data: &'world WorldData) where 'this: 'world { #( check_params_are_compatible!(I, TParam~I, $c); )* let func = *self; func(#({ TParam~I::new(self, world_data) },)*); } fn into_type_erased(self) -> TypeErased { TypeErased { data: Box::new(self), run: Box::new(|data, world_data| { // SAFETY: The caller of TypeErased::run ensures the lifetime // is correct let data = unsafe { &*std::ptr::from_ref(data) }; let me = data .downcast_ref::() .expect("Function downcast failed"); // SAFETY: The caller of TypeErased::run ensures the lifetime // is correct let world_data = unsafe { &*std::ptr::from_ref(world_data) }; me.run(world_data); }), prepare: Box::new(|data, world_data| { // SAFETY: The caller of TypeErased::run ensures the lifetime // is correct let data = unsafe { &*std::ptr::from_ref(data) }; let me = data .downcast_ref::() .expect("Function downcast failed"); // SAFETY: The caller of TypeErased::run ensures the lifetime // is correct let world_data = unsafe { &*std::ptr::from_ref(world_data) }; me.prepare(world_data); }), } } fn get_local_component_mut( &self, ) -> Option> { 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 1..16 { impl_system!(C); }); pub trait Into { type System; fn into_system(self) -> Self::System; } pub struct TypeErased { data: Box, run: Box, prepare: Box, } impl TypeErased { /// Runs the system. /// /// # Safety /// `world_data` must live at least as long as the [`World`] the system belongs to. pub unsafe fn run(&self, world_data: &WorldData) { // You have to dereference for downcasting to work for some reason let data = &*self.data; (self.run)(data, world_data); } /// Prepares the system. /// /// # Safety /// `world_data` must live at least as long as the [`World`] the system belongs to. pub unsafe fn prepare(&self, world_data: &WorldData) { // You have to dereference for downcasting to work for some reason let data = &*self.data; (self.prepare)(data, world_data); } } 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 TypeErasedRunFn = dyn Fn(&dyn Any, &WorldData) + RefUnwindSafe + UnwindSafe; /// Function in [`TypeErased`] used to prepare the system. type TypeErasedPrepareFn = dyn Fn(&dyn Any, &WorldData) + RefUnwindSafe + UnwindSafe; /// 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<'world, SystemImpl>, input: Self::Input, ); fn new( system: &'world impl System<'world, SystemImpl>, world_data: &'world WorldData, ) -> Self; fn is_compatible>() -> bool; fn get_comparable() -> Box; fn handle_pre_run(_world_data: &WorldData) {} } pub struct NoInitParamFlag {} /// A type which can be used as input to a [`System`]. pub trait Input: 'static {} /// Component tuple reducing operation to get the parameters that takes input. pub struct ParamWithInputFilter; impl TupleReduceElement for InputT where Accumulator: TupleWith, { type Return = Accumulator::With; } impl TupleReduceElement for () { type Return = Accumulator; } #[derive(Debug)] pub struct ComponentRefMut<'a, ComponentT: Component> { inner: WriteGuard<'a, Box>, _ph: PhantomData, } impl<'a, ComponentT: Component> ComponentRefMut<'a, ComponentT> { pub(crate) fn new(inner: WriteGuard<'a, Box>) -> Self { Self { inner, _ph: PhantomData } } } impl<'component, ComponentT: Component> FromOptionalComponent<'component> for ComponentRefMut<'component, ComponentT> { fn from_optional_component( inner: Option>>, ) -> Self { Self { inner: inner.unwrap_or_else(|| { panic!( "Component {} was not found in entity", type_name::() ); }), _ph: PhantomData, } } } impl<'comp, ComponentT> FromOptionalComponent<'comp> for Option> where ComponentT: Component, { fn from_optional_component( optional_component: Option>>, ) -> Self { optional_component.map(|component| ComponentRefMut::new(component)) } } impl<'a, ComponentT: Component> Deref for ComponentRefMut<'a, ComponentT> { type Target = ComponentT; fn deref(&self) -> &Self::Target { self.inner.downcast_ref().unwrap() } } impl<'a, ComponentT: Component> DerefMut for ComponentRefMut<'a, ComponentT> { fn deref_mut(&mut self) -> &mut Self::Target { self.inner.downcast_mut().unwrap() } }