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}