bevy/crates/bevy_ecs/src/query/fetch.rs
James Liu ec8c8fbc8a Remove unnecesary branches/panics from Query accesses (#6461)
# Objective
Supercedes #6452. Upon inspection of the [generated assembly](https://gist.github.com/james7132/c2740c6941b80d7912f1e8888e223cbb#file-original-s) of a [simple Bevy binary](https://gist.github.com/james7132/c2740c6941b80d7912f1e8888e223cbb#file-source-rs) compiled with `cargo rustc --release -- --emit asm`, it's apparent that there are multiple unnecessary branches in the generated assembly:

```assembly
.LBB5_5:
	cmpq	%r10, %r11
	je	.LBB5_15
	movq	(%r11), %rcx
	movq	328(%r15), %rdx
	cmpq	%rdx, %rcx
	jae	.LBB5_14
	movq	312(%r15), %rdi
	leaq	(%rcx,%rcx,2), %rcx
	shlq	$5, %rcx
	movq	336(%r12), %rdx
	movq	64(%rdi,%rcx), %rax
	cmpq	%rdx, %rax
	jbe	.LBB5_4
	leaq	(%rdi,%rcx), %rsi
	movq	48(%rsi), %rbp
	shlq	$4, %rdx
	cmpq	$0, (%rbp,%rdx)
	je	.LBB5_4
	movq	344(%r12), %rbx
	cmpq	%rbx, %rax
	jbe	.LBB5_4
	shlq	$4, %rbx
	cmpq	$0, (%rbp,%rbx)
	je	.LBB5_4
	addq	$8, %r11
	movq	88(%rdi,%rcx), %rcx
	testq	%rcx, %rcx
	je	.LBB5_5
	movq	(%rsi), %rax
	movq	8(%rbp,%rdx), %rdx
	leaq	(%rdx,%rdx,4), %rdi
	shlq	$4, %rdi
	movq	32(%rax,%rdi), %rdx
	movq	56(%rax,%rdi), %r8
	movq	8(%rbp,%rbx), %rbp
	leaq	(%rbp,%rbp,4), %rbp
	shlq	$4, %rbp
	movq	32(%rax,%rbp), %r9
	xorl	%ebp, %ebp
	jmp	.LBB5_13
	.p2align	4, 0x90
```

Almost every one of the instructions starting with `j` is a potential branch, which can significantly slow down accesses. Of these, two labels are both common and never used:

```asm
.LBB5_14:
	leaq	__unnamed_2(%rip), %r8
	callq	_ZN4core9panicking18panic_bounds_check17h70367088e72af65aE
	ud2
.LBB5_4:
	callq	_ZN8bevy_ecs5query25debug_checked_unreachable17h0855ff520ceaea77E
	ud2
	.seh_endproc
```

These correpsond to subprocedure calls to panicking due to out of bounds from indexing `Tables` and `debug_checked_unreadable`. Both of which should be inlined and optimized out, but are not.

## Solution
Make `debug_checked_unreachable` a macro to forcibly inline either `unreachable!()` in debug builds, and `std::hint::unreachable_unchecked()` in release mode. Replace the `Tables` and `Archetype` index access with `get(id).unwrap_or_else(|| debug_checked_unreachable!())` to assume that the table or archetype provided exists.

This has no external breaking change of any kind.

The equivalent section of code with these changes removes most of the conditional jump instructions:

```asm
.LBB5_5:
	movss	(%rbx,%rbp,4), %xmm0
	movl	%r14d, 4(%r8,%rbp,8)
	addss	(%rdi,%rbp,4), %xmm0
	movss	%xmm0, (%rdi,%rbp,4)
	incq	%rbp
.LBB5_1:
	cmpq	%rdx, %rbp
	jne	.LBB5_5
	.p2align	4, 0x90
.LBB5_2:
	cmpq	%rcx, %rax
	je	.LBB5_6
	movq	(%rax), %rdx
	addq	$8, %rax
	movq	312(%rsi), %rbp
	leaq	(%rdx,%rdx,2), %rbx
	shlq	$5, %rbx
	movq	88(%rbp,%rbx), %rdx
	testq	%rdx, %rdx
	je	.LBB5_2
	leaq	(%rbx,%rbp), %r8
	movq	336(%r15), %rdi
	movq	344(%r15), %r9
	movq	48(%rbp,%rbx), %r10
	shlq	$4, %rdi
	movq	(%r8), %rbx
	movq	8(%r10,%rdi), %rdi
	leaq	(%rdi,%rdi,4), %rbp
	shlq	$4, %rbp
	movq	32(%rbx,%rbp), %rdi
	movq	56(%rbx,%rbp), %r8
	shlq	$4, %r9
	movq	8(%r10,%r9), %rbp
	leaq	(%rbp,%rbp,4), %rbp
	shlq	$4, %rbp
	movq	32(%rbx,%rbp), %rbx
	xorl	%ebp, %ebp
	jmp	.LBB5_5
.LBB5_6:
	addq	$40, %rsp
	popq	%rbx
	popq	%rbp
	popq	%rdi
	popq	%rsi
	popq	%r14
	popq	%r15
	retq
	.seh_endproc

```

## Performance

Microbenchmarks results:

<details>

```
group                                                    main                                     no-panic-query
-----                                                    ----                                     --------------
busy_systems/01x_entities_03_systems                     1.20     42.4±2.66µs        ? ?/sec      1.00     35.3±1.68µs        ? ?/sec
busy_systems/01x_entities_06_systems                     1.32     83.8±3.50µs        ? ?/sec      1.00     63.6±1.72µs        ? ?/sec
busy_systems/01x_entities_09_systems                     1.15    113.3±8.90µs        ? ?/sec      1.00     98.2±6.15µs        ? ?/sec
busy_systems/01x_entities_12_systems                     1.27   160.8±32.44µs        ? ?/sec      1.00    126.6±4.70µs        ? ?/sec
busy_systems/01x_entities_15_systems                     1.12    179.6±3.71µs        ? ?/sec      1.00   160.3±11.03µs        ? ?/sec
busy_systems/02x_entities_03_systems                     1.18     76.8±3.14µs        ? ?/sec      1.00     65.2±3.17µs        ? ?/sec
busy_systems/02x_entities_06_systems                     1.16    144.6±6.10µs        ? ?/sec      1.00    124.5±5.14µs        ? ?/sec
busy_systems/02x_entities_09_systems                     1.19    215.3±9.18µs        ? ?/sec      1.00    181.5±5.67µs        ? ?/sec
busy_systems/02x_entities_12_systems                     1.20    266.7±8.33µs        ? ?/sec      1.00    222.0±9.53µs        ? ?/sec
busy_systems/02x_entities_15_systems                     1.23   338.8±10.53µs        ? ?/sec      1.00    276.3±6.94µs        ? ?/sec
busy_systems/03x_entities_03_systems                     1.43    113.5±5.06µs        ? ?/sec      1.00     79.6±1.49µs        ? ?/sec
busy_systems/03x_entities_06_systems                     1.38   217.3±12.67µs        ? ?/sec      1.00    157.5±3.07µs        ? ?/sec
busy_systems/03x_entities_09_systems                     1.23   308.8±24.75µs        ? ?/sec      1.00    251.6±8.93µs        ? ?/sec
busy_systems/03x_entities_12_systems                     1.05   347.7±12.43µs        ? ?/sec      1.00   330.6±11.43µs        ? ?/sec
busy_systems/03x_entities_15_systems                     1.13   455.5±13.88µs        ? ?/sec      1.00   401.7±17.29µs        ? ?/sec
busy_systems/04x_entities_03_systems                     1.24    144.7±5.89µs        ? ?/sec      1.00    116.9±6.29µs        ? ?/sec
busy_systems/04x_entities_06_systems                     1.24   282.8±21.40µs        ? ?/sec      1.00   228.6±21.31µs        ? ?/sec
busy_systems/04x_entities_09_systems                     1.35   431.8±14.10µs        ? ?/sec      1.00    319.6±9.83µs        ? ?/sec
busy_systems/04x_entities_12_systems                     1.16   493.8±22.87µs        ? ?/sec      1.00   424.9±15.24µs        ? ?/sec
busy_systems/04x_entities_15_systems                     1.10   587.5±23.25µs        ? ?/sec      1.00   531.7±16.32µs        ? ?/sec
busy_systems/05x_entities_03_systems                     1.14    148.2±9.61µs        ? ?/sec      1.00    129.5±4.32µs        ? ?/sec
busy_systems/05x_entities_06_systems                     1.31   359.7±17.46µs        ? ?/sec      1.00   273.6±10.55µs        ? ?/sec
busy_systems/05x_entities_09_systems                     1.22   473.5±23.11µs        ? ?/sec      1.00   389.3±13.62µs        ? ?/sec
busy_systems/05x_entities_12_systems                     1.05   562.9±20.76µs        ? ?/sec      1.00   536.5±24.35µs        ? ?/sec
busy_systems/05x_entities_15_systems                     1.23   818.5±28.70µs        ? ?/sec      1.00   666.6±45.87µs        ? ?/sec
contrived/01x_entities_03_systems                        1.27     27.5±0.49µs        ? ?/sec      1.00     21.6±1.71µs        ? ?/sec
contrived/01x_entities_06_systems                        1.22     49.9±1.18µs        ? ?/sec      1.00     40.7±2.62µs        ? ?/sec
contrived/01x_entities_09_systems                        1.30     72.3±2.39µs        ? ?/sec      1.00     55.4±2.60µs        ? ?/sec
contrived/01x_entities_12_systems                        1.28     94.3±9.44µs        ? ?/sec      1.00     73.7±3.62µs        ? ?/sec
contrived/01x_entities_15_systems                        1.25    118.0±2.43µs        ? ?/sec      1.00     94.1±3.99µs        ? ?/sec
contrived/02x_entities_03_systems                        1.23     41.6±1.71µs        ? ?/sec      1.00     33.7±2.30µs        ? ?/sec
contrived/02x_entities_06_systems                        1.19     78.6±2.63µs        ? ?/sec      1.00     65.9±2.35µs        ? ?/sec
contrived/02x_entities_09_systems                        1.28    113.6±3.60µs        ? ?/sec      1.00     88.6±3.60µs        ? ?/sec
contrived/02x_entities_12_systems                        1.20    146.4±5.75µs        ? ?/sec      1.00    121.7±3.35µs        ? ?/sec
contrived/02x_entities_15_systems                        1.23    178.5±4.86µs        ? ?/sec      1.00    145.7±4.00µs        ? ?/sec
contrived/03x_entities_03_systems                        1.42     58.3±2.77µs        ? ?/sec      1.00     41.1±1.54µs        ? ?/sec
contrived/03x_entities_06_systems                        1.32    108.5±7.30µs        ? ?/sec      1.00     82.4±4.86µs        ? ?/sec
contrived/03x_entities_09_systems                        1.23    153.7±4.61µs        ? ?/sec      1.00    125.0±4.76µs        ? ?/sec
contrived/03x_entities_12_systems                        1.18    197.5±5.12µs        ? ?/sec      1.00    166.8±8.14µs        ? ?/sec
contrived/03x_entities_15_systems                        1.23    238.8±6.38µs        ? ?/sec      1.00    194.6±4.55µs        ? ?/sec
contrived/04x_entities_03_systems                        1.34     66.4±3.42µs        ? ?/sec      1.00     49.5±1.98µs        ? ?/sec
contrived/04x_entities_06_systems                        1.27    134.3±4.86µs        ? ?/sec      1.00    105.8±3.58µs        ? ?/sec
contrived/04x_entities_09_systems                        1.26    193.2±3.83µs        ? ?/sec      1.00    153.0±5.60µs        ? ?/sec
contrived/04x_entities_12_systems                        1.16    237.1±5.78µs        ? ?/sec      1.00   204.9±18.77µs        ? ?/sec
contrived/04x_entities_15_systems                        1.17    289.2±4.76µs        ? ?/sec      1.00    246.3±8.57µs        ? ?/sec
contrived/05x_entities_03_systems                        1.26     80.4±2.90µs        ? ?/sec      1.00     63.7±3.07µs        ? ?/sec
contrived/05x_entities_06_systems                        1.27   161.6±13.47µs        ? ?/sec      1.00    127.2±5.59µs        ? ?/sec
contrived/05x_entities_09_systems                        1.22    228.0±7.76µs        ? ?/sec      1.00    186.2±7.68µs        ? ?/sec
contrived/05x_entities_12_systems                        1.20    289.5±6.21µs        ? ?/sec      1.00    241.8±7.52µs        ? ?/sec
contrived/05x_entities_15_systems                        1.18   357.3±11.24µs        ? ?/sec      1.00    302.7±7.21µs        ? ?/sec
heavy_compute/base                                       1.01    302.4±3.52µs        ? ?/sec      1.00    300.2±3.40µs        ? ?/sec
iter_fragmented/base                                     1.00    348.1±7.51ns        ? ?/sec      1.01    351.9±8.32ns        ? ?/sec
iter_fragmented/foreach                                  1.03   239.8±23.78ns        ? ?/sec      1.00   233.8±18.12ns        ? ?/sec
iter_fragmented/foreach_wide                             1.00      3.9±0.13µs        ? ?/sec      1.02      4.0±0.22µs        ? ?/sec
iter_fragmented/wide                                     1.18      4.6±0.15µs        ? ?/sec      1.00      3.9±0.10µs        ? ?/sec
iter_fragmented_sparse/base                              1.02      8.1±0.15ns        ? ?/sec      1.00      7.9±0.56ns        ? ?/sec
iter_fragmented_sparse/foreach                           1.00      7.8±0.22ns        ? ?/sec      1.01      7.9±0.62ns        ? ?/sec
iter_fragmented_sparse/foreach_wide                      1.00     37.2±1.17ns        ? ?/sec      1.10     40.9±0.95ns        ? ?/sec
iter_fragmented_sparse/wide                              1.09     48.4±2.13ns        ? ?/sec      1.00    44.5±18.34ns        ? ?/sec
iter_simple/base                                         1.02      8.4±0.10µs        ? ?/sec      1.00      8.2±0.14µs        ? ?/sec
iter_simple/foreach                                      1.01      8.3±0.07µs        ? ?/sec      1.00      8.2±0.09µs        ? ?/sec
iter_simple/foreach_sparse_set                           1.00     25.3±0.32µs        ? ?/sec      1.02     25.7±0.42µs        ? ?/sec
iter_simple/foreach_wide                                 1.03     41.1±0.94µs        ? ?/sec      1.00     39.9±0.41µs        ? ?/sec
iter_simple/foreach_wide_sparse_set                      1.05    123.6±2.05µs        ? ?/sec      1.00    118.1±2.78µs        ? ?/sec
iter_simple/sparse_set                                   1.14     30.5±1.40µs        ? ?/sec      1.00     26.9±0.64µs        ? ?/sec
iter_simple/system                                       1.01      8.4±0.25µs        ? ?/sec      1.00      8.4±0.11µs        ? ?/sec
iter_simple/wide                                         1.18     48.2±0.62µs        ? ?/sec      1.00     40.7±0.38µs        ? ?/sec
iter_simple/wide_sparse_set                              1.12   140.8±21.56µs        ? ?/sec      1.00    126.0±2.30µs        ? ?/sec
query_get/50000_entities_sparse                          1.17    378.6±7.60µs        ? ?/sec      1.00   324.1±23.17µs        ? ?/sec
query_get/50000_entities_table                           1.08   330.9±10.90µs        ? ?/sec      1.00    306.8±4.98µs        ? ?/sec
query_get_component/50000_entities_sparse                1.00   976.7±19.55µs        ? ?/sec      1.00   979.8±35.87µs        ? ?/sec
query_get_component/50000_entities_table                 1.00  1029.0±15.11µs        ? ?/sec      1.05  1080.0±59.18µs        ? ?/sec
query_get_component_simple/system                        1.13   839.7±14.18µs        ? ?/sec      1.00   742.8±10.72µs        ? ?/sec
query_get_component_simple/unchecked                     1.01   909.0±15.17µs        ? ?/sec      1.00   898.0±13.56µs        ? ?/sec
query_get_many_10/50000_calls_sparse                     1.04      5.5±0.54ms        ? ?/sec      1.00      5.3±0.67ms        ? ?/sec
query_get_many_10/50000_calls_table                      1.01      4.9±0.49ms        ? ?/sec      1.00      4.8±0.45ms        ? ?/sec
query_get_many_2/50000_calls_sparse                      1.28  848.4±210.89µs        ? ?/sec      1.00   664.8±47.69µs        ? ?/sec
query_get_many_2/50000_calls_table                       1.05   779.0±73.85µs        ? ?/sec      1.00   739.2±83.02µs        ? ?/sec
query_get_many_5/50000_calls_sparse                      1.05      2.4±0.37ms        ? ?/sec      1.00      2.3±0.33ms        ? ?/sec
query_get_many_5/50000_calls_table                       1.00  1939.9±75.22µs        ? ?/sec      1.04      2.0±0.19ms        ? ?/sec
run_criteria/yes_using_query/001_systems                 1.00      3.7±0.38µs        ? ?/sec      1.30      4.9±0.14µs        ? ?/sec
run_criteria/yes_using_query/006_systems                 1.00      8.9±0.40µs        ? ?/sec      1.17     10.3±0.57µs        ? ?/sec
run_criteria/yes_using_query/011_systems                 1.00     13.9±0.49µs        ? ?/sec      1.08     15.0±0.89µs        ? ?/sec
run_criteria/yes_using_query/016_systems                 1.00     18.8±0.74µs        ? ?/sec      1.00     18.8±1.43µs        ? ?/sec
run_criteria/yes_using_query/021_systems                 1.07     24.1±0.87µs        ? ?/sec      1.00     22.6±1.58µs        ? ?/sec
run_criteria/yes_using_query/026_systems                 1.04     27.9±0.62µs        ? ?/sec      1.00     26.8±1.71µs        ? ?/sec
run_criteria/yes_using_query/031_systems                 1.09     33.3±1.03µs        ? ?/sec      1.00     30.5±2.18µs        ? ?/sec
run_criteria/yes_using_query/036_systems                 1.14     38.7±0.80µs        ? ?/sec      1.00     33.9±1.75µs        ? ?/sec
run_criteria/yes_using_query/041_systems                 1.18     43.7±1.07µs        ? ?/sec      1.00     37.0±2.39µs        ? ?/sec
run_criteria/yes_using_query/046_systems                 1.14     47.6±1.16µs        ? ?/sec      1.00     41.9±2.09µs        ? ?/sec
run_criteria/yes_using_query/051_systems                 1.17     52.9±2.04µs        ? ?/sec      1.00     45.3±1.75µs        ? ?/sec
run_criteria/yes_using_query/056_systems                 1.25     59.2±2.38µs        ? ?/sec      1.00     47.2±2.01µs        ? ?/sec
run_criteria/yes_using_query/061_systems                 1.28    66.1±15.84µs        ? ?/sec      1.00     51.5±2.47µs        ? ?/sec
run_criteria/yes_using_query/066_systems                 1.28     70.2±2.57µs        ? ?/sec      1.00     54.7±2.58µs        ? ?/sec
run_criteria/yes_using_query/071_systems                 1.30     75.5±2.27µs        ? ?/sec      1.00     58.2±3.31µs        ? ?/sec
run_criteria/yes_using_query/076_systems                 1.26     81.5±2.66µs        ? ?/sec      1.00     64.5±3.13µs        ? ?/sec
run_criteria/yes_using_query/081_systems                 1.29     89.7±2.58µs        ? ?/sec      1.00     69.3±3.47µs        ? ?/sec
run_criteria/yes_using_query/086_systems                 1.33     95.6±3.39µs        ? ?/sec      1.00     71.8±3.48µs        ? ?/sec
run_criteria/yes_using_query/091_systems                 1.25    102.0±3.67µs        ? ?/sec      1.00     81.4±4.82µs        ? ?/sec
run_criteria/yes_using_query/096_systems                 1.33    111.7±3.29µs        ? ?/sec      1.00     83.8±4.15µs        ? ?/sec
run_criteria/yes_using_query/101_systems                 1.29   113.2±12.04µs        ? ?/sec      1.00     87.7±5.15µs        ? ?/sec
world_query_for_each/50000_entities_sparse               1.00     47.4±0.51µs        ? ?/sec      1.00     47.3±0.33µs        ? ?/sec
world_query_for_each/50000_entities_table                1.00     27.2±0.50µs        ? ?/sec      1.00     27.2±0.17µs        ? ?/sec
world_query_get/50000_entities_sparse_wide               1.09    210.5±1.78µs        ? ?/sec      1.00    192.5±2.61µs        ? ?/sec
world_query_get/50000_entities_table                     1.00    127.7±2.09µs        ? ?/sec      1.07    136.2±5.95µs        ? ?/sec
world_query_get/50000_entities_table_wide                1.00    209.8±2.37µs        ? ?/sec      1.15    240.6±2.04µs        ? ?/sec
world_query_iter/50000_entities_sparse                   1.00     54.2±0.36µs        ? ?/sec      1.01     54.7±0.61µs        ? ?/sec
world_query_iter/50000_entities_table                    1.00     27.2±0.31µs        ? ?/sec      1.00     27.3±0.64µs        ? ?/sec
```
</details>

NOTE: This PR includes a change to enable LTO on our benchmarks to get a "fully optimized" baseline for our benchmarks. Both the main and the current PR's results were with LTO enabled.
2022-11-04 06:04:55 +00:00

1464 lines
49 KiB
Rust

use crate::{
archetype::{Archetype, ArchetypeComponentId},
change_detection::Ticks,
component::{Component, ComponentId, ComponentStorage, ComponentTicks, StorageType},
entity::Entity,
query::{Access, DebugCheckedUnwrap, FilteredAccess},
storage::{ComponentSparseSet, Table},
world::{Mut, World},
};
use bevy_ecs_macros::all_tuples;
pub use bevy_ecs_macros::WorldQuery;
use bevy_ptr::{ThinSlicePtr, UnsafeCellDeref};
use std::{cell::UnsafeCell, marker::PhantomData};
/// Types that can be fetched from a [`World`] using a [`Query`].
///
/// There are many types that natively implement this trait:
///
/// - **Component references.**
/// Fetches a component by reference (immutably or mutably).
/// - **`WorldQuery` tuples.**
/// If every element of a tuple implements `WorldQuery`, then the tuple itself also implements the same trait.
/// This enables a single `Query` to access multiple components and filter over multiple conditions.
/// Due to the current lack of variadic generics in Rust, the trait has been implemented for tuples from 0 to 15 elements,
/// but nesting of tuples allows infinite `WorldQuery`s.
/// - **Component filters.**
/// [`With`] and [`Without`] filters can be applied to check if the queried entity contains or not a particular component.
/// - **Change detection filters.**
/// [`Added`] and [`Changed`] filters can be applied to detect component changes to an entity.
/// - **Filter disjunction operator.**
/// By default, tuples compose query filters in such a way that all conditions must be satisfied to generate a query item for a given entity.
/// Wrapping a tuple inside an [`Or`] operator will relax the requirement to just one condition.
/// - **[`Entity`].**
/// Gets the identifier of the queried entity.
/// - **[`Option`].**
/// By default, a world query only tests entities that have the matching component types.
/// Wrapping it into an `Option` will increase the query search space, and it will return `None` if an entity doesn't satisfy the `WorldQuery`.
/// - **[`AnyOf`].**
/// Equivalent to wrapping each world query inside it into an `Option`.
/// - **[`ChangeTrackers`].**
/// Similar to change detection filters but it is used as a query fetch parameter.
/// It exposes methods to check for changes to the wrapped component.
///
/// Implementing the trait manually can allow for a fundamentally new type of behaviour.
///
/// # Trait derivation
///
/// Query design can be easily structured by deriving `WorldQuery` for custom types.
/// Despite the added complexity, this approach has several advantages over using `WorldQuery` tuples.
/// The most relevant improvements are:
///
/// - Reusability across multiple systems.
/// - There is no need to destructure a tuple since all fields are named.
/// - Subqueries can be composed together to create a more complex query.
/// - Methods can be implemented for the query items.
/// - There is no hardcoded limit on the number of elements.
///
/// This trait can only be derived if each field either
///
/// * also implements `WorldQuery`, or
/// * is marked with `#[world_query(ignore)]`. Fields decorated with this attribute
/// must implement [`Default`] and will be initialized to the default value as defined
/// by the trait.
///
/// The derive macro only supports regular structs (structs with named fields).
///
/// ```
/// # use bevy_ecs::prelude::*;
/// use bevy_ecs::query::WorldQuery;
/// #
/// # #[derive(Component)]
/// # struct ComponentA;
/// # #[derive(Component)]
/// # struct ComponentB;
///
/// #[derive(WorldQuery)]
/// struct MyQuery {
/// entity: Entity,
/// // It is required that all reference lifetimes are explicitly annotated, just like in any
/// // struct. Each lifetime should be 'static.
/// component_a: &'static ComponentA,
/// component_b: &'static ComponentB,
/// }
///
/// fn my_system(query: Query<MyQuery>) {
/// for q in &query {
/// q.component_a;
/// }
/// }
/// # bevy_ecs::system::assert_is_system(my_system);
/// ```
///
/// ## Macro expansion
///
/// Expanding the macro will declare three or six additional structs, depending on whether or not the struct is marked as mutable.
/// For a struct named `X`, the additional structs will be:
///
/// |Struct name|`mutable` only|Description|
/// |:---:|:---:|---|
/// |`XState`|---|Used as the [`State`] type for `X` and `XReadOnly`|
/// |`XItem`|---|The type of the query item for `X`|
/// |`XFetch`|---|Used as the [`Fetch`] type for `X`|
/// |`XReadOnlyItem`|✓|The type of the query item for `XReadOnly`|
/// |`XReadOnlyFetch`|✓|Used as the [`Fetch`] type for `XReadOnly`|
/// |`XReadOnly`|✓|[`ReadOnly`] variant of `X`|
///
/// ## Adding mutable references
///
/// Simply adding mutable references to a derived `WorldQuery` will result in a compilation error:
///
/// ```compile_fail
/// # use bevy_ecs::prelude::*;
/// # use bevy_ecs::query::WorldQuery;
/// #
/// # #[derive(Component)]
/// # struct ComponentA;
/// #
/// #[derive(WorldQuery)]
/// struct CustomQuery {
/// component_a: &'static mut ComponentA,
/// }
/// ```
///
/// To grant mutable access to components, the struct must be marked with the `#[world_query(mutable)]` attribute.
/// This will also create three more structs that will be used for accessing the query immutably (see table above).
///
/// ```
/// # use bevy_ecs::prelude::*;
/// # use bevy_ecs::query::WorldQuery;
/// #
/// # #[derive(Component)]
/// # struct ComponentA;
/// #
/// #[derive(WorldQuery)]
/// #[world_query(mutable)]
/// struct CustomQuery {
/// component_a: &'static mut ComponentA,
/// }
/// ```
///
/// ## Adding methods to query items
///
/// It is possible to add methods to query items in order to write reusable logic about related components.
/// This will often make systems more readable because low level logic is moved out from them.
/// It is done by adding `impl` blocks with methods for the `-Item` or `-ReadOnlyItem` generated structs.
///
/// ```
/// # use bevy_ecs::prelude::*;
/// # use bevy_ecs::query::WorldQuery;
/// #
/// #[derive(Component)]
/// struct Health(f32);
///
/// #[derive(Component)]
/// struct Buff(f32);
///
/// #[derive(WorldQuery)]
/// #[world_query(mutable)]
/// struct HealthQuery {
/// health: &'static mut Health,
/// buff: Option<&'static mut Buff>,
/// }
///
/// // `HealthQueryItem` is only available when accessing the query with mutable methods.
/// impl<'w> HealthQueryItem<'w> {
/// fn damage(&mut self, value: f32) {
/// self.health.0 -= value;
/// }
///
/// fn total(&self) -> f32 {
/// self.health.0 + self.buff.as_deref().map_or(0.0, |Buff(buff)| *buff)
/// }
/// }
///
/// // `HealthQueryReadOnlyItem` is only available when accessing the query with immutable methods.
/// impl<'w> HealthQueryReadOnlyItem<'w> {
/// fn total(&self) -> f32 {
/// self.health.0 + self.buff.map_or(0.0, |Buff(buff)| *buff)
/// }
/// }
///
/// fn my_system(mut health_query: Query<HealthQuery>) {
/// // The item returned by the iterator is of type `HealthQueryReadOnlyItem`.
/// for health in health_query.iter() {
/// println!("Total: {}", health.total());
/// }
/// // The item returned by the iterator is of type `HealthQueryItem`.
/// for mut health in &mut health_query {
/// health.damage(1.0);
/// println!("Total (mut): {}", health.total());
/// }
/// }
/// # bevy_ecs::system::assert_is_system(my_system);
/// ```
///
/// ## Deriving traits for query items
///
/// The `WorldQuery` derive macro does not automatically implement the traits of the struct to the query item types.
/// Something similar can be done by using the `#[world_query(derive(...))]` attribute.
/// This will apply the listed derivable traits to the query item structs.
///
/// ```
/// # use bevy_ecs::prelude::*;
/// # use bevy_ecs::query::WorldQuery;
/// #
/// # #[derive(Component, Debug)]
/// # struct ComponentA;
/// #
/// #[derive(WorldQuery)]
/// #[world_query(mutable, derive(Debug))]
/// struct CustomQuery {
/// component_a: &'static ComponentA,
/// }
///
/// // This function statically checks that `T` implements `Debug`.
/// fn assert_debug<T: std::fmt::Debug>() {}
///
/// assert_debug::<CustomQueryItem>();
/// assert_debug::<CustomQueryReadOnlyItem>();
/// ```
///
/// ## Query composition
///
/// It is possible to use any `WorldQuery` as a field of another one.
/// This means that a `WorldQuery` can also be used as a subquery, potentially in multiple places.
///
/// ```
/// # use bevy_ecs::prelude::*;
/// # use bevy_ecs::query::WorldQuery;
/// #
/// # #[derive(Component)]
/// # struct ComponentA;
/// # #[derive(Component)]
/// # struct ComponentB;
/// # #[derive(Component)]
/// # struct ComponentC;
/// #
/// #[derive(WorldQuery)]
/// struct SubQuery {
/// component_a: &'static ComponentA,
/// component_b: &'static ComponentB,
/// }
///
/// #[derive(WorldQuery)]
/// struct MyQuery {
/// subquery: SubQuery,
/// component_c: &'static ComponentC,
/// }
/// ```
///
/// ## Filters
///
/// Since the query filter type parameter is `WorldQuery`, it is also possible to use this macro to create filters.
///
/// ```
/// # use bevy_ecs::prelude::*;
/// # use bevy_ecs::{query::WorldQuery, component::Component};
/// #
/// # #[derive(Component)]
/// # struct ComponentA;
/// # #[derive(Component)]
/// # struct ComponentB;
/// # #[derive(Component)]
/// # struct ComponentC;
/// # #[derive(Component)]
/// # struct ComponentD;
/// # #[derive(Component)]
/// # struct ComponentE;
/// #
/// #[derive(WorldQuery)]
/// struct MyFilter<T: Component, P: Component> {
/// // Field names are not relevant, since they are never manually accessed.
/// with_a: With<ComponentA>,
/// or_filter: Or<(With<ComponentC>, Added<ComponentB>)>,
/// generic_tuple: (With<T>, Without<P>),
/// }
///
/// fn my_system(query: Query<Entity, MyFilter<ComponentD, ComponentE>>) {
/// // ...
/// }
/// # bevy_ecs::system::assert_is_system(my_system);
/// ```
///
/// # Safety
///
/// Component access of `Self::ReadOnly` must be a subset of `Self`
/// and `Self::ReadOnly` must match exactly the same archetypes/tables as `Self`
///
/// Implementor must ensure that
/// [`update_component_access`] and [`update_archetype_component_access`]
/// exactly reflects the results of the following methods:
///
/// - [`matches_component_set`]
/// - [`fetch`]
///
/// [`Added`]: crate::query::Added
/// [`fetch`]: Self::fetch
/// [`Changed`]: crate::query::Changed
/// [`Fetch`]: crate::query::WorldQuery::Fetch
/// [`matches_component_set`]: Self::matches_component_set
/// [`Or`]: crate::query::Or
/// [`Query`]: crate::system::Query
/// [`ReadOnly`]: Self::ReadOnly
/// [`State`]: Self::State
/// [`update_archetype_component_access`]: Self::update_archetype_component_access
/// [`update_component_access`]: Self::update_component_access
/// [`With`]: crate::query::With
/// [`Without`]: crate::query::Without
pub unsafe trait WorldQuery {
/// The item returned by this [`WorldQuery`]
type Item<'a>;
/// Per archetype/table state used by this [`WorldQuery`] to fetch [`Self::Item`](crate::query::WorldQuery::Item)
type Fetch<'a>;
/// The read-only variant of this [`WorldQuery`], which satisfies the [`ReadOnlyWorldQuery`] trait.
type ReadOnly: ReadOnlyWorldQuery<State = Self::State>;
/// State used to construct a [`Self::Fetch`](crate::query::WorldQuery::Fetch). This will be cached inside [`QueryState`](crate::query::QueryState),
/// so it is best to move as much data / computation here as possible to reduce the cost of
/// constructing [`Self::Fetch`](crate::query::WorldQuery::Fetch).
type State: Send + Sync + Sized;
/// This function manually implements subtyping for the query items.
fn shrink<'wlong: 'wshort, 'wshort>(item: Self::Item<'wlong>) -> Self::Item<'wshort>;
/// Creates a new instance of this fetch.
///
/// # Safety
///
/// `state` must have been initialized (via [`WorldQuery::init_state`]) using the same `world` passed
/// in to this function.
unsafe fn init_fetch<'w>(
world: &'w World,
state: &Self::State,
last_change_tick: u32,
change_tick: u32,
) -> Self::Fetch<'w>;
/// While this function can be called for any query, it is always safe to call if `Self: ReadOnlyWorldQuery` holds.
///
/// # Safety
/// While calling this method on its own cannot cause UB it is marked `unsafe` as the caller must ensure
/// that the returned value is not used in any way that would cause two `QueryItem<Self>` for the same
/// `archetype_index` or `table_row` to be alive at the same time.
unsafe fn clone_fetch<'w>(fetch: &Self::Fetch<'w>) -> Self::Fetch<'w>;
/// Returns true if (and only if) every table of every archetype matched by this fetch contains
/// all of the matched components. This is used to select a more efficient "table iterator"
/// for "dense" queries. If this returns true, [`WorldQuery::set_table`] must be used before
/// [`WorldQuery::fetch`] can be called for iterators. If this returns false,
/// [`WorldQuery::set_archetype`] must be used before [`WorldQuery::fetch`] can be called for
/// iterators.
const IS_DENSE: bool;
/// Returns true if (and only if) this Fetch relies strictly on archetypes to limit which
/// components are accessed by the Query.
///
/// This enables optimizations for [`crate::query::QueryIter`] that rely on knowing exactly how
/// many elements are being iterated (such as `Iterator::collect()`).
const IS_ARCHETYPAL: bool;
/// Adjusts internal state to account for the next [`Archetype`]. This will always be called on
/// archetypes that match this [`WorldQuery`].
///
/// # Safety
///
/// `archetype` and `tables` must be from the [`World`] [`WorldQuery::init_state`] was called on. `state` must
/// be the [`Self::State`] this was initialized with.
unsafe fn set_archetype<'w>(
fetch: &mut Self::Fetch<'w>,
state: &Self::State,
archetype: &'w Archetype,
table: &'w Table,
);
/// Adjusts internal state to account for the next [`Table`]. This will always be called on tables
/// that match this [`WorldQuery`].
///
/// # Safety
///
/// `table` must be from the [`World`] [`WorldQuery::init_state`] was called on. `state` must be the
/// [`Self::State`] this was initialized with.
unsafe fn set_table<'w>(fetch: &mut Self::Fetch<'w>, state: &Self::State, table: &'w Table);
/// Fetch [`Self::Item`](`WorldQuery::Item`) for either the given `entity` in the current [`Table`],
/// or for the given `entity` in the current [`Archetype`]. This must always be called after
/// [`WorldQuery::set_table`] with a `table_row` in the range of the current [`Table`] or after
/// [`WorldQuery::set_archetype`] with a `entity` in the current archetype.
///
/// # Safety
///
/// Must always be called _after_ [`WorldQuery::set_table`] or [`WorldQuery::set_archetype`]. `entity` and
/// `table_row` must be in the range of the current table and archetype.
unsafe fn fetch<'w>(
fetch: &mut Self::Fetch<'w>,
entity: Entity,
table_row: usize,
) -> Self::Item<'w>;
/// # Safety
///
/// Must always be called _after_ [`WorldQuery::set_table`] or [`WorldQuery::set_archetype`]. `entity` and
/// `table_row` must be in the range of the current table and archetype.
#[allow(unused_variables)]
#[inline(always)]
unsafe fn filter_fetch(fetch: &mut Self::Fetch<'_>, entity: Entity, table_row: usize) -> bool {
true
}
// This does not have a default body of `{}` because 99% of cases need to add accesses
// and forgetting to do so would be unsound.
fn update_component_access(state: &Self::State, access: &mut FilteredAccess<ComponentId>);
// This does not have a default body of `{}` becaues 99% of cases need to add accesses
// and forgetting to do so would be unsound.
fn update_archetype_component_access(
state: &Self::State,
archetype: &Archetype,
access: &mut Access<ArchetypeComponentId>,
);
fn init_state(world: &mut World) -> Self::State;
fn matches_component_set(
state: &Self::State,
set_contains_id: &impl Fn(ComponentId) -> bool,
) -> bool;
}
/// A world query that is read only.
///
/// # Safety
///
/// This must only be implemented for read-only [`WorldQuery`]'s.
pub unsafe trait ReadOnlyWorldQuery: WorldQuery<ReadOnly = Self> {}
/// The `Fetch` of a [`WorldQuery`], which is used to store state for each archetype/table.
pub type QueryFetch<'w, Q> = <Q as WorldQuery>::Fetch<'w>;
/// The item type returned when a [`WorldQuery`] is iterated over
pub type QueryItem<'w, Q> = <Q as WorldQuery>::Item<'w>;
/// The read-only `Fetch` of a [`WorldQuery`], which is used to store state for each archetype/table.
pub type ROQueryFetch<'w, Q> = QueryFetch<'w, <Q as WorldQuery>::ReadOnly>;
/// The read-only variant of the item type returned when a [`WorldQuery`] is iterated over immutably
pub type ROQueryItem<'w, Q> = QueryItem<'w, <Q as WorldQuery>::ReadOnly>;
/// SAFETY: no component or archetype access
unsafe impl WorldQuery for Entity {
type Fetch<'w> = ();
type Item<'w> = Entity;
type ReadOnly = Self;
type State = ();
fn shrink<'wlong: 'wshort, 'wshort>(item: Self::Item<'wlong>) -> Self::Item<'wshort> {
item
}
const IS_DENSE: bool = true;
const IS_ARCHETYPAL: bool = true;
unsafe fn init_fetch<'w>(
_world: &'w World,
_state: &Self::State,
_last_change_tick: u32,
_change_tick: u32,
) -> Self::Fetch<'w> {
}
unsafe fn clone_fetch<'w>(_fetch: &Self::Fetch<'w>) -> Self::Fetch<'w> {}
#[inline]
unsafe fn set_archetype<'w>(
_fetch: &mut Self::Fetch<'w>,
_state: &Self::State,
_archetype: &'w Archetype,
_table: &Table,
) {
}
#[inline]
unsafe fn set_table<'w>(_fetch: &mut Self::Fetch<'w>, _state: &Self::State, _table: &'w Table) {
}
#[inline(always)]
unsafe fn fetch<'w>(
_fetch: &mut Self::Fetch<'w>,
entity: Entity,
_table_row: usize,
) -> Self::Item<'w> {
entity
}
fn update_component_access(_state: &Self::State, _access: &mut FilteredAccess<ComponentId>) {}
fn update_archetype_component_access(
_state: &Self::State,
_archetype: &Archetype,
_access: &mut Access<ArchetypeComponentId>,
) {
}
fn init_state(_world: &mut World) {}
fn matches_component_set(
_state: &Self::State,
_set_contains_id: &impl Fn(ComponentId) -> bool,
) -> bool {
true
}
}
/// SAFETY: access is read only
unsafe impl ReadOnlyWorldQuery for Entity {}
#[doc(hidden)]
pub struct ReadFetch<'w, T> {
// T::Storage = TableStorage
table_components: Option<ThinSlicePtr<'w, UnsafeCell<T>>>,
// T::Storage = SparseStorage
sparse_set: Option<&'w ComponentSparseSet>,
}
/// SAFETY: `Self` is the same as `Self::ReadOnly`
unsafe impl<T: Component> WorldQuery for &T {
type Fetch<'w> = ReadFetch<'w, T>;
type Item<'w> = &'w T;
type ReadOnly = Self;
type State = ComponentId;
fn shrink<'wlong: 'wshort, 'wshort>(item: &'wlong T) -> &'wshort T {
item
}
const IS_DENSE: bool = {
match T::Storage::STORAGE_TYPE {
StorageType::Table => true,
StorageType::SparseSet => false,
}
};
const IS_ARCHETYPAL: bool = true;
unsafe fn init_fetch<'w>(
world: &'w World,
&component_id: &ComponentId,
_last_change_tick: u32,
_change_tick: u32,
) -> ReadFetch<'w, T> {
ReadFetch {
table_components: None,
sparse_set: (T::Storage::STORAGE_TYPE == StorageType::SparseSet).then(|| {
world
.storages()
.sparse_sets
.get(component_id)
.debug_checked_unwrap()
}),
}
}
unsafe fn clone_fetch<'w>(fetch: &Self::Fetch<'w>) -> Self::Fetch<'w> {
ReadFetch {
table_components: fetch.table_components,
sparse_set: fetch.sparse_set,
}
}
#[inline]
unsafe fn set_archetype<'w>(
fetch: &mut ReadFetch<'w, T>,
component_id: &ComponentId,
_archetype: &'w Archetype,
table: &'w Table,
) {
if Self::IS_DENSE {
Self::set_table(fetch, component_id, table);
}
}
#[inline]
unsafe fn set_table<'w>(
fetch: &mut ReadFetch<'w, T>,
&component_id: &ComponentId,
table: &'w Table,
) {
fetch.table_components = Some(
table
.get_column(component_id)
.debug_checked_unwrap()
.get_data_slice()
.into(),
);
}
#[inline(always)]
unsafe fn fetch<'w>(
fetch: &mut Self::Fetch<'w>,
entity: Entity,
table_row: usize,
) -> Self::Item<'w> {
match T::Storage::STORAGE_TYPE {
StorageType::Table => fetch
.table_components
.debug_checked_unwrap()
.get(table_row)
.deref(),
StorageType::SparseSet => fetch
.sparse_set
.debug_checked_unwrap()
.get(entity)
.debug_checked_unwrap()
.deref(),
}
}
fn update_component_access(
&component_id: &ComponentId,
access: &mut FilteredAccess<ComponentId>,
) {
assert!(
!access.access().has_write(component_id),
"&{} conflicts with a previous access in this query. Shared access cannot coincide with exclusive access.",
std::any::type_name::<T>(),
);
access.add_read(component_id);
}
fn update_archetype_component_access(
&component_id: &ComponentId,
archetype: &Archetype,
access: &mut Access<ArchetypeComponentId>,
) {
if let Some(archetype_component_id) = archetype.get_archetype_component_id(component_id) {
access.add_read(archetype_component_id);
}
}
fn init_state(world: &mut World) -> ComponentId {
world.init_component::<T>()
}
fn matches_component_set(
&state: &ComponentId,
set_contains_id: &impl Fn(ComponentId) -> bool,
) -> bool {
set_contains_id(state)
}
}
/// SAFETY: access is read only
unsafe impl<T: Component> ReadOnlyWorldQuery for &T {}
#[doc(hidden)]
pub struct WriteFetch<'w, T> {
// T::Storage = TableStorage
table_data: Option<(
ThinSlicePtr<'w, UnsafeCell<T>>,
ThinSlicePtr<'w, UnsafeCell<ComponentTicks>>,
)>,
// T::Storage = SparseStorage
sparse_set: Option<&'w ComponentSparseSet>,
last_change_tick: u32,
change_tick: u32,
}
/// SAFETY: access of `&T` is a subset of `&mut T`
unsafe impl<'__w, T: Component> WorldQuery for &'__w mut T {
type Fetch<'w> = WriteFetch<'w, T>;
type Item<'w> = Mut<'w, T>;
type ReadOnly = &'__w T;
type State = ComponentId;
fn shrink<'wlong: 'wshort, 'wshort>(item: Mut<'wlong, T>) -> Mut<'wshort, T> {
item
}
const IS_DENSE: bool = {
match T::Storage::STORAGE_TYPE {
StorageType::Table => true,
StorageType::SparseSet => false,
}
};
const IS_ARCHETYPAL: bool = true;
unsafe fn init_fetch<'w>(
world: &'w World,
&component_id: &ComponentId,
last_change_tick: u32,
change_tick: u32,
) -> WriteFetch<'w, T> {
WriteFetch {
table_data: None,
sparse_set: (T::Storage::STORAGE_TYPE == StorageType::SparseSet).then(|| {
world
.storages()
.sparse_sets
.get(component_id)
.debug_checked_unwrap()
}),
last_change_tick,
change_tick,
}
}
unsafe fn clone_fetch<'w>(fetch: &Self::Fetch<'w>) -> Self::Fetch<'w> {
WriteFetch {
table_data: fetch.table_data,
sparse_set: fetch.sparse_set,
last_change_tick: fetch.last_change_tick,
change_tick: fetch.change_tick,
}
}
#[inline]
unsafe fn set_archetype<'w>(
fetch: &mut WriteFetch<'w, T>,
component_id: &ComponentId,
_archetype: &'w Archetype,
table: &'w Table,
) {
if Self::IS_DENSE {
Self::set_table(fetch, component_id, table);
}
}
#[inline]
unsafe fn set_table<'w>(
fetch: &mut WriteFetch<'w, T>,
&component_id: &ComponentId,
table: &'w Table,
) {
let column = table.get_column(component_id).debug_checked_unwrap();
fetch.table_data = Some((
column.get_data_slice().into(),
column.get_ticks_slice().into(),
));
}
#[inline(always)]
unsafe fn fetch<'w>(
fetch: &mut Self::Fetch<'w>,
entity: Entity,
table_row: usize,
) -> Self::Item<'w> {
match T::Storage::STORAGE_TYPE {
StorageType::Table => {
let (table_components, table_ticks) = fetch.table_data.debug_checked_unwrap();
Mut {
value: table_components.get(table_row).deref_mut(),
ticks: Ticks {
component_ticks: table_ticks.get(table_row).deref_mut(),
change_tick: fetch.change_tick,
last_change_tick: fetch.last_change_tick,
},
}
}
StorageType::SparseSet => {
let (component, component_ticks) = fetch
.sparse_set
.debug_checked_unwrap()
.get_with_ticks(entity)
.debug_checked_unwrap();
Mut {
value: component.assert_unique().deref_mut(),
ticks: Ticks {
component_ticks: component_ticks.deref_mut(),
change_tick: fetch.change_tick,
last_change_tick: fetch.last_change_tick,
},
}
}
}
}
fn update_component_access(
&component_id: &ComponentId,
access: &mut FilteredAccess<ComponentId>,
) {
assert!(
!access.access().has_read(component_id),
"&mut {} conflicts with a previous access in this query. Mutable component access must be unique.",
std::any::type_name::<T>(),
);
access.add_write(component_id);
}
fn update_archetype_component_access(
&component_id: &ComponentId,
archetype: &Archetype,
access: &mut Access<ArchetypeComponentId>,
) {
if let Some(archetype_component_id) = archetype.get_archetype_component_id(component_id) {
access.add_write(archetype_component_id);
}
}
fn init_state(world: &mut World) -> ComponentId {
world.init_component::<T>()
}
fn matches_component_set(
&state: &ComponentId,
set_contains_id: &impl Fn(ComponentId) -> bool,
) -> bool {
set_contains_id(state)
}
}
#[doc(hidden)]
pub struct OptionFetch<'w, T: WorldQuery> {
fetch: T::Fetch<'w>,
matches: bool,
}
// SAFETY: defers to soundness of `T: WorldQuery` impl
unsafe impl<T: WorldQuery> WorldQuery for Option<T> {
type Fetch<'w> = OptionFetch<'w, T>;
type Item<'w> = Option<T::Item<'w>>;
type ReadOnly = Option<T::ReadOnly>;
type State = T::State;
fn shrink<'wlong: 'wshort, 'wshort>(item: Self::Item<'wlong>) -> Self::Item<'wshort> {
item.map(T::shrink)
}
const IS_DENSE: bool = T::IS_DENSE;
const IS_ARCHETYPAL: bool = T::IS_ARCHETYPAL;
unsafe fn init_fetch<'w>(
world: &'w World,
state: &T::State,
last_change_tick: u32,
change_tick: u32,
) -> OptionFetch<'w, T> {
OptionFetch {
fetch: T::init_fetch(world, state, last_change_tick, change_tick),
matches: false,
}
}
unsafe fn clone_fetch<'w>(fetch: &Self::Fetch<'w>) -> Self::Fetch<'w> {
OptionFetch {
fetch: T::clone_fetch(&fetch.fetch),
matches: fetch.matches,
}
}
#[inline]
unsafe fn set_archetype<'w>(
fetch: &mut OptionFetch<'w, T>,
state: &T::State,
archetype: &'w Archetype,
table: &'w Table,
) {
fetch.matches = T::matches_component_set(state, &|id| archetype.contains(id));
if fetch.matches {
T::set_archetype(&mut fetch.fetch, state, archetype, table);
}
}
#[inline]
unsafe fn set_table<'w>(fetch: &mut OptionFetch<'w, T>, state: &T::State, table: &'w Table) {
fetch.matches = T::matches_component_set(state, &|id| table.has_column(id));
if fetch.matches {
T::set_table(&mut fetch.fetch, state, table);
}
}
#[inline(always)]
unsafe fn fetch<'w>(
fetch: &mut Self::Fetch<'w>,
entity: Entity,
table_row: usize,
) -> Self::Item<'w> {
fetch
.matches
.then(|| T::fetch(&mut fetch.fetch, entity, table_row))
}
fn update_component_access(state: &T::State, access: &mut FilteredAccess<ComponentId>) {
// We don't want to add the `with`/`without` of `T` as `Option<T>` will match things regardless of
// `T`'s filters. for example `Query<(Option<&U>, &mut V)>` will match every entity with a `V` component
// regardless of whether it has a `U` component. If we dont do this the query will not conflict with
// `Query<&mut V, Without<U>>` which would be unsound.
let mut intermediate = access.clone();
T::update_component_access(state, &mut intermediate);
access.extend_access(&intermediate);
}
fn update_archetype_component_access(
state: &T::State,
archetype: &Archetype,
access: &mut Access<ArchetypeComponentId>,
) {
if T::matches_component_set(state, &|id| archetype.contains(id)) {
T::update_archetype_component_access(state, archetype, access);
}
}
fn init_state(world: &mut World) -> T::State {
T::init_state(world)
}
fn matches_component_set(
_state: &T::State,
_set_contains_id: &impl Fn(ComponentId) -> bool,
) -> bool {
true
}
}
/// SAFETY: [`OptionFetch`] is read only because `T` is read only
unsafe impl<T: ReadOnlyWorldQuery> ReadOnlyWorldQuery for Option<T> {}
/// [`WorldQuery`] that tracks changes and additions for component `T`.
///
/// Wraps a [`Component`] to track whether the component changed for the corresponding entities in
/// a query since the last time the system that includes these queries ran.
///
/// If you only care about entities that changed or that got added use the
/// [`Changed`](crate::query::Changed) and [`Added`](crate::query::Added) filters instead.
///
/// # Examples
///
/// ```
/// # use bevy_ecs::component::Component;
/// # use bevy_ecs::query::ChangeTrackers;
/// # use bevy_ecs::system::IntoSystem;
/// # use bevy_ecs::system::Query;
/// #
/// # #[derive(Component, Debug)]
/// # struct Name {};
/// # #[derive(Component)]
/// # struct Transform {};
/// #
/// fn print_moving_objects_system(query: Query<(&Name, ChangeTrackers<Transform>)>) {
/// for (name, tracker) in &query {
/// if tracker.is_changed() {
/// println!("Entity moved: {:?}", name);
/// } else {
/// println!("Entity stood still: {:?}", name);
/// }
/// }
/// }
/// # bevy_ecs::system::assert_is_system(print_moving_objects_system);
/// ```
pub struct ChangeTrackers<T: Component> {
pub(crate) component_ticks: ComponentTicks,
pub(crate) last_change_tick: u32,
pub(crate) change_tick: u32,
marker: PhantomData<T>,
}
impl<T: Component> Clone for ChangeTrackers<T> {
fn clone(&self) -> Self {
Self {
component_ticks: self.component_ticks,
last_change_tick: self.last_change_tick,
change_tick: self.change_tick,
marker: PhantomData,
}
}
}
impl<T: Component> Copy for ChangeTrackers<T> {}
impl<T: Component> std::fmt::Debug for ChangeTrackers<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ChangeTrackers")
.field("component_ticks", &self.component_ticks)
.field("last_change_tick", &self.last_change_tick)
.field("change_tick", &self.change_tick)
.finish()
}
}
impl<T: Component> ChangeTrackers<T> {
/// Returns true if this component has been added since the last execution of this system.
pub fn is_added(&self) -> bool {
self.component_ticks
.is_added(self.last_change_tick, self.change_tick)
}
/// Returns true if this component has been changed since the last execution of this system.
pub fn is_changed(&self) -> bool {
self.component_ticks
.is_changed(self.last_change_tick, self.change_tick)
}
}
#[doc(hidden)]
pub struct ChangeTrackersFetch<'w, T> {
// T::Storage = TableStorage
table_ticks: Option<ThinSlicePtr<'w, UnsafeCell<ComponentTicks>>>,
// T::Storage = SparseStorage
sparse_set: Option<&'w ComponentSparseSet>,
marker: PhantomData<T>,
last_change_tick: u32,
change_tick: u32,
}
// SAFETY: `ROQueryFetch<Self>` is the same as `QueryFetch<Self>`
unsafe impl<T: Component> WorldQuery for ChangeTrackers<T> {
type Fetch<'w> = ChangeTrackersFetch<'w, T>;
type Item<'w> = ChangeTrackers<T>;
type ReadOnly = Self;
type State = ComponentId;
fn shrink<'wlong: 'wshort, 'wshort>(item: Self::Item<'wlong>) -> Self::Item<'wshort> {
item
}
const IS_DENSE: bool = {
match T::Storage::STORAGE_TYPE {
StorageType::Table => true,
StorageType::SparseSet => false,
}
};
const IS_ARCHETYPAL: bool = true;
unsafe fn init_fetch<'w>(
world: &'w World,
&component_id: &ComponentId,
last_change_tick: u32,
change_tick: u32,
) -> ChangeTrackersFetch<'w, T> {
ChangeTrackersFetch {
table_ticks: None,
sparse_set: (T::Storage::STORAGE_TYPE == StorageType::SparseSet).then(|| {
world
.storages()
.sparse_sets
.get(component_id)
.debug_checked_unwrap()
}),
marker: PhantomData,
last_change_tick,
change_tick,
}
}
unsafe fn clone_fetch<'w>(fetch: &Self::Fetch<'w>) -> Self::Fetch<'w> {
ChangeTrackersFetch {
table_ticks: fetch.table_ticks,
sparse_set: fetch.sparse_set,
marker: fetch.marker,
last_change_tick: fetch.last_change_tick,
change_tick: fetch.change_tick,
}
}
#[inline]
unsafe fn set_archetype<'w>(
fetch: &mut ChangeTrackersFetch<'w, T>,
component_id: &ComponentId,
_archetype: &'w Archetype,
table: &'w Table,
) {
if Self::IS_DENSE {
Self::set_table(fetch, component_id, table);
}
}
#[inline]
unsafe fn set_table<'w>(
fetch: &mut ChangeTrackersFetch<'w, T>,
&id: &ComponentId,
table: &'w Table,
) {
fetch.table_ticks = Some(
table
.get_column(id)
.debug_checked_unwrap()
.get_ticks_slice()
.into(),
);
}
#[inline(always)]
unsafe fn fetch<'w>(
fetch: &mut Self::Fetch<'w>,
entity: Entity,
table_row: usize,
) -> Self::Item<'w> {
match T::Storage::STORAGE_TYPE {
StorageType::Table => ChangeTrackers {
component_ticks: {
let table_ticks = fetch.table_ticks.debug_checked_unwrap();
table_ticks.get(table_row).read()
},
marker: PhantomData,
last_change_tick: fetch.last_change_tick,
change_tick: fetch.change_tick,
},
StorageType::SparseSet => ChangeTrackers {
component_ticks: *fetch
.sparse_set
.debug_checked_unwrap()
.get_ticks(entity)
.debug_checked_unwrap()
.get(),
marker: PhantomData,
last_change_tick: fetch.last_change_tick,
change_tick: fetch.change_tick,
},
}
}
fn update_component_access(&id: &ComponentId, access: &mut FilteredAccess<ComponentId>) {
assert!(
!access.access().has_write(id),
"ChangeTrackers<{}> conflicts with a previous access in this query. Shared access cannot coincide with exclusive access.",
std::any::type_name::<T>()
);
access.add_read(id);
}
fn update_archetype_component_access(
&id: &ComponentId,
archetype: &Archetype,
access: &mut Access<ArchetypeComponentId>,
) {
if let Some(archetype_component_id) = archetype.get_archetype_component_id(id) {
access.add_read(archetype_component_id);
}
}
fn init_state(world: &mut World) -> ComponentId {
world.init_component::<T>()
}
fn matches_component_set(
&id: &ComponentId,
set_contains_id: &impl Fn(ComponentId) -> bool,
) -> bool {
set_contains_id(id)
}
}
/// SAFETY: access is read only
unsafe impl<T: Component> ReadOnlyWorldQuery for ChangeTrackers<T> {}
macro_rules! impl_tuple_fetch {
($(($name: ident, $state: ident)),*) => {
#[allow(non_snake_case)]
#[allow(clippy::unused_unit)]
// SAFETY: defers to soundness `$name: WorldQuery` impl
unsafe impl<$($name: WorldQuery),*> WorldQuery for ($($name,)*) {
type Fetch<'w> = ($($name::Fetch<'w>,)*);
type Item<'w> = ($($name::Item<'w>,)*);
type ReadOnly = ($($name::ReadOnly,)*);
type State = ($($name::State,)*);
fn shrink<'wlong: 'wshort, 'wshort>(item: Self::Item<'wlong>) -> Self::Item<'wshort> {
let ($($name,)*) = item;
($(
$name::shrink($name),
)*)
}
#[allow(clippy::unused_unit)]
unsafe fn init_fetch<'w>(_world: &'w World, state: &Self::State, _last_change_tick: u32, _change_tick: u32) -> Self::Fetch<'w> {
let ($($name,)*) = state;
($($name::init_fetch(_world, $name, _last_change_tick, _change_tick),)*)
}
unsafe fn clone_fetch<'w>(
fetch: &Self::Fetch<'w>,
) -> Self::Fetch<'w> {
let ($($name,)*) = &fetch;
($($name::clone_fetch($name),)*)
}
const IS_DENSE: bool = true $(&& $name::IS_DENSE)*;
const IS_ARCHETYPAL: bool = true $(&& $name::IS_ARCHETYPAL)*;
#[inline]
unsafe fn set_archetype<'w>(
_fetch: &mut Self::Fetch<'w>,
_state: &Self::State,
_archetype: &'w Archetype,
_table: &'w Table
) {
let ($($name,)*) = _fetch;
let ($($state,)*) = _state;
$($name::set_archetype($name, $state, _archetype, _table);)*
}
#[inline]
unsafe fn set_table<'w>(_fetch: &mut Self::Fetch<'w>, _state: &Self::State, _table: &'w Table) {
let ($($name,)*) = _fetch;
let ($($state,)*) = _state;
$($name::set_table($name, $state, _table);)*
}
#[inline(always)]
#[allow(clippy::unused_unit)]
unsafe fn fetch<'w>(
_fetch: &mut Self::Fetch<'w>,
_entity: Entity,
_table_row: usize
) -> Self::Item<'w> {
let ($($name,)*) = _fetch;
($($name::fetch($name, _entity, _table_row),)*)
}
#[inline(always)]
unsafe fn filter_fetch<'w>(
_fetch: &mut Self::Fetch<'w>,
_entity: Entity,
_table_row: usize
) -> bool {
let ($($name,)*) = _fetch;
true $(&& $name::filter_fetch($name, _entity, _table_row))*
}
fn update_component_access(state: &Self::State, _access: &mut FilteredAccess<ComponentId>) {
let ($($name,)*) = state;
$($name::update_component_access($name, _access);)*
}
fn update_archetype_component_access(state: &Self::State, _archetype: &Archetype, _access: &mut Access<ArchetypeComponentId>) {
let ($($name,)*) = state;
$($name::update_archetype_component_access($name, _archetype, _access);)*
}
fn init_state(_world: &mut World) -> Self::State {
($($name::init_state(_world),)*)
}
fn matches_component_set(state: &Self::State, _set_contains_id: &impl Fn(ComponentId) -> bool) -> bool {
let ($($name,)*) = state;
true $(&& $name::matches_component_set($name, _set_contains_id))*
}
}
/// SAFETY: each item in the tuple is read only
unsafe impl<$($name: ReadOnlyWorldQuery),*> ReadOnlyWorldQuery for ($($name,)*) {}
};
}
/// The `AnyOf` query parameter fetches entities with any of the component types included in T.
///
/// `Query<AnyOf<(&A, &B, &mut C)>>` is equivalent to `Query<(Option<&A>, Option<&B>, Option<&mut C>), Or<(With<A>, With<B>, With<C>)>>`.
/// Each of the components in `T` is returned as an `Option`, as with `Option<A>` queries.
/// Entities are guaranteed to have at least one of the components in `T`.
pub struct AnyOf<T>(PhantomData<T>);
macro_rules! impl_anytuple_fetch {
($(($name: ident, $state: ident)),*) => {
#[allow(non_snake_case)]
#[allow(clippy::unused_unit)]
// SAFETY: defers to soundness of `$name: WorldQuery` impl
unsafe impl<$($name: WorldQuery),*> WorldQuery for AnyOf<($($name,)*)> {
type Fetch<'w> = ($(($name::Fetch<'w>, bool),)*);
type Item<'w> = ($(Option<$name::Item<'w>>,)*);
type ReadOnly = AnyOf<($($name::ReadOnly,)*)>;
type State = ($($name::State,)*);
fn shrink<'wlong: 'wshort, 'wshort>(item: Self::Item<'wlong>) -> Self::Item<'wshort> {
let ($($name,)*) = item;
($(
$name.map($name::shrink),
)*)
}
#[allow(clippy::unused_unit)]
unsafe fn init_fetch<'w>(_world: &'w World, state: &Self::State, _last_change_tick: u32, _change_tick: u32) -> Self::Fetch<'w> {
let ($($name,)*) = state;
($(($name::init_fetch(_world, $name, _last_change_tick, _change_tick), false),)*)
}
unsafe fn clone_fetch<'w>(
fetch: &Self::Fetch<'w>,
) -> Self::Fetch<'w> {
let ($($name,)*) = &fetch;
($(($name::clone_fetch(& $name.0), $name.1),)*)
}
const IS_DENSE: bool = true $(&& $name::IS_DENSE)*;
const IS_ARCHETYPAL: bool = true $(&& $name::IS_ARCHETYPAL)*;
#[inline]
unsafe fn set_archetype<'w>(
_fetch: &mut Self::Fetch<'w>,
_state: &Self::State,
_archetype: &'w Archetype,
_table: &'w Table
) {
let ($($name,)*) = _fetch;
let ($($state,)*) = _state;
$(
$name.1 = $name::matches_component_set($state, &|id| _archetype.contains(id));
if $name.1 {
$name::set_archetype(&mut $name.0, $state, _archetype, _table);
}
)*
}
#[inline]
unsafe fn set_table<'w>(_fetch: &mut Self::Fetch<'w>, _state: &Self::State, _table: &'w Table) {
let ($($name,)*) = _fetch;
let ($($state,)*) = _state;
$(
$name.1 = $name::matches_component_set($state, &|id| _table.has_column(id));
if $name.1 {
$name::set_table(&mut $name.0, $state, _table);
}
)*
}
#[inline(always)]
#[allow(clippy::unused_unit)]
unsafe fn fetch<'w>(
_fetch: &mut Self::Fetch<'w>,
_entity: Entity,
_table_row: usize
) -> Self::Item<'w> {
let ($($name,)*) = _fetch;
($(
$name.1.then(|| $name::fetch(&mut $name.0, _entity, _table_row)),
)*)
}
fn update_component_access(state: &Self::State, _access: &mut FilteredAccess<ComponentId>) {
let ($($name,)*) = state;
// We do not unconditionally add `$name`'s `with`/`without` accesses to `_access`
// as this would be unsound. For example the following two queries should conflict:
// - Query<(AnyOf<(&A, ())>, &mut B)>
// - Query<&mut B, Without<A>>
//
// If we were to unconditionally add `$name`'s `with`/`without` accesses then `AnyOf<(&A, ())>`
// would have a `With<A>` access which is incorrect as this `WorldQuery` will match entities that
// do not have the `A` component. This is the same logic as the `Or<...>: WorldQuery` impl.
//
// The correct thing to do here is to only add a `with`/`without` access to `_access` if all
// `$name` params have that `with`/`without` access. More jargony put- we add the intersection
// of all `with`/`without` accesses of the `$name` params to `_access`.
let mut _intersected_access = _access.clone();
let mut _not_first = false;
$(
if _not_first {
let mut intermediate = _access.clone();
$name::update_component_access($name, &mut intermediate);
_intersected_access.extend_intersect_filter(&intermediate);
_intersected_access.extend_access(&intermediate);
} else {
$name::update_component_access($name, &mut _intersected_access);
_not_first = true;
}
)*
*_access = _intersected_access;
}
fn update_archetype_component_access(state: &Self::State, _archetype: &Archetype, _access: &mut Access<ArchetypeComponentId>) {
let ($($name,)*) = state;
$(
if $name::matches_component_set($name, &|id| _archetype.contains(id)) {
$name::update_archetype_component_access($name, _archetype, _access);
}
)*
}
fn init_state(_world: &mut World) -> Self::State {
($($name::init_state(_world),)*)
}
fn matches_component_set(_state: &Self::State, _set_contains_id: &impl Fn(ComponentId) -> bool) -> bool {
let ($($name,)*) = _state;
false $(|| $name::matches_component_set($name, _set_contains_id))*
}
}
/// SAFETY: each item in the tuple is read only
unsafe impl<$($name: ReadOnlyWorldQuery),*> ReadOnlyWorldQuery for AnyOf<($($name,)*)> {}
};
}
all_tuples!(impl_tuple_fetch, 0, 15, F, S);
all_tuples!(impl_anytuple_fetch, 0, 15, F, S);
/// [`WorldQuery`] used to nullify queries by turning `Query<Q>` into `Query<NopWorldQuery<Q>>`
///
/// This will rarely be useful to consumers of `bevy_ecs`.
pub struct NopWorldQuery<Q: WorldQuery>(PhantomData<Q>);
/// SAFETY: `Self::ReadOnly` is `Self`
unsafe impl<Q: WorldQuery> WorldQuery for NopWorldQuery<Q> {
type Fetch<'w> = ();
type Item<'w> = ();
type ReadOnly = Self;
type State = Q::State;
fn shrink<'wlong: 'wshort, 'wshort>(_: ()) {}
const IS_DENSE: bool = Q::IS_DENSE;
const IS_ARCHETYPAL: bool = true;
#[inline(always)]
unsafe fn init_fetch(
_world: &World,
_state: &Q::State,
_last_change_tick: u32,
_change_tick: u32,
) {
}
unsafe fn clone_fetch<'w>(_fetch: &Self::Fetch<'w>) -> Self::Fetch<'w> {}
#[inline(always)]
unsafe fn set_archetype(
_fetch: &mut (),
_state: &Q::State,
_archetype: &Archetype,
_tables: &Table,
) {
}
#[inline(always)]
unsafe fn set_table<'w>(_fetch: &mut (), _state: &Q::State, _table: &Table) {}
#[inline(always)]
unsafe fn fetch<'w>(
_fetch: &mut Self::Fetch<'w>,
_entity: Entity,
_table_row: usize,
) -> Self::Item<'w> {
}
fn update_component_access(_state: &Q::State, _access: &mut FilteredAccess<ComponentId>) {}
fn update_archetype_component_access(
_state: &Q::State,
_archetype: &Archetype,
_access: &mut Access<ArchetypeComponentId>,
) {
}
fn init_state(world: &mut World) -> Self::State {
Q::init_state(world)
}
fn matches_component_set(
state: &Self::State,
set_contains_id: &impl Fn(ComponentId) -> bool,
) -> bool {
Q::matches_component_set(state, set_contains_id)
}
}
/// SAFETY: `NopFetch` never accesses any data
unsafe impl<Q: WorldQuery> ReadOnlyWorldQuery for NopWorldQuery<Q> {}