hybrid_array/
iter.rs

1//! Support for constructing arrays using a provided iterator function and other iterator-related
2//! functionality.
3
4use crate::{Array, ArraySize};
5use core::{
6    fmt,
7    mem::size_of,
8    slice::{Iter, IterMut},
9};
10
11/// Couldn't construct an array from an iterator because the number of items in the iterator
12/// didn't match the array size.
13#[derive(Clone, Copy, Debug)]
14pub struct TryFromIteratorError;
15
16impl fmt::Display for TryFromIteratorError {
17    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
18        f.write_str("iterator did not contain the correct number of items for the array size")
19    }
20}
21
22impl core::error::Error for TryFromIteratorError {}
23
24impl<T, U> Array<T, U>
25where
26    U: ArraySize,
27{
28    /// Construct an array from the given iterator, returning [`TryFromIteratorError`] in the event
29    /// that the number of items in the iterator does not match the array size.
30    ///
31    /// # Errors
32    ///
33    /// Returns [`TryFromIteratorError`] in the event the iterator does not return a number of
34    /// items which is exactly equal to the array size.
35    pub fn try_from_iter<I: IntoIterator<Item = T>>(iter: I) -> Result<Self, TryFromIteratorError> {
36        let mut iter = iter.into_iter();
37        let ret = Self::try_from_fn(|_| iter.next().ok_or(TryFromIteratorError))?;
38
39        match iter.next() {
40            None => Ok(ret),
41            Some(_) => Err(TryFromIteratorError),
42        }
43    }
44}
45
46impl<T, U> FromIterator<T> for Array<T, U>
47where
48    U: ArraySize,
49{
50    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
51        let mut iter = iter.into_iter();
52        let ret = Self::from_fn(|_| {
53            iter.next()
54                .expect("iterator should have enough items to fill array")
55        });
56
57        assert!(
58            iter.next().is_none(),
59            "too many items in iterator to fit in array"
60        );
61
62        ret
63    }
64}
65
66impl<T, U> IntoIterator for Array<T, U>
67where
68    U: ArraySize,
69{
70    type Item = T;
71    type IntoIter = <U::ArrayType<T> as IntoIterator>::IntoIter;
72
73    /// Creates a consuming iterator, that is, one that moves each value out of the array (from
74    /// start to end).
75    ///
76    /// The array cannot be used after calling this unless `T` implements `Copy`, so the whole
77    /// array is copied.
78    #[inline]
79    fn into_iter(self) -> Self::IntoIter {
80        self.0.into_iter()
81    }
82}
83
84impl<'a, T, U> IntoIterator for &'a Array<T, U>
85where
86    U: ArraySize,
87{
88    type Item = &'a T;
89    type IntoIter = Iter<'a, T>;
90
91    #[inline]
92    fn into_iter(self) -> Iter<'a, T> {
93        self.iter()
94    }
95}
96
97impl<'a, T, U> IntoIterator for &'a mut Array<T, U>
98where
99    U: ArraySize,
100{
101    type Item = &'a mut T;
102    type IntoIter = IterMut<'a, T>;
103
104    #[inline]
105    fn into_iter(self) -> IterMut<'a, T> {
106        self.iter_mut()
107    }
108}
109
110impl<T, U, V> Array<Array<T, U>, V>
111where
112    U: ArraySize,
113    V: ArraySize,
114{
115    /// Takes a `&mut Array<Array<T, N>,M>`, and flattens it to a `&mut [T]`.
116    ///
117    /// # Panics
118    ///
119    /// This panics if the length of the resulting slice would overflow a `usize`.
120    ///
121    /// This is only possible when flattening a slice of arrays of zero-sized
122    /// types, and thus tends to be irrelevant in practice. If
123    /// `size_of::<T>() > 0`, this will never panic.
124    ///
125    /// # Examples
126    ///
127    /// ```
128    /// use hybrid_array::{Array, typenum::U3};
129    ///
130    /// fn add_5_to_all(slice: &mut [i32]) {
131    ///     for i in slice {
132    ///         *i += 5;
133    ///     }
134    /// }
135    ///
136    /// let mut array: Array<Array<i32, U3>, U3> = Array([Array([1_i32, 2, 3]), Array([4, 5, 6]), Array([7, 8, 9])]);
137    /// add_5_to_all(array.as_flattened_mut());
138    /// assert_eq!(array, Array([Array([6, 7, 8]), Array([9, 10, 11]), Array([12, 13, 14])]));
139    /// ```
140    pub fn as_flattened_mut(&mut self) -> &mut [T] {
141        let len = if size_of::<T>() == 0 {
142            self.len()
143                .checked_mul(U::USIZE)
144                .expect("slice len overflow")
145        } else {
146            // SAFETY: `self.len() * N` cannot overflow because `self` is
147            // already in the address space.
148            unsafe { self.len().unchecked_mul(U::USIZE) }
149        };
150        // SAFETY: `[T]` is layout-identical to `[T; U]`
151        unsafe { core::slice::from_raw_parts_mut(self.as_mut_ptr().cast(), len) }
152    }
153
154    /// Takes a `&Array<Array<T, N>, >>`, and flattens it to a `&[T]`.
155    ///
156    /// # Panics
157    ///
158    /// This panics if the length of the resulting slice would overflow a `usize`.
159    ///
160    /// This is only possible when flattening a slice of arrays of zero-sized
161    /// types, and thus tends to be irrelevant in practice. If
162    /// `size_of::<T>() > 0`, this will never panic.
163    ///
164    /// # Examples
165    ///
166    /// ```
167    /// use hybrid_array::{Array, typenum::{U0, U2, U3, U5, U10}};
168    ///
169    /// let a: Array<Array<usize, U3>, U2> = Array([Array([1, 2, 3]), Array([4, 5, 6])]);
170    /// assert_eq!(a.as_flattened(), &[1, 2, 3, 4, 5, 6]);
171    ///
172    /// let b: Array<Array<usize, U2>, U3> = Array([Array([1, 2]), Array([3, 4]), Array([5, 6])]);
173    /// assert_eq!(a.as_flattened(), b.as_flattened());
174    ///
175    /// let c: Array<[usize; 2], U3> = Array([[1, 2], [3, 4], [5, 6]]);
176    /// assert_eq!(a.as_flattened(), c.as_flattened());
177    ///
178    /// let slice_of_empty_arrays: &Array<Array<i32, U5>, U0> = &Array::from_fn(|_| Array([1, 2, 3, 4, 5]));
179    /// assert!(slice_of_empty_arrays.as_flattened().is_empty());
180    ///
181    /// let empty_slice_of_arrays: &Array<Array<u32, U10>, U0>  = &Array([]);
182    /// assert!(empty_slice_of_arrays.as_flattened().is_empty());
183    /// ```
184    pub fn as_flattened(&self) -> &[T] {
185        let len = if size_of::<T>() == 0 {
186            self.len()
187                .checked_mul(U::USIZE)
188                .expect("slice len overflow")
189        } else {
190            // SAFETY: `self.len() * N` cannot overflow because `self` is
191            // already in the address space.
192            unsafe { self.len().unchecked_mul(U::USIZE) }
193        };
194        // SAFETY: `[T]` is layout-identical to `[T; U]`
195        unsafe { core::slice::from_raw_parts(self.as_ptr().cast(), len) }
196    }
197}