exp_golomb/
encoder.rs

1/// An Exponential-Golomb writer.
2pub struct ExpGolombEncoder<'a> {
3    bit_buf: BitBuffer<'a>,
4}
5
6impl<'a> ExpGolombEncoder<'a> {
7    /// Create a new `ExpGolombEncoder`.
8    ///
9    /// `start` denotes the starting position in the first byte of `buf` and goes from 0 (first) to
10    ///  7 (last). This function returns `None` if the buffer is empty or if `start` is  not within
11    /// \[0, 7\].
12    /// 
13    /// # Examples
14    ///
15    /// ```
16    /// # use exp_golomb::ExpGolombEncoder;
17    /// let mut buf = [0u8; 1];
18    /// // Write starting at the second bit
19    /// let mut writer = ExpGolombEncoder::new(&mut buf, 1).unwrap();
20    /// writer.put_unsigned(2).unwrap();
21    /// writer.close();
22    /// assert_eq!(buf[0], 0b00110000);
23    /// ```
24    #[inline]
25    #[must_use]
26    pub fn new(buf: &'a mut [u8], start: u32) -> Option<ExpGolombEncoder<'a>> {
27        if buf.is_empty() || start > 7 {
28            return None;
29        }
30        Some(ExpGolombEncoder {
31            bit_buf: BitBuffer::new(buf, start),
32        })
33    }
34
35    /// Encode a `u64` into the buffer. Returns `None` if the buffer is full.
36    ///
37    /// # Examples
38    ///
39    /// ```
40    /// # use exp_golomb::ExpGolombEncoder;
41    /// let mut buf = [0u8; 6];
42    /// let mut writer = ExpGolombEncoder::new(&mut buf, 0).unwrap();
43    /// for i in 0..=8 {
44    ///     writer.put_unsigned(i).unwrap();
45    /// }
46    /// writer.close();
47    /// 
48    /// assert_eq!(
49    ///     buf,
50    ///     [0b10100110, 0b01000010, 0b10011000, 0b11100010, 0b00000100, 0b10000000]
51    /// );
52    /// ```
53    /// 
54    /// This function guards against out of bounds indexing by returning `None`:
55    /// 
56    /// ```
57    /// # use exp_golomb::ExpGolombEncoder;
58    /// let mut buf = [0u8; 1];
59    /// let mut writer = ExpGolombEncoder::new(&mut buf, 0).unwrap();
60    /// assert!(writer.put_unsigned(1).is_some());
61    /// assert!(writer.put_unsigned(1).is_some());
62    /// assert!(writer.put_unsigned(1).is_none());
63    /// ```
64    #[inline]
65    #[must_use]
66    pub fn put_unsigned(&mut self, value: u64) -> Option<()> {
67        let xp1 = value.wrapping_add(1);
68
69        let bytes = xp1.to_be_bytes();
70        let lz = xp1.leading_zeros();
71        let start = (lz / 8) as usize;
72        let bit_start = lz - (lz / 8 * 8);
73
74        let num_zeros = 64 - lz - 1;
75        self.bit_buf.put_zeros(num_zeros);
76
77        self.bit_buf.put_bytes(&bytes[start..], bit_start)
78    }
79
80    /// Write a single bit to the buffer. Returns `None` if the buffer is full.
81    /// 
82    /// # Examples
83    ///
84    /// ```
85    /// # use exp_golomb::ExpGolombEncoder;
86    /// let mut buf = [0u8; 1];
87    /// let mut writer = ExpGolombEncoder::new(&mut buf, 6).unwrap();
88    /// writer.put_bit(true).unwrap();
89    /// writer.put_bit(false).unwrap();
90    /// assert!(writer.put_bit(true).is_none());
91    /// assert!(writer.put_bit(true).is_none());
92    /// writer.close();
93    /// assert_eq!(buf[0], 0b00000010);
94    /// ```
95    #[inline]
96    #[must_use]
97    pub fn put_bit(&mut self, value: bool) -> Option<()> {
98        self.bit_buf.put_bit(value)
99    }
100
101    /// Consumes the `ExpGolombEncoder`, returning the bit position one past the last written bit.
102    /// 
103    /// # Examples
104    ///
105    /// ```
106    /// # use exp_golomb::ExpGolombEncoder;
107    /// let mut buf = [0u8; 1];
108    /// let mut writer = ExpGolombEncoder::new(&mut buf, 2).unwrap();
109    /// writer.put_unsigned(0).unwrap();
110    /// assert_eq!(writer.close(), (0, 3));
111    /// ```
112    #[inline]
113    pub fn close(self) -> (usize, u32) {
114        (self.bit_buf.index, self.bit_buf.bit_pos)
115    }
116}
117
118struct BitBuffer<'a> {
119    buf: &'a mut [u8],
120    index: usize,
121    bit_pos: u32,
122}
123
124impl<'a> BitBuffer<'a> {
125    #[inline]
126    fn new(buf: &'a mut [u8], bit_pos: u32) -> BitBuffer<'a> {
127        BitBuffer {
128            buf,
129            index: 0,
130            bit_pos,
131        }
132    }
133
134    #[inline]
135    fn put_bit(&mut self, value: bool) -> Option<()> {
136        *self.buf.get_mut(self.index)? |= (value as u8) << (7 - self.bit_pos);
137        self.bit_pos += 1;
138        if self.bit_pos >= 8 {
139            self.bit_pos -= 8;
140            self.index += 1;
141        }
142        Some(())
143    }
144
145    #[inline]
146    fn put_zeros(&mut self, num_zeros: u32) -> Option<()> {
147        // TODO: Suboptimal
148        for _ in 0..num_zeros {
149            self.put_bit(false)?;
150        }
151        Some(())
152    }
153
154    #[inline]
155    #[must_use]
156    fn put_bytes(&mut self, bytes: &[u8], mut start_pos: u32) -> Option<()> {
157        for &byte in bytes {
158            while start_pos < 8 {
159                let data = ((byte as u32) << start_pos) >> self.bit_pos;
160                *self.buf.get_mut(self.index)? |= data as u8;
161
162                let shift_amount = 8 - u32::max(self.bit_pos, start_pos);
163                self.bit_pos += shift_amount;
164                if self.bit_pos >= 8 {
165                    self.bit_pos -= 8;
166                    self.index += 1;
167                }
168
169                start_pos += shift_amount;
170            }
171            start_pos -= 8;
172        }
173        Some(())
174    }
175}