bevy_trait_query/one/impls/
one.rsuse bevy_ecs::change_detection::{Mut, Ref};
use bevy_ecs::entity::Entity;
use bevy_ecs::prelude::World;
use bevy_ecs::ptr::UnsafeCellDeref;
use bevy_ecs::{
component::{ComponentId, Components, Tick},
query::{QueryData, QueryItem, ReadOnlyQueryData, WorldQuery},
storage::TableRow,
world::unsafe_world_cell::UnsafeWorldCell,
};
use crate::{
debug_unreachable, one::FetchStorage, zip_exact, OneTraitFetch, TraitQuery, TraitQueryState,
};
pub struct One<T>(pub T);
unsafe impl<'a, T: ?Sized + TraitQuery> QueryData for One<&'a T> {
type ReadOnly = Self;
}
unsafe impl<'a, T: ?Sized + TraitQuery> ReadOnlyQueryData for One<&'a T> {}
unsafe impl<'a, T: ?Sized + TraitQuery> QueryData for One<&'a mut T> {
type ReadOnly = One<&'a T>;
}
unsafe impl<'a, Trait: ?Sized + TraitQuery> WorldQuery for One<&'a Trait> {
type Item<'w> = Ref<'w, Trait>;
type Fetch<'w> = OneTraitFetch<'w, Trait>;
type State = TraitQueryState<Trait>;
#[inline]
fn shrink<'wlong: 'wshort, 'wshort>(item: QueryItem<'wlong, Self>) -> QueryItem<'wshort, Self> {
item
}
#[inline]
unsafe fn init_fetch<'w>(
world: UnsafeWorldCell<'w>,
_state: &Self::State,
_last_run: Tick,
_this_run: Tick,
) -> OneTraitFetch<'w, Trait> {
OneTraitFetch {
storage: FetchStorage::Uninit,
last_run: Tick::new(0),
sparse_sets: &world.storages().sparse_sets,
this_run: Tick::new(0),
}
}
const IS_DENSE: bool = false;
#[inline]
unsafe fn set_archetype<'w>(
fetch: &mut OneTraitFetch<'w, Trait>,
state: &Self::State,
_archetype: &'w bevy_ecs::archetype::Archetype,
table: &'w bevy_ecs::storage::Table,
) {
for (&component, &meta) in zip_exact(&*state.components, &*state.meta) {
if let Some(column) = table.get_column(component) {
fetch.storage = FetchStorage::Table {
column: column.get_data_ptr(),
added_ticks: column.get_added_ticks_slice().into(),
changed_ticks: column.get_changed_ticks_slice().into(),
meta,
};
return;
}
}
for (&component, &meta) in zip_exact(&*state.components, &*state.meta) {
if let Some(sparse_set) = fetch.sparse_sets.get(component) {
fetch.storage = FetchStorage::SparseSet {
components: sparse_set,
meta,
};
return;
}
}
debug_unreachable()
}
#[inline]
unsafe fn set_table<'w>(
fetch: &mut OneTraitFetch<'w, Trait>,
state: &Self::State,
table: &'w bevy_ecs::storage::Table,
) {
for (&component, &meta) in std::iter::zip(&*state.components, &*state.meta) {
if let Some(column) = table.get_column(component) {
fetch.storage = FetchStorage::Table {
column: column.get_data_ptr(),
added_ticks: column.get_added_ticks_slice().into(),
changed_ticks: column.get_changed_ticks_slice().into(),
meta,
}
}
}
debug_unreachable()
}
#[inline]
unsafe fn fetch<'w>(
fetch: &mut Self::Fetch<'w>,
entity: Entity,
table_row: TableRow,
) -> Self::Item<'w> {
let table_row = table_row.as_usize();
let dyn_ctor;
let (ptr, added, changed) = match fetch.storage {
FetchStorage::Uninit => debug_unreachable(),
FetchStorage::Table {
column,
added_ticks,
changed_ticks,
meta,
} => {
dyn_ctor = meta.dyn_ctor;
let ptr = column.byte_add(table_row * meta.size_bytes);
(
ptr,
added_ticks.get(table_row).deref(),
changed_ticks.get(table_row).deref(),
)
}
FetchStorage::SparseSet { components, meta } => {
dyn_ctor = meta.dyn_ctor;
let (ptr, ticks) = components
.get_with_ticks(entity)
.unwrap_or_else(|| debug_unreachable());
(
ptr,
ticks.added.deref(),
ticks.changed.deref(),
)
}
};
Ref::new(
dyn_ctor.cast(ptr),
added,
changed,
fetch.last_run,
fetch.this_run,
)
}
#[inline]
fn update_component_access(
state: &Self::State,
access: &mut bevy_ecs::query::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");
}
#[inline]
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<'a, Trait: ?Sized + TraitQuery> WorldQuery for One<&'a mut Trait> {
type Item<'w> = Mut<'w, Trait>;
type Fetch<'w> = OneTraitFetch<'w, Trait>;
type State = TraitQueryState<Trait>;
#[inline]
fn shrink<'wlong: 'wshort, 'wshort>(item: QueryItem<'wlong, Self>) -> QueryItem<'wshort, Self> {
item
}
#[inline]
unsafe fn init_fetch<'w>(
world: UnsafeWorldCell<'w>,
_state: &Self::State,
last_run: Tick,
this_run: Tick,
) -> OneTraitFetch<'w, Trait> {
OneTraitFetch {
storage: FetchStorage::Uninit,
sparse_sets: &world.storages().sparse_sets,
last_run,
this_run,
}
}
const IS_DENSE: bool = false;
#[inline]
unsafe fn set_archetype<'w>(
fetch: &mut OneTraitFetch<'w, Trait>,
state: &Self::State,
_archetype: &'w bevy_ecs::archetype::Archetype,
table: &'w bevy_ecs::storage::Table,
) {
for (&component, &meta) in zip_exact(&*state.components, &*state.meta) {
if let Some(column) = table.get_column(component) {
fetch.storage = FetchStorage::Table {
column: column.get_data_ptr(),
added_ticks: column.get_added_ticks_slice().into(),
changed_ticks: column.get_changed_ticks_slice().into(),
meta,
};
return;
}
}
for (&component, &meta) in zip_exact(&*state.components, &*state.meta) {
if let Some(sparse_set) = fetch.sparse_sets.get(component) {
fetch.storage = FetchStorage::SparseSet {
components: sparse_set,
meta,
};
return;
}
}
debug_unreachable()
}
#[inline]
unsafe fn set_table<'w>(
fetch: &mut OneTraitFetch<'w, Trait>,
state: &Self::State,
table: &'w bevy_ecs::storage::Table,
) {
for (&component, &meta) in std::iter::zip(&*state.components, &*state.meta) {
if let Some(column) = table.get_column(component) {
fetch.storage = FetchStorage::Table {
column: column.get_data_ptr(),
added_ticks: column.get_added_ticks_slice().into(),
changed_ticks: column.get_changed_ticks_slice().into(),
meta,
};
return;
}
}
debug_unreachable()
}
#[inline]
unsafe fn fetch<'w>(
fetch: &mut Self::Fetch<'w>,
entity: Entity,
table_row: TableRow,
) -> Mut<'w, Trait> {
let table_row = table_row.as_usize();
let dyn_ctor;
let (ptr, added, changed) = match fetch.storage {
FetchStorage::Uninit => debug_unreachable(),
FetchStorage::Table {
column,
added_ticks,
changed_ticks,
meta,
} => {
dyn_ctor = meta.dyn_ctor;
let ptr = column.byte_add(table_row * meta.size_bytes);
(
ptr.assert_unique(),
added_ticks.get(table_row).deref_mut(),
changed_ticks.get(table_row).deref_mut(),
)
}
FetchStorage::SparseSet { components, meta } => {
dyn_ctor = meta.dyn_ctor;
let (ptr, ticks) = components
.get_with_ticks(entity)
.unwrap_or_else(|| debug_unreachable());
(
ptr.assert_unique(),
ticks.added.deref_mut(),
ticks.changed.deref_mut(),
)
}
};
Mut::new(
dyn_ctor.cast_mut(ptr),
added,
changed,
fetch.last_run,
fetch.this_run,
)
}
#[inline]
fn update_component_access(
state: &Self::State,
access: &mut bevy_ecs::query::FilteredAccess<ComponentId>,
) {
let mut new_access = access.clone();
let mut not_first = false;
for &component in &*state.components {
assert!(
!access.access().has_write(component),
"&mut {} conflicts with a previous access in this query. Mutable component access must be unique.",
std::any::type_name::<Trait>(),
);
if not_first {
let mut intermediate = access.clone();
intermediate.add_write(component);
new_access.append_or(&intermediate);
new_access.extend_access(&intermediate);
} else {
new_access.and_with(component);
new_access.access_mut().add_write(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");
}
#[inline]
fn matches_component_set(
state: &Self::State,
set_contains_id: &impl Fn(ComponentId) -> bool,
) -> bool {
state.matches_component_set_one(set_contains_id)
}
}