#![cfg(feature = "alloc")]
use std::{io, vec::Vec};
use super::{
BitCount, BitWrite, BitWriter, Counter, Endianness, Integer, Overflowed, PhantomData,
Primitive, SignedBitCount, SignedInteger, ToBitStream, ToBitStreamWith, UnsignedInteger,
};
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
pub struct BitRecorder<N, E: Endianness> {
writer: BitWriter<Vec<u8>, E>,
phantom: PhantomData<N>,
}
impl<N: Counter, E: Endianness> BitRecorder<N, E> {
#[inline]
pub fn new() -> Self {
BitRecorder {
writer: BitWriter::new(Vec::new()),
phantom: PhantomData,
}
}
#[inline]
pub fn with_capacity(bytes: usize) -> Self {
BitRecorder {
writer: BitWriter::new(Vec::with_capacity(bytes)),
phantom: PhantomData,
}
}
#[inline]
pub fn endian(endian: E) -> Self {
BitRecorder {
writer: BitWriter::endian(Vec::new(), endian),
phantom: PhantomData,
}
}
#[inline]
pub fn written(&self) -> N {
self.written_checked()
.expect("writer maintains checked count when tracking is enabled")
}
#[inline]
pub fn written_checked(&self) -> Result<N, Overflowed> {
let mut written = N::try_from(self.writer.writer.len())
.map_err(|_| Overflowed)?
.checked_mul(8u8.into())?;
written.checked_add_assign(N::try_from(self.writer.bits).map_err(|_| Overflowed)?)?;
Ok(written)
}
#[inline]
pub fn playback<W: BitWrite>(&self, writer: &mut W) -> io::Result<()> {
writer.write_bytes(self.writer.writer.as_slice())?;
writer.write_var(self.writer.bits, self.writer.value)?;
Ok(())
}
#[inline]
pub fn clear(&mut self) {
self.writer = BitWriter::new({
let mut v = core::mem::take(&mut self.writer.writer);
v.clear();
v
});
}
}
impl<N: Counter, E: Endianness> Default for BitRecorder<N, E> {
#[inline]
fn default() -> Self {
Self::new()
}
}
impl<N, E> BitWrite for BitRecorder<N, E>
where
E: Endianness,
N: Counter,
{
#[inline]
fn write_bit(&mut self, bit: bool) -> io::Result<()> {
BitWrite::write_bit(&mut self.writer, bit)
}
#[inline]
fn write<const BITS: u32, I>(&mut self, value: I) -> io::Result<()>
where
I: Integer,
{
BitWrite::write::<BITS, I>(&mut self.writer, value)
}
#[inline]
fn write_const<const BITS: u32, const VALUE: u32>(&mut self) -> io::Result<()> {
self.writer.write_const::<BITS, VALUE>()
}
#[inline]
fn write_var<I>(&mut self, bits: u32, value: I) -> io::Result<()>
where
I: Integer,
{
self.writer.write_var(bits, value)
}
#[inline]
fn write_unsigned<const BITS: u32, U>(&mut self, value: U) -> io::Result<()>
where
U: UnsignedInteger,
{
BitWrite::write_unsigned::<BITS, U>(&mut self.writer, value)
}
#[inline]
fn write_unsigned_var<U>(&mut self, bits: u32, value: U) -> io::Result<()>
where
U: UnsignedInteger,
{
self.writer.write_unsigned_var(bits, value)
}
#[inline]
fn write_signed<const BITS: u32, S>(&mut self, value: S) -> io::Result<()>
where
S: SignedInteger,
{
BitWrite::write_signed::<BITS, S>(&mut self.writer, value)
}
#[inline(always)]
fn write_signed_var<S>(&mut self, bits: u32, value: S) -> io::Result<()>
where
S: SignedInteger,
{
self.writer.write_signed_var(bits, value)
}
#[inline]
fn write_count<const MAX: u32>(&mut self, count: BitCount<MAX>) -> io::Result<()> {
self.writer.write_count::<MAX>(count)
}
#[inline]
fn write_counted<const MAX: u32, I>(&mut self, bits: BitCount<MAX>, value: I) -> io::Result<()>
where
I: Integer + Sized,
{
self.writer.write_counted::<MAX, I>(bits, value)
}
#[inline]
fn write_unsigned_counted<const BITS: u32, U>(
&mut self,
bits: BitCount<BITS>,
value: U,
) -> io::Result<()>
where
U: UnsignedInteger,
{
self.writer.write_unsigned_counted::<BITS, U>(bits, value)
}
#[inline]
fn write_signed_counted<const MAX: u32, S>(
&mut self,
bits: impl TryInto<SignedBitCount<MAX>>,
value: S,
) -> io::Result<()>
where
S: SignedInteger,
{
self.writer.write_signed_counted::<MAX, S>(bits, value)
}
#[inline]
fn write_from<V>(&mut self, value: V) -> io::Result<()>
where
V: Primitive,
{
BitWrite::write_from::<V>(&mut self.writer, value)
}
#[inline]
fn write_as_from<F, V>(&mut self, value: V) -> io::Result<()>
where
F: Endianness,
V: Primitive,
{
BitWrite::write_as_from::<F, V>(&mut self.writer, value)
}
#[inline]
fn pad(&mut self, bits: u32) -> io::Result<()> {
BitWrite::pad(&mut self.writer, bits)
}
#[inline]
fn write_bytes(&mut self, buf: &[u8]) -> io::Result<()> {
BitWrite::write_bytes(&mut self.writer, buf)
}
#[inline]
fn write_unary<const STOP_BIT: u8>(&mut self, value: u32) -> io::Result<()> {
self.writer.write_unary::<STOP_BIT>(value)
}
#[inline]
fn build<T: ToBitStream>(&mut self, build: &T) -> Result<(), T::Error> {
BitWrite::build(&mut self.writer, build)
}
#[inline]
fn build_with<'a, T: ToBitStreamWith<'a>>(
&mut self,
build: &T,
context: &T::Context,
) -> Result<(), T::Error> {
BitWrite::build_with(&mut self.writer, build, context)
}
#[inline]
fn byte_aligned(&self) -> bool {
BitWrite::byte_aligned(&self.writer)
}
#[inline]
fn byte_align(&mut self) -> io::Result<()> {
BitWrite::byte_align(&mut self.writer)
}
#[inline]
fn write_huffman<T>(&mut self, value: T::Symbol) -> io::Result<()>
where
T: crate::huffman::ToBits,
{
BitWrite::write_huffman::<T>(&mut self.writer, value)
}
}
impl<N: PartialOrd + Counter + Copy, E: Endianness> BitRecorder<N, E> {
pub fn best<F>(
mut self,
candidate: &mut Self,
f: impl FnOnce(&mut Self) -> Result<(), F>,
) -> Result<Self, F> {
candidate.clear();
f(candidate)?;
if candidate.written() < self.written() {
core::mem::swap(&mut self, candidate);
}
Ok(self)
}
}