1#[allow(unused_imports)]
8use std_shims::prelude::*;
9use std_shims::io::{self, Read, Write};
10
11use crate::{read_byte, write_byte};
12
13const VARINT_CONTINUATION_FLAG: u8 = 0b1000_0000;
14const VARINT_VALUE_MASK: u8 = !VARINT_CONTINUATION_FLAG;
15
16mod sealed {
17 pub trait Sealed {
19 fn into_u64(self) -> u64;
25 }
26}
27
28#[allow(clippy::cast_possible_truncation)]
33const fn upper_bound(bits: u32) -> usize {
34 assert!(bits <= 256, "defining a number exceeding u256 as a VarInt");
36 ((bits + (7 - 1)) / 7) as usize
39}
40
41pub trait VarInt: TryFrom<u64> + Copy + sealed::Sealed {
46 const LOWER_BOUND: usize;
48
49 const UPPER_BOUND: usize;
51
52 fn varint_len(self) -> usize {
54 let varint_u64 = self.into_u64();
55 usize::try_from(u64::BITS - varint_u64.leading_zeros()).expect("64 > usize::MAX?").div_ceil(7)
56 }
57
58 fn read<R: Read>(r: &mut R) -> io::Result<Self> {
60 let mut bits = 0;
61 let mut res = 0;
62 while {
63 let b = read_byte(r)?;
64 if (bits != 0) && (b == 0) {
68 Err(io::Error::other("non-canonical varint"))?;
69 }
70
71 #[allow(non_snake_case)]
74 let U_BITS = core::mem::size_of::<Self>() * 8;
75 if ((bits + 7) >= U_BITS) && (b >= (1 << (U_BITS - bits))) {
76 Err(io::Error::other("varint overflow"))?;
77 }
78
79 res += u64::from(b & VARINT_VALUE_MASK) << bits;
80 bits += 7;
81 (b & VARINT_CONTINUATION_FLAG) == VARINT_CONTINUATION_FLAG
82 } {}
83 res.try_into().map_err(|_| io::Error::other("VarInt does not fit into integer type"))
84 }
85
86 fn write<W: Write>(varint: &Self, w: &mut W) -> io::Result<()> {
91 let mut varint: u64 = varint.into_u64();
92
93 while {
95 let mut b = u8::try_from(varint & u64::from(VARINT_VALUE_MASK))
97 .expect("& 0b0111_1111 left more than 8 bits set");
98 varint >>= 7;
99
100 if varint != 0 {
102 b |= VARINT_CONTINUATION_FLAG;
103 }
104
105 write_byte(&b, w)?;
107
108 varint != 0
110 } {}
111
112 Ok(())
113 }
114}
115
116impl sealed::Sealed for u8 {
117 fn into_u64(self) -> u64 {
118 self.into()
119 }
120}
121impl VarInt for u8 {
122 const LOWER_BOUND: usize = 1;
123 const UPPER_BOUND: usize = upper_bound(Self::BITS);
124}
125
126impl sealed::Sealed for u32 {
127 fn into_u64(self) -> u64 {
128 self.into()
129 }
130}
131impl VarInt for u32 {
132 const LOWER_BOUND: usize = 1;
133 const UPPER_BOUND: usize = upper_bound(Self::BITS);
134}
135
136impl sealed::Sealed for u64 {
137 fn into_u64(self) -> u64 {
138 self
139 }
140}
141impl VarInt for u64 {
142 const LOWER_BOUND: usize = 1;
143 const UPPER_BOUND: usize = upper_bound(Self::BITS);
144}
145
146impl sealed::Sealed for usize {
147 fn into_u64(self) -> u64 {
148 const _NO_128_BIT_PLATFORMS: [(); (u64::BITS - usize::BITS) as usize] =
150 [(); (u64::BITS - usize::BITS) as usize];
151
152 self.try_into().expect("compiling on platform with <64-bit usize yet value didn't fit in u64")
153 }
154}
155impl VarInt for usize {
156 const LOWER_BOUND: usize = 1;
157 const UPPER_BOUND: usize = upper_bound(Self::BITS);
158}