Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_ecs/src/query/builder.rs
6600 views
1
use core::marker::PhantomData;
2
3
use crate::{
4
component::{ComponentId, StorageType},
5
prelude::*,
6
};
7
8
use super::{FilteredAccess, QueryData, QueryFilter};
9
10
/// Builder struct to create [`QueryState`] instances at runtime.
11
///
12
/// ```
13
/// # use bevy_ecs::prelude::*;
14
/// #
15
/// # #[derive(Component)]
16
/// # struct A;
17
/// #
18
/// # #[derive(Component)]
19
/// # struct B;
20
/// #
21
/// # #[derive(Component)]
22
/// # struct C;
23
/// #
24
/// let mut world = World::new();
25
/// let entity_a = world.spawn((A, B)).id();
26
/// let entity_b = world.spawn((A, C)).id();
27
///
28
/// // Instantiate the builder using the type signature of the iterator you will consume
29
/// let mut query = QueryBuilder::<(Entity, &B)>::new(&mut world)
30
/// // Add additional terms through builder methods
31
/// .with::<A>()
32
/// .without::<C>()
33
/// .build();
34
///
35
/// // Consume the QueryState
36
/// let (entity, b) = query.single(&world).unwrap();
37
/// ```
38
pub struct QueryBuilder<'w, D: QueryData = (), F: QueryFilter = ()> {
39
access: FilteredAccess,
40
world: &'w mut World,
41
or: bool,
42
first: bool,
43
_marker: PhantomData<(D, F)>,
44
}
45
46
impl<'w, D: QueryData, F: QueryFilter> QueryBuilder<'w, D, F> {
47
/// Creates a new builder with the accesses required for `Q` and `F`
48
pub fn new(world: &'w mut World) -> Self {
49
let fetch_state = D::init_state(world);
50
let filter_state = F::init_state(world);
51
52
let mut access = FilteredAccess::default();
53
D::update_component_access(&fetch_state, &mut access);
54
55
// Use a temporary empty FilteredAccess for filters. This prevents them from conflicting with the
56
// main Query's `fetch_state` access. Filters are allowed to conflict with the main query fetch
57
// because they are evaluated *before* a specific reference is constructed.
58
let mut filter_access = FilteredAccess::default();
59
F::update_component_access(&filter_state, &mut filter_access);
60
61
// Merge the temporary filter access with the main access. This ensures that filter access is
62
// properly considered in a global "cross-query" context (both within systems and across systems).
63
access.extend(&filter_access);
64
65
Self {
66
access,
67
world,
68
or: false,
69
first: false,
70
_marker: PhantomData,
71
}
72
}
73
74
pub(super) fn is_dense(&self) -> bool {
75
// Note: `component_id` comes from the user in safe code, so we cannot trust it to
76
// exist. If it doesn't exist we pessimistically assume it's sparse.
77
let is_dense = |component_id| {
78
self.world()
79
.components()
80
.get_info(component_id)
81
.is_some_and(|info| info.storage_type() == StorageType::Table)
82
};
83
84
let Ok(component_accesses) = self.access.access().try_iter_component_access() else {
85
// Access is unbounded, pessimistically assume it's sparse.
86
return false;
87
};
88
89
component_accesses
90
.map(|access| *access.index())
91
.all(is_dense)
92
&& !self.access.access().has_read_all_components()
93
&& self.access.with_filters().all(is_dense)
94
&& self.access.without_filters().all(is_dense)
95
}
96
97
/// Returns a reference to the world passed to [`Self::new`].
98
pub fn world(&self) -> &World {
99
self.world
100
}
101
102
/// Returns a mutable reference to the world passed to [`Self::new`].
103
pub fn world_mut(&mut self) -> &mut World {
104
self.world
105
}
106
107
/// Adds access to self's underlying [`FilteredAccess`] respecting [`Self::or`] and [`Self::and`]
108
pub fn extend_access(&mut self, mut access: FilteredAccess) {
109
if self.or {
110
if self.first {
111
access.required.clear();
112
self.access.extend(&access);
113
self.first = false;
114
} else {
115
self.access.append_or(&access);
116
}
117
} else {
118
self.access.extend(&access);
119
}
120
}
121
122
/// Adds accesses required for `T` to self.
123
pub fn data<T: QueryData>(&mut self) -> &mut Self {
124
let state = T::init_state(self.world);
125
let mut access = FilteredAccess::default();
126
T::update_component_access(&state, &mut access);
127
self.extend_access(access);
128
self
129
}
130
131
/// Adds filter from `T` to self.
132
pub fn filter<T: QueryFilter>(&mut self) -> &mut Self {
133
let state = T::init_state(self.world);
134
let mut access = FilteredAccess::default();
135
T::update_component_access(&state, &mut access);
136
self.extend_access(access);
137
self
138
}
139
140
/// Adds [`With<T>`] to the [`FilteredAccess`] of self.
141
pub fn with<T: Component>(&mut self) -> &mut Self {
142
self.filter::<With<T>>();
143
self
144
}
145
146
/// Adds [`With<T>`] to the [`FilteredAccess`] of self from a runtime [`ComponentId`].
147
pub fn with_id(&mut self, id: ComponentId) -> &mut Self {
148
let mut access = FilteredAccess::default();
149
access.and_with(id);
150
self.extend_access(access);
151
self
152
}
153
154
/// Adds [`Without<T>`] to the [`FilteredAccess`] of self.
155
pub fn without<T: Component>(&mut self) -> &mut Self {
156
self.filter::<Without<T>>();
157
self
158
}
159
160
/// Adds [`Without<T>`] to the [`FilteredAccess`] of self from a runtime [`ComponentId`].
161
pub fn without_id(&mut self, id: ComponentId) -> &mut Self {
162
let mut access = FilteredAccess::default();
163
access.and_without(id);
164
self.extend_access(access);
165
self
166
}
167
168
/// Adds `&T` to the [`FilteredAccess`] of self.
169
pub fn ref_id(&mut self, id: ComponentId) -> &mut Self {
170
self.with_id(id);
171
self.access.add_component_read(id);
172
self
173
}
174
175
/// Adds `&mut T` to the [`FilteredAccess`] of self.
176
pub fn mut_id(&mut self, id: ComponentId) -> &mut Self {
177
self.with_id(id);
178
self.access.add_component_write(id);
179
self
180
}
181
182
/// Takes a function over mutable access to a [`QueryBuilder`], calls that function
183
/// on an empty builder and then adds all accesses from that builder to self as optional.
184
pub fn optional(&mut self, f: impl Fn(&mut QueryBuilder)) -> &mut Self {
185
let mut builder = QueryBuilder::new(self.world);
186
f(&mut builder);
187
self.access.extend_access(builder.access());
188
self
189
}
190
191
/// Takes a function over mutable access to a [`QueryBuilder`], calls that function
192
/// on an empty builder and then adds all accesses from that builder to self.
193
///
194
/// Primarily used when inside a [`Self::or`] closure to group several terms.
195
pub fn and(&mut self, f: impl Fn(&mut QueryBuilder)) -> &mut Self {
196
let mut builder = QueryBuilder::new(self.world);
197
f(&mut builder);
198
let access = builder.access().clone();
199
self.extend_access(access);
200
self
201
}
202
203
/// Takes a function over mutable access to a [`QueryBuilder`], calls that function
204
/// on an empty builder, all accesses added to that builder will become terms in an or expression.
205
///
206
/// ```
207
/// # use bevy_ecs::prelude::*;
208
/// #
209
/// # #[derive(Component)]
210
/// # struct A;
211
/// #
212
/// # #[derive(Component)]
213
/// # struct B;
214
/// #
215
/// # let mut world = World::new();
216
/// #
217
/// QueryBuilder::<Entity>::new(&mut world).or(|builder| {
218
/// builder.with::<A>();
219
/// builder.with::<B>();
220
/// });
221
/// // is equivalent to
222
/// QueryBuilder::<Entity>::new(&mut world).filter::<Or<(With<A>, With<B>)>>();
223
/// ```
224
pub fn or(&mut self, f: impl Fn(&mut QueryBuilder)) -> &mut Self {
225
let mut builder = QueryBuilder::new(self.world);
226
builder.or = true;
227
builder.first = true;
228
f(&mut builder);
229
self.access.extend(builder.access());
230
self
231
}
232
233
/// Returns a reference to the [`FilteredAccess`] that will be provided to the built [`Query`].
234
pub fn access(&self) -> &FilteredAccess {
235
&self.access
236
}
237
238
/// Transmute the existing builder adding required accesses.
239
/// This will maintain all existing accesses.
240
///
241
/// If including a filter type see [`Self::transmute_filtered`]
242
pub fn transmute<NewD: QueryData>(&mut self) -> &mut QueryBuilder<'w, NewD> {
243
self.transmute_filtered::<NewD, ()>()
244
}
245
246
/// Transmute the existing builder adding required accesses.
247
/// This will maintain all existing accesses.
248
pub fn transmute_filtered<NewD: QueryData, NewF: QueryFilter>(
249
&mut self,
250
) -> &mut QueryBuilder<'w, NewD, NewF> {
251
let fetch_state = NewD::init_state(self.world);
252
let filter_state = NewF::init_state(self.world);
253
254
let mut access = FilteredAccess::default();
255
NewD::update_component_access(&fetch_state, &mut access);
256
NewF::update_component_access(&filter_state, &mut access);
257
258
self.extend_access(access);
259
// SAFETY:
260
// - We have included all required accesses for NewQ and NewF
261
// - The layout of all QueryBuilder instances is the same
262
unsafe { core::mem::transmute(self) }
263
}
264
265
/// Create a [`QueryState`] with the accesses of the builder.
266
///
267
/// Takes `&mut self` to access the inner world reference while initializing
268
/// state for the new [`QueryState`]
269
pub fn build(&mut self) -> QueryState<D, F> {
270
QueryState::<D, F>::from_builder(self)
271
}
272
}
273
274
#[cfg(test)]
275
mod tests {
276
use crate::{
277
prelude::*,
278
world::{EntityMutExcept, EntityRefExcept, FilteredEntityMut, FilteredEntityRef},
279
};
280
use std::dbg;
281
282
#[derive(Component, PartialEq, Debug)]
283
struct A(usize);
284
285
#[derive(Component, PartialEq, Debug)]
286
struct B(usize);
287
288
#[derive(Component, PartialEq, Debug)]
289
struct C(usize);
290
291
#[test]
292
fn builder_with_without_static() {
293
let mut world = World::new();
294
let entity_a = world.spawn((A(0), B(0))).id();
295
let entity_b = world.spawn((A(0), C(0))).id();
296
297
let mut query_a = QueryBuilder::<Entity>::new(&mut world)
298
.with::<A>()
299
.without::<C>()
300
.build();
301
assert_eq!(entity_a, query_a.single(&world).unwrap());
302
303
let mut query_b = QueryBuilder::<Entity>::new(&mut world)
304
.with::<A>()
305
.without::<B>()
306
.build();
307
assert_eq!(entity_b, query_b.single(&world).unwrap());
308
}
309
310
#[test]
311
fn builder_with_without_dynamic() {
312
let mut world = World::new();
313
let entity_a = world.spawn((A(0), B(0))).id();
314
let entity_b = world.spawn((A(0), C(0))).id();
315
let component_id_a = world.register_component::<A>();
316
let component_id_b = world.register_component::<B>();
317
let component_id_c = world.register_component::<C>();
318
319
let mut query_a = QueryBuilder::<Entity>::new(&mut world)
320
.with_id(component_id_a)
321
.without_id(component_id_c)
322
.build();
323
assert_eq!(entity_a, query_a.single(&world).unwrap());
324
325
let mut query_b = QueryBuilder::<Entity>::new(&mut world)
326
.with_id(component_id_a)
327
.without_id(component_id_b)
328
.build();
329
assert_eq!(entity_b, query_b.single(&world).unwrap());
330
}
331
332
#[test]
333
fn builder_or() {
334
let mut world = World::new();
335
world.spawn((A(0), B(0)));
336
world.spawn(B(0));
337
world.spawn(C(0));
338
339
let mut query_a = QueryBuilder::<Entity>::new(&mut world)
340
.or(|builder| {
341
builder.with::<A>();
342
builder.with::<B>();
343
})
344
.build();
345
assert_eq!(2, query_a.iter(&world).count());
346
347
let mut query_b = QueryBuilder::<Entity>::new(&mut world)
348
.or(|builder| {
349
builder.with::<A>();
350
builder.without::<B>();
351
})
352
.build();
353
dbg!(&query_b.component_access);
354
assert_eq!(2, query_b.iter(&world).count());
355
356
let mut query_c = QueryBuilder::<Entity>::new(&mut world)
357
.or(|builder| {
358
builder.with::<A>();
359
builder.with::<B>();
360
builder.with::<C>();
361
})
362
.build();
363
assert_eq!(3, query_c.iter(&world).count());
364
}
365
366
#[test]
367
fn builder_transmute() {
368
let mut world = World::new();
369
world.spawn(A(0));
370
world.spawn((A(1), B(0)));
371
let mut query = QueryBuilder::<()>::new(&mut world)
372
.with::<B>()
373
.transmute::<&A>()
374
.build();
375
376
query.iter(&world).for_each(|a| assert_eq!(a.0, 1));
377
}
378
379
#[test]
380
fn builder_static_components() {
381
let mut world = World::new();
382
let entity = world.spawn((A(0), B(1))).id();
383
384
let mut query = QueryBuilder::<FilteredEntityRef>::new(&mut world)
385
.data::<&A>()
386
.data::<&B>()
387
.build();
388
389
let entity_ref = query.single(&world).unwrap();
390
391
assert_eq!(entity, entity_ref.id());
392
393
let a = entity_ref.get::<A>().unwrap();
394
let b = entity_ref.get::<B>().unwrap();
395
396
assert_eq!(0, a.0);
397
assert_eq!(1, b.0);
398
}
399
400
#[test]
401
fn builder_dynamic_components() {
402
let mut world = World::new();
403
let entity = world.spawn((A(0), B(1))).id();
404
let component_id_a = world.register_component::<A>();
405
let component_id_b = world.register_component::<B>();
406
407
let mut query = QueryBuilder::<FilteredEntityRef>::new(&mut world)
408
.ref_id(component_id_a)
409
.ref_id(component_id_b)
410
.build();
411
412
let entity_ref = query.single(&world).unwrap();
413
414
assert_eq!(entity, entity_ref.id());
415
416
let a = entity_ref.get_by_id(component_id_a).unwrap();
417
let b = entity_ref.get_by_id(component_id_b).unwrap();
418
419
// SAFETY: We set these pointers to point to these components
420
unsafe {
421
assert_eq!(0, a.deref::<A>().0);
422
assert_eq!(1, b.deref::<B>().0);
423
}
424
}
425
426
#[test]
427
fn builder_provide_access() {
428
let mut world = World::new();
429
world.spawn((A(0), B(1)));
430
431
let mut query =
432
QueryBuilder::<(Entity, FilteredEntityRef, FilteredEntityMut)>::new(&mut world)
433
.data::<&mut A>()
434
.data::<&B>()
435
.build();
436
437
// The `FilteredEntityRef` only has read access, so the `FilteredEntityMut` can have read access without conflicts
438
let (_entity, entity_ref_1, mut entity_ref_2) = query.single_mut(&mut world).unwrap();
439
assert!(entity_ref_1.get::<A>().is_some());
440
assert!(entity_ref_1.get::<B>().is_some());
441
assert!(entity_ref_2.get::<A>().is_some());
442
assert!(entity_ref_2.get_mut::<A>().is_none());
443
assert!(entity_ref_2.get::<B>().is_some());
444
assert!(entity_ref_2.get_mut::<B>().is_none());
445
446
let mut query =
447
QueryBuilder::<(Entity, FilteredEntityMut, FilteredEntityMut)>::new(&mut world)
448
.data::<&mut A>()
449
.data::<&B>()
450
.build();
451
452
// The first `FilteredEntityMut` has write access to A, so the second one cannot have write access
453
let (_entity, mut entity_ref_1, mut entity_ref_2) = query.single_mut(&mut world).unwrap();
454
assert!(entity_ref_1.get::<A>().is_some());
455
assert!(entity_ref_1.get_mut::<A>().is_some());
456
assert!(entity_ref_1.get::<B>().is_some());
457
assert!(entity_ref_1.get_mut::<B>().is_none());
458
assert!(entity_ref_2.get::<A>().is_none());
459
assert!(entity_ref_2.get_mut::<A>().is_none());
460
assert!(entity_ref_2.get::<B>().is_some());
461
assert!(entity_ref_2.get_mut::<B>().is_none());
462
463
let mut query = QueryBuilder::<(FilteredEntityMut, &mut A, &B)>::new(&mut world)
464
.data::<&mut A>()
465
.data::<&mut B>()
466
.build();
467
468
// Any `A` access would conflict with `&mut A`, and write access to `B` would conflict with `&B`.
469
let (mut entity_ref, _a, _b) = query.single_mut(&mut world).unwrap();
470
assert!(entity_ref.get::<A>().is_none());
471
assert!(entity_ref.get_mut::<A>().is_none());
472
assert!(entity_ref.get::<B>().is_some());
473
assert!(entity_ref.get_mut::<B>().is_none());
474
475
let mut query = QueryBuilder::<(FilteredEntityMut, &mut A, &B)>::new(&mut world)
476
.data::<EntityMut>()
477
.build();
478
479
// Same as above, but starting from "all" access
480
let (mut entity_ref, _a, _b) = query.single_mut(&mut world).unwrap();
481
assert!(entity_ref.get::<A>().is_none());
482
assert!(entity_ref.get_mut::<A>().is_none());
483
assert!(entity_ref.get::<B>().is_some());
484
assert!(entity_ref.get_mut::<B>().is_none());
485
486
let mut query = QueryBuilder::<(FilteredEntityMut, EntityMutExcept<A>)>::new(&mut world)
487
.data::<EntityMut>()
488
.build();
489
490
// Removing `EntityMutExcept<A>` just leaves A
491
let (mut entity_ref_1, _entity_ref_2) = query.single_mut(&mut world).unwrap();
492
assert!(entity_ref_1.get::<A>().is_some());
493
assert!(entity_ref_1.get_mut::<A>().is_some());
494
assert!(entity_ref_1.get::<B>().is_none());
495
assert!(entity_ref_1.get_mut::<B>().is_none());
496
497
let mut query = QueryBuilder::<(FilteredEntityMut, EntityRefExcept<A>)>::new(&mut world)
498
.data::<EntityMut>()
499
.build();
500
501
// Removing `EntityRefExcept<A>` just leaves A, plus read access
502
let (mut entity_ref_1, _entity_ref_2) = query.single_mut(&mut world).unwrap();
503
assert!(entity_ref_1.get::<A>().is_some());
504
assert!(entity_ref_1.get_mut::<A>().is_some());
505
assert!(entity_ref_1.get::<B>().is_some());
506
assert!(entity_ref_1.get_mut::<B>().is_none());
507
}
508
509
/// Regression test for issue #14348
510
#[test]
511
fn builder_static_dense_dynamic_sparse() {
512
#[derive(Component)]
513
struct Dense;
514
515
#[derive(Component)]
516
#[component(storage = "SparseSet")]
517
struct Sparse;
518
519
let mut world = World::new();
520
521
world.spawn(Dense);
522
world.spawn((Dense, Sparse));
523
524
let mut query = QueryBuilder::<&Dense>::new(&mut world)
525
.with::<Sparse>()
526
.build();
527
528
let matched = query.iter(&world).count();
529
assert_eq!(matched, 1);
530
}
531
}
532
533