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}