use crate::{
archetype::Archetype,
change_detection::Tick,
component::{ComponentId, Components},
query::FilteredAccess,
storage::Table,
world::{unsafe_world_cell::UnsafeWorldCell, World},
};
use variadics_please::all_tuples;
pub unsafe trait WorldQuery {
type Fetch<'w>: Clone;
type State: Send + Sync + Sized;
fn shrink_fetch<'wlong: 'wshort, 'wshort>(fetch: Self::Fetch<'wlong>) -> Self::Fetch<'wshort>;
unsafe fn init_fetch<'w, 's>(
world: UnsafeWorldCell<'w>,
state: &'s Self::State,
last_run: Tick,
this_run: Tick,
) -> Self::Fetch<'w>;
const IS_DENSE: bool;
unsafe fn set_archetype<'w, 's>(
fetch: &mut Self::Fetch<'w>,
state: &'s Self::State,
archetype: &'w Archetype,
table: &'w Table,
);
unsafe fn set_table<'w, 's>(
fetch: &mut Self::Fetch<'w>,
state: &'s Self::State,
table: &'w Table,
);
fn update_component_access(state: &Self::State, access: &mut FilteredAccess);
fn init_state(world: &mut World) -> Self::State;
fn get_state(components: &Components) -> Option<Self::State>;
fn matches_component_set(
state: &Self::State,
set_contains_id: &impl Fn(ComponentId) -> bool,
) -> bool;
}
macro_rules! impl_tuple_world_query {
($(#[$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."
)]
#[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."
)]
$(#[$meta])*
unsafe impl<$($name: WorldQuery),*> WorldQuery for ($($name,)*) {
type Fetch<'w> = ($($name::Fetch<'w>,)*);
type State = ($($name::State,)*);
fn shrink_fetch<'wlong: 'wshort, 'wshort>(fetch: Self::Fetch<'wlong>) -> Self::Fetch<'wshort> {
let ($($name,)*) = fetch;
($(
$name::shrink_fetch($name),
)*)
}
#[inline]
unsafe fn init_fetch<'w, 's>(world: UnsafeWorldCell<'w>, state: &'s Self::State, last_run: Tick, this_run: Tick) -> Self::Fetch<'w> {
let ($($name,)*) = state;
($(unsafe { $name::init_fetch(world, $name, last_run, this_run) },)*)
}
const IS_DENSE: bool = true $(&& $name::IS_DENSE)*;
#[inline]
unsafe fn set_archetype<'w, 's>(
fetch: &mut Self::Fetch<'w>,
state: &'s Self::State,
archetype: &'w Archetype,
table: &'w Table
) {
let ($($name,)*) = fetch;
let ($($state,)*) = state;
$(unsafe { $name::set_archetype($name, $state, archetype, table); })*
}
#[inline]
unsafe fn set_table<'w, 's>(fetch: &mut Self::Fetch<'w>, state: &'s Self::State, table: &'w Table) {
let ($($name,)*) = fetch;
let ($($state,)*) = state;
$(unsafe { $name::set_table($name, $state, table); })*
}
fn update_component_access(state: &Self::State, access: &mut FilteredAccess) {
let ($($name,)*) = state;
$($name::update_component_access($name, access);)*
}
fn init_state(world: &mut World) -> Self::State {
($($name::init_state(world),)*)
}
fn get_state(components: &Components) -> Option<Self::State> {
Some(($($name::get_state(components)?,)*))
}
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))*
}
}
};
}
all_tuples!(
#[doc(fake_variadic)]
impl_tuple_world_query,
0,
15,
F,
S
);