diff --git a/Cargo.lock b/Cargo.lock index 215d56d..13db3dc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,6 +19,14 @@ dependencies = [ "wasi", ] +[[package]] +name = "haya_ident" +version = "0.1.0" +dependencies = [ + "haya_str", + "mser", +] + [[package]] name = "haya_nbt" version = "0.1.0" @@ -33,6 +41,7 @@ dependencies = [ name = "haya_protocol" version = "0.1.0-rc.0+1.21.11" dependencies = [ + "haya_ident", "haya_nbt", "minecraft_data", "mser", diff --git a/Cargo.toml b/Cargo.toml index 8ada286..f1a5b2b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = ["haya_data", "haya_nbt", "haya_protocol", "haya_ser", "haya_ser_macro", "haya_str"] +members = ["haya_data", "haya_ident", "haya_nbt", "haya_protocol", "haya_ser", "haya_ser_macro", "haya_str"] resolver = "2" [workspace.package] @@ -14,6 +14,8 @@ mser = { path = "haya_ser", version = "2.2", default-features = false } mser_macro = { path = "haya_ser_macro", version = "2.2", default-features = false } minecraft_data = { path = "haya_data", version = "2.2", default-features = false } haya_nbt = { path = "haya_nbt", version = "0.1" } +haya_str = { path = "haya_str", version = "0.1" } +haya_ident = { path = "haya_ident", version = "0.1" } uuid = { version = "1", default-features = false } diff --git a/haya_ident/Cargo.toml b/haya_ident/Cargo.toml new file mode 100644 index 0000000..6fad901 --- /dev/null +++ b/haya_ident/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "haya_ident" +version = "0.1.0" +authors.workspace = true +readme.workspace = true +license.workspace = true +repository.workspace = true +edition.workspace = true + +[dependencies] +mser = { workspace = true } +haya_str = { workspace = true } diff --git a/haya_ident/src/lib.rs b/haya_ident/src/lib.rs new file mode 100644 index 0000000..aded9f7 --- /dev/null +++ b/haya_ident/src/lib.rs @@ -0,0 +1,163 @@ +#![no_std] + +extern crate alloc; + +use alloc::borrow::ToOwned; +use alloc::boxed::Box; +use core::str::from_utf8_unchecked; +use haya_str::HayaStr; +use mser::{ByteArray, Error, Read, UnsafeWriter, V21, Write}; + +pub const MINECRAFT: &str = "minecraft"; + +const fn is_valid_path(c: u8) -> bool { + matches!(c, b'a'..=b'z' | b'0'..=b'9' | b'_' | b'-' | b'.' | b'/') +} + +const fn is_valid_namespace(c: u8) -> bool { + matches!(c, b'a'..=b'z' | b'0'..=b'9' | b'_' | b'-' | b'.') +} + +fn split_once(n: &[u8]) -> Option<(&[u8], &[u8])> { + let index = n.iter().position(|&x| x == b':')?; + Some((&n[..index], &n[index + 1..])) +} + +pub fn parse_ident(ident: &[u8]) -> Option<(Option<&str>, &str)> { + if !ident.is_ascii() { + return None; + } + parse_ident_ascii(ident) +} + +fn parse_ident_ascii(ident: &[u8]) -> Option<(Option<&str>, &str)> { + match ident.strip_prefix(b"minecraft:") { + Some(path) => unsafe { + if path.iter().copied().all(is_valid_path) { + Some((None, from_utf8_unchecked(path))) + } else { + None + } + }, + None => match split_once(ident) { + Some((ns, path)) => unsafe { + if ns.iter().copied().all(is_valid_namespace) + && path.iter().copied().all(is_valid_path) + { + Some(( + if !ns.is_empty() { + Some(from_utf8_unchecked(ns)) + } else { + None + }, + from_utf8_unchecked(path), + )) + } else { + None + } + }, + None => unsafe { + if ident.iter().copied().all(is_valid_path) { + Some((None, from_utf8_unchecked(ident))) + } else { + None + } + }, + }, + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Ident<'a> { + namespace: Option<&'a str>, + path: &'a str, +} + +impl<'a> Ident<'a> { + pub fn namespace(&self) -> Option<&str> { + self.namespace + } + + pub fn path(&self) -> &str { + self.path + } +} + +impl<'a> Read<'a> for Ident<'a> { + fn read(buf: &mut &'a [u8]) -> Result { + let identifier = ByteArray::<32767>::read(buf)?.0; + match parse_ident(identifier) { + Some((namespace, path)) => Ok(Self { namespace, path }), + None => Err(Error), + } + } +} + +impl Write for Ident<'_> { + unsafe fn write(&self, w: &mut UnsafeWriter) { + unsafe { + let namespace = match self.namespace { + Some(x) => x, + None => MINECRAFT, + }; + V21((namespace.len() + 1 + self.path.len()) as _).write(w); + w.write(namespace.as_bytes()); + w.write_byte(b':'); + w.write(self.path.as_bytes()); + } + } + + fn len_s(&self) -> usize { + let namespace = match self.namespace { + Some(x) => x, + None => MINECRAFT, + }; + let a = namespace.len() + 1 + self.path.len(); + V21(a as u32).len_s() + a + } +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Identifier(Inner); + +impl Identifier { + pub fn new(ident: Ident) -> Self { + let Ident { namespace, path } = ident; + match namespace { + Some(namespace) => { + let namespace = namespace.to_owned().into_boxed_str(); + let path = path.to_owned().into_boxed_str(); + Self(Inner::Full { namespace, path }) + } + None => match HayaStr::new(path) { + Ok(path) => Self(Inner::Thin { path }), + Err(_) => Self(Inner::Heap { + path: path.to_owned().into_boxed_str(), + }), + }, + } + } + + pub fn path(&self) -> &str { + match &self.0 { + Inner::Thin { path } => path, + Inner::Heap { path } => path, + Inner::Full { path, .. } => path, + } + } + + pub fn namespace(&self) -> Option<&str> { + match &self.0 { + Inner::Thin { .. } => None, + Inner::Heap { .. } => None, + Inner::Full { namespace, .. } => Some(namespace), + } + } +} + +#[derive(Clone, Debug, PartialEq, Eq)] +enum Inner { + Thin { path: HayaStr }, + Heap { path: Box }, + Full { namespace: Box, path: Box }, +} diff --git a/haya_nbt/src/byte_array.rs b/haya_nbt/src/byte_array.rs index 81f7105..40f86ce 100644 --- a/haya_nbt/src/byte_array.rs +++ b/haya_nbt/src/byte_array.rs @@ -9,7 +9,7 @@ pub(crate) const fn i8_to_u8_slice(x: &[i8]) -> &[u8] { unsafe { core::slice::from_raw_parts(x.as_ptr().cast::(), x.len()) } } -pub struct ByteArray(pub Vec); +pub(crate) struct ByteArray(pub Vec); impl<'a> Read<'a> for ByteArray { fn read(buf: &mut &'a [u8]) -> Result { diff --git a/haya_nbt/src/int_array.rs b/haya_nbt/src/int_array.rs index 5d345f5..2b80e1b 100644 --- a/haya_nbt/src/int_array.rs +++ b/haya_nbt/src/int_array.rs @@ -2,7 +2,7 @@ use alloc::vec::Vec; use mser::{Error, Read}; #[derive(Clone)] -pub struct IntArray(pub Vec); +pub(crate) struct IntArray(pub Vec); impl<'a> Read<'a> for IntArray { fn read(buf: &mut &'a [u8]) -> Result { diff --git a/haya_nbt/src/lib.rs b/haya_nbt/src/lib.rs index db42dac..9224c09 100644 --- a/haya_nbt/src/lib.rs +++ b/haya_nbt/src/lib.rs @@ -10,11 +10,11 @@ mod long_array; mod string; mod stringify; -pub use self::byte_array::ByteArray; +use self::byte_array::ByteArray; pub use self::compound::{Compound, CompoundNamed}; -pub use self::int_array::IntArray; +use self::int_array::IntArray; pub use self::list::{List, ListInfo}; -pub use self::long_array::LongArray; +use self::long_array::LongArray; pub use self::string::{RefStringTag, StringTag, StringTagRaw}; pub use self::stringify::StringifyCompound; use alloc::boxed::Box; diff --git a/haya_nbt/src/long_array.rs b/haya_nbt/src/long_array.rs index f693c14..8dc39f1 100644 --- a/haya_nbt/src/long_array.rs +++ b/haya_nbt/src/long_array.rs @@ -2,7 +2,7 @@ use alloc::vec::Vec; use mser::{Error, Read}; #[derive(Clone)] -pub struct LongArray(pub Vec); +pub(crate) struct LongArray(pub Vec); impl<'a> Read<'a> for LongArray { fn read(buf: &mut &'a [u8]) -> Result { diff --git a/haya_nbt/src/stringify.rs b/haya_nbt/src/stringify.rs index ec9969c..a66e83b 100644 --- a/haya_nbt/src/stringify.rs +++ b/haya_nbt/src/stringify.rs @@ -4,7 +4,7 @@ use alloc::boxed::Box; use alloc::vec; use alloc::vec::Vec; use core::str::from_utf8_unchecked; -use mser::{hex_to_u8, parse_int_s, u8_to_hex}; +use mser::{hex_to_u8, u8_to_hex}; const BYTE_ARRAY_PREFIX: &[u8; 3] = b"[B;"; const INT_ARRAY_PREFIX: &[u8; 3] = b"[I;"; @@ -55,7 +55,7 @@ fn peek(n: &[u8]) -> Result<(u8, &[u8]), Error> { } } -fn dec_arr_peek(n: &mut &[u8]) -> Result { +fn dec_arr_peek(n: &mut &[u8], tmp: &mut TBuf) -> Result { match n { [b'B', b';', rest @ ..] => { *n = rest; @@ -68,26 +68,14 @@ fn dec_arr_peek(n: &mut &[u8]) -> Result { } loop { skip_ws(n); - let x = match peek(n)? { - (b't' | b'T', rest) => { - *n = dec_true_peek(rest)?; - 1 - } - (b'f' | b'F', rest) => { - *n = dec_false_peek(rest)?; - 0 - } - _ => { - let (a, b) = parse_int_s::(n); - *n = match peek(b)? { - (b'B' | b'b', rest) => rest, - _ => b, - }; - a - } + let (value, rest) = find_next_value(n)?; + *n = rest; + let a = match dec_num(value, tmp.next()) { + Ok(TagPrimitive::Byte(l)) => l, + _ => return Err(Error), }; skip_ws(n); - vec.push(x); + vec.push(a); match u8::read(n)? { b']' => break, b',' => continue, @@ -108,10 +96,14 @@ fn dec_arr_peek(n: &mut &[u8]) -> Result { } loop { skip_ws(n); - let (x, l) = parse_int_s::(n); - *n = l; + let (value, rest) = find_next_value(n)?; + *n = rest; + let a = match dec_num(value, tmp.next()) { + Ok(TagPrimitive::Int(l)) => l, + _ => return Err(Error), + }; skip_ws(n); - vec.push(x); + vec.push(a); match u8::read(n)? { b']' => break, b',' => continue, @@ -132,10 +124,11 @@ fn dec_arr_peek(n: &mut &[u8]) -> Result { } loop { skip_ws(n); - let (a, b) = parse_int_s::(n); - *n = match peek(b)? { - (b'L' | b'l', rest) => rest, - _ => b, + let (value, rest) = find_next_value(n)?; + *n = rest; + let a = match dec_num(value, tmp.next()) { + Ok(TagPrimitive::Long(l)) => l, + _ => return Err(Error), }; skip_ws(n); vec.push(a); @@ -152,12 +145,21 @@ fn dec_arr_peek(n: &mut &[u8]) -> Result { } } +struct TBuf(Vec); +impl TBuf { + fn next(&mut self) -> &mut Vec { + self.0.clear(); + &mut self.0 + } +} + unsafe fn decode(n: &mut &[u8], max_depth: usize) -> Result { enum Bl { C(Compound), L(List), } - let mut tmp = Vec::::new(); + + let mut tmp = TBuf(Vec::new()); let mut names = Vec::::new(); let mut blocks = vec![Bl::C(Compound::new())]; let mut on_start = true; @@ -325,7 +327,7 @@ unsafe fn decode(n: &mut &[u8], max_depth: usize) -> Result { } (b'[', rest) => { *n = rest; - match dec_arr_peek(n) { + match dec_arr_peek(n, &mut tmp) { Ok(TagArray::Byte(x)) => Tag::ByteArray(x), Ok(TagArray::Int(x)) => Tag::IntArray(x), Ok(TagArray::Long(x)) => Tag::LongArray(x), @@ -340,20 +342,18 @@ unsafe fn decode(n: &mut &[u8], max_depth: usize) -> Result { } (b'"', rest) => unsafe { *n = rest; - tmp.clear(); - let s = dec_quoted_str(n, &mut tmp, b'"')?; + let s = dec_quoted_str(n, tmp.next(), b'"')?; Tag::String(Box::from(from_utf8_unchecked(s))) }, (b'\'', rest) => unsafe { *n = rest; - tmp.clear(); - let s = dec_quoted_str(n, &mut tmp, b'\'')?; + let s = dec_quoted_str(n, tmp.next(), b'\'')?; Tag::String(Box::from(from_utf8_unchecked(s))) }, _ => unsafe { let (value, rest) = find_next_value(n)?; *n = rest; - match dec_num(value, &mut tmp) { + match dec_num(value, tmp.next()) { Ok(x) => Tag::from(x), Err(_) => Tag::String(Box::from(from_utf8_unchecked(value))), } @@ -375,7 +375,7 @@ unsafe fn decode(n: &mut &[u8], max_depth: usize) -> Result { } (b'[', rest) => { *n = rest; - match dec_arr_peek(n) { + match dec_arr_peek(n, &mut tmp) { Ok(arr) => { match arr { TagArray::Byte(b) => { @@ -427,20 +427,18 @@ unsafe fn decode(n: &mut &[u8], max_depth: usize) -> Result { let tag = match first { (b'"', rest) => { *n = rest; - tmp.clear(); - let s = dec_quoted_str(n, &mut tmp, b'"')?; + let s = dec_quoted_str(n, tmp.next(), b'"')?; Err(Box::from(from_utf8_unchecked(s))) } (b'\'', rest) => { *n = rest; - tmp.clear(); - let s = dec_quoted_str(n, &mut tmp, b'\'')?; + let s = dec_quoted_str(n, tmp.next(), b'\'')?; Err(Box::from(from_utf8_unchecked(s))) } _ => { let (value, rest) = find_next_value(n)?; *n = rest; - match dec_num(value, &mut tmp) { + match dec_num(value, tmp.next()) { Ok(x) => Ok(x), Err(_) => Err(Box::from(from_utf8_unchecked(value))), } @@ -463,7 +461,7 @@ unsafe fn decode(n: &mut &[u8], max_depth: usize) -> Result { unsafe fn dec_list_string( n: &mut &[u8], - tmp: &mut Vec, + tmp: &mut TBuf, list: &mut Vec>, ) -> Result<(), Error> { loop { @@ -471,15 +469,15 @@ unsafe fn dec_list_string( match u8::read(n)? { b',' => { skip_ws(n); - tmp.clear(); + let buf = tmp.next(); let x = match peek(n)? { (b'\"', rest) => unsafe { *n = rest; - Box::from(from_utf8_unchecked(dec_quoted_str(n, tmp, b'\"')?)) + Box::from(from_utf8_unchecked(dec_quoted_str(n, buf, b'\"')?)) }, (b'\'', rest) => unsafe { *n = rest; - Box::from(from_utf8_unchecked(dec_quoted_str(n, tmp, b'\'')?)) + Box::from(from_utf8_unchecked(dec_quoted_str(n, buf, b'\'')?)) }, _ => unsafe { let (value, rest) = find_next_value(n)?; @@ -498,7 +496,7 @@ unsafe fn dec_list_string( unsafe fn dec_list_primitive( n: &mut &[u8], - tmp: &mut Vec, + tmp: &mut TBuf, tag: TagPrimitive, ) -> Result { let mut list = match tag { @@ -516,7 +514,7 @@ unsafe fn dec_list_primitive( skip_ws(n); let (value, rest) = find_next_value(n)?; *n = rest; - let num = match dec_num(value, tmp)? { + let num = match dec_num(value, tmp.next())? { TagPrimitive::Byte(x) => x as i64, TagPrimitive::Short(x) => x as i64, TagPrimitive::Int(x) => x as i64, @@ -782,7 +780,6 @@ fn dec_num(mut n: &[u8], tmp: &mut Vec) -> Result { let mut start = 0; let mut cur = 0; - tmp.clear(); while let Some(b'_') = n.get(cur) { tmp.extend(unsafe { n.get_unchecked(start..cur) }); cur += 1; diff --git a/haya_protocol/Cargo.toml b/haya_protocol/Cargo.toml index cc8ceca..ed0c746 100644 --- a/haya_protocol/Cargo.toml +++ b/haya_protocol/Cargo.toml @@ -15,6 +15,7 @@ minecraft_data = { workspace = true } mser = { workspace = true } mser_macro = { workspace = true } haya_nbt = { workspace = true } +haya_ident = { workspace = true } uuid = { workspace = true } diff --git a/haya_protocol/src/clientbound/common.rs b/haya_protocol/src/clientbound/common.rs index 1f072b0..87fd10c 100644 --- a/haya_protocol/src/clientbound/common.rs +++ b/haya_protocol/src/clientbound/common.rs @@ -1,8 +1,7 @@ -use crate::{ - ByteArray, Component, Ident, List, Rest, ServerLinkUntrustedEntry, TagNetworkEntry, Utf8, -}; +use crate::{Component, List, Rest, ServerLinkUntrustedEntry, TagNetworkEntry, Utf8}; +use haya_ident::Ident; use haya_nbt::Tag; -use mser::V32; +use mser::{ByteArray, V32}; use uuid::Uuid; #[derive(Clone, Serialize, Deserialize)] diff --git a/haya_protocol/src/clientbound/configuration.rs b/haya_protocol/src/clientbound/configuration.rs index b6ef04e..131ed3f 100644 --- a/haya_protocol/src/clientbound/configuration.rs +++ b/haya_protocol/src/clientbound/configuration.rs @@ -1,4 +1,5 @@ -use crate::{Ident, KnownPack, List, RegistryKey, Utf8}; +use crate::{KnownPack, List, RegistryKey, Utf8}; +use haya_ident::Ident; use haya_nbt::Tag; #[derive(Clone, Serialize, Deserialize)] diff --git a/haya_protocol/src/clientbound/cookie.rs b/haya_protocol/src/clientbound/cookie.rs index cf944e7..4a80c1e 100644 --- a/haya_protocol/src/clientbound/cookie.rs +++ b/haya_protocol/src/clientbound/cookie.rs @@ -1,4 +1,4 @@ -use crate::Ident; +use haya_ident::Ident; #[derive(Clone, Serialize, Deserialize)] pub struct LoginCookieRequest<'a> { diff --git a/haya_protocol/src/clientbound/login.rs b/haya_protocol/src/clientbound/login.rs index bead179..198b77e 100644 --- a/haya_protocol/src/clientbound/login.rs +++ b/haya_protocol/src/clientbound/login.rs @@ -1,6 +1,7 @@ use crate::profile::GameProfileRef; -use crate::{ByteArray, Ident, Rest, Utf8}; -use mser::V32; +use crate::{Rest, Utf8}; +use haya_ident::Ident; +use mser::{ByteArray, V32}; #[derive(Clone, Serialize, Deserialize)] pub struct LoginDisconnect<'a> { diff --git a/haya_protocol/src/lib.rs b/haya_protocol/src/lib.rs index 062794a..ae7a30b 100644 --- a/haya_protocol/src/lib.rs +++ b/haya_protocol/src/lib.rs @@ -1,8 +1,8 @@ #![no_std] -use crate::str::BoxStr; use alloc::boxed::Box; use alloc::vec::Vec; +use haya_ident::Ident; use haya_nbt::Tag; use mser::{Error, Read, UnsafeWriter, V21, V32, Write}; @@ -12,7 +12,6 @@ pub mod clientbound; pub mod item; pub mod profile; pub mod serverbound; -pub mod str; pub mod types; #[macro_use] @@ -94,38 +93,6 @@ impl<'a, const MAX: usize> Read<'a> for Utf8<'a, MAX> { } } -#[derive(Clone, Copy, Debug)] -pub struct ByteArray<'a, const MAX: usize = { usize::MAX }>(pub &'a [u8]); - -impl<'a, const MAX: usize> Write for ByteArray<'a, MAX> { - unsafe fn write(&self, w: &mut UnsafeWriter) { - unsafe { - V21(self.0.len() as u32).write(w); - w.write(self.0); - } - } - - fn len_s(&self) -> usize { - V21(self.0.len() as u32).len_s() + self.0.len() - } -} - -impl<'a, const MAX: usize> Read<'a> for ByteArray<'a, MAX> { - fn read(buf: &mut &'a [u8]) -> Result { - let len = V21::read(buf)?.0 as usize; - if len > MAX { - return Err(Error); - } - match buf.split_at_checked(len) { - Some((x, y)) => { - *buf = y; - Ok(Self(x)) - } - None => Err(Error), - } - } -} - #[derive(Clone, Debug)] pub enum List<'a, T: 'a, const MAX: usize = { usize::MAX }> { Borrowed(&'a [T]), @@ -202,143 +169,14 @@ impl<'a, const MAX: usize> Write for Rest<'a, MAX> { } } -#[derive(Clone, Copy, PartialEq, Eq)] -pub struct Ident<'a> { - pub namespace: &'a str, - pub path: &'a str, -} - -impl<'a> Ident<'a> { - pub const MINECRAFT: &'static str = "minecraft"; - - pub fn is_valid_path(c: char) -> bool { - matches!(c, 'a'..='z' | '0'..='9' | '_' | '-' | '.' | '/') - } - - pub fn is_valid_namespace(c: char) -> bool { - matches!(c, 'a'..='z' | '0'..='9' | '_' | '-' | '.') - } - - pub fn parse(identifier: &'a str) -> Option { - match identifier.strip_prefix("minecraft:") { - Some(path) => { - if path.chars().all(Self::is_valid_path) { - Some(Self { - namespace: Self::MINECRAFT, - path, - }) - } else { - None - } - } - None => match identifier.split_once(':') { - Some((namespace, path)) => { - if namespace.chars().all(Self::is_valid_namespace) - && path.chars().all(Self::is_valid_path) - { - Some(Self { - namespace: if !namespace.is_empty() { - namespace - } else { - Self::MINECRAFT - }, - path, - }) - } else { - None - } - } - None => { - if identifier.chars().all(Self::is_valid_path) { - Some(Self { - namespace: Self::MINECRAFT, - path: identifier, - }) - } else { - None - } - } - }, - } - } -} - -impl<'a> Read<'a> for Ident<'a> { - fn read(buf: &mut &'a [u8]) -> Result { - let identifier = Utf8::<32767>::read(buf)?.0; - match Self::parse(identifier) { - Some(x) => Ok(x), - None => Err(Error), - } - } -} - -impl Write for Ident<'_> { - unsafe fn write(&self, w: &mut UnsafeWriter) { - unsafe { - V21((self.namespace.len() + 1 + self.path.len()) as _).write(w); - w.write(self.namespace.as_bytes()); - w.write_byte(b':'); - w.write(self.path.as_bytes()); - } - } - - fn len_s(&self) -> usize { - let a = self.namespace.len() + 1 + self.path.len(); - V21(a as u32).len_s() + a - } -} - -#[derive(Clone)] -pub struct Identifier { - pub namespace: Option, - pub path: BoxStr, -} - -impl Identifier { - pub fn as_ident(&self) -> Ident<'_> { - Ident { - namespace: match self.namespace.as_deref() { - Some(x) => x, - None => Ident::MINECRAFT, - }, - path: &self.path, - } - } -} - #[derive(Clone, Serialize, Deserialize)] pub struct Component(pub Tag); -#[derive(Clone)] -pub struct ResourceKey { - pub registry_name: Identifier, - pub identifier: Identifier, -} - #[derive(Clone, Serialize, Deserialize)] pub struct RegistryKey<'a> { pub identifier: Ident<'a>, } -#[derive(Clone)] -pub struct TagKey { - pub registry: ResourceKey, - pub location: Identifier, -} - -#[derive(Clone)] -pub enum HolderSet { - Direct(Vec>), - Named(TagKey), -} - -#[derive(Clone)] -pub enum Holder { - Direct(T), - Reference(ResourceKey), -} - #[derive(Clone, Serialize, Deserialize)] pub struct TagNetworkEntry<'a> { pub registry: RegistryKey<'a>, diff --git a/haya_protocol/src/profile.rs b/haya_protocol/src/profile.rs index e9e9210..6a91e27 100644 --- a/haya_protocol/src/profile.rs +++ b/haya_protocol/src/profile.rs @@ -1,7 +1,7 @@ //mod nbt; -use crate::str::BoxStr; -use crate::{Identifier, List, Utf8}; +use crate::{List, Utf8}; +use alloc::boxed::Box; use alloc::vec::Vec; use uuid::Uuid; @@ -28,7 +28,7 @@ pub struct PropertyRef<'a> { #[derive(Clone)] pub struct ResolvableProfile { - pub name: Option, + pub name: Option>, pub id: Option, pub properties: PropertyMap, pub patch: PlayerSkin, @@ -36,7 +36,7 @@ pub struct ResolvableProfile { #[derive(Clone)] pub struct GameProfile { - pub name: BoxStr, + pub name: Box, pub id: Uuid, pub properties: PropertyMap, pub patch: PlayerSkin, @@ -47,16 +47,16 @@ pub struct PropertyMap(pub Vec); #[derive(Clone)] pub struct Property { - pub name: BoxStr, - pub value: BoxStr, - pub signature: Option, + pub name: Box, + pub value: Box, + pub signature: Option>, } #[derive(Clone)] pub struct PlayerSkin { - pub texture: Option, - pub cape: Option, - pub elytra: Option, + pub texture: Option>, + pub cape: Option>, + pub elytra: Option>, pub model: Option, } diff --git a/haya_protocol/src/serverbound/configuration.rs b/haya_protocol/src/serverbound/configuration.rs index e69de29..8b13789 100644 --- a/haya_protocol/src/serverbound/configuration.rs +++ b/haya_protocol/src/serverbound/configuration.rs @@ -0,0 +1 @@ + diff --git a/haya_protocol/src/serverbound/cookie.rs b/haya_protocol/src/serverbound/cookie.rs index 0306760..0b6fec7 100644 --- a/haya_protocol/src/serverbound/cookie.rs +++ b/haya_protocol/src/serverbound/cookie.rs @@ -1,4 +1,5 @@ -use crate::{ByteArray, Ident}; +use haya_ident::Ident; +use mser::ByteArray; #[derive(Clone, Serialize, Deserialize)] pub struct CookieResponse<'a> { diff --git a/haya_protocol/src/serverbound/login.rs b/haya_protocol/src/serverbound/login.rs index a1ede1a..3ea80be 100644 --- a/haya_protocol/src/serverbound/login.rs +++ b/haya_protocol/src/serverbound/login.rs @@ -1,5 +1,5 @@ -use crate::{ByteArray, Rest, Utf8}; -use mser::V32; +use crate::{Rest, Utf8}; +use mser::{ByteArray, V32}; use uuid::Uuid; #[derive(Clone, Serialize, Deserialize)] diff --git a/haya_protocol/src/str.rs b/haya_protocol/src/str.rs deleted file mode 100644 index e710989..0000000 --- a/haya_protocol/src/str.rs +++ /dev/null @@ -1,71 +0,0 @@ -use alloc::boxed::Box; -use alloc::vec::Vec; -use core::ops::{Deref, DerefMut}; - -#[repr(transparent)] -#[derive(Clone)] -pub struct BoxStr(Box<[u8]>); - -impl BoxStr { - pub fn new(bytes: Box<[u8]>) -> Result { - match core::str::from_utf8(&bytes) { - Ok(_) => Ok(Self(bytes)), - Err(e) => Err(e), - } - } - - /// # Safety - /// - /// `bytes` must be valid UTF-8. - pub unsafe fn new_unchecked(bytes: Box<[u8]>) -> Self { - Self(bytes) - } - - pub fn as_str(&self) -> &str { - unsafe { core::str::from_utf8_unchecked(&self.0) } - } - - pub fn as_str_mut(&mut self) -> &mut str { - unsafe { core::str::from_utf8_unchecked_mut(&mut self.0) } - } - - pub fn as_bytes_mut(&mut self) -> &mut [u8] { - &mut self.0 - } - - pub fn as_bytes(&self) -> &[u8] { - &self.0 - } -} - -impl BoxStr { - pub fn empty() -> Self { - unsafe { Self::new_unchecked(Vec::::new().into_boxed_slice()) } - } -} - -impl Deref for BoxStr { - type Target = str; - - fn deref(&self) -> &Self::Target { - unsafe { core::str::from_utf8_unchecked(&self.0) } - } -} - -impl DerefMut for BoxStr { - fn deref_mut(&mut self) -> &mut Self::Target { - unsafe { core::str::from_utf8_unchecked_mut(&mut self.0) } - } -} - -impl AsRef for BoxStr { - fn as_ref(&self) -> &str { - self.as_str() - } -} - -impl AsMut for BoxStr { - fn as_mut(&mut self) -> &mut str { - self.as_str_mut() - } -} diff --git a/haya_ser/src/hex.rs b/haya_ser/src/hex.rs index f7b7c65..bf237f8 100644 --- a/haya_ser/src/hex.rs +++ b/haya_ser/src/hex.rs @@ -1,5 +1,5 @@ macro_rules! parse_impl { - ($($t:ident => $to:ident),* $(,)?) => { + ($($t:ident),* $(,)?) => { $( impl Integer for $t { fn parse(buf: &[u8]) -> (Self, usize) { @@ -14,7 +14,7 @@ macro_rules! parse_impl { x = x.get_unchecked(1..); } } - let mut out: $to = 0; + let mut out: $t = 0; match x.split_first() { Some((&dig, y)) => { if let Some(dig) = hex_to_u8(dig) { @@ -34,7 +34,7 @@ macro_rules! parse_impl { break; } } - ($t::from_ne_bytes(out.to_ne_bytes()), buf.len() - x.len()) + (out, buf.len() - x.len()) } } )* @@ -50,16 +50,12 @@ pub fn parse_hex(n: &[u8]) -> (T, usize) { } parse_impl! { - u8 => u8, - u16 => u16, - u32 => u32, - u64 => u64, - i8 => u8, - i16 => u16, - i32 => u32, - f32 => u32, - f64 => u64, + u8, + u16, + u32, + u64, } + const HEX_DIG: &[u8; 16] = b"0123456789abcdef"; #[inline] diff --git a/haya_ser/src/integer.rs b/haya_ser/src/integer.rs deleted file mode 100644 index 1ada808..0000000 --- a/haya_ser/src/integer.rs +++ /dev/null @@ -1,102 +0,0 @@ -macro_rules! parse_signed { - ($t:ty) => { - impl Integer for $t { - fn parse(mut x: &[u8]) -> ($t, &[u8]) { - let is_neg; - let dig = match x[..] { - [b'+', dig @ b'0'..=b'9', ref rest @ ..] => { - x = rest; - is_neg = false; - dig - } - [b'-', dig @ b'0'..=b'9', ref rest @ ..] => { - x = rest; - is_neg = true; - dig - } - [dig @ b'0'..=b'9', ref rest @ ..] => { - x = rest; - is_neg = false; - dig - } - _ => return (0, x), - }; - let out = if !is_neg { - let mut out: $t = (dig - b'0') as $t; - while let [dig @ b'0'..=b'9', ref y @ ..] = x[..] { - x = y; - out = out.wrapping_mul(10).wrapping_add((dig - b'0') as $t); - } - out - } else { - let mut out: $t = 0; - out = out.wrapping_sub((dig - b'0') as $t); - while let [dig @ b'0'..=b'9', ref y @ ..] = x[..] { - x = y; - out = out.wrapping_mul(10).wrapping_sub((dig - b'0') as $t); - } - out - }; - (out, x) - } - } - }; -} - -macro_rules! parse_unsigned { - ($t:ty) => { - impl Integer for $t { - fn parse(mut x: &[u8]) -> ($t, &[u8]) { - let dig = match x[..] { - [b'+', dig @ b'0'..=b'9', ref rest @ ..] => { - x = rest; - dig - } - [dig @ b'0'..=b'9', ref rest @ ..] => { - x = rest; - dig - } - _ => return (0, x), - }; - let mut out: $t = (dig - b'0') as $t; - while let [dig @ b'0'..=b'9', ref y @ ..] = x[..] { - x = y; - out = out.wrapping_mul(10).wrapping_add((dig - b'0') as $t); - } - (out, x) - } - } - }; -} - -pub trait Integer: Copy { - fn parse(buf: &[u8]) -> (Self, &[u8]); -} - -pub fn parse_int(n: &[u8]) -> (T, usize) { - let len = n.len(); - let (out, x) = T::parse(n); - (out, len - x.len()) -} - -pub fn parse_int_s(n: &[u8]) -> (T, &[u8]) { - T::parse(n) -} - -parse_signed!(i8); -parse_signed!(i16); -parse_signed!(i32); -parse_signed!(i64); -parse_unsigned!(u8); -parse_unsigned!(u16); -parse_unsigned!(u32); -parse_unsigned!(u64); - -#[test] -fn test() { - assert_eq!(parse_int(b"1004"), (1004, 4)); - assert_eq!(parse_int(b"-44a"), (-44, 3)); - assert_eq!(parse_int(b"+142"), (142, 4)); - assert_eq!(parse_int(b"+4544["), (4544, 5)); - assert_eq!(parse_int(b"++4544["), (0, 0)); -} diff --git a/haya_ser/src/lib.rs b/haya_ser/src/lib.rs index 5e9b722..e59f5d8 100644 --- a/haya_ser/src/lib.rs +++ b/haya_ser/src/lib.rs @@ -1,8 +1,6 @@ #![no_std] -#![allow(internal_features)] mod hex; -mod integer; mod json; mod mutf8; mod read; @@ -11,7 +9,6 @@ mod write; mod writer; pub use self::hex::{hex_to_u8, parse_hex, u8_to_hex}; -pub use self::integer::{parse_int, parse_int_s}; pub use self::json::json_char_width_escaped; pub use self::mutf8::{ decode_mutf8, decode_mutf8_len, encode_mutf8, encode_mutf8_len, is_ascii_mutf8, is_mutf8, @@ -73,3 +70,35 @@ pub const fn hash128(n: &[u8], seed: u64) -> [u64; 2] { let h = h.wrapping_mul(N); [(h >> 64) as u64, h as u64] } + +#[derive(Clone, Copy, Debug)] +pub struct ByteArray<'a, const MAX: usize = { usize::MAX }>(pub &'a [u8]); + +impl<'a, const MAX: usize> Write for ByteArray<'a, MAX> { + unsafe fn write(&self, w: &mut UnsafeWriter) { + unsafe { + V21(self.0.len() as u32).write(w); + w.write(self.0); + } + } + + fn len_s(&self) -> usize { + V21(self.0.len() as u32).len_s() + self.0.len() + } +} + +impl<'a, const MAX: usize> Read<'a> for ByteArray<'a, MAX> { + fn read(buf: &mut &'a [u8]) -> Result { + let len = V21::read(buf)?.0 as usize; + if len > MAX { + return Err(Error); + } + match buf.split_at_checked(len) { + Some((x, y)) => { + *buf = y; + Ok(Self(x)) + } + None => Err(Error), + } + } +} diff --git a/haya_str/src/lib.rs b/haya_str/src/lib.rs index 9073e91..6c12916 100644 --- a/haya_str/src/lib.rs +++ b/haya_str/src/lib.rs @@ -64,6 +64,22 @@ impl AsMut for HayaStr { } } +impl core::ops::Deref for HayaStr { + type Target = str; + + #[inline] + fn deref(&self) -> &Self::Target { + self.as_ref() + } +} + +impl core::ops::DerefMut for HayaStr { + #[inline] + fn deref_mut(&mut self) -> &mut Self::Target { + self.as_mut() + } +} + impl core::fmt::Debug for HayaStr { #[inline] fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {