From e229b104593d3afede47cc07e9917a42d6d13e60 Mon Sep 17 00:00:00 2001 From: HampusM Date: Fri, 15 Aug 2025 13:38:27 +0200 Subject: refactor(ecs): store local components as system entity components --- ecs/src/system/initializable.rs | 131 +++++++++++++++++++++++++++++++ ecs/src/system/stateful.rs | 165 +++++++++++++++++----------------------- 2 files changed, 202 insertions(+), 94 deletions(-) create mode 100644 ecs/src/system/initializable.rs (limited to 'ecs/src/system') diff --git a/ecs/src/system/initializable.rs b/ecs/src/system/initializable.rs new file mode 100644 index 0000000..40fbb0f --- /dev/null +++ b/ecs/src/system/initializable.rs @@ -0,0 +1,131 @@ +use std::marker::PhantomData; + +use seq_macro::seq; + +use crate::system::{Input, Param as SystemParam, System}; +use crate::tuple::{Reduce as TupleReduce, ReduceElement as TupleReduceElement, Tuple}; + +/// A initializable system. +pub trait Initializable<'world, Impl>: System<'world, Impl> +{ + type Inputs; + + #[must_use] + fn initialize(self, inputs: Self::Inputs) -> Self; +} + +pub trait Param<'world, SystemT>: SystemParam<'world> +{ + fn initialize(system: &mut SystemT, input: Self::Input); +} + +pub struct ParamTupleFilter<'world, SystemT> +{ + _pd: PhantomData<(&'world (), SystemT)>, +} + +impl<'world, SystemT, ParamT, Accumulator> + TupleReduceElement> for ParamT +where + ParamT: SystemParam< + 'world, + Input: AppendInitializableParam<'world, Accumulator, ParamT, SystemT>, + >, + Accumulator: Tuple, +{ + type Return = >::Return; +} + +pub trait AppendInitializableParam<'world, Accumulator, ParamT, SystemT> +{ + type Return; +} + +impl<'world, InputT, ParamT, Accumulator, SystemT> + AppendInitializableParam<'world, Accumulator, ParamT, SystemT> for InputT +where + InputT: Input, + Accumulator: Tuple, + ParamT: Param<'world, SystemT>, +{ + type Return = Accumulator::WithElementAtEnd; +} + +impl<'world, ParamT, Accumulator, SystemT> + AppendInitializableParam<'world, Accumulator, ParamT, SystemT> for () +where + Accumulator: Tuple, +{ + type Return = Accumulator; +} + +pub trait ParamTuple<'world, SystemT> +{ + type Inputs; + + fn initialize_all(system: &mut SystemT, inputs: Self::Inputs); +} + +macro_rules! impl_initializable_param_tuple { + ($c: tt) => { + seq!(I in 0..$c { + impl<'world, SystemT, #(Param~I,)*> ParamTuple<'world, SystemT> + for (#(Param~I,)*) + where + #(Param~I: Param<'world, SystemT>,)* + { + type Inputs = (#(Param~I::Input,)*); + + fn initialize_all( + system: &mut SystemT, + inputs: Self::Inputs, + ) { + #( + >::initialize( + system, + inputs.I + ); + )* + } + } + }); + }; +} + +seq!(C in 1..16 { + impl_initializable_param_tuple!(C); +}); + +impl<'world, SystemT> ParamTuple<'world, SystemT> for () +{ + type Inputs = (); + + fn initialize_all(_system: &mut SystemT, _inputs: Self::Inputs) {} +} + +/// A tuple of system parameters that may or may not be initializable. +pub trait MaybeInitializableParamTuple<'world, SystemT> +{ + /// A tuple of the inputs of the initializable system parameters in this tuple. + type Inputs; + + fn init_initializable(system: &mut SystemT, inputs: Self::Inputs); +} + +impl<'world, SystemT, Params> MaybeInitializableParamTuple<'world, SystemT> for Params +where + Params: + TupleReduce, Out: ParamTuple<'world, SystemT>>, +{ + type Inputs = >::Inputs; + + fn init_initializable(system: &mut SystemT, inputs: Self::Inputs) + { + Params::Out::initialize_all(system, inputs); + } +} 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, - local_components: HashMap>>, + local_components: Vec, } macro_rules! impl_system { ($c: tt) => { seq!(I in 0..$c { - impl<'world, Func, #(TParam~I,)*> System<'world, fn(&'world (), #(TParam~I,)*)> - for Stateful + impl<'world, Func, #(TParam~I,)*> + System<'world, fn(&'world (), #(TParam~I,)*)> for Stateful where Func: Fn(#(TParam~I,)*) + Copy + RefUnwindSafe + UnwindSafe + 'static, - #(TParam~I: Param<'world>,)* - #(TParam~I::Input: 'static,)* - (#(TParam~I::Input,)*): TupleReduce< - ParamWithInputFilter, - Out: Tuple - >, + #(TParam~I: Param<'world, Input: 'static>,)* { - type Input = - <(#(TParam~I::Input,)*) as TupleReduce>::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::() != - TypeId::of::<()>() - { - let input = option_input - .get_mut::>(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::(data) }; + let Self { func, local_components } = self; - let me = data.downcast_ref::().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( - &self, - ) -> Option> - { - 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 + 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( - &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::() - ) - ); + 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 SystemWithLocalComponents for Stateful +{ + fn add_local_component(&mut self, component_parts: ComponentParts) + { + self.local_components.push(component_parts); + } +} + +#[derive(Debug)] +pub struct Callbacks +{ + local_components: Vec, +} + +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); +} -- cgit v1.2.3-18-g5258