#[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", "!"]);
}
}