use core::marker::PhantomData;
use bevy::ecs::archetype::Archetype;
use bevy::ecs::query::{FilteredAccess, QueryData, ReadOnlyQueryData, WorldQuery};
use bevy::ecs::storage::Table;
use bevy::ecs::world::World;
use bevy::ecs::world::unsafe_world_cell::UnsafeWorldCell;
#[derive(Debug)]
pub struct ModQ<T>(PhantomData<T>);
#[derive(Debug)]
pub struct ModQMut<T>(PhantomData<T>);
pub trait ModQuery {
type FromQuery: ReadOnlyQueryData;
type ModItem<'q, 'r>;
fn modify_reference<'w, 's>(
from: <Self::FromQuery as QueryData>::Item<'w, 's>,
) -> Self::ModItem<'w, 's>;
fn shrink<'wlong: 'wshort, 'wshort, 's>(
item: Self::ModItem<'wlong, 's>,
) -> Self::ModItem<'wshort, 's>;
}
pub trait ModQueryMut {
type FromQuery: QueryData;
type ModItem<'q, 'r>;
type ReadOnly: ReadOnlyQueryData<
State = <<Self as ModQueryMut>::FromQuery as WorldQuery>::State,
>;
fn modify_reference<'w, 's>(
from: <Self::FromQuery as QueryData>::Item<'w, 's>,
) -> Self::ModItem<'w, 's>;
fn shrink<'wlong: 'wshort, 'wshort, 's>(
item: Self::ModItem<'wlong, 's>,
) -> Self::ModItem<'wshort, 's>;
}
unsafe impl<T: ModQuery> QueryData for ModQ<T> {
type ReadOnly = Self;
type Item<'w, 's> = T::ModItem<'w, 's>;
const IS_READ_ONLY: bool = true;
const IS_ARCHETYPAL: bool = <T::FromQuery as QueryData>::IS_ARCHETYPAL;
fn shrink<'wlong: 'wshort, 'wshort, 's>(
item: Self::Item<'wlong, 's>,
) -> Self::Item<'wshort, 's> {
T::shrink(item)
}
fn iter_access(state: &Self::State) -> impl Iterator<Item = bevy::ecs::query::EcsAccessType<'_>> {
<T::FromQuery as QueryData>::iter_access(state)
}
unsafe fn fetch<'w, 's>(
state: &'s Self::State,
fetch: &mut Self::Fetch<'w>,
entity: bevy::prelude::Entity,
table_row: bevy::ecs::storage::TableRow,
) -> Option<Self::Item<'w, 's>> {
unsafe {
(<T::FromQuery as QueryData>::fetch(
state, fetch, entity, table_row,
)).map(T::modify_reference)
}
}
}
unsafe impl<T: ModQuery> WorldQuery for ModQ<T> {
type Fetch<'w> = <T::FromQuery as WorldQuery>::Fetch<'w>;
type State = <T::FromQuery as WorldQuery>::State;
const IS_DENSE: bool = <T::FromQuery>::IS_DENSE;
#[inline]
unsafe fn init_fetch<'w>(
world: UnsafeWorldCell<'w>,
state: &Self::State,
last_run: bevy::ecs::change_detection::Tick,
this_run: bevy::ecs::change_detection::Tick,
) -> Self::Fetch<'w> {
unsafe { <T::FromQuery as WorldQuery>::init_fetch(world, state, last_run, this_run) }
}
#[inline]
unsafe fn set_archetype<'w>(
fetch: &mut Self::Fetch<'w>,
state: &Self::State,
archetype: &'w Archetype,
table: &'w Table,
) {
unsafe {
<T::FromQuery as WorldQuery>::set_archetype(fetch, state, archetype, table);
}
}
unsafe fn set_table<'w>(fetch: &mut Self::Fetch<'w>, state: &Self::State, table: &'w Table) {
unsafe {
<T::FromQuery as WorldQuery>::set_table(fetch, state, table);
}
}
fn shrink_fetch<'wlong: 'wshort, 'wshort>(fetch: Self::Fetch<'wlong>) -> Self::Fetch<'wshort> {
<T::FromQuery as WorldQuery>::shrink_fetch(fetch)
}
fn update_component_access(state: &Self::State, access: &mut FilteredAccess) {
<T::FromQuery as WorldQuery>::update_component_access(state, access)
}
fn init_state(world: &mut World) -> Self::State {
<T::FromQuery as WorldQuery>::init_state(world)
}
fn matches_component_set(
state: &Self::State,
set_contains_id: &impl Fn(bevy::ecs::component::ComponentId) -> bool,
) -> bool {
<T::FromQuery as WorldQuery>::matches_component_set(state, set_contains_id)
}
fn get_state(components: &bevy::ecs::component::Components) -> Option<Self::State> {
<T::FromQuery as WorldQuery>::get_state(components)
}
}
unsafe impl<T: ModQuery> ReadOnlyQueryData for ModQ<T> {}
unsafe impl<T: ModQueryMut> WorldQuery for ModQMut<T> {
type Fetch<'w> = <T::FromQuery as WorldQuery>::Fetch<'w>;
type State = <T::FromQuery as WorldQuery>::State;
const IS_DENSE: bool = <T::FromQuery>::IS_DENSE;
#[inline]
unsafe fn init_fetch<'w>(
world: UnsafeWorldCell<'w>,
state: &Self::State,
last_run: bevy::ecs::change_detection::Tick,
this_run: bevy::ecs::change_detection::Tick,
) -> Self::Fetch<'w> {
unsafe { <T::FromQuery as WorldQuery>::init_fetch(world, state, last_run, this_run) }
}
#[inline]
unsafe fn set_archetype<'w>(
fetch: &mut Self::Fetch<'w>,
state: &Self::State,
archetype: &'w Archetype,
table: &'w Table,
) {
unsafe {
<T::FromQuery as WorldQuery>::set_archetype(fetch, state, archetype, table);
}
}
unsafe fn set_table<'w>(fetch: &mut Self::Fetch<'w>, state: &Self::State, table: &'w Table) {
unsafe {
<T::FromQuery as WorldQuery>::set_table(fetch, state, table);
}
}
fn shrink_fetch<'wlong: 'wshort, 'wshort>(fetch: Self::Fetch<'wlong>) -> Self::Fetch<'wshort> {
<T::FromQuery as WorldQuery>::shrink_fetch(fetch)
}
fn update_component_access(state: &Self::State, access: &mut FilteredAccess) {
<T::FromQuery as WorldQuery>::update_component_access(state, access)
}
fn init_state(world: &mut World) -> Self::State {
<T::FromQuery as WorldQuery>::init_state(world)
}
fn matches_component_set(
state: &Self::State,
set_contains_id: &impl Fn(bevy::ecs::component::ComponentId) -> bool,
) -> bool {
<T::FromQuery as WorldQuery>::matches_component_set(state, set_contains_id)
}
fn get_state(components: &bevy::ecs::component::Components) -> Option<Self::State> {
<T::FromQuery as WorldQuery>::get_state(components)
}
}
unsafe impl<T: ModQueryMut> QueryData for ModQMut<T> {
type ReadOnly = T::ReadOnly;
type Item<'w, 's> = T::ModItem<'w, 's>;
const IS_ARCHETYPAL: bool = T::FromQuery::IS_ARCHETYPAL;
const IS_READ_ONLY: bool = T::FromQuery::IS_READ_ONLY;
fn shrink<'wlong: 'wshort, 'wshort, 's>(
item: Self::Item<'wlong, 's>,
) -> Self::Item<'wshort, 's> {
T::shrink(item)
}
fn iter_access(state: &Self::State) -> impl Iterator<Item = bevy::ecs::query::EcsAccessType<'_>> {
T::FromQuery::iter_access(state)
}
unsafe fn fetch<'w, 's>(
state: &'s Self::State,
fetch: &mut Self::Fetch<'w>,
entity: bevy::prelude::Entity,
table_row: bevy::ecs::storage::TableRow,
) -> Option<Self::Item<'w, 's>> {
unsafe {
(<T::FromQuery as QueryData>::fetch(
state, fetch, entity, table_row,
)).map(T::modify_reference)
}
}
}