diff --git a/src/query/mod.rs b/src/query/mod.rs index dcdd09e..29dada5 100644 --- a/src/query/mod.rs +++ b/src/query/mod.rs @@ -1,7 +1,7 @@ mod ptr; mod vec; -pub use ptr::{ComponentPtr, ComponentPtrDense}; +pub use ptr::ComponentPtr; pub use vec::VecPtr; #[allow(unreachable_code)] @@ -35,13 +35,15 @@ mod tests { let component_id = world.init_component::(); let mut query = unsafe { - QueryState::<&ComponentPtrDense, ()>::new_with_state(&mut world, component_id, ()) + QueryState::<&ComponentPtr, ()>::new_with_state(&mut world, component_id, ()) }; let count = query.iter(&mut world).count(); assert_eq!(count, 0); + // Check dynamic VecPtr variations + let mut query = unsafe { - QueryState::, ()>::new_with_state( + QueryState::, ()>::new_with_state( &mut world, vec![component_id], (), @@ -62,7 +64,7 @@ mod tests { world.spawn(A); let mut query = - unsafe { QueryState::<&ComponentPtrDense, ()>::new_with_state(&mut world, a, ()) }; + unsafe { QueryState::<&ComponentPtr, ()>::new_with_state(&mut world, a, ()) }; let count = query.iter(&mut world).count(); assert_eq!(count, 2); @@ -72,16 +74,25 @@ mod tests { assert_eq!(count, 1); let mut query = unsafe { - QueryState::<(&ComponentPtrDense, &ComponentPtr), ()>::new_with_state( - &mut world, - (a, b), - (), - ) + QueryState::<(&ComponentPtr, &ComponentPtr), ()>::new_with_state(&mut world, (a, b), ()) + }; + let count = query.iter(&mut world).count(); + assert_eq!(count, 1); + + // Check dynamic VecPtr variations + + let mut query = unsafe { + QueryState::, ()>::new_with_state(&mut world, vec![a], ()) + }; + let count = query.iter(&mut world).count(); + assert_eq!(count, 2); + + let mut query = unsafe { + QueryState::, ()>::new_with_state(&mut world, vec![b], ()) }; let count = query.iter(&mut world).count(); assert_eq!(count, 1); - // Pick VecPtr<&ComponentPtr> due to presence of &ComponentPtr in query let mut query = unsafe { QueryState::, ()>::new_with_state(&mut world, vec![a, b], ()) }; @@ -101,7 +112,7 @@ mod tests { world.spawn(Data("Hello, World!".to_string())); let mut query = unsafe { - QueryState::<&ComponentPtrDense, ()>::new_with_state(&mut world, component_id, ()) + QueryState::<&ComponentPtr, ()>::new_with_state(&mut world, component_id, ()) }; for data in query.iter(&mut world) { @@ -129,7 +140,7 @@ mod tests { world.spawn(Data("Hello, World!".to_string())); let mut query = unsafe { - QueryState::<&ComponentPtrDense, ()>::new_with_state(&mut world, component_id, ()) + QueryState::<&ComponentPtr, ()>::new_with_state(&mut world, component_id, ()) }; let res = query.iter_mut(&mut world).collect::>(); diff --git a/src/query/ptr.rs b/src/query/ptr.rs index 5692137..b459345 100644 --- a/src/query/ptr.rs +++ b/src/query/ptr.rs @@ -10,139 +10,18 @@ use bevy::{ ptr::{Ptr, ThinSlicePtr}, }; -/// Type used to query dense components -pub struct ComponentPtrDense; +/// Type used to query non-dense components +pub struct ComponentPtr; #[doc(hidden)] -pub struct ReadFetchDense<'w> { +pub struct ReadFetchSparse<'w> { + storage_type: StorageType, component_size: usize, + // T::Storage = TableStorage table_components: Option>, entity_table_rows: Option>, -} - -impl<'w> WorldQueryGats<'w> for &ComponentPtrDense { - type Item = Ptr<'w>; - type Fetch = ReadFetchDense<'w>; -} - -unsafe impl ReadOnlyWorldQuery for &ComponentPtrDense {} -unsafe impl WorldQuery for &ComponentPtrDense { - type ReadOnly = Self; - type State = ComponentId; - - fn shrink<'wlong: 'wshort, 'wshort>(item: Ptr<'wlong>) -> Ptr<'wshort> { - item - } - - const IS_DENSE: bool = true; - const IS_ARCHETYPAL: bool = true; - - unsafe fn init_fetch<'w>( - world: &'w World, - &component_id: &ComponentId, - _last_change_tick: u32, - _change_tick: u32, - ) -> ReadFetchDense<'w> { - let component_info = world.components().get_info(component_id).unwrap(); - - debug_assert_eq!(component_info.storage_type(), StorageType::Table); - - ReadFetchDense { - component_size: component_info.layout().size(), - table_components: None, - entity_table_rows: None, - } - } - - #[inline] - unsafe fn set_archetype<'w>( - fetch: &mut ReadFetchDense<'w>, - &component_id: &ComponentId, - archetype: &'w Archetype, - tables: &'w Tables, - ) { - fetch.entity_table_rows = Some(archetype.entity_table_rows().into()); - let column = tables[archetype.table_id()] - .get_column(component_id) - .unwrap(); - fetch.table_components = Some(column.get_data_ptr()); - } - - #[inline] - unsafe fn set_table<'w>( - fetch: &mut ReadFetchDense<'w>, - &component_id: &ComponentId, - table: &'w Table, - ) { - fetch.table_components = Some(table.get_column(component_id).unwrap().get_data_ptr()); - } - - #[inline] - unsafe fn archetype_fetch<'w>( - fetch: &mut >::Fetch, - archetype_index: usize, - ) -> >::Item { - let (entity_table_rows, table_components) = fetch - .entity_table_rows - .zip(fetch.table_components) - .unwrap_or_else(|| debug_checked_unreachable()); - - let table_row = *entity_table_rows.get(archetype_index); - table_components.byte_add(table_row * fetch.component_size) - } - - #[inline] - unsafe fn table_fetch<'w>( - fetch: &mut >::Fetch, - table_row: usize, - ) -> >::Item { - let components = fetch - .table_components - .unwrap_or_else(|| debug_checked_unreachable()); - components.byte_add(table_row * fetch.component_size) - } - - fn update_component_access( - &component_id: &ComponentId, - access: &mut FilteredAccess, - ) { - assert!( - !access.access().has_write(component_id), - "Read access to component with id: {:?} conflicts with a previous access in this query. Shared access cannot coincide with exclusive access.", - component_id - ); - access.add_read(component_id); - } - - fn update_archetype_component_access( - &component_id: &ComponentId, - archetype: &Archetype, - access: &mut Access, - ) { - if let Some(archetype_component_id) = archetype.get_archetype_component_id(component_id) { - access.add_read(archetype_component_id); - } - } - - fn init_state(_world: &mut World) -> Self::State { - panic!("Dynamic queries can only be initialized through QueryState::new_with_state"); - } - - fn matches_component_set( - &component_id: &ComponentId, - set_contains_id: &impl Fn(ComponentId) -> bool, - ) -> bool { - set_contains_id(component_id) - } -} - -/// Type used to query non-dense components -pub struct ComponentPtr; - -#[doc(hidden)] -pub struct ReadFetchSparse<'w> { // T::Storage = SparseStorage entities: Option>, sparse_set: Option<&'w ComponentSparseSet>, @@ -169,13 +48,16 @@ unsafe impl WorldQuery for &ComponentPtr { _last_change_tick: u32, _change_tick: u32, ) -> >::Fetch { - let storage_type = world - .components() - .get_info(component_id) - .unwrap() - .storage_type(); + let component_info = world.components().get_info(component_id).unwrap(); + let storage_type = component_info.storage_type(); ReadFetchSparse { + storage_type, + component_size: component_info.layout().size(), + + table_components: None, + entity_table_rows: None, + entities: None, sparse_set: (storage_type == StorageType::SparseSet) .then(|| world.storages().sparse_sets.get(component_id).unwrap()), @@ -188,21 +70,29 @@ unsafe impl WorldQuery for &ComponentPtr { #[inline] unsafe fn set_archetype<'w>( fetch: &mut >::Fetch, - _component_id: &ComponentId, + &component_id: &ComponentId, archetype: &'w Archetype, - _tables: &'w Tables, + tables: &'w Tables, ) { - fetch.entities = Some(archetype.entities().into()) + match fetch.storage_type { + StorageType::Table => { + fetch.entity_table_rows = Some(archetype.entity_table_rows().into()); + let column = tables[archetype.table_id()] + .get_column(component_id) + .unwrap(); + fetch.table_components = Some(column.get_data_ptr()); + } + StorageType::SparseSet => fetch.entities = Some(archetype.entities().into()), + } } #[inline] unsafe fn set_table<'w>( - _fetch: &mut >::Fetch, - _component_id: &ComponentId, - _table: &'w Table, + fetch: &mut >::Fetch, + &component_id: &ComponentId, + table: &'w Table, ) { - panic!("hi"); - debug_checked_unreachable(); + fetch.table_components = Some(table.get_column(component_id).unwrap().get_data_ptr()); } #[inline] @@ -210,24 +100,39 @@ unsafe impl WorldQuery for &ComponentPtr { fetch: &mut >::Fetch, archetype_index: usize, ) -> >::Item { - let (entities, sparse_set) = fetch - .entities - .zip(fetch.sparse_set) - .unwrap_or_else(|| debug_checked_unreachable()); - - let entity = *entities.get(archetype_index); - sparse_set - .get(entity) - .unwrap_or_else(|| debug_checked_unreachable()) + match fetch.storage_type { + StorageType::Table => { + let (entity_table_rows, table_components) = fetch + .entity_table_rows + .zip(fetch.table_components) + .unwrap_or_else(|| debug_checked_unreachable()); + + let table_row = *entity_table_rows.get(archetype_index); + table_components.byte_add(table_row * fetch.component_size) + } + StorageType::SparseSet => { + let (entities, sparse_set) = fetch + .entities + .zip(fetch.sparse_set) + .unwrap_or_else(|| debug_checked_unreachable()); + + let entity = *entities.get(archetype_index); + sparse_set + .get(entity) + .unwrap_or_else(|| debug_checked_unreachable()) + } + } } #[inline] unsafe fn table_fetch<'w>( - _fetch: &mut >::Fetch, - _table_row: usize, + fetch: &mut >::Fetch, + table_row: usize, ) -> >::Item { - panic!("hi"); - debug_checked_unreachable(); + let components = fetch + .table_components + .unwrap_or_else(|| debug_checked_unreachable()); + components.byte_add(table_row * fetch.component_size) } fn update_component_access( diff --git a/src/query/vec.rs b/src/query/vec.rs new file mode 100644 index 0000000..07ed3e7 --- /dev/null +++ b/src/query/vec.rs @@ -0,0 +1,150 @@ +use bevy::{ + ecs::{ + archetype::{Archetype, ArchetypeComponentId}, + component::ComponentId, + query::{ + Access, FilteredAccess, QueryItem, ReadOnlyWorldQuery, WorldQuery, WorldQueryGats, + }, + storage::{Table, Tables}, + }, + prelude::*, +}; + +use std::marker::PhantomData; + +/// Type used to query dense components +pub struct VecPtr { + _phantom: PhantomData, +} + +impl<'w, T> WorldQueryGats<'w> for VecPtr +where + T: WorldQueryGats<'w>, +{ + type Item = Vec; + type Fetch = Vec; +} + +/// SAFETY: each item in the vec is read only +unsafe impl ReadOnlyWorldQuery for VecPtr where T: ReadOnlyWorldQuery {} + +unsafe impl WorldQuery for VecPtr +where + T: WorldQuery, +{ + type ReadOnly = VecPtr; + type State = Vec; + + fn shrink<'wlong: 'wshort, 'wshort>(item: QueryItem<'wlong, Self>) -> QueryItem<'wshort, Self> { + item.into_iter().map(|item| T::shrink(item)).collect() + } + + const IS_DENSE: bool = T::IS_DENSE; + const IS_ARCHETYPAL: bool = T::IS_ARCHETYPAL; + + unsafe fn init_fetch<'w>( + world: &'w World, + state: &Vec, + last_change_tick: u32, + change_tick: u32, + ) -> >::Fetch { + state + .iter() + .map(|state| T::init_fetch(world, state, last_change_tick, change_tick)) + .collect() + } + + #[inline] + unsafe fn set_archetype<'w>( + fetch: &mut >::Fetch, + state: &Vec, + archetype: &'w Archetype, + tables: &'w Tables, + ) { + for (fetch, state) in fetch.iter_mut().zip(state.iter()) { + T::set_archetype(fetch, state, archetype, tables) + } + } + + #[inline] + unsafe fn set_table<'w>( + fetch: &mut >::Fetch, + state: &Self::State, + table: &'w Table, + ) { + for (fetch, state) in fetch.iter_mut().zip(state.iter()) { + T::set_table(fetch, state, table) + } + } + + #[inline] + unsafe fn archetype_fetch<'w>( + fetch: &mut >::Fetch, + archetype_index: usize, + ) -> >::Item { + fetch + .iter_mut() + .map(|fetch| T::archetype_fetch(fetch, archetype_index)) + .collect() + } + + #[inline] + unsafe fn table_fetch<'w>( + fetch: &mut >::Fetch, + table_row: usize, + ) -> >::Item { + fetch + .iter_mut() + .map(|fetch| T::archetype_fetch(fetch, table_row)) + .collect() + } + + #[inline] + unsafe fn table_filter_fetch( + fetch: &mut >::Fetch, + table_row: usize, + ) -> bool { + fetch.iter_mut().fold(true, |fold, fetch| { + fold && T::table_filter_fetch(fetch, table_row) + }) + } + + #[inline] + unsafe fn archetype_filter_fetch( + fetch: &mut >::Fetch, + archetype_index: usize, + ) -> bool { + fetch.iter_mut().fold(true, |fold, fetch| { + fold && T::archetype_filter_fetch(fetch, archetype_index) + }) + } + + fn update_component_access(state: &Self::State, access: &mut FilteredAccess) { + for state in state.iter() { + T::update_component_access(state, access); + } + } + + fn update_archetype_component_access( + state: &Self::State, + archetype: &Archetype, + access: &mut Access, + ) { + for state in state.iter() { + T::update_archetype_component_access(state, archetype, access); + } + } + + fn init_state(_world: &mut World) -> Self::State { + panic!("Dynamic queries can only be initialized through QueryState::new_with_state"); + } + + fn matches_component_set( + state: &Self::State, + set_contains_id: &impl Fn(ComponentId) -> bool, + ) -> bool { + state.iter().fold(true, |fold, state| { + fold && T::matches_component_set(state, set_contains_id) + }) + } +}