use bincode::{
de::Decoder,
enc::Encoder,
error::{DecodeError, EncodeError},
Decode, Encode,
};
use std::{fmt::Debug, ops};
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Bit(u64);
impl Bit {
pub fn zero() -> Self {
Bit(0)
}
pub fn select(x: u64, bit: usize) -> Self {
debug_assert!(bit < 64);
Self((x >> bit) & 1)
}
pub fn select_u8(x: u8, bit: usize) -> Self {
debug_assert!(bit < 8);
Self::select(x as u64, bit)
}
}
impl From<Bit> for u64 {
fn from(b: Bit) -> Self {
b.0
}
}
impl ops::BitXor for Bit {
type Output = Self;
fn bitxor(self, rhs: Self) -> Self::Output {
let mut out = self;
out ^= rhs;
out
}
}
impl ops::BitXorAssign for Bit {
fn bitxor_assign(&mut self, rhs: Self) {
self.0 ^= rhs.0;
}
}
impl ops::BitAnd for Bit {
type Output = Self;
fn bitand(self, rhs: Self) -> Self::Output {
let mut out = self;
out &= rhs;
out
}
}
impl ops::BitAndAssign for Bit {
fn bitand_assign(&mut self, rhs: Self) {
self.0 &= rhs.0;
}
}
impl ops::Not for Bit {
type Output = Self;
fn not(self) -> Self::Output {
Self(1 ^ self.0)
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct BitBuf {
bits: Vec<u64>,
index: usize,
}
impl BitBuf {
fn end(&mut self) -> &mut u64 {
self.bits.last_mut().unwrap()
}
}
impl Default for BitBuf {
fn default() -> Self {
Self::new()
}
}
impl BitBuf {
pub fn new() -> Self {
Self {
bits: vec![0],
index: 0,
}
}
pub fn from_bytes(bytes: &[u8]) -> Self {
let index = 8 * (bytes.len() % 8);
let mut bits = Vec::with_capacity((bytes.len() + 7) / 8);
bytes.chunks(8).for_each(|chunk| {
let mut le_bytes = [0u8; 8];
le_bytes[..chunk.len()].copy_from_slice(chunk);
bits.push(u64::from_le_bytes(le_bytes));
});
Self { bits, index }
}
pub fn push(&mut self, bit: Bit) {
*self.end() |= bit.0 << self.index;
self.index += 1;
if self.index >= 64 {
self.bits.push(0);
self.index = 0;
}
}
pub fn pop(&mut self) -> Option<Bit> {
if self.index == 0 {
if self.bits.is_empty() {
return None;
}
self.index = 63;
self.bits.pop();
} else {
self.index -= 1;
}
let selected = *self.end() & (1 << self.index);
*self.end() ^= selected;
let output = Bit(selected >> self.index);
Some(output)
}
pub fn get(&self, index: usize) -> Option<Bit> {
let hi = index >> 6;
let lo = index & ((1 << 6) - 1);
if lo >= self.index {
return None;
}
self.bits.get(hi).map(|x| Bit((x >> lo) & 1))
}
pub fn len(&self) -> usize {
64 * (self.bits.len() - 1) + self.index
}
pub fn resize(&mut self, bit_len: usize) {
let len = bit_len / 64 + 1;
self.index = bit_len % 64;
self.bits.resize(len, 0);
*self.end() &= (1 << self.index) - 1;
}
pub(crate) fn xor(&mut self, other: &BitBuf) {
for (self_i, other_i) in self.bits.iter_mut().zip(other.bits.iter()) {
*self_i ^= other_i;
}
*self.end() &= (1 << self.index) - 1;
}
}
impl Encode for BitBuf {
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
self.len().encode(encoder)?;
self.bits.encode(encoder)
}
}
impl Decode for BitBuf {
fn decode<D: Decoder>(decoder: &mut D) -> Result<Self, DecodeError> {
let bit_len = usize::decode(decoder)?;
let len = bit_len / 64 + 1;
let index = len % 64;
decoder.claim_container_read::<u64>(len)?;
let mut bits = Vec::with_capacity(len);
for _ in 0..len {
decoder.unclaim_bytes_read(core::mem::size_of::<u64>());
bits.push(u64::decode(decoder)?)
}
Ok(Self { bits, index })
}
}
#[cfg(test)]
mod test {
use super::*;
use proptest::collection::*;
use proptest::prelude::*;
prop_compose! {
fn arb_bit_buf()(mut bits in vec(any::<u64>(), 1..100usize), index in 0..64usize) -> BitBuf {
*bits.last_mut().unwrap() &= (1 << index) - 1;
BitBuf { bits, index }
}
}
proptest! {
#[test]
fn test_push_then_pop_is_identity(buf in arb_bit_buf(), x in any::<u64>(), index in 0..64usize) {
let bit = Bit::select(x, index);
let mut buf2 = buf.clone();
buf2.push(bit);
let bit2 = buf2.pop();
assert_eq!(buf2, buf);
assert_eq!(bit2, Some(bit));
}
}
proptest! {
#[test]
fn test_push_increases_len_by_one(mut buf in arb_bit_buf()) {
let start_len = buf.len();
buf.push(Bit::select(0, 0));
assert_eq!(buf.len(), start_len + 1);
}
}
#[test]
fn test_bitbuf_get() {
let buf = BitBuf {
bits: vec![0, 0b10],
index: 2,
};
assert_eq!(buf.get(65), Some(Bit(1)));
assert_eq!(buf.get(64), Some(Bit(0)));
assert_eq!(buf.get(67), None);
}
#[test]
fn test_bitbuf_from_bytes() {
let buf = BitBuf::from_bytes(&[0xAB, 0xCD]);
let expected = BitBuf {
bits: vec![0xCDAB],
index: 16,
};
assert_eq!(buf, expected);
}
}