#![cfg_attr(feature = "no-std", no_std)]
#![forbid(unsafe_code)]
#![forbid(unsafe_op_in_unsafe_fn)]
#![forbid(rustdoc::broken_intra_doc_links)]
use core::cmp;
#[cfg(not(feature = "no-std"))]
use std::io::{Read, Result, Write};
#[cfg(feature = "no-std")]
use acid_io::{Read, Result, Write};
#[cfg(test)]
mod test;
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct BitpackedIntegerWidth(u8);
impl BitpackedIntegerWidth {
pub const fn new(width: u8) -> Option<Self> {
if width <= 32 {
Some(Self(width))
} else {
None
}
}
pub const fn get(self) -> u8 {
self.0
}
#[doc(hidden)]
pub const fn __internal_unchecked_new(width: u8) -> Self {
Self(width)
}
}
#[macro_export]
macro_rules! bitpacked_integer_width {
($width:expr) => {{
const _: [(); 32 - $width as usize] = [(); 32 - $width as usize];
$crate::BitpackedIntegerWidth::__internal_unchecked_new($width)
}};
}
#[derive(Debug)]
pub struct BitpackReader<R: Read> {
last_read_byte: u8,
remaining_bits: u8,
source: R
}
impl<R: Read> BitpackReader<R> {
pub fn new(source: R) -> Self {
Self {
last_read_byte: 0,
remaining_bits: 0,
source
}
}
pub fn read_unsigned_integer(&mut self, width: BitpackedIntegerWidth) -> Result<u32> {
let remaining_bits = self.remaining_bits;
let result;
if remaining_bits >= width.get() {
result = self.last_read_byte as u32 & ones_mask(width);
self.remaining_bits -= width.get();
self.last_read_byte >>= width.get();
} else {
let mut read_buf = [0u8; 4];
let bits_to_read = width.get() - remaining_bits;
let bytes_to_read = (1 + (bits_to_read - 1) / 8) as usize;
for byte_to_read in &mut read_buf[..bytes_to_read] {
self.source
.read_exact(core::slice::from_mut(byte_to_read))?;
}
let mut partial_result = self.last_read_byte as u32
& ones_mask(BitpackedIntegerWidth::__internal_unchecked_new(
remaining_bits
));
for (i, byte) in read_buf.iter().enumerate().take(bytes_to_read) {
partial_result |= (*byte as u32) << (remaining_bits + 8 * i as u8);
}
result = partial_result & ones_mask(width);
self.remaining_bits = bytes_to_read as u8 * 8 - bits_to_read;
self.last_read_byte =
read_buf[bytes_to_read - 1].rotate_right(8 - self.remaining_bits as u32);
}
Ok(result)
}
pub fn read_signed_integer(&mut self, width: BitpackedIntegerWidth) -> Result<i32> {
Ok(sign_extend(self.read_unsigned_integer(width)?, width))
}
pub fn read_float32(&mut self) -> Result<f64> {
Ok(float32_unpack(
self.read_unsigned_integer(bitpacked_integer_width!(32))?
))
}
pub fn read_flag(&mut self) -> Result<bool> {
Ok(self.read_unsigned_integer(bitpacked_integer_width!(1))? != 0)
}
pub fn into_inner(self) -> R {
self.source
}
}
#[derive(Debug)]
pub struct BitpackWriter<W: Write> {
byte_to_be_written: u8,
bits_to_be_written: u8,
sink: W
}
impl<W: Write> BitpackWriter<W> {
pub fn new(sink: W) -> Self {
Self {
byte_to_be_written: 0,
bits_to_be_written: 0,
sink
}
}
pub fn write_unsigned_integer(
&mut self,
mut integer: u32,
width: BitpackedIntegerWidth
) -> Result<()> {
let mut remaining_bits = width.get();
let free_bits_in_byte_to_be_written = 8 - self.bits_to_be_written;
let bits_to_write_in_byte_to_be_written =
cmp::min(remaining_bits, free_bits_in_byte_to_be_written);
let bits_to_write_in_byte_to_be_written_width =
BitpackedIntegerWidth::__internal_unchecked_new(bits_to_write_in_byte_to_be_written);
self.byte_to_be_written |= ((integer & ones_mask(bits_to_write_in_byte_to_be_written_width))
as u8) << self.bits_to_be_written;
remaining_bits -= bits_to_write_in_byte_to_be_written;
self.bits_to_be_written += bits_to_write_in_byte_to_be_written;
if self.bits_to_be_written == 8 {
self.sink.write_all(&[self.byte_to_be_written])?;
self.byte_to_be_written = 0;
self.bits_to_be_written = 0;
}
if remaining_bits == 0 {
return Ok(());
}
let bytes_to_write = remaining_bits / 8;
let remainder_bits = remaining_bits % 8;
integer >>= bits_to_write_in_byte_to_be_written;
for byte_to_write in &integer.to_le_bytes()[..bytes_to_write as usize] {
self.sink.write_all(&[*byte_to_write])?;
}
integer >>= 8 * bytes_to_write;
self.byte_to_be_written = integer as u8;
self.bits_to_be_written = remainder_bits;
Ok(())
}
pub fn write_signed_integer(
&mut self,
integer: i32,
width: BitpackedIntegerWidth
) -> Result<()> {
self.write_unsigned_integer(integer as u32, width)
}
pub fn write_float32(&mut self, float: f64) -> Result<()> {
self.write_unsigned_integer(float32_pack(float), bitpacked_integer_width!(32))
}
pub fn write_flag(&mut self, flag: bool) -> Result<()> {
self.write_unsigned_integer(flag as u32, bitpacked_integer_width!(1))
}
pub fn finalize(&mut self) -> Result<()> {
if self.bits_to_be_written > 0 {
self.bits_to_be_written = 0;
self.sink.write_all(&[self.byte_to_be_written])
} else {
Ok(())
}
}
pub fn flush(&mut self) -> Result<()> {
self.sink.flush()
}
}
impl<W: Write> Drop for BitpackWriter<W> {
fn drop(&mut self) {
self.finalize().ok();
}
}
const fn ones_mask(width: BitpackedIntegerWidth) -> u32 {
((1u64 << width.get() as u64) - 1) as u32
}
const fn sign_extend(integer: u32, width: BitpackedIntegerWidth) -> i32 {
let extended_bits = 32 - width.get() as u32;
(integer as i32) << extended_bits >> extended_bits
}
fn float32_unpack(word: u32) -> f64 {
let mantissa = f32::from_bits(((word & 0x1FFFFF) as f32).to_bits() | word & 0x80000000);
let exponent = ((word & 0x7FE00000) >> 21) as f64 - 788.0;
#[cfg(not(feature = "no-std"))]
{
mantissa as f64 * exponent.exp2()
}
#[cfg(feature = "no-std")]
{
mantissa as f64 * libm::exp2(exponent)
}
}
fn float32_pack(float: f64) -> u32 {
const VORBIS_FLOAT32_MAX_EXPONENT: u32 = (1 << 10) - 1;
let sign_component = ((float.to_bits() & 0x8000_0000_0000_0000) >> 32) as u32;
let exponent = ((float.to_bits() & 0x7FF0_0000_0000_0000) >> 52) as u32;
let adjusted_exponent = cmp::min(
exponent.saturating_sub(235 + 20),
VORBIS_FLOAT32_MAX_EXPONENT
);
let exponent_component = adjusted_exponent << 21;
let mantissa_component = ((float.to_bits() & 0x000F_FFFF_0000_0000) >> 32) as u32 | 0x10_00_00;
sign_component | exponent_component | mantissa_component
}