auto-concat-array 0.1.0

Concatenate fixed-size arrays on stable Rust with automatic array length inference.
Documentation
#[doc(hidden)]
pub use seq_macro::seq as _seq;

pub trait ConcatHelper<T, const N: usize, const M: usize> {
    type Output;
    fn do_concat(a: [T; N], b: [T; M]) -> Self::Output;
}

#[macro_export]
macro_rules! impl_concat {
    ( @single $target:ident, $n:tt, $m:tt ) => {
        impl<T: Copy> $crate::ConcatHelper<T, $n, $m> for $target {
            type Output = [T; $n + $m];

            #[inline]
            #[allow(unused_comparisons)]
            fn do_concat(a: [T; $n], b: [T; $m]) -> Self::Output {
                ::core::array::from_fn(|idx| {
                    if idx < $n {
                        a[idx]
                    } else {
                        b[idx - $n]
                    }
                })
            }
        }
    };

    ( $target:ident ; $( ($n:literal, $m:literal) ),* $(,)? ) => {
        $(
            $crate::impl_concat!( @single $target, $n, $m );
        )*
    };

    ( $target:ident ; $n_start:literal .. $n_end:literal ; $m_start:literal .. $m_end:literal ) => {
        $crate::_seq!(N in $n_start..$n_end {
            $crate::_seq!(M in $m_start..$m_end {
                $crate::impl_concat!( @single $target, N, M );
            });
        });
    };
}

#[cfg(test)]
mod tests {
    use super::*;

    struct MyArrayTools;
    impl_concat!(MyArrayTools; (100, 200), (300, 100));
    impl_concat!(MyArrayTools; 0..16 ; 0..16);

    fn array_concat<T, const N: usize, const M: usize>(
        a: [T; N],
        b: [T; M],
    ) -> <MyArrayTools as ConcatHelper<T, N, M>>::Output
    where
        T: Copy,
        MyArrayTools: ConcatHelper<T, N, M>,
    {
        MyArrayTools::do_concat(a, b)
    }

    #[test]
    fn test() {
        let large_a = [0; 100];
        let large_b = [1; 200];
        let large_c = array_concat(array_concat(large_a, large_b), large_a);
        assert_eq!(large_c.len(), 400);

        let str_a = ["Rust", "is"];
        let str_b = ["Awesome", "!"];
        let str_c = array_concat(str_a, str_b);
        assert_eq!(str_c, ["Rust", "is", "Awesome", "!"]);
    }
}