Mon, 24 Oct 2022 10:52:19 +0300
Added type for numerical errors
0 | 1 | /// |
2 | /// Mapping utilities | |
3 | /// | |
4 | ||
5 | use std::mem::MaybeUninit; | |
6 | use itertools::izip; | |
7 | ||
8 | pub trait FixedLength<const N : usize> { | |
9 | type Elem; | |
10 | type Iter : Iterator<Item=Self::Elem>; | |
11 | fn fl_iter(self) -> Self::Iter; | |
12 | } | |
13 | ||
14 | pub trait FixedLengthMut<const N : usize> : FixedLength<N> { | |
15 | type IterMut<'a> : Iterator<Item=&'a mut Self::Elem> where Self : 'a; | |
16 | fn fl_iter_mut(&mut self) -> Self::IterMut<'_>; | |
17 | } | |
18 | ||
19 | impl<A, const N : usize> FixedLength<N> for [A; N] { | |
20 | type Elem = A; | |
21 | type Iter = std::array::IntoIter<A, N>; | |
22 | #[inline] | |
23 | fn fl_iter(self) -> Self::Iter { | |
24 | self.into_iter() | |
25 | } | |
26 | } | |
27 | ||
28 | impl<A, const N : usize> FixedLengthMut<N> for [A; N] { | |
29 | type IterMut<'a> = std::slice::IterMut<'a, A> where A : 'a; | |
30 | #[inline] | |
31 | fn fl_iter_mut(&mut self) -> Self::IterMut<'_> { | |
32 | self.iter_mut() | |
33 | } | |
34 | } | |
35 | ||
36 | impl<'a, A, const N : usize> FixedLength<N> for &'a [A; N] { | |
37 | type Elem = &'a A; | |
38 | type Iter = std::slice::Iter<'a, A>; | |
39 | #[inline] | |
40 | fn fl_iter(self) -> Self::Iter { | |
41 | self.iter() | |
42 | } | |
43 | } | |
44 | ||
45 | macro_rules! tuple_or_singleton { | |
46 | ($a:ident,) => { $a }; | |
47 | ($($a:ident),+) => { ($($a),+) } | |
48 | } | |
49 | ||
50 | macro_rules! make_mapmany { | |
51 | ($name:ident, $name_indexed:ident, $var0:ident $($var:ident)* ; | |
52 | $etype0:ident $($etype:ident)*, $ctype0:ident $($ctype:ident)*) => { | |
53 | /// Map over multiple [`FixedLength`] containers, returning an array. | |
54 | #[inline] | |
55 | pub fn $name< | |
56 | $etype0, | |
57 | $($etype,)* | |
58 | $ctype0 : FixedLength<N,Elem=$etype0>, | |
59 | $($ctype : FixedLength<N,Elem=$etype>,)* | |
60 | Res, | |
61 | const N : usize | |
62 | >( | |
63 | $var0 : $ctype0, | |
64 | $($var : $ctype,)* | |
65 | f : impl Fn($etype0, $($etype),*) -> Res | |
66 | ) -> [Res; N] { | |
67 | let zipit = izip!($var0.fl_iter(), $($var.fl_iter()),*); | |
68 | let map = zipit.map(|tuple_or_singleton!($var0, $($var),*)| f($var0, $($var),*)); | |
69 | collect_into_array_unchecked(map) | |
70 | } | |
71 | ||
72 | /// Map over multiple [`FixedLength`] containers, returning an array. | |
73 | /// This version also passes the index to the mapping function. | |
74 | #[inline] | |
75 | pub fn $name_indexed< | |
76 | $etype0, | |
77 | $($etype,)* | |
78 | $ctype0 : FixedLength<N,Elem=$etype0>, | |
79 | $($ctype : FixedLength<N,Elem=$etype>,)* | |
80 | Res, | |
81 | const N : usize | |
82 | >( | |
83 | $var0 : $ctype0, | |
84 | $($var : $ctype,)* | |
85 | f : impl Fn(usize, $etype0, $($etype),*) -> Res | |
86 | ) -> [Res; N] { | |
87 | let zipit = (0..N).zip(izip!($var0.fl_iter(), $($var.fl_iter()),*)); | |
88 | let map = zipit.map(|(i, tuple_or_singleton!($var0, $($var),*))| f(i, $var0, $($var),*)); | |
89 | collect_into_array_unchecked(map) | |
90 | } | |
91 | } | |
92 | } | |
93 | ||
94 | make_mapmany!(map1, map1_indexed, a; A, CA); | |
95 | make_mapmany!(map2, map2_indexed, a b; A B, CA CB); | |
96 | make_mapmany!(map3, map3_indexed, a b c; A B C, CA CB CC); | |
97 | make_mapmany!(map4, map4_indexed, a b c d; A B C D, CA CB CC CD); | |
98 | make_mapmany!(map5, map5_indexed, a b c d e; A B C D E, CA CB CC CD CE); | |
99 | make_mapmany!(map6, map6_indexed, a b c d e f; A B C D E F, CA CB CC CD CE CF); | |
100 | ||
101 | macro_rules! make_mapmany_mut{ | |
102 | ($name:ident, $name_indexed:ident, $var0:ident $($var:ident)* ; | |
103 | $etype0:ident $($etype:ident)*, $ctype0:ident $($ctype:ident)*) => { | |
2
ac84e995e119
Convert iteration utilities to GATs
Tuomo Valkonen <tuomov@iki.fi>
parents:
0
diff
changeset
|
104 | /// Map over [`FixedLength`] container(s) with mutable references to the first container. |
0 | 105 | #[inline] |
106 | pub fn $name< | |
107 | $etype0, | |
108 | $($etype,)* | |
109 | $ctype0 : FixedLengthMut<N,Elem=$etype0>, | |
110 | $($ctype : FixedLength<N,Elem=$etype>,)* | |
111 | const N : usize | |
112 | > ( | |
113 | $var0 : &mut $ctype0, | |
114 | $($var : $ctype,)* | |
115 | f : impl Fn(&mut $etype0, $($etype),*) | |
116 | ) { | |
117 | let zipit = izip!($var0.fl_iter_mut(), $($var.fl_iter()),*); | |
118 | zipit.for_each(|tuple_or_singleton!($var0, $($var),*)| f($var0, $($var),*)); | |
119 | } | |
120 | ||
2
ac84e995e119
Convert iteration utilities to GATs
Tuomo Valkonen <tuomov@iki.fi>
parents:
0
diff
changeset
|
121 | /// Map over [`FixedLength`] container(s) and element indices |
ac84e995e119
Convert iteration utilities to GATs
Tuomo Valkonen <tuomov@iki.fi>
parents:
0
diff
changeset
|
122 | /// with mutable references to the first container. |
0 | 123 | #[inline] |
124 | pub fn $name_indexed< | |
125 | $etype0, | |
126 | $($etype,)* | |
127 | $ctype0 : FixedLengthMut<N,Elem=$etype0>, | |
128 | $($ctype : FixedLength<N,Elem=$etype>,)* | |
129 | const N : usize | |
130 | > ( | |
131 | $var0 : &mut $ctype0, | |
132 | $($var : $ctype,)* | |
133 | f : impl Fn(usize, &mut $etype0, $($etype),*) | |
134 | ) { | |
135 | let zipit = (0..N).zip(izip!($var0.fl_iter_mut(), $($var.fl_iter()),*)); | |
136 | zipit.for_each(|(i, tuple_or_singleton!($var0, $($var),*))| f(i, $var0, $($var),*)); | |
137 | } | |
138 | } | |
139 | } | |
140 | ||
141 | make_mapmany_mut!(map1_mut, map1_indexed_mut, a; A, CA); | |
142 | make_mapmany_mut!(map2_mut, map2_indexed_mut, a b; A B, CA CB); | |
143 | make_mapmany_mut!(map3_mut, map3_indexed_mut, a b c; A B C, CA CB CC); | |
144 | make_mapmany_mut!(map4_mut, map4_indexed_mut, a b c d; A B C D, CA CB CC CD); | |
145 | make_mapmany_mut!(map5_mut, map5_indexed_mut, a b c d e; A B C D E, CA CB CC CD CE); | |
146 | make_mapmany_mut!(map6_mut, map6_indexed_mut, a b c d e f; A B C D E F, CA CB CC CD CE CF); | |
147 | ||
148 | ||
149 | /// Initialise an array of length `N` by calling `f` multiple times. | |
150 | #[inline] | |
151 | pub fn array_init<A, F : Fn() -> A, const N : usize>(f : F) -> [A; N] { | |
152 | //[(); N].map(|_| f()) | |
153 | core::array::from_fn(|_| f()) | |
154 | } | |
155 | ||
156 | // /// Initialise an array of length `N` by calling `f` with the index of each element. | |
157 | // #[inline] | |
158 | // pub fn array_gen<A, F : Fn(usize) -> A, const N : usize>(f : F) -> [A; N] { | |
159 | // //[(); N].indexmap(|i, _| f(i)) | |
160 | // core::array::from_fn(f) | |
161 | // } | |
162 | ||
163 | ||
2
ac84e995e119
Convert iteration utilities to GATs
Tuomo Valkonen <tuomov@iki.fi>
parents:
0
diff
changeset
|
164 | /// Iterator returned by [`foldmap`][FoldMappable::foldmap] applied to an iterator. |
0 | 165 | pub struct FoldMap<I : Iterator<Item=A>, A, B, J : Copy, F : Fn(J, A) -> (J, B)> { |
166 | iter : I, | |
167 | f : F, | |
168 | j : J, | |
169 | } | |
170 | ||
171 | impl<A, B, I : Iterator<Item=A>, J : Copy, F : Fn(J, A) -> (J, B)> Iterator for FoldMap<I, A, B, J, F> { | |
172 | type Item = B; | |
173 | #[inline] | |
174 | fn next(&mut self) -> Option<B> { | |
175 | self.iter.next().map(|a| { | |
176 | let (jnew, b) = (self.f)(self.j, a); | |
177 | self.j = jnew; | |
178 | b | |
179 | }) | |
180 | } | |
181 | } | |
182 | ||
2
ac84e995e119
Convert iteration utilities to GATs
Tuomo Valkonen <tuomov@iki.fi>
parents:
0
diff
changeset
|
183 | /// Iterator returned by [`indexmap`][IndexMappable::indexmap] applied to an iterator. |
0 | 184 | pub struct IndexMap<I : Iterator<Item=A>, A, B, F : Fn(usize, A) -> B> { |
185 | iter : I, | |
186 | f : F, | |
187 | j : usize, | |
188 | } | |
189 | ||
190 | impl<A, B, I : Iterator<Item=A>, F : Fn(usize, A) -> B> Iterator for IndexMap<I, A, B, F> { | |
191 | type Item = B; | |
192 | #[inline] | |
193 | fn next(&mut self) -> Option<B> { | |
194 | self.iter.next().map(|a| { | |
195 | let b = (self.f)(self.j, a); | |
196 | self.j = self.j+1; | |
197 | b | |
198 | }) | |
199 | } | |
200 | } | |
201 | ||
2
ac84e995e119
Convert iteration utilities to GATs
Tuomo Valkonen <tuomov@iki.fi>
parents:
0
diff
changeset
|
202 | /// Trait for things that can be foldmapped. |
ac84e995e119
Convert iteration utilities to GATs
Tuomo Valkonen <tuomov@iki.fi>
parents:
0
diff
changeset
|
203 | /// |
ac84e995e119
Convert iteration utilities to GATs
Tuomo Valkonen <tuomov@iki.fi>
parents:
0
diff
changeset
|
204 | /// `A` is the type of elements of `Self`, and `J` the accumulator type for the folding. |
ac84e995e119
Convert iteration utilities to GATs
Tuomo Valkonen <tuomov@iki.fi>
parents:
0
diff
changeset
|
205 | pub trait FoldMappable<A, J> : Sized { |
ac84e995e119
Convert iteration utilities to GATs
Tuomo Valkonen <tuomov@iki.fi>
parents:
0
diff
changeset
|
206 | type Output<B, F> where F : Fn(J, A) -> (J, B); |
ac84e995e119
Convert iteration utilities to GATs
Tuomo Valkonen <tuomov@iki.fi>
parents:
0
diff
changeset
|
207 | /// Fold and map over `self` with `f`. `j` is the initial accumulator for folding. |
ac84e995e119
Convert iteration utilities to GATs
Tuomo Valkonen <tuomov@iki.fi>
parents:
0
diff
changeset
|
208 | /// |
ac84e995e119
Convert iteration utilities to GATs
Tuomo Valkonen <tuomov@iki.fi>
parents:
0
diff
changeset
|
209 | /// The output type depends on the implementation, but will generally have elements of |
ac84e995e119
Convert iteration utilities to GATs
Tuomo Valkonen <tuomov@iki.fi>
parents:
0
diff
changeset
|
210 | /// type `B`. |
ac84e995e119
Convert iteration utilities to GATs
Tuomo Valkonen <tuomov@iki.fi>
parents:
0
diff
changeset
|
211 | fn foldmap<B, F : Fn(J, A) -> (J, B)>(self, j : J, f : F) -> Self::Output<B, F>; |
0 | 212 | } |
213 | ||
2
ac84e995e119
Convert iteration utilities to GATs
Tuomo Valkonen <tuomov@iki.fi>
parents:
0
diff
changeset
|
214 | /// Trait for things that can be indexmapped. |
ac84e995e119
Convert iteration utilities to GATs
Tuomo Valkonen <tuomov@iki.fi>
parents:
0
diff
changeset
|
215 | /// |
ac84e995e119
Convert iteration utilities to GATs
Tuomo Valkonen <tuomov@iki.fi>
parents:
0
diff
changeset
|
216 | /// `A` is the type of elements of `Self`. |
ac84e995e119
Convert iteration utilities to GATs
Tuomo Valkonen <tuomov@iki.fi>
parents:
0
diff
changeset
|
217 | pub trait IndexMappable<A> : Sized { |
ac84e995e119
Convert iteration utilities to GATs
Tuomo Valkonen <tuomov@iki.fi>
parents:
0
diff
changeset
|
218 | type Output<B, F> where F : Fn(usize, A) -> B; |
ac84e995e119
Convert iteration utilities to GATs
Tuomo Valkonen <tuomov@iki.fi>
parents:
0
diff
changeset
|
219 | /// Map over element indices and elements of `self`. |
ac84e995e119
Convert iteration utilities to GATs
Tuomo Valkonen <tuomov@iki.fi>
parents:
0
diff
changeset
|
220 | /// |
ac84e995e119
Convert iteration utilities to GATs
Tuomo Valkonen <tuomov@iki.fi>
parents:
0
diff
changeset
|
221 | /// The output type depends on the implementation, but will generally have elements of |
ac84e995e119
Convert iteration utilities to GATs
Tuomo Valkonen <tuomov@iki.fi>
parents:
0
diff
changeset
|
222 | /// type `B`. |
ac84e995e119
Convert iteration utilities to GATs
Tuomo Valkonen <tuomov@iki.fi>
parents:
0
diff
changeset
|
223 | fn indexmap<B, F : Fn(usize, A) -> B>(self, f : F) -> Self::Output<B, F>; |
0 | 224 | } |
225 | ||
2
ac84e995e119
Convert iteration utilities to GATs
Tuomo Valkonen <tuomov@iki.fi>
parents:
0
diff
changeset
|
226 | impl<'a, A, J : Copy> FoldMappable<&'a A, J> |
0 | 227 | for std::slice::Iter<'a, A> { |
2
ac84e995e119
Convert iteration utilities to GATs
Tuomo Valkonen <tuomov@iki.fi>
parents:
0
diff
changeset
|
228 | type Output<B, F> = FoldMap<Self, &'a A, B, J, F> where F : Fn(J, &'a A) -> (J, B); |
0 | 229 | #[inline] |
2
ac84e995e119
Convert iteration utilities to GATs
Tuomo Valkonen <tuomov@iki.fi>
parents:
0
diff
changeset
|
230 | fn foldmap<B, F : Fn(J, &'a A) -> (J, B)>(self, j : J, f : F) -> Self::Output<B, F> { |
0 | 231 | FoldMap { iter : self, j, f } |
232 | } | |
233 | } | |
234 | ||
2
ac84e995e119
Convert iteration utilities to GATs
Tuomo Valkonen <tuomov@iki.fi>
parents:
0
diff
changeset
|
235 | impl<'a, A> IndexMappable<&'a A> |
0 | 236 | for std::slice::Iter<'a, A> { |
2
ac84e995e119
Convert iteration utilities to GATs
Tuomo Valkonen <tuomov@iki.fi>
parents:
0
diff
changeset
|
237 | type Output<B, F> = IndexMap<Self, &'a A, B, F> where F : Fn(usize, &'a A) -> B; |
0 | 238 | #[inline] |
2
ac84e995e119
Convert iteration utilities to GATs
Tuomo Valkonen <tuomov@iki.fi>
parents:
0
diff
changeset
|
239 | fn indexmap<B, F : Fn(usize, &'a A) -> B>(self, f : F) -> Self::Output<B, F> { |
0 | 240 | IndexMap { iter : self, j : 0, f } |
241 | } | |
242 | } | |
243 | ||
244 | ||
2
ac84e995e119
Convert iteration utilities to GATs
Tuomo Valkonen <tuomov@iki.fi>
parents:
0
diff
changeset
|
245 | impl<A, J : Copy, const N : usize> FoldMappable<A, J> |
0 | 246 | for std::array::IntoIter<A, N> { |
2
ac84e995e119
Convert iteration utilities to GATs
Tuomo Valkonen <tuomov@iki.fi>
parents:
0
diff
changeset
|
247 | type Output<B, F> = FoldMap<Self, A, B, J, F> where F : Fn(J, A) -> (J, B); |
0 | 248 | #[inline] |
2
ac84e995e119
Convert iteration utilities to GATs
Tuomo Valkonen <tuomov@iki.fi>
parents:
0
diff
changeset
|
249 | fn foldmap<B, F : Fn(J, A) -> (J, B)>(self, j : J, f : F) -> Self::Output<B, F> { |
0 | 250 | FoldMap { iter : self, j, f } |
251 | } | |
252 | } | |
253 | ||
2
ac84e995e119
Convert iteration utilities to GATs
Tuomo Valkonen <tuomov@iki.fi>
parents:
0
diff
changeset
|
254 | impl<'a, A, const N : usize> IndexMappable<A> |
0 | 255 | for std::array::IntoIter<A, N> { |
2
ac84e995e119
Convert iteration utilities to GATs
Tuomo Valkonen <tuomov@iki.fi>
parents:
0
diff
changeset
|
256 | type Output<B, F> = IndexMap<Self, A, B, F> where F : Fn(usize, A) -> B; |
0 | 257 | #[inline] |
2
ac84e995e119
Convert iteration utilities to GATs
Tuomo Valkonen <tuomov@iki.fi>
parents:
0
diff
changeset
|
258 | fn indexmap<B, F : Fn(usize, A) -> B>(self, f : F) -> Self::Output<B, F> { |
0 | 259 | IndexMap { iter : self, j : 0, f } |
260 | } | |
261 | } | |
262 | ||
263 | ||
264 | ||
265 | ||
2
ac84e995e119
Convert iteration utilities to GATs
Tuomo Valkonen <tuomov@iki.fi>
parents:
0
diff
changeset
|
266 | impl<A, J : Copy, const N : usize> FoldMappable<A, J> for [A; N] { |
ac84e995e119
Convert iteration utilities to GATs
Tuomo Valkonen <tuomov@iki.fi>
parents:
0
diff
changeset
|
267 | type Output<B, F> = [B; N] where F : Fn(J, A) -> (J, B); |
0 | 268 | #[inline] |
2
ac84e995e119
Convert iteration utilities to GATs
Tuomo Valkonen <tuomov@iki.fi>
parents:
0
diff
changeset
|
269 | fn foldmap<B, F : Fn(J, A) -> (J, B)>(self, j : J, f : F) -> [B; N] { |
0 | 270 | // //let mut res : [MaybeUninit<B>; N] = unsafe { MaybeUninit::uninit().assume_init() }; |
271 | // let mut res = MaybeUninit::uninit_array::<N>(); | |
272 | // for (a, i) in self.into_iter().zip(0..N) { | |
273 | // let (jnew, b) = f(j, a); | |
274 | // unsafe { *(res.get_unchecked_mut(i)) = MaybeUninit::new(b) }; | |
275 | // j = jnew; | |
276 | // } | |
277 | // //unsafe { res.as_mut_ptr().cast::<[B; N]>().read() } | |
278 | // unsafe { MaybeUninit::array_assume_init(res) } | |
279 | let it = self.into_iter().foldmap(j, f); | |
280 | collect_into_array_unchecked(it) | |
281 | } | |
282 | } | |
283 | ||
2
ac84e995e119
Convert iteration utilities to GATs
Tuomo Valkonen <tuomov@iki.fi>
parents:
0
diff
changeset
|
284 | impl<A, const N : usize> IndexMappable<A> for [A; N] { |
ac84e995e119
Convert iteration utilities to GATs
Tuomo Valkonen <tuomov@iki.fi>
parents:
0
diff
changeset
|
285 | type Output<B, F> = [B; N] where F : Fn(usize, A) -> B; |
0 | 286 | #[inline] |
2
ac84e995e119
Convert iteration utilities to GATs
Tuomo Valkonen <tuomov@iki.fi>
parents:
0
diff
changeset
|
287 | fn indexmap<B, F : Fn(usize, A) -> B>(self, f : F) -> [B; N] { |
0 | 288 | // //let mut res : [MaybeUninit<B>; N] = unsafe { MaybeUninit::uninit().assume_init() }; |
289 | // let mut res = MaybeUninit::uninit_array::<N>(); | |
290 | // for (a, i) in self.into_iter().zip(0..N) { | |
291 | // let b = f(i, a); | |
292 | // unsafe { *(res.get_unchecked_mut(i)) = MaybeUninit::new(b) }; | |
293 | // } | |
294 | // //unsafe { res.as_mut_ptr().cast::<[B; N]>().read() } | |
295 | // unsafe { MaybeUninit::array_assume_init(res) } | |
296 | let it = self.into_iter().indexmap(f); | |
297 | collect_into_array_unchecked(it) | |
298 | } | |
299 | } | |
300 | ||
301 | /// | |
302 | /// This is taken and simplified from core::array to not involve `ControlFlow`, | |
303 | /// `Try` etc. (Pulling everything including `NeverShortCircuit` turned out | |
304 | /// too much to maintain here.) | |
305 | /// | |
306 | /// Pulls `N` items from `iter` and returns them as an array. If the iterator | |
307 | /// yields fewer than `N` items, `None` is returned and all already yielded | |
308 | /// items are dropped. | |
309 | /// | |
310 | /// Since the iterator is passed as a mutable reference and this function calls | |
311 | /// `next` at most `N` times, the iterator can still be used afterwards to | |
312 | /// retrieve the remaining items. | |
313 | /// | |
314 | /// If `iter.next()` panicks, all items already yielded by the iterator are | |
315 | /// dropped. | |
316 | #[inline] | |
317 | pub(crate) fn collect_into_array_unchecked<T, I : Iterator<Item=T>, const N: usize>(mut iter: I) -> [T; N] | |
318 | { | |
319 | if N == 0 { | |
320 | // SAFETY: An empty array is always inhabited and has no validity invariants. | |
321 | return unsafe { core::mem::zeroed() }; | |
322 | } | |
323 | ||
324 | struct Guard<'a, T, const N: usize> { | |
325 | array_mut: &'a mut [MaybeUninit<T>; N], | |
326 | initialized: usize, | |
327 | } | |
328 | ||
329 | impl<T, const N: usize> Drop for Guard<'_, T, N> { | |
330 | #[inline] | |
331 | fn drop(&mut self) { | |
332 | debug_assert!(self.initialized <= N); | |
333 | ||
334 | // SAFETY: this slice will contain only initialized objects. | |
335 | unsafe { | |
336 | core::ptr::drop_in_place(MaybeUninit::slice_assume_init_mut( | |
337 | &mut self.array_mut.get_unchecked_mut(..self.initialized), | |
338 | )); | |
339 | } | |
340 | } | |
341 | } | |
342 | ||
343 | let mut array = MaybeUninit::uninit_array::<N>(); | |
344 | let mut guard = Guard { array_mut: &mut array, initialized: 0 }; | |
345 | ||
346 | while let Some(item) = iter.next() { | |
347 | // SAFETY: `guard.initialized` starts at 0, is increased by one in the | |
348 | // loop and the loop is aborted once it reaches N (which is | |
349 | // `array.len()`). | |
350 | unsafe { | |
351 | guard.array_mut.get_unchecked_mut(guard.initialized).write(item); | |
352 | } | |
353 | guard.initialized += 1; | |
354 | ||
355 | // Check if the whole array was initialized. | |
356 | if guard.initialized == N { | |
357 | core::mem::forget(guard); | |
358 | ||
359 | // SAFETY: the condition above asserts that all elements are | |
360 | // initialized. | |
361 | let out = unsafe { MaybeUninit::array_assume_init(array) }; | |
362 | return out; | |
363 | } | |
364 | } | |
365 | ||
366 | unreachable!("Something went wrong with iterator length") | |
367 | } | |
368 | ||
369 | ||
370 | #[cfg(test)] | |
371 | mod tests { | |
372 | use super::*; | |
373 | ||
374 | #[test] | |
375 | fn mapx_test() { | |
376 | let a = [0,1,2]; | |
377 | let mut b = [2,1,0]; | |
378 | assert_eq!(map1(a, |x| x+1), [1,2,3]); | |
379 | assert_eq!(map2(a, b, |x, y| x+y), [2,2,2]); | |
380 | assert_eq!(map1_indexed(a, |i, y| y-i), [0,0,0]); | |
381 | map1_indexed_mut(&mut b, |i, y| *y=i); | |
382 | assert_eq!(b, a); | |
383 | } | |
384 | } |