Skip to main content

bincode_next/de/
bit_reader.rs

1use crate::de::read::Reader;
2use crate::error::DecodeError;
3
4/// A wrapper around a `Reader` that allows reading data bit-by-bit.
5pub struct BitReader<'a, R: Reader> {
6    reader: &'a mut R,
7    current_byte: u8,
8    bits_available: u8,
9}
10
11impl<'a, R: Reader> BitReader<'a, R> {
12    /// Creates a new `BitReader`.
13    #[inline(always)]
14    pub const fn new(reader: &'a mut R) -> Self {
15        Self {
16            reader,
17            current_byte: 0,
18            bits_available: 0,
19        }
20    }
21
22    /// Creates a new `BitReader` with an existing state.
23    #[inline(always)]
24    pub const fn from_state(
25        reader: &'a mut R,
26        current_byte: u8,
27        bits_available: u8,
28    ) -> Self {
29        Self {
30            reader,
31            current_byte,
32            bits_available,
33        }
34    }
35
36    /// Returns the current state of the bit reader (`current_byte`, `bits_available`).
37    #[inline(always)]
38    #[must_use]
39    pub const fn get_state(&self) -> (u8, u8) {
40        (self.current_byte, self.bits_available)
41    }
42
43    /// Reads `num_bits` from the stream, using LSB-first bit ordering.
44    ///
45    /// # Errors
46    ///
47    /// Returns `DecodeError` if the underlying reader fails to provide enough bytes.
48    #[inline]
49    pub fn read_bits_lsb(
50        &mut self,
51        mut num_bits: u8,
52    ) -> Result<u64, DecodeError> {
53        let mut result: u64 = 0;
54        let mut bits_read: u8 = 0;
55
56        while num_bits > 0 {
57            if self.bits_available == 0 {
58                let mut buf = [0u8; 1];
59                self.reader.read(&mut buf)?;
60                self.current_byte = buf[0];
61                self.bits_available = 8;
62            }
63
64            let bits_to_read = num_bits.min(self.bits_available);
65            let mask = ((1u16 << bits_to_read) - 1) as u8;
66
67            let chunk = self.current_byte & mask;
68            result |= u64::from(chunk) << bits_read;
69
70            self.current_byte >>= bits_to_read;
71            self.bits_available -= bits_to_read;
72
73            bits_read += bits_to_read;
74            num_bits -= bits_to_read;
75        }
76
77        Ok(result)
78    }
79
80    /// Reads `num_bits` from the stream, using MSB-first bit ordering.
81    ///
82    /// # Errors
83    ///
84    /// Returns `DecodeError` if the underlying reader fails to provide enough bytes.
85    #[inline]
86    pub fn read_bits_msb(
87        &mut self,
88        mut num_bits: u8,
89    ) -> Result<u64, DecodeError> {
90        let mut result: u64 = 0;
91
92        while num_bits > 0 {
93            if self.bits_available == 0 {
94                let mut buf = [0u8; 1];
95                self.reader.read(&mut buf)?;
96                self.current_byte = buf[0];
97                self.bits_available = 8;
98            }
99
100            let bits_to_read = num_bits.min(self.bits_available);
101            let shift_down = self.bits_available - bits_to_read;
102            let mask = ((1u16 << bits_to_read) - 1) as u8;
103
104            let chunk = (self.current_byte >> shift_down) & mask;
105            result = (result << bits_to_read) | u64::from(chunk);
106
107            self.bits_available -= bits_to_read;
108            num_bits -= bits_to_read;
109        }
110
111        Ok(result)
112    }
113
114    /// Reads `num_bits` from the stream, using the bit ordering from the configuration.
115    ///
116    /// # Errors
117    ///
118    /// Returns `DecodeError` if the underlying reader fails to provide enough bytes.
119    #[inline(always)]
120    pub fn read_bits<C: crate::config::Config>(
121        &mut self,
122        num_bits: u8,
123        config: &C,
124    ) -> Result<u64, DecodeError> {
125        use crate::config::BitOrdering;
126        match config.bit_ordering() {
127            | BitOrdering::Lsb => self.read_bits_lsb(num_bits),
128            | BitOrdering::Msb => self.read_bits_msb(num_bits),
129        }
130    }
131
132    /// Discards any remaining unread bits in the current byte, effectively returning to byte alignment.
133    #[inline(always)]
134    pub const fn align_to_byte(&mut self) {
135        self.bits_available = 0;
136        self.current_byte = 0;
137    }
138}
139
140/// A helper trait to unpack `u64` into various types for the `BitPacked` macro.
141pub trait Unpackable {
142    /// Convert the unpacked `u64` to `Self`.
143    fn unpack(val: u64) -> Self;
144}
145
146impl Unpackable for bool {
147    #[inline(always)]
148    fn unpack(val: u64) -> Self {
149        val != 0
150    }
151}
152
153macro_rules! impl_unpackable_int {
154    ($($ty:ty),*) => {
155        $(
156            impl Unpackable for $ty {
157                #[inline(always)]
158                fn unpack(val: u64) -> Self {
159                    val as $ty
160                }
161            }
162        )*
163    };
164}
165
166impl_unpackable_int!(
167    u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize
168);