| 1 | use crate::simd::{ |
| 2 | LaneCount, Simd, SimdElement, SupportedLaneCount, |
| 3 | num::{SimdFloat, SimdInt, SimdUint}, |
| 4 | }; |
| 5 | |
| 6 | mod sealed { |
| 7 | use super::*; |
| 8 | pub trait Sealed {} |
| 9 | impl<T: SimdElement, const N: usize> Sealed for Simd<T, N> where LaneCount<N>: SupportedLaneCount {} |
| 10 | } |
| 11 | use sealed::Sealed; |
| 12 | |
| 13 | /// Converts SIMD vectors to vectors of bytes |
| 14 | pub trait ToBytes: Sealed { |
| 15 | /// This type, reinterpreted as bytes. |
| 16 | type Bytes: Copy |
| 17 | + Unpin |
| 18 | + Send |
| 19 | + Sync |
| 20 | + AsRef<[u8]> |
| 21 | + AsMut<[u8]> |
| 22 | + SimdUint<Scalar = u8> |
| 23 | + 'static; |
| 24 | |
| 25 | /// Returns the memory representation of this integer as a byte array in native byte |
| 26 | /// order. |
| 27 | fn to_ne_bytes(self) -> Self::Bytes; |
| 28 | |
| 29 | /// Returns the memory representation of this integer as a byte array in big-endian |
| 30 | /// (network) byte order. |
| 31 | fn to_be_bytes(self) -> Self::Bytes; |
| 32 | |
| 33 | /// Returns the memory representation of this integer as a byte array in little-endian |
| 34 | /// byte order. |
| 35 | fn to_le_bytes(self) -> Self::Bytes; |
| 36 | |
| 37 | /// Creates a native endian integer value from its memory representation as a byte array |
| 38 | /// in native endianness. |
| 39 | fn from_ne_bytes(bytes: Self::Bytes) -> Self; |
| 40 | |
| 41 | /// Creates an integer value from its representation as a byte array in big endian. |
| 42 | fn from_be_bytes(bytes: Self::Bytes) -> Self; |
| 43 | |
| 44 | /// Creates an integer value from its representation as a byte array in little endian. |
| 45 | fn from_le_bytes(bytes: Self::Bytes) -> Self; |
| 46 | } |
| 47 | |
| 48 | macro_rules! swap_bytes { |
| 49 | { f32, $x:expr } => { Simd::from_bits($x.to_bits().swap_bytes()) }; |
| 50 | { f64, $x:expr } => { Simd::from_bits($x.to_bits().swap_bytes()) }; |
| 51 | { $ty:ty, $x:expr } => { $x.swap_bytes() } |
| 52 | } |
| 53 | |
| 54 | macro_rules! impl_to_bytes { |
| 55 | { $ty:tt, 1 } => { impl_to_bytes! { $ty, 1 * [1, 2, 4, 8, 16, 32, 64] } }; |
| 56 | { $ty:tt, 2 } => { impl_to_bytes! { $ty, 2 * [1, 2, 4, 8, 16, 32] } }; |
| 57 | { $ty:tt, 4 } => { impl_to_bytes! { $ty, 4 * [1, 2, 4, 8, 16] } }; |
| 58 | { $ty:tt, 8 } => { impl_to_bytes! { $ty, 8 * [1, 2, 4, 8] } }; |
| 59 | { $ty:tt, 16 } => { impl_to_bytes! { $ty, 16 * [1, 2, 4] } }; |
| 60 | { $ty:tt, 32 } => { impl_to_bytes! { $ty, 32 * [1, 2] } }; |
| 61 | { $ty:tt, 64 } => { impl_to_bytes! { $ty, 64 * [1] } }; |
| 62 | |
| 63 | { $ty:tt, $size:literal * [$($elems:literal),*] } => { |
| 64 | $( |
| 65 | impl ToBytes for Simd<$ty, $elems> { |
| 66 | type Bytes = Simd<u8, { $size * $elems }>; |
| 67 | |
| 68 | #[inline] |
| 69 | fn to_ne_bytes(self) -> Self::Bytes { |
| 70 | // Safety: transmuting between vectors is safe |
| 71 | unsafe { |
| 72 | #![allow(clippy::useless_transmute)] |
| 73 | core::mem::transmute(self) |
| 74 | } |
| 75 | } |
| 76 | |
| 77 | #[inline] |
| 78 | fn to_be_bytes(mut self) -> Self::Bytes { |
| 79 | if !cfg!(target_endian = "big" ) { |
| 80 | self = swap_bytes!($ty, self); |
| 81 | } |
| 82 | self.to_ne_bytes() |
| 83 | } |
| 84 | |
| 85 | #[inline] |
| 86 | fn to_le_bytes(mut self) -> Self::Bytes { |
| 87 | if !cfg!(target_endian = "little" ) { |
| 88 | self = swap_bytes!($ty, self); |
| 89 | } |
| 90 | self.to_ne_bytes() |
| 91 | } |
| 92 | |
| 93 | #[inline] |
| 94 | fn from_ne_bytes(bytes: Self::Bytes) -> Self { |
| 95 | // Safety: transmuting between vectors is safe |
| 96 | unsafe { |
| 97 | #![allow(clippy::useless_transmute)] |
| 98 | core::mem::transmute(bytes) |
| 99 | } |
| 100 | } |
| 101 | |
| 102 | #[inline] |
| 103 | fn from_be_bytes(bytes: Self::Bytes) -> Self { |
| 104 | let ret = Self::from_ne_bytes(bytes); |
| 105 | if cfg!(target_endian = "big" ) { |
| 106 | ret |
| 107 | } else { |
| 108 | swap_bytes!($ty, ret) |
| 109 | } |
| 110 | } |
| 111 | |
| 112 | #[inline] |
| 113 | fn from_le_bytes(bytes: Self::Bytes) -> Self { |
| 114 | let ret = Self::from_ne_bytes(bytes); |
| 115 | if cfg!(target_endian = "little" ) { |
| 116 | ret |
| 117 | } else { |
| 118 | swap_bytes!($ty, ret) |
| 119 | } |
| 120 | } |
| 121 | } |
| 122 | )* |
| 123 | } |
| 124 | } |
| 125 | |
| 126 | impl_to_bytes! { u8, 1 } |
| 127 | impl_to_bytes! { u16, 2 } |
| 128 | impl_to_bytes! { u32, 4 } |
| 129 | impl_to_bytes! { u64, 8 } |
| 130 | #[cfg (target_pointer_width = "32" )] |
| 131 | impl_to_bytes! { usize, 4 } |
| 132 | #[cfg (target_pointer_width = "64" )] |
| 133 | impl_to_bytes! { usize, 8 } |
| 134 | |
| 135 | impl_to_bytes! { i8, 1 } |
| 136 | impl_to_bytes! { i16, 2 } |
| 137 | impl_to_bytes! { i32, 4 } |
| 138 | impl_to_bytes! { i64, 8 } |
| 139 | #[cfg (target_pointer_width = "32" )] |
| 140 | impl_to_bytes! { isize, 4 } |
| 141 | #[cfg (target_pointer_width = "64" )] |
| 142 | impl_to_bytes! { isize, 8 } |
| 143 | |
| 144 | impl_to_bytes! { f32, 4 } |
| 145 | impl_to_bytes! { f64, 8 } |
| 146 | |