array_fusion/
chunks.rs

1//! Array of arrays utilities.
2
3
4use core::ops::Mul;
5
6pub use hybrid_array;
7use hybrid_array::Array;
8use hybrid_array::ArraySize;
9use hybrid_array::AssocArraySize;
10use hybrid_array::typenum::Prod;
11
12#[cfg(doc)]
13use crate::array_from_core;
14#[cfg(doc)]
15use crate::array_to_core;
16
17
18
19/// Flatten an array of arrays into a single contigues array.
20///
21/// # Examples
22///
23/// ```rust
24/// use array_fusion::hybrid_array::Array;
25/// use array_fusion::hybrid_array::sizes::{U2, U3, U6};
26/// use array_fusion::chunks::flatten;
27///
28/// let array_of_arrays: Array<Array<u8, U2>, U3> = Array([
29///     Array([1, 2]),
30///     Array([3, 4]),
31///     Array([5, 6]),
32/// ]);
33///
34/// let flattened: Array<u8, U6> = flatten(array_of_arrays);
35///
36/// assert_eq!(flattened, Array([1, 2, 3, 4, 5, 6]));
37/// ```
38pub fn flatten<T, I, O>(input: Array<Array<T, I>, O>) -> Array<T, Prod<I, O>>
39where
40	I: Mul<O>,
41	I::Output: ArraySize,
42	I: ArraySize,
43	O: ArraySize,
44	// TODO: find a way to lift this constraint
45	T: Default + Copy,
46{
47	let mut output = Array::default();
48
49	// TODO: is there a more efficient way to do this?
50
51	let mut offset = 0;
52	for array in input.iter() {
53		let len = array.len();
54		output[offset..offset + len].copy_from_slice(array);
55		offset += len;
56	}
57
58	output
59}
60
61/// Split a contigues array into an array of arrays.
62///
63///
64/// # Examples
65///
66/// ```rust
67/// use array_fusion::hybrid_array::Array;
68/// use array_fusion::hybrid_array::sizes::{U2, U3, U6};
69/// use array_fusion::chunks::chunks;
70///
71/// let input: Array<u8, U6> = Array([1, 2, 3, 4, 5, 6]);
72///
73/// let chunked: Array<Array<u8, U2>, U3> = chunks(input);
74///
75/// assert_eq!(chunked, Array([
76///     Array([1, 2]),
77///     Array([3, 4]),
78///     Array([5, 6]),
79/// ]));
80/// ```
81pub fn chunks<T, I, O>(input: Array<T, Prod<I, O>>) -> Array<Array<T, I>, O>
82where
83	I: Mul<O>,
84	I::Output: ArraySize,
85	I: ArraySize,
86	O: ArraySize,
87	// TODO: find a way to lift this constraint
88	T: Default + Copy,
89{
90	let mut output: Array<Array<T, I>, O> = Array::default();
91
92	let mut offset = 0;
93	for array in output.iter_mut() {
94		let len = array.len();
95		array.copy_from_slice(&input[offset..offset + len]);
96		offset += len;
97	}
98
99	output
100}
101
102/// Type alias for an `Array` of `Array`s using const generic sizes.
103///
104/// This is just a shorthand for `Array<Array<T, IT>, OT>`, where `IT` and `OT`
105/// are the respective `typenum` sizes for `I` and `O`.
106///
107/// This is mostly useful when working with const generics, to avoid having
108/// to manually map from const generics to `typenum` sizes.
109///
110/// # Example
111///
112/// ```rust
113/// use array_fusion::chunks::ArrayOfArrays;
114/// use array_fusion::hybrid_array::Array;
115/// use array_fusion::hybrid_array::sizes::{U2, U3};
116///
117/// let array_of_arrays: ArrayOfArrays<u8, 3, 2> =
118/// # Array([
119/// #    Array([10, 20, 30]),
120/// #    Array([40, 50, 60]),
121/// # ])
122///     /* -snip- */ ;
123/// // => equals the following type:
124/// let array_of_arrays: Array<Array<u8, U3>, U2> = array_of_arrays;
125/// ```
126pub type ArrayOfArrays<T, const I: usize, const O: usize> =
127	Array<Array<T, <[T; I] as AssocArraySize>::Size>, <[[T; I]; O] as AssocArraySize>::Size>;
128
129/// Converts an `Array` of `Array`s into a core array of arrays.
130///
131/// Notice this is similar to the [`array_to_core`] function, but works on
132/// chunks (i.e. arrays of arrays).
133pub fn chunks_to_core<T, const I: usize, const O: usize>(
134	input: ArrayOfArrays<T, I, O>,
135) -> [[T; I]; O]
136where
137	[T; I]: AssocArraySize,
138	[[T; I]; O]: AssocArraySize,
139	<[T; I] as AssocArraySize>::Size: ArraySize<ArrayType<T> = [T; I]>,
140	<[[T; I]; O] as AssocArraySize>::Size: ArraySize<ArrayType<[T; I]> = [[T; I]; O]>,
141{
142	let a = input.map(|array| array.0);
143
144	a.0
145}
146
147/// Converts a core array of arrays into an `Array` of `Array`s.
148///
149/// This is similar to the [`array_from_core`] function, but works on
150/// chunks (i.e. arrays of arrays).
151pub fn chunks_from_core<T, const I: usize, const O: usize>(
152	input: [[T; I]; O],
153) -> ArrayOfArrays<T, I, O>
154where
155	[T; I]: AssocArraySize,
156	[[T; I]; O]: AssocArraySize,
157	<[T; I] as AssocArraySize>::Size: ArraySize<ArrayType<T> = [T; I]>,
158	<[[T; I]; O] as AssocArraySize>::Size: ArraySize<ArrayType<[T; I]> = [[T; I]; O]>,
159{
160	Array(input).map(|array| Array(array))
161}