From ba2f89b4c4b63224ff94f32c346b4f80638897b2 Mon Sep 17 00:00:00 2001 From: MeexReay Date: Fri, 6 Jun 2025 15:22:13 +0300 Subject: [PATCH] fix varint --- .gitea/workflows/rust.yml | 26 +++ Cargo.toml | 2 +- src/data/mod.rs | 1 - src/data/reader.rs | 338 +++++++++++++++++++++++++------------- src/data/varint.rs | 70 -------- src/data/writer.rs | 165 ++++++++++++++----- src/lib.rs | 34 +--- src/tests.rs | 45 +++++ src/zigzag.rs | 65 -------- 9 files changed, 423 insertions(+), 323 deletions(-) create mode 100644 .gitea/workflows/rust.yml delete mode 100644 src/data/varint.rs delete mode 100644 src/zigzag.rs diff --git a/.gitea/workflows/rust.yml b/.gitea/workflows/rust.yml new file mode 100644 index 0000000..7c43414 --- /dev/null +++ b/.gitea/workflows/rust.yml @@ -0,0 +1,26 @@ +on: [push, pull_request] + +name: Rust + +jobs: + check: + name: Check + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions-rust-lang/setup-rust-toolchain@v1 + - run: cargo check + build: + name: Build + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions-rust-lang/setup-rust-toolchain@v1 + - run: cargo build + test: + name: Test Suite + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions-rust-lang/setup-rust-toolchain@v1 + - run: cargo test \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index decf3ed..0d80e8f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,4 +13,4 @@ edition = "2024" [dependencies] flate2 = "1.1.1" uuid = "1.16.0" -tokio = { version = "1", features = ["io-util", "rt", "macros", "net", "rt-multi-thread"] } \ No newline at end of file +tokio = { version = "1", features = ["io-util", "rt", "macros", "net", "rt-multi-thread"] } diff --git a/src/data/mod.rs b/src/data/mod.rs index fada9ef..9706c1b 100644 --- a/src/data/mod.rs +++ b/src/data/mod.rs @@ -1,7 +1,6 @@ //! `DataReader` and `DataWriter` traits for reading and writing primitive types in the Minecraft protocol pub mod reader; -pub mod varint; pub mod writer; pub use reader::*; diff --git a/src/data/reader.rs b/src/data/reader.rs index a4aea96..f9bd158 100644 --- a/src/data/reader.rs +++ b/src/data/reader.rs @@ -1,8 +1,4 @@ -use crate::{ - data::varint::{read_varint, size_varint}, - zigzag::Zigzag, - ProtocolError, -}; +use crate::ProtocolError; use tokio::io::AsyncReadExt; use uuid::Uuid; @@ -79,122 +75,242 @@ pub trait DataReader { }} } - /// Read VarInt as usize with size in bytes (varint, size) - fn read_usize_varint_size(&mut self) -> impl Future> { - async {size_varint!(usize, self)} - } - /// Read VarInt as u8 with size in bytes (varint, size) - fn read_u8_varint_size(&mut self) -> impl Future> { - async {size_varint!(u8, self)} - } - /// Read VarInt as u16 with size in bytes (varint, size) - fn read_u16_varint_size(&mut self) -> impl Future> { - async {size_varint!(u16, self)} - } - /// Read VarInt as u32 with size in bytes (varint, size) - fn read_u32_varint_size(&mut self) -> impl Future> { - async {size_varint!(u32, self)} - } - /// Read VarInt as u64 with size in bytes (varint, size) - fn read_u64_varint_size(&mut self) -> impl Future> { - async {size_varint!(u64, self)} - } - /// Read VarInt as u128 with size in bytes (varint, size) - fn read_u128_varint_size(&mut self) -> impl Future> { - async {size_varint!(u128, self)} - } - - /// Read VarInt as isize with size in bytes (varint, size) - fn read_isize_varint_size(&mut self) -> impl Future> { - async {Ok({ - let i = self.read_usize_varint_size().await?; - (i.0.zigzag(), i.1) - })} - } - /// Read VarInt as i8 with size in bytes (varint, size) - fn read_i8_varint_size(&mut self) -> impl Future> { - async {Ok({ - let i = self.read_u8_varint_size().await?; - (i.0.zigzag(), i.1) - })} - } - /// Read VarInt as i16 with size in bytes (varint, size) - fn read_i16_varint_size(&mut self) -> impl Future> { - async {Ok({ - let i = self.read_u16_varint_size().await?; - (i.0.zigzag(), i.1) - })} - } - /// Read VarInt as i32 with size in bytes (varint, size) - fn read_i32_varint_size(&mut self) -> impl Future> { - async {Ok({ - let i = self.read_u32_varint_size().await?; - (i.0.zigzag(), i.1) - })} - } - /// Read VarInt as i64 with size in bytes (varint, size) - fn read_i64_varint_size(&mut self) -> impl Future> { - async {Ok({ - let i = self.read_u64_varint_size().await?; - (i.0.zigzag(), i.1) - })} - } - /// Read VarInt as i128 with size in bytes (varint, size) - fn read_i128_varint_size(&mut self) -> impl Future> { - async {Ok({ - let i = self.read_u128_varint_size().await?; - (i.0.zigzag(), i.1) - })} - } - - /// Read VarInt as usize - fn read_usize_varint(&mut self) -> impl Future> { - async {read_varint!(usize, self)} - } - /// Read VarInt as u8 - fn read_u8_varint(&mut self) -> impl Future> { - async {read_varint!(u8, self)} - } - /// Read VarInt as u16 - fn read_u16_varint(&mut self) -> impl Future> { - async {read_varint!(u16, self)} - } /// Read VarInt as u32 - fn read_u32_varint(&mut self) -> impl Future> { - async {read_varint!(u32, self)} + /// + /// Returns error if the value is greater than i32::MAX + async fn read_u32_varint(&mut self) -> Result { + let val = self.read_varint().await?; + if val < 0 { return Err(ProtocolError::VarIntError); } + TryInto::::try_into(val).map_err(|_| ProtocolError::VarIntError) } - /// Read VarInt as u64 - fn read_u64_varint(&mut self) -> impl Future> { - async {read_varint!(u64, self)} - } - /// Read VarInt as u128 - fn read_u128_varint(&mut self) -> impl Future> { - async {read_varint!(u128, self)} - } - - /// Read VarInt as isize - fn read_isize_varint(&mut self) -> impl Future> { - async {Ok(self.read_usize_varint().await?.zigzag())} + /// Read VarInt as usize + async fn read_usize_varint(&mut self) -> Result { + Ok(TryInto::::try_into(self.read_varint().await?).map_err(|_| ProtocolError::VarIntError)?) } /// Read VarInt as i8 - fn read_i8_varint(&mut self) -> impl Future> { - async {Ok(self.read_u8_varint().await?.zigzag())} + async fn read_i8_varint(&mut self) -> Result { + TryInto::::try_into(self.read_varint().await?).map_err(|_| ProtocolError::VarIntError) } /// Read VarInt as i16 - fn read_i16_varint(&mut self) -> impl Future> { - async {Ok(self.read_u16_varint().await?.zigzag())} + async fn read_i16_varint(&mut self,) -> Result { + TryInto::::try_into(self.read_varint().await?).map_err(|_| ProtocolError::VarIntError) } /// Read VarInt as i32 - fn read_i32_varint(&mut self) -> impl Future> { - async {Ok(self.read_u32_varint().await?.zigzag())} + /// + /// *Use [read_varint](DataReader::read_varint) instead* + async fn read_i32_varint(&mut self) -> Result { + self.read_varint().await } - /// Read VarInt as i64 - fn read_i64_varint(&mut self) -> impl Future> { - async {Ok(self.read_u64_varint().await?.zigzag())} + /// Read VarInt as isize + async fn read_isize_varint(&mut self) -> Result { + Ok(TryInto::::try_into(self.read_varint().await?).map_err(|_| ProtocolError::VarIntError)?) } - /// Read VarInt as i128 - fn read_i128_varint(&mut self) -> impl Future> { - async {Ok(self.read_u128_varint().await?.zigzag())} + + /// Read VarLong as u8 + async fn read_u8_varlong(&mut self) -> Result { + TryInto::::try_into(self.read_varlong().await?).map_err(|_| ProtocolError::VarIntError) + } + /// Read VarLong as u16 + async fn read_u16_varlong(&mut self) -> Result { + TryInto::::try_into(self.read_varlong().await?).map_err(|_| ProtocolError::VarIntError) + } + /// Read VarLong as u32 + async fn read_u32_varlong(&mut self) -> Result { + TryInto::::try_into(self.read_varlong().await?).map_err(|_| ProtocolError::VarIntError) + } + /// Read VarLong as usize + /// + /// Returns error if the value is greater than i64::MAX + async fn read_usize_varlong(&mut self) -> Result { + let val = TryInto::::try_into(self.read_varlong().await?).map_err(|_| ProtocolError::VarIntError)?; + if val as u64 > i64::MAX as u64 { return Err(ProtocolError::VarIntError); } + Ok(val) + } + /// Read VarLong as u64 + /// + /// Returns error if the value is greater than i64::MAX + async fn read_u64_varlong(&mut self) -> Result { + let val = self.read_varlong().await?; + if val < 0 { return Err(ProtocolError::VarIntError); } + TryInto::::try_into(val).map_err(|_| ProtocolError::VarIntError) + } + /// Read VarLong as i8 + async fn read_i8_varlong(&mut self) -> Result { + TryInto::::try_into(self.read_varlong().await?).map_err(|_| ProtocolError::VarIntError) + } + /// Read VarLong as i16 + async fn read_i16_varlong(&mut self) -> Result { + TryInto::::try_into(self.read_varlong().await?).map_err(|_| ProtocolError::VarIntError) + } + /// Read VarLong as i32 + async fn read_i32_varlong(&mut self) -> Result { + TryInto::::try_into(self.read_varlong().await?).map_err(|_| ProtocolError::VarIntError) + } + /// Read VarLong as isize + async fn read_isize_varlong(&mut self) -> Result { + Ok(TryInto::::try_into(self.read_varlong().await?).map_err(|_| ProtocolError::VarIntError)?) + } + /// Read VarLong as i64 + /// + /// *Use [read_varlong](DataReader::read_varlong) instead* + async fn read_i64_varlong(&mut self) -> Result { + self.read_varlong().await + } + + /// Read VarInt as u8 with size in bytes (value, size) + async fn read_u8_varint_size(&mut self) -> Result<(u8, usize), ProtocolError> { + let (val, size) = self.read_varint_size().await?; + Ok((TryInto::::try_into(val).map_err(|_| ProtocolError::VarIntError)?, size)) + } + /// Read VarInt as u16 with size in bytes (value, size) + async fn read_u16_varint_size(&mut self) -> Result<(u16, usize), ProtocolError> { + let (val, size) = self.read_varint_size().await?; + Ok((TryInto::::try_into(val).map_err(|_| ProtocolError::VarIntError)?, size)) + } + /// Read VarInt as u32 with size in bytes (value, size) + /// + /// Returns error if the value is greater than i32::MAX + async fn read_u32_varint_size(&mut self) -> Result<(u32, usize), ProtocolError> { + let (val, size) = self.read_varint_size().await?; + if val < 0 { return Err(ProtocolError::VarIntError); } + Ok((TryInto::::try_into(val).map_err(|_| ProtocolError::VarIntError)?, size)) + } + /// Read VarInt as usize with size in bytes (value, size) + async fn read_usize_varint_size(&mut self) -> Result<(usize, usize), ProtocolError> { + let (val, size) = self.read_varint_size().await?; + Ok((TryInto::::try_into(val).map_err(|_| ProtocolError::VarIntError)?, size)) + } + /// Read VarInt as i8 with size in bytes (value, size) + async fn read_i8_varint_size(&mut self) -> Result<(i8, usize), ProtocolError> { + let (val, size) = self.read_varint_size().await?; + Ok((TryInto::::try_into(val).map_err(|_| ProtocolError::VarIntError)?, size)) + } + /// Read VarInt as i16 with size in bytes (value, size) + async fn read_i16_varint_size(&mut self,) -> Result<(i16, usize), ProtocolError> { + let (val, size) = self.read_varint_size().await?; + Ok((TryInto::::try_into(val).map_err(|_| ProtocolError::VarIntError)?, size)) + } + /// Read VarInt as i32 with size in bytes (value, size) + /// + /// *Use [read_varint_size](DataReader::read_varint_size) instead* + async fn read_i32_varint_size(&mut self) -> Result<(i32, usize), ProtocolError> { + self.read_varint_size().await + } + /// Read VarInt as isize with size in bytes (value, size) + async fn read_isize_varint_size(&mut self) -> Result<(isize, usize), ProtocolError> { + let (val, size) = self.read_varint_size().await?; + Ok((TryInto::::try_into(val).map_err(|_| ProtocolError::VarIntError)?, size)) + } + + /// Read VarLong as u8 with size in bytes (value, size) + async fn read_u8_varlong_size(&mut self) -> Result<(u8, usize), ProtocolError> { + let (val, size) = self.read_varlong_size().await?; + Ok((TryInto::::try_into(val).map_err(|_| ProtocolError::VarIntError)?, size)) + } + /// Read VarLong as u16 with size in bytes (value, size) + async fn read_u16_varlong_size(&mut self) -> Result<(u16, usize), ProtocolError> { + let (val, size) = self.read_varlong_size().await?; + Ok((TryInto::::try_into(val).map_err(|_| ProtocolError::VarIntError)?, size)) + } + /// Read VarLong as u32 with size in bytes (value, size) + async fn read_u32_varlong_size(&mut self) -> Result<(u32, usize), ProtocolError> { + let (val, size) = self.read_varlong_size().await?; + Ok((TryInto::::try_into(val).map_err(|_| ProtocolError::VarIntError)?, size)) + } + /// Read VarLong as usize with size in bytes (value, size) + /// + /// Returns error if the value is greater than i64::MAX + async fn read_usize_varlong_size(&mut self) -> Result<(usize, usize), ProtocolError> { + let (val, size) = self.read_varlong_size().await?; + let val = TryInto::::try_into(val).map_err(|_| ProtocolError::VarIntError)?; + if val as u64 > i64::MAX as u64 { return Err(ProtocolError::VarIntError); } + Ok((val, size)) + } + /// Read VarLong as u64 with size in bytes (value, size) + /// + /// Returns error if the value is greater than i64::MAX + async fn read_u64_varlong_size(&mut self) -> Result<(u64, usize), ProtocolError> { + let (val, size) = self.read_varlong_size().await?; + if val < 0 { return Err(ProtocolError::VarIntError); } + Ok((TryInto::::try_into(val).map_err(|_| ProtocolError::VarIntError)?, size)) + } + /// Read VarLong as i8 with size in bytes (value, size) + async fn read_i8_varlong_size(&mut self) -> Result<(i8, usize), ProtocolError> { + let (val, size) = self.read_varlong_size().await?; + Ok((TryInto::::try_into(val).map_err(|_| ProtocolError::VarIntError)?, size)) + } + /// Read VarLong as i16 with size in bytes (value, size) + async fn read_i16_varlong_size(&mut self) -> Result<(i16, usize), ProtocolError> { + let (val, size) = self.read_varlong_size().await?; + Ok((TryInto::::try_into(val).map_err(|_| ProtocolError::VarIntError)?, size)) + } + /// Read VarLong as i32 with size in bytes (value, size) + async fn read_i32_varlong_size(&mut self) -> Result<(i32, usize), ProtocolError> { + let (val, size) = self.read_varlong_size().await?; + Ok((TryInto::::try_into(val).map_err(|_| ProtocolError::VarIntError)?, size)) + } + /// Read VarLong as isize with size in bytes (value, size) + async fn read_isize_varlong_size(&mut self) -> Result<(isize, usize), ProtocolError> { + let (val, size) = self.read_varlong_size().await?; + Ok((TryInto::::try_into(val).map_err(|_| ProtocolError::VarIntError)?, size)) + } + /// Read VarLong as i64 with size in bytes (value, size) + /// + /// *Use [read_varlong_size](DataReader::read_varlong_size) instead* + async fn read_i64_varlong_size(&mut self) -> Result<(i64, usize), ProtocolError> { + self.read_varlong_size().await + } + + /// Read VarInt as i32 with size in bytes (value, size) + async fn read_varint_size(&mut self) -> Result<(i32, usize), ProtocolError> { + let mut value: u32 = 0; + let mut position: u32 = 0; + let mut size = 0; + + loop { + let byte = self.read_byte().await?; + value |= TryInto::::try_into(byte & 0x7F).map_err(|_| ProtocolError::VarIntError)? << position; + + size += 1; + + if (byte & 0x80) == 0 { + break; + } + + position += 7; + } + + Ok((value as i32, size)) + } + /// Read VarLong as i64 with size in bytes (value, size) + async fn read_varlong_size(&mut self) -> Result<(i64, usize), ProtocolError> { + let mut value: u64 = 0; + let mut position: u32 = 0; + let mut size = 0; + + loop { + let byte = self.read_byte().await?; + value |= TryInto::::try_into(byte & 0x7F).map_err(|_| ProtocolError::VarIntError)? << position; + + size += 1; + + if (byte & 0x80) == 0 { + break; + } + + position += 7; + } + + Ok((value as i64, size)) + } + + /// Read VarInt as i32 + async fn read_varint(&mut self) -> Result { + self.read_varint_size().await.map(|o| o.0) + } + /// Read VarLong as i64 + async fn read_varlong(&mut self) -> Result { + self.read_varlong_size().await.map(|o| o.0) } } diff --git a/src/data/varint.rs b/src/data/varint.rs deleted file mode 100644 index 7a91e5e..0000000 --- a/src/data/varint.rs +++ /dev/null @@ -1,70 +0,0 @@ -macro_rules! size_varint { - ($type:ty, $self:expr) => {{ - let mut shift: $type = 0; - let mut decoded: $type = 0; - let mut size: usize = 0; - - loop { - let next = DataReader::read_byte($self).await?; - size += 1; - - if shift >= (std::mem::size_of::<$type>() * 8) as $type { - return Err(ProtocolError::VarIntError); - } - - decoded |= ((next & 0b01111111) as $type) << shift; - - if next & 0b10000000 == 0b10000000 { - shift += 7; - } else { - return Ok((decoded, size)); - } - } - }}; -} - -macro_rules! read_varint { - ($type:ty, $self:expr) => {{ - let mut shift: $type = 0; - let mut decoded: $type = 0; - - loop { - let next = DataReader::read_byte($self).await?; - - if shift >= (std::mem::size_of::<$type>() * 8) as $type { - return Err(ProtocolError::VarIntError); - } - - decoded |= ((next & 0b01111111) as $type) << shift; - - if next & 0b10000000 == 0b10000000 { - shift += 7; - } else { - return Ok(decoded); - } - } - }}; -} - -macro_rules! write_varint { - ($type:ty, $self:expr, $value:expr) => {{ - let mut value: $type = $value; - - if value == 0 { - DataWriter::write_byte($self, 0).await - } else { - while value >= 0b10000000 { - let next: u8 = ((value & 0b01111111) as u8) | 0b10000000; - value >>= 7; - - DataWriter::write_byte($self, next).await?; - } - - DataWriter::write_byte($self, (value & 0b01111111) as u8).await - } - }}; -} - -pub(crate) use read_varint; -pub(crate) use size_varint; -pub(crate) use write_varint; diff --git a/src/data/writer.rs b/src/data/writer.rs index 60d15f7..b2ac819 100644 --- a/src/data/writer.rs +++ b/src/data/writer.rs @@ -1,4 +1,4 @@ -use crate::{data::varint::write_varint, zigzag::Zigzag, ProtocolError}; +use crate::ProtocolError; use tokio::io::AsyncWriteExt; use uuid::Uuid; @@ -25,81 +25,156 @@ pub trait DataWriter { } /// Write Unsigned Short as u16 fn write_unsigned_short(&mut self, val: u16) -> impl Future> { - async move { self.write_bytes(&val.to_be_bytes()).await.map_err(|_| ProtocolError::UnsignedShortError) } + async move { self.write_bytes(&val.to_be_bytes()).await } } /// Write Boolean fn write_boolean(&mut self, val: bool) -> impl Future> { - async move { self.write_byte(if val { 0x01 } else { 0x00 }).await.map_err(|_| ProtocolError::UnsignedShortError) } + async move { self.write_byte(if val { 0x01 } else { 0x00 }).await } } /// Write Short as i16 fn write_short(&mut self, val: i16) -> impl Future> { - async move { self.write_bytes(&val.to_be_bytes()).await.map_err(|_| ProtocolError::UnsignedShortError) } + async move { self.write_bytes(&val.to_be_bytes()).await } } /// Write Long as i64 fn write_long(&mut self, val: i64) -> impl Future> { - async move { self.write_bytes(&val.to_be_bytes()).await.map_err(|_| ProtocolError::UnsignedShortError) } + async move { self.write_bytes(&val.to_be_bytes()).await } } /// Write Float as f32 fn write_float(&mut self, val: f32) -> impl Future> { - async move { self.write_bytes(&val.to_be_bytes()).await.map_err(|_| ProtocolError::UnsignedShortError) } + async move { self.write_bytes(&val.to_be_bytes()).await } } /// Write Double as f64 fn write_double(&mut self, val: f64) -> impl Future> { - async move { self.write_bytes(&val.to_be_bytes()).await.map_err(|_| ProtocolError::UnsignedShortError) } + async move { self.write_bytes(&val.to_be_bytes()).await } } /// Write Int as i32 fn write_int(&mut self, val: i32) -> impl Future> { - async move { self.write_bytes(&val.to_be_bytes()).await.map_err(|_| ProtocolError::UnsignedShortError) } + async move { self.write_bytes(&val.to_be_bytes()).await } } - /// Write VarInt as usize - fn write_usize_varint(&mut self, val: usize) -> impl Future> { - async move { write_varint!(usize, self, val) } - } - /// Write VarInt as u8 - fn write_u8_varint(&mut self, val: u8) -> impl Future> { - async move { write_varint!(u8, self, val) } + /// Write VarInt as u8 + async fn write_u8_varint(&mut self, val: u8) -> Result<(), ProtocolError> { + self.write_varint(val.try_into().map_err(|_| ProtocolError::VarIntError)?).await } /// Write VarInt as u16 - fn write_u16_varint(&mut self, val: u16) -> impl Future> { - async move { write_varint!(u16, self, val) } + async fn write_u16_varint(&mut self, val: u16) -> Result<(), ProtocolError> { + self.write_varint(val.try_into().map_err(|_| ProtocolError::VarIntError)?).await + } + /// Write VarInt as usize + /// + /// Returns error if the value is greater than i32::MAX + async fn write_usize_varint(&mut self, val: usize) -> Result<(), ProtocolError> { + let val = val.try_into().map_err(|_| ProtocolError::VarIntError)?; + if val < 0 { return Err(ProtocolError::VarIntError); } + self.write_varint(val).await } /// Write VarInt as u32 - fn write_u32_varint(&mut self, val: u32) -> impl Future> { - async move { write_varint!(u32, self, val) } - } - /// Write VarInt as u64 - fn write_u64_varint(&mut self, val: u64) -> impl Future> { - async move { write_varint!(u64, self, val) } - } - /// Write VarInt as u128 - fn write_u128_varint(&mut self, val: u128) -> impl Future> { - async move { write_varint!(u128, self, val) } - } - - /// Write VarInt as isize - fn write_isize_varint(&mut self, val: isize) -> impl Future> { - async move { self.write_usize_varint(val.zigzag()).await } + /// + /// Returns error if the value is greater than i32::MAX + async fn write_u32_varint(&mut self, val: u32) -> Result<(), ProtocolError> { + let val = val.try_into().map_err(|_| ProtocolError::VarIntError)?; + if val < 0 { return Err(ProtocolError::VarIntError); } + self.write_varint(val).await } /// Write VarInt as i8 - fn write_i8_varint(&mut self, val: i8) -> impl Future> { - async move { self.write_u8_varint(val.zigzag()).await } + async fn write_i8_varint(&mut self, val: i8) -> Result<(), ProtocolError> { + self.write_varint(val.try_into().map_err(|_| ProtocolError::VarIntError)?).await } /// Write VarInt as i16 - fn write_i16_varint(&mut self, val: i16) -> impl Future> { - async move { self.write_u16_varint(val.zigzag()).await } + async fn write_i16_varint(&mut self, val: i16) -> Result<(), ProtocolError> { + self.write_varint(val.try_into().map_err(|_| ProtocolError::VarIntError)?).await + } + /// Write VarInt as isize + async fn write_isize_varint(&mut self, val: isize) -> Result<(), ProtocolError> { + self.write_varint(val.try_into().map_err(|_| ProtocolError::VarIntError)?).await } /// Write VarInt as i32 - fn write_i32_varint(&mut self, val: i32) -> impl Future> { - async move { self.write_u32_varint(val.zigzag()).await } + /// + /// *Use [write_varint](DataWriter::write_varint) instead* + async fn write_i32_varint(&mut self, val: i32) -> Result<(), ProtocolError> { + self.write_varint(val).await } - /// Write VarInt as i64 - fn write_i64_varint(&mut self, val: i64) -> impl Future> { - async move { self.write_u64_varint(val.zigzag()).await } + + /// Write VarLong as u8 + async fn write_u8_varlong(&mut self, val: u8) -> Result<(), ProtocolError> { + self.write_varlong(val.try_into().map_err(|_| ProtocolError::VarIntError)?).await } - /// Write VarInt as i128 - fn write_i128_varint(&mut self, val: i128) -> impl Future> { - async move { self.write_u128_varint(val.zigzag()).await } + /// Write VarLong as u16 + async fn write_u16_varlong(&mut self, val: u16) -> Result<(), ProtocolError> { + self.write_varlong(val.try_into().map_err(|_| ProtocolError::VarIntError)?).await + } + /// Write VarLong as u32 + async fn write_u32_varlong(&mut self, val: u32) -> Result<(), ProtocolError> { + self.write_varlong(val.try_into().map_err(|_| ProtocolError::VarIntError)?).await + } + /// Write VarLong as u64 + /// + /// Returns error if the value is greater than i64::MAX + async fn write_u64_varlong(&mut self, val: u64) -> Result<(), ProtocolError> { + let val = val.try_into().map_err(|_| ProtocolError::VarIntError)?; + if val < 0 { return Err(ProtocolError::VarIntError); } + self.write_varlong(val).await + } + /// Write VarLong as usize + /// + /// Returns error if the value is greater than i64::MAX + async fn write_usize_varlong(&mut self, val: u64) -> Result<(), ProtocolError> { + let val = val.try_into().map_err(|_| ProtocolError::VarIntError)?; + if val < 0 { return Err(ProtocolError::VarIntError); } + self.write_varlong(val).await + } + /// Write VarLong as i8 + async fn write_i8_varlong(&mut self, val: i8) -> Result<(), ProtocolError> { + self.write_varlong(val.try_into().map_err(|_| ProtocolError::VarIntError)?).await + } + /// Write VarLong as i16 + async fn write_i16_varlong(&mut self, val: i16) -> Result<(), ProtocolError> { + self.write_varlong(val.try_into().map_err(|_| ProtocolError::VarIntError)?).await + } + /// Write VarLong as i32 + async fn write_i32_varlong(&mut self, val: i32) -> Result<(), ProtocolError> { + self.write_varlong(val.try_into().map_err(|_| ProtocolError::VarIntError)?).await + } + /// Write VarLong as i64 + /// + /// *Use [write_varlong](DataWriter::write_varlong) instead* + async fn write_i64_varlong(&mut self, val: i64) -> Result<(), ProtocolError> { + self.write_varlong(val).await + } + + /// Write VarInt as i32 + async fn write_varint(&mut self, val: i32) -> Result<(), ProtocolError> { + let mut value = val as u32; + + loop { + if value & !0x7F == 0 { + self.write_byte(TryInto::::try_into(value).map_err(|_| ProtocolError::VarIntError)?).await?; + break; + } + + self.write_byte(TryInto::::try_into((value & 0x7F) | 0x80).map_err(|_| ProtocolError::VarIntError)?).await?; + + value >>= 7; + } + + Ok(()) + } + /// Write VarLong as i64 + async fn write_varlong(&mut self, val: i64) -> Result<(), ProtocolError> { + let mut value = val as u64; + + loop { + if value & !0x7F == 0 { + self.write_byte(TryInto::::try_into(value).map_err(|_| ProtocolError::VarIntError)?).await?; + break; + } + + self.write_byte(TryInto::::try_into((value & 0x7F) | 0x80).map_err(|_| ProtocolError::VarIntError)?).await?; + + value >>= 7; + } + + Ok(()) } } @@ -107,4 +182,4 @@ impl DataWriter for W { async fn write_bytes(&mut self, bytes: &[u8]) -> Result<(), ProtocolError> { self.write_all(bytes).await.map_err(|_| ProtocolError::WriteError) } -} \ No newline at end of file +} diff --git a/src/lib.rs b/src/lib.rs index bf13c9d..0048866 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,7 +3,6 @@ mod tests; pub mod data; pub mod packet; -pub mod zigzag; pub mod prelude { pub use crate::{DataReader, DataWriter}; @@ -31,7 +30,6 @@ pub enum ProtocolError { ReadError, WriteError, ZlibError, - UnsignedShortError, CloneError, ConnectionClosedError } @@ -48,8 +46,7 @@ impl Error for ProtocolError {} pub struct MinecraftConnection { stream: T, compression: Option, - compression_type: u32, - is_alive: bool, + compression_type: u32 } impl MinecraftConnection { @@ -69,7 +66,6 @@ impl MinecraftConnection { Ok(MinecraftConnection { stream, compression: None, - is_alive: true, compression_type: 1, }) } @@ -77,7 +73,6 @@ impl MinecraftConnection { /// Close TcpStream pub async fn close(&mut self) { let _ = self.stream.shutdown().await; - self.is_alive = false; } } @@ -103,22 +98,11 @@ impl MinecraftConnection { MinecraftConnection { stream, compression: None, - is_alive: true, compression_type: 1, } } - /// Set alive state - fn set_alive(&mut self, state: bool) { - self.is_alive = state; - } - - /// Is connection alive - pub fn is_alive(&self) -> bool { - self.is_alive - } - - /// Set compression threshold + /// Set compression threshold pub fn set_compression(&mut self, threshold: Option) { self.compression = threshold; } @@ -158,13 +142,8 @@ impl MinecraftConnection { /// Read [`Packet`](Packet) from connection pub async fn read_packet(&mut self) -> Result { - if !self.is_alive() { - return Err(ProtocolError::ConnectionClosedError); - } - match read_packet(&mut self.stream, self.compression).await { Err(ProtocolError::ConnectionClosedError) => { - self.set_alive(false); Err(ProtocolError::ConnectionClosedError) }, i => i @@ -173,10 +152,6 @@ impl MinecraftConnection { /// Write [`Packet`](Packet) to connection pub async fn write_packet(&mut self, packet: &Packet) -> Result<(), ProtocolError> { - if !self.is_alive() { - return Err(ProtocolError::ConnectionClosedError); - } - write_packet(&mut self.stream, self.compression, self.compression_type, packet).await } } @@ -186,8 +161,7 @@ impl MinecraftConnection { pub fn clone(&mut self) -> MinecraftConnection { MinecraftConnection { stream: self.stream.clone(), - compression: self.compression.clone(), - is_alive: self.is_alive.clone(), + compression: self.compression, compression_type: self.compression_type, } } @@ -289,4 +263,4 @@ pub async fn write_packet( stream.write_bytes(&buf).await?; Ok(()) -} \ No newline at end of file +} diff --git a/src/tests.rs b/src/tests.rs index 5a5b278..c73738f 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -4,6 +4,51 @@ use std::io::Cursor; use crate::*; +#[tokio::test] +async fn test_varint() -> Result<(), ProtocolError> { + let mut src = Packet::empty(0x00); + + src.write_u8_varint(0).await?; // 0x00 + src.write_u8_varint(1).await?; // 0x01 + src.write_u8_varint(2).await?; // 0x02 + src.write_u8_varint(127).await?; // 0x7f + src.write_u8_varint(128).await?; // 0x80 0x01 + src.write_u16_varint(255).await?; // 0xff 0x01 + src.write_u16_varint(25565).await?; // 0xdd 0xc7 0x01 + src.write_u32_varint(2097151).await?; // 0xff 0xff 0x7f + src.write_u32_varint(2147483647).await?; // 0xff 0xff 0xff 0xff 0x07 + src.write_i8_varint(-1).await?; // 0xff 0xff 0xff 0xff 0x0f + src.write_i32_varint(-2147483648).await?; // 0x80 0x80 0x80 0x80 0x08 + + let mut packet = Packet::from_bytes(0x00, src.get_bytes()); + assert_eq!(packet.read_u8_varint().await?, 0); + assert_eq!(packet.read_u8_varint().await?, 1); + assert_eq!(packet.read_u8_varint().await?, 2); + assert_eq!(packet.read_u8_varint().await?, 127); + assert_eq!(packet.read_u8_varint().await?, 128); + assert_eq!(packet.read_u16_varint().await?, 255); + assert_eq!(packet.read_u16_varint().await?, 25565); + assert_eq!(packet.read_u32_varint().await?, 2097151); + assert_eq!(packet.read_u32_varint().await?, 2147483647); + assert_eq!(packet.read_i8_varint().await?, -1); + assert_eq!(packet.read_i32_varint().await?, -2147483648); + + let mut packet = Packet::from_bytes(0x00, src.get_bytes()); + assert_eq!(packet.read_bytes(1).await?, vec![0x00]); // 0 + assert_eq!(packet.read_bytes(1).await?, vec![0x01]); // 1 + assert_eq!(packet.read_bytes(1).await?, vec![0x02]); // 2 + assert_eq!(packet.read_bytes(1).await?, vec![0x7f]); // 127 + assert_eq!(packet.read_bytes(2).await?, vec![0x80, 0x01]); // 128 + assert_eq!(packet.read_bytes(2).await?, vec![0xff, 0x01]); // 255 + assert_eq!(packet.read_bytes(3).await?, vec![0xdd, 0xc7, 0x01]); // 25565 + assert_eq!(packet.read_bytes(3).await?, vec![0xff, 0xff, 0x7f]); // 2097151 + assert_eq!(packet.read_bytes(5).await?, vec![0xff, 0xff, 0xff, 0xff, 0x07]); // 2147483647 + assert_eq!(packet.read_bytes(5).await?, vec![0xff, 0xff, 0xff, 0xff, 0x0f]); // -1 + assert_eq!(packet.read_bytes(5).await?, vec![0x80, 0x80, 0x80, 0x80, 0x08]); // -2147483648 + + Ok(()) +} + #[tokio::test] async fn test_data_transfer() -> Result<(), ProtocolError> { diff --git a/src/zigzag.rs b/src/zigzag.rs deleted file mode 100644 index b41018d..0000000 --- a/src/zigzag.rs +++ /dev/null @@ -1,65 +0,0 @@ -//! VarInt reading helper - -pub trait Zigzag { - fn zigzag(&self) -> T; -} -impl Zigzag for i8 { - fn zigzag(&self) -> u8 { - ((self << 1) ^ (self >> 7)) as u8 - } -} -impl Zigzag for u8 { - fn zigzag(&self) -> i8 { - ((self >> 1) as i8) ^ (-((self & 1) as i8)) - } -} -impl Zigzag for i16 { - fn zigzag(&self) -> u16 { - ((self << 1) ^ (self >> 15)) as u16 - } -} -impl Zigzag for u16 { - fn zigzag(&self) -> i16 { - ((self >> 1) as i16) ^ (-((self & 1) as i16)) - } -} -impl Zigzag for i32 { - fn zigzag(&self) -> u32 { - ((self << 1) ^ (self >> 31)) as u32 - } -} -impl Zigzag for u32 { - fn zigzag(&self) -> i32 { - ((self >> 1) as i32) ^ (-((self & 1) as i32)) - } -} -impl Zigzag for i64 { - fn zigzag(&self) -> u64 { - ((self << 1) ^ (self >> 63)) as u64 - } -} -impl Zigzag for u64 { - fn zigzag(&self) -> i64 { - ((self >> 1) as i64) ^ (-((self & 1) as i64)) - } -} -impl Zigzag for i128 { - fn zigzag(&self) -> u128 { - ((self << 1) ^ (self >> 127)) as u128 - } -} -impl Zigzag for u128 { - fn zigzag(&self) -> i128 { - ((self >> 1) as i128) ^ (-((self & 1) as i128)) - } -} -impl Zigzag for isize { - fn zigzag(&self) -> usize { - ((self << 1) ^ (self >> std::mem::size_of::() - 1)) as usize - } -} -impl Zigzag for usize { - fn zigzag(&self) -> isize { - ((self >> 1) as isize) ^ (-((self & 1) as isize)) - } -}