use super::resolve_column_ptr;
use super::{Chunk, QueryComponent, QueryDescriptor};
use crate::ecs::component_type;
use core::slice;
use smallvec::SmallVec;
pub unsafe trait QueryParam {
type Slice<'w>;
type Item<'w>;
fn component() -> QueryComponent;
#[doc(hidden)]
#[inline(always)]
unsafe fn resolve_column(chunk: &Chunk, component_index: u8) -> *mut u8 {
resolve_column_ptr(chunk, component_index)
}
unsafe fn slice_from_raw<'w>(ptr: *mut u8, start: usize, len: usize) -> Self::Slice<'w>;
unsafe fn item_from_raw<'w>(ptr: *mut u8, index: usize) -> Self::Item<'w>;
}
pub unsafe trait ReadOnlyQueryParam: QueryParam {}
unsafe impl<T: 'static> QueryParam for &T {
type Slice<'w> = &'w [T];
type Item<'w> = &'w T;
#[inline(always)]
fn component() -> QueryComponent {
QueryComponent::new(component_type::<T>(), false)
}
#[inline(always)]
unsafe fn resolve_column(chunk: &Chunk, component_index: u8) -> *mut u8 {
debug_assert_ne!(component_index, u8::MAX);
chunk.column_ptr(component_index as usize)
}
#[inline(always)]
unsafe fn slice_from_raw<'w>(ptr: *mut u8, start: usize, len: usize) -> Self::Slice<'w> {
unsafe { slice::from_raw_parts((ptr as *const T).add(start), len) }
}
#[inline(always)]
unsafe fn item_from_raw<'w>(ptr: *mut u8, index: usize) -> Self::Item<'w> {
unsafe { &*((ptr as *const T).add(index)) }
}
}
unsafe impl<T: 'static> ReadOnlyQueryParam for &T {}
unsafe impl<T: 'static> QueryParam for &mut T {
type Slice<'w> = &'w mut [T];
type Item<'w> = &'w mut T;
#[inline(always)]
fn component() -> QueryComponent {
QueryComponent::new(component_type::<T>(), true)
}
#[inline(always)]
unsafe fn resolve_column(chunk: &Chunk, component_index: u8) -> *mut u8 {
debug_assert_ne!(component_index, u8::MAX);
chunk.column_ptr(component_index as usize)
}
#[inline(always)]
unsafe fn slice_from_raw<'w>(ptr: *mut u8, start: usize, len: usize) -> Self::Slice<'w> {
unsafe { slice::from_raw_parts_mut((ptr as *mut T).add(start), len) }
}
#[inline(always)]
unsafe fn item_from_raw<'w>(ptr: *mut u8, index: usize) -> Self::Item<'w> {
unsafe { &mut *((ptr as *mut T).add(index)) }
}
}
unsafe impl<T: 'static> QueryParam for Option<&T> {
type Slice<'w> = Option<&'w [T]>;
type Item<'w> = Option<&'w T>;
#[inline(always)]
fn component() -> QueryComponent {
QueryComponent::optional(component_type::<T>(), false)
}
#[inline(always)]
unsafe fn slice_from_raw<'w>(ptr: *mut u8, start: usize, len: usize) -> Self::Slice<'w> {
if ptr.is_null() {
None
} else {
Some(unsafe { slice::from_raw_parts((ptr as *const T).add(start), len) })
}
}
#[inline(always)]
unsafe fn item_from_raw<'w>(ptr: *mut u8, index: usize) -> Self::Item<'w> {
if ptr.is_null() {
None
} else {
Some(unsafe { &*((ptr as *const T).add(index)) })
}
}
}
unsafe impl<T: 'static> ReadOnlyQueryParam for Option<&T> {}
unsafe impl<T: 'static> QueryParam for Option<&mut T> {
type Slice<'w> = Option<&'w mut [T]>;
type Item<'w> = Option<&'w mut T>;
#[inline(always)]
fn component() -> QueryComponent {
QueryComponent::optional(component_type::<T>(), true)
}
#[inline(always)]
unsafe fn slice_from_raw<'w>(ptr: *mut u8, start: usize, len: usize) -> Self::Slice<'w> {
if ptr.is_null() {
None
} else {
Some(unsafe { slice::from_raw_parts_mut((ptr as *mut T).add(start), len) })
}
}
#[inline(always)]
unsafe fn item_from_raw<'w>(ptr: *mut u8, index: usize) -> Self::Item<'w> {
if ptr.is_null() {
None
} else {
Some(unsafe { &mut *((ptr as *mut T).add(index)) })
}
}
}
pub unsafe trait QuerySpec {
type Chunk<'w>;
type Item<'w>;
fn descriptor() -> QueryDescriptor;
unsafe fn chunk_from_raw<'w>(chunk: &'w Chunk, component_indices: &[u8]) -> Self::Chunk<'w>;
#[doc(hidden)]
unsafe fn chunk_from_raw_parts<'w>(
component_ptrs: &[*mut u8],
start: usize,
len: usize,
) -> Self::Chunk<'w>;
#[doc(hidden)]
unsafe fn for_each_entity_raw_parts<'w, Func>(
component_ptrs: &[*mut u8],
start: usize,
len: usize,
f: &mut Func,
) where
Func: FnMut(Self::Item<'w>);
unsafe fn for_each_entity<'w, Func>(chunk: &'w Chunk, component_indices: &[u8], f: &mut Func)
where
Func: FnMut(Self::Item<'w>);
}
pub unsafe trait ReadOnlyQuerySpec: QuerySpec {}
unsafe impl<P: QueryParam> QuerySpec for P {
type Chunk<'w> = P::Slice<'w>;
type Item<'w> = P::Item<'w>;
#[inline(always)]
fn descriptor() -> QueryDescriptor {
let mut components = SmallVec::new();
components.push(P::component());
QueryDescriptor::new(components)
}
#[inline(always)]
unsafe fn chunk_from_raw<'w>(chunk: &'w Chunk, component_indices: &[u8]) -> Self::Chunk<'w> {
unsafe {
P::slice_from_raw(
P::resolve_column(chunk, *component_indices.get_unchecked(0)),
0,
chunk.entity_count,
)
}
}
#[inline(always)]
unsafe fn chunk_from_raw_parts<'w>(
component_ptrs: &[*mut u8],
start: usize,
len: usize,
) -> Self::Chunk<'w> {
unsafe { P::slice_from_raw(component_ptrs[0], start, len) }
}
#[inline(always)]
unsafe fn for_each_entity<'w, Func>(chunk: &'w Chunk, component_indices: &[u8], f: &mut Func)
where
Func: FnMut(Self::Item<'w>),
{
unsafe {
let base = P::resolve_column(chunk, *component_indices.get_unchecked(0));
for entity_index in 0..chunk.entity_count {
f(P::item_from_raw(base, entity_index));
}
}
}
#[inline(always)]
unsafe fn for_each_entity_raw_parts<'w, Func>(
component_ptrs: &[*mut u8],
start: usize,
len: usize,
f: &mut Func,
) where
Func: FnMut(Self::Item<'w>),
{
unsafe {
let base = component_ptrs[0];
for entity_index in start..start + len {
f(P::item_from_raw(base, entity_index));
}
}
}
}
unsafe impl<P: ReadOnlyQueryParam> ReadOnlyQuerySpec for P {}
macro_rules! impl_query_spec_tuple {
($(($Param:ident, $base:ident, $index:tt)),+ $(,)?) => {
unsafe impl<$($Param: QueryParam),+> QuerySpec for ($($Param,)+) {
type Chunk<'w> = ($($Param::Slice<'w>,)+);
type Item<'w> = ($($Param::Item<'w>,)+);
#[inline(always)]
fn descriptor() -> QueryDescriptor {
let mut components = SmallVec::new();
$(components.push($Param::component());)+
QueryDescriptor::new(components)
}
#[inline(always)]
unsafe fn chunk_from_raw<'w>(
chunk: &'w Chunk,
component_indices: &[u8],
) -> Self::Chunk<'w> {
unsafe {
(
$(
$Param::slice_from_raw(
$Param::resolve_column(
chunk,
*component_indices.get_unchecked($index),
),
0,
chunk.entity_count,
),
)+
)
}
}
#[inline(always)]
unsafe fn chunk_from_raw_parts<'w>(
component_ptrs: &[*mut u8],
start: usize,
len: usize,
) -> Self::Chunk<'w> {
unsafe {
(
$(
$Param::slice_from_raw(component_ptrs[$index], start, len),
)+
)
}
}
#[inline(always)]
unsafe fn for_each_entity<'w, Func>(
chunk: &'w Chunk,
component_indices: &[u8],
f: &mut Func,
)
where
Func: FnMut(Self::Item<'w>),
{
unsafe {
$(let $base = $Param::resolve_column(
chunk,
*component_indices.get_unchecked($index),
);)+
for entity_index in 0..chunk.entity_count {
f((
$(
$Param::item_from_raw($base, entity_index),
)+
));
}
}
}
#[inline(always)]
unsafe fn for_each_entity_raw_parts<'w, Func>(
component_ptrs: &[*mut u8],
start: usize,
len: usize,
f: &mut Func,
)
where
Func: FnMut(Self::Item<'w>),
{
unsafe {
$(let $base = component_ptrs[$index];)+
for entity_index in start..start + len {
f((
$(
$Param::item_from_raw($base, entity_index),
)+
));
}
}
}
}
unsafe impl<$($Param: ReadOnlyQueryParam),+> ReadOnlyQuerySpec for ($($Param,)+) {}
};
}
impl_query_spec_tuple!((A, a, 0), (B, b, 1));
impl_query_spec_tuple!((A, a, 0), (B, b, 1), (C, c, 2));
impl_query_spec_tuple!((A, a, 0), (B, b, 1), (C, c, 2), (D, d, 3));
impl_query_spec_tuple!((A, a, 0), (B, b, 1), (C, c, 2), (D, d, 3), (E, e, 4));
impl_query_spec_tuple!(
(A, a, 0),
(B, b, 1),
(C, c, 2),
(D, d, 3),
(E, e, 4),
(F, f, 5)
);
impl_query_spec_tuple!(
(A, a, 0),
(B, b, 1),
(C, c, 2),
(D, d, 3),
(E, e, 4),
(F, f, 5),
(G, g, 6)
);
impl_query_spec_tuple!(
(A, a, 0),
(B, b, 1),
(C, c, 2),
(D, d, 3),
(E, e, 4),
(F, f, 5),
(G, g, 6),
(H, h, 7)
);
impl_query_spec_tuple!(
(A, a, 0),
(B, b, 1),
(C, c, 2),
(D, d, 3),
(E, e, 4),
(F, f, 5),
(G, g, 6),
(H, h, 7),
(I, i, 8)
);
impl_query_spec_tuple!(
(A, a, 0),
(B, b, 1),
(C, c, 2),
(D, d, 3),
(E, e, 4),
(F, f, 5),
(G, g, 6),
(H, h, 7),
(I, i, 8),
(J, j, 9)
);
impl_query_spec_tuple!(
(A, a, 0),
(B, b, 1),
(C, c, 2),
(D, d, 3),
(E, e, 4),
(F, f, 5),
(G, g, 6),
(H, h, 7),
(I, i, 8),
(J, j, 9),
(K, k, 10)
);
impl_query_spec_tuple!(
(A, a, 0),
(B, b, 1),
(C, c, 2),
(D, d, 3),
(E, e, 4),
(F, f, 5),
(G, g, 6),
(H, h, 7),
(I, i, 8),
(J, j, 9),
(K, k, 10),
(L, l, 11)
);
impl_query_spec_tuple!(
(A, a, 0),
(B, b, 1),
(C, c, 2),
(D, d, 3),
(E, e, 4),
(F, f, 5),
(G, g, 6),
(H, h, 7),
(I, i, 8),
(J, j, 9),
(K, k, 10),
(L, l, 11),
(M, m, 12)
);
impl_query_spec_tuple!(
(A, a, 0),
(B, b, 1),
(C, c, 2),
(D, d, 3),
(E, e, 4),
(F, f, 5),
(G, g, 6),
(H, h, 7),
(I, i, 8),
(J, j, 9),
(K, k, 10),
(L, l, 11),
(M, m, 12),
(N, n, 13)
);
impl_query_spec_tuple!(
(A, a, 0),
(B, b, 1),
(C, c, 2),
(D, d, 3),
(E, e, 4),
(F, f, 5),
(G, g, 6),
(H, h, 7),
(I, i, 8),
(J, j, 9),
(K, k, 10),
(L, l, 11),
(M, m, 12),
(N, n, 13),
(O, o, 14)
);
impl_query_spec_tuple!(
(A, a, 0),
(B, b, 1),
(C, c, 2),
(D, d, 3),
(E, e, 4),
(F, f, 5),
(G, g, 6),
(H, h, 7),
(I, i, 8),
(J, j, 9),
(K, k, 10),
(L, l, 11),
(M, m, 12),
(N, n, 13),
(O, o, 14),
(P, p, 15)
);