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}