summaryrefslogtreecommitdiff
path: root/ecs/src/system/stateful.rs
diff options
context:
space:
mode:
Diffstat (limited to 'ecs/src/system/stateful.rs')
-rw-r--r--ecs/src/system/stateful.rs295
1 files changed, 193 insertions, 102 deletions
diff --git a/ecs/src/system/stateful.rs b/ecs/src/system/stateful.rs
index 54f6979..e74ef31 100644
--- a/ecs/src/system/stateful.rs
+++ b/ecs/src/system/stateful.rs
@@ -1,152 +1,243 @@
-use std::any::{type_name, Any, TypeId};
+use std::mem::transmute;
use std::panic::{RefUnwindSafe, UnwindSafe};
-use hashbrown::HashMap;
use seq_macro::seq;
-use crate::component::{Component, HandleMut as ComponentHandleMut};
-use crate::lock::Lock;
-use crate::system::{
- Into as IntoSystem,
- Param,
- ParamWithInputFilter,
- System,
- TypeErased,
+use crate::component::local::SystemWithLocalComponents;
+use crate::component::Parts as ComponentParts;
+use crate::event::Emitted as EmittedEvent;
+use crate::system::initializable::{Initializable, MaybeInitializableParamTuple};
+use crate::system::observer::{
+ Observe,
+ Observed,
+ Observer,
+ WrapperComponent as ObserverWrapperComponent,
};
-use crate::tuple::{
- Reduce as TupleReduce,
- Tuple,
- WithAllElemLtStatic as TupleWithAllElemLtStatic,
-};
-use crate::uid::Uid;
+use crate::system::{Into as IntoSystem, Metadata, Param, System, TypeErased};
use crate::World;
/// A stateful system.
pub struct Stateful<Func>
{
func: Func,
- local_components: HashMap<Uid, Lock<Box<dyn Any>>>,
+ local_components: Vec<ComponentParts>,
}
macro_rules! impl_system {
($c: tt) => {
seq!(I in 0..$c {
- impl<'world, Func, #(TParam~I,)*> System<'world, fn(&'world (), #(TParam~I,)*)>
- for Stateful<Func>
+ impl<'world, Func, #(TParam~I,)*>
+ System<'world, fn(&'world (), #(TParam~I,)*)> for Stateful<Func>
where
Func: Fn(#(TParam~I,)*) + Copy + RefUnwindSafe + UnwindSafe + 'static,
- #(TParam~I: Param<'world>,)*
- #(TParam~I::Input: 'static,)*
- (#(TParam~I::Input,)*): TupleReduce<
- ParamWithInputFilter,
- Out: Tuple<InOptions: TupleWithAllElemLtStatic>
- >,
+ #(TParam~I: Param<'world, Input: 'static>,)*
{
- type Input =
- <(#(TParam~I::Input,)*) as TupleReduce<ParamWithInputFilter>>::Out;
+ type Callbacks = Callbacks;
- fn initialize(mut self, input: Self::Input) -> Self
+ fn finish(self) -> (TypeErased, Self::Callbacks)
{
- let mut option_input = input.into_in_options();
-
- let mut index = 0;
-
- #(
- if TypeId::of::<TParam~I::Input>() !=
- TypeId::of::<()>()
- {
- let input = option_input
- .get_mut::<Option<TParam~I::Input>>(index)
- .expect("Input element index out of range")
- .take()
- .expect("Input element is already taken");
-
- TParam~I::initialize(
- &mut self,
- input
- );
-
- #[allow(unused_assignments)]
- {
- index += 1;
- }
- }
- )*
+ let Self { func, local_components } = self;
- 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)
+ },)*);
+ }),
+ };
+
+
+ (type_erased, callbacks)
}
+ }
- fn run<'this>(&'this self, world: &'world World)
- where
- 'this: 'world
+ impl<'world, Func, #(TParam~I,)*>
+ Initializable<'world, fn(&'world (), #(TParam~I,)*)> for Stateful<Func>
+ where
+ Func: Fn(#(TParam~I,)*) + Copy + RefUnwindSafe + UnwindSafe + 'static,
+ #(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
{
- let func = self.func;
+ init_initializable_params::<_, (#(TParam~I,)*)>(&mut self, inputs);
- func(#({
- TParam~I::new(self, &world)
- },)*);
+ self
}
+ }
- fn into_type_erased(self) -> TypeErased
+ impl<'world, Func, #(TParam~I,)*> IntoSystem<'world, fn(#(TParam~I,)*)>
+ for Func
+ where
+ #(TParam~I: Param<'world>,)*
+ Func: Fn(#(TParam~I,)*) + Copy + 'static,
+ {
+ type System = Stateful<Func>;
+
+ fn into_system(self) -> Self::System
{
- TypeErased {
- data: Box::new(self),
- run: Box::new(|data, world| {
- // SAFETY: The caller of TypeErased::run ensures the lifetime
- // is correct
- let data = unsafe { &*std::ptr::from_ref::<dyn Any>(data) };
+ Self::System {
+ func: self,
+ local_components: Vec::new(), // TODO: Use Vec::with_capacity
+ }
+ }
+ }
+ });
+ };
+}
- let me = data.downcast_ref::<Self>().unwrap();
+seq!(C in 1..16 {
+ impl_system!(C);
+});
- // SAFETY: The caller of TypeErased::run ensures the lifetime
- // is correct
- let world = unsafe { &*std::ptr::from_ref(world) };
+impl<Func> SystemWithLocalComponents for Stateful<Func>
+{
+ fn add_local_component(&mut self, component_parts: ComponentParts)
+ {
+ self.local_components.push(component_parts);
+ }
+}
- me.run(world);
- }),
- }
+#[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, #(TParam~I,)*> System<
+ 'world,
+ fn(Observe<'world, ObservedT>, #(TParam~I,)*)
+ > for Stateful<Func>
+ where
+ ObservedT: Observed,
+ Func: Fn(Observe<'world, ObservedT>, #(TParam~I,)*) + Copy + 'static,
+ #(TParam~I: Param<'world>,)*
+ {
+ type Callbacks = Callbacks;
+
+ fn finish(self) -> (TypeErased, Callbacks)
+ {
+ unimplemented!();
}
+ }
- fn get_local_component_mut<LocalComponent: Component>(
- &self,
- ) -> Option<ComponentHandleMut<LocalComponent>>
+ impl<'world, ObservedT, Func, #(TParam~I,)*> Initializable<
+ 'world,
+ fn(Observe<'world, ObservedT>, #(TParam~I,)*)
+ > for Stateful<Func>
+ where
+ ObservedT: Observed,
+ Func: Fn(Observe<'world, ObservedT>, #(TParam~I,)*) + Copy + 'static,
+ #(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
{
- let local_component = self.local_components
- .get(&LocalComponent::id())?
- .write_nonblock()
- .expect("Failed to aquire read-write local component lock");
+ init_initializable_params::<_, (#(TParam~I,)*)>(&mut self, inputs);
- Some(ComponentHandleMut::new(local_component))
+ self
}
+ }
+
+ impl<'world, ObservedT, Func, #(TParam~I,)*> Observer<
+ 'world,
+ fn(Observe<'world, ObservedT>, #(TParam~I,)*)
+ > for Stateful<Func>
+ where
+ ObservedT: Observed,
+ Func: Fn(Observe<'world, ObservedT>, #(TParam~I,)*) + Copy + 'static,
+ #(TParam~I: Param<'world>,)*
+ {
+ type ObservedEvents = ObservedT::Events;
- fn set_local_component<LocalComponent: Component>(
- &mut self,
- local_component: LocalComponent,
- )
+ fn observed_events() -> Self::ObservedEvents
{
- self.local_components
- .insert(
- LocalComponent::id(),
- Lock::new(
- Box::new(local_component),
- type_name::<LocalComponent>()
- )
- );
+ ObservedT::events()
+ }
+
+ fn finish_observer(self) -> (ObserverWrapperComponent, Callbacks)
+ {
+ 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)
+ },)*);
+ },
+ );
+
+ (wrapper_comp, callbacks)
}
}
- impl<Func, #(TParam~I,)*> IntoSystem<fn(#(TParam~I,)*)>
- for Func
+ impl<'world, Func, ObservedT, #(TParam~I,)*> IntoSystem<
+ 'world,
+ fn(Observe<'world, ObservedT>,
+ #(TParam~I,)*)
+ > for Func
where
- Func: Fn(#(TParam~I,)*) + Copy + 'static,
+ ObservedT: Observed,
+ #(TParam~I: Param<'world>,)*
+ Func: Fn(Observe<'world, ObservedT>, #(TParam~I,)*) + Copy + 'static,
{
type System = Stateful<Func>;
- fn into_system(self) -> Self::System
+ fn into_system(self) -> Stateful<Func>
{
- Self::System {
+ Stateful {
func: self,
- local_components: HashMap::new(),
+ local_components: Vec::new(), // TODO: Use Vec::with_capacity
}
}
}
@@ -155,5 +246,5 @@ macro_rules! impl_system {
}
seq!(C in 1..16 {
- impl_system!(C);
+ impl_observer!(C);
});