use super::sealed;
use crate::archetype::Archetype;
use crate::world::World;
use std::any::TypeId;
pub trait FetchComponent: sealed::SealedFetch {
type Component: 'static;
type Fetch<'w>: Copy; type Item<'w>;
type Slice<'w>;
const IS_MUT: bool;
unsafe fn fetch_raw<'w>(world: &'w World, arch: &Archetype, system_tick: u32) -> Option<Self::Fetch<'w>>;
unsafe fn get_item<'w>(fetch: Self::Fetch<'w>, row: usize, entity_id: u32) -> Self::Item<'w>;
unsafe fn get_slice<'w>(fetch: Self::Fetch<'w>, len: usize) -> Self::Slice<'w>;
unsafe fn contains_entity<'w>(fetch: Self::Fetch<'w>, entity_id: u32) -> bool {
let _ = (fetch, entity_id);
true
}
}
impl<T: crate::component::Component> sealed::SealedFetch for &T {}
impl<T: crate::component::Component> FetchComponent for &T {
type Component = T;
type Fetch<'w> = (*const u8, Option<*const crate::archetype::sparse_set::ComponentSparseSet>);
type Item<'w> = &'w T;
type Slice<'w> = &'w [T];
const IS_MUT: bool = false;
unsafe fn fetch_raw<'w>(world: &'w World, arch: &Archetype, _system_tick: u32) -> Option<Self::Fetch<'w>> {
if T::storage_type() == crate::component::StorageType::SparseSet {
let set = world.sparse_sets.get(&TypeId::of::<T>())?;
Some((std::ptr::null(), Some(set as *const _)))
} else {
let col = arch.get_column(TypeId::of::<T>())?;
Some((col.data_ptr(), None))
}
}
unsafe fn get_item<'w>(fetch: Self::Fetch<'w>, row: usize, entity_id: u32) -> Self::Item<'w> {
if let Some(set_ptr) = fetch.1 {
let set = &*set_ptr;
let ptr = set.get_ptr(entity_id).unwrap() as *const T;
&*ptr
} else {
let ptr = fetch.0.add(row * std::mem::size_of::<T>()) as *const T;
&*ptr
}
}
unsafe fn get_slice<'w>(fetch: Self::Fetch<'w>, len: usize) -> Self::Slice<'w> {
if fetch.1.is_some() {
panic!("Cannot use iter_chunks with SparseSet components");
}
std::slice::from_raw_parts(fetch.0 as *const T, len)
}
unsafe fn contains_entity<'w>(fetch: Self::Fetch<'w>, entity_id: u32) -> bool {
match fetch.1 {
Some(set_ptr) => (*set_ptr).contains(entity_id),
None => true,
}
}
}
pub struct Mut<'a, T: 'static> {
value: &'a mut T,
ticks: &'a mut crate::archetype::ComponentTicks,
current_tick: u32,
}
impl<T> std::ops::Deref for Mut<'_, T> {
type Target = T;
#[inline]
fn deref(&self) -> &T {
self.value
}
}
impl<T> std::ops::DerefMut for Mut<'_, T> {
#[inline]
fn deref_mut(&mut self) -> &mut T {
self.ticks.changed = self.current_tick;
self.value
}
}
impl<'a, T> Mut<'a, T> {
#[inline]
pub fn bypass_change_detection(&mut self) -> &mut T {
self.value
}
}
impl<T: crate::component::Component> sealed::SealedFetch for Mut<'_, T> {}
impl<T: crate::component::Component> FetchComponent for Mut<'_, T> {
type Component = T;
type Fetch<'w> = (*mut u8, *mut crate::archetype::ComponentTicks, u32, Option<*mut crate::archetype::sparse_set::ComponentSparseSet>);
type Item<'w> = Mut<'w, T>;
type Slice<'w> = &'w mut [T];
const IS_MUT: bool = true;
unsafe fn fetch_raw<'w>(world: &'w World, arch: &Archetype, system_tick: u32) -> Option<Self::Fetch<'w>> {
if T::storage_type() == crate::component::StorageType::SparseSet {
let set = world.sparse_sets.get(&TypeId::of::<T>())?;
Some((std::ptr::null_mut(), std::ptr::null_mut(), system_tick, Some(set as *const _ as *mut _)))
} else {
let col = arch.get_column_mut(TypeId::of::<T>())?;
Some((col.data_ptr_mut(), col.ticks_ptr_mut(), system_tick, None))
}
}
unsafe fn get_item<'w>(fetch: Self::Fetch<'w>, row: usize, entity_id: u32) -> Self::Item<'w> {
let (data_ptr, ticks_ptr, system_tick, set_opt) = fetch;
if let Some(set_ptr) = set_opt {
let set = &*set_ptr;
let e = entity_id as usize;
let dense_row = set.sparse[e] as usize;
let ptr = set.dense.get_unchecked_mut(dense_row) as *mut T;
let ticks_ptr = (*set.ticks.as_ptr().add(dense_row)).get();
Mut {
value: &mut *ptr,
ticks: &mut *ticks_ptr,
current_tick: system_tick,
}
} else {
let ptr = data_ptr.add(row * std::mem::size_of::<T>()) as *mut T;
Mut {
value: &mut *ptr,
ticks: &mut *ticks_ptr.add(row),
current_tick: system_tick,
}
}
}
unsafe fn contains_entity<'w>(fetch: Self::Fetch<'w>, entity_id: u32) -> bool {
match fetch.3 {
Some(set_ptr) => (*set_ptr).contains(entity_id),
None => true,
}
}
unsafe fn get_slice<'w>(fetch: Self::Fetch<'w>, len: usize) -> Self::Slice<'w> {
let (data_ptr, ticks_ptr, system_tick, set_opt) = fetch;
if set_opt.is_some() {
panic!("Cannot use iter_chunks with SparseSet components");
}
let ticks = std::slice::from_raw_parts_mut(ticks_ptr, len);
for tick in ticks.iter_mut() {
tick.changed = system_tick;
}
std::slice::from_raw_parts_mut(data_ptr as *mut T, len)
}
}