Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -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]
Expand All @@ -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 }

Expand Down
12 changes: 12 additions & 0 deletions haya_ident/Cargo.toml
Original file line number Diff line number Diff line change
@@ -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 }
163 changes: 163 additions & 0 deletions haya_ident/src/lib.rs
Original file line number Diff line number Diff line change
@@ -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, 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<Self, Error> {
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, 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, PartialEq, Eq)]
enum Inner {
Thin { path: HayaStr },
Heap { path: Box<str> },
Full { namespace: Box<str>, path: Box<str> },
}
2 changes: 1 addition & 1 deletion haya_nbt/src/byte_array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::<u8>(), x.len()) }
}

pub struct ByteArray(pub Vec<i8>);
pub(crate) struct ByteArray(pub Vec<i8>);

impl<'a> Read<'a> for ByteArray {
fn read(buf: &mut &'a [u8]) -> Result<Self, mser::Error> {
Expand Down
2 changes: 1 addition & 1 deletion haya_nbt/src/int_array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use alloc::vec::Vec;
use mser::{Error, Read};

#[derive(Clone)]
pub struct IntArray(pub Vec<i32>);
pub(crate) struct IntArray(pub Vec<i32>);

impl<'a> Read<'a> for IntArray {
fn read(buf: &mut &'a [u8]) -> Result<Self, mser::Error> {
Expand Down
6 changes: 3 additions & 3 deletions haya_nbt/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion haya_nbt/src/long_array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use alloc::vec::Vec;
use mser::{Error, Read};

#[derive(Clone)]
pub struct LongArray(pub Vec<i64>);
pub(crate) struct LongArray(pub Vec<i64>);

impl<'a> Read<'a> for LongArray {
fn read(buf: &mut &'a [u8]) -> Result<Self, mser::Error> {
Expand Down
52 changes: 23 additions & 29 deletions haya_nbt/src/stringify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;";
Expand Down Expand Up @@ -55,7 +55,8 @@ fn peek(n: &[u8]) -> Result<(u8, &[u8]), Error> {
}
}

fn dec_arr_peek(n: &mut &[u8]) -> Result<TagArray, Error> {
fn dec_arr_peek(n: &mut &[u8], tmp: &mut Vec<u8>) -> Result<TagArray, Error> {
tmp.clear();
match n {
[b'B', b';', rest @ ..] => {
*n = rest;
Expand All @@ -68,26 +69,14 @@ fn dec_arr_peek(n: &mut &[u8]) -> Result<TagArray, Error> {
}
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::<i8>(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) {
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,
Expand All @@ -108,10 +97,14 @@ fn dec_arr_peek(n: &mut &[u8]) -> Result<TagArray, Error> {
}
loop {
skip_ws(n);
let (x, l) = parse_int_s::<i32>(n);
*n = l;
let (value, rest) = find_next_value(n)?;
*n = rest;
let a = match dec_num(value, tmp) {
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,
Expand All @@ -132,10 +125,11 @@ fn dec_arr_peek(n: &mut &[u8]) -> Result<TagArray, Error> {
}
loop {
skip_ws(n);
let (a, b) = parse_int_s::<i64>(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) {
Ok(TagPrimitive::Long(l)) => l,
_ => return Err(Error),
};
skip_ws(n);
vec.push(a);
Expand Down Expand Up @@ -325,7 +319,7 @@ unsafe fn decode(n: &mut &[u8], max_depth: usize) -> Result<Compound, Error> {
}
(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),
Expand Down Expand Up @@ -375,7 +369,7 @@ unsafe fn decode(n: &mut &[u8], max_depth: usize) -> Result<Compound, Error> {
}
(b'[', rest) => {
*n = rest;
match dec_arr_peek(n) {
match dec_arr_peek(n, &mut tmp) {
Ok(arr) => {
match arr {
TagArray::Byte(b) => {
Expand Down
1 change: 1 addition & 0 deletions haya_protocol/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }

Expand Down
7 changes: 3 additions & 4 deletions haya_protocol/src/clientbound/common.rs
Original file line number Diff line number Diff line change
@@ -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)]
Expand Down
3 changes: 2 additions & 1 deletion haya_protocol/src/clientbound/configuration.rs
Original file line number Diff line number Diff line change
@@ -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)]
Expand Down
2 changes: 1 addition & 1 deletion haya_protocol/src/clientbound/cookie.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::Ident;
use haya_ident::Ident;

#[derive(Clone, Serialize, Deserialize)]
pub struct LoginCookieRequest<'a> {
Expand Down
Loading