1#![no_std]
2
3#[macro_export]
5macro_rules! concat_arrays_size {
6 ($( $array:expr ),*) => {{
7 0 $(+ $array.len())*
8 }};
9}
10
11#[macro_export]
13macro_rules! concat_arrays {
14 ($( $array:expr ),*) => ({
15 #[repr(C)]
16 struct ArrayConcatDecomposed<T, A, B>(core::mem::ManuallyDrop<[T; 0]>, core::mem::ManuallyDrop<A>, core::mem::ManuallyDrop<B>);
17
18 impl<T> ArrayConcatDecomposed<T, [T; 0], [T; 0]> {
19 #[inline(always)]
20 const fn default() -> Self {
21 Self::new(core::mem::ManuallyDrop::new([]), [])
22 }
23 }
24 impl<T, A, B> ArrayConcatDecomposed<T, A, B> {
25 #[inline(always)]
26 const fn new(a: core::mem::ManuallyDrop<A>, b: B) -> Self {
27 Self(core::mem::ManuallyDrop::new([]), a, core::mem::ManuallyDrop::new(b))
28 }
29 #[inline(always)]
30 const fn concat<const N: usize>(self, v: [T; N]) -> ArrayConcatDecomposed<T, A, ArrayConcatDecomposed<T, B, [T; N]>> {
31 ArrayConcatDecomposed::new(self.1, ArrayConcatDecomposed::new(self.2, v))
32 }
33 }
34
35 #[repr(C)]
36 union ArrayConcatComposed<T, A, B, const N: usize> {
37 full: core::mem::ManuallyDrop<[T; N]>,
38 decomposed: core::mem::ManuallyDrop<ArrayConcatDecomposed<T, A, B>>,
39 }
40
41 impl<T, A, B, const N: usize> ArrayConcatComposed<T, A, B, N> {
42 const PANIC: bool = $crate::_const_assert_same_size::<[T; N], Self>();
43
44 #[inline(always)]
45 const fn have_same_size(&self) -> bool {
46 Self::PANIC
47 }
48 }
49
50 let composed = ArrayConcatComposed {
51 decomposed: core::mem::ManuallyDrop::new(
52 ArrayConcatDecomposed::default()$(.concat($array))*,
53 )
54 };
55
56 composed.have_same_size();
58
59 core::mem::ManuallyDrop::into_inner(unsafe { composed.full })
61 });
62}
63
64#[macro_export]
69#[doc(hidden)]
70macro_rules! flatten_split {
71 (($($tail:tt)*), $head:expr, $pop:expr) => {
72 ($head, $($tail)*)
73 };
74 (($($tail:tt)*), $head:expr, $pop1:expr, $pop2:expr$(, $remaining:expr)+) => {
76 $crate::flatten_split!(
77 ($head.1.2, $head.2, $($tail)*),
78 $head.1.1$(,
79 $remaining)+
80 )
81 };
82 (($($tail:tt)*), $head:expr, $pop:expr$(, $remaining:expr)+) => {
83 $crate::flatten_split!(
84 ($head.2, $($tail)*),
85 $head.1$(,
86 $remaining)+
87 )
88 };
89}
90
91#[macro_export]
93macro_rules! split_array {
94 ($array:expr, $size:expr) => ($array);
95 ($array:expr, $size0:expr, $($sizes:expr),+) => ({
96 struct ArrayConcatDecomposedMarkerBase<T, A>(core::marker::PhantomData<(T, A)>);
97 struct ArrayConcatDecomposedMarker<T, A, B>(core::marker::PhantomData<(T, A, B)>);
98
99 #[repr(C)]
100 struct ArrayConcatDecomposed<T, A, B>([T; 0], A, B);
101
102 trait Storage {
103 type Data;
104 }
105 impl<T, const A: usize> Storage for [T; A] {
106 type Data = [T; A];
107 }
108
109 impl<T> ArrayConcatDecomposedMarkerBase<T, ()> {
110 #[inline(always)]
111 const fn default(_: &[T]) -> Self {
112 Self(core::marker::PhantomData)
113 }
114 #[inline(always)]
115 const fn concat<const N: usize>(self, _: [(); N]) -> ArrayConcatDecomposedMarkerBase<T, [T; N]> {
116 ArrayConcatDecomposedMarkerBase(core::marker::PhantomData)
117 }
118 }
119 impl<T, const A: usize> ArrayConcatDecomposedMarkerBase<T, [T; A]> {
120 #[inline(always)]
121 const fn concat<const B: usize>(self, _: [(); B]) -> ArrayConcatDecomposedMarker<T, [T; A], [T; B]> {
122 ArrayConcatDecomposedMarker(core::marker::PhantomData)
123 }
124 }
125
126 impl<T, A: Storage, B: Storage> Storage for ArrayConcatDecomposedMarker<T, A, B> {
127 type Data = ArrayConcatDecomposed<T, A::Data, B::Data>;
128 }
129
130 impl<T, A: Storage, B: Storage> ArrayConcatDecomposedMarker<T, A, B> {
131 #[inline(always)]
132 const fn concat<const C: usize>(self, _: [(); C]) -> ArrayConcatDecomposedMarker<T, ArrayConcatDecomposedMarker<T, A, B>, [T; C]> {
133 ArrayConcatDecomposedMarker(core::marker::PhantomData)
134 }
135 #[inline(always)]
136 const fn make<const N: usize>(self, full: [T; N]) -> ArrayConcatDecomposed<T, A::Data, B::Data> {
137 #[repr(C)]
138 union ArrayConcatComposed<T, A, B, const N: usize> {
139 full: core::mem::ManuallyDrop<[T; N]>,
140 decomposed: core::mem::ManuallyDrop<ArrayConcatDecomposed<T, A, B>>,
141 }
142
143 impl<T, A, B, const N: usize> ArrayConcatComposed<T, A, B, N> {
144 const PANIC: bool = $crate::_const_assert_same_size::<[T; N], Self>();
145
146 #[inline(always)]
147 const fn have_same_size(&self) -> bool {
148 Self::PANIC
149 }
150 }
151
152 let composed = ArrayConcatComposed::<T, A::Data, B::Data, N> {
153 full: core::mem::ManuallyDrop::new(full)
154 };
155
156 composed.have_same_size();
158
159 core::mem::ManuallyDrop::into_inner(unsafe { composed.decomposed })
161 }
162 }
163
164
165 let array = $array;
166 let decomposed = ArrayConcatDecomposedMarkerBase::default(&array)
167 .concat([(); $size0])
168 $(.concat([(); $sizes]))
169 *.make(array);
170
171 $crate::flatten_split!((), decomposed, $size0$(, $sizes)*)
172 });
173}
174
175#[inline(always)]
180#[doc(hidden)]
181pub const fn _const_assert_same_size<A, B>() -> bool {
182 let have_same_size = core::mem::size_of::<A>() == core::mem::size_of::<B>();
183
184 #[cfg(feature = "const_panic")]
185 {
186 have_same_size || panic!("Size Mismatch")
187 }
188
189 #[cfg(not(feature = "const_panic"))]
190 {
191 !["Size mismatch"][!have_same_size as usize].is_empty()
192 }
193}
194
195#[allow(dead_code)]
196#[cfg(test)]
197mod tests {
198 use super::*;
199
200 const A: [u32; 3] = [1, 2, 3];
201 const B: [u32; 3] = [4, 5, 6];
202 const C: [u32; 2] = [4, 5];
203
204 #[test]
205 fn test_simple_concat() {
206 let d = concat_arrays!(A, B);
207 const D: [u32; concat_arrays_size!(A, B)] = concat_arrays!(A, B);
208 assert_eq!([1, 2, 3, 4, 5, 6], D);
209 assert_eq!([1, 2, 3, 4, 5, 6], d);
210 }
211
212 #[test]
213 fn test_simple_split() {
214 let d: [u32; 6] = concat_arrays!(A, B);
215 const D: [u32; 6] = concat_arrays!(A, B);
216
217 const A_B: ([u32; 3], [u32; 3]) = split_array!(D, A.len(), B.len());
218
219 assert_eq!((A, B), A_B);
220 assert_eq!((A, B), split_array!(d, 3, 3));
221 assert_eq!(([1], [2, 3, 4, 5, 6]), split_array!(d, 1, 5));
222 assert_eq!(([1, 2, 3, 4, 5], [6]), split_array!(d, 5, 1));
223 assert_eq!(([1], [2, 3, 4, 5], [6]), split_array!(d, 1, 4, 1));
224 assert_eq!(([1], [2, 3], [4, 5, 6]), split_array!(d, 1, 2, 3));
225 assert_eq!(
226 ([1], [2], [3], [4], [5], [6]),
227 split_array!(d, 1, 1, 1, 1, 1, 1)
228 );
229 }
230
231 #[test]
232 fn test_different_sizes() {
233 let e = concat_arrays!(A, C);
234 const E: [u32; concat_arrays_size!(A, C)] = concat_arrays!(A, C);
235 assert_eq!([1, 2, 3, 4, 5], E);
236 assert_eq!([1, 2, 3, 4, 5], e);
237 }
238
239 #[test]
240 fn test_literal_arrays() {
241 let f = concat_arrays!(A, C, [6, 7, 8]);
242 const F: [u32; concat_arrays_size!(A, C, [6, 7, 8])] = concat_arrays!(A, C, [6, 7, 8]);
243 assert_eq!([1, 2, 3, 4, 5, 6, 7, 8], F);
244 assert_eq!([1, 2, 3, 4, 5, 6, 7, 8], f);
245 }
246
247 #[test]
248 fn test_non_const_arrays() {
249 let a = [1, 2, 3];
250 let c = [4, 5];
251 let f = concat_arrays!(a, c, [6, 7, 8]);
252 assert_eq!([1, 2, 3, 4, 5, 6, 7, 8], f);
253 }
254}