array_ext/
lib.rs

1//! Extra functionality for Rust arrays.
2#![cfg_attr(feature = "nightly", feature(generic_const_exprs))]
3
4/// Generic array type.
5///
6/// This trait allows passing arrays by value in a generic way without turning them into slices,
7/// so the functions get monomorphized for a specific size.
8///
9/// # Examples
10/// ```
11/// use array_ext::Array;
12///
13/// fn average<T: Array<f32>>(arr: T) -> f32
14/// {
15///     let n = arr.len() as f32;
16///     arr.foldl(0.0, |acc, val| acc + val) / n
17/// }
18///
19/// assert!((average([8.96, 3.14, 17.9]) - 10.0).abs() < f32::EPSILON);
20/// ```
21pub trait Array<T> {
22    /// Returns the number of elements in the array.
23    fn len(&self) -> usize;
24
25    /// Returns true if the array has a length of 0
26    fn is_empty(&self) -> bool;
27
28    /// Returns the first element of the array, or `None` if it is empty.
29    fn first(&self) -> Option<&T>;
30
31    /// Returns a mutable pointer to the first element of the array, or `None` if it is empty.
32    fn first_mut(&mut self) -> Option<&mut T>;
33
34    /// Returns the last element of the array, or `None` if it is empty.
35    fn last(&self) -> Option<&T>;
36
37    /// Returns a mutable pointer to the last element of the array, or `None` if it is empty.
38    fn last_mut(&mut self) -> Option<&mut T>;
39
40    /// Returns the element of an array at the given index, or `None` if the index is out of bounds.
41    fn get(&self, index: usize) -> Option<&T>;
42
43    /// Returns a mutable reference to the element at the given index, or `None` if the index is out of bounds.
44    fn get_mut(&mut self, index: usize) -> Option<&mut T>;
45
46    /// Extracts a slice containing the entire array.
47    fn as_slice(&self) -> &[T];
48
49    /// Extracts a mutable slice of the entire array.
50    fn as_mut_slice(&mut self) -> &mut [T];
51
52    /// Takes a `FnMut(T) -> T` closure and creates a new array by calling that closure on each element.
53    fn map_<F>(self, f: F) -> Self
54    where
55        F: FnMut(T) -> T,
56        Self: Sized;
57
58    /// Applies a function over the entire array, producing a single final value.
59    fn foldl<A, F>(self, acc: A, f: F) -> A
60    where
61        F: FnMut(A, T) -> A,
62        Self: Sized;
63
64    /// Applies a function over the entire array (in reverse order), producing a single final value.
65    fn foldr<A, F>(self, acc: A, f: F) -> A
66    where
67        F: FnMut(A, T) -> A,
68        Self: Sized;
69
70    /// Resizes the array, filling new spaces at the end with the specified element.
71    fn resize<const S: usize>(self, elem: T) -> [T; S]
72    where
73        T: Clone,
74        Self: Sized;
75
76    /// Resizes the array, filling new spaces at the end with the values generated from a function.
77    fn resize_with<F, const S: usize>(self, f: F) -> [T; S]
78    where
79        F: FnMut(usize) -> T,
80        Self: Sized;
81
82    #[deprecated(since = "0.4.0", note = "use std::array::from_fn instead")]
83    /// Creates a new array using the provided closure.
84    fn from_fn<F>(f: F) -> Self
85    where
86        F: FnMut(usize) -> T,
87        Self: Sized;
88
89    /// Creates an array by extracting elements from the provided iterator.
90    fn from_iter(iter: impl Iterator<Item = T>) -> Option<Self>
91    where
92        Self: Sized;
93}
94
95impl<T, const N: usize> Array<T> for [T; N] {
96    #[inline]
97    fn len(&self) -> usize {
98        N
99    }
100
101    #[inline]
102    fn is_empty(&self) -> bool {
103        N == 0
104    }
105
106    #[inline]
107    fn first(&self) -> Option<&T> {
108        if N > 0 {
109            Some(&self[0])
110        } else {
111            None
112        }
113    }
114
115    #[inline]
116    fn first_mut(&mut self) -> Option<&mut T> {
117        if N > 0 {
118            Some(&mut self[0])
119        } else {
120            None
121        }
122    }
123
124    #[inline]
125    fn last(&self) -> Option<&T> {
126        if N > 0 {
127            Some(&self[N - 1])
128        } else {
129            None
130        }
131    }
132
133    #[inline]
134    fn last_mut(&mut self) -> Option<&mut T> {
135        if N > 0 {
136            Some(&mut self[N - 1])
137        } else {
138            None
139        }
140    }
141
142    #[inline]
143    fn get(&self, index: usize) -> Option<&T> {
144        if index < N {
145            Some(&self[index])
146        } else {
147            None
148        }
149    }
150
151    #[inline]
152    fn get_mut(&mut self, index: usize) -> Option<&mut T> {
153        if index < N {
154            Some(&mut self[index])
155        } else {
156            None
157        }
158    }
159
160    #[inline]
161    fn as_slice(&self) -> &[T] {
162        self
163    }
164
165    #[inline]
166    fn as_mut_slice(&mut self) -> &mut [T] {
167        self
168    }
169
170    #[inline]
171    fn map_<F>(self, f: F) -> Self
172    where
173        F: FnMut(T) -> T,
174    {
175        self.map(f)
176    }
177
178    #[inline]
179    fn foldl<A, F>(self, mut acc: A, mut f: F) -> A
180    where
181        F: FnMut(A, T) -> A,
182    {
183        for val in self {
184            acc = f(acc, val);
185        }
186        acc
187    }
188
189    #[inline]
190    fn foldr<A, F>(self, mut acc: A, mut f: F) -> A
191    where
192        F: FnMut(A, T) -> A,
193    {
194        for val in self.into_iter().rev() {
195            acc = f(acc, val);
196        }
197        acc
198    }
199
200    #[inline]
201    fn resize<const S: usize>(self, elem: T) -> [T; S]
202    where
203        T: Clone,
204    {
205        self.resize_with(|_| elem.clone())
206    }
207
208    #[inline]
209    fn resize_with<F, const S: usize>(self, mut f: F) -> [T; S]
210    where
211        F: FnMut(usize) -> T,
212    {
213        let mut a = self.into_iter();
214        std::array::from_fn(|i| if i < N { a.next().unwrap() } else { f(i) })
215    }
216
217    #[inline]
218    fn from_fn<F>(f: F) -> Self
219    where
220        F: FnMut(usize) -> T,
221    {
222        std::array::from_fn(f)
223    }
224
225    #[inline]
226    fn from_iter(mut iter: impl Iterator<Item = T>) -> Option<Self> {
227        let mut v = Vec::with_capacity(N); //FIXME: use try_map when it's stable
228        for _ in 0..N {
229            v.push(iter.next()?);
230        }
231        v.try_into().ok()
232    }
233}
234
235/// Array with size information on the type.
236pub trait ArrayN<T, const N: usize>: Array<T> {
237    /// Merges elements with another array by calling a `FnMut(T, U) -> V` closure for each pair.
238    fn zip_with<U, V, F>(self, other: [U; N], f: F) -> [V; N]
239    where
240        F: FnMut(T, U) -> V,
241        Self: Sized;
242
243    /// Converts this object into it's concrete array type.
244    fn downcast(self) -> [T; N];
245
246    /// Gets a reference to this object's concrete array type.
247    fn downcast_ref(&self) -> &[T; N];
248
249    /// Gets a mutable reference to this object's concrete array type.
250    fn downcast_mut(&mut self) -> &mut [T; N];
251
252    /// Concatenates two arrays together.
253    #[cfg(feature = "nightly")]
254    fn concat<const M: usize>(self, other: [T; M]) -> [T; N + M]
255    where
256        Self: Sized;
257
258    /// Splits an array into two sub-arrays.
259    #[cfg(feature = "nightly")]
260    fn split<const P: usize>(self) -> ([T; P], [T; N - P])
261    where
262        Self: Sized;
263}
264
265impl<T, const N: usize> ArrayN<T, N> for [T; N] {
266    #[inline]
267    fn zip_with<U, V, F>(self, other: [U; N], mut f: F) -> [V; N]
268    where
269        F: FnMut(T, U) -> V,
270    {
271        let mut b = other.into_iter();
272        self.map(|a| f(a, b.next().unwrap()))
273    }
274
275    #[inline]
276    fn downcast(self) -> [T; N] {
277        self
278    }
279
280    #[inline]
281    fn downcast_ref(&self) -> &[T; N] {
282        self
283    }
284
285    #[inline]
286    fn downcast_mut(&mut self) -> &mut [T; N] {
287        self
288    }
289
290    #[cfg(feature = "nightly")]
291    fn concat<const M: usize>(self, other: [T; M]) -> [T; N + M] {
292        let mut a = self.into_iter();
293        let mut b = other.into_iter();
294        std::array::from_fn(|i| if i < N { a.next() } else { b.next() }.unwrap())
295    }
296
297    #[cfg(feature = "nightly")]
298    fn split<const P: usize>(self) -> ([T; P], [T; N - P]) {
299        let mut a = self.into_iter();
300        let l = [(); P].map(|_| a.next().unwrap());
301        let r = [(); N - P].map(|_| a.next().unwrap());
302        (l, r)
303    }
304}
305
306#[cfg(test)]
307mod tests;