use std::io;
use crate::endian::write_byte;
use super::{
BitCount, BitWrite, BitWriter, Checkable, CheckedSigned, CheckedUnsigned, Endianness, Integer,
Primitive, SignedBitCount, SignedInteger, ToBitStream, ToBitStreamWith, UnsignedInteger,
};
pub trait BitWrite2 {
fn write_bit(&mut self, bit: bool) -> io::Result<()> {
self.write_unsigned_out::<1, u8>(u8::from(bit))
}
fn write<I>(&mut self, bits: u32, value: I) -> io::Result<()>
where
I: Integer;
fn write_out<const BITS: u32, I>(&mut self, value: I) -> io::Result<()>
where
I: Integer;
fn write_unsigned<U>(&mut self, bits: u32, value: U) -> io::Result<()>
where
U: UnsignedInteger;
#[inline]
fn write_unsigned_out<const BITS: u32, U>(&mut self, value: U) -> io::Result<()>
where
U: UnsignedInteger,
{
self.write_unsigned(BITS, value)
}
fn write_signed<S>(&mut self, bits: u32, value: S) -> io::Result<()>
where
S: SignedInteger;
fn write_signed_out<const BITS: u32, S>(&mut self, value: S) -> io::Result<()>
where
S: SignedInteger,
{
self.write_signed(BITS, value)
}
fn write_from<V>(&mut self, value: V) -> io::Result<()>
where
V: Primitive;
fn write_as_from<F, V>(&mut self, value: V) -> io::Result<()>
where
F: Endianness,
V: Primitive;
fn pad(&mut self, mut bits: u32) -> io::Result<()> {
loop {
match bits {
0 => break Ok(()),
bits @ 1..64 => break self.write(bits, 0u64),
_ => {
self.write_out::<64, u64>(0)?;
bits -= 64;
}
}
}
}
#[inline]
fn write_bytes(&mut self, buf: &[u8]) -> io::Result<()> {
buf.iter()
.try_for_each(|b| self.write_unsigned_out::<8, _>(*b))
}
fn write_unary0(&mut self, value: u32) -> io::Result<()>;
fn write_unary1(&mut self, value: u32) -> io::Result<()>;
fn build<T: ToBitStream>(&mut self, build: &T) -> Result<(), T::Error>
where
Self: BitWrite,
{
build.to_writer(self)
}
fn build_with<'a, T: ToBitStreamWith<'a>>(
&mut self,
build: &T,
context: &T::Context,
) -> Result<(), T::Error>
where
Self: BitWrite,
{
build.to_writer(self, context)
}
fn byte_aligned(&self) -> bool;
fn byte_align(&mut self) -> io::Result<()> {
while !self.byte_aligned() {
self.write_bit(false)?;
}
Ok(())
}
fn write_huffman<T>(&mut self, value: T::Symbol) -> io::Result<()>
where
T: crate::huffman::ToBits,
{
T::to_bits(value, |b| self.write_bit(b))
}
}
impl<W: BitWrite> BitWrite2 for W {
#[inline]
fn write_bit(&mut self, bit: bool) -> io::Result<()> {
BitWrite::write_bit(self, bit)
}
#[inline]
fn write<I>(&mut self, bits: u32, value: I) -> io::Result<()>
where
I: Integer,
{
BitWrite::write_var(self, bits, value)
}
#[inline]
fn write_out<const BITS: u32, I>(&mut self, value: I) -> io::Result<()>
where
I: Integer,
{
BitWrite::write::<BITS, I>(self, value)
}
#[inline]
fn write_unsigned<U>(&mut self, bits: u32, value: U) -> io::Result<()>
where
U: UnsignedInteger,
{
BitWrite::write_unsigned_var::<U>(self, bits, value)
}
#[inline]
fn write_unsigned_out<const BITS: u32, U>(&mut self, value: U) -> io::Result<()>
where
U: UnsignedInteger,
{
BitWrite::write_unsigned::<BITS, U>(self, value)
}
#[inline]
fn write_signed<S>(&mut self, bits: u32, value: S) -> io::Result<()>
where
S: SignedInteger,
{
BitWrite::write_signed_var::<S>(self, bits, value)
}
#[inline]
fn write_signed_out<const BITS: u32, S>(&mut self, value: S) -> io::Result<()>
where
S: SignedInteger,
{
BitWrite::write_signed::<BITS, S>(self, value)
}
#[inline]
fn write_from<V>(&mut self, value: V) -> io::Result<()>
where
V: Primitive,
{
BitWrite::write_from(self, 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>(self, value)
}
#[inline]
fn pad(&mut self, bits: u32) -> io::Result<()> {
BitWrite::pad(self, bits)
}
#[inline]
fn write_bytes(&mut self, buf: &[u8]) -> io::Result<()> {
BitWrite::write_bytes(self, buf)
}
#[inline]
fn write_unary0(&mut self, value: u32) -> io::Result<()> {
BitWrite::write_unary::<0>(self, value)
}
#[inline]
fn write_unary1(&mut self, value: u32) -> io::Result<()> {
BitWrite::write_unary::<1>(self, value)
}
#[inline]
fn byte_aligned(&self) -> bool {
BitWrite::byte_aligned(self)
}
#[inline]
fn byte_align(&mut self) -> io::Result<()> {
BitWrite::byte_align(self)
}
}
impl<W: io::Write, E: Endianness> BitWrite for BitWriter<W, E> {
fn write_bit(&mut self, bit: bool) -> io::Result<()> {
match E::push_bit_flush(&mut self.value, &mut self.bits, bit) {
None => Ok(()),
Some(byte) => write_byte(&mut self.writer, byte),
}
}
#[inline(always)]
fn write_unsigned<const BITS: u32, U>(&mut self, value: U) -> io::Result<()>
where
U: UnsignedInteger,
{
let Self {
value: queue_value,
bits: queue_bits,
writer,
..
} = self;
E::write_bits_checked(
writer,
queue_value,
queue_bits,
CheckedUnsigned::<BITS, U>::new_fixed::<BITS>(value)?,
)
}
fn write_unsigned_counted<const BITS: u32, U>(
&mut self,
count: BitCount<BITS>,
value: U,
) -> io::Result<()>
where
U: UnsignedInteger,
{
let Self {
value: queue_value,
bits: queue_bits,
writer,
..
} = self;
E::write_bits_checked(
writer,
queue_value,
queue_bits,
CheckedUnsigned::new(count, value)?,
)
}
#[inline(always)]
fn write_signed_counted<const BITS: u32, S>(
&mut self,
bits: impl TryInto<SignedBitCount<BITS>>,
value: S,
) -> io::Result<()>
where
S: SignedInteger,
{
E::write_signed_bits_checked(
&mut self.writer,
&mut self.value,
&mut self.bits,
CheckedSigned::new(
bits.try_into().map_err(|_| {
io::Error::new(
io::ErrorKind::InvalidInput,
"signed writes need at least 1 bit for sign",
)
})?,
value,
)?,
)
}
#[inline]
fn write_signed<const BITS: u32, S>(&mut self, value: S) -> io::Result<()>
where
S: SignedInteger,
{
E::write_signed_bits_checked(
&mut self.writer,
&mut self.value,
&mut self.bits,
CheckedSigned::<BITS, _>::new_fixed::<BITS>(value)?,
)
}
#[inline]
fn write_from<V>(&mut self, value: V) -> io::Result<()>
where
V: Primitive,
{
E::write_bytes::<8, _>(
&mut self.writer,
&mut self.value,
self.bits,
E::primitive_to_bytes(value).as_ref(),
)
}
#[inline]
fn write_as_from<F, V>(&mut self, value: V) -> io::Result<()>
where
F: Endianness,
V: Primitive,
{
F::write_bytes::<8, _>(
&mut self.writer,
&mut self.value,
self.bits,
F::primitive_to_bytes(value).as_ref(),
)
}
#[inline]
fn write_checked<C: Checkable>(&mut self, value: C) -> io::Result<()> {
value.write_endian::<E, _>(&mut self.writer, &mut self.value, &mut self.bits)
}
#[inline]
fn write_bytes(&mut self, buf: &[u8]) -> io::Result<()> {
E::write_bytes::<1024, _>(&mut self.writer, &mut self.value, self.bits, buf)
}
#[inline(always)]
fn byte_aligned(&self) -> bool {
self.bits == 0
}
}