#![allow(clippy::wrong_self_convention)]
use core::mem::size_of;
mod private {
pub trait TriviallyTransmutable {}
impl TriviallyTransmutable for i8 {}
impl TriviallyTransmutable for i16 {}
impl TriviallyTransmutable for i32 {}
impl TriviallyTransmutable for i64 {}
impl TriviallyTransmutable for u8 {}
impl TriviallyTransmutable for u16 {}
impl TriviallyTransmutable for u32 {}
impl TriviallyTransmutable for u64 {}
}
pub trait EndianScalar: Sized + PartialEq + Copy + Clone {
type Scalar: private::TriviallyTransmutable;
fn to_little_endian(self) -> Self::Scalar;
fn from_little_endian(v: Self::Scalar) -> Self;
}
macro_rules! impl_endian_scalar {
($ty:ident) => {
impl EndianScalar for $ty {
type Scalar = Self;
#[inline]
fn to_little_endian(self) -> Self::Scalar {
Self::to_le(self)
}
#[inline]
fn from_little_endian(v: Self::Scalar) -> Self {
Self::from_le(v)
}
}
};
}
impl_endian_scalar!(u8);
impl_endian_scalar!(i8);
impl_endian_scalar!(u16);
impl_endian_scalar!(u32);
impl_endian_scalar!(u64);
impl_endian_scalar!(i16);
impl_endian_scalar!(i32);
impl_endian_scalar!(i64);
impl EndianScalar for bool {
type Scalar = u8;
fn to_little_endian(self) -> Self::Scalar {
self as u8
}
fn from_little_endian(v: Self::Scalar) -> Self {
v != 0
}
}
impl EndianScalar for f32 {
type Scalar = u32;
#[inline]
fn to_little_endian(self) -> u32 {
self.to_bits().to_le()
}
#[inline]
fn from_little_endian(v: u32) -> Self {
f32::from_bits(u32::from_le(v))
}
}
impl EndianScalar for f64 {
type Scalar = u64;
#[inline]
fn to_little_endian(self) -> u64 {
self.to_bits().to_le()
}
#[inline]
fn from_little_endian(v: u64) -> Self {
f64::from_bits(u64::from_le(v))
}
}
#[inline]
pub unsafe fn emplace_scalar<T: EndianScalar>(s: &mut [u8], x: T) {
let size = size_of::<T::Scalar>();
debug_assert!(
s.len() >= size,
"insufficient capacity for emplace_scalar, needed {} got {}",
size,
s.len()
);
let x_le = x.to_little_endian();
core::ptr::copy_nonoverlapping(
&x_le as *const T::Scalar as *const u8,
s.as_mut_ptr() as *mut u8,
size,
);
}
#[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 size = size_of::<T::Scalar>();
debug_assert!(
s.len() >= size,
"insufficient capacity for emplace_scalar, needed {} got {}",
size,
s.len()
);
let mut mem = core::mem::MaybeUninit::<T::Scalar>::uninit();
core::ptr::copy_nonoverlapping(s.as_ptr(), mem.as_mut_ptr() as *mut u8, size);
T::from_little_endian(mem.assume_init())
}