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}