Skip to main content

limnus_system/
lib.rs

1/*
2 * Copyright (c) Peter Bjorklund. All rights reserved. https://github.com/swamp/limnus
3 * Licensed under the MIT License. See LICENSE in the project root for license information.
4 */
5use core::marker::PhantomData;
6use limnus_system_state::State;
7
8// Systems
9pub trait System: 'static {
10    fn run(&self, world: &mut State);
11}
12
13/// Convert to system (to create a trait object)
14pub trait IntoSystem<Params> {
15    type System: System;
16
17    fn into_system(self) -> Self::System;
18}
19
20/// Convert any function with only system params into a system
21impl<F, Params: SystemParam> IntoSystem<Params> for F
22where
23    F: SystemParamFunction<Params>,
24{
25    type System = FunctionSystem<F, Params>;
26
27    fn into_system(self) -> Self::System {
28        FunctionSystem {
29            system: self,
30            params: PhantomData,
31        }
32    }
33}
34
35/// Wraps a system with params
36pub struct FunctionSystem<F: 'static, Params: SystemParam> {
37    system: F,
38    params: PhantomData<Params>,
39}
40
41/// Implement `System` for the `FunctionSystem` wrapper
42impl<F, Params: SystemParam> System for FunctionSystem<F, Params>
43where
44    F: SystemParamFunction<Params>,
45{
46    fn run(&self, state: &mut State) {
47        SystemParamFunction::run(&self.system, state);
48    }
49}
50
51/// A function with only `SystemParam`, which is the only thing that is supported (and unit function)
52trait SystemParamFunction<Params: SystemParam>: 'static {
53    fn run(&self, state: &mut State);
54}
55
56/// Support for unit function, for convenience
57impl<F> SystemParamFunction<()> for F
58where
59    F: Fn() + 'static,
60{
61    fn run(&self, _state: &mut State) {
62        self(); // We don't need state, since we are just calling without any parameter
63    }
64}
65
66/// implement `SystemParamFunction` for function with one parameter
67impl<F, P1: SystemParam<Item = P1>> SystemParamFunction<(P1,)> for F
68where
69    F: Fn(P1) + 'static,
70{
71    fn run(&self, world: &mut State) {
72        let Some(v1) = P1::get(world) else { return };
73
74        self(v1);
75    }
76}
77
78/// implement `SystemParamFunction` for function with two parameters
79impl<F, P1: SystemParam<Item = P1>, P2: SystemParam<Item = P2>> SystemParamFunction<(P1, P2)> for F
80where
81    F: Fn(P1, P2) + 'static,
82{
83    fn run(&self, world: &mut State) {
84        let Some(v1) = P1::get(world) else { return };
85        let Some(v2) = P2::get(world) else { return };
86
87        self(v1, v2);
88    }
89}
90
91/// implement `SystemParamFunction` for function with three parameters
92impl<F, P1: SystemParam<Item = P1>, P2: SystemParam<Item = P2>, P3: SystemParam<Item = P3>>
93    SystemParamFunction<(P1, P2, P3)> for F
94where
95    F: Fn(P1, P2, P3) + 'static,
96{
97    fn run(&self, world: &mut State) {
98        let Some(v1) = P1::get(world) else { return };
99        let Some(v2) = P2::get(world) else { return };
100        let Some(v3) = P3::get(world) else { return };
101
102        self(v1, v2, v3);
103    }
104}
105
106/// implement `SystemParamFunction` for function with four parameters
107impl<
108    F,
109    P1: SystemParam<Item = P1>,
110    P2: SystemParam<Item = P2>,
111    P3: SystemParam<Item = P3>,
112    P4: SystemParam<Item = P4>,
113> SystemParamFunction<(P1, P2, P3, P4)> for F
114where
115    F: Fn(P1, P2, P3, P4) + 'static,
116{
117    fn run(&self, world: &mut State) {
118        let Some(v1) = P1::get(world) else { return };
119        let Some(v2) = P2::get(world) else { return };
120        let Some(v3) = P3::get(world) else { return };
121        let Some(v4) = P4::get(world) else { return };
122
123        self(v1, v2, v3, v4);
124    }
125}
126
127/// implement `SystemParamFunction` for function with five parameters
128impl<
129    F,
130    P1: SystemParam<Item = P1>,
131    P2: SystemParam<Item = P2>,
132    P3: SystemParam<Item = P3>,
133    P4: SystemParam<Item = P4>,
134    P5: SystemParam<Item = P5>,
135> SystemParamFunction<(P1, P2, P3, P4, P5)> for F
136where
137    F: Fn(P1, P2, P3, P4, P5) + 'static,
138{
139    fn run(&self, world: &mut State) {
140        let Some(v1) = P1::get(world) else { return };
141        let Some(v2) = P2::get(world) else { return };
142        let Some(v3) = P3::get(world) else { return };
143        let Some(v4) = P4::get(world) else { return };
144        let Some(v5) = P5::get(world) else { return };
145
146        self(v1, v2, v3, v4, v5);
147    }
148}
149
150/// implement `SystemParamFunction` for function with six parameters
151impl<
152    F,
153    P1: SystemParam<Item = P1>,
154    P2: SystemParam<Item = P2>,
155    P3: SystemParam<Item = P3>,
156    P4: SystemParam<Item = P4>,
157    P5: SystemParam<Item = P5>,
158    P6: SystemParam<Item = P6>,
159> SystemParamFunction<(P1, P2, P3, P4, P5, P6)> for F
160where
161    F: Fn(P1, P2, P3, P4, P5, P6) + 'static,
162{
163    fn run(&self, world: &mut State) {
164        let Some(v1) = P1::get(world) else { return };
165        let Some(v2) = P2::get(world) else { return };
166        let Some(v3) = P3::get(world) else { return };
167        let Some(v4) = P4::get(world) else { return };
168        let Some(v5) = P5::get(world) else { return };
169        let Some(v6) = P6::get(world) else { return };
170
171        self(v1, v2, v3, v4, v5, v6);
172    }
173}
174
175/// implement `SystemParamFunction` for function with seven parameters
176impl<
177    F,
178    P1: SystemParam<Item = P1>,
179    P2: SystemParam<Item = P2>,
180    P3: SystemParam<Item = P3>,
181    P4: SystemParam<Item = P4>,
182    P5: SystemParam<Item = P5>,
183    P6: SystemParam<Item = P6>,
184    P7: SystemParam<Item = P7>,
185> SystemParamFunction<(P1, P2, P3, P4, P5, P6, P7)> for F
186where
187    F: Fn(P1, P2, P3, P4, P5, P6, P7) + 'static,
188{
189    fn run(&self, world: &mut State) {
190        let Some(v1) = P1::get(world) else { return };
191        let Some(v2) = P2::get(world) else { return };
192        let Some(v3) = P3::get(world) else { return };
193        let Some(v4) = P4::get(world) else { return };
194        let Some(v5) = P5::get(world) else { return };
195        let Some(v6) = P6::get(world) else { return };
196        let Some(v7) = P7::get(world) else { return };
197
198        self(v1, v2, v3, v4, v5, v6, v7);
199    }
200}
201
202/// implement `SystemParamFunction` for function with eight parameters
203impl<
204    F,
205    P1: SystemParam<Item = P1>,
206    P2: SystemParam<Item = P2>,
207    P3: SystemParam<Item = P3>,
208    P4: SystemParam<Item = P4>,
209    P5: SystemParam<Item = P5>,
210    P6: SystemParam<Item = P6>,
211    P7: SystemParam<Item = P7>,
212    P8: SystemParam<Item = P8>,
213> SystemParamFunction<(P1, P2, P3, P4, P5, P6, P7, P8)> for F
214where
215    F: Fn(P1, P2, P3, P4, P5, P6, P7, P8) + 'static,
216{
217    fn run(&self, world: &mut State) {
218        let Some(v1) = P1::get(world) else { return };
219        let Some(v2) = P2::get(world) else { return };
220        let Some(v3) = P3::get(world) else { return };
221        let Some(v4) = P4::get(world) else { return };
222        let Some(v5) = P5::get(world) else { return };
223        let Some(v6) = P6::get(world) else { return };
224        let Some(v7) = P7::get(world) else { return };
225        let Some(v8) = P8::get(world) else { return };
226
227        self(v1, v2, v3, v4, v5, v6, v7, v8);
228    }
229}
230
231/// Abstraction of a parameter for a system function
232pub trait SystemParam: 'static {
233    type Item;
234
235    fn get(world: &mut State) -> Option<Self::Item>;
236}
237
238impl SystemParam for () {
239    type Item = ();
240
241    fn get(_world: &mut State) -> Option<Self::Item> {
242        // it is easy to fetch, it is nothing `()`
243        None
244    }
245}
246
247/// implement one parameter for a `SystemParam`
248impl<T1> SystemParam for (T1,)
249where
250    T1: SystemParam,
251{
252    type Item = (T1::Item,);
253
254    fn get(world: &mut State) -> Option<Self::Item> {
255        T1::get(world).map(|t1| (t1,))
256    }
257}
258
259/// implement two parameters for a `SystemParam`
260impl<T1, T2> SystemParam for (T1, T2)
261where
262    T1: SystemParam,
263    T2: SystemParam,
264{
265    type Item = (T1::Item, T2::Item);
266
267    fn get(world: &mut State) -> Option<Self::Item> {
268        T1::get(world).zip(T2::get(world))
269    }
270}
271
272/// implement three parameters for a `SystemParam`
273impl<T1, T2, T3> SystemParam for (T1, T2, T3)
274where
275    T1: SystemParam,
276    T2: SystemParam,
277    T3: SystemParam,
278{
279    type Item = (T1::Item, T2::Item, T3::Item);
280
281    fn get(world: &mut State) -> Option<Self::Item> {
282        Some((T1::get(world)?, T2::get(world)?, T3::get(world)?))
283    }
284}
285
286/// implement four parameters for a `SystemParam`
287impl<T1, T2, T3, T4> SystemParam for (T1, T2, T3, T4)
288where
289    T1: SystemParam,
290    T2: SystemParam,
291    T3: SystemParam,
292    T4: SystemParam,
293{
294    type Item = (T1::Item, T2::Item, T3::Item, T4::Item);
295
296    fn get(world: &mut State) -> Option<Self::Item> {
297        Some((
298            T1::get(world)?,
299            T2::get(world)?,
300            T3::get(world)?,
301            T4::get(world)?,
302        ))
303    }
304}
305
306/// implement five parameters for a `SystemParam`
307impl<T1, T2, T3, T4, T5> SystemParam for (T1, T2, T3, T4, T5)
308where
309    T1: SystemParam,
310    T2: SystemParam,
311    T3: SystemParam,
312    T4: SystemParam,
313    T5: SystemParam,
314{
315    type Item = (T1::Item, T2::Item, T3::Item, T4::Item, T5::Item);
316
317    fn get(world: &mut State) -> Option<Self::Item> {
318        Some((
319            T1::get(world)?,
320            T2::get(world)?,
321            T3::get(world)?,
322            T4::get(world)?,
323            T5::get(world)?,
324        ))
325    }
326}
327
328/// implement six parameters for a `SystemParam`
329impl<T1, T2, T3, T4, T5, T6> SystemParam for (T1, T2, T3, T4, T5, T6)
330where
331    T1: SystemParam,
332    T2: SystemParam,
333    T3: SystemParam,
334    T4: SystemParam,
335    T5: SystemParam,
336    T6: SystemParam,
337{
338    type Item = (T1::Item, T2::Item, T3::Item, T4::Item, T5::Item, T6::Item);
339
340    fn get(world: &mut State) -> Option<Self::Item> {
341        Some((
342            T1::get(world)?,
343            T2::get(world)?,
344            T3::get(world)?,
345            T4::get(world)?,
346            T5::get(world)?,
347            T6::get(world)?,
348        ))
349    }
350}
351
352/// implement seven parameters for a `SystemParam`
353impl<T1, T2, T3, T4, T5, T6, T7> SystemParam for (T1, T2, T3, T4, T5, T6, T7)
354where
355    T1: SystemParam,
356    T2: SystemParam,
357    T3: SystemParam,
358    T4: SystemParam,
359    T5: SystemParam,
360    T6: SystemParam,
361    T7: SystemParam,
362{
363    type Item = (
364        T1::Item,
365        T2::Item,
366        T3::Item,
367        T4::Item,
368        T5::Item,
369        T6::Item,
370        T7::Item,
371    );
372
373    fn get(world: &mut State) -> Option<Self::Item> {
374        Some((
375            T1::get(world)?,
376            T2::get(world)?,
377            T3::get(world)?,
378            T4::get(world)?,
379            T5::get(world)?,
380            T6::get(world)?,
381            T7::get(world)?,
382        ))
383    }
384}
385
386/// implement seven parameters for a `SystemParam`
387impl<T1, T2, T3, T4, T5, T6, T7, T8> SystemParam for (T1, T2, T3, T4, T5, T6, T7, T8)
388where
389    T1: SystemParam,
390    T2: SystemParam,
391    T3: SystemParam,
392    T4: SystemParam,
393    T5: SystemParam,
394    T6: SystemParam,
395    T7: SystemParam,
396    T8: SystemParam,
397{
398    type Item = (
399        T1::Item,
400        T2::Item,
401        T3::Item,
402        T4::Item,
403        T5::Item,
404        T6::Item,
405        T7::Item,
406        T8::Item,
407    );
408
409    fn get(world: &mut State) -> Option<Self::Item> {
410        Some((
411            T1::get(world)?,
412            T2::get(world)?,
413            T3::get(world)?,
414            T4::get(world)?,
415            T5::get(world)?,
416            T6::get(world)?,
417            T7::get(world)?,
418            T8::get(world)?,
419        ))
420    }
421}