1use crate::archetype::Archetype;
2use crate::world::World;
3use std::any::TypeId;
4use std::marker::PhantomData;
5
6pub trait FetchComponent {
11 type Component: 'static;
12 type Fetch<'w>: Copy; type Item<'w>;
14 type Slice<'w>;
15
16 const IS_MUT: bool;
17
18 unsafe fn fetch_raw<'w>(world: &'w World, arch: &Archetype, system_tick: u32) -> Option<Self::Fetch<'w>>;
23
24 unsafe fn get_item<'w>(fetch: Self::Fetch<'w>, row: usize, entity_id: u32) -> Self::Item<'w>;
29
30 unsafe fn get_slice<'w>(fetch: Self::Fetch<'w>, len: usize) -> Self::Slice<'w>;
35}
36
37impl<T: crate::component::Component> FetchComponent for &T {
38 type Component = T;
39 type Fetch<'w> = (*const u8, Option<*const crate::archetype::sparse_set::ComponentSparseSet>);
40 type Item<'w> = &'w T;
41 type Slice<'w> = &'w [T];
42 const IS_MUT: bool = false;
43
44 unsafe fn fetch_raw<'w>(world: &'w World, arch: &Archetype, _system_tick: u32) -> Option<Self::Fetch<'w>> {
45 if T::storage_type() == crate::component::StorageType::SparseSet {
46 let set = world.sparse_sets.get(&TypeId::of::<T>())?;
47 Some((std::ptr::null(), Some(set as *const _)))
48 } else {
49 let col = arch.get_column(TypeId::of::<T>())?;
50 Some((col.data_ptr(), None))
51 }
52 }
53
54 unsafe fn get_item<'w>(fetch: Self::Fetch<'w>, row: usize, entity_id: u32) -> Self::Item<'w> {
55 if let Some(set_ptr) = fetch.1 {
56 let set = &*set_ptr;
57 let ptr = set.get_ptr(entity_id).unwrap() as *const T;
58 &*ptr
59 } else {
60 let ptr = fetch.0.add(row * std::mem::size_of::<T>()) as *const T;
61 &*ptr
62 }
63 }
64
65 unsafe fn get_slice<'w>(fetch: Self::Fetch<'w>, len: usize) -> Self::Slice<'w> {
66 if fetch.1.is_some() {
67 panic!("Cannot use iter_chunks with SparseSet components");
68 }
69 std::slice::from_raw_parts(fetch.0 as *const T, len)
70 }
71}
72
73pub struct Mut<'a, T: 'static> {
74 value: &'a mut T,
75 ticks: &'a mut crate::archetype::ComponentTicks,
76 current_tick: u32,
77}
78
79impl<T> std::ops::Deref for Mut<'_, T> {
80 type Target = T;
81 #[inline]
82 fn deref(&self) -> &T {
83 self.value
84 }
85}
86
87impl<T> std::ops::DerefMut for Mut<'_, T> {
88 #[inline]
89 fn deref_mut(&mut self) -> &mut T {
90 self.ticks.changed = self.current_tick;
91 self.value
92 }
93}
94
95impl<'a, T> Mut<'a, T> {
96 #[inline]
97 pub fn bypass_change_detection(&mut self) -> &mut T {
98 self.value
99 }
100}
101
102impl<T: crate::component::Component> FetchComponent for Mut<'_, T> {
103 type Component = T;
104 type Fetch<'w> = (*mut u8, *mut crate::archetype::ComponentTicks, u32, Option<*mut crate::archetype::sparse_set::ComponentSparseSet>);
105 type Item<'w> = Mut<'w, T>;
106 type Slice<'w> = &'w mut [T];
107 const IS_MUT: bool = true;
108
109 unsafe fn fetch_raw<'w>(world: &'w World, arch: &Archetype, system_tick: u32) -> Option<Self::Fetch<'w>> {
110 if T::storage_type() == crate::component::StorageType::SparseSet {
111 let world_mut = world as *const World as *mut World;
112 let set = (*world_mut).sparse_sets.get_mut(&TypeId::of::<T>())?;
113 Some((std::ptr::null_mut(), std::ptr::null_mut(), system_tick, Some(set as *mut _)))
114 } else {
115 let col = arch.get_column_mut(TypeId::of::<T>())?;
116 Some((col.data_ptr_mut(), col.ticks_ptr_mut(), system_tick, None))
117 }
118 }
119
120 unsafe fn get_item<'w>(fetch: Self::Fetch<'w>, row: usize, entity_id: u32) -> Self::Item<'w> {
121 let (data_ptr, ticks_ptr, system_tick, set_opt) = fetch;
122 if let Some(set_ptr) = set_opt {
123 let set = &mut *set_ptr;
124 let e = entity_id as usize;
126 let dense_row = set.sparse[e] as usize;
127 let ptr = set.dense.get_unchecked_mut(dense_row) as *mut T;
128 Mut {
129 value: &mut *ptr,
130 ticks: &mut set.ticks[dense_row],
131 current_tick: system_tick,
132 }
133 } else {
134 let ptr = data_ptr.add(row * std::mem::size_of::<T>()) as *mut T;
135 Mut {
136 value: &mut *ptr,
137 ticks: &mut *ticks_ptr.add(row),
138 current_tick: system_tick,
139 }
140 }
141 }
142
143 unsafe fn get_slice<'w>(fetch: Self::Fetch<'w>, len: usize) -> Self::Slice<'w> {
144 let (data_ptr, ticks_ptr, system_tick, set_opt) = fetch;
145 if set_opt.is_some() {
146 panic!("Cannot use iter_chunks with SparseSet components");
147 }
148 let ticks = std::slice::from_raw_parts_mut(ticks_ptr, len);
149 for tick in ticks.iter_mut() {
150 tick.changed = system_tick;
151 }
152 std::slice::from_raw_parts_mut(data_ptr as *mut T, len)
153 }
154}
155
156pub trait WorldQuery {
161 type StaticType: 'static;
162 type Fetch<'w>: Copy;
163 type Item<'w>;
164 type Slice<'w>;
165
166 unsafe fn fetch_raw<'w>(world: &'w World, arch: &Archetype, system_tick: u32) -> Option<Self::Fetch<'w>>;
169 fn check_aliasing(types: &mut Vec<(TypeId, bool)>);
170 fn matches_archetype(arch: &Archetype) -> bool;
171
172 unsafe fn get_item<'w>(fetch: Self::Fetch<'w>, row: usize, entity_id: u32) -> Self::Item<'w>;
175
176 unsafe fn filter_row<'w>(fetch: Self::Fetch<'w>, row: usize, entity_id: u32, system_tick: u32) -> bool;
179
180 unsafe fn get_slice<'w>(fetch: Self::Fetch<'w>, len: usize) -> Self::Slice<'w>;
183}
184
185pub struct Query<'w, Q: WorldQuery + ?Sized> {
190 world: &'w World,
191 matching_archetypes: Vec<usize>,
192 _marker: PhantomData<Q>,
193}
194
195impl<'w, Q: WorldQuery> Query<'w, Q> {
196 pub fn new(world: &'w World) -> Option<Self> {
197 let mut used_types = Vec::new();
198 Q::check_aliasing(&mut used_types);
199 let matching = world
200 .archetype_index
201 .matching_archetypes_readonly(Q::matches_archetype);
202 Some(Self {
203 world,
204 matching_archetypes: matching,
205 _marker: PhantomData,
206 })
207 }
208
209 pub fn new_cached(world: &'w mut World) -> Option<Self> {
210 let mut used_types = Vec::new();
211 Q::check_aliasing(&mut used_types);
212 let matching = world
213 .archetype_index
214 .matching_archetypes(TypeId::of::<Q::StaticType>(), Q::matches_archetype)
215 .to_vec();
216 Some(Self {
217 world,
218 matching_archetypes: matching,
219 _marker: PhantomData,
220 })
221 }
222
223 pub fn iter<'a>(&'a self) -> QueryIter<'a, 'w, Q> {
224 QueryIter {
225 world: self.world,
226 archetype_indices: &self.matching_archetypes,
227 current_arch_idx: 0,
228 current_row: 0,
229 current_fetch: None,
230 _marker: PhantomData,
231 _marker_w: PhantomData,
232 }
233 }
234
235 pub fn iter_mut<'a>(&'a mut self) -> QueryIter<'a, 'w, Q> {
236 self.iter()
237 }
238
239 pub fn iter_chunks<'a>(&'a self) -> QueryChunksIter<'a, 'w, Q> {
240 QueryChunksIter {
241 world: self.world,
242 archetype_indices: &self.matching_archetypes,
243 current_arch_idx: 0,
244 _marker: PhantomData,
245 }
246 }
247
248 pub fn iter_chunks_mut<'a>(&'a mut self) -> QueryChunksIter<'a, 'w, Q> {
249 self.iter_chunks()
250 }
251
252 #[inline]
253 pub fn get(&self, entity_id: u32) -> Option<Q::Item<'_>> {
254 let loc = self.world.entity_location(entity_id);
255 if !loc.is_valid() {
256 return None;
257 }
258 let arch = &self.world.archetype_index.archetypes[loc.archetype_id as usize];
259 unsafe {
260 let fetch = Q::fetch_raw(self.world, arch, self.world.tick)?;
261 if !Q::filter_row(fetch, loc.row as usize, entity_id, self.world.tick) {
262 return None;
263 }
264 Some(Q::get_item(fetch, loc.row as usize, entity_id))
265 }
266 }
267
268 #[inline]
269 pub fn get_mut(&self, entity_id: u32) -> Option<Q::Item<'_>> {
270 self.get(entity_id)
271 }
272
273 #[inline]
274 pub fn entity_count(&self) -> usize {
275 self.matching_archetypes
276 .iter()
277 .map(|&idx| self.world.archetype_index.archetypes[idx].len())
278 .sum()
279 }
280
281 #[inline]
282 pub fn len(&self) -> usize {
283 self.entity_count()
284 }
285
286 #[inline]
287 pub fn is_empty(&self) -> bool {
288 self.entity_count() == 0
289 }
290
291 #[inline]
293 pub fn contains(&self, entity_id: u32) -> bool {
294 self.get(entity_id).is_some()
295 }
296
297 pub fn entities<'a>(&'a self) -> impl Iterator<Item = u32> + 'a {
298 self.iter().map(|(id, _)| id)
299 }
300
301 pub fn par_for_each<F>(&self, func: F)
303 where
304 F: Fn((u32, Q::Item<'_>)) + Send + Sync,
305 {
306 use rayon::prelude::*;
307
308 #[derive(Copy, Clone)]
310 struct FetchWrapper<T>(T);
311 unsafe impl<T> Send for FetchWrapper<T> {}
312 unsafe impl<T> Sync for FetchWrapper<T> {}
313
314 impl<T: Copy> FetchWrapper<T> {
315 fn get(&self) -> T {
316 self.0
317 }
318 }
319
320 let tick = self.world.tick;
321 self.matching_archetypes.par_iter().for_each(|&arch_idx| {
322 let arch = &self.world.archetype_index.archetypes[arch_idx];
323 if let Some(fetch) = unsafe { Q::fetch_raw(self.world, arch, tick) } {
324 let len = arch.len();
325 let wrapped_fetch = FetchWrapper(fetch);
326 let entities_ptr = FetchWrapper(arch.entities().as_ptr());
327 let func_ref = &func;
328
329 (0..len)
332 .into_par_iter()
333 .with_min_len(512)
334 .for_each(move |row| unsafe {
335 let id = *entities_ptr.get().add(row);
336 if Q::filter_row(wrapped_fetch.get(), row, id, tick) {
337 let item = Q::get_item(wrapped_fetch.get(), row, id);
338 func_ref((id, item));
339 }
340 });
341 }
342 });
343 }
344
345 pub fn par_for_each_mut<F>(&mut self, func: F)
346 where
347 F: Fn((u32, Q::Item<'_>)) + Send + Sync,
348 {
349 self.par_for_each(func);
350 }
351}
352
353pub struct QueryIter<'a, 'w, Q: WorldQuery> {
358 world: &'a World,
359 archetype_indices: &'a [usize],
360 current_arch_idx: usize,
361 current_row: usize,
362 current_fetch: Option<Q::Fetch<'a>>,
363 _marker: PhantomData<Q>,
364 _marker_w: PhantomData<&'w ()>,
365}
366
367impl<'a, 'w, Q: WorldQuery> Iterator for QueryIter<'a, 'w, Q>
368where
369 'w: 'a,
370{
371 type Item = (u32, Q::Item<'a>);
372
373 fn next(&mut self) -> Option<Self::Item> {
374 loop {
375 if self.current_arch_idx >= self.archetype_indices.len() {
376 return None;
377 }
378
379 let arch_idx = self.archetype_indices[self.current_arch_idx];
380 let arch = &self.world.archetype_index.archetypes[arch_idx];
381
382 let fetch = match self.current_fetch {
383 Some(f) => f,
384 None => {
385 match unsafe { Q::fetch_raw(self.world, arch, self.world.tick) } {
386 Some(f) => {
387 self.current_fetch = Some(f);
388 self.current_row = 0;
389 f
390 }
391 None => {
392 self.current_arch_idx += 1;
394 continue;
395 }
396 }
397 }
398 };
399
400 if self.current_row < arch.len() {
401 let row = self.current_row;
402 self.current_row += 1;
403 let id = arch.entities()[row];
404 if unsafe { Q::filter_row(fetch, row, id, self.world.tick) } {
405 let item = unsafe { Q::get_item(fetch, row, id) };
406 return Some((id, item));
407 }
408 continue;
409 }
410
411 self.current_fetch = None;
412 self.current_arch_idx += 1;
413 }
414 }
415
416 #[inline(always)]
417 fn for_each<F>(self, mut f: F)
418 where
419 Self: Sized,
420 F: FnMut(Self::Item),
421 {
422 for &arch_idx in self.archetype_indices {
423 let arch = &self.world.archetype_index.archetypes[arch_idx];
424 let len = arch.len();
425 if len == 0 {
426 continue;
427 }
428 if let Some(fetch) = unsafe { Q::fetch_raw(self.world, arch, self.world.tick) } {
429 let entities = arch.entities();
430 for row in 0..len {
431 let id = entities[row];
432 if unsafe { Q::filter_row(fetch, row, id, self.world.tick) } {
433 let item = unsafe { Q::get_item(fetch, row, id) };
434 f((id, item));
435 }
436 }
437 }
438 }
439 }
440}
441
442pub struct QueryChunksIter<'a, 'w, Q: WorldQuery> {
447 world: &'a World,
448 archetype_indices: &'a [usize],
449 current_arch_idx: usize,
450 _marker: PhantomData<&'w Q>,
451}
452
453impl<'a, 'w, Q: WorldQuery> Iterator for QueryChunksIter<'a, 'w, Q>
454where
455 'w: 'a,
456{
457 type Item = (&'a [u32], Q::Slice<'a>);
458
459 fn next(&mut self) -> Option<Self::Item> {
460 while self.current_arch_idx < self.archetype_indices.len() {
461 let arch_idx = self.archetype_indices[self.current_arch_idx];
462 self.current_arch_idx += 1;
463
464 let arch = &self.world.archetype_index.archetypes[arch_idx];
465 let len = arch.len();
466 if len == 0 {
467 continue;
468 }
469
470 let fetch = match unsafe { Q::fetch_raw(self.world, arch, self.world.tick) } {
471 Some(f) => f,
472 None => continue,
473 };
474
475 let ids = unsafe { std::slice::from_raw_parts(arch.entities().as_ptr(), len) };
476 let slice = unsafe { Q::get_slice(fetch, len) };
477
478 return Some((ids, slice));
479 }
480 None
481 }
482}
483
484#[inline]
502fn check(tid: TypeId, is_mut: bool, types: &mut Vec<(TypeId, bool)>) {
503 for &(existing_tid, existing_mut) in types.iter() {
504 if existing_tid == tid && (existing_mut || is_mut) {
505 panic!(
506 "Query aliasing UB detected! Component TypeId {:?} is accessed mutably more than once \
507 in the same query. This would cause undefined behavior. \
508 Use separate queries for components of the same type that need independent mutable access.",
509 tid
510 );
511 }
512 }
513 types.push((tid, is_mut));
514}
515
516impl<T0: FetchComponent> WorldQuery for T0 where T0::Component: crate::component::Component {
517 type StaticType = T0::Component;
518 type Fetch<'w> = T0::Fetch<'w>;
519 type Item<'w> = T0::Item<'w>;
520 type Slice<'w> = T0::Slice<'w>;
521
522 unsafe fn fetch_raw<'w>(world: &'w World, arch: &Archetype, tick: u32) -> Option<Self::Fetch<'w>> {
523 T0::fetch_raw(world, arch, tick)
524 }
525 fn check_aliasing(types: &mut Vec<(TypeId, bool)>) {
526 check(TypeId::of::<T0::Component>(), T0::IS_MUT, types);
527 }
528 fn matches_archetype(arch: &Archetype) -> bool {
529 if <T0::Component as crate::component::Component>::storage_type() == crate::component::StorageType::SparseSet { true } else { arch.has_component(TypeId::of::<T0::Component>()) }
530 }
531
532 unsafe fn get_item<'w>(fetch: Self::Fetch<'w>, row: usize, entity_id: u32) -> Self::Item<'w> {
533 T0::get_item(fetch, row, entity_id)
534 }
535
536 unsafe fn filter_row<'w>(_fetch: Self::Fetch<'w>, _row: usize, _entity_id: u32, _tick: u32) -> bool {
537 true
538 }
539
540 unsafe fn get_slice<'w>(fetch: Self::Fetch<'w>, len: usize) -> Self::Slice<'w> {
541 T0::get_slice(fetch, len)
542 }
543}
544
545pub struct Changed<T>(PhantomData<T>);
546
547impl<T: crate::component::Component> WorldQuery for Changed<T> {
548 type StaticType = Changed<T>;
549 type Fetch<'w> = *const crate::archetype::ComponentTicks;
550 type Item<'w> = ();
551 type Slice<'w> = ();
552
553 unsafe fn fetch_raw<'w>(_world: &'w World, arch: &Archetype, _tick: u32) -> Option<Self::Fetch<'w>> {
554 let col = arch.get_column(TypeId::of::<T>())?;
555 Some(col.ticks_ptr())
556 }
557
558 fn check_aliasing(_types: &mut Vec<(TypeId, bool)>) {}
559
560 fn matches_archetype(arch: &Archetype) -> bool {
561 if T::storage_type() == crate::component::StorageType::SparseSet { true } else { arch.has_component(TypeId::of::<T>()) }
562 }
563
564 unsafe fn filter_row<'w>(fetch: Self::Fetch<'w>, row: usize, _entity_id: u32, tick: u32) -> bool {
565 if T::storage_type() == crate::component::StorageType::SparseSet {
566 true
568 } else {
569 let ticks = &*fetch.add(row);
570 ticks.changed == tick
571 }
572 }
573
574 unsafe fn get_item<'w>(_fetch: Self::Fetch<'w>, _row: usize, _entity_id: u32) -> Self::Item<'w> {}
575
576 unsafe fn get_slice<'w>(_fetch: Self::Fetch<'w>, _len: usize) -> Self::Slice<'w> {}
577}
578
579pub struct Added<T>(PhantomData<T>);
580
581impl<T: crate::component::Component> WorldQuery for Added<T> {
582 type StaticType = Added<T>;
583 type Fetch<'w> = *const crate::archetype::ComponentTicks;
584 type Item<'w> = ();
585 type Slice<'w> = ();
586
587 unsafe fn fetch_raw<'w>(_world: &'w World, arch: &Archetype, _tick: u32) -> Option<Self::Fetch<'w>> {
588 let col = arch.get_column(TypeId::of::<T>())?;
589 Some(col.ticks_ptr())
590 }
591
592 fn check_aliasing(_types: &mut Vec<(TypeId, bool)>) {}
593
594 fn matches_archetype(arch: &Archetype) -> bool {
595 if T::storage_type() == crate::component::StorageType::SparseSet { true } else { arch.has_component(TypeId::of::<T>()) }
596 }
597
598 unsafe fn filter_row<'w>(fetch: Self::Fetch<'w>, row: usize, _entity_id: u32, tick: u32) -> bool {
599 if T::storage_type() == crate::component::StorageType::SparseSet {
600 true
601 } else {
602 let ticks = &*fetch.add(row);
603 ticks.added == tick
604 }
605 }
606
607 unsafe fn get_item<'w>(_fetch: Self::Fetch<'w>, _row: usize, _entity_id: u32) -> Self::Item<'w> {}
608
609 unsafe fn get_slice<'w>(_fetch: Self::Fetch<'w>, _len: usize) -> Self::Slice<'w> {}
610}
611
612macro_rules! impl_query_tuple {
613 ($($t:ident),*) => {
614 #[allow(non_snake_case)]
615 impl<$($t: WorldQuery),*> WorldQuery for ($($t,)*) {
616 type StaticType = ($($t::StaticType,)*);
617 type Fetch<'w> = ($($t::Fetch<'w>,)*);
618 type Item<'w> = ($($t::Item<'w>,)*);
619 type Slice<'w> = ($($t::Slice<'w>,)*);
620
621 unsafe fn fetch_raw<'w>(world: &'w World, arch: &Archetype, tick: u32) -> Option<Self::Fetch<'w>> {
622 Some(($($t::fetch_raw(world, arch, tick)?,)*))
623 }
624 fn check_aliasing(types: &mut Vec<(TypeId, bool)>) {
625 $($t::check_aliasing(types);)*
626 }
627 fn matches_archetype(arch: &Archetype) -> bool {
628 $($t::matches_archetype(arch) &&)* true
629 }
630 unsafe fn get_item<'w>(fetch: Self::Fetch<'w>, row: usize, entity_id: u32) -> Self::Item<'w> {
631 let ($($t,)*) = fetch;
632 ($($t::get_item($t, row, entity_id),)*)
633 }
634 unsafe fn filter_row<'w>(fetch: Self::Fetch<'w>, row: usize, entity_id: u32, tick: u32) -> bool {
635 let ($($t,)*) = fetch;
636 $($t::filter_row($t, row, entity_id, tick) &&)* true
637 }
638 unsafe fn get_slice<'w>(fetch: Self::Fetch<'w>, len: usize) -> Self::Slice<'w> {
639 let ($($t,)*) = fetch;
640 ($($t::get_slice($t, len),)*)
641 }
642 }
643 };
644}
645
646impl_query_tuple!(T0, T1);
647impl_query_tuple!(T0, T1, T2);
648impl_query_tuple!(T0, T1, T2, T3);
649impl_query_tuple!(T0, T1, T2, T3, T4);
650impl_query_tuple!(T0, T1, T2, T3, T4, T5);
651impl_query_tuple!(T0, T1, T2, T3, T4, T5, T6);
652impl_query_tuple!(T0, T1, T2, T3, T4, T5, T6, T7);
653impl_query_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8);
654impl_query_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9);
655impl_query_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10);
656impl_query_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11);
657
658pub struct With<T>(PhantomData<T>);
663
664impl<T: crate::component::Component> WorldQuery for With<T> {
665 type StaticType = With<T>;
666 type Fetch<'w> = ();
667 type Item<'w> = ();
668 type Slice<'w> = ();
669
670 unsafe fn fetch_raw<'w>(_world: &'w World, _arch: &Archetype, _tick: u32) -> Option<Self::Fetch<'w>> {
671 Some(())
672 }
673
674 fn check_aliasing(_types: &mut Vec<(TypeId, bool)>) {}
675
676 fn matches_archetype(arch: &Archetype) -> bool {
677 if T::storage_type() == crate::component::StorageType::SparseSet { true } else { arch.has_component(TypeId::of::<T>()) }
678 }
679
680 unsafe fn filter_row<'w>(_fetch: Self::Fetch<'w>, _row: usize, _entity_id: u32, _tick: u32) -> bool {
681 true
682 }
683 unsafe fn get_item<'w>(_fetch: Self::Fetch<'w>, _row: usize, _entity_id: u32) -> Self::Item<'w> {}
684 unsafe fn get_slice<'w>(_fetch: Self::Fetch<'w>, _len: usize) -> Self::Slice<'w> {}
685}
686
687pub struct Without<T>(PhantomData<T>);
688
689impl<T: crate::component::Component> WorldQuery for Without<T> {
690 type StaticType = Without<T>;
691 type Fetch<'w> = ();
692 type Item<'w> = ();
693 type Slice<'w> = ();
694
695 unsafe fn fetch_raw<'w>(_world: &'w World, _arch: &Archetype, _tick: u32) -> Option<Self::Fetch<'w>> {
696 Some(())
697 }
698
699 fn check_aliasing(_types: &mut Vec<(TypeId, bool)>) {}
700
701 fn matches_archetype(arch: &Archetype) -> bool {
702 if T::storage_type() == crate::component::StorageType::SparseSet { true } else { !arch.has_component(TypeId::of::<T>()) }
703 }
704
705 unsafe fn filter_row<'w>(_fetch: Self::Fetch<'w>, _row: usize, _entity_id: u32, _tick: u32) -> bool {
706 true
707 }
708 unsafe fn get_item<'w>(_fetch: Self::Fetch<'w>, _row: usize, _entity_id: u32) -> Self::Item<'w> {}
709 unsafe fn get_slice<'w>(_fetch: Self::Fetch<'w>, _len: usize) -> Self::Slice<'w> {}
710}
711
712pub struct Or<T1, T2>(PhantomData<(T1, T2)>);
713
714impl<T1: WorldQuery, T2: WorldQuery> WorldQuery for Or<T1, T2> {
715 type StaticType = Or<T1::StaticType, T2::StaticType>;
716 type Fetch<'w> = ();
717 type Item<'w> = ();
718 type Slice<'w> = ();
719
720 unsafe fn fetch_raw<'w>(_world: &'w World, _arch: &Archetype, _tick: u32) -> Option<Self::Fetch<'w>> {
721 Some(())
722 }
723
724 fn check_aliasing(_types: &mut Vec<(TypeId, bool)>) {}
725
726 fn matches_archetype(arch: &Archetype) -> bool {
727 T1::matches_archetype(arch) || T2::matches_archetype(arch)
728 }
729
730 unsafe fn filter_row<'w>(_fetch: Self::Fetch<'w>, _row: usize, _entity_id: u32, _tick: u32) -> bool {
731 true
732 }
733 unsafe fn get_item<'w>(_fetch: Self::Fetch<'w>, _row: usize, _entity_id: u32) -> Self::Item<'w> {}
734 unsafe fn get_slice<'w>(_fetch: Self::Fetch<'w>, _len: usize) -> Self::Slice<'w> {}
735}
736
737#[cfg(test)]
738mod tests {
739 use super::*;
740 use crate::impl_component;
741
742 #[derive(Debug, Clone, PartialEq)]
743 struct Position {
744 x: f32,
745 y: f32,
746 }
747 impl_component!(Position);
748
749 #[derive(Debug, Clone, PartialEq)]
750 struct Velocity {
751 x: f32,
752 y: f32,
753 }
754 impl_component!(Velocity);
755
756 #[test]
759 #[should_panic(expected = "Query aliasing UB detected")]
760 fn test_same_type_mut_mut_panics() {
761 let mut types = Vec::new();
762 check(TypeId::of::<Position>(), true, &mut types);
764 check(TypeId::of::<Position>(), true, &mut types);
766 }
767
768 #[test]
771 #[should_panic(expected = "Query aliasing UB detected")]
772 fn test_same_type_ref_mut_panics() {
773 let mut types = Vec::new();
774 check(TypeId::of::<Position>(), false, &mut types); check(TypeId::of::<Position>(), true, &mut types); }
777
778 #[test]
780 fn test_different_types_mut_mut_ok() {
781 let mut types = Vec::new();
782 check(TypeId::of::<Position>(), true, &mut types);
783 check(TypeId::of::<Velocity>(), true, &mut types);
784 assert_eq!(types.len(), 2);
785 }
786
787 #[test]
789 fn test_same_type_ref_ref_ok() {
790 let mut types = Vec::new();
791 check(TypeId::of::<Position>(), false, &mut types);
792 check(TypeId::of::<Position>(), false, &mut types);
793 assert_eq!(types.len(), 2);
794 }
795
796 #[test]
798 fn test_query_new_with_valid_types() {
799 let mut world = crate::World::new();
800 world.register_component_type::<Position>();
801 world.register_component_type::<Velocity>();
802 let e = world.spawn();
803 world.add_component(e, Position { x: 1.0, y: 2.0 });
804 world.add_component(e, Velocity { x: 0.0, y: 0.0 });
805
806 let q = world.query::<(Mut<Position>, Mut<Velocity>)>();
808 assert!(q.is_some());
809 }
810}