use crate::{EntityID, QMI, storage::ComponentPool};
pub trait TupleQuery<'a> {
type Out: Iterator + 'a;
fn query_tuple(qmi: &'a QMI) -> Self::Out;
}
pub trait TupleQueryMut<'a> {
type Out: Iterator + 'a;
fn query_tuple_mut(qmi: &'a mut QMI) -> Self::Out;
}
macro_rules! impl_tuple_query {
( $first:ident ) => {
impl<'a, $first> TupleQuery<'a> for ($first,)
where
$first: 'static,
{
type Out = Box<dyn Iterator<Item = (EntityID, &'a $first)> + 'a>;
fn query_tuple(qmi: &'a QMI) -> Self::Out {
let first_pool = match qmi.component_storage.get(std::any::type_name::<$first>()) {
Some(s) => s.as_any().downcast_ref::<ComponentPool<$first>>().unwrap(),
None => return Box::new(std::iter::empty()),
};
Box::new(first_pool.iter_entities())
}
}
impl<'a, $first> TupleQueryMut<'a> for ($first,)
where
$first: 'static,
{
type Out = Box<dyn Iterator<Item = (EntityID, &'a mut $first)> + 'a>;
fn query_tuple_mut(qmi: &'a mut QMI) -> Self::Out {
let first_ptr = match qmi.component_storage.get_mut(std::any::type_name::<$first>()) {
Some(s) => s.as_any_mut().downcast_mut::<ComponentPool<$first>>().unwrap() as *mut ComponentPool<$first>,
None => return Box::new(std::iter::empty()),
};
unsafe { Box::new((*first_ptr).iter_entities_mut()) }
}
}
};
( $first:ident, $( $ty:ident ),+ ) => {
impl<'a, $first, $($ty),+> TupleQuery<'a> for ($first, $($ty),+)
where
$first: 'static,
$($ty: 'static),+
{
type Out = Box<dyn Iterator<Item = (EntityID, (&'a $first, $(&'a $ty),+))> + 'a>;
fn query_tuple(qmi: &'a QMI) -> Self::Out {
let first_pool = match qmi.component_storage.get(std::any::type_name::<$first>()) {
Some(s) => s.as_any().downcast_ref::<ComponentPool<$first>>().unwrap(),
None => return Box::new(std::iter::empty()),
};
$(
#[allow(non_snake_case)]
let $ty = match qmi.component_storage.get(std::any::type_name::<$ty>()) {
Some(s) => s.as_any().downcast_ref::<ComponentPool<$ty>>().unwrap(),
None => return Box::new(std::iter::empty()),
};
)+
Box::new(first_pool.iter_entities().filter_map(move |(entity, first_comp)| {
Some((
entity,
(
first_comp,
$(
{
let idx = $ty.sparse_map.get(entity.0 as usize)?;
&$ty.dense_data[idx]
},
)+
)
))
}))
}
}
impl<'a, $first, $($ty),+> TupleQueryMut<'a> for ($first, $($ty),+)
where
$first: 'static,
$($ty: 'static),+
{
type Out = Box<dyn Iterator<Item = (EntityID, (&'a mut $first, $(&'a mut $ty),+))> + 'a>;
fn query_tuple_mut(qmi: &'a mut QMI) -> Self::Out {
let first_ptr = match qmi.component_storage.get_mut(std::any::type_name::<$first>()) {
Some(s) => s.as_any_mut().downcast_mut::<ComponentPool<$first>>().unwrap() as *mut ComponentPool<$first>,
None => return Box::new(std::iter::empty()),
};
$(
#[allow(non_snake_case)]
let $ty = match qmi.component_storage.get_mut(std::any::type_name::<$ty>()) {
Some(s) => s.as_any_mut().downcast_mut::<ComponentPool<$ty>>().unwrap() as *mut ComponentPool<$ty>,
None => return Box::new(std::iter::empty()),
};
)+
unsafe {
Box::new((*first_ptr).iter_entities_mut().filter_map(move |(entity, first_comp)| {
Some((
entity,
(
first_comp,
$(
{
let pool = &mut *($ty);
let idx = pool.sparse_map.get(entity.0 as usize)?;
&mut pool.dense_data[idx]
},
)+
)
))
}))
}
}
}
};
}
impl_tuple_query!(A);
impl_tuple_query!(A, B);
impl_tuple_query!(A, B, C);
impl_tuple_query!(A, B, C, D);
impl_tuple_query!(A, B, C, D, E);
impl_tuple_query!(A, B, C, D, E, F);
impl_tuple_query!(A, B, C, D, E, F, G);
impl_tuple_query!(A, B, C, D, E, F, G, H);
impl_tuple_query!(A, B, C, D, E, F, G, H, I);
impl_tuple_query!(A, B, C, D, E, F, G, H, I, J);
impl_tuple_query!(A, B, C, D, E, F, G, H, I, J, K);
impl_tuple_query!(A, B, C, D, E, F, G, H, I, J, K, L);
impl_tuple_query!(A, B, C, D, E, F, G, H, I, J, K, L, M);
impl_tuple_query!(A, B, C, D, E, F, G, H, I, J, K, L, M, N);
impl_tuple_query!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O);
impl_tuple_query!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);
impl QMI {
pub fn query<'a, T>(&'a self) -> T::Out
where
T: TupleQuery<'a>,
{
T::query_tuple(self)
}
pub fn query_mut<'a, T>(&'a mut self) -> T::Out
where
T: TupleQueryMut<'a>,
{
T::query_tuple_mut(self)
}
}