qmi 0.1.5

An ECS with too much macro usage
Documentation
use crate::{EntityID, QMI, pool::ComponentPool};

pub trait TupleQuery<'a> {
    type Item: 'a;
    fn query_tuple(qmi: &'a QMI) -> impl Iterator<Item = Self::Item> + 'a;
}

pub trait TupleQueryMut<'a> {
    type Item: 'a;
    fn query_tuple_mut(qmi: &'a mut QMI) -> impl Iterator<Item = Self::Item> + 'a;
}

macro_rules! impl_tuple_query {
    ( $first:ident ) => {
        impl<'a, $first> TupleQuery<'a> for ($first,)
        where
            $first: 'static,
        {
            type Item = (EntityID, &'a $first);
            fn query_tuple(qmi: &'a QMI) -> impl Iterator<Item = Self::Item> + 'a {
                qmi.component_storage.get(std::any::type_name::<$first>().rsplit("::").next().unwrap())
                    .and_then(|s| s.as_any().downcast_ref::<ComponentPool<$first>>())
                    .into_iter()
                    .flat_map(|pool| pool.iter_entities())
            }
        }

        impl<'a, $first> TupleQueryMut<'a> for ($first,)
        where
            $first: 'static,
        {
            type Item = (EntityID, &'a mut $first);
            fn query_tuple_mut(qmi: &'a mut QMI) -> impl Iterator<Item = Self::Item> + 'a {
                let first_ptr = qmi.component_storage.get_mut(std::any::type_name::<$first>().rsplit("::").next().unwrap())
                    .and_then(|s| s.as_any_mut().downcast_mut::<ComponentPool<$first>>())
                    .map(|p| p as *mut ComponentPool<$first>);

                first_ptr.into_iter().flat_map(|ptr| unsafe { (*ptr).iter_entities_mut() })
            }
        }
    };
    ( $first:ident, $( $ty:ident ),+ ) => {
        impl<'a, $first, $($ty),+> TupleQuery<'a> for ($first, $($ty),+)
        where
            $first: 'static,
            $($ty: 'static),+
        {
            type Item = (EntityID, (&'a $first, $(&'a $ty),+));
            fn query_tuple(qmi: &'a QMI) -> impl Iterator<Item = Self::Item> + 'a {
                let first_pool = qmi.component_storage.get(std::any::type_name::<$first>().rsplit("::").next().unwrap())
                    .and_then(|s| s.as_any().downcast_ref::<ComponentPool<$first>>());

                $(
                    #[allow(non_snake_case)]
                    let $ty = qmi.component_storage.get(std::any::type_name::<$ty>().rsplit("::").next().unwrap())
                        .and_then(|s| s.as_any().downcast_ref::<ComponentPool<$ty>>());
                )+

                first_pool.into_iter().flat_map(move |pool| {
                    pool.iter_entities().filter_map(move |(entity, first_comp)| {
                        Some((
                            entity,
                            (
                                first_comp,
                                $(
                                    {
                                        let p = $ty?;
                                        let id = p.sparse_map.get(entity.0 as usize)?;
                                        &p.dense_data[id]
                                    },
                                )+
                            )
                        ))
                    })
                })
            }
        }

        impl<'a, $first, $($ty),+> TupleQueryMut<'a> for ($first, $($ty),+)
        where
            $first: 'static,
            $($ty: 'static),+
        {
            type Item = (EntityID, (&'a mut $first, $(&'a mut $ty),+));
            fn query_tuple_mut(qmi: &'a mut QMI) -> impl Iterator<Item = Self::Item> + 'a {
                let first_ptr = qmi.component_storage.get_mut(std::any::type_name::<$first>().rsplit("::").next().unwrap())
                    .and_then(|s| s.as_any_mut().downcast_mut::<ComponentPool<$first>>())
                    .map(|p| p as *mut ComponentPool<$first>);

                $(
                    #[allow(non_snake_case)]
                    let $ty = qmi.component_storage.get_mut(std::any::type_name::<$ty>().rsplit("::").next().unwrap())
                        .and_then(|s| s.as_any_mut().downcast_mut::<ComponentPool<$ty>>())
                        .map(|p| p as *mut ComponentPool<$ty>);
                )+

                first_ptr.into_iter().flat_map(move |ptr| unsafe {
                    (*ptr).iter_entities_mut().filter_map(move |(entity, first_comp)| {
                        Some((
                            entity,
                            (
                                first_comp,
                                $(
                                    {
                                        let p_ptr = $ty?;
                                        let pool = &mut *p_ptr;
                                        let id = pool.sparse_map.get(entity.0 as usize)?;
                                        &mut pool.dense_data[id]
                                    },
                                )+
                            )
                        ))
                    })
                })
            }
        }
    };
}

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) -> impl Iterator<Item = T::Item> + 'a
    where
        T: TupleQuery<'a>,
    {
        T::query_tuple(self)
    }

    pub fn query_mut<'a, T>(&'a mut self) -> impl Iterator<Item = T::Item> + 'a
    where
        T: TupleQueryMut<'a>,
    {
        T::query_tuple_mut(self)
    }
}