summaryrefslogtreecommitdiff
path: root/ecs/src/system/stateful.rs
diff options
context:
space:
mode:
authorHampusM <hampus@hampusmat.com>2025-08-15 13:38:27 +0200
committerHampusM <hampus@hampusmat.com>2025-08-22 17:18:54 +0200
commite229b104593d3afede47cc07e9917a42d6d13e60 (patch)
tree25cd15befc8bf3e5864158aa791895c6d5bea751 /ecs/src/system/stateful.rs
parentc8d3b211b8328452c9d15955004030430a99d1fc (diff)
refactor(ecs): store local components as system entity components
Diffstat (limited to 'ecs/src/system/stateful.rs')
-rw-r--r--ecs/src/system/stateful.rs165
1 files changed, 71 insertions, 94 deletions
diff --git a/ecs/src/system/stateful.rs b/ecs/src/system/stateful.rs
index 2ec448c..93bfd5e 100644
--- a/ecs/src/system/stateful.rs
+++ b/ecs/src/system/stateful.rs
@@ -1,137 +1,81 @@
-use std::any::{type_name, Any, TypeId};
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::tuple::{
- Reduce as TupleReduce,
- Tuple,
- WithAllElemLtStatic as TupleWithAllElemLtStatic,
-};
-use crate::uid::Uid;
+use crate::component::local::SystemWithLocalComponents;
+use crate::component::Parts as ComponentParts;
+use crate::system::initializable::{Initializable, MaybeInitializableParamTuple};
+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
- {
- 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;
- }
- }
- )*
-
- self
- }
-
- fn run<'this>(&'this self, world: &'world World)
+ fn run<'this>(&'this self, world: &'world World, metadata: Metadata)
where
'this: 'world
{
let func = self.func;
func(#({
- TParam~I::new(self, &world)
+ TParam~I::new(&world, &metadata)
},)*);
}
- fn into_type_erased(self) -> TypeErased
+ fn finish(self) -> (TypeErased, Self::Callbacks)
{
- 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) };
+ let Self { func, local_components } = self;
- let me = data.downcast_ref::<Self>().unwrap();
+ 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) };
- me.run(world);
+ func(#({
+ TParam~I::new(&world, &metadata)
+ },)*);
}),
- }
- }
+ };
- fn get_local_component_mut<LocalComponent: Component>(
- &self,
- ) -> Option<ComponentHandleMut<LocalComponent>>
- {
- let local_component = self.local_components
- .get(&LocalComponent::id())?
- .write_nonblock()
- .expect("Failed to aquire read-write local component lock");
- Some(ComponentHandleMut::new(local_component).unwrap())
+ (type_erased, callbacks)
}
+ }
+
+ 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 set_local_component<LocalComponent: Component>(
- &mut self,
- local_component: LocalComponent,
- )
+ fn initialize(mut self, inputs: Self::Inputs) -> Self
{
- self.local_components
- .insert(
- LocalComponent::id(),
- Lock::new(
- Box::new(local_component),
- type_name::<LocalComponent>()
- )
- );
+ init_initializable_params::<_, (#(TParam~I,)*)>(&mut self, inputs);
+
+ self
}
}
@@ -146,7 +90,7 @@ macro_rules! impl_system {
{
Self::System {
func: self,
- local_components: HashMap::new(),
+ local_components: Vec::new(), // TODO: Use Vec::with_capacity
}
}
}
@@ -157,3 +101,36 @@ macro_rules! impl_system {
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);
+}