use core::mem::{align_of_val, size_of_val};
use core::num::{
NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize, NonZeroU128,
NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize,
};
use crate::Chunk;
use crate::{integer::*, Buf, Result};
pub unsafe trait Abi: Sized + 'static {
const ALIGN: usize = core::mem::align_of::<Self>();
const SIZE: usize = core::mem::size_of::<Self>();
const IS_ZST: bool = Self::SIZE == 0;
#[inline]
fn alignment(&self) -> usize {
debug_assert_eq!(align_of_val(self), Self::ALIGN);
core::mem::align_of_val(self)
}
#[inline]
fn size(&self) -> usize {
debug_assert_eq!(size_of_val(self), Self::SIZE);
size_of_val(self)
}
}
pub trait Transmute {
#[inline]
fn transmute_bytes<T: Abi>(bytes: &[u8]) -> Result<T> {
if bytes.len() != T::SIZE {
Err(crate::Error::size_mismatch(T::SIZE, bytes.len()))
} else if !bytes.is_aligned_with::<T>() {
Err(crate::Error::misaligned_access())
} else {
Ok(unsafe { bytes.as_ptr().cast::<T>().read() })
}
}
#[inline]
fn transmute_array<T: Abi, const N: usize>(array: [u8; N]) -> Result<T> {
if array.len() != T::SIZE {
Err(crate::Error::size_mismatch(T::SIZE, array.len()))
} else if !array.is_aligned_with::<T>() {
Err(crate::Error::misaligned_access())
} else {
Ok(unsafe { array.as_ptr().cast::<T>().read() })
}
}
}
unsafe impl<T, const N: usize> Abi for [T; N] where T: Abi + Integer {}
macro_rules! impl_abi_for_primitives {
($($ty:ty),* $(,)?) => {
$(
unsafe impl Abi for $ty {}
)*
};
}
impl_abi_for_primitives!((), bool, char);
impl_abi_for_primitives!(u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize);
impl_abi_for_primitives!(U8, U16, U32, U64, U128, Usize, I8, I16, I32, I64, I128, Isize);
impl_abi_for_primitives!(NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128, NonZeroUsize);
impl_abi_for_primitives!(NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI128, NonZeroIsize);
unsafe impl<T: Abi> Abi for *const T {}
unsafe impl<T: Abi> Abi for *mut T {}
unsafe impl<const N: usize> Abi for Chunk<N> {}