1use core::mem::{needs_drop, MaybeUninit};
2use core::ops::{Add, Div, Mul, Sub};
3
4use crate::iter::uninit_array;
5use crate::{iter::Slice, Array};
6
7impl<T, const N: usize> Array<T, N> {
8 pub fn zip_map<U, O>(self, rhs: [U; N], mut op: impl FnMut(T, U) -> O) -> [O; N] {
9 if needs_drop::<T>() || needs_drop::<U>() || needs_drop::<O>() {
10 let mut lhs = Slice::full(self.0);
11 let mut rhs = Slice::full(rhs);
12 let mut output = Slice::new();
13
14 for _ in 0..N {
15 unsafe {
16 let lhs = lhs.pop_front_unchecked();
17 let rhs = rhs.pop_front_unchecked();
18 output.push_unchecked(op(lhs, rhs));
19 }
20 }
21
22 unsafe { output.output() }
23 } else {
24 let mut output: [MaybeUninit<O>; N] = uninit_array();
27
28 for i in 0..N {
29 unsafe {
30 let lhs = core::ptr::read(&self.0[i]);
31 let rhs = core::ptr::read(&rhs[i]);
32 output[i].write(op(lhs, rhs));
33 }
34 }
35
36 unsafe { core::ptr::read(&output as *const [MaybeUninit<O>; N] as *const [O; N]) }
37 }
38 }
39}
40
41macro_rules! binop {
42 ($trait:ident, $method:ident) => {
43 impl<T, U, const N: usize> $trait<[U; N]> for Array<T, N>
44 where
45 T: $trait<U>,
46 {
47 type Output = [T::Output; N];
48
49 fn $method(self, rhs: [U; N]) -> Self::Output {
50 self.zip_map(rhs, T::$method)
51 }
52 }
53
54 impl<T, U, const N: usize> $trait<Array<U, N>> for Array<T, N>
55 where
56 T: $trait<U>,
57 {
58 type Output = Array<T::Output, N>;
59
60 fn $method(self, rhs: Array<U, N>) -> Self::Output {
61 Array(self.zip_map(rhs.0, T::$method))
62 }
63 }
64 };
65}
66
67binop!(Add, add);
68binop!(Mul, mul);
69binop!(Div, div);
70binop!(Sub, sub);