vectoreyes/
array_utils.rs

1//! Perform manually unrolled operations on arrays.
2//!
3//! Look at [ArrayUnrolledExt] for the meat of this module.
4
5/// A type which can be used to require that unrolled operations exist for a given array size.
6///
7/// # Example
8/// ```
9/// use vectoreyes::array_utils::*;
10/// pub fn make_fun_array<const N: usize>() -> [usize; N]
11///     where ArrayUnrolledOps: UnrollableArraySize<N>
12/// {
13///     <[usize; N]>::array_generate(|i| i + 10)
14/// }
15/// assert_eq!(make_fun_array::<4>(), [10, 11, 12, 13]);
16/// ```
17pub enum ArrayUnrolledOps {}
18
19/// A marker trait you shouldn't invoke directly. See the module documentation for more info.
20pub trait UnrollableArraySize<const N: usize> {
21    #[doc(hidden)]
22    fn array_generate<T, F: FnMut(usize) -> T>(f: F) -> [T; N];
23    #[doc(hidden)]
24    fn array_map<T, U, F: FnMut(T) -> U>(arr: [T; N], f: F) -> [U; N];
25    #[doc(hidden)]
26    fn array_map_result<T, U, E, F: FnMut(T) -> Result<U, E>>(
27        arr: [T; N],
28        f: F,
29    ) -> Result<[U; N], E>;
30    #[doc(hidden)]
31    fn array_fold<T, U, F: FnMut(U, T) -> U>(arr: [T; N], init: U, f: F) -> U;
32    #[doc(hidden)]
33    fn array_zip<T1, T2>(arr1: [T1; N], arr2: [T2; N]) -> [(T1, T2); N];
34    #[doc(hidden)]
35    fn array_enumerate<T>(arr: [T; N]) -> [(usize, T); N];
36    #[doc(hidden)]
37    fn array_as_ref<T>(arr: &[T; N]) -> [&T; N];
38    #[doc(hidden)]
39    fn array_as_mut<T>(arr: &mut [T; N]) -> [&mut T; N];
40}
41
42/// Manually unrolled operations on arrays.
43///
44/// To ensure that operations are unrolled, consider annotating your closures with
45/// `#[inline(always)]`. See the examples below for more details.
46pub trait ArrayUnrolledExt<T, const N: usize>: Sized {
47    /// Perform some computation over the elements of an array.
48    #[inline(always)]
49    fn array_for_each<F: FnMut(T)>(self, f: F) {
50        let _ = self.array_map(f);
51    }
52    /// Generate an array by filling the entries.
53    /// # Example
54    /// ```
55    /// use vectoreyes::array_utils::*;
56    /// let arr = <[usize; 2]>::array_generate(#[inline(always)] |i| i + 1);
57    /// assert_eq!(arr, [1, 2]);
58    /// ```
59    fn array_generate<F: FnMut(usize) -> T>(f: F) -> [T; N];
60    /// Map over elements of an array.
61    /// # Example
62    /// ```
63    /// use vectoreyes::array_utils::*;
64    /// let arr = [0, 1];
65    /// assert_eq!(arr.array_map(#[inline(always)] |x| x + 1), [1, 2]);
66    /// ```
67    fn array_map<U, F: FnMut(T) -> U>(self, f: F) -> [U; N];
68    /// Map over elements of an array, halting on the first error.
69    /// # Example
70    /// ```
71    /// use vectoreyes::array_utils::*;
72    /// let arr = [0, 1];
73    /// assert_eq!(arr.array_map_result::<u32, u32, _>(#[inline(always)] |x| Err(x)), Err(0));
74    /// assert_eq!(arr.array_map_result::<u32, u32, _>(#[inline(always)] |x| Ok(x)), Ok([0, 1]));
75    /// ```
76    fn array_map_result<U, E, F: FnMut(T) -> Result<U, E>>(self, f: F) -> Result<[U; N], E>;
77    /// Fold over an array.
78    /// # Example
79    /// ```
80    /// use vectoreyes::array_utils::*;
81    /// let out = [1, 2, 3].array_fold(0, #[inline(always)] |acu, x| acu + x);
82    /// assert_eq!(out, 6);
83    /// ```
84    fn array_fold<U, F: FnMut(U, T) -> U>(self, init: U, f: F) -> U;
85    /// Zip two arrays together.
86    /// # Example
87    /// ```
88    /// use vectoreyes::array_utils::*;
89    /// assert_eq!(
90    ///     ['a', 'b', 'c'].array_zip(['x', 'y', 'z']),
91    ///     [('a', 'x'), ('b', 'y'), ('c', 'z')]
92    /// );
93    /// ```
94    fn array_zip<T2>(self, arr2: [T2; N]) -> [(T, T2); N];
95    /// Produce an array where each element is a tuple containing each element's index.
96    /// # Example
97    /// ```
98    /// use vectoreyes::array_utils::*;
99    /// assert_eq!(
100    ///     ['a', 'b', 'c'].array_enumerate(),
101    ///     [(0, 'a'), (1, 'b'), (2, 'c')],
102    /// );
103    /// ```
104    fn array_enumerate(self) -> [(usize, T); N];
105    /// Produce an array containing references to the initial array.
106    fn array_as_ref(&self) -> [&T; N];
107    /// Produce an array containing mutable references to the initial array.
108    fn array_as_mut(&mut self) -> [&mut T; N];
109}
110impl<T, const N: usize> ArrayUnrolledExt<T, N> for [T; N]
111where
112    ArrayUnrolledOps: UnrollableArraySize<N>,
113{
114    #[inline(always)]
115    fn array_generate<F: FnMut(usize) -> T>(f: F) -> [T; N] {
116        ArrayUnrolledOps::array_generate(f)
117    }
118    #[inline(always)]
119    fn array_map<U, F: FnMut(T) -> U>(self, f: F) -> [U; N] {
120        ArrayUnrolledOps::array_map(self, f)
121    }
122    #[inline(always)]
123    fn array_map_result<U, E, F: FnMut(T) -> Result<U, E>>(self, f: F) -> Result<[U; N], E> {
124        ArrayUnrolledOps::array_map_result(self, f)
125    }
126    #[inline(always)]
127    fn array_fold<U, F: FnMut(U, T) -> U>(self, init: U, f: F) -> U {
128        ArrayUnrolledOps::array_fold(self, init, f)
129    }
130    #[inline(always)]
131    fn array_zip<T2>(self, arr2: [T2; N]) -> [(T, T2); N] {
132        ArrayUnrolledOps::array_zip(self, arr2)
133    }
134    #[inline(always)]
135    fn array_enumerate(self) -> [(usize, T); N] {
136        ArrayUnrolledOps::array_enumerate(self)
137    }
138    #[inline(always)]
139    fn array_as_ref(&self) -> [&T; N] {
140        ArrayUnrolledOps::array_as_ref(self)
141    }
142    #[inline(always)]
143    fn array_as_mut(&mut self) -> [&mut T; N] {
144        ArrayUnrolledOps::array_as_mut(self)
145    }
146}
147
148/// An array for which vectoreyes has implemented adjacent pairing operations
149///
150/// This is implemented for all arrays of size 0..=32
151pub trait ArrayAdjacentPairs {
152    /// The type contained in this array
153    type T;
154    /// An array which is `[Self::T; ceil(Self::LEN / 2)]`
155    type AdjacentPairs;
156
157    /// Turn an array into an array of pairs where each element is paired with an adjacent element.
158    /// If the array has odd length, use the fallback.
159    /// # Example
160    /// ```
161    /// use vectoreyes::array_utils::*;
162    /// assert_eq!(
163    ///     [0, 1, 2, 3].pair_adjacent_maybe_odd(42),
164    ///     [(0, 1), (2, 3)]
165    /// );
166    /// assert_eq!(
167    ///     [0, 1, 2, 3, 4].pair_adjacent_maybe_odd(42),
168    ///     [(0, 1), (2, 3), (4, 42)]
169    /// );
170    /// ```
171    fn pair_adjacent_maybe_odd(self, fallback: Self::T) -> Self::AdjacentPairs;
172}
173
174/// An even-sized array.
175pub trait EvenArrayAdjacentPairs: ArrayAdjacentPairs {
176    /// Turn an array into an array of pairs where each element is paired with an adjacent element.
177    /// # Example
178    /// ```
179    /// use vectoreyes::array_utils::*;
180    /// assert_eq!(
181    ///     [0, 1, 2, 3].pair_adjacent(),
182    ///     [(0, 1), (2, 3)]
183    /// );
184    /// ```
185    fn pair_adjacent(self) -> Self::AdjacentPairs;
186}
187
188mod impls {
189    include!(concat!(env!("OUT_DIR"), "/array_utils_impls.rs"));
190}