@@ -39,8 +39,6 @@ macro_rules! concat_arrays {
3939 }
4040
4141 impl <T , A , B , const N : usize > ArrayConcatComposed <T , A , B , N > {
42- const HAVE_SAME_SIZE : bool = core:: mem:: size_of:: <[ T ; N ] >( ) == core:: mem:: size_of:: <Self >( ) ;
43-
4442 const PANIC : bool = $crate:: _const_assert_same_size:: <[ T ; N ] , Self >( ) ;
4543
4644 #[ inline( always) ]
@@ -63,22 +61,134 @@ macro_rules! concat_arrays {
6361 } ) ;
6462}
6563
64+ /// Flatten a nested tuple based on the number of nestings.
65+ ///
66+ /// This is an implementation detail of the crate and should only be used by the
67+ /// macros in this crate.
68+ #[ macro_export]
69+ #[ doc( hidden) ]
70+ macro_rules! flatten_split {
71+ ( ( $( $tail: tt) * ) , $head: expr, $pop: expr) => {
72+ ( $head, $( $tail) * )
73+ } ;
74+ // We can dramatically reduce macro recursion by adding an additional_case
75+ ( ( $( $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+ /// Split the provided array into the specified sizes.
92+ #[ macro_export]
93+ macro_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+ // Sanity check that composed's two fields are the same size
157+ composed. have_same_size( ) ;
158+
159+ // SAFETY: Sizes of both fields in composed are the same so this assignment should be sound
160+ 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+
66175/// Assert at compile time that these types have the same size.
67176///
68177/// This is an implementation detail of the crate and should only be used by the
69178/// macros in this crate.
179+ #[ inline( always) ]
70180#[ doc( hidden) ]
71181pub const fn _const_assert_same_size < A , B > ( ) -> bool {
72182 let have_same_size = core:: mem:: size_of :: < A > ( ) == core:: mem:: size_of :: < B > ( ) ;
73183
74184 #[ cfg( feature = "const_panic" ) ]
75185 {
76- return have_same_size || panic ! ( "Size Mismatch" ) ;
186+ have_same_size || panic ! ( "Size Mismatch" )
77187 }
78188
79189 #[ cfg( not( feature = "const_panic" ) ) ]
80190 {
81- return ![ "Size mismatch" ] [ !have_same_size as usize ] . is_empty ( ) ;
191+ ![ "Size mismatch" ] [ !have_same_size as usize ] . is_empty ( )
82192 }
83193}
84194
@@ -99,6 +209,25 @@ mod tests {
99209 assert_eq ! ( [ 1 , 2 , 3 , 4 , 5 , 6 ] , d) ;
100210 }
101211
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+
102231 #[ test]
103232 fn test_different_sizes ( ) {
104233 let e = concat_arrays ! ( A , C ) ;
0 commit comments