Skip to main content

bevy_ecs/query/
mod.rs

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
6//! Contains APIs for retrieving component data from the world.
7
8mod 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/// A debug checked version of [`Option::unwrap_unchecked`]. Will panic in
32/// debug modes if unwrapping a `None` or `Err` value in debug mode, but is
33/// equivalent to `Option::unwrap_unchecked` or `Result::unwrap_unchecked`
34/// in release mode.
35#[doc(hidden)]
36pub trait DebugCheckedUnwrap {
37    type Item;
38    /// # Panics
39    /// Panics if the value is `None` or `Err`, only in debug mode.
40    ///
41    /// # Safety
42    /// This must never be called on a `None` or `Err` value. This can
43    /// only be called on `Some` or `Ok` values.
44    unsafe fn debug_checked_unwrap(self) -> Self::Item;
45}
46
47// These two impls are explicitly split to ensure that the unreachable! macro
48// does not cause inlining to fail when compiling in release mode.
49#[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// These two impls are explicitly split to ensure that the unreachable! macro
65// does not cause inlining to fail when compiling in release mode.
66#[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// These two impls are explicitly split to ensure that the unreachable! macro
82// does not cause inlining to fail when compiling in release mode.
83#[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            // `count` tests that not only it is the expected value, but also
227            // the value is accurate to what the query returns.
228            let count = iterator.count();
229            // This will show up when one of the asserts in this function fails
230            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        // With/Without for B and C
264        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        // With/Without (And) combinations
270        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        // With/Without Or<()> combinations
276        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        // a fair amount of entities
291        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    // the order of the combinations is not guaranteed, but each unique combination is present
298    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        // Check if Added<T>, Changed<T> works
401        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        // state
765        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        // system param
779        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    // regression test for https://github.com/bevyengine/bevy/pull/8029
793    #[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]
822    fn par_iter_many_unique_visits_each_listed_entity_once() {
823        use crate::entity::UniqueEntityVec;
824        use core::sync::atomic::{AtomicUsize, Ordering};
825
826        bevy_tasks::ComputeTaskPool::get_or_init(bevy_tasks::TaskPool::new);
827
828        let mut world = World::new();
829        let entities: Vec<Entity> = world.spawn_batch((0..1000).map(|i| (A(i), B(0)))).collect();
830        // Every other entity.
831        let subset: UniqueEntityVec = entities.iter().copied().step_by(2).collect();
832
833        let mut state = SystemState::<Query<(&A, &mut B)>>::new(&mut world);
834        let mut query = state.get_mut(&mut world).unwrap();
835        query.par_iter_many_unique_mut(&subset).for_each(|item| {
836            let (a, mut b) = item.unwrap();
837            b.0 = a.0 + 1;
838        });
839
840        let sum = AtomicUsize::new(0);
841        query.par_iter_many_unique(&subset).for_each(|item| {
842            let (_, b) = item.unwrap();
843            sum.fetch_add(b.0, Ordering::Relaxed);
844        });
845        // Listed entities hold A(i) + 1 for i = 0, 2, ..., 998.
846        assert_eq!(
847            sum.into_inner(),
848            (0..1000).step_by(2).map(|i| i + 1).sum::<usize>()
849        );
850
851        for (i, &entity) in entities.iter().enumerate() {
852            let expected = if i % 2 == 0 { i + 1 } else { 0 };
853            assert_eq!(world.get::<B>(entity).unwrap().0, expected);
854        }
855    }
856
857    // regression test for https://github.com/bevyengine/bevy/pull/23352
858    #[test]
859    // presence/lack of trailing commas are significant in this test, so skip rustfmt
860    #[rustfmt::skip]
861    fn query_data_derive_where_clause() {
862        #[derive(QueryData)]
863        struct QueryDataA<C>
864        where
865            C: Component,
866        {
867            component: &'static C,
868        }
869
870        #[derive(QueryData)]
871        struct QueryDataB<C>(&'static C)
872        where
873            C: Component;
874    }
875
876    // Declare a couple of components that have summary ticks.
877    #[derive(Component)]
878    #[component(summary_tick)]
879    #[expect(
880        dead_code,
881        reason = "Nothing reads the interior value but it's nice for debugging anyway"
882    )]
883    struct SA(usize);
884    #[derive(Component)]
885    #[component(summary_tick)]
886    struct SB(usize);
887
888    /// Tests that summary ticks are disabled for components by default.
889    #[test]
890    fn summary_tick_is_disabled_by_default() {
891        let mut world = World::new();
892        let id = world.register_component::<A>();
893        assert!(!world.components.get_info(id).unwrap().summary_tick());
894
895        // Make sure that `summary_tick_is_changed` returns `None`, as there is
896        // no summary tick.
897        world.spawn(A(1));
898        let mut query = world.query::<Ref<A>>();
899        let item = query.contiguous_iter(&world).unwrap().next().unwrap();
900        let (_, ticks) = ContiguousRef::split(item);
901        assert!(ticks.summary_tick_is_changed().is_none());
902    }
903
904    /// Tests that summary ticks are enabled for components when the
905    /// `component(summary_tick)` attribute is present.
906    #[test]
907    fn summary_tick_is_enabled_via_an_attribute() {
908        let mut world = World::new();
909        let id = world.register_component::<SA>();
910        assert!(world.components().get_info(id).unwrap().summary_tick());
911
912        // The summary tick should be present and should reflect a change, as
913        // `SA` was just spawned.
914        world.spawn(SA(1));
915        let mut query = world.query::<Ref<SA>>();
916        let item = query.contiguous_iter(&world).unwrap().next().unwrap();
917        let (_, ticks) = ContiguousRef::split(item);
918        assert_eq!(ticks.summary_tick_is_changed(), Some(true));
919    }
920
921    /// Ensure that, when an entity changes archetype on account of a component
922    /// insertion, all components in the destination table with summary ticks
923    /// have those summary ticks updated.
924    #[test]
925    fn summary_tick_is_updated_when_archetypes_change() {
926        // Spawn an entity with an `SA` component into the world.
927        let mut world = World::new();
928        let entity = world.spawn(SA(1)).id();
929
930        // Add the `SB` component to that entity.
931        world.entity_mut(entity).insert(SB(2));
932
933        // Both components' summary ticks should be present and should reflect
934        // changes, as an archetype move occurred.
935        let mut query = world.query::<(Ref<SA>, Ref<SB>)>();
936        let (item_sa, item_sb) = query.contiguous_iter(&world).unwrap().next().unwrap();
937        let (_, ticks_sa) = ContiguousRef::split(item_sa);
938        let (_, ticks_sb) = ContiguousRef::split(item_sb);
939        assert_eq!(ticks_sa.summary_tick_is_changed(), Some(true));
940        assert_eq!(ticks_sb.summary_tick_is_changed(), Some(true));
941    }
942
943    /// Ensure that, when an entity changes archetype due to the removal of a
944    /// component, that the components in the destination table with summary
945    /// ticks have those summary ticks updated.
946    #[test]
947    fn summary_tick_is_updated_when_archetypes_change_on_remove() {
948        let mut world = World::new();
949        let entity = world.spawn((SA(1), SB(2))).id();
950
951        world.entity_mut(entity).remove::<SB>();
952
953        let mut query = world.query::<Ref<SA>>();
954        let item_sa = query.contiguous_iter(&world).unwrap().next().unwrap();
955        let (_, ticks_sa) = ContiguousRef::split(item_sa);
956        assert_eq!(ticks_sa.summary_tick_is_changed(), Some(true));
957    }
958
959    /// Ensure that, when multiple instances of a component in a single table
960    /// are updated, the summary tick is also updated.
961    #[test]
962    fn summary_ticks_reflect_changes_to_multiple_instances_of_a_component() {
963        let mut world = World::new();
964        world.spawn((SA(1), SB(1)));
965        world.spawn((SA(2), SB(2)));
966
967        // Initialize the query. The summary tick should be present and should
968        // reflect a change, as two components were just spawned.
969        let mut q_sb = world.query_filtered::<Ref<SB>, With<SA>>();
970        assert_eq!(get_summary_tick_is_changed(&world, &mut q_sb), Some(true));
971
972        // Clear trackers, and update. The summary tick should reflect a change
973        // now.
974        world.clear_trackers();
975        for mut sb in world.query::<&mut SB>().iter_mut(&mut world) {
976            sb.0 += 1;
977        }
978        assert_eq!(get_summary_tick_is_changed(&world, &mut q_sb), Some(true));
979
980        // Clear trackers, and don't update. The summary tick should not reflect
981        // a change.
982        world.clear_trackers();
983        assert_eq!(get_summary_tick_is_changed(&world, &mut q_sb), Some(false));
984
985        // Returns the result of `summary_tick_is_changed` for the first table
986        // containing `SB`.
987        fn get_summary_tick_is_changed(
988            world: &World,
989            q_sb: &mut QueryState<Ref<SB>, With<SA>>,
990        ) -> Option<bool> {
991            let item = q_sb.contiguous_iter(world).unwrap().next().unwrap();
992            let (_, ticks) = ContiguousRef::split(item);
993            ticks.summary_tick_is_changed()
994        }
995    }
996
997    /// Ensure that, when a single instance of a component in a single table
998    /// are updated, the summary tick is also updated.
999    #[test]
1000    fn summary_ticks_reflect_changes_to_a_single_instance_of_a_component() {
1001        let mut world = World::new();
1002        world.spawn((SA(1), SB(1)));
1003        let entity_1 = world.spawn((SA(2), SB(2))).id();
1004
1005        world.clear_trackers();
1006
1007        world.get_mut::<SB>(entity_1).unwrap().0 = 20;
1008
1009        let mut query = world.query::<Ref<SB>>();
1010        let item = query.contiguous_iter(&world).unwrap().next().unwrap();
1011        let (values, ticks) = ContiguousRef::split(item);
1012        assert_eq!(values.len(), 2);
1013        // One entity has changed, so the summary tick is changed.
1014        assert_eq!(ticks.summary_tick_is_changed(), Some(true));
1015    }
1016
1017    // regression test for https://github.com/bevyengine/bevy/pull/23394
1018    #[test]
1019    fn query_data_derive_contiguous_tuple() {
1020        #[derive(QueryData)]
1021        #[query_data(contiguous(mutable))]
1022        struct QueryDataA(Entity, &'static A);
1023
1024        #[derive(QueryData)]
1025        #[query_data(contiguous(all))]
1026        struct QueryDataB<C>(&'static C)
1027        where
1028            C: Component + PartialEq;
1029
1030        let mut world = World::new();
1031        let _ = world.query::<QueryDataA>().contiguous_iter_mut(&mut world);
1032        let _ = world.query::<QueryDataB<D>>().contiguous_iter(&world);
1033    }
1034
1035    // regression test for https://github.com/bevyengine/bevy/pull/23930
1036    #[test]
1037    fn query_data_derive_empty() {
1038        #[derive(QueryData)]
1039        struct QueryDataA {}
1040
1041        #[derive(QueryData)]
1042        struct QueryDataB();
1043
1044        #[derive(QueryData)]
1045        #[query_data(mutable)]
1046        struct QueryDataC {}
1047
1048        #[derive(QueryData)]
1049        #[query_data(mutable)]
1050        struct QueryDataD();
1051
1052        #[derive(QueryData)]
1053        #[query_data(contiguous(immutable))]
1054        struct QueryDataE {}
1055
1056        #[derive(QueryData)]
1057        #[query_data(contiguous(immutable))]
1058        struct QueryDataF();
1059
1060        #[derive(QueryData)]
1061        #[query_data(mutable, contiguous(immutable))]
1062        struct QueryDataG {}
1063
1064        #[derive(QueryData)]
1065        #[query_data(mutable, contiguous(immutable))]
1066        struct QueryDataH();
1067
1068        #[derive(QueryData)]
1069        #[query_data(contiguous(mutable))]
1070        struct QueryDataI {}
1071
1072        #[derive(QueryData)]
1073        #[query_data(contiguous(mutable))]
1074        struct QueryDataJ();
1075
1076        #[derive(QueryData)]
1077        #[query_data(mutable, contiguous(mutable))]
1078        struct QueryDataK {}
1079
1080        #[derive(QueryData)]
1081        #[query_data(mutable, contiguous(mutable))]
1082        struct QueryDataL();
1083
1084        #[derive(QueryData)]
1085        #[query_data(contiguous(all))]
1086        struct QueryDataM {}
1087
1088        #[derive(QueryData)]
1089        #[query_data(contiguous(all))]
1090        struct QueryDataN();
1091
1092        #[derive(QueryData)]
1093        #[query_data(mutable, contiguous(all))]
1094        struct QueryDataO {}
1095
1096        #[derive(QueryData)]
1097        #[query_data(mutable, contiguous(all))]
1098        struct QueryDataP();
1099    }
1100}