pub trait Scalar {
type Raw: Copy + AsRef<[u8]>;
fn from_raw(raw: Self::Raw) -> Self;
fn to_raw(self) -> Self::Raw;
}
pub trait FixedSize: Sized {
const RAW_BYTE_LEN: usize;
}
pub trait ReadScalar: FixedSize {
fn read(bytes: &[u8]) -> Option<Self>;
}
#[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);
impl<T: Scalar> BigEndian<T> {
pub fn new(raw: T::Raw) -> BigEndian<T> {
BigEndian(raw)
}
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<const N: usize> FixedSize for [u8; N] {
const RAW_BYTE_LEN: usize = N;
}
impl<const N: usize> ReadScalar for [u8; N] {
#[inline]
fn read(bytes: &[u8]) -> Option<Self> {
bytes.try_into().ok()
}
}
impl<T> ReadScalar for BigEndian<T>
where
T: Scalar + FixedSize,
<T as Scalar>::Raw: ReadScalar,
{
#[inline]
fn read(bytes: &[u8]) -> Option<Self> {
T::Raw::read(bytes).map(BigEndian)
}
}
impl<T> ReadScalar for T
where
T: Scalar + FixedSize,
<T as Scalar>::Raw: ReadScalar,
{
#[inline]
fn read(bytes: &[u8]) -> Option<Self> {
BigEndian::<T>::read(bytes).as_ref().map(BigEndian::get)
}
}
impl<T> FixedSize for T
where
T: Scalar,
<T as Scalar>::Raw: FixedSize,
{
const RAW_BYTE_LEN: usize = <T as Scalar>::Raw::RAW_BYTE_LEN;
}
impl<T: Scalar + FixedSize> 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()
}
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()
}
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]);
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)
}
}