1use std::any::TypeId;
2use std::iter::FusedIterator;
3use std::marker::PhantomData;
4use std::mem::{transmute, transmute_copy, MaybeUninit};
5use std::ptr::NonNull;
6use std::slice::Iter;
7
8use crate::{
9 archetype::Archetype,
10 borrow_flags::{BorrowFlags, Ref, RefMut},
11 world::{Entity, EntityMetadata, World},
12};
13
14#[cfg(feature = "rayon")]
15use crate::rayon::QueryParIter;
16
17pub struct Query<S>
96where
97 S: QuerySpec,
98{
99 tag_gen: (u32, u16),
100 flags: Option<<S::Fetch as Fetch<'static>>::Ty>,
101 comps: Box<[(u16, <S::Fetch as Fetch<'static>>::Ty)]>,
102 ptrs: Box<[Option<<S::Fetch as Fetch<'static>>::Ptr>]>,
103}
104
105unsafe impl<S> Send for Query<S> where S: QuerySpec {}
106
107impl<S> Default for Query<S>
108where
109 S: QuerySpec,
110{
111 fn default() -> Self {
113 Self::new()
114 }
115}
116
117impl<S> Query<S>
118where
119 S: QuerySpec,
120{
121 pub fn new() -> Self {
132 Self {
133 tag_gen: Default::default(),
134 flags: Default::default(),
135 comps: Default::default(),
136 ptrs: Default::default(),
137 }
138 }
139
140 pub fn borrow<'w>(&'w mut self, world: &'w World) -> QueryRef<'w, S> {
155 if self.tag_gen != world.tag_gen() {
156 self.find(world);
157 }
158
159 let _ref = self
160 .flags
161 .map(|ty| unsafe { S::Fetch::borrow(&world.borrow_flags, transmute_copy(&ty)) });
162
163 QueryRef {
164 world,
165 _ref,
166 #[allow(clippy::missing_transmute_annotations)]
167 comps: unsafe { transmute(&*self.comps) },
168 #[allow(clippy::missing_transmute_annotations)]
169 ptrs: unsafe { transmute(&mut *self.ptrs) },
170 }
171 }
172
173 #[cold]
174 #[inline(never)]
175 fn find(&mut self, world: &World) {
176 self.flags = S::Fetch::find_flags(&world.borrow_flags);
177
178 self.comps = world
179 .archetypes
180 .iter()
181 .enumerate()
182 .filter_map(|(idx, archetype)| {
183 S::Fetch::find_comps(archetype).map(|ty| (idx as u16, ty))
184 })
185 .collect();
186
187 self.ptrs = world.archetypes.iter().map(|_| None).collect();
188
189 self.tag_gen = world.tag_gen();
190 }
191}
192
193pub struct QueryRef<'w, S>
195where
196 S: QuerySpec,
197{
198 world: &'w World,
199 _ref: Option<<S::Fetch as Fetch<'w>>::Ref>,
200 comps: &'w [(u16, <S::Fetch as Fetch<'w>>::Ty)],
201 ptrs: &'w mut [Option<<S::Fetch as Fetch<'w>>::Ptr>],
202}
203
204impl<S> QueryRef<'_, S>
205where
206 S: QuerySpec,
207{
208 pub fn for_each<'q, F>(&'q mut self, mut f: F)
210 where
211 F: FnMut(<S::Fetch as Fetch<'q>>::Item),
212 {
213 let comps: &'q [(u16, <S::Fetch as Fetch<'q>>::Ty)] = unsafe { transmute(self.comps) };
214
215 for (idx, ty) in comps {
216 let archetype = &self.world.archetypes[*idx as usize];
217
218 let ptr = unsafe { S::Fetch::base_pointer(archetype, *ty) };
219
220 for idx in 0..archetype.len() {
221 let val = unsafe { S::Fetch::deref(ptr, idx) };
222
223 f(val);
224 }
225 }
226 }
227
228 pub fn iter<'q>(&'q mut self) -> QueryIter<'q, S> {
230 let comps: &'q [(u16, <S::Fetch as Fetch<'q>>::Ty)] = unsafe { transmute(self.comps) };
231
232 QueryIter {
233 comps: comps.iter(),
234 archetypes: &self.world.archetypes,
235 idx: 0,
236 len: 0,
237 ptr: S::Fetch::dangling(),
238 }
239 }
240
241 #[cfg(feature = "rayon")]
242 pub fn par_iter<'q>(&'q mut self) -> QueryParIter<'q, S>
281 where
282 <S::Fetch as Fetch<'q>>::Item: Send,
283 {
284 let comps: &'q [(u16, <S::Fetch as Fetch<'q>>::Ty)] = unsafe { transmute(self.comps) };
285
286 QueryParIter::new(comps, &self.world.archetypes)
287 }
288
289 pub fn map<'q>(&'q mut self) -> QueryMap<'q, S> {
312 let comps: &'q [(u16, <S::Fetch as Fetch<'q>>::Ty)] = unsafe { transmute(self.comps) };
313
314 let ptrs: &'q mut [Option<<S::Fetch as Fetch<'q>>::Ptr>] =
315 unsafe { transmute(&mut *self.ptrs) };
316
317 ptrs.fill(None);
318
319 for (idx, ty) in comps {
320 let archetype = &self.world.archetypes[*idx as usize];
321
322 let ptr = unsafe { S::Fetch::base_pointer(archetype, *ty) };
323
324 ptrs[*idx as usize] = Some(ptr);
325 }
326
327 QueryMap {
328 entities: &self.world.entities,
329 ptrs,
330 }
331 }
332}
333
334pub struct QueryIter<'q, S>
336where
337 S: QuerySpec,
338{
339 comps: Iter<'q, (u16, <S::Fetch as Fetch<'q>>::Ty)>,
340 archetypes: &'q [Archetype],
341 idx: u32,
342 len: u32,
343 ptr: <S::Fetch as Fetch<'q>>::Ptr,
344}
345
346unsafe impl<'q, S> Send for QueryIter<'q, S>
347where
348 S: QuerySpec,
349 <S::Fetch as Fetch<'q>>::Item: Send,
350{
351}
352
353impl<'q, S> Iterator for QueryIter<'q, S>
354where
355 S: QuerySpec,
356{
357 type Item = <S::Fetch as Fetch<'q>>::Item;
358
359 fn next(&mut self) -> Option<Self::Item> {
360 loop {
361 if self.idx != self.len {
362 let val = unsafe { S::Fetch::deref(self.ptr, self.idx) };
363 self.idx += 1;
364 return Some(val);
365 } else {
366 let (idx, ty) = self.comps.next()?;
367 let archetype = &self.archetypes[*idx as usize];
368 self.idx = 0;
369 self.len = archetype.len();
370 self.ptr = unsafe { S::Fetch::base_pointer(archetype, *ty) };
371 }
372 }
373 }
374
375 fn size_hint(&self) -> (usize, Option<usize>) {
376 let len = self.len();
377 (len, Some(len))
378 }
379}
380
381impl<S> ExactSizeIterator for QueryIter<'_, S>
382where
383 S: QuerySpec,
384{
385 fn len(&self) -> usize {
386 let len = self
387 .comps
388 .clone()
389 .map(|(idx, _)| self.archetypes[*idx as usize].len())
390 .sum::<u32>()
391 + self.len
392 - self.idx;
393 len as usize
394 }
395}
396
397impl<S> FusedIterator for QueryIter<'_, S> where S: QuerySpec {}
398
399pub struct QueryMap<'q, S>
401where
402 S: QuerySpec,
403{
404 entities: &'q [EntityMetadata],
405 ptrs: &'q [Option<<S::Fetch as Fetch<'q>>::Ptr>],
406}
407
408unsafe impl<'q, S> Send for QueryMap<'q, S>
409where
410 S: QuerySpec,
411 <S::Fetch as Fetch<'q>>::Item: Send,
412{
413}
414
415unsafe impl<'q, S> Sync for QueryMap<'q, S>
416where
417 S: QuerySpec,
418 <S::Fetch as Fetch<'q>>::Item: Send,
419{
420}
421
422impl<S> QueryMap<'_, S>
423where
424 S: QuerySpec,
425{
426 pub fn contains(&self, ent: Entity) -> bool {
451 let meta = self.entities[ent.id as usize];
452 assert_eq!(ent.gen, meta.gen, "Entity is stale");
453
454 let ptr = unsafe { self.ptrs.get_unchecked(meta.ty as usize) };
455
456 ptr.is_some()
457 }
458
459 pub fn get(&self, ent: Entity) -> Option<<S::Fetch as Fetch<'_>>::Item>
488 where
489 S::Fetch: FetchShared,
490 {
491 unsafe { self.get_unchecked(ent) }
492 }
493
494 pub fn get_mut(&mut self, ent: Entity) -> Option<<S::Fetch as Fetch<'_>>::Item> {
496 unsafe { self.get_unchecked(ent) }
497 }
498
499 pub fn get_many_mut<const N: usize>(
523 &mut self,
524 ent: [Entity; N],
525 ) -> [Option<<S::Fetch as Fetch<'_>>::Item>; N] {
526 let mut val = MaybeUninit::uninit();
527
528 let ptr = val.as_mut_ptr() as *mut Option<<S::Fetch as Fetch>::Item>;
529
530 for idx in 0..N {
531 for idx1 in (idx + 1)..N {
532 assert_ne!(ent[idx], ent[idx1], "Duplicate entity");
533 }
534
535 unsafe {
536 let val = self.get_unchecked(ent[idx]);
537
538 ptr.add(idx).write(val);
539 }
540 }
541
542 unsafe { val.assume_init() }
543 }
544
545 unsafe fn get_unchecked<'m>(&'m self, ent: Entity) -> Option<<S::Fetch as Fetch<'m>>::Item> {
546 let meta = self.entities[ent.id as usize];
547 assert_eq!(ent.gen, meta.gen, "Entity is stale");
548
549 let ptr: &'m Option<<S::Fetch as Fetch<'m>>::Ptr> =
550 transmute(self.ptrs.get_unchecked(meta.ty as usize));
551
552 ptr.map(|ptr| S::Fetch::deref(ptr, meta.idx))
553 }
554}
555
556pub trait QuerySpec {
558 #[doc(hidden)]
559 type Fetch: for<'a> Fetch<'a>;
560}
561
562#[allow(clippy::missing_safety_doc)]
563pub unsafe trait Fetch<'q> {
564 type Ty: Copy + 'static;
565 type Ref;
566 type Ptr: Copy + 'static;
567
568 type Item;
569
570 fn find_flags(borrow_flags: &BorrowFlags) -> Option<Self::Ty>;
571 fn find_comps(archetype: &Archetype) -> Option<Self::Ty>;
572 unsafe fn borrow(borrows: &'q BorrowFlags, ty: Self::Ty) -> Self::Ref;
573 unsafe fn base_pointer(archetype: &'q Archetype, ty: Self::Ty) -> Self::Ptr;
574
575 fn dangling() -> Self::Ptr;
576 unsafe fn deref(ptr: Self::Ptr, idx: u32) -> Self::Item;
577}
578
579#[allow(clippy::missing_safety_doc)]
580pub unsafe trait FetchShared {}
581
582impl<C> QuerySpec for &C
583where
584 C: 'static,
585{
586 type Fetch = FetchRead<C>;
587}
588
589pub struct FetchRead<C>(PhantomData<C>);
590
591unsafe impl<'q, C> Fetch<'q> for FetchRead<C>
592where
593 C: 'static,
594{
595 type Ty = u16;
596 type Ref = Ref<'q>;
597 type Ptr = NonNull<C>;
598
599 type Item = &'q C;
600
601 fn find_flags(borrow_flags: &BorrowFlags) -> Option<Self::Ty> {
602 borrow_flags.find::<C>()
603 }
604
605 fn find_comps(archetype: &Archetype) -> Option<Self::Ty> {
606 archetype.find::<C>()
607 }
608
609 unsafe fn borrow(borrow_flags: &'q BorrowFlags, ty: Self::Ty) -> Self::Ref {
610 borrow_flags.borrow::<C>(ty)
611 }
612
613 unsafe fn base_pointer(archetype: &'q Archetype, ty: Self::Ty) -> Self::Ptr {
614 NonNull::new_unchecked(archetype.base_pointer::<C>(ty))
615 }
616
617 fn dangling() -> Self::Ptr {
618 NonNull::dangling()
619 }
620
621 unsafe fn deref(ptr: Self::Ptr, idx: u32) -> Self::Item {
622 &*ptr.as_ptr().add(idx as usize)
623 }
624}
625
626unsafe impl<C> FetchShared for FetchRead<C> {}
627
628impl<C> QuerySpec for &mut C
629where
630 C: 'static,
631{
632 type Fetch = FetchWrite<C>;
633}
634
635pub struct FetchWrite<C>(PhantomData<C>);
636
637unsafe impl<'q, C> Fetch<'q> for FetchWrite<C>
638where
639 C: 'static,
640{
641 type Ty = u16;
642 type Ref = RefMut<'q>;
643 type Ptr = NonNull<C>;
644
645 type Item = &'q mut C;
646
647 fn find_flags(borrow_flags: &BorrowFlags) -> Option<Self::Ty> {
648 assert_ne!(
649 TypeId::of::<C>(),
650 TypeId::of::<Entity>(),
651 "Entity cannot be queried mutably"
652 );
653
654 borrow_flags.find::<C>()
655 }
656
657 fn find_comps(archetype: &Archetype) -> Option<Self::Ty> {
658 archetype.find::<C>()
659 }
660
661 unsafe fn borrow(borrow_flags: &'q BorrowFlags, ty: Self::Ty) -> Self::Ref {
662 borrow_flags.borrow_mut::<C>(ty)
663 }
664
665 unsafe fn base_pointer(archetype: &'q Archetype, ty: Self::Ty) -> Self::Ptr {
666 NonNull::new_unchecked(archetype.base_pointer::<C>(ty))
667 }
668
669 fn dangling() -> Self::Ptr {
670 NonNull::dangling()
671 }
672
673 unsafe fn deref(ptr: Self::Ptr, idx: u32) -> Self::Item {
674 &mut *ptr.as_ptr().add(idx as usize)
675 }
676}
677
678impl<S> QuerySpec for Option<S>
679where
680 S: QuerySpec,
681{
682 type Fetch = TryFetch<S::Fetch>;
683}
684
685pub struct TryFetch<F>(PhantomData<F>);
686
687unsafe impl<'q, F> Fetch<'q> for TryFetch<F>
688where
689 F: Fetch<'q>,
690{
691 type Ty = Option<F::Ty>;
692 type Ref = Option<F::Ref>;
693 type Ptr = Option<F::Ptr>;
694
695 type Item = Option<F::Item>;
696
697 fn find_flags(borrow_flags: &BorrowFlags) -> Option<Self::Ty> {
698 Some(F::find_flags(borrow_flags))
699 }
700
701 fn find_comps(archetype: &Archetype) -> Option<Self::Ty> {
702 Some(F::find_comps(archetype))
703 }
704
705 unsafe fn borrow(borrow_flags: &'q BorrowFlags, ty: Self::Ty) -> Self::Ref {
706 ty.map(|ty| F::borrow(borrow_flags, ty))
707 }
708
709 unsafe fn base_pointer(archetype: &'q Archetype, ty: Self::Ty) -> Self::Ptr {
710 ty.map(|ty| F::base_pointer(archetype, ty))
711 }
712
713 fn dangling() -> Self::Ptr {
714 None
715 }
716
717 unsafe fn deref(ptr: Self::Ptr, idx: u32) -> Self::Item {
718 ptr.map(|ptr| F::deref(ptr, idx))
719 }
720}
721
722unsafe impl<F> FetchShared for TryFetch<F> where F: FetchShared {}
723
724pub struct With<S, C>(PhantomData<(S, C)>);
737
738impl<S, C> QuerySpec for With<S, C>
739where
740 S: QuerySpec,
741 C: 'static,
742{
743 type Fetch = FetchWith<S::Fetch, C>;
744}
745
746pub struct FetchWith<F, C>(PhantomData<(F, C)>);
747
748unsafe impl<'q, F, C> Fetch<'q> for FetchWith<F, C>
749where
750 F: Fetch<'q>,
751 C: 'static,
752{
753 type Ty = F::Ty;
754 type Ref = F::Ref;
755 type Ptr = F::Ptr;
756
757 type Item = F::Item;
758
759 fn find_flags(borrow_flags: &BorrowFlags) -> Option<Self::Ty> {
760 F::find_flags(borrow_flags)
761 }
762
763 fn find_comps(archetype: &Archetype) -> Option<Self::Ty> {
764 match archetype.find::<C>() {
765 Some(_) => F::find_comps(archetype),
766 None => None,
767 }
768 }
769
770 unsafe fn borrow(borrow_flags: &'q BorrowFlags, ty: Self::Ty) -> Self::Ref {
771 F::borrow(borrow_flags, ty)
772 }
773
774 unsafe fn base_pointer(archetype: &'q Archetype, ty: Self::Ty) -> Self::Ptr {
775 F::base_pointer(archetype, ty)
776 }
777
778 fn dangling() -> Self::Ptr {
779 F::dangling()
780 }
781
782 unsafe fn deref(ptr: Self::Ptr, idx: u32) -> Self::Item {
783 F::deref(ptr, idx)
784 }
785}
786
787unsafe impl<F, C> FetchShared for FetchWith<F, C> where F: FetchShared {}
788
789pub struct Without<S, C>(PhantomData<(S, C)>);
801
802impl<S, C> QuerySpec for Without<S, C>
803where
804 S: QuerySpec,
805 C: 'static,
806{
807 type Fetch = FetchWithout<S::Fetch, C>;
808}
809
810pub struct FetchWithout<F, C>(PhantomData<(F, C)>);
811
812unsafe impl<'q, F, C> Fetch<'q> for FetchWithout<F, C>
813where
814 F: Fetch<'q>,
815 C: 'static,
816{
817 type Ty = F::Ty;
818 type Ref = F::Ref;
819 type Ptr = F::Ptr;
820
821 type Item = F::Item;
822
823 fn find_flags(borrow_flags: &BorrowFlags) -> Option<Self::Ty> {
824 F::find_flags(borrow_flags)
825 }
826
827 fn find_comps(archetype: &Archetype) -> Option<Self::Ty> {
828 match archetype.find::<C>() {
829 None => F::find_comps(archetype),
830 Some(_) => None,
831 }
832 }
833
834 unsafe fn borrow(borrow_flags: &'q BorrowFlags, ty: Self::Ty) -> Self::Ref {
835 F::borrow(borrow_flags, ty)
836 }
837
838 unsafe fn base_pointer(archetype: &'q Archetype, ty: Self::Ty) -> Self::Ptr {
839 F::base_pointer(archetype, ty)
840 }
841
842 fn dangling() -> Self::Ptr {
843 F::dangling()
844 }
845
846 unsafe fn deref(ptr: Self::Ptr, idx: u32) -> Self::Item {
847 F::deref(ptr, idx)
848 }
849}
850
851unsafe impl<F, C> FetchShared for FetchWithout<F, C> where F: FetchShared {}
852
853pub struct Matches<S>(PhantomData<S>);
881
882impl<S> QuerySpec for Matches<S>
883where
884 S: QuerySpec,
885{
886 type Fetch = FetchMatches<S::Fetch>;
887}
888
889pub struct FetchMatches<F>(PhantomData<F>);
890
891unsafe impl<'q, F> Fetch<'q> for FetchMatches<F>
892where
893 F: Fetch<'q>,
894{
895 type Ty = bool;
896 type Ref = ();
897 type Ptr = bool;
898
899 type Item = bool;
900
901 fn find_flags(_borrow_flags: &BorrowFlags) -> Option<Self::Ty> {
902 Some(false)
903 }
904
905 fn find_comps(archetype: &Archetype) -> Option<Self::Ty> {
906 Some(F::find_comps(archetype).is_some())
907 }
908
909 unsafe fn borrow(_borrow_flags: &'q BorrowFlags, _ty: Self::Ty) -> Self::Ref {}
910
911 unsafe fn base_pointer(_archetype: &'q Archetype, ty: Self::Ty) -> Self::Ptr {
912 ty
913 }
914
915 fn dangling() -> Self::Ptr {
916 false
917 }
918
919 unsafe fn deref(ptr: Self::Ptr, _idx: u32) -> Self::Item {
920 ptr
921 }
922}
923
924unsafe impl<F> FetchShared for FetchMatches<F> {}
925
926macro_rules! impl_fetch_for_tuples {
927 () => {
928 impl_fetch_for_tuples!(@impl);
929 };
930
931 ($head:ident $(,$tail:ident)*) => {
932 impl_fetch_for_tuples!($($tail),*);
933 impl_fetch_for_tuples!(@rev $head $(,$tail)*;);
934 };
935
936 (@rev ; $($rev:ident),*) => {
937 impl_fetch_for_tuples!(@impl $($rev),*);
938 };
939
940 (@rev $head:ident $(,$tail:ident)*; $($rev:ident),*) => {
941 impl_fetch_for_tuples!(@rev $($tail),*; $head $(,$rev)*);
942 };
943
944 (@impl $($types:ident),*) => {
945 impl<$($types),*> QuerySpec for ($($types,)*)
946 where
947 $($types: QuerySpec,)*
948 {
949 type Fetch = ($($types::Fetch,)*);
950 }
951
952 #[allow(unused_variables, clippy::unused_unit)]
953 unsafe impl<'q, $($types),*> Fetch<'q> for ($($types,)*)
954 where
955 $($types: Fetch<'q>,)*
956 {
957 type Ty = ($($types::Ty,)*);
958 type Ref = ($($types::Ref,)*);
959 type Ptr = ($($types::Ptr,)*);
960
961 type Item = ($($types::Item,)*);
962
963 #[allow(non_snake_case)]
964 fn find_flags(borrow_flags: &BorrowFlags) -> Option<Self::Ty> {
965 $(let $types = $types::find_flags(borrow_flags)?;)*
966
967 Some(($($types,)*))
968 }
969
970 #[allow(non_snake_case)]
971 fn find_comps(archetype: &Archetype) -> Option<Self::Ty> {
972 $(let $types = $types::find_comps(archetype)?;)*
973
974 Some(($($types,)*))
975 }
976
977 #[allow(non_snake_case)]
978 unsafe fn borrow(borrow_flags: &'q BorrowFlags, ty: Self::Ty) -> Self::Ref {
979 let ($($types,)*) = ty;
980
981 ($($types::borrow(borrow_flags, $types),)*)
982 }
983
984 #[allow(non_snake_case)]
985 unsafe fn base_pointer(archetype: &'q Archetype, ty: Self::Ty) -> Self::Ptr {
986 let ($($types,)*) = ty;
987
988 ($($types::base_pointer(archetype, $types),)*)
989 }
990
991 fn dangling() -> Self::Ptr {
992 ($($types::dangling(),)*)
993 }
994
995 #[allow(non_snake_case)]
996 unsafe fn deref(ptr: Self::Ptr, idx: u32) -> Self::Item {
997 let ($($types,)*) = ptr;
998
999 ($($types::deref($types, idx),)*)
1000 }
1001 }
1002
1003 unsafe impl<$($types),*> FetchShared for ($($types,)*)
1004 where
1005 $($types: FetchShared,)*
1006 {
1007 }
1008 };
1009}
1010
1011impl_fetch_for_tuples!(J, I, H, G, F, E, D, C, B, A);
1012
1013#[cfg(test)]
1014mod tests {
1015 use super::*;
1016
1017 use std::convert::TryInto;
1018 use std::mem::{forget, size_of};
1019 use std::panic::{catch_unwind, AssertUnwindSafe};
1020
1021 fn spawn_three(world: &mut World) {
1022 let ent = world.alloc();
1023 world.insert(ent, (23_i32, 42_u64));
1024
1025 let ent = world.alloc();
1026 world.insert(ent, (1_i32, 2_i8, 3_u16));
1027
1028 let ent = world.alloc();
1029 world.insert(ent, (42_i32, 23_u64, true));
1030 }
1031
1032 #[test]
1033 fn queries_can_be_used_once() {
1034 let mut world = World::new();
1035
1036 spawn_three(&mut world);
1037
1038 let mut query = Query::<&i32>::new();
1039
1040 let comps = query.borrow(&world).iter().copied().collect::<Vec<_>>();
1041 assert_eq!(&comps, &[23, 1, 42]);
1042 }
1043
1044 #[test]
1045 fn queries_can_be_reused() {
1046 let mut world = World::new();
1047
1048 spawn_three(&mut world);
1049
1050 let mut query = Query::<&i32>::new();
1051
1052 let comps1 = query.borrow(&world).iter().copied().collect::<Vec<_>>();
1053 assert_eq!(&comps1, &[23, 1, 42]);
1054
1055 let comps2 = query.borrow(&world).iter().copied().collect::<Vec<_>>();
1056 assert_eq!(&comps2, &comps1);
1057 }
1058
1059 #[test]
1060 fn queries_can_be_reused_after_adding_an_archetype() {
1061 let mut world = World::new();
1062
1063 spawn_three(&mut world);
1064
1065 let mut query = Query::<&i32>::new();
1066
1067 let comps1 = query.borrow(&world).iter().copied().collect::<Vec<_>>();
1068 assert_eq!(&comps1, &[23, 1, 42]);
1069
1070 let ent = world.alloc();
1071 world.insert(ent, (0_i64,));
1072
1073 let comps2 = query.borrow(&world).iter().copied().collect::<Vec<_>>();
1074 assert_eq!(&comps2, &comps1);
1075 }
1076
1077 #[test]
1078 fn queries_can_modify_components() {
1079 let mut world = World::new();
1080
1081 spawn_three(&mut world);
1082
1083 {
1084 let mut query = Query::<&mut i32>::new();
1085
1086 for comp in query.borrow(&world).iter() {
1087 *comp *= -1;
1088 }
1089 }
1090
1091 let mut query = Query::<&i32>::new();
1092 let comps = query.borrow(&world).iter().copied().collect::<Vec<_>>();
1093
1094 assert_eq!(&comps, &[-23, -1, -42]);
1095 }
1096
1097 #[test]
1098 fn forgotten_query_ref_does_not_use_after_free() {
1099 let mut world = World::new();
1100
1101 spawn_three(&mut world);
1102
1103 let mut query = Query::<&mut i32>::new();
1104 forget(query.borrow(&world));
1105
1106 drop(world);
1107 drop(query);
1108 }
1109
1110 #[test]
1111 #[should_panic]
1112 fn forgotten_query_ref_leaks_borrows() {
1113 let mut world = World::new();
1114
1115 spawn_three(&mut world);
1116
1117 let mut query = Query::<&mut i32>::new();
1118 forget(query.borrow(&world));
1119
1120 let _ = query.borrow(&world);
1121 }
1122
1123 #[test]
1124 fn conflicting_borrow_leaves_world_in_consistent_state() {
1125 let mut world = World::new();
1126
1127 spawn_three(&mut world);
1128
1129 let res = catch_unwind(AssertUnwindSafe(|| {
1130 let mut query = Query::<(&i32, Option<(&mut i32, &bool)>)>::new();
1131 let _ = query.borrow(&world);
1132 }));
1133
1134 assert!(res.is_err());
1135
1136 let mut query = Query::<&mut i32>::new();
1137 let _ = query.borrow(&world);
1138 }
1139
1140 #[test]
1141 fn borrows_can_be_reused() {
1142 let mut world = World::new();
1143
1144 spawn_three(&mut world);
1145
1146 let mut query = Query::<&i32>::new();
1147 let mut query = query.borrow(&world);
1148
1149 let cnt1 = query.iter().count();
1150 let cnt2 = query.iter().count();
1151
1152 assert_eq!(cnt1, 3);
1153 assert_eq!(cnt2, cnt1);
1154 }
1155
1156 #[test]
1157 fn entities_can_be_queried_immutably() {
1158 let mut world = World::new();
1159
1160 spawn_three(&mut world);
1161
1162 let mut query = Query::<&Entity>::new();
1163 let cnt = query.borrow(&world).iter().count();
1164
1165 assert_eq!(cnt, 3);
1166 }
1167
1168 #[test]
1169 #[should_panic]
1170 fn entities_cannot_be_queried_mutably() {
1171 let mut world = World::new();
1172
1173 spawn_three(&mut world);
1174
1175 let mut query = Query::<&mut Entity>::new();
1176 let _ = query.borrow(&world).iter();
1177 }
1178
1179 #[test]
1180 fn try_exposes_optional_components() {
1181 let mut world = World::new();
1182
1183 spawn_three(&mut world);
1184
1185 let mut query = Query::<Option<&u64>>::new();
1186 let cnt = query.borrow(&world).iter().count();
1187 let cnt_some = query.borrow(&world).iter().flatten().count();
1188
1189 assert_eq!(cnt, 3);
1190 assert_eq!(cnt_some, 2);
1191 }
1192
1193 #[test]
1194 fn with_checks_for_presence() {
1195 let mut world = World::new();
1196
1197 spawn_three(&mut world);
1198
1199 let mut query = Query::<With<&i32, bool>>::new();
1200 let sum = query.borrow(&world).iter().sum::<i32>();
1201
1202 assert_eq!(sum, 42);
1203 }
1204
1205 #[test]
1206 fn without_checks_for_absence() {
1207 let mut world = World::new();
1208
1209 spawn_three(&mut world);
1210
1211 let mut query = Query::<Without<&i32, bool>>::new();
1212 let sum = query.borrow(&world).iter().sum::<i32>();
1213
1214 assert_eq!(sum, 23 + 1);
1215 }
1216
1217 #[test]
1218 fn map_enables_access_by_entity_id() {
1219 let mut world = World::new();
1220
1221 spawn_three(&mut world);
1222
1223 let entities = Query::<&Entity>::new()
1224 .borrow(&world)
1225 .iter()
1226 .copied()
1227 .collect::<Vec<_>>();
1228
1229 let mut query = Query::<&i32>::new();
1230 let mut query = query.borrow(&world);
1231 let mut query = query.map();
1232
1233 for ent in entities {
1234 query.get_mut(ent).unwrap();
1235 }
1236 }
1237
1238 #[test]
1239 fn map_enables_concurrent_access_to_multiple_entities() {
1240 let mut world = World::new();
1241
1242 spawn_three(&mut world);
1243
1244 let entities = Query::<&Entity>::new()
1245 .borrow(&world)
1246 .iter()
1247 .copied()
1248 .collect::<Vec<_>>();
1249
1250 let mut query = Query::<&mut i32>::new();
1251 let mut query = query.borrow(&world);
1252 let mut query = query.map();
1253
1254 let entities: [Entity; 3] = entities.try_into().unwrap();
1255
1256 let mut values = query.get_many_mut(entities);
1257
1258 for (index, value) in values.iter_mut().enumerate() {
1259 **value.as_mut().unwrap() = index as i32;
1260 }
1261 }
1262
1263 #[test]
1264 #[should_panic]
1265 fn map_prohibits_aliasing_via_concurrent_access() {
1266 let mut world = World::new();
1267
1268 spawn_three(&mut world);
1269
1270 let entities = Query::<&Entity>::new()
1271 .borrow(&world)
1272 .iter()
1273 .copied()
1274 .collect::<Vec<_>>();
1275
1276 let mut query = Query::<&mut i32>::new();
1277 let mut query = query.borrow(&world);
1278 let mut query = query.map();
1279
1280 let entities = [entities[0], entities[1], entities[1]];
1281
1282 query.get_many_mut(entities);
1283 }
1284
1285 #[test]
1286 fn empty_queries_yields_unit_for_all_entities() {
1287 let mut world = World::new();
1288
1289 spawn_three(&mut world);
1290
1291 let res = Query::<()>::new().borrow(&world).iter().collect::<Vec<_>>();
1292
1293 assert_eq!(res, vec![(), (), ()]);
1294 }
1295
1296 #[test]
1297 fn fetch_ptr_has_niche() {
1298 assert_eq!(
1299 size_of::<<<(&i32, &mut f64) as QuerySpec>::Fetch as Fetch>::Ptr>(),
1300 size_of::<Option<<<(&i32, &mut f64) as QuerySpec>::Fetch as Fetch>::Ptr>>()
1301 );
1302 }
1303}