Skip to main content

core_simd/
to_bytes.rs

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