Skip to main content

pebble/
system.rs

1use std::cell::RefMut;
2use std::ops::{Deref, DerefMut};
3
4use crate::resources::Resources;
5
6pub struct Res<'a, T: hecs::Component> {
7    data: hecs::Ref<'a, T>,
8}
9
10impl<'a, T: hecs::Component> Deref for Res<'a, T> {
11    type Target = T;
12    fn deref(&self) -> &Self::Target {
13        &self.data
14    }
15}
16
17pub struct ResMut<'a, T: hecs::Component> {
18    data: hecs::RefMut<'a, T>,
19}
20
21impl<'a, T: hecs::Component> Deref for ResMut<'a, T> {
22    type Target = T;
23    fn deref(&self) -> &Self::Target {
24        &self.data
25    }
26}
27
28impl<'a, T: hecs::Component> DerefMut for ResMut<'a, T> {
29    fn deref_mut(&mut self) -> &mut Self::Target {
30        &mut self.data
31    }
32}
33
34pub struct Query<'a, Q: hecs::Query> {
35    borrow: hecs::QueryBorrow<'a, Q>,
36}
37
38impl<'a, Q: hecs::Query> Deref for Query<'a, Q> {
39    type Target = hecs::QueryBorrow<'a, Q>;
40    fn deref(&self) -> &Self::Target {
41        &self.borrow
42    }
43}
44
45impl<'a, Q: hecs::Query> DerefMut for Query<'a, Q> {
46    fn deref_mut(&mut self) -> &mut Self::Target {
47        &mut self.borrow
48    }
49}
50
51pub struct Commands<'a> {
52    buffer: RefMut<'a, hecs::CommandBuffer>,
53    resource_entity: hecs::Entity,
54}
55
56impl<'a> Commands<'a> {
57    pub fn insert_resource<T: hecs::Component>(&mut self, res: T) {
58        self.buffer.insert_one(self.resource_entity, res);
59    }
60
61    pub fn remove_resource<T: hecs::Component>(&mut self) {
62        self.buffer.remove_one::<T>(self.resource_entity);
63    }
64}
65
66impl<'a> Deref for Commands<'a> {
67    type Target = hecs::CommandBuffer;
68    fn deref(&self) -> &Self::Target {
69        &self.buffer
70    }
71}
72
73impl<'a> DerefMut for Commands<'a> {
74    fn deref_mut(&mut self) -> &mut Self::Target {
75        &mut self.buffer
76    }
77}
78
79trait SystemParam {
80    type Item<'a>;
81    fn fetch<'a>(world: &'a hecs::World, resources: &'a Resources) -> Self::Item<'a>;
82}
83
84impl<T> SystemParam for Res<'static, T>
85where
86    T: 'static + Sync + Send,
87{
88    type Item<'a> = Res<'a, T>;
89
90    fn fetch<'a>(world: &'a hecs::World, resource: &'a Resources) -> Self::Item<'a> {
91        Res {
92            data: resource.get_resource(world),
93        }
94    }
95}
96
97impl<T> SystemParam for Option<Res<'static, T>>
98where
99    T: 'static + Sync + Send,
100{
101    type Item<'a> = Option<Res<'a, T>>;
102
103    fn fetch<'a>(world: &'a hecs::World, resource: &'a Resources) -> Self::Item<'a> {
104        if resource.has_resource::<T>(world) {
105            return Some(Res {
106                data: resource.get_resource(world),
107            });
108        }
109
110        None
111    }
112}
113
114impl<T> SystemParam for ResMut<'static, T>
115where
116    T: 'static + Sync + Send,
117{
118    type Item<'a> = ResMut<'a, T>;
119
120    fn fetch<'a>(world: &'a hecs::World, resource: &'a Resources) -> Self::Item<'a> {
121        ResMut {
122            data: resource.get_resource_mut(world),
123        }
124    }
125}
126
127impl<T> SystemParam for Option<ResMut<'static, T>>
128where
129    T: 'static + Sync + Send,
130{
131    type Item<'a> = Option<ResMut<'a, T>>;
132
133    fn fetch<'a>(world: &'a hecs::World, resource: &'a Resources) -> Self::Item<'a> {
134        if resource.has_resource::<T>(world) {
135            return Some(ResMut {
136                data: resource.get_resource_mut(world),
137            });
138        }
139
140        None
141    }
142}
143
144impl<Q> SystemParam for Query<'static, Q>
145where
146    Q: hecs::Query + 'static,
147{
148    type Item<'a> = Query<'a, Q>;
149
150    fn fetch<'a>(world: &'a hecs::World, _resources: &'a Resources) -> Self::Item<'a> {
151        Query {
152            borrow: world.query::<Q>(),
153        }
154    }
155}
156
157impl SystemParam for Commands<'static> {
158    type Item<'a> = Commands<'a>;
159
160    fn fetch<'a>(_world: &'a hecs::World, resources: &'a Resources) -> Self::Item<'a> {
161        Commands {
162            buffer: resources.get_command_buffer(),
163            resource_entity: resources.resource_entity,
164        }
165    }
166}
167
168pub trait System: 'static {
169    fn run(&mut self, world: &hecs::World, resources: &Resources);
170}
171
172pub struct FunctionSystem<F, Marker> {
173    pub func: F,
174    _marker: std::marker::PhantomData<Marker>,
175}
176
177pub trait IntoSystem<Marker> {
178    type System: System;
179
180    fn into_system(self) -> Self::System;
181}
182
183macro_rules! impl_system {
184    ($($param:ident),*) => {
185        impl<T, $($param),*> IntoSystem<($($param,)*)> for T
186        where
187            T: for<'a> FnMut($($param::Item<'a>),*) + 'static,
188            for<'a> &'a mut T: FnMut($($param),*),
189            $($param: SystemParam + 'static),*
190        {
191            type System = FunctionSystem<T, ($($param,)*)>;
192
193            fn into_system(self) -> Self::System {
194                FunctionSystem {
195                    func: self,
196                    _marker: std::marker::PhantomData,
197                }
198            }
199        }
200
201        impl<T, $($param),*> System for FunctionSystem<T, ($($param,)*)>
202        where
203            T: for<'a> FnMut($($param::Item<'a>),*) + 'static,
204            $($param: SystemParam + 'static),*
205        {
206            fn run(&mut self, _world: &hecs::World, _resources: &Resources) {
207                (self.func)($($param::fetch(_world, _resources)),*);
208            }
209        }
210    };
211}
212
213impl_system!();
214impl_system!(A);
215impl_system!(A, B);
216impl_system!(A, B, C);
217impl_system!(A, B, C, D);
218impl_system!(A, B, C, D, E);
219impl_system!(A, B, C, D, E, F);
220impl_system!(A, B, C, D, E, F, G);
221impl_system!(A, B, C, D, E, F, G, H);