#![cfg_attr(docsrs, feature(doc_cfg))]
#![warn(missing_docs)]
#![forbid(unsafe_code)]
#![no_std]
#[cfg(feature = "alloc")]
extern crate alloc;
#[cfg(feature = "std")]
extern crate std;
#[cfg(not(feature = "std"))]
use no_std_io2::io;
use core::convert::TryInto;
use core::num::NonZero;
use core::ops::{
BitAnd, BitOr, BitOrAssign, BitXor, Not, Rem, RemAssign, Shl, ShlAssign, Shr, ShrAssign, Sub,
};
use core::{fmt::Debug, marker::PhantomData, mem};
#[cfg(feature = "std")]
use std::io;
pub mod huffman;
pub mod read;
pub mod write;
pub use read::{
BitRead, BitRead2, BitReader, ByteRead, ByteReader, FromBitStream, FromBitStreamUsing,
FromBitStreamWith, FromByteStream, FromByteStreamUsing, FromByteStreamWith,
};
#[cfg(feature = "alloc")]
pub use write::BitRecorder;
pub use write::{
BitWrite, BitWrite2, BitWriter, BitsWritten, ByteWrite, ByteWriter, ToBitStream,
ToBitStreamUsing, ToBitStreamWith, ToByteStream, ToByteStreamUsing, ToByteStreamWith,
};
#[allow(deprecated)]
pub use write::BitCounter;
pub trait Primitive {
type Bytes: AsRef<[u8]> + AsMut<[u8]>;
fn buffer() -> Self::Bytes;
fn to_be_bytes(self) -> Self::Bytes;
fn to_le_bytes(self) -> Self::Bytes;
fn from_be_bytes(bytes: Self::Bytes) -> Self;
fn from_le_bytes(bytes: Self::Bytes) -> Self;
}
macro_rules! define_primitive_numeric {
($t:ty) => {
impl Primitive for $t {
type Bytes = [u8; mem::size_of::<$t>()];
#[inline(always)]
fn buffer() -> Self::Bytes {
[0; mem::size_of::<$t>()]
}
#[inline(always)]
fn to_be_bytes(self) -> Self::Bytes {
self.to_be_bytes()
}
#[inline(always)]
fn to_le_bytes(self) -> Self::Bytes {
self.to_le_bytes()
}
#[inline(always)]
fn from_be_bytes(bytes: Self::Bytes) -> Self {
<$t>::from_be_bytes(bytes)
}
#[inline(always)]
fn from_le_bytes(bytes: Self::Bytes) -> Self {
<$t>::from_le_bytes(bytes)
}
}
};
}
impl<const N: usize> Primitive for [u8; N] {
type Bytes = [u8; N];
#[inline(always)]
fn buffer() -> Self::Bytes {
[0; N]
}
#[inline(always)]
fn to_be_bytes(self) -> Self::Bytes {
self
}
#[inline(always)]
fn to_le_bytes(self) -> Self::Bytes {
self
}
#[inline(always)]
fn from_be_bytes(bytes: Self::Bytes) -> Self {
bytes
}
#[inline(always)]
fn from_le_bytes(bytes: Self::Bytes) -> Self {
bytes
}
}
pub trait Integer {
fn read<const BITS: u32, R: BitRead + ?Sized>(reader: &mut R) -> io::Result<Self>
where
Self: Sized;
fn read_var<const MAX: u32, R>(reader: &mut R, bits: BitCount<MAX>) -> io::Result<Self>
where
R: BitRead + ?Sized,
Self: Sized;
fn write<const BITS: u32, W: BitWrite + ?Sized>(self, writer: &mut W) -> io::Result<()>;
fn write_var<const MAX: u32, W: BitWrite + ?Sized>(
self,
writer: &mut W,
bits: BitCount<MAX>,
) -> io::Result<()>;
}
pub trait VBRInteger: Integer {
fn read_vbr<const FIELD_SIZE: u32, R>(reader: &mut R) -> io::Result<Self>
where
R: BitRead + ?Sized,
Self: Sized;
fn write_vbr<const FIELD_SIZE: u32, W: BitWrite + ?Sized>(
self,
writer: &mut W,
) -> io::Result<()>;
}
impl Integer for bool {
#[inline(always)]
fn read<const BITS: u32, R: BitRead + ?Sized>(reader: &mut R) -> io::Result<Self>
where
Self: Sized,
{
const {
assert!(BITS == 1, "booleans require exactly 1 bit");
}
reader.read_bit()
}
fn read_var<const MAX: u32, R>(
reader: &mut R,
BitCount { bits }: BitCount<MAX>,
) -> io::Result<Self>
where
R: BitRead + ?Sized,
Self: Sized,
{
if bits == 1 {
reader.read_bit()
} else {
Err(io::Error::new(
io::ErrorKind::InvalidInput,
"booleans require exactly 1 bit",
))
}
}
#[inline(always)]
fn write<const BITS: u32, W: BitWrite + ?Sized>(self, writer: &mut W) -> io::Result<()> {
const {
assert!(BITS == 1, "booleans require exactly 1 bit");
}
writer.write_bit(self)
}
fn write_var<const MAX: u32, W: BitWrite + ?Sized>(
self,
writer: &mut W,
BitCount { bits }: BitCount<MAX>,
) -> io::Result<()> {
if bits == 1 {
writer.write_bit(self)
} else {
Err(io::Error::new(
io::ErrorKind::InvalidInput,
"booleans require exactly 1 bit",
))
}
}
}
impl<const SIZE: usize, I: Integer + Copy + Default> Integer for [I; SIZE] {
#[inline]
fn read<const BITS: u32, R: BitRead + ?Sized>(reader: &mut R) -> io::Result<Self>
where
Self: Sized,
{
let mut a = [I::default(); SIZE];
a.iter_mut().try_for_each(|v| {
*v = reader.read::<BITS, I>()?;
Ok::<(), io::Error>(())
})?;
Ok(a)
}
#[inline]
fn read_var<const MAX: u32, R>(reader: &mut R, count: BitCount<MAX>) -> io::Result<Self>
where
R: BitRead + ?Sized,
Self: Sized,
{
let mut a = [I::default(); SIZE];
a.iter_mut().try_for_each(|v| {
*v = reader.read_counted(count)?;
Ok::<(), io::Error>(())
})?;
Ok(a)
}
#[inline]
fn write<const BITS: u32, W: BitWrite + ?Sized>(self, writer: &mut W) -> io::Result<()> {
IntoIterator::into_iter(self).try_for_each(|v| writer.write::<BITS, I>(v))
}
#[inline]
fn write_var<const MAX: u32, W: BitWrite + ?Sized>(
self,
writer: &mut W,
count: BitCount<MAX>,
) -> io::Result<()> {
IntoIterator::into_iter(self).try_for_each(|v| writer.write_counted(count, v))
}
}
impl<const SIZE: usize, I: VBRInteger + Copy + Default> VBRInteger for [I; SIZE] {
fn read_vbr<const FIELD_SIZE: u32, R>(reader: &mut R) -> io::Result<Self>
where
R: BitRead + ?Sized,
Self: Sized,
{
let mut a = [I::default(); SIZE];
a.iter_mut().try_for_each(|v| {
I::read_vbr::<FIELD_SIZE, R>(reader).map(|item| {
*v = item;
})
})?;
Ok(a)
}
fn write_vbr<const FIELD_SIZE: u32, W: BitWrite + ?Sized>(
self,
writer: &mut W,
) -> io::Result<()> {
IntoIterator::into_iter(self).try_for_each(|v| I::write_vbr::<FIELD_SIZE, W>(v, writer))
}
}
pub trait Numeric:
Primitive
+ Sized
+ Copy
+ Default
+ Debug
+ PartialOrd
+ Shl<u32, Output = Self>
+ ShlAssign<u32>
+ Shr<u32, Output = Self>
+ ShrAssign<u32>
+ Rem<Self, Output = Self>
+ RemAssign<Self>
+ BitAnd<Self, Output = Self>
+ BitOr<Self, Output = Self>
+ BitOrAssign<Self>
+ BitXor<Self, Output = Self>
+ Not<Output = Self>
+ Sub<Self, Output = Self>
{
const BITS_SIZE: u32;
const ZERO: Self;
const ONE: Self;
fn from_u8(u: u8) -> Self;
fn to_u8(self) -> u8;
}
macro_rules! define_numeric {
($t:ty) => {
define_primitive_numeric!($t);
impl Numeric for $t {
const BITS_SIZE: u32 = mem::size_of::<$t>() as u32 * 8;
const ZERO: Self = 0;
const ONE: Self = 1;
#[inline(always)]
fn from_u8(u: u8) -> Self {
u as $t
}
#[inline(always)]
fn to_u8(self) -> u8 {
self as u8
}
}
};
}
pub trait UnsignedInteger: Numeric {
const MSB_BIT: Self;
const LSB_BIT: Self;
const ALL: Self;
type Signed: SignedInteger<Unsigned = Self>;
fn as_non_negative(self) -> Self::Signed;
fn as_negative(self, bits: u32) -> Self::Signed;
fn as_negative_fixed<const BITS: u32>(self) -> Self::Signed;
fn checked_shl(self, rhs: u32) -> Option<Self>;
fn checked_shr(self, rhs: u32) -> Option<Self>;
fn shl_default(self, rhs: u32) -> Self {
self.checked_shl(rhs).unwrap_or(Self::ZERO)
}
fn shr_default(self, rhs: u32) -> Self {
self.checked_shr(rhs).unwrap_or(Self::ZERO)
}
}
macro_rules! define_unsigned_integer {
($t:ty, $s:ty) => {
define_numeric!($t);
impl UnsignedInteger for $t {
type Signed = $s;
const MSB_BIT: Self = 1 << (Self::BITS_SIZE - 1);
const LSB_BIT: Self = 1;
const ALL: Self = <$t>::MAX;
#[inline(always)]
fn as_non_negative(self) -> Self::Signed {
self as $s
}
#[inline(always)]
fn as_negative(self, bits: u32) -> Self::Signed {
(self as $s) + (-1 << (bits - 1))
}
#[inline(always)]
fn as_negative_fixed<const BITS: u32>(self) -> Self::Signed {
(self as $s) + (-1 << (BITS - 1))
}
#[inline(always)]
fn checked_shl(self, rhs: u32) -> Option<Self> {
self.checked_shl(rhs)
}
#[inline(always)]
fn checked_shr(self, rhs: u32) -> Option<Self> {
self.checked_shr(rhs)
}
}
impl Integer for $t {
#[inline(always)]
fn read<const BITS: u32, R: BitRead + ?Sized>(reader: &mut R) -> io::Result<Self>
where
Self: Sized,
{
reader.read_unsigned::<BITS, _>()
}
#[inline(always)]
fn read_var<const MAX: u32, R>(reader: &mut R, bits: BitCount<MAX>) -> io::Result<Self>
where
R: BitRead + ?Sized,
Self: Sized,
{
reader.read_unsigned_counted::<MAX, _>(bits)
}
#[inline(always)]
fn write<const BITS: u32, W: BitWrite + ?Sized>(
self,
writer: &mut W,
) -> io::Result<()> {
writer.write_unsigned::<BITS, _>(self)
}
#[inline(always)]
fn write_var<const MAX: u32, W: BitWrite + ?Sized>(
self,
writer: &mut W,
bits: BitCount<MAX>,
) -> io::Result<()> {
writer.write_unsigned_counted(bits, self)
}
}
impl VBRInteger for $t {
#[inline(always)]
fn read_vbr<const FIELD_SIZE: u32, R>(reader: &mut R) -> io::Result<Self>
where
R: BitRead + ?Sized,
Self: Sized,
{
reader.read_unsigned_vbr::<FIELD_SIZE, _>()
}
#[inline(always)]
fn write_vbr<const FIELD_SIZE: u32, W: BitWrite + ?Sized>(
self,
writer: &mut W,
) -> io::Result<()> {
writer.write_unsigned_vbr::<FIELD_SIZE, _>(self)
}
}
impl Integer for NonZero<$t> {
#[inline]
fn read<const BITS: u32, R: BitRead + ?Sized>(reader: &mut R) -> io::Result<Self>
where
Self: Sized,
{
const {
assert!(
BITS < <$t>::BITS_SIZE,
"BITS must be less than the type's size in bits"
);
}
<$t as Integer>::read::<BITS, R>(reader).map(|u| NonZero::new(u + 1).unwrap())
}
#[inline]
fn read_var<const MAX: u32, R>(
reader: &mut R,
count @ BitCount { bits }: BitCount<MAX>,
) -> io::Result<Self>
where
R: BitRead + ?Sized,
Self: Sized,
{
if MAX < <$t>::BITS_SIZE || bits < <$t>::BITS_SIZE {
<$t as Integer>::read_var::<MAX, R>(reader, count)
.map(|u| NonZero::new(u + 1).unwrap())
} else {
Err(io::Error::new(
io::ErrorKind::InvalidInput,
"bit count must be less than the type's size in bits",
))
}
}
#[inline]
fn write<const BITS: u32, W: BitWrite + ?Sized>(
self,
writer: &mut W,
) -> io::Result<()> {
const {
assert!(
BITS < <$t>::BITS_SIZE,
"BITS must be less than the type's size in bits"
);
}
<$t as Integer>::write::<BITS, W>(self.get() - 1, writer)
}
#[inline]
fn write_var<const MAX: u32, W: BitWrite + ?Sized>(
self,
writer: &mut W,
count @ BitCount { bits }: BitCount<MAX>,
) -> io::Result<()> {
if MAX < <$t>::BITS_SIZE || bits < <$t>::BITS_SIZE {
<$t as Integer>::write_var::<MAX, W>(self.get() - 1, writer, count)
} else {
Err(io::Error::new(
io::ErrorKind::InvalidInput,
"bit count must be less than the type's size in bits",
))
}
}
}
impl VBRInteger for NonZero<$t> {
#[inline]
fn read_vbr<const FIELD_SIZE: u32, R>(reader: &mut R) -> io::Result<Self>
where
R: BitRead + ?Sized,
Self: Sized,
{
<$t as VBRInteger>::read_vbr::<FIELD_SIZE, R>(reader)
.map(|u| NonZero::new(u + 1).unwrap())
}
#[inline]
fn write_vbr<const FIELD_SIZE: u32, W: BitWrite + ?Sized>(
self,
writer: &mut W,
) -> io::Result<()> {
<$t as VBRInteger>::write_vbr::<FIELD_SIZE, W>(self.get() - 1, writer)
}
}
impl Integer for Option<NonZero<$t>> {
#[inline]
fn read<const BITS: u32, R: BitRead + ?Sized>(reader: &mut R) -> io::Result<Self>
where
Self: Sized,
{
<$t as Integer>::read::<BITS, R>(reader).map(NonZero::new)
}
#[inline]
fn read_var<const MAX: u32, R>(reader: &mut R, count: BitCount<MAX>) -> io::Result<Self>
where
R: BitRead + ?Sized,
Self: Sized,
{
<$t as Integer>::read_var::<MAX, R>(reader, count).map(NonZero::new)
}
#[inline]
fn write<const BITS: u32, W: BitWrite + ?Sized>(
self,
writer: &mut W,
) -> io::Result<()> {
<$t as Integer>::write::<BITS, W>(self.map(|n| n.get()).unwrap_or(0), writer)
}
#[inline]
fn write_var<const MAX: u32, W: BitWrite + ?Sized>(
self,
writer: &mut W,
count: BitCount<MAX>,
) -> io::Result<()> {
<$t as Integer>::write_var::<MAX, W>(
self.map(|n| n.get()).unwrap_or(0),
writer,
count,
)
}
}
impl VBRInteger for Option<NonZero<$t>> {
#[inline(always)]
fn read_vbr<const FIELD_SIZE: u32, R>(reader: &mut R) -> io::Result<Self>
where
R: BitRead + ?Sized,
Self: Sized,
{
<$t as VBRInteger>::read_vbr::<FIELD_SIZE, _>(reader).map(NonZero::new)
}
#[inline]
fn write_vbr<const FIELD_SIZE: u32, W: BitWrite + ?Sized>(
self,
writer: &mut W,
) -> io::Result<()> {
<$t as VBRInteger>::write_vbr::<FIELD_SIZE, W>(
self.map(|n| n.get()).unwrap_or(0),
writer,
)
}
}
};
}
pub trait SignedInteger: Numeric {
type Unsigned: UnsignedInteger<Signed = Self>;
fn is_negative(self) -> bool;
fn as_non_negative(self) -> Self::Unsigned;
fn as_negative(self, bits: u32) -> Self::Unsigned;
fn as_negative_fixed<const BITS: u32>(self) -> Self::Unsigned;
}
macro_rules! define_signed_integer {
($t:ty, $u:ty) => {
define_numeric!($t);
impl SignedInteger for $t {
type Unsigned = $u;
#[inline(always)]
fn is_negative(self) -> bool {
self.is_negative()
}
fn as_non_negative(self) -> Self::Unsigned {
self as $u
}
fn as_negative(self, bits: u32) -> Self::Unsigned {
(self - (-1 << (bits - 1))) as $u
}
fn as_negative_fixed<const BITS: u32>(self) -> Self::Unsigned {
(self - (-1 << (BITS - 1))) as $u
}
}
impl Integer for $t {
#[inline(always)]
fn read<const BITS: u32, R: BitRead + ?Sized>(reader: &mut R) -> io::Result<Self>
where
Self: Sized,
{
reader.read_signed::<BITS, _>()
}
#[inline(always)]
fn read_var<const MAX: u32, R>(reader: &mut R, bits: BitCount<MAX>) -> io::Result<Self>
where
R: BitRead + ?Sized,
Self: Sized,
{
reader.read_signed_counted::<MAX, _>(bits)
}
#[inline(always)]
fn write<const BITS: u32, W: BitWrite + ?Sized>(
self,
writer: &mut W,
) -> io::Result<()> {
writer.write_signed::<BITS, _>(self)
}
#[inline(always)]
fn write_var<const MAX: u32, W: BitWrite + ?Sized>(
self,
writer: &mut W,
bits: BitCount<MAX>,
) -> io::Result<()> {
writer.write_signed_counted::<MAX, _>(bits, self)
}
}
impl VBRInteger for $t {
#[inline(always)]
fn read_vbr<const FIELD_SIZE: u32, R>(reader: &mut R) -> io::Result<Self>
where
R: BitRead + ?Sized,
Self: Sized,
{
reader.read_signed_vbr::<FIELD_SIZE, _>()
}
#[inline(always)]
fn write_vbr<const FIELD_SIZE: u32, W: BitWrite + ?Sized>(
self,
writer: &mut W,
) -> io::Result<()> {
writer.write_signed_vbr::<FIELD_SIZE, _>(self)
}
}
};
}
define_unsigned_integer!(u8, i8);
define_unsigned_integer!(u16, i16);
define_unsigned_integer!(u32, i32);
define_unsigned_integer!(u64, i64);
define_unsigned_integer!(u128, i128);
define_signed_integer!(i8, u8);
define_signed_integer!(i16, u16);
define_signed_integer!(i32, u32);
define_signed_integer!(i64, u64);
define_signed_integer!(i128, u128);
define_primitive_numeric!(f32);
define_primitive_numeric!(f64);
mod private {
use crate::{
io, BitCount, BitRead, BitWrite, CheckedSigned, CheckedUnsigned, Primitive, SignedBitCount,
SignedInteger, UnsignedInteger,
};
#[test]
fn test_checked_signed() {
assert!(CheckedSigned::new(SignedBitCount::<8>::new::<8>(), -128i8).is_ok());
assert!(CheckedSigned::new(SignedBitCount::<8>::new::<8>(), 127i8).is_ok());
assert!(CheckedSigned::new(SignedBitCount::<8>::new::<7>(), -64i8).is_ok());
assert!(CheckedSigned::new(SignedBitCount::<8>::new::<7>(), 63i8).is_ok());
assert!(CheckedSigned::new(SignedBitCount::<8>::new::<6>(), -32i8).is_ok());
assert!(CheckedSigned::new(SignedBitCount::<8>::new::<6>(), 31i8).is_ok());
assert!(CheckedSigned::new(SignedBitCount::<8>::new::<5>(), -16i8).is_ok());
assert!(CheckedSigned::new(SignedBitCount::<8>::new::<5>(), 15i8).is_ok());
assert!(CheckedSigned::new(SignedBitCount::<8>::new::<4>(), -8i8).is_ok());
assert!(CheckedSigned::new(SignedBitCount::<8>::new::<4>(), 7i8).is_ok());
assert!(CheckedSigned::new(SignedBitCount::<8>::new::<3>(), -4i8).is_ok());
assert!(CheckedSigned::new(SignedBitCount::<8>::new::<3>(), 3i8).is_ok());
assert!(CheckedSigned::new(SignedBitCount::<8>::new::<2>(), -2i8).is_ok());
assert!(CheckedSigned::new(SignedBitCount::<8>::new::<2>(), 1i8).is_ok());
assert!(CheckedSigned::new(SignedBitCount::<8>::new::<1>(), -1i8).is_ok());
assert!(CheckedSigned::new(SignedBitCount::<8>::new::<1>(), 0i8).is_ok());
assert!(CheckedSigned::new(SignedBitCount::<8>::new::<7>(), -65i8).is_err());
assert!(CheckedSigned::new(SignedBitCount::<8>::new::<7>(), 64i8).is_err());
assert!(CheckedSigned::new(SignedBitCount::<8>::new::<6>(), -33i8).is_err());
assert!(CheckedSigned::new(SignedBitCount::<8>::new::<6>(), 32i8).is_err());
assert!(CheckedSigned::new(SignedBitCount::<8>::new::<5>(), -17i8).is_err());
assert!(CheckedSigned::new(SignedBitCount::<8>::new::<5>(), 16i8).is_err());
assert!(CheckedSigned::new(SignedBitCount::<8>::new::<4>(), -9i8).is_err());
assert!(CheckedSigned::new(SignedBitCount::<8>::new::<4>(), 8i8).is_err());
assert!(CheckedSigned::new(SignedBitCount::<8>::new::<3>(), -5i8).is_err());
assert!(CheckedSigned::new(SignedBitCount::<8>::new::<3>(), 4i8).is_err());
assert!(CheckedSigned::new(SignedBitCount::<8>::new::<2>(), -3i8).is_err());
assert!(CheckedSigned::new(SignedBitCount::<8>::new::<2>(), 2i8).is_err());
assert!(CheckedSigned::new(SignedBitCount::<8>::new::<1>(), -2i8).is_err());
assert!(CheckedSigned::new(SignedBitCount::<8>::new::<1>(), 1i8).is_err());
}
pub trait Endianness: Sized {
fn pop_bit_refill<R>(
reader: &mut R,
queue_value: &mut u8,
queue_bits: &mut u32,
) -> io::Result<bool>
where
R: io::Read;
fn pop_unary<const STOP_BIT: u8, R>(
reader: &mut R,
queue_value: &mut u8,
queue_bits: &mut u32,
) -> io::Result<u32>
where
R: io::Read;
fn push_bit_flush(queue_value: &mut u8, queue_bits: &mut u32, bit: bool) -> Option<u8>;
fn read_bits<const MAX: u32, R, U>(
reader: &mut R,
queue_value: &mut u8,
queue_bits: &mut u32,
count: BitCount<MAX>,
) -> io::Result<U>
where
R: io::Read,
U: UnsignedInteger;
fn read_bits_fixed<const BITS: u32, R, U>(
reader: &mut R,
queue_value: &mut u8,
queue_bits: &mut u32,
) -> io::Result<U>
where
R: io::Read,
U: UnsignedInteger;
fn write_bits_checked<const MAX: u32, W, U>(
writer: &mut W,
queue_value: &mut u8,
queue_bits: &mut u32,
value: CheckedUnsigned<MAX, U>,
) -> io::Result<()>
where
W: io::Write,
U: UnsignedInteger;
fn write_signed_bits_checked<const MAX: u32, W, S>(
writer: &mut W,
queue_value: &mut u8,
queue_bits: &mut u32,
value: CheckedSigned<MAX, S>,
) -> io::Result<()>
where
W: io::Write,
S: SignedInteger;
fn read_signed_counted<const MAX: u32, R, S>(
r: &mut R,
bits: SignedBitCount<MAX>,
) -> io::Result<S>
where
R: BitRead,
S: SignedInteger;
fn read_bytes<const CHUNK_SIZE: usize, R>(
reader: &mut R,
queue_value: &mut u8,
queue_bits: u32,
buf: &mut [u8],
) -> io::Result<()>
where
R: io::Read;
fn write_bytes<const CHUNK_SIZE: usize, W>(
writer: &mut W,
queue_value: &mut u8,
queue_bits: u32,
buf: &[u8],
) -> io::Result<()>
where
W: io::Write;
fn bytes_to_primitive<P: Primitive>(buf: P::Bytes) -> P;
fn primitive_to_bytes<P: Primitive>(p: P) -> P::Bytes;
#[deprecated(since = "4.0.0")]
fn read_primitive<R, V>(r: &mut R) -> io::Result<V>
where
R: BitRead,
V: Primitive;
#[deprecated(since = "4.0.0")]
fn write_primitive<W, V>(w: &mut W, value: V) -> io::Result<()>
where
W: BitWrite,
V: Primitive;
}
pub trait Checkable {
fn write_endian<E, W>(
self,
writer: &mut W,
queue_value: &mut u8,
queue_bits: &mut u32,
) -> io::Result<()>
where
E: Endianness,
W: io::Write;
}
}
pub trait Endianness: private::Endianness {}
#[inline(always)]
fn read_byte<R>(mut reader: R) -> io::Result<u8>
where
R: io::Read,
{
let mut byte = 0;
reader
.read_exact(core::slice::from_mut(&mut byte))
.map(|()| byte)
}
#[inline(always)]
fn write_byte<W>(mut writer: W, byte: u8) -> io::Result<()>
where
W: io::Write,
{
writer.write_all(core::slice::from_ref(&byte))
}
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
pub struct BitCount<const MAX: u32> {
bits: u32,
}
impl<const MAX: u32> BitCount<MAX> {
pub const fn new<const BITS: u32>() -> Self {
const {
assert!(BITS <= MAX, "BITS must be <= MAX");
}
Self { bits: BITS }
}
#[inline]
pub const fn checked_add<const NEW_MAX: u32>(self, bits: u32) -> Option<BitCount<NEW_MAX>> {
match self.bits.checked_add(bits) {
Some(bits) if bits <= NEW_MAX => Some(BitCount { bits }),
_ => None,
}
}
#[inline]
pub const fn checked_sub<const NEW_MAX: u32>(self, bits: u32) -> Option<BitCount<NEW_MAX>> {
match self.bits.checked_sub(bits) {
Some(bits) if bits <= NEW_MAX => Some(BitCount { bits }),
_ => None,
}
}
#[inline]
pub fn try_map<const NEW_MAX: u32, F>(self, f: F) -> Option<BitCount<NEW_MAX>>
where
F: FnOnce(u32) -> Option<u32>,
{
f(self.bits)
.filter(|bits| *bits <= NEW_MAX)
.map(|bits| BitCount { bits })
}
#[inline(always)]
pub const fn max(&self) -> u32 {
MAX
}
#[inline(always)]
pub const fn signed_count(&self) -> Option<SignedBitCount<MAX>> {
match self.bits.checked_sub(1) {
Some(bits) => Some(SignedBitCount {
bits: *self,
unsigned: BitCount { bits },
}),
None => None,
}
}
pub fn mask_lsb<U: UnsignedInteger>(self) -> impl Fn(U) -> (U, CheckedUnsigned<MAX, U>) {
use core::convert::TryFrom;
let (mask, shift, count) = match U::BITS_SIZE.checked_sub(self.bits) {
Some(mask_bits) => (U::ALL.shr_default(mask_bits), self.bits, self),
None => (
U::ALL,
U::BITS_SIZE,
BitCount::try_from(U::BITS_SIZE).expect("bit count too small for type"),
),
};
move |v| {
(
v.shr_default(shift),
Checked {
value: v & mask,
count,
},
)
}
}
#[inline]
pub fn range<U: UnsignedInteger>(&self) -> core::ops::RangeInclusive<U> {
match U::ONE.checked_shl(self.bits) {
Some(top) => U::ZERO..=(top - U::ONE),
None => U::ZERO..=U::ALL,
}
}
#[inline(always)]
pub fn min(self, bits: u32) -> Self {
Self {
bits: self.bits.min(bits),
}
}
#[inline(always)]
pub fn none<U: UnsignedInteger>(self) -> CheckedUnsigned<MAX, U> {
CheckedUnsigned {
value: U::ZERO,
count: self,
}
}
#[inline(always)]
pub fn all<U: UnsignedInteger>(self) -> CheckedUnsigned<MAX, U> {
CheckedUnsigned {
value: match U::ONE.checked_shl(self.bits) {
Some(top) => top - U::ONE,
None => U::ALL,
},
count: self,
}
}
}
impl<const MAX: u32> core::convert::TryFrom<u32> for BitCount<MAX> {
type Error = u32;
fn try_from(bits: u32) -> Result<Self, Self::Error> {
(bits <= MAX).then_some(Self { bits }).ok_or(bits)
}
}
impl<const MAX: u32> core::fmt::Display for BitCount<MAX> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
core::fmt::Display::fmt(&self.bits, f)
}
}
impl BitCount<{ u32::MAX }> {
pub const fn unknown(bits: u32) -> Self {
Self { bits }
}
}
#[test]
fn test_unknown_bitcount() {
let count = BitCount::unknown(u32::MAX);
assert!(u32::from(count) <= count.max());
}
impl<const MAX: u32> From<BitCount<MAX>> for u32 {
#[inline(always)]
fn from(BitCount { bits }: BitCount<MAX>) -> u32 {
bits
}
}
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
pub struct SignedBitCount<const MAX: u32> {
bits: BitCount<MAX>,
unsigned: BitCount<MAX>,
}
impl<const MAX: u32> SignedBitCount<MAX> {
pub const fn new<const BITS: u32>() -> Self {
const {
assert!(BITS > 0, "BITS must be > 0");
}
Self {
bits: BitCount::new::<BITS>(),
unsigned: BitCount { bits: BITS - 1 },
}
}
#[inline]
pub const fn checked_add<const NEW_MAX: u32>(
self,
bits: u32,
) -> Option<SignedBitCount<NEW_MAX>> {
match self.bits.checked_add(bits) {
Some(bits_new) => match self.unsigned.checked_add(bits) {
Some(unsigned) => Some(SignedBitCount {
bits: bits_new,
unsigned,
}),
None => None,
},
None => None,
}
}
#[inline]
pub const fn checked_sub<const NEW_MAX: u32>(
self,
bits: u32,
) -> Option<SignedBitCount<NEW_MAX>> {
match self.bits.checked_sub(bits) {
Some(bits_new) => match self.unsigned.checked_sub(bits) {
Some(unsigned) => Some(SignedBitCount {
bits: bits_new,
unsigned,
}),
None => None,
},
None => None,
}
}
#[inline]
pub fn try_map<const NEW_MAX: u32, F>(self, f: F) -> Option<SignedBitCount<NEW_MAX>>
where
F: FnOnce(u32) -> Option<u32>,
{
self.bits.try_map(f).and_then(|b| b.signed_count())
}
#[inline(always)]
pub const fn max(&self) -> u32 {
MAX
}
#[inline(always)]
pub const fn count(&self) -> BitCount<MAX> {
self.bits
}
#[inline(always)]
pub const fn unsigned_count(&self) -> BitCount<MAX> {
self.unsigned
}
pub fn range<S: SignedInteger>(&self) -> core::ops::RangeInclusive<S> {
if self.bits.bits < S::BITS_SIZE {
(!S::ZERO << self.unsigned.bits)..=((S::ONE << self.unsigned.bits) - S::ONE)
} else {
S::Unsigned::ZERO.as_negative(S::BITS_SIZE)..=(S::Unsigned::ALL >> 1).as_non_negative()
}
}
}
impl<const MAX: u32> core::fmt::Display for SignedBitCount<MAX> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
core::fmt::Display::fmt(&self.bits, f)
}
}
impl<const MAX: u32> core::convert::TryFrom<BitCount<MAX>> for SignedBitCount<MAX> {
type Error = ();
#[inline]
fn try_from(count: BitCount<MAX>) -> Result<Self, Self::Error> {
count.signed_count().ok_or(())
}
}
impl<const MAX: u32> core::convert::TryFrom<u32> for SignedBitCount<MAX> {
type Error = u32;
#[inline]
fn try_from(count: u32) -> Result<Self, Self::Error> {
BitCount::<MAX>::try_from(count).and_then(|b| b.signed_count().ok_or(count))
}
}
impl<const MAX: u32> From<SignedBitCount<MAX>> for u32 {
#[inline(always)]
fn from(
SignedBitCount {
bits: BitCount { bits },
..
}: SignedBitCount<MAX>,
) -> u32 {
bits
}
}
#[derive(Copy, Clone, Debug)]
pub enum CheckedError {
ExcessiveBits,
ExcessiveValue,
}
impl core::error::Error for CheckedError {}
impl core::fmt::Display for CheckedError {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
match self {
Self::ExcessiveBits => core::fmt::Display::fmt("excessive bits for type written", f),
Self::ExcessiveValue => core::fmt::Display::fmt("excessive value for bits written", f),
}
}
}
impl From<CheckedError> for io::Error {
#[inline]
fn from(error: CheckedError) -> Self {
match error {
CheckedError::ExcessiveBits => io::Error::new(
io::ErrorKind::InvalidInput,
"excessive bits for type written",
),
CheckedError::ExcessiveValue => io::Error::new(
io::ErrorKind::InvalidInput,
"excessive value for bits written",
),
}
}
}
#[derive(Copy, Clone, Debug)]
pub struct Checked<C, T> {
count: C,
value: T,
}
impl<C, T> Checked<C, T> {
#[inline]
pub fn into_count_value(self) -> (C, T) {
(self.count, self.value)
}
#[inline]
pub fn into_value(self) -> T {
self.value
}
}
impl<C, T> AsRef<T> for Checked<C, T> {
fn as_ref(&self) -> &T {
&self.value
}
}
pub type CheckedUnsigned<const MAX: u32, T> = Checked<BitCount<MAX>, T>;
impl<const MAX: u32, U: UnsignedInteger> Checkable for CheckedUnsigned<MAX, U> {
#[inline]
fn write<W: BitWrite + ?Sized>(&self, writer: &mut W) -> io::Result<()> {
writer.write_unsigned_counted(self.count, self.value)
}
#[inline]
fn written_bits(&self) -> u32 {
self.count.bits
}
}
impl<const MAX: u32, U: UnsignedInteger> CheckablePrimitive for CheckedUnsigned<MAX, U> {
type CountType = BitCount<MAX>;
#[inline]
fn read<R: BitRead + ?Sized>(reader: &mut R, count: Self::CountType) -> io::Result<Self> {
reader
.read_unsigned_counted(count)
.map(|value| Self { value, count })
}
}
impl<const MAX: u32, U: UnsignedInteger> private::Checkable for CheckedUnsigned<MAX, U> {
fn write_endian<E, W>(
self,
writer: &mut W,
queue_value: &mut u8,
queue_bits: &mut u32,
) -> io::Result<()>
where
E: private::Endianness,
W: io::Write,
{
E::write_bits_checked(writer, queue_value, queue_bits, self)
}
}
impl<const MAX: u32, U: UnsignedInteger> CheckedUnsigned<MAX, U> {
#[inline]
pub fn new(count: impl TryInto<BitCount<MAX>>, value: U) -> Result<Self, CheckedError> {
let count @ BitCount { bits } =
count.try_into().map_err(|_| CheckedError::ExcessiveBits)?;
if MAX <= U::BITS_SIZE || bits <= U::BITS_SIZE {
if bits == 0 {
Ok(Self {
count,
value: U::ZERO,
})
} else if value <= U::ALL >> (U::BITS_SIZE - bits) {
Ok(Self { count, value })
} else {
Err(CheckedError::ExcessiveValue)
}
} else {
Err(CheckedError::ExcessiveBits)
}
}
pub fn new_fixed<const BITS: u32>(value: U) -> Result<Self, CheckedError> {
const {
assert!(BITS <= U::BITS_SIZE, "excessive bits for type written");
}
if BITS == 0 {
Ok(Self {
count: BitCount::new::<0>(),
value: U::ZERO,
})
} else if BITS == U::BITS_SIZE || value <= (U::ALL >> (U::BITS_SIZE - BITS)) {
Ok(Self {
count: BitCount::new::<BITS>(),
value,
})
} else {
Err(CheckedError::ExcessiveValue)
}
}
}
#[derive(Copy, Clone, Debug)]
pub struct FixedBitCount<const BITS: u32>;
impl<const BITS: u32> From<FixedBitCount<BITS>> for BitCount<BITS> {
fn from(_count: FixedBitCount<BITS>) -> Self {
BitCount::new::<BITS>()
}
}
impl<const BITS: u32, const MAX: u32> core::convert::TryFrom<BitCount<MAX>>
for FixedBitCount<BITS>
{
type Error = BitCount<MAX>;
fn try_from(count: BitCount<MAX>) -> Result<Self, Self::Error> {
(count.bits == BITS).then_some(FixedBitCount).ok_or(count)
}
}
pub type CheckedUnsignedFixed<const BITS: u32, T> = Checked<FixedBitCount<BITS>, T>;
impl<const BITS: u32, U: UnsignedInteger> CheckedUnsignedFixed<BITS, U> {
pub fn new_fixed(value: U) -> Result<Self, CheckedError> {
const {
assert!(BITS <= U::BITS_SIZE, "excessive bits for type written");
}
if BITS == 0 {
Ok(Self {
count: FixedBitCount,
value: U::ZERO,
})
} else if BITS == U::BITS_SIZE || value <= (U::ALL >> (U::BITS_SIZE - BITS)) {
Ok(Self {
count: FixedBitCount,
value,
})
} else {
Err(CheckedError::ExcessiveValue)
}
}
}
impl<const BITS: u32, U: UnsignedInteger> Checkable for CheckedUnsignedFixed<BITS, U> {
#[inline]
fn write<W: BitWrite + ?Sized>(&self, writer: &mut W) -> io::Result<()> {
writer.write_unsigned::<BITS, _>(self.value)
}
#[inline]
fn written_bits(&self) -> u32 {
BITS
}
}
impl<const BITS: u32, U: UnsignedInteger> private::Checkable for CheckedUnsignedFixed<BITS, U> {
fn write_endian<E, W>(
self,
writer: &mut W,
queue_value: &mut u8,
queue_bits: &mut u32,
) -> io::Result<()>
where
E: private::Endianness,
W: io::Write,
{
E::write_bits_checked(
writer,
queue_value,
queue_bits,
Checked {
value: self.value,
count: self.count.into(),
},
)
}
}
impl<const BITS: u32, U: UnsignedInteger> CheckablePrimitive for CheckedUnsignedFixed<BITS, U> {
type CountType = FixedBitCount<BITS>;
fn read<R: BitRead + ?Sized>(reader: &mut R, count: FixedBitCount<BITS>) -> io::Result<Self> {
Ok(Self {
value: reader.read_unsigned::<BITS, _>()?,
count,
})
}
}
pub type CheckedSigned<const MAX: u32, T> = Checked<SignedBitCount<MAX>, T>;
impl<const MAX: u32, S: SignedInteger> Checkable for CheckedSigned<MAX, S> {
#[inline]
fn write<W: BitWrite + ?Sized>(&self, writer: &mut W) -> io::Result<()> {
writer.write_signed_counted(self.count, self.value)
}
#[inline]
fn written_bits(&self) -> u32 {
self.count.bits.into()
}
}
impl<const MAX: u32, S: SignedInteger> CheckablePrimitive for CheckedSigned<MAX, S> {
type CountType = SignedBitCount<MAX>;
#[inline]
fn read<R: BitRead + ?Sized>(reader: &mut R, count: Self::CountType) -> io::Result<Self> {
reader
.read_signed_counted(count)
.map(|value| Self { value, count })
}
}
impl<const MAX: u32, S: SignedInteger> private::Checkable for CheckedSigned<MAX, S> {
#[inline]
fn write_endian<E, W>(
self,
writer: &mut W,
queue_value: &mut u8,
queue_bits: &mut u32,
) -> io::Result<()>
where
E: private::Endianness,
W: io::Write,
{
E::write_signed_bits_checked(writer, queue_value, queue_bits, self)
}
}
impl<const MAX: u32, S: SignedInteger> CheckedSigned<MAX, S> {
#[inline]
pub fn new(count: impl TryInto<SignedBitCount<MAX>>, value: S) -> Result<Self, CheckedError> {
let count @ SignedBitCount {
bits: BitCount { bits },
unsigned: BitCount {
bits: unsigned_bits,
},
} = count.try_into().map_err(|_| CheckedError::ExcessiveBits)?;
if MAX <= S::BITS_SIZE || bits <= S::BITS_SIZE {
if bits == S::BITS_SIZE
|| (((S::ZERO - S::ONE) << unsigned_bits) <= value
&& value < (S::ONE << unsigned_bits))
{
Ok(Self { count, value })
} else {
Err(CheckedError::ExcessiveValue)
}
} else {
Err(CheckedError::ExcessiveBits)
}
}
pub fn new_fixed<const BITS: u32>(value: S) -> Result<Self, CheckedError> {
const {
assert!(BITS <= S::BITS_SIZE, "excessive bits for type written");
}
if BITS == S::BITS_SIZE
|| (((S::ZERO - S::ONE) << (BITS - 1)) <= value && value < (S::ONE << (BITS - 1)))
{
Ok(Self {
count: SignedBitCount::new::<BITS>(),
value,
})
} else {
Err(CheckedError::ExcessiveValue)
}
}
}
#[derive(Copy, Clone, Debug)]
pub struct FixedSignedBitCount<const BITS: u32>;
impl<const BITS: u32> From<FixedSignedBitCount<BITS>> for SignedBitCount<BITS> {
fn from(_count: FixedSignedBitCount<BITS>) -> Self {
SignedBitCount::new::<BITS>()
}
}
impl<const BITS: u32, const MAX: u32> core::convert::TryFrom<SignedBitCount<MAX>>
for FixedSignedBitCount<BITS>
{
type Error = SignedBitCount<MAX>;
fn try_from(count: SignedBitCount<MAX>) -> Result<Self, Self::Error> {
(count.bits.bits == BITS)
.then_some(FixedSignedBitCount)
.ok_or(count)
}
}
pub type CheckedSignedFixed<const BITS: u32, T> = Checked<FixedSignedBitCount<BITS>, T>;
impl<const BITS: u32, S: SignedInteger> CheckedSignedFixed<BITS, S> {
pub fn new_fixed(value: S) -> Result<Self, CheckedError> {
const {
assert!(BITS <= S::BITS_SIZE, "excessive bits for type written");
}
if BITS == S::BITS_SIZE
|| (((S::ZERO - S::ONE) << (BITS - 1)) <= value && value < (S::ONE << (BITS - 1)))
{
Ok(Self {
count: FixedSignedBitCount,
value,
})
} else {
Err(CheckedError::ExcessiveValue)
}
}
}
impl<const BITS: u32, S: SignedInteger> Checkable for CheckedSignedFixed<BITS, S> {
#[inline]
fn write<W: BitWrite + ?Sized>(&self, writer: &mut W) -> io::Result<()> {
writer.write_signed::<BITS, _>(self.value)
}
#[inline]
fn written_bits(&self) -> u32 {
BITS
}
}
impl<const BITS: u32, S: SignedInteger> private::Checkable for CheckedSignedFixed<BITS, S> {
#[inline]
fn write_endian<E, W>(
self,
writer: &mut W,
queue_value: &mut u8,
queue_bits: &mut u32,
) -> io::Result<()>
where
E: private::Endianness,
W: io::Write,
{
E::write_signed_bits_checked(
writer,
queue_value,
queue_bits,
CheckedSigned {
value: self.value,
count: self.count.into(),
},
)
}
}
impl<const BITS: u32, S: SignedInteger> CheckablePrimitive for CheckedSignedFixed<BITS, S> {
type CountType = FixedSignedBitCount<BITS>;
fn read<R: BitRead + ?Sized>(
reader: &mut R,
count: FixedSignedBitCount<BITS>,
) -> io::Result<Self> {
Ok(Self {
value: reader.read_signed::<BITS, _>()?,
count,
})
}
}
pub trait Checkable: private::Checkable + Sized {
fn write<W: BitWrite + ?Sized>(&self, writer: &mut W) -> io::Result<()>;
fn written_bits(&self) -> u32;
}
pub trait CheckablePrimitive: Checkable {
type CountType;
fn read<R: BitRead + ?Sized>(reader: &mut R, count: Self::CountType) -> io::Result<Self>;
}
#[derive(Copy, Clone, Debug)]
pub struct BigEndian;
pub type BE = BigEndian;
impl BigEndian {
#[inline]
fn read_bits_checked<const MAX: u32, R, U>(
reader: &mut R,
queue: &mut u8,
queue_bits: &mut u32,
BitCount { bits }: BitCount<MAX>,
) -> io::Result<U>
where
R: io::Read,
U: UnsignedInteger,
{
#[inline(always)]
fn read_bytes<R, U>(reader: &mut R, bytes: usize) -> io::Result<U>
where
R: io::Read,
U: UnsignedInteger,
{
let mut buf = U::buffer();
reader
.read_exact(&mut buf.as_mut()[(mem::size_of::<U>() - bytes)..])
.map(|()| U::from_be_bytes(buf))
}
if bits <= *queue_bits {
let value = queue.shr_default(u8::BITS_SIZE - bits);
*queue = queue.shl_default(bits);
*queue_bits -= bits;
Ok(U::from_u8(value))
} else {
let needed_bits = bits - *queue_bits;
match (needed_bits / 8, needed_bits % 8) {
(0, needed) => {
let next_byte = read_byte(reader)?;
Ok(U::from_u8(
mem::replace(queue, next_byte.shl_default(needed)).shr_default(
u8::BITS_SIZE - mem::replace(queue_bits, u8::BITS_SIZE - needed),
),
)
.shl_default(needed)
| U::from_u8(next_byte.shr_default(u8::BITS_SIZE - needed)))
}
(bytes, 0) => {
Ok(U::from_u8(
mem::take(queue).shr_default(u8::BITS_SIZE - mem::take(queue_bits)),
)
.shl_default(needed_bits)
| read_bytes(reader, bytes as usize)?)
}
(bytes, needed) => {
let whole: U = read_bytes(reader, bytes as usize)?;
let next_byte = read_byte(reader)?;
Ok(U::from_u8(
mem::replace(queue, next_byte.shl_default(needed)).shr_default(
u8::BITS_SIZE - mem::replace(queue_bits, u8::BITS_SIZE - needed),
),
)
.shl_default(needed_bits)
| whole.shl_default(needed)
| U::from_u8(next_byte.shr_default(u8::BITS_SIZE - needed)))
}
}
}
}
}
impl Endianness for BigEndian {}
impl private::Endianness for BigEndian {
#[inline]
fn push_bit_flush(queue_value: &mut u8, queue_bits: &mut u32, bit: bool) -> Option<u8> {
*queue_value = (*queue_value << 1) | u8::from(bit);
*queue_bits = (*queue_bits + 1) % 8;
(*queue_bits == 0).then(|| mem::take(queue_value))
}
#[inline]
fn read_bits<const MAX: u32, R, U>(
reader: &mut R,
queue_value: &mut u8,
queue_bits: &mut u32,
count @ BitCount { bits }: BitCount<MAX>,
) -> io::Result<U>
where
R: io::Read,
U: UnsignedInteger,
{
if MAX <= U::BITS_SIZE || bits <= U::BITS_SIZE {
Self::read_bits_checked::<MAX, R, U>(reader, queue_value, queue_bits, count)
} else {
Err(io::Error::new(
io::ErrorKind::InvalidInput,
"excessive bits for type read",
))
}
}
#[inline]
fn read_bits_fixed<const BITS: u32, R, U>(
reader: &mut R,
queue_value: &mut u8,
queue_bits: &mut u32,
) -> io::Result<U>
where
R: io::Read,
U: UnsignedInteger,
{
const {
assert!(BITS <= U::BITS_SIZE, "excessive bits for type read");
}
Self::read_bits_checked::<BITS, R, U>(
reader,
queue_value,
queue_bits,
BitCount::new::<BITS>(),
)
}
#[inline]
fn write_bits_checked<const MAX: u32, W, U>(
writer: &mut W,
queue_value: &mut u8,
queue_bits: &mut u32,
CheckedUnsigned {
count: BitCount { bits },
value,
}: CheckedUnsigned<MAX, U>,
) -> io::Result<()>
where
W: io::Write,
U: UnsignedInteger,
{
fn write_bytes<W, U>(writer: &mut W, bytes: usize, value: U) -> io::Result<()>
where
W: io::Write,
U: UnsignedInteger,
{
let buf = U::to_be_bytes(value);
writer.write_all(&buf.as_ref()[(mem::size_of::<U>() - bytes)..])
}
let available_bits = u8::BITS_SIZE - *queue_bits;
if bits < available_bits {
*queue_value = queue_value.shl_default(bits) | U::to_u8(value);
*queue_bits += bits;
Ok(())
} else {
let excess_bits = bits - available_bits;
match (excess_bits / 8, excess_bits % 8) {
(0, excess) => {
*queue_bits = excess;
write_byte(
writer,
mem::replace(
queue_value,
U::to_u8(value & U::ALL.shr_default(U::BITS_SIZE - excess)),
)
.shl_default(available_bits)
| U::to_u8(value.shr_default(excess)),
)
}
(bytes, 0) => {
*queue_bits = 0;
write_byte(
writer.by_ref(),
mem::take(queue_value).shl_default(available_bits)
| U::to_u8(value.shr_default(bytes * 8)),
)?;
write_bytes(writer, bytes as usize, value)
}
(bytes, excess) => {
*queue_bits = excess;
write_byte(
writer.by_ref(),
mem::replace(
queue_value,
U::to_u8(value & U::ALL.shr_default(U::BITS_SIZE - excess)),
)
.shl_default(available_bits)
| U::to_u8(value.shr_default(excess + bytes * 8)),
)?;
write_bytes(writer, bytes as usize, value.shr_default(excess))
}
}
}
}
fn write_signed_bits_checked<const MAX: u32, W, S>(
writer: &mut W,
queue_value: &mut u8,
queue_bits: &mut u32,
value: CheckedSigned<MAX, S>,
) -> io::Result<()>
where
W: io::Write,
S: SignedInteger,
{
let (
SignedBitCount {
bits: BitCount { bits },
unsigned,
},
value,
) = value.into_count_value();
if let Some(b) = Self::push_bit_flush(queue_value, queue_bits, value.is_negative()) {
write_byte(writer.by_ref(), b)?;
}
Self::write_bits_checked(
writer,
queue_value,
queue_bits,
Checked {
value: if value.is_negative() {
value.as_negative(bits)
} else {
value.as_non_negative()
},
count: unsigned,
},
)
}
#[inline]
fn pop_bit_refill<R>(
reader: &mut R,
queue_value: &mut u8,
queue_bits: &mut u32,
) -> io::Result<bool>
where
R: io::Read,
{
Ok(if *queue_bits == 0 {
let value = read_byte(reader)?;
let msb = value & u8::MSB_BIT;
*queue_value = value << 1;
*queue_bits = u8::BITS_SIZE - 1;
msb
} else {
let msb = *queue_value & u8::MSB_BIT;
*queue_value <<= 1;
*queue_bits -= 1;
msb
} != 0)
}
#[inline]
fn pop_unary<const STOP_BIT: u8, R>(
reader: &mut R,
queue_value: &mut u8,
queue_bits: &mut u32,
) -> io::Result<u32>
where
R: io::Read,
{
const {
assert!(matches!(STOP_BIT, 0 | 1), "stop bit must be 0 or 1");
}
match STOP_BIT {
0 => find_unary(
reader,
queue_value,
queue_bits,
|v| v.leading_ones(),
|q| *q,
|v, b| v.checked_shl(b),
),
1 => find_unary(
reader,
queue_value,
queue_bits,
|v| v.leading_zeros(),
|_| u8::BITS_SIZE,
|v, b| v.checked_shl(b),
),
_ => unreachable!(),
}
}
#[inline]
fn read_signed_counted<const MAX: u32, R, S>(
r: &mut R,
SignedBitCount {
bits: BitCount { bits },
unsigned,
}: SignedBitCount<MAX>,
) -> io::Result<S>
where
R: BitRead,
S: SignedInteger,
{
if MAX <= S::BITS_SIZE || bits <= S::BITS_SIZE {
let is_negative = r.read_bit()?;
let unsigned = r.read_unsigned_counted::<MAX, S::Unsigned>(unsigned)?;
Ok(if is_negative {
unsigned.as_negative(bits)
} else {
unsigned.as_non_negative()
})
} else {
Err(io::Error::new(
io::ErrorKind::InvalidInput,
"excessive bits for type read",
))
}
}
fn read_bytes<const CHUNK_SIZE: usize, R>(
reader: &mut R,
queue_value: &mut u8,
queue_bits: u32,
buf: &mut [u8],
) -> io::Result<()>
where
R: io::Read,
{
if queue_bits == 0 {
reader.read_exact(buf)
} else {
let mut input_chunk: [u8; CHUNK_SIZE] = [0; CHUNK_SIZE];
for output_chunk in buf.chunks_mut(CHUNK_SIZE) {
let input_chunk = &mut input_chunk[0..output_chunk.len()];
reader.read_exact(input_chunk)?;
output_chunk
.iter_mut()
.zip(input_chunk.iter())
.for_each(|(o, i)| {
*o = i >> queue_bits;
});
output_chunk[1..]
.iter_mut()
.zip(input_chunk.iter())
.for_each(|(o, i)| {
*o |= *i << (u8::BITS_SIZE - queue_bits);
});
output_chunk[0] |= mem::replace(
queue_value,
input_chunk.last().unwrap() << (u8::BITS_SIZE - queue_bits),
);
}
Ok(())
}
}
fn write_bytes<const CHUNK_SIZE: usize, W>(
writer: &mut W,
queue_value: &mut u8,
queue_bits: u32,
buf: &[u8],
) -> io::Result<()>
where
W: io::Write,
{
if queue_bits == 0 {
writer.write_all(buf)
} else {
let mut output_chunk: [u8; CHUNK_SIZE] = [0; CHUNK_SIZE];
for input_chunk in buf.chunks(CHUNK_SIZE) {
let output_chunk = &mut output_chunk[0..input_chunk.len()];
output_chunk
.iter_mut()
.zip(input_chunk.iter())
.for_each(|(o, i)| {
*o = i >> queue_bits;
});
output_chunk[1..]
.iter_mut()
.zip(input_chunk.iter())
.for_each(|(o, i)| {
*o |= *i << (u8::BITS_SIZE - queue_bits);
});
output_chunk[0] |= mem::replace(
queue_value,
input_chunk.last().unwrap() & (u8::ALL >> (u8::BITS_SIZE - queue_bits)),
) << (u8::BITS_SIZE - queue_bits);
writer.write_all(output_chunk)?;
}
Ok(())
}
}
#[inline(always)]
fn bytes_to_primitive<P: Primitive>(buf: P::Bytes) -> P {
P::from_be_bytes(buf)
}
#[inline(always)]
fn primitive_to_bytes<P: Primitive>(p: P) -> P::Bytes {
p.to_be_bytes()
}
#[inline]
fn read_primitive<R, V>(r: &mut R) -> io::Result<V>
where
R: BitRead,
V: Primitive,
{
let mut buffer = V::buffer();
r.read_bytes(buffer.as_mut())?;
Ok(V::from_be_bytes(buffer))
}
#[inline]
fn write_primitive<W, V>(w: &mut W, value: V) -> io::Result<()>
where
W: BitWrite,
V: Primitive,
{
w.write_bytes(value.to_be_bytes().as_ref())
}
}
#[derive(Copy, Clone, Debug)]
pub struct LittleEndian;
pub type LE = LittleEndian;
impl LittleEndian {
#[inline]
fn read_bits_checked<const MAX: u32, R, U>(
reader: &mut R,
queue: &mut u8,
queue_bits: &mut u32,
BitCount { bits }: BitCount<MAX>,
) -> io::Result<U>
where
R: io::Read,
U: UnsignedInteger,
{
#[inline(always)]
fn read_bytes<R, U>(reader: &mut R, bytes: usize) -> io::Result<U>
where
R: io::Read,
U: UnsignedInteger,
{
let mut buf = U::buffer();
reader
.read_exact(&mut buf.as_mut()[0..bytes])
.map(|()| U::from_le_bytes(buf))
}
if bits <= *queue_bits {
let value = *queue & u8::ALL.shr_default(u8::BITS_SIZE - bits);
*queue = queue.shr_default(bits);
*queue_bits -= bits;
Ok(U::from_u8(value))
} else {
let needed_bits = bits - *queue_bits;
match (needed_bits / 8, needed_bits % 8) {
(0, needed) => {
let next_byte = read_byte(reader)?;
Ok(
U::from_u8(mem::replace(queue, next_byte.shr_default(needed)))
| (U::from_u8(next_byte & (u8::ALL >> (u8::BITS_SIZE - needed)))
<< mem::replace(queue_bits, u8::BITS_SIZE - needed)),
)
}
(bytes, 0) => {
Ok(U::from_u8(mem::take(queue))
| (read_bytes::<R, U>(reader, bytes as usize)? << mem::take(queue_bits)))
}
(bytes, needed) => {
let whole: U = read_bytes(reader, bytes as usize)?;
let next_byte = read_byte(reader)?;
Ok(
U::from_u8(mem::replace(queue, next_byte.shr_default(needed)))
| (whole << *queue_bits)
| (U::from_u8(next_byte & (u8::ALL >> (u8::BITS_SIZE - needed)))
<< (mem::replace(queue_bits, u8::BITS_SIZE - needed) + bytes * 8)),
)
}
}
}
}
}
impl Endianness for LittleEndian {}
impl private::Endianness for LittleEndian {
#[inline]
fn push_bit_flush(queue_value: &mut u8, queue_bits: &mut u32, bit: bool) -> Option<u8> {
*queue_value |= u8::from(bit) << *queue_bits;
*queue_bits = (*queue_bits + 1) % 8;
(*queue_bits == 0).then(|| mem::take(queue_value))
}
#[inline]
fn read_bits<const MAX: u32, R, U>(
reader: &mut R,
queue_value: &mut u8,
queue_bits: &mut u32,
count @ BitCount { bits }: BitCount<MAX>,
) -> io::Result<U>
where
R: io::Read,
U: UnsignedInteger,
{
if MAX <= U::BITS_SIZE || bits <= U::BITS_SIZE {
Self::read_bits_checked::<MAX, R, U>(reader, queue_value, queue_bits, count)
} else {
Err(io::Error::new(
io::ErrorKind::InvalidInput,
"excessive bits for type read",
))
}
}
#[inline]
fn read_bits_fixed<const BITS: u32, R, U>(
reader: &mut R,
queue_value: &mut u8,
queue_bits: &mut u32,
) -> io::Result<U>
where
R: io::Read,
U: UnsignedInteger,
{
const {
assert!(BITS <= U::BITS_SIZE, "excessive bits for type read");
}
Self::read_bits_checked::<BITS, R, U>(
reader,
queue_value,
queue_bits,
BitCount::new::<BITS>(),
)
}
#[inline]
fn write_bits_checked<const MAX: u32, W, U>(
writer: &mut W,
queue_value: &mut u8,
queue_bits: &mut u32,
CheckedUnsigned {
count: BitCount { bits },
value,
}: CheckedUnsigned<MAX, U>,
) -> io::Result<()>
where
W: io::Write,
U: UnsignedInteger,
{
fn write_bytes<W, U>(writer: &mut W, bytes: usize, value: U) -> io::Result<()>
where
W: io::Write,
U: UnsignedInteger,
{
let buf = U::to_le_bytes(value);
writer.write_all(&buf.as_ref()[0..bytes])
}
let available_bits = u8::BITS_SIZE - *queue_bits;
if bits < available_bits {
*queue_value |= U::to_u8(value.shl_default(*queue_bits));
*queue_bits += bits;
Ok(())
} else {
let excess_bits = bits - available_bits;
match (excess_bits / 8, excess_bits % 8) {
(0, excess) => {
write_byte(
writer,
mem::replace(queue_value, U::to_u8(value.shr_default(available_bits)))
| U::to_u8(
(value << mem::replace(queue_bits, excess)) & U::from_u8(u8::ALL),
),
)
}
(bytes, 0) => {
write_byte(
writer.by_ref(),
mem::take(queue_value)
| U::to_u8((value << mem::take(queue_bits)) & U::from_u8(u8::ALL)),
)?;
write_bytes(writer, bytes as usize, value >> available_bits)
}
(bytes, excess) => {
write_byte(
writer.by_ref(),
mem::replace(
queue_value,
U::to_u8(value.shr_default(available_bits + bytes * 8)),
) | U::to_u8(
(value << mem::replace(queue_bits, excess)) & U::from_u8(u8::ALL),
),
)?;
write_bytes(writer, bytes as usize, value >> available_bits)
}
}
}
}
fn write_signed_bits_checked<const MAX: u32, W, S>(
writer: &mut W,
queue_value: &mut u8,
queue_bits: &mut u32,
value: CheckedSigned<MAX, S>,
) -> io::Result<()>
where
W: io::Write,
S: SignedInteger,
{
let (
SignedBitCount {
bits: BitCount { bits },
unsigned,
},
value,
) = value.into_count_value();
Self::write_bits_checked(
writer.by_ref(),
queue_value,
queue_bits,
Checked {
value: if value.is_negative() {
value.as_negative(bits)
} else {
value.as_non_negative()
},
count: unsigned,
},
)?;
match Self::push_bit_flush(queue_value, queue_bits, value.is_negative()) {
Some(b) => write_byte(writer, b),
None => Ok(()),
}
}
#[inline]
fn pop_bit_refill<R>(
reader: &mut R,
queue_value: &mut u8,
queue_bits: &mut u32,
) -> io::Result<bool>
where
R: io::Read,
{
Ok(if *queue_bits == 0 {
let value = read_byte(reader)?;
let lsb = value & u8::LSB_BIT;
*queue_value = value >> 1;
*queue_bits = u8::BITS_SIZE - 1;
lsb
} else {
let lsb = *queue_value & u8::LSB_BIT;
*queue_value >>= 1;
*queue_bits -= 1;
lsb
} != 0)
}
#[inline]
fn pop_unary<const STOP_BIT: u8, R>(
reader: &mut R,
queue_value: &mut u8,
queue_bits: &mut u32,
) -> io::Result<u32>
where
R: io::Read,
{
const {
assert!(matches!(STOP_BIT, 0 | 1), "stop bit must be 0 or 1");
}
match STOP_BIT {
0 => find_unary(
reader,
queue_value,
queue_bits,
|v| v.trailing_ones(),
|q| *q,
|v, b| v.checked_shr(b),
),
1 => find_unary(
reader,
queue_value,
queue_bits,
|v| v.trailing_zeros(),
|_| u8::BITS_SIZE,
|v, b| v.checked_shr(b),
),
_ => unreachable!(),
}
}
#[inline]
fn read_signed_counted<const MAX: u32, R, S>(
r: &mut R,
SignedBitCount {
bits: BitCount { bits },
unsigned,
}: SignedBitCount<MAX>,
) -> io::Result<S>
where
R: BitRead,
S: SignedInteger,
{
if MAX <= S::BITS_SIZE || bits <= S::BITS_SIZE {
let unsigned = r.read_unsigned_counted::<MAX, S::Unsigned>(unsigned)?;
let is_negative = r.read_bit()?;
Ok(if is_negative {
unsigned.as_negative(bits)
} else {
unsigned.as_non_negative()
})
} else {
Err(io::Error::new(
io::ErrorKind::InvalidInput,
"excessive bits for type read",
))
}
}
fn read_bytes<const CHUNK_SIZE: usize, R>(
reader: &mut R,
queue_value: &mut u8,
queue_bits: u32,
buf: &mut [u8],
) -> io::Result<()>
where
R: io::Read,
{
if queue_bits == 0 {
reader.read_exact(buf)
} else {
let mut input_chunk: [u8; CHUNK_SIZE] = [0; CHUNK_SIZE];
for output_chunk in buf.chunks_mut(CHUNK_SIZE) {
let input_chunk = &mut input_chunk[0..output_chunk.len()];
reader.read_exact(input_chunk)?;
output_chunk
.iter_mut()
.zip(input_chunk.iter())
.for_each(|(o, i)| {
*o = i << queue_bits;
});
output_chunk[1..]
.iter_mut()
.zip(input_chunk.iter())
.for_each(|(o, i)| {
*o |= i >> (u8::BITS_SIZE - queue_bits);
});
output_chunk[0] |= mem::replace(
queue_value,
input_chunk.last().unwrap() >> (u8::BITS_SIZE - queue_bits),
);
}
Ok(())
}
}
fn write_bytes<const CHUNK_SIZE: usize, W>(
writer: &mut W,
queue_value: &mut u8,
queue_bits: u32,
buf: &[u8],
) -> io::Result<()>
where
W: io::Write,
{
if queue_bits == 0 {
writer.write_all(buf)
} else {
let mut output_chunk: [u8; CHUNK_SIZE] = [0; CHUNK_SIZE];
for input_chunk in buf.chunks(CHUNK_SIZE) {
let output_chunk = &mut output_chunk[0..input_chunk.len()];
output_chunk
.iter_mut()
.zip(input_chunk.iter())
.for_each(|(o, i)| {
*o = i << queue_bits;
});
output_chunk[1..]
.iter_mut()
.zip(input_chunk.iter())
.for_each(|(o, i)| {
*o |= i >> (u8::BITS_SIZE - queue_bits);
});
output_chunk[0] |= mem::replace(
queue_value,
input_chunk.last().unwrap() >> (u8::BITS_SIZE - queue_bits),
);
writer.write_all(output_chunk)?;
}
Ok(())
}
}
#[inline(always)]
fn bytes_to_primitive<P: Primitive>(buf: P::Bytes) -> P {
P::from_le_bytes(buf)
}
#[inline(always)]
fn primitive_to_bytes<P: Primitive>(p: P) -> P::Bytes {
p.to_le_bytes()
}
#[inline]
fn read_primitive<R, V>(r: &mut R) -> io::Result<V>
where
R: BitRead,
V: Primitive,
{
let mut buffer = V::buffer();
r.read_bytes(buffer.as_mut())?;
Ok(V::from_le_bytes(buffer))
}
#[inline]
fn write_primitive<W, V>(w: &mut W, value: V) -> io::Result<()>
where
W: BitWrite,
V: Primitive,
{
w.write_bytes(value.to_le_bytes().as_ref())
}
}
#[inline]
fn find_unary<R>(
reader: &mut R,
queue_value: &mut u8,
queue_bits: &mut u32,
leading_bits: impl Fn(u8) -> u32,
max_bits: impl Fn(&mut u32) -> u32,
checked_shift: impl Fn(u8, u32) -> Option<u8>,
) -> io::Result<u32>
where
R: io::Read,
{
let mut acc = 0;
loop {
match leading_bits(*queue_value) {
bits if bits == max_bits(queue_bits) => {
acc += *queue_bits;
*queue_value = read_byte(reader.by_ref())?;
*queue_bits = u8::BITS_SIZE;
}
bits => match checked_shift(*queue_value, bits + 1) {
Some(value) => {
*queue_value = value;
*queue_bits -= bits + 1;
break Ok(acc + bits);
}
None => {
*queue_value = 0;
*queue_bits = 0;
break Ok(acc + bits);
}
},
}
}
}