diff --git a/Cargo.lock b/Cargo.lock index 597b51d..c6c2435 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -66,58 +66,11 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "any_vec" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6ac04794a7749710e3c7f3c93222e3d04692993b69876d69393efd2565401a" - [[package]] name = "anyhow" -version = "1.0.93" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" - -[[package]] -name = "apecs" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6df7760d4baebb17003dcf99134d8e3a63f487e146d58911f0bcd27afb185d1c" -dependencies = [ - "any_vec", - "apecs-derive", - "async-channel", - "itertools", - "log", - "moongraph", - "parking_lot", - "rayon", - "smallvec", - "snafu 0.8.5", -] - -[[package]] -name = "apecs-derive" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc0f3ddfd31fd5276fb8039b75dc4d284c21213757a969e480c6ef8fde494f3b" -dependencies = [ - "moongraph-macros-syntax", - "proc-macro2", - "quote", - "syn 2.0.90", -] - -[[package]] -name = "async-channel" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" -dependencies = [ - "concurrent-queue", - "event-listener", - "futures-core", -] +checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7" [[package]] name = "async-trait" @@ -127,7 +80,7 @@ checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn", ] [[package]] @@ -163,23 +116,6 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" -[[package]] -name = "broomdog" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52ec65645d8167b03c07e049f114a878a11ab889f20c071d6f7b30bf88fbe5af" -dependencies = [ - "log", - "rustc-hash", - "snafu 0.8.5", -] - -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - [[package]] name = "bytes" version = "1.9.0" @@ -194,9 +130,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clap" -version = "4.5.21" +version = "4.5.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb3b4b9e5a7c7514dfa52869339ee98b3156b0bfb4e8a77c4ff4babb64b1604f" +checksum = "69371e34337c4c984bbe322360c2547210bf632eb2814bbe78a6e87a2935bd2b" dependencies = [ "clap_builder", "clap_derive", @@ -204,9 +140,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.21" +version = "4.5.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b17a95aa67cc7b5ebd32aa5370189aa0d79069ef1c64ce893bd30fb24bff20ec" +checksum = "6e24c1b4099818523236a8ca881d2b45db98dadfb4625cf6608c12069fcbbde1" dependencies = [ "anstream", "anstyle", @@ -220,10 +156,10 @@ version = "4.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" dependencies = [ - "heck 0.5.0", + "heck", "proc-macro2", "quote", - "syn 2.0.90", + "syn", ] [[package]] @@ -243,15 +179,14 @@ name = "composition" version = "0.1.0" dependencies = [ "anyhow", - "apecs", "async-trait", "base64", - "byteorder", "clap", + "nom", "once_cell", "serde", "serde_json", - "thiserror 2.0.3", + "thiserror 2.0.4", "tokio", "tokio-util", "toml", @@ -260,15 +195,6 @@ dependencies = [ "tracing-subscriber", ] -[[package]] -name = "concurrent-queue" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" -dependencies = [ - "crossbeam-utils", -] - [[package]] name = "crossbeam-channel" version = "0.5.13" @@ -278,42 +204,12 @@ dependencies = [ "crossbeam-utils", ] -[[package]] -name = "crossbeam-deque" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" -dependencies = [ - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" -dependencies = [ - "crossbeam-utils", -] - [[package]] name = "crossbeam-utils" version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" -[[package]] -name = "dagga" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04cf0d7dcd307c9c5d81277737c35d1faf08af9e2cb262966a01c91021686b68" -dependencies = [ - "log", - "rustc-hash", - "snafu 0.7.5", -] - [[package]] name = "deranged" version = "0.3.11" @@ -323,30 +219,12 @@ dependencies = [ "powerfmt", ] -[[package]] -name = "doc-comment" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" - -[[package]] -name = "either" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" - [[package]] name = "equivalent" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" -[[package]] -name = "event-listener" -version = "2.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" - [[package]] name = "futures-core" version = "0.3.31" @@ -371,12 +249,6 @@ version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - [[package]] name = "heck" version = "0.5.0" @@ -399,15 +271,6 @@ version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" -[[package]] -name = "itertools" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" -dependencies = [ - "either", -] - [[package]] name = "itoa" version = "1.0.14" @@ -448,6 +311,12 @@ version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "miniz_oxide" version = "0.8.0" @@ -469,27 +338,13 @@ dependencies = [ ] [[package]] -name = "moongraph" -version = "0.4.3" +name = "nom" +version = "7.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5a4b09eb96a84205062b48ec5469c8c35c128167e838aa73dc620c4411af598" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" dependencies = [ - "broomdog", - "dagga", - "log", - "rayon", - "snafu 0.8.5", -] - -[[package]] -name = "moongraph-macros-syntax" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08112087acc92cc28fb5d8f7bda1307123ecc9a275ed4835f1c03f1a8dd02c1d" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.90", + "memchr", + "minimal-lexical", ] [[package]] @@ -582,26 +437,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "rayon" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" -dependencies = [ - "either", - "rayon-core", -] - -[[package]] -name = "rayon-core" -version = "1.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" -dependencies = [ - "crossbeam-deque", - "crossbeam-utils", -] - [[package]] name = "redox_syscall" version = "0.5.7" @@ -617,12 +452,6 @@ version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - [[package]] name = "ryu" version = "1.0.18" @@ -652,7 +481,7 @@ checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn", ] [[package]] @@ -700,49 +529,6 @@ version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" -[[package]] -name = "snafu" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4de37ad025c587a29e8f3f5605c00f70b98715ef90b9061a815b9e59e9042d6" -dependencies = [ - "doc-comment", - "snafu-derive 0.7.5", -] - -[[package]] -name = "snafu" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "223891c85e2a29c3fe8fb900c1fae5e69c2e42415e3177752e8718475efa5019" -dependencies = [ - "snafu-derive 0.8.5", -] - -[[package]] -name = "snafu-derive" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "990079665f075b699031e9c08fd3ab99be5029b96f3b78dc0709e8f77e4efebf" -dependencies = [ - "heck 0.4.1", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "snafu-derive" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c3c6b7927ffe7ecaa769ee0e3994da3b8cafc8f444578982c83ecb161af917" -dependencies = [ - "heck 0.5.0", - "proc-macro2", - "quote", - "syn 2.0.90", -] - [[package]] name = "socket2" version = "0.5.8" @@ -759,17 +545,6 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - [[package]] name = "syn" version = "2.0.90" @@ -792,11 +567,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.3" +version = "2.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c006c85c7651b3cf2ada4584faa36773bd07bac24acfb39f3c431b36d7e667aa" +checksum = "2f49a1853cf82743e3b7950f77e0f4d622ca36cf4317cba00c767838bac8d490" dependencies = [ - "thiserror-impl 2.0.3", + "thiserror-impl 2.0.4", ] [[package]] @@ -807,18 +582,18 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn", ] [[package]] name = "thiserror-impl" -version = "2.0.3" +version = "2.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f077553d607adc1caf65430528a576c757a71ed73944b66ebb58ef2bbd243568" +checksum = "8381894bb3efe0c4acac3ded651301ceee58a15d47c2e34885ed1908ad667061" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn", ] [[package]] @@ -864,9 +639,9 @@ dependencies = [ [[package]] name = "tokio" -version = "1.41.1" +version = "1.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22cfb5bee7a6a52939ca9224d6ac897bb669134078daa8735560897f69de4d33" +checksum = "5cec9b21b0450273377fc97bd4c33a8acffc8c996c987a7c5b319a0083707551" dependencies = [ "backtrace", "bytes", @@ -888,14 +663,14 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn", ] [[package]] name = "tokio-util" -version = "0.7.12" +version = "0.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" +checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078" dependencies = [ "bytes", "futures-core", @@ -970,7 +745,7 @@ checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index cc806f4..72a8226 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,19 +18,18 @@ default = [] update_1_20 = [] [dependencies] -anyhow = "1.0.71" -apecs = "0.8.4" +anyhow = "1.0.94" async-trait = "0.1.68" base64 = "0.22.1" -byteorder = "1.4.3" -clap = { version = "4.2.7", features = ["derive"] } +clap = { version = "4.5.22", features = ["derive"] } once_cell = "1.17.1" serde = { version = "1.0.160", features = ["serde_derive"] } serde_json = "1.0.96" -thiserror = "2.0.3" -tokio = { version = "1.28.0", features = ["full"] } -tokio-util = "0.7.8" +thiserror = "2.0.4" +tokio = { version = "1.42.0", features = ["full"] } +tokio-util = "0.7.13" toml = "0.8.19" tracing = { version = "0.1.37", features = ["log"] } tracing-subscriber = { version = "0.3.17", features = ["tracing-log"] } tracing-appender = "0.2.2" +nom = "7.1.3" diff --git a/src/net.rs b/src/net.rs index 4a041f8..400013f 100644 --- a/src/net.rs +++ b/src/net.rs @@ -1,7 +1,7 @@ use crate::protocol::{ ClientState, packets::{GenericPacket, serverbound::SL00LoginStart}, - parsing::parsable::Parsable, + parsing::Parsable, }; use std::{collections::VecDeque, sync::Arc, time::Instant}; use tokio::io::AsyncWriteExt; @@ -148,11 +148,11 @@ impl NetworkClient { data = d; self.incoming_packet_queue.push_back(packet); } - Err(crate::protocol::parsing::Error::Eof) => break, - Err(e) => { + Err(nom::Err::Incomplete(_)) => break, + Err(_) => { // Remove the valid bytes before this packet. self.incoming_data = self.incoming_data.split_off(bytes_consumed); - return Err(e.into()); + return Err(crate::protocol::Error::Parsing); } } } @@ -218,7 +218,7 @@ impl NetworkClient { Ok(()) } #[tracing::instrument] - pub async fn disconnect(&mut self, reason: Option) { + pub async fn disconnect(&mut self, reason: Option) { use crate::protocol::packets::clientbound::{CL00Disconnect, CP17Disconnect}; let reason = reason.unwrap_or(serde_json::json!({ "text": "You have been disconnected!" diff --git a/src/protocol/entities/cat.rs b/src/protocol/entities/cat.rs index c52115e..4ba6af6 100644 --- a/src/protocol/entities/cat.rs +++ b/src/protocol/entities/cat.rs @@ -1,4 +1,4 @@ -use crate::protocol::mctypes::VarInt; +use crate::protocol::types::VarInt; #[derive(Debug, Copy, Clone, PartialEq, Eq, Default)] pub struct Cat { diff --git a/src/protocol/entities/metadata.rs b/src/protocol/entities/metadata.rs index 89818e1..45bdd13 100644 --- a/src/protocol/entities/metadata.rs +++ b/src/protocol/entities/metadata.rs @@ -1,6 +1,6 @@ use crate::protocol::{ blocks::BlockFace, - mctypes::{Chat, Position, Uuid, VarInt}, + types::{Chat, Position, Uuid, VarInt}, }; pub type EntityMetadata = Vec; diff --git a/src/protocol/entities/mod.rs b/src/protocol/entities/mod.rs index 9266a52..22a3fd0 100644 --- a/src/protocol/entities/mod.rs +++ b/src/protocol/entities/mod.rs @@ -7,10 +7,10 @@ pub mod player; pub mod sniffer; pub mod villager; -use crate::protocol::parsing::{ParseResult, parsable::Parsable}; +use crate::protocol::parsing::{IResult, Parsable}; use crate::protocol::{ blocks::BlockPosition, - mctypes::{Chat, Uuid, VarInt}, + types::{Chat, Uuid, VarInt}, }; pub type EntityId = VarInt; @@ -24,7 +24,7 @@ pub struct EntityPosition { } impl Parsable for EntityPosition { #[tracing::instrument] - fn parse(data: &[u8]) -> ParseResult<'_, Self> { + fn parse(data: &[u8]) -> IResult<&[u8], Self> { let (data, x) = f64::parse(data)?; let (data, y) = f64::parse(data)?; let (data, z) = f64::parse(data)?; @@ -47,7 +47,7 @@ pub struct EntityRotation { } impl Parsable for EntityRotation { #[tracing::instrument] - fn parse(data: &[u8]) -> ParseResult<'_, Self> { + fn parse(data: &[u8]) -> IResult<&[u8], Self> { let (data, pitch) = u8::parse(data)?; let (data, yaw) = u8::parse(data)?; Ok((data, EntityRotation { pitch, yaw })) @@ -69,7 +69,7 @@ pub struct EntityVelocity { } impl Parsable for EntityVelocity { #[tracing::instrument] - fn parse(data: &[u8]) -> ParseResult<'_, Self> { + fn parse(data: &[u8]) -> IResult<&[u8], Self> { let (data, x) = i16::parse(data)?; let (data, y) = i16::parse(data)?; let (data, z) = i16::parse(data)?; diff --git a/src/protocol/entities/particle.rs b/src/protocol/entities/particle.rs index 54773bb..609cb41 100644 --- a/src/protocol/entities/particle.rs +++ b/src/protocol/entities/particle.rs @@ -1,5 +1,5 @@ use super::EntityId; -use crate::protocol::mctypes::{Position, VarInt}; +use crate::protocol::types::{Position, VarInt}; #[derive(Debug, Copy, Clone, PartialEq)] pub struct Particle { diff --git a/src/protocol/entities/player.rs b/src/protocol/entities/player.rs index 022e962..4eba58b 100644 --- a/src/protocol/entities/player.rs +++ b/src/protocol/entities/player.rs @@ -1,4 +1,4 @@ -use crate::protocol::mctypes::VarInt; +use crate::protocol::types::VarInt; #[derive(Clone, Debug, PartialEq, Default)] pub struct Player { diff --git a/src/protocol/entities/villager.rs b/src/protocol/entities/villager.rs index b8fa958..203e4dd 100644 --- a/src/protocol/entities/villager.rs +++ b/src/protocol/entities/villager.rs @@ -1,4 +1,4 @@ -use crate::protocol::mctypes::VarInt; +use crate::protocol::types::VarInt; #[derive(Debug, Copy, Clone, PartialEq, Eq, Default)] pub struct Villager { diff --git a/src/protocol/error.rs b/src/protocol/error.rs index ef80e9a..1cb7414 100644 --- a/src/protocol/error.rs +++ b/src/protocol/error.rs @@ -13,9 +13,9 @@ pub enum Error { /// This error was caused by attempting to send or receive data from a disconnected client. #[error("communicating to disconnected client")] Disconnected, - /// This error is a wrapper for `crate::parsing::Error`. - #[error(transparent)] - ParseError(#[from] crate::protocol::parsing::Error), + /// The data was not able to be parsed. + #[error("parsing")] + Parsing, /// This error is general purpose. /// When possible, other error variants should be used. #[error(transparent)] diff --git a/src/protocol/mod.rs b/src/protocol/mod.rs index 31439cd..3564415 100644 --- a/src/protocol/mod.rs +++ b/src/protocol/mod.rs @@ -7,7 +7,7 @@ pub mod error; /// Implementation of Minecraft's items and inventories. pub mod inventory; /// Useful types for representing the Minecraft protocol. -pub mod mctypes; +pub mod types; /// Network packets. /// /// The packet naming convention used is "DSIDName" where diff --git a/src/protocol/packets/clientbound/login.rs b/src/protocol/packets/clientbound/login.rs index ea514b0..2b6953a 100644 --- a/src/protocol/packets/clientbound/login.rs +++ b/src/protocol/packets/clientbound/login.rs @@ -1,5 +1,5 @@ -use crate::protocol::mctypes::{Chat, Json, Uuid, VarInt}; -use crate::protocol::parsing::parsable::Parsable; +use crate::protocol::types::{Chat, Json, Uuid, VarInt}; +use crate::protocol::parsing::Parsable; #[derive(Clone, Debug, PartialEq)] pub struct CL00Disconnect { @@ -10,7 +10,7 @@ crate::protocol::packets::packet!( 0x00, crate::protocol::ClientState::Login, false, - |data: &'data [u8]| -> crate::protocol::parsing::ParseResult<'data, CL00Disconnect> { + |data: &'data [u8]| -> crate::protocol::parsing::IResult<&'data [u8], CL00Disconnect> { let (data, reason) = Json::parse(data)?; Ok((data, CL00Disconnect { reason })) }, @@ -28,7 +28,7 @@ crate::protocol::packets::packet!( 0x01, crate::protocol::ClientState::Login, false, - |data: &'data [u8]| -> crate::protocol::parsing::ParseResult<'data, CL01EncryptionRequest> { + |data: &'data [u8]| -> crate::protocol::parsing::IResult<&'data [u8], CL01EncryptionRequest> { let (data, server_id) = String::parse(data)?; let (data, public_key) = u8::parse_vec(data)?; let (data, verify_token) = u8::parse_vec(data)?; @@ -62,7 +62,7 @@ pub struct CL02LoginSuccessProperty { } impl Parsable for CL02LoginSuccessProperty { #[tracing::instrument] - fn parse(data: &[u8]) -> crate::protocol::parsing::ParseResult<'_, Self> { + fn parse(data: &[u8]) -> crate::protocol::parsing::IResult<&[u8], Self> { let (data, name) = String::parse(data)?; let (data, value) = String::parse(data)?; let (data, signature) = String::parse_optional(data)?; @@ -86,7 +86,7 @@ crate::protocol::packets::packet!( 0x02, crate::protocol::ClientState::Login, false, - |data: &'data [u8]| -> crate::protocol::parsing::ParseResult<'data, CL02LoginSuccess> { + |data: &'data [u8]| -> crate::protocol::parsing::IResult<&'data [u8], CL02LoginSuccess> { let (data, uuid) = Uuid::parse(data)?; let (data, username) = String::parse(data)?; let (data, properties) = CL02LoginSuccessProperty::parse_vec(data)?; @@ -115,7 +115,7 @@ crate::protocol::packets::packet!( 0x03, crate::protocol::ClientState::Login, false, - |data: &'data [u8]| -> crate::protocol::parsing::ParseResult<'data, CL03SetCompression> { + |data: &'data [u8]| -> crate::protocol::parsing::IResult<&'data [u8], CL03SetCompression> { let (data, threshold) = VarInt::parse(data)?; Ok((data, CL03SetCompression { threshold })) }, @@ -133,7 +133,7 @@ crate::protocol::packets::packet!( 0x04, crate::protocol::ClientState::Login, false, - |data: &'data [u8]| -> crate::protocol::parsing::ParseResult<'data, CL04LoginPluginRequest> { + |data: &'data [u8]| -> crate::protocol::parsing::IResult<&'data [u8], CL04LoginPluginRequest> { let (data, message_id) = VarInt::parse(data)?; let (data, channel) = String::parse(data)?; Ok((data, CL04LoginPluginRequest { diff --git a/src/protocol/packets/clientbound/play.rs b/src/protocol/packets/clientbound/play.rs index e4e9b1e..999a516 100644 --- a/src/protocol/packets/clientbound/play.rs +++ b/src/protocol/packets/clientbound/play.rs @@ -1,6 +1,6 @@ use crate::protocol::{ entities::{EntityPosition, EntityRotation, EntityVelocity}, - mctypes::{Chat, Difficulty, Position, Uuid, VarInt}, + types::{Chat, Difficulty, Position, Uuid, VarInt}, }; #[derive(Copy, Clone, Debug, PartialEq)] @@ -19,7 +19,7 @@ crate::protocol::packets::packet!( 0x00, crate::protocol::ClientState::Play, false, - |data: &'data [u8]| -> crate::protocol::parsing::ParseResult<'data, CP00SpawnEntity> { + |data: &'data [u8]| -> crate::protocol::parsing::IResult<&'data [u8], CP00SpawnEntity> { let (data, id) = VarInt::parse(data)?; let (data, uuid) = Uuid::parse(data)?; let (data, kind) = VarInt::parse(data)?; @@ -64,7 +64,7 @@ crate::protocol::packets::packet!( 0x0b, crate::protocol::ClientState::Play, false, - |data: &'data [u8]| -> crate::protocol::parsing::ParseResult<'data, CP0BChangeDifficulty> { + |data: &'data [u8]| -> crate::protocol::parsing::IResult<&'data [u8], CP0BChangeDifficulty> { let (data, difficulty) = Difficulty::parse(data)?; let (data, is_locked) = bool::parse(data)?; Ok((data, CP0BChangeDifficulty { @@ -89,7 +89,7 @@ crate::protocol::packets::packet!( 0x17, crate::protocol::ClientState::Play, false, - |data: &'data [u8]| -> crate::protocol::parsing::ParseResult<'data, CP17Disconnect> { + |data: &'data [u8]| -> crate::protocol::parsing::IResult<&'data [u8], CP17Disconnect> { let (data, reason) = Chat::parse(data)?; Ok((data, CP17Disconnect { reason })) }, @@ -105,7 +105,7 @@ crate::protocol::packets::packet!( 0x1f, crate::protocol::ClientState::Play, false, - |data: &'data [u8]| -> crate::protocol::parsing::ParseResult<'data, CP1FKeepAlive> { + |data: &'data [u8]| -> crate::protocol::parsing::IResult<&'data [u8], CP1FKeepAlive> { let (data, payload) = i64::parse(data)?; Ok((data, CP1FKeepAlive { payload })) }, @@ -124,7 +124,7 @@ crate::protocol::packets::packet!( 0x21, crate::protocol::ClientState::Play, false, - |data: &'data [u8]| -> crate::protocol::parsing::ParseResult<'data, CP21WorldEvent> { + |data: &'data [u8]| -> crate::protocol::parsing::IResult<&'data [u8], CP21WorldEvent> { let (data, event) = i32::parse(data)?; let (data, location) = Position::parse(data)?; let (data, d) = i32::parse(data)?; @@ -156,7 +156,7 @@ crate::protocol::packets::packet!( 0x50, crate::protocol::ClientState::Play, false, - |data: &'data [u8]| -> crate::protocol::parsing::ParseResult<'data, CP50SetEntityVelocity> { + |data: &'data [u8]| -> crate::protocol::parsing::IResult<&'data [u8], CP50SetEntityVelocity> { let (data, entity_id) = VarInt::parse(data)?; let (data, entity_velocity) = EntityVelocity::parse(data)?; Ok((data, CP50SetEntityVelocity { @@ -183,7 +183,7 @@ crate::protocol::packets::packet!( 0x52, crate::protocol::ClientState::Play, false, - |data: &'data [u8]| -> crate::protocol::parsing::ParseResult<'data, CP52SetExperience> { + |data: &'data [u8]| -> crate::protocol::parsing::IResult<&'data [u8], CP52SetExperience> { let (data, experience_bar) = f32::parse(data)?; let (data, total_experience) = VarInt::parse(data)?; let (data, level) = VarInt::parse(data)?; @@ -219,7 +219,7 @@ crate::protocol::packets::packet!( 0x68, crate::protocol::ClientState::Play, false, - |data: &'data [u8]| -> crate::protocol::parsing::ParseResult<'data, CP68EntityEffect> { + |data: &'data [u8]| -> crate::protocol::parsing::IResult<&'data [u8], CP68EntityEffect> { let (data, entity_id) = VarInt::parse(data)?; let (data, effect_id) = VarInt::parse(data)?; let (data, amplifier) = i8::parse(data)?; diff --git a/src/protocol/packets/clientbound/status.rs b/src/protocol/packets/clientbound/status.rs index 2b2e934..a817348 100644 --- a/src/protocol/packets/clientbound/status.rs +++ b/src/protocol/packets/clientbound/status.rs @@ -1,4 +1,4 @@ -use crate::protocol::mctypes::Json; +use crate::protocol::types::Json; #[derive(Clone, Debug, PartialEq)] pub struct CS00StatusResponse { @@ -9,7 +9,7 @@ crate::protocol::packets::packet!( 0x00, crate::protocol::ClientState::Status, false, - |data: &'data [u8]| -> crate::protocol::parsing::ParseResult<'data, CS00StatusResponse> { + |data: &'data [u8]| -> crate::protocol::parsing::IResult<&'data [u8], CS00StatusResponse> { let (data, response) = Json::parse(data)?; Ok((data, CS00StatusResponse { response })) }, @@ -25,7 +25,7 @@ crate::protocol::packets::packet!( 0x01, crate::protocol::ClientState::Status, false, - |data: &'data [u8]| -> crate::protocol::parsing::ParseResult<'data, CS01PingResponse> { + |data: &'data [u8]| -> crate::protocol::parsing::IResult<&'data [u8], CS01PingResponse> { let (data, payload) = i64::parse(data)?; Ok((data, CS01PingResponse { payload })) }, diff --git a/src/protocol/packets/mod.rs b/src/protocol/packets/mod.rs index 385dc9d..b03ea82 100644 --- a/src/protocol/packets/mod.rs +++ b/src/protocol/packets/mod.rs @@ -3,8 +3,7 @@ pub mod clientbound; /// Packets that are heading to the server. pub mod serverbound; -use crate::protocol::mctypes::VarInt; -use crate::protocol::parsing::prelude::*; +use crate::protocol::parsing::{VarInt, Parsable}; /// Alias for a `VarInt`. pub type PacketId = VarInt; @@ -31,16 +30,16 @@ macro_rules! generic_packet { client_state: crate::protocol::ClientState, is_serverbound: bool, data: &'data [u8] - ) -> crate::protocol::parsing::ParseResult<'data, Self> { - use crate::protocol::parsing::parsable::Parsable; + ) -> crate::protocol::parsing::IResult<&'data [u8], Self> { + use crate::protocol::parsing::Parsable; tracing::trace!( "GenericPacket::parse_uncompressed: {:?} {} {:?}", client_state, is_serverbound, data ); - let (data, packet_length) = crate::protocol::mctypes::VarInt::parse(data)?; - let (data, packet_data) = crate::protocol::parsing::take_bytes(*packet_length as usize)(data)?; + let (data, packet_length) = crate::protocol::types::VarInt::parse(data)?; + let (data, packet_data) = nom::bytes::streaming::take(*packet_length as usize)(data)?; let (packet_data, packet_id) = PacketId::parse(packet_data)?; let (_packet_data, packet_body) = @@ -59,8 +58,8 @@ macro_rules! generic_packet { packet_id: crate::protocol::packets::PacketId, is_serverbound: bool, data: &'data [u8], - ) -> crate::protocol::parsing::ParseResult<'data, Self> { - use crate::protocol::parsing::parsable::Parsable; + ) -> crate::protocol::parsing::IResult<&'data [u8], Self> { + use crate::protocol::parsing::Parsable; tracing::trace!( "GenericPacket::parse_body: {:?} {} {}", client_state, @@ -77,7 +76,7 @@ macro_rules! generic_packet { #[tracing::instrument] pub fn serialize(&self) -> (crate::protocol::packets::PacketId, Vec) { - use crate::protocol::parsing::parsable::Parsable; + use crate::protocol::parsing::Parsable; tracing::trace!("GenericPacket::serialize: {:?}", self); match self { $( @@ -96,7 +95,7 @@ packet!( 0x00, crate::protocol::ClientState::Disconnected, false, - |data: &'data [u8]| -> crate::protocol::parsing::ParseResult<'data, UnimplementedPacket> { + |data: &'data [u8]| -> crate::protocol::parsing::IResult<&'data [u8], UnimplementedPacket> { Ok((data, UnimplementedPacket(0i32.into()))) }, |_packet: &UnimplementedPacket| -> Vec { vec![] } @@ -145,11 +144,11 @@ macro_rules! packet { const CLIENT_STATE: crate::protocol::ClientState = $client_state; const IS_SERVERBOUND: bool = $serverbound; } - impl crate::protocol::parsing::parsable::Parsable for $packet_type { + impl crate::protocol::parsing::Parsable for $packet_type { #[tracing::instrument] fn parse<'data>( data: &'data [u8], - ) -> crate::protocol::parsing::ParseResult<'data, Self> { + ) -> crate::protocol::parsing::IResult<&'data [u8], Self> { $parse_body(data) } #[tracing::instrument] diff --git a/src/protocol/packets/serverbound/handshake.rs b/src/protocol/packets/serverbound/handshake.rs index cdc3121..56ecb8f 100644 --- a/src/protocol/packets/serverbound/handshake.rs +++ b/src/protocol/packets/serverbound/handshake.rs @@ -1,4 +1,5 @@ -use crate::protocol::{ClientState, mctypes::VarInt}; +use crate::protocol::{ClientState, types::VarInt}; +use nom::combinator::map_res; #[derive(Clone, Debug, PartialEq)] pub struct SH00Handshake { @@ -12,21 +13,22 @@ crate::protocol::packets::packet!( 0x00, ClientState::Handshake, true, - |data: &'data [u8]| -> crate::protocol::parsing::ParseResult<'data, SH00Handshake> { + |data: &'data [u8]| -> crate::protocol::parsing::IResult<&'data [u8], SH00Handshake> { let (data, protocol_version) = VarInt::parse(data)?; let (data, server_address) = String::parse(data)?; let (data, server_port) = u16::parse(data)?; - let (data, next_state) = VarInt::parse(data)?; + // let (data, next_state) = VarInt::parse(data)?; + let (data, next_state) = map_res(VarInt::parse, |next_state: VarInt| match *next_state { + 1 => Ok(ClientState::Status), + 2 => Ok(ClientState::Login), + _ => Err(()), + })(data)?; Ok((data, SH00Handshake { protocol_version, server_address, server_port, - next_state: match *next_state { - 1 => ClientState::Status, - 2 => ClientState::Login, - _ => todo!("Invalid next state"), - }, + next_state, })) }, |packet: &SH00Handshake| -> Vec { diff --git a/src/protocol/packets/serverbound/login.rs b/src/protocol/packets/serverbound/login.rs index ae10eac..05406a5 100644 --- a/src/protocol/packets/serverbound/login.rs +++ b/src/protocol/packets/serverbound/login.rs @@ -1,5 +1,5 @@ -use crate::protocol::mctypes::{Uuid, VarInt}; -use crate::protocol::parsing::take_bytes; +use crate::protocol::types::{Uuid, VarInt}; +use nom::bytes::streaming::take; #[derive(Clone, Debug, PartialEq)] pub struct SL00LoginStart { @@ -11,7 +11,7 @@ crate::protocol::packets::packet!( 0x00, crate::protocol::ClientState::Login, true, - |data: &'data [u8]| -> crate::protocol::parsing::ParseResult<'data, SL00LoginStart> { + |data: &'data [u8]| -> crate::protocol::parsing::IResult<&'data [u8], SL00LoginStart> { let (data, name) = String::parse(data)?; let (data, has_uuid) = bool::parse(data)?; if has_uuid { @@ -45,11 +45,11 @@ crate::protocol::packets::packet!( 0x01, crate::protocol::ClientState::Login, true, - |data: &'data [u8]| -> crate::protocol::parsing::ParseResult<'data, SL01EncryptionResponse> { + |data: &'data [u8]| -> crate::protocol::parsing::IResult<&'data [u8], SL01EncryptionResponse> { let (data, shared_secret_len) = VarInt::parse(data)?; - let (data, shared_secret) = take_bytes(*shared_secret_len as usize)(data)?; + let (data, shared_secret) = take(*shared_secret_len as usize)(data)?; let (data, verify_token_len) = VarInt::parse(data)?; - let (data, verify_token) = take_bytes(*verify_token_len as usize)(data)?; + let (data, verify_token) = take(*verify_token_len as usize)(data)?; Ok((data, SL01EncryptionResponse { shared_secret: shared_secret.to_vec(), @@ -77,7 +77,7 @@ crate::protocol::packets::packet!( 0x02, crate::protocol::ClientState::Login, true, - |data: &'data [u8]| -> crate::protocol::parsing::ParseResult<'data, SL02LoginPluginResponse> { + |data: &'data [u8]| -> crate::protocol::parsing::IResult<&'data [u8], SL02LoginPluginResponse> { let (data, message_id) = VarInt::parse(data)?; let (data, successful) = bool::parse(data)?; if successful { diff --git a/src/protocol/packets/serverbound/play.rs b/src/protocol/packets/serverbound/play.rs index 294b5d7..71a9143 100644 --- a/src/protocol/packets/serverbound/play.rs +++ b/src/protocol/packets/serverbound/play.rs @@ -1,6 +1,6 @@ use crate::protocol::{ entities::{EntityPosition, EntityRotation}, - mctypes::VarInt, + types::VarInt, }; #[derive(Clone, Debug, PartialEq)] @@ -13,7 +13,7 @@ crate::protocol::packets::packet!( 0x08, crate::protocol::ClientState::Play, true, - |data: &'data [u8]| -> crate::protocol::parsing::ParseResult<'data, SP08CommandSuggestionsRequest> { + |data: &'data [u8]| -> crate::protocol::parsing::IResult<&'data [u8], SP08CommandSuggestionsRequest> { let (data, transaction_id) = VarInt::parse(data)?; let (data, text) = String::parse(data)?; Ok((data, SP08CommandSuggestionsRequest { @@ -38,7 +38,7 @@ crate::protocol::packets::packet!( 0x11, crate::protocol::ClientState::Play, true, - |data: &'data [u8]| -> crate::protocol::parsing::ParseResult<'data, SP11KeepAlive> { + |data: &'data [u8]| -> crate::protocol::parsing::IResult<&'data [u8], SP11KeepAlive> { let (data, payload) = i64::parse(data)?; Ok((data, SP11KeepAlive { payload })) }, @@ -55,7 +55,7 @@ crate::protocol::packets::packet!( 0x13, crate::protocol::ClientState::Play, true, - |data: &'data [u8]| -> crate::protocol::parsing::ParseResult<'data, SP13SetPlayerPosition> { + |data: &'data [u8]| -> crate::protocol::parsing::IResult<&'data [u8], SP13SetPlayerPosition> { let (data, position) = EntityPosition::parse(data)?; let (data, on_ground) = bool::parse(data)?; Ok((data, SP13SetPlayerPosition { @@ -82,7 +82,7 @@ crate::protocol::packets::packet!( 0x14, crate::protocol::ClientState::Play, true, - |data: &'data [u8]| -> crate::protocol::parsing::ParseResult<'data, SP14SetPlayerPositionAndRotation> { + |data: &'data [u8]| -> crate::protocol::parsing::IResult<&'data [u8], SP14SetPlayerPositionAndRotation> { let (data, position) = EntityPosition::parse(data)?; let (data, rotation) = EntityRotation::parse(data)?; let (data, on_ground) = bool::parse(data)?; @@ -111,7 +111,7 @@ crate::protocol::packets::packet!( 0x15, crate::protocol::ClientState::Play, true, - |data: &'data [u8]| -> crate::protocol::parsing::ParseResult<'data, SP15SetPlayerRotation> { + |data: &'data [u8]| -> crate::protocol::parsing::IResult<&'data [u8], SP15SetPlayerRotation> { let (data, rotation) = EntityRotation::parse(data)?; let (data, on_ground) = bool::parse(data)?; Ok((data, SP15SetPlayerRotation { diff --git a/src/protocol/packets/serverbound/status.rs b/src/protocol/packets/serverbound/status.rs index 31f156d..c4b3b8d 100644 --- a/src/protocol/packets/serverbound/status.rs +++ b/src/protocol/packets/serverbound/status.rs @@ -5,7 +5,7 @@ crate::protocol::packets::packet!( 0x00, crate::protocol::ClientState::Status, true, - |data: &'data [u8]| -> crate::protocol::parsing::ParseResult<'data, SS00StatusRequest> { + |data: &'data [u8]| -> crate::protocol::parsing::IResult<&'data [u8], SS00StatusRequest> { Ok((data, SS00StatusRequest)) }, |_packet: &SS00StatusRequest| -> Vec { vec![] } @@ -20,7 +20,7 @@ crate::protocol::packets::packet!( 0x01, crate::protocol::ClientState::Status, true, - |data: &'data [u8]| -> crate::protocol::parsing::ParseResult<'data, SS01PingRequest> { + |data: &'data [u8]| -> crate::protocol::parsing::IResult<&'data [u8], SS01PingRequest> { let (data, payload) = i64::parse(data)?; Ok((data, SS01PingRequest { payload })) }, diff --git a/src/protocol/parsing/parsable.rs b/src/protocol/parsing.rs similarity index 65% rename from src/protocol/parsing/parsable.rs rename to src/protocol/parsing.rs index a451ee0..7d8968c 100644 --- a/src/protocol/parsing/parsable.rs +++ b/src/protocol/parsing.rs @@ -1,12 +1,50 @@ -use super::{Error, ParseResult, VarInt, take_bytes}; -use byteorder::{BigEndian, ReadBytesExt}; +pub use nom::IResult; +use nom::{bytes::streaming::{take, take_while_m_n}, number::streaming as nom_nums, combinator::map_res}; + +/// Implementation of the protocol's VarInt type. +/// +/// Simple wrapper around an i32, but is parsed and serialized differently. +/// When the original i32 value is needed, simply `Deref` it. +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Default, Hash)] +pub struct VarInt(i32); +impl std::ops::Deref for VarInt { + type Target = i32; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl std::ops::DerefMut for VarInt { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl From for VarInt { + fn from(value: i32) -> Self { + VarInt(value) + } +} +impl From for i32 { + fn from(value: VarInt) -> Self { + *value + } +} +impl From for VarInt { + fn from(value: usize) -> Self { + (value as i32).into() + } +} +impl std::fmt::Display for VarInt { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self) + } +} /// A structure that can be serialized and deserialized. /// /// Similar to serde's `Serialize` and `Deserialize` traits. pub trait Parsable { /// Attempt to parse (deserialize) `Self` from the given byte slice. - fn parse(data: &[u8]) -> ParseResult<'_, Self> + fn parse(data: &[u8]) -> IResult<&[u8], Self> where Self: Sized; /// Serialize `self` into a vector of bytes. @@ -16,7 +54,7 @@ pub trait Parsable { /// /// An `Option` is represented in the protocol as /// a boolean optionally followed by `T` if the boolean was true. - fn parse_optional(data: &[u8]) -> ParseResult<'_, Option> + fn parse_optional(data: &[u8]) -> IResult<&[u8], Option> where Self: Sized, { @@ -32,7 +70,7 @@ pub trait Parsable { /// Helper to parse `num` repetitions of `Self`. /// /// Useful with an array of known length. - fn parse_repeated(num: usize, mut data: &[u8]) -> ParseResult<'_, Vec> + fn parse_repeated(num: usize, mut data: &[u8]) -> IResult<&[u8], Vec> where Self: Sized, { @@ -49,7 +87,7 @@ pub trait Parsable { /// /// In the protocol, arrays are commonly prefixed with their length /// as a `VarInt`. - fn parse_vec(data: &[u8]) -> ParseResult<'_, Vec> + fn parse_vec(data: &[u8]) -> IResult<&[u8], Vec> where Self: Sized, { @@ -59,7 +97,7 @@ pub trait Parsable { } impl Parsable for Option { #[tracing::instrument] - fn parse(data: &[u8]) -> ParseResult<'_, Self> { + fn parse(data: &[u8]) -> IResult<&[u8], Self> { let (data, exists) = bool::parse(data)?; if exists { let (data, thing) = T::parse(data)?; @@ -83,7 +121,7 @@ impl Parsable for Option { } impl Parsable for Vec { #[tracing::instrument] - fn parse(data: &[u8]) -> ParseResult<'_, Self> { + fn parse(data: &[u8]) -> IResult<&[u8], Self> { T::parse_vec(data) } #[tracing::instrument] @@ -99,10 +137,8 @@ impl Parsable for Vec { impl Parsable for serde_json::Value { #[tracing::instrument] - fn parse(data: &[u8]) -> ParseResult<'_, Self> { - let (data, json) = String::parse(data)?; - let json = serde_json::from_str(&json)?; - Ok((data, json)) + fn parse(data: &[u8]) -> IResult<&[u8], Self> { + map_res(String::parse, |json: String| serde_json::from_str(&json))(data) } #[tracing::instrument] fn serialize(&self) -> Vec { @@ -111,29 +147,14 @@ impl Parsable for serde_json::Value { } impl Parsable for VarInt { #[tracing::instrument] - fn parse(data: &[u8]) -> ParseResult<'_, Self> { + fn parse(data: &[u8]) -> IResult<&[u8], Self> { let mut output = 0u32; - let mut bytes_read = 0; - for i in 0..=5 { - if i == 5 { - // VarInts can only have 5 bytes maximum. - return Err(Error::VarIntTooLong); - } else if data.len() <= i { - return Err(Error::Eof); - } - - let byte = data[i]; - output |= ((byte & 0x7f) as u32) << (7 * i); - - if byte & 0x80 != 0x80 { - // We found the last byte of the VarInt. - bytes_read = i + 1; - break; - } + let (rest, bytes) = take_while_m_n(1, 5, |byte| byte & 0x80 == 0x80)(data)?; + for (i, &b) in bytes.iter().enumerate() { + output |= ((b & 0x7f) as u32) << (7 * i); } - - Ok((&data[bytes_read..], VarInt(output as i32))) + Ok((rest, VarInt(output as i32))) } #[tracing::instrument] fn serialize(&self) -> Vec { @@ -155,9 +176,9 @@ impl Parsable for VarInt { } impl Parsable for String { #[tracing::instrument] - fn parse(data: &[u8]) -> ParseResult<'_, Self> { + fn parse(data: &[u8]) -> IResult<&[u8], Self> { let (data, len) = VarInt::parse(data)?; - let (data, str_bytes) = take_bytes(*len as usize)(data)?; + let (data, str_bytes) = take(*len as usize)(data)?; let s = String::from_utf8_lossy(str_bytes).to_string(); Ok((data, s)) } @@ -171,10 +192,8 @@ impl Parsable for String { } impl Parsable for u8 { #[tracing::instrument] - fn parse(data: &[u8]) -> ParseResult<'_, Self> { - let (data, mut bytes) = take_bytes(1)(data)?; - let i = bytes.read_u8().map_err(|_| Error::Eof)?; - Ok((data, i)) + fn parse(data: &[u8]) -> IResult<&[u8], Self> { + nom_nums::u8(data) } #[tracing::instrument] fn serialize(&self) -> Vec { @@ -183,10 +202,8 @@ impl Parsable for u8 { } impl Parsable for i8 { #[tracing::instrument] - fn parse(data: &[u8]) -> ParseResult<'_, Self> { - let (data, mut bytes) = take_bytes(1)(data)?; - let i = bytes.read_i8().map_err(|_| Error::Eof)?; - Ok((data, i)) + fn parse(data: &[u8]) -> IResult<&[u8], Self> { + nom_nums::i8(data) } #[tracing::instrument] fn serialize(&self) -> Vec { @@ -195,10 +212,8 @@ impl Parsable for i8 { } impl Parsable for u16 { #[tracing::instrument] - fn parse(data: &[u8]) -> ParseResult<'_, Self> { - let (data, mut bytes) = take_bytes(2)(data)?; - let i = bytes.read_u16::().map_err(|_| Error::Eof)?; - Ok((data, i)) + fn parse(data: &[u8]) -> IResult<&[u8], Self> { + nom_nums::be_u16(data) } #[tracing::instrument] fn serialize(&self) -> Vec { @@ -207,10 +222,8 @@ impl Parsable for u16 { } impl Parsable for i16 { #[tracing::instrument] - fn parse(data: &[u8]) -> ParseResult<'_, Self> { - let (data, mut bytes) = take_bytes(2)(data)?; - let i = bytes.read_i16::().map_err(|_| Error::Eof)?; - Ok((data, i)) + fn parse(data: &[u8]) -> IResult<&[u8], Self> { + nom_nums::be_i16(data) } #[tracing::instrument] fn serialize(&self) -> Vec { @@ -219,10 +232,8 @@ impl Parsable for i16 { } impl Parsable for u32 { #[tracing::instrument] - fn parse(data: &[u8]) -> ParseResult<'_, Self> { - let (data, mut bytes) = take_bytes(4)(data)?; - let i = bytes.read_u32::().map_err(|_| Error::Eof)?; - Ok((data, i)) + fn parse(data: &[u8]) -> IResult<&[u8], Self> { + nom_nums::be_u32(data) } #[tracing::instrument] fn serialize(&self) -> Vec { @@ -231,10 +242,8 @@ impl Parsable for u32 { } impl Parsable for i32 { #[tracing::instrument] - fn parse(data: &[u8]) -> ParseResult<'_, Self> { - let (data, mut bytes) = take_bytes(4)(data)?; - let i = bytes.read_i32::().map_err(|_| Error::Eof)?; - Ok((data, i)) + fn parse(data: &[u8]) -> IResult<&[u8], Self> { + nom_nums::be_i32(data) } #[tracing::instrument] fn serialize(&self) -> Vec { @@ -243,10 +252,8 @@ impl Parsable for i32 { } impl Parsable for u64 { #[tracing::instrument] - fn parse(data: &[u8]) -> ParseResult<'_, Self> { - let (data, mut bytes) = take_bytes(8)(data)?; - let i = bytes.read_u64::().map_err(|_| Error::Eof)?; - Ok((data, i)) + fn parse(data: &[u8]) -> IResult<&[u8], Self> { + nom_nums::be_u64(data) } #[tracing::instrument] fn serialize(&self) -> Vec { @@ -255,10 +262,8 @@ impl Parsable for u64 { } impl Parsable for i64 { #[tracing::instrument] - fn parse(data: &[u8]) -> ParseResult<'_, Self> { - let (data, mut bytes) = take_bytes(8)(data)?; - let i = bytes.read_i64::().map_err(|_| Error::Eof)?; - Ok((data, i)) + fn parse(data: &[u8]) -> IResult<&[u8], Self> { + nom_nums::be_i64(data) } #[tracing::instrument] fn serialize(&self) -> Vec { @@ -267,10 +272,8 @@ impl Parsable for i64 { } impl Parsable for u128 { #[tracing::instrument] - fn parse(data: &[u8]) -> ParseResult<'_, Self> { - let (data, mut bytes) = take_bytes(16)(data)?; - let i = bytes.read_u128::().map_err(|_| Error::Eof)?; - Ok((data, i)) + fn parse(data: &[u8]) -> IResult<&[u8], Self> { + nom_nums::be_u128(data) } #[tracing::instrument] fn serialize(&self) -> Vec { @@ -279,10 +282,8 @@ impl Parsable for u128 { } impl Parsable for i128 { #[tracing::instrument] - fn parse(data: &[u8]) -> ParseResult<'_, Self> { - let (data, mut bytes) = take_bytes(16)(data)?; - let i = bytes.read_i128::().map_err(|_| Error::Eof)?; - Ok((data, i)) + fn parse(data: &[u8]) -> IResult<&[u8], Self> { + nom_nums::be_i128(data) } #[tracing::instrument] fn serialize(&self) -> Vec { @@ -291,10 +292,8 @@ impl Parsable for i128 { } impl Parsable for f32 { #[tracing::instrument] - fn parse(data: &[u8]) -> ParseResult<'_, Self> { - let (data, mut bytes) = take_bytes(4)(data)?; - let i = bytes.read_f32::().map_err(|_| Error::Eof)?; - Ok((data, i)) + fn parse(data: &[u8]) -> IResult<&[u8], Self> { + nom_nums::be_f32(data) } #[tracing::instrument] fn serialize(&self) -> Vec { @@ -303,10 +302,8 @@ impl Parsable for f32 { } impl Parsable for f64 { #[tracing::instrument] - fn parse(data: &[u8]) -> ParseResult<'_, Self> { - let (data, mut bytes) = take_bytes(8)(data)?; - let i = bytes.read_f64::().map_err(|_| Error::Eof)?; - Ok((data, i)) + fn parse(data: &[u8]) -> IResult<&[u8], Self> { + nom_nums::be_f64(data) } #[tracing::instrument] fn serialize(&self) -> Vec { @@ -315,9 +312,8 @@ impl Parsable for f64 { } impl Parsable for bool { #[tracing::instrument] - fn parse(data: &[u8]) -> ParseResult<'_, Self> { - let (data, bytes) = take_bytes(1)(data)?; - Ok((data, bytes[0] > 0x00)) + fn parse(data: &[u8]) -> IResult<&[u8], Self> { + nom_nums::u8(data).map(|(data, num)| (data, num > 0x00)) } #[tracing::instrument] fn serialize(&self) -> Vec { @@ -384,3 +380,4 @@ mod tests { } } } + diff --git a/src/protocol/parsing/error.rs b/src/protocol/parsing/error.rs deleted file mode 100644 index 1e55355..0000000 --- a/src/protocol/parsing/error.rs +++ /dev/null @@ -1,29 +0,0 @@ -/// This type represents all possible errors that can occur when serializing or deserializing Minecraft data. -#[derive(thiserror::Error, Debug)] -pub enum Error { - /// This error was caused by unexpected or invalid data. - #[error("invalid syntax")] - Syntax, - /// This error was caused by prematurely reaching the end of the input data. - #[error("unexpected end of file")] - Eof, - /// This error was caused by reading a `crate::parsing::VarInt` that was longer than 5 bytes. - #[error("VarInt was more than 5 bytes")] - VarIntTooLong, - /// This error is a wrapper for `serde_json::Error`. - #[error(transparent)] - InvalidJson(#[from] serde_json::Error), - /// This error is general purpose. - /// When possible, other error variants should be used. - #[error("custom error: {0}")] - Message(String), -} - -/// Alias for a Result with the error type `crate::parsing::Error`. -pub type Result = std::result::Result; - -/// Alias for a Result that helps with zero-copy parsing. -/// -/// The error type is `crate::parsing::Error`, -/// and the result type is a tuple of the remaining bytes and the parsed item. -pub type ParseResult<'data, T> = Result<(&'data [u8], T)>; diff --git a/src/protocol/parsing/mod.rs b/src/protocol/parsing/mod.rs deleted file mode 100644 index b28ac45..0000000 --- a/src/protocol/parsing/mod.rs +++ /dev/null @@ -1,79 +0,0 @@ -/// When serializing or deserializing data encounters errors. -pub mod error; -/// The `Parsable` trait, and implementations for useful types. -pub mod parsable; -/// Useful re-exports. -pub mod prelude { - pub use super::{VarInt, parsable::Parsable, take_bytes}; -} - -pub use error::{Error, ParseResult, Result}; -pub use serde_json; - -/// Returns a function that returns a `ParseResult<&[u8]>`, where the slice is size `num`. -pub fn take_bytes(num: usize) -> impl Fn(&'_ [u8]) -> ParseResult<'_, &'_ [u8]> { - move |data| { - use std::cmp::Ordering; - - match data.len().cmp(&num) { - Ordering::Greater => Ok((&data[num..], &data[..num])), - Ordering::Equal => Ok((&[], data)), - Ordering::Less => Err(Error::Eof), - } - } -} - -/// Implementation of the protocol's VarInt type. -/// -/// Simple wrapper around an i32, but is parsed and serialized differently. -/// When the original i32 value is needed, simply `Deref` it. -#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Default, Hash)] -pub struct VarInt(i32); -impl std::ops::Deref for VarInt { - type Target = i32; - fn deref(&self) -> &Self::Target { - &self.0 - } -} -impl std::ops::DerefMut for VarInt { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } -} -impl From for VarInt { - fn from(value: i32) -> Self { - VarInt(value) - } -} -impl From for i32 { - fn from(value: VarInt) -> Self { - *value - } -} -impl From for VarInt { - fn from(value: usize) -> Self { - (value as i32).into() - } -} -impl std::fmt::Display for VarInt { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn take_bytes_works() { - let data: [u8; 5] = [0, 1, 2, 3, 4]; - - assert_eq!(take_bytes(3)(&data).unwrap(), (&data[3..], &data[..3])); - assert_eq!(take_bytes(1)(&data).unwrap().0.len(), data.len() - 1); - assert_eq!(take_bytes(1)(&data).unwrap().0[0], 1); - assert_eq!(take_bytes(1)(&[0, 1]).unwrap().0.len(), 1); - assert_eq!(take_bytes(1)(&[1]).unwrap().0.len(), 0); - assert!(take_bytes(1)(&[]).is_err()); - } -} diff --git a/src/protocol/mctypes.rs b/src/protocol/types.rs similarity index 84% rename from src/protocol/mctypes.rs rename to src/protocol/types.rs index a7d34c5..0f3d53c 100644 --- a/src/protocol/mctypes.rs +++ b/src/protocol/types.rs @@ -1,10 +1,10 @@ -use crate::protocol::parsing::parsable::Parsable; +use crate::protocol::parsing::{IResult, Parsable}; /// Alias for a u128. pub type Uuid = u128; pub use crate::protocol::parsing::VarInt; /// Alias for a `serde_json::Value`. -pub type Json = crate::protocol::parsing::serde_json::Value; +pub type Json = serde_json::Value; /// Alias for a `Json`. pub type Chat = Json; @@ -23,7 +23,7 @@ impl Position { } impl Parsable for Position { #[tracing::instrument] - fn parse(data: &[u8]) -> crate::protocol::parsing::ParseResult<'_, Self> { + fn parse(data: &[u8]) -> IResult<&[u8], Self> { let (data, i) = i64::parse(data)?; // x: i26, z: i26, y: i12 @@ -67,12 +67,8 @@ impl TryFrom for Difficulty { } impl Parsable for Difficulty { #[tracing::instrument] - fn parse(data: &[u8]) -> crate::protocol::parsing::ParseResult<'_, Self> { - let (data, difficulty) = u8::parse(data)?; - let difficulty: Difficulty = difficulty - .try_into() - .expect("TODO: handle invalid difficulty"); - Ok((data, difficulty)) + fn parse(data: &[u8]) -> IResult<&[u8], Self> { + nom::combinator::map_res(u8::parse, Difficulty::try_from)(data) } #[tracing::instrument] fn serialize(&self) -> Vec {