#![allow(clippy::wrong_self_convention)]
use std::mem::size_of;
pub trait EndianScalar: Sized + PartialEq + Copy + Clone {
fn to_little_endian(self) -> Self;
fn from_little_endian(self) -> Self;
}
macro_rules! impl_endian_scalar_noop {
($ty:ident) => {
impl EndianScalar for $ty {
#[inline]
fn to_little_endian(self) -> Self {
self
}
#[inline]
fn from_little_endian(self) -> Self {
self
}
}
};
}
macro_rules! impl_endian_scalar_stdlib_le_conversion {
($ty:ident) => {
impl EndianScalar for $ty {
#[inline]
fn to_little_endian(self) -> Self {
Self::to_le(self)
}
#[inline]
fn from_little_endian(self) -> Self {
Self::from_le(self)
}
}
};
}
impl_endian_scalar_noop!(bool);
impl_endian_scalar_noop!(u8);
impl_endian_scalar_noop!(i8);
impl_endian_scalar_stdlib_le_conversion!(u16);
impl_endian_scalar_stdlib_le_conversion!(u32);
impl_endian_scalar_stdlib_le_conversion!(u64);
impl_endian_scalar_stdlib_le_conversion!(i16);
impl_endian_scalar_stdlib_le_conversion!(i32);
impl_endian_scalar_stdlib_le_conversion!(i64);
impl EndianScalar for f32 {
#[inline]
fn to_little_endian(self) -> Self {
#[cfg(target_endian = "little")]
{
self
}
#[cfg(not(target_endian = "little"))]
{
byte_swap_f32(self)
}
}
#[inline]
fn from_little_endian(self) -> Self {
#[cfg(target_endian = "little")]
{
self
}
#[cfg(not(target_endian = "little"))]
{
byte_swap_f32(self)
}
}
}
impl EndianScalar for f64 {
#[inline]
fn to_little_endian(self) -> Self {
#[cfg(target_endian = "little")]
{
self
}
#[cfg(not(target_endian = "little"))]
{
byte_swap_f64(self)
}
}
#[inline]
fn from_little_endian(self) -> Self {
#[cfg(target_endian = "little")]
{
self
}
#[cfg(not(target_endian = "little"))]
{
byte_swap_f64(self)
}
}
}
#[allow(dead_code)]
#[inline]
pub fn byte_swap_f32(x: f32) -> f32 {
f32::from_bits(x.to_bits().swap_bytes())
}
#[allow(dead_code)]
#[inline]
pub fn byte_swap_f64(x: f64) -> f64 {
f64::from_bits(x.to_bits().swap_bytes())
}
#[inline]
pub unsafe fn emplace_scalar<T: EndianScalar>(s: &mut [u8], x: T) {
let x_le = x.to_little_endian();
core::ptr::copy_nonoverlapping(
&x_le as *const T as *const u8,
s.as_mut_ptr() as *mut u8,
size_of::<T>(),
);
}
#[inline]
pub unsafe fn read_scalar_at<T: EndianScalar>(s: &[u8], loc: usize) -> T {
read_scalar(&s[loc..])
}
#[inline]
pub unsafe fn read_scalar<T: EndianScalar>(s: &[u8]) -> T {
let mut mem = core::mem::MaybeUninit::<T>::uninit();
core::ptr::copy_nonoverlapping(s.as_ptr(), mem.as_mut_ptr() as *mut u8, size_of::<T>());
mem.assume_init().from_little_endian()
}