use crate::tiles::Tile;
use primitive_types::{U256, U512};
use std::fmt::Debug;
use std::hash::Hash;
use std::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, Not, Shl, Shr};
pub trait ZeroArray {
fn zero() -> Self;
}
macro_rules! impl_zero_array {
($t:ty) => {
impl ZeroArray for [u8; size_of::<$t>()] {
fn zero() -> Self {
[0; size_of::<$t>()]
}
}
}
}
pub trait CommonBitFieldSuperTraits:
Sized +
Copy +
From<u8> +
BitAnd<Output=Self> +
BitAndAssign +
BitOr<Output=Self> +
BitOrAssign +
Not<Output=Self> +
Shr<u32, Output=Self> +
Shl<u32, Output=Self> +
PartialOrd +
Eq +
PartialEq +
Hash +
Default +
Debug {}
#[cfg(feature = "serde")]
pub trait BitFieldSuperTraits:
CommonBitFieldSuperTraits +
serde::Serialize +
for<'de> serde::Deserialize<'de> {}
#[cfg(not(feature = "serde"))]
pub trait BitFieldSuperTraits: CommonBitFieldSuperTraits {}
impl<T: BitField> CommonBitFieldSuperTraits for T {}
impl<T: BitField> BitFieldSuperTraits for T {}
pub trait BitField: BitFieldSuperTraits
{
type Bytes: AsRef<[u8]> + AsMut<[u8]> + ZeroArray;
const ROW_WIDTH: u8;
fn count_ones(&self) -> u32;
fn to_be_bytes(&self) -> Self::Bytes;
fn from_be_bytes(bytes: Self::Bytes) -> Self;
fn from_be_bytes_slice(bytes: &[u8]) -> Self {
let mut new_bytes = Self::Bytes::zero();
new_bytes.as_mut().copy_from_slice(bytes.as_ref());
Self::from_be_bytes(new_bytes)
}
fn tile_mask(t: Tile) -> Self {
Self::from(1) << ((t.row * Self::ROW_WIDTH) + t.col).into()
}
fn bit_to_tile(bit: u32) -> Tile {
let row = bit / (Self::ROW_WIDTH as u32);
let col = bit - (row * (Self::ROW_WIDTH as u32));
Tile { row: row as u8, col: col as u8 }
}
fn trailing_zeros(&self) -> u32;
fn leading_zeros(&self) -> u32;
fn is_empty(&self) -> bool;
fn clear(&mut self);
}
#[macro_export] macro_rules! impl_bitfield {
($t:ty, $row_width:expr) => {
impl_zero_array!($t);
impl BitField for $t {
type Bytes = [u8; size_of::<$t>()];
const ROW_WIDTH: u8 = $row_width;
fn count_ones(&self) -> u32 {
<$t>::count_ones(*self)
}
fn to_be_bytes(&self) -> Self::Bytes {
<$t>::to_be_bytes(*self)
}
fn from_be_bytes(bytes: Self::Bytes) -> Self {
<$t>::from_be_bytes(bytes)
}
fn trailing_zeros(&self) -> u32 {
<$t>::trailing_zeros(*self)
}
fn leading_zeros(&self) -> u32 {
<$t>::leading_zeros(*self)
}
fn is_empty(&self) -> bool {
*self == 0
}
fn clear(&mut self) {
*self = 0;
}
}
};
}
#[macro_export] macro_rules! impl_bitfield_bigint {
($t:ty, $row_width:expr) => {
impl_zero_array!($t);
impl BitField for $t {
type Bytes = [u8; size_of::<$t>()];
const ROW_WIDTH: u8 = $row_width;
fn count_ones(&self) -> u32 {
self.to_be_bytes().iter().map(|b| b.count_ones()).sum()
}
fn to_be_bytes(&self) -> Self::Bytes {
<$t>::to_big_endian(self)
}
fn from_be_bytes(bytes: Self::Bytes) -> Self {
<$t>::from_big_endian(&bytes)
}
fn trailing_zeros(&self) -> u32 {
<$t>::trailing_zeros(self)
}
fn leading_zeros(&self) -> u32 {
<$t>::leading_zeros(self)
}
fn is_empty(&self) -> bool {
*self == Self::zero()
}
fn clear(&mut self) {
*self = Self::zero();
}
}
};
}
impl_bitfield!(u64, 7);
impl_bitfield!(u128, 11);
impl_bitfield_bigint!(U256, 15);
impl_bitfield_bigint!(U512, 21);