1 //! Implements `From<[T; N]>` and `Into<[T; N]>` for vector types.
2 
3 macro_rules! impl_from_array {
4     ([$elem_ty:ident; $elem_count:expr]: $id:ident | $test_tt:tt
5      | ($non_default_array:expr, $non_default_vec:expr)) => {
6         impl From<[$elem_ty; $elem_count]> for $id {
7             #[inline]
8             fn from(array: [$elem_ty; $elem_count]) -> Self {
9                 union U {
10                     array: [$elem_ty; $elem_count],
11                     vec: $id,
12                 }
13                 unsafe { U { array }.vec }
14             }
15         }
16 
17         impl From<$id> for [$elem_ty; $elem_count] {
18             #[inline]
19             fn from(vec: $id) -> Self {
20                 union U {
21                     array: [$elem_ty; $elem_count],
22                     vec: $id,
23                 }
24                 unsafe { U { vec }.array }
25             }
26         }
27 
28         // FIXME: `Into::into` is not inline, but due to
29         // the blanket impl in `std`, which is not
30         // marked `default`, we cannot override it here with
31         // specialization.
32         /*
33         impl Into<[$elem_ty; $elem_count]> for $id {
34             #[inline]
35             fn into(self) -> [$elem_ty; $elem_count] {
36                 union U {
37                     array: [$elem_ty; $elem_count],
38                     vec: $id,
39                 }
40                 unsafe { U { vec: self }.array }
41             }
42         }
43 
44         impl Into<$id> for [$elem_ty; $elem_count] {
45             #[inline]
46             fn into(self) -> $id {
47                 union U {
48                     array: [$elem_ty; $elem_count],
49                     vec: $id,
50                 }
51                 unsafe { U { array: self }.vec }
52             }
53         }
54         */
55 
56         test_if! {
57             $test_tt:
58             paste::item! {
59                 // Comparisons use integer casts within mantissa^1 range.
60                 #[allow(clippy::float_cmp)]
61                 mod [<$id _from>] {
62                     use super::*;
63                     #[test]
64                     fn array() {
65                         let vec: $id = Default::default();
66 
67                         // FIXME: Workaround for arrays with more than 32
68                         // elements.
69                         //
70                         // Safe because we never take a reference to any
71                         // uninitialized element.
72                         union W {
73                             array: [$elem_ty; $elem_count],
74                             other: ()
75                         }
76                         let mut array = W { other: () };
77                         for i in 0..$elem_count {
78                             let default: $elem_ty = Default::default();
79                             // note: array.other is the active member and
80                             // initialized so we can take a reference to it:
81                             let p = unsafe {
82                                 &mut array.other as *mut () as *mut $elem_ty
83                             };
84                             // note: default is a valid bit-pattern for
85                             // $elem_ty:
86                             unsafe {
87                                 crate::ptr::write(p.wrapping_add(i), default)
88                             };
89                         }
90                         // note: the array variant of the union is properly
91                         // initialized:
92                         let mut array = unsafe {
93                             array.array
94                         };
95 
96                         array[0] = $non_default_array;
97                         let vec = vec.replace(0, $non_default_vec);
98 
99                         let vec_from_array = $id::from(array);
100                         assert_eq!(vec_from_array, vec);
101                         let array_from_vec
102                             = <[$elem_ty; $elem_count]>::from(vec);
103                         // FIXME: Workaround for arrays with more than 32
104                         // elements.
105                         for i in 0..$elem_count {
106                             assert_eq!(array_from_vec[i], array[i]);
107                         }
108 
109                         let vec_from_into_array: $id = array.into();
110                         assert_eq!(vec_from_into_array, vec);
111                         let array_from_into_vec: [$elem_ty; $elem_count]
112                             = vec.into();
113                         // FIXME: Workaround for arrays with more than 32
114                         // elements.
115                         for i in 0..$elem_count {
116                             assert_eq!(array_from_into_vec[i], array[i]);
117                         }
118                     }
119                 }
120             }
121         }
122     };
123 }
124