mirror of
https://github.com/azalea-rs/simdnbt.git
synced 2025-08-02 07:26:04 +00:00
use a u64 instead of a union for TapeElement
This commit is contained in:
parent
16c67d2743
commit
6d23e4e481
5 changed files with 339 additions and 427 deletions
|
@ -15,7 +15,7 @@ use crate::{
|
|||
use super::{
|
||||
extra_tapes::ExtraTapes,
|
||||
list::{self, NbtList},
|
||||
tape::{TapeElement, TapeTagKind, TapeTagValue, UnalignedU16},
|
||||
tape::{TapeElement, TapeTagKind, UnalignedU16},
|
||||
NbtTag, Tapes,
|
||||
};
|
||||
|
||||
|
@ -37,15 +37,12 @@ impl<'a: 'tape, 'tape> NbtCompound<'a, 'tape> {
|
|||
stack.push(ParsingStackElement::Compound {
|
||||
index_of_compound_element: index_of_compound_element as u32,
|
||||
})?;
|
||||
tapes.main.push(TapeElement {
|
||||
kind: (
|
||||
TapeTagKind::Compound,
|
||||
TapeTagValue {
|
||||
// this gets overwritten later
|
||||
compound: (0.into(), 0.into()),
|
||||
},
|
||||
),
|
||||
});
|
||||
tapes.main.push(TapeElement::new_with_approx_len_and_offset(
|
||||
TapeTagKind::Compound,
|
||||
// these get overwritten later
|
||||
0,
|
||||
0,
|
||||
));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -128,15 +125,15 @@ impl<'a: 'tape, 'tape> NbtCompound<'a, 'tape> {
|
|||
}
|
||||
|
||||
/// Get the tape element kind and value for this compound.
|
||||
fn element(&self) -> (TapeTagKind, TapeTagValue) {
|
||||
unsafe { (*self.element).kind }
|
||||
fn element(&self) -> TapeElement {
|
||||
unsafe { *self.element }
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> CompoundIter<'a, 'tape> {
|
||||
let (kind, value) = self.element();
|
||||
debug_assert_eq!(kind, TapeTagKind::Compound);
|
||||
let el = self.element();
|
||||
debug_assert_eq!(el.kind(), TapeTagKind::Compound);
|
||||
|
||||
let max_tape_offset = u32::from(unsafe { value.list_list.1 }) as usize;
|
||||
let max_tape_offset = el.approx_len_and_offset().1 as usize;
|
||||
let tape_slice =
|
||||
unsafe { std::slice::from_raw_parts(self.element.add(1), max_tape_offset) };
|
||||
|
||||
|
@ -155,18 +152,18 @@ impl<'a: 'tape, 'tape> NbtCompound<'a, 'tape> {
|
|||
/// want to avoid that.
|
||||
pub fn len(&self) -> usize {
|
||||
let len = self.approx_len();
|
||||
if len < 2usize.pow(24) {
|
||||
len
|
||||
if len < 2u32.pow(24) {
|
||||
len as usize
|
||||
} else {
|
||||
self.iter().count()
|
||||
}
|
||||
}
|
||||
|
||||
/// A version of [`Self::len`] that saturates at 2^24.
|
||||
pub fn approx_len(self) -> usize {
|
||||
let (kind, value) = self.element();
|
||||
debug_assert_eq!(kind, TapeTagKind::Compound);
|
||||
unsafe { u32::from(value.list_list.0) as usize }
|
||||
pub fn approx_len(self) -> u32 {
|
||||
let el = self.element();
|
||||
debug_assert_eq!(el.kind(), TapeTagKind::Compound);
|
||||
el.approx_len_and_offset().0
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
|
@ -212,11 +209,10 @@ impl<'a: 'tape, 'tape> Iterator for CompoundIter<'a, 'tape> {
|
|||
return None;
|
||||
}
|
||||
|
||||
let name_length_ptr = unsafe { self.tape[self.current_tape_offset].name };
|
||||
let name_length_ptr = name_length_ptr as *const UnalignedU16;
|
||||
let name_length_ptr = self.tape[self.current_tape_offset].u64() as *const UnalignedU16;
|
||||
let name_length = u16::from(unsafe { *name_length_ptr }).swap_bytes();
|
||||
let name_pointer = unsafe { name_length_ptr.add(1) as *const u8 };
|
||||
let name_slice = unsafe { std::slice::from_raw_parts(name_pointer, name_length as usize) };
|
||||
let name_ptr = unsafe { name_length_ptr.add(1) as *const u8 };
|
||||
let name_slice = unsafe { std::slice::from_raw_parts(name_ptr, name_length as usize) };
|
||||
let name = Mutf8Str::from_slice(name_slice);
|
||||
|
||||
self.current_tape_offset += 1;
|
||||
|
@ -338,94 +334,75 @@ pub(crate) fn read_tag<'a>(
|
|||
match tag_type {
|
||||
BYTE_ID => {
|
||||
let byte = data.read_i8()?;
|
||||
tapes.main.push(TapeElement {
|
||||
kind: (TapeTagKind::Byte, TapeTagValue { byte }),
|
||||
});
|
||||
tapes
|
||||
.main
|
||||
.push(TapeElement::new_with_u8(TapeTagKind::Byte, byte as u8));
|
||||
}
|
||||
SHORT_ID => {
|
||||
let short = data.read_i16()?;
|
||||
tapes.main.push(TapeElement {
|
||||
kind: (TapeTagKind::Short, TapeTagValue { short }),
|
||||
});
|
||||
tapes
|
||||
.main
|
||||
.push(TapeElement::new_with_u16(TapeTagKind::Short, short as u16));
|
||||
}
|
||||
INT_ID => {
|
||||
let int = data.read_i32()?;
|
||||
tapes.main.push(TapeElement {
|
||||
kind: (TapeTagKind::Int, TapeTagValue { int }),
|
||||
});
|
||||
tapes
|
||||
.main
|
||||
.push(TapeElement::new_with_u32(TapeTagKind::Int, int as u32));
|
||||
}
|
||||
LONG_ID => {
|
||||
let long = data.read_i64()?;
|
||||
tapes.main.push(TapeElement {
|
||||
kind: (TapeTagKind::Long, TapeTagValue { long: () }),
|
||||
});
|
||||
tapes.main.push(TapeElement { long });
|
||||
tapes.main.push(TapeElement::new_with_0(TapeTagKind::Long));
|
||||
tapes.main.push(TapeElement::new(long as u64));
|
||||
}
|
||||
FLOAT_ID => {
|
||||
let float = data.read_f32()?;
|
||||
tapes.main.push(TapeElement {
|
||||
kind: (TapeTagKind::Float, TapeTagValue { float }),
|
||||
});
|
||||
tapes
|
||||
.main
|
||||
.push(TapeElement::new_with_u32(TapeTagKind::Float, float as u32));
|
||||
}
|
||||
DOUBLE_ID => {
|
||||
let double = data.read_f64()?;
|
||||
tapes.main.push(TapeElement {
|
||||
kind: (TapeTagKind::Double, TapeTagValue { double: () }),
|
||||
});
|
||||
tapes.main.push(TapeElement { double });
|
||||
tapes
|
||||
.main
|
||||
.push(TapeElement::new_with_0(TapeTagKind::Double));
|
||||
tapes.main.push(TapeElement::new(double as u64));
|
||||
}
|
||||
BYTE_ARRAY_ID => {
|
||||
let byte_array_pointer = data.cur as u64;
|
||||
let byte_array_ptr = data.cur;
|
||||
read_with_u32_length(data, 1)?;
|
||||
tapes.main.push(TapeElement {
|
||||
kind: (
|
||||
TapeTagKind::ByteArray,
|
||||
TapeTagValue {
|
||||
byte_array: byte_array_pointer.into(),
|
||||
},
|
||||
),
|
||||
});
|
||||
tapes.main.push(TapeElement::new_with_ptr(
|
||||
TapeTagKind::ByteArray,
|
||||
byte_array_ptr,
|
||||
));
|
||||
}
|
||||
STRING_ID => {
|
||||
let string_pointer = data.cur as u64;
|
||||
let string_ptr = data.cur;
|
||||
|
||||
// assert that the top 8 bits of the pointer are 0 (because we rely on this)
|
||||
debug_assert_eq!(string_pointer >> 56, 0);
|
||||
debug_assert_eq!(string_ptr as u64 >> 56, 0);
|
||||
|
||||
read_string(data)?;
|
||||
|
||||
tapes.main.push(TapeElement {
|
||||
kind: (
|
||||
TapeTagKind::String,
|
||||
TapeTagValue {
|
||||
string: string_pointer.into(),
|
||||
},
|
||||
),
|
||||
});
|
||||
tapes
|
||||
.main
|
||||
.push(TapeElement::new_with_ptr(TapeTagKind::String, string_ptr));
|
||||
}
|
||||
INT_ARRAY_ID => {
|
||||
let int_array_pointer = data.cur as u64;
|
||||
let int_array_ptr = data.cur;
|
||||
read_int_array(data)?;
|
||||
tapes.main.push(TapeElement {
|
||||
kind: (
|
||||
TapeTagKind::IntArray,
|
||||
TapeTagValue {
|
||||
int_array: int_array_pointer.into(),
|
||||
},
|
||||
),
|
||||
});
|
||||
tapes.main.push(TapeElement::new_with_ptr(
|
||||
TapeTagKind::IntArray,
|
||||
int_array_ptr,
|
||||
));
|
||||
}
|
||||
LONG_ARRAY_ID => {
|
||||
let long_array_pointer = data.cur as u64;
|
||||
let long_array_ptr = data.cur;
|
||||
read_long_array(data)?;
|
||||
tapes.main.push(TapeElement {
|
||||
kind: (
|
||||
TapeTagKind::LongArray,
|
||||
TapeTagValue {
|
||||
long_array: long_array_pointer.into(),
|
||||
},
|
||||
),
|
||||
});
|
||||
tapes.main.push(TapeElement::new_with_ptr(
|
||||
TapeTagKind::LongArray,
|
||||
long_array_ptr,
|
||||
));
|
||||
}
|
||||
_ => return Err(NonRootError::unknown_tag_id(tag_type)),
|
||||
};
|
||||
|
@ -444,12 +421,10 @@ pub(crate) fn read_tag_in_compound<'a>(
|
|||
return Ok(());
|
||||
}
|
||||
|
||||
let tag_name_pointer = data.cur as u64;
|
||||
debug_assert_eq!(tag_name_pointer >> 56, 0);
|
||||
let tag_name_ptr = data.cur;
|
||||
debug_assert_eq!(tag_name_ptr as u64 >> 56, 0);
|
||||
read_string(data)?;
|
||||
tapes.main.push(TapeElement {
|
||||
name: tag_name_pointer,
|
||||
});
|
||||
tapes.main.push(TapeElement::new(tag_name_ptr as u64));
|
||||
|
||||
read_tag(data, tapes, stack, tag_type)
|
||||
}
|
||||
|
@ -468,16 +443,13 @@ fn handle_compound_end(tapes: &mut Tapes, stack: &mut ParsingStack) {
|
|||
tapes
|
||||
.main
|
||||
.get_unchecked_mut(index_of_compound_element as usize)
|
||||
.kind
|
||||
.1
|
||||
.compound
|
||||
.1 = (index_after_end_element as u32 - index_of_compound_element).into();
|
||||
.set_offset(index_after_end_element as u32 - index_of_compound_element);
|
||||
};
|
||||
}
|
||||
|
||||
pub(crate) fn write_tag(tag: NbtTag, data: &mut Vec<u8>) {
|
||||
let (kind, value) = tag.element();
|
||||
match kind {
|
||||
let el = tag.element();
|
||||
match el.kind() {
|
||||
TapeTagKind::Byte => unsafe {
|
||||
unchecked_push(data, tag.byte().unwrap() as u8);
|
||||
},
|
||||
|
@ -507,7 +479,7 @@ pub(crate) fn write_tag(tag: NbtTag, data: &mut Vec<u8>) {
|
|||
let string = tag.string().unwrap();
|
||||
write_string(data, string);
|
||||
}
|
||||
_ if kind.is_list() => {
|
||||
kind if kind.is_list() => {
|
||||
tag.list().unwrap().write(data);
|
||||
}
|
||||
TapeTagKind::Compound => {
|
||||
|
@ -515,7 +487,7 @@ pub(crate) fn write_tag(tag: NbtTag, data: &mut Vec<u8>) {
|
|||
}
|
||||
TapeTagKind::IntArray => {
|
||||
let int_array =
|
||||
unsafe { list::u32_prefixed_list_to_rawlist_unchecked::<i32>(value).unwrap() };
|
||||
unsafe { list::u32_prefixed_list_to_rawlist_unchecked::<i32>(el.ptr()).unwrap() };
|
||||
unsafe {
|
||||
unchecked_extend(data, &int_array.len().to_be_bytes());
|
||||
}
|
||||
|
@ -523,12 +495,12 @@ pub(crate) fn write_tag(tag: NbtTag, data: &mut Vec<u8>) {
|
|||
}
|
||||
TapeTagKind::LongArray => {
|
||||
let long_array =
|
||||
unsafe { list::u32_prefixed_list_to_rawlist_unchecked::<i64>(value).unwrap() };
|
||||
unsafe { list::u32_prefixed_list_to_rawlist_unchecked::<i64>(el.ptr()).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:?}"),
|
||||
kind => unreachable!("Invalid tag kind {kind:?}"),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ use crate::{
|
|||
use super::{
|
||||
compound::{ParsingStack, ParsingStackElement},
|
||||
extra_tapes::{ExtraTapeElement, ExtraTapes},
|
||||
tape::{TapeElement, TapeTagKind, TapeTagValue, UnalignedU32},
|
||||
tape::{TapeElement, TapeTagKind, UnalignedU32},
|
||||
NbtCompound, Tapes,
|
||||
};
|
||||
|
||||
|
@ -38,92 +38,64 @@ impl<'a, 'tape> NbtList<'a, 'tape> {
|
|||
END_ID => {
|
||||
// the length is unused for this type of lists
|
||||
data.skip(4)?;
|
||||
tapes.main.push(TapeElement {
|
||||
kind: (TapeTagKind::EmptyList, TapeTagValue { empty_list: () }),
|
||||
});
|
||||
tapes
|
||||
.main
|
||||
.push(TapeElement::new_with_0(TapeTagKind::EmptyList));
|
||||
}
|
||||
BYTE_ID => {
|
||||
let byte_list_pointer = data.cur as u64;
|
||||
let byte_list_ptr = data.cur;
|
||||
let _ = read_i8_array(data)?;
|
||||
tapes.main.push(TapeElement {
|
||||
kind: (
|
||||
TapeTagKind::ByteList,
|
||||
TapeTagValue {
|
||||
byte_list: byte_list_pointer.into(),
|
||||
},
|
||||
),
|
||||
});
|
||||
tapes.main.push(TapeElement::new_with_ptr(
|
||||
TapeTagKind::ByteList,
|
||||
byte_list_ptr,
|
||||
));
|
||||
}
|
||||
SHORT_ID => {
|
||||
let short_list_pointer = data.cur as u64;
|
||||
let short_list_ptr = data.cur;
|
||||
read_with_u32_length(data, 2)?;
|
||||
tapes.main.push(TapeElement {
|
||||
kind: (
|
||||
TapeTagKind::ShortList,
|
||||
TapeTagValue {
|
||||
short_list: short_list_pointer.into(),
|
||||
},
|
||||
),
|
||||
});
|
||||
tapes.main.push(TapeElement::new_with_ptr(
|
||||
TapeTagKind::ShortList,
|
||||
short_list_ptr,
|
||||
));
|
||||
}
|
||||
INT_ID => {
|
||||
let int_list_pointer = data.cur as u64;
|
||||
let int_list_ptr = data.cur;
|
||||
read_with_u32_length(data, 4)?;
|
||||
tapes.main.push(TapeElement {
|
||||
kind: (
|
||||
TapeTagKind::IntList,
|
||||
TapeTagValue {
|
||||
int_list: int_list_pointer.into(),
|
||||
},
|
||||
),
|
||||
});
|
||||
tapes.main.push(TapeElement::new_with_ptr(
|
||||
TapeTagKind::IntList,
|
||||
int_list_ptr,
|
||||
));
|
||||
}
|
||||
LONG_ID => {
|
||||
let long_list_pointer = data.cur as u64;
|
||||
let long_list_ptr = data.cur;
|
||||
read_with_u32_length(data, 8)?;
|
||||
tapes.main.push(TapeElement {
|
||||
kind: (
|
||||
TapeTagKind::LongList,
|
||||
TapeTagValue {
|
||||
long_list: long_list_pointer.into(),
|
||||
},
|
||||
),
|
||||
});
|
||||
tapes.main.push(TapeElement::new_with_ptr(
|
||||
TapeTagKind::LongList,
|
||||
long_list_ptr,
|
||||
));
|
||||
}
|
||||
FLOAT_ID => {
|
||||
let float_list_pointer = data.cur as u64;
|
||||
let float_list_ptr = data.cur;
|
||||
read_with_u32_length(data, 4)?;
|
||||
tapes.main.push(TapeElement {
|
||||
kind: (
|
||||
TapeTagKind::FloatList,
|
||||
TapeTagValue {
|
||||
float_list: float_list_pointer.into(),
|
||||
},
|
||||
),
|
||||
});
|
||||
tapes.main.push(TapeElement::new_with_ptr(
|
||||
TapeTagKind::FloatList,
|
||||
float_list_ptr,
|
||||
));
|
||||
}
|
||||
DOUBLE_ID => {
|
||||
let double_list_pointer = data.cur as u64;
|
||||
let double_list_ptr = data.cur;
|
||||
read_with_u32_length(data, 8)?;
|
||||
tapes.main.push(TapeElement {
|
||||
kind: (
|
||||
TapeTagKind::DoubleList,
|
||||
TapeTagValue {
|
||||
double_list: double_list_pointer.into(),
|
||||
},
|
||||
),
|
||||
});
|
||||
tapes.main.push(TapeElement::new_with_ptr(
|
||||
TapeTagKind::DoubleList,
|
||||
double_list_ptr,
|
||||
));
|
||||
}
|
||||
BYTE_ARRAY_ID => {
|
||||
let index_of_element = tapes.extra.elements.len() as u32;
|
||||
tapes.main.push(TapeElement {
|
||||
kind: (
|
||||
TapeTagKind::ByteArrayList,
|
||||
TapeTagValue {
|
||||
byte_array_list: (0.into(), index_of_element.into()),
|
||||
},
|
||||
),
|
||||
});
|
||||
tapes.main.push(TapeElement::new_with_u32(
|
||||
TapeTagKind::ByteArrayList,
|
||||
index_of_element,
|
||||
));
|
||||
|
||||
let length = data.read_u32()?;
|
||||
tapes.extra.elements.push(ExtraTapeElement { length });
|
||||
|
@ -134,14 +106,10 @@ impl<'a, 'tape> NbtList<'a, 'tape> {
|
|||
}
|
||||
STRING_ID => {
|
||||
let index_of_element = tapes.extra.elements.len() as u32;
|
||||
tapes.main.push(TapeElement {
|
||||
kind: (
|
||||
TapeTagKind::StringList,
|
||||
TapeTagValue {
|
||||
string_list: (0.into(), index_of_element.into()),
|
||||
},
|
||||
),
|
||||
});
|
||||
tapes.main.push(TapeElement::new_with_u32(
|
||||
TapeTagKind::StringList,
|
||||
index_of_element,
|
||||
));
|
||||
|
||||
let length = data.read_u32()?;
|
||||
tapes.extra.elements.push(ExtraTapeElement { length });
|
||||
|
@ -159,15 +127,12 @@ impl<'a, 'tape> NbtList<'a, 'tape> {
|
|||
index_of_list_element: index_of_list_element as u32,
|
||||
})?;
|
||||
stack.set_list_length(length);
|
||||
tapes.main.push(TapeElement {
|
||||
kind: (
|
||||
TapeTagKind::ListList,
|
||||
TapeTagValue {
|
||||
// can't know the offset until after
|
||||
list_list: (length.into(), 0.into()),
|
||||
},
|
||||
),
|
||||
});
|
||||
tapes.main.push(TapeElement::new_with_approx_len_and_offset(
|
||||
TapeTagKind::ListList,
|
||||
length,
|
||||
// can't know the offset until after
|
||||
0,
|
||||
));
|
||||
}
|
||||
COMPOUND_ID => {
|
||||
let length = data.read_u32()?;
|
||||
|
@ -178,26 +143,19 @@ impl<'a, 'tape> NbtList<'a, 'tape> {
|
|||
index_of_list_element: index_of_list_element as u32,
|
||||
})?;
|
||||
stack.set_list_length(length);
|
||||
tapes.main.push(TapeElement {
|
||||
kind: (
|
||||
TapeTagKind::CompoundList,
|
||||
TapeTagValue {
|
||||
// this gets overwritten after the list is fully read
|
||||
compound_list: (length.into(), 0.into()),
|
||||
},
|
||||
),
|
||||
});
|
||||
tapes.main.push(TapeElement::new_with_approx_len_and_offset(
|
||||
TapeTagKind::CompoundList,
|
||||
length,
|
||||
// this gets overwritten after the list is fully read
|
||||
0,
|
||||
));
|
||||
}
|
||||
INT_ARRAY_ID => {
|
||||
let index_of_element = tapes.extra.elements.len() as u32;
|
||||
tapes.main.push(TapeElement {
|
||||
kind: (
|
||||
TapeTagKind::IntArrayList,
|
||||
TapeTagValue {
|
||||
int_array_list: (0.into(), index_of_element.into()),
|
||||
},
|
||||
),
|
||||
});
|
||||
tapes.main.push(TapeElement::new_with_u32(
|
||||
TapeTagKind::IntArrayList,
|
||||
index_of_element,
|
||||
));
|
||||
let length = data.read_u32()?;
|
||||
tapes.extra.elements.push(ExtraTapeElement { length });
|
||||
for _ in 0..length {
|
||||
|
@ -207,14 +165,10 @@ impl<'a, 'tape> NbtList<'a, 'tape> {
|
|||
}
|
||||
LONG_ARRAY_ID => {
|
||||
let index_of_element = tapes.extra.elements.len() as u32;
|
||||
tapes.main.push(TapeElement {
|
||||
kind: (
|
||||
TapeTagKind::LongArrayList,
|
||||
TapeTagValue {
|
||||
long_array_list: (0.into(), index_of_element.into()),
|
||||
},
|
||||
),
|
||||
});
|
||||
tapes.main.push(TapeElement::new_with_u32(
|
||||
TapeTagKind::LongArrayList,
|
||||
index_of_element.into(),
|
||||
));
|
||||
let length = data.read_u32()?;
|
||||
tapes.extra.elements.push(ExtraTapeElement { length });
|
||||
for _ in 0..length {
|
||||
|
@ -228,11 +182,11 @@ impl<'a, 'tape> NbtList<'a, 'tape> {
|
|||
}
|
||||
|
||||
pub fn write(&self, data: &mut Vec<u8>) {
|
||||
let (kind, _) = self.element();
|
||||
let el = self.element();
|
||||
|
||||
data.push(self.id());
|
||||
|
||||
match kind {
|
||||
match el.kind() {
|
||||
TapeTagKind::EmptyList => {
|
||||
data.extend(&0u32.to_be_bytes());
|
||||
}
|
||||
|
@ -326,14 +280,14 @@ impl<'a, 'tape> NbtList<'a, 'tape> {
|
|||
}
|
||||
|
||||
/// Get the tape element kind and value for this list.
|
||||
fn element(&self) -> (TapeTagKind, TapeTagValue) {
|
||||
unsafe { (*self.element).kind }
|
||||
fn element(&self) -> TapeElement {
|
||||
unsafe { *self.element }
|
||||
}
|
||||
|
||||
/// Get the numerical ID of the tag type.
|
||||
#[inline]
|
||||
pub fn id(&self) -> u8 {
|
||||
match self.element().0 {
|
||||
match self.element().kind() {
|
||||
TapeTagKind::EmptyList => END_ID,
|
||||
TapeTagKind::ByteList => BYTE_ID,
|
||||
TapeTagKind::ShortList => SHORT_ID,
|
||||
|
@ -354,15 +308,15 @@ 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
|
||||
self.element().kind() == TapeTagKind::EmptyList
|
||||
}
|
||||
|
||||
pub fn bytes(&self) -> Option<&[i8]> {
|
||||
let (kind, value) = self.element();
|
||||
if kind != TapeTagKind::ByteList {
|
||||
let el = self.element();
|
||||
if el.kind() != TapeTagKind::ByteList {
|
||||
return None;
|
||||
}
|
||||
let length_ptr = u64::from(unsafe { value.byte_list }) as usize as *const UnalignedU32;
|
||||
let length_ptr = el.ptr::<UnalignedU32>();
|
||||
let length = unsafe { u32::from(*length_ptr).swap_bytes() as usize };
|
||||
let byte_array =
|
||||
unsafe { std::slice::from_raw_parts(length_ptr.add(1) as *const i8, length) };
|
||||
|
@ -384,11 +338,11 @@ impl<'a, 'tape> NbtList<'a, 'tape> {
|
|||
u32_prefixed_list_to_vec(TapeTagKind::DoubleList, self.element)
|
||||
}
|
||||
pub fn byte_arrays(&self) -> Option<&'a [&'a [u8]]> {
|
||||
let (kind, value) = self.element();
|
||||
if kind != TapeTagKind::ByteArrayList {
|
||||
let el = self.element();
|
||||
if el.kind() != TapeTagKind::ByteArrayList {
|
||||
return None;
|
||||
}
|
||||
let index_to_extra_tapes = u32::from(unsafe { value.byte_array_list.1 }) as usize;
|
||||
let index_to_extra_tapes = el.u32() as usize;
|
||||
let length_ref = &self.extra_tapes.elements[index_to_extra_tapes];
|
||||
let length = unsafe { length_ref.length as usize };
|
||||
let slice = unsafe {
|
||||
|
@ -404,11 +358,11 @@ impl<'a, 'tape> NbtList<'a, 'tape> {
|
|||
Some(slice)
|
||||
}
|
||||
pub fn strings(&self) -> Option<&'a [&'a Mutf8Str]> {
|
||||
let (kind, value) = self.element();
|
||||
if kind != TapeTagKind::StringList {
|
||||
let el = self.element();
|
||||
if el.kind() != TapeTagKind::StringList {
|
||||
return None;
|
||||
}
|
||||
let index_to_extra_tapes = u32::from(unsafe { value.string_list.1 }) as usize;
|
||||
let index_to_extra_tapes = el.u32() as usize;
|
||||
let length_ref = &self.extra_tapes.elements[index_to_extra_tapes];
|
||||
let length = unsafe { length_ref.length as usize };
|
||||
let slice = unsafe {
|
||||
|
@ -424,19 +378,18 @@ impl<'a, 'tape> NbtList<'a, 'tape> {
|
|||
Some(slice)
|
||||
}
|
||||
pub fn lists(&self) -> Option<ListList<'a, 'tape>> {
|
||||
let (kind, value) = self.element();
|
||||
if kind != TapeTagKind::ListList {
|
||||
let el = self.element();
|
||||
if el.kind() != TapeTagKind::ListList {
|
||||
return None;
|
||||
}
|
||||
|
||||
let length = u32::from(unsafe { value.list_list.0 }) as usize;
|
||||
let max_tape_offset = u32::from(unsafe { value.list_list.1 }) as usize;
|
||||
let (approx_length, max_tape_offset) = el.approx_len_and_offset();
|
||||
|
||||
Some(ListList {
|
||||
iter: ListListIter {
|
||||
current_tape_offset: 0, // it's an iterator, it starts at 0
|
||||
max_tape_offset,
|
||||
approx_length: length,
|
||||
max_tape_offset: max_tape_offset as usize,
|
||||
approx_length,
|
||||
tape: unsafe { self.element.add(1) }, // the first element is the listlist element so we don't include it
|
||||
extra_tapes: self.extra_tapes,
|
||||
_phantom: PhantomData,
|
||||
|
@ -445,14 +398,14 @@ impl<'a, 'tape> NbtList<'a, 'tape> {
|
|||
}
|
||||
|
||||
pub fn compounds(&self) -> Option<CompoundList<'a, 'tape>> {
|
||||
let (kind, value) = self.element();
|
||||
if kind != TapeTagKind::CompoundList {
|
||||
let el = self.element();
|
||||
if el.kind() != TapeTagKind::CompoundList {
|
||||
return None;
|
||||
}
|
||||
|
||||
let length = u32::from(unsafe { value.compound_list.0 }) as usize;
|
||||
let (approx_length, max_tape_offset) = el.approx_len_and_offset();
|
||||
let max_tape_offset = max_tape_offset as usize;
|
||||
|
||||
let max_tape_offset = u32::from(unsafe { value.compound_list.1 }) as usize;
|
||||
let tape_slice =
|
||||
unsafe { std::slice::from_raw_parts(self.element.add(1), max_tape_offset) };
|
||||
|
||||
|
@ -460,18 +413,18 @@ impl<'a, 'tape> NbtList<'a, 'tape> {
|
|||
iter: CompoundListIter {
|
||||
current_tape_offset: 0,
|
||||
max_tape_offset,
|
||||
approx_length: length,
|
||||
approx_length,
|
||||
tape: tape_slice,
|
||||
extra_tapes: self.extra_tapes,
|
||||
},
|
||||
})
|
||||
}
|
||||
pub fn int_arrays(&self) -> Option<&[RawList<i32>]> {
|
||||
let (kind, value) = self.element();
|
||||
if kind != TapeTagKind::IntArrayList {
|
||||
let el = self.element();
|
||||
if el.kind() != TapeTagKind::IntArrayList {
|
||||
return None;
|
||||
}
|
||||
let index_to_extra_tapes = u32::from(unsafe { value.int_array_list.1 }) as usize;
|
||||
let index_to_extra_tapes = el.u32() as usize;
|
||||
let length_ref = &self.extra_tapes.elements[index_to_extra_tapes];
|
||||
let length = unsafe { length_ref.length as usize };
|
||||
let slice = unsafe {
|
||||
|
@ -487,11 +440,11 @@ impl<'a, 'tape> NbtList<'a, 'tape> {
|
|||
Some(slice)
|
||||
}
|
||||
pub fn long_arrays(&self) -> Option<&[RawList<i64>]> {
|
||||
let (kind, value) = self.element();
|
||||
if kind != TapeTagKind::LongArrayList {
|
||||
let el = self.element();
|
||||
if el.kind() != TapeTagKind::LongArrayList {
|
||||
return None;
|
||||
}
|
||||
let index_to_extra_tapes = u32::from(unsafe { value.long_array_list.1 }) as usize;
|
||||
let index_to_extra_tapes = el.u32() as usize;
|
||||
let length_ref = &self.extra_tapes.elements[index_to_extra_tapes];
|
||||
let length = unsafe { length_ref.length as usize };
|
||||
let slice = unsafe {
|
||||
|
@ -508,9 +461,9 @@ impl<'a, 'tape> NbtList<'a, 'tape> {
|
|||
}
|
||||
|
||||
pub fn to_owned(&self) -> crate::owned::NbtList {
|
||||
let (kind, _value) = self.element();
|
||||
let el = self.element();
|
||||
|
||||
match kind {
|
||||
match el.kind() {
|
||||
TapeTagKind::EmptyList => crate::owned::NbtList::Empty,
|
||||
TapeTagKind::ByteList => crate::owned::NbtList::Byte(self.bytes().unwrap().to_vec()),
|
||||
TapeTagKind::ShortList => crate::owned::NbtList::Short(self.shorts().unwrap().to_vec()),
|
||||
|
@ -569,12 +522,12 @@ impl<'a, 'tape> NbtList<'a, 'tape> {
|
|||
|
||||
impl PartialEq for NbtList<'_, '_> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
let (self_kind, _) = self.element();
|
||||
let (other_kind, _) = other.element();
|
||||
if self_kind != other_kind {
|
||||
let self_el = self.element();
|
||||
let other_el = other.element();
|
||||
if self_el.kind() != other_el.kind() {
|
||||
return false;
|
||||
}
|
||||
match self_kind {
|
||||
match self_el.kind() {
|
||||
TapeTagKind::EmptyList => true,
|
||||
TapeTagKind::ByteList => self.bytes().unwrap() == other.bytes().unwrap(),
|
||||
TapeTagKind::ShortList => self.shorts().unwrap() == other.shorts().unwrap(),
|
||||
|
@ -612,7 +565,7 @@ impl<'a, 'tape> ListList<'a, 'tape> {
|
|||
self.iter.len()
|
||||
}
|
||||
/// A version of [`Self::len`] that saturates at 2^24.
|
||||
pub fn approx_len(&self) -> usize {
|
||||
pub fn approx_len(&self) -> u32 {
|
||||
self.iter.approx_len()
|
||||
}
|
||||
/// Get the element at the given index. This is O(n) where n is index, so if you'll be calling
|
||||
|
@ -654,7 +607,7 @@ impl PartialEq for ListList<'_, '_> {
|
|||
pub struct ListListIter<'a, 'tape> {
|
||||
current_tape_offset: usize,
|
||||
max_tape_offset: usize,
|
||||
approx_length: usize,
|
||||
approx_length: u32,
|
||||
tape: *const TapeElement,
|
||||
extra_tapes: *const ExtraTapes<'a>,
|
||||
_phantom: PhantomData<&'tape ()>,
|
||||
|
@ -667,15 +620,15 @@ impl<'a: 'tape, 'tape> ListListIter<'a, 'tape> {
|
|||
/// want to avoid that.
|
||||
pub fn len(self) -> usize {
|
||||
let len = self.approx_len();
|
||||
if len < 2usize.pow(24) {
|
||||
len
|
||||
if len < 2u32.pow(24) {
|
||||
len as usize
|
||||
} else {
|
||||
self.count()
|
||||
}
|
||||
}
|
||||
|
||||
/// A version of [`Self::len`] that saturates at 2^24.
|
||||
pub fn approx_len(&self) -> usize {
|
||||
pub fn approx_len(&self) -> u32 {
|
||||
self.approx_length
|
||||
}
|
||||
}
|
||||
|
@ -687,19 +640,18 @@ impl<'a: 'tape, 'tape> Iterator for ListListIter<'a, 'tape> {
|
|||
return None;
|
||||
}
|
||||
|
||||
let element = unsafe { self.tape.add(self.current_tape_offset) };
|
||||
// println!("{:?}", unsafe { *element });
|
||||
let (kind, value) = unsafe { (*element).kind };
|
||||
debug_assert!(kind.is_list());
|
||||
let el_ptr = unsafe { self.tape.add(self.current_tape_offset) };
|
||||
let el = unsafe { *el_ptr };
|
||||
debug_assert!(el.kind().is_list());
|
||||
|
||||
let offset = if matches!(kind, TapeTagKind::CompoundList | TapeTagKind::ListList) {
|
||||
u32::from(unsafe { value.list_list.1 }) as usize
|
||||
let offset = if matches!(el.kind(), TapeTagKind::CompoundList | TapeTagKind::ListList) {
|
||||
el.u32() as usize
|
||||
} else {
|
||||
1
|
||||
};
|
||||
|
||||
let nbt_list = NbtList {
|
||||
element,
|
||||
element: el_ptr,
|
||||
extra_tapes: unsafe { &*self.extra_tapes },
|
||||
};
|
||||
|
||||
|
@ -736,7 +688,7 @@ impl<'a, 'tape> CompoundList<'a, 'tape> {
|
|||
self.iter.len()
|
||||
}
|
||||
/// A version of [`Self::len`] that saturates at 2^24.
|
||||
pub fn approx_len(&self) -> usize {
|
||||
pub fn approx_len(&self) -> u32 {
|
||||
self.iter.approx_len()
|
||||
}
|
||||
/// Get the element at the given index. This is `O(n)` where n is index, so
|
||||
|
@ -779,7 +731,7 @@ impl PartialEq for CompoundList<'_, '_> {
|
|||
pub struct CompoundListIter<'a, 'tape> {
|
||||
current_tape_offset: usize,
|
||||
max_tape_offset: usize,
|
||||
approx_length: usize,
|
||||
approx_length: u32,
|
||||
tape: &'tape [TapeElement],
|
||||
extra_tapes: *const ExtraTapes<'a>,
|
||||
}
|
||||
|
@ -791,15 +743,15 @@ impl<'a: 'tape, 'tape> CompoundListIter<'a, 'tape> {
|
|||
/// want to avoid that.
|
||||
pub fn len(self) -> usize {
|
||||
let len = self.approx_len();
|
||||
if len < 2usize.pow(24) {
|
||||
len
|
||||
if len < 2u32.pow(24) {
|
||||
len as usize
|
||||
} else {
|
||||
self.count()
|
||||
}
|
||||
}
|
||||
|
||||
/// A version of [`Self::len`] that saturates at 2^24.
|
||||
pub fn approx_len(&self) -> usize {
|
||||
pub fn approx_len(&self) -> u32 {
|
||||
self.approx_length
|
||||
}
|
||||
}
|
||||
|
@ -811,14 +763,14 @@ impl<'a: 'tape, 'tape> Iterator for CompoundListIter<'a, 'tape> {
|
|||
return None;
|
||||
}
|
||||
|
||||
let element = unsafe { self.tape.as_ptr().add(self.current_tape_offset) };
|
||||
let (kind, value) = unsafe { (*element).kind };
|
||||
debug_assert_eq!(kind, TapeTagKind::Compound);
|
||||
let el_ptr = unsafe { self.tape.as_ptr().add(self.current_tape_offset) };
|
||||
let el = unsafe { *el_ptr };
|
||||
debug_assert_eq!(el.kind(), TapeTagKind::Compound);
|
||||
|
||||
let offset = u32::from(unsafe { value.list_list.1 }) as usize;
|
||||
let offset = el.u32() as usize;
|
||||
|
||||
let compound = NbtCompound {
|
||||
element,
|
||||
element: el_ptr,
|
||||
extra_tapes: unsafe { &*self.extra_tapes },
|
||||
};
|
||||
|
||||
|
@ -841,32 +793,30 @@ impl Default for CompoundListIter<'_, '_> {
|
|||
|
||||
pub(crate) fn u32_prefixed_list_to_rawlist<'a, T>(
|
||||
expected_kind: TapeTagKind,
|
||||
element: *const TapeElement,
|
||||
el_ptr: *const TapeElement,
|
||||
) -> Option<RawList<'a, T>>
|
||||
where
|
||||
T: Copy + SwappableNumber,
|
||||
{
|
||||
let (kind, value) = unsafe { (*element).kind };
|
||||
if kind != expected_kind {
|
||||
let el = unsafe { *el_ptr };
|
||||
if el.kind() != expected_kind {
|
||||
return None;
|
||||
}
|
||||
|
||||
unsafe { u32_prefixed_list_to_rawlist_unchecked(value) }
|
||||
unsafe { u32_prefixed_list_to_rawlist_unchecked(el.ptr()) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) unsafe fn u32_prefixed_list_to_rawlist_unchecked<'a, T>(
|
||||
value: TapeTagValue,
|
||||
ptr: *const UnalignedU32,
|
||||
) -> Option<RawList<'a, T>>
|
||||
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 };
|
||||
let length = unsafe { u32::from(*ptr).swap_bytes() as usize };
|
||||
let length_in_bytes = length * std::mem::size_of::<T>();
|
||||
let array_be =
|
||||
unsafe { std::slice::from_raw_parts(length_ptr.add(1) as *const u8, length_in_bytes) };
|
||||
let array_be = unsafe { std::slice::from_raw_parts(ptr.add(1) as *const u8, length_in_bytes) };
|
||||
Some(RawList::new(array_be))
|
||||
}
|
||||
|
||||
|
@ -903,10 +853,7 @@ pub fn read_list_in_list<'a>(
|
|||
tapes
|
||||
.main
|
||||
.get_unchecked_mut(index_of_list_element as usize)
|
||||
.kind
|
||||
.1
|
||||
.list_list
|
||||
.1 = (index_after_end_element as u32 - index_of_list_element).into();
|
||||
.set_offset(index_after_end_element as u32 - index_of_list_element);
|
||||
};
|
||||
return Ok(());
|
||||
}
|
||||
|
@ -939,10 +886,7 @@ pub(crate) fn read_compound_in_list<'a>(
|
|||
tapes
|
||||
.main
|
||||
.get_unchecked_mut(index_of_list_element as usize)
|
||||
.kind
|
||||
.1
|
||||
.compound_list
|
||||
.1 = (index_after_end_element as u32 - index_of_list_element).into();
|
||||
.set_offset(index_after_end_element as u32 - index_of_list_element);
|
||||
};
|
||||
return Ok(());
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ use std::{
|
|||
};
|
||||
|
||||
use byteorder::ReadBytesExt;
|
||||
use tape::UnalignedU32;
|
||||
use tape::{UnalignedU16, UnalignedU32};
|
||||
|
||||
use crate::{
|
||||
common::{
|
||||
|
@ -27,7 +27,7 @@ use self::{
|
|||
compound::{read_tag_in_compound, ParsingStack, ParsingStackElement},
|
||||
extra_tapes::ExtraTapes,
|
||||
list::{read_compound_in_list, read_list_in_list},
|
||||
tape::{MainTape, TapeElement, TapeTagKind, TapeTagValue, UnalignedU16},
|
||||
tape::{MainTape, TapeElement, TapeTagKind},
|
||||
};
|
||||
|
||||
/// Read a normal root NBT compound. This is either empty or has a name and compound tag.
|
||||
|
@ -50,15 +50,12 @@ pub fn read<'a>(data: &mut Cursor<&'a [u8]>) -> Result<Nbt<'a>, Error> {
|
|||
stack.push(ParsingStackElement::Compound {
|
||||
index_of_compound_element: 0,
|
||||
})?;
|
||||
tapes.main.push(TapeElement {
|
||||
kind: (
|
||||
TapeTagKind::Compound,
|
||||
TapeTagValue {
|
||||
// this gets overwritten later
|
||||
compound: (0.into(), 0.into()),
|
||||
},
|
||||
),
|
||||
});
|
||||
tapes.main.push(TapeElement::new_with_approx_len_and_offset(
|
||||
TapeTagKind::Compound,
|
||||
// these get overwritten later
|
||||
0,
|
||||
0,
|
||||
));
|
||||
|
||||
read_with_stack(&mut data, &mut tapes, &mut stack)?;
|
||||
|
||||
|
@ -91,15 +88,12 @@ pub fn read_compound<'a>(data: &mut Cursor<&'a [u8]>) -> Result<BaseNbtCompound<
|
|||
stack.push(ParsingStackElement::Compound {
|
||||
index_of_compound_element: 0,
|
||||
})?;
|
||||
tapes.main.push(TapeElement {
|
||||
kind: (
|
||||
TapeTagKind::Compound,
|
||||
TapeTagValue {
|
||||
// this gets overwritten later
|
||||
compound: (0.into(), 0.into()),
|
||||
},
|
||||
),
|
||||
});
|
||||
tapes.main.push(TapeElement::new_with_approx_len_and_offset(
|
||||
TapeTagKind::Compound,
|
||||
// these get overwritten later
|
||||
0,
|
||||
0,
|
||||
));
|
||||
|
||||
read_with_stack(&mut data, &mut tapes, &mut stack)?;
|
||||
|
||||
|
@ -350,7 +344,7 @@ impl<'a: 'tape, 'tape> NbtTag<'a, 'tape> {
|
|||
/// Get the numerical ID of the tag type.
|
||||
#[inline]
|
||||
pub fn id(&self) -> u8 {
|
||||
match self.element().0 {
|
||||
match self.element().kind() {
|
||||
TapeTagKind::Byte => BYTE_ID,
|
||||
TapeTagKind::Short => SHORT_ID,
|
||||
TapeTagKind::Int => INT_ID,
|
||||
|
@ -368,74 +362,62 @@ impl<'a: 'tape, 'tape> NbtTag<'a, 'tape> {
|
|||
}
|
||||
|
||||
pub fn byte(&self) -> Option<i8> {
|
||||
let (kind, value) = self.element();
|
||||
if kind != TapeTagKind::Byte {
|
||||
return None;
|
||||
}
|
||||
Some(unsafe { value.byte })
|
||||
let el = self.element();
|
||||
ensure_kind(el, TapeTagKind::Byte)?;
|
||||
Some(el.u8() as i8)
|
||||
}
|
||||
pub fn short(&self) -> Option<i16> {
|
||||
let (kind, value) = self.element();
|
||||
if kind != TapeTagKind::Short {
|
||||
return None;
|
||||
}
|
||||
Some(unsafe { value.short })
|
||||
let el = self.element();
|
||||
ensure_kind(el, TapeTagKind::Short)?;
|
||||
Some(el.u16() as i16)
|
||||
}
|
||||
pub fn int(&self) -> Option<i32> {
|
||||
let (kind, value) = unsafe { (*self.element).kind };
|
||||
if kind != TapeTagKind::Int {
|
||||
return None;
|
||||
}
|
||||
Some(unsafe { value.int })
|
||||
let el = self.element();
|
||||
ensure_kind(el, TapeTagKind::Int)?;
|
||||
Some(el.u32() as i32)
|
||||
}
|
||||
pub fn long(&self) -> Option<i64> {
|
||||
let (kind, _) = self.element();
|
||||
if kind != TapeTagKind::Long {
|
||||
return None;
|
||||
}
|
||||
let el = self.element();
|
||||
ensure_kind(el, TapeTagKind::Long)?;
|
||||
// the value is in the next element because longs are too big to fit in a single element
|
||||
let value = unsafe { self.element.add(1) };
|
||||
Some(unsafe { (*value).long })
|
||||
let value_el = unsafe { *self.element.add(1) };
|
||||
Some(value_el.u64() as i64)
|
||||
}
|
||||
pub fn float(&self) -> Option<f32> {
|
||||
let (kind, value) = self.element();
|
||||
if kind != TapeTagKind::Float {
|
||||
return None;
|
||||
}
|
||||
Some(unsafe { value.float })
|
||||
let el = self.element();
|
||||
ensure_kind(el, TapeTagKind::Float)?;
|
||||
Some(el.u32() as f32)
|
||||
}
|
||||
pub fn double(&self) -> Option<f64> {
|
||||
let (kind, _) = self.element();
|
||||
if kind != TapeTagKind::Double {
|
||||
return None;
|
||||
}
|
||||
let el = self.element();
|
||||
ensure_kind(el, TapeTagKind::Double)?;
|
||||
// the value is in the next element because doubles are too big to fit in a single element
|
||||
let value = unsafe { self.element.add(1) };
|
||||
Some(unsafe { (*value).double })
|
||||
let value_el = unsafe { *self.element.add(1) };
|
||||
Some(value_el.u64() as f64)
|
||||
}
|
||||
pub fn byte_array(&self) -> Option<&'a [u8]> {
|
||||
let (kind, value) = self.element();
|
||||
if kind != TapeTagKind::ByteArray {
|
||||
return None;
|
||||
}
|
||||
let length_ptr = unsafe { u64::from(value.byte_array) as *const UnalignedU32 };
|
||||
let length = unsafe { u32::from(*length_ptr).swap_bytes() as usize };
|
||||
let el = self.element();
|
||||
ensure_kind(el, TapeTagKind::ByteArray)?;
|
||||
let length_ptr = el.ptr::<UnalignedU32>();
|
||||
let length = u32::from(unsafe { *length_ptr });
|
||||
#[cfg(target_endian = "little")]
|
||||
let length = length.swap_bytes();
|
||||
let data_ptr = unsafe { length_ptr.add(1) as *const u8 };
|
||||
Some(unsafe { std::slice::from_raw_parts(data_ptr, length) })
|
||||
Some(unsafe { std::slice::from_raw_parts(data_ptr, length as usize) })
|
||||
}
|
||||
pub fn string(&self) -> Option<&'a Mutf8Str> {
|
||||
let (kind, value) = self.element();
|
||||
if kind != TapeTagKind::String {
|
||||
return None;
|
||||
}
|
||||
let length_ptr = unsafe { u64::from(value.string) as usize as *const UnalignedU16 };
|
||||
let length = unsafe { u16::from(*length_ptr).swap_bytes() as usize };
|
||||
let el = self.element();
|
||||
ensure_kind(el, TapeTagKind::String)?;
|
||||
let length_ptr = el.ptr::<UnalignedU16>();
|
||||
let length = u16::from(unsafe { *length_ptr });
|
||||
#[cfg(target_endian = "little")]
|
||||
let length = length.swap_bytes();
|
||||
let data_ptr = unsafe { length_ptr.add(1) as *const u8 };
|
||||
Some(unsafe { Mutf8Str::from_slice(std::slice::from_raw_parts(data_ptr, length)) })
|
||||
Some(unsafe { Mutf8Str::from_slice(std::slice::from_raw_parts(data_ptr, length as usize)) })
|
||||
}
|
||||
pub fn list(&self) -> Option<NbtList<'a, 'tape>> {
|
||||
let (kind, _) = self.element();
|
||||
if !kind.is_list() {
|
||||
let el = self.element();
|
||||
if !el.kind().is_list() {
|
||||
return None;
|
||||
}
|
||||
|
||||
|
@ -445,10 +427,8 @@ impl<'a: 'tape, 'tape> NbtTag<'a, 'tape> {
|
|||
})
|
||||
}
|
||||
pub fn compound(&self) -> Option<NbtCompound<'a, 'tape>> {
|
||||
let (kind, _) = self.element();
|
||||
if kind != TapeTagKind::Compound {
|
||||
return None;
|
||||
}
|
||||
let el = self.element();
|
||||
ensure_kind(el, TapeTagKind::Compound)?;
|
||||
|
||||
Some(NbtCompound {
|
||||
element: self.element,
|
||||
|
@ -462,15 +442,15 @@ impl<'a: 'tape, 'tape> NbtTag<'a, 'tape> {
|
|||
list::u32_prefixed_list_to_vec(TapeTagKind::LongArray, self.element)
|
||||
}
|
||||
|
||||
/// Get the tape element kind and value for this tag.
|
||||
fn element(&self) -> (TapeTagKind, TapeTagValue) {
|
||||
unsafe { (*self.element).kind }
|
||||
/// Get the tape element for this tag.
|
||||
fn element(&self) -> TapeElement {
|
||||
unsafe { *self.element }
|
||||
}
|
||||
|
||||
pub fn to_owned(&self) -> crate::owned::NbtTag {
|
||||
let (kind, _value) = self.element();
|
||||
let el = self.element();
|
||||
|
||||
match kind {
|
||||
match el.kind() {
|
||||
TapeTagKind::Byte => crate::owned::NbtTag::Byte(self.byte().unwrap()),
|
||||
TapeTagKind::Short => crate::owned::NbtTag::Short(self.short().unwrap()),
|
||||
TapeTagKind::Int => crate::owned::NbtTag::Int(self.int().unwrap()),
|
||||
|
@ -484,7 +464,7 @@ impl<'a: 'tape, 'tape> NbtTag<'a, 'tape> {
|
|||
TapeTagKind::Compound => {
|
||||
crate::owned::NbtTag::Compound(self.compound().unwrap().to_owned())
|
||||
}
|
||||
_ if kind.is_list() => crate::owned::NbtTag::List(self.list().unwrap().to_owned()),
|
||||
kind if kind.is_list() => crate::owned::NbtTag::List(self.list().unwrap().to_owned()),
|
||||
TapeTagKind::IntArray => crate::owned::NbtTag::IntArray(self.int_array().unwrap()),
|
||||
TapeTagKind::LongArray => crate::owned::NbtTag::LongArray(self.long_array().unwrap()),
|
||||
_ => unreachable!(),
|
||||
|
@ -492,14 +472,22 @@ impl<'a: 'tape, 'tape> NbtTag<'a, 'tape> {
|
|||
}
|
||||
}
|
||||
|
||||
fn ensure_kind(el: TapeElement, other: TapeTagKind) -> Option<()> {
|
||||
if el.kind() != other {
|
||||
return None;
|
||||
} else {
|
||||
Some(())
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for NbtTag<'_, '_> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
let (self_kind, _) = self.element();
|
||||
let (other_kind, _) = other.element();
|
||||
if self_kind != other_kind {
|
||||
let self_el = self.element();
|
||||
let other_el = other.element();
|
||||
if self_el.kind() != other_el.kind() {
|
||||
return false;
|
||||
}
|
||||
match self_kind {
|
||||
match self_el.kind() {
|
||||
TapeTagKind::Byte => self.byte().unwrap() == other.byte().unwrap(),
|
||||
TapeTagKind::Short => self.short().unwrap() == other.short().unwrap(),
|
||||
TapeTagKind::Int => self.int().unwrap() == other.int().unwrap(),
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
use std::fmt::{self, Debug};
|
||||
use std::{
|
||||
fmt::{self, Debug},
|
||||
mem,
|
||||
};
|
||||
|
||||
use crate::common::{
|
||||
BYTE_ARRAY_ID, BYTE_ID, COMPOUND_ID, DOUBLE_ID, FLOAT_ID, INT_ARRAY_ID, INT_ID, LONG_ARRAY_ID,
|
||||
|
@ -39,41 +42,77 @@ impl Default for MainTape {
|
|||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
#[repr(C)]
|
||||
pub union TapeElement {
|
||||
pub kind: (TapeTagKind, TapeTagValue),
|
||||
pub struct TapeElement(u64);
|
||||
|
||||
pub long: i64,
|
||||
pub double: f64,
|
||||
impl TapeElement {
|
||||
pub fn kind(self) -> TapeTagKind {
|
||||
let kind_id = (self.0 >> 56) as u8;
|
||||
unsafe { mem::transmute::<u8, TapeTagKind>(kind_id) }
|
||||
}
|
||||
pub fn u8(self) -> u8 {
|
||||
self.0 as u8
|
||||
}
|
||||
pub fn u16(self) -> u16 {
|
||||
self.0 as u16
|
||||
}
|
||||
pub fn u32(self) -> u32 {
|
||||
self.0 as u32
|
||||
}
|
||||
pub fn u64(self) -> u64 {
|
||||
self.0
|
||||
}
|
||||
|
||||
pub name: u64, // pointer to the original data
|
||||
pub fn approx_len_and_offset(self) -> (u32, u32) {
|
||||
((self.0 >> 32) as u32 & 0xff_ffff, self.0 as u32)
|
||||
}
|
||||
pub fn ptr<T>(self) -> *const T {
|
||||
(self.0 & 0xff_ffff_ffff_ffff) as *const T
|
||||
}
|
||||
|
||||
pub fn new_with_approx_len_and_offset(kind: TapeTagKind, approx_len: u32, offset: u32) -> Self {
|
||||
debug_assert!(approx_len < 2u32.pow(24));
|
||||
Self((kind as u64) << 56 | (approx_len as u64) << 32 | (offset as u64))
|
||||
}
|
||||
pub fn set_offset(&mut self, offset: u32) {
|
||||
*self = Self::new_with_approx_len_and_offset(
|
||||
self.kind(),
|
||||
self.approx_len_and_offset().0,
|
||||
offset,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn new_with_u8(kind: TapeTagKind, u8: u8) -> Self {
|
||||
Self((kind as u64) << 56 | u8 as u64)
|
||||
}
|
||||
pub fn new_with_u16(kind: TapeTagKind, u16: u16) -> Self {
|
||||
Self((kind as u64) << 56 | u16 as u64)
|
||||
}
|
||||
pub fn new_with_u32(kind: TapeTagKind, u32: u32) -> Self {
|
||||
Self((kind as u64) << 56 | u32 as u64)
|
||||
}
|
||||
pub fn new_with_ptr<T>(kind: TapeTagKind, ptr: *const T) -> Self {
|
||||
Self((kind as u64) << 56 | ptr as u64)
|
||||
}
|
||||
/// Create a new TapeElement with the given kind and everything else set to 0.
|
||||
pub fn new_with_0(kind: TapeTagKind) -> Self {
|
||||
Self((kind as u64) << 56)
|
||||
}
|
||||
pub fn new(u64: u64) -> Self {
|
||||
Self(u64)
|
||||
}
|
||||
}
|
||||
|
||||
impl TapeElement {
|
||||
/// Returns how much we should increment the tape index to get to the next tag.
|
||||
///
|
||||
/// # Safety
|
||||
/// The element must be a tag and not something else like a continuation of a long or double.
|
||||
pub unsafe fn skip_offset(&self) -> usize {
|
||||
match self.kind {
|
||||
(TapeTagKind::Long | TapeTagKind::Double, _) => 2,
|
||||
(
|
||||
TapeTagKind::Compound,
|
||||
TapeTagValue {
|
||||
compound: (_, offset),
|
||||
},
|
||||
) => u32::from(offset) as usize,
|
||||
(
|
||||
TapeTagKind::ListList,
|
||||
TapeTagValue {
|
||||
list_list: (_, offset),
|
||||
},
|
||||
) => u32::from(offset) as usize,
|
||||
(
|
||||
TapeTagKind::CompoundList,
|
||||
TapeTagValue {
|
||||
compound_list: (_, offset),
|
||||
},
|
||||
) => u32::from(offset) as usize,
|
||||
match self.kind() {
|
||||
TapeTagKind::Long | TapeTagKind::Double => 2,
|
||||
TapeTagKind::Compound | TapeTagKind::ListList | TapeTagKind::CompoundList => {
|
||||
self.approx_len_and_offset().1 as usize
|
||||
}
|
||||
_ => 1,
|
||||
}
|
||||
}
|
||||
|
@ -81,42 +120,11 @@ impl TapeElement {
|
|||
impl Debug for TapeElement {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
// just writes the u64
|
||||
write!(f, "TapeElement({:#016x})", unsafe { self.name })?;
|
||||
write!(f, "TapeElement({:#016x})", self.0)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C, packed)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub union TapeTagValue {
|
||||
pub byte: i8,
|
||||
pub short: i16,
|
||||
pub int: i32,
|
||||
pub long: (), // value is in next tape element
|
||||
pub float: f32,
|
||||
pub double: (), // value is in next tape element
|
||||
pub byte_array: u56, // pointer to the original data
|
||||
pub string: u56, // pointer to the original data
|
||||
pub compound: (u24, UnalignedU32), // length estimate + tape index offset to the end of the compound
|
||||
pub int_array: u56, // pointer to the original data
|
||||
pub long_array: u56, // pointer to the original data
|
||||
|
||||
// lists
|
||||
pub empty_list: (),
|
||||
pub byte_list: u56, // pointer to the original data
|
||||
pub short_list: u56, // pointer to the original data
|
||||
pub int_list: u56, // pointer to the original data
|
||||
pub long_list: u56, // pointer to the original data
|
||||
pub float_list: u56, // pointer to the original data
|
||||
pub double_list: u56, // pointer to the original data
|
||||
pub byte_array_list: (u24, UnalignedU32), // padding + index to ExtraTapes which has a fat pointer that points to the original data
|
||||
pub string_list: (u24, UnalignedU32), // padding + index to ExtraTapes
|
||||
pub list_list: (u24, UnalignedU32), // length estimate + tape index offset to the end of the list
|
||||
pub compound_list: (u24, UnalignedU32), // length estimate + tape index offset to the end of the list
|
||||
pub int_array_list: (u24, UnalignedU32), // padding + index to ExtraTapes
|
||||
pub long_array_list: (u24, UnalignedU32), // padding + index to ExtraTapes
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[repr(packed)]
|
||||
#[allow(non_camel_case_types)]
|
||||
|
|
|
@ -39,7 +39,7 @@ pub trait ToNbtTag: Sized {
|
|||
|
||||
impl<K: Display + FromStr + Eq + Hash, V: FromNbtTag> Deserialize for HashMap<K, V> {
|
||||
fn from_compound(compound: crate::borrow::NbtCompound) -> Result<Self, DeserializeError> {
|
||||
let mut hashmap = HashMap::with_capacity(compound.approx_len());
|
||||
let mut hashmap = HashMap::with_capacity(compound.approx_len() as usize);
|
||||
|
||||
for (k, v) in compound.iter() {
|
||||
let k_str = k.to_str();
|
||||
|
@ -277,7 +277,7 @@ impl<T: Deserialize> FromNbtTag for Vec<Option<T>> {
|
|||
fn from_nbt_tag(tag: crate::borrow::NbtTag) -> Option<Self> {
|
||||
let list = tag.list()?;
|
||||
let list = list.compounds()?;
|
||||
let mut vec = Vec::with_capacity(list.approx_len());
|
||||
let mut vec = Vec::with_capacity(list.approx_len() as usize);
|
||||
for tag in list {
|
||||
if tag.is_empty() {
|
||||
vec.push(None);
|
||||
|
@ -306,7 +306,7 @@ impl<T: Deserialize> FromNbtTag for Vec<T> {
|
|||
fn from_nbt_tag(tag: crate::borrow::NbtTag) -> Option<Self> {
|
||||
let list = tag.list()?;
|
||||
let list = list.compounds()?;
|
||||
let mut vec = Vec::with_capacity(list.approx_len());
|
||||
let mut vec = Vec::with_capacity(list.approx_len() as usize);
|
||||
for tag in list {
|
||||
vec.push(T::from_compound(tag).ok()?);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue