Skip to main content

wire_codec/
varint.rs

1//! Unsigned LEB128 varint encoding.
2//!
3//! A varint encodes an unsigned integer in one to ten bytes. The low seven
4//! bits of each byte carry payload, and the top bit signals continuation:
5//! `1` means more bytes follow, `0` means the value is complete.
6//!
7//! The encoding is identical to the format used by Protocol Buffers, WebAssembly,
8//! and DWARF.
9
10use crate::buf::{ReadBuf, WriteBuf};
11use crate::error::{Error, Result};
12
13/// Maximum encoded length of a `u16` varint.
14pub const MAX_LEN_U16: usize = 3;
15/// Maximum encoded length of a `u32` varint.
16pub const MAX_LEN_U32: usize = 5;
17/// Maximum encoded length of a `u64` varint.
18pub const MAX_LEN_U64: usize = 10;
19
20/// Encoded length of `value` as a `u32` varint, in bytes (1 to 5).
21///
22/// # Example
23///
24/// ```
25/// use wire_codec::varint;
26/// assert_eq!(varint::encoded_len_u32(0), 1);
27/// assert_eq!(varint::encoded_len_u32(127), 1);
28/// assert_eq!(varint::encoded_len_u32(128), 2);
29/// assert_eq!(varint::encoded_len_u32(u32::MAX), 5);
30/// ```
31#[inline]
32// Manual ceiling-divide. `usize::div_ceil` is not const-stable on MSRV 1.75.
33// `unknown_lints` shields older clippy releases that lack `manual_div_ceil`.
34#[allow(unknown_lints, clippy::manual_div_ceil)]
35pub const fn encoded_len_u32(value: u32) -> usize {
36    let bits = (u32::BITS - value.leading_zeros()) as usize;
37    if bits == 0 {
38        1
39    } else {
40        (bits + 6) / 7
41    }
42}
43
44/// Encoded length of `value` as a `u64` varint, in bytes (1 to 10).
45///
46/// # Example
47///
48/// ```
49/// use wire_codec::varint;
50/// assert_eq!(varint::encoded_len_u64(0), 1);
51/// assert_eq!(varint::encoded_len_u64(u64::MAX), 10);
52/// ```
53#[inline]
54// Manual ceiling-divide. `usize::div_ceil` is not const-stable on MSRV 1.75.
55// `unknown_lints` shields older clippy releases that lack `manual_div_ceil`.
56#[allow(unknown_lints, clippy::manual_div_ceil)]
57pub const fn encoded_len_u64(value: u64) -> usize {
58    let bits = (u64::BITS - value.leading_zeros()) as usize;
59    if bits == 0 {
60        1
61    } else {
62        (bits + 6) / 7
63    }
64}
65
66/// Encode `value` as a `u32` varint into `buf`.
67///
68/// # Errors
69///
70/// Returns [`Error::BufferFull`] if `buf` has fewer than [`encoded_len_u32`]
71/// bytes available.
72///
73/// # Example
74///
75/// ```
76/// use wire_codec::{varint, WriteBuf};
77/// let mut out = [0u8; 5];
78/// let mut buf = WriteBuf::new(&mut out);
79/// varint::encode_u32(300, &mut buf).unwrap();
80/// assert_eq!(buf.written(), &[0xAC, 0x02]);
81/// ```
82#[inline]
83pub fn encode_u32(mut value: u32, buf: &mut WriteBuf<'_>) -> Result<()> {
84    while value >= 0x80 {
85        buf.write_u8(((value & 0x7F) as u8) | 0x80)?;
86        value >>= 7;
87    }
88    buf.write_u8(value as u8)
89}
90
91/// Encode `value` as a `u64` varint into `buf`.
92///
93/// # Errors
94///
95/// Returns [`Error::BufferFull`] if `buf` has fewer than [`encoded_len_u64`]
96/// bytes available.
97#[inline]
98pub fn encode_u64(mut value: u64, buf: &mut WriteBuf<'_>) -> Result<()> {
99    while value >= 0x80 {
100        buf.write_u8(((value & 0x7F) as u8) | 0x80)?;
101        value >>= 7;
102    }
103    buf.write_u8(value as u8)
104}
105
106/// Decode a `u32` varint from `buf`.
107///
108/// # Errors
109///
110/// - [`Error::UnexpectedEof`] if `buf` is exhausted before the terminator byte.
111/// - [`Error::VarintOverflow`] if the decoded value exceeds `u32::MAX` or if
112///   more than [`MAX_LEN_U32`] bytes are consumed.
113///
114/// # Example
115///
116/// ```
117/// use wire_codec::{varint, ReadBuf};
118/// let mut buf = ReadBuf::new(&[0xAC, 0x02]);
119/// assert_eq!(varint::decode_u32(&mut buf).unwrap(), 300);
120/// ```
121#[inline]
122pub fn decode_u32(buf: &mut ReadBuf<'_>) -> Result<u32> {
123    let mut value: u64 = 0;
124    let mut shift: u32 = 0;
125    for i in 0..MAX_LEN_U32 {
126        let byte = buf.read_u8()?;
127        value |= u64::from(byte & 0x7F) << shift;
128        if byte & 0x80 == 0 {
129            if value > u64::from(u32::MAX) {
130                return Err(Error::VarintOverflow);
131            }
132            // Final byte of a 5-byte u32 varint can only hold 4 payload bits.
133            if i == MAX_LEN_U32 - 1 && byte > 0x0F {
134                return Err(Error::VarintOverflow);
135            }
136            return Ok(value as u32);
137        }
138        shift += 7;
139    }
140    Err(Error::VarintOverflow)
141}
142
143/// Decode a `u64` varint from `buf`.
144///
145/// # Errors
146///
147/// - [`Error::UnexpectedEof`] if `buf` is exhausted before the terminator byte.
148/// - [`Error::VarintOverflow`] if more than [`MAX_LEN_U64`] bytes are consumed
149///   or the final byte carries bits that would overflow `u64`.
150#[inline]
151pub fn decode_u64(buf: &mut ReadBuf<'_>) -> Result<u64> {
152    let mut value: u64 = 0;
153    let mut shift: u32 = 0;
154    for i in 0..MAX_LEN_U64 {
155        let byte = buf.read_u8()?;
156        if i == MAX_LEN_U64 - 1 {
157            // Final byte of a 10-byte u64 varint can only carry 1 payload bit.
158            if byte & 0xFE != 0 {
159                return Err(Error::VarintOverflow);
160            }
161            value |= u64::from(byte & 0x01) << shift;
162            return Ok(value);
163        }
164        value |= u64::from(byte & 0x7F) << shift;
165        if byte & 0x80 == 0 {
166            return Ok(value);
167        }
168        shift += 7;
169    }
170    Err(Error::VarintOverflow)
171}
172
173#[cfg(test)]
174mod tests {
175    use super::*;
176
177    fn round_trip_u32(value: u32) {
178        let mut storage = [0u8; MAX_LEN_U32];
179        let mut w = WriteBuf::new(&mut storage);
180        encode_u32(value, &mut w).unwrap();
181        let n = w.position();
182        assert_eq!(n, encoded_len_u32(value));
183        let mut r = ReadBuf::new(&storage[..n]);
184        assert_eq!(decode_u32(&mut r).unwrap(), value);
185        assert!(r.is_empty());
186    }
187
188    fn round_trip_u64(value: u64) {
189        let mut storage = [0u8; MAX_LEN_U64];
190        let mut w = WriteBuf::new(&mut storage);
191        encode_u64(value, &mut w).unwrap();
192        let n = w.position();
193        assert_eq!(n, encoded_len_u64(value));
194        let mut r = ReadBuf::new(&storage[..n]);
195        assert_eq!(decode_u64(&mut r).unwrap(), value);
196        assert!(r.is_empty());
197    }
198
199    #[test]
200    fn u32_boundaries() {
201        for &v in &[
202            0u32,
203            1,
204            127,
205            128,
206            16_383,
207            16_384,
208            2_097_151,
209            2_097_152,
210            u32::MAX,
211        ] {
212            round_trip_u32(v);
213        }
214    }
215
216    #[test]
217    fn u64_boundaries() {
218        for &v in &[0u64, 127, 128, 1 << 35, 1 << 56, u64::MAX] {
219            round_trip_u64(v);
220        }
221    }
222
223    #[test]
224    fn decode_u32_overflow_on_sixth_byte() {
225        let mut buf = ReadBuf::new(&[0x80, 0x80, 0x80, 0x80, 0x80, 0x01]);
226        assert_eq!(decode_u32(&mut buf), Err(Error::VarintOverflow));
227    }
228
229    #[test]
230    fn decode_u32_overflow_in_final_byte() {
231        // Five bytes, terminator carries bits above the 32-bit window.
232        let mut buf = ReadBuf::new(&[0xFF, 0xFF, 0xFF, 0xFF, 0x10]);
233        assert_eq!(decode_u32(&mut buf), Err(Error::VarintOverflow));
234    }
235
236    #[test]
237    fn decode_truncated() {
238        // Continuation bit set on the only byte present.
239        let mut buf = ReadBuf::new(&[0x80]);
240        assert_eq!(decode_u32(&mut buf), Err(Error::UnexpectedEof));
241    }
242}