Skip to main content

questdb/egress/wire/
bit_reader.rs

1/*******************************************************************************
2 *     ___                  _   ____  ____
3 *    / _ \ _   _  ___  ___| |_|  _ \| __ )
4 *   | | | | | | |/ _ \/ __| __| | | |  _ \
5 *   | |_| | |_| |  __/\__ \ |_| |_| | |_) |
6 *    \__\_\\__,_|\___||___/\__|____/|____/
7 *
8 *  Copyright (c) 2014-2019 Appsicle
9 *  Copyright (c) 2019-2025 QuestDB
10 *
11 *  Licensed under the Apache License, Version 2.0 (the "License");
12 *  you may not use this file except in compliance with the License.
13 *  You may obtain a copy of the License at
14 *
15 *  http://www.apache.org/licenses/LICENSE-2.0
16 *
17 *  Unless required by applicable law or agreed to in writing, software
18 *  distributed under the License is distributed on an "AS IS" BASIS,
19 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 *  See the License for the specific language governing permissions and
21 *  limitations under the License.
22 *
23 ******************************************************************************/
24
25//! LSB-first bit reader for Gorilla-compressed columns.
26//!
27//! Mirrors `QwpBitReader.java`: bytes are pulled from the underlying slice
28//! lazily into a 64-bit window; bits consume from the low end. Reads past
29//! the end surface as `ProtocolError`.
30
31use crate::error::{Result, fmt};
32
33/// Borrowed bit reader over `&[u8]`. LSB-first within each byte.
34pub struct BitReader<'a> {
35    bytes: &'a [u8],
36    /// Next byte to pull into the window.
37    byte_pos: usize,
38    /// Sliding bit window. Low `bits_in_window` bits are valid.
39    window: u64,
40    bits_in_window: u32,
41    /// Total bits consumed via `read_bit` / `read_bits`.
42    bits_read: u64,
43    /// Total bits available (byte length × 8).
44    bits_total: u64,
45}
46
47impl<'a> BitReader<'a> {
48    pub fn new(bytes: &'a [u8]) -> Self {
49        Self {
50            bytes,
51            byte_pos: 0,
52            window: 0,
53            bits_in_window: 0,
54            bits_read: 0,
55            bits_total: (bytes.len() as u64) * 8,
56        }
57    }
58
59    /// Total bits consumed so far.
60    pub fn bit_position(&self) -> u64 {
61        self.bits_read
62    }
63
64    /// Bytes consumed so far, rounded up — useful for advancing an outer
65    /// byte cursor past the bitstream.
66    pub fn bytes_consumed(&self) -> usize {
67        self.bits_read.div_ceil(8) as usize
68    }
69
70    /// Read one bit (0 or 1).
71    #[inline]
72    pub fn read_bit(&mut self) -> Result<u8> {
73        if self.bits_read >= self.bits_total {
74            return Err(fmt!(ProtocolError, "BitReader: read past end"));
75        }
76        if !self.ensure_bits(1) {
77            return Err(fmt!(ProtocolError, "BitReader: read past end"));
78        }
79        let bit = (self.window & 1) as u8;
80        self.window >>= 1;
81        self.bits_in_window -= 1;
82        self.bits_read += 1;
83        Ok(bit)
84    }
85
86    /// Read `n` bits LSB-first as an unsigned integer in the low bits.
87    #[inline]
88    pub fn read_bits(&mut self, n: u32) -> Result<u64> {
89        if n == 0 {
90            return Ok(0);
91        }
92        if n > 64 {
93            return Err(fmt!(
94                ProtocolError,
95                "BitReader: cannot read {} bits into u64",
96                n
97            ));
98        }
99        if self.bits_read + n as u64 > self.bits_total {
100            return Err(fmt!(ProtocolError, "BitReader: read past end"));
101        }
102
103        let mut result: u64 = 0;
104        let mut remaining = n;
105        let mut shift: u32 = 0;
106        while remaining > 0 {
107            if self.bits_in_window == 0 {
108                let want = remaining.min(64);
109                if !self.ensure_bits(want) {
110                    return Err(fmt!(ProtocolError, "BitReader: read past end"));
111                }
112            }
113            let take = remaining.min(self.bits_in_window);
114            let mask = if take == 64 {
115                u64::MAX
116            } else {
117                (1u64 << take) - 1
118            };
119            result |= (self.window & mask) << shift;
120            // Avoid the `>>= 64` no-op pitfall.
121            if take == 64 {
122                self.window = 0;
123            } else {
124                self.window >>= take;
125            }
126            self.bits_in_window -= take;
127            remaining -= take;
128            shift += take;
129        }
130        self.bits_read += n as u64;
131        Ok(result)
132    }
133
134    /// Read `n` bits and sign-extend (two's complement). `n` must be ≤ 64.
135    #[inline]
136    pub fn read_signed(&mut self, n: u32) -> Result<i64> {
137        let unsigned = self.read_bits(n)?;
138        if n == 0 || n == 64 {
139            return Ok(unsigned as i64);
140        }
141        let sign_bit = 1u64 << (n - 1);
142        let extended = if unsigned & sign_bit != 0 {
143            unsigned | (u64::MAX << n)
144        } else {
145            unsigned
146        };
147        Ok(extended as i64)
148    }
149
150    /// Pull bytes into the window until at least `want` bits are buffered or
151    /// the source runs dry. Returns whether the demand was satisfied.
152    #[inline]
153    fn ensure_bits(&mut self, want: u32) -> bool {
154        while self.bits_in_window < want
155            && self.bits_in_window <= 56
156            && self.byte_pos < self.bytes.len()
157        {
158            let b = self.bytes[self.byte_pos] as u64;
159            self.byte_pos += 1;
160            self.window |= b << self.bits_in_window;
161            self.bits_in_window += 8;
162        }
163        self.bits_in_window >= want
164    }
165}
166
167#[cfg(test)]
168mod tests {
169    use super::*;
170    use crate::error::ErrorCode;
171
172    #[test]
173    fn single_bits_lsb_first() {
174        // Byte 0b1010_0001: bits are read low-to-high → 1, 0, 0, 0, 0, 1, 0, 1
175        let bytes = [0b1010_0001u8];
176        let mut r = BitReader::new(&bytes);
177        let order = [1, 0, 0, 0, 0, 1, 0, 1];
178        for (i, expected) in order.iter().enumerate() {
179            assert_eq!(r.read_bit().unwrap(), *expected, "bit {}", i);
180        }
181        // Past-end yields an error.
182        assert_eq!(r.read_bit().unwrap_err().code(), ErrorCode::ProtocolError);
183    }
184
185    #[test]
186    fn read_bits_groups_lsb_first() {
187        // Two bytes: 0xAC, 0x02 (the canonical varint(300) but interpreted
188        // here as a raw bit stream). Read 8 bits → 0xAC, then 4 bits → 0x02 & 0xF = 0x02.
189        let bytes = [0xAC, 0x02];
190        let mut r = BitReader::new(&bytes);
191        assert_eq!(r.read_bits(8).unwrap(), 0xAC);
192        assert_eq!(r.read_bits(4).unwrap(), 0x02);
193    }
194
195    #[test]
196    fn read_bits_spans_byte_boundary() {
197        // 0xFF 0x01 → first 12 bits LSB-first = 0b0001_1111_1111 = 0x1FF.
198        let bytes = [0xFF, 0x01];
199        let mut r = BitReader::new(&bytes);
200        assert_eq!(r.read_bits(12).unwrap(), 0x1FF);
201    }
202
203    #[test]
204    fn read_signed_sign_extends() {
205        // 7-bit value 0b1000000 (0x40) → signed -64.
206        let bytes = [0x40];
207        let mut r = BitReader::new(&bytes);
208        assert_eq!(r.read_signed(7).unwrap(), -64);
209
210        // 7-bit value 0b0111111 (63) → +63.
211        let bytes = [0b0011_1111];
212        let mut r = BitReader::new(&bytes);
213        assert_eq!(r.read_signed(7).unwrap(), 63);
214    }
215
216    #[test]
217    fn read_64_bits_works() {
218        let bytes = 0x0102_0304_0506_0708u64.to_le_bytes();
219        let mut r = BitReader::new(&bytes);
220        assert_eq!(r.read_bits(64).unwrap(), 0x0102_0304_0506_0708);
221        assert!(r.read_bit().is_err()); // exhausted
222    }
223
224    #[test]
225    fn bit_position_and_bytes_consumed() {
226        let bytes = [0xFFu8, 0xFF, 0xFF];
227        let mut r = BitReader::new(&bytes);
228        let _ = r.read_bits(13).unwrap();
229        assert_eq!(r.bit_position(), 13);
230        assert_eq!(r.bytes_consumed(), 2); // ceil(13/8) = 2
231    }
232
233    #[test]
234    fn n_zero_returns_zero() {
235        let bytes = [0u8; 0];
236        let mut r = BitReader::new(&bytes);
237        assert_eq!(r.read_bits(0).unwrap(), 0);
238        assert_eq!(r.bit_position(), 0);
239    }
240
241    #[test]
242    fn over_64_bits_rejected() {
243        let bytes = [0u8; 16];
244        let mut r = BitReader::new(&bytes);
245        assert_eq!(
246            r.read_bits(65).unwrap_err().code(),
247            ErrorCode::ProtocolError
248        );
249    }
250
251    #[test]
252    fn read_past_end_in_read_bits_errors() {
253        let bytes = [0xFFu8];
254        let mut r = BitReader::new(&bytes);
255        let _ = r.read_bits(7).unwrap();
256        assert!(r.read_bits(2).is_err()); // would need 9 bits total, have 8
257    }
258}