diff options
| author | HampusM <hampus@hampusmat.com> | 2026-05-21 17:55:20 +0200 |
|---|---|---|
| committer | HampusM <hampus@hampusmat.com> | 2026-05-21 17:55:20 +0200 |
| commit | 8022e8998290b067b8aa0cb9cba8ba410826bdab (patch) | |
| tree | 7171e79ce530e03079046ee8fd12167160c45480 /engine-ecs/src/system/stateful.rs | |
| parent | 412cee02c252f91bcf0b70a3f5cc5fca6d2b4c62 (diff) | |
Diffstat (limited to 'engine-ecs/src/system/stateful.rs')
| -rw-r--r-- | engine-ecs/src/system/stateful.rs | 269 |
1 files changed, 269 insertions, 0 deletions
diff --git a/engine-ecs/src/system/stateful.rs b/engine-ecs/src/system/stateful.rs new file mode 100644 index 0000000..3e0076a --- /dev/null +++ b/engine-ecs/src/system/stateful.rs @@ -0,0 +1,269 @@ +use std::any::type_name; +use std::mem::transmute; + +use seq_macro::seq; + +use crate::World; +use crate::component::Parts as ComponentParts; +use crate::component::local::SystemWithLocalComponents; +use crate::event::Emitted as EmittedEvent; +use crate::system::initializable::{Initializable, MaybeInitializableParamTuple}; +use crate::system::observer::{ + Observe, + Observed, + Observer, + WrapperComponent as ObserverWrapperComponent, +}; +use crate::system::{ + Into as IntoSystem, + Metadata, + Param, + ReturnValue, + System, + TypeErased, +}; + +/// A stateful system. +pub struct Stateful<Func> +{ + func: Func, + local_components: Vec<ComponentParts>, +} + +macro_rules! impl_system { + ($c: tt) => { + seq!(I in 0..$c { + impl<'world, Func, Ret, #(TParam~I,)*> + System<'world, fn(#(TParam~I,)*) -> Ret> for Stateful<Func> + where + Func: Fn(#(TParam~I,)*) -> Ret + 'static, + Ret: ReturnValue, + #(TParam~I: Param<'world, Input: 'static>,)* + { + type Callbacks = Callbacks; + + fn finish(self) -> (TypeErased, Self::Callbacks) + { + let Self { func, local_components } = self; + + let callbacks = Callbacks { local_components }; + + 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) }; + + func(#({ + TParam~I::new(&world, &metadata) + },)*); + + Ok(()) + }), + name: type_name::<Func>() + }; + + + (type_erased, callbacks) + } + } + + impl<'world, Func, Ret, #(TParam~I,)*> + Initializable<'world, fn(#(TParam~I,)*) -> Ret> for Stateful<Func> + where + Func: Fn(#(TParam~I,)*) -> Ret + 'static, + Ret: ReturnValue, + #(TParam~I: Param<'world, Input: 'static>,)* + (#(TParam~I,)*): MaybeInitializableParamTuple<'world, Self> + { + type Inputs = < + (#(TParam~I,)*) as MaybeInitializableParamTuple<'world, Self> + >::Inputs; + + fn initialize(mut self, inputs: Self::Inputs) -> Self + { + init_initializable_params::<_, (#(TParam~I,)*)>(&mut self, inputs); + + self + } + } + + impl<'world, Func, Ret, #(TParam~I,)*> + IntoSystem<'world, fn(#(TParam~I,)*) -> Ret> for Func + where + Func: Fn(#(TParam~I,)*) -> Ret + 'static, + Ret: ReturnValue, + #(TParam~I: Param<'world>,)* + { + type System = Stateful<Func>; + + fn into_system(self) -> Self::System + { + Self::System { + func: self, + local_components: Vec::new(), // TODO: Use Vec::with_capacity + } + } + } + }); + }; +} + +seq!(C in 1..16 { + impl_system!(C); +}); + +impl<Func> SystemWithLocalComponents for Stateful<Func> +{ + fn add_local_component(&mut self, component_parts: ComponentParts) + { + self.local_components.push(component_parts); + } +} + +#[derive(Debug)] +pub struct Callbacks +{ + local_components: Vec<ComponentParts>, +} + +impl crate::system::Callbacks for Callbacks +{ + fn on_created(&mut self, world: &mut World, metadata: Metadata) + { + for local_comp_parts in self.local_components.drain(..) { + world.add_component(metadata.ent_id, local_comp_parts); + } + } +} + +fn init_initializable_params<'world, SystemT, Params>( + system: &mut SystemT, + inputs: Params::Inputs, +) where + Params: MaybeInitializableParamTuple<'world, SystemT>, +{ + Params::init_initializable(system, inputs); +} + +macro_rules! impl_observer { + ($c: tt) => { + seq!(I in 0..$c { + impl<'world, ObservedT, Func, Ret, #(TParam~I,)*> System< + 'world, + fn(Observe<'world, ObservedT>, #(TParam~I,)*) -> Ret + > for Stateful<Func> + where + ObservedT: Observed, + Func: Fn(Observe<'world, ObservedT>, #(TParam~I,)*) -> Ret + 'static, + Ret: ReturnValue, + #(TParam~I: Param<'world>,)* + { + type Callbacks = Callbacks; + + fn finish(self) -> (TypeErased, Callbacks) + { + unimplemented!(); + } + } + + impl<'world, ObservedT, Func, Ret, #(TParam~I,)*> Initializable< + 'world, + fn(Observe<'world, ObservedT>, #(TParam~I,)*) -> Ret + > for Stateful<Func> + where + ObservedT: Observed, + Func: Fn(Observe<'world, ObservedT>, #(TParam~I,)*) -> Ret + 'static, + Ret: ReturnValue, + #(TParam~I: Param<'world>,)* + (#(TParam~I,)*): MaybeInitializableParamTuple<'world, Self> + { + type Inputs = < + (#(TParam~I,)*) as MaybeInitializableParamTuple<'world, Self> + >::Inputs; + + fn initialize(mut self, inputs: Self::Inputs) -> Self + { + init_initializable_params::<_, (#(TParam~I,)*)>(&mut self, inputs); + + self + } + } + + impl<'world, ObservedT, Func, Ret, #(TParam~I,)*> Observer< + 'world, + fn(Observe<'world, ObservedT>, #(TParam~I,)*) -> Ret + > for Stateful<Func> + where + ObservedT: Observed, + Func: Fn(Observe<'world, ObservedT>, #(TParam~I,)*) -> Ret + 'static, + Ret: ReturnValue, + #(TParam~I: Param<'world>,)* + { + type ObservedEvents = ObservedT::Events; + + fn observed_events() -> Self::ObservedEvents + { + ObservedT::events() + } + + fn finish_observer(self) -> (ObserverWrapperComponent, Callbacks) + { + #![allow(unused)] + + let Self { func, local_components } = self; + + let callbacks = Callbacks { local_components }; + + let wrapper_comp = ObserverWrapperComponent::new( + move |world, metadata, emitted_event| { + // SAFETY: The caller of TypeErased::run ensures the lifetime + // is correct + let world = unsafe { &*std::ptr::from_ref(world) }; + + // SAFETY: The caller of TypeErased::run ensures the lifetime + // is correct + let emitted_event = unsafe { + transmute::<EmittedEvent<'_>, EmittedEvent<'_>>( + emitted_event + ) + }; + + func(Observe::new(world, emitted_event), #({ + TParam~I::new(world, &metadata) + },)*).into_result() + }, + type_name::<Func>() + ); + + (wrapper_comp, callbacks) + } + } + + impl<'world, Func, Ret, ObservedT, #(TParam~I,)*> IntoSystem< + 'world, + fn(Observe<'world, ObservedT>, #(TParam~I,)*) -> Ret + > for Func + where + ObservedT: Observed, + Func: Fn(Observe<'world, ObservedT>, #(TParam~I,)*) -> Ret + 'static, + Ret: ReturnValue, + #(TParam~I: Param<'world>,)* + { + type System = Stateful<Func>; + + fn into_system(self) -> Stateful<Func> + { + Stateful { + func: self, + local_components: Vec::new(), // TODO: Use Vec::with_capacity + } + } + } + }); + }; +} + +seq!(C in 0..16 { + impl_observer!(C); +}); |
