radicle_protocol/wire/
varint.rs

1//! Variable-length integer implementation based on QUIC.
2#![warn(clippy::missing_docs_in_private_items)]
3
4// This implementation is largely based on the `quinn` crate.
5// Copyright (c) 2018 The quinn developers.
6use std::{fmt, ops};
7
8use bytes::{Buf, BufMut};
9use thiserror::Error;
10
11use crate::wire;
12use crate::wire::{Decode, Encode};
13
14/// An integer less than 2^62
15///
16/// Based on QUIC variable-length integers (RFC 9000).
17///
18/// > The QUIC variable-length integer encoding reserves the two most significant bits of the first
19/// > byte to encode the base-2 logarithm of the integer encoding length in bytes. The integer value is
20/// > encoded on the remaining bits, in network byte order. This means that integers are encoded on 1,
21/// > 2, 4, or 8 bytes and can encode 6-, 14-, 30-, or 62-bit values, respectively. Table 4 summarizes
22/// > the encoding properties.
23///
24/// ```text
25/// MSB   Length   Usable Bits   Range
26/// ----------------------------------------------------
27/// 00    1        6             0 - 63
28/// 01    2        14            0 - 16383
29/// 10    4        30            0 - 1073741823
30/// 11    8        62            0 - 4611686018427387903
31/// ```
32#[derive(Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
33pub struct VarInt(pub(crate) u64);
34
35impl VarInt {
36    /// The largest representable value.
37    pub const MAX: VarInt = VarInt((1 << 62) - 1);
38
39    /// Succeeds iff `x` < 2^62.
40    pub fn new(x: u64) -> Result<Self, BoundsExceeded> {
41        if x <= Self::MAX.0 {
42            Ok(Self(x))
43        } else {
44            Err(BoundsExceeded)
45        }
46    }
47
48    pub fn new_unchecked(x: u64) -> Self {
49        Self(x)
50    }
51}
52
53impl ops::Deref for VarInt {
54    type Target = u64;
55
56    fn deref(&self) -> &Self::Target {
57        &self.0
58    }
59}
60
61impl From<u8> for VarInt {
62    fn from(x: u8) -> Self {
63        VarInt(x.into())
64    }
65}
66
67impl From<u16> for VarInt {
68    fn from(x: u16) -> Self {
69        VarInt(x.into())
70    }
71}
72
73impl From<u32> for VarInt {
74    fn from(x: u32) -> Self {
75        VarInt(x.into())
76    }
77}
78
79impl std::convert::TryFrom<u64> for VarInt {
80    type Error = BoundsExceeded;
81    /// Succeeds iff `x` < 2^62.
82    fn try_from(x: u64) -> Result<Self, BoundsExceeded> {
83        VarInt::new(x)
84    }
85}
86
87impl fmt::Debug for VarInt {
88    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
89        self.0.fmt(f)
90    }
91}
92
93impl fmt::Display for VarInt {
94    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
95        self.0.fmt(f)
96    }
97}
98
99/// Error returned when constructing a `VarInt` from a value >= 2^62.
100#[derive(Debug, Copy, Clone, Eq, PartialEq, Error)]
101#[error("value too large for varint encoding")]
102pub struct BoundsExceeded;
103
104impl Decode for VarInt {
105    fn decode(buf: &mut impl Buf) -> Result<Self, wire::Error> {
106        let mut tmp = [0; 8];
107        tmp[0] = buf.try_get_u8()?;
108
109        // Integer length.
110        let tag = tmp[0] >> 6;
111        tmp[0] &= 0b0011_1111;
112
113        let x = match tag {
114            0b00 => u64::from(tmp[0]),
115            0b01 => {
116                buf.try_copy_to_slice(&mut tmp[1..2])?;
117                u64::from(u16::from_be_bytes([tmp[0], tmp[1]]))
118            }
119            0b10 => {
120                buf.try_copy_to_slice(&mut tmp[1..4])?;
121                u64::from(u32::from_be_bytes([tmp[0], tmp[1], tmp[2], tmp[3]]))
122            }
123            0b11 => {
124                buf.try_copy_to_slice(&mut tmp[1..8])?;
125                u64::from_be_bytes(tmp)
126            }
127            // SAFETY: It should be obvious that we can't have any other bit pattern
128            // than the above, since all other bits are zeroed.
129            _ => unreachable! {},
130        };
131        Ok(Self(x))
132    }
133}
134
135impl Encode for VarInt {
136    fn encode(&self, w: &mut impl BufMut) {
137        let x: u64 = self.0;
138
139        if x < 2u64.pow(6) {
140            (x as u8).encode(w)
141        } else if x < 2u64.pow(14) {
142            ((0b01 << 14) | x as u16).encode(w)
143        } else if x < 2u64.pow(30) {
144            ((0b10 << 30) | x as u32).encode(w)
145        } else if x < 2u64.pow(62) {
146            ((0b11 << 62) | x).encode(w)
147        } else {
148            panic!("VarInt::encode: integer overflow");
149        }
150    }
151}
152
153/// Encoding and decoding varint-prefixed payloads.
154pub mod payload {
155    use super::*;
156
157    /// Encode varint-prefixed data payload.
158    pub fn encode(payload: &[u8], buf: &mut impl BufMut) {
159        let len = payload.len();
160        let varint = VarInt::new_unchecked(len as u64);
161
162        varint.encode(buf); // The length of the payload length.
163        buf.put_slice(payload);
164    }
165
166    /// Decode varint-prefixed data payload.
167    pub fn decode(buf: &mut impl Buf) -> Result<Vec<u8>, wire::Error> {
168        let size = VarInt::decode(buf)?;
169        let mut data = vec![0; *size as usize];
170        buf.try_copy_to_slice(&mut data[..])?;
171
172        Ok(data)
173    }
174}
175
176#[cfg(test)]
177mod test {
178    use qcheck_macros::quickcheck;
179
180    use crate::prop_roundtrip;
181
182    use super::*;
183
184    prop_roundtrip!(VarInt);
185
186    impl qcheck::Arbitrary for VarInt {
187        fn arbitrary(g: &mut qcheck::Gen) -> Self {
188            let a = u16::arbitrary(g) as u64;
189            let b = u32::arbitrary(g) as u64;
190            let n = g
191                .choose(&[
192                    0,
193                    1,
194                    3,
195                    7,
196                    13,
197                    37,
198                    255,
199                    4931,
200                    54019,
201                    69149,
202                    151288809941952652,
203                    u8::MAX as u64,
204                    u16::MAX as u64,
205                    u16::MAX as u64 - 1,
206                    u32::MAX as u64,
207                    u32::MAX as u64 - 1,
208                    *Self::MAX,
209                    a,
210                    b,
211                ])
212                .copied()
213                .unwrap();
214
215            Self(n)
216        }
217    }
218
219    #[test]
220    #[should_panic(expected = "overflow")]
221    fn test_encode_overflow() {
222        VarInt(u64::MAX).encode_to_vec();
223    }
224
225    #[test]
226    fn test_encoding() {
227        assert_eq!(VarInt(0).encode_to_vec(), vec![0x0]);
228        assert_eq!(VarInt(1).encode_to_vec(), vec![0x01]);
229        assert_eq!(VarInt(10).encode_to_vec(), vec![0x0a]);
230        assert_eq!(VarInt(37).encode_to_vec(), vec![0x25]);
231        assert_eq!(VarInt::decode_exact(&[0x40, 0x25]).unwrap(), VarInt(37));
232        assert_eq!(VarInt(15293).encode_to_vec(), vec![0x7b, 0xbd]);
233        assert_eq!(
234            VarInt(494878333).encode_to_vec(),
235            vec![0x9d, 0x7f, 0x3e, 0x7d],
236        );
237        assert_eq!(
238            VarInt(151288809941952652).encode_to_vec(),
239            vec![0xc2, 0x19, 0x7c, 0x5e, 0xff, 0x14, 0xe8, 0x8c]
240        );
241        assert_eq!(
242            VarInt(10000000000).encode_to_vec(),
243            vec![0xc0, 0x00, 0x00, 0x02, 0x54, 0x0b, 0xe4, 0x00],
244        );
245    }
246}