array_fusion/
lib.rs

1#![no_std]
2//! Array fusion and fission utilies.
3//!
4//! This crate contains utilities to combine multiple arrays together
5//! (aka fusion) as well as splitting them (aka fission).
6//!
7//! This crate is based on the [`hybrid_array`] crate, which provides
8//! all the building blocks for this crate. The `hybrid_array` crate
9//! has its own [`Array`] type for an array type that uses the
10//! `typenum` type parameters to represent the size of the array,
11//! instead of the const generic array size of classic "core" arrays.
12//!
13//! The reason of using `typenum` is that you can use `typenum`s
14//! type parameters in generic context unlike the classic const
15//! generics which at the time of writing (2025) have still many
16//! limitations that limits the usability of them in generic context.
17//!
18//! However when working within the limited scopes (and in
19//! non-generic context) the "core" arrays have much better ergonomics.
20//! Due to this ambivalence, this crate offers most functions in two variants
21//! the "normal" way is baed on `hybrid_array`s `Array` and the "core" variant
22//! the work with the ordinary arrays.
23//!
24//! This crate also offers convenient functions for converting between the
25//! "core" and `hybrid_array` arrays via [`array_from_core`] and
26//! [`array_to_core`]. Their trait bounds demonstrate the complexity of
27//! interchanging between these type. Tho, if you have a concrete array all
28//! these bounds can be inferred, and if you dont have a concrete array e.g.
29//! due to generic context, you better use the `hybrid_array` array.
30//!
31
32pub use hybrid_array;
33// Hidden import used by macros.
34#[doc(hidden)]
35pub use hybrid_array::Array;
36use hybrid_array::ArraySize;
37use hybrid_array::AssocArraySize;
38// Hidden import used by macros.
39#[doc(hidden)]
40pub use hybrid_array::sizes;
41// Use statement for documentation.
42#[cfg(doc)]
43use hybrid_array::typenum;
44
45
46
47pub mod bytes;
48pub mod chunks;
49mod macros;
50
51
52
53/// Convert a core array into an [`Array`].
54///
55/// This is mostly equivalent to `Array(array)`, but it also infers the size of
56/// the `Array`.
57///
58/// # Example
59///
60/// ```
61/// use hybrid_array::Array;
62/// use array_fusion::array_from_core;
63///
64/// let data = [0, 42, 0x0, 0x0, 0x12, 0x34];
65/// // Notice that the size is inferred
66/// let hybird: Array<u8, _> = array_from_core(data);
67///
68/// assert_eq!(hybird, Array(data));
69/// ```
70///
71pub fn array_from_core<T, const N: usize>(
72	array: [T; N],
73) -> Array<T, <[T; N] as AssocArraySize>::Size>
74where
75	[T; N]: AssocArraySize,
76	<[T; N] as AssocArraySize>::Size: ArraySize<ArrayType<T> = [T; N]>,
77{
78	Array(array)
79}
80
81/// Convert an `Array` into a core array.
82///
83/// This is mostly equivalent to `array.0`, but it also infers the size of
84/// the `Array` from the returned core array, if possible.
85///
86/// # Example
87///
88/// ```
89/// use hybrid_array::Array;
90/// use array_fusion::array_to_core;
91///
92/// let data = [0, 42, 0x0, 0x0, 0x12, 0x34];
93/// // Notice that the size is inferred due to the use of `array_to_core` below
94/// let hybird: Array<u8, _> = Array(data);
95///
96/// // Allows to infer the size of `hybird` based on the type of `core`
97/// let core: [u8; 6] = array_to_core(hybird);
98///
99/// assert_eq!(core, data);
100/// ```
101///
102pub fn array_to_core<T, const N: usize>(array: Array<T, <[T; N] as AssocArraySize>::Size>) -> [T; N]
103where
104	[T; N]: AssocArraySize,
105	<[T; N] as AssocArraySize>::Size: ArraySize<ArrayType<T> = [T; N]>,
106{
107	array.0
108}
109
110
111
112#[cfg(test)]
113mod test {
114	use hybrid_array::sizes::U0;
115	use hybrid_array::sizes::U1;
116	use hybrid_array::sizes::U2;
117	use hybrid_array::sizes::U3;
118	use hybrid_array::sizes::U4;
119	use hybrid_array::sizes::U10;
120
121	use super::*;
122
123	#[test]
124	fn test_split_array_manual() {
125		let data = [
126			0, 42, // foo
127			0x0, 0x0, 0x12, 0x34, // bar
128			0,    // padding
129			b'a', b'b', b'c', // alpha
130		];
131		let data = Array::<_, U10>(data);
132
133		let (foo, rest) = data.split::<U2>();
134		assert_eq!(u16::from_be_bytes(foo.0), 42);
135
136		let (bar, rest) = rest.split::<U4>();
137		assert_eq!(u32::from_be_bytes(bar.0), 0x1234);
138
139		let (_pad, rest) = rest.split::<U1>();
140
141		let (alpha, rest) = rest.split::<U3>();
142		assert_eq!(alpha.0, *b"abc");
143
144		// Assert that we split the entire array
145		let _rest: Array<_, U0> = rest;
146	}
147
148	#[test]
149	fn test_split_array() {
150		let data = [
151			0, 42, // foo
152			0x0, 0x0, 0x12, 0x34, // bar
153			0,    // padding
154			b'a', b'b', b'c', // alpha
155		];
156		split_array! {
157			let split [
158				foo,
159				bar,
160				_pad: array U1,
161				alpha: array U3,
162			] = Array::<_, U10>(data);
163		}
164		assert_eq!(u16::from_be_bytes(array_to_core(foo)), 42);
165		assert_eq!(u32::from_be_bytes(array_to_core(bar)), 0x1234);
166		assert_eq!(alpha.0, *b"abc");
167	}
168
169	#[test]
170	fn test_split_core_array() {
171		let data = [
172			0, 42, // foo
173			0x0, 0x0, 0x12, 0x34, // bar
174			0,    // padding
175			b'a', b'b', b'c', // alpha
176		];
177		split_core_array! {
178			let split [
179				foo,
180				bar,
181				_pad: [u8;1],
182				alpha,
183			] = data;
184		}
185		assert_eq!(u16::from_be_bytes(foo), 42);
186		assert_eq!(u32::from_be_bytes(bar), 0x1234);
187		assert_eq!(alpha, *b"abc");
188	}
189
190	#[test]
191	fn test_merge_array() {
192		let foo = Array::<_, U2>(u16::to_be_bytes(42));
193		let bar = Array::<_, U4>(u32::to_be_bytes(0x1234));
194		let padding = Array::<_, U1>([0]);
195		let alpha = Array::<_, U3>(*b"abc");
196
197		let data = merge_array!([foo, bar, padding, alpha]);
198
199		assert_eq!(
200			data,
201			Array([
202				0, 42, // foo
203				0x0, 0x0, 0x12, 0x34, // bar
204				0,    // padding
205				b'a', b'b', b'c', // alpha
206			])
207		);
208	}
209
210	#[test]
211	fn test_merge_core_array() {
212		let foo = u16::to_be_bytes(42);
213		let bar = u32::to_be_bytes(0x1234);
214		let padding = [0];
215		let alpha = *b"abc";
216
217		let data = merge_core_array!([foo, bar, padding, alpha]);
218
219		assert_eq!(
220			data,
221			[
222				0, 42, // foo
223				0x0, 0x0, 0x12, 0x34, // bar
224				0,    // padding
225				b'a', b'b', b'c', // alpha
226			]
227		);
228	}
229
230	#[test]
231	fn test_split_emtpy_array() {
232		let data: Array<u8, U0> = Array([]);
233
234		split_array! {
235			let split [ ] = data;
236		}
237	}
238
239	#[test]
240	fn test_split_emtpy_core_array() {
241		let data: [u8; 0] = [];
242
243		split_core_array! {
244			let split [ ] = data;
245		}
246	}
247}