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