Repository: sharksforarms/deku
Pull request #528 (2025-03-01 17:44:45)

reader: Remove constraint of MAX_BITS_AMT
* In order to allow one to read a large amount of bytes after an unaligned bit reading, remove MAX_BITS_AMT and allocate a length of bytes_len to store the byte read result.

  See #527

github-actions[bot]: ## Benchmark for 0f373cc
  <details>
    <summary>Click to view benchmark</summary>

| Test | Base         | PR               | % |
|------|--------------|------------------|---|
| count_from_u8_specialize | 96.4±0.99ns | **93.6±1.30ns** | **-2.90%** |
| count_no_specialize | 2.4±0.04µs | 2.4±0.01µs | 0.00% |
| count_specialize | **97.0±0.84ns** | 99.5±0.86ns | **+2.58%** |
| deku_read_bits | **1250.5±15.82ns** | 1283.1±15.25ns | **+2.61%** |
| deku_read_byte | 5.3±0.05ns | **4.7±0.09ns** | **-11.32%** |
| deku_read_enum | 4.3±0.05ns | **3.8±0.06ns** | **-11.63%** |
| deku_read_vec | 30.7±0.48ns | 31.1±0.73ns | +1.30% |
| deku_write_bits | **245.1±4.37ns** | 251.4±5.95ns | **+2.57%** |
| deku_write_byte | **24.0±0.42ns** | 24.3±0.25ns | **+1.25%** |
| deku_write_enum | **22.6±1.03ns** | 23.1±0.41ns | **+2.21%** |
| deku_write_vec | 511.6±6.27ns | **490.8±5.22ns** | **-4.07%** |
| read_all | 5.1±0.04µs | **4.3±0.06µs** | **-15.69%** |
| read_all_bytes | 5.4±0.31µs | **4.3±0.06µs** | **-20.37%** |

  </details>
  

Patch:
diff --git a/src/reader.rs b/src/reader.rs
index 1ff56a7..a924ada 100644
--- a/src/reader.rs
+++ b/src/reader.rs
@@ -21,9 +21,6 @@ pub enum ReaderRet {
     Bits(Option<BitVec<u8, Msb0>>),
 }
 
-/// Max bits requested from [`Reader::read_bits`] during one call
-pub const MAX_BITS_AMT: usize = 128;
-
 #[derive(Debug)]
 enum Leftover {
     Byte(u8),
@@ -214,7 +211,7 @@ impl<'a, R: Read + Seek> Reader<'a, R> {
     ///   `self.bits_read` will increase by `amt`
     ///
     /// # Params
-    /// `amt`    - Amount of bits that will be read. Must be <= [`MAX_BITS_AMT`].
+    /// `amt`    - Amount of bits that will be read
     #[inline(never)]
     #[cfg(feature = "bits")]
     pub fn read_bits(
@@ -282,8 +279,8 @@ impl<'a, R: Read + Seek> Reader<'a, R> {
                 }
 
                 // read in new bytes
-                let mut buf = [0; MAX_BITS_AMT];
-                if let Err(e) = self.inner.read_exact(&mut buf[..bytes_len]) {
+                let mut buf = vec![0; bytes_len];
+                if let Err(e) = self.inner.read_exact(&mut buf) {
                     if e.kind() == ErrorKind::UnexpectedEof {
                         return Err(DekuError::Incomplete(NeedSize::new(amt)));
                     }
@@ -803,4 +800,20 @@ mod tests {
         let bits = reader.read_bits(4, Order::Msb0).unwrap();
         assert_eq!(bits, Some(bitvec![u8, Msb0; 0, 1, 0, 1]));
     }
+
+    #[cfg(feature = "bits")]
+    #[test]
+    fn test_long_unaligned_bytes_read() {
+        let input = vec![0xff; 0xff * 2];
+        let mut cursor = Cursor::new(input);
+        let mut reader = Reader::new(&mut cursor);
+
+        // read 1 bits to make this unaligned
+        let bits = reader.read_bits(1, Order::Lsb0).unwrap();
+        assert_eq!(bits, Some(bitvec![u8, Msb0; 1]));
+        // Now, read the bytes
+        let mut out = vec![0x00; 0xff * 2];
+        // doesn't crash
+        let _ = reader.read_bytes(0xfe * 2, &mut out, Order::Lsb0).unwrap();
+    }
 }


Test patch:
diff --git a/tests/test_alloc.rs b/tests/test_alloc.rs
index eee3319..9050c01 100644
--- a/tests/test_alloc.rs
+++ b/tests/test_alloc.rs
@@ -66,7 +66,7 @@ mod tests {
                 let _ = TestDeku::from_reader((&mut cursor, 0)).unwrap();
             })
             .0,
-            (5, 0, 5)
+            (6, 0, 6)
         );
     }