@@ -25,6 +25,34 @@ use super::{
2525
2626use core:: convert:: TryInto ;
2727
28+ /// An error returned if performing VBR read overflows
29+ #[ derive( Copy , Clone , Debug ) ]
30+ pub ( crate ) struct VariableWidthOverflow ;
31+
32+ impl core:: fmt:: Display for VariableWidthOverflow {
33+ fn fmt ( & self , f : & mut core:: fmt:: Formatter ) -> core:: fmt:: Result {
34+ "variable bit rate overflowed" . fmt ( f)
35+ }
36+ }
37+
38+ impl core:: error:: Error for VariableWidthOverflow { }
39+
40+ impl From < VariableWidthOverflow > for io:: Error {
41+ fn from ( VariableWidthOverflow : VariableWidthOverflow ) -> Self {
42+ io:: Error :: new (
43+ #[ cfg( feature = "std" ) ]
44+ {
45+ io:: ErrorKind :: StorageFull
46+ } ,
47+ #[ cfg( not( feature = "std" ) ) ]
48+ {
49+ io:: ErrorKind :: Other
50+ } ,
51+ "variable bit rate overflow" ,
52+ )
53+ }
54+ }
55+
2856/// A trait for anything that can read a variable number of
2957/// potentially un-aligned values from an input stream
3058pub trait BitRead {
@@ -874,6 +902,97 @@ pub trait BitRead {
874902 T :: from_bits ( || self . read_bit ( ) )
875903 }
876904
905+ /// Reads a number using a variable using a variable-width integer.
906+ /// This optimises the case when the number is small.
907+ ///
908+ /// The integer is mapped to an unsigned value using zigzag encoding.
909+ /// For an integer X:
910+ /// - if X >= 0 -> 2X
911+ /// - else -> -2X + 1
912+ ///
913+ /// # Errors
914+ ///
915+ /// Passes along any I/O error from the underlying stream.
916+ /// Returns an error if the data read would overflow the size of the result
917+ ///
918+ /// # Example
919+ /// ```
920+ /// use bitstream_io::{BitReader, BitRead, BigEndian};
921+ ///
922+ /// let bytes: &[u8] = &[0b0111_1100, 0b1100_0001];
923+ /// let mut r = BitReader::endian(bytes, BigEndian);
924+ /// assert_eq!(r.read_unsigned_vbr::<4, u32>().unwrap(), 7);
925+ /// assert_eq!(r.read_unsigned_vbr::<4, u32>().unwrap(), 100);
926+ /// ```
927+ /// ```
928+ /// use bitstream_io::{BitReader, BitRead, BigEndian};
929+ ///
930+ /// let bytes: &[u8] = &[0b1111_1111, 0b0011_1000, 0b1000_0100, 0b1000_1000, 0b1000_0000];
931+ /// let mut r = BitReader::endian(bytes, BigEndian);
932+ /// assert_eq!(r.read_unsigned_vbr::<4, u8>().unwrap(), 255); // Tries to read <011><111><111>
933+ /// assert!(r.read_unsigned_vbr::<4, u8>().is_err()); // Tries to read a value of <100><000><000>
934+ /// assert!(r.read_unsigned_vbr::<4, u8>().is_err()); // Tries to read a value of <000><000><000><000>
935+ /// ```
936+ fn read_unsigned_vbr < const FIELD_SIZE : u32 , U : UnsignedInteger > ( & mut self ) -> io:: Result < U > {
937+ const { assert ! ( FIELD_SIZE >= 2 && FIELD_SIZE < U :: BITS_SIZE ) } ;
938+ let payload_bits = FIELD_SIZE - 1 ;
939+ let mut value = U :: ZERO ;
940+ let mut shift = 0u32 ;
941+ loop {
942+ let ( data, continuation) = self . read_unsigned :: < FIELD_SIZE , U > ( ) . map ( |item| {
943+ (
944+ item & ( ( U :: ONE << payload_bits) - U :: ONE ) ,
945+ ( item >> payload_bits) != U :: ZERO ,
946+ )
947+ } ) ?;
948+ let shifted = data << shift;
949+ value |= shifted;
950+ if !continuation {
951+ if ( data << shift) >> shift == data {
952+ break Ok ( value) ;
953+ } else {
954+ break Err ( VariableWidthOverflow { } . into ( ) ) ;
955+ }
956+ }
957+ shift += payload_bits;
958+ if shift >= U :: BITS_SIZE {
959+ break Err ( VariableWidthOverflow { } . into ( ) ) ;
960+ }
961+ }
962+ }
963+
964+ /// Reads a number using a variable using a variable-width integer.
965+ /// This optimises the case when the number is small.
966+ ///
967+ /// The integer is mapped to an unsigned value using zigzag encoding.
968+ /// For an integer X:
969+ /// - if X >= 0 -> 2X
970+ /// - else -> -2X + 1
971+ ///
972+ /// # Errors
973+ ///
974+ /// Passes along any I/O error from the underlying stream.
975+ /// Returns an error if the data read would overflow the size of the result
976+ ///
977+ /// # Example
978+ /// ```
979+ /// use bitstream_io::{BitReader, BitRead, BigEndian};
980+ ///
981+ /// let bytes: &[u8] = &[0b0110_1011, 0b1100_0001];
982+ /// let mut r = BitReader::endian(bytes, BigEndian);
983+ /// assert_eq!(r.read_signed_vbr::<4, i32>().unwrap(), 3);
984+ /// assert_eq!(r.read_signed_vbr::<4, i32>().unwrap(), -50);
985+ /// ```
986+ fn read_signed_vbr < const FIELD_SIZE : u32 , I : SignedInteger > ( & mut self ) -> io:: Result < I > {
987+ self . read_unsigned_vbr :: < FIELD_SIZE , I :: Unsigned > ( )
988+ . map ( |zig_zag| {
989+ let shifted = zig_zag >> 1 ;
990+ let complimented = zig_zag & <I :: Unsigned as crate :: Numeric >:: ONE ;
991+ let neg = I :: ZERO - complimented. as_non_negative ( ) ;
992+ shifted. as_non_negative ( ) ^ neg
993+ } )
994+ }
995+
877996 /// Creates a "by reference" adaptor for this `BitRead`
878997 ///
879998 /// The returned adapter also implements `BitRead`
0 commit comments