From 1526a21276fdf02f25cac08e4f135416de05ba4f Mon Sep 17 00:00:00 2001 From: mat Date: Thu, 21 Sep 2023 22:51:39 -0500 Subject: [PATCH] random polish --- src/borrow/compound.rs | 73 ++++++++-------- src/borrow/list.rs | 12 +-- src/borrow/mod.rs | 40 ++++----- src/mutf8.rs | 19 +++- src/owned/compound.rs | 94 +++++++++++--------- src/owned/list.rs | 12 +-- src/owned/mod.rs | 191 +++++++++++++++++++++++++++++++++-------- 7 files changed, 296 insertions(+), 145 deletions(-) diff --git a/src/borrow/compound.rs b/src/borrow/compound.rs index a2a3b29..bc06fd9 100644 --- a/src/borrow/compound.rs +++ b/src/borrow/compound.rs @@ -12,16 +12,20 @@ use crate::{ Error, Mutf8Str, }; -use super::{list::ListTag, Tag}; +use super::{list::ListTag, NbtTag}; /// A list of named tags. The order of the tags is preserved. #[derive(Debug, Default, PartialEq)] -pub struct CompoundTag<'a> { - values: Vec<(&'a Mutf8Str, Tag<'a>)>, +pub struct NbtCompound<'a> { + values: Vec<(&'a Mutf8Str, NbtTag<'a>)>, } -impl<'a> CompoundTag<'a> { - pub fn new(data: &mut Cursor<&'a [u8]>, depth: usize) -> Result { +impl<'a> NbtCompound<'a> { + pub fn read(data: &mut Cursor<&'a [u8]>) -> Result { + Self::read_with_depth(data, 0) + } + + pub fn read_with_depth(data: &mut Cursor<&'a [u8]>, depth: usize) -> Result { if depth > MAX_DEPTH { return Err(Error::MaxDepthExceeded); } @@ -36,38 +40,39 @@ impl<'a> CompoundTag<'a> { match tag_type { BYTE_ID => values.push(( tag_name, - Tag::Byte(data.read_i8().map_err(|_| Error::UnexpectedEof)?), + NbtTag::Byte(data.read_i8().map_err(|_| Error::UnexpectedEof)?), )), SHORT_ID => values.push(( tag_name, - Tag::Short(data.read_i16::().map_err(|_| Error::UnexpectedEof)?), + NbtTag::Short(data.read_i16::().map_err(|_| Error::UnexpectedEof)?), )), INT_ID => values.push(( tag_name, - Tag::Int(data.read_i32::().map_err(|_| Error::UnexpectedEof)?), + NbtTag::Int(data.read_i32::().map_err(|_| Error::UnexpectedEof)?), )), LONG_ID => values.push(( tag_name, - Tag::Long(data.read_i64::().map_err(|_| Error::UnexpectedEof)?), + NbtTag::Long(data.read_i64::().map_err(|_| Error::UnexpectedEof)?), )), FLOAT_ID => values.push(( tag_name, - Tag::Float(data.read_f32::().map_err(|_| Error::UnexpectedEof)?), + NbtTag::Float(data.read_f32::().map_err(|_| Error::UnexpectedEof)?), )), DOUBLE_ID => values.push(( tag_name, - Tag::Double(data.read_f64::().map_err(|_| Error::UnexpectedEof)?), + NbtTag::Double(data.read_f64::().map_err(|_| Error::UnexpectedEof)?), )), 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)?))), - 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 => values.push((tag_name, Tag::IntArray(read_int_array(data)?))), - LONG_ARRAY_ID => values.push((tag_name, Tag::LongArray(read_long_array(data)?))), + STRING_ID => values.push((tag_name, NbtTag::String(read_string(data)?))), + 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)?), + )), + 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)), } } @@ -85,46 +90,46 @@ impl<'a> CompoundTag<'a> { unchecked_write_string(data, name); } match tag { - Tag::Byte(byte) => unsafe { + NbtTag::Byte(byte) => unsafe { unchecked_push(data, *byte as u8); }, - Tag::Short(short) => unsafe { + NbtTag::Short(short) => unsafe { unchecked_extend(data, &short.to_be_bytes()); }, - Tag::Int(int) => unsafe { + NbtTag::Int(int) => unsafe { unchecked_extend(data, &int.to_be_bytes()); }, - Tag::Long(long) => { + NbtTag::Long(long) => { data.extend_from_slice(&long.to_be_bytes()); } - Tag::Float(float) => unsafe { + NbtTag::Float(float) => unsafe { unchecked_extend(data, &float.to_be_bytes()); }, - Tag::Double(double) => { + NbtTag::Double(double) => { data.extend_from_slice(&double.to_be_bytes()); } - Tag::ByteArray(byte_array) => { + NbtTag::ByteArray(byte_array) => { unsafe { unchecked_extend(data, &byte_array.len().to_be_bytes()); } data.extend_from_slice(byte_array); } - Tag::String(string) => { + NbtTag::String(string) => { write_string(data, string); } - Tag::List(list) => { + NbtTag::List(list) => { list.write(data); } - Tag::Compound(compound) => { + NbtTag::Compound(compound) => { compound.write(data); } - Tag::IntArray(int_array) => { + NbtTag::IntArray(int_array) => { unsafe { unchecked_extend(data, &int_array.len().to_be_bytes()); } data.extend_from_slice(&int_array.as_big_endian()); } - Tag::LongArray(long_array) => { + NbtTag::LongArray(long_array) => { unsafe { unchecked_extend(data, &long_array.len().to_be_bytes()); } @@ -136,7 +141,7 @@ impl<'a> CompoundTag<'a> { } #[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 = name.as_ref(); for (key, value) in &self.values { @@ -186,7 +191,7 @@ impl<'a> CompoundTag<'a> { pub fn list(&self, name: &str) -> Option<&ListTag<'a>> { 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()) } pub fn int_array(&self, name: &str) -> Option> { @@ -196,7 +201,7 @@ impl<'a> CompoundTag<'a> { self.get(name).and_then(|tag| tag.long_array()) } - pub fn iter(&self) -> impl Iterator)> { + pub fn iter(&self) -> impl Iterator)> { self.values.iter().map(|(k, v)| (*k, v)) } } diff --git a/src/borrow/list.rs b/src/borrow/list.rs index 3e21e4a..d5a534d 100644 --- a/src/borrow/list.rs +++ b/src/borrow/list.rs @@ -13,7 +13,7 @@ use crate::{ 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. #[repr(u8)] @@ -30,12 +30,12 @@ pub enum ListTag<'a> { ByteArray(Vec<&'a [u8]>) = BYTE_ARRAY_ID, String(Vec<&'a Mutf8Str>) = STRING_ID, List(Vec>) = LIST_ID, - Compound(Vec>) = COMPOUND_ID, + Compound(Vec>) = COMPOUND_ID, IntArray(Vec>) = INT_ARRAY_ID, LongArray(Vec>) = LONG_ARRAY_ID, } impl<'a> ListTag<'a> { - pub fn new(data: &mut Cursor<&'a [u8]>, depth: usize) -> Result { + pub fn read(data: &mut Cursor<&'a [u8]>, depth: usize) -> Result { if depth > MAX_DEPTH { return Err(Error::MaxDepthExceeded); } @@ -74,7 +74,7 @@ impl<'a> ListTag<'a> { // arbitrary number to prevent big allocations let mut lists = Vec::with_capacity(length.min(128) as usize); for _ in 0..length { - lists.push(ListTag::new(data, depth + 1)?) + lists.push(ListTag::read(data, depth + 1)?) } lists }), @@ -83,7 +83,7 @@ impl<'a> ListTag<'a> { // arbitrary number to prevent big allocations let mut compounds = Vec::with_capacity(length.min(128) as usize); for _ in 0..length { - compounds.push(CompoundTag::new(data, depth + 1)?) + compounds.push(NbtCompound::read_with_depth(data, depth + 1)?) } compounds }), @@ -247,7 +247,7 @@ impl<'a> ListTag<'a> { _ => None, } } - pub fn compounds(&self) -> Option<&[CompoundTag]> { + pub fn compounds(&self) -> Option<&[NbtCompound]> { match self { ListTag::Compound(compounds) => Some(compounds), _ => None, diff --git a/src/borrow/mod.rs b/src/borrow/mod.rs index 8f27628..7ccf688 100644 --- a/src/borrow/mod.rs +++ b/src/borrow/mod.rs @@ -17,13 +17,13 @@ use crate::{ 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. #[derive(Debug, PartialEq)] pub struct BaseNbt<'a> { name: &'a Mutf8Str, - tag: CompoundTag<'a>, + tag: NbtCompound<'a>, } #[derive(Debug, PartialEq)] @@ -43,7 +43,7 @@ impl<'a> Nbt<'a> { return Err(Error::InvalidRootType(root_type)); } 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 })) } @@ -83,7 +83,7 @@ impl<'a> BaseNbt<'a> { } } impl<'a> Deref for BaseNbt<'a> { - type Target = CompoundTag<'a>; + type Target = NbtCompound<'a>; fn deref(&self) -> &Self::Target { &self.tag @@ -102,7 +102,7 @@ impl<'a> BaseNbt<'a> { /// A single NBT tag. #[repr(u8)] #[derive(Debug, PartialEq)] -pub enum Tag<'a> { +pub enum NbtTag<'a> { Byte(i8) = BYTE_ID, Short(i16) = SHORT_ID, Int(i32) = INT_ID, @@ -112,11 +112,11 @@ pub enum Tag<'a> { ByteArray(&'a [u8]) = BYTE_ARRAY_ID, String(&'a Mutf8Str) = STRING_ID, List(ListTag<'a>) = LIST_ID, - Compound(CompoundTag<'a>) = COMPOUND_ID, + Compound(NbtCompound<'a>) = COMPOUND_ID, IntArray(RawList<'a, i32>) = INT_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. #[inline] pub fn id(&self) -> u8 { @@ -129,73 +129,73 @@ impl<'a> Tag<'a> { pub fn byte(&self) -> Option { match self { - Tag::Byte(byte) => Some(*byte), + NbtTag::Byte(byte) => Some(*byte), _ => None, } } pub fn short(&self) -> Option { match self { - Tag::Short(short) => Some(*short), + NbtTag::Short(short) => Some(*short), _ => None, } } pub fn int(&self) -> Option { match self { - Tag::Int(int) => Some(*int), + NbtTag::Int(int) => Some(*int), _ => None, } } pub fn long(&self) -> Option { match self { - Tag::Long(long) => Some(*long), + NbtTag::Long(long) => Some(*long), _ => None, } } pub fn float(&self) -> Option { match self { - Tag::Float(float) => Some(*float), + NbtTag::Float(float) => Some(*float), _ => None, } } pub fn double(&self) -> Option { match self { - Tag::Double(double) => Some(*double), + NbtTag::Double(double) => Some(*double), _ => None, } } pub fn byte_array(&self) -> Option<&[u8]> { match self { - Tag::ByteArray(byte_array) => Some(byte_array), + NbtTag::ByteArray(byte_array) => Some(byte_array), _ => None, } } pub fn string(&self) -> Option<&Mutf8Str> { match self { - Tag::String(string) => Some(string), + NbtTag::String(string) => Some(string), _ => None, } } pub fn list(&self) -> Option<&ListTag<'a>> { match self { - Tag::List(list) => Some(list), + NbtTag::List(list) => Some(list), _ => None, } } - pub fn compound(&self) -> Option<&CompoundTag<'a>> { + pub fn compound(&self) -> Option<&NbtCompound<'a>> { match self { - Tag::Compound(compound) => Some(compound), + NbtTag::Compound(compound) => Some(compound), _ => None, } } pub fn int_array(&self) -> Option> { match self { - Tag::IntArray(int_array) => Some(int_array.to_vec()), + NbtTag::IntArray(int_array) => Some(int_array.to_vec()), _ => None, } } pub fn long_array(&self) -> Option> { match self { - Tag::LongArray(long_array) => Some(long_array.to_vec()), + NbtTag::LongArray(long_array) => Some(long_array.to_vec()), _ => None, } } diff --git a/src/mutf8.rs b/src/mutf8.rs index 6245333..d0c51ff 100644 --- a/src/mutf8.rs +++ b/src/mutf8.rs @@ -15,7 +15,7 @@ pub struct Mutf8Str { /// An owned M-UTF8 string. #[derive(Debug, Eq, PartialEq, Clone, Default)] pub struct Mutf8String { - vec: Vec, + pub(crate) vec: Vec, } #[inline] @@ -168,6 +168,16 @@ impl Mutf8String { pub fn len(&self) -> usize { self.vec.len() } + + #[inline] + pub fn from_vec(vec: Vec) -> Mutf8String { + Self { vec } + } + + #[inline] + pub fn from_string(s: String) -> Mutf8String { + Self::from_vec(mutf8::encode(&s).into_owned()) + } } impl Deref for Mutf8String { type Target = Mutf8Str; @@ -178,7 +188,12 @@ impl Deref for Mutf8String { } } -// TODO: make Mutf8 correct +impl From for Mutf8String { + #[inline] + fn from(s: String) -> Self { + Self::from_string(s) + } +} #[cfg(test)] mod tests { diff --git a/src/owned/compound.rs b/src/owned/compound.rs index 5164def..3eebf38 100644 --- a/src/owned/compound.rs +++ b/src/owned/compound.rs @@ -13,16 +13,24 @@ use crate::{ Error, Mutf8Str, }; -use super::{list::ListTag, Tag}; +use super::{list::ListTag, NbtTag}; /// A list of named tags. The order of the tags is preserved. #[derive(Debug, Default, Clone, PartialEq)] -pub struct CompoundTag { - values: Vec<(Mutf8String, Tag)>, +pub struct NbtCompound { + pub(crate) values: Vec<(Mutf8String, NbtTag)>, } -impl CompoundTag { - pub fn new(data: &mut Cursor<&[u8]>, depth: usize) -> Result { +impl NbtCompound { + pub fn new() -> Self { + Self::default() + } + + pub fn read(data: &mut Cursor<&[u8]>) -> Result { + Self::read_with_depth(data, 0) + } + + pub fn read_with_depth(data: &mut Cursor<&[u8]>, depth: usize) -> Result { if depth > MAX_DEPTH { return Err(Error::MaxDepthExceeded); } @@ -37,42 +45,43 @@ impl CompoundTag { match tag_type { BYTE_ID => values.push(( tag_name, - Tag::Byte(data.read_i8().map_err(|_| Error::UnexpectedEof)?), + NbtTag::Byte(data.read_i8().map_err(|_| Error::UnexpectedEof)?), )), SHORT_ID => values.push(( tag_name, - Tag::Short(data.read_i16::().map_err(|_| Error::UnexpectedEof)?), + NbtTag::Short(data.read_i16::().map_err(|_| Error::UnexpectedEof)?), )), INT_ID => values.push(( tag_name, - Tag::Int(data.read_i32::().map_err(|_| Error::UnexpectedEof)?), + NbtTag::Int(data.read_i32::().map_err(|_| Error::UnexpectedEof)?), )), LONG_ID => values.push(( tag_name, - Tag::Long(data.read_i64::().map_err(|_| Error::UnexpectedEof)?), + NbtTag::Long(data.read_i64::().map_err(|_| Error::UnexpectedEof)?), )), FLOAT_ID => values.push(( tag_name, - Tag::Float(data.read_f32::().map_err(|_| Error::UnexpectedEof)?), + NbtTag::Float(data.read_f32::().map_err(|_| Error::UnexpectedEof)?), )), DOUBLE_ID => values.push(( tag_name, - Tag::Double(data.read_f64::().map_err(|_| Error::UnexpectedEof)?), + NbtTag::Double(data.read_f64::().map_err(|_| Error::UnexpectedEof)?), )), BYTE_ARRAY_ID => values.push(( 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 => { - 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 => { - 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)), } @@ -91,46 +100,46 @@ impl CompoundTag { unchecked_write_string(data, name); } match tag { - Tag::Byte(byte) => unsafe { + NbtTag::Byte(byte) => unsafe { unchecked_push(data, *byte as u8); }, - Tag::Short(short) => unsafe { + NbtTag::Short(short) => unsafe { unchecked_extend(data, &short.to_be_bytes()); }, - Tag::Int(int) => unsafe { + NbtTag::Int(int) => unsafe { unchecked_extend(data, &int.to_be_bytes()); }, - Tag::Long(long) => { + NbtTag::Long(long) => { data.extend_from_slice(&long.to_be_bytes()); } - Tag::Float(float) => unsafe { + NbtTag::Float(float) => unsafe { unchecked_extend(data, &float.to_be_bytes()); }, - Tag::Double(double) => { + NbtTag::Double(double) => { data.extend_from_slice(&double.to_be_bytes()); } - Tag::ByteArray(byte_array) => { + NbtTag::ByteArray(byte_array) => { unsafe { unchecked_extend(data, &byte_array.len().to_be_bytes()); } data.extend_from_slice(byte_array); } - Tag::String(string) => { + NbtTag::String(string) => { write_string(data, string); } - Tag::List(list) => { + NbtTag::List(list) => { list.write(data); } - Tag::Compound(compound) => { + NbtTag::Compound(compound) => { compound.write(data); } - Tag::IntArray(int_array) => { + NbtTag::IntArray(int_array) => { unsafe { unchecked_extend(data, &int_array.len().to_be_bytes()); } data.extend_from_slice(&slice_into_u8_big_endian(int_array)); } - Tag::LongArray(long_array) => { + NbtTag::LongArray(long_array) => { unsafe { unchecked_extend(data, &long_array.len().to_be_bytes()); } @@ -142,7 +151,7 @@ impl CompoundTag { } #[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 = name.as_ref(); for (key, value) in &self.values { @@ -154,7 +163,7 @@ impl CompoundTag { } #[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 = name.as_ref(); for (key, value) in &mut self.values { @@ -231,10 +240,10 @@ impl CompoundTag { pub fn list_mut(&mut self, name: &str) -> Option<&mut ListTag> { 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()) } - 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()) } 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()) } - pub fn iter(&self) -> impl Iterator { + pub fn iter(&self) -> impl Iterator { self.values.iter().map(|(k, v)| (k.as_str(), v)) } - pub fn iter_mut(&mut self) -> impl Iterator { + pub fn iter_mut(&mut self) -> impl Iterator { self.values.iter_mut().map(|(k, v)| (k.as_str(), v)) } pub fn len(&self) -> usize { @@ -268,22 +277,23 @@ impl CompoundTag { pub fn keys_mut(&mut self) -> impl Iterator { self.values.iter_mut().map(|(k, _)| k) } - pub fn values(&self) -> impl Iterator { + pub fn values(&self) -> impl Iterator { self.values.iter().map(|(_, v)| v) } - pub fn values_mut(&mut self) -> impl Iterator { + pub fn values_mut(&mut self) -> impl Iterator { self.values.iter_mut().map(|(_, v)| v) } - pub fn into_iter(self) -> impl Iterator { + pub fn into_iter(self) -> impl Iterator { self.values.into_iter() } pub fn clear(&mut self) { self.values.clear(); } - pub fn insert(&mut self, name: Mutf8String, tag: Tag) { + pub fn insert(&mut self, name: impl Into, tag: NbtTag) { + let name = name.into(); self.values.push((name, tag)); } - pub fn remove(&mut self, name: &str) -> Option { + pub fn remove(&mut self, name: &str) -> Option { let name = Mutf8Str::from_str(name); let name = name.as_ref(); for i in 0..self.values.len() { diff --git a/src/owned/list.rs b/src/owned/list.rs index e8c294f..8265e38 100644 --- a/src/owned/list.rs +++ b/src/owned/list.rs @@ -15,7 +15,7 @@ use crate::{ 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. #[repr(u8)] @@ -32,12 +32,12 @@ pub enum ListTag { ByteArray(Vec>) = BYTE_ARRAY_ID, String(Vec) = STRING_ID, List(Vec) = LIST_ID, - Compound(Vec) = COMPOUND_ID, + Compound(Vec) = COMPOUND_ID, IntArray(Vec>) = INT_ARRAY_ID, LongArray(Vec>) = LONG_ARRAY_ID, } impl ListTag { - pub fn new(data: &mut Cursor<&[u8]>, depth: usize) -> Result { + pub fn read(data: &mut Cursor<&[u8]>, depth: usize) -> Result { if depth > MAX_DEPTH { return Err(Error::MaxDepthExceeded); } @@ -76,7 +76,7 @@ impl ListTag { // arbitrary number to prevent big allocations let mut lists = Vec::with_capacity(length.min(128) as usize); for _ in 0..length { - lists.push(ListTag::new(data, depth + 1)?) + lists.push(ListTag::read(data, depth + 1)?) } lists }), @@ -85,7 +85,7 @@ impl ListTag { // arbitrary number to prevent big allocations let mut compounds = Vec::with_capacity(length.min(128) as usize); for _ in 0..length { - compounds.push(CompoundTag::new(data, depth + 1)?) + compounds.push(NbtCompound::read_with_depth(data, depth + 1)?) } compounds }), @@ -249,7 +249,7 @@ impl ListTag { _ => None, } } - pub fn compounds(&self) -> Option<&[CompoundTag]> { + pub fn compounds(&self) -> Option<&[NbtCompound]> { match self { ListTag::Compound(compounds) => Some(compounds), _ => None, diff --git a/src/owned/mod.rs b/src/owned/mod.rs index e68ed25..fe6332e 100644 --- a/src/owned/mod.rs +++ b/src/owned/mod.rs @@ -17,13 +17,13 @@ use crate::{ 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. #[derive(Debug, Clone, PartialEq, Default)] pub struct BaseNbt { name: Mutf8String, - tag: CompoundTag, + tag: NbtCompound, } #[derive(Debug, Clone, PartialEq)] @@ -33,7 +33,7 @@ pub enum Nbt { } impl Nbt { - pub fn new(name: Mutf8String, tag: CompoundTag) -> Self { + pub fn new(name: Mutf8String, tag: NbtCompound) -> Self { Self::Some(BaseNbt { name, tag }) } @@ -47,7 +47,7 @@ impl Nbt { return Err(Error::InvalidRootType(root_type)); } 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 })) } @@ -78,10 +78,44 @@ impl Nbt { pub fn is_none(&self) -> bool { !self.is_some() } + + pub fn iter(&self) -> impl Iterator { + 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 { + 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 { - pub fn new(name: Mutf8String, tag: CompoundTag) -> Self { + pub fn new(name: Mutf8String, tag: NbtCompound) -> Self { Self { name, tag } } @@ -96,9 +130,13 @@ impl BaseNbt { write_string(data, &self.name); self.tag.write(data); } + + pub fn into_iter(self) -> impl Iterator { + self.tag.into_iter() + } } impl Deref for BaseNbt { - type Target = CompoundTag; + type Target = NbtCompound; fn deref(&self) -> &Self::Target { &self.tag @@ -108,7 +146,7 @@ impl Deref for BaseNbt { /// A single NBT tag. #[repr(u8)] #[derive(Debug, Clone, PartialEq)] -pub enum Tag { +pub enum NbtTag { Byte(i8) = BYTE_ID, Short(i16) = SHORT_ID, Int(i32) = INT_ID, @@ -118,11 +156,11 @@ pub enum Tag { ByteArray(Vec) = BYTE_ARRAY_ID, String(Mutf8String) = STRING_ID, List(ListTag) = LIST_ID, - Compound(CompoundTag) = COMPOUND_ID, + Compound(NbtCompound) = COMPOUND_ID, IntArray(Vec) = INT_ARRAY_ID, LongArray(Vec) = LONG_ARRAY_ID, } -impl Tag { +impl NbtTag { /// Get the numerical ID of the tag type. #[inline] pub fn id(&self) -> u8 { @@ -135,145 +173,228 @@ impl Tag { pub fn byte(&self) -> Option { match self { - Tag::Byte(byte) => Some(*byte), + NbtTag::Byte(byte) => Some(*byte), _ => None, } } pub fn byte_mut(&mut self) -> Option<&mut i8> { match self { - Tag::Byte(byte) => Some(byte), + NbtTag::Byte(byte) => Some(byte), _ => None, } } + pub fn into_byte(self) -> Option { + match self { + NbtTag::Byte(byte) => Some(byte), + _ => None, + } + } + pub fn short(&self) -> Option { match self { - Tag::Short(short) => Some(*short), + NbtTag::Short(short) => Some(*short), _ => None, } } pub fn short_mut(&mut self) -> Option<&mut i16> { match self { - Tag::Short(short) => Some(short), + NbtTag::Short(short) => Some(short), _ => None, } } + pub fn into_short(self) -> Option { + match self { + NbtTag::Short(short) => Some(short), + _ => None, + } + } + pub fn int(&self) -> Option { match self { - Tag::Int(int) => Some(*int), + NbtTag::Int(int) => Some(*int), _ => None, } } pub fn int_mut(&mut self) -> Option<&mut i32> { match self { - Tag::Int(int) => Some(int), + NbtTag::Int(int) => Some(int), _ => None, } } + pub fn into_int(self) -> Option { + match self { + NbtTag::Int(int) => Some(int), + _ => None, + } + } + pub fn long(&self) -> Option { match self { - Tag::Long(long) => Some(*long), + NbtTag::Long(long) => Some(*long), _ => None, } } pub fn long_mut(&mut self) -> Option<&mut i64> { match self { - Tag::Long(long) => Some(long), + NbtTag::Long(long) => Some(long), _ => None, } } + pub fn into_long(self) -> Option { + match self { + NbtTag::Long(long) => Some(long), + _ => None, + } + } + pub fn float(&self) -> Option { match self { - Tag::Float(float) => Some(*float), + NbtTag::Float(float) => Some(*float), _ => None, } } pub fn float_mut(&mut self) -> Option<&mut f32> { match self { - Tag::Float(float) => Some(float), + NbtTag::Float(float) => Some(float), _ => None, } } + pub fn into_float(self) -> Option { + match self { + NbtTag::Float(float) => Some(float), + _ => None, + } + } + pub fn double(&self) -> Option { match self { - Tag::Double(double) => Some(*double), + NbtTag::Double(double) => Some(*double), _ => None, } } pub fn double_mut(&mut self) -> Option<&mut f64> { match self { - Tag::Double(double) => Some(double), + NbtTag::Double(double) => Some(double), _ => None, } } + pub fn into_double(self) -> Option { + match self { + NbtTag::Double(double) => Some(double), + _ => None, + } + } + pub fn byte_array(&self) -> Option<&[u8]> { match self { - Tag::ByteArray(byte_array) => Some(byte_array), + NbtTag::ByteArray(byte_array) => Some(byte_array), _ => None, } } pub fn byte_array_mut(&mut self) -> Option<&mut Vec> { match self { - Tag::ByteArray(byte_array) => Some(byte_array), + NbtTag::ByteArray(byte_array) => Some(byte_array), _ => None, } } + pub fn into_byte_array(self) -> Option> { + match self { + NbtTag::ByteArray(byte_array) => Some(byte_array), + _ => None, + } + } + pub fn string(&self) -> Option<&Mutf8Str> { match self { - Tag::String(string) => Some(string), + NbtTag::String(string) => Some(string), _ => None, } } pub fn string_mut(&mut self) -> Option<&mut Mutf8String> { match self { - Tag::String(string) => Some(string), + NbtTag::String(string) => Some(string), _ => None, } } + pub fn into_string(self) -> Option { + match self { + NbtTag::String(string) => Some(string), + _ => None, + } + } + pub fn list(&self) -> Option<&ListTag> { match self { - Tag::List(list) => Some(list), + NbtTag::List(list) => Some(list), _ => None, } } pub fn list_mut(&mut self) -> Option<&mut ListTag> { match self { - Tag::List(list) => Some(list), + NbtTag::List(list) => Some(list), _ => None, } } - pub fn compound(&self) -> Option<&CompoundTag> { + pub fn into_list(self) -> Option { match self { - Tag::Compound(compound) => Some(compound), + NbtTag::List(list) => Some(list), _ => None, } } - pub fn compound_mut(&mut self) -> Option<&mut CompoundTag> { + + pub fn compound(&self) -> Option<&NbtCompound> { match self { - Tag::Compound(compound) => Some(compound), + NbtTag::Compound(compound) => Some(compound), _ => None, } } + pub fn compound_mut(&mut self) -> Option<&mut NbtCompound> { + match self { + NbtTag::Compound(compound) => Some(compound), + _ => None, + } + } + pub fn into_compound(self) -> Option { + match self { + NbtTag::Compound(compound) => Some(compound), + _ => None, + } + } + pub fn int_array(&self) -> Option<&[i32]> { match self { - Tag::IntArray(int_array) => Some(int_array), + NbtTag::IntArray(int_array) => Some(int_array), _ => None, } } pub fn int_array_mut(&mut self) -> Option<&mut Vec> { match self { - Tag::IntArray(int_array) => Some(int_array), + NbtTag::IntArray(int_array) => Some(int_array), _ => None, } } + pub fn into_int_array(self) -> Option> { + match self { + NbtTag::IntArray(int_array) => Some(int_array), + _ => None, + } + } + pub fn long_array(&self) -> Option<&[i64]> { match self { - Tag::LongArray(long_array) => Some(long_array), + NbtTag::LongArray(long_array) => Some(long_array), _ => None, } } pub fn long_array_mut(&mut self) -> Option<&mut Vec> { match self { - Tag::LongArray(long_array) => Some(long_array), + NbtTag::LongArray(long_array) => Some(long_array), + _ => None, + } + } + pub fn into_long_array(self) -> Option> { + match self { + NbtTag::LongArray(long_array) => Some(long_array), _ => None, } }