wtransport_proto/
varint.rs1use std::fmt;
2
3#[derive(Debug, thiserror::Error)]
5#[error("varint value is out of bounds")]
6pub struct VarIntBoundsExceeded;
7
8#[derive(Default, Copy, Clone, Eq, Hash, Ord, PartialEq, PartialOrd)]
12pub struct VarInt(u64);
13
14impl VarInt {
15 pub const MAX: Self = Self(4_611_686_018_427_387_903);
17
18 pub const MIN: Self = Self(0);
20
21 pub const MAX_SIZE: usize = 8;
23
24 #[inline(always)]
26 pub const fn from_u32(value: u32) -> Self {
27 Self(value as u64)
28 }
29
30 #[inline(always)]
32 pub const fn try_from_u64(value: u64) -> Result<Self, VarIntBoundsExceeded> {
33 if value <= Self::MAX.0 {
34 Ok(Self(value))
35 } else {
36 Err(VarIntBoundsExceeded)
37 }
38 }
39
40 #[inline(always)]
46 pub const unsafe fn from_u64_unchecked(value: u64) -> Self {
47 debug_assert!(value <= Self::MAX.into_inner());
48 Self(value)
49 }
50
51 #[inline(always)]
53 pub const fn into_inner(self) -> u64 {
54 self.0
55 }
56
57 pub const fn size(self) -> usize {
62 if self.0 <= 63 {
63 1
64 } else if self.0 <= 16383 {
65 2
66 } else if self.0 <= 1_073_741_823 {
67 4
68 } else if self.0 <= 4_611_686_018_427_387_903 {
69 8
70 } else {
71 unreachable!()
72 }
73 }
74
75 pub const fn parse_size(first: u8) -> usize {
77 match first >> 6 {
78 0 => 1,
79 1 => 2,
80 2 => 4,
81 3 => 8,
82 _ => unreachable!(),
83 }
84 }
85}
86
87impl From<u8> for VarInt {
88 #[inline(always)]
89 fn from(value: u8) -> Self {
90 Self::from_u32(u32::from(value))
91 }
92}
93
94impl From<u16> for VarInt {
95 #[inline(always)]
96 fn from(value: u16) -> Self {
97 Self::from_u32(u32::from(value))
98 }
99}
100
101impl From<u32> for VarInt {
102 #[inline(always)]
103 fn from(value: u32) -> Self {
104 Self::from_u32(value)
105 }
106}
107
108impl TryFrom<u64> for VarInt {
109 type Error = VarIntBoundsExceeded;
110
111 #[inline(always)]
112 fn try_from(value: u64) -> Result<Self, Self::Error> {
113 Self::try_from_u64(value)
114 }
115}
116
117impl From<VarInt> for u64 {
118 #[inline]
119 fn from(value: VarInt) -> Self {
120 value.0
121 }
122}
123
124impl fmt::Debug for VarInt {
125 #[inline]
126 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
127 self.0.fmt(f)
128 }
129}
130
131impl fmt::Display for VarInt {
132 #[inline]
133 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
134 self.0.fmt(f)
135 }
136}
137
138#[cfg(test)]
139mod tests {
140 use super::*;
141
142 #[test]
143 fn bounds() {
144 assert!(VarInt::try_from_u64(VarInt::MAX.into_inner()).is_ok());
145 assert!(VarInt::try_from_u64(VarInt::MAX.into_inner() + 1).is_err());
146 assert!(VarInt::try_from_u64(2_u64.pow(62)).is_err());
147 assert!(VarInt::try_from_u64(2_u64.pow(62) - 1).is_ok());
148 }
149
150 #[test]
151 fn size() {
152 assert!((1..=VarInt::MAX_SIZE).contains(&VarInt::try_from_u64(0).unwrap().size()));
153 assert!((1..=VarInt::MAX_SIZE).contains(&VarInt::try_from_u64(63).unwrap().size()));
154
155 assert!((2..=VarInt::MAX_SIZE).contains(&VarInt::try_from_u64(64).unwrap().size()));
156 assert!((2..=VarInt::MAX_SIZE).contains(&VarInt::try_from_u64(16383).unwrap().size()));
157
158 assert!((4..=VarInt::MAX_SIZE).contains(&VarInt::try_from_u64(16384).unwrap().size()));
159 assert!(
160 (4..=VarInt::MAX_SIZE).contains(&VarInt::try_from_u64(1_073_741_823).unwrap().size())
161 );
162
163 assert!(
164 (8..=VarInt::MAX_SIZE).contains(&VarInt::try_from_u64(1_073_741_824).unwrap().size())
165 );
166 assert!((8..=VarInt::MAX_SIZE).contains(
167 &VarInt::try_from_u64(4_611_686_018_427_387_903)
168 .unwrap()
169 .size()
170 ));
171
172 assert_eq!(VarInt::MAX_SIZE, 8);
173 assert_eq!(VarInt::MAX.size(), VarInt::MAX_SIZE);
174 }
175
176 #[test]
177 fn parse() {
178 assert_eq!(VarInt::parse_size(0xc2), 8);
179 assert_eq!(VarInt::parse_size(0x9d), 4);
180 assert_eq!(VarInt::parse_size(0x7b), 2);
181 assert_eq!(VarInt::parse_size(0x25), 1);
182 }
183}