use bevy_ecs::{
change_detection::{DetectChanges, Mut, Ref},
component::{ComponentId, Tick},
entity::Entity,
ptr::UnsafeCellDeref,
query::{QueryData, QueryItem, ReadOnlyQueryData, WorldQuery},
storage::{SparseSets, Table, TableRow},
world::{unsafe_world_cell::UnsafeWorldCell, World},
};
use crate::{
debug_unreachable, trait_registry_error, zip_exact, TraitImplMeta, TraitImplRegistry,
TraitQuery, TraitQueryState,
};
pub struct ReadTraits<'a, Trait: ?Sized + TraitQuery> {
registry: &'a TraitImplRegistry<Trait>,
table: &'a Table,
table_row: TableRow,
sparse_sets: &'a SparseSets,
last_run: Tick,
this_run: Tick,
}
#[doc(hidden)]
pub type CombinedReadTraitsIter<'a, Trait> =
std::iter::Chain<ReadTableTraitsIter<'a, Trait>, ReadSparseTraitsIter<'a, Trait>>;
#[doc(hidden)]
pub struct ReadTableTraitsIter<'a, Trait: ?Sized> {
components: std::slice::Iter<'a, ComponentId>,
meta: std::slice::Iter<'a, TraitImplMeta<Trait>>,
table_row: TableRow,
table: &'a Table,
last_run: Tick,
this_run: Tick,
}
impl<'a, Trait: ?Sized + TraitQuery> Iterator for ReadTableTraitsIter<'a, Trait> {
type Item = Ref<'a, Trait>;
fn next(&mut self) -> Option<Self::Item> {
let (column, meta) = unsafe { zip_exact(&mut self.components, &mut self.meta) }
.find_map(|(&component, meta)| self.table.get_column(component).zip(Some(meta)))?;
let ptr = unsafe {
column
.get_data_ptr()
.byte_add(self.table_row.as_usize() * meta.size_bytes)
};
let trait_object = unsafe { meta.dyn_ctor.cast(ptr) };
let added_tick = unsafe { column.get_added_tick_unchecked(self.table_row).deref() };
let changed_tick = unsafe { column.get_changed_tick_unchecked(self.table_row).deref() };
Some(Ref::new(
trait_object,
added_tick,
changed_tick,
self.last_run,
self.this_run,
))
}
}
#[doc(hidden)]
pub struct ReadSparseTraitsIter<'a, Trait: ?Sized> {
components: std::slice::Iter<'a, ComponentId>,
meta: std::slice::Iter<'a, TraitImplMeta<Trait>>,
entity: Entity,
sparse_sets: &'a SparseSets,
last_run: Tick,
this_run: Tick,
}
impl<'a, Trait: ?Sized + TraitQuery> Iterator for ReadSparseTraitsIter<'a, Trait> {
type Item = Ref<'a, Trait>;
fn next(&mut self) -> Option<Self::Item> {
let ((ptr, ticks_ptr), meta) = unsafe { zip_exact(&mut self.components, &mut self.meta) }
.find_map(|(&component, meta)| {
self.sparse_sets
.get(component)
.and_then(|set| set.get_with_ticks(self.entity))
.zip(Some(meta))
})?;
let trait_object = unsafe { meta.dyn_ctor.cast(ptr) };
let added_tick = unsafe { ticks_ptr.added.deref() };
let changed_tick = unsafe { ticks_ptr.changed.deref() };
Some(Ref::new(
trait_object,
added_tick,
changed_tick,
self.last_run,
self.this_run,
))
}
}
impl<'w, Trait: ?Sized + TraitQuery> IntoIterator for ReadTraits<'w, Trait> {
type Item = Ref<'w, Trait>;
type IntoIter = CombinedReadTraitsIter<'w, Trait>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
let table = ReadTableTraitsIter {
components: self.registry.table_components.iter(),
meta: self.registry.table_meta.iter(),
table: self.table,
table_row: self.table_row,
last_run: self.last_run,
this_run: self.this_run,
};
let sparse = ReadSparseTraitsIter {
components: self.registry.sparse_components.iter(),
meta: self.registry.sparse_meta.iter(),
entity: self.table.entities()[self.table_row.as_usize()],
sparse_sets: self.sparse_sets,
last_run: self.last_run,
this_run: self.this_run,
};
table.chain(sparse)
}
}
impl<'w, Trait: ?Sized + TraitQuery> IntoIterator for &ReadTraits<'w, Trait> {
type Item = Ref<'w, Trait>;
type IntoIter = CombinedReadTraitsIter<'w, Trait>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
let table = ReadTableTraitsIter {
components: self.registry.table_components.iter(),
meta: self.registry.table_meta.iter(),
table: self.table,
table_row: self.table_row,
last_run: self.last_run,
this_run: self.this_run,
};
let sparse = ReadSparseTraitsIter {
components: self.registry.sparse_components.iter(),
meta: self.registry.sparse_meta.iter(),
entity: self.table.entities()[self.table_row.as_usize()],
sparse_sets: self.sparse_sets,
last_run: self.last_run,
this_run: self.this_run,
};
table.chain(sparse)
}
}
impl<'w, Trait: ?Sized + TraitQuery> ReadTraits<'w, Trait> {
pub fn iter(&self) -> CombinedReadTraitsIter<'w, Trait> {
self.into_iter()
}
pub fn iter_added(&self) -> impl Iterator<Item = Ref<'w, Trait>> {
self.iter().filter(DetectChanges::is_added)
}
pub fn iter_changed(&self) -> impl Iterator<Item = Ref<'w, Trait>> {
self.iter().filter(DetectChanges::is_changed)
}
}
#[doc(hidden)]
pub struct AllTraitsFetch<'w, Trait: ?Sized> {
registry: &'w TraitImplRegistry<Trait>,
table: Option<&'w Table>,
sparse_sets: &'w SparseSets,
last_run: Tick,
this_run: Tick,
}
impl<Trait: ?Sized> Clone for AllTraitsFetch<'_, Trait> {
fn clone(&self) -> Self {
*self
}
}
impl<Trait: ?Sized> Copy for AllTraitsFetch<'_, Trait> {}
pub struct WriteTraits<'a, Trait: ?Sized + TraitQuery> {
registry: &'a TraitImplRegistry<Trait>,
table: &'a Table,
table_row: TableRow,
last_run: Tick,
this_run: Tick,
sparse_sets: &'a SparseSets,
}
#[doc(hidden)]
pub type CombinedWriteTraitsIter<'a, Trait> =
std::iter::Chain<WriteTableTraitsIter<'a, Trait>, WriteSparseTraitsIter<'a, Trait>>;
#[doc(hidden)]
pub struct WriteTableTraitsIter<'a, Trait: ?Sized> {
components: std::slice::Iter<'a, ComponentId>,
meta: std::slice::Iter<'a, TraitImplMeta<Trait>>,
table: &'a Table,
table_row: TableRow,
last_run: Tick,
this_run: Tick,
}
impl<'a, Trait: ?Sized + TraitQuery> Iterator for WriteTableTraitsIter<'a, Trait> {
type Item = Mut<'a, Trait>;
fn next(&mut self) -> Option<Self::Item> {
let (column, meta) = unsafe { zip_exact(&mut self.components, &mut self.meta) }
.find_map(|(&component, meta)| self.table.get_column(component).zip(Some(meta)))?;
let ptr = unsafe {
column
.get_data_ptr()
.byte_add(self.table_row.as_usize() * meta.size_bytes)
};
let ptr = unsafe { ptr.assert_unique() };
let trait_object = unsafe { meta.dyn_ctor.cast_mut(ptr) };
let added = unsafe { column.get_added_tick_unchecked(self.table_row).deref_mut() };
let changed = unsafe {
column
.get_changed_tick_unchecked(self.table_row)
.deref_mut()
};
Some(Mut::new(
trait_object,
added,
changed,
self.last_run,
self.this_run,
))
}
}
#[doc(hidden)]
pub struct WriteSparseTraitsIter<'a, Trait: ?Sized> {
components: std::slice::Iter<'a, ComponentId>,
meta: std::slice::Iter<'a, TraitImplMeta<Trait>>,
entity: Entity,
sparse_sets: &'a SparseSets,
last_run: Tick,
this_run: Tick,
}
impl<'a, Trait: ?Sized + TraitQuery> Iterator for WriteSparseTraitsIter<'a, Trait> {
type Item = Mut<'a, Trait>;
fn next(&mut self) -> Option<Self::Item> {
let ((ptr, component_ticks), meta) =
unsafe { zip_exact(&mut self.components, &mut self.meta) }.find_map(
|(&component, meta)| {
self.sparse_sets
.get(component)
.and_then(|set| set.get_with_ticks(self.entity))
.zip(Some(meta))
},
)?;
let ptr = unsafe { ptr.assert_unique() };
let trait_object = unsafe { meta.dyn_ctor.cast_mut(ptr) };
let added = unsafe { component_ticks.added.deref_mut() };
let changed = unsafe { component_ticks.changed.deref_mut() };
Some(Mut::new(
trait_object,
added,
changed,
self.last_run,
self.this_run,
))
}
}
impl<Trait: ?Sized + TraitQuery> WriteTraits<'_, Trait> {
pub fn iter(&self) -> CombinedReadTraitsIter<'_, Trait> {
self.into_iter()
}
pub fn iter_mut(&mut self) -> CombinedWriteTraitsIter<'_, Trait> {
self.into_iter()
}
pub fn iter_added(&self) -> impl Iterator<Item = Ref<'_, Trait>> {
self.iter().filter(DetectChanges::is_added)
}
pub fn iter_changed(&self) -> impl Iterator<Item = Ref<'_, Trait>> {
self.iter().filter(DetectChanges::is_changed)
}
pub fn iter_added_mut(&mut self) -> impl Iterator<Item = Mut<'_, Trait>> {
self.iter_mut().filter(DetectChanges::is_added)
}
pub fn iter_changed_mut(&mut self) -> impl Iterator<Item = Mut<'_, Trait>> {
self.iter_mut().filter(DetectChanges::is_changed)
}
}
impl<'w, Trait: ?Sized + TraitQuery> IntoIterator for WriteTraits<'w, Trait> {
type Item = Mut<'w, Trait>;
type IntoIter = CombinedWriteTraitsIter<'w, Trait>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
let table = WriteTableTraitsIter {
components: self.registry.table_components.iter(),
meta: self.registry.table_meta.iter(),
table: self.table,
table_row: self.table_row,
last_run: self.last_run,
this_run: self.this_run,
};
let sparse = WriteSparseTraitsIter {
components: self.registry.sparse_components.iter(),
meta: self.registry.sparse_meta.iter(),
entity: self.table.entities()[self.table_row.as_usize()],
sparse_sets: self.sparse_sets,
last_run: self.last_run,
this_run: self.this_run,
};
table.chain(sparse)
}
}
impl<'world, 'local, Trait: ?Sized + TraitQuery> IntoIterator
for &'local WriteTraits<'world, Trait>
{
type Item = Ref<'local, Trait>;
type IntoIter = CombinedReadTraitsIter<'local, Trait>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
let table = ReadTableTraitsIter {
components: self.registry.table_components.iter(),
meta: self.registry.table_meta.iter(),
table: self.table,
table_row: self.table_row,
last_run: self.last_run,
this_run: self.this_run,
};
let sparse = ReadSparseTraitsIter {
components: self.registry.sparse_components.iter(),
meta: self.registry.sparse_meta.iter(),
entity: self.table.entities()[self.table_row.as_usize()],
sparse_sets: self.sparse_sets,
last_run: self.last_run,
this_run: self.this_run,
};
table.chain(sparse)
}
}
impl<'world, 'local, Trait: ?Sized + TraitQuery> IntoIterator
for &'local mut WriteTraits<'world, Trait>
{
type Item = Mut<'local, Trait>;
type IntoIter = CombinedWriteTraitsIter<'local, Trait>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
let table = WriteTableTraitsIter {
components: self.registry.table_components.iter(),
meta: self.registry.table_meta.iter(),
table: self.table,
table_row: self.table_row,
last_run: self.last_run,
this_run: self.this_run,
};
let sparse = WriteSparseTraitsIter {
components: self.registry.sparse_components.iter(),
meta: self.registry.sparse_meta.iter(),
entity: self.table.entities()[self.table_row.as_usize()],
sparse_sets: self.sparse_sets,
last_run: self.last_run,
this_run: self.this_run,
};
table.chain(sparse)
}
}
pub struct All<T: ?Sized>(T);
unsafe impl<'a, Trait: ?Sized + TraitQuery> QueryData for All<&'a Trait> {
type ReadOnly = Self;
}
unsafe impl<'a, Trait: ?Sized + TraitQuery> ReadOnlyQueryData for All<&'a Trait> {}
unsafe impl<'a, Trait: ?Sized + TraitQuery> WorldQuery for All<&'a Trait> {
type Item<'w> = ReadTraits<'w, Trait>;
type Fetch<'w> = AllTraitsFetch<'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,
) -> Self::Fetch<'w> {
AllTraitsFetch {
registry: world
.get_resource()
.unwrap_or_else(|| trait_registry_error()),
table: None,
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 bevy_ecs::archetype::Archetype,
table: &'w bevy_ecs::storage::Table,
) {
fetch.table = Some(table);
}
unsafe fn set_table<'w>(
fetch: &mut Self::Fetch<'w>,
_state: &Self::State,
table: &'w bevy_ecs::storage::Table,
) {
fetch.table = Some(table);
}
#[inline]
unsafe fn fetch<'w>(
fetch: &mut Self::Fetch<'w>,
_entity: Entity,
table_row: TableRow,
) -> Self::Item<'w> {
let table = fetch.table.unwrap_or_else(|| debug_unreachable());
ReadTraits {
registry: fetch.registry,
table,
table_row,
sparse_sets: fetch.sparse_sets,
last_run: fetch.last_run,
this_run: fetch.this_run,
}
}
#[inline]
fn update_component_access(
state: &Self::State,
access: &mut bevy_ecs::query::FilteredAccess<ComponentId>,
) {
let mut not_first = false;
let mut new_access = access.clone();
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(world: &World) -> Option<Self::State> {
TraitQueryState::get(world)
}
#[inline]
fn matches_component_set(
state: &Self::State,
set_contains_id: &impl Fn(ComponentId) -> bool,
) -> bool {
state.matches_component_set_any(set_contains_id)
}
}
unsafe impl<'a, Trait: ?Sized + TraitQuery> QueryData for All<&'a mut Trait> {
type ReadOnly = All<&'a Trait>;
}
unsafe impl<'a, Trait: ?Sized + TraitQuery> WorldQuery for All<&'a mut Trait> {
type Item<'w> = WriteTraits<'w, Trait>;
type Fetch<'w> = AllTraitsFetch<'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,
) -> Self::Fetch<'w> {
AllTraitsFetch {
registry: world
.get_resource()
.unwrap_or_else(|| trait_registry_error()),
table: None,
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 bevy_ecs::archetype::Archetype,
table: &'w bevy_ecs::storage::Table,
) {
fetch.table = Some(table);
}
#[inline]
unsafe fn set_table<'w>(
fetch: &mut Self::Fetch<'w>,
_state: &Self::State,
table: &'w bevy_ecs::storage::Table,
) {
fetch.table = Some(table);
}
#[inline]
unsafe fn fetch<'w>(
fetch: &mut Self::Fetch<'w>,
_entity: Entity,
table_row: TableRow,
) -> Self::Item<'w> {
let table = fetch.table.unwrap_or_else(|| debug_unreachable());
WriteTraits {
registry: fetch.registry,
table,
table_row,
sparse_sets: fetch.sparse_sets,
last_run: fetch.last_run,
this_run: fetch.this_run,
}
}
#[inline]
fn update_component_access(
state: &Self::State,
access: &mut bevy_ecs::query::FilteredAccess<ComponentId>,
) {
let mut not_first = false;
let mut new_access = access.clone();
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(world: &World) -> Option<Self::State> {
TraitQueryState::get(world)
}
#[inline]
fn matches_component_set(
state: &Self::State,
set_contains_id: &impl Fn(ComponentId) -> bool,
) -> bool {
state.matches_component_set_any(set_contains_id)
}
}