use ::core::debug_assert;
use ::core::marker::Copy;
use ::core::mem::size_of;
pub(crate) const SIGN: u8 = 0b1000_0000;
pub unsafe trait Uint: Copy {}
unsafe impl<const N: usize> Uint for [u8; N] {}
macro_rules! implement_uint {
($($type:ty)+) => {
$(
unsafe impl Uint for $type {}
)+
};
}
implement_uint! {
i8 i16 i32 i64 i128 isize
u8 u16 u32 u64 u128 usize
}
pub(crate) trait Consts {
const SIZE: usize;
const BITS: u32;
const UMAX: Self;
const UMIN: Self;
const SMAX: Self;
const SMIN: Self;
const ONE: Self;
}
impl<T: Uint> Consts for T {
const SIZE: usize = size_of::<T>();
const BITS: u32 = (Self::SIZE as u32) << 3;
const UMAX: Self = maybe_uninit_fill(u8::MAX);
const UMIN: Self = maybe_uninit_fill(u8::MIN);
const SMAX: Self = {
let mut value: Self = Self::UMAX;
let slice: &mut [u8] = maybe_uninit_slice(&mut value);
let index: usize = Index::ZERO.msb_of(Self::SIZE);
slice[index] ^= SIGN;
value
};
const SMIN: Self = {
let mut value: Self = Self::UMIN;
let slice: &mut [u8] = maybe_uninit_slice(&mut value);
let index: usize = Index::ZERO.msb_of(Self::SIZE);
slice[index] |= SIGN;
value
};
const ONE: Self = {
let mut value: Self = Self::UMIN;
let slice: &mut [u8] = maybe_uninit_slice(&mut value);
let index: usize = Index::ZERO.lsb_of(Self::SIZE);
slice[index] = 1;
value
};
}
#[inline]
const fn maybe_uninit_fill<T: Uint>(fill: u8) -> T {
let mut this: ::core::mem::MaybeUninit<T> = ::core::mem::MaybeUninit::uninit();
unsafe {
this.as_mut_ptr().write_bytes(fill, 1);
}
unsafe { this.assume_init() }
}
const fn maybe_uninit_slice<T: Uint>(value: &mut T) -> &mut [u8] {
let ptr: *mut T = ::core::ptr::from_mut(value);
let len: usize = ::core::mem::size_of::<T>();
unsafe { ::core::slice::from_raw_parts_mut(ptr.cast(), len) }
}
#[repr(transparent)]
pub(crate) struct Index(pub(crate) usize);
impl Index {
pub(crate) const ZERO: Self = Self(0);
#[cfg(target_endian = "big")]
#[inline]
pub(crate) const fn lsb_of(self, size: usize) -> usize {
size - 1 - self.0
}
#[cfg(target_endian = "little")]
#[inline]
pub(crate) const fn lsb_of(self, _size: usize) -> usize {
self.0
}
#[cfg(target_endian = "big")]
#[inline]
pub(crate) const fn msb_of(self, _size: usize) -> usize {
self.0
}
#[cfg(target_endian = "little")]
#[inline]
pub(crate) const fn msb_of(self, size: usize) -> usize {
size - 1 - self.0
}
}
#[inline]
pub(crate) const unsafe fn transmute<T, U>(src: T) -> U {
#[cfg(feature = "core_intrinsics")]
#[inline]
const fn __impl<T, U>(src: T) -> U {
unsafe { ::core::intrinsics::transmute_unchecked(src) }
}
#[cfg(not(feature = "core_intrinsics"))]
#[inline]
const fn __impl<T, U>(src: T) -> U {
#[repr(C)]
union Transmute<T, U> {
src: ::core::mem::ManuallyDrop<T>,
dst: ::core::mem::ManuallyDrop<U>,
}
::core::mem::ManuallyDrop::into_inner(unsafe {
Transmute { src: ::core::mem::ManuallyDrop::new(src) }.dst
})
}
debug_assert!(
size_of::<T>() == size_of::<U>(),
"cannot transmute between types of different sizes",
);
__impl::<T, U>(src)
}