Use nom to parse

This commit is contained in:
Garen Tyler 2024-12-04 18:39:31 -07:00
parent 02fd42bb72
commit c85b9a4bc2
Signed by: garentyler
SSH Key Fingerprint: SHA256:G4ke7blZMdpWPbkescyZ7IQYE4JAtwpI85YoJdq+S7U
23 changed files with 204 additions and 544 deletions

297
Cargo.lock generated
View File

@ -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]]

View File

@ -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"

View File

@ -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<crate::protocol::mctypes::Chat>) {
pub async fn disconnect(&mut self, reason: Option<crate::protocol::types::Chat>) {
use crate::protocol::packets::clientbound::{CL00Disconnect, CP17Disconnect};
let reason = reason.unwrap_or(serde_json::json!({
"text": "You have been disconnected!"

View File

@ -1,4 +1,4 @@
use crate::protocol::mctypes::VarInt;
use crate::protocol::types::VarInt;
#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)]
pub struct Cat {

View File

@ -1,6 +1,6 @@
use crate::protocol::{
blocks::BlockFace,
mctypes::{Chat, Position, Uuid, VarInt},
types::{Chat, Position, Uuid, VarInt},
};
pub type EntityMetadata = Vec<EntityMetadataEntry>;

View File

@ -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)?;

View File

@ -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 {

View File

@ -1,4 +1,4 @@
use crate::protocol::mctypes::VarInt;
use crate::protocol::types::VarInt;
#[derive(Clone, Debug, PartialEq, Default)]
pub struct Player {

View File

@ -1,4 +1,4 @@
use crate::protocol::mctypes::VarInt;
use crate::protocol::types::VarInt;
#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)]
pub struct Villager {

View File

@ -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)]

View File

@ -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

View File

@ -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 {

View File

@ -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)?;

View File

@ -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 }))
},

View File

@ -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<u8>) {
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<u8> { 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]

View File

@ -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<u8> {

View File

@ -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 {

View File

@ -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 {

View File

@ -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<u8> { 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 }))
},

View File

@ -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<i32> for VarInt {
fn from(value: i32) -> Self {
VarInt(value)
}
}
impl From<VarInt> for i32 {
fn from(value: VarInt) -> Self {
*value
}
}
impl From<usize> 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<T>` is represented in the protocol as
/// a boolean optionally followed by `T` if the boolean was true.
fn parse_optional(data: &[u8]) -> ParseResult<'_, Option<Self>>
fn parse_optional(data: &[u8]) -> IResult<&[u8], Option<Self>>
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<Self>>
fn parse_repeated(num: usize, mut data: &[u8]) -> IResult<&[u8], Vec<Self>>
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<Self>>
fn parse_vec(data: &[u8]) -> IResult<&[u8], Vec<Self>>
where
Self: Sized,
{
@ -59,7 +97,7 @@ pub trait Parsable {
}
impl<T: Parsable + std::fmt::Debug> Parsable for Option<T> {
#[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<T: Parsable + std::fmt::Debug> Parsable for Option<T> {
}
impl<T: Parsable + std::fmt::Debug> Parsable for Vec<T> {
#[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<T: Parsable + std::fmt::Debug> Parsable for Vec<T> {
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<u8> {
@ -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<u8> {
@ -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<u8> {
@ -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<u8> {
@ -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::<BigEndian>().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<u8> {
@ -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::<BigEndian>().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<u8> {
@ -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::<BigEndian>().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<u8> {
@ -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::<BigEndian>().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<u8> {
@ -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::<BigEndian>().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<u8> {
@ -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::<BigEndian>().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<u8> {
@ -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::<BigEndian>().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<u8> {
@ -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::<BigEndian>().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<u8> {
@ -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::<BigEndian>().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<u8> {
@ -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::<BigEndian>().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<u8> {
@ -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<u8> {
@ -384,3 +380,4 @@ mod tests {
}
}
}

View File

@ -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<T> = std::result::Result<T, Error>;
/// 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)>;

View File

@ -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<i32> for VarInt {
fn from(value: i32) -> Self {
VarInt(value)
}
}
impl From<VarInt> for i32 {
fn from(value: VarInt) -> Self {
*value
}
}
impl From<usize> 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());
}
}

View File

@ -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<u8> 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<u8> {