Skip to main content

cram_codec/
bitio.rs

1//! Byte- and bit-level serialization primitives.
2//!
3//! Everything the codec emits goes through [`ByteWriter`], so the length of
4//! its buffer *is* the bit account: there is no side channel.
5
6/// Errors raised while parsing a bitstream.
7#[derive(Debug, Clone, PartialEq, Eq)]
8pub enum DecodeError {
9    /// The stream ended before a field was complete.
10    Truncated,
11    /// A field held a value the format does not allow.
12    Invalid(&'static str),
13}
14
15impl core::fmt::Display for DecodeError {
16    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
17        match self {
18            DecodeError::Truncated => write!(f, "bitstream truncated"),
19            DecodeError::Invalid(what) => write!(f, "invalid bitstream: {what}"),
20        }
21    }
22}
23
24impl std::error::Error for DecodeError {}
25
26/// Append-only byte buffer with LEB128 varints.
27#[derive(Default, Debug, Clone)]
28pub struct ByteWriter {
29    /// The bytes written so far.
30    pub buf: Vec<u8>,
31}
32
33impl ByteWriter {
34    /// Empty writer.
35    pub fn new() -> Self {
36        Self::default()
37    }
38    /// One raw byte.
39    pub fn u8(&mut self, v: u8) {
40        self.buf.push(v);
41    }
42    /// Unsigned LEB128.
43    pub fn varint(&mut self, mut v: u64) {
44        loop {
45            let b = (v & 0x7f) as u8;
46            v >>= 7;
47            if v == 0 {
48                self.buf.push(b);
49                return;
50            }
51            self.buf.push(b | 0x80);
52        }
53    }
54    /// Zigzag-mapped signed LEB128.
55    pub fn svarint(&mut self, v: i64) {
56        self.varint(zigzag(v));
57    }
58    /// Little-endian f64.
59    pub fn f64(&mut self, v: f64) {
60        self.buf.extend_from_slice(&v.to_le_bytes());
61    }
62    /// Length-prefixed byte block.
63    pub fn block(&mut self, bytes: &[u8]) {
64        self.varint(bytes.len() as u64);
65        self.buf.extend_from_slice(bytes);
66    }
67    /// Raw bytes, no prefix.
68    pub fn bytes(&mut self, bytes: &[u8]) {
69        self.buf.extend_from_slice(bytes);
70    }
71}
72
73/// Cursor over a byte slice, mirroring [`ByteWriter`].
74#[derive(Debug, Clone)]
75pub struct ByteReader<'a> {
76    buf: &'a [u8],
77    pos: usize,
78}
79
80impl<'a> ByteReader<'a> {
81    /// Start reading at offset 0.
82    pub fn new(buf: &'a [u8]) -> Self {
83        Self { buf, pos: 0 }
84    }
85    /// Bytes consumed so far.
86    pub fn position(&self) -> usize {
87        self.pos
88    }
89    /// One raw byte.
90    pub fn u8(&mut self) -> Result<u8, DecodeError> {
91        let b = *self.buf.get(self.pos).ok_or(DecodeError::Truncated)?;
92        self.pos += 1;
93        Ok(b)
94    }
95    /// Unsigned LEB128.
96    pub fn varint(&mut self) -> Result<u64, DecodeError> {
97        let mut v = 0u64;
98        let mut shift = 0;
99        loop {
100            let b = self.u8()?;
101            if shift >= 64 {
102                return Err(DecodeError::Invalid("varint overflow"));
103            }
104            v |= ((b & 0x7f) as u64) << shift;
105            if b & 0x80 == 0 {
106                return Ok(v);
107            }
108            shift += 7;
109        }
110    }
111    /// Zigzag-mapped signed LEB128.
112    pub fn svarint(&mut self) -> Result<i64, DecodeError> {
113        Ok(unzigzag(self.varint()?))
114    }
115    /// Little-endian f64.
116    pub fn f64(&mut self) -> Result<f64, DecodeError> {
117        let b = self.take(8)?;
118        Ok(f64::from_le_bytes(b.try_into().unwrap()))
119    }
120    /// `n` raw bytes.
121    pub fn take(&mut self, n: usize) -> Result<&'a [u8], DecodeError> {
122        let end = self.pos.checked_add(n).ok_or(DecodeError::Truncated)?;
123        let s = self.buf.get(self.pos..end).ok_or(DecodeError::Truncated)?;
124        self.pos = end;
125        Ok(s)
126    }
127    /// Length-prefixed byte block.
128    pub fn block(&mut self) -> Result<&'a [u8], DecodeError> {
129        let n = self.varint()? as usize;
130        self.take(n)
131    }
132}
133
134/// Signed → unsigned interleaving (0, -1, 1, -2, …).
135pub fn zigzag(v: i64) -> u64 {
136    ((v << 1) ^ (v >> 63)) as u64
137}
138
139/// Inverse of [`zigzag`].
140pub fn unzigzag(u: u64) -> i64 {
141    ((u >> 1) as i64) ^ -((u & 1) as i64)
142}
143
144/// LSB-first bit packer for raw (uniformly distributed) extra bits.
145#[derive(Default, Debug, Clone)]
146pub struct BitWriter {
147    buf: Vec<u8>,
148    acc: u64,
149    n: u32,
150}
151
152impl BitWriter {
153    /// Empty packer.
154    pub fn new() -> Self {
155        Self::default()
156    }
157    /// Append the low `nbits` (≤ 57) of `v`.
158    pub fn put(&mut self, v: u64, nbits: u32) {
159        debug_assert!(nbits <= 57);
160        if nbits == 0 {
161            return;
162        }
163        self.acc |= (v & ((1u64 << nbits) - 1)) << self.n;
164        self.n += nbits;
165        while self.n >= 8 {
166            self.buf.push(self.acc as u8);
167            self.acc >>= 8;
168            self.n -= 8;
169        }
170    }
171    /// Flush the partial byte and return the buffer.
172    pub fn finish(mut self) -> Vec<u8> {
173        if self.n > 0 {
174            self.buf.push(self.acc as u8);
175        }
176        self.buf
177    }
178}
179
180/// Reader for [`BitWriter`] output.
181#[derive(Debug, Clone)]
182pub struct BitReader<'a> {
183    buf: &'a [u8],
184    pos: usize,
185    acc: u64,
186    n: u32,
187}
188
189impl<'a> BitReader<'a> {
190    /// Start at bit 0.
191    pub fn new(buf: &'a [u8]) -> Self {
192        Self {
193            buf,
194            pos: 0,
195            acc: 0,
196            n: 0,
197        }
198    }
199    /// Read `nbits` (≤ 57) bits.
200    pub fn get(&mut self, nbits: u32) -> Result<u64, DecodeError> {
201        if nbits == 0 {
202            return Ok(0);
203        }
204        while self.n < nbits {
205            let b = *self.buf.get(self.pos).ok_or(DecodeError::Truncated)?;
206            self.pos += 1;
207            self.acc |= (b as u64) << self.n;
208            self.n += 8;
209        }
210        let v = self.acc & ((1u64 << nbits) - 1);
211        self.acc >>= nbits;
212        self.n -= nbits;
213        Ok(v)
214    }
215}
216
217#[cfg(test)]
218mod tests {
219    use super::*;
220
221    #[test]
222    fn varint_and_zigzag_roundtrip() {
223        let mut w = ByteWriter::new();
224        let vals = [0i64, -1, 1, 63, -64, 1 << 40, i64::MIN + 1, i64::MAX];
225        for &v in &vals {
226            w.svarint(v);
227        }
228        w.f64(-3.25);
229        let mut r = ByteReader::new(&w.buf);
230        for &v in &vals {
231            assert_eq!(r.svarint().unwrap(), v);
232        }
233        assert_eq!(r.f64().unwrap(), -3.25);
234        assert_eq!(r.u8(), Err(DecodeError::Truncated));
235    }
236
237    #[test]
238    fn bits_roundtrip() {
239        let mut w = BitWriter::new();
240        for i in 0..200u64 {
241            w.put(i * 7919, (i % 30) as u32);
242        }
243        let buf = w.finish();
244        let mut r = BitReader::new(&buf);
245        for i in 0..200u64 {
246            let nb = (i % 30) as u32;
247            let mask = if nb == 0 { 0 } else { (1u64 << nb) - 1 };
248            assert_eq!(r.get(nb).unwrap(), (i * 7919) & mask);
249        }
250    }
251}