use common_traits::{IntoAtomic, SignedInt};
use dsi_bitstream::{
prelude::{ToInt, ToNat},
traits::Endianness,
};
use num_traits::{Bounded, NumCast, ToPrimitive};
use std::fmt::Debug;
pub trait Word:
Bounded
+ ToPrimitive
+ dsi_bitstream::traits::Word
+ NumCast
+ Copy
+ Send
+ Sync
+ Debug
+ IntoAtomic
+ 'static
{
const BITS: usize = std::mem::size_of::<Self>() * 8;
}
macro_rules! impl_word_for {
($($t:ty),*) => {$(
impl Word for $t {}
)*};
}
impl_word_for!(u8, u16, u32, u64, usize);
pub trait Storable<W: Word>: Sized + Copy {
fn into_word(self) -> W;
fn from_word(word: W) -> Self;
}
macro_rules! impl_storable_for_unsigned {
($($T:ty),*) => {$(
impl<W> Storable<W> for $T
where
W: Word + TryFrom<$T>,
W: TryInto<$T>,
{
#[inline(always)]
fn into_word(self) -> W {
self.try_into().unwrap_or_else(|_| panic!("BUG: T -> W conversion failed."))
}
#[inline(always)]
fn from_word(word: W) -> Self {
word.try_into().unwrap_or_else(|_| {
panic!("BUG: W -> T conversion failed. Logic error in FixedVec's bit manipulation.")
})
}
}
)*};
}
macro_rules! impl_storable_for_signed {
($($T:ty),*) => {$(
impl<W> Storable<W> for $T
where
W: Word,
<$T as SignedInt>::UnsignedInt: TryInto<W>,
W: TryInto<<$T as SignedInt>::UnsignedInt>,
{
#[inline(always)]
fn into_word(self) -> W {
self.to_nat().try_into().unwrap_or_else(|_| panic!("BUG: Signed -> Unsigned -> W conversion failed."))
}
#[inline(always)]
fn from_word(word: W) -> Self {
let unsigned_val: <$T as SignedInt>::UnsignedInt =
word.try_into().unwrap_or_else(|_| {
panic!("BUG: W -> Unsigned conversion failed. Logic error in FixedVec.")
});
ToInt::to_int(unsigned_val)
}
}
)*};
}
impl_storable_for_unsigned!(u8, u16, u32, u64, u128, usize);
impl_storable_for_signed!(i8, i16, i32, i64, i128, isize);
pub trait DefaultParams: Sized {
type W: Word;
type E: Endianness;
}
macro_rules! impl_default_params_unsigned {
($($T:ty),*) => {$(
impl DefaultParams for $T {
type W = usize;
type E = dsi_bitstream::prelude::LE;
}
)*};
}
macro_rules! impl_default_params_signed {
($($T:ty),*) => {$(
impl DefaultParams for $T {
type W = usize;
type E = dsi_bitstream::prelude::LE;
}
)*};
}
impl_default_params_unsigned!(u8, u16, u32, u64, u128, usize);
impl_default_params_signed!(i8, i16, i32, i64, i128, isize);