bevy_trait_query/one/impls/
one_changed.rsuse bevy_ecs::ptr::UnsafeCellDeref;
use std::marker::PhantomData;
use bevy_ecs::{
archetype::Archetype,
component::{ComponentId, Components, Tick},
prelude::{Entity, World},
query::{FilteredAccess, QueryData, QueryFilter, ReadOnlyQueryData, WorldQuery},
storage::{Table, TableRow},
world::unsafe_world_cell::UnsafeWorldCell,
};
use crate::{debug_unreachable, TraitQuery, TraitQueryState};
use crate::{ChangeDetectionFetch, ChangeDetectionStorage};
pub struct OneChanged<Trait: ?Sized + TraitQuery> {
marker: PhantomData<&'static Trait>,
}
unsafe impl<Trait: ?Sized + TraitQuery> WorldQuery for OneChanged<Trait> {
type Item<'w> = bool;
type Fetch<'w> = ChangeDetectionFetch<'w>;
type State = TraitQueryState<Trait>;
fn shrink<'wlong: 'wshort, 'wshort>(item: Self::Item<'wlong>) -> Self::Item<'wshort> {
item
}
unsafe fn init_fetch<'w>(
world: UnsafeWorldCell<'w>,
_state: &Self::State,
last_run: Tick,
this_run: Tick,
) -> Self::Fetch<'w> {
Self::Fetch::<'w> {
storage: ChangeDetectionStorage::Uninit,
sparse_sets: &world.storages().sparse_sets,
last_run,
this_run,
}
}
const IS_DENSE: bool = false;
#[inline]
unsafe fn set_archetype<'w>(
fetch: &mut Self::Fetch<'w>,
state: &Self::State,
_archetype: &'w Archetype,
table: &'w Table,
) {
for &component in &*state.components {
if let Some(column) = table.get_column(component) {
fetch.storage = ChangeDetectionStorage::Table {
ticks: column.get_changed_ticks_slice().into(),
};
return;
}
}
for &component in &*state.components {
if let Some(components) = fetch.sparse_sets.get(component) {
fetch.storage = ChangeDetectionStorage::SparseSet { components };
return;
}
}
debug_unreachable()
}
#[inline]
unsafe fn set_table<'w>(_fetch: &mut Self::Fetch<'w>, _state: &Self::State, _table: &'w Table) {
debug_unreachable()
}
#[inline(always)]
unsafe fn fetch<'w>(
fetch: &mut Self::Fetch<'w>,
entity: Entity,
table_row: TableRow,
) -> Self::Item<'w> {
let ticks_ptr = match fetch.storage {
ChangeDetectionStorage::Uninit => {
debug_unreachable()
}
ChangeDetectionStorage::Table { ticks } => ticks.get(table_row.as_usize()),
ChangeDetectionStorage::SparseSet { components } => components
.get_changed_tick(entity)
.unwrap_or_else(|| debug_unreachable()),
};
(*ticks_ptr)
.deref()
.is_newer_than(fetch.last_run, fetch.this_run)
}
#[inline]
fn update_component_access(state: &Self::State, access: &mut FilteredAccess<ComponentId>) {
let mut new_access = access.clone();
let mut not_first = false;
for &component in &*state.components {
assert!(
!access.access().has_write(component),
"&{} conflicts with a previous access in this query. Shared access cannot coincide with exclusive access.",
std::any::type_name::<Trait>(),
);
if not_first {
let mut intermediate = access.clone();
intermediate.add_read(component);
new_access.append_or(&intermediate);
new_access.extend_access(&intermediate);
} else {
new_access.and_with(component);
new_access.access_mut().add_read(component);
not_first = true;
}
}
*access = new_access;
}
#[inline]
fn init_state(world: &mut World) -> Self::State {
TraitQueryState::init(world)
}
#[inline]
fn get_state(_: &Components) -> Option<Self::State> {
panic!("transmuting and any other operations concerning the state of a query are currently broken and shouldn't be used. See https://github.com/JoJoJet/bevy-trait-query/issues/59");
}
fn matches_component_set(
state: &Self::State,
set_contains_id: &impl Fn(ComponentId) -> bool,
) -> bool {
state.matches_component_set_one(set_contains_id)
}
}
unsafe impl<Trait: ?Sized + TraitQuery> QueryData for OneChanged<Trait> {
type ReadOnly = Self;
}
unsafe impl<Trait: ?Sized + TraitQuery> ReadOnlyQueryData for OneChanged<Trait> {}
impl<Trait: ?Sized + TraitQuery> QueryFilter for OneChanged<Trait> {
const IS_ARCHETYPAL: bool = false;
unsafe fn filter_fetch(
fetch: &mut Self::Fetch<'_>,
entity: Entity,
table_row: TableRow,
) -> bool {
<Self as WorldQuery>::fetch(fetch, entity, table_row)
}
}