Skip to main content

weida_protocol/
varint.rs

1//! QUIC variable-length integers (RFC 9000 §16).
2//!
3//! Used for the `header_len` field of the stream preamble. The two most
4//! significant bits of the first byte select the encoding length, so the
5//! representable range is `0..=2^62-1`.
6//!
7//! Encoding always uses the shortest form. Decoding accepts *any* form,
8//! including non-minimal ones, exactly as RFC 9000 requires: a peer that pads
9//! its length field is unusual but not hostile, and rejecting it would be an
10//! interoperability bug rather than a defence.
11
12use std::fmt;
13
14/// Largest value a QUIC varint can carry.
15pub const MAX: u64 = (1 << 62) - 1;
16
17/// Longest possible encoding, in bytes.
18pub const MAX_ENCODED_LEN: usize = 8;
19
20/// Why a varint could not be encoded or decoded.
21#[derive(Clone, Copy, Debug, PartialEq, Eq)]
22pub enum VarintError {
23    /// The value exceeds `2^62-1` and has no QUIC varint representation.
24    OutOfRange,
25    /// The input ended in the middle of a varint. Read more bytes and retry;
26    /// this is not a protocol violation.
27    Truncated,
28}
29
30impl fmt::Display for VarintError {
31    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
32        match self {
33            VarintError::OutOfRange => f.write_str("value exceeds the QUIC varint range"),
34            VarintError::Truncated => f.write_str("input ended inside a varint"),
35        }
36    }
37}
38
39impl std::error::Error for VarintError {}
40
41/// Number of bytes [`encode_varint`] will write for `value`.
42pub const fn varint_len(value: u64) -> usize {
43    if value < 1 << 6 {
44        1
45    } else if value < 1 << 14 {
46        2
47    } else if value < 1 << 30 {
48        4
49    } else {
50        8
51    }
52}
53
54/// Writes `value` into the front of `out` in its shortest QUIC varint form,
55/// and reports how many bytes it took.
56///
57/// The `Vec`-appending form below delegates to this one. A caller with a fixed
58/// buffer — a send path building a preamble it will right-align against an
59/// already-encoded header — allocates nothing (B-250).
60///
61/// # Errors
62///
63/// [`VarintError::OutOfRange`] above 2^62 − 1, and when `out` is shorter than
64/// the form `value` needs.
65pub fn write_varint(value: u64, out: &mut [u8]) -> Result<usize, VarintError> {
66    if value > MAX {
67        return Err(VarintError::OutOfRange);
68    }
69    let len = varint_len(value);
70    if out.len() < len {
71        return Err(VarintError::OutOfRange);
72    }
73    match len {
74        1 => out[0] = value as u8,
75        2 => out[..2].copy_from_slice(&((value as u16) | 0x4000).to_be_bytes()),
76        4 => out[..4].copy_from_slice(&((value as u32) | 0x8000_0000).to_be_bytes()),
77        _ => out[..8].copy_from_slice(&(value | 0xc000_0000_0000_0000).to_be_bytes()),
78    }
79    Ok(len)
80}
81
82/// Appends `value` to `out` in its shortest QUIC varint form.
83///
84/// # Errors
85///
86/// [`VarintError::OutOfRange`] above 2^62 − 1.
87pub fn encode_varint(value: u64, out: &mut Vec<u8>) -> Result<(), VarintError> {
88    let mut bytes = [0u8; 8];
89    let len = write_varint(value, &mut bytes)?;
90    out.extend_from_slice(&bytes[..len]);
91    Ok(())
92}
93
94/// Decodes a varint from the front of `input`.
95///
96/// Returns the value and the number of bytes consumed.
97pub fn decode_varint(input: &[u8]) -> Result<(u64, usize), VarintError> {
98    let first = *input.first().ok_or(VarintError::Truncated)?;
99    let len = 1usize << (first >> 6);
100    if input.len() < len {
101        return Err(VarintError::Truncated);
102    }
103    let mut value = u64::from(first & 0x3f);
104    for b in &input[1..len] {
105        value = (value << 8) | u64::from(*b);
106    }
107    Ok((value, len))
108}
109
110#[cfg(test)]
111mod tests {
112    use super::*;
113
114    fn enc(v: u64) -> Vec<u8> {
115        let mut out = Vec::new();
116        encode_varint(v, &mut out).unwrap();
117        out
118    }
119
120    #[test]
121    fn rfc_9000_appendix_a_vectors() {
122        // The worked examples from RFC 9000 §A.1.
123        assert_eq!(
124            decode_varint(&[0xc2, 0x19, 0x7c, 0x5e, 0xff, 0x14, 0xe8, 0x8c]).unwrap(),
125            (151_288_809_941_952_652, 8)
126        );
127        assert_eq!(
128            decode_varint(&[0x9d, 0x7f, 0x3e, 0x7d]).unwrap(),
129            (494_878_333, 4)
130        );
131        assert_eq!(decode_varint(&[0x7b, 0xbd]).unwrap(), (15_293, 2));
132        assert_eq!(decode_varint(&[0x25]).unwrap(), (37, 1));
133        // Non-minimal encoding of 37 in two bytes must still decode.
134        assert_eq!(decode_varint(&[0x40, 0x25]).unwrap(), (37, 2));
135    }
136
137    #[test]
138    fn encoding_is_minimal_at_every_boundary() {
139        let cases = [
140            (0u64, 1usize),
141            (63, 1),
142            (64, 2),
143            (16_383, 2),
144            (16_384, 4),
145            (1_073_741_823, 4),
146            (1_073_741_824, 8),
147            (MAX, 8),
148        ];
149        for (value, len) in cases {
150            assert_eq!(varint_len(value), len, "len of {value}");
151            assert_eq!(enc(value).len(), len, "encoded len of {value}");
152            assert_eq!(decode_varint(&enc(value)).unwrap(), (value, len));
153        }
154    }
155
156    #[test]
157    fn header_len_of_16384_is_the_four_byte_form() {
158        assert_eq!(enc(16_384), vec![0x80, 0x00, 0x40, 0x00]);
159    }
160
161    #[test]
162    fn out_of_range_is_rejected() {
163        let mut out = Vec::new();
164        assert_eq!(
165            encode_varint(MAX + 1, &mut out),
166            Err(VarintError::OutOfRange)
167        );
168        assert_eq!(
169            encode_varint(u64::MAX, &mut out),
170            Err(VarintError::OutOfRange)
171        );
172        assert!(out.is_empty(), "nothing is written on rejection");
173    }
174
175    #[test]
176    fn truncated_input_is_distinguishable_from_corruption() {
177        assert_eq!(decode_varint(&[]), Err(VarintError::Truncated));
178        assert_eq!(decode_varint(&[0x40]), Err(VarintError::Truncated));
179        assert_eq!(decode_varint(&[0x80, 0x00]), Err(VarintError::Truncated));
180        assert_eq!(decode_varint(&[0xc0; 7]), Err(VarintError::Truncated));
181        assert!(decode_varint(&[0xc0; 8]).is_ok());
182    }
183
184    #[test]
185    fn trailing_bytes_are_left_for_the_caller() {
186        let (v, n) = decode_varint(&[0x25, 0xff, 0xff]).unwrap();
187        assert_eq!((v, n), (37, 1));
188    }
189
190    #[test]
191    fn roundtrip_over_a_wide_spread_of_values() {
192        let mut x = 0x2545_f491_4f6c_dd1du64;
193        for _ in 0..2000 {
194            // xorshift64: deterministic, no dependency.
195            x ^= x << 13;
196            x ^= x >> 7;
197            x ^= x << 17;
198            let v = x & MAX;
199            assert_eq!(decode_varint(&enc(v)).unwrap().0, v);
200        }
201    }
202}