Skip to main content

auto_concat_array/
lib.rs

1#[doc(hidden)]
2pub use seq_macro::seq as _seq;
3
4pub trait ConcatHelper<T, const N: usize, const M: usize> {
5    type Output;
6    fn do_concat(a: [T; N], b: [T; M]) -> Self::Output;
7}
8
9#[macro_export]
10macro_rules! impl_concat {
11    ( @single $target:ident, $n:tt, $m:tt ) => {
12        impl<T: Copy> $crate::ConcatHelper<T, $n, $m> for $target {
13            type Output = [T; $n + $m];
14
15            #[inline]
16            #[allow(unused_comparisons)]
17            fn do_concat(a: [T; $n], b: [T; $m]) -> Self::Output {
18                ::core::array::from_fn(|idx| {
19                    if idx < $n {
20                        a[idx]
21                    } else {
22                        b[idx - $n]
23                    }
24                })
25            }
26        }
27    };
28
29    ( $target:ident ; $( ($n:literal, $m:literal) ),* $(,)? ) => {
30        $(
31            $crate::impl_concat!( @single $target, $n, $m );
32        )*
33    };
34
35    ( $target:ident ; $n_start:literal .. $n_end:literal ; $m_start:literal .. $m_end:literal ) => {
36        $crate::_seq!(N in $n_start..$n_end {
37            $crate::_seq!(M in $m_start..$m_end {
38                $crate::impl_concat!( @single $target, N, M );
39            });
40        });
41    };
42}
43
44#[cfg(test)]
45mod tests {
46    use super::*;
47
48    struct MyArrayTools;
49    impl_concat!(MyArrayTools; (100, 200), (300, 100));
50    impl_concat!(MyArrayTools; 0..16 ; 0..16);
51
52    fn array_concat<T, const N: usize, const M: usize>(
53        a: [T; N],
54        b: [T; M],
55    ) -> <MyArrayTools as ConcatHelper<T, N, M>>::Output
56    where
57        T: Copy,
58        MyArrayTools: ConcatHelper<T, N, M>,
59    {
60        MyArrayTools::do_concat(a, b)
61    }
62
63    #[test]
64    fn test() {
65        let large_a = [0; 100];
66        let large_b = [1; 200];
67        let large_c = array_concat(array_concat(large_a, large_b), large_a);
68        assert_eq!(large_c.len(), 400);
69
70        let str_a = ["Rust", "is"];
71        let str_b = ["Awesome", "!"];
72        let str_c = array_concat(str_a, str_b);
73        assert_eq!(str_c, ["Rust", "is", "Awesome", "!"]);
74    }
75}