summaryrefslogtreecommitdiff
path: root/ecs/src/system.rs
blob: a7ca4df983ac2f8111ca285b57df22f0775f427c (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
132
133
134
135
136
137
138
139
140
use std::fmt::Debug;

use ecs_macros::Component;
use seq_macro::seq;

use crate::uid::Uid;
use crate::World;

pub mod initializable;
pub mod stateful;

/// Metadata of a system.
#[derive(Debug)]
#[non_exhaustive]
pub struct Metadata
{
    pub ent_id: Uid,
}

pub trait System<'world, Impl>: 'static
{
    type Callbacks: Callbacks;

    fn run<'this>(&'this self, world: &'world World, metadata: Metadata)
    where
        'this: 'world;

    fn finish(self) -> (TypeErased, Self::Callbacks);
}

macro_rules! impl_system {
    ($c: tt) => {
        seq!(I in 0..$c {
            impl<'world, Func, #(TParam~I,)*> System<'world, fn(#(TParam~I,)*)>
                for Func
            where
                Func: Fn(#(TParam~I,)*) + Copy + 'static,
                #(TParam~I: Param<'world, Input = ()>,)*
            {
                type Callbacks = NoCallbacks;

                fn run<'this>(&'this self, world: &'world World, metadata: Metadata)
                where
                    'this: 'world
                {
                    let func = *self;

                    func(#({
                        TParam~I::new(world, &metadata)
                    },)*);
                }

                fn finish(self) -> (TypeErased, Self::Callbacks)
                {
                    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) };

                            self(#({
                                TParam~I::new(world, &metadata)
                            },)*);
                        }),
                    };

                    (type_erased, NoCallbacks)
                }
            }
        });
    };
}

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

pub trait Into<Impl>
{
    type System;

    fn into_system(self) -> Self::System;
}

pub struct TypeErased
{
    run: Box<TypeErasedRunFn>,
}

impl TypeErased
{
    /// Runs the system.
    ///
    /// # Safety
    /// `world_data` must live at least as long as the [`World`] the system belongs to.
    pub unsafe fn run(&self, world: &World, metadata: Metadata)
    {
        (self.run)(world, metadata);
    }
}

impl Debug for TypeErased
{
    fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result
    {
        formatter.debug_struct("TypeErased").finish_non_exhaustive()
    }
}

/// Function in [`TypeErased`] used to run the system.
type TypeErasedRunFn = dyn Fn(&World, Metadata);

/// A parameter to a [`System`].
pub trait Param<'world>
{
    type Input;

    fn new(world: &'world World, system_metadata: &Metadata) -> Self;
}

/// A type which can be used as input to a [`System`].
pub trait Input: 'static {}

pub trait Callbacks
{
    fn on_created(&mut self, world: &mut World, metadata: Metadata);
}

pub struct NoCallbacks;

impl Callbacks for NoCallbacks
{
    fn on_created(&mut self, _world: &mut World, _metadata: Metadata) {}
}

#[derive(Debug, Component)]
pub(crate) struct SystemComponent
{
    pub(crate) system: TypeErased,
}