diff --git a/src/lib.rs b/src/lib.rs index 9004d52..27ad95b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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(reader: &mut R) -> io::Result + where + R: BitRead + ?Sized, + Self: Sized; + /// Writes ourself to the stream using the given const number of bits. /// /// # Errors @@ -319,6 +329,16 @@ pub trait Integer { writer: &mut W, bits: BitCount, ) -> 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( + self, + writer: &mut W, + ) -> io::Result<()>; } /// Reading and writing booleans as `Integer` requires the number of bits to be 1. @@ -376,6 +396,15 @@ impl Integer for bool { } } + #[inline(always)] + fn read_vbr(_reader: &mut R) -> io::Result + where + R: BitRead + ?Sized, + Self: Sized, + { + unimplemented!("Can't read a VBR boolean") + } + #[inline(always)] fn write(self, writer: &mut W) -> io::Result<()> { const { @@ -399,6 +428,14 @@ impl Integer for bool { )) } } + + #[inline(always)] + fn write_vbr( + self, + _writer: &mut W, + ) -> io::Result<()> { + unimplemented!("Can't write a VBR for boolean") + } } impl Integer for [I; SIZE] { @@ -432,6 +469,21 @@ impl Integer for [I; SIZE] { Ok(a) } + fn read_vbr(reader: &mut R) -> io::Result + where + R: BitRead + ?Sized, + Self: Sized, + { + let mut a = [I::default(); SIZE]; + + a.iter_mut().try_for_each(|v| { + I::read_vbr::(reader).map(|item| { + *v = item; + }) + })?; + + Ok(a) + } #[inline] fn write(self, writer: &mut W) -> io::Result<()> { @@ -446,6 +498,13 @@ impl Integer for [I; SIZE] { ) -> io::Result<()> { IntoIterator::into_iter(self).try_for_each(|v| writer.write_counted(count, v)) } + + fn write_vbr( + self, + writer: &mut W, + ) -> io::Result<()> { + IntoIterator::into_iter(self).try_for_each(|v| I::write_vbr::(v, writer)) + } } /// This trait extends many common integer types (both unsigned and signed) @@ -642,6 +701,15 @@ macro_rules! define_unsigned_integer { reader.read_unsigned_counted::(bits) } + #[inline(always)] + fn read_vbr(reader: &mut R) -> io::Result + where + R: BitRead + ?Sized, + Self: Sized, + { + reader.read_unsigned_vbr::() + } + #[inline(always)] fn write( self, @@ -658,6 +726,14 @@ macro_rules! define_unsigned_integer { ) -> io::Result<()> { writer.write_unsigned_counted(bits, self) } + + #[inline(always)] + fn write_vbr( + self, + writer: &mut W, + ) -> io::Result<()> { + writer.write_unsigned_vbr::(self) + } } /// Unsigned NonZero types increment their value by 1 @@ -728,6 +804,16 @@ macro_rules! define_unsigned_integer { } } + #[inline] + fn read_vbr(reader: &mut R) -> io::Result + where + R: BitRead + ?Sized, + Self: Sized, + { + <$t as Integer>::read_vbr::(reader) + .map(|u| NonZero::new(u + 1).unwrap()) + } + #[inline] fn write( self, @@ -758,6 +844,14 @@ macro_rules! define_unsigned_integer { )) } } + + #[inline] + fn write_vbr( + self, + writer: &mut W, + ) -> io::Result<()> { + <$t as Integer>::write_vbr::(self.get() - 1, writer) + } } impl Integer for Option> { @@ -778,6 +872,15 @@ macro_rules! define_unsigned_integer { <$t as Integer>::read_var::(reader, count).map(NonZero::new) } + #[inline(always)] + fn read_vbr(reader: &mut R) -> io::Result + where + R: BitRead + ?Sized, + Self: Sized, + { + <$t as Integer>::read_vbr::(reader).map(NonZero::new) + } + #[inline] fn write( self, @@ -798,6 +901,17 @@ macro_rules! define_unsigned_integer { count, ) } + + #[inline] + fn write_vbr( + self, + writer: &mut W, + ) -> io::Result<()> { + <$t as Integer>::write_vbr::( + self.map(|n| n.get()).unwrap_or(0), + writer, + ) + } } }; } @@ -896,6 +1010,15 @@ macro_rules! define_signed_integer { reader.read_signed_counted::(bits) } + #[inline(always)] + fn read_vbr(reader: &mut R) -> io::Result + where + R: BitRead + ?Sized, + Self: Sized, + { + reader.read_signed_vbr::() + } + #[inline(always)] fn write( self, @@ -912,6 +1035,14 @@ macro_rules! define_signed_integer { ) -> io::Result<()> { writer.write_signed_counted::(bits, self) } + + #[inline(always)] + fn write_vbr( + self, + writer: &mut W, + ) -> io::Result<()> { + writer.write_signed_vbr::(self) + } } }; } diff --git a/src/read.rs b/src/read.rs index 1fe2b19..4a71a40 100644 --- a/src/read.rs +++ b/src/read.rs @@ -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. @@ -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. @@ -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(&mut self) -> io::Result { + I::read_vbr::(self) + } + /// Creates a "by reference" adaptor for this `BitRead` /// /// The returned adapter also implements `BitRead` diff --git a/src/write.rs b/src/write.rs index df092bf..669e704 100644 --- a/src/write.rs +++ b/src/write.rs @@ -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. @@ -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. @@ -1034,6 +1034,26 @@ pub trait BitWrite { self.write_unsigned_vbr::(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(&mut self, value: I) -> io::Result<()> { + I::write_vbr::(value, self) + } + /// Creates a "by reference" adaptor for this `BitWrite` /// /// The returned adapter also implements `BitWrite`