1#![expect(
2 unsafe_op_in_unsafe_fn,
3 reason = "See #11590. To be removed once all applicable unsafe code has an unsafe block with a safety comment."
4)]
5
6mod access;
9mod access_iter;
10mod builder;
11mod error;
12mod fetch;
13mod filter;
14mod iter;
15mod par_iter;
16mod state;
17mod world_query;
18
19pub use access::*;
20pub use access_iter::*;
21pub use bevy_ecs_macros::{QueryData, QueryFilter};
22pub use builder::*;
23pub use error::*;
24pub use fetch::*;
25pub use filter::*;
26pub use iter::*;
27pub use par_iter::*;
28pub use state::*;
29pub use world_query::*;
30
31#[doc(hidden)]
36pub trait DebugCheckedUnwrap {
37 type Item;
38 unsafe fn debug_checked_unwrap(self) -> Self::Item;
45}
46
47#[cfg(debug_assertions)]
50impl<T> DebugCheckedUnwrap for Option<T> {
51 type Item = T;
52
53 #[inline(always)]
54 #[track_caller]
55 unsafe fn debug_checked_unwrap(self) -> Self::Item {
56 if let Some(inner) = self {
57 inner
58 } else {
59 unreachable!()
60 }
61 }
62}
63
64#[cfg(debug_assertions)]
67impl<T, U> DebugCheckedUnwrap for Result<T, U> {
68 type Item = T;
69
70 #[inline(always)]
71 #[track_caller]
72 unsafe fn debug_checked_unwrap(self) -> Self::Item {
73 if let Ok(inner) = self {
74 inner
75 } else {
76 unreachable!()
77 }
78 }
79}
80
81#[cfg(not(debug_assertions))]
84impl<T, U> DebugCheckedUnwrap for Result<T, U> {
85 type Item = T;
86
87 #[inline(always)]
88 #[track_caller]
89 unsafe fn debug_checked_unwrap(self) -> Self::Item {
90 if let Ok(inner) = self {
91 inner
92 } else {
93 core::hint::unreachable_unchecked()
94 }
95 }
96}
97
98#[cfg(not(debug_assertions))]
99impl<T> DebugCheckedUnwrap for Option<T> {
100 type Item = T;
101
102 #[inline(always)]
103 unsafe fn debug_checked_unwrap(self) -> Self::Item {
104 if let Some(inner) = self {
105 inner
106 } else {
107 core::hint::unreachable_unchecked()
108 }
109 }
110}
111
112#[cfg(test)]
113#[expect(clippy::print_stdout, reason = "Allowed in tests.")]
114mod tests {
115 use crate::{
116 change_detection::ContiguousRef,
117 component::Component,
118 prelude::{AnyOf, Changed, Entity, Or, QueryState, With, Without},
119 query::{
120 ArchetypeFilter, ArchetypeQueryData, Has, QueryCombinationIter, QueryData, QueryFilter,
121 ReadOnlyQueryData,
122 },
123 schedule::{IntoScheduleConfigs, Schedule},
124 system::{IntoSystem, Query, System, SystemState},
125 world::{Ref, World},
126 };
127 use alloc::{vec, vec::Vec};
128 use core::{any::type_name, fmt::Debug, hash::Hash};
129 use std::{collections::HashSet, println};
130
131 #[derive(Component, Debug, Hash, Eq, PartialEq, Clone, Copy, PartialOrd, Ord)]
132 struct A(usize);
133 #[derive(Component, Debug, Hash, Eq, PartialEq, Clone, Copy)]
134 struct B(usize);
135 #[derive(Component, Debug, Eq, PartialEq, Clone, Copy)]
136 struct C(usize);
137 #[derive(Component, Debug, Eq, PartialEq, Clone, Copy)]
138 struct D(usize);
139
140 #[derive(Component, Debug, Hash, Eq, PartialEq, Clone, Copy, PartialOrd, Ord)]
141 #[component(storage = "SparseSet")]
142 struct Sparse(usize);
143
144 #[test]
145 fn query() {
146 let mut world = World::new();
147 world.spawn((A(1), B(1)));
148 world.spawn(A(2));
149 let values = world.query::<&A>().iter(&world).collect::<HashSet<&A>>();
150 assert!(values.contains(&A(1)));
151 assert!(values.contains(&A(2)));
152
153 for (_a, mut b) in world.query::<(&A, &mut B)>().iter_mut(&mut world) {
154 b.0 = 3;
155 }
156 let values = world.query::<&B>().iter(&world).collect::<Vec<&B>>();
157 assert_eq!(values, vec![&B(3)]);
158 }
159
160 #[test]
161 #[cfg_attr(miri, ignore = "This test takes ~170s on CI")]
162 fn query_filtered_exactsizeiterator_len() {
163 fn choose(n: usize, k: usize) -> usize {
164 if n == 0 || k == 0 || n < k {
165 return 0;
166 }
167 let ks = 1..=k;
168 let ns = (n - k + 1..=n).rev();
169 ks.zip(ns).fold(1, |acc, (k, n)| acc * n / k)
170 }
171 fn assert_combination<D, F, const K: usize>(world: &mut World, expected_size: usize)
172 where
173 D: ReadOnlyQueryData + ArchetypeQueryData,
174 F: ArchetypeFilter,
175 {
176 let mut query = world.query_filtered::<D, F>();
177 let query_type = type_name::<QueryCombinationIter<D, F, K>>();
178 let iter = query.iter_combinations::<K>(world);
179 assert_all_sizes_iterator_equal(iter, expected_size, 0, query_type);
180 let iter = query.iter_combinations::<K>(world);
181 assert_all_sizes_iterator_equal(iter, expected_size, 1, query_type);
182 let iter = query.iter_combinations::<K>(world);
183 assert_all_sizes_iterator_equal(iter, expected_size, 5, query_type);
184 }
185 fn assert_all_sizes_equal<D, F>(world: &mut World, expected_size: usize)
186 where
187 D: ReadOnlyQueryData + ArchetypeQueryData,
188 F: ArchetypeFilter,
189 {
190 let mut query = world.query_filtered::<D, F>();
191 let query_type = type_name::<QueryState<D, F>>();
192 assert_all_exact_sizes_iterator_equal(query.iter(world), expected_size, 0, query_type);
193 assert_all_exact_sizes_iterator_equal(query.iter(world), expected_size, 1, query_type);
194 assert_all_exact_sizes_iterator_equal(query.iter(world), expected_size, 5, query_type);
195
196 let expected = expected_size;
197 assert_combination::<D, F, 1>(world, choose(expected, 1));
198 assert_combination::<D, F, 2>(world, choose(expected, 2));
199 assert_combination::<D, F, 5>(world, choose(expected, 5));
200 assert_combination::<D, F, 43>(world, choose(expected, 43));
201 assert_combination::<D, F, 64>(world, choose(expected, 64));
202 }
203 fn assert_all_exact_sizes_iterator_equal(
204 iterator: impl ExactSizeIterator,
205 expected_size: usize,
206 skip: usize,
207 query_type: &'static str,
208 ) {
209 let len = iterator.len();
210 println!("len: {len}");
211 assert_all_sizes_iterator_equal(iterator, expected_size, skip, query_type);
212 assert_eq!(len, expected_size);
213 }
214 fn assert_all_sizes_iterator_equal(
215 mut iterator: impl Iterator,
216 expected_size: usize,
217 skip: usize,
218 query_type: &'static str,
219 ) {
220 let expected_size = expected_size.saturating_sub(skip);
221 for _ in 0..skip {
222 iterator.next();
223 }
224 let size_hint_0 = iterator.size_hint().0;
225 let size_hint_1 = iterator.size_hint().1;
226 let count = iterator.count();
229 println!(
231 "query declared sizes: \n\
232 for query: {query_type} \n\
233 expected: {expected_size} \n\
234 size_hint().0: {size_hint_0} \n\
235 size_hint().1: {size_hint_1:?} \n\
236 count(): {count}"
237 );
238 assert_eq!(size_hint_0, expected_size);
239 assert_eq!(size_hint_1, Some(expected_size));
240 assert_eq!(count, expected_size);
241 }
242
243 let mut world = World::new();
244 world.spawn((A(1), B(1)));
245 world.spawn(A(2));
246 world.spawn(A(3));
247
248 assert_all_sizes_equal::<&A, With<B>>(&mut world, 1);
249 assert_all_sizes_equal::<&A, Without<B>>(&mut world, 2);
250
251 let mut world = World::new();
252 world.spawn((A(1), B(1), C(1)));
253 world.spawn((A(2), B(2)));
254 world.spawn((A(3), B(3)));
255 world.spawn((A(4), C(4)));
256 world.spawn((A(5), C(5)));
257 world.spawn((A(6), C(6)));
258 world.spawn(A(7));
259 world.spawn(A(8));
260 world.spawn(A(9));
261 world.spawn(A(10));
262
263 assert_all_sizes_equal::<&A, With<B>>(&mut world, 3);
265 assert_all_sizes_equal::<&A, With<C>>(&mut world, 4);
266 assert_all_sizes_equal::<&A, Without<B>>(&mut world, 7);
267 assert_all_sizes_equal::<&A, Without<C>>(&mut world, 6);
268
269 assert_all_sizes_equal::<&A, (With<B>, With<C>)>(&mut world, 1);
271 assert_all_sizes_equal::<&A, (With<B>, Without<C>)>(&mut world, 2);
272 assert_all_sizes_equal::<&A, (Without<B>, With<C>)>(&mut world, 3);
273 assert_all_sizes_equal::<&A, (Without<B>, Without<C>)>(&mut world, 4);
274
275 assert_all_sizes_equal::<&A, Or<(With<B>, With<C>)>>(&mut world, 6);
277 assert_all_sizes_equal::<&A, Or<(With<B>, Without<C>)>>(&mut world, 7);
278 assert_all_sizes_equal::<&A, Or<(Without<B>, With<C>)>>(&mut world, 8);
279 assert_all_sizes_equal::<&A, Or<(Without<B>, Without<C>)>>(&mut world, 9);
280 assert_all_sizes_equal::<&A, (Or<(With<B>,)>, Or<(With<C>,)>)>(&mut world, 1);
281 assert_all_sizes_equal::<&A, Or<(Or<(With<B>, With<C>)>, With<D>)>>(&mut world, 6);
282
283 for i in 11..14 {
284 world.spawn((A(i), D(i)));
285 }
286
287 assert_all_sizes_equal::<&A, Or<(Or<(With<B>, With<C>)>, With<D>)>>(&mut world, 9);
288 assert_all_sizes_equal::<&A, Or<(Or<(With<B>, With<C>)>, Without<D>)>>(&mut world, 10);
289
290 for i in 14..20 {
292 world.spawn((C(i), D(i)));
293 }
294 assert_all_sizes_equal::<Entity, (With<C>, With<D>)>(&mut world, 6);
295 }
296
297 fn check_combinations<T: Ord + Hash + Debug, const K: usize>(
299 values: HashSet<[&T; K]>,
300 expected: HashSet<[&T; K]>,
301 ) {
302 values.iter().for_each(|pair| {
303 let mut sorted = *pair;
304 sorted.sort();
305 assert!(expected.contains(&sorted),
306 "the results of iter_combinations should contain this combination {:?}. Expected: {:?}, got: {:?}",
307 sorted, expected, values);
308 });
309 }
310
311 #[test]
312 fn query_iter_combinations() {
313 let mut world = World::new();
314
315 world.spawn((A(1), B(1)));
316 world.spawn(A(2));
317 world.spawn(A(3));
318 world.spawn(A(4));
319
320 let values: HashSet<[&A; 2]> = world.query::<&A>().iter_combinations(&world).collect();
321 check_combinations(
322 values,
323 HashSet::from([
324 [&A(1), &A(2)],
325 [&A(1), &A(3)],
326 [&A(1), &A(4)],
327 [&A(2), &A(3)],
328 [&A(2), &A(4)],
329 [&A(3), &A(4)],
330 ]),
331 );
332 let mut a_query = world.query::<&A>();
333
334 let values: HashSet<[&A; 3]> = a_query.iter_combinations(&world).collect();
335 check_combinations(
336 values,
337 HashSet::from([
338 [&A(1), &A(2), &A(3)],
339 [&A(1), &A(2), &A(4)],
340 [&A(1), &A(3), &A(4)],
341 [&A(2), &A(3), &A(4)],
342 ]),
343 );
344
345 let mut b_query = world.query::<&B>();
346 assert_eq!(
347 b_query.iter_combinations::<2>(&world).size_hint(),
348 (0, Some(0))
349 );
350 let values: Vec<[&B; 2]> = b_query.iter_combinations(&world).collect();
351 assert_eq!(values, Vec::<[&B; 2]>::new());
352 }
353
354 #[test]
355 fn query_filtered_iter_combinations() {
356 use bevy_ecs::query::{Added, Or, With, Without};
357
358 let mut world = World::new();
359
360 world.spawn((A(1), B(1)));
361 world.spawn(A(2));
362 world.spawn(A(3));
363 world.spawn(A(4));
364
365 let mut a_wout_b = world.query_filtered::<&A, Without<B>>();
366 let values: HashSet<[&A; 2]> = a_wout_b.iter_combinations(&world).collect();
367 check_combinations(
368 values,
369 HashSet::from([[&A(2), &A(3)], [&A(2), &A(4)], [&A(3), &A(4)]]),
370 );
371
372 let values: HashSet<[&A; 3]> = a_wout_b.iter_combinations(&world).collect();
373 check_combinations(values, HashSet::from([[&A(2), &A(3), &A(4)]]));
374
375 let mut query = world.query_filtered::<&A, Or<(With<A>, With<B>)>>();
376 let values: HashSet<[&A; 2]> = query.iter_combinations(&world).collect();
377 check_combinations(
378 values,
379 HashSet::from([
380 [&A(1), &A(2)],
381 [&A(1), &A(3)],
382 [&A(1), &A(4)],
383 [&A(2), &A(3)],
384 [&A(2), &A(4)],
385 [&A(3), &A(4)],
386 ]),
387 );
388
389 let mut query = world.query_filtered::<&mut A, Without<B>>();
390 let mut combinations = query.iter_combinations_mut(&mut world);
391 while let Some([mut a, mut b, mut c]) = combinations.fetch_next() {
392 a.0 += 10;
393 b.0 += 100;
394 c.0 += 1000;
395 }
396
397 let values: HashSet<[&A; 3]> = a_wout_b.iter_combinations(&world).collect();
398 check_combinations(values, HashSet::from([[&A(12), &A(103), &A(1004)]]));
399
400 let mut world = World::new();
402
403 world.spawn((A(1), B(1)));
404 world.spawn((A(2), B(2)));
405 world.spawn((A(3), B(3)));
406 world.spawn((A(4), B(4)));
407
408 let mut query_added = world.query_filtered::<&A, Added<A>>();
409
410 world.clear_trackers();
411 world.spawn(A(5));
412
413 assert_eq!(query_added.iter_combinations::<2>(&world).count(), 0);
414
415 world.clear_trackers();
416 world.spawn(A(6));
417 world.spawn(A(7));
418
419 assert_eq!(query_added.iter_combinations::<2>(&world).count(), 1);
420
421 world.clear_trackers();
422 world.spawn(A(8));
423 world.spawn(A(9));
424 world.spawn(A(10));
425
426 assert_eq!(query_added.iter_combinations::<2>(&world).count(), 3);
427 }
428
429 #[test]
430 fn query_iter_combinations_sparse() {
431 let mut world = World::new();
432
433 world.spawn_batch((1..=4).map(Sparse));
434
435 let values: HashSet<[&Sparse; 3]> =
436 world.query::<&Sparse>().iter_combinations(&world).collect();
437 check_combinations(
438 values,
439 HashSet::from([
440 [&Sparse(1), &Sparse(2), &Sparse(3)],
441 [&Sparse(1), &Sparse(2), &Sparse(4)],
442 [&Sparse(1), &Sparse(3), &Sparse(4)],
443 [&Sparse(2), &Sparse(3), &Sparse(4)],
444 ]),
445 );
446 }
447
448 #[test]
449 fn get_many_only_mut_checks_duplicates() {
450 let mut world = World::new();
451 let id = world.spawn(A(10)).id();
452 let mut query_state = world.query::<&mut A>();
453 let mut query = query_state.query_mut(&mut world);
454 let result = query.get_many([id, id]);
455 assert_eq!(result, Ok([&A(10), &A(10)]));
456 let mut_result = query.get_many_mut([id, id]);
457 assert!(mut_result.is_err());
458 }
459
460 #[test]
461 fn multi_storage_query() {
462 let mut world = World::new();
463
464 world.spawn((Sparse(1), B(2)));
465 world.spawn(Sparse(2));
466
467 let values = world
468 .query::<&Sparse>()
469 .iter(&world)
470 .collect::<HashSet<&Sparse>>();
471 assert!(values.contains(&Sparse(1)));
472 assert!(values.contains(&Sparse(2)));
473
474 for (_a, mut b) in world.query::<(&Sparse, &mut B)>().iter_mut(&mut world) {
475 b.0 = 3;
476 }
477
478 let values = world.query::<&B>().iter(&world).collect::<Vec<&B>>();
479 assert_eq!(values, vec![&B(3)]);
480 }
481
482 #[test]
483 fn any_query() {
484 let mut world = World::new();
485
486 world.spawn((A(1), B(2)));
487 world.spawn(A(2));
488 world.spawn(C(3));
489
490 let values: Vec<(Option<&A>, Option<&B>)> =
491 world.query::<AnyOf<(&A, &B)>>().iter(&world).collect();
492
493 assert_eq!(
494 values,
495 vec![(Some(&A(1)), Some(&B(2))), (Some(&A(2)), None),]
496 );
497 }
498
499 #[test]
500 fn has_query() {
501 let mut world = World::new();
502
503 world.spawn((A(1), B(1)));
504 world.spawn(A(2));
505 world.spawn((A(3), B(1)));
506 world.spawn(A(4));
507
508 let values: HashSet<(&A, bool)> = world.query::<(&A, Has<B>)>().iter(&world).collect();
509
510 assert!(values.contains(&(&A(1), true)));
511 assert!(values.contains(&(&A(2), false)));
512 assert!(values.contains(&(&A(3), true)));
513 assert!(values.contains(&(&A(4), false)));
514 }
515
516 #[test]
517 #[should_panic]
518 fn self_conflicting_worldquery() {
519 #[derive(QueryData)]
520 #[query_data(mutable)]
521 struct SelfConflicting {
522 a: &'static mut A,
523 b: &'static mut A,
524 }
525
526 let mut world = World::new();
527 world.query::<SelfConflicting>();
528 }
529
530 #[test]
531 fn derived_worldqueries() {
532 let mut world = World::new();
533
534 world.spawn((A(10), B(18), C(3), Sparse(4)));
535
536 world.spawn((A(101), B(148), C(13)));
537 world.spawn((A(51), B(46), Sparse(72)));
538 world.spawn((A(398), C(6), Sparse(9)));
539 world.spawn((B(11), C(28), Sparse(92)));
540
541 world.spawn((C(18348), Sparse(101)));
542 world.spawn((B(839), Sparse(5)));
543 world.spawn((B(6721), C(122)));
544 world.spawn((A(220), Sparse(63)));
545 world.spawn((A(1092), C(382)));
546 world.spawn((A(2058), B(3019)));
547
548 world.spawn((B(38), C(8), Sparse(100)));
549 world.spawn((A(111), C(52), Sparse(1)));
550 world.spawn((A(599), B(39), Sparse(13)));
551 world.spawn((A(55), B(66), C(77)));
552
553 world.spawn_empty();
554
555 {
556 #[derive(QueryData)]
557 struct CustomAB {
558 a: &'static A,
559 b: &'static B,
560 }
561
562 let custom_param_data = world
563 .query::<CustomAB>()
564 .iter(&world)
565 .map(|item| (*item.a, *item.b))
566 .collect::<Vec<_>>();
567 let normal_data = world
568 .query::<(&A, &B)>()
569 .iter(&world)
570 .map(|(a, b)| (*a, *b))
571 .collect::<Vec<_>>();
572 assert_eq!(custom_param_data, normal_data);
573 }
574
575 {
576 #[derive(QueryData)]
577 struct FancyParam {
578 e: Entity,
579 b: &'static B,
580 opt: Option<&'static Sparse>,
581 }
582
583 let custom_param_data = world
584 .query::<FancyParam>()
585 .iter(&world)
586 .map(|fancy| (fancy.e, *fancy.b, fancy.opt.copied()))
587 .collect::<Vec<_>>();
588 let normal_data = world
589 .query::<(Entity, &B, Option<&Sparse>)>()
590 .iter(&world)
591 .map(|(e, b, opt)| (e, *b, opt.copied()))
592 .collect::<Vec<_>>();
593 assert_eq!(custom_param_data, normal_data);
594 }
595
596 {
597 #[derive(QueryData)]
598 struct MaybeBSparse {
599 blah: Option<(&'static B, &'static Sparse)>,
600 }
601 #[derive(QueryData)]
602 struct MatchEverything {
603 abcs: AnyOf<(&'static A, &'static B, &'static C)>,
604 opt_bsparse: MaybeBSparse,
605 }
606
607 let custom_param_data = world
608 .query::<MatchEverything>()
609 .iter(&world)
610 .map(
611 |MatchEverythingItem {
612 abcs: (a, b, c),
613 opt_bsparse: MaybeBSparseItem { blah: bsparse },
614 }| {
615 (
616 (a.copied(), b.copied(), c.copied()),
617 bsparse.map(|(b, sparse)| (*b, *sparse)),
618 )
619 },
620 )
621 .collect::<Vec<_>>();
622 let normal_data = world
623 .query::<(AnyOf<(&A, &B, &C)>, Option<(&B, &Sparse)>)>()
624 .iter(&world)
625 .map(|((a, b, c), bsparse)| {
626 (
627 (a.copied(), b.copied(), c.copied()),
628 bsparse.map(|(b, sparse)| (*b, *sparse)),
629 )
630 })
631 .collect::<Vec<_>>();
632 assert_eq!(custom_param_data, normal_data);
633 }
634
635 {
636 #[derive(QueryFilter)]
637 struct AOrBFilter {
638 a: Or<(With<A>, With<B>)>,
639 }
640 #[derive(QueryFilter)]
641 struct NoSparseThatsSlow {
642 no: Without<Sparse>,
643 }
644
645 let custom_param_entities = world
646 .query_filtered::<Entity, (AOrBFilter, NoSparseThatsSlow)>()
647 .iter(&world)
648 .collect::<Vec<_>>();
649 let normal_entities = world
650 .query_filtered::<Entity, (Or<(With<A>, With<B>)>, Without<Sparse>)>()
651 .iter(&world)
652 .collect::<Vec<_>>();
653 assert_eq!(custom_param_entities, normal_entities);
654 }
655
656 {
657 #[derive(QueryFilter)]
658 struct CSparseFilter {
659 tuple_structs_pls: With<C>,
660 ugh: With<Sparse>,
661 }
662
663 let custom_param_entities = world
664 .query_filtered::<Entity, CSparseFilter>()
665 .iter(&world)
666 .collect::<Vec<_>>();
667 let normal_entities = world
668 .query_filtered::<Entity, (With<C>, With<Sparse>)>()
669 .iter(&world)
670 .collect::<Vec<_>>();
671 assert_eq!(custom_param_entities, normal_entities);
672 }
673
674 {
675 #[derive(QueryFilter)]
676 struct WithoutComps {
677 _1: Without<A>,
678 _2: Without<B>,
679 _3: Without<C>,
680 }
681
682 let custom_param_entities = world
683 .query_filtered::<Entity, WithoutComps>()
684 .iter(&world)
685 .collect::<Vec<_>>();
686 let normal_entities = world
687 .query_filtered::<Entity, (Without<A>, Without<B>, Without<C>)>()
688 .iter(&world)
689 .collect::<Vec<_>>();
690 assert_eq!(custom_param_entities, normal_entities);
691 }
692
693 {
694 #[derive(QueryData)]
695 struct IterCombAB {
696 a: &'static A,
697 b: &'static B,
698 }
699
700 let custom_param_data = world
701 .query::<IterCombAB>()
702 .iter_combinations::<2>(&world)
703 .map(|[item0, item1]| [(*item0.a, *item0.b), (*item1.a, *item1.b)])
704 .collect::<Vec<_>>();
705 let normal_data = world
706 .query::<(&A, &B)>()
707 .iter_combinations(&world)
708 .map(|[(a0, b0), (a1, b1)]| [(*a0, *b0), (*a1, *b1)])
709 .collect::<Vec<_>>();
710 assert_eq!(custom_param_data, normal_data);
711 }
712 }
713
714 #[test]
715 fn many_entities() {
716 let mut world = World::new();
717 world.spawn((A(0), B(0)));
718 world.spawn((A(0), B(0)));
719 world.spawn(A(0));
720 world.spawn(B(0));
721 {
722 fn system(has_a: Query<Entity, With<A>>, has_a_and_b: Query<(&A, &B)>) {
723 assert_eq!(has_a_and_b.iter_many(&has_a).matched().count(), 2);
724 assert_eq!(has_a_and_b.iter_many(&has_a).count(), 3);
725 }
726 let mut system = IntoSystem::into_system(system);
727 system.initialize(&mut world);
728 system.run((), &mut world).unwrap();
729 }
730 {
731 fn system(has_a: Query<Entity, With<A>>, mut b_query: Query<&mut B>) {
732 let mut iter = b_query.iter_many_mut(&has_a).matched();
733 while let Some(mut b) = iter.fetch_next() {
734 b.0 = 1;
735 }
736 }
737 let mut system = IntoSystem::into_system(system);
738 system.initialize(&mut world);
739 system.run((), &mut world).unwrap();
740 }
741 {
742 fn system(query: Query<(Option<&A>, &B)>) {
743 for (maybe_a, b) in &query {
744 match maybe_a {
745 Some(_) => assert_eq!(b.0, 1),
746 None => assert_eq!(b.0, 0),
747 }
748 }
749 }
750 let mut system = IntoSystem::into_system(system);
751 system.initialize(&mut world);
752 system.run((), &mut world).unwrap();
753 }
754 }
755
756 #[test]
757 fn mut_to_immut_query_methods_have_immut_item() {
758 #[derive(Component)]
759 struct Foo;
760
761 let mut world = World::new();
762 let e = world.spawn(Foo).id();
763
764 let mut q = world.query::<&mut Foo>();
766 let _: Option<&Foo> = q.iter(&world).next();
767 let _: Option<[&Foo; 2]> = q.iter_combinations::<2>(&world).next();
768 let _: Option<&Foo> = q.iter_manual(&world).next();
769 let _: Option<&Foo> = q.iter_many(&world, [e]).next().map(Result::unwrap);
770 q.iter(&world).for_each(|_: &Foo| ());
771
772 let _: Option<&Foo> = q.get(&world, e).ok();
773 let _: Option<&Foo> = q.get_manual(&world, e).ok();
774 let _: Option<[&Foo; 1]> = q.get_many(&world, [e]).ok();
775 let _: Option<&Foo> = q.single(&world).ok();
776 let _: &Foo = q.single(&world).unwrap();
777
778 let mut q = SystemState::<Query<&mut Foo>>::new(&mut world);
780 let q = q.get_mut(&mut world).unwrap();
781 let _: Option<&Foo> = q.iter().next();
782 let _: Option<[&Foo; 2]> = q.iter_combinations::<2>().next();
783 let _: Option<&Foo> = q.iter_many([e]).next().map(Result::unwrap);
784 q.iter().for_each(|_: &Foo| ());
785
786 let _: Option<&Foo> = q.get(e).ok();
787 let _: Option<[&Foo; 1]> = q.get_many([e]).ok();
788 let _: Option<&Foo> = q.single().ok();
789 let _: &Foo = q.single().unwrap();
790 }
791
792 #[test]
794 fn par_iter_mut_change_detection() {
795 let mut world = World::new();
796 world.spawn((A(1), B(1)));
797
798 fn propagate_system(mut query: Query<(&A, &mut B), Changed<A>>) {
799 query.par_iter_mut().for_each(|(a, mut b)| {
800 b.0 = a.0;
801 });
802 }
803
804 fn modify_system(mut query: Query<&mut A>) {
805 for mut a in &mut query {
806 a.0 = 2;
807 }
808 }
809
810 let mut schedule = Schedule::default();
811 schedule.add_systems((propagate_system, modify_system).chain());
812 schedule.run(&mut world);
813 world.clear_trackers();
814 schedule.run(&mut world);
815 world.clear_trackers();
816
817 let values = world.query::<&B>().iter(&world).collect::<Vec<&B>>();
818 assert_eq!(values, vec![&B(2)]);
819 }
820
821 #[test]
823 #[rustfmt::skip]
825 fn query_data_derive_where_clause() {
826 #[derive(QueryData)]
827 struct QueryDataA<C>
828 where
829 C: Component,
830 {
831 component: &'static C,
832 }
833
834 #[derive(QueryData)]
835 struct QueryDataB<C>(&'static C)
836 where
837 C: Component;
838 }
839
840 #[derive(Component)]
842 #[component(summary_tick)]
843 #[expect(
844 dead_code,
845 reason = "Nothing reads the interior value but it's nice for debugging anyway"
846 )]
847 struct SA(usize);
848 #[derive(Component)]
849 #[component(summary_tick)]
850 struct SB(usize);
851
852 #[test]
854 fn summary_tick_is_disabled_by_default() {
855 let mut world = World::new();
856 let id = world.register_component::<A>();
857 assert!(!world.components.get_info(id).unwrap().summary_tick());
858
859 world.spawn(A(1));
862 let mut query = world.query::<Ref<A>>();
863 let item = query.contiguous_iter(&world).unwrap().next().unwrap();
864 let (_, ticks) = ContiguousRef::split(item);
865 assert!(ticks.summary_tick_is_changed().is_none());
866 }
867
868 #[test]
871 fn summary_tick_is_enabled_via_an_attribute() {
872 let mut world = World::new();
873 let id = world.register_component::<SA>();
874 assert!(world.components().get_info(id).unwrap().summary_tick());
875
876 world.spawn(SA(1));
879 let mut query = world.query::<Ref<SA>>();
880 let item = query.contiguous_iter(&world).unwrap().next().unwrap();
881 let (_, ticks) = ContiguousRef::split(item);
882 assert_eq!(ticks.summary_tick_is_changed(), Some(true));
883 }
884
885 #[test]
889 fn summary_tick_is_updated_when_archetypes_change() {
890 let mut world = World::new();
892 let entity = world.spawn(SA(1)).id();
893
894 world.entity_mut(entity).insert(SB(2));
896
897 let mut query = world.query::<(Ref<SA>, Ref<SB>)>();
900 let (item_sa, item_sb) = query.contiguous_iter(&world).unwrap().next().unwrap();
901 let (_, ticks_sa) = ContiguousRef::split(item_sa);
902 let (_, ticks_sb) = ContiguousRef::split(item_sb);
903 assert_eq!(ticks_sa.summary_tick_is_changed(), Some(true));
904 assert_eq!(ticks_sb.summary_tick_is_changed(), Some(true));
905 }
906
907 #[test]
911 fn summary_tick_is_updated_when_archetypes_change_on_remove() {
912 let mut world = World::new();
913 let entity = world.spawn((SA(1), SB(2))).id();
914
915 world.entity_mut(entity).remove::<SB>();
916
917 let mut query = world.query::<Ref<SA>>();
918 let item_sa = query.contiguous_iter(&world).unwrap().next().unwrap();
919 let (_, ticks_sa) = ContiguousRef::split(item_sa);
920 assert_eq!(ticks_sa.summary_tick_is_changed(), Some(true));
921 }
922
923 #[test]
926 fn summary_ticks_reflect_changes_to_multiple_instances_of_a_component() {
927 let mut world = World::new();
928 world.spawn((SA(1), SB(1)));
929 world.spawn((SA(2), SB(2)));
930
931 let mut q_sb = world.query_filtered::<Ref<SB>, With<SA>>();
934 assert_eq!(get_summary_tick_is_changed(&world, &mut q_sb), Some(true));
935
936 world.clear_trackers();
939 for mut sb in world.query::<&mut SB>().iter_mut(&mut world) {
940 sb.0 += 1;
941 }
942 assert_eq!(get_summary_tick_is_changed(&world, &mut q_sb), Some(true));
943
944 world.clear_trackers();
947 assert_eq!(get_summary_tick_is_changed(&world, &mut q_sb), Some(false));
948
949 fn get_summary_tick_is_changed(
952 world: &World,
953 q_sb: &mut QueryState<Ref<SB>, With<SA>>,
954 ) -> Option<bool> {
955 let item = q_sb.contiguous_iter(world).unwrap().next().unwrap();
956 let (_, ticks) = ContiguousRef::split(item);
957 ticks.summary_tick_is_changed()
958 }
959 }
960
961 #[test]
964 fn summary_ticks_reflect_changes_to_a_single_instance_of_a_component() {
965 let mut world = World::new();
966 world.spawn((SA(1), SB(1)));
967 let entity_1 = world.spawn((SA(2), SB(2))).id();
968
969 world.clear_trackers();
970
971 world.get_mut::<SB>(entity_1).unwrap().0 = 20;
972
973 let mut query = world.query::<Ref<SB>>();
974 let item = query.contiguous_iter(&world).unwrap().next().unwrap();
975 let (values, ticks) = ContiguousRef::split(item);
976 assert_eq!(values.len(), 2);
977 assert_eq!(ticks.summary_tick_is_changed(), Some(true));
979 }
980
981 #[test]
983 fn query_data_derive_contiguous_tuple() {
984 #[derive(QueryData)]
985 #[query_data(contiguous(mutable))]
986 struct QueryDataA(Entity, &'static A);
987
988 #[derive(QueryData)]
989 #[query_data(contiguous(all))]
990 struct QueryDataB<C>(&'static C)
991 where
992 C: Component + PartialEq;
993
994 let mut world = World::new();
995 let _ = world.query::<QueryDataA>().contiguous_iter_mut(&mut world);
996 let _ = world.query::<QueryDataB<D>>().contiguous_iter(&world);
997 }
998
999 #[test]
1001 fn query_data_derive_empty() {
1002 #[derive(QueryData)]
1003 struct QueryDataA {}
1004
1005 #[derive(QueryData)]
1006 struct QueryDataB();
1007
1008 #[derive(QueryData)]
1009 #[query_data(mutable)]
1010 struct QueryDataC {}
1011
1012 #[derive(QueryData)]
1013 #[query_data(mutable)]
1014 struct QueryDataD();
1015
1016 #[derive(QueryData)]
1017 #[query_data(contiguous(immutable))]
1018 struct QueryDataE {}
1019
1020 #[derive(QueryData)]
1021 #[query_data(contiguous(immutable))]
1022 struct QueryDataF();
1023
1024 #[derive(QueryData)]
1025 #[query_data(mutable, contiguous(immutable))]
1026 struct QueryDataG {}
1027
1028 #[derive(QueryData)]
1029 #[query_data(mutable, contiguous(immutable))]
1030 struct QueryDataH();
1031
1032 #[derive(QueryData)]
1033 #[query_data(contiguous(mutable))]
1034 struct QueryDataI {}
1035
1036 #[derive(QueryData)]
1037 #[query_data(contiguous(mutable))]
1038 struct QueryDataJ();
1039
1040 #[derive(QueryData)]
1041 #[query_data(mutable, contiguous(mutable))]
1042 struct QueryDataK {}
1043
1044 #[derive(QueryData)]
1045 #[query_data(mutable, contiguous(mutable))]
1046 struct QueryDataL();
1047
1048 #[derive(QueryData)]
1049 #[query_data(contiguous(all))]
1050 struct QueryDataM {}
1051
1052 #[derive(QueryData)]
1053 #[query_data(contiguous(all))]
1054 struct QueryDataN();
1055
1056 #[derive(QueryData)]
1057 #[query_data(mutable, contiguous(all))]
1058 struct QueryDataO {}
1059
1060 #[derive(QueryData)]
1061 #[query_data(mutable, contiguous(all))]
1062 struct QueryDataP();
1063 }
1064}