1use std::io::{Error, ErrorKind};
2use tokio::io::AsyncReadExt;
3
4pub async fn read_varint<R: AsyncReadExt + Unpin>(reader: &mut R) -> tokio::io::Result<i32> {
5 let mut value = 0;
6 let mut position = 0;
7 let mut byte_buf = [0u8; 1];
8 loop {
9 reader.read_exact(&mut byte_buf[..]).await?;
10 let byte = byte_buf[0];
11 value |= ((byte & 0x7F) as i32) << position;
12 if (byte & 0x80) == 0 {
13 break;
14 }
15 position += 7;
16 if position >= 32 {
17 return Err(Error::new(ErrorKind::InvalidData, "VarInt too big"));
18 }
19 }
20 Ok(value)
21}
22
23pub fn write_varint(buf: &mut Vec<u8>, mut value: i32) {
24 loop {
25 if (value & !0x7F) == 0 {
26 buf.push(value as u8);
27 return;
28 }
29 buf.push(((value & 0x7F) | 0x80) as u8);
30 value >>= 7;
31 }
32}
33
34pub async fn read_string<R: AsyncReadExt + Unpin>(reader: &mut R) -> tokio::io::Result<String> {
35 let len = read_varint(reader).await?;
36 let mut buf = vec![0u8; len as usize];
37 reader.read_exact(&mut buf[..]).await?;
38 Ok(String::from_utf8_lossy(&buf).to_string())
39}
40
41pub fn write_string(buf: &mut Vec<u8>, s: &str) {
42 write_varint(buf, s.len() as i32);
43 buf.extend_from_slice(s.as_bytes());
44}