summaryrefslogtreecommitdiff
path: root/engine-ecs/src/system/stateful.rs
diff options
context:
space:
mode:
Diffstat (limited to 'engine-ecs/src/system/stateful.rs')
-rw-r--r--engine-ecs/src/system/stateful.rs269
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);
+});