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}