array_fusion/macros.rs
1//! A few utility macros.
2//!
3//! If you work with byte arrays, consider using the utilities from the
4//! `crate::bytes` module instead.
5//!
6
7#[cfg(doc)]
8use hybrid_array::Array;
9#[cfg(doc)]
10use hybrid_array::typenum;
11
12#[cfg(doc)]
13use crate::array_from_core;
14#[cfg(doc)]
15use crate::array_to_core;
16
17/// Splits an [`Array`] into multiple sub-`Array`s.
18///
19/// Notice that each sub-`Array` must have a defined size, and the total
20/// size of the sub-`Array`s must match the size of the `Aarray` on the
21/// right-hand side.
22///
23/// The macro expects a let-assignment style syntax with a array pattern,
24/// where each element happens to be bind a new variable with type `Array`.
25///
26/// If the size of a sub-`Array` cannot be inferred, you can specify it
27/// explicitly by adding `: array <size>` after the variable name, where
28/// `<size>` is a type of an `typenum` type-"number".
29///
30/// This macro is the reversal of the [`crate::merge_array`] macro.
31///
32/// # Syntax
33///
34/// ```text
35/// split_array!{
36/// let split \[
37/// ( <name> [ : array <typenum-size> ] , )*
38/// \] = <value>;
39/// }
40/// ```
41///
42/// # Example
43///
44/// ```
45/// use hybrid_array::Array;
46/// use array_fusion::array_from_core;
47/// use array_fusion::array_to_core;
48/// use array_fusion::split_array;
49/// use hybrid_array::sizes::U4;
50///
51/// // An Array consisting of a 2-byte and a 4-byte sub array
52/// let data: Array<_,_> = array_from_core([
53/// 0, 42, // foo
54/// 0x0, 0x0, 0x12, 0x34, // bar
55/// ]);
56///
57/// // Split it into a `foo` and a `bar`.
58/// // The size of foo is inferred by the subsequent usage, while bar is given
59/// // an explicit size.
60/// split_array!{
61/// let split [
62/// foo,
63/// bar: array U4,
64/// ] = data;
65/// };
66///
67/// // Use foo in a way to make its size inferrable, where `from_be_bytes`
68/// // gives the size of the core array, and `array_to_core` inferres the
69/// // Array size from the size of that core array.
70/// let foo = u16::from_be_bytes(array_to_core(foo));
71/// assert_eq!(foo, 42);
72///
73/// // Use bar, actually this could also infer the size, but we specified it
74/// // already above.
75/// assert_eq!(u32::from_be_bytes(array_to_core(bar)), 0x1234);
76/// ```
77///
78#[macro_export]
79macro_rules! split_array {
80 (
81 let split [
82 $($name:ident $( : array $size:ty)? ),* $(,)?
83 ] = $data:expr $(;)?
84 ) => {
85
86 // Ensure we got an array type
87 let rest: $crate::Array<_, _> = $data;
88
89 $(
90 let (sub, rest) = rest.split $( ::<$size> )? () ;
91 let $name = sub;
92 )*
93
94 // Assert that we split the entire array
95 let _rest: $crate::Array<_, $crate::sizes::U0> = rest;
96 };
97}
98
99/// Split a core arrays in core arrays.
100///
101/// This function is essentially [`split_array`], but on core arrays.
102/// In fact, it is implemented using `split_array` and surrounds the right-hand
103/// side with [`array_from_core`] and the output arrays with [`array_to_core`].
104///
105/// Also if you need to specify the size of an array you have to specifiy the
106/// full core array.
107///
108///
109/// # Syntax
110///
111/// ```text
112/// split_core_array!{
113/// let split \[
114/// ( <name> [ : <array-type> ] , )*
115/// \] = <value>;
116/// }
117/// ```
118///
119/// # Example
120///
121/// ```
122/// use array_fusion::split_core_array;
123///
124/// let data = [
125/// 0, 42, // foo
126/// 0x0, 0x0, 0x12, 0x34, // bar
127/// ];
128///
129/// // Split the array, core to core
130/// // The size of `foo` is inferred from the subsequent usage of it, whereas
131/// // the size of `bar` is explicitly specified.
132/// split_core_array! {
133/// let split [
134/// foo,
135/// bar: [_; 4],
136/// ] = data;
137/// };
138///
139/// // Use foo in a way to make it's size inferrable
140/// let foo = u16::from_be_bytes(foo);
141/// assert_eq!(foo, 42);
142///
143/// // Use bar, actually this would also infere its size, but we specified it
144/// // already above.
145/// assert_eq!(u32::from_be_bytes(bar), 0x1234);
146/// ```
147///
148#[macro_export]
149macro_rules! split_core_array {
150 (
151 let split [
152 $($name:ident $( : $ty:ty)? ),* $(,)?
153 ] = $data:expr $(;)?
154 ) => {
155
156 $crate::split_array!{
157 let split [
158 $($name),*
159 ] = $crate::array_from_core($data);
160 }
161
162 $(
163 let $name $( : $ty )? = $crate::array_to_core($name) ;
164 )*
165 };
166}
167
168/// Merge multiple [`Array`]s into one combined [`Array`].
169///
170/// Notice that each component Array's size must be known before hand.
171///
172/// The macro expects an array list `[a,b,c]` expression with each element
173/// being an `Array`.
174///
175/// The result of this macro will be a single `Array` value that contains
176/// the concatination of all vaules from all the given arrays.
177///
178/// This macro is the reversal of the [`split_array`] macro.
179///
180///
181/// # Syntax
182///
183/// ```text
184/// merge_array!{
185/// \[
186/// ( <array-vaule> , )*
187/// \];
188/// }
189/// ```
190///
191/// # Example
192///
193/// ```
194/// use hybrid_array::Array;
195/// use hybrid_array::sizes::U2;
196/// use hybrid_array::sizes::U4;
197/// use array_fusion::merge_array;
198///
199/// let foo: Array<_, U2> = Array([1, 2]);
200/// let bar: Array<_, U4> = Array([0x12, 0x34, 0x56, 0x78]);
201///
202/// let combi: Array<_,_> = merge_array!(
203/// [
204/// foo,
205/// bar,
206/// ]
207/// );
208///
209/// assert_eq!(combi, [
210/// 1, 2, // foo
211/// 0x12, 0x34, 0x56, 0x78, // bar
212/// ]);
213/// ```
214///
215///
216///
217#[macro_export]
218macro_rules! merge_array {
219 ([
220 $( $value:expr ),* $(,)?
221 ]) => {{
222 let empty = $crate::Array::<_ , $crate::sizes::U0>([]);
223
224 empty
225 $(
226 .concat({
227 let value: $crate::Array<_, _> = $value;
228 value
229 })
230 )*
231 }};
232}
233
234/// Merge core arrays into a combined core array
235///
236///
237///
238/// # Example
239///
240/// ```
241/// use array_fusion::merge_core_array;
242///
243/// let foo: [u8; 2] = [1, 2];
244/// let bar: [u8; 4] = [0x12, 0x34, 0x56, 0x78];
245///
246/// let combi = merge_core_array!(
247/// [
248/// foo,
249/// bar,
250/// ]
251/// );
252///
253/// assert_eq!(combi, [
254/// 1, 2, // foo
255/// 0x12, 0x34, 0x56, 0x78, // bar
256/// ]);
257/// ```
258///
259#[macro_export]
260macro_rules! merge_core_array {
261 ([
262 $( $value:expr ),* $(,)?
263 ]) => {
264 $crate::array_to_core(
265 $crate::merge_array!([
266 $(
267 $crate::array_from_core(
268 $value
269 )
270 ),*
271 ])
272 )
273 };
274}