From 0549a7c569317a58e2eff40d2c56c68ff7bd3b12 Mon Sep 17 00:00:00 2001 From: mat Date: Fri, 5 Jul 2024 04:22:41 +0000 Subject: [PATCH] fix macros and make it more useable --- simdnbt-derive/src/lib.rs | 2 +- simdnbt/src/borrow/compound.rs | 120 ++++++++++++++++----------------- simdnbt/src/borrow/list.rs | 16 +++++ simdnbt/src/borrow/mod.rs | 25 +++++-- 4 files changed, 96 insertions(+), 67 deletions(-) diff --git a/simdnbt-derive/src/lib.rs b/simdnbt-derive/src/lib.rs index 112a105..08e59a5 100644 --- a/simdnbt-derive/src/lib.rs +++ b/simdnbt-derive/src/lib.rs @@ -168,7 +168,7 @@ pub fn from_nbt_tag_derive(input: proc_macro::TokenStream) -> proc_macro::TokenS let output = quote! { impl #generics simdnbt::FromNbtTag for #ident #generics #where_clause { - fn from_nbt_tag(tag: &simdnbt::borrow::NbtTag) -> Option { + fn from_nbt_tag(tag: simdnbt::borrow::NbtTag) -> Option { match tag.string()?.to_str().as_ref() { #(#matchers)* _ => None, diff --git a/simdnbt/src/borrow/compound.rs b/simdnbt/src/borrow/compound.rs index 7927ed3..4ad8622 100644 --- a/simdnbt/src/borrow/compound.rs +++ b/simdnbt/src/borrow/compound.rs @@ -60,67 +60,7 @@ impl<'a: 'tape, 'tape> NbtCompound<'a, 'tape> { unchecked_write_string(data, name); } - let (kind, _) = tag.element(); - match kind { - TapeTagKind::Byte => unsafe { - unchecked_push(data, tag.byte().unwrap() as u8); - }, - TapeTagKind::Short => unsafe { - unchecked_extend(data, &tag.short().unwrap().to_be_bytes()); - }, - TapeTagKind::Int => unsafe { - unchecked_extend(data, &tag.int().unwrap().to_be_bytes()); - }, - TapeTagKind::Long => { - data.extend_from_slice(&tag.long().unwrap().to_be_bytes()); - } - TapeTagKind::Float => unsafe { - unchecked_extend(data, &tag.float().unwrap().to_be_bytes()); - }, - TapeTagKind::Double => { - data.extend_from_slice(&tag.double().unwrap().to_be_bytes()); - } - TapeTagKind::ByteArray => { - let byte_array = tag.byte_array().unwrap(); - unsafe { - unchecked_extend(data, &byte_array.len().to_be_bytes()); - } - data.extend_from_slice(byte_array); - } - TapeTagKind::String => { - let string = tag.string().unwrap(); - write_string(data, string); - } - _ if kind.is_list() => { - tag.list().unwrap().write(data); - } - TapeTagKind::Compound => { - tag.compound().unwrap().write(data); - } - TapeTagKind::IntArray => { - let int_array = list::u32_prefixed_list_to_rawlist::( - TapeTagKind::IntArray, - self.element, - ) - .unwrap(); - unsafe { - unchecked_extend(data, &int_array.len().to_be_bytes()); - } - data.extend_from_slice(int_array.as_big_endian()); - } - TapeTagKind::LongArray => { - let long_array = list::u32_prefixed_list_to_rawlist::( - TapeTagKind::LongArray, - self.element, - ) - .unwrap(); - unsafe { - unchecked_extend(data, &long_array.len().to_be_bytes()); - } - data.extend_from_slice(long_array.as_big_endian()); - } - _ => unreachable!("Invalid tag kind {kind:?}"), - } + write_tag(tag, data); } data.push(END_ID); } @@ -533,3 +473,61 @@ fn handle_compound_end(tapes: &mut Tapes, stack: &mut ParsingStack) { .1 = (index_after_end_element as u32 - index_of_compound_element).into(); }; } + +pub(crate) fn write_tag(tag: NbtTag, data: &mut Vec) { + let (kind, value) = tag.element(); + match kind { + TapeTagKind::Byte => unsafe { + unchecked_push(data, tag.byte().unwrap() as u8); + }, + TapeTagKind::Short => unsafe { + unchecked_extend(data, &tag.short().unwrap().to_be_bytes()); + }, + TapeTagKind::Int => unsafe { + unchecked_extend(data, &tag.int().unwrap().to_be_bytes()); + }, + TapeTagKind::Long => { + data.extend_from_slice(&tag.long().unwrap().to_be_bytes()); + } + TapeTagKind::Float => unsafe { + unchecked_extend(data, &tag.float().unwrap().to_be_bytes()); + }, + TapeTagKind::Double => { + data.extend_from_slice(&tag.double().unwrap().to_be_bytes()); + } + TapeTagKind::ByteArray => { + let byte_array = tag.byte_array().unwrap(); + unsafe { + unchecked_extend(data, &byte_array.len().to_be_bytes()); + } + data.extend_from_slice(byte_array); + } + TapeTagKind::String => { + let string = tag.string().unwrap(); + write_string(data, string); + } + _ if kind.is_list() => { + tag.list().unwrap().write(data); + } + TapeTagKind::Compound => { + tag.compound().unwrap().write(data); + } + TapeTagKind::IntArray => { + let int_array = + unsafe { list::u32_prefixed_list_to_rawlist_unchecked::(value).unwrap() }; + unsafe { + unchecked_extend(data, &int_array.len().to_be_bytes()); + } + data.extend_from_slice(int_array.as_big_endian()); + } + TapeTagKind::LongArray => { + let long_array = + unsafe { list::u32_prefixed_list_to_rawlist_unchecked::(value).unwrap() }; + unsafe { + unchecked_extend(data, &long_array.len().to_be_bytes()); + } + data.extend_from_slice(long_array.as_big_endian()); + } + _ => unreachable!("Invalid tag kind {kind:?}"), + } +} diff --git a/simdnbt/src/borrow/list.rs b/simdnbt/src/borrow/list.rs index 640cfd9..0278b5e 100644 --- a/simdnbt/src/borrow/list.rs +++ b/simdnbt/src/borrow/list.rs @@ -350,6 +350,12 @@ impl<'a, 'tape> NbtList<'a, 'tape> { } } + /// Returns whether the list is specifically a list with the `empty` tag type. This will return + /// false if the list is any other type (even it has a length of zero). + pub fn empty(&self) -> bool { + self.element().0 == TapeTagKind::EmptyList + } + pub fn bytes(&self) -> Option<&[i8]> { let (kind, value) = self.element(); if kind != TapeTagKind::ByteList { @@ -827,6 +833,16 @@ where return None; } + unsafe { u32_prefixed_list_to_rawlist_unchecked(value) } +} + +#[inline] +pub(crate) unsafe fn u32_prefixed_list_to_rawlist_unchecked<'a, T>( + value: TapeTagValue, +) -> Option> +where + T: Copy + SwappableNumber, +{ // length is always a u32 let length_ptr = u64::from(unsafe { value.int_list }) as usize as *const UnalignedU32; let length = unsafe { u32::from(*length_ptr).swap_bytes() as usize }; diff --git a/simdnbt/src/borrow/mod.rs b/simdnbt/src/borrow/mod.rs index 3609f65..9de5d23 100644 --- a/simdnbt/src/borrow/mod.rs +++ b/simdnbt/src/borrow/mod.rs @@ -253,23 +253,38 @@ impl<'a> Debug for BaseNbt<'a> { pub struct BaseNbtCompound<'a> { tapes: Tapes<'a>, } +impl<'a, 'tape> From<&'a BaseNbtCompound<'a>> for NbtCompound<'a, 'tape> { + fn from(compound: &'a BaseNbtCompound<'a>) -> Self + where + 'a: 'tape, + { + NbtCompound { + element: compound.tapes.main.as_ptr(), + extra_tapes: &compound.tapes.extra, + } + } +} /// A nameless NBT tag. pub struct BaseNbtTag<'a> { tapes: Tapes<'a>, } impl<'a> BaseNbtTag<'a> { - pub fn compound<'tape>(&'a self) -> NbtCompound<'a, 'tape> + pub fn as_tag<'tape>(&'a self) -> NbtTag<'a, 'tape> where 'a: 'tape, { - NbtCompound { + NbtTag { element: self.tapes.main.as_ptr(), extra_tapes: &self.tapes.extra, } } } - +impl<'a, 'tape> From<&'a BaseNbtTag<'a>> for NbtTag<'a, 'tape> { + fn from(tag: &'a BaseNbtTag<'a>) -> Self { + tag.as_tag() + } +} /// Either a complete NBT container, or nothing. #[derive(Debug, PartialEq, Default)] pub enum Nbt<'a> { @@ -677,7 +692,7 @@ mod tests { } #[test] - fn read_complexplayer_with_given_alloc() { + fn read_complex_player_as_tag() { let src = include_bytes!("../../tests/complex_player.dat").to_vec(); let mut src_slice = src.as_slice(); let mut decoded_src_decoder = GzDecoder::new(&mut src_slice); @@ -690,7 +705,7 @@ mod tests { decoded_src_as_tag.push(END_ID); let nbt = super::read_tag(&mut Cursor::new(&decoded_src_as_tag)).unwrap(); - let nbt = nbt.compound().compound("").unwrap(); + let nbt = nbt.as_tag().compound().unwrap().compound("").unwrap(); assert_eq!(nbt.float("foodExhaustionLevel").unwrap() as u32, 2); assert_eq!(nbt.list("Rotation").unwrap().floats().unwrap().len(), 2);