1mod access;
4mod access_iter;
5mod builder;
6mod error;
7mod fetch;
8mod filter;
9mod iter;
10mod par_iter;
11mod state;
12mod world_query;
13
14pub use access::*;
15pub use access_iter::*;
16pub use bevy_ecs_macros::{QueryData, QueryFilter};
17pub use builder::*;
18pub use error::*;
19pub use fetch::*;
20pub use filter::*;
21pub use iter::*;
22pub use par_iter::*;
23pub use state::*;
24pub use world_query::*;
25
26#[doc(hidden)]
31pub trait DebugCheckedUnwrap {
32 type Item;
33 unsafe fn debug_checked_unwrap(self) -> Self::Item;
40}
41
42#[cfg(debug_assertions)]
45impl<T> DebugCheckedUnwrap for Option<T> {
46 type Item = T;
47
48 #[inline(always)]
49 #[track_caller]
50 unsafe fn debug_checked_unwrap(self) -> Self::Item {
51 if let Some(inner) = self {
52 inner
53 } else {
54 unreachable!()
55 }
56 }
57}
58
59#[cfg(debug_assertions)]
62impl<T, U> DebugCheckedUnwrap for Result<T, U> {
63 type Item = T;
64
65 #[inline(always)]
66 #[track_caller]
67 unsafe fn debug_checked_unwrap(self) -> Self::Item {
68 if let Ok(inner) = self {
69 inner
70 } else {
71 unreachable!()
72 }
73 }
74}
75
76#[cfg(not(debug_assertions))]
79impl<T, U> DebugCheckedUnwrap for Result<T, U> {
80 type Item = T;
81
82 #[inline(always)]
83 #[track_caller]
84 unsafe fn debug_checked_unwrap(self) -> Self::Item {
85 if let Ok(inner) = self {
86 inner
87 } else {
88 core::hint::unreachable_unchecked()
89 }
90 }
91}
92
93#[cfg(not(debug_assertions))]
94impl<T> DebugCheckedUnwrap for Option<T> {
95 type Item = T;
96
97 #[inline(always)]
98 unsafe fn debug_checked_unwrap(self) -> Self::Item {
99 if let Some(inner) = self {
100 inner
101 } else {
102 core::hint::unreachable_unchecked()
103 }
104 }
105}
106
107#[cfg(test)]
108#[expect(clippy::print_stdout, reason = "Allowed in tests.")]
109mod tests {
110 use crate::{
111 archetype::Archetype,
112 change_detection::Tick,
113 component::{Component, ComponentId, Components},
114 prelude::{AnyOf, Changed, Entity, Or, QueryState, Resource, With, Without},
115 query::{
116 ArchetypeFilter, ArchetypeQueryData, FilteredAccess, Has, QueryCombinationIter,
117 QueryData, QueryFilter, ReadOnlyQueryData, WorldQuery,
118 },
119 schedule::{IntoScheduleConfigs, Schedule},
120 storage::{Table, TableRow},
121 system::{assert_is_system, IntoSystem, Query, System, SystemState},
122 world::{unsafe_world_cell::UnsafeWorldCell, World},
123 };
124 use alloc::{vec, vec::Vec};
125 use core::{any::type_name, fmt::Debug, hash::Hash};
126 use std::{collections::HashSet, println};
127
128 #[derive(Component, Debug, Hash, Eq, PartialEq, Clone, Copy, PartialOrd, Ord)]
129 struct A(usize);
130 #[derive(Component, Debug, Hash, Eq, PartialEq, Clone, Copy)]
131 struct B(usize);
132 #[derive(Component, Debug, Eq, PartialEq, Clone, Copy)]
133 struct C(usize);
134 #[derive(Component, Debug, Eq, PartialEq, Clone, Copy)]
135 struct D(usize);
136
137 #[derive(Component, Debug, Hash, Eq, PartialEq, Clone, Copy, PartialOrd, Ord)]
138 #[component(storage = "SparseSet")]
139 struct Sparse(usize);
140
141 #[test]
142 fn query() {
143 let mut world = World::new();
144 world.spawn((A(1), B(1)));
145 world.spawn(A(2));
146 let values = world.query::<&A>().iter(&world).collect::<HashSet<&A>>();
147 assert!(values.contains(&A(1)));
148 assert!(values.contains(&A(2)));
149
150 for (_a, mut b) in world.query::<(&A, &mut B)>().iter_mut(&mut world) {
151 b.0 = 3;
152 }
153 let values = world.query::<&B>().iter(&world).collect::<Vec<&B>>();
154 assert_eq!(values, vec![&B(3)]);
155 }
156
157 #[test]
158 fn query_filtered_exactsizeiterator_len() {
159 fn choose(n: usize, k: usize) -> usize {
160 if n == 0 || k == 0 || n < k {
161 return 0;
162 }
163 let ks = 1..=k;
164 let ns = (n - k + 1..=n).rev();
165 ks.zip(ns).fold(1, |acc, (k, n)| acc * n / k)
166 }
167 fn assert_combination<D, F, const K: usize>(world: &mut World, expected_size: usize)
168 where
169 D: ReadOnlyQueryData + ArchetypeQueryData,
170 F: ArchetypeFilter,
171 {
172 let mut query = world.query_filtered::<D, F>();
173 let query_type = type_name::<QueryCombinationIter<D, F, K>>();
174 let iter = query.iter_combinations::<K>(world);
175 assert_all_sizes_iterator_equal(iter, expected_size, 0, query_type);
176 let iter = query.iter_combinations::<K>(world);
177 assert_all_sizes_iterator_equal(iter, expected_size, 1, query_type);
178 let iter = query.iter_combinations::<K>(world);
179 assert_all_sizes_iterator_equal(iter, expected_size, 5, query_type);
180 }
181 fn assert_all_sizes_equal<D, F>(world: &mut World, expected_size: usize)
182 where
183 D: ReadOnlyQueryData + ArchetypeQueryData,
184 F: ArchetypeFilter,
185 {
186 let mut query = world.query_filtered::<D, F>();
187 let query_type = type_name::<QueryState<D, F>>();
188 assert_all_exact_sizes_iterator_equal(query.iter(world), expected_size, 0, query_type);
189 assert_all_exact_sizes_iterator_equal(query.iter(world), expected_size, 1, query_type);
190 assert_all_exact_sizes_iterator_equal(query.iter(world), expected_size, 5, query_type);
191
192 let expected = expected_size;
193 assert_combination::<D, F, 1>(world, choose(expected, 1));
194 assert_combination::<D, F, 2>(world, choose(expected, 2));
195 assert_combination::<D, F, 5>(world, choose(expected, 5));
196 assert_combination::<D, F, 43>(world, choose(expected, 43));
197 assert_combination::<D, F, 64>(world, choose(expected, 64));
198 }
199 fn assert_all_exact_sizes_iterator_equal(
200 iterator: impl ExactSizeIterator,
201 expected_size: usize,
202 skip: usize,
203 query_type: &'static str,
204 ) {
205 let len = iterator.len();
206 println!("len: {len}");
207 assert_all_sizes_iterator_equal(iterator, expected_size, skip, query_type);
208 assert_eq!(len, expected_size);
209 }
210 fn assert_all_sizes_iterator_equal(
211 mut iterator: impl Iterator,
212 expected_size: usize,
213 skip: usize,
214 query_type: &'static str,
215 ) {
216 let expected_size = expected_size.saturating_sub(skip);
217 for _ in 0..skip {
218 iterator.next();
219 }
220 let size_hint_0 = iterator.size_hint().0;
221 let size_hint_1 = iterator.size_hint().1;
222 let count = iterator.count();
225 println!(
227 "query declared sizes: \n\
228 for query: {query_type} \n\
229 expected: {expected_size} \n\
230 size_hint().0: {size_hint_0} \n\
231 size_hint().1: {size_hint_1:?} \n\
232 count(): {count}"
233 );
234 assert_eq!(size_hint_0, expected_size);
235 assert_eq!(size_hint_1, Some(expected_size));
236 assert_eq!(count, expected_size);
237 }
238
239 let mut world = World::new();
240 world.spawn((A(1), B(1)));
241 world.spawn(A(2));
242 world.spawn(A(3));
243
244 assert_all_sizes_equal::<&A, With<B>>(&mut world, 1);
245 assert_all_sizes_equal::<&A, Without<B>>(&mut world, 2);
246
247 let mut world = World::new();
248 world.spawn((A(1), B(1), C(1)));
249 world.spawn((A(2), B(2)));
250 world.spawn((A(3), B(3)));
251 world.spawn((A(4), C(4)));
252 world.spawn((A(5), C(5)));
253 world.spawn((A(6), C(6)));
254 world.spawn(A(7));
255 world.spawn(A(8));
256 world.spawn(A(9));
257 world.spawn(A(10));
258
259 assert_all_sizes_equal::<&A, With<B>>(&mut world, 3);
261 assert_all_sizes_equal::<&A, With<C>>(&mut world, 4);
262 assert_all_sizes_equal::<&A, Without<B>>(&mut world, 7);
263 assert_all_sizes_equal::<&A, Without<C>>(&mut world, 6);
264
265 assert_all_sizes_equal::<&A, (With<B>, With<C>)>(&mut world, 1);
267 assert_all_sizes_equal::<&A, (With<B>, Without<C>)>(&mut world, 2);
268 assert_all_sizes_equal::<&A, (Without<B>, With<C>)>(&mut world, 3);
269 assert_all_sizes_equal::<&A, (Without<B>, Without<C>)>(&mut world, 4);
270
271 assert_all_sizes_equal::<&A, Or<(With<B>, With<C>)>>(&mut world, 6);
273 assert_all_sizes_equal::<&A, Or<(With<B>, Without<C>)>>(&mut world, 7);
274 assert_all_sizes_equal::<&A, Or<(Without<B>, With<C>)>>(&mut world, 8);
275 assert_all_sizes_equal::<&A, Or<(Without<B>, Without<C>)>>(&mut world, 9);
276 assert_all_sizes_equal::<&A, (Or<(With<B>,)>, Or<(With<C>,)>)>(&mut world, 1);
277 assert_all_sizes_equal::<&A, Or<(Or<(With<B>, With<C>)>, With<D>)>>(&mut world, 6);
278
279 for i in 11..14 {
280 world.spawn((A(i), D(i)));
281 }
282
283 assert_all_sizes_equal::<&A, Or<(Or<(With<B>, With<C>)>, With<D>)>>(&mut world, 9);
284 assert_all_sizes_equal::<&A, Or<(Or<(With<B>, With<C>)>, Without<D>)>>(&mut world, 10);
285
286 for i in 14..20 {
288 world.spawn((C(i), D(i)));
289 }
290 assert_all_sizes_equal::<Entity, (With<C>, With<D>)>(&mut world, 6);
291 }
292
293 fn check_combinations<T: Ord + Hash + Debug, const K: usize>(
295 values: HashSet<[&T; K]>,
296 expected: HashSet<[&T; K]>,
297 ) {
298 values.iter().for_each(|pair| {
299 let mut sorted = *pair;
300 sorted.sort();
301 assert!(expected.contains(&sorted),
302 "the results of iter_combinations should contain this combination {:?}. Expected: {:?}, got: {:?}",
303 &sorted, &expected, &values);
304 });
305 }
306
307 #[test]
308 fn query_iter_combinations() {
309 let mut world = World::new();
310
311 world.spawn((A(1), B(1)));
312 world.spawn(A(2));
313 world.spawn(A(3));
314 world.spawn(A(4));
315
316 let values: HashSet<[&A; 2]> = world.query::<&A>().iter_combinations(&world).collect();
317 check_combinations(
318 values,
319 HashSet::from([
320 [&A(1), &A(2)],
321 [&A(1), &A(3)],
322 [&A(1), &A(4)],
323 [&A(2), &A(3)],
324 [&A(2), &A(4)],
325 [&A(3), &A(4)],
326 ]),
327 );
328 let mut a_query = world.query::<&A>();
329
330 let values: HashSet<[&A; 3]> = a_query.iter_combinations(&world).collect();
331 check_combinations(
332 values,
333 HashSet::from([
334 [&A(1), &A(2), &A(3)],
335 [&A(1), &A(2), &A(4)],
336 [&A(1), &A(3), &A(4)],
337 [&A(2), &A(3), &A(4)],
338 ]),
339 );
340
341 let mut b_query = world.query::<&B>();
342 assert_eq!(
343 b_query.iter_combinations::<2>(&world).size_hint(),
344 (0, Some(0))
345 );
346 let values: Vec<[&B; 2]> = b_query.iter_combinations(&world).collect();
347 assert_eq!(values, Vec::<[&B; 2]>::new());
348 }
349
350 #[test]
351 fn query_filtered_iter_combinations() {
352 use bevy_ecs::query::{Added, Or, With, Without};
353
354 let mut world = World::new();
355
356 world.spawn((A(1), B(1)));
357 world.spawn(A(2));
358 world.spawn(A(3));
359 world.spawn(A(4));
360
361 let mut a_wout_b = world.query_filtered::<&A, Without<B>>();
362 let values: HashSet<[&A; 2]> = a_wout_b.iter_combinations(&world).collect();
363 check_combinations(
364 values,
365 HashSet::from([[&A(2), &A(3)], [&A(2), &A(4)], [&A(3), &A(4)]]),
366 );
367
368 let values: HashSet<[&A; 3]> = a_wout_b.iter_combinations(&world).collect();
369 check_combinations(values, HashSet::from([[&A(2), &A(3), &A(4)]]));
370
371 let mut query = world.query_filtered::<&A, Or<(With<A>, With<B>)>>();
372 let values: HashSet<[&A; 2]> = query.iter_combinations(&world).collect();
373 check_combinations(
374 values,
375 HashSet::from([
376 [&A(1), &A(2)],
377 [&A(1), &A(3)],
378 [&A(1), &A(4)],
379 [&A(2), &A(3)],
380 [&A(2), &A(4)],
381 [&A(3), &A(4)],
382 ]),
383 );
384
385 let mut query = world.query_filtered::<&mut A, Without<B>>();
386 let mut combinations = query.iter_combinations_mut(&mut world);
387 while let Some([mut a, mut b, mut c]) = combinations.fetch_next() {
388 a.0 += 10;
389 b.0 += 100;
390 c.0 += 1000;
391 }
392
393 let values: HashSet<[&A; 3]> = a_wout_b.iter_combinations(&world).collect();
394 check_combinations(values, HashSet::from([[&A(12), &A(103), &A(1004)]]));
395
396 let mut world = World::new();
398
399 world.spawn((A(1), B(1)));
400 world.spawn((A(2), B(2)));
401 world.spawn((A(3), B(3)));
402 world.spawn((A(4), B(4)));
403
404 let mut query_added = world.query_filtered::<&A, Added<A>>();
405
406 world.clear_trackers();
407 world.spawn(A(5));
408
409 assert_eq!(query_added.iter_combinations::<2>(&world).count(), 0);
410
411 world.clear_trackers();
412 world.spawn(A(6));
413 world.spawn(A(7));
414
415 assert_eq!(query_added.iter_combinations::<2>(&world).count(), 1);
416
417 world.clear_trackers();
418 world.spawn(A(8));
419 world.spawn(A(9));
420 world.spawn(A(10));
421
422 assert_eq!(query_added.iter_combinations::<2>(&world).count(), 3);
423 }
424
425 #[test]
426 fn query_iter_combinations_sparse() {
427 let mut world = World::new();
428
429 world.spawn_batch((1..=4).map(Sparse));
430
431 let values: HashSet<[&Sparse; 3]> =
432 world.query::<&Sparse>().iter_combinations(&world).collect();
433 check_combinations(
434 values,
435 HashSet::from([
436 [&Sparse(1), &Sparse(2), &Sparse(3)],
437 [&Sparse(1), &Sparse(2), &Sparse(4)],
438 [&Sparse(1), &Sparse(3), &Sparse(4)],
439 [&Sparse(2), &Sparse(3), &Sparse(4)],
440 ]),
441 );
442 }
443
444 #[test]
445 fn get_many_only_mut_checks_duplicates() {
446 let mut world = World::new();
447 let id = world.spawn(A(10)).id();
448 let mut query_state = world.query::<&mut A>();
449 let mut query = query_state.query_mut(&mut world);
450 let result = query.get_many([id, id]);
451 assert_eq!(result, Ok([&A(10), &A(10)]));
452 let mut_result = query.get_many_mut([id, id]);
453 assert!(mut_result.is_err());
454 }
455
456 #[test]
457 fn multi_storage_query() {
458 let mut world = World::new();
459
460 world.spawn((Sparse(1), B(2)));
461 world.spawn(Sparse(2));
462
463 let values = world
464 .query::<&Sparse>()
465 .iter(&world)
466 .collect::<HashSet<&Sparse>>();
467 assert!(values.contains(&Sparse(1)));
468 assert!(values.contains(&Sparse(2)));
469
470 for (_a, mut b) in world.query::<(&Sparse, &mut B)>().iter_mut(&mut world) {
471 b.0 = 3;
472 }
473
474 let values = world.query::<&B>().iter(&world).collect::<Vec<&B>>();
475 assert_eq!(values, vec![&B(3)]);
476 }
477
478 #[test]
479 fn any_query() {
480 let mut world = World::new();
481
482 world.spawn((A(1), B(2)));
483 world.spawn(A(2));
484 world.spawn(C(3));
485
486 let values: Vec<(Option<&A>, Option<&B>)> =
487 world.query::<AnyOf<(&A, &B)>>().iter(&world).collect();
488
489 assert_eq!(
490 values,
491 vec![(Some(&A(1)), Some(&B(2))), (Some(&A(2)), None),]
492 );
493 }
494
495 #[test]
496 fn has_query() {
497 let mut world = World::new();
498
499 world.spawn((A(1), B(1)));
500 world.spawn(A(2));
501 world.spawn((A(3), B(1)));
502 world.spawn(A(4));
503
504 let values: HashSet<(&A, bool)> = world.query::<(&A, Has<B>)>().iter(&world).collect();
505
506 assert!(values.contains(&(&A(1), true)));
507 assert!(values.contains(&(&A(2), false)));
508 assert!(values.contains(&(&A(3), true)));
509 assert!(values.contains(&(&A(4), false)));
510 }
511
512 #[test]
513 #[should_panic]
514 fn self_conflicting_worldquery() {
515 #[derive(QueryData)]
516 #[query_data(mutable)]
517 struct SelfConflicting {
518 a: &'static mut A,
519 b: &'static mut A,
520 }
521
522 let mut world = World::new();
523 world.query::<SelfConflicting>();
524 }
525
526 #[test]
527 fn derived_worldqueries() {
528 let mut world = World::new();
529
530 world.spawn((A(10), B(18), C(3), Sparse(4)));
531
532 world.spawn((A(101), B(148), C(13)));
533 world.spawn((A(51), B(46), Sparse(72)));
534 world.spawn((A(398), C(6), Sparse(9)));
535 world.spawn((B(11), C(28), Sparse(92)));
536
537 world.spawn((C(18348), Sparse(101)));
538 world.spawn((B(839), Sparse(5)));
539 world.spawn((B(6721), C(122)));
540 world.spawn((A(220), Sparse(63)));
541 world.spawn((A(1092), C(382)));
542 world.spawn((A(2058), B(3019)));
543
544 world.spawn((B(38), C(8), Sparse(100)));
545 world.spawn((A(111), C(52), Sparse(1)));
546 world.spawn((A(599), B(39), Sparse(13)));
547 world.spawn((A(55), B(66), C(77)));
548
549 world.spawn_empty();
550
551 {
552 #[derive(QueryData)]
553 struct CustomAB {
554 a: &'static A,
555 b: &'static B,
556 }
557
558 let custom_param_data = world
559 .query::<CustomAB>()
560 .iter(&world)
561 .map(|item| (*item.a, *item.b))
562 .collect::<Vec<_>>();
563 let normal_data = world
564 .query::<(&A, &B)>()
565 .iter(&world)
566 .map(|(a, b)| (*a, *b))
567 .collect::<Vec<_>>();
568 assert_eq!(custom_param_data, normal_data);
569 }
570
571 {
572 #[derive(QueryData)]
573 struct FancyParam {
574 e: Entity,
575 b: &'static B,
576 opt: Option<&'static Sparse>,
577 }
578
579 let custom_param_data = world
580 .query::<FancyParam>()
581 .iter(&world)
582 .map(|fancy| (fancy.e, *fancy.b, fancy.opt.copied()))
583 .collect::<Vec<_>>();
584 let normal_data = world
585 .query::<(Entity, &B, Option<&Sparse>)>()
586 .iter(&world)
587 .map(|(e, b, opt)| (e, *b, opt.copied()))
588 .collect::<Vec<_>>();
589 assert_eq!(custom_param_data, normal_data);
590 }
591
592 {
593 #[derive(QueryData)]
594 struct MaybeBSparse {
595 blah: Option<(&'static B, &'static Sparse)>,
596 }
597 #[derive(QueryData)]
598 struct MatchEverything {
599 abcs: AnyOf<(&'static A, &'static B, &'static C)>,
600 opt_bsparse: MaybeBSparse,
601 }
602
603 let custom_param_data = world
604 .query::<MatchEverything>()
605 .iter(&world)
606 .map(
607 |MatchEverythingItem {
608 abcs: (a, b, c),
609 opt_bsparse: MaybeBSparseItem { blah: bsparse },
610 }| {
611 (
612 (a.copied(), b.copied(), c.copied()),
613 bsparse.map(|(b, sparse)| (*b, *sparse)),
614 )
615 },
616 )
617 .collect::<Vec<_>>();
618 let normal_data = world
619 .query::<(AnyOf<(&A, &B, &C)>, Option<(&B, &Sparse)>)>()
620 .iter(&world)
621 .map(|((a, b, c), bsparse)| {
622 (
623 (a.copied(), b.copied(), c.copied()),
624 bsparse.map(|(b, sparse)| (*b, *sparse)),
625 )
626 })
627 .collect::<Vec<_>>();
628 assert_eq!(custom_param_data, normal_data);
629 }
630
631 {
632 #[derive(QueryFilter)]
633 struct AOrBFilter {
634 a: Or<(With<A>, With<B>)>,
635 }
636 #[derive(QueryFilter)]
637 struct NoSparseThatsSlow {
638 no: Without<Sparse>,
639 }
640
641 let custom_param_entities = world
642 .query_filtered::<Entity, (AOrBFilter, NoSparseThatsSlow)>()
643 .iter(&world)
644 .collect::<Vec<_>>();
645 let normal_entities = world
646 .query_filtered::<Entity, (Or<(With<A>, With<B>)>, Without<Sparse>)>()
647 .iter(&world)
648 .collect::<Vec<_>>();
649 assert_eq!(custom_param_entities, normal_entities);
650 }
651
652 {
653 #[derive(QueryFilter)]
654 struct CSparseFilter {
655 tuple_structs_pls: With<C>,
656 ugh: With<Sparse>,
657 }
658
659 let custom_param_entities = world
660 .query_filtered::<Entity, CSparseFilter>()
661 .iter(&world)
662 .collect::<Vec<_>>();
663 let normal_entities = world
664 .query_filtered::<Entity, (With<C>, With<Sparse>)>()
665 .iter(&world)
666 .collect::<Vec<_>>();
667 assert_eq!(custom_param_entities, normal_entities);
668 }
669
670 {
671 #[derive(QueryFilter)]
672 struct WithoutComps {
673 _1: Without<A>,
674 _2: Without<B>,
675 _3: Without<C>,
676 }
677
678 let custom_param_entities = world
679 .query_filtered::<Entity, WithoutComps>()
680 .iter(&world)
681 .collect::<Vec<_>>();
682 let normal_entities = world
683 .query_filtered::<Entity, (Without<A>, Without<B>, Without<C>)>()
684 .iter(&world)
685 .collect::<Vec<_>>();
686 assert_eq!(custom_param_entities, normal_entities);
687 }
688
689 {
690 #[derive(QueryData)]
691 struct IterCombAB {
692 a: &'static A,
693 b: &'static B,
694 }
695
696 let custom_param_data = world
697 .query::<IterCombAB>()
698 .iter_combinations::<2>(&world)
699 .map(|[item0, item1]| [(*item0.a, *item0.b), (*item1.a, *item1.b)])
700 .collect::<Vec<_>>();
701 let normal_data = world
702 .query::<(&A, &B)>()
703 .iter_combinations(&world)
704 .map(|[(a0, b0), (a1, b1)]| [(*a0, *b0), (*a1, *b1)])
705 .collect::<Vec<_>>();
706 assert_eq!(custom_param_data, normal_data);
707 }
708 }
709
710 #[test]
711 fn many_entities() {
712 let mut world = World::new();
713 world.spawn((A(0), B(0)));
714 world.spawn((A(0), B(0)));
715 world.spawn(A(0));
716 world.spawn(B(0));
717 {
718 fn system(has_a: Query<Entity, With<A>>, has_a_and_b: Query<(&A, &B)>) {
719 assert_eq!(has_a_and_b.iter_many(&has_a).count(), 2);
720 }
721 let mut system = IntoSystem::into_system(system);
722 system.initialize(&mut world);
723 system.run((), &mut world).unwrap();
724 }
725 {
726 fn system(has_a: Query<Entity, With<A>>, mut b_query: Query<&mut B>) {
727 let mut iter = b_query.iter_many_mut(&has_a);
728 while let Some(mut b) = iter.fetch_next() {
729 b.0 = 1;
730 }
731 }
732 let mut system = IntoSystem::into_system(system);
733 system.initialize(&mut world);
734 system.run((), &mut world).unwrap();
735 }
736 {
737 fn system(query: Query<(Option<&A>, &B)>) {
738 for (maybe_a, b) in &query {
739 match maybe_a {
740 Some(_) => assert_eq!(b.0, 1),
741 None => assert_eq!(b.0, 0),
742 }
743 }
744 }
745 let mut system = IntoSystem::into_system(system);
746 system.initialize(&mut world);
747 system.run((), &mut world).unwrap();
748 }
749 }
750
751 #[test]
752 fn mut_to_immut_query_methods_have_immut_item() {
753 #[derive(Component)]
754 struct Foo;
755
756 let mut world = World::new();
757 let e = world.spawn(Foo).id();
758
759 let mut q = world.query::<&mut Foo>();
761 let _: Option<&Foo> = q.iter(&world).next();
762 let _: Option<[&Foo; 2]> = q.iter_combinations::<2>(&world).next();
763 let _: Option<&Foo> = q.iter_manual(&world).next();
764 let _: Option<&Foo> = q.iter_many(&world, [e]).next();
765 q.iter(&world).for_each(|_: &Foo| ());
766
767 let _: Option<&Foo> = q.get(&world, e).ok();
768 let _: Option<&Foo> = q.get_manual(&world, e).ok();
769 let _: Option<[&Foo; 1]> = q.get_many(&world, [e]).ok();
770 let _: Option<&Foo> = q.single(&world).ok();
771 let _: &Foo = q.single(&world).unwrap();
772
773 let mut q = SystemState::<Query<&mut Foo>>::new(&mut world);
775 let q = q.get_mut(&mut world);
776 let _: Option<&Foo> = q.iter().next();
777 let _: Option<[&Foo; 2]> = q.iter_combinations::<2>().next();
778 let _: Option<&Foo> = q.iter_many([e]).next();
779 q.iter().for_each(|_: &Foo| ());
780
781 let _: Option<&Foo> = q.get(e).ok();
782 let _: Option<[&Foo; 1]> = q.get_many([e]).ok();
783 let _: Option<&Foo> = q.single().ok();
784 let _: &Foo = q.single().unwrap();
785 }
786
787 #[test]
789 fn par_iter_mut_change_detection() {
790 let mut world = World::new();
791 world.spawn((A(1), B(1)));
792
793 fn propagate_system(mut query: Query<(&A, &mut B), Changed<A>>) {
794 query.par_iter_mut().for_each(|(a, mut b)| {
795 b.0 = a.0;
796 });
797 }
798
799 fn modify_system(mut query: Query<&mut A>) {
800 for mut a in &mut query {
801 a.0 = 2;
802 }
803 }
804
805 let mut schedule = Schedule::default();
806 schedule.add_systems((propagate_system, modify_system).chain());
807 schedule.run(&mut world);
808 world.clear_trackers();
809 schedule.run(&mut world);
810 world.clear_trackers();
811
812 let values = world.query::<&B>().iter(&world).collect::<Vec<&B>>();
813 assert_eq!(values, vec![&B(2)]);
814 }
815
816 #[derive(Resource)]
817 struct R;
818
819 struct ReadsRData;
821
822 unsafe impl WorldQuery for ReadsRData {
825 type Fetch<'w> = ();
826 type State = ComponentId;
827
828 fn shrink_fetch<'wlong: 'wshort, 'wshort>(_: Self::Fetch<'wlong>) -> Self::Fetch<'wshort> {}
829
830 unsafe fn init_fetch<'w, 's>(
831 _world: UnsafeWorldCell<'w>,
832 _state: &'s Self::State,
833 _last_run: Tick,
834 _this_run: Tick,
835 ) -> Self::Fetch<'w> {
836 }
837
838 const IS_DENSE: bool = true;
839
840 #[inline]
841 unsafe fn set_archetype<'w, 's>(
842 _fetch: &mut Self::Fetch<'w>,
843 _state: &'s Self::State,
844 _archetype: &'w Archetype,
845 _table: &Table,
846 ) {
847 }
848
849 #[inline]
850 unsafe fn set_table<'w, 's>(
851 _fetch: &mut Self::Fetch<'w>,
852 _state: &'s Self::State,
853 _table: &'w Table,
854 ) {
855 }
856
857 fn update_component_access(&component_id: &Self::State, access: &mut FilteredAccess) {
858 assert!(
859 !access.access().has_resource_write(component_id),
860 "ReadsRData conflicts with a previous access in this query. Shared access cannot coincide with exclusive access."
861 );
862 access.add_resource_read(component_id);
863 }
864
865 fn init_state(world: &mut World) -> Self::State {
866 world.components_registrator().register_resource::<R>()
867 }
868
869 fn get_state(components: &Components) -> Option<Self::State> {
870 components.resource_id::<R>()
871 }
872
873 fn matches_component_set(
874 _state: &Self::State,
875 _set_contains_id: &impl Fn(ComponentId) -> bool,
876 ) -> bool {
877 true
878 }
879 }
880
881 unsafe impl QueryData for ReadsRData {
883 const IS_READ_ONLY: bool = true;
884 const IS_ARCHETYPAL: bool = true;
885 type ReadOnly = Self;
886 type Item<'w, 's> = ();
887
888 fn shrink<'wlong: 'wshort, 'wshort, 's>(
889 _item: Self::Item<'wlong, 's>,
890 ) -> Self::Item<'wshort, 's> {
891 }
892
893 #[inline(always)]
894 unsafe fn fetch<'w, 's>(
895 _state: &'s Self::State,
896 _fetch: &mut Self::Fetch<'w>,
897 _entity: Entity,
898 _table_row: TableRow,
899 ) -> Option<Self::Item<'w, 's>> {
900 Some(())
901 }
902
903 fn iter_access(
904 state: &Self::State,
905 ) -> impl Iterator<Item = super::access_iter::EcsAccessType<'_>> {
906 core::iter::once(super::access_iter::EcsAccessType::Resource(
907 super::access_iter::ResourceAccessLevel::Read(*state),
908 ))
909 }
910 }
911
912 unsafe impl ReadOnlyQueryData for ReadsRData {}
914
915 impl ArchetypeQueryData for ReadsRData {}
916
917 #[test]
918 fn read_res_read_res_no_conflict() {
919 fn system(_q1: Query<ReadsRData, With<A>>, _q2: Query<ReadsRData, Without<A>>) {}
920 assert_is_system(system);
921 }
922}