1
0
Fork 0
mirror of https://github.com/azalea-rs/simdnbt.git synced 2025-08-02 23:44:40 +00:00

random polish

This commit is contained in:
mat 2023-09-21 22:51:39 -05:00
commit 1526a21276
7 changed files with 296 additions and 145 deletions

View file

@ -12,16 +12,20 @@ use crate::{
Error, Mutf8Str, Error, Mutf8Str,
}; };
use super::{list::ListTag, Tag}; use super::{list::ListTag, NbtTag};
/// A list of named tags. The order of the tags is preserved. /// A list of named tags. The order of the tags is preserved.
#[derive(Debug, Default, PartialEq)] #[derive(Debug, Default, PartialEq)]
pub struct CompoundTag<'a> { pub struct NbtCompound<'a> {
values: Vec<(&'a Mutf8Str, Tag<'a>)>, values: Vec<(&'a Mutf8Str, NbtTag<'a>)>,
} }
impl<'a> CompoundTag<'a> { impl<'a> NbtCompound<'a> {
pub fn new(data: &mut Cursor<&'a [u8]>, depth: usize) -> Result<Self, Error> { pub fn read(data: &mut Cursor<&'a [u8]>) -> Result<Self, Error> {
Self::read_with_depth(data, 0)
}
pub fn read_with_depth(data: &mut Cursor<&'a [u8]>, depth: usize) -> Result<Self, Error> {
if depth > MAX_DEPTH { if depth > MAX_DEPTH {
return Err(Error::MaxDepthExceeded); return Err(Error::MaxDepthExceeded);
} }
@ -36,38 +40,39 @@ impl<'a> CompoundTag<'a> {
match tag_type { match tag_type {
BYTE_ID => values.push(( BYTE_ID => values.push((
tag_name, tag_name,
Tag::Byte(data.read_i8().map_err(|_| Error::UnexpectedEof)?), NbtTag::Byte(data.read_i8().map_err(|_| Error::UnexpectedEof)?),
)), )),
SHORT_ID => values.push(( SHORT_ID => values.push((
tag_name, tag_name,
Tag::Short(data.read_i16::<BE>().map_err(|_| Error::UnexpectedEof)?), NbtTag::Short(data.read_i16::<BE>().map_err(|_| Error::UnexpectedEof)?),
)), )),
INT_ID => values.push(( INT_ID => values.push((
tag_name, tag_name,
Tag::Int(data.read_i32::<BE>().map_err(|_| Error::UnexpectedEof)?), NbtTag::Int(data.read_i32::<BE>().map_err(|_| Error::UnexpectedEof)?),
)), )),
LONG_ID => values.push(( LONG_ID => values.push((
tag_name, tag_name,
Tag::Long(data.read_i64::<BE>().map_err(|_| Error::UnexpectedEof)?), NbtTag::Long(data.read_i64::<BE>().map_err(|_| Error::UnexpectedEof)?),
)), )),
FLOAT_ID => values.push(( FLOAT_ID => values.push((
tag_name, tag_name,
Tag::Float(data.read_f32::<BE>().map_err(|_| Error::UnexpectedEof)?), NbtTag::Float(data.read_f32::<BE>().map_err(|_| Error::UnexpectedEof)?),
)), )),
DOUBLE_ID => values.push(( DOUBLE_ID => values.push((
tag_name, tag_name,
Tag::Double(data.read_f64::<BE>().map_err(|_| Error::UnexpectedEof)?), NbtTag::Double(data.read_f64::<BE>().map_err(|_| Error::UnexpectedEof)?),
)), )),
BYTE_ARRAY_ID => { BYTE_ARRAY_ID => {
values.push((tag_name, Tag::ByteArray(read_with_u32_length(data, 1)?))) values.push((tag_name, NbtTag::ByteArray(read_with_u32_length(data, 1)?)))
} }
STRING_ID => values.push((tag_name, Tag::String(read_string(data)?))), STRING_ID => values.push((tag_name, NbtTag::String(read_string(data)?))),
LIST_ID => values.push((tag_name, Tag::List(ListTag::new(data, depth + 1)?))), LIST_ID => values.push((tag_name, NbtTag::List(ListTag::read(data, depth + 1)?))),
COMPOUND_ID => { COMPOUND_ID => values.push((
values.push((tag_name, Tag::Compound(CompoundTag::new(data, depth + 1)?))) tag_name,
} NbtTag::Compound(NbtCompound::read_with_depth(data, depth + 1)?),
INT_ARRAY_ID => values.push((tag_name, Tag::IntArray(read_int_array(data)?))), )),
LONG_ARRAY_ID => values.push((tag_name, Tag::LongArray(read_long_array(data)?))), INT_ARRAY_ID => values.push((tag_name, NbtTag::IntArray(read_int_array(data)?))),
LONG_ARRAY_ID => values.push((tag_name, NbtTag::LongArray(read_long_array(data)?))),
_ => return Err(Error::UnknownTagId(tag_type)), _ => return Err(Error::UnknownTagId(tag_type)),
} }
} }
@ -85,46 +90,46 @@ impl<'a> CompoundTag<'a> {
unchecked_write_string(data, name); unchecked_write_string(data, name);
} }
match tag { match tag {
Tag::Byte(byte) => unsafe { NbtTag::Byte(byte) => unsafe {
unchecked_push(data, *byte as u8); unchecked_push(data, *byte as u8);
}, },
Tag::Short(short) => unsafe { NbtTag::Short(short) => unsafe {
unchecked_extend(data, &short.to_be_bytes()); unchecked_extend(data, &short.to_be_bytes());
}, },
Tag::Int(int) => unsafe { NbtTag::Int(int) => unsafe {
unchecked_extend(data, &int.to_be_bytes()); unchecked_extend(data, &int.to_be_bytes());
}, },
Tag::Long(long) => { NbtTag::Long(long) => {
data.extend_from_slice(&long.to_be_bytes()); data.extend_from_slice(&long.to_be_bytes());
} }
Tag::Float(float) => unsafe { NbtTag::Float(float) => unsafe {
unchecked_extend(data, &float.to_be_bytes()); unchecked_extend(data, &float.to_be_bytes());
}, },
Tag::Double(double) => { NbtTag::Double(double) => {
data.extend_from_slice(&double.to_be_bytes()); data.extend_from_slice(&double.to_be_bytes());
} }
Tag::ByteArray(byte_array) => { NbtTag::ByteArray(byte_array) => {
unsafe { unsafe {
unchecked_extend(data, &byte_array.len().to_be_bytes()); unchecked_extend(data, &byte_array.len().to_be_bytes());
} }
data.extend_from_slice(byte_array); data.extend_from_slice(byte_array);
} }
Tag::String(string) => { NbtTag::String(string) => {
write_string(data, string); write_string(data, string);
} }
Tag::List(list) => { NbtTag::List(list) => {
list.write(data); list.write(data);
} }
Tag::Compound(compound) => { NbtTag::Compound(compound) => {
compound.write(data); compound.write(data);
} }
Tag::IntArray(int_array) => { NbtTag::IntArray(int_array) => {
unsafe { unsafe {
unchecked_extend(data, &int_array.len().to_be_bytes()); unchecked_extend(data, &int_array.len().to_be_bytes());
} }
data.extend_from_slice(&int_array.as_big_endian()); data.extend_from_slice(&int_array.as_big_endian());
} }
Tag::LongArray(long_array) => { NbtTag::LongArray(long_array) => {
unsafe { unsafe {
unchecked_extend(data, &long_array.len().to_be_bytes()); unchecked_extend(data, &long_array.len().to_be_bytes());
} }
@ -136,7 +141,7 @@ impl<'a> CompoundTag<'a> {
} }
#[inline] #[inline]
pub fn get(&self, name: &str) -> Option<&Tag<'a>> { pub fn get(&self, name: &str) -> Option<&NbtTag<'a>> {
let name = Mutf8Str::from_str(name); let name = Mutf8Str::from_str(name);
let name = name.as_ref(); let name = name.as_ref();
for (key, value) in &self.values { for (key, value) in &self.values {
@ -186,7 +191,7 @@ impl<'a> CompoundTag<'a> {
pub fn list(&self, name: &str) -> Option<&ListTag<'a>> { pub fn list(&self, name: &str) -> Option<&ListTag<'a>> {
self.get(name).and_then(|tag| tag.list()) self.get(name).and_then(|tag| tag.list())
} }
pub fn compound(&self, name: &str) -> Option<&CompoundTag<'a>> { pub fn compound(&self, name: &str) -> Option<&NbtCompound<'a>> {
self.get(name).and_then(|tag| tag.compound()) self.get(name).and_then(|tag| tag.compound())
} }
pub fn int_array(&self, name: &str) -> Option<Vec<i32>> { pub fn int_array(&self, name: &str) -> Option<Vec<i32>> {
@ -196,7 +201,7 @@ impl<'a> CompoundTag<'a> {
self.get(name).and_then(|tag| tag.long_array()) self.get(name).and_then(|tag| tag.long_array())
} }
pub fn iter(&self) -> impl Iterator<Item = (&Mutf8Str, &Tag<'a>)> { pub fn iter(&self) -> impl Iterator<Item = (&Mutf8Str, &NbtTag<'a>)> {
self.values.iter().map(|(k, v)| (*k, v)) self.values.iter().map(|(k, v)| (*k, v))
} }
} }

View file

@ -13,7 +13,7 @@ use crate::{
Error, Mutf8Str, Error, Mutf8Str,
}; };
use super::{read_u32, CompoundTag, MAX_DEPTH}; use super::{read_u32, NbtCompound, MAX_DEPTH};
/// A list of NBT tags of a single type. /// A list of NBT tags of a single type.
#[repr(u8)] #[repr(u8)]
@ -30,12 +30,12 @@ pub enum ListTag<'a> {
ByteArray(Vec<&'a [u8]>) = BYTE_ARRAY_ID, ByteArray(Vec<&'a [u8]>) = BYTE_ARRAY_ID,
String(Vec<&'a Mutf8Str>) = STRING_ID, String(Vec<&'a Mutf8Str>) = STRING_ID,
List(Vec<ListTag<'a>>) = LIST_ID, List(Vec<ListTag<'a>>) = LIST_ID,
Compound(Vec<CompoundTag<'a>>) = COMPOUND_ID, Compound(Vec<NbtCompound<'a>>) = COMPOUND_ID,
IntArray(Vec<RawList<'a, i32>>) = INT_ARRAY_ID, IntArray(Vec<RawList<'a, i32>>) = INT_ARRAY_ID,
LongArray(Vec<RawList<'a, i64>>) = LONG_ARRAY_ID, LongArray(Vec<RawList<'a, i64>>) = LONG_ARRAY_ID,
} }
impl<'a> ListTag<'a> { impl<'a> ListTag<'a> {
pub fn new(data: &mut Cursor<&'a [u8]>, depth: usize) -> Result<Self, Error> { pub fn read(data: &mut Cursor<&'a [u8]>, depth: usize) -> Result<Self, Error> {
if depth > MAX_DEPTH { if depth > MAX_DEPTH {
return Err(Error::MaxDepthExceeded); return Err(Error::MaxDepthExceeded);
} }
@ -74,7 +74,7 @@ impl<'a> ListTag<'a> {
// arbitrary number to prevent big allocations // arbitrary number to prevent big allocations
let mut lists = Vec::with_capacity(length.min(128) as usize); let mut lists = Vec::with_capacity(length.min(128) as usize);
for _ in 0..length { for _ in 0..length {
lists.push(ListTag::new(data, depth + 1)?) lists.push(ListTag::read(data, depth + 1)?)
} }
lists lists
}), }),
@ -83,7 +83,7 @@ impl<'a> ListTag<'a> {
// arbitrary number to prevent big allocations // arbitrary number to prevent big allocations
let mut compounds = Vec::with_capacity(length.min(128) as usize); let mut compounds = Vec::with_capacity(length.min(128) as usize);
for _ in 0..length { for _ in 0..length {
compounds.push(CompoundTag::new(data, depth + 1)?) compounds.push(NbtCompound::read_with_depth(data, depth + 1)?)
} }
compounds compounds
}), }),
@ -247,7 +247,7 @@ impl<'a> ListTag<'a> {
_ => None, _ => None,
} }
} }
pub fn compounds(&self) -> Option<&[CompoundTag]> { pub fn compounds(&self) -> Option<&[NbtCompound]> {
match self { match self {
ListTag::Compound(compounds) => Some(compounds), ListTag::Compound(compounds) => Some(compounds),
_ => None, _ => None,

View file

@ -17,13 +17,13 @@ use crate::{
Error, Mutf8Str, Error, Mutf8Str,
}; };
pub use self::{compound::CompoundTag, list::ListTag}; pub use self::{compound::NbtCompound, list::ListTag};
/// A complete NBT container. This contains a name and a compound tag. /// A complete NBT container. This contains a name and a compound tag.
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub struct BaseNbt<'a> { pub struct BaseNbt<'a> {
name: &'a Mutf8Str, name: &'a Mutf8Str,
tag: CompoundTag<'a>, tag: NbtCompound<'a>,
} }
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
@ -43,7 +43,7 @@ impl<'a> Nbt<'a> {
return Err(Error::InvalidRootType(root_type)); return Err(Error::InvalidRootType(root_type));
} }
let name = read_string(data)?; let name = read_string(data)?;
let tag = CompoundTag::new(data, 0)?; let tag = NbtCompound::read_with_depth(data, 0)?;
Ok(Nbt::Some(BaseNbt { name, tag })) Ok(Nbt::Some(BaseNbt { name, tag }))
} }
@ -83,7 +83,7 @@ impl<'a> BaseNbt<'a> {
} }
} }
impl<'a> Deref for BaseNbt<'a> { impl<'a> Deref for BaseNbt<'a> {
type Target = CompoundTag<'a>; type Target = NbtCompound<'a>;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
&self.tag &self.tag
@ -102,7 +102,7 @@ impl<'a> BaseNbt<'a> {
/// A single NBT tag. /// A single NBT tag.
#[repr(u8)] #[repr(u8)]
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub enum Tag<'a> { pub enum NbtTag<'a> {
Byte(i8) = BYTE_ID, Byte(i8) = BYTE_ID,
Short(i16) = SHORT_ID, Short(i16) = SHORT_ID,
Int(i32) = INT_ID, Int(i32) = INT_ID,
@ -112,11 +112,11 @@ pub enum Tag<'a> {
ByteArray(&'a [u8]) = BYTE_ARRAY_ID, ByteArray(&'a [u8]) = BYTE_ARRAY_ID,
String(&'a Mutf8Str) = STRING_ID, String(&'a Mutf8Str) = STRING_ID,
List(ListTag<'a>) = LIST_ID, List(ListTag<'a>) = LIST_ID,
Compound(CompoundTag<'a>) = COMPOUND_ID, Compound(NbtCompound<'a>) = COMPOUND_ID,
IntArray(RawList<'a, i32>) = INT_ARRAY_ID, IntArray(RawList<'a, i32>) = INT_ARRAY_ID,
LongArray(RawList<'a, i64>) = LONG_ARRAY_ID, LongArray(RawList<'a, i64>) = LONG_ARRAY_ID,
} }
impl<'a> Tag<'a> { impl<'a> NbtTag<'a> {
/// Get the numerical ID of the tag type. /// Get the numerical ID of the tag type.
#[inline] #[inline]
pub fn id(&self) -> u8 { pub fn id(&self) -> u8 {
@ -129,73 +129,73 @@ impl<'a> Tag<'a> {
pub fn byte(&self) -> Option<i8> { pub fn byte(&self) -> Option<i8> {
match self { match self {
Tag::Byte(byte) => Some(*byte), NbtTag::Byte(byte) => Some(*byte),
_ => None, _ => None,
} }
} }
pub fn short(&self) -> Option<i16> { pub fn short(&self) -> Option<i16> {
match self { match self {
Tag::Short(short) => Some(*short), NbtTag::Short(short) => Some(*short),
_ => None, _ => None,
} }
} }
pub fn int(&self) -> Option<i32> { pub fn int(&self) -> Option<i32> {
match self { match self {
Tag::Int(int) => Some(*int), NbtTag::Int(int) => Some(*int),
_ => None, _ => None,
} }
} }
pub fn long(&self) -> Option<i64> { pub fn long(&self) -> Option<i64> {
match self { match self {
Tag::Long(long) => Some(*long), NbtTag::Long(long) => Some(*long),
_ => None, _ => None,
} }
} }
pub fn float(&self) -> Option<f32> { pub fn float(&self) -> Option<f32> {
match self { match self {
Tag::Float(float) => Some(*float), NbtTag::Float(float) => Some(*float),
_ => None, _ => None,
} }
} }
pub fn double(&self) -> Option<f64> { pub fn double(&self) -> Option<f64> {
match self { match self {
Tag::Double(double) => Some(*double), NbtTag::Double(double) => Some(*double),
_ => None, _ => None,
} }
} }
pub fn byte_array(&self) -> Option<&[u8]> { pub fn byte_array(&self) -> Option<&[u8]> {
match self { match self {
Tag::ByteArray(byte_array) => Some(byte_array), NbtTag::ByteArray(byte_array) => Some(byte_array),
_ => None, _ => None,
} }
} }
pub fn string(&self) -> Option<&Mutf8Str> { pub fn string(&self) -> Option<&Mutf8Str> {
match self { match self {
Tag::String(string) => Some(string), NbtTag::String(string) => Some(string),
_ => None, _ => None,
} }
} }
pub fn list(&self) -> Option<&ListTag<'a>> { pub fn list(&self) -> Option<&ListTag<'a>> {
match self { match self {
Tag::List(list) => Some(list), NbtTag::List(list) => Some(list),
_ => None, _ => None,
} }
} }
pub fn compound(&self) -> Option<&CompoundTag<'a>> { pub fn compound(&self) -> Option<&NbtCompound<'a>> {
match self { match self {
Tag::Compound(compound) => Some(compound), NbtTag::Compound(compound) => Some(compound),
_ => None, _ => None,
} }
} }
pub fn int_array(&self) -> Option<Vec<i32>> { pub fn int_array(&self) -> Option<Vec<i32>> {
match self { match self {
Tag::IntArray(int_array) => Some(int_array.to_vec()), NbtTag::IntArray(int_array) => Some(int_array.to_vec()),
_ => None, _ => None,
} }
} }
pub fn long_array(&self) -> Option<Vec<i64>> { pub fn long_array(&self) -> Option<Vec<i64>> {
match self { match self {
Tag::LongArray(long_array) => Some(long_array.to_vec()), NbtTag::LongArray(long_array) => Some(long_array.to_vec()),
_ => None, _ => None,
} }
} }

View file

@ -15,7 +15,7 @@ pub struct Mutf8Str {
/// An owned M-UTF8 string. /// An owned M-UTF8 string.
#[derive(Debug, Eq, PartialEq, Clone, Default)] #[derive(Debug, Eq, PartialEq, Clone, Default)]
pub struct Mutf8String { pub struct Mutf8String {
vec: Vec<u8>, pub(crate) vec: Vec<u8>,
} }
#[inline] #[inline]
@ -168,6 +168,16 @@ impl Mutf8String {
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
self.vec.len() self.vec.len()
} }
#[inline]
pub fn from_vec(vec: Vec<u8>) -> Mutf8String {
Self { vec }
}
#[inline]
pub fn from_string(s: String) -> Mutf8String {
Self::from_vec(mutf8::encode(&s).into_owned())
}
} }
impl Deref for Mutf8String { impl Deref for Mutf8String {
type Target = Mutf8Str; type Target = Mutf8Str;
@ -178,7 +188,12 @@ impl Deref for Mutf8String {
} }
} }
// TODO: make Mutf8 correct impl From<String> for Mutf8String {
#[inline]
fn from(s: String) -> Self {
Self::from_string(s)
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {

View file

@ -13,16 +13,24 @@ use crate::{
Error, Mutf8Str, Error, Mutf8Str,
}; };
use super::{list::ListTag, Tag}; use super::{list::ListTag, NbtTag};
/// A list of named tags. The order of the tags is preserved. /// A list of named tags. The order of the tags is preserved.
#[derive(Debug, Default, Clone, PartialEq)] #[derive(Debug, Default, Clone, PartialEq)]
pub struct CompoundTag { pub struct NbtCompound {
values: Vec<(Mutf8String, Tag)>, pub(crate) values: Vec<(Mutf8String, NbtTag)>,
} }
impl CompoundTag { impl NbtCompound {
pub fn new(data: &mut Cursor<&[u8]>, depth: usize) -> Result<Self, Error> { pub fn new() -> Self {
Self::default()
}
pub fn read(data: &mut Cursor<&[u8]>) -> Result<Self, Error> {
Self::read_with_depth(data, 0)
}
pub fn read_with_depth(data: &mut Cursor<&[u8]>, depth: usize) -> Result<Self, Error> {
if depth > MAX_DEPTH { if depth > MAX_DEPTH {
return Err(Error::MaxDepthExceeded); return Err(Error::MaxDepthExceeded);
} }
@ -37,42 +45,43 @@ impl CompoundTag {
match tag_type { match tag_type {
BYTE_ID => values.push(( BYTE_ID => values.push((
tag_name, tag_name,
Tag::Byte(data.read_i8().map_err(|_| Error::UnexpectedEof)?), NbtTag::Byte(data.read_i8().map_err(|_| Error::UnexpectedEof)?),
)), )),
SHORT_ID => values.push(( SHORT_ID => values.push((
tag_name, tag_name,
Tag::Short(data.read_i16::<BE>().map_err(|_| Error::UnexpectedEof)?), NbtTag::Short(data.read_i16::<BE>().map_err(|_| Error::UnexpectedEof)?),
)), )),
INT_ID => values.push(( INT_ID => values.push((
tag_name, tag_name,
Tag::Int(data.read_i32::<BE>().map_err(|_| Error::UnexpectedEof)?), NbtTag::Int(data.read_i32::<BE>().map_err(|_| Error::UnexpectedEof)?),
)), )),
LONG_ID => values.push(( LONG_ID => values.push((
tag_name, tag_name,
Tag::Long(data.read_i64::<BE>().map_err(|_| Error::UnexpectedEof)?), NbtTag::Long(data.read_i64::<BE>().map_err(|_| Error::UnexpectedEof)?),
)), )),
FLOAT_ID => values.push(( FLOAT_ID => values.push((
tag_name, tag_name,
Tag::Float(data.read_f32::<BE>().map_err(|_| Error::UnexpectedEof)?), NbtTag::Float(data.read_f32::<BE>().map_err(|_| Error::UnexpectedEof)?),
)), )),
DOUBLE_ID => values.push(( DOUBLE_ID => values.push((
tag_name, tag_name,
Tag::Double(data.read_f64::<BE>().map_err(|_| Error::UnexpectedEof)?), NbtTag::Double(data.read_f64::<BE>().map_err(|_| Error::UnexpectedEof)?),
)), )),
BYTE_ARRAY_ID => values.push(( BYTE_ARRAY_ID => values.push((
tag_name, tag_name,
Tag::ByteArray(read_with_u32_length(data, 1)?.to_owned()), NbtTag::ByteArray(read_with_u32_length(data, 1)?.to_owned()),
)),
STRING_ID => values.push((tag_name, NbtTag::String(read_string(data)?.to_owned()))),
LIST_ID => values.push((tag_name, NbtTag::List(ListTag::read(data, depth + 1)?))),
COMPOUND_ID => values.push((
tag_name,
NbtTag::Compound(NbtCompound::read_with_depth(data, depth + 1)?),
)), )),
STRING_ID => values.push((tag_name, Tag::String(read_string(data)?.to_owned()))),
LIST_ID => values.push((tag_name, Tag::List(ListTag::new(data, depth + 1)?))),
COMPOUND_ID => {
values.push((tag_name, Tag::Compound(CompoundTag::new(data, depth + 1)?)))
}
INT_ARRAY_ID => { INT_ARRAY_ID => {
values.push((tag_name, Tag::IntArray(read_int_array(data)?.to_vec()))) values.push((tag_name, NbtTag::IntArray(read_int_array(data)?.to_vec())))
} }
LONG_ARRAY_ID => { LONG_ARRAY_ID => {
values.push((tag_name, Tag::LongArray(read_long_array(data)?.to_vec()))) values.push((tag_name, NbtTag::LongArray(read_long_array(data)?.to_vec())))
} }
_ => return Err(Error::UnknownTagId(tag_type)), _ => return Err(Error::UnknownTagId(tag_type)),
} }
@ -91,46 +100,46 @@ impl CompoundTag {
unchecked_write_string(data, name); unchecked_write_string(data, name);
} }
match tag { match tag {
Tag::Byte(byte) => unsafe { NbtTag::Byte(byte) => unsafe {
unchecked_push(data, *byte as u8); unchecked_push(data, *byte as u8);
}, },
Tag::Short(short) => unsafe { NbtTag::Short(short) => unsafe {
unchecked_extend(data, &short.to_be_bytes()); unchecked_extend(data, &short.to_be_bytes());
}, },
Tag::Int(int) => unsafe { NbtTag::Int(int) => unsafe {
unchecked_extend(data, &int.to_be_bytes()); unchecked_extend(data, &int.to_be_bytes());
}, },
Tag::Long(long) => { NbtTag::Long(long) => {
data.extend_from_slice(&long.to_be_bytes()); data.extend_from_slice(&long.to_be_bytes());
} }
Tag::Float(float) => unsafe { NbtTag::Float(float) => unsafe {
unchecked_extend(data, &float.to_be_bytes()); unchecked_extend(data, &float.to_be_bytes());
}, },
Tag::Double(double) => { NbtTag::Double(double) => {
data.extend_from_slice(&double.to_be_bytes()); data.extend_from_slice(&double.to_be_bytes());
} }
Tag::ByteArray(byte_array) => { NbtTag::ByteArray(byte_array) => {
unsafe { unsafe {
unchecked_extend(data, &byte_array.len().to_be_bytes()); unchecked_extend(data, &byte_array.len().to_be_bytes());
} }
data.extend_from_slice(byte_array); data.extend_from_slice(byte_array);
} }
Tag::String(string) => { NbtTag::String(string) => {
write_string(data, string); write_string(data, string);
} }
Tag::List(list) => { NbtTag::List(list) => {
list.write(data); list.write(data);
} }
Tag::Compound(compound) => { NbtTag::Compound(compound) => {
compound.write(data); compound.write(data);
} }
Tag::IntArray(int_array) => { NbtTag::IntArray(int_array) => {
unsafe { unsafe {
unchecked_extend(data, &int_array.len().to_be_bytes()); unchecked_extend(data, &int_array.len().to_be_bytes());
} }
data.extend_from_slice(&slice_into_u8_big_endian(int_array)); data.extend_from_slice(&slice_into_u8_big_endian(int_array));
} }
Tag::LongArray(long_array) => { NbtTag::LongArray(long_array) => {
unsafe { unsafe {
unchecked_extend(data, &long_array.len().to_be_bytes()); unchecked_extend(data, &long_array.len().to_be_bytes());
} }
@ -142,7 +151,7 @@ impl CompoundTag {
} }
#[inline] #[inline]
pub fn get(&self, name: &str) -> Option<&Tag> { pub fn get(&self, name: &str) -> Option<&NbtTag> {
let name = Mutf8Str::from_str(name); let name = Mutf8Str::from_str(name);
let name = name.as_ref(); let name = name.as_ref();
for (key, value) in &self.values { for (key, value) in &self.values {
@ -154,7 +163,7 @@ impl CompoundTag {
} }
#[inline] #[inline]
pub fn get_mut(&mut self, name: &str) -> Option<&mut Tag> { pub fn get_mut(&mut self, name: &str) -> Option<&mut NbtTag> {
let name = Mutf8Str::from_str(name); let name = Mutf8Str::from_str(name);
let name = name.as_ref(); let name = name.as_ref();
for (key, value) in &mut self.values { for (key, value) in &mut self.values {
@ -231,10 +240,10 @@ impl CompoundTag {
pub fn list_mut(&mut self, name: &str) -> Option<&mut ListTag> { pub fn list_mut(&mut self, name: &str) -> Option<&mut ListTag> {
self.get_mut(name).and_then(|tag| tag.list_mut()) self.get_mut(name).and_then(|tag| tag.list_mut())
} }
pub fn compound(&self, name: &str) -> Option<&CompoundTag> { pub fn compound(&self, name: &str) -> Option<&NbtCompound> {
self.get(name).and_then(|tag| tag.compound()) self.get(name).and_then(|tag| tag.compound())
} }
pub fn compound_mut(&mut self, name: &str) -> Option<&mut CompoundTag> { pub fn compound_mut(&mut self, name: &str) -> Option<&mut NbtCompound> {
self.get_mut(name).and_then(|tag| tag.compound_mut()) self.get_mut(name).and_then(|tag| tag.compound_mut())
} }
pub fn int_array(&self, name: &str) -> Option<&[i32]> { pub fn int_array(&self, name: &str) -> Option<&[i32]> {
@ -250,10 +259,10 @@ impl CompoundTag {
self.get_mut(name).and_then(|tag| tag.long_array_mut()) self.get_mut(name).and_then(|tag| tag.long_array_mut())
} }
pub fn iter(&self) -> impl Iterator<Item = (&Mutf8Str, &Tag)> { pub fn iter(&self) -> impl Iterator<Item = (&Mutf8Str, &NbtTag)> {
self.values.iter().map(|(k, v)| (k.as_str(), v)) self.values.iter().map(|(k, v)| (k.as_str(), v))
} }
pub fn iter_mut(&mut self) -> impl Iterator<Item = (&Mutf8Str, &mut Tag)> { pub fn iter_mut(&mut self) -> impl Iterator<Item = (&Mutf8Str, &mut NbtTag)> {
self.values.iter_mut().map(|(k, v)| (k.as_str(), v)) self.values.iter_mut().map(|(k, v)| (k.as_str(), v))
} }
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
@ -268,22 +277,23 @@ impl CompoundTag {
pub fn keys_mut(&mut self) -> impl Iterator<Item = &mut Mutf8String> { pub fn keys_mut(&mut self) -> impl Iterator<Item = &mut Mutf8String> {
self.values.iter_mut().map(|(k, _)| k) self.values.iter_mut().map(|(k, _)| k)
} }
pub fn values(&self) -> impl Iterator<Item = &Tag> { pub fn values(&self) -> impl Iterator<Item = &NbtTag> {
self.values.iter().map(|(_, v)| v) self.values.iter().map(|(_, v)| v)
} }
pub fn values_mut(&mut self) -> impl Iterator<Item = &mut Tag> { pub fn values_mut(&mut self) -> impl Iterator<Item = &mut NbtTag> {
self.values.iter_mut().map(|(_, v)| v) self.values.iter_mut().map(|(_, v)| v)
} }
pub fn into_iter(self) -> impl Iterator<Item = (Mutf8String, Tag)> { pub fn into_iter(self) -> impl Iterator<Item = (Mutf8String, NbtTag)> {
self.values.into_iter() self.values.into_iter()
} }
pub fn clear(&mut self) { pub fn clear(&mut self) {
self.values.clear(); self.values.clear();
} }
pub fn insert(&mut self, name: Mutf8String, tag: Tag) { pub fn insert(&mut self, name: impl Into<Mutf8String>, tag: NbtTag) {
let name = name.into();
self.values.push((name, tag)); self.values.push((name, tag));
} }
pub fn remove(&mut self, name: &str) -> Option<Tag> { pub fn remove(&mut self, name: &str) -> Option<NbtTag> {
let name = Mutf8Str::from_str(name); let name = Mutf8Str::from_str(name);
let name = name.as_ref(); let name = name.as_ref();
for i in 0..self.values.len() { for i in 0..self.values.len() {

View file

@ -15,7 +15,7 @@ use crate::{
Error, Error,
}; };
use super::{compound::CompoundTag, read_u32, MAX_DEPTH}; use super::{compound::NbtCompound, read_u32, MAX_DEPTH};
/// A list of NBT tags of a single type. /// A list of NBT tags of a single type.
#[repr(u8)] #[repr(u8)]
@ -32,12 +32,12 @@ pub enum ListTag {
ByteArray(Vec<Vec<u8>>) = BYTE_ARRAY_ID, ByteArray(Vec<Vec<u8>>) = BYTE_ARRAY_ID,
String(Vec<Mutf8String>) = STRING_ID, String(Vec<Mutf8String>) = STRING_ID,
List(Vec<ListTag>) = LIST_ID, List(Vec<ListTag>) = LIST_ID,
Compound(Vec<CompoundTag>) = COMPOUND_ID, Compound(Vec<NbtCompound>) = COMPOUND_ID,
IntArray(Vec<Vec<i32>>) = INT_ARRAY_ID, IntArray(Vec<Vec<i32>>) = INT_ARRAY_ID,
LongArray(Vec<Vec<i64>>) = LONG_ARRAY_ID, LongArray(Vec<Vec<i64>>) = LONG_ARRAY_ID,
} }
impl ListTag { impl ListTag {
pub fn new(data: &mut Cursor<&[u8]>, depth: usize) -> Result<Self, Error> { pub fn read(data: &mut Cursor<&[u8]>, depth: usize) -> Result<Self, Error> {
if depth > MAX_DEPTH { if depth > MAX_DEPTH {
return Err(Error::MaxDepthExceeded); return Err(Error::MaxDepthExceeded);
} }
@ -76,7 +76,7 @@ impl ListTag {
// arbitrary number to prevent big allocations // arbitrary number to prevent big allocations
let mut lists = Vec::with_capacity(length.min(128) as usize); let mut lists = Vec::with_capacity(length.min(128) as usize);
for _ in 0..length { for _ in 0..length {
lists.push(ListTag::new(data, depth + 1)?) lists.push(ListTag::read(data, depth + 1)?)
} }
lists lists
}), }),
@ -85,7 +85,7 @@ impl ListTag {
// arbitrary number to prevent big allocations // arbitrary number to prevent big allocations
let mut compounds = Vec::with_capacity(length.min(128) as usize); let mut compounds = Vec::with_capacity(length.min(128) as usize);
for _ in 0..length { for _ in 0..length {
compounds.push(CompoundTag::new(data, depth + 1)?) compounds.push(NbtCompound::read_with_depth(data, depth + 1)?)
} }
compounds compounds
}), }),
@ -249,7 +249,7 @@ impl ListTag {
_ => None, _ => None,
} }
} }
pub fn compounds(&self) -> Option<&[CompoundTag]> { pub fn compounds(&self) -> Option<&[NbtCompound]> {
match self { match self {
ListTag::Compound(compounds) => Some(compounds), ListTag::Compound(compounds) => Some(compounds),
_ => None, _ => None,

View file

@ -17,13 +17,13 @@ use crate::{
Error, Mutf8Str, Error, Mutf8Str,
}; };
pub use self::{compound::CompoundTag, list::ListTag}; pub use self::{compound::NbtCompound, list::ListTag};
/// A complete NBT container. This contains a name and a compound tag. /// A complete NBT container. This contains a name and a compound tag.
#[derive(Debug, Clone, PartialEq, Default)] #[derive(Debug, Clone, PartialEq, Default)]
pub struct BaseNbt { pub struct BaseNbt {
name: Mutf8String, name: Mutf8String,
tag: CompoundTag, tag: NbtCompound,
} }
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
@ -33,7 +33,7 @@ pub enum Nbt {
} }
impl Nbt { impl Nbt {
pub fn new(name: Mutf8String, tag: CompoundTag) -> Self { pub fn new(name: Mutf8String, tag: NbtCompound) -> Self {
Self::Some(BaseNbt { name, tag }) Self::Some(BaseNbt { name, tag })
} }
@ -47,7 +47,7 @@ impl Nbt {
return Err(Error::InvalidRootType(root_type)); return Err(Error::InvalidRootType(root_type));
} }
let name = read_string(data)?.to_owned(); let name = read_string(data)?.to_owned();
let tag = CompoundTag::new(data, 0)?; let tag = NbtCompound::read_with_depth(data, 0)?;
Ok(Nbt::Some(BaseNbt { name, tag })) Ok(Nbt::Some(BaseNbt { name, tag }))
} }
@ -78,10 +78,44 @@ impl Nbt {
pub fn is_none(&self) -> bool { pub fn is_none(&self) -> bool {
!self.is_some() !self.is_some()
} }
pub fn iter(&self) -> impl Iterator<Item = (&Mutf8Str, &NbtTag)> {
const EMPTY: &'static NbtCompound = &NbtCompound { values: Vec::new() };
if let Nbt::Some(nbt) = self {
nbt.iter()
} else {
EMPTY.iter()
}
}
pub fn into_iter(self) -> impl Iterator<Item = (Mutf8String, NbtTag)> {
const EMPTY: NbtCompound = NbtCompound { values: Vec::new() };
match self {
Nbt::Some(nbt) => nbt.tag.into_iter(),
Nbt::None => EMPTY.into_iter(),
}
}
}
impl Deref for Nbt {
type Target = BaseNbt;
fn deref(&self) -> &Self::Target {
const EMPTY: &'static BaseNbt = &BaseNbt {
name: Mutf8String { vec: Vec::new() },
tag: NbtCompound { values: Vec::new() },
};
match self {
Nbt::Some(nbt) => nbt,
Nbt::None => EMPTY,
}
}
} }
impl BaseNbt { impl BaseNbt {
pub fn new(name: Mutf8String, tag: CompoundTag) -> Self { pub fn new(name: Mutf8String, tag: NbtCompound) -> Self {
Self { name, tag } Self { name, tag }
} }
@ -96,9 +130,13 @@ impl BaseNbt {
write_string(data, &self.name); write_string(data, &self.name);
self.tag.write(data); self.tag.write(data);
} }
pub fn into_iter(self) -> impl Iterator<Item = (Mutf8String, NbtTag)> {
self.tag.into_iter()
}
} }
impl Deref for BaseNbt { impl Deref for BaseNbt {
type Target = CompoundTag; type Target = NbtCompound;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
&self.tag &self.tag
@ -108,7 +146,7 @@ impl Deref for BaseNbt {
/// A single NBT tag. /// A single NBT tag.
#[repr(u8)] #[repr(u8)]
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub enum Tag { pub enum NbtTag {
Byte(i8) = BYTE_ID, Byte(i8) = BYTE_ID,
Short(i16) = SHORT_ID, Short(i16) = SHORT_ID,
Int(i32) = INT_ID, Int(i32) = INT_ID,
@ -118,11 +156,11 @@ pub enum Tag {
ByteArray(Vec<u8>) = BYTE_ARRAY_ID, ByteArray(Vec<u8>) = BYTE_ARRAY_ID,
String(Mutf8String) = STRING_ID, String(Mutf8String) = STRING_ID,
List(ListTag) = LIST_ID, List(ListTag) = LIST_ID,
Compound(CompoundTag) = COMPOUND_ID, Compound(NbtCompound) = COMPOUND_ID,
IntArray(Vec<i32>) = INT_ARRAY_ID, IntArray(Vec<i32>) = INT_ARRAY_ID,
LongArray(Vec<i64>) = LONG_ARRAY_ID, LongArray(Vec<i64>) = LONG_ARRAY_ID,
} }
impl Tag { impl NbtTag {
/// Get the numerical ID of the tag type. /// Get the numerical ID of the tag type.
#[inline] #[inline]
pub fn id(&self) -> u8 { pub fn id(&self) -> u8 {
@ -135,145 +173,228 @@ impl Tag {
pub fn byte(&self) -> Option<i8> { pub fn byte(&self) -> Option<i8> {
match self { match self {
Tag::Byte(byte) => Some(*byte), NbtTag::Byte(byte) => Some(*byte),
_ => None, _ => None,
} }
} }
pub fn byte_mut(&mut self) -> Option<&mut i8> { pub fn byte_mut(&mut self) -> Option<&mut i8> {
match self { match self {
Tag::Byte(byte) => Some(byte), NbtTag::Byte(byte) => Some(byte),
_ => None, _ => None,
} }
} }
pub fn into_byte(self) -> Option<i8> {
match self {
NbtTag::Byte(byte) => Some(byte),
_ => None,
}
}
pub fn short(&self) -> Option<i16> { pub fn short(&self) -> Option<i16> {
match self { match self {
Tag::Short(short) => Some(*short), NbtTag::Short(short) => Some(*short),
_ => None, _ => None,
} }
} }
pub fn short_mut(&mut self) -> Option<&mut i16> { pub fn short_mut(&mut self) -> Option<&mut i16> {
match self { match self {
Tag::Short(short) => Some(short), NbtTag::Short(short) => Some(short),
_ => None, _ => None,
} }
} }
pub fn into_short(self) -> Option<i16> {
match self {
NbtTag::Short(short) => Some(short),
_ => None,
}
}
pub fn int(&self) -> Option<i32> { pub fn int(&self) -> Option<i32> {
match self { match self {
Tag::Int(int) => Some(*int), NbtTag::Int(int) => Some(*int),
_ => None, _ => None,
} }
} }
pub fn int_mut(&mut self) -> Option<&mut i32> { pub fn int_mut(&mut self) -> Option<&mut i32> {
match self { match self {
Tag::Int(int) => Some(int), NbtTag::Int(int) => Some(int),
_ => None, _ => None,
} }
} }
pub fn into_int(self) -> Option<i32> {
match self {
NbtTag::Int(int) => Some(int),
_ => None,
}
}
pub fn long(&self) -> Option<i64> { pub fn long(&self) -> Option<i64> {
match self { match self {
Tag::Long(long) => Some(*long), NbtTag::Long(long) => Some(*long),
_ => None, _ => None,
} }
} }
pub fn long_mut(&mut self) -> Option<&mut i64> { pub fn long_mut(&mut self) -> Option<&mut i64> {
match self { match self {
Tag::Long(long) => Some(long), NbtTag::Long(long) => Some(long),
_ => None, _ => None,
} }
} }
pub fn into_long(self) -> Option<i64> {
match self {
NbtTag::Long(long) => Some(long),
_ => None,
}
}
pub fn float(&self) -> Option<f32> { pub fn float(&self) -> Option<f32> {
match self { match self {
Tag::Float(float) => Some(*float), NbtTag::Float(float) => Some(*float),
_ => None, _ => None,
} }
} }
pub fn float_mut(&mut self) -> Option<&mut f32> { pub fn float_mut(&mut self) -> Option<&mut f32> {
match self { match self {
Tag::Float(float) => Some(float), NbtTag::Float(float) => Some(float),
_ => None, _ => None,
} }
} }
pub fn into_float(self) -> Option<f32> {
match self {
NbtTag::Float(float) => Some(float),
_ => None,
}
}
pub fn double(&self) -> Option<f64> { pub fn double(&self) -> Option<f64> {
match self { match self {
Tag::Double(double) => Some(*double), NbtTag::Double(double) => Some(*double),
_ => None, _ => None,
} }
} }
pub fn double_mut(&mut self) -> Option<&mut f64> { pub fn double_mut(&mut self) -> Option<&mut f64> {
match self { match self {
Tag::Double(double) => Some(double), NbtTag::Double(double) => Some(double),
_ => None, _ => None,
} }
} }
pub fn into_double(self) -> Option<f64> {
match self {
NbtTag::Double(double) => Some(double),
_ => None,
}
}
pub fn byte_array(&self) -> Option<&[u8]> { pub fn byte_array(&self) -> Option<&[u8]> {
match self { match self {
Tag::ByteArray(byte_array) => Some(byte_array), NbtTag::ByteArray(byte_array) => Some(byte_array),
_ => None, _ => None,
} }
} }
pub fn byte_array_mut(&mut self) -> Option<&mut Vec<u8>> { pub fn byte_array_mut(&mut self) -> Option<&mut Vec<u8>> {
match self { match self {
Tag::ByteArray(byte_array) => Some(byte_array), NbtTag::ByteArray(byte_array) => Some(byte_array),
_ => None, _ => None,
} }
} }
pub fn into_byte_array(self) -> Option<Vec<u8>> {
match self {
NbtTag::ByteArray(byte_array) => Some(byte_array),
_ => None,
}
}
pub fn string(&self) -> Option<&Mutf8Str> { pub fn string(&self) -> Option<&Mutf8Str> {
match self { match self {
Tag::String(string) => Some(string), NbtTag::String(string) => Some(string),
_ => None, _ => None,
} }
} }
pub fn string_mut(&mut self) -> Option<&mut Mutf8String> { pub fn string_mut(&mut self) -> Option<&mut Mutf8String> {
match self { match self {
Tag::String(string) => Some(string), NbtTag::String(string) => Some(string),
_ => None, _ => None,
} }
} }
pub fn into_string(self) -> Option<Mutf8String> {
match self {
NbtTag::String(string) => Some(string),
_ => None,
}
}
pub fn list(&self) -> Option<&ListTag> { pub fn list(&self) -> Option<&ListTag> {
match self { match self {
Tag::List(list) => Some(list), NbtTag::List(list) => Some(list),
_ => None, _ => None,
} }
} }
pub fn list_mut(&mut self) -> Option<&mut ListTag> { pub fn list_mut(&mut self) -> Option<&mut ListTag> {
match self { match self {
Tag::List(list) => Some(list), NbtTag::List(list) => Some(list),
_ => None, _ => None,
} }
} }
pub fn compound(&self) -> Option<&CompoundTag> { pub fn into_list(self) -> Option<ListTag> {
match self { match self {
Tag::Compound(compound) => Some(compound), NbtTag::List(list) => Some(list),
_ => None, _ => None,
} }
} }
pub fn compound_mut(&mut self) -> Option<&mut CompoundTag> {
pub fn compound(&self) -> Option<&NbtCompound> {
match self { match self {
Tag::Compound(compound) => Some(compound), NbtTag::Compound(compound) => Some(compound),
_ => None, _ => None,
} }
} }
pub fn compound_mut(&mut self) -> Option<&mut NbtCompound> {
match self {
NbtTag::Compound(compound) => Some(compound),
_ => None,
}
}
pub fn into_compound(self) -> Option<NbtCompound> {
match self {
NbtTag::Compound(compound) => Some(compound),
_ => None,
}
}
pub fn int_array(&self) -> Option<&[i32]> { pub fn int_array(&self) -> Option<&[i32]> {
match self { match self {
Tag::IntArray(int_array) => Some(int_array), NbtTag::IntArray(int_array) => Some(int_array),
_ => None, _ => None,
} }
} }
pub fn int_array_mut(&mut self) -> Option<&mut Vec<i32>> { pub fn int_array_mut(&mut self) -> Option<&mut Vec<i32>> {
match self { match self {
Tag::IntArray(int_array) => Some(int_array), NbtTag::IntArray(int_array) => Some(int_array),
_ => None, _ => None,
} }
} }
pub fn into_int_array(self) -> Option<Vec<i32>> {
match self {
NbtTag::IntArray(int_array) => Some(int_array),
_ => None,
}
}
pub fn long_array(&self) -> Option<&[i64]> { pub fn long_array(&self) -> Option<&[i64]> {
match self { match self {
Tag::LongArray(long_array) => Some(long_array), NbtTag::LongArray(long_array) => Some(long_array),
_ => None, _ => None,
} }
} }
pub fn long_array_mut(&mut self) -> Option<&mut Vec<i64>> { pub fn long_array_mut(&mut self) -> Option<&mut Vec<i64>> {
match self { match self {
Tag::LongArray(long_array) => Some(long_array), NbtTag::LongArray(long_array) => Some(long_array),
_ => None,
}
}
pub fn into_long_array(self) -> Option<Vec<i64>> {
match self {
NbtTag::LongArray(long_array) => Some(long_array),
_ => None, _ => None,
} }
} }