steel_utils/codec/
variable_integer.rs1use std::io::{Cursor, Error, Write};
2
3use tokio::io::{AsyncRead, AsyncReadExt};
4
5use crate::{
6 FrontVec,
7 serial::{ReadFrom, WriteTo},
8};
9
10#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
12pub struct VarInt(pub i32);
13
14impl VarInt {
15 pub const MAX_SIZE: usize = 5;
17
18 #[must_use]
21 pub const fn written_size(val: i32) -> usize {
22 match val {
23 0 => 1,
24 n => (31 - n.leading_zeros() as usize) / 7 + 1,
25 }
26 }
27
28 pub async fn read_async(read: &mut (impl AsyncRead + Unpin)) -> Result<i32, Error> {
33 let mut val = 0;
34 for i in 0..Self::MAX_SIZE {
35 let byte = read
36 .read_u8()
37 .await
38 .map_err(|err| Error::new(err.kind(), "VarInt"))?;
39 val |= (i32::from(byte) & 0x7F) << (i * 7);
40 if byte & 0x80 == 0 {
41 return Ok(val);
42 }
43 }
44 Err(Error::other("VarInt"))
45 }
46
47 pub fn set_in_front(self, vec: &mut FrontVec, varint_size: usize) {
54 let mut buf = [0; Self::MAX_SIZE];
56 self.write(&mut Cursor::new(&mut buf[..]))
57 .expect("writing to a buffer should not fail");
58 vec.set_in_front(&buf[..varint_size]);
59 }
60}
61
62impl ReadFrom for VarInt {
63 fn read(read: &mut Cursor<&[u8]>) -> Result<Self, Error> {
64 let mut val = 0;
65 for i in 0..Self::MAX_SIZE {
66 let byte = u8::read(read)?;
67 val |= (i32::from(byte) & 0x7F) << (i * 7);
68 if byte & 0x80 == 0 {
69 return Ok(Self(val));
70 }
71 }
72 Err(Error::other("VarInt to long"))
73 }
74}
75
76impl WriteTo for VarInt {
77 fn write(&self, writer: &mut impl Write) -> Result<(), Error> {
78 let mut val = self.0 as u32;
79 loop {
80 let b: u8 = val as u8 & 0x7F;
81 val >>= 7;
82 if val == 0 {
83 b.write(writer)?;
84 break;
85 }
86 (b | 0x80).write(writer)?;
87 }
88 Ok(())
89 }
90}
91
92impl From<usize> for VarInt {
93 fn from(value: usize) -> Self {
94 Self(value as _)
95 }
96}
97
98#[expect(
99 clippy::cast_sign_loss,
100 reason = "VarInt values used as lengths are always non-negative"
101)]
102impl From<VarInt> for usize {
103 fn from(value: VarInt) -> usize {
104 value.0 as _
105 }
106}
107
108impl From<i32> for VarInt {
109 fn from(value: i32) -> Self {
110 Self(value as _)
111 }
112}
113
114impl From<VarInt> for i32 {
115 fn from(value: VarInt) -> i32 {
116 value.0
117 }
118}
119
120#[cfg(test)]
121mod var_int_tests {
122 use super::*;
123 use std::io::Cursor;
124
125 #[test]
126 fn test_varint_read_write_negative() {
127 let val = VarInt(-1);
128 let mut buf = Vec::new();
129 val.write(&mut buf).expect("write failed");
130
131 assert_eq!(buf, vec![0xff, 0xff, 0xff, 0xff, 0x0f]);
133
134 let mut cursor = Cursor::new(buf.as_slice());
135 let read_val = VarInt::read(&mut cursor).expect("read failed");
136 assert_eq!(read_val, val);
137 }
138}
139#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
141pub struct VarLong(pub i64);
142
143impl VarLong {
144 pub const MAX_SIZE: usize = 10;
146}
147
148impl ReadFrom for VarLong {
149 fn read(read: &mut Cursor<&[u8]>) -> Result<Self, Error> {
150 let mut val = 0i64;
151 for i in 0..Self::MAX_SIZE {
152 let byte = u8::read(read)?;
153 val |= (i64::from(byte) & 0x7F) << (i * 7);
154 if byte & 0x80 == 0 {
155 return Ok(Self(val));
156 }
157 }
158 Err(Error::other("VarLong too long"))
159 }
160}
161
162impl WriteTo for VarLong {
163 fn write(&self, writer: &mut impl Write) -> Result<(), Error> {
164 let mut val = self.0 as u64;
165 loop {
166 let b: u8 = val as u8 & 0x7F;
167 val >>= 7;
168 if val == 0 {
169 b.write(writer)?;
170 break;
171 }
172 (b | 0x80).write(writer)?;
173 }
174 Ok(())
175 }
176}
177
178impl From<i64> for VarLong {
179 fn from(value: i64) -> Self {
180 Self(value)
181 }
182}
183
184impl From<VarLong> for i64 {
185 fn from(value: VarLong) -> i64 {
186 value.0
187 }
188}
189
190#[cfg(test)]
191mod var_long_tests {
192 use super::*;
193 use std::io::Cursor;
194
195 #[test]
196 fn test_varlong_read_write() {
197 let test_values = vec![
198 0i64,
199 1i64,
200 127i64,
201 128i64,
202 255i64,
203 2_147_483_647_i64,
204 9_223_372_036_854_775_807_i64,
205 -1i64,
206 -2_147_483_648_i64,
207 ];
208
209 for val in test_values {
210 let var_long = VarLong(val);
211 let mut buf = Vec::new();
212 var_long.write(&mut buf).expect("write failed");
213
214 let mut cursor = Cursor::new(buf.as_slice());
215 let read_val = VarLong::read(&mut cursor).expect("read failed");
216 assert_eq!(read_val, var_long, "Failed for value {val}");
217 }
218 }
219}
220#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
222pub struct VarUint(pub u32);
223
224impl VarUint {
225 const MAX_SIZE: usize = 5;
226
227 #[must_use]
230 pub const fn written_size(self) -> usize {
231 (32 - self.0.leading_zeros() as usize).max(1).div_ceil(7)
232 }
233
234 pub fn write(self, writer: &mut impl Write) -> Result<(), Error> {
239 let mut val = self.0;
240 loop {
241 let mut byte = (val & 0x7F) as u8;
242 val >>= 7;
243 if val != 0 {
244 byte |= 0x80;
245 }
246 byte.write(writer)?;
247 if val == 0 {
248 break;
249 }
250 }
251 Ok(())
252 }
253
254 pub fn read(read: &mut Cursor<&[u8]>) -> Result<u32, Error> {
259 let mut val = 0;
260 for i in 0..Self::MAX_SIZE {
261 let byte = u8::read(read)?;
262 val |= (u32::from(byte) & 0x7F) << (i * 7);
263 if byte & 0x80 == 0 {
264 return Ok(val);
265 }
266 }
267 Err(Error::other("Malformed VarUint"))
268 }
269}