radicle_protocol/wire/
varint.rs1#![warn(clippy::missing_docs_in_private_items)]
3
4use std::{fmt, ops};
7
8use bytes::{Buf, BufMut};
9use thiserror::Error;
10
11use crate::wire;
12use crate::wire::{Decode, Encode};
13
14#[derive(Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
33pub struct VarInt(pub(crate) u64);
34
35impl VarInt {
36 pub const MAX: VarInt = VarInt((1 << 62) - 1);
38
39 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 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#[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 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 _ => 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
153pub mod payload {
155 use super::*;
156
157 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); buf.put_slice(payload);
164 }
165
166 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}