#![allow(clippy::upper_case_acronyms)]
use super::*;
use crate::impl_ule_from_array;
use crate::ZeroSlice;
use core::num::{NonZeroI8, NonZeroU8};
#[repr(transparent)]
#[derive(Debug, PartialEq, Eq, Clone, Copy, PartialOrd, Ord, Hash)]
#[allow(clippy::exhaustive_structs)] pub struct RawBytesULE<const N: usize>(pub [u8; N]);
impl<const N: usize> RawBytesULE<N> {
#[inline]
pub fn as_bytes(&self) -> &[u8] {
&self.0
}
#[inline]
pub fn from_bytes_unchecked_mut(bytes: &mut [u8]) -> &mut [Self] {
let data = bytes.as_mut_ptr();
let len = bytes.len() / N;
unsafe { slice::from_raw_parts_mut(data as *mut Self, len) }
}
}
unsafe impl<const N: usize> ULE for RawBytesULE<N> {
#[inline]
fn validate_bytes(bytes: &[u8]) -> Result<(), UleError> {
if bytes.len() % N == 0 {
Ok(())
} else {
Err(UleError::length::<Self>(bytes.len()))
}
}
}
impl<const N: usize> From<[u8; N]> for RawBytesULE<N> {
#[inline]
fn from(le_bytes: [u8; N]) -> Self {
Self(le_bytes)
}
}
macro_rules! impl_numbers_with_raw_bytes_ule {
($unsigned:ty, $signed:ty $(, $float:ty)?) => {
const _: () = assert!(size_of::<$unsigned>() == size_of::<$signed>() $(&& size_of::<$unsigned>() == size_of::<$float>())?);
impl RawBytesULE<{ size_of::<$unsigned>() }> {
#[doc = concat!("Gets this `RawBytesULE` as a `", stringify!($unsigned), "`. This is equivalent to calling [`AsULE::from_unaligned()`] on [`", stringify!($unsigned), "`].")]
#[inline]
pub const fn as_unsigned_int(&self) -> $unsigned {
<$unsigned>::from_le_bytes(self.0)
}
#[doc = concat!("Gets this `RawBytesULE` as a `", stringify!($unsigned), "`. This is equivalent to calling [`AsULE::from_unaligned()`] on [`", stringify!($signed), "`].")]
#[inline]
pub const fn as_signed_int(&self) -> $signed {
<$signed>::from_le_bytes(self.0)
}
$(
#[doc = concat!("Gets this `RawBytesULE` as a `", stringify!($float), "`. This is equivalent to calling [`AsULE::from_unaligned()`] on [`", stringify!($float), "`].")]
#[inline]
pub const fn as_float(&self) -> $float {
<$float>::from_le_bytes(self.0)
}
)?
#[doc = concat!("Converts a `", stringify!($unsigned), "` to a `RawBytesULE`. This is equivalent to calling [`AsULE::to_unaligned()`] on [`", stringify!($unsigned), "`].")]
#[inline]
pub const fn from_aligned(value: $unsigned) -> Self {
Self(value.to_le_bytes())
}
impl_ule_from_array!(
$unsigned,
RawBytesULE<{ size_of::<$unsigned>() }>,
RawBytesULE([0; { size_of::<$unsigned>() }])
);
}
impl_byte_slice_type!(from_unsigned, $unsigned);
impl_const_constructors!($unsigned);
impl_byte_slice_type!(from_signed, $signed);
impl_const_constructors!($signed);
$(
impl_byte_slice_type!(from_float, $float);
impl_const_constructors!($float);
)?
};
}
macro_rules! impl_const_constructors {
($base:ty) => {
impl ZeroSlice<$base> {
pub const fn try_from_bytes(bytes: &[u8]) -> Result<&Self, UleError> {
let len = bytes.len();
const STRIDE: usize = size_of::<$base>();
#[allow(clippy::modulo_one)]
if (if STRIDE <= 1 { len } else { len % STRIDE }) == 0 {
Ok(unsafe { Self::from_bytes_unchecked(bytes) })
} else {
Err(UleError::InvalidLength {
ty: concat!("<const construct: ", stringify!($base), ">"),
len,
})
}
}
}
};
}
macro_rules! impl_byte_slice_type {
($single_fn:ident, $type:ty) => {
impl From<$type> for RawBytesULE<{ size_of::<$type>() }> {
#[inline]
fn from(value: $type) -> Self {
Self(value.to_le_bytes())
}
}
impl AsULE for $type {
type ULE = RawBytesULE<{ size_of::<$type>() }>;
#[inline]
fn to_unaligned(self) -> Self::ULE {
RawBytesULE(self.to_le_bytes())
}
#[inline]
fn from_unaligned(unaligned: Self::ULE) -> Self {
<$type>::from_le_bytes(unaligned.0)
}
}
unsafe impl EqULE for $type {}
impl RawBytesULE<{ size_of::<$type>() }> {
pub const fn $single_fn(v: $type) -> Self {
RawBytesULE(v.to_le_bytes())
}
}
};
}
impl_numbers_with_raw_bytes_ule!(u16, i16);
impl_numbers_with_raw_bytes_ule!(u32, i32, f32);
impl_numbers_with_raw_bytes_ule!(u64, i64, f64);
impl_numbers_with_raw_bytes_ule!(u128, i128);
unsafe impl ULE for u8 {
#[inline]
fn validate_bytes(_bytes: &[u8]) -> Result<(), UleError> {
Ok(())
}
}
impl AsULE for u8 {
type ULE = Self;
#[inline]
fn to_unaligned(self) -> Self::ULE {
self
}
#[inline]
fn from_unaligned(unaligned: Self::ULE) -> Self {
unaligned
}
}
unsafe impl EqULE for u8 {}
impl_const_constructors!(u8);
unsafe impl ULE for NonZeroU8 {
#[inline]
fn validate_bytes(bytes: &[u8]) -> Result<(), UleError> {
bytes.iter().try_for_each(|b| {
if *b == 0x00 {
Err(UleError::parse::<Self>())
} else {
Ok(())
}
})
}
}
impl AsULE for NonZeroU8 {
type ULE = Self;
#[inline]
fn to_unaligned(self) -> Self::ULE {
self
}
#[inline]
fn from_unaligned(unaligned: Self::ULE) -> Self {
unaligned
}
}
unsafe impl EqULE for NonZeroU8 {}
impl NicheBytes<1> for NonZeroU8 {
const NICHE_BIT_PATTERN: [u8; 1] = [0x00];
}
unsafe impl ULE for i8 {
#[inline]
fn validate_bytes(_bytes: &[u8]) -> Result<(), UleError> {
Ok(())
}
}
impl AsULE for i8 {
type ULE = Self;
#[inline]
fn to_unaligned(self) -> Self::ULE {
self
}
#[inline]
fn from_unaligned(unaligned: Self::ULE) -> Self {
unaligned
}
}
unsafe impl EqULE for i8 {}
impl AsULE for NonZeroI8 {
type ULE = NonZeroU8;
#[inline]
fn to_unaligned(self) -> Self::ULE {
unsafe { NonZeroU8::new_unchecked(self.get() as u8) }
}
#[inline]
fn from_unaligned(unaligned: Self::ULE) -> Self {
unsafe { NonZeroI8::new_unchecked(unaligned.get() as i8) }
}
}
unsafe impl ULE for bool {
#[inline]
fn validate_bytes(bytes: &[u8]) -> Result<(), UleError> {
for byte in bytes {
if *byte > 1 {
return Err(UleError::parse::<Self>());
}
}
Ok(())
}
}
impl AsULE for bool {
type ULE = Self;
#[inline]
fn to_unaligned(self) -> Self::ULE {
self
}
#[inline]
fn from_unaligned(unaligned: Self::ULE) -> Self {
unaligned
}
}
unsafe impl EqULE for bool {}
impl_const_constructors!(bool);
unsafe impl ULE for () {
#[inline]
fn validate_bytes(bytes: &[u8]) -> Result<(), UleError> {
if bytes.is_empty() {
Ok(())
} else {
Err(UleError::length::<Self>(bytes.len()))
}
}
}
impl AsULE for () {
type ULE = Self;
#[inline]
fn to_unaligned(self) -> Self::ULE {
self
}
#[inline]
fn from_unaligned(unaligned: Self::ULE) -> Self {
unaligned
}
}
unsafe impl EqULE for () {}
impl_const_constructors!(());