summaryrefslogtreecommitdiff
path: root/ecs/src/system/initializable.rs
blob: b6ec8e8bb53cddabea4939ed46b4dc81ca354582 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
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<Accumulator, ParamTupleFilter<'world, SystemT>> for ParamT
where
    ParamT: SystemParam<
        'world,
        Input: AppendInitializableParam<'world, Accumulator, ParamT, SystemT>,
    >,
    Accumulator: Tuple,
{
    type Return = <ParamT::Input as AppendInitializableParam<
        'world,
        Accumulator,
        ParamT,
        SystemT,
    >>::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<ParamT>;
}

impl<ParamT, Accumulator, SystemT>
    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,
                ) {
                    #(
                        <Param~I as Param<'world, SystemT>>::initialize(
                            system,
                            inputs.I
                        );
                    )*
                }
            }
        });
    };
}

seq!(C in 1..16 {
    impl_initializable_param_tuple!(C);
});

impl<SystemT> 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<ParamTupleFilter<'world, SystemT>, Out: ParamTuple<'world, SystemT>>,
{
    type Inputs = <Params::Out as ParamTuple<'world, SystemT>>::Inputs;

    fn init_initializable(system: &mut SystemT, inputs: Self::Inputs)
    {
        Params::Out::initialize_all(system, inputs);
    }
}