1use std::cell::RefMut;
2use std::ops::{Deref, DerefMut};
3
4use crate::ecs::resources::Resources;
5use crate::threading::SpawnableFuture;
9
10#[derive(Clone, Copy)]
20pub struct RequiredResource {
21 pub name: &'static str,
22 pub type_id: std::any::TypeId,
23 pub present: fn(&hecs::World, &Resources) -> bool,
24 pub hint: Option<&'static str>,
31}
32
33pub struct Res<'a, T: hecs::Component> {
37 pub(crate) data: hecs::Ref<'a, T>,
38}
39
40impl<'a, T: hecs::Component> Deref for Res<'a, T> {
41 type Target = T;
42 fn deref(&self) -> &Self::Target {
43 &self.data
44 }
45}
46
47pub struct ResMut<'a, T: hecs::Component> {
51 data: hecs::RefMut<'a, T>,
52}
53
54impl<'a, T: hecs::Component> Deref for ResMut<'a, T> {
55 type Target = T;
56 fn deref(&self) -> &Self::Target {
57 &self.data
58 }
59}
60
61impl<'a, T: hecs::Component> DerefMut for ResMut<'a, T> {
62 fn deref_mut(&mut self) -> &mut Self::Target {
63 &mut self.data
64 }
65}
66
67pub struct Query<'a, Q: hecs::Query> {
108 world: &'a hecs::World,
109 borrow: hecs::QueryBorrow<'a, Q>,
110 scratch: Option<hecs::QueryOne<'a, Q>>,
115}
116
117impl<'q, Q: hecs::Query> IntoIterator for &'q mut Query<'_, Q> {
118 type Item = Q::Item<'q>;
119 type IntoIter = hecs::QueryIter<'q, Q>;
120
121 fn into_iter(self) -> Self::IntoIter {
122 (&mut self.borrow).into_iter()
123 }
124}
125
126impl<'a, Q: hecs::Query> Query<'a, Q> {
127 pub fn iter(&mut self) -> impl Iterator<Item = Q::Item<'_>> {
131 self.borrow.iter()
132 }
133
134 pub fn get(&mut self, entity: hecs::Entity) -> Option<Q::Item<'_>> {
137 self.scratch = Some(self.world.query_one::<Q>(entity));
138 self.scratch.as_mut().unwrap().get().ok()
139 }
140
141 pub fn with<R: hecs::Query>(self) -> Query<'a, hecs::With<Q, R>> {
145 Query { world: self.world, borrow: self.borrow.with::<R>(), scratch: None }
146 }
147
148 pub fn without<R: hecs::Query>(self) -> Query<'a, hecs::Without<Q, R>> {
151 Query { world: self.world, borrow: self.borrow.without::<R>(), scratch: None }
152 }
153
154 pub fn single(&mut self) -> Q::Item<'_> {
162 self.get_single()
163 .expect("Query::single: expected exactly one matching entity")
164 }
165
166 pub fn get_single(&mut self) -> Option<Q::Item<'_>> {
169 let mut iter = self.borrow.iter();
170 let first = iter.next()?;
171 if iter.next().is_some() {
172 return None;
173 }
174 Some(first)
175 }
176}
177
178pub struct Commands<'a> {
187 buffer: RefMut<'a, hecs::CommandBuffer>,
188 resource_entity: hecs::Entity,
189 resources: &'a Resources,
191}
192
193impl<'a> Commands<'a> {
194 pub fn insert_resource<T: hecs::Component>(&mut self, res: T) {
200 self.buffer.insert_one(self.resource_entity, res);
201 self.resources.bump_generation();
202 }
203
204 pub fn remove_resource<T: hecs::Component>(&mut self) {
206 self.buffer.remove_one::<T>(self.resource_entity);
207 }
208}
209
210impl<'a> Deref for Commands<'a> {
211 type Target = hecs::CommandBuffer;
212 fn deref(&self) -> &Self::Target {
213 &self.buffer
214 }
215}
216
217impl<'a> DerefMut for Commands<'a> {
218 fn deref_mut(&mut self) -> &mut Self::Target {
219 &mut self.buffer
220 }
221}
222
223pub struct Local<'a, T: Default + Send + Sync + 'static> {
233 data: &'a mut T,
234}
235
236impl<'a, T: Default + Send + Sync + 'static> Deref for Local<'a, T> {
237 type Target = T;
238 fn deref(&self) -> &Self::Target {
239 self.data
240 }
241}
242
243impl<'a, T: Default + Send + Sync + 'static> DerefMut for Local<'a, T> {
244 fn deref_mut(&mut self) -> &mut Self::Target {
245 self.data
246 }
247}
248
249pub trait SystemParam {
257 type Item<'a>;
258 type State: Default + 'static;
259 fn fetch<'a>(
260 state: &'a mut Self::State,
261 world: &'a hecs::World,
262 resources: &'a Resources,
263 ) -> Self::Item<'a>;
264
265 fn requires() -> Vec<RequiredResource> {
276 Vec::new()
277 }
278}
279
280impl<T> SystemParam for Res<'static, T>
281where
282 T: 'static + Sync + Send,
283{
284 type Item<'a> = Res<'a, T>;
285 type State = ();
286
287 fn fetch<'a>(
288 _state: &'a mut Self::State,
289 world: &'a hecs::World,
290 resource: &'a Resources,
291 ) -> Self::Item<'a> {
292 Res {
293 data: resource.get_resource(world),
294 }
295 }
296
297 fn requires() -> Vec<RequiredResource> {
298 vec![RequiredResource {
299 name: std::any::type_name::<T>(),
300 type_id: std::any::TypeId::of::<T>(),
301 present: |world, resources| resources.has_resource::<T>(world),
302 hint: None,
303 }]
304 }
305}
306
307impl<T> SystemParam for Option<Res<'static, T>>
308where
309 T: 'static + Sync + Send,
310{
311 type Item<'a> = Option<Res<'a, T>>;
312 type State = ();
313
314 fn fetch<'a>(
315 _state: &'a mut Self::State,
316 world: &'a hecs::World,
317 resource: &'a Resources,
318 ) -> Self::Item<'a> {
319 if resource.has_resource::<T>(world) {
320 return Some(Res {
321 data: resource.get_resource(world),
322 });
323 }
324
325 None
326 }
327}
328
329impl<T> SystemParam for ResMut<'static, T>
330where
331 T: 'static + Sync + Send,
332{
333 type Item<'a> = ResMut<'a, T>;
334 type State = ();
335
336 fn fetch<'a>(
337 _state: &'a mut Self::State,
338 world: &'a hecs::World,
339 resource: &'a Resources,
340 ) -> Self::Item<'a> {
341 ResMut {
342 data: resource.get_resource_mut(world),
343 }
344 }
345
346 fn requires() -> Vec<RequiredResource> {
347 vec![RequiredResource {
348 name: std::any::type_name::<T>(),
349 type_id: std::any::TypeId::of::<T>(),
350 present: |world, resources| resources.has_resource::<T>(world),
351 hint: None,
352 }]
353 }
354}
355
356impl<T> SystemParam for Option<ResMut<'static, T>>
357where
358 T: 'static + Sync + Send,
359{
360 type Item<'a> = Option<ResMut<'a, T>>;
361 type State = ();
362
363 fn fetch<'a>(
364 _state: &'a mut Self::State,
365 world: &'a hecs::World,
366 resource: &'a Resources,
367 ) -> Self::Item<'a> {
368 if resource.has_resource::<T>(world) {
369 return Some(ResMut {
370 data: resource.get_resource_mut(world),
371 });
372 }
373
374 None
375 }
376}
377
378impl<Q> SystemParam for Query<'static, Q>
379where
380 Q: hecs::Query + 'static,
381{
382 type Item<'a> = Query<'a, Q>;
383 type State = ();
384
385 fn fetch<'a>(
386 _state: &'a mut Self::State,
387 world: &'a hecs::World,
388 _resources: &'a Resources,
389 ) -> Self::Item<'a> {
390 Query {
391 world,
392 borrow: world.query::<Q>(),
393 scratch: None,
394 }
395 }
396}
397
398impl SystemParam for Commands<'static> {
399 type Item<'a> = Commands<'a>;
400 type State = ();
401
402 fn fetch<'a>(
403 _state: &'a mut Self::State,
404 _world: &'a hecs::World,
405 resources: &'a Resources,
406 ) -> Self::Item<'a> {
407 Commands {
408 buffer: resources.get_command_buffer(),
409 resource_entity: resources.resource_entity,
410 resources,
411 }
412 }
413}
414
415impl SystemParam for &'static hecs::World {
416 type Item<'a> = &'a hecs::World;
417 type State = ();
418
419 fn fetch<'a>(
420 _state: &'a mut Self::State,
421 world: &'a hecs::World,
422 _resources: &'a Resources,
423 ) -> Self::Item<'a> {
424 world
425 }
426}
427
428impl SystemParam for &'static Resources {
429 type Item<'a> = &'a Resources;
430 type State = ();
431
432 fn fetch<'a>(
433 _state: &'a mut Self::State,
434 _world: &'a hecs::World,
435 resources: &'a Resources,
436 ) -> Self::Item<'a> {
437 resources
438 }
439}
440
441impl<T> SystemParam for Local<'static, T>
442where
443 T: Default + Send + Sync + 'static,
444{
445 type Item<'a> = Local<'a, T>;
446 type State = T;
447
448 fn fetch<'a>(
449 state: &'a mut Self::State,
450 _world: &'a hecs::World,
451 _resources: &'a Resources,
452 ) -> Self::Item<'a> {
453 Local { data: state }
454 }
455}
456
457pub trait System: 'static {
459 fn run(&mut self, world: &hecs::World, resources: &Resources);
460
461 fn requires(&self) -> Vec<RequiredResource> {
468 Vec::new()
469 }
470
471 fn name(&self) -> &'static str {
477 std::any::type_name::<Self>()
478 }
479
480 fn ordering_id(&self) -> std::any::TypeId {
489 std::any::TypeId::of::<Self>()
490 }
491
492 fn after_ids(&self) -> &[std::any::TypeId] {
496 &[]
497 }
498
499 fn before_ids(&self) -> &[std::any::TypeId] {
503 &[]
504 }
505}
506
507pub struct Labeled<S: System> {
516 inner: S,
517 after: Vec<std::any::TypeId>,
518 before: Vec<std::any::TypeId>,
519}
520
521impl<S: System> Labeled<S> {
522 pub fn after<F: 'static, Marker>(mut self, system: F) -> Self
525 where
526 F: IntoSystem<Marker>,
527 {
528 let _ = system;
529 self.after.push(std::any::TypeId::of::<F>());
530 self
531 }
532
533 pub fn before<F: 'static, Marker>(mut self, system: F) -> Self
536 where
537 F: IntoSystem<Marker>,
538 {
539 let _ = system;
540 self.before.push(std::any::TypeId::of::<F>());
541 self
542 }
543}
544
545impl<S: System> System for Labeled<S> {
546 fn run(&mut self, world: &hecs::World, resources: &Resources) {
547 self.inner.run(world, resources)
548 }
549
550 fn requires(&self) -> Vec<RequiredResource> {
551 self.inner.requires()
552 }
553
554 fn name(&self) -> &'static str {
555 self.inner.name()
556 }
557
558 fn ordering_id(&self) -> std::any::TypeId {
559 self.inner.ordering_id()
560 }
561
562 fn after_ids(&self) -> &[std::any::TypeId] {
563 &self.after
564 }
565
566 fn before_ids(&self) -> &[std::any::TypeId] {
567 &self.before
568 }
569}
570
571impl<S: System> IntoSystem<()> for Labeled<S> {
572 type System = Self;
573
574 fn into_system(self) -> Self::System {
575 self
576 }
577}
578
579pub trait SystemOrderingExt<Marker>: IntoSystem<Marker> + Sized {
589 fn after<F: 'static, Marker2>(self, system: F) -> Labeled<Self::System>
591 where
592 F: IntoSystem<Marker2>,
593 {
594 let _ = system;
595 Labeled {
596 inner: self.into_system(),
597 after: vec![std::any::TypeId::of::<F>()],
598 before: Vec::new(),
599 }
600 }
601
602 fn before<F: 'static, Marker2>(self, system: F) -> Labeled<Self::System>
604 where
605 F: IntoSystem<Marker2>,
606 {
607 let _ = system;
608 Labeled {
609 inner: self.into_system(),
610 after: Vec::new(),
611 before: vec![std::any::TypeId::of::<F>()],
612 }
613 }
614}
615
616impl<T, Marker> SystemOrderingExt<Marker> for T where T: IntoSystem<Marker> {}
617
618pub struct FunctionSystem<F, Marker, State = ()> {
623 pub func: F,
624 state: State,
625 _marker: std::marker::PhantomData<Marker>,
626}
627
628pub trait IntoSystem<Marker> {
633 type System: System;
634
635 fn into_system(self) -> Self::System;
636}
637
638macro_rules! impl_system {
639 ($($param:ident),*) => {
640 impl<T, $($param),*> IntoSystem<($($param,)*)> for T
641 where
642 T: for<'a> FnMut($($param::Item<'a>),*) + 'static,
643 for<'a> &'a mut T: FnMut($($param),*),
644 $($param: SystemParam + 'static),*
645 {
646 type System = FunctionSystem<T, ($($param,)*), ($($param::State,)*)>;
647
648 fn into_system(self) -> Self::System {
649 FunctionSystem {
650 func: self,
651 state: Default::default(),
652 _marker: std::marker::PhantomData,
653 }
654 }
655 }
656
657 impl<T, $($param),*> System for FunctionSystem<T, ($($param,)*), ($($param::State,)*)>
658 where
659 T: for<'a> FnMut($($param::Item<'a>),*) + 'static,
660 $($param: SystemParam + 'static),*
661 {
662 fn run(&mut self, _world: &hecs::World, _resources: &Resources) {
663 #[allow(non_snake_case)]
664 let ($($param,)*) = &mut self.state;
665 (self.func)($($param::fetch($param, _world, _resources)),*);
666 }
667
668 fn requires(&self) -> Vec<RequiredResource> {
669 let mut _v = Vec::new();
670 $(_v.extend($param::requires());)*
671 _v
672 }
673
674 fn name(&self) -> &'static str {
675 std::any::type_name::<T>()
676 }
677
678 fn ordering_id(&self) -> std::any::TypeId {
679 std::any::TypeId::of::<T>()
680 }
681 }
682 };
683}
684
685impl_system!();
686impl_system!(A);
687impl_system!(A, B);
688impl_system!(A, B, C);
689impl_system!(A, B, C, D);
690impl_system!(A, B, C, D, E);
691impl_system!(A, B, C, D, E, F);
692impl_system!(A, B, C, D, E, F, G);
693impl_system!(A, B, C, D, E, F, G, H);
694impl_system!(A, B, C, D, E, F, G, H, I);
695impl_system!(A, B, C, D, E, F, G, H, I, J);
696impl_system!(A, B, C, D, E, F, G, H, I, J, K);
697impl_system!(A, B, C, D, E, F, G, H, I, J, K, L);
698
699pub struct OnceFunctionSystem<F, Marker, State = ()> {
706 func: F,
707 state: State,
708 done: bool,
709 _marker: std::marker::PhantomData<Marker>,
710}
711
712pub trait OnceExt<Marker> {
734 type System: System;
735 fn once(self) -> Self::System;
736}
737
738macro_rules! impl_once_system {
739 ($($param:ident),*) => {
740 impl<T, $($param),*> OnceExt<($($param,)*)> for T
741 where
742 T: for<'a> FnMut($($param::Item<'a>),*) -> Option<()> + 'static,
743 for<'a> &'a mut T: FnMut($($param),*) -> Option<()>,
744 $($param: SystemParam + 'static),*
745 {
746 type System = OnceFunctionSystem<T, ($($param,)*), ($($param::State,)*)>;
747
748 fn once(self) -> Self::System {
749 OnceFunctionSystem {
750 func: self,
751 state: Default::default(),
752 done: false,
753 _marker: std::marker::PhantomData,
754 }
755 }
756 }
757
758 impl<T, $($param),*> IntoSystem<($($param,)*)> for OnceFunctionSystem<T, ($($param,)*), ($($param::State,)*)>
759 where
760 T: for<'a> FnMut($($param::Item<'a>),*) -> Option<()> + 'static,
761 $($param: SystemParam + 'static),*
762 {
763 type System = Self;
764
765 fn into_system(self) -> Self::System {
766 self
767 }
768 }
769
770 impl<T, $($param),*> System for OnceFunctionSystem<T, ($($param,)*), ($($param::State,)*)>
771 where
772 T: for<'a> FnMut($($param::Item<'a>),*) -> Option<()> + 'static,
773 $($param: SystemParam + 'static),*
774 {
775 fn run(&mut self, _world: &hecs::World, _resources: &Resources) {
776 if self.done {
777 return;
778 }
779 #[allow(non_snake_case)]
780 let ($($param,)*) = &mut self.state;
781 let result = (self.func)($($param::fetch($param, _world, _resources)),*);
782 if result.is_some() {
783 self.done = true;
784 }
785 }
786
787 fn requires(&self) -> Vec<RequiredResource> {
788 if self.done {
789 return Vec::new();
790 }
791 let mut _v = Vec::new();
792 $(_v.extend($param::requires());)*
793 _v
794 }
795
796 fn name(&self) -> &'static str {
797 std::any::type_name::<T>()
798 }
799
800 fn ordering_id(&self) -> std::any::TypeId {
801 std::any::TypeId::of::<T>()
802 }
803 }
804 };
805}
806
807impl_once_system!();
808impl_once_system!(A);
809impl_once_system!(A, B);
810impl_once_system!(A, B, C);
811impl_once_system!(A, B, C, D);
812impl_once_system!(A, B, C, D, E);
813impl_once_system!(A, B, C, D, E, F);
814impl_once_system!(A, B, C, D, E, F, G);
815impl_once_system!(A, B, C, D, E, F, G, H);
816impl_once_system!(A, B, C, D, E, F, G, H, I);
817impl_once_system!(A, B, C, D, E, F, G, H, I, J);
818impl_once_system!(A, B, C, D, E, F, G, H, I, J, K);
819impl_once_system!(A, B, C, D, E, F, G, H, I, J, K, L);
820
821pub struct DetachedFunctionSystem<F, Marker, State = ()> {
824 func: F,
825 state: State,
826 _marker: std::marker::PhantomData<Marker>,
827}
828
829pub trait AsyncExt<Marker> {
872 type System: System;
873 fn detach(self) -> Self::System;
874}
875
876macro_rules! impl_async_system {
877 ($($param:ident),*) => {
878 impl<T, Fut, $($param),*> AsyncExt<($($param,)*)> for T
879 where
880 T: for<'a> FnMut($($param::Item<'a>),*) -> Fut + 'static,
881 for<'a> &'a mut T: FnMut($($param),*) -> Fut,
882 Fut: SpawnableFuture<()>,
883 $($param: SystemParam + 'static),*
884 {
885 type System = DetachedFunctionSystem<T, ($($param,)*), ($($param::State,)*)>;
886
887 fn detach(self) -> Self::System {
888 DetachedFunctionSystem {
889 func: self,
890 state: Default::default(),
891 _marker: std::marker::PhantomData,
892 }
893 }
894 }
895
896 impl<T, Fut, $($param),*> IntoSystem<($($param,)*)> for DetachedFunctionSystem<T, ($($param,)*), ($($param::State,)*)>
897 where
898 T: for<'a> FnMut($($param::Item<'a>),*) -> Fut + 'static,
899 Fut: SpawnableFuture<()>,
900 $($param: SystemParam + 'static),*
901 {
902 type System = Self;
903
904 fn into_system(self) -> Self::System {
905 self
906 }
907 }
908
909 impl<T, Fut, $($param),*> System for DetachedFunctionSystem<T, ($($param,)*), ($($param::State,)*)>
910 where
911 T: for<'a> FnMut($($param::Item<'a>),*) -> Fut + 'static,
912 Fut: SpawnableFuture<()>,
913 $($param: SystemParam + 'static),*
914 {
915 fn run(&mut self, _world: &hecs::World, _resources: &Resources) {
916 #[allow(non_snake_case)]
917 let ($($param,)*) = &mut self.state;
918 let future = (self.func)($($param::fetch($param, _world, _resources)),*);
919 let tasks = _resources.get_resource::<crate::threading::BackgroundTasks>(_world);
920 let _ = tasks.spawn_async(future);
921 }
922
923 fn requires(&self) -> Vec<RequiredResource> {
924 let mut _v = vec![RequiredResource {
925 name: std::any::type_name::<crate::threading::BackgroundTasks>(),
926 type_id: std::any::TypeId::of::<crate::threading::BackgroundTasks>(),
927 present: |world, resources| resources.has_resource::<crate::threading::BackgroundTasks>(world),
928 hint: Some(
929 "`.detach()` drives its future through `BackgroundTasks` — register \
930 `app.add_plugin(BackgroundTasksPlugin::new(worker_count))` before this system runs.",
931 ),
932 }];
933 $(_v.extend($param::requires());)*
934 _v
935 }
936
937 fn name(&self) -> &'static str {
938 std::any::type_name::<T>()
939 }
940
941 fn ordering_id(&self) -> std::any::TypeId {
942 std::any::TypeId::of::<T>()
943 }
944 }
945 };
946}
947
948impl_async_system!();
949impl_async_system!(A);
950impl_async_system!(A, B);
951impl_async_system!(A, B, C);
952impl_async_system!(A, B, C, D);
953impl_async_system!(A, B, C, D, E);
954impl_async_system!(A, B, C, D, E, F);
955impl_async_system!(A, B, C, D, E, F, G);
956impl_async_system!(A, B, C, D, E, F, G, H);
957impl_async_system!(A, B, C, D, E, F, G, H, I);
958impl_async_system!(A, B, C, D, E, F, G, H, I, J);
959impl_async_system!(A, B, C, D, E, F, G, H, I, J, K);
960impl_async_system!(A, B, C, D, E, F, G, H, I, J, K, L);
961
962#[cfg(test)]
963mod tests {
964 use super::*;
965
966 struct Health(i32);
967 struct Enemy;
968 struct Dead;
969
970 fn make_query<Q: hecs::Query>(world: &hecs::World) -> Query<'_, Q> {
971 Query { world, borrow: world.query::<Q>(), scratch: None }
972 }
973
974 #[test]
975 fn iter_yields_every_matching_entity() {
976 let mut world = hecs::World::new();
977 world.spawn((Health(10),));
978 world.spawn((Health(20),));
979
980 let mut query = make_query::<&Health>(&world);
981 let mut totals: Vec<i32> = query.iter().map(|h| h.0).collect();
982 totals.sort();
983 assert_eq!(totals, vec![10, 20]);
984 }
985
986 #[test]
987 fn iter_composes_with_standard_iterator_adapters() {
988 let mut world = hecs::World::new();
991 world.spawn((Health(5),));
992 world.spawn((Health(50),));
993
994 let mut query = make_query::<&Health>(&world);
995 let low_health_count = query.iter().filter(|h| h.0 < 10).count();
996 assert_eq!(low_health_count, 1);
997 }
998
999 #[test]
1000 fn get_returns_some_for_a_matching_entity_and_none_otherwise() {
1001 let mut world = hecs::World::new();
1002 let matching = world.spawn((Health(7),));
1003 let non_matching = world.spawn(()); let mut query = make_query::<&Health>(&world);
1006 assert_eq!(query.get(matching).map(|h| h.0), Some(7));
1007 assert!(query.get(non_matching).is_none());
1008 }
1009
1010 #[test]
1011 fn get_can_be_called_more_than_once_on_the_same_query() {
1012 let mut world = hecs::World::new();
1015 let a = world.spawn((Health(1),));
1016 let b = world.spawn((Health(2),));
1017
1018 let mut query = make_query::<&Health>(&world);
1019 assert_eq!(query.get(a).map(|h| h.0), Some(1));
1020 assert_eq!(query.get(b).map(|h| h.0), Some(2));
1021 }
1022
1023 #[test]
1024 fn with_and_without_chain_and_narrow_by_component_presence() {
1025 let mut world = hecs::World::new();
1026 let alive_enemy = world.spawn((Health(1), Enemy));
1027 world.spawn((Health(1), Enemy, Dead));
1028 world.spawn((Health(1),));
1029
1030 let query = make_query::<&Health>(&world);
1031 let mut narrowed = query.with::<&Enemy>().without::<&Dead>();
1034
1035 assert_eq!(narrowed.iter().count(), 1);
1036 assert!(narrowed.get(alive_enemy).is_some());
1037 }
1038
1039 #[test]
1040 fn single_panics_on_zero_or_multiple_matches_get_single_does_not() {
1041 let mut world = hecs::World::new();
1042
1043 assert!(make_query::<&Health>(&world).get_single().is_none());
1044
1045 world.spawn((Health(1),));
1046 assert_eq!(make_query::<&Health>(&world).single().0, 1);
1047
1048 world.spawn((Health(2),));
1049 assert!(make_query::<&Health>(&world).get_single().is_none());
1050 }
1051}