Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_ecs/src/query/mod.rs
9367 views
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
8
mod access;
9
mod access_iter;
10
mod builder;
11
mod error;
12
mod fetch;
13
mod filter;
14
mod iter;
15
mod par_iter;
16
mod state;
17
mod world_query;
18
19
pub use access::*;
20
pub use access_iter::*;
21
pub use bevy_ecs_macros::{QueryData, QueryFilter};
22
pub use builder::*;
23
pub use error::*;
24
pub use fetch::*;
25
pub use filter::*;
26
pub use iter::*;
27
pub use par_iter::*;
28
pub use state::*;
29
pub 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)]
36
pub 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)]
50
impl<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)]
67
impl<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))]
84
impl<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))]
99
impl<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.")]
114
mod tests {
115
use crate::{
116
archetype::Archetype,
117
change_detection::Tick,
118
component::{Component, ComponentId, Components},
119
prelude::{AnyOf, Changed, Entity, Or, QueryState, Resource, With, Without},
120
query::{
121
ArchetypeFilter, ArchetypeQueryData, FilteredAccess, Has, QueryCombinationIter,
122
QueryData, QueryFilter, ReadOnlyQueryData, WorldQuery,
123
},
124
schedule::{IntoScheduleConfigs, Schedule},
125
storage::{Table, TableRow},
126
system::{assert_is_system, IntoSystem, Query, System, SystemState},
127
world::{unsafe_world_cell::UnsafeWorldCell, World},
128
};
129
use alloc::{vec, vec::Vec};
130
use core::{any::type_name, fmt::Debug, hash::Hash};
131
use std::{collections::HashSet, println};
132
133
#[derive(Component, Debug, Hash, Eq, PartialEq, Clone, Copy, PartialOrd, Ord)]
134
struct A(usize);
135
#[derive(Component, Debug, Hash, Eq, PartialEq, Clone, Copy)]
136
struct B(usize);
137
#[derive(Component, Debug, Eq, PartialEq, Clone, Copy)]
138
struct C(usize);
139
#[derive(Component, Debug, Eq, PartialEq, Clone, Copy)]
140
struct D(usize);
141
142
#[derive(Component, Debug, Hash, Eq, PartialEq, Clone, Copy, PartialOrd, Ord)]
143
#[component(storage = "SparseSet")]
144
struct Sparse(usize);
145
146
#[test]
147
fn query() {
148
let mut world = World::new();
149
world.spawn((A(1), B(1)));
150
world.spawn(A(2));
151
let values = world.query::<&A>().iter(&world).collect::<HashSet<&A>>();
152
assert!(values.contains(&A(1)));
153
assert!(values.contains(&A(2)));
154
155
for (_a, mut b) in world.query::<(&A, &mut B)>().iter_mut(&mut world) {
156
b.0 = 3;
157
}
158
let values = world.query::<&B>().iter(&world).collect::<Vec<&B>>();
159
assert_eq!(values, vec![&B(3)]);
160
}
161
162
#[test]
163
fn query_filtered_exactsizeiterator_len() {
164
fn choose(n: usize, k: usize) -> usize {
165
if n == 0 || k == 0 || n < k {
166
return 0;
167
}
168
let ks = 1..=k;
169
let ns = (n - k + 1..=n).rev();
170
ks.zip(ns).fold(1, |acc, (k, n)| acc * n / k)
171
}
172
fn assert_combination<D, F, const K: usize>(world: &mut World, expected_size: usize)
173
where
174
D: ReadOnlyQueryData + ArchetypeQueryData,
175
F: ArchetypeFilter,
176
{
177
let mut query = world.query_filtered::<D, F>();
178
let query_type = type_name::<QueryCombinationIter<D, F, K>>();
179
let iter = query.iter_combinations::<K>(world);
180
assert_all_sizes_iterator_equal(iter, expected_size, 0, query_type);
181
let iter = query.iter_combinations::<K>(world);
182
assert_all_sizes_iterator_equal(iter, expected_size, 1, query_type);
183
let iter = query.iter_combinations::<K>(world);
184
assert_all_sizes_iterator_equal(iter, expected_size, 5, query_type);
185
}
186
fn assert_all_sizes_equal<D, F>(world: &mut World, expected_size: usize)
187
where
188
D: ReadOnlyQueryData + ArchetypeQueryData,
189
F: ArchetypeFilter,
190
{
191
let mut query = world.query_filtered::<D, F>();
192
let query_type = type_name::<QueryState<D, F>>();
193
assert_all_exact_sizes_iterator_equal(query.iter(world), expected_size, 0, query_type);
194
assert_all_exact_sizes_iterator_equal(query.iter(world), expected_size, 1, query_type);
195
assert_all_exact_sizes_iterator_equal(query.iter(world), expected_size, 5, query_type);
196
197
let expected = expected_size;
198
assert_combination::<D, F, 1>(world, choose(expected, 1));
199
assert_combination::<D, F, 2>(world, choose(expected, 2));
200
assert_combination::<D, F, 5>(world, choose(expected, 5));
201
assert_combination::<D, F, 43>(world, choose(expected, 43));
202
assert_combination::<D, F, 64>(world, choose(expected, 64));
203
}
204
fn assert_all_exact_sizes_iterator_equal(
205
iterator: impl ExactSizeIterator,
206
expected_size: usize,
207
skip: usize,
208
query_type: &'static str,
209
) {
210
let len = iterator.len();
211
println!("len: {len}");
212
assert_all_sizes_iterator_equal(iterator, expected_size, skip, query_type);
213
assert_eq!(len, expected_size);
214
}
215
fn assert_all_sizes_iterator_equal(
216
mut iterator: impl Iterator,
217
expected_size: usize,
218
skip: usize,
219
query_type: &'static str,
220
) {
221
let expected_size = expected_size.saturating_sub(skip);
222
for _ in 0..skip {
223
iterator.next();
224
}
225
let size_hint_0 = iterator.size_hint().0;
226
let size_hint_1 = iterator.size_hint().1;
227
// `count` tests that not only it is the expected value, but also
228
// the value is accurate to what the query returns.
229
let count = iterator.count();
230
// This will show up when one of the asserts in this function fails
231
println!(
232
"query declared sizes: \n\
233
for query: {query_type} \n\
234
expected: {expected_size} \n\
235
size_hint().0: {size_hint_0} \n\
236
size_hint().1: {size_hint_1:?} \n\
237
count(): {count}"
238
);
239
assert_eq!(size_hint_0, expected_size);
240
assert_eq!(size_hint_1, Some(expected_size));
241
assert_eq!(count, expected_size);
242
}
243
244
let mut world = World::new();
245
world.spawn((A(1), B(1)));
246
world.spawn(A(2));
247
world.spawn(A(3));
248
249
assert_all_sizes_equal::<&A, With<B>>(&mut world, 1);
250
assert_all_sizes_equal::<&A, Without<B>>(&mut world, 2);
251
252
let mut world = World::new();
253
world.spawn((A(1), B(1), C(1)));
254
world.spawn((A(2), B(2)));
255
world.spawn((A(3), B(3)));
256
world.spawn((A(4), C(4)));
257
world.spawn((A(5), C(5)));
258
world.spawn((A(6), C(6)));
259
world.spawn(A(7));
260
world.spawn(A(8));
261
world.spawn(A(9));
262
world.spawn(A(10));
263
264
// With/Without for B and C
265
assert_all_sizes_equal::<&A, With<B>>(&mut world, 3);
266
assert_all_sizes_equal::<&A, With<C>>(&mut world, 4);
267
assert_all_sizes_equal::<&A, Without<B>>(&mut world, 7);
268
assert_all_sizes_equal::<&A, Without<C>>(&mut world, 6);
269
270
// With/Without (And) combinations
271
assert_all_sizes_equal::<&A, (With<B>, With<C>)>(&mut world, 1);
272
assert_all_sizes_equal::<&A, (With<B>, Without<C>)>(&mut world, 2);
273
assert_all_sizes_equal::<&A, (Without<B>, With<C>)>(&mut world, 3);
274
assert_all_sizes_equal::<&A, (Without<B>, Without<C>)>(&mut world, 4);
275
276
// With/Without Or<()> combinations
277
assert_all_sizes_equal::<&A, Or<(With<B>, With<C>)>>(&mut world, 6);
278
assert_all_sizes_equal::<&A, Or<(With<B>, Without<C>)>>(&mut world, 7);
279
assert_all_sizes_equal::<&A, Or<(Without<B>, With<C>)>>(&mut world, 8);
280
assert_all_sizes_equal::<&A, Or<(Without<B>, Without<C>)>>(&mut world, 9);
281
assert_all_sizes_equal::<&A, (Or<(With<B>,)>, Or<(With<C>,)>)>(&mut world, 1);
282
assert_all_sizes_equal::<&A, Or<(Or<(With<B>, With<C>)>, With<D>)>>(&mut world, 6);
283
284
for i in 11..14 {
285
world.spawn((A(i), D(i)));
286
}
287
288
assert_all_sizes_equal::<&A, Or<(Or<(With<B>, With<C>)>, With<D>)>>(&mut world, 9);
289
assert_all_sizes_equal::<&A, Or<(Or<(With<B>, With<C>)>, Without<D>)>>(&mut world, 10);
290
291
// a fair amount of entities
292
for i in 14..20 {
293
world.spawn((C(i), D(i)));
294
}
295
assert_all_sizes_equal::<Entity, (With<C>, With<D>)>(&mut world, 6);
296
}
297
298
// the order of the combinations is not guaranteed, but each unique combination is present
299
fn check_combinations<T: Ord + Hash + Debug, const K: usize>(
300
values: HashSet<[&T; K]>,
301
expected: HashSet<[&T; K]>,
302
) {
303
values.iter().for_each(|pair| {
304
let mut sorted = *pair;
305
sorted.sort();
306
assert!(expected.contains(&sorted),
307
"the results of iter_combinations should contain this combination {:?}. Expected: {:?}, got: {:?}",
308
&sorted, &expected, &values);
309
});
310
}
311
312
#[test]
313
fn query_iter_combinations() {
314
let mut world = World::new();
315
316
world.spawn((A(1), B(1)));
317
world.spawn(A(2));
318
world.spawn(A(3));
319
world.spawn(A(4));
320
321
let values: HashSet<[&A; 2]> = world.query::<&A>().iter_combinations(&world).collect();
322
check_combinations(
323
values,
324
HashSet::from([
325
[&A(1), &A(2)],
326
[&A(1), &A(3)],
327
[&A(1), &A(4)],
328
[&A(2), &A(3)],
329
[&A(2), &A(4)],
330
[&A(3), &A(4)],
331
]),
332
);
333
let mut a_query = world.query::<&A>();
334
335
let values: HashSet<[&A; 3]> = a_query.iter_combinations(&world).collect();
336
check_combinations(
337
values,
338
HashSet::from([
339
[&A(1), &A(2), &A(3)],
340
[&A(1), &A(2), &A(4)],
341
[&A(1), &A(3), &A(4)],
342
[&A(2), &A(3), &A(4)],
343
]),
344
);
345
346
let mut b_query = world.query::<&B>();
347
assert_eq!(
348
b_query.iter_combinations::<2>(&world).size_hint(),
349
(0, Some(0))
350
);
351
let values: Vec<[&B; 2]> = b_query.iter_combinations(&world).collect();
352
assert_eq!(values, Vec::<[&B; 2]>::new());
353
}
354
355
#[test]
356
fn query_filtered_iter_combinations() {
357
use bevy_ecs::query::{Added, Or, With, Without};
358
359
let mut world = World::new();
360
361
world.spawn((A(1), B(1)));
362
world.spawn(A(2));
363
world.spawn(A(3));
364
world.spawn(A(4));
365
366
let mut a_wout_b = world.query_filtered::<&A, Without<B>>();
367
let values: HashSet<[&A; 2]> = a_wout_b.iter_combinations(&world).collect();
368
check_combinations(
369
values,
370
HashSet::from([[&A(2), &A(3)], [&A(2), &A(4)], [&A(3), &A(4)]]),
371
);
372
373
let values: HashSet<[&A; 3]> = a_wout_b.iter_combinations(&world).collect();
374
check_combinations(values, HashSet::from([[&A(2), &A(3), &A(4)]]));
375
376
let mut query = world.query_filtered::<&A, Or<(With<A>, With<B>)>>();
377
let values: HashSet<[&A; 2]> = query.iter_combinations(&world).collect();
378
check_combinations(
379
values,
380
HashSet::from([
381
[&A(1), &A(2)],
382
[&A(1), &A(3)],
383
[&A(1), &A(4)],
384
[&A(2), &A(3)],
385
[&A(2), &A(4)],
386
[&A(3), &A(4)],
387
]),
388
);
389
390
let mut query = world.query_filtered::<&mut A, Without<B>>();
391
let mut combinations = query.iter_combinations_mut(&mut world);
392
while let Some([mut a, mut b, mut c]) = combinations.fetch_next() {
393
a.0 += 10;
394
b.0 += 100;
395
c.0 += 1000;
396
}
397
398
let values: HashSet<[&A; 3]> = a_wout_b.iter_combinations(&world).collect();
399
check_combinations(values, HashSet::from([[&A(12), &A(103), &A(1004)]]));
400
401
// Check if Added<T>, Changed<T> works
402
let mut world = World::new();
403
404
world.spawn((A(1), B(1)));
405
world.spawn((A(2), B(2)));
406
world.spawn((A(3), B(3)));
407
world.spawn((A(4), B(4)));
408
409
let mut query_added = world.query_filtered::<&A, Added<A>>();
410
411
world.clear_trackers();
412
world.spawn(A(5));
413
414
assert_eq!(query_added.iter_combinations::<2>(&world).count(), 0);
415
416
world.clear_trackers();
417
world.spawn(A(6));
418
world.spawn(A(7));
419
420
assert_eq!(query_added.iter_combinations::<2>(&world).count(), 1);
421
422
world.clear_trackers();
423
world.spawn(A(8));
424
world.spawn(A(9));
425
world.spawn(A(10));
426
427
assert_eq!(query_added.iter_combinations::<2>(&world).count(), 3);
428
}
429
430
#[test]
431
fn query_iter_combinations_sparse() {
432
let mut world = World::new();
433
434
world.spawn_batch((1..=4).map(Sparse));
435
436
let values: HashSet<[&Sparse; 3]> =
437
world.query::<&Sparse>().iter_combinations(&world).collect();
438
check_combinations(
439
values,
440
HashSet::from([
441
[&Sparse(1), &Sparse(2), &Sparse(3)],
442
[&Sparse(1), &Sparse(2), &Sparse(4)],
443
[&Sparse(1), &Sparse(3), &Sparse(4)],
444
[&Sparse(2), &Sparse(3), &Sparse(4)],
445
]),
446
);
447
}
448
449
#[test]
450
fn get_many_only_mut_checks_duplicates() {
451
let mut world = World::new();
452
let id = world.spawn(A(10)).id();
453
let mut query_state = world.query::<&mut A>();
454
let mut query = query_state.query_mut(&mut world);
455
let result = query.get_many([id, id]);
456
assert_eq!(result, Ok([&A(10), &A(10)]));
457
let mut_result = query.get_many_mut([id, id]);
458
assert!(mut_result.is_err());
459
}
460
461
#[test]
462
fn multi_storage_query() {
463
let mut world = World::new();
464
465
world.spawn((Sparse(1), B(2)));
466
world.spawn(Sparse(2));
467
468
let values = world
469
.query::<&Sparse>()
470
.iter(&world)
471
.collect::<HashSet<&Sparse>>();
472
assert!(values.contains(&Sparse(1)));
473
assert!(values.contains(&Sparse(2)));
474
475
for (_a, mut b) in world.query::<(&Sparse, &mut B)>().iter_mut(&mut world) {
476
b.0 = 3;
477
}
478
479
let values = world.query::<&B>().iter(&world).collect::<Vec<&B>>();
480
assert_eq!(values, vec![&B(3)]);
481
}
482
483
#[test]
484
fn any_query() {
485
let mut world = World::new();
486
487
world.spawn((A(1), B(2)));
488
world.spawn(A(2));
489
world.spawn(C(3));
490
491
let values: Vec<(Option<&A>, Option<&B>)> =
492
world.query::<AnyOf<(&A, &B)>>().iter(&world).collect();
493
494
assert_eq!(
495
values,
496
vec![(Some(&A(1)), Some(&B(2))), (Some(&A(2)), None),]
497
);
498
}
499
500
#[test]
501
fn has_query() {
502
let mut world = World::new();
503
504
world.spawn((A(1), B(1)));
505
world.spawn(A(2));
506
world.spawn((A(3), B(1)));
507
world.spawn(A(4));
508
509
let values: HashSet<(&A, bool)> = world.query::<(&A, Has<B>)>().iter(&world).collect();
510
511
assert!(values.contains(&(&A(1), true)));
512
assert!(values.contains(&(&A(2), false)));
513
assert!(values.contains(&(&A(3), true)));
514
assert!(values.contains(&(&A(4), false)));
515
}
516
517
#[test]
518
#[should_panic]
519
fn self_conflicting_worldquery() {
520
#[derive(QueryData)]
521
#[query_data(mutable)]
522
struct SelfConflicting {
523
a: &'static mut A,
524
b: &'static mut A,
525
}
526
527
let mut world = World::new();
528
world.query::<SelfConflicting>();
529
}
530
531
#[test]
532
fn derived_worldqueries() {
533
let mut world = World::new();
534
535
world.spawn((A(10), B(18), C(3), Sparse(4)));
536
537
world.spawn((A(101), B(148), C(13)));
538
world.spawn((A(51), B(46), Sparse(72)));
539
world.spawn((A(398), C(6), Sparse(9)));
540
world.spawn((B(11), C(28), Sparse(92)));
541
542
world.spawn((C(18348), Sparse(101)));
543
world.spawn((B(839), Sparse(5)));
544
world.spawn((B(6721), C(122)));
545
world.spawn((A(220), Sparse(63)));
546
world.spawn((A(1092), C(382)));
547
world.spawn((A(2058), B(3019)));
548
549
world.spawn((B(38), C(8), Sparse(100)));
550
world.spawn((A(111), C(52), Sparse(1)));
551
world.spawn((A(599), B(39), Sparse(13)));
552
world.spawn((A(55), B(66), C(77)));
553
554
world.spawn_empty();
555
556
{
557
#[derive(QueryData)]
558
struct CustomAB {
559
a: &'static A,
560
b: &'static B,
561
}
562
563
let custom_param_data = world
564
.query::<CustomAB>()
565
.iter(&world)
566
.map(|item| (*item.a, *item.b))
567
.collect::<Vec<_>>();
568
let normal_data = world
569
.query::<(&A, &B)>()
570
.iter(&world)
571
.map(|(a, b)| (*a, *b))
572
.collect::<Vec<_>>();
573
assert_eq!(custom_param_data, normal_data);
574
}
575
576
{
577
#[derive(QueryData)]
578
struct FancyParam {
579
e: Entity,
580
b: &'static B,
581
opt: Option<&'static Sparse>,
582
}
583
584
let custom_param_data = world
585
.query::<FancyParam>()
586
.iter(&world)
587
.map(|fancy| (fancy.e, *fancy.b, fancy.opt.copied()))
588
.collect::<Vec<_>>();
589
let normal_data = world
590
.query::<(Entity, &B, Option<&Sparse>)>()
591
.iter(&world)
592
.map(|(e, b, opt)| (e, *b, opt.copied()))
593
.collect::<Vec<_>>();
594
assert_eq!(custom_param_data, normal_data);
595
}
596
597
{
598
#[derive(QueryData)]
599
struct MaybeBSparse {
600
blah: Option<(&'static B, &'static Sparse)>,
601
}
602
#[derive(QueryData)]
603
struct MatchEverything {
604
abcs: AnyOf<(&'static A, &'static B, &'static C)>,
605
opt_bsparse: MaybeBSparse,
606
}
607
608
let custom_param_data = world
609
.query::<MatchEverything>()
610
.iter(&world)
611
.map(
612
|MatchEverythingItem {
613
abcs: (a, b, c),
614
opt_bsparse: MaybeBSparseItem { blah: bsparse },
615
}| {
616
(
617
(a.copied(), b.copied(), c.copied()),
618
bsparse.map(|(b, sparse)| (*b, *sparse)),
619
)
620
},
621
)
622
.collect::<Vec<_>>();
623
let normal_data = world
624
.query::<(AnyOf<(&A, &B, &C)>, Option<(&B, &Sparse)>)>()
625
.iter(&world)
626
.map(|((a, b, c), bsparse)| {
627
(
628
(a.copied(), b.copied(), c.copied()),
629
bsparse.map(|(b, sparse)| (*b, *sparse)),
630
)
631
})
632
.collect::<Vec<_>>();
633
assert_eq!(custom_param_data, normal_data);
634
}
635
636
{
637
#[derive(QueryFilter)]
638
struct AOrBFilter {
639
a: Or<(With<A>, With<B>)>,
640
}
641
#[derive(QueryFilter)]
642
struct NoSparseThatsSlow {
643
no: Without<Sparse>,
644
}
645
646
let custom_param_entities = world
647
.query_filtered::<Entity, (AOrBFilter, NoSparseThatsSlow)>()
648
.iter(&world)
649
.collect::<Vec<_>>();
650
let normal_entities = world
651
.query_filtered::<Entity, (Or<(With<A>, With<B>)>, Without<Sparse>)>()
652
.iter(&world)
653
.collect::<Vec<_>>();
654
assert_eq!(custom_param_entities, normal_entities);
655
}
656
657
{
658
#[derive(QueryFilter)]
659
struct CSparseFilter {
660
tuple_structs_pls: With<C>,
661
ugh: With<Sparse>,
662
}
663
664
let custom_param_entities = world
665
.query_filtered::<Entity, CSparseFilter>()
666
.iter(&world)
667
.collect::<Vec<_>>();
668
let normal_entities = world
669
.query_filtered::<Entity, (With<C>, With<Sparse>)>()
670
.iter(&world)
671
.collect::<Vec<_>>();
672
assert_eq!(custom_param_entities, normal_entities);
673
}
674
675
{
676
#[derive(QueryFilter)]
677
struct WithoutComps {
678
_1: Without<A>,
679
_2: Without<B>,
680
_3: Without<C>,
681
}
682
683
let custom_param_entities = world
684
.query_filtered::<Entity, WithoutComps>()
685
.iter(&world)
686
.collect::<Vec<_>>();
687
let normal_entities = world
688
.query_filtered::<Entity, (Without<A>, Without<B>, Without<C>)>()
689
.iter(&world)
690
.collect::<Vec<_>>();
691
assert_eq!(custom_param_entities, normal_entities);
692
}
693
694
{
695
#[derive(QueryData)]
696
struct IterCombAB {
697
a: &'static A,
698
b: &'static B,
699
}
700
701
let custom_param_data = world
702
.query::<IterCombAB>()
703
.iter_combinations::<2>(&world)
704
.map(|[item0, item1]| [(*item0.a, *item0.b), (*item1.a, *item1.b)])
705
.collect::<Vec<_>>();
706
let normal_data = world
707
.query::<(&A, &B)>()
708
.iter_combinations(&world)
709
.map(|[(a0, b0), (a1, b1)]| [(*a0, *b0), (*a1, *b1)])
710
.collect::<Vec<_>>();
711
assert_eq!(custom_param_data, normal_data);
712
}
713
}
714
715
#[test]
716
fn many_entities() {
717
let mut world = World::new();
718
world.spawn((A(0), B(0)));
719
world.spawn((A(0), B(0)));
720
world.spawn(A(0));
721
world.spawn(B(0));
722
{
723
fn system(has_a: Query<Entity, With<A>>, has_a_and_b: Query<(&A, &B)>) {
724
assert_eq!(has_a_and_b.iter_many(&has_a).count(), 2);
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);
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();
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);
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();
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
#[derive(Resource)]
822
struct R;
823
824
/// `QueryData` that performs read access on R to test that resource access is tracked
825
struct ReadsRData;
826
827
// SAFETY:
828
// `update_component_access` adds resource read access for `R`.
829
unsafe impl WorldQuery for ReadsRData {
830
type Fetch<'w> = ();
831
type State = ComponentId;
832
833
fn shrink_fetch<'wlong: 'wshort, 'wshort>(_: Self::Fetch<'wlong>) -> Self::Fetch<'wshort> {}
834
835
unsafe fn init_fetch<'w, 's>(
836
_world: UnsafeWorldCell<'w>,
837
_state: &'s Self::State,
838
_last_run: Tick,
839
_this_run: Tick,
840
) -> Self::Fetch<'w> {
841
}
842
843
const IS_DENSE: bool = true;
844
845
#[inline]
846
unsafe fn set_archetype<'w, 's>(
847
_fetch: &mut Self::Fetch<'w>,
848
_state: &'s Self::State,
849
_archetype: &'w Archetype,
850
_table: &Table,
851
) {
852
}
853
854
#[inline]
855
unsafe fn set_table<'w, 's>(
856
_fetch: &mut Self::Fetch<'w>,
857
_state: &'s Self::State,
858
_table: &'w Table,
859
) {
860
}
861
862
fn update_component_access(&component_id: &Self::State, access: &mut FilteredAccess) {
863
assert!(
864
!access.access().has_resource_write(component_id),
865
"ReadsRData conflicts with a previous access in this query. Shared access cannot coincide with exclusive access."
866
);
867
access.add_resource_read(component_id);
868
}
869
870
fn init_state(world: &mut World) -> Self::State {
871
world.components_registrator().register_component::<R>()
872
}
873
874
fn get_state(components: &Components) -> Option<Self::State> {
875
components.resource_id::<R>()
876
}
877
878
fn matches_component_set(
879
_state: &Self::State,
880
_set_contains_id: &impl Fn(ComponentId) -> bool,
881
) -> bool {
882
true
883
}
884
}
885
886
// SAFETY: `Self` is the same as `Self::ReadOnly`
887
unsafe impl QueryData for ReadsRData {
888
const IS_READ_ONLY: bool = true;
889
const IS_ARCHETYPAL: bool = true;
890
type ReadOnly = Self;
891
type Item<'w, 's> = ();
892
893
fn shrink<'wlong: 'wshort, 'wshort, 's>(
894
_item: Self::Item<'wlong, 's>,
895
) -> Self::Item<'wshort, 's> {
896
}
897
898
#[inline(always)]
899
unsafe fn fetch<'w, 's>(
900
_state: &'s Self::State,
901
_fetch: &mut Self::Fetch<'w>,
902
_entity: Entity,
903
_table_row: TableRow,
904
) -> Option<Self::Item<'w, 's>> {
905
Some(())
906
}
907
908
fn iter_access(
909
state: &Self::State,
910
) -> impl Iterator<Item = super::access_iter::EcsAccessType<'_>> {
911
core::iter::once(super::access_iter::EcsAccessType::Resource(
912
super::access_iter::ResourceAccessLevel::Read(*state),
913
))
914
}
915
}
916
917
// SAFETY: access is read only
918
unsafe impl ReadOnlyQueryData for ReadsRData {}
919
920
impl ArchetypeQueryData for ReadsRData {}
921
922
#[test]
923
fn read_res_read_res_no_conflict() {
924
fn system(_q1: Query<ReadsRData, With<A>>, _q2: Query<ReadsRData, Without<A>>) {}
925
assert_is_system(system);
926
}
927
}
928
929