use std::fmt::Debug; use ecs_macros::Component; use seq_macro::seq; use crate::uid::Uid; use crate::World; pub mod initializable; pub mod stateful; /// Metadata of a system. #[derive(Debug)] #[non_exhaustive] pub struct Metadata { pub ent_id: Uid, } pub trait System<'world, Impl>: 'static { type Callbacks: Callbacks; fn run<'this>(&'this self, world: &'world World, metadata: Metadata) where 'this: 'world; fn finish(self) -> (TypeErased, Self::Callbacks); } 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 + 'static, #(TParam~I: Param<'world, Input = ()>,)* { type Callbacks = NoCallbacks; fn run<'this>(&'this self, world: &'world World, metadata: Metadata) where 'this: 'world { let func = *self; func(#({ TParam~I::new(world, &metadata) },)*); } fn finish(self) -> (TypeErased, Self::Callbacks) { let type_erased = TypeErased { run: Box::new(move |world, metadata| { // SAFETY: The caller of TypeErased::run ensures the lifetime // is correct let world = unsafe { &*std::ptr::from_ref(world) }; self(#({ TParam~I::new(world, &metadata) },)*); }), }; (type_erased, NoCallbacks) } } }); }; } seq!(C in 1..16 { impl_system!(C); }); pub trait Into { type System; fn into_system(self) -> Self::System; } pub struct TypeErased { run: 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: &World, metadata: Metadata) { (self.run)(world, metadata); } } 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(&World, Metadata); /// A parameter to a [`System`]. pub trait Param<'world> { type Input; fn new(world: &'world World, system_metadata: &Metadata) -> Self; } /// A type which can be used as input to a [`System`]. pub trait Input: 'static {} pub trait Callbacks { fn on_created(&mut self, world: &mut World, metadata: Metadata); } pub struct NoCallbacks; impl Callbacks for NoCallbacks { fn on_created(&mut self, _world: &mut World, _metadata: Metadata) {} } #[derive(Debug, Component)] pub(crate) struct SystemComponent { pub(crate) system: TypeErased, }