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        component::Component,
117        prelude::{AnyOf, Changed, Entity, Or, QueryState, With, Without},
118        query::{
119            ArchetypeFilter, ArchetypeQueryData, Has, QueryCombinationIter, QueryData, QueryFilter,
120            ReadOnlyQueryData,
121        },
122        schedule::{IntoScheduleConfigs, Schedule},
123        system::{IntoSystem, Query, System, SystemState},
124        world::World,
125    };
126    use alloc::{vec, vec::Vec};
127    use core::{any::type_name, fmt::Debug, hash::Hash};
128    use std::{collections::HashSet, println};
129
130    #[derive(Component, Debug, Hash, Eq, PartialEq, Clone, Copy, PartialOrd, Ord)]
131    struct A(usize);
132    #[derive(Component, Debug, Hash, Eq, PartialEq, Clone, Copy)]
133    struct B(usize);
134    #[derive(Component, Debug, Eq, PartialEq, Clone, Copy)]
135    struct C(usize);
136    #[derive(Component, Debug, Eq, PartialEq, Clone, Copy)]
137    struct D(usize);
138
139    #[derive(Component, Debug, Hash, Eq, PartialEq, Clone, Copy, PartialOrd, Ord)]
140    #[component(storage = "SparseSet")]
141    struct Sparse(usize);
142
143    #[test]
144    fn query() {
145        let mut world = World::new();
146        world.spawn((A(1), B(1)));
147        world.spawn(A(2));
148        let values = world.query::<&A>().iter(&world).collect::<HashSet<&A>>();
149        assert!(values.contains(&A(1)));
150        assert!(values.contains(&A(2)));
151
152        for (_a, mut b) in world.query::<(&A, &mut B)>().iter_mut(&mut world) {
153            b.0 = 3;
154        }
155        let values = world.query::<&B>().iter(&world).collect::<Vec<&B>>();
156        assert_eq!(values, vec![&B(3)]);
157    }
158
159    #[test]
160    #[cfg_attr(miri, ignore = "This test takes ~170s on CI")]
161    fn query_filtered_exactsizeiterator_len() {
162        fn choose(n: usize, k: usize) -> usize {
163            if n == 0 || k == 0 || n < k {
164                return 0;
165            }
166            let ks = 1..=k;
167            let ns = (n - k + 1..=n).rev();
168            ks.zip(ns).fold(1, |acc, (k, n)| acc * n / k)
169        }
170        fn assert_combination<D, F, const K: usize>(world: &mut World, expected_size: usize)
171        where
172            D: ReadOnlyQueryData + ArchetypeQueryData,
173            F: ArchetypeFilter,
174        {
175            let mut query = world.query_filtered::<D, F>();
176            let query_type = type_name::<QueryCombinationIter<D, F, K>>();
177            let iter = query.iter_combinations::<K>(world);
178            assert_all_sizes_iterator_equal(iter, expected_size, 0, query_type);
179            let iter = query.iter_combinations::<K>(world);
180            assert_all_sizes_iterator_equal(iter, expected_size, 1, query_type);
181            let iter = query.iter_combinations::<K>(world);
182            assert_all_sizes_iterator_equal(iter, expected_size, 5, query_type);
183        }
184        fn assert_all_sizes_equal<D, F>(world: &mut World, expected_size: usize)
185        where
186            D: ReadOnlyQueryData + ArchetypeQueryData,
187            F: ArchetypeFilter,
188        {
189            let mut query = world.query_filtered::<D, F>();
190            let query_type = type_name::<QueryState<D, F>>();
191            assert_all_exact_sizes_iterator_equal(query.iter(world), expected_size, 0, query_type);
192            assert_all_exact_sizes_iterator_equal(query.iter(world), expected_size, 1, query_type);
193            assert_all_exact_sizes_iterator_equal(query.iter(world), expected_size, 5, query_type);
194
195            let expected = expected_size;
196            assert_combination::<D, F, 1>(world, choose(expected, 1));
197            assert_combination::<D, F, 2>(world, choose(expected, 2));
198            assert_combination::<D, F, 5>(world, choose(expected, 5));
199            assert_combination::<D, F, 43>(world, choose(expected, 43));
200            assert_combination::<D, F, 64>(world, choose(expected, 64));
201        }
202        fn assert_all_exact_sizes_iterator_equal(
203            iterator: impl ExactSizeIterator,
204            expected_size: usize,
205            skip: usize,
206            query_type: &'static str,
207        ) {
208            let len = iterator.len();
209            println!("len:           {len}");
210            assert_all_sizes_iterator_equal(iterator, expected_size, skip, query_type);
211            assert_eq!(len, expected_size);
212        }
213        fn assert_all_sizes_iterator_equal(
214            mut iterator: impl Iterator,
215            expected_size: usize,
216            skip: usize,
217            query_type: &'static str,
218        ) {
219            let expected_size = expected_size.saturating_sub(skip);
220            for _ in 0..skip {
221                iterator.next();
222            }
223            let size_hint_0 = iterator.size_hint().0;
224            let size_hint_1 = iterator.size_hint().1;
225            // `count` tests that not only it is the expected value, but also
226            // the value is accurate to what the query returns.
227            let count = iterator.count();
228            // This will show up when one of the asserts in this function fails
229            println!(
230                "query declared sizes: \n\
231                for query:     {query_type} \n\
232                expected:      {expected_size} \n\
233                size_hint().0: {size_hint_0} \n\
234                size_hint().1: {size_hint_1:?} \n\
235                count():       {count}"
236            );
237            assert_eq!(size_hint_0, expected_size);
238            assert_eq!(size_hint_1, Some(expected_size));
239            assert_eq!(count, expected_size);
240        }
241
242        let mut world = World::new();
243        world.spawn((A(1), B(1)));
244        world.spawn(A(2));
245        world.spawn(A(3));
246
247        assert_all_sizes_equal::<&A, With<B>>(&mut world, 1);
248        assert_all_sizes_equal::<&A, Without<B>>(&mut world, 2);
249
250        let mut world = World::new();
251        world.spawn((A(1), B(1), C(1)));
252        world.spawn((A(2), B(2)));
253        world.spawn((A(3), B(3)));
254        world.spawn((A(4), C(4)));
255        world.spawn((A(5), C(5)));
256        world.spawn((A(6), C(6)));
257        world.spawn(A(7));
258        world.spawn(A(8));
259        world.spawn(A(9));
260        world.spawn(A(10));
261
262        // With/Without for B and C
263        assert_all_sizes_equal::<&A, With<B>>(&mut world, 3);
264        assert_all_sizes_equal::<&A, With<C>>(&mut world, 4);
265        assert_all_sizes_equal::<&A, Without<B>>(&mut world, 7);
266        assert_all_sizes_equal::<&A, Without<C>>(&mut world, 6);
267
268        // With/Without (And) combinations
269        assert_all_sizes_equal::<&A, (With<B>, With<C>)>(&mut world, 1);
270        assert_all_sizes_equal::<&A, (With<B>, Without<C>)>(&mut world, 2);
271        assert_all_sizes_equal::<&A, (Without<B>, With<C>)>(&mut world, 3);
272        assert_all_sizes_equal::<&A, (Without<B>, Without<C>)>(&mut world, 4);
273
274        // With/Without Or<()> combinations
275        assert_all_sizes_equal::<&A, Or<(With<B>, With<C>)>>(&mut world, 6);
276        assert_all_sizes_equal::<&A, Or<(With<B>, Without<C>)>>(&mut world, 7);
277        assert_all_sizes_equal::<&A, Or<(Without<B>, With<C>)>>(&mut world, 8);
278        assert_all_sizes_equal::<&A, Or<(Without<B>, Without<C>)>>(&mut world, 9);
279        assert_all_sizes_equal::<&A, (Or<(With<B>,)>, Or<(With<C>,)>)>(&mut world, 1);
280        assert_all_sizes_equal::<&A, Or<(Or<(With<B>, With<C>)>, With<D>)>>(&mut world, 6);
281
282        for i in 11..14 {
283            world.spawn((A(i), D(i)));
284        }
285
286        assert_all_sizes_equal::<&A, Or<(Or<(With<B>, With<C>)>, With<D>)>>(&mut world, 9);
287        assert_all_sizes_equal::<&A, Or<(Or<(With<B>, With<C>)>, Without<D>)>>(&mut world, 10);
288
289        // a fair amount of entities
290        for i in 14..20 {
291            world.spawn((C(i), D(i)));
292        }
293        assert_all_sizes_equal::<Entity, (With<C>, With<D>)>(&mut world, 6);
294    }
295
296    // the order of the combinations is not guaranteed, but each unique combination is present
297    fn check_combinations<T: Ord + Hash + Debug, const K: usize>(
298        values: HashSet<[&T; K]>,
299        expected: HashSet<[&T; K]>,
300    ) {
301        values.iter().for_each(|pair| {
302            let mut sorted = *pair;
303            sorted.sort();
304            assert!(expected.contains(&sorted),
305                    "the results of iter_combinations should contain this combination {:?}. Expected: {:?}, got: {:?}",
306                    &sorted, &expected, &values);
307        });
308    }
309
310    #[test]
311    fn query_iter_combinations() {
312        let mut world = World::new();
313
314        world.spawn((A(1), B(1)));
315        world.spawn(A(2));
316        world.spawn(A(3));
317        world.spawn(A(4));
318
319        let values: HashSet<[&A; 2]> = world.query::<&A>().iter_combinations(&world).collect();
320        check_combinations(
321            values,
322            HashSet::from([
323                [&A(1), &A(2)],
324                [&A(1), &A(3)],
325                [&A(1), &A(4)],
326                [&A(2), &A(3)],
327                [&A(2), &A(4)],
328                [&A(3), &A(4)],
329            ]),
330        );
331        let mut a_query = world.query::<&A>();
332
333        let values: HashSet<[&A; 3]> = a_query.iter_combinations(&world).collect();
334        check_combinations(
335            values,
336            HashSet::from([
337                [&A(1), &A(2), &A(3)],
338                [&A(1), &A(2), &A(4)],
339                [&A(1), &A(3), &A(4)],
340                [&A(2), &A(3), &A(4)],
341            ]),
342        );
343
344        let mut b_query = world.query::<&B>();
345        assert_eq!(
346            b_query.iter_combinations::<2>(&world).size_hint(),
347            (0, Some(0))
348        );
349        let values: Vec<[&B; 2]> = b_query.iter_combinations(&world).collect();
350        assert_eq!(values, Vec::<[&B; 2]>::new());
351    }
352
353    #[test]
354    fn query_filtered_iter_combinations() {
355        use bevy_ecs::query::{Added, Or, With, Without};
356
357        let mut world = World::new();
358
359        world.spawn((A(1), B(1)));
360        world.spawn(A(2));
361        world.spawn(A(3));
362        world.spawn(A(4));
363
364        let mut a_wout_b = world.query_filtered::<&A, Without<B>>();
365        let values: HashSet<[&A; 2]> = a_wout_b.iter_combinations(&world).collect();
366        check_combinations(
367            values,
368            HashSet::from([[&A(2), &A(3)], [&A(2), &A(4)], [&A(3), &A(4)]]),
369        );
370
371        let values: HashSet<[&A; 3]> = a_wout_b.iter_combinations(&world).collect();
372        check_combinations(values, HashSet::from([[&A(2), &A(3), &A(4)]]));
373
374        let mut query = world.query_filtered::<&A, Or<(With<A>, With<B>)>>();
375        let values: HashSet<[&A; 2]> = query.iter_combinations(&world).collect();
376        check_combinations(
377            values,
378            HashSet::from([
379                [&A(1), &A(2)],
380                [&A(1), &A(3)],
381                [&A(1), &A(4)],
382                [&A(2), &A(3)],
383                [&A(2), &A(4)],
384                [&A(3), &A(4)],
385            ]),
386        );
387
388        let mut query = world.query_filtered::<&mut A, Without<B>>();
389        let mut combinations = query.iter_combinations_mut(&mut world);
390        while let Some([mut a, mut b, mut c]) = combinations.fetch_next() {
391            a.0 += 10;
392            b.0 += 100;
393            c.0 += 1000;
394        }
395
396        let values: HashSet<[&A; 3]> = a_wout_b.iter_combinations(&world).collect();
397        check_combinations(values, HashSet::from([[&A(12), &A(103), &A(1004)]]));
398
399        // Check if Added<T>, Changed<T> works
400        let mut world = World::new();
401
402        world.spawn((A(1), B(1)));
403        world.spawn((A(2), B(2)));
404        world.spawn((A(3), B(3)));
405        world.spawn((A(4), B(4)));
406
407        let mut query_added = world.query_filtered::<&A, Added<A>>();
408
409        world.clear_trackers();
410        world.spawn(A(5));
411
412        assert_eq!(query_added.iter_combinations::<2>(&world).count(), 0);
413
414        world.clear_trackers();
415        world.spawn(A(6));
416        world.spawn(A(7));
417
418        assert_eq!(query_added.iter_combinations::<2>(&world).count(), 1);
419
420        world.clear_trackers();
421        world.spawn(A(8));
422        world.spawn(A(9));
423        world.spawn(A(10));
424
425        assert_eq!(query_added.iter_combinations::<2>(&world).count(), 3);
426    }
427
428    #[test]
429    fn query_iter_combinations_sparse() {
430        let mut world = World::new();
431
432        world.spawn_batch((1..=4).map(Sparse));
433
434        let values: HashSet<[&Sparse; 3]> =
435            world.query::<&Sparse>().iter_combinations(&world).collect();
436        check_combinations(
437            values,
438            HashSet::from([
439                [&Sparse(1), &Sparse(2), &Sparse(3)],
440                [&Sparse(1), &Sparse(2), &Sparse(4)],
441                [&Sparse(1), &Sparse(3), &Sparse(4)],
442                [&Sparse(2), &Sparse(3), &Sparse(4)],
443            ]),
444        );
445    }
446
447    #[test]
448    fn get_many_only_mut_checks_duplicates() {
449        let mut world = World::new();
450        let id = world.spawn(A(10)).id();
451        let mut query_state = world.query::<&mut A>();
452        let mut query = query_state.query_mut(&mut world);
453        let result = query.get_many([id, id]);
454        assert_eq!(result, Ok([&A(10), &A(10)]));
455        let mut_result = query.get_many_mut([id, id]);
456        assert!(mut_result.is_err());
457    }
458
459    #[test]
460    fn multi_storage_query() {
461        let mut world = World::new();
462
463        world.spawn((Sparse(1), B(2)));
464        world.spawn(Sparse(2));
465
466        let values = world
467            .query::<&Sparse>()
468            .iter(&world)
469            .collect::<HashSet<&Sparse>>();
470        assert!(values.contains(&Sparse(1)));
471        assert!(values.contains(&Sparse(2)));
472
473        for (_a, mut b) in world.query::<(&Sparse, &mut B)>().iter_mut(&mut world) {
474            b.0 = 3;
475        }
476
477        let values = world.query::<&B>().iter(&world).collect::<Vec<&B>>();
478        assert_eq!(values, vec![&B(3)]);
479    }
480
481    #[test]
482    fn any_query() {
483        let mut world = World::new();
484
485        world.spawn((A(1), B(2)));
486        world.spawn(A(2));
487        world.spawn(C(3));
488
489        let values: Vec<(Option<&A>, Option<&B>)> =
490            world.query::<AnyOf<(&A, &B)>>().iter(&world).collect();
491
492        assert_eq!(
493            values,
494            vec![(Some(&A(1)), Some(&B(2))), (Some(&A(2)), None),]
495        );
496    }
497
498    #[test]
499    fn has_query() {
500        let mut world = World::new();
501
502        world.spawn((A(1), B(1)));
503        world.spawn(A(2));
504        world.spawn((A(3), B(1)));
505        world.spawn(A(4));
506
507        let values: HashSet<(&A, bool)> = world.query::<(&A, Has<B>)>().iter(&world).collect();
508
509        assert!(values.contains(&(&A(1), true)));
510        assert!(values.contains(&(&A(2), false)));
511        assert!(values.contains(&(&A(3), true)));
512        assert!(values.contains(&(&A(4), false)));
513    }
514
515    #[test]
516    #[should_panic]
517    fn self_conflicting_worldquery() {
518        #[derive(QueryData)]
519        #[query_data(mutable)]
520        struct SelfConflicting {
521            a: &'static mut A,
522            b: &'static mut A,
523        }
524
525        let mut world = World::new();
526        world.query::<SelfConflicting>();
527    }
528
529    #[test]
530    fn derived_worldqueries() {
531        let mut world = World::new();
532
533        world.spawn((A(10), B(18), C(3), Sparse(4)));
534
535        world.spawn((A(101), B(148), C(13)));
536        world.spawn((A(51), B(46), Sparse(72)));
537        world.spawn((A(398), C(6), Sparse(9)));
538        world.spawn((B(11), C(28), Sparse(92)));
539
540        world.spawn((C(18348), Sparse(101)));
541        world.spawn((B(839), Sparse(5)));
542        world.spawn((B(6721), C(122)));
543        world.spawn((A(220), Sparse(63)));
544        world.spawn((A(1092), C(382)));
545        world.spawn((A(2058), B(3019)));
546
547        world.spawn((B(38), C(8), Sparse(100)));
548        world.spawn((A(111), C(52), Sparse(1)));
549        world.spawn((A(599), B(39), Sparse(13)));
550        world.spawn((A(55), B(66), C(77)));
551
552        world.spawn_empty();
553
554        {
555            #[derive(QueryData)]
556            struct CustomAB {
557                a: &'static A,
558                b: &'static B,
559            }
560
561            let custom_param_data = world
562                .query::<CustomAB>()
563                .iter(&world)
564                .map(|item| (*item.a, *item.b))
565                .collect::<Vec<_>>();
566            let normal_data = world
567                .query::<(&A, &B)>()
568                .iter(&world)
569                .map(|(a, b)| (*a, *b))
570                .collect::<Vec<_>>();
571            assert_eq!(custom_param_data, normal_data);
572        }
573
574        {
575            #[derive(QueryData)]
576            struct FancyParam {
577                e: Entity,
578                b: &'static B,
579                opt: Option<&'static Sparse>,
580            }
581
582            let custom_param_data = world
583                .query::<FancyParam>()
584                .iter(&world)
585                .map(|fancy| (fancy.e, *fancy.b, fancy.opt.copied()))
586                .collect::<Vec<_>>();
587            let normal_data = world
588                .query::<(Entity, &B, Option<&Sparse>)>()
589                .iter(&world)
590                .map(|(e, b, opt)| (e, *b, opt.copied()))
591                .collect::<Vec<_>>();
592            assert_eq!(custom_param_data, normal_data);
593        }
594
595        {
596            #[derive(QueryData)]
597            struct MaybeBSparse {
598                blah: Option<(&'static B, &'static Sparse)>,
599            }
600            #[derive(QueryData)]
601            struct MatchEverything {
602                abcs: AnyOf<(&'static A, &'static B, &'static C)>,
603                opt_bsparse: MaybeBSparse,
604            }
605
606            let custom_param_data = world
607                .query::<MatchEverything>()
608                .iter(&world)
609                .map(
610                    |MatchEverythingItem {
611                         abcs: (a, b, c),
612                         opt_bsparse: MaybeBSparseItem { blah: bsparse },
613                     }| {
614                        (
615                            (a.copied(), b.copied(), c.copied()),
616                            bsparse.map(|(b, sparse)| (*b, *sparse)),
617                        )
618                    },
619                )
620                .collect::<Vec<_>>();
621            let normal_data = world
622                .query::<(AnyOf<(&A, &B, &C)>, Option<(&B, &Sparse)>)>()
623                .iter(&world)
624                .map(|((a, b, c), bsparse)| {
625                    (
626                        (a.copied(), b.copied(), c.copied()),
627                        bsparse.map(|(b, sparse)| (*b, *sparse)),
628                    )
629                })
630                .collect::<Vec<_>>();
631            assert_eq!(custom_param_data, normal_data);
632        }
633
634        {
635            #[derive(QueryFilter)]
636            struct AOrBFilter {
637                a: Or<(With<A>, With<B>)>,
638            }
639            #[derive(QueryFilter)]
640            struct NoSparseThatsSlow {
641                no: Without<Sparse>,
642            }
643
644            let custom_param_entities = world
645                .query_filtered::<Entity, (AOrBFilter, NoSparseThatsSlow)>()
646                .iter(&world)
647                .collect::<Vec<_>>();
648            let normal_entities = world
649                .query_filtered::<Entity, (Or<(With<A>, With<B>)>, Without<Sparse>)>()
650                .iter(&world)
651                .collect::<Vec<_>>();
652            assert_eq!(custom_param_entities, normal_entities);
653        }
654
655        {
656            #[derive(QueryFilter)]
657            struct CSparseFilter {
658                tuple_structs_pls: With<C>,
659                ugh: With<Sparse>,
660            }
661
662            let custom_param_entities = world
663                .query_filtered::<Entity, CSparseFilter>()
664                .iter(&world)
665                .collect::<Vec<_>>();
666            let normal_entities = world
667                .query_filtered::<Entity, (With<C>, With<Sparse>)>()
668                .iter(&world)
669                .collect::<Vec<_>>();
670            assert_eq!(custom_param_entities, normal_entities);
671        }
672
673        {
674            #[derive(QueryFilter)]
675            struct WithoutComps {
676                _1: Without<A>,
677                _2: Without<B>,
678                _3: Without<C>,
679            }
680
681            let custom_param_entities = world
682                .query_filtered::<Entity, WithoutComps>()
683                .iter(&world)
684                .collect::<Vec<_>>();
685            let normal_entities = world
686                .query_filtered::<Entity, (Without<A>, Without<B>, Without<C>)>()
687                .iter(&world)
688                .collect::<Vec<_>>();
689            assert_eq!(custom_param_entities, normal_entities);
690        }
691
692        {
693            #[derive(QueryData)]
694            struct IterCombAB {
695                a: &'static A,
696                b: &'static B,
697            }
698
699            let custom_param_data = world
700                .query::<IterCombAB>()
701                .iter_combinations::<2>(&world)
702                .map(|[item0, item1]| [(*item0.a, *item0.b), (*item1.a, *item1.b)])
703                .collect::<Vec<_>>();
704            let normal_data = world
705                .query::<(&A, &B)>()
706                .iter_combinations(&world)
707                .map(|[(a0, b0), (a1, b1)]| [(*a0, *b0), (*a1, *b1)])
708                .collect::<Vec<_>>();
709            assert_eq!(custom_param_data, normal_data);
710        }
711    }
712
713    #[test]
714    fn many_entities() {
715        let mut world = World::new();
716        world.spawn((A(0), B(0)));
717        world.spawn((A(0), B(0)));
718        world.spawn(A(0));
719        world.spawn(B(0));
720        {
721            fn system(has_a: Query<Entity, With<A>>, has_a_and_b: Query<(&A, &B)>) {
722                assert_eq!(has_a_and_b.iter_many(&has_a).count(), 2);
723            }
724            let mut system = IntoSystem::into_system(system);
725            system.initialize(&mut world);
726            system.run((), &mut world).unwrap();
727        }
728        {
729            fn system(has_a: Query<Entity, With<A>>, mut b_query: Query<&mut B>) {
730                let mut iter = b_query.iter_many_mut(&has_a);
731                while let Some(mut b) = iter.fetch_next() {
732                    b.0 = 1;
733                }
734            }
735            let mut system = IntoSystem::into_system(system);
736            system.initialize(&mut world);
737            system.run((), &mut world).unwrap();
738        }
739        {
740            fn system(query: Query<(Option<&A>, &B)>) {
741                for (maybe_a, b) in &query {
742                    match maybe_a {
743                        Some(_) => assert_eq!(b.0, 1),
744                        None => assert_eq!(b.0, 0),
745                    }
746                }
747            }
748            let mut system = IntoSystem::into_system(system);
749            system.initialize(&mut world);
750            system.run((), &mut world).unwrap();
751        }
752    }
753
754    #[test]
755    fn mut_to_immut_query_methods_have_immut_item() {
756        #[derive(Component)]
757        struct Foo;
758
759        let mut world = World::new();
760        let e = world.spawn(Foo).id();
761
762        // state
763        let mut q = world.query::<&mut Foo>();
764        let _: Option<&Foo> = q.iter(&world).next();
765        let _: Option<[&Foo; 2]> = q.iter_combinations::<2>(&world).next();
766        let _: Option<&Foo> = q.iter_manual(&world).next();
767        let _: Option<&Foo> = q.iter_many(&world, [e]).next();
768        q.iter(&world).for_each(|_: &Foo| ());
769
770        let _: Option<&Foo> = q.get(&world, e).ok();
771        let _: Option<&Foo> = q.get_manual(&world, e).ok();
772        let _: Option<[&Foo; 1]> = q.get_many(&world, [e]).ok();
773        let _: Option<&Foo> = q.single(&world).ok();
774        let _: &Foo = q.single(&world).unwrap();
775
776        // system param
777        let mut q = SystemState::<Query<&mut Foo>>::new(&mut world);
778        let q = q.get_mut(&mut world).unwrap();
779        let _: Option<&Foo> = q.iter().next();
780        let _: Option<[&Foo; 2]> = q.iter_combinations::<2>().next();
781        let _: Option<&Foo> = q.iter_many([e]).next();
782        q.iter().for_each(|_: &Foo| ());
783
784        let _: Option<&Foo> = q.get(e).ok();
785        let _: Option<[&Foo; 1]> = q.get_many([e]).ok();
786        let _: Option<&Foo> = q.single().ok();
787        let _: &Foo = q.single().unwrap();
788    }
789
790    // regression test for https://github.com/bevyengine/bevy/pull/8029
791    #[test]
792    fn par_iter_mut_change_detection() {
793        let mut world = World::new();
794        world.spawn((A(1), B(1)));
795
796        fn propagate_system(mut query: Query<(&A, &mut B), Changed<A>>) {
797            query.par_iter_mut().for_each(|(a, mut b)| {
798                b.0 = a.0;
799            });
800        }
801
802        fn modify_system(mut query: Query<&mut A>) {
803            for mut a in &mut query {
804                a.0 = 2;
805            }
806        }
807
808        let mut schedule = Schedule::default();
809        schedule.add_systems((propagate_system, modify_system).chain());
810        schedule.run(&mut world);
811        world.clear_trackers();
812        schedule.run(&mut world);
813        world.clear_trackers();
814
815        let values = world.query::<&B>().iter(&world).collect::<Vec<&B>>();
816        assert_eq!(values, vec![&B(2)]);
817    }
818
819    // regression test for https://github.com/bevyengine/bevy/pull/23352
820    #[test]
821    // presence/lack of trailing commas are significant in this test, so skip rustfmt
822    #[rustfmt::skip]
823    fn query_data_derive_where_clause() {
824        #[derive(QueryData)]
825        struct QueryDataA<C>
826        where
827            C: Component,
828        {
829            component: &'static C,
830        }
831
832        #[derive(QueryData)]
833        struct QueryDataB<C>(&'static C)
834        where
835            C: Component;
836    }
837
838    // regression test for https://github.com/bevyengine/bevy/pull/23394
839    #[test]
840    fn query_data_derive_contiguous_tuple() {
841        #[derive(QueryData)]
842        #[query_data(contiguous(mutable))]
843        struct QueryDataA(Entity, &'static A);
844
845        #[derive(QueryData)]
846        #[query_data(contiguous(all))]
847        struct QueryDataB<C>(&'static C)
848        where
849            C: Component + PartialEq;
850
851        let mut world = World::new();
852        let _ = world.query::<QueryDataA>().contiguous_iter_mut(&mut world);
853        let _ = world.query::<QueryDataB<D>>().contiguous_iter(&world);
854    }
855
856    // regression test for https://github.com/bevyengine/bevy/pull/23930
857    #[test]
858    fn query_data_derive_empty() {
859        #[derive(QueryData)]
860        struct QueryDataA {}
861
862        #[derive(QueryData)]
863        struct QueryDataB();
864
865        #[derive(QueryData)]
866        #[query_data(mutable)]
867        struct QueryDataC {}
868
869        #[derive(QueryData)]
870        #[query_data(mutable)]
871        struct QueryDataD();
872
873        #[derive(QueryData)]
874        #[query_data(contiguous(immutable))]
875        struct QueryDataE {}
876
877        #[derive(QueryData)]
878        #[query_data(contiguous(immutable))]
879        struct QueryDataF();
880
881        #[derive(QueryData)]
882        #[query_data(mutable, contiguous(immutable))]
883        struct QueryDataG {}
884
885        #[derive(QueryData)]
886        #[query_data(mutable, contiguous(immutable))]
887        struct QueryDataH();
888
889        #[derive(QueryData)]
890        #[query_data(contiguous(mutable))]
891        struct QueryDataI {}
892
893        #[derive(QueryData)]
894        #[query_data(contiguous(mutable))]
895        struct QueryDataJ();
896
897        #[derive(QueryData)]
898        #[query_data(mutable, contiguous(mutable))]
899        struct QueryDataK {}
900
901        #[derive(QueryData)]
902        #[query_data(mutable, contiguous(mutable))]
903        struct QueryDataL();
904
905        #[derive(QueryData)]
906        #[query_data(contiguous(all))]
907        struct QueryDataM {}
908
909        #[derive(QueryData)]
910        #[query_data(contiguous(all))]
911        struct QueryDataN();
912
913        #[derive(QueryData)]
914        #[query_data(mutable, contiguous(all))]
915        struct QueryDataO {}
916
917        #[derive(QueryData)]
918        #[query_data(mutable, contiguous(all))]
919        struct QueryDataP();
920    }
921}