use std::fmt::{self, Debug, Display, Formatter};
#[repr(C)]
#[derive(Copy)]
pub struct Int<const N: usize>([u8; N]);
impl<const N: usize> Int<N> {
pub const BITS: u32 = u8::BITS * N as u32;
#[inline]
#[must_use]
pub const fn from_be(value: Self) -> Self {
Self::from_be_bytes(value.to_ne_bytes())
}
#[inline(always)]
#[must_use]
pub const fn from_ne_bytes(bytes: [u8; N]) -> Self {
Self(bytes)
}
#[inline]
#[must_use]
pub const fn from_be_bytes(mut bytes: [u8; N]) -> Self {
if cfg!(target_endian = "little") {
bytes.reverse();
}
Self::from_ne_bytes(bytes)
}
#[inline]
#[must_use]
pub const fn to_be(self) -> Self {
Self::from_ne_bytes(self.to_be_bytes())
}
#[inline(always)]
#[must_use]
pub const fn to_ne_bytes(self) -> [u8; N] {
self.0
}
#[inline]
#[must_use]
pub const fn to_be_bytes(mut self) -> [u8; N] {
if cfg!(target_endian = "little") {
self.0.reverse();
}
self.0
}
}
impl Int<1> {
#[inline(always)]
#[must_use]
pub const fn from_u8(value: u8) -> Self {
Self::from_ne_bytes(value.to_ne_bytes())
}
#[inline(always)]
#[must_use]
pub const fn from_i8(value: i8) -> Self {
Self::from_ne_bytes(value.to_ne_bytes())
}
#[inline]
#[must_use]
pub const fn zero_extend(self) -> Int<2> {
let bytes = u16::from(self.as_u8()).to_ne_bytes();
Int::from_ne_bytes(bytes)
}
#[inline]
#[must_use]
pub const fn sign_extend(self) -> Int<2> {
let bytes = i16::from(self.as_i8()).to_ne_bytes();
Int::from_ne_bytes(bytes)
}
#[inline(always)]
#[must_use]
pub const fn as_u8(self) -> u8 {
u8::from_ne_bytes(self.0)
}
#[inline(always)]
#[must_use]
pub const fn as_i8(self) -> i8 {
i8::from_ne_bytes(self.0)
}
}
impl Int<2> {
#[inline(always)]
#[must_use]
pub const fn from_u16(value: u16) -> Self {
Self::from_ne_bytes(value.to_ne_bytes())
}
#[inline(always)]
#[must_use]
pub const fn from_i16(value: i16) -> Self {
Self::from_ne_bytes(value.to_ne_bytes())
}
#[inline]
#[must_use]
pub const fn zero_extend(self) -> Int<4> {
let bytes = u32::from(self.as_u16()).to_ne_bytes();
Int::from_ne_bytes(bytes)
}
#[inline]
#[must_use]
pub const fn sign_extend(self) -> Int<4> {
let bytes = i32::from(self.as_i16()).to_ne_bytes();
Int::from_ne_bytes(bytes)
}
#[inline(always)]
#[must_use]
pub const fn as_u16(self) -> u16 {
u16::from_ne_bytes(self.0)
}
#[inline(always)]
#[must_use]
pub const fn as_i16(self) -> i16 {
i16::from_ne_bytes(self.0)
}
}
impl Int<4> {
#[inline(always)]
#[must_use]
pub const fn from_u32(value: u32) -> Self {
Self::from_ne_bytes(value.to_ne_bytes())
}
#[inline(always)]
#[must_use]
pub const fn from_i32(value: i32) -> Self {
Self::from_ne_bytes(value.to_ne_bytes())
}
#[inline(always)]
#[must_use]
pub const fn as_u32(self) -> u32 {
u32::from_ne_bytes(self.0)
}
#[inline(always)]
#[must_use]
pub const fn as_i32(self) -> i32 {
i32::from_ne_bytes(self.0)
}
#[inline]
#[must_use]
pub const fn as_usize(self) -> usize {
self.as_u32() as usize
}
}
const impl<const N: usize> Clone for Int<N> {
#[inline(always)]
fn clone(&self) -> Self {
*self
}
}
impl Debug for Int<1> {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{:#04X}", self.as_i8())
}
}
impl Debug for Int<2> {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{:#06X}", self.as_i16())
}
}
const impl<const N: usize> Default for Int<N> {
#[inline(always)]
fn default() -> Self {
const { Self::from_ne_bytes([Default::default(); _]) }
}
}
impl Debug for Int<4> {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{:#010X}", self.as_i32())
}
}
impl Display for Int<1> {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
Debug::fmt(self, f)
}
}
impl Display for Int<2> {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
Debug::fmt(self, f)
}
}
impl Display for Int<4> {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
Debug::fmt(self, f)
}
}
const impl Eq for Int<1> {}
const impl Eq for Int<2> {}
const impl Eq for Int<4> {}
const impl PartialEq for Int<1> {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.as_u8().eq(&other.as_u8())
}
}
const impl PartialEq for Int<2> {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.as_u16().eq(&other.as_u16())
}
}
const impl PartialEq for Int<4> {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.as_u32().eq(&other.as_u32())
}
}