Skip to main content

boon/io/
bitreader.rs

1use crate::error::{Error, Result};
2
3// Source 2 coordinate encoding constants. A coordinate is encoded as an
4// optional integer part (14 bits) plus an optional fractional part (5 bits).
5const COORD_INTEGER_BITS: usize = 14;
6const COORD_FRACTIONAL_BITS: usize = 5;
7const COORD_DENOMINATOR: f32 = (1 << COORD_FRACTIONAL_BITS) as f32;
8const COORD_RESOLUTION: f32 = 1.0 / COORD_DENOMINATOR;
9
10// Source 2 normal encoding constants. A normal component is a sign bit
11// followed by an 11-bit fractional value in [0, 1].
12const NORMAL_FRACTIONAL_BITS: usize = 11;
13const NORMAL_DENOMINATOR: f32 = ((1 << NORMAL_FRACTIONAL_BITS) - 1) as f32;
14const NORMAL_RESOLUTION: f32 = 1.0 / NORMAL_DENOMINATOR;
15
16/// High-performance bit-level reader over a byte slice.
17///
18/// Uses safe unaligned 64-bit reads via `u64::from_le_bytes` for fast
19/// bit extraction. Every read returns `Result<T>` with overflow checking.
20pub struct BitReader<'a> {
21    data: &'a [u8],
22    position: usize,
23    total_bits: usize,
24}
25
26impl<'a> BitReader<'a> {
27    /// Create a new reader starting at bit 0 of `data`.
28    #[inline]
29    pub fn new(data: &'a [u8]) -> Self {
30        Self {
31            data,
32            position: 0,
33            total_bits: data.len() * 8,
34        }
35    }
36
37    /// Number of bits between the cursor and the end of the buffer.
38    #[inline]
39    pub fn bits_remaining(&self) -> usize {
40        self.total_bits.saturating_sub(self.position)
41    }
42
43    /// Current bit offset from the start of the buffer.
44    #[inline]
45    pub fn position(&self) -> usize {
46        self.position
47    }
48
49    /// Read up to 64 bits. Returns the value right-aligned in a u64.
50    #[inline]
51    pub fn read_bits(&mut self, n: usize) -> Result<u64> {
52        if n == 0 {
53            return Ok(0);
54        }
55        if n > 64 || self.position + n > self.total_bits {
56            return Err(Error::Overflow {
57                needed: n,
58                available: self.bits_remaining(),
59            });
60        }
61
62        let value = self.peek_bits_unchecked(n);
63        self.position += n;
64        Ok(value)
65    }
66
67    /// Peek at up to 64 bits without advancing the position.
68    #[inline]
69    pub fn peek_bits(&self, n: usize) -> Result<u64> {
70        if n == 0 {
71            return Ok(0);
72        }
73        if n > 64 || self.position + n > self.total_bits {
74            return Err(Error::Overflow {
75                needed: n,
76                available: self.bits_remaining(),
77            });
78        }
79        Ok(self.peek_bits_unchecked(n))
80    }
81
82    /// Internal: peek without bounds checking.
83    ///
84    /// Reads a little-endian u64 from the byte at `position / 8`, shifts
85    /// right by the intra-byte bit offset, and masks to `n` bits.
86    #[inline(always)]
87    fn peek_bits_unchecked(&self, n: usize) -> u64 {
88        let byte_pos = self.position / 8;
89        let bit_offset = self.position % 8;
90        let remaining_bytes = self.data.len() - byte_pos;
91
92        let mut buf = [0u8; 8];
93        if remaining_bytes >= 8 {
94            buf.copy_from_slice(&self.data[byte_pos..byte_pos + 8]);
95        } else {
96            buf[..remaining_bytes]
97                .copy_from_slice(&self.data[byte_pos..byte_pos + remaining_bytes]);
98        }
99        let raw = u64::from_le_bytes(buf);
100        (raw >> bit_offset) & mask(n)
101    }
102
103    /// Read a single bit as a boolean.
104    #[inline]
105    pub fn read_bool(&mut self) -> Result<bool> {
106        Ok(self.read_bits(1)? != 0)
107    }
108
109    /// Read 8 bits as a `u8`.
110    #[inline]
111    pub fn read_u8(&mut self) -> Result<u8> {
112        Ok(self.read_bits(8)? as u8)
113    }
114
115    /// Read 16 bits as a little-endian `u16`.
116    #[inline]
117    pub fn read_u16(&mut self) -> Result<u16> {
118        Ok(self.read_bits(16)? as u16)
119    }
120
121    /// Read 32 bits as a little-endian `u32`.
122    #[inline]
123    pub fn read_u32(&mut self) -> Result<u32> {
124        Ok(self.read_bits(32)? as u32)
125    }
126
127    /// Read 64 bits as a little-endian `u64`.
128    #[inline]
129    pub fn read_u64(&mut self) -> Result<u64> {
130        self.read_bits(64)
131    }
132
133    /// Read 32 bits and reinterpret as an IEEE 754 `f32`.
134    #[inline]
135    pub fn read_f32(&mut self) -> Result<f32> {
136        Ok(f32::from_bits(self.read_bits(32)? as u32))
137    }
138
139    /// Read N bytes into the provided buffer.
140    pub fn read_bytes(&mut self, buf: &mut [u8]) -> Result<()> {
141        let needed = buf.len() * 8;
142        if self.position + needed > self.total_bits {
143            return Err(Error::Overflow {
144                needed,
145                available: self.bits_remaining(),
146            });
147        }
148
149        // Fast path: byte-aligned — direct memcpy.
150        if self.position.is_multiple_of(8) {
151            let byte_pos = self.position / 8;
152            buf.copy_from_slice(&self.data[byte_pos..byte_pos + buf.len()]);
153            self.position += needed;
154            return Ok(());
155        }
156
157        // Slow path: unaligned — read byte at a time via bit extraction.
158        for byte in buf.iter_mut() {
159            *byte = self.peek_bits_unchecked(8) as u8;
160            self.position += 8;
161        }
162        Ok(())
163    }
164
165    /// Read a specified number of bits into a byte buffer, filling LSB-first.
166    pub fn read_bits_to_bytes(&mut self, buf: &mut [u8], bits: usize) -> Result<()> {
167        let full_bytes = bits / 8;
168        let remaining_bits = bits % 8;
169
170        if remaining_bits == 0 {
171            return self.read_bytes(&mut buf[..full_bytes]);
172        }
173
174        // Has trailing bits — can still fast-path the full bytes.
175        if full_bytes > 0 {
176            self.read_bytes(&mut buf[..full_bytes])?;
177        }
178        buf[full_bytes] = self.read_bits(remaining_bits)? as u8;
179        Ok(())
180    }
181
182    /// Read an unsigned varint (up to 32 bits).
183    pub fn read_uvarint32(&mut self) -> Result<u32> {
184        let mut result: u32 = 0;
185        for i in 0..5 {
186            let byte = self.read_u8()? as u32;
187            result |= (byte & 0x7F) << (7 * i);
188            if byte & 0x80 == 0 {
189                return Ok(result);
190            }
191        }
192        Ok(result)
193    }
194
195    /// Read an unsigned varint (up to 64 bits).
196    pub fn read_uvarint64(&mut self) -> Result<u64> {
197        let mut result: u64 = 0;
198        for i in 0..10 {
199            let byte = self.read_u8()? as u64;
200            result |= (byte & 0x7F) << (7 * i);
201            if byte & 0x80 == 0 {
202                return Ok(result);
203            }
204        }
205        Ok(result)
206    }
207
208    /// Read a signed varint (zigzag encoded, 32-bit).
209    pub fn read_varint32(&mut self) -> Result<i32> {
210        let n = self.read_uvarint32()?;
211        Ok(((n >> 1) as i32) ^ -((n & 1) as i32))
212    }
213
214    /// Read a signed varint (zigzag encoded, 64-bit).
215    pub fn read_varint64(&mut self) -> Result<i64> {
216        let n = self.read_uvarint64()?;
217        Ok(((n >> 1) as i64) ^ -((n & 1) as i64))
218    }
219
220    /// Valve's variable-length unsigned integer encoding.
221    ///
222    /// Reads 6 bits; bits 4-5 select the total width:
223    /// `00` → 6 bits, `01` → 4+4, `10` → 4+8, `11` → 4+28.
224    pub fn read_ubitvar(&mut self) -> Result<u32> {
225        let ret = self.read_bits(6)? as u32;
226        match ret & (16 | 32) {
227            16 => Ok((ret & 15) | (self.read_bits(4)? as u32) << 4),
228            32 => Ok((ret & 15) | (self.read_bits(8)? as u32) << 4),
229            48 => Ok((ret & 15) | (self.read_bits(28)? as u32) << 4),
230            _ => Ok(ret),
231        }
232    }
233
234    /// Field-path variant of ubitvar — cascading 1-bit selectors.
235    ///
236    /// Used exclusively for encoding field path operation indices:
237    /// 2, 4, 10, 17, or 31 bits depending on which prefix bit is set.
238    pub fn read_ubitvarfp(&mut self) -> Result<u32> {
239        if self.read_bool()? {
240            return Ok(self.read_bits(2)? as u32);
241        }
242        if self.read_bool()? {
243            return Ok(self.read_bits(4)? as u32);
244        }
245        if self.read_bool()? {
246            return Ok(self.read_bits(10)? as u32);
247        }
248        if self.read_bool()? {
249            return Ok(self.read_bits(17)? as u32);
250        }
251        Ok(self.read_bits(31)? as u32)
252    }
253
254    /// Read a coordinate value.
255    pub fn read_bitcoord(&mut self) -> Result<f32> {
256        let has_int = self.read_bool()?;
257        let has_frac = self.read_bool()?;
258
259        if !has_int && !has_frac {
260            return Ok(0.0);
261        }
262
263        let negative = self.read_bool()?;
264        let mut value = 0.0f32;
265
266        if has_int {
267            value += self.read_bits(COORD_INTEGER_BITS)? as f32 + 1.0;
268        }
269        if has_frac {
270            value += self.read_bits(COORD_FRACTIONAL_BITS)? as f32 * COORD_RESOLUTION;
271        }
272
273        if negative {
274            value = -value;
275        }
276
277        Ok(value)
278    }
279
280    /// Read a normal component (sign + 11-bit fraction).
281    pub fn read_bitnormal(&mut self) -> Result<f32> {
282        let negative = self.read_bool()?;
283        let frac = self.read_bits(NORMAL_FRACTIONAL_BITS)? as f32;
284        let mut value = frac * NORMAL_RESOLUTION;
285        if negative {
286            value = -value;
287        }
288        Ok(value)
289    }
290
291    /// Read a 3D coordinate vector.
292    pub fn read_bitvec3coord(&mut self) -> Result<[f32; 3]> {
293        let has_x = self.read_bool()?;
294        let has_y = self.read_bool()?;
295        let has_z = self.read_bool()?;
296
297        let x = if has_x { self.read_bitcoord()? } else { 0.0 };
298        let y = if has_y { self.read_bitcoord()? } else { 0.0 };
299        let z = if has_z { self.read_bitcoord()? } else { 0.0 };
300
301        Ok([x, y, z])
302    }
303
304    /// Read a 3D normal vector (2 components + derived Z).
305    pub fn read_bitvec3normal(&mut self) -> Result<[f32; 3]> {
306        let has_x = self.read_bool()?;
307        let has_y = self.read_bool()?;
308
309        let x = if has_x { self.read_bitnormal()? } else { 0.0 };
310        let y = if has_y { self.read_bitnormal()? } else { 0.0 };
311
312        let z_sign = self.read_bool()?;
313        let z_sq = 1.0 - x * x - y * y;
314        let z = if z_sq > 0.0 { z_sq.sqrt() } else { 0.0 };
315        let z = if z_sign { -z } else { z };
316
317        Ok([x, y, z])
318    }
319
320    /// Read an angle encoded as N bits, returning degrees in [0, 360).
321    pub fn read_bitangle(&mut self, n: usize) -> Result<f32> {
322        let raw = self.read_bits(n)? as f32;
323        let shift = (1u64 << n) as f32;
324        Ok(raw * 360.0 / shift)
325    }
326
327    /// Read a null-terminated string.
328    pub fn read_string(&mut self) -> Result<String> {
329        let mut bytes = Vec::new();
330        loop {
331            let b = self.read_u8()?;
332            if b == 0 {
333                break;
334            }
335            bytes.push(b);
336        }
337        Ok(String::from_utf8_lossy(&bytes).into_owned())
338    }
339
340    /// Read a string into the provided buffer, returning bytes written (excluding null).
341    pub fn read_string_into(&mut self, buf: &mut [u8]) -> Result<usize> {
342        let mut i = 0;
343        loop {
344            let b = self.read_u8()?;
345            if b == 0 {
346                break;
347            }
348            if i < buf.len() {
349                buf[i] = b;
350                i += 1;
351            }
352        }
353        Ok(i)
354    }
355
356    /// Read a string as raw bytes into a Vec, returning bytes written (excluding null).
357    pub fn read_string_raw(&mut self, buf: &mut Vec<u8>) -> Result<usize> {
358        let start = buf.len();
359        loop {
360            let b = self.read_u8()?;
361            if b == 0 {
362                break;
363            }
364            buf.push(b);
365        }
366        Ok(buf.len() - start)
367    }
368
369    /// Skip forward by N bits.
370    pub fn skip_bits(&mut self, n: usize) -> Result<()> {
371        if self.position + n > self.total_bits {
372            return Err(Error::Overflow {
373                needed: n,
374                available: self.bits_remaining(),
375            });
376        }
377        self.position += n;
378        Ok(())
379    }
380
381    /// Skip a varint without decoding it.
382    pub fn skip_varint(&mut self) -> Result<()> {
383        for _ in 0..10 {
384            let byte = self.read_u8()?;
385            if byte & 0x80 == 0 {
386                return Ok(());
387            }
388        }
389        Ok(())
390    }
391
392    /// Skip a bitcoord value.
393    pub fn skip_bitcoord(&mut self) -> Result<()> {
394        let has_int = self.read_bool()?;
395        let has_frac = self.read_bool()?;
396
397        if !has_int && !has_frac {
398            return Ok(());
399        }
400
401        self.skip_bits(1)?; // negative flag
402
403        if has_int {
404            self.skip_bits(COORD_INTEGER_BITS)?;
405        }
406        if has_frac {
407            self.skip_bits(COORD_FRACTIONAL_BITS)?;
408        }
409
410        Ok(())
411    }
412
413    /// Skip a bitnormal value.
414    pub fn skip_bitnormal(&mut self) -> Result<()> {
415        self.skip_bits(1 + NORMAL_FRACTIONAL_BITS)
416    }
417
418    /// Skip a 3D coordinate vector.
419    pub fn skip_bitvec3coord(&mut self) -> Result<()> {
420        let has_x = self.read_bool()?;
421        let has_y = self.read_bool()?;
422        let has_z = self.read_bool()?;
423
424        if has_x {
425            self.skip_bitcoord()?;
426        }
427        if has_y {
428            self.skip_bitcoord()?;
429        }
430        if has_z {
431            self.skip_bitcoord()?;
432        }
433
434        Ok(())
435    }
436
437    /// Skip a 3D normal vector.
438    pub fn skip_bitvec3normal(&mut self) -> Result<()> {
439        let has_x = self.read_bool()?;
440        let has_y = self.read_bool()?;
441
442        if has_x {
443            self.skip_bitnormal()?;
444        }
445        if has_y {
446            self.skip_bitnormal()?;
447        }
448
449        self.skip_bits(1)?; // z_sign
450
451        Ok(())
452    }
453
454    /// Skip a null-terminated string.
455    pub fn skip_string(&mut self) -> Result<()> {
456        loop {
457            let b = self.read_u8()?;
458            if b == 0 {
459                return Ok(());
460            }
461        }
462    }
463}
464
465/// Create a bitmask with n bits set.
466#[inline(always)]
467fn mask(n: usize) -> u64 {
468    if n >= 64 { u64::MAX } else { (1u64 << n) - 1 }
469}
470
471#[cfg(test)]
472mod tests {
473    use super::*;
474
475    #[test]
476    fn test_read_bits_basic() {
477        let data = [0b10110100, 0b11001010];
478        let mut br = BitReader::new(&data);
479
480        assert_eq!(br.read_bits(1).unwrap(), 0);
481        assert_eq!(br.read_bits(1).unwrap(), 0);
482        assert_eq!(br.read_bits(1).unwrap(), 1);
483        assert_eq!(br.read_bits(1).unwrap(), 0);
484        assert_eq!(br.read_bits(1).unwrap(), 1);
485        assert_eq!(br.read_bits(1).unwrap(), 1);
486        assert_eq!(br.read_bits(1).unwrap(), 0);
487        assert_eq!(br.read_bits(1).unwrap(), 1);
488    }
489
490    #[test]
491    fn test_read_byte() {
492        let data = [0xAB, 0xCD];
493        let mut br = BitReader::new(&data);
494        assert_eq!(br.read_u8().unwrap(), 0xAB);
495        assert_eq!(br.read_u8().unwrap(), 0xCD);
496    }
497
498    #[test]
499    fn test_read_across_boundary() {
500        let data = [0xFF, 0x00, 0xFF];
501        let mut br = BitReader::new(&data);
502        br.read_bits(4).unwrap();
503        let val = br.read_bits(8).unwrap();
504        assert_eq!(val, 0x0F);
505    }
506
507    #[test]
508    fn test_read_bool() {
509        let data = [0b10000001];
510        let mut br = BitReader::new(&data);
511        assert!(br.read_bool().unwrap());
512        assert!(!br.read_bool().unwrap());
513    }
514
515    #[test]
516    fn test_overflow() {
517        let data = [0xFF];
518        let mut br = BitReader::new(&data);
519        br.read_bits(8).unwrap();
520        assert!(br.read_bits(1).is_err());
521    }
522
523    #[test]
524    fn test_uvarint32() {
525        // Encode 300 as varint: 300 = 0b100101100
526        // byte 0: 10101100 (0xAC), byte 1: 00000010 (0x02)
527        let data = [0xAC, 0x02];
528        let mut br = BitReader::new(&data);
529        assert_eq!(br.read_uvarint32().unwrap(), 300);
530    }
531
532    #[test]
533    fn test_varint32_negative() {
534        // zigzag(-1) = 1
535        let data = [0x01];
536        let mut br = BitReader::new(&data);
537        assert_eq!(br.read_varint32().unwrap(), -1);
538    }
539
540    #[test]
541    fn test_varint32_positive() {
542        // zigzag(1) = 2
543        let data = [0x02];
544        let mut br = BitReader::new(&data);
545        assert_eq!(br.read_varint32().unwrap(), 1);
546    }
547
548    #[test]
549    fn test_read_f32() {
550        let val: f32 = 1.5;
551        let data = val.to_bits().to_le_bytes();
552        let mut br = BitReader::new(&data);
553        let read_val = br.read_f32().unwrap();
554        assert!((read_val - val).abs() < f32::EPSILON);
555    }
556
557    #[test]
558    fn test_read_string() {
559        let data = b"hello\0world";
560        let mut br = BitReader::new(data);
561        assert_eq!(br.read_string().unwrap(), "hello");
562    }
563
564    #[test]
565    fn test_bits_remaining() {
566        let data = [0xFF, 0xFF];
567        let mut br = BitReader::new(&data);
568        assert_eq!(br.bits_remaining(), 16);
569        br.read_bits(5).unwrap();
570        assert_eq!(br.bits_remaining(), 11);
571    }
572
573    #[test]
574    fn test_skip_bits() {
575        let data = [0b11110000, 0b10101010];
576        let mut br = BitReader::new(&data);
577        br.skip_bits(4).unwrap();
578        assert_eq!(br.read_bits(4).unwrap(), 0b1111);
579    }
580
581    #[test]
582    fn test_peek_bits() {
583        let data = [0xAB];
584        let br = BitReader::new(&data);
585        assert_eq!(br.peek_bits(8).unwrap(), 0xAB);
586        assert_eq!(br.position(), 0);
587    }
588
589    #[test]
590    fn test_ubitvar() {
591        // Simple case: value fits in 6 bits, bits 4,5 = 00
592        // Value 5 = 0b000101
593        let data = [0b00000101];
594        let mut br = BitReader::new(&data);
595        assert_eq!(br.read_ubitvar().unwrap(), 5);
596    }
597
598    #[test]
599    fn test_bitangle() {
600        let data = [0x00, 0x00, 0x00, 0x00];
601        let mut br = BitReader::new(&data);
602        assert!((br.read_bitangle(16).unwrap() - 0.0).abs() < f32::EPSILON);
603    }
604}