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