Repository: sharksforarms/deku
Pull request #526 (2025-02-16 05:22:15)

Modify reader bits_read during seek action

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

| Test | Base         | PR               | % |
|------|--------------|------------------|---|
| count_from_u8_specialize | **97.3±1.02ns** | 98.4±0.99ns | **+1.13%** |
| count_no_specialize | 2.6±0.03µs | **2.4±0.02µs** | **-7.69%** |
| count_specialize | **96.2±0.74ns** | 100.2±1.10ns | **+4.16%** |
| deku_read_bits | 1217.4±15.44ns | 1232.0±15.36ns | +1.20% |
| deku_read_byte | 5.0±0.05ns | **4.5±0.08ns** | **-10.00%** |
| deku_read_enum | 4.1±0.04ns | **3.8±0.05ns** | **-7.32%** |
| deku_read_vec | 30.6±0.54ns | 30.7±0.43ns | +0.33% |
| deku_write_bits | 223.6±3.00ns | **219.9±4.95ns** | **-1.65%** |
| deku_write_byte | **23.7±0.36ns** | 24.1±0.60ns | **+1.69%** |
| deku_write_enum | 22.8±0.35ns | 22.8±0.34ns | 0.00% |
| deku_write_vec | 488.1±7.71ns | 492.1±6.23ns | +0.82% |
| read_all | 5.2±0.05µs | **4.2±0.06µs** | **-19.23%** |
| read_all_bytes | 5.1±0.04µs | **4.2±0.05µs** | **-17.65%** |

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

| Test | Base         | PR               | % |
|------|--------------|------------------|---|
| count_from_u8_specialize | 98.0±1.20ns | 97.6±1.37ns | -0.41% |
| count_no_specialize | 2.7±0.03µs | **2.4±0.03µs** | **-11.11%** |
| count_specialize | **97.3±1.24ns** | 100.1±1.06ns | **+2.88%** |
| deku_read_bits | 1307.8±14.54ns | **1234.5±11.84ns** | **-5.60%** |
| deku_read_byte | 5.0±0.06ns | **4.6±0.03ns** | **-8.00%** |
| deku_read_enum | 4.2±0.31ns | **3.8±0.03ns** | **-9.52%** |
| deku_read_vec | 32.2±0.26ns | **31.3±0.56ns** | **-2.80%** |
| deku_write_bits | **233.1±3.68ns** | 243.4±6.74ns | **+4.42%** |
| deku_write_byte | 24.6±0.43ns | **24.0±0.41ns** | **-2.44%** |
| deku_write_enum | 22.8±0.23ns | **22.4±0.28ns** | **-1.75%** |
| deku_write_vec | 512.5±7.96ns | 507.9±4.78ns | -0.90% |
| read_all | 5.1±0.04µs | **4.5±0.08µs** | **-11.76%** |
| read_all_bytes | 5.1±0.05µs | **4.5±0.05µs** | **-11.76%** |

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

| Test | Base         | PR               | % |
|------|--------------|------------------|---|
| count_from_u8_specialize | 98.2±1.21ns | **93.6±1.13ns** | **-4.68%** |
| count_no_specialize | 2.4±0.02µs | 2.4±0.02µs | 0.00% |
| count_specialize | 97.4±0.82ns | **96.5±0.96ns** | **-0.92%** |
| deku_read_bits | 1293.0±11.57ns | **1215.4±18.69ns** | **-6.00%** |
| deku_read_byte | **5.3±0.09ns** | 5.4±0.14ns | **+1.89%** |
| deku_read_enum | 5.1±0.03ns | 5.1±0.02ns | 0.00% |
| deku_read_vec | 30.9±0.39ns | 31.1±0.76ns | +0.65% |
| deku_write_bits | 233.9±2.88ns | 233.7±3.21ns | -0.09% |
| deku_write_byte | 24.0±0.36ns | 24.3±0.38ns | +1.25% |
| deku_write_enum | 22.5±0.36ns | 22.5±0.40ns | 0.00% |
| deku_write_vec | 490.4±6.55ns | 490.9±6.13ns | +0.10% |
| read_all | 5.1±0.04µs | **5.0±0.03µs** | **-1.96%** |
| read_all_bytes | 5.2±0.07µs | **5.1±0.04µs** | **-1.92%** |

  </details>
  
sharksforarms: x-ref: https://github.com/sharksforarms/deku/discussions/525

Patch:
diff --git a/src/reader.rs b/src/reader.rs
index 286bb41..fbc64fa 100644
--- a/src/reader.rs
+++ b/src/reader.rs
@@ -50,6 +50,23 @@ impl<R: Read + Seek> Seek for Reader<'_, R> {
 
         // clear leftover
         self.leftover = None;
+        // set bits read
+        match pos {
+            // When reading from the start, reset the bits_read so from_bytes
+            // return can still be reasonable
+            SeekFrom::Start(n) => {
+                if n > 0 {
+                    self.bits_read = (n * 8) as usize;
+                }
+            }
+            SeekFrom::End(_) => (),
+            // If seeking from current, act as if we just read those bytes
+            SeekFrom::Current(n) => {
+                if n > 0 {
+                    self.bits_read += (n * 8) as usize;
+                }
+            }
+        }
         self.inner.seek(pos)
     }
 }
@@ -76,12 +93,17 @@ impl<'a, R: Read + Seek> Reader<'a, R> {
     /// Seek to previous previous before the last read, used for `id_pat`
     #[inline]
     pub fn seek_last_read(&mut self) -> no_std_io::io::Result<()> {
+        // save the previous bits read
+        let bits_read = self.bits_read;
+
         let number = self.last_bits_read_amt as i64;
         let seek_amt = (number / 8).saturating_add((number % 8).signum());
         #[cfg(feature = "logging")]
         log::trace!("seek_last_read: {seek_amt:?}");
         self.seek(SeekFrom::Current(seek_amt.saturating_neg()))?;
-        self.bits_read -= self.last_bits_read_amt;
+
+        // restore bits read, minus bits we read last time
+        self.bits_read = bits_read - self.last_bits_read_amt;
         self.leftover = None;
 
         Ok(())
@@ -188,9 +210,10 @@ impl<'a, R: Read + Seek> Reader<'a, R> {
                     i64::try_from(bytes_amt).expect("could not convert seek usize into i64"),
                 ))
                 .map_err(|e| DekuError::Io(e.kind()))?;
+                self.bits_read = 0;
             }
 
-            // Unlike normal seek not couting as bits_read, this one does
+            // Unlike normal seek not counting as bits_read, this one does
             // to keep from_bytes returns
             self.bits_read += bytes_amt * 8;
 


Test patch:
diff --git a/tests/test_regression.rs b/tests/test_regression.rs
index 4d005e7..89bfa8f 100644
--- a/tests/test_regression.rs
+++ b/tests/test_regression.rs
@@ -406,3 +406,24 @@ fn issue_533() {
     let v = BitsAndValue::from_reader_with_ctx(&mut reader, ()).unwrap();
     assert_eq!(v, BitsAndValue::Other(1));
 }
+
+#[test]
+fn issue_525() {
+    env_logger::init();
+    use deku::{DekuContainerRead, DekuRead, DekuWrite};
+
+    #[derive(Debug, DekuRead, DekuWrite, PartialEq)]
+    #[deku(endian = "big")]
+    pub struct TestSeek {
+        pub a: u8,
+        #[deku(seek_from_start = "2")]
+        pub b: u8,
+        pub c: u8,
+    }
+
+    let data: &[u8] = &[0, 1, 2, 3, 4, 5];
+    let test = TestSeek::from_bytes((data, 0)).unwrap();
+    let ret: &[u8] = &[4, 5];
+    assert_eq!(test.0, (ret, 0));
+    assert_eq!(test.1, TestSeek { a: 0, b: 2, c: 3 });
+}