rust_bitfield_serializer/
utils.rs

1//! Utility structures and functions for bit manipulation.
2
3/// A utility for writing bits to a byte vector.
4#[derive(Debug, Clone)]
5pub struct BitWriter {
6    data: Vec<u8>,
7    bit_pos: usize,
8}
9
10impl BitWriter {
11    /// Create a new BitWriter.
12    pub fn new() -> Self {
13        Self {
14            data: Vec::new(),
15            bit_pos: 0,
16        }
17    }
18
19    /// Write multiple bits from a u64 value.
20    pub fn write_bits(&mut self, value: u64, num_bits: usize) {
21        for i in 0..num_bits {
22            // Extract bits from MSB first
23            let bit = (value >> (num_bits - 1 - i)) & 1;
24            self.write_bit(bit != 0);
25        }
26    }
27
28    /// Write a single bit.
29    pub fn write_bit(&mut self, bit: bool) {
30        let byte_pos = self.bit_pos / 8;
31        // Use big-endian bit order within each byte
32        let bit_offset = 7 - (self.bit_pos % 8);
33
34        // Ensure we have enough bytes
35        while self.data.len() <= byte_pos {
36            self.data.push(0);
37        }
38
39        if bit {
40            self.data[byte_pos] |= 1 << bit_offset;
41        }
42
43        self.bit_pos += 1;
44    }
45
46    /// Write bits directly to an existing byte array.
47    pub fn write_bits_to(data: &mut [u8], start_bit: usize, value: u64, num_bits: usize) {
48        for i in 0..num_bits {
49            let bit_pos = start_bit + i;
50            let byte_pos = bit_pos / 8;
51            // Big-endian bit order in byte
52            let bit_offset = 7 - (bit_pos % 8);
53
54            if byte_pos >= data.len() {
55                break;
56            }
57
58            // Extract bits MSB first
59            let bit = (value >> (num_bits - 1 - i)) & 1;
60            if bit != 0 {
61                data[byte_pos] |= 1 << bit_offset;
62            } else {
63                data[byte_pos] &= !(1 << bit_offset);
64            }
65        }
66    }
67
68    /// Finish writing and return the byte vector.
69    pub fn finish(mut self) -> Vec<u8> {
70        // Ensure the last byte is included if we wrote any bits to it
71        if self.bit_pos % 8 != 0 {
72            let byte_pos = self.bit_pos / 8;
73            while self.data.len() <= byte_pos {
74                self.data.push(0);
75            }
76        }
77        self.data
78    }
79
80    /// Get the current bit position.
81    pub fn bit_position(&self) -> usize {
82        self.bit_pos
83    }
84
85    /// Get a reference to the current data.
86    pub fn data(&self) -> &[u8] {
87        &self.data
88    }
89}
90
91impl Default for BitWriter {
92    fn default() -> Self {
93        Self::new()
94    }
95}
96
97/// A utility for reading bits from a byte slice.
98#[derive(Debug, Clone)]
99pub struct BitReader<'a> {
100    data: &'a [u8],
101    bit_pos: usize,
102}
103
104impl<'a> BitReader<'a> {
105    /// Create a new BitReader.
106    pub fn new(data: &'a [u8]) -> Self {
107        Self { data, bit_pos: 0 }
108    }
109
110    /// Read multiple bits as a u64 value.
111    pub fn read_bits(&mut self, num_bits: usize) -> Result<u64, String> {
112        let mut value = 0u64;
113        for i in 0..num_bits {
114            let bit = self.read_bit()?;
115            if bit {
116                // Assemble value MSB first
117                value |= 1 << (num_bits - 1 - i);
118            }
119        }
120        Ok(value)
121    }
122
123    /// Read a single bit.
124    pub fn read_bit(&mut self) -> Result<bool, String> {
125        let byte_pos = self.bit_pos / 8;
126        // Big-endian bit order
127        let bit_offset = 7 - (self.bit_pos % 8);
128
129        if byte_pos >= self.data.len() {
130            return Err("Unexpected end of data".to_string());
131        }
132
133        let bit = (self.data[byte_pos] >> bit_offset) & 1;
134        self.bit_pos += 1;
135
136        Ok(bit != 0)
137    }
138
139    /// Read bits from a specific position without advancing the reader.
140    pub fn read_bits_at(data: &[u8], start_bit: usize, num_bits: usize) -> u64 {
141        let mut value = 0u64;
142        for i in 0..num_bits {
143            let bit_pos = start_bit + i;
144            let byte_pos = bit_pos / 8;
145            // Big-endian bit order
146            let bit_offset = 7 - (bit_pos % 8);
147
148            if byte_pos >= data.len() {
149                break;
150            }
151
152            let bit = (data[byte_pos] >> bit_offset) & 1;
153            if bit != 0 {
154                // Assemble MSB first
155                value |= 1 << (num_bits - 1 - i);
156            }
157        }
158        value
159    }
160
161    /// Get the current bit position.
162    pub fn bit_position(&self) -> usize {
163        self.bit_pos
164    }
165
166    /// Check if there are more bits to read.
167    pub fn has_bits(&self) -> bool {
168        self.bit_pos < self.data.len() * 8
169    }
170
171    /// Reset the reader to the beginning.
172    pub fn reset(&mut self) {
173        self.bit_pos = 0;
174    }
175}
176
177#[cfg(test)]
178mod tests {
179    use super::*;
180
181    #[test]
182    fn test_bit_writer_basic() {
183        let mut writer = BitWriter::new();
184        writer.write_bits(0b1010, 4);
185        let data = writer.finish();
186        // Should write in big-endian into high bits of byte
187        assert_eq!(data, vec![0b1010_0000]);
188    }
189
190    #[test]
191    fn test_bit_writer_multiple_bytes() {
192        let mut writer = BitWriter::new();
193        writer.write_bits(0xFF, 8); // First byte
194        writer.write_bits(0xAA, 8); // Second byte
195        let data = writer.finish();
196        assert_eq!(data, vec![0xFF, 0xAA]);
197    }
198
199    #[test]
200    fn test_bit_reader_basic() {
201        // Data in big-endian nibble
202        let data = vec![0b1010_0000];
203        let mut reader = BitReader::new(&data);
204        let value = reader.read_bits(4).unwrap();
205        assert_eq!(value, 0b1010);
206    }
207
208    #[test]
209    fn test_bit_reader_multiple_bytes() {
210        let data = vec![0xFF, 0xAA];
211        let mut reader = BitReader::new(&data);
212        let first = reader.read_bits(8).unwrap();
213        let second = reader.read_bits(8).unwrap();
214        assert_eq!(first, 0xFF);
215        assert_eq!(second, 0xAA);
216    }
217
218    #[test]
219    fn test_roundtrip() {
220        let mut writer = BitWriter::new();
221        writer.write_bits(0b10101010, 8);
222        writer.write_bits(0b11001100, 8);
223        let data = writer.finish();
224
225        assert_eq!(data, vec![0b10101010, 0b11001100]);
226
227        let mut reader = BitReader::new(&data);
228        let first = reader.read_bits(8).unwrap();
229        let second = reader.read_bits(8).unwrap();
230
231        assert_eq!(first, 0b10101010);
232        assert_eq!(second, 0b11001100);
233    }
234
235    #[test]
236    fn test_write_bits_to() {
237        let mut data = vec![0u8; 2];
238        BitWriter::write_bits_to(&mut data, 0, 0b1010, 4);
239        BitWriter::write_bits_to(&mut data, 4, 0b1100, 4);
240        // High nibble 1010, low nibble 1100
241        assert_eq!(data[0], 0b1010_1100);
242    }
243
244    #[test]
245    fn test_read_bits_at() {
246        let data = vec![0b1010_1100];
247        let first_nibble = BitReader::read_bits_at(&data, 0, 4);
248        let second_nibble = BitReader::read_bits_at(&data, 4, 4);
249        assert_eq!(first_nibble, 0b1010);
250        assert_eq!(second_nibble, 0b1100);
251    }
252}