1use std::cell::RefMut;
2use std::ops::{Deref, DerefMut};
3
4use crate::ecs::resources::Resources;
5
6pub struct Res<'a, T: hecs::Component> {
10 pub(crate) data: hecs::Ref<'a, T>,
11}
12
13impl<'a, T: hecs::Component> Deref for Res<'a, T> {
14 type Target = T;
15 fn deref(&self) -> &Self::Target {
16 &self.data
17 }
18}
19
20pub struct ResMut<'a, T: hecs::Component> {
24 data: hecs::RefMut<'a, T>,
25}
26
27impl<'a, T: hecs::Component> Deref for ResMut<'a, T> {
28 type Target = T;
29 fn deref(&self) -> &Self::Target {
30 &self.data
31 }
32}
33
34impl<'a, T: hecs::Component> DerefMut for ResMut<'a, T> {
35 fn deref_mut(&mut self) -> &mut Self::Target {
36 &mut self.data
37 }
38}
39
40pub struct Query<'a, Q: hecs::Query> {
65 world: &'a hecs::World,
66 borrow: hecs::QueryBorrow<'a, Q>,
67}
68
69impl<'a, Q: hecs::Query> Deref for Query<'a, Q> {
70 type Target = hecs::QueryBorrow<'a, Q>;
71 fn deref(&self) -> &Self::Target {
72 &self.borrow
73 }
74}
75
76impl<'a, Q: hecs::Query> DerefMut for Query<'a, Q> {
77 fn deref_mut(&mut self) -> &mut Self::Target {
78 &mut self.borrow
79 }
80}
81
82impl<'q, Q: hecs::Query> IntoIterator for &'q mut Query<'_, Q> {
83 type Item = Q::Item<'q>;
84 type IntoIter = hecs::QueryIter<'q, Q>;
85
86 fn into_iter(self) -> Self::IntoIter {
87 (&mut self.borrow).into_iter()
88 }
89}
90
91impl<'a, Q: hecs::Query> Query<'a, Q> {
92 pub fn get<T>(
106 &self,
107 entity: hecs::Entity,
108 f: impl for<'r> FnOnce(Q::Item<'r>) -> T,
109 ) -> Option<T> {
110 self.world.query_one::<Q>(entity).get().ok().map(f)
111 }
112
113 pub fn with<R: hecs::Query>(self) -> hecs::QueryBorrow<'a, hecs::With<Q, R>> {
117 self.borrow.with::<R>()
118 }
119
120 pub fn without<R: hecs::Query>(self) -> hecs::QueryBorrow<'a, hecs::Without<Q, R>> {
123 self.borrow.without::<R>()
124 }
125
126 pub fn single(&mut self) -> Q::Item<'_> {
134 self.get_single()
135 .expect("Query::single: expected exactly one matching entity")
136 }
137
138 pub fn get_single(&mut self) -> Option<Q::Item<'_>> {
141 let mut iter = self.borrow.iter();
142 let first = iter.next()?;
143 if iter.next().is_some() {
144 return None;
145 }
146 Some(first)
147 }
148}
149
150pub struct Commands<'a> {
155 buffer: RefMut<'a, hecs::CommandBuffer>,
156 resource_entity: hecs::Entity,
157}
158
159impl<'a> Commands<'a> {
160 pub fn insert_resource<T: hecs::Component>(&mut self, res: T) {
162 self.buffer.insert_one(self.resource_entity, res);
163 }
164
165 pub fn remove_resource<T: hecs::Component>(&mut self) {
167 self.buffer.remove_one::<T>(self.resource_entity);
168 }
169}
170
171impl<'a> Deref for Commands<'a> {
172 type Target = hecs::CommandBuffer;
173 fn deref(&self) -> &Self::Target {
174 &self.buffer
175 }
176}
177
178impl<'a> DerefMut for Commands<'a> {
179 fn deref_mut(&mut self) -> &mut Self::Target {
180 &mut self.buffer
181 }
182}
183
184pub struct Local<'a, T: Default + Send + Sync + 'static> {
194 data: &'a mut T,
195}
196
197impl<'a, T: Default + Send + Sync + 'static> Deref for Local<'a, T> {
198 type Target = T;
199 fn deref(&self) -> &Self::Target {
200 self.data
201 }
202}
203
204impl<'a, T: Default + Send + Sync + 'static> DerefMut for Local<'a, T> {
205 fn deref_mut(&mut self) -> &mut Self::Target {
206 self.data
207 }
208}
209
210pub trait SystemParam {
218 type Item<'a>;
219 type State: Default + 'static;
220 fn fetch<'a>(
221 state: &'a mut Self::State,
222 world: &'a hecs::World,
223 resources: &'a Resources,
224 ) -> Self::Item<'a>;
225}
226
227impl<T> SystemParam for Res<'static, T>
228where
229 T: 'static + Sync + Send,
230{
231 type Item<'a> = Res<'a, T>;
232 type State = ();
233
234 fn fetch<'a>(
235 _state: &'a mut Self::State,
236 world: &'a hecs::World,
237 resource: &'a Resources,
238 ) -> Self::Item<'a> {
239 Res {
240 data: resource.get_resource(world),
241 }
242 }
243}
244
245impl<T> SystemParam for Option<Res<'static, T>>
246where
247 T: 'static + Sync + Send,
248{
249 type Item<'a> = Option<Res<'a, T>>;
250 type State = ();
251
252 fn fetch<'a>(
253 _state: &'a mut Self::State,
254 world: &'a hecs::World,
255 resource: &'a Resources,
256 ) -> Self::Item<'a> {
257 if resource.has_resource::<T>(world) {
258 return Some(Res {
259 data: resource.get_resource(world),
260 });
261 }
262
263 None
264 }
265}
266
267impl<T> SystemParam for ResMut<'static, T>
268where
269 T: 'static + Sync + Send,
270{
271 type Item<'a> = ResMut<'a, T>;
272 type State = ();
273
274 fn fetch<'a>(
275 _state: &'a mut Self::State,
276 world: &'a hecs::World,
277 resource: &'a Resources,
278 ) -> Self::Item<'a> {
279 ResMut {
280 data: resource.get_resource_mut(world),
281 }
282 }
283}
284
285impl<T> SystemParam for Option<ResMut<'static, T>>
286where
287 T: 'static + Sync + Send,
288{
289 type Item<'a> = Option<ResMut<'a, T>>;
290 type State = ();
291
292 fn fetch<'a>(
293 _state: &'a mut Self::State,
294 world: &'a hecs::World,
295 resource: &'a Resources,
296 ) -> Self::Item<'a> {
297 if resource.has_resource::<T>(world) {
298 return Some(ResMut {
299 data: resource.get_resource_mut(world),
300 });
301 }
302
303 None
304 }
305}
306
307impl<Q> SystemParam for Query<'static, Q>
308where
309 Q: hecs::Query + 'static,
310{
311 type Item<'a> = Query<'a, Q>;
312 type State = ();
313
314 fn fetch<'a>(
315 _state: &'a mut Self::State,
316 world: &'a hecs::World,
317 _resources: &'a Resources,
318 ) -> Self::Item<'a> {
319 Query {
320 world: world,
321 borrow: world.query::<Q>(),
322 }
323 }
324}
325
326impl SystemParam for Commands<'static> {
327 type Item<'a> = Commands<'a>;
328 type State = ();
329
330 fn fetch<'a>(
331 _state: &'a mut Self::State,
332 _world: &'a hecs::World,
333 resources: &'a Resources,
334 ) -> Self::Item<'a> {
335 Commands {
336 buffer: resources.get_command_buffer(),
337 resource_entity: resources.resource_entity,
338 }
339 }
340}
341
342impl SystemParam for &'static hecs::World {
343 type Item<'a> = &'a hecs::World;
344 type State = ();
345
346 fn fetch<'a>(
347 _state: &'a mut Self::State,
348 world: &'a hecs::World,
349 _resources: &'a Resources,
350 ) -> Self::Item<'a> {
351 world
352 }
353}
354
355impl SystemParam for &'static Resources {
356 type Item<'a> = &'a Resources;
357 type State = ();
358
359 fn fetch<'a>(
360 _state: &'a mut Self::State,
361 _world: &'a hecs::World,
362 resources: &'a Resources,
363 ) -> Self::Item<'a> {
364 resources
365 }
366}
367
368impl<T> SystemParam for Local<'static, T>
369where
370 T: Default + Send + Sync + 'static,
371{
372 type Item<'a> = Local<'a, T>;
373 type State = T;
374
375 fn fetch<'a>(
376 state: &'a mut Self::State,
377 _world: &'a hecs::World,
378 _resources: &'a Resources,
379 ) -> Self::Item<'a> {
380 Local { data: state }
381 }
382}
383
384pub trait System: 'static {
386 fn run(&mut self, world: &hecs::World, resources: &Resources);
387}
388
389pub struct FunctionSystem<F, Marker, State = ()> {
394 pub func: F,
395 state: State,
396 _marker: std::marker::PhantomData<Marker>,
397}
398
399pub trait IntoSystem<Marker> {
404 type System: System;
405
406 fn into_system(self) -> Self::System;
407}
408
409macro_rules! impl_system {
410 ($($param:ident),*) => {
411 impl<T, $($param),*> IntoSystem<($($param,)*)> for T
412 where
413 T: for<'a> FnMut($($param::Item<'a>),*) + 'static,
414 for<'a> &'a mut T: FnMut($($param),*),
415 $($param: SystemParam + 'static),*
416 {
417 type System = FunctionSystem<T, ($($param,)*), ($($param::State,)*)>;
418
419 fn into_system(self) -> Self::System {
420 FunctionSystem {
421 func: self,
422 state: Default::default(),
423 _marker: std::marker::PhantomData,
424 }
425 }
426 }
427
428 impl<T, $($param),*> System for FunctionSystem<T, ($($param,)*), ($($param::State,)*)>
429 where
430 T: for<'a> FnMut($($param::Item<'a>),*) + 'static,
431 $($param: SystemParam + 'static),*
432 {
433 fn run(&mut self, _world: &hecs::World, _resources: &Resources) {
434 #[allow(non_snake_case)]
435 let ($($param,)*) = &mut self.state;
436 (self.func)($($param::fetch($param, _world, _resources)),*);
437 }
438 }
439 };
440}
441
442impl_system!();
443impl_system!(A);
444impl_system!(A, B);
445impl_system!(A, B, C);
446impl_system!(A, B, C, D);
447impl_system!(A, B, C, D, E);
448impl_system!(A, B, C, D, E, F);
449impl_system!(A, B, C, D, E, F, G);
450impl_system!(A, B, C, D, E, F, G, H);