Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
131 changes: 131 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,16 @@ pub trait Integer {
R: BitRead + ?Sized,
Self: Sized;

/// Reads a valur of ourself from the stream using a variable width integer.
///
/// # Errors
///
/// Passes along any I/O error from the underlying stream.
fn read_vbr<const FIELD_SIZE: u32, R>(reader: &mut R) -> io::Result<Self>
where
R: BitRead + ?Sized,
Self: Sized;

/// Writes ourself to the stream using the given const number of bits.
///
/// # Errors
Expand All @@ -319,6 +329,16 @@ pub trait Integer {
writer: &mut W,
bits: BitCount<MAX>,
) -> io::Result<()>;

/// Writes ourself to the stream using a variable width integer.
///
/// # Errors
///
/// Passes along any I/O error from the underlying stream.
fn write_vbr<const FIELD_SIZE: u32, W: BitWrite + ?Sized>(
self,
writer: &mut W,
) -> io::Result<()>;
}

/// Reading and writing booleans as `Integer` requires the number of bits to be 1.
Expand Down Expand Up @@ -376,6 +396,15 @@ impl Integer for bool {
}
}

#[inline(always)]
fn read_vbr<const FIELD_SIZE: u32, R>(_reader: &mut R) -> io::Result<Self>
where
R: BitRead + ?Sized,
Self: Sized,
{
unimplemented!("Can't read a VBR boolean")
}

#[inline(always)]
fn write<const BITS: u32, W: BitWrite + ?Sized>(self, writer: &mut W) -> io::Result<()> {
const {
Expand All @@ -399,6 +428,14 @@ impl Integer for bool {
))
}
}

#[inline(always)]
fn write_vbr<const FIELD_SIZE: u32, W: BitWrite + ?Sized>(
self,
_writer: &mut W,
) -> io::Result<()> {
unimplemented!("Can't write a VBR for boolean")
}
}

impl<const SIZE: usize, I: Integer + Copy + Default> Integer for [I; SIZE] {
Expand Down Expand Up @@ -432,6 +469,21 @@ impl<const SIZE: usize, I: Integer + Copy + Default> Integer for [I; SIZE] {

Ok(a)
}
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)
}

#[inline]
fn write<const BITS: u32, W: BitWrite + ?Sized>(self, writer: &mut W) -> io::Result<()> {
Expand All @@ -446,6 +498,13 @@ impl<const SIZE: usize, I: Integer + Copy + Default> Integer for [I; SIZE] {
) -> io::Result<()> {
IntoIterator::into_iter(self).try_for_each(|v| writer.write_counted(count, v))
}

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))
}
}

/// This trait extends many common integer types (both unsigned and signed)
Expand Down Expand Up @@ -642,6 +701,15 @@ macro_rules! define_unsigned_integer {
reader.read_unsigned_counted::<MAX, _>(bits)
}

#[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<const BITS: u32, W: BitWrite + ?Sized>(
self,
Expand All @@ -658,6 +726,14 @@ macro_rules! define_unsigned_integer {
) -> io::Result<()> {
writer.write_unsigned_counted(bits, self)
}

#[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)
}
}

/// Unsigned NonZero types increment their value by 1
Expand Down Expand Up @@ -728,6 +804,16 @@ macro_rules! define_unsigned_integer {
}
}

#[inline]
fn read_vbr<const FIELD_SIZE: u32, R>(reader: &mut R) -> io::Result<Self>
where
R: BitRead + ?Sized,
Self: Sized,
{
<$t as Integer>::read_vbr::<FIELD_SIZE, R>(reader)
.map(|u| NonZero::new(u + 1).unwrap())
}

#[inline]
fn write<const BITS: u32, W: BitWrite + ?Sized>(
self,
Expand Down Expand Up @@ -758,6 +844,14 @@ macro_rules! define_unsigned_integer {
))
}
}

#[inline]
fn write_vbr<const FIELD_SIZE: u32, W: BitWrite + ?Sized>(
self,
writer: &mut W,
) -> io::Result<()> {
<$t as Integer>::write_vbr::<FIELD_SIZE, W>(self.get() - 1, writer)
}
}

impl Integer for Option<NonZero<$t>> {
Expand All @@ -778,6 +872,15 @@ macro_rules! define_unsigned_integer {
<$t as Integer>::read_var::<MAX, R>(reader, count).map(NonZero::new)
}

#[inline(always)]
fn read_vbr<const FIELD_SIZE: u32, R>(reader: &mut R) -> io::Result<Self>
where
R: BitRead + ?Sized,
Self: Sized,
{
<$t as Integer>::read_vbr::<FIELD_SIZE, _>(reader).map(NonZero::new)
}

#[inline]
fn write<const BITS: u32, W: BitWrite + ?Sized>(
self,
Expand All @@ -798,6 +901,17 @@ macro_rules! define_unsigned_integer {
count,
)
}

#[inline]
fn write_vbr<const FIELD_SIZE: u32, W: BitWrite + ?Sized>(
self,
writer: &mut W,
) -> io::Result<()> {
<$t as Integer>::write_vbr::<FIELD_SIZE, W>(
self.map(|n| n.get()).unwrap_or(0),
writer,
)
}
}
};
}
Expand Down Expand Up @@ -896,6 +1010,15 @@ macro_rules! define_signed_integer {
reader.read_signed_counted::<MAX, _>(bits)
}

#[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<const BITS: u32, W: BitWrite + ?Sized>(
self,
Expand All @@ -912,6 +1035,14 @@ macro_rules! define_signed_integer {
) -> io::Result<()> {
writer.write_signed_counted::<MAX, _>(bits, self)
}

#[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)
}
}
};
}
Expand Down
25 changes: 23 additions & 2 deletions src/read.rs
Original file line number Diff line number Diff line change
Expand Up @@ -902,7 +902,7 @@ pub trait BitRead {
T::from_bits(|| self.read_bit())
}

/// Reads a number using a variable using a variable-width integer.
/// Reads a number using a variable using a variable width integer.
/// This optimises the case when the number is small.
///
/// The integer is mapped to an unsigned value using zigzag encoding.
Expand Down Expand Up @@ -961,7 +961,7 @@ pub trait BitRead {
}
}

/// Reads a number using a variable using a variable-width integer.
/// Reads a number using a variable using a variable width integer.
/// This optimises the case when the number is small.
///
/// The integer is mapped to an unsigned value using zigzag encoding.
Expand Down Expand Up @@ -993,6 +993,27 @@ pub trait BitRead {
})
}

/// Reads a signed or unsigned variable width integer from the stream.
///
/// # Errors
///
/// Passes along any I/O error from the underlying stream.
/// Returns an error if the data read would overflow the size of the result
///
/// # Example
/// ```
/// use bitstream_io::{BitReader, BitRead, BigEndian};
///
/// let bytes: &[u8] = &[0b0110_1011, 0b1100_0001];
/// let mut r = BitReader::endian(bytes, BigEndian);
/// assert_eq!(r.read_vbr::<4, u32>().unwrap(), 6);
/// assert_eq!(r.read_vbr::<4, i32>().unwrap(), -50);
/// ```
#[inline]
fn read_vbr<const FIELD_SIZE: u32, I: Integer>(&mut self) -> io::Result<I> {
I::read_vbr::<FIELD_SIZE, _>(self)
}

/// Creates a "by reference" adaptor for this `BitRead`
///
/// The returned adapter also implements `BitRead`
Expand Down
24 changes: 22 additions & 2 deletions src/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -962,7 +962,7 @@ pub trait BitWrite {
T::to_bits(value, |b| self.write_bit(b))
}

/// Writes a number using a variable using a variable-width integer.
/// Writes a number using a variable using a variable width integer.
/// This optimises the case when the number is small.
///
/// Given a 4-bit VBR field, any 3-bit value (0 through 7) is encoded directly, with the high bit set to zero.
Expand Down Expand Up @@ -1004,7 +1004,7 @@ pub trait BitWrite {
Ok(())
}

/// Writes a number using a variable using a variable-width integer.
/// Writes a number using a variable using a variable width integer.
/// This optimises the case when the number is small.
///
/// The integer is mapped to an unsigned value using zigzag encoding.
Expand Down Expand Up @@ -1034,6 +1034,26 @@ pub trait BitWrite {
self.write_unsigned_vbr::<FIELD_SIZE, _>(zig_zag.as_non_negative())
}

/// Writes a signed or unsigned variable width integer to the stream
///
/// # Errors
///
/// Passes along any I/O error from the underlying stream.
///
/// # Example
/// ```
/// use std::io::Write;
/// use bitstream_io::{BigEndian, BitWriter, BitWrite};
/// let mut writer = BitWriter::endian(Vec::new(), BigEndian);
/// writer.write_vbr::<4,_>(6u32);
/// writer.write_vbr::<4,_>(-50i32);
/// assert_eq!(writer.into_writer(), [0b0110_1011, 0b1100_0001]);
/// ```
#[inline]
fn write_vbr<const FIELD_SIZE: u32, I: Integer>(&mut self, value: I) -> io::Result<()> {
I::write_vbr::<FIELD_SIZE, _>(value, self)
}

/// Creates a "by reference" adaptor for this `BitWrite`
///
/// The returned adapter also implements `BitWrite`
Expand Down
Loading