qmi 0.1.2

An ECS with too much macro usage
Documentation
use crate::{EntityID, QMI, storage::ComponentPool};
use itertools::{EitherOrBoth, Itertools};

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_ty:ident => $first_var:ident ) => {
        impl<'a, $first_ty> TupleQuery<'a> for ($first_ty,)
        where
            $first_ty: 'static,
        {
            type Out = Box<dyn Iterator<Item = (EntityID, &'a $first_ty)> + 'a>;
            fn query_tuple(qmi: &'a QMI) -> Self::Out {
                Box::new(qmi.query_single::<$first_ty>())
            }
        }
        impl<'a, $first_ty> TupleQueryMut<'a> for ($first_ty,)
        where
            $first_ty: 'static,
        {
            type Out = Box<dyn Iterator<Item = (EntityID, &'a mut $first_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_ty>()) {
                    Some(s) => s.as_any_mut().downcast_mut::<ComponentPool<$first_ty>>().unwrap() as *mut ComponentPool<$first_ty>,
                    None => return Box::new(std::iter::empty()),
                };
                unsafe { Box::new((*first_ptr).iter_entities_mut()) }
            }
        }
    };
    (
        $first_ty:ident => $first_var:ident
        $(, $ty:ident => $var:ident, $prev_tuple:pat, $flat_tuple:expr )+
    ) => {
        impl<'a, $first_ty, $($ty),+> TupleQuery<'a> for ($first_ty, $($ty),+)
        where
            $first_ty: 'static,
            $($ty: 'static),+
        {
            type Out = Box<dyn Iterator<Item = (EntityID, (&'a $first_ty, $(&'a $ty),+))> + 'a>;
            fn query_tuple(qmi: &'a QMI) -> Self::Out {
                Box::new(
                    qmi.query_single::<$first_ty>()
                    $(
                        .merge_join_by(qmi.query_single::<$ty>(), |(e1, _), (e2, _)| e1.cmp(e2))
                        .filter_map(|e| match e {
                            EitherOrBoth::Both((e, $prev_tuple), (_, $var)) => Some((e, $flat_tuple)),
                            _ => None,
                        })
                    )+
                )
            }
        }
        impl<'a, $first_ty, $($ty),+> TupleQueryMut<'a> for ($first_ty, $($ty),+)
        where
            $first_ty: 'static,
            $($ty: 'static),+
        {
            type Out = Box<dyn Iterator<Item = (EntityID, (&'a mut $first_ty, $(&'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_ty>()) {
                    Some(s) => s.as_any_mut().downcast_mut::<ComponentPool<$first_ty>>().unwrap() as *mut ComponentPool<$first_ty>,
                    None => return Box::new(std::iter::empty()),
                };
                $(
                    let $var = 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()
                        $(
                            .merge_join_by((*$var).iter_entities_mut(), |(e1, _), (e2, _)| e1.cmp(e2))
                            .filter_map(|e| match e {
                                EitherOrBoth::Both((e, $prev_tuple), (_, $var)) => Some((e, $flat_tuple)),
                                _ => None,
                            })
                        )+
                    )
                }
            }
        }
    };
}

impl_tuple_query!(A => a);
impl_tuple_query!(A => a, B => b, a, (a, b));
impl_tuple_query!(A => a, B => b, a, (a, b), C => c, (a, b), (a, b, c));
impl_tuple_query!(
    A => a,
    B => b, a, (a, b),
    C => c, (a, b), (a, b, c),
    D => d, (a, b, c), (a, b, c, d)
);
impl_tuple_query!(
    A => a,
    B => b, a, (a, b),
    C => c, (a, b), (a, b, c),
    D => d, (a, b, c), (a, b, c, d),
    E => e, (a, b, c, d), (a, b, c, d, e)
);
impl_tuple_query!(
    A => a,
    B => b, a, (a, b),
    C => c, (a, b), (a, b, c),
    D => d, (a, b, c), (a, b, c, d),
    E => e, (a, b, c, d), (a, b, c, d, e),
    F => f, (a, b, c, d, e), (a, b, c, d, e, f)
);
impl_tuple_query!(
    A => a,
    B => b, a, (a, b),
    C => c, (a, b), (a, b, c),
    D => d, (a, b, c), (a, b, c, d),
    E => e, (a, b, c, d), (a, b, c, d, e),
    F => f, (a, b, c, d, e), (a, b, c, d, e, f),
    G => g, (a, b, c, d, e, f), (a, b, c, d, e, f, g)
);
impl_tuple_query!(
    A => a,
    B => b, a, (a, b),
    C => c, (a, b), (a, b, c),
    D => d, (a, b, c), (a, b, c, d),
    E => e, (a, b, c, d), (a, b, c, d, e),
    F => f, (a, b, c, d, e), (a, b, c, d, e, f),
    G => g, (a, b, c, d, e, f), (a, b, c, d, e, f, g),
    H => h, (a, b, c, d, e, f, g), (a, b, c, d, e, f, g, h)
);
impl_tuple_query!(
    A => a, B => b, a, (a, b), C => c, (a, b), (a, b, c),
    D => d, (a, b, c), (a, b, c, d), E => e, (a, b, c, d), (a, b, c, d, e),
    F => f, (a, b, c, d, e), (a, b, c, d, e, f), G => g, (a, b, c, d, e, f), (a, b, c, d, e, f, g),
    H => h, (a, b, c, d, e, f, g), (a, b, c, d, e, f, g, h),
    I => i, (a, b, c, d, e, f, g, h), (a, b, c, d, e, f, g, h, i)
);
impl_tuple_query!(
    A => a, B => b, a, (a, b), C => c, (a, b), (a, b, c),
    D => d, (a, b, c), (a, b, c, d), E => e, (a, b, c, d), (a, b, c, d, e),
    F => f, (a, b, c, d, e), (a, b, c, d, e, f), G => g, (a, b, c, d, e, f), (a, b, c, d, e, f, g),
    H => h, (a, b, c, d, e, f, g), (a, b, c, d, e, f, g, h),
    I => i, (a, b, c, d, e, f, g, h), (a, b, c, d, e, f, g, h, i),
    J => j, (a, b, c, d, e, f, g, h, i), (a, b, c, d, e, f, g, h, i, j)
);
impl_tuple_query!(
    A => a, B => b, a, (a, b), C => c, (a, b), (a, b, c),
    D => d, (a, b, c), (a, b, c, d), E => e, (a, b, c, d), (a, b, c, d, e),
    F => f, (a, b, c, d, e), (a, b, c, d, e, f), G => g, (a, b, c, d, e, f), (a, b, c, d, e, f, g),
    H => h, (a, b, c, d, e, f, g), (a, b, c, d, e, f, g, h),
    I => i, (a, b, c, d, e, f, g, h), (a, b, c, d, e, f, g, h, i),
    J => j, (a, b, c, d, e, f, g, h, i), (a, b, c, d, e, f, g, h, i, j),
    K => k, (a, b, c, d, e, f, g, h, i, j), (a, b, c, d, e, f, g, h, i, j, k)
);
impl_tuple_query!(
    A => a, B => b, a, (a, b), C => c, (a, b), (a, b, c),
    D => d, (a, b, c), (a, b, c, d), E => e, (a, b, c, d), (a, b, c, d, e),
    F => f, (a, b, c, d, e), (a, b, c, d, e, f), G => g, (a, b, c, d, e, f), (a, b, c, d, e, f, g),
    H => h, (a, b, c, d, e, f, g), (a, b, c, d, e, f, g, h),
    I => i, (a, b, c, d, e, f, g, h), (a, b, c, d, e, f, g, h, i),
    J => j, (a, b, c, d, e, f, g, h, i), (a, b, c, d, e, f, g, h, i, j),
    K => k, (a, b, c, d, e, f, g, h, i, j), (a, b, c, d, e, f, g, h, i, j, k),
    L => l, (a, b, c, d, e, f, g, h, i, j, k), (a, b, c, d, e, f, g, h, i, j, k, l)
);
impl_tuple_query!(
    A => a, B => b, a, (a, b), C => c, (a, b), (a, b, c),
    D => d, (a, b, c), (a, b, c, d), E => e, (a, b, c, d), (a, b, c, d, e),
    F => f, (a, b, c, d, e), (a, b, c, d, e, f), G => g, (a, b, c, d, e, f), (a, b, c, d, e, f, g),
    H => h, (a, b, c, d, e, f, g), (a, b, c, d, e, f, g, h),
    I => i, (a, b, c, d, e, f, g, h), (a, b, c, d, e, f, g, h, i),
    J => j, (a, b, c, d, e, f, g, h, i), (a, b, c, d, e, f, g, h, i, j),
    K => k, (a, b, c, d, e, f, g, h, i, j), (a, b, c, d, e, f, g, h, i, j, k),
    L => l, (a, b, c, d, e, f, g, h, i, j, k), (a, b, c, d, e, f, g, h, i, j, k, l),
    M => m, (a, b, c, d, e, f, g, h, i, j, k, l), (a, b, c, d, e, f, g, h, i, j, k, l, m)
);
impl_tuple_query!(
    A => a, B => b, a, (a, b), C => c, (a, b), (a, b, c),
    D => d, (a, b, c), (a, b, c, d), E => e, (a, b, c, d), (a, b, c, d, e),
    F => f, (a, b, c, d, e), (a, b, c, d, e, f), G => g, (a, b, c, d, e, f), (a, b, c, d, e, f, g),
    H => h, (a, b, c, d, e, f, g), (a, b, c, d, e, f, g, h),
    I => i, (a, b, c, d, e, f, g, h), (a, b, c, d, e, f, g, h, i),
    J => j, (a, b, c, d, e, f, g, h, i), (a, b, c, d, e, f, g, h, i, j),
    K => k, (a, b, c, d, e, f, g, h, i, j), (a, b, c, d, e, f, g, h, i, j, k),
    L => l, (a, b, c, d, e, f, g, h, i, j, k), (a, b, c, d, e, f, g, h, i, j, k, l),
    M => m, (a, b, c, d, e, f, g, h, i, j, k, l), (a, b, c, d, e, f, g, h, i, j, k, l, m),
    N => n, (a, b, c, d, e, f, g, h, i, j, k, l, m), (a, b, c, d, e, f, g, h, i, j, k, l, m, n)
);
impl_tuple_query!(
    A => a, B => b, a, (a, b), C => c, (a, b), (a, b, c),
    D => d, (a, b, c), (a, b, c, d), E => e, (a, b, c, d), (a, b, c, d, e),
    F => f, (a, b, c, d, e), (a, b, c, d, e, f), G => g, (a, b, c, d, e, f), (a, b, c, d, e, f, g),
    H => h, (a, b, c, d, e, f, g), (a, b, c, d, e, f, g, h),
    I => i, (a, b, c, d, e, f, g, h), (a, b, c, d, e, f, g, h, i),
    J => j, (a, b, c, d, e, f, g, h, i), (a, b, c, d, e, f, g, h, i, j),
    K => k, (a, b, c, d, e, f, g, h, i, j), (a, b, c, d, e, f, g, h, i, j, k),
    L => l, (a, b, c, d, e, f, g, h, i, j, k), (a, b, c, d, e, f, g, h, i, j, k, l),
    M => m, (a, b, c, d, e, f, g, h, i, j, k, l), (a, b, c, d, e, f, g, h, i, j, k, l, m),
    N => n, (a, b, c, d, e, f, g, h, i, j, k, l, m), (a, b, c, d, e, f, g, h, i, j, k, l, m, n),
    O => o, (a, b, c, d, e, f, g, h, i, j, k, l, m, n), (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o)
);
impl_tuple_query!(
    A => a, B => b, a, (a, b), C => c, (a, b), (a, b, c),
    D => d, (a, b, c), (a, b, c, d), E => e, (a, b, c, d), (a, b, c, d, e),
    F => f, (a, b, c, d, e), (a, b, c, d, e, f), G => g, (a, b, c, d, e, f), (a, b, c, d, e, f, g),
    H => h, (a, b, c, d, e, f, g), (a, b, c, d, e, f, g, h),
    I => i, (a, b, c, d, e, f, g, h), (a, b, c, d, e, f, g, h, i),
    J => j, (a, b, c, d, e, f, g, h, i), (a, b, c, d, e, f, g, h, i, j),
    K => k, (a, b, c, d, e, f, g, h, i, j), (a, b, c, d, e, f, g, h, i, j, k),
    L => l, (a, b, c, d, e, f, g, h, i, j, k), (a, b, c, d, e, f, g, h, i, j, k, l),
    M => m, (a, b, c, d, e, f, g, h, i, j, k, l), (a, b, c, d, e, f, g, h, i, j, k, l, m),
    N => n, (a, b, c, d, e, f, g, h, i, j, k, l, m), (a, b, c, d, e, f, g, h, i, j, k, l, m, n),
    O => o, (a, b, c, d, e, f, g, h, i, j, k, l, m, n), (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o),
    P => p, (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o), (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)
    }
}