use crate::varint::{VarInt, CONTINUE_BIT};
use async_trait::async_trait;
use bytes::{BufMut, BytesMut};
use std::io::{Error, ErrorKind};
use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, Result};
#[async_trait]
pub(crate) trait ReadWriteVarInt {
async fn read_varint(&mut self) -> Result<i32>;
}
#[async_trait]
pub(crate) trait ReadWriteMinecraftString {
async fn read_mc_string(&mut self) -> Result<String>;
}
#[async_trait]
impl<T> ReadWriteVarInt for T
where
T: AsyncRead + AsyncWrite + Unpin + Send,
{
async fn read_varint(&mut self) -> Result<i32> {
let mut bytes = BytesMut::with_capacity(5);
loop {
let current = self.read_u8().await?;
bytes.put_u8(current);
if current & CONTINUE_BIT == 0 {
break;
}
}
VarInt::new(bytes.freeze())
.try_into()
.map_err(|err| Error::new(ErrorKind::InvalidData, err))
}
}
#[async_trait]
impl<T> ReadWriteMinecraftString for T
where
T: AsyncRead + AsyncWrite + Unpin + Send,
{
async fn read_mc_string(&mut self) -> Result<String> {
let len = self.read_varint().await?;
let mut buffer = vec![0; len as usize];
self.read_exact(&mut buffer).await?;
String::from_utf8(buffer).map_err(|err| Error::new(ErrorKind::InvalidData, err))
}
}