core/portable-simd/crates/core_simd/src/
to_bytes.rs

1use crate::simd::{
2    num::{SimdFloat, SimdInt, SimdUint},
3    LaneCount, Simd, SimdElement, SupportedLaneCount,
4};
5
6mod 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}
11use sealed::Sealed;
12
13/// Converts SIMD vectors to vectors of bytes
14pub 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
48macro_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
54macro_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
126impl_to_bytes! { u8, 1 }
127impl_to_bytes! { u16, 2 }
128impl_to_bytes! { u32, 4 }
129impl_to_bytes! { u64, 8 }
130#[cfg(target_pointer_width = "32")]
131impl_to_bytes! { usize, 4 }
132#[cfg(target_pointer_width = "64")]
133impl_to_bytes! { usize, 8 }
134
135impl_to_bytes! { i8, 1 }
136impl_to_bytes! { i16, 2 }
137impl_to_bytes! { i32, 4 }
138impl_to_bytes! { i64, 8 }
139#[cfg(target_pointer_width = "32")]
140impl_to_bytes! { isize, 4 }
141#[cfg(target_pointer_width = "64")]
142impl_to_bytes! { isize, 8 }
143
144impl_to_bytes! { f32, 4 }
145impl_to_bytes! { f64, 8 }