use core::fmt::Debug;
use core::hash::Hash;
use crate::integer::Integer;
use crate::source::Chunk;
use crate::{Error, Result};
macro_rules! unsafe_write_num_bytes {
($ty:ty, $size:expr, $value:expr, $dst:expr, $which:ident) => {{
if $dst.len() < $size {
Err($crate::Error::out_of_bounds($size, $dst.len()))
} else {
unsafe {
let bytes = *(&$value.$which() as *const _ as *const [u8; $size]);
::core::ptr::copy_nonoverlapping((&bytes).as_ptr(), $dst.as_mut_ptr(), $size);
Ok(())
}
}
}};
}
macro_rules! read_endian_bytes {
( $($bytes:ident, $integer:ty, $endianness:tt),* $(,)? ) => {
$(
match $crate::source::Chunk::from_bytes($bytes) {
Ok(chunk) => Ok(<$integer>::$endianness(chunk.into_array())),
Err(err) => Err(err),
}
)*
}
}
pub trait Endianness: Clone + Copy + Debug + Eq + Hash + Ord + PartialEq + PartialOrd {
fn read_u8(bytes: &[u8]) -> Result<u8>;
fn read_u16(bytes: &[u8]) -> Result<u16>;
fn read_u32(bytes: &[u8]) -> Result<u32>;
fn read_u64(bytes: &[u8]) -> Result<u64>;
fn read_u128(bytes: &[u8]) -> Result<u128>;
fn read_i8(bytes: &[u8]) -> Result<i8>;
fn read_i16(bytes: &[u8]) -> Result<i16>;
fn read_i32(bytes: &[u8]) -> Result<i32>;
fn read_i64(bytes: &[u8]) -> Result<i64>;
fn read_i128(bytes: &[u8]) -> Result<i128>;
fn write_u8(buf: &mut [u8], value: u8) -> Result<()>;
fn write_u16(buf: &mut [u8], value: u16) -> Result<()>;
fn write_u32(buf: &mut [u8], value: u32) -> Result<()>;
fn write_u64(buf: &mut [u8], value: u64) -> Result<()>;
fn write_u128(buf: &mut [u8], value: u128) -> Result<()>;
fn write_i8(buf: &mut [u8], value: i8) -> Result<()>;
fn write_i16(buf: &mut [u8], value: i16) -> Result<()>;
fn write_i32(buf: &mut [u8], value: i32) -> Result<()>;
fn write_i64(buf: &mut [u8], value: i64) -> Result<()>;
fn write_i128(buf: &mut [u8], value: i128) -> Result<()>;
}
impl Endianness for LittleEndian {
#[inline]
fn read_u8(bytes: &[u8]) -> Result<u8> {
read_endian_bytes!(bytes, u8, from_le_bytes)
}
#[inline]
fn read_u16(bytes: &[u8]) -> Result<u16> {
read_endian_bytes!(bytes, u16, from_le_bytes)
}
#[inline]
fn read_u32(bytes: &[u8]) -> Result<u32> {
read_endian_bytes!(bytes, u32, from_le_bytes)
}
#[inline]
fn read_u64(bytes: &[u8]) -> Result<u64> {
read_endian_bytes!(bytes, u64, from_le_bytes)
}
#[inline]
fn read_u128(bytes: &[u8]) -> Result<u128> {
read_endian_bytes!(bytes, u128, from_le_bytes)
}
#[inline]
fn read_i8(bytes: &[u8]) -> Result<i8> {
read_endian_bytes!(bytes, i8, from_le_bytes)
}
#[inline]
fn read_i16(bytes: &[u8]) -> Result<i16> {
read_endian_bytes!(bytes, i16, from_le_bytes)
}
#[inline]
fn read_i32(bytes: &[u8]) -> Result<i32> {
read_endian_bytes!(bytes, i32, from_le_bytes)
}
#[inline]
fn read_i64(bytes: &[u8]) -> Result<i64> {
read_endian_bytes!(bytes, i64, from_le_bytes)
}
#[inline]
fn read_i128(bytes: &[u8]) -> Result<i128> {
read_endian_bytes!(bytes, i128, from_le_bytes)
}
#[inline]
fn write_u8(buf: &mut [u8], value: u8) -> Result<()> {
unsafe_write_num_bytes!(u8, 1, value, buf, to_le)
}
#[inline]
fn write_u16(buf: &mut [u8], value: u16) -> Result<()> {
unsafe_write_num_bytes!(u16, 2, value, buf, to_le)
}
#[inline]
fn write_u32(buf: &mut [u8], value: u32) -> Result<()> {
if buf.len() < 4 {
Err(Error::out_of_bounds(4, buf.len()))
} else {
unsafe {
let src = value.to_le().as_ptr().cast::<u8>();
::core::ptr::copy_nonoverlapping(src, buf.as_mut_ptr(), 4);
Ok(())
}
}
}
#[inline]
fn write_u64(buf: &mut [u8], value: u64) -> Result<()> {
unsafe_write_num_bytes!(u64, 8, value, buf, to_le)
}
#[inline]
fn write_u128(buf: &mut [u8], value: u128) -> Result<()> {
unsafe_write_num_bytes!(u128, 16, value, buf, to_le)
}
#[inline]
fn write_i8(buf: &mut [u8], value: i8) -> Result<()> {
unsafe_write_num_bytes!(i8, 1, value, buf, to_le)
}
#[inline]
fn write_i16(buf: &mut [u8], value: i16) -> Result<()> {
unsafe_write_num_bytes!(i16, 2, value, buf, to_le)
}
#[inline]
fn write_i32(buf: &mut [u8], value: i32) -> Result<()> {
unsafe_write_num_bytes!(i32, 4, value, buf, to_le)
}
#[inline]
fn write_i64(buf: &mut [u8], value: i64) -> Result<()> {
unsafe_write_num_bytes!(i64, 8, value, buf, to_le)
}
#[inline]
fn write_i128(buf: &mut [u8], value: i128) -> Result<()> {
unsafe_write_num_bytes!(i128, 16, value, buf, to_le)
}
}
impl Endianness for BigEndian {
#[inline]
fn read_u8(bytes: &[u8]) -> Result<u8> {
match Chunk::from_bytes(bytes) {
Ok(chunk) => Ok(u8::from_be_bytes(chunk.into_array())),
Err(err) => Err(err),
}
}
#[inline]
fn read_u16(bytes: &[u8]) -> Result<u16> {
match Chunk::from_bytes(bytes) {
Ok(chunk) => Ok(u16::from_be_bytes(chunk.into_array())),
Err(err) => Err(err),
}
}
#[inline]
fn read_u32(bytes: &[u8]) -> Result<u32> {
match Chunk::from_bytes(bytes) {
Ok(chunk) => Ok(u32::from_be_bytes(chunk.into_array())),
Err(err) => Err(err),
}
}
#[inline]
fn read_u64(bytes: &[u8]) -> Result<u64> {
match Chunk::from_bytes(bytes) {
Ok(chunk) => Ok(u64::from_be_bytes(chunk.into_array())),
Err(err) => Err(err),
}
}
#[inline]
fn read_u128(bytes: &[u8]) -> Result<u128> {
match Chunk::from_bytes(bytes) {
Ok(chunk) => Ok(u128::from_be_bytes(chunk.into_array())),
Err(err) => Err(err),
}
}
#[inline]
fn read_i8(bytes: &[u8]) -> Result<i8> {
match Chunk::from_bytes(bytes) {
Ok(chunk) => Ok(i8::from_be_bytes(chunk.into_array())),
Err(err) => Err(err),
}
}
#[inline]
fn read_i16(bytes: &[u8]) -> Result<i16> {
match Chunk::from_bytes(bytes) {
Ok(chunk) => Ok(i16::from_be_bytes(chunk.into_array())),
Err(err) => Err(err),
}
}
#[inline]
fn read_i32(bytes: &[u8]) -> Result<i32> {
match Chunk::from_bytes(bytes) {
Ok(chunk) => Ok(i32::from_be_bytes(chunk.into_array())),
Err(err) => Err(err),
}
}
#[inline]
fn read_i64(bytes: &[u8]) -> Result<i64> {
match Chunk::from_bytes(bytes) {
Ok(chunk) => Ok(i64::from_be_bytes(chunk.into_array())),
Err(err) => Err(err),
}
}
#[inline]
fn read_i128(bytes: &[u8]) -> Result<i128> {
match Chunk::from_bytes(bytes) {
Ok(chunk) => Ok(i128::from_be_bytes(chunk.into_array())),
Err(err) => Err(err),
}
}
#[inline]
fn write_u8(buf: &mut [u8], value: u8) -> Result<()> {
unsafe_write_num_bytes!(u8, 1, value, buf, to_be)
}
#[inline]
fn write_u16(buf: &mut [u8], value: u16) -> Result<()> {
unsafe_write_num_bytes!(u16, 2, value, buf, to_be)
}
#[inline]
fn write_u32(buf: &mut [u8], value: u32) -> Result<()> {
unsafe_write_num_bytes!(u32, 4, value, buf, to_be)
}
#[inline]
fn write_u64(buf: &mut [u8], value: u64) -> Result<()> {
unsafe_write_num_bytes!(u64, 8, value, buf, to_be)
}
#[inline]
fn write_u128(buf: &mut [u8], value: u128) -> Result<()> {
unsafe_write_num_bytes!(u128, 16, value, buf, to_be)
}
#[inline]
fn write_i8(buf: &mut [u8], value: i8) -> Result<()> {
unsafe_write_num_bytes!(i8, 1, value, buf, to_be)
}
#[inline]
fn write_i16(buf: &mut [u8], value: i16) -> Result<()> {
unsafe_write_num_bytes!(i16, 2, value, buf, to_be)
}
#[inline]
fn write_i32(buf: &mut [u8], value: i32) -> Result<()> {
unsafe_write_num_bytes!(i32, 4, value, buf, to_be)
}
#[inline]
fn write_i64(buf: &mut [u8], value: i64) -> Result<()> {
unsafe_write_num_bytes!(i64, 8, value, buf, to_be)
}
#[inline]
fn write_i128(buf: &mut [u8], value: i128) -> Result<()> {
unsafe_write_num_bytes!(i128, 16, value, buf, to_be)
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct LittleEndian;
pub type LE = LittleEndian;
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct BigEndian;
pub type BE = BigEndian;
#[cfg(target_endian = "big")]
pub type NativeEndian = BigEndian;
#[cfg(target_endian = "little")]
pub type NativeEndian = LittleEndian;
pub const fn little_endian_codec() -> Endian {
Endian::Little
}
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub enum Endian {
Big,
Little,
}
impl Endian {
#[must_use]
#[doc(alias = "is_be")]
#[inline]
pub const fn is_big_endian(&self) -> bool {
matches!(self, Self::Big)
}
#[must_use]
#[doc(alias = "is_le")]
#[inline]
pub const fn is_little_endian(&self) -> bool {
matches!(self, Self::Little)
}
}
impl From<BigEndian> for Endian {
#[inline]
fn from(_: BigEndian) -> Endian {
Endian::Big
}
}
impl From<LittleEndian> for Endian {
#[inline]
fn from(_: LittleEndian) -> Endian {
Endian::Little
}
}