wide/
lib.rs

1#![no_std]
2#![allow(non_camel_case_types)]
3#![warn(clippy::doc_markdown)]
4#![warn(clippy::missing_inline_in_public_items)]
5#![allow(clippy::eq_op)]
6#![allow(clippy::excessive_precision)]
7#![allow(clippy::let_and_return)]
8#![allow(clippy::unusual_byte_groupings)]
9#![allow(clippy::misrefactored_assign_op)]
10#![allow(clippy::approx_constant)]
11
12//! A crate to help you go wide.
13//!
14//! This crate provides SIMD-compatible data types.
15//!
16//! When possible, explicit SIMD is used with all the math operations here. As a
17//! fallback, the fact that all the lengths of a fixed length array are doing
18//! the same thing will often make LLVM notice that it should use SIMD
19//! instructions to complete the task. In the worst case, the code just becomes
20//! totally scalar (though the math is still correct, at least).
21//!
22//! ## Casting
23//!
24//! The SIMD types implement the [`bytemuck::Pod`] trait, which means that it
25//! is possible to do bitwise casts between SIMD types of the same size with
26//! the [`bytemuck::cast()`] function and others. `bytemuck` is re-exported by
27//! this crate for convenience.
28//!
29//! This typically does not have much, if any, runtime overhead in optimized
30//! builds.
31//!
32//! ## Crate Features
33//!
34//! * `std`: This causes the feature to link to `std`.
35//!   * Currently this just improves the performance of `sqrt` when an explicit
36//!     SIMD `sqrt` isn't available.
37
38// Note(Lokathor): Due to standard library magic, the std-only methods for f32
39// and f64 will automatically be available simply by declaring this.
40#[cfg(feature = "std")]
41extern crate std;
42
43// TODO
44// Add/Sub/Mul/Div with constant
45// Shuffle left/right/by index
46
47use core::{
48  fmt::{
49    Binary, Debug, Display, LowerExp, LowerHex, Octal, UpperExp, UpperHex,
50  },
51  ops::*,
52};
53
54#[allow(unused_imports)]
55#[cfg(any(target_arch = "x86_64", target_arch = "x86"))]
56use safe_arch::*;
57
58use bytemuck::*;
59
60// Re-export so that users don't need to add a bytemuck dependency of their own
61pub use bytemuck;
62
63#[cfg(feature = "serde")]
64use serde_core::{ser::SerializeTuple, Deserialize, Serialize};
65
66#[macro_use]
67mod macros;
68
69macro_rules! pick {
70  ($(if #[cfg($($test:meta),*)] {
71      $($if_tokens:tt)*
72    })else+ else {
73      $($else_tokens:tt)*
74    }) => {
75    pick!{
76      @__forests [ ] ;
77      $( [ {$($test),*} {$($if_tokens)*} ], )*
78      [ { } {$($else_tokens)*} ],
79    }
80  };
81  (if #[cfg($($if_meta:meta),*)] {
82      $($if_tokens:tt)*
83    } $(else if #[cfg($($else_meta:meta),*)] {
84      $($else_tokens:tt)*
85    })*) => {
86    pick!{
87      @__forests [ ] ;
88      [ {$($if_meta),*} {$($if_tokens)*} ],
89      $( [ {$($else_meta),*} {$($else_tokens)*} ], )*
90    }
91  };
92  (@__forests [$($not:meta,)*];) => {
93    /* halt expansion */
94  };
95  (@__forests [$($not:meta,)*]; [{$($m:meta),*} {$($tokens:tt)*}], $($rest:tt)*) => {
96    #[cfg(all( $($m,)* not(any($($not),*)) ))]
97    pick!{ @__identity $($tokens)* }
98    pick!{ @__forests [ $($not,)* $($m,)* ] ; $($rest)* }
99  };
100  (@__identity $($tokens:tt)*) => {
101    $($tokens)*
102  };
103}
104
105// TODO: make these generic over `mul_add`? Worth it?
106
107macro_rules! polynomial_2 {
108  ($x:expr, $c0:expr, $c1:expr, $c2:expr $(,)?) => {{
109    let x = $x;
110    let x2 = x * x;
111    x2.mul_add($c2, x.mul_add($c1, $c0))
112  }};
113}
114
115macro_rules! polynomial_3 {
116  ($x:expr, $c0:expr, $c1:expr, $c2:expr, $c3:expr $(,)?) => {{
117    let x = $x;
118    let x2 = x * x;
119    $c3.mul_add(x, $c2).mul_add(x2, $c1.mul_add(x, $c0))
120  }};
121}
122
123macro_rules! polynomial_4 {
124  ($x:expr, $c0:expr, $c1:expr, $c2:expr ,$c3:expr, $c4:expr $(,)?) => {{
125    let x = $x;
126    let x2 = x * x;
127    let x4 = x2 * x2;
128    $c3.mul_add(x, $c2).mul_add(x2, $c1.mul_add(x, $c0)) + $c4 * x4
129  }};
130}
131
132macro_rules! polynomial_5 {
133  ($x:expr, $c0:expr, $c1:expr, $c2:expr, $c3:expr, $c4:expr, $c5:expr $(,)?) => {{
134    let x = $x;
135    let x2 = x * x;
136    let x4 = x2 * x2;
137    $c3
138      .mul_add(x, $c2)
139      .mul_add(x2, $c5.mul_add(x, $c4).mul_add(x4, $c1.mul_add(x, $c0)))
140  }};
141}
142
143macro_rules! polynomial_5n {
144  ($x:expr, $c0:expr, $c1:expr, $c2:expr, $c3:expr, $c4:expr $(,)?) => {{
145    let x = $x;
146    let x2 = x * x;
147    let x4 = x2 * x2;
148    x2.mul_add(x.mul_add($c3, $c2), (x4.mul_add($c4 + x, x.mul_add($c1, $c0))))
149  }};
150}
151
152macro_rules! polynomial_6 {
153  ($x:expr, $c0:expr, $c1:expr, $c2:expr, $c3:expr, $c4:expr, $c5:expr ,$c6:expr $(,)?) => {{
154    let x = $x;
155    let x2 = x * x;
156    let x4 = x2 * x2;
157    x4.mul_add(
158      x2.mul_add($c6, x.mul_add($c5, $c4)),
159      x2.mul_add(x.mul_add($c3, $c2), x.mul_add($c1, $c0)),
160    )
161  }};
162}
163
164macro_rules! polynomial_6n {
165  ($x:expr, $c0:expr, $c1:expr, $c2:expr, $c3:expr, $c4:expr, $c5:expr $(,)?) => {{
166    let x = $x;
167    let x2 = x * x;
168    let x4 = x2 * x2;
169    x4.mul_add(
170      x.mul_add($c5, x2 + $c4),
171      x2.mul_add(x.mul_add($c3, $c2), x.mul_add($c1, $c0)),
172    )
173  }};
174}
175
176macro_rules! polynomial_8 {
177  ($x:expr, $c0:expr, $c1:expr, $c2:expr, $c3:expr, $c4:expr, $c5:expr,  $c6:expr, $c7:expr, $c8:expr $(,)?) => {{
178    let x = $x;
179    let x2 = x * x;
180    let x4 = x2 * x2;
181    let x8 = x4 * x4;
182    x4.mul_add(
183      x2.mul_add($c7.mul_add(x, $c6), x.mul_add($c5, $c4)),
184      x8.mul_add($c8, x2.mul_add(x.mul_add($c3, $c2), x.mul_add($c1, $c0))),
185    )
186  }};
187}
188
189macro_rules! polynomial_13 {
190  // calculates polynomial c13*x^13 + c12*x^12 + ... + c1*x + c0
191  ($x:expr,  $c2:expr, $c3:expr, $c4:expr, $c5:expr,$c6:expr, $c7:expr, $c8:expr,$c9:expr, $c10:expr, $c11:expr, $c12:expr, $c13:expr  $(,)?) => {{
192    let x = $x;
193    let x2 = x * x;
194    let x4 = x2 * x2;
195    let x8 = x4 * x4;
196    x8.mul_add(
197      x4.mul_add(
198        x.mul_add($c13, $c12),
199        x2.mul_add(x.mul_add($c11, $c10), x.mul_add($c9, $c8)),
200      ),
201      x4.mul_add(
202        x2.mul_add(x.mul_add($c7, $c6), x.mul_add($c5, $c4)),
203        x2.mul_add(x.mul_add($c3, $c2), x),
204      ),
205    )
206  }};
207}
208
209macro_rules! polynomial_13m {
210  // return  ((c8+c9*x) + (c10+c11*x)*x2 + (c12+c13*x)*x4)*x8 + (((c6+c7*x)*x2 +
211  // (c4+c5*x))*x4 + ((c2+c3*x)*x2 + x));
212  ($x:expr,  $c2:expr, $c3:expr, $c4:expr, $c5:expr,$c6:expr, $c7:expr, $c8:expr,$c9:expr, $c10:expr, $c11:expr, $c12:expr, $c13:expr  $(,)?) => {{
213    let x = $x;
214    let x2 = x * x;
215    let x4 = x2 * x2;
216    let x8 = x4 * x4;
217
218    x8.mul_add(
219      x4.mul_add(
220        x.mul_add($c13, $c12),
221        x2.mul_add(x.mul_add($c11, $c10), x.mul_add($c9, $c8)),
222      ),
223      x4.mul_add(
224        x2.mul_add(x.mul_add($c7, $c6), x.mul_add($c5, $c4)),
225        x2.mul_add(x.mul_add($c3, $c2), x),
226      ),
227    )
228  }};
229}
230
231mod f32x16_;
232pub use f32x16_::*;
233
234mod f32x8_;
235pub use f32x8_::*;
236
237mod f32x4_;
238pub use f32x4_::*;
239
240mod f64x8_;
241pub use f64x8_::*;
242
243mod f64x4_;
244pub use f64x4_::*;
245
246mod f64x2_;
247pub use f64x2_::*;
248
249mod i8x16_;
250pub use i8x16_::*;
251
252mod i16x16_;
253pub use i16x16_::*;
254
255mod i16x32_;
256pub use i16x32_::*;
257
258mod i8x32_;
259pub use i8x32_::*;
260
261mod i16x8_;
262pub use i16x8_::*;
263
264mod i32x4_;
265pub use i32x4_::*;
266
267mod i32x8_;
268pub use i32x8_::*;
269
270mod i32x16_;
271pub use i32x16_::*;
272
273mod i64x2_;
274pub use i64x2_::*;
275
276mod i64x4_;
277pub use i64x4_::*;
278
279mod i64x8_;
280pub use i64x8_::*;
281
282mod u8x16_;
283pub use u8x16_::*;
284
285mod u8x32_;
286pub use u8x32_::*;
287
288mod u16x8_;
289pub use u16x8_::*;
290
291mod u16x16_;
292pub use u16x16_::*;
293
294mod u16x32_;
295pub use u16x32_::*;
296
297mod u32x4_;
298pub use u32x4_::*;
299
300mod u32x8_;
301pub use u32x8_::*;
302
303mod u32x16_;
304pub use u32x16_::*;
305
306mod u64x2_;
307pub use u64x2_::*;
308
309mod u64x4_;
310pub use u64x4_::*;
311
312mod u64x8_;
313pub use u64x8_::*;
314
315#[allow(dead_code)]
316fn generic_bit_blend<T>(mask: T, y: T, n: T) -> T
317where
318  T: Copy + BitXor<Output = T> + BitAnd<Output = T>,
319{
320  n ^ ((n ^ y) & mask)
321}
322
323/// given `type.op(type)` and type is `Copy`, impls `type.op(&type)`
324macro_rules! bulk_impl_op_ref_self_for {
325  ($(($op:ident, $method:ident) => [$($t:ty),+]),+ $(,)?) => {
326    $( // do each trait/list matching given
327      $( // do the current trait for each type in its list.
328        impl $op<&Self> for $t {
329          type Output = Self;
330          #[inline]
331          fn $method(self, rhs: &Self) -> Self::Output {
332            self.$method(*rhs)
333          }
334        }
335      )+
336    )+
337  };
338}
339
340bulk_impl_op_ref_self_for! {
341  (Add, add) => [f32x16, f32x8, f32x4, f64x8, f64x4, f64x2, i8x32, i8x16, i16x8, i16x16, i16x32, i32x8, i32x4, i32x16, i64x2, i64x4, i64x8, u8x32, u8x16, u16x8, u16x16, u16x32, u32x8, u32x4, u32x16, u64x4, u64x2, u64x8],
342  (Sub, sub) => [f32x16, f32x8, f32x4, f64x8, f64x4, f64x2, i8x32, i8x16, i16x8, i16x16, i16x32, i32x8, i32x4, i32x16, i64x2, i64x4, i64x8, u8x32, u8x16, u16x8, u16x16, u16x32, u32x8, u32x4, u32x16, u64x4, u64x2, u64x8],
343  (Mul, mul) => [f32x16, f32x8, f32x4, f64x8, f64x4, f64x2, i16x8, i16x16, i16x32, i32x8, i32x4, i32x16, u16x8, u16x16, u16x32],
344  (Div, div) => [f32x16, f32x8, f32x4, f64x8, f64x4, f64x2],
345  (BitAnd, bitand) => [f32x16, f32x8, f32x4, f64x8, f64x4, f64x2, i8x32, i8x16, i16x8, i16x16, i16x32, i32x8, i32x4, i32x16, i64x2, i64x4, i64x8, u8x32, u8x16, u16x8, u16x16, u16x32, u32x8, u32x4, u32x16, u64x4, u64x2, u64x8],
346  (BitOr, bitor) => [f32x16, f32x8, f32x4, f64x8, f64x4, f64x2, i8x32, i8x16, i16x8, i16x16, i16x32, i32x8, i32x4, i32x16, i64x2, i64x4, i64x8, u8x32, u8x16, u16x8, u16x16, u16x32, u32x8, u32x4, u32x16, u64x4, u64x2, u64x8],
347  (BitXor, bitxor) => [f32x16, f32x8, f32x4, f64x8, f64x4, f64x2, i8x32, i8x16, i16x8, i16x16, i16x32, i32x8, i32x4, i32x16, i64x2, i64x4, i64x8, u8x32, u8x16, u16x8, u16x16, u16x32, u32x8, u32x4, u32x16, u64x4, u64x2, u64x8],
348}
349
350/// given `type.op(rhs)` and type is Copy, impls `type.op_assign(rhs)`
351macro_rules! bulk_impl_op_assign_for {
352  ($(($op:ident<$rhs:ty>, $method:ident, $method_assign:ident) => [$($t:ty),+]),+ $(,)?) => {
353    $( // do each trait/list matching given
354      $( // do the current trait for each type in its list.
355        impl $op<$rhs> for $t {
356          #[inline]
357          fn $method_assign(&mut self, rhs: $rhs) {
358            *self = self.$method(rhs);
359          }
360        }
361      )+
362    )+
363  };
364}
365
366// Note: remember to update bulk_impl_op_ref_self_for first or this will give
367// weird errors!
368bulk_impl_op_assign_for! {
369  (AddAssign<Self>, add, add_assign) => [f32x16, f32x8, f32x4, f64x8, f64x4, f64x2, i8x32, i8x16, i16x8, i16x16, i16x32, i32x8, i32x4, i32x16, i64x2, i64x4, i64x8, u8x32, u8x16, u16x8, u16x16, u16x32, u32x8, u32x4, u32x16, u64x4, u64x2, u64x8],
370  (AddAssign<&Self>, add, add_assign) => [f32x16, f32x8, f32x4, f64x8, f64x4, f64x2, i8x32, i8x16, i16x8, i16x16, i16x32, i32x8, i32x4, i32x16, i64x2, i64x4, i64x8, u8x32, u8x16, u16x8, u16x16, u16x32, u32x8, u32x4, u32x16, u64x4, u64x2, u64x8],
371  (SubAssign<Self>, sub, sub_assign) => [f32x16, f32x8, f32x4, f64x8, f64x4, f64x2, i8x32, i8x16, i16x8, i16x16, i16x32, i32x8, i32x4, i32x16, i64x2, i64x4, i64x8, u8x32, u8x16, u16x8, u16x16, u16x32, u32x8, u32x4, u32x16, u64x4, u64x2, u64x8],
372  (SubAssign<&Self>, sub, sub_assign) => [f32x16, f32x8, f32x4, f64x8, f64x4, f64x2, i8x32, i8x16, i16x8, i16x16, i16x32, i32x8, i32x4, i32x16, i64x2, i64x4, i64x8, u8x32, u8x16, u16x8, u16x16, u16x32, u32x8, u32x4, u32x16, u64x4, u64x2, u64x8],
373  (MulAssign<Self>, mul, mul_assign) => [f32x16, f32x8, f32x4, f64x8, f64x4, f64x2, i16x8, i16x16, i16x32, i32x8, i32x4, i32x16, u16x8, u16x16, u16x32],
374  (MulAssign<&Self>, mul, mul_assign) => [f32x16, f32x8, f32x4, f64x8, f64x4, f64x2, i16x8, i16x16, i16x32, i32x8, i32x4, i32x16, u16x8, u16x16, u16x32],
375  (DivAssign<Self>, div, div_assign) => [f32x16, f32x8, f32x4, f64x8, f64x4, f64x2],
376  (DivAssign<&Self>, div, div_assign) => [f32x16, f32x8, f32x4, f64x8, f64x4, f64x2],
377  (BitAndAssign<Self>, bitand, bitand_assign) => [f32x16, f32x8, f32x4, f64x8, f64x4, f64x2, i8x32, i8x16, i16x8, i16x16, i16x32, u16x16, u16x32, i32x8, i32x4, i32x16, i64x2, i64x4, i64x8, u8x32, u8x16, u16x8, u32x8, u32x4, u32x16, u64x4, u64x2, u64x8],
378  (BitAndAssign<&Self>, bitand, bitand_assign) => [f32x16, f32x8, f32x4, f64x8, f64x4, f64x2, i8x32, i8x16, i16x8, i16x16, i16x32, u16x16, u16x32, i32x8, i32x4, i32x16, i64x2, i64x4, i64x8, u8x32, u8x16, u16x8, u32x8, u32x4, u32x16, u64x4, u64x2, u64x8],
379  (BitOrAssign<Self>, bitor, bitor_assign) => [f32x16, f32x8, f32x4, f64x8, f64x4, f64x2, i8x32, i8x16, i16x8, i16x16, i16x32, u16x16, u16x32, i32x8, i32x4, i32x16, i64x2, i64x4, i64x8, u8x32, u8x16, u16x8, u32x8, u32x4, u32x16, u64x4, u64x2, u64x8],
380  (BitOrAssign<&Self>, bitor, bitor_assign) => [f32x16, f32x8, f32x4, f64x8, f64x4, f64x2, i8x32, i8x16, i16x8, i16x16, i16x32, u16x16, u16x32, i32x8, i32x4, i32x16, i64x2, i64x4, i64x8, u8x32, u8x16, u16x8, u32x8, u32x4, u32x16, u64x4, u64x2, u64x8],
381  (BitXorAssign<Self>, bitxor, bitxor_assign) => [f32x16, f32x8, f32x4, f64x8, f64x4, f64x2, i8x32, i8x16, i16x8, i16x16, i16x32, u16x16, u16x32, i32x8, i32x4, i32x16, i64x2, i64x4, i64x8, u8x32, u8x16, u16x8, u32x8, u32x4, u32x16, u64x4, u64x2, u64x8],
382  (BitXorAssign<&Self>, bitxor, bitxor_assign) => [f32x16, f32x8, f32x4, f64x8, f64x4, f64x2, i8x32, i8x16, i16x8, i16x16, i16x32, u16x16, u16x32, i32x8, i32x4, i32x16, i64x2, i64x4, i64x8, u8x32, u8x16, u16x8, u32x8, u32x4, u32x16, u64x4, u64x2, u64x8],
383}
384
385macro_rules! impl_integer_neg {
386  ($($t:ty),+ $(,)?) => {
387    $(
388      impl Neg for $t {
389        type Output = Self;
390        #[inline(always)]
391        fn neg(self) -> Self::Output {
392          Self::default() - self
393        }
394      }
395      impl Neg for &'_ $t {
396        type Output = $t;
397        #[inline(always)]
398        fn neg(self) -> Self::Output {
399          <$t>::default() - *self
400        }
401      }
402    )+
403  };
404}
405
406impl_integer_neg! {
407  i8x32, i8x16, i16x8, i16x16, i16x32, i32x8, i32x4, i32x16, i64x4, i64x2, i64x8, u8x32, u8x16, u16x8, u16x16, u16x32, u32x8, u32x4, u32x16, u64x2, u64x4, u64x8
408}
409
410// only works for 128 bit values
411macro_rules! impl_simple_not {
412  ($($t:ty),+ $(,)?) => {
413    $(
414      impl Not for $t {
415        type Output = Self;
416        #[inline]
417        fn not(self) -> Self::Output {
418          self ^ cast::<u128, $t>(u128::MAX)
419        }
420      }
421      impl Not for &'_ $t {
422        type Output = $t;
423        #[inline]
424        fn not(self) -> Self::Output {
425          *self ^ cast::<u128, $t>(u128::MAX)
426        }
427      }
428    )+
429  };
430}
431
432impl_simple_not! {
433  f32x4, i8x16, i16x8, i32x4, i64x2, u8x16, u16x8, u32x4, u64x2,
434}
435
436macro_rules! impl_simple_sum {
437  ($($t:ty),+ $(,)?) => {
438    $(
439      impl<RHS> core::iter::Sum<RHS> for $t where $t: AddAssign<RHS> {
440        #[inline]
441        fn sum<I: Iterator<Item = RHS>>(iter: I) -> Self {
442          let mut total = Self::zeroed();
443          for val in iter {
444            total += val;
445          }
446          total
447        }
448      }
449    )+
450  };
451}
452
453impl_simple_sum! {
454  f32x16, f32x4, f64x8, f64x4, f64x2, i8x32, i8x16, i16x8, i16x16, i16x32, i32x8, i32x4, i32x16, i64x4, i64x2, i64x8, u8x32, u8x16, u16x8, u16x16, u16x32, u32x8, u32x4, u32x16, u64x2, u64x4, u64x8
455}
456
457macro_rules! impl_floating_product {
458  ($($t:ty),+ $(,)?) => {
459    $(
460      impl<RHS> core::iter::Product<RHS> for $t where $t: MulAssign<RHS> {
461        #[inline]
462        fn product<I: Iterator<Item = RHS>>(iter: I) -> Self {
463          let mut total = Self::from(1.0);
464          for val in iter {
465            total *= val;
466          }
467          total
468        }
469      }
470    )+
471  };
472}
473
474impl_floating_product! {
475  f32x16, f32x8, f32x4, f64x8, f64x4, f64x2
476}
477
478macro_rules! impl_integer_product {
479  ($($t:ty),+ $(,)?) => {
480    $(
481      impl<RHS> core::iter::Product<RHS> for $t where $t: MulAssign<RHS> {
482        #[inline]
483        fn product<I: Iterator<Item = RHS>>(iter: I) -> Self {
484          let mut total = Self::from(1);
485          for val in iter {
486            total *= val;
487          }
488          total
489        }
490      }
491    )+
492  };
493}
494
495impl_integer_product! {
496  i16x8, i16x32, i32x4, i32x8, i32x16,
497}
498
499/// impls `From<a> for b` by just calling `cast`
500macro_rules! impl_from_a_for_b_with_cast {
501  ($(($arr:ty, $simd:ty)),+  $(,)?) => {
502    $(impl From<$arr> for $simd {
503      #[inline]
504      fn from(arr: $arr) -> Self {
505        cast(arr)
506      }
507    }
508    impl From<$simd> for $arr {
509      #[inline]
510      fn from(simd: $simd) -> Self {
511        cast(simd)
512      }
513    })+
514  };
515}
516
517impl_from_a_for_b_with_cast! {
518  ([f32;16], f32x16), ([f32;8], f32x8),
519  ([f32;4], f32x4), ([f64;8], f64x8), ([f64;4], f64x4), ([f64;2], f64x2),
520  ([i8;32], i8x32), ([i8;16], i8x16), ([i16;8], i16x8), ([i16;16], i16x16), ([i16;32], i16x32), ([i32;8], i32x8), ([i32;4], i32x4), ([i32;16], i32x16), ([i64;2], i64x2), ([i64;4], i64x4), ([i64;8], i64x8),
521  ([u8;32], u8x32), ([u8;16], u8x16), ([u16;8], u16x8), ([u16;16], u16x16), ([u16;32], u16x32), ([u32;8], u32x8), ([u32;4], u32x4), ([u32;16], u32x16), ([u64;2], u64x2), ([u64;4], u64x4), ([u64;8], u64x8),
522}
523
524macro_rules! impl_from_single_value {
525  ($(([$elem:ty;$len:expr], $simd:ty)),+  $(,)?) => {
526    $(impl From<$elem> for $simd {
527      /// Splats the single value given across all lanes.
528      #[inline]
529      fn from(elem: $elem) -> Self {
530        cast([elem; $len])
531      }
532    }
533    impl $simd {
534      #[inline]
535      #[must_use]
536      pub const fn splat(elem: $elem) -> $simd {
537        unsafe { core::mem::transmute([elem; $len]) }
538      }
539    })+
540  };
541}
542
543impl_from_single_value! {
544  ([f32;16], f32x16), ([f32;8], f32x8),
545  ([f32;4], f32x4), ([f64;8], f64x8), ([f64;4], f64x4), ([f64;2], f64x2),
546  ([i8;32], i8x32), ([i8;16], i8x16), ([i16;8], i16x8), ([i16;16], i16x16), ([i16;32], i16x32), ([i32;8], i32x8), ([i32;4], i32x4), ([i32;16], i32x16), ([i64;2], i64x2), ([i64;4], i64x4), ([i64;8], i64x8),
547  ([u8;32], u8x32), ([u8;16], u8x16), ([u16;8], u16x8), ([u16;16], u16x16), ([u16;32], u16x32), ([u32;8], u32x8), ([u32;4], u32x4), ([u32;16], u32x16), ([u64;2], u64x2), ([u64;4], u64x4), ([u64;8], u64x8),
548}
549
550/// formatter => [(arr, simd)+],+
551macro_rules! impl_formatter_for {
552  ($($trait:ident => [$(($arr:ty, $simd:ty)),+]),+ $(,)?) => {
553    $( // do per trait
554      $( // do per simd type
555        impl $trait for $simd {
556          #[allow(clippy::missing_inline_in_public_items)]
557          fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
558            let a: $arr = cast(*self);
559            write!(f, "(")?;
560            for (x, a_ref) in a.iter().enumerate() {
561              if x > 0 {
562                write!(f, ", ")?;
563              }
564              $trait::fmt(a_ref, f)?;
565            }
566            write!(f, ")")
567          }
568        }
569      )+
570    )+
571  }
572}
573
574impl_formatter_for! {
575  Binary => [([u32;16], f32x16), ([u32;8], f32x8), ([u32;4], f32x4), ([u64;8], f64x8), ([u64;4], f64x4), ([u64;2], f64x2),
576  ([i8;32], i8x32), ([i8;16], i8x16), ([i16;8], i16x8), ([i16;16], i16x16), ([i16;32], i16x32), ([i32;8], i32x8), ([i32;4], i32x4), ([i32;16], i32x16), ([i64;2], i64x2),([i64;4], i64x4),([i64;8], i64x8),
577  ([u8;32], u8x32), ([u8;16], u8x16), ([u16;8], u16x8), ([u16;16], u16x16), ([u16;32], u16x32), ([u32;8], u32x8), ([u32;4], u32x4), ([u32;16], u32x16), ([u64;2], u64x2),([u64;4], u64x4),([u64;8], u64x8)],
578  Debug => [([f32;16], f32x16), ([f32;8], f32x8), ([f32;4], f32x4), ([f64;8], f64x8), ([f64;4], f64x4), ([f64;2], f64x2),
579  ([i8;32], i8x32), ([i8;16], i8x16), ([i16;8], i16x8), ([i16;16], i16x16), ([i16;32], i16x32), ([i32;8], i32x8), ([i32;4], i32x4), ([i32;16], i32x16), ([i64;2], i64x2),([i64;4], i64x4),([i64;8], i64x8),
580  ([u8;32], u8x32), ([u8;16], u8x16), ([u16;8], u16x8), ([u16;16], u16x16), ([u16;32], u16x32), ([u32;8], u32x8), ([u32;4], u32x4), ([u32;16], u32x16), ([u64;2], u64x2),([u64;4], u64x4),([u64;8], u64x8)],
581  Display => [([f32;16], f32x16), ([f32;8], f32x8), ([f32;4], f32x4), ([f64;8], f64x8), ([f64;4], f64x4), ([f64;2], f64x2),
582  ([i8;32], i8x32), ([i8;16], i8x16), ([i16;8], i16x8), ([i16;16], i16x16), ([i16;32], i16x32), ([i32;8], i32x8), ([i32;4], i32x4), ([i32;16], i32x16), ([i64;2], i64x2),([i64;4], i64x4),([i64;8], i64x8),
583  ([u8;32], u8x32), ([u8;16], u8x16), ([u16;8], u16x8), ([u16;16], u16x16), ([u16;32], u16x32), ([u32;8], u32x8), ([u32;4], u32x4), ([u32;16], u32x16), ([u64;2], u64x2),([u64;4], u64x4),([u64;8], u64x8)],
584  LowerExp => [([f32;16], f32x16), ([f32;8], f32x8), ([f32;4], f32x4), ([f64;8], f64x8), ([f64;4], f64x4), ([f64;2], f64x2),
585  ([i8;32], i8x32), ([i8;16], i8x16), ([i16;8], i16x8), ([i16;16], i16x16), ([i16;32], i16x32), ([i32;8], i32x8), ([i32;4], i32x4), ([i32;16], i32x16), ([i64;2], i64x2),([i64;4], i64x4),([i64;8], i64x8),
586  ([u8;32], u8x32), ([u8;16], u8x16), ([u16;8], u16x8), ([u16;16], u16x16), ([u16;32], u16x32), ([u32;8], u32x8), ([u32;4], u32x4), ([u32;16], u32x16), ([u64;2], u64x2),([u64;4], u64x4),([u64;8], u64x8)],
587  LowerHex => [([u32;16], f32x16), ([u32;8], f32x8), ([u32;4], f32x4), ([u64;8], f64x8), ([u64;4], f64x4), ([u64;2], f64x2),
588  ([i8;32], i8x32), ([i8;16], i8x16), ([i16;8], i16x8), ([i16;16], i16x16), ([i16;32], i16x32), ([i32;8], i32x8), ([i32;4], i32x4), ([i32;16], i32x16), ([i64;2], i64x2),([i64;4], i64x4),([i64;8], i64x8),
589  ([u8;32], u8x32), ([u8;16], u8x16), ([u16;8], u16x8), ([u16;16], u16x16), ([u16;32], u16x32), ([u32;8], u32x8), ([u32;4], u32x4), ([u32;16], u32x16), ([u64;2], u64x2),([u64;4], u64x4),([u64;8], u64x8)],
590  Octal => [([u32;16], f32x16), ([u32;8], f32x8), ([u32;4], f32x4), ([u64;8], f64x8), ([u64;4], f64x4), ([u64;2], f64x2),
591  ([i8;32], i8x32), ([i8;16], i8x16), ([i16;8], i16x8), ([i16;16], i16x16), ([i16;32], i16x32), ([i32;8], i32x8), ([i32;4], i32x4), ([i32;16], i32x16), ([i64;2], i64x2),([i64;4], i64x4),([i64;8], i64x8),
592  ([u8;32], u8x32), ([u8;16], u8x16), ([u16;8], u16x8), ([u16;16], u16x16), ([u16;32], u16x32), ([u32;8], u32x8), ([u32;4], u32x4), ([u32;16], u32x16), ([u64;2], u64x2),([u64;4], u64x4),([u64;8], u64x8)],
593  UpperExp => [([u32;16], f32x16), ([u32;8], f32x8), ([u32;4], f32x4), ([u64;8], f64x8), ([u64;4], f64x4), ([u64;2], f64x2),
594  ([i8;32], i8x32), ([i8;16], i8x16), ([i16;8], i16x8), ([i16;16], i16x16), ([i16;32], i16x32), ([i32;8], i32x8), ([i32;4], i32x4), ([i32;16], i32x16), ([i64;2], i64x2),([i64;4], i64x4),([i64;8], i64x8),
595  ([u8;32], u8x32), ([u8;16], u8x16), ([u16;8], u16x8), ([u16;16], u16x16), ([u16;32], u16x32), ([u32;8], u32x8), ([u32;4], u32x4), ([u32;16], u32x16), ([u64;2], u64x2),([u64;4], u64x4),([u64;8], u64x8)],
596  UpperHex => [([u32;16], f32x16), ([u32;8], f32x8), ([u32;4], f32x4), ([u64;8], f64x8), ([u64;4], f64x4), ([u64;2], f64x2),
597  ([i8;32], i8x32), ([i8;16], i8x16), ([i16;8], i16x8), ([i16;16], i16x16), ([i16;32], i16x32), ([i32;8], i32x8), ([i32;4], i32x4), ([i32;16], i32x16), ([i64;2], i64x2),([i64;4], i64x4),([i64;8], i64x8),
598  ([u8;32], u8x32), ([u8;16], u8x16), ([u16;8], u16x8), ([u16;16], u16x16), ([u16;32], u16x32), ([u32;8], u32x8), ([u32;4], u32x4), ([u32;16], u32x16), ([u64;2], u64x2),([u64;4], u64x4),([u64;8], u64x8)],
599}
600
601// With const generics this could be simplified I hope
602macro_rules! from_array {
603  ($ty:ty,$dst:ty,$dst_wide:ident,32) => {
604    impl From<&[$ty]> for $dst_wide {
605      #[inline]
606      fn from(src: &[$ty]) -> $dst_wide {
607        match src.len() {
608          32 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst, src[7] as $dst, src[8] as $dst, src[9] as $dst, src[10] as $dst, src[11] as $dst, src[12] as $dst, src[13] as $dst, src[14] as $dst, src[15] as $dst, src[16] as $dst, src[17] as $dst, src[18] as $dst, src[19] as $dst, src[20] as $dst, src[21] as $dst, src[22] as $dst, src[23] as $dst, src[24] as $dst, src[25] as $dst, src[26] as $dst, src[27] as $dst, src[28] as $dst, src[29] as $dst, src[30] as $dst, src[31] as $dst,]),
609          31 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst, src[7] as $dst, src[8] as $dst, src[9] as $dst, src[10] as $dst, src[11] as $dst, src[12] as $dst, src[13] as $dst, src[14] as $dst, src[15] as $dst, src[16] as $dst, src[17] as $dst, src[18] as $dst, src[19] as $dst, src[20] as $dst, src[21] as $dst, src[22] as $dst, src[23] as $dst, src[24] as $dst, src[25] as $dst, src[26] as $dst, src[27] as $dst, src[28] as $dst, src[29] as $dst, src[30] as $dst,0 as $dst,]),
610          30 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst, src[7] as $dst, src[8] as $dst, src[9] as $dst, src[10] as $dst, src[11] as $dst, src[12] as $dst, src[13] as $dst, src[14] as $dst, src[15] as $dst, src[16] as $dst, src[17] as $dst, src[18] as $dst, src[19] as $dst, src[20] as $dst, src[21] as $dst, src[22] as $dst, src[23] as $dst, src[24] as $dst, src[25] as $dst, src[26] as $dst, src[27] as $dst, src[28] as $dst, src[29] as $dst,0 as $dst,0 as $dst,]),
611          29 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst, src[7] as $dst, src[8] as $dst, src[9] as $dst, src[10] as $dst, src[11] as $dst, src[12] as $dst, src[13] as $dst, src[14] as $dst, src[15] as $dst, src[16] as $dst, src[17] as $dst, src[18] as $dst, src[19] as $dst, src[20] as $dst, src[21] as $dst, src[22] as $dst, src[23] as $dst, src[24] as $dst, src[25] as $dst, src[26] as $dst, src[27] as $dst, src[28] as $dst,0 as $dst,0 as $dst,0 as $dst,]),
612          28 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst, src[7] as $dst, src[8] as $dst, src[9] as $dst, src[10] as $dst, src[11] as $dst, src[12] as $dst, src[13] as $dst, src[14] as $dst, src[15] as $dst, src[16] as $dst, src[17] as $dst, src[18] as $dst, src[19] as $dst, src[20] as $dst, src[21] as $dst, src[22] as $dst, src[23] as $dst, src[24] as $dst, src[25] as $dst, src[26] as $dst, src[27] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
613          27 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst, src[7] as $dst, src[8] as $dst, src[9] as $dst, src[10] as $dst, src[11] as $dst, src[12] as $dst, src[13] as $dst, src[14] as $dst, src[15] as $dst, src[16] as $dst, src[17] as $dst, src[18] as $dst, src[19] as $dst, src[20] as $dst, src[21] as $dst, src[22] as $dst, src[23] as $dst, src[24] as $dst, src[25] as $dst, src[26] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
614          26 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst, src[7] as $dst, src[8] as $dst, src[9] as $dst, src[10] as $dst, src[11] as $dst, src[12] as $dst, src[13] as $dst, src[14] as $dst, src[15] as $dst, src[16] as $dst, src[17] as $dst, src[18] as $dst, src[19] as $dst, src[20] as $dst, src[21] as $dst, src[22] as $dst, src[23] as $dst, src[24] as $dst, src[25] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
615          25 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst, src[7] as $dst, src[8] as $dst, src[9] as $dst, src[10] as $dst, src[11] as $dst, src[12] as $dst, src[13] as $dst, src[14] as $dst, src[15] as $dst, src[16] as $dst, src[17] as $dst, src[18] as $dst, src[19] as $dst, src[20] as $dst, src[21] as $dst, src[22] as $dst, src[23] as $dst, src[24] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
616          24 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst, src[7] as $dst, src[8] as $dst, src[9] as $dst, src[10] as $dst, src[11] as $dst, src[12] as $dst, src[13] as $dst, src[14] as $dst, src[15] as $dst, src[16] as $dst, src[17] as $dst, src[18] as $dst, src[19] as $dst, src[20] as $dst, src[21] as $dst, src[22] as $dst, src[23] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
617          23 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst, src[7] as $dst, src[8] as $dst, src[9] as $dst, src[10] as $dst, src[11] as $dst, src[12] as $dst, src[13] as $dst, src[14] as $dst, src[15] as $dst, src[16] as $dst, src[17] as $dst, src[18] as $dst, src[19] as $dst, src[20] as $dst, src[21] as $dst, src[22] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
618          22 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst, src[7] as $dst, src[8] as $dst, src[9] as $dst, src[10] as $dst, src[11] as $dst, src[12] as $dst, src[13] as $dst, src[14] as $dst, src[15] as $dst, src[16] as $dst, src[17] as $dst, src[18] as $dst, src[19] as $dst, src[20] as $dst, src[21] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
619          21 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst, src[7] as $dst, src[8] as $dst, src[9] as $dst, src[10] as $dst, src[11] as $dst, src[12] as $dst, src[13] as $dst, src[14] as $dst, src[15] as $dst, src[16] as $dst, src[17] as $dst, src[18] as $dst, src[19] as $dst, src[20] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
620          20 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst, src[7] as $dst, src[8] as $dst, src[9] as $dst, src[10] as $dst, src[11] as $dst, src[12] as $dst, src[13] as $dst, src[14] as $dst, src[15] as $dst, src[16] as $dst, src[17] as $dst, src[18] as $dst, src[19] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
621          19 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst, src[7] as $dst, src[8] as $dst, src[9] as $dst, src[10] as $dst, src[11] as $dst, src[12] as $dst, src[13] as $dst, src[14] as $dst, src[15] as $dst, src[16] as $dst, src[17] as $dst, src[18] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
622          18 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst, src[7] as $dst, src[8] as $dst, src[9] as $dst, src[10] as $dst, src[11] as $dst, src[12] as $dst, src[13] as $dst, src[14] as $dst, src[15] as $dst, src[16] as $dst, src[17] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
623          17 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst, src[7] as $dst, src[8] as $dst, src[9] as $dst, src[10] as $dst, src[11] as $dst, src[12] as $dst, src[13] as $dst, src[14] as $dst, src[15] as $dst, src[16] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
624          16 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst, src[7] as $dst, src[8] as $dst, src[9] as $dst, src[10] as $dst, src[11] as $dst, src[12] as $dst, src[13] as $dst, src[14] as $dst, src[15] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
625          15 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst, src[7] as $dst, src[8] as $dst, src[9] as $dst, src[10] as $dst, src[11] as $dst, src[12] as $dst, src[13] as $dst, src[14] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
626          14 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst, src[7] as $dst, src[8] as $dst, src[9] as $dst, src[10] as $dst, src[11] as $dst, src[12] as $dst, src[13] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
627          13 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst, src[7] as $dst, src[8] as $dst, src[9] as $dst, src[10] as $dst, src[11] as $dst, src[12] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
628          12 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst, src[7] as $dst, src[8] as $dst, src[9] as $dst, src[10] as $dst, src[11] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
629          11 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst, src[7] as $dst, src[8] as $dst, src[9] as $dst, src[10] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
630          10 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst, src[7] as $dst, src[8] as $dst, src[9] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
631          9 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst, src[7] as $dst, src[8] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
632          8 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst, src[7] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
633          7 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
634          6 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
635          5 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
636          4 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
637          3 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
638          2 => $dst_wide::from([src[0] as $dst, src[1] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
639          1 => $dst_wide::from([src[0] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
640          _ => panic!(
641            "Converting from an array larger than what can be stored in $dst_wide"
642          ),
643        }
644      }
645    }
646  };
647  ($ty:ty,$dst:ty,$dst_wide:ident,16) => {
648    impl From<&[$ty]> for $dst_wide {
649      #[inline]
650      fn from(src: &[$ty]) -> $dst_wide {
651        match src.len() {
652          16 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst, src[7] as $dst, src[8] as $dst, src[9] as $dst, src[10] as $dst, src[11] as $dst, src[12] as $dst, src[13] as $dst, src[14] as $dst, src[15] as $dst,]),
653          15 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst, src[7] as $dst, src[8] as $dst, src[9] as $dst, src[10] as $dst, src[11] as $dst, src[12] as $dst, src[13] as $dst, src[14] as $dst,0 as $dst,]),
654          14 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst, src[7] as $dst, src[8] as $dst, src[9] as $dst, src[10] as $dst, src[11] as $dst, src[12] as $dst, src[13] as $dst,0 as $dst,0 as $dst,]),
655          13 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst, src[7] as $dst, src[8] as $dst, src[9] as $dst, src[10] as $dst, src[11] as $dst, src[12] as $dst,0 as $dst,0 as $dst,0 as $dst,]),
656          12 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst, src[7] as $dst, src[8] as $dst, src[9] as $dst, src[10] as $dst, src[11] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
657          11 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst, src[7] as $dst, src[8] as $dst, src[9] as $dst, src[10] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
658          10 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst, src[7] as $dst, src[8] as $dst, src[9] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
659          9 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst, src[7] as $dst, src[8] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
660          8 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst, src[7] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
661          7 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
662          6 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
663          5 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
664          4 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
665          3 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
666          2 => $dst_wide::from([src[0] as $dst, src[1] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
667          1 => $dst_wide::from([src[0] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
668          _ => panic!(
669            "Converting from an array larger than what can be stored in $dst_wide"
670          ),
671        }
672      }
673    }
674  };
675  ($ty:ty,$dst:ty,$dst_wide:ident,8) => {
676    impl From<&[$ty]> for $dst_wide {
677      #[inline]
678      fn from(src: &[$ty]) -> $dst_wide {
679        match src.len() {
680          8 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst, src[7] as $dst,]),
681          7 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst,0 as $dst,]),
682          6 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst,0 as $dst,0 as $dst,]),
683          5 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst,0 as $dst,0 as $dst,0 as $dst,]),
684          4 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
685          3 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
686          2 => $dst_wide::from([src[0] as $dst, src[1] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
687          1 => $dst_wide::from([src[0] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
688          0 => $dst_wide::from([0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
689          _ => panic!(
690            "Converting from an array larger than what can be stored in $dst_wide"
691          ),
692        }
693      }
694    }
695  };
696  ($ty:ty,$dst:ty,$dst_wide:ident,4) => {
697    impl From<&[$ty]> for $dst_wide {
698      #[inline]
699      fn from(src: &[$ty]) -> $dst_wide {
700        match src.len() {
701          4 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst,]),
702          3 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst,0 as $dst,]),
703          2 => $dst_wide::from([src[0] as $dst, src[1] as $dst,0 as $dst,0 as $dst,]),
704          1 => $dst_wide::from([src[0] as $dst,0 as $dst,0 as $dst,0 as $dst,]),
705          _ => panic!(
706            "Converting from an array larger than what can be stored in $dst_wide"
707          ),
708        }
709      }
710    }
711  };
712}
713
714from_array!(i8, i8, i8x32, 32);
715from_array!(i8, i8, i8x16, 16);
716from_array!(i8, i32, i32x8, 8);
717from_array!(u8, u8, u8x16, 16);
718from_array!(u8, u8, u8x32, 32);
719from_array!(i16, i16, i16x16, 16);
720from_array!(u16, u16, u16x16, 16);
721from_array!(i32, i32, i32x8, 8);
722from_array!(f32, f32, f32x8, 8);
723from_array!(f32, f32, f32x4, 4);
724from_array!(f64, f64, f64x4, 4);
725from_array!(u64, u64, u64x4, 4);
726from_array!(i64, i64, i64x4, 4);
727from_array!(u64, u64, u64x8, 8);
728from_array!(i64, i64, i64x8, 8);
729from_array!(i16, i16, i16x32, 32);
730from_array!(u16, u16, u16x32, 32);
731from_array!(i32, i32, i32x16, 16);
732from_array!(u32, u32, u32x16, 16);
733from_array!(f32, f32, f32x16, 16);
734from_array!(f64, f64, f64x8, 8);
735
736#[allow(unused)]
737fn software_sqrt(x: f64) -> f64 {
738  use core::num::Wrapping;
739  type wu32 = Wrapping<u32>;
740  const fn w(u: u32) -> wu32 {
741    Wrapping(u)
742  }
743  let mut z: f64;
744  let sign: wu32 = w(0x80000000);
745  let mut ix0: i32;
746  let mut s0: i32;
747  let mut q: i32;
748  let mut m: i32;
749  let mut t: i32;
750  let mut i: i32;
751  let mut r: wu32;
752  let mut t1: wu32;
753  let mut s1: wu32;
754  let mut ix1: wu32;
755  let mut q1: wu32;
756  // extract data
757
758  pick! {
759    if #[cfg(target_endian = "little")]
760    {
761      let [low, high]: [u32; 2] = cast(x);
762      ix0 = high as i32;
763      ix1 = w(low);
764    }
765    else
766    {
767      let [high, low]: [u32; 2] = cast(x);
768      ix0 = high as i32;
769      ix1 = w(low);
770    }
771  }
772
773  // inf and nan
774  {
775    if x.is_nan() {
776      return f64::NAN;
777    }
778    if ix0 & 0x7ff00000 == 0x7ff00000 {
779      return x * x + x;
780    }
781  }
782  // handle zero
783  {
784    if ix0 <= 0 {
785      if ((ix0 & (!sign).0 as i32) | (ix1.0 as i32)) == 0 {
786        return x;
787      } else if ix0 < 0 {
788        return (x - x) / (x - x);
789      }
790    }
791  }
792  // normalize
793  {
794    m = ix0 >> 20;
795    if m == 0 {
796      // subnormal
797      while ix0 == 0 {
798        m -= 21;
799        ix0 |= (ix1 >> 11).0 as i32;
800        ix1 <<= 21;
801      }
802      i = 0;
803      while ix0 & 0x00100000 == 0 {
804        ix0 <<= 1;
805        i += 1;
806      }
807      m -= i - 1;
808      ix0 |= (ix1.0 >> (31 - i)) as i32;
809      ix1 <<= i as usize;
810    }
811    // un-bias exponent
812    m -= 1023;
813    ix0 = (ix0 & 0x000fffff) | 0x00100000;
814    if (m & 1) != 0 {
815      // odd m, double the input to make it even
816      ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32;
817      ix1 += ix1;
818    }
819    m >>= 1;
820  }
821  // generate sqrt bit by bit
822  {
823    ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32;
824    ix1 += ix1;
825    // q and q1 store the sqrt(x);
826    q = 0;
827    q1 = w(0);
828    s0 = 0;
829    s1 = w(0);
830    // our bit that moves from right to left
831    r = w(0x00200000);
832    while r != w(0) {
833      t = s0 + (r.0 as i32);
834      if t <= ix0 {
835        s0 = t + (r.0 as i32);
836        ix0 -= t;
837        q += (r.0 as i32);
838      }
839      ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32;
840      ix1 += ix1;
841      r >>= 1;
842    }
843    r = sign;
844    while r != w(0) {
845      t1 = s1 + r;
846      t = s0;
847      if (t < ix0) || ((t == ix0) && (t1 <= ix1)) {
848        s1 = t1 + r;
849        if t1 & sign == sign && (s1 & sign) == w(0) {
850          s0 += 1;
851        }
852        ix0 -= t;
853        if ix1 < t1 {
854          ix0 -= 1;
855        }
856        ix1 -= t1;
857        q1 += r;
858      }
859      ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32;
860      ix1 += ix1;
861      r >>= 1;
862    }
863  }
864  // use floating add to find out rounding direction
865  {
866    if ix0 | (ix1.0 as i32) != 0 {
867      z = 1.0 - 1.0e-300;
868      if z >= 1.0 {
869        z = 1.0 + 1.0e-300;
870        if q1 == w(0xffffffff) {
871          q1 = w(0);
872          q += 1;
873        } else if z > 1.0 {
874          if q1 == w(0xfffffffe) {
875            q += 1;
876          }
877          q1 += w(2);
878        } else {
879          q1 += q1 & w(1);
880        }
881      }
882    }
883  }
884  // finish up
885  ix0 = (q >> 1) + 0x3fe00000;
886  ix1 = q1 >> 1;
887  if q & 1 == 1 {
888    ix1 |= sign;
889  }
890  ix0 += m << 20;
891
892  pick! {
893    if #[cfg(target_endian = "little")]
894    {
895      cast::<[u32; 2], f64>([ix1.0, ix0 as u32])
896    }
897    else
898    {
899      cast::<[u32; 2], f64>([ix0 as u32, ix1.0])
900    }
901  }
902}
903
904#[test]
905fn test_software_sqrt() {
906  assert!(software_sqrt(f64::NAN).is_nan());
907  assert_eq!(software_sqrt(f64::INFINITY), f64::INFINITY);
908  assert_eq!(software_sqrt(0.0), 0.0);
909  assert_eq!(software_sqrt(-0.0), -0.0);
910  assert!(software_sqrt(-1.0).is_nan());
911  assert!(software_sqrt(f64::NEG_INFINITY).is_nan());
912  assert_eq!(software_sqrt(4.0), 2.0);
913  assert_eq!(software_sqrt(9.0), 3.0);
914  assert_eq!(software_sqrt(16.0), 4.0);
915  assert_eq!(software_sqrt(25.0), 5.0);
916  assert_eq!(software_sqrt(5000.0 * 5000.0), 5000.0);
917}
918
919pub trait CmpEq<Rhs = Self> {
920  type Output;
921  fn simd_eq(self, rhs: Rhs) -> Self::Output;
922}
923
924pub trait CmpGt<Rhs = Self> {
925  type Output;
926  fn simd_gt(self, rhs: Rhs) -> Self::Output;
927}
928
929pub trait CmpGe<Rhs = Self> {
930  type Output;
931  fn simd_ge(self, rhs: Rhs) -> Self::Output;
932}
933
934pub trait CmpNe<Rhs = Self> {
935  type Output;
936  fn simd_ne(self, rhs: Rhs) -> Self::Output;
937}
938
939pub trait CmpLt<Rhs = Self> {
940  type Output;
941  fn simd_lt(self, rhs: Rhs) -> Self::Output;
942}
943
944pub trait CmpLe<Rhs = Self> {
945  type Output;
946  fn simd_le(self, rhs: Rhs) -> Self::Output;
947}
948pub trait AlignTo
949where
950  Self: Pod + Default + PartialEq + From<Self::Elem>,
951  Self::Elem: Pod + Default + PartialEq,
952{
953  type Elem;
954
955  #[inline]
956  fn simd_align_to(
957    slice: &[Self::Elem],
958  ) -> (&[Self::Elem], &[Self], &[Self::Elem]) {
959    pod_align_to(slice)
960  }
961
962  #[inline]
963  fn simd_align_to_mut(
964    slice: &mut [Self::Elem],
965  ) -> (&mut [Self::Elem], &mut [Self], &mut [Self::Elem]) {
966    pod_align_to_mut(slice)
967  }
968}
969
970macro_rules! bulk_impl_const_rhs_op {
971  (($op:ident,$method:ident) => [$(($lhs:ty,$rhs:ty),)+]) => {
972    $(
973    impl $op<$rhs> for $lhs {
974      type Output = Self;
975      #[inline]
976      fn $method(self, rhs: $rhs) -> Self::Output {
977        self.$method(<$lhs>::splat(rhs))
978      }
979    }
980    )+
981  };
982}
983
984bulk_impl_const_rhs_op!((CmpEq, simd_eq) => [(f64x8, f64), (f64x4, f64), (f64x2, f64), (f32x4,f32), (f32x8,f32), (f32x16,f32),]);
985bulk_impl_const_rhs_op!((CmpLt, simd_lt) => [(f64x8, f64), (f64x4, f64), (f64x2, f64), (f32x4,f32), (f32x8,f32), (f32x16,f32),]);
986bulk_impl_const_rhs_op!((CmpGt, simd_gt) => [(f64x8, f64), (f64x4, f64), (f64x2, f64), (f32x4,f32), (f32x8,f32), (f32x16,f32),]);
987bulk_impl_const_rhs_op!((CmpNe, simd_ne) => [(f64x8, f64), (f64x4, f64), (f64x2, f64), (f32x4,f32), (f32x8,f32), (f32x16,f32),]);
988bulk_impl_const_rhs_op!((CmpLe, simd_le) => [(f64x8, f64), (f64x4, f64), (f64x2, f64), (f32x4,f32), (f32x8,f32), (f32x16,f32),]);
989bulk_impl_const_rhs_op!((CmpGe, simd_ge) => [(f64x8, f64), (f64x4, f64), (f64x2, f64), (f32x4,f32), (f32x8,f32), (f32x16,f32),]);
990
991macro_rules! impl_serde {
992  ($i:ident, [$t:ty; $len:expr]) => {
993    #[cfg(feature = "serde")]
994    impl Serialize for $i {
995      #[inline]
996      fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
997      where
998        S: serde_core::Serializer,
999      {
1000        let array = self.as_array();
1001        let mut seq = serializer.serialize_tuple($len)?;
1002        for e in array {
1003          seq.serialize_element(e)?;
1004        }
1005        seq.end()
1006      }
1007    }
1008
1009    #[cfg(feature = "serde")]
1010    impl<'de> Deserialize<'de> for $i {
1011      #[inline]
1012      fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1013      where
1014        D: serde_core::Deserializer<'de>,
1015      {
1016        Ok(<[$t; $len]>::deserialize(deserializer)?.into())
1017      }
1018    }
1019  };
1020}
1021
1022impl_serde!(f32x8, [f32; 8]);
1023impl_serde!(f32x4, [f32; 4]);
1024impl_serde!(f64x4, [f64; 4]);
1025impl_serde!(f64x2, [f64; 2]);
1026impl_serde!(i8x16, [i8; 16]);
1027impl_serde!(i16x16, [i16; 16]);
1028impl_serde!(i8x32, [i8; 32]);
1029impl_serde!(i16x8, [i16; 8]);
1030impl_serde!(i32x4, [i32; 4]);
1031impl_serde!(i32x8, [i32; 8]);
1032impl_serde!(i64x2, [i64; 2]);
1033impl_serde!(i64x4, [i64; 4]);
1034impl_serde!(u8x16, [u8; 16]);
1035impl_serde!(u8x32, [u8; 32]);
1036impl_serde!(u16x8, [u16; 8]);
1037impl_serde!(u16x16, [u16; 16]);
1038impl_serde!(u32x4, [u32; 4]);
1039impl_serde!(u32x8, [u32; 8]);
1040impl_serde!(u64x2, [u64; 2]);
1041impl_serde!(u64x4, [u64; 4]);
1042impl_serde!(u64x8, [u64; 8]);
1043impl_serde!(i64x8, [i64; 8]);
1044impl_serde!(i16x32, [i16; 32]);
1045impl_serde!(u16x32, [u16; 32]);
1046impl_serde!(i32x16, [i32; 16]);
1047impl_serde!(u32x16, [u32; 16]);
1048impl_serde!(f32x16, [f32; 16]);
1049impl_serde!(f64x8, [f64; 8]);