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 AppendInitializableParam<'_, 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 ParamTuple<'_, 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); } }