use crate::{
archetype::Archetype,
change_detection::Tick,
component::{Component, ComponentId, Components, StorageType},
entity::{Entities, Entity},
query::{DebugCheckedUnwrap, FilteredAccess, StorageSwitch, WorldQuery},
storage::{ComponentSparseSet, Table, TableRow},
world::{unsafe_world_cell::UnsafeWorldCell, World},
};
use bevy_ptr::{ThinSlicePtr, UnsafeCellDeref};
use bevy_utils::prelude::DebugName;
use core::{cell::UnsafeCell, marker::PhantomData};
use variadics_please::all_tuples;
#[diagnostic::on_unimplemented(
message = "`{Self}` is not a valid `Query` filter",
label = "invalid `Query` filter",
note = "a `QueryFilter` typically uses a combination of `With<T>` and `Without<T>` statements"
)]
pub unsafe trait QueryFilter: WorldQuery {
const IS_ARCHETYPAL: bool;
unsafe fn filter_fetch(
state: &Self::State,
fetch: &mut Self::Fetch<'_>,
entity: Entity,
table_row: TableRow,
) -> bool;
}
pub struct With<T>(PhantomData<T>);
unsafe impl<T: Component> WorldQuery for With<T> {
type Fetch<'w> = ();
type State = ComponentId;
fn shrink_fetch<'wlong: 'wshort, 'wshort>(_: Self::Fetch<'wlong>) -> Self::Fetch<'wshort> {}
#[inline]
unsafe fn init_fetch(
_world: UnsafeWorldCell,
_state: &ComponentId,
_last_run: Tick,
_this_run: Tick,
) {
}
const IS_DENSE: bool = {
match T::STORAGE_TYPE {
StorageType::Table => true,
StorageType::SparseSet => false,
}
};
#[inline]
unsafe fn set_archetype(
_fetch: &mut (),
_state: &ComponentId,
_archetype: &Archetype,
_table: &Table,
) {
}
#[inline]
unsafe fn set_table(_fetch: &mut (), _state: &ComponentId, _table: &Table) {}
#[inline]
fn update_component_access(&id: &ComponentId, access: &mut FilteredAccess) {
access.and_with(id);
}
fn init_state(world: &mut World) -> ComponentId {
world.register_component::<T>()
}
fn get_state(components: &Components) -> Option<Self::State> {
components.component_id::<T>()
}
fn matches_component_set(
&id: &ComponentId,
set_contains_id: &impl Fn(ComponentId) -> bool,
) -> bool {
set_contains_id(id)
}
}
unsafe impl<T: Component> QueryFilter for With<T> {
const IS_ARCHETYPAL: bool = true;
#[inline(always)]
unsafe fn filter_fetch(
_state: &Self::State,
_fetch: &mut Self::Fetch<'_>,
_entity: Entity,
_table_row: TableRow,
) -> bool {
true
}
}
pub struct Without<T>(PhantomData<T>);
unsafe impl<T: Component> WorldQuery for Without<T> {
type Fetch<'w> = ();
type State = ComponentId;
fn shrink_fetch<'wlong: 'wshort, 'wshort>(_: Self::Fetch<'wlong>) -> Self::Fetch<'wshort> {}
#[inline]
unsafe fn init_fetch(
_world: UnsafeWorldCell,
_state: &ComponentId,
_last_run: Tick,
_this_run: Tick,
) {
}
const IS_DENSE: bool = {
match T::STORAGE_TYPE {
StorageType::Table => true,
StorageType::SparseSet => false,
}
};
#[inline]
unsafe fn set_archetype(
_fetch: &mut (),
_state: &ComponentId,
_archetype: &Archetype,
_table: &Table,
) {
}
#[inline]
unsafe fn set_table(_fetch: &mut (), _state: &Self::State, _table: &Table) {}
#[inline]
fn update_component_access(&id: &ComponentId, access: &mut FilteredAccess) {
access.and_without(id);
}
fn init_state(world: &mut World) -> ComponentId {
world.register_component::<T>()
}
fn get_state(components: &Components) -> Option<Self::State> {
components.component_id::<T>()
}
fn matches_component_set(
&id: &ComponentId,
set_contains_id: &impl Fn(ComponentId) -> bool,
) -> bool {
!set_contains_id(id)
}
}
unsafe impl<T: Component> QueryFilter for Without<T> {
const IS_ARCHETYPAL: bool = true;
#[inline(always)]
unsafe fn filter_fetch(
_state: &Self::State,
_fetch: &mut Self::Fetch<'_>,
_entity: Entity,
_table_row: TableRow,
) -> bool {
true
}
}
pub struct Or<T>(PhantomData<T>);
#[doc(hidden)]
pub struct OrFetch<'w, T: WorldQuery> {
fetch: T::Fetch<'w>,
matches: bool,
}
impl<T: WorldQuery> Clone for OrFetch<'_, T> {
fn clone(&self) -> Self {
Self {
fetch: self.fetch.clone(),
matches: self.matches,
}
}
}
macro_rules! impl_or_query_filter {
($(#[$meta:meta])* $(($filter: ident, $state: ident)),*) => {
$(#[$meta])*
#[expect(
clippy::allow_attributes,
reason = "This is a tuple-related macro; as such the lints below may not always apply."
)]
#[allow(
non_snake_case,
reason = "The names of some variables are provided by the macro's caller, not by us."
)]
#[allow(
unused_variables,
reason = "Zero-length tuples won't use any of the parameters."
)]
#[allow(
clippy::unused_unit,
reason = "Zero-length tuples will generate some function bodies equivalent to `()`; however, this macro is meant for all applicable tuples, and as such it makes no sense to rewrite it just for that case."
)]
unsafe impl<$($filter: QueryFilter),*> WorldQuery for Or<($($filter,)*)> {
type Fetch<'w> = ($(OrFetch<'w, $filter>,)*);
type State = ($($filter::State,)*);
fn shrink_fetch<'wlong: 'wshort, 'wshort>(fetch: Self::Fetch<'wlong>) -> Self::Fetch<'wshort> {
let ($($filter,)*) = fetch;
($(
OrFetch {
fetch: $filter::shrink_fetch($filter.fetch),
matches: $filter.matches
},
)*)
}
const IS_DENSE: bool = true $(&& $filter::IS_DENSE)*;
#[inline]
unsafe fn init_fetch<'w, 's>(world: UnsafeWorldCell<'w>, state: &'s Self::State, last_run: Tick, this_run: Tick) -> Self::Fetch<'w> {
let ($($filter,)*) = state;
($(OrFetch {
fetch: unsafe { $filter::init_fetch(world, $filter, last_run, this_run) },
matches: false,
},)*)
}
#[inline]
unsafe fn set_table<'w, 's>(fetch: &mut Self::Fetch<'w>, state: &'s Self::State, table: &'w Table) {
if Self::IS_ARCHETYPAL {
return;
}
let ($($filter,)*) = fetch;
let ($($state,)*) = state;
$(
$filter.matches = $filter::matches_component_set($state, &|id| table.has_column(id));
if $filter.matches {
unsafe { $filter::set_table(&mut $filter.fetch, $state, table); }
}
)*
}
#[inline]
unsafe fn set_archetype<'w, 's>(
fetch: &mut Self::Fetch<'w>,
state: &'s Self::State,
archetype: &'w Archetype,
table: &'w Table
) {
if Self::IS_ARCHETYPAL {
return;
}
let ($($filter,)*) = fetch;
let ($($state,)*) = &state;
$(
$filter.matches = $filter::matches_component_set($state, &|id| archetype.contains(id));
if $filter.matches {
unsafe { $filter::set_archetype(&mut $filter.fetch, $state, archetype, table); }
}
)*
}
fn update_component_access(state: &Self::State, access: &mut FilteredAccess) {
let ($($filter,)*) = state;
let mut new_access = FilteredAccess::matches_nothing();
$(
let mut intermediate = access.clone();
$filter::update_component_access($filter, &mut intermediate);
new_access.append_or(&intermediate);
new_access.extend_access(&intermediate);
)*
new_access.required = core::mem::take(&mut access.required);
*access = new_access;
}
fn init_state(world: &mut World) -> Self::State {
($($filter::init_state(world),)*)
}
fn get_state(components: &Components) -> Option<Self::State> {
Some(($($filter::get_state(components)?,)*))
}
fn matches_component_set(state: &Self::State, set_contains_id: &impl Fn(ComponentId) -> bool) -> bool {
let ($($filter,)*) = state;
false $(|| $filter::matches_component_set($filter, set_contains_id))*
}
}
#[expect(
clippy::allow_attributes,
reason = "This is a tuple-related macro; as such the lints below may not always apply."
)]
#[allow(
non_snake_case,
reason = "The names of some variables are provided by the macro's caller, not by us."
)]
#[allow(
unused_variables,
reason = "Zero-length tuples won't use any of the parameters."
)]
$(#[$meta])*
unsafe impl<$($filter: QueryFilter),*> QueryFilter for Or<($($filter,)*)> {
const IS_ARCHETYPAL: bool = true $(&& $filter::IS_ARCHETYPAL)*;
#[inline(always)]
unsafe fn filter_fetch(
state: &Self::State,
fetch: &mut Self::Fetch<'_>,
entity: Entity,
table_row: TableRow
) -> bool {
let ($($state,)*) = state;
let ($($filter,)*) = fetch;
(Self::IS_ARCHETYPAL
$(|| ($filter.matches && unsafe { $filter::filter_fetch($state, &mut $filter.fetch, entity, table_row) }))*
|| !(false $(|| $filter.matches)*))
}
}
};
}
macro_rules! impl_tuple_query_filter {
($(#[$meta:meta])* $(($name: ident, $state: ident)),*) => {
#[expect(
clippy::allow_attributes,
reason = "This is a tuple-related macro; as such the lints below may not always apply."
)]
#[allow(
non_snake_case,
reason = "The names of some variables are provided by the macro's caller, not by us."
)]
#[allow(
unused_variables,
reason = "Zero-length tuples won't use any of the parameters."
)]
$(#[$meta])*
unsafe impl<$($name: QueryFilter),*> QueryFilter for ($($name,)*) {
const IS_ARCHETYPAL: bool = true $(&& $name::IS_ARCHETYPAL)*;
#[inline(always)]
unsafe fn filter_fetch(
state: &Self::State,
fetch: &mut Self::Fetch<'_>,
entity: Entity,
table_row: TableRow
) -> bool {
let ($($state,)*) = state;
let ($($name,)*) = fetch;
true $(&& unsafe { $name::filter_fetch($state, $name, entity, table_row) })*
}
}
};
}
all_tuples!(
#[doc(fake_variadic)]
impl_tuple_query_filter,
0,
15,
F,
S
);
all_tuples!(
#[doc(fake_variadic)]
impl_or_query_filter,
0,
15,
F,
S
);
pub struct Allow<T>(PhantomData<T>);
unsafe impl<T: Component> WorldQuery for Allow<T> {
type Fetch<'w> = ();
type State = ComponentId;
fn shrink_fetch<'wlong: 'wshort, 'wshort>(_: Self::Fetch<'wlong>) -> Self::Fetch<'wshort> {}
#[inline]
unsafe fn init_fetch(_: UnsafeWorldCell, _: &ComponentId, _: Tick, _: Tick) {}
const IS_DENSE: bool = true;
#[inline]
unsafe fn set_archetype(_: &mut (), _: &ComponentId, _: &Archetype, _: &Table) {}
#[inline]
unsafe fn set_table(_: &mut (), _: &ComponentId, _: &Table) {}
#[inline]
fn update_component_access(&id: &ComponentId, access: &mut FilteredAccess) {
access.access_mut().add_archetypal(id);
}
fn init_state(world: &mut World) -> ComponentId {
world.register_component::<T>()
}
fn get_state(components: &Components) -> Option<Self::State> {
components.component_id::<T>()
}
fn matches_component_set(_: &ComponentId, _: &impl Fn(ComponentId) -> bool) -> bool {
true
}
}
unsafe impl<T: Component> QueryFilter for Allow<T> {
const IS_ARCHETYPAL: bool = true;
#[inline(always)]
unsafe fn filter_fetch(
_: &Self::State,
_: &mut Self::Fetch<'_>,
_: Entity,
_: TableRow,
) -> bool {
true
}
}
pub struct Added<T>(PhantomData<T>);
#[doc(hidden)]
pub struct AddedFetch<'w, T: Component> {
ticks: StorageSwitch<
T,
Option<ThinSlicePtr<'w, UnsafeCell<Tick>>>,
Option<&'w ComponentSparseSet>,
>,
last_run: Tick,
this_run: Tick,
}
impl<T: Component> Clone for AddedFetch<'_, T> {
fn clone(&self) -> Self {
Self {
ticks: self.ticks,
last_run: self.last_run,
this_run: self.this_run,
}
}
}
unsafe impl<T: Component> WorldQuery for Added<T> {
type Fetch<'w> = AddedFetch<'w, T>;
type State = ComponentId;
fn shrink_fetch<'wlong: 'wshort, 'wshort>(fetch: Self::Fetch<'wlong>) -> Self::Fetch<'wshort> {
fetch
}
#[inline]
unsafe fn init_fetch<'w, 's>(
world: UnsafeWorldCell<'w>,
&id: &'s ComponentId,
last_run: Tick,
this_run: Tick,
) -> Self::Fetch<'w> {
Self::Fetch::<'w> {
ticks: StorageSwitch::new(
|| None,
|| {
unsafe { world.storages().sparse_sets.get(id) }
},
),
last_run,
this_run,
}
}
const IS_DENSE: bool = {
match T::STORAGE_TYPE {
StorageType::Table => true,
StorageType::SparseSet => false,
}
};
#[inline]
unsafe fn set_archetype<'w, 's>(
fetch: &mut Self::Fetch<'w>,
component_id: &'s ComponentId,
_archetype: &'w Archetype,
table: &'w Table,
) {
if Self::IS_DENSE {
unsafe {
Self::set_table(fetch, component_id, table);
}
}
}
#[inline]
unsafe fn set_table<'w, 's>(
fetch: &mut Self::Fetch<'w>,
&component_id: &'s ComponentId,
table: &'w Table,
) {
let table_ticks = Some(
table
.get_added_ticks_slice_for(component_id)
.debug_checked_unwrap()
.into(),
);
unsafe { fetch.ticks.set_table(table_ticks) };
}
#[inline]
fn update_component_access(&id: &ComponentId, access: &mut FilteredAccess) {
if access.access().has_component_write(id) {
panic!("$state_name<{}> conflicts with a previous access in this query. Shared access cannot coincide with exclusive access.", DebugName::type_name::<T>());
}
access.add_component_read(id);
}
fn init_state(world: &mut World) -> ComponentId {
world.register_component::<T>()
}
fn get_state(components: &Components) -> Option<ComponentId> {
components.component_id::<T>()
}
fn matches_component_set(
&id: &ComponentId,
set_contains_id: &impl Fn(ComponentId) -> bool,
) -> bool {
set_contains_id(id)
}
}
unsafe impl<T: Component> QueryFilter for Added<T> {
const IS_ARCHETYPAL: bool = false;
#[inline(always)]
unsafe fn filter_fetch(
_state: &Self::State,
fetch: &mut Self::Fetch<'_>,
entity: Entity,
table_row: TableRow,
) -> bool {
fetch.ticks.extract(
|table| {
let table = unsafe { table.debug_checked_unwrap() };
let tick = unsafe { table.get_unchecked(table_row.index()) };
tick.deref().is_newer_than(fetch.last_run, fetch.this_run)
},
|sparse_set| {
let tick = unsafe {
sparse_set
.debug_checked_unwrap()
.get_added_tick(entity)
.debug_checked_unwrap()
};
tick.deref().is_newer_than(fetch.last_run, fetch.this_run)
},
)
}
}
pub struct Changed<T>(PhantomData<T>);
#[doc(hidden)]
pub struct ChangedFetch<'w, T: Component> {
ticks: StorageSwitch<
T,
Option<ThinSlicePtr<'w, UnsafeCell<Tick>>>,
Option<&'w ComponentSparseSet>,
>,
last_run: Tick,
this_run: Tick,
}
impl<T: Component> Clone for ChangedFetch<'_, T> {
fn clone(&self) -> Self {
Self {
ticks: self.ticks,
last_run: self.last_run,
this_run: self.this_run,
}
}
}
unsafe impl<T: Component> WorldQuery for Changed<T> {
type Fetch<'w> = ChangedFetch<'w, T>;
type State = ComponentId;
fn shrink_fetch<'wlong: 'wshort, 'wshort>(fetch: Self::Fetch<'wlong>) -> Self::Fetch<'wshort> {
fetch
}
#[inline]
unsafe fn init_fetch<'w, 's>(
world: UnsafeWorldCell<'w>,
&id: &'s ComponentId,
last_run: Tick,
this_run: Tick,
) -> Self::Fetch<'w> {
Self::Fetch::<'w> {
ticks: StorageSwitch::new(
|| None,
|| {
unsafe { world.storages().sparse_sets.get(id) }
},
),
last_run,
this_run,
}
}
const IS_DENSE: bool = {
match T::STORAGE_TYPE {
StorageType::Table => true,
StorageType::SparseSet => false,
}
};
#[inline]
unsafe fn set_archetype<'w, 's>(
fetch: &mut Self::Fetch<'w>,
component_id: &'s ComponentId,
_archetype: &'w Archetype,
table: &'w Table,
) {
if Self::IS_DENSE {
unsafe {
Self::set_table(fetch, component_id, table);
}
}
}
#[inline]
unsafe fn set_table<'w, 's>(
fetch: &mut Self::Fetch<'w>,
&component_id: &'s ComponentId,
table: &'w Table,
) {
let table_ticks = Some(
table
.get_changed_ticks_slice_for(component_id)
.debug_checked_unwrap()
.into(),
);
unsafe { fetch.ticks.set_table(table_ticks) };
}
#[inline]
fn update_component_access(&id: &ComponentId, access: &mut FilteredAccess) {
if access.access().has_component_write(id) {
panic!("$state_name<{}> conflicts with a previous access in this query. Shared access cannot coincide with exclusive access.", DebugName::type_name::<T>());
}
access.add_component_read(id);
}
fn init_state(world: &mut World) -> ComponentId {
world.register_component::<T>()
}
fn get_state(components: &Components) -> Option<ComponentId> {
components.component_id::<T>()
}
fn matches_component_set(
&id: &ComponentId,
set_contains_id: &impl Fn(ComponentId) -> bool,
) -> bool {
set_contains_id(id)
}
}
unsafe impl<T: Component> QueryFilter for Changed<T> {
const IS_ARCHETYPAL: bool = false;
#[inline(always)]
unsafe fn filter_fetch(
_state: &Self::State,
fetch: &mut Self::Fetch<'_>,
entity: Entity,
table_row: TableRow,
) -> bool {
fetch.ticks.extract(
|table| {
let table = unsafe { table.debug_checked_unwrap() };
let tick = unsafe { table.get_unchecked(table_row.index()) };
tick.deref().is_newer_than(fetch.last_run, fetch.this_run)
},
|sparse_set| {
let tick = unsafe {
sparse_set
.debug_checked_unwrap()
.get_changed_tick(entity)
.debug_checked_unwrap()
};
tick.deref().is_newer_than(fetch.last_run, fetch.this_run)
},
)
}
}
pub struct Spawned;
#[doc(hidden)]
#[derive(Clone)]
pub struct SpawnedFetch<'w> {
entities: &'w Entities,
last_run: Tick,
this_run: Tick,
}
unsafe impl WorldQuery for Spawned {
type Fetch<'w> = SpawnedFetch<'w>;
type State = ();
fn shrink_fetch<'wlong: 'wshort, 'wshort>(fetch: Self::Fetch<'wlong>) -> Self::Fetch<'wshort> {
fetch
}
#[inline]
unsafe fn init_fetch<'w, 's>(
world: UnsafeWorldCell<'w>,
_state: &'s (),
last_run: Tick,
this_run: Tick,
) -> Self::Fetch<'w> {
SpawnedFetch {
entities: world.entities(),
last_run,
this_run,
}
}
const IS_DENSE: bool = true;
#[inline]
unsafe fn set_archetype<'w, 's>(
_fetch: &mut Self::Fetch<'w>,
_state: &'s (),
_archetype: &'w Archetype,
_table: &'w Table,
) {
}
#[inline]
unsafe fn set_table<'w, 's>(_fetch: &mut Self::Fetch<'w>, _state: &'s (), _table: &'w Table) {}
#[inline]
fn update_component_access(_state: &(), _access: &mut FilteredAccess) {}
fn init_state(_world: &mut World) {}
fn get_state(_components: &Components) -> Option<()> {
Some(())
}
fn matches_component_set(_state: &(), _set_contains_id: &impl Fn(ComponentId) -> bool) -> bool {
true
}
}
unsafe impl QueryFilter for Spawned {
const IS_ARCHETYPAL: bool = false;
#[inline(always)]
unsafe fn filter_fetch(
_state: &Self::State,
fetch: &mut Self::Fetch<'_>,
entity: Entity,
_table_row: TableRow,
) -> bool {
let spawned = unsafe {
fetch
.entities
.entity_get_spawned_or_despawned_unchecked(entity)
.1
};
spawned.is_newer_than(fetch.last_run, fetch.this_run)
}
}
#[diagnostic::on_unimplemented(
message = "`{Self}` is not a valid `Query` filter based on archetype information",
label = "invalid `Query` filter",
note = "an `ArchetypeFilter` typically uses a combination of `With<T>` and `Without<T>` statements"
)]
pub trait ArchetypeFilter: QueryFilter {}
impl<T: Component> ArchetypeFilter for With<T> {}
impl<T: Component> ArchetypeFilter for Without<T> {}
macro_rules! impl_archetype_filter_tuple {
($(#[$meta:meta])* $($filter: ident),*) => {
$(#[$meta])*
impl<$($filter: ArchetypeFilter),*> ArchetypeFilter for ($($filter,)*) {}
};
}
macro_rules! impl_archetype_or_filter_tuple {
($(#[$meta:meta])* $($filter: ident),*) => {
$(#[$meta])*
impl<$($filter: ArchetypeFilter),*> ArchetypeFilter for Or<($($filter,)*)> {}
};
}
all_tuples!(
#[doc(fake_variadic)]
impl_archetype_filter_tuple,
0,
15,
F
);
all_tuples!(
#[doc(fake_variadic)]
impl_archetype_or_filter_tuple,
0,
15,
F
);