aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock59
-rw-r--r--Cargo.toml25
-rw-r--r--README.md7
-rw-r--r--src/chat.rs12
-rw-r--r--src/deserialize.rs3
-rw-r--r--src/lib.rs7
-rw-r--r--src/nbt.rs10
-rw-r--r--src/protocol.rs16
-rw-r--r--src/serialize.rs2
-rw-r--r--src/status.rs109
-rw-r--r--src/test_macros.rs10
-rw-r--r--src/types.rs46
-rw-r--r--src/utils.rs1
-rw-r--r--src/uuid.rs135
-rw-r--r--src/v1_15_2.rs134
15 files changed, 277 insertions, 299 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 3827740..0b731db 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -7,15 +7,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e"
[[package]]
-name = "aho-corasick"
-version = "0.7.14"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b476ce7103678b0c6d3d395dbbae31d48ff910bd28be979ba5d48c6351131d0d"
-dependencies = [
- "memchr",
-]
-
-[[package]]
name = "autocfg"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -72,12 +63,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6"
[[package]]
-name = "lazy_static"
-version = "1.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
-
-[[package]]
name = "libc"
version = "0.2.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -85,32 +70,17 @@ checksum = "2448f6066e80e3bfc792e9c98bf705b4b0fc6e8ef5b43e5889aff0eaa9c58743"
[[package]]
name = "mcproto-rs"
-version = "0.1.0"
+version = "0.2.0"
dependencies = [
"base64",
"flate2",
- "lazy_static",
- "md5",
"paste",
"rand",
- "regex",
"serde",
"serde_json",
]
[[package]]
-name = "md5"
-version = "0.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771"
-
-[[package]]
-name = "memchr"
-version = "2.3.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400"
-
-[[package]]
name = "miniz_oxide"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -192,24 +162,6 @@ dependencies = [
]
[[package]]
-name = "regex"
-version = "1.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8963b85b8ce3074fecffde43b4b0dded83ce2f367dc8d363afc56679f3ee820b"
-dependencies = [
- "aho-corasick",
- "memchr",
- "regex-syntax",
- "thread_local",
-]
-
-[[package]]
-name = "regex-syntax"
-version = "0.6.20"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8cab7a364d15cde1e505267766a2d3c4e22a843e1a601f0fa7564c0f82ced11c"
-
-[[package]]
name = "ryu"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -258,15 +210,6 @@ dependencies = [
]
[[package]]
-name = "thread_local"
-version = "1.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14"
-dependencies = [
- "lazy_static",
-]
-
-[[package]]
name = "unicode-xid"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
index 829b191..85dc86a 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,23 +1,26 @@
[package]
name = "mcproto-rs"
-version = "0.1.0"
+version = "0.2.0"
authors = ["Joey Sacchini <joey@sacchini.net>"]
edition = "2018"
license = "Apache-2.0"
keywords = ["minecraft", "games", "protocol", "serialziers", "deserializers", "packets", "mc"]
-# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
-
[dependencies]
-serde_json = "1.0"
-regex = "1"
-lazy_static = "1.4"
-rand = "0.7"
-flate2 = "1.0.17"
-base64 = "0.12.3"
+serde_json = { version = "1.0", default-features = false, features = ["alloc"] }
+base64 = { version = "0.12.3", default-features = false, features = ["alloc"] }
+rand = { version = "0.7", optional = true }
paste = "1.0.1"
-md5 = "0.7.0"
[dependencies.serde]
version = "1.0.116"
-features = [ "derive" ] \ No newline at end of file
+features = [ "derive", "alloc" ]
+default-features = false
+
+[dev-dependencies]
+flate2 = "1.0.17"
+
+[features]
+default = [ "std" ]
+
+std = [ "rand" ] \ No newline at end of file
diff --git a/README.md b/README.md
index 365fed9..448d35d 100644
--- a/README.md
+++ b/README.md
@@ -7,4 +7,9 @@ This crate can be used to implement any version of the minecraft protocol, and h
To implement your own protocol, consult this example, and use the macros to define a protocol to your heart's content!
-More documentation to come, just dumping the code since I finished it. \ No newline at end of file
+More documentation to come, just dumping the code since I finished it.
+
+## `#![no_std]`
+
+You can use this crate without the standard library (but requiring `alloc`) by setting `default-features = false` in
+your Cargo.toml. This will only disable the `UUID4::random()` function, which requires `OsRandom` to generate a random UUID. \ No newline at end of file
diff --git a/src/chat.rs b/src/chat.rs
index 198e231..3913a6c 100644
--- a/src/chat.rs
+++ b/src/chat.rs
@@ -1,7 +1,6 @@
-use std::{fmt, str};
+use alloc::{vec::Vec, string::{String, ToString}, fmt, collections::{BTreeMap}, boxed::Box, borrow::ToOwned};
use serde::{Serialize, Deserialize, Deserializer, de, Serializer};
use serde::de::{Visitor, Error, IntoDeserializer, MapAccess};
-use std::collections::BTreeMap;
use serde::ser::SerializeMap;
use serde_json::Value;
use crate::{SerializeResult, DeserializeResult};
@@ -797,7 +796,8 @@ impl<'de> Deserialize<'de> for ColorCode {
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E> where
- E: Error, {
+ E: de::Error,
+ {
if let Some(code) = ColorCode::from_name(v) {
Ok(code)
} else {
@@ -1029,10 +1029,10 @@ impl super::Deserialize for Chat {
}
}
-#[cfg(test)]
+#[cfg(all(test, feature = "std"))]
use super::protocol::TestRandom;
-#[cfg(test)]
+#[cfg(all(test, feature = "std"))]
impl TestRandom for Chat {
fn test_gen_random() -> Self {
let str = String::test_gen_random();
@@ -1040,7 +1040,7 @@ impl TestRandom for Chat {
}
}
-#[cfg(test)]
+#[cfg(all(test, feature = "std"))]
pub mod tests {
use super::*;
diff --git a/src/deserialize.rs b/src/deserialize.rs
index 044560d..0fd32a6 100644
--- a/src/deserialize.rs
+++ b/src/deserialize.rs
@@ -1,6 +1,5 @@
use crate::types::VarInt;
-use std::fmt;
-use std::string::FromUtf8Error;
+use alloc::{vec::Vec, string::{FromUtf8Error, String}, fmt};
pub enum DeserializeErr {
Eof,
diff --git a/src/lib.rs b/src/lib.rs
index bea81eb..3082bdf 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,7 +1,10 @@
#![feature(const_fn)]
#![feature(test)]
+#![cfg_attr(not(test), no_std)]
-#[cfg(test)]
+extern crate alloc;
+
+#[cfg(all(test, feature = "std"))]
extern crate test;
mod deserialize;
@@ -17,6 +20,6 @@ pub mod v1_15_2;
pub use deserialize::*;
pub use serialize::*;
-#[cfg(test)]
+#[cfg(all(test, feature = "std"))]
mod test_macros;
mod chat;
diff --git a/src/nbt.rs b/src/nbt.rs
index ad5de3c..3424b9a 100644
--- a/src/nbt.rs
+++ b/src/nbt.rs
@@ -2,9 +2,9 @@ use crate::utils::{
read_int, read_long, read_one_byte, read_short, take, write_int, write_long, write_short,
};
use crate::{DeserializeErr, DeserializeResult, Deserialized};
-use std::fmt;
+use alloc::{string::{String, ToString}, borrow::ToOwned, fmt, vec::Vec};
-#[cfg(test)]
+#[cfg(all(test, feature = "std"))]
use crate::protocol::TestRandom;
#[derive(Clone, Debug, PartialEq)]
@@ -26,7 +26,7 @@ impl NamedTag {
}
}
-#[cfg(test)]
+#[cfg(all(test, feature = "std"))]
impl TestRandom for NamedTag {
fn test_gen_random() -> Self {
Self {
@@ -125,7 +125,7 @@ impl Tag {
}
}
-#[cfg(test)]
+#[cfg(all(test, feature = "std"))]
impl TestRandom for Tag {
fn test_gen_random() -> Self {
let random_idx = rand::random::<usize>() % 8;
@@ -518,7 +518,7 @@ impl Tag {
}
// test
-#[cfg(test)]
+#[cfg(all(test, feature = "std"))]
mod tests {
use super::*;
use flate2::read::GzDecoder;
diff --git a/src/protocol.rs b/src/protocol.rs
index 5f2ea67..9e7307e 100644
--- a/src/protocol.rs
+++ b/src/protocol.rs
@@ -1,5 +1,5 @@
use crate::{Deserialize, DeserializeErr, Serialize};
-use std::fmt;
+use alloc::{string::String, fmt, vec::Vec};
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
pub struct ProtocolSpec {
@@ -73,7 +73,7 @@ pub trait ProtocolType: Serialize + Deserialize {}
impl<T: Serialize + Deserialize> ProtocolType for T {}
-#[cfg(test)]
+#[cfg(all(test, feature = "std"))]
pub trait TestRandom {
fn test_gen_random() -> Self;
}
@@ -115,7 +115,7 @@ macro_rules! __protocol_body_def_helper {
}
}
- #[cfg(test)]
+ #[cfg(all(test, feature = "std"))]
impl TestRandom for $bodyt {
fn test_gen_random() -> Self {
Self::default()
@@ -147,7 +147,7 @@ macro_rules! __protocol_body_def_helper {
}
}
- #[cfg(test)]
+ #[cfg(all(test, feature = "std"))]
impl TestRandom for $bodyt {
fn test_gen_random() -> Self {
Self{ $($fname: <$ftyp>::test_gen_random()),+ }
@@ -433,7 +433,7 @@ macro_rules! proto_enum_with_type {
}
}
- #[cfg(test)]
+ #[cfg(all(test, feature = "std"))]
impl TestRandom for $typname {
fn test_gen_random() -> Self {
let mut idx: usize = (rand::random::<usize>() % (count_num!($($bval),+))) + 1;
@@ -537,7 +537,7 @@ macro_rules! proto_str_enum {
}
}
- #[cfg(test)]
+ #[cfg(all(test, feature = "std"))]
impl TestRandom for $typname {
fn test_gen_random() -> Self {
let mut idx: usize = (rand::random::<usize>() % (count_num!($($nam),+))) + 1;
@@ -601,7 +601,7 @@ macro_rules! proto_byte_flag {
}
}
- #[cfg(test)]
+ #[cfg(all(test, feature = "std"))]
impl TestRandom for $typname {
fn test_gen_random() -> Self {
let mut out = <$typname>::default();
@@ -722,7 +722,7 @@ macro_rules! counted_array_type {
}
}
- #[cfg(test)]
+ #[cfg(all(test, feature = "std"))]
impl<T> TestRandom for $name<T>
where
T: TestRandom + Debug + Clone + PartialEq,
diff --git a/src/serialize.rs b/src/serialize.rs
index 6425e98..3b96a3f 100644
--- a/src/serialize.rs
+++ b/src/serialize.rs
@@ -1,4 +1,4 @@
-use std::fmt;
+use alloc::{string::String, fmt};
pub enum SerializeErr {
FailedJsonEncode(String),
diff --git a/src/status.rs b/src/status.rs
index a0068ee..6944e89 100644
--- a/src/status.rs
+++ b/src/status.rs
@@ -5,9 +5,9 @@ use crate::{
SerializeErr, SerializeResult,
};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
-use std::fmt;
+use alloc::{string::String, fmt, vec::Vec};
-#[cfg(test)]
+#[cfg(all(test, feature = "std"))]
use crate::protocol::TestRandom;
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
@@ -42,7 +42,7 @@ impl McDeserialize for StatusSpec {
}
}
-#[cfg(test)]
+#[cfg(all(test, feature = "std"))]
impl TestRandom for StatusSpec {
fn test_gen_random() -> Self {
Self {
@@ -113,45 +113,78 @@ impl<'de> Deserialize<'de> for StatusFaviconSpec {
}
fn visit_str<E: serde::de::Error>(self, v: &str) -> Result<Self::Value, E> {
- use lazy_static::lazy_static;
- use regex::Regex;
- // regex to parse valid base64 content
- const PATTERN: &str = r"^data:([A-Za-z/]+);base64,([-A-Za-z0-9+/]*={0,3})$";
- lazy_static! {
- static ref RE: Regex = Regex::new(PATTERN).expect("regex is valid");
- }
-
- // try to use regex on the input
- // RE.captures_iter(v).next() means "try to get the first capture iterator"
- // then we take that iterator, get(1), and if 1 exists, get(2), and if both exist,
- // then we try to parse the base64, and drop the error if one occurs. We then
- // wrap the content_type and parsed data in StatusFaviconSpec
- // then we convert the option to a result using map and unwrap_or_else
- let mut captures: regex::CaptureMatches<'_, '_> = RE.captures_iter(v);
- captures
- .next()
- .and_then(move |captures| {
- captures.get(1).and_then(move |content_type| {
- captures.get(2).and_then(move |raw_base64| {
- base64::decode(raw_base64.as_str().as_bytes())
- .map(move |data| StatusFaviconSpec {
- content_type: content_type.as_str().to_owned(),
- data,
- })
- .ok()
- })
+ // favicon syntax data:{content-type};base64,{}
+ let v = str_tag(v, "data:", &self)?;
+ let content_type = str_until_pat(v, ";", &self)?;
+ let rest = str_tag(v, "base64,", &self)?;
+ match base64::decode(rest) {
+ Ok(data) => {
+ Ok(StatusFaviconSpec{
+ data,
+ content_type: content_type.to_owned(),
})
- })
- .map(move |result| Ok(result))
- .unwrap_or_else(|| {
- Err(serde::de::Error::invalid_value(
- serde::de::Unexpected::Str(v),
- &self,
- ))
- })
+ },
+ Err(err) => {
+ Err(E::custom(format_args!("failed base64 decode {:?}", err)))
+ }
+ }
}
}
deserializer.deserialize_str(Visitor {})
}
}
+
+fn str_tag<'a, E, V>(
+ target: &'a str,
+ expected: &str,
+ v: &V,
+) -> Result<&'a str, E> where
+ E: serde::de::Error,
+ V: serde::de::Visitor<'a>
+{
+ let (front, back) = str_take(target, expected.len(), v)?;
+ if front != expected {
+ Err(E::invalid_value(serde::de::Unexpected::Str(target), v))
+ } else {
+ Ok(back)
+ }
+}
+
+fn str_until_pat<'a, E, V>(
+ target: &'a str,
+ pat: &str,
+ v: &V,
+) -> Result<&'a str, E> where
+ E: serde::de::Error,
+ V: serde::de::Visitor<'a>
+{
+ let n_pat = pat.len();
+ if target.len() < n_pat {
+ return Err(E::invalid_value(serde::de::Unexpected::Str(target), v));
+ }
+
+ for i in 0..=(target.len()-n_pat) {
+ let v = &target[i..i+n_pat];
+ if v == pat {
+ return Ok(&target[..i]);
+ }
+ }
+
+ Err(E::invalid_value(serde::de::Unexpected::Str(target), v))
+}
+
+fn str_take<'a, E, V>(
+ target: &'a str,
+ n: usize,
+ v: &V,
+) -> Result<(&'a str, &'a str), E> where
+ E: serde::de::Error,
+ V: serde::de::Visitor<'a>
+{
+ if target.len() < n {
+ Err(E::invalid_value(serde::de::Unexpected::Str(target), v))
+ } else {
+ Ok(target.split_at(n))
+ }
+} \ No newline at end of file
diff --git a/src/test_macros.rs b/src/test_macros.rs
index 254c3bb..ead3208 100644
--- a/src/test_macros.rs
+++ b/src/test_macros.rs
@@ -1,5 +1,7 @@
use crate::{SerializeResult, Serializer};
-#[cfg(test)]
+use alloc::vec::Vec;
+
+#[cfg(all(test, feature = "std"))]
#[macro_export]
macro_rules! packet_test_cases {
($pnam: ident, $varnam: ident, $bodnam: ident, $testnam: ident, $benchnams: ident, $benchnamd: ident) => {
@@ -70,13 +72,13 @@ macro_rules! packet_test_cases {
};
}
-#[cfg(test)]
+#[cfg(all(test, feature = "std"))]
#[derive(Clone, Debug, Default, PartialEq)]
pub struct BenchSerializer {
data: Vec<u8>,
}
-#[cfg(test)]
+#[cfg(all(test, feature = "std"))]
impl Serializer for BenchSerializer {
fn serialize_bytes(&mut self, data: &[u8]) -> SerializeResult {
self.data.extend_from_slice(data);
@@ -84,7 +86,7 @@ impl Serializer for BenchSerializer {
}
}
-#[cfg(test)]
+#[cfg(all(test, feature = "std"))]
impl BenchSerializer {
pub fn reset(&mut self) {
self.data.clear();
diff --git a/src/types.rs b/src/types.rs
index 734f40f..47df47b 100644
--- a/src/types.rs
+++ b/src/types.rs
@@ -1,12 +1,13 @@
// ... PRIMITIVE TYPES ...
+use alloc::{string::String, vec::Vec};
use crate::utils::*;
use crate::uuid::UUID4;
use crate::*;
pub use super::chat::*;
-#[cfg(test)]
+#[cfg(all(test, feature = "std"))]
use crate::protocol::TestRandom;
// bool
@@ -26,7 +27,7 @@ impl Deserialize for bool {
}
}
-#[cfg(test)]
+#[cfg(all(test, feature = "std"))]
impl TestRandom for bool {
fn test_gen_random() -> Self {
rand::random()
@@ -46,7 +47,7 @@ impl Deserialize for u8 {
}
}
-#[cfg(test)]
+#[cfg(all(test, feature = "std"))]
impl TestRandom for u8 {
fn test_gen_random() -> Self {
rand::random()
@@ -66,7 +67,7 @@ impl Deserialize for i8 {
}
}
-#[cfg(test)]
+#[cfg(all(test, feature = "std"))]
impl TestRandom for i8 {
fn test_gen_random() -> Self {
rand::random()
@@ -87,7 +88,7 @@ impl Deserialize for u16 {
}
}
-#[cfg(test)]
+#[cfg(all(test, feature = "std"))]
impl TestRandom for u16 {
fn test_gen_random() -> Self {
rand::random()
@@ -109,7 +110,7 @@ impl Deserialize for i16 {
}
}
-#[cfg(test)]
+#[cfg(all(test, feature = "std"))]
impl TestRandom for i16 {
fn test_gen_random() -> Self {
rand::random()
@@ -130,7 +131,7 @@ impl Deserialize for i32 {
}
}
-#[cfg(test)]
+#[cfg(all(test, feature = "std"))]
impl TestRandom for i32 {
fn test_gen_random() -> Self {
rand::random()
@@ -151,7 +152,7 @@ impl Deserialize for i64 {
}
}
-#[cfg(test)]
+#[cfg(all(test, feature = "std"))]
impl TestRandom for i64 {
fn test_gen_random() -> Self {
rand::random()
@@ -175,7 +176,7 @@ impl Deserialize for f32 {
}
}
-#[cfg(test)]
+#[cfg(all(test, feature = "std"))]
impl TestRandom for f32 {
fn test_gen_random() -> Self {
rand::random()
@@ -199,7 +200,7 @@ impl Deserialize for f64 {
}
}
-#[cfg(test)]
+#[cfg(all(test, feature = "std"))]
impl TestRandom for f64 {
fn test_gen_random() -> Self {
rand::random()
@@ -256,7 +257,7 @@ impl std::fmt::Display for VarInt {
}
}
-#[cfg(test)]
+#[cfg(all(test, feature = "std"))]
impl TestRandom for VarInt {
fn test_gen_random() -> Self {
let out: i32 = rand::random();
@@ -280,7 +281,7 @@ impl Deserialize for VarLong {
}
}
-#[cfg(test)]
+#[cfg(all(test, feature = "std"))]
impl TestRandom for VarLong {
fn test_gen_random() -> Self {
let out: i64 = rand::random();
@@ -358,7 +359,7 @@ impl Deserialize for String {
}
}
-#[cfg(test)]
+#[cfg(all(test, feature = "std"))]
impl TestRandom for String {
fn test_gen_random() -> Self {
let raw_len: u8 = rand::random();
@@ -445,7 +446,7 @@ impl Deserialize for IntPosition {
}
}
-#[cfg(test)]
+#[cfg(all(test, feature = "std"))]
impl TestRandom for IntPosition {
fn test_gen_random() -> Self {
let x: i32 = ((rand::random::<u32>() % (1 << 26)) as i32) - (1 << 25);
@@ -473,7 +474,7 @@ impl Deserialize for Angle {
}
}
-#[cfg(test)]
+#[cfg(all(test, feature = "std"))]
impl TestRandom for Angle {
fn test_gen_random() -> Self {
Self {
@@ -517,7 +518,7 @@ impl Deserialize for UUID4 {
}
}
-#[cfg(test)]
+#[cfg(all(test, feature = "std"))]
impl TestRandom for UUID4 {
fn test_gen_random() -> Self {
UUID4::random()
@@ -559,7 +560,7 @@ impl Into<nbt::NamedTag> for NamedNbtTag {
}
}
-#[cfg(test)]
+#[cfg(all(test, feature = "std"))]
impl TestRandom for NamedNbtTag {
fn test_gen_random() -> Self {
Self {
@@ -597,7 +598,7 @@ impl FixedInt {
}
}
-#[cfg(test)]
+#[cfg(all(test, feature = "std"))]
impl TestRandom for FixedInt {
fn test_gen_random() -> Self {
FixedInt::new(f64::test_gen_random(), 16)
@@ -658,7 +659,7 @@ where
}
}
-#[cfg(test)]
+#[cfg(all(test, feature = "std"))]
impl<T> TestRandom for Option<T>
where
T: TestRandom,
@@ -723,7 +724,7 @@ impl Deserialize for Slot {
}
}
-#[cfg(test)]
+#[cfg(all(test, feature = "std"))]
impl TestRandom for Slot {
fn test_gen_random() -> Self {
let item_id = VarInt::test_gen_random();
@@ -738,10 +739,11 @@ impl TestRandom for Slot {
}
}
-#[cfg(test)]
+#[cfg(all(test, feature = "std"))]
mod tests {
use super::*;
- use std::fmt::Debug;
+ use alloc::fmt::Debug;
+ use alloc::borrow::ToOwned;
#[test]
fn test_bool() {
diff --git a/src/utils.rs b/src/utils.rs
index 85642c9..bb8ea36 100644
--- a/src/utils.rs
+++ b/src/utils.rs
@@ -1,4 +1,5 @@
use crate::{DeserializeErr, DeserializeResult, Deserialized};
+use alloc::string::String;
#[inline]
pub fn read_one_byte(data: &[u8]) -> DeserializeResult<u8> {
diff --git a/src/uuid.rs b/src/uuid.rs
index 514fd61..0b9d8ba 100644
--- a/src/uuid.rs
+++ b/src/uuid.rs
@@ -1,8 +1,7 @@
use crate::utils::*;
-use lazy_static::lazy_static;
-use regex::Regex;
use serde::{Deserializer, Serializer};
-use std::fmt::{Debug, Display, Formatter};
+use alloc::{fmt, string::{ToString, String}};
+use fmt::{Display, Debug, Formatter};
#[derive(Copy, Clone, PartialEq, Hash, Eq)]
pub struct UUID4 {
@@ -10,13 +9,13 @@ pub struct UUID4 {
}
impl Display for UUID4 {
- fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+ fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.write_str(self.hex().as_str())
}
}
impl Debug for UUID4 {
- fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+ fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.write_str("UUID4{")?;
f.write_str(self.hex().as_str())?;
f.write_str("}")
@@ -72,6 +71,7 @@ impl UUID4 {
RawUUID::from_str(from).and_then(move |raw| raw.parse4())
}
+ #[cfg(feature = "std")]
pub fn random() -> Self {
UUID4 {
raw: rand::random(),
@@ -101,27 +101,26 @@ struct RawUUID<'a> {
impl<'a> RawUUID<'a> {
fn from_str(from: &'a str) -> Option<RawUUID<'a>> {
- const PATTERN: &str = r"^([A-Fa-f0-9]{8})-?([A-Fa-f0-9]{4})-?([A-Fa-f0-9]{4})-?([A-Fa-f0-9]{4})-?([A-Fa-f0-9]{12})$";
- // let re = Regex::new(PATTERN).expect("regex is valid");
- lazy_static! {
- static ref RE: Regex = Regex::new(PATTERN).expect("regex is valid");
- }
-
- RE.captures_iter(from)
- .filter_map(move |c| {
- c.get(1).map(move |g| g.as_str()).and_then(move |g0| {
- c.get(2).map(move |g| g.as_str()).and_then(move |g1| {
- c.get(3).map(move |g| g.as_str()).and_then(move |g2| {
- c.get(4).map(move |g| g.as_str()).and_then(move |g3| {
- c.get(5).map(move |g4| RawUUID {
- parts: [g0, g1, g2, g3, g4.as_str()],
- })
- })
- })
- })
- })
- })
- .nth(0)
+ // 8-4-4-4-12
+ let (s0, from) = str_split(from, 8)?;
+ str_check_hex(s0)?;
+ let from = str_tag(from, "-")?;
+ let (s1, from) = str_split(from, 4)?;
+ str_check_hex(s1)?;
+ let from = str_tag(from, "-")?;
+ let (s2, from) = str_split(from, 4)?;
+ str_check_hex(s2)?;
+ let from = str_tag(from, "-")?;
+ let (s3, from) = str_split(from, 4)?;
+ str_check_hex(s3)?;
+ let from = str_tag(from, "-")?;
+ let (s4, from) = str_split(from, 12)?;
+ str_check_hex(s4)?;
+ str_check_eof(from)?;
+
+ Some(Self{
+ parts: [s0, s1, s2, s3, s4],
+ })
}
fn parse4(self) -> Option<UUID4> {
@@ -141,30 +140,55 @@ impl<'a> RawUUID<'a> {
Some(UUID4 { raw })
}
- //
- // fn parse3(self) -> Option<UUID3> {
- // self.parse4().map(move |id| UUID3 { raw: id.raw })
- // }
}
-// #[derive(Clone, Copy, Debug, PartialEq, Hash, Eq)]
-// pub struct UUID3 {
-// raw: u128,
-// }
-//
-// impl UUID3 {
-// pub fn parse(from: &str) -> Option<UUID3> {
-// RawUUID::from_str(from).and_then(move |id| id.parse3())
-// }
-//
-// pub fn from(namespace: UUID4, data: &str) -> UUID3 {
-// namespace.raw
-// }
-// }
-
-#[cfg(test)]
+fn str_tag<'a>(source: &'a str, tag: &str) -> Option<&'a str> {
+ let (front, back) = str_split(source, tag.len())?;
+ if front != tag {
+ None
+ } else {
+ Some(back)
+ }
+}
+
+fn str_check_eof(source: &str) -> Option<()> {
+ if source.is_empty() {
+ Some(())
+ } else {
+ None
+ }
+}
+
+fn str_check_hex(mut source: &str) -> Option<()> {
+ if source.is_empty() {
+ return None
+ }
+
+ loop {
+ let (part, rest) = str_split(source, 2)?;
+ for c in part.chars() {
+ parse_hex_char(c as u8)?;
+ }
+
+ source = rest;
+ if source.is_empty() {
+ return Some(());
+ }
+ }
+}
+
+fn str_split(source: &str, n: usize) -> Option<(&str, &str)> {
+ if source.len() < n {
+ None
+ } else {
+ Some(source.split_at(n))
+ }
+}
+
+#[cfg(all(test, feature = "std"))]
mod tests {
use super::UUID4;
+ use alloc::string::ToString;
#[test]
fn test_random_uuid4() {
@@ -229,4 +253,23 @@ mod tests {
let deserialized: UUID4 = serde_json::from_str(json.as_str()).expect("should read fine");
assert_eq!(deserialized, id);
}
+
+ #[bench]
+ fn bench_parse_uuid4(b: &mut test::Bencher) {
+ let rand = UUID4::random();
+ let str = rand.to_string();
+ b.bytes = str.bytes().len() as u64;
+ b.iter(|| {
+ UUID4::parse(str.as_str()).expect("should parse fine")
+ })
+ }
+
+ #[bench]
+ fn bench_uuid4_to_str(b: &mut test::Bencher) {
+ let rand = UUID4::random();
+ b.bytes = 128;
+ b.iter(|| {
+ rand.to_string()
+ })
+ }
}
diff --git a/src/v1_15_2.rs b/src/v1_15_2.rs
index 602a7a3..77d01f9 100644
--- a/src/v1_15_2.rs
+++ b/src/v1_15_2.rs
@@ -1,8 +1,9 @@
use crate::{types::*, uuid::*, *};
-use std::fmt::Debug;
-use std::cell::Cell;
+use alloc::{string::{String, ToString}, vec::Vec, borrow::ToOwned, boxed::Box};
+use alloc::fmt;
+use fmt::Debug;
-#[cfg(test)]
+#[cfg(all(test, feature = "std"))]
use crate::protocol::TestRandom;
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
@@ -903,7 +904,7 @@ impl From<Vec<u8>> for RemainingBytes {
}
}
-#[cfg(test)]
+#[cfg(all(test, feature = "std"))]
impl TestRandom for RemainingBytes {
fn test_gen_random() -> Self {
let size: usize = rand::random::<usize>() % 256;
@@ -1060,7 +1061,7 @@ impl Deserialize for BlockChangeHorizontalPosition {
}
}
-#[cfg(test)]
+#[cfg(all(test, feature = "std"))]
impl TestRandom for BlockChangeHorizontalPosition {
fn test_gen_random() -> Self {
BlockChangeHorizontalPosition {
@@ -1219,7 +1220,7 @@ impl Deserialize for CommandNodeSpec {
}
}
-#[cfg(test)]
+#[cfg(all(test, feature = "std"))]
impl TestRandom for CommandNodeSpec {
fn test_gen_random() -> Self {
let children_indices = <VarIntCountedArray<VarInt>>::test_gen_random();
@@ -1278,7 +1279,7 @@ impl CommandArgumentNodeSpec {
}
}
-#[cfg(test)]
+#[cfg(all(test, feature = "std"))]
impl TestRandom for CommandArgumentNodeSpec {
fn test_gen_random() -> Self {
let name = String::test_gen_random();
@@ -1374,7 +1375,7 @@ impl<T> Clone for NumParserProps<T> where T: Clone {
}
impl<T> Debug for NumParserProps<T> where T: Debug {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "NumParserProps(min={:?}, max={:?})", self.min, self.max)
}
}
@@ -1434,7 +1435,7 @@ impl<T> Deserialize for NumParserProps<T> where T: Deserialize {
}
}
-#[cfg(test)]
+#[cfg(all(test, feature = "std"))]
impl<T> TestRandom for NumParserProps<T> where
T: TestRandom + std::cmp::PartialOrd,
rand::distributions::Standard: rand::distributions::Distribution<T>,
@@ -1525,7 +1526,7 @@ impl Deserialize for TeamMember {
}
}
-#[cfg(test)]
+#[cfg(all(test, feature = "std"))]
impl TestRandom for TeamMember {
fn test_gen_random() -> Self {
use TeamMember::*;
@@ -1618,7 +1619,7 @@ impl Deserialize for UpdateScoreSpec {
}
}
-#[cfg(test)]
+#[cfg(all(test, feature = "std"))]
impl TestRandom for UpdateScoreSpec {
fn test_gen_random() -> Self {
Self {
@@ -1715,7 +1716,7 @@ impl Deserialize for StopSoundSpec {
}
}
-#[cfg(test)]
+#[cfg(all(test, feature = "std"))]
impl TestRandom for StopSoundSpec {
fn test_gen_random() -> Self {
let source = if rand::random::<bool>() {
@@ -1850,7 +1851,7 @@ impl Deserialize for GameChangeReason {
}
}
-#[cfg(test)]
+#[cfg(all(test, feature = "std"))]
impl TestRandom for GameChangeReason {
fn test_gen_random() -> Self {
// todo
@@ -1950,7 +1951,7 @@ impl From<Option<MapColumnsSpec>> for MapColumns {
}
}
-#[cfg(test)]
+#[cfg(all(test, feature = "std"))]
impl TestRandom for MapColumns {
fn test_gen_random() -> Self {
<Option<MapColumnsSpec>>::test_gen_random().into()
@@ -2051,7 +2052,7 @@ impl<A> Deserialize for PlayerInfoAction<A>
}
}
-#[cfg(test)]
+#[cfg(all(test, feature = "std"))]
impl<A> TestRandom for PlayerInfoAction<A>
where
A: Clone + PartialEq + Debug + TestRandom
@@ -2281,7 +2282,7 @@ impl Deserialize for AdvancementDisplayFlags {
}
}
-#[cfg(test)]
+#[cfg(all(test, feature = "std"))]
impl TestRandom for AdvancementDisplayFlags {
fn test_gen_random() -> Self {
let background_texture = if rand::random::<bool>() {
@@ -2574,7 +2575,7 @@ impl Deserialize for RecipeSpec {
}
}
-#[cfg(test)]
+#[cfg(all(test, feature = "std"))]
impl TestRandom for RecipeSpec {
fn test_gen_random() -> Self {
RecipeSpec {
@@ -2645,7 +2646,7 @@ impl Deserialize for RecipeCraftingShapedSpec {
}
}
-#[cfg(test)]
+#[cfg(all(test, feature = "std"))]
impl TestRandom for RecipeCraftingShapedSpec {
fn test_gen_random() -> Self {
use rand::distributions::Distribution;
@@ -2768,7 +2769,7 @@ impl Deserialize for ChunkData {
}
}
-#[cfg(test)]
+#[cfg(all(test, feature = "std"))]
impl TestRandom for ChunkData {
fn test_gen_random() -> Self {
ChunkData {
@@ -2786,15 +2787,13 @@ impl TestRandom for ChunkData {
pub const LIGHT_DATA_LENGTH: usize = 2048;
pub const LIGHT_DATA_SECTIONS: usize = 18;
+#[derive(Clone, PartialEq)]
pub struct LightingData {
pub data: Box<[Option<[u8; LIGHT_DATA_LENGTH]>; LIGHT_DATA_SECTIONS]>,
-
- _update_mask: Cell<Option<VarInt>>,
- _reset_mask: Cell<Option<VarInt>>,
}
impl LightingData {
- fn deserialize(update_mask: VarInt, reset_mask: VarInt, mut data: &[u8]) -> DeserializeResult<Self> {
+ fn deserialize(update_mask: VarInt, mut data: &[u8]) -> DeserializeResult<Self> {
let mut out = Box::new([None; LIGHT_DATA_SECTIONS]);
for i in 0..LIGHT_DATA_SECTIONS {
// gotta read the var int
@@ -2819,39 +2818,16 @@ impl LightingData {
let result = Self {
data: out,
- _update_mask: Cell::new(Some(update_mask)),
- _reset_mask: Cell::new(Some(reset_mask)),
};
Deserialized::ok(result, data)
}
- fn update_mask(&self) -> &VarInt {
- Self::lazily_get(&self._update_mask, || self.compute_update_mask())
- }
-
- fn reset_mask(&self) -> &VarInt {
- Self::lazily_get(&self._reset_mask, || self.compute_reset_mask())
- }
-
- fn lazily_get<T, F>(option: &Cell<Option<T>>, provider: F) -> &T where F: FnOnce() -> T {
- unsafe {
- let ptr = option.as_ptr().as_mut().expect("non-null");
- match ptr {
- Some(data) => data,
- None => {
- ptr.replace(provider());
- ptr.as_ref().expect("it's there")
- }
- }
- }
- }
-
- fn compute_update_mask(&self) -> VarInt {
+ fn update_mask(&self) -> VarInt {
self.compute_has_mask(true)
}
- fn compute_reset_mask(&self) -> VarInt {
+ fn reset_mask(&self) -> VarInt {
self.compute_has_mask(false)
}
@@ -2878,8 +2854,8 @@ impl LightingData {
}
}
-impl std::fmt::Debug for LightingData {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+impl fmt::Debug for LightingData {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"LightingData(update={:018b}, reset={:018b}, size={}, bytes={})",
@@ -2893,33 +2869,13 @@ impl std::fmt::Debug for LightingData {
}
}
-impl std::fmt::Display for LightingData {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- <dyn std::fmt::Debug>::fmt(self, f)
+impl fmt::Display for LightingData {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ <dyn fmt::Debug>::fmt(self, f)
}
}
-impl Clone for LightingData {
- fn clone(&self) -> Self {
- Self {
- data: self.data.clone(),
- _update_mask: Cell::new(Some(self.update_mask().clone())),
- _reset_mask: Cell::new(Some(self.reset_mask().clone())),
- }
- }
-}
-
-impl PartialEq for LightingData {
- fn eq(&self, other: &Self) -> bool {
- self.data.eq(&other.data) &&
- self.update_mask().eq(other.update_mask()) &&
- self.reset_mask().eq(other.reset_mask())
- }
-}
-
-unsafe impl Sync for LightingData {}
-
-#[cfg(test)]
+#[cfg(all(test, feature = "std"))]
impl LightingData {
fn gen_random_mask() -> i32 {
let rand: u32 = rand::random();
@@ -2927,7 +2883,7 @@ impl LightingData {
}
}
-#[cfg(test)]
+#[cfg(all(test, feature = "std"))]
impl TestRandom for LightingData {
fn test_gen_random() -> Self {
let set_mask = Self::gen_random_mask();
@@ -2942,20 +2898,8 @@ impl TestRandom for LightingData {
}
}
- let cache_masks = rand::random::<bool>();
-
- if cache_masks {
- Self {
- data,
- _update_mask: Cell::new(Some(VarInt(set_mask))),
- _reset_mask: Cell::new(None),
- }
- } else {
- Self {
- data,
- _update_mask: Cell::new(None),
- _reset_mask: Cell::new(None),
- }
+ Self {
+ data,
}
}
}
@@ -2981,11 +2925,11 @@ impl Deserialize for LightingUpdateSpec {
fn mc_deserialize(data: &[u8]) -> DeserializeResult<'_, Self> {
let Deserialized { value: skylight_update_mask, data } = VarInt::mc_deserialize(data)?;
let Deserialized { value: blocklight_update_mask, data } = VarInt::mc_deserialize(data)?;
- let Deserialized { value: skylight_reset_mask, data } = VarInt::mc_deserialize(data)?;
- let Deserialized { value: blocklight_reset_mask, data } = VarInt::mc_deserialize(data)?;
+ let Deserialized { value: _, data } = VarInt::mc_deserialize(data)?;
+ let Deserialized { value: _, data } = VarInt::mc_deserialize(data)?;
- let Deserialized { value: skylight_data, data } = LightingData::deserialize(skylight_update_mask, skylight_reset_mask, data)?;
- let Deserialized { value: blocklight_data, data } = LightingData::deserialize(blocklight_update_mask, blocklight_reset_mask, data)?;
+ let Deserialized { value: skylight_data, data } = LightingData::deserialize(skylight_update_mask, data)?;
+ let Deserialized { value: blocklight_data, data } = LightingData::deserialize(blocklight_update_mask, data)?;
Deserialized::ok(Self {
skylight_data,
@@ -2994,7 +2938,7 @@ impl Deserialize for LightingUpdateSpec {
}
}
-#[cfg(test)]
+#[cfg(all(test, feature = "std"))]
impl TestRandom for LightingUpdateSpec {
fn test_gen_random() -> Self {
Self {
@@ -3004,7 +2948,7 @@ impl TestRandom for LightingUpdateSpec {
}
}
-#[cfg(test)]
+#[cfg(all(test, feature = "std"))]
pub mod tests {
use super::*;
use crate::packet_test_cases;