pub trait Scalar: Sized {
type Raw: sealed::BeByteArray;
fn from_raw(raw: Self::Raw) -> Self;
fn to_raw(self) -> Self::Raw;
fn read(slice: &[u8]) -> Option<Self> {
sealed::BeByteArray::from_slice(slice).map(Self::from_raw)
}
}
pub trait FixedSize: Sized {
const RAW_BYTE_LEN: usize;
}
mod sealed {
#[cfg(not(feature = "bytemuck"))]
pub trait BeByteArray: Copy + AsRef<[u8]> {
fn from_slice(slice: &[u8]) -> Option<Self>;
}
#[cfg(feature = "bytemuck")]
pub trait BeByteArray:
Copy + AsRef<[u8]> + bytemuck::AnyBitPattern + bytemuck::Zeroable
{
fn from_slice(slice: &[u8]) -> Option<Self>;
}
impl<const N: usize> BeByteArray for [u8; N] {
fn from_slice(slice: &[u8]) -> Option<Self> {
slice.try_into().ok()
}
}
}
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[repr(transparent)]
pub struct BigEndian<T: Scalar>(pub(crate) T::Raw);
#[cfg(feature = "bytemuck")]
unsafe impl<T> bytemuck::Zeroable for BigEndian<T> where T: Scalar + Copy {}
#[cfg(feature = "bytemuck")]
unsafe impl<T> bytemuck::AnyBitPattern for BigEndian<T> where T: Scalar + Copy + 'static {}
impl<T: Scalar> BigEndian<T> {
pub fn new(raw: T::Raw) -> BigEndian<T> {
BigEndian(raw)
}
pub fn from_slice(slice: &[u8]) -> Option<Self> {
sealed::BeByteArray::from_slice(slice).map(Self)
}
#[inline(always)]
pub fn get(&self) -> T {
T::from_raw(self.0)
}
pub fn set(&mut self, value: T) {
self.0 = value.to_raw();
}
pub fn be_bytes(&self) -> &[u8] {
self.0.as_ref()
}
}
impl<T: Scalar> From<T> for BigEndian<T> {
#[inline]
fn from(val: T) -> Self {
BigEndian(val.to_raw())
}
}
impl<T: Scalar + Default> Default for BigEndian<T> {
fn default() -> Self {
Self::from(T::default())
}
}
impl<T: Scalar + Copy + PartialEq> PartialEq<T> for BigEndian<T> {
fn eq(&self, other: &T) -> bool {
self.get() == *other
}
}
impl<T: Scalar + Copy + PartialOrd + PartialEq> PartialOrd for BigEndian<T>
where
<T as Scalar>::Raw: PartialEq,
{
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
self.get().partial_cmp(&other.get())
}
}
impl<T: Scalar + Copy + Ord + Eq> Ord for BigEndian<T>
where
<T as Scalar>::Raw: Eq,
{
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
self.get().cmp(&other.get())
}
}
impl<T: Scalar> FixedSize for T {
const RAW_BYTE_LEN: usize = std::mem::size_of::<T::Raw>();
}
impl<T: Scalar> FixedSize for BigEndian<T> {
const RAW_BYTE_LEN: usize = T::RAW_BYTE_LEN;
}
#[macro_export]
macro_rules! newtype_scalar {
($ty:ident, $raw:ty) => {
impl $crate::raw::Scalar for $ty {
type Raw = $raw;
fn to_raw(self) -> $raw {
self.0.to_raw()
}
#[inline(always)]
fn from_raw(raw: $raw) -> Self {
Self($crate::raw::Scalar::from_raw(raw))
}
}
};
}
macro_rules! int_scalar {
($ty:ty, $raw:ty) => {
impl crate::raw::Scalar for $ty {
type Raw = $raw;
fn to_raw(self) -> $raw {
self.to_be_bytes()
}
#[inline(always)]
fn from_raw(raw: $raw) -> $ty {
Self::from_be_bytes(raw)
}
}
};
}
int_scalar!(u8, [u8; 1]);
int_scalar!(i8, [u8; 1]);
int_scalar!(u16, [u8; 2]);
int_scalar!(i16, [u8; 2]);
int_scalar!(u32, [u8; 4]);
int_scalar!(i32, [u8; 4]);
int_scalar!(i64, [u8; 8]);
int_scalar!(crate::Uint24, [u8; 3]);
int_scalar!(crate::Int24, [u8; 3]);
impl<T: std::fmt::Debug + Scalar + Copy> std::fmt::Debug for BigEndian<T> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
self.get().fmt(f)
}
}
impl<T: std::fmt::Display + Scalar + Copy> std::fmt::Display for BigEndian<T> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
self.get().fmt(f)
}
}