mirror of
https://github.com/azalea-rs/simdnbt.git
synced 2025-08-02 07:26:04 +00:00
add rustfmt.toml for comment wrapping and import sorting
This commit is contained in:
parent
acb56cd97a
commit
47131f4d9e
16 changed files with 116 additions and 93 deletions
2
rustfmt.toml
Normal file
2
rustfmt.toml
Normal file
|
@ -0,0 +1,2 @@
|
|||
wrap_comments = true
|
||||
group_imports = "StdExternalCrate"
|
|
@ -127,7 +127,8 @@ fn simdnbt_items_from_nbt(nbt: simdnbt::borrow::BaseNbt) -> Option<Vec<Option<It
|
|||
.and_then(|textures| textures.compounds())
|
||||
.and_then(|textures| textures.first())
|
||||
.and_then(|texture| texture.string("Value"))
|
||||
// the real program does some base64+json decoding here but that's unnecessary for the benchmark
|
||||
// the real program does some base64+json decoding here but that's unnecessary for
|
||||
// the benchmark
|
||||
.map(|value| value.to_string()),
|
||||
skyblock_id: item_extra_attributes
|
||||
.and_then(|e| e.string("id"))
|
||||
|
@ -300,7 +301,8 @@ fn graphite_items_from_nbt(nbt: graphite_binary::nbt::NBT) -> Option<Vec<Option<
|
|||
.and_then(|properties| nbt.find(properties, "textures"))
|
||||
.and_then(|textures| nbt.iter(textures)?.next())
|
||||
.and_then(|texture| nbt.find(texture, "Value"))
|
||||
// the real program does some base64+json decoding here but that's unnecessary for the benchmark
|
||||
// the real program does some base64+json decoding here but that's unnecessary for
|
||||
// the benchmark
|
||||
.and_then(|value| value.as_string().cloned()),
|
||||
skyblock_id: item_extra_attributes
|
||||
.and_then(|e| nbt.find(e, "id"))
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
use criterion::{black_box, criterion_group, criterion_main, Criterion, Throughput};
|
||||
use flate2::read::GzDecoder;
|
||||
use std::{
|
||||
fs::File,
|
||||
io::{Cursor, Read},
|
||||
};
|
||||
|
||||
use criterion::{black_box, criterion_group, criterion_main, Criterion, Throughput};
|
||||
use flate2::read::GzDecoder;
|
||||
|
||||
fn bench_file(filename: &str, c: &mut Criterion) {
|
||||
let mut file = File::open(format!("tests/{filename}")).unwrap();
|
||||
let mut contents = Vec::new();
|
||||
|
|
|
@ -59,7 +59,8 @@ fn items_from_nbt(nbt: BaseNbt) -> Option<Vec<Option<Item>>> {
|
|||
.and_then(|textures| textures.compounds())
|
||||
.and_then(|textures| textures.first())
|
||||
.and_then(|texture| texture.string("Value"))
|
||||
// the real program does some base64+json decoding here but that's unnecessary for the benchmark
|
||||
// the real program does some base64+json decoding here but that's unnecessary for
|
||||
// the benchmark
|
||||
.map(|value| value.to_string()),
|
||||
skyblock_id: item_extra_attributes
|
||||
.and_then(|e| e.string("id"))
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
use std::mem::MaybeUninit;
|
||||
|
||||
use super::{
|
||||
extra_tapes::ExtraTapes,
|
||||
list::{self, NbtList},
|
||||
tape::{TapeElement, TapeTagKind, UnalignedU16},
|
||||
NbtTag, Tapes,
|
||||
};
|
||||
use crate::{
|
||||
common::{
|
||||
extend_unchecked, push_unchecked, read_int_array, read_long_array, read_string,
|
||||
|
@ -12,13 +18,6 @@ use crate::{
|
|||
Mutf8Str,
|
||||
};
|
||||
|
||||
use super::{
|
||||
extra_tapes::ExtraTapes,
|
||||
list::{self, NbtList},
|
||||
tape::{TapeElement, TapeTagKind, UnalignedU16},
|
||||
NbtTag, Tapes,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct NbtCompound<'a: 'tape, 'tape> {
|
||||
pub(crate) element: *const TapeElement, // includes the initial compound element
|
||||
|
@ -51,8 +50,8 @@ impl<'a: 'tape, 'tape> NbtCompound<'a, 'tape> {
|
|||
for (name, tag) in self.iter() {
|
||||
// reserve 4 bytes extra so we can avoid reallocating for small tags
|
||||
data.reserve(1 + 2 + name.len() + 4);
|
||||
// SAFETY: We just reserved enough space for the tag ID, the name length, the name, and
|
||||
// 4 bytes of tag data.
|
||||
// SAFETY: We just reserved enough space for the tag ID, the name length, the
|
||||
// name, and 4 bytes of tag data.
|
||||
unsafe {
|
||||
push_unchecked(data, tag.id());
|
||||
write_string_unchecked(data, name);
|
||||
|
|
|
@ -14,8 +14,8 @@ impl Debug for ExtraTapes<'_> {
|
|||
}
|
||||
|
||||
pub union ExtraTapeElement<'a> {
|
||||
/// An indicator for how long the following list is. This is what we point to from
|
||||
/// `TapeTagValue`.
|
||||
/// An indicator for how long the following list is. This is what we point
|
||||
/// to from `TapeTagValue`.
|
||||
pub length: u32,
|
||||
pub byte_array: &'a [u8],
|
||||
pub string: &'a Mutf8Str,
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
use std::{marker::PhantomData, mem};
|
||||
|
||||
use super::{
|
||||
compound::{ParsingStack, ParsingStackElement},
|
||||
extra_tapes::{ExtraTapeElement, ExtraTapes},
|
||||
tape::{TapeElement, TapeTagKind, UnalignedU32},
|
||||
NbtCompound, Tapes,
|
||||
};
|
||||
use crate::{
|
||||
common::{
|
||||
read_i8_array, read_int_array, read_long_array, read_string, read_u8_array,
|
||||
|
@ -14,13 +20,6 @@ use crate::{
|
|||
Mutf8Str,
|
||||
};
|
||||
|
||||
use super::{
|
||||
compound::{ParsingStack, ParsingStackElement},
|
||||
extra_tapes::{ExtraTapeElement, ExtraTapes},
|
||||
tape::{TapeElement, TapeTagKind, UnalignedU32},
|
||||
NbtCompound, Tapes,
|
||||
};
|
||||
|
||||
/// A list of NBT tags of a single type.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct NbtList<'a: 'tape, 'tape> {
|
||||
|
@ -281,8 +280,9 @@ 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).
|
||||
/// 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().kind() == TapeTagKind::EmptyList
|
||||
}
|
||||
|
@ -365,10 +365,12 @@ impl<'a, 'tape> NbtList<'a, 'tape> {
|
|||
|
||||
Some(NbtListList {
|
||||
iter: NbtListListIter {
|
||||
current_tape_offset: 0, // it's an iterator, it starts at 0
|
||||
// it's an iterator, it starts at 0
|
||||
current_tape_offset: 0,
|
||||
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
|
||||
// the first element is the listlist element so we don't include it
|
||||
tape: unsafe { self.element.add(1) },
|
||||
extra_tapes: self.extra_tapes,
|
||||
_phantom: PhantomData,
|
||||
},
|
||||
|
@ -546,8 +548,9 @@ impl<'a, 'tape> NbtListList<'a, 'tape> {
|
|||
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
|
||||
/// this more than once you should probably just use the iterator.
|
||||
/// Get the element at the given index. This is O(n) where n is index, so if
|
||||
/// you'll be calling this more than once you should probably just use
|
||||
/// the iterator.
|
||||
pub fn get(&self, index: usize) -> Option<NbtList<'a, 'tape>> {
|
||||
self.iter.clone().nth(index)
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
//! The borrowed variant of NBT. This is useful if you're only reading data and you can keep a reference to the original buffer.
|
||||
//! The borrowed variant of NBT. This is useful if you're only reading data and
|
||||
//! you can keep a reference to the original buffer.
|
||||
|
||||
mod compound;
|
||||
mod extra_tapes;
|
||||
|
@ -14,15 +15,6 @@ use byteorder::ReadBytesExt;
|
|||
use compound::ParsingStackElementKind;
|
||||
use tape::{UnalignedU16, UnalignedU32, UnalignedU64};
|
||||
|
||||
use crate::{
|
||||
common::{
|
||||
read_string, write_string, BYTE_ARRAY_ID, BYTE_ID, COMPOUND_ID, DOUBLE_ID, END_ID,
|
||||
FLOAT_ID, INT_ARRAY_ID, INT_ID, LIST_ID, LONG_ARRAY_ID, LONG_ID, SHORT_ID, STRING_ID,
|
||||
},
|
||||
reader::{Reader, ReaderFromCursor},
|
||||
Error, Mutf8Str,
|
||||
};
|
||||
|
||||
use self::{
|
||||
compound::{read_tag_in_compound, ParsingStack, ParsingStackElement},
|
||||
extra_tapes::ExtraTapes,
|
||||
|
@ -33,8 +25,17 @@ pub use self::{
|
|||
compound::{NbtCompound, NbtCompoundIter},
|
||||
list::{NbtCompoundList, NbtCompoundListIter, NbtList, NbtListList, NbtListListIter},
|
||||
};
|
||||
use crate::{
|
||||
common::{
|
||||
read_string, write_string, BYTE_ARRAY_ID, BYTE_ID, COMPOUND_ID, DOUBLE_ID, END_ID,
|
||||
FLOAT_ID, INT_ARRAY_ID, INT_ID, LIST_ID, LONG_ARRAY_ID, LONG_ID, SHORT_ID, STRING_ID,
|
||||
},
|
||||
reader::{Reader, ReaderFromCursor},
|
||||
Error, Mutf8Str,
|
||||
};
|
||||
|
||||
/// Read a normal root NBT compound. This is either empty or has a name and compound tag.
|
||||
/// Read a normal root NBT compound. This is either empty or has a name and
|
||||
/// compound tag.
|
||||
///
|
||||
/// Returns `Ok(Nbt::None)` if there is no data.
|
||||
pub fn read<'a>(data: &mut Cursor<&'a [u8]>) -> Result<Nbt<'a>, Error> {
|
||||
|
@ -63,11 +64,11 @@ pub fn read<'a>(data: &mut Cursor<&'a [u8]>) -> Result<Nbt<'a>, Error> {
|
|||
|
||||
Ok(Nbt::Some(BaseNbt { name, tapes }))
|
||||
}
|
||||
/// Read a root NBT compound, but without reading the name. This is used in Minecraft when reading
|
||||
/// NBT over the network.
|
||||
/// Read a root NBT compound, but without reading the name. This is used in
|
||||
/// Minecraft when reading NBT over the network.
|
||||
///
|
||||
/// This is similar to [`read_tag`], but returns an [`Nbt`] instead (guaranteeing it'll be either
|
||||
/// empty or a compound).
|
||||
/// This is similar to [`read_tag`], but returns an [`Nbt`] instead
|
||||
/// (guaranteeing it'll be either empty or a compound).
|
||||
pub fn read_unnamed<'a>(data: &mut Cursor<&'a [u8]>) -> Result<Nbt<'a>, Error> {
|
||||
let root_type = data.read_u8().map_err(|_| Error::UnexpectedEof)?;
|
||||
if root_type == END_ID {
|
||||
|
@ -100,8 +101,9 @@ pub fn read_compound<'a>(data: &mut Cursor<&'a [u8]>) -> Result<BaseNbtCompound<
|
|||
|
||||
Ok(BaseNbtCompound { tapes })
|
||||
}
|
||||
/// Read an NBT tag, without reading its name. This may be any type of tag except for an end tag. If you need to be able to
|
||||
/// handle end tags, use [`read_optional_tag`].
|
||||
/// Read an NBT tag, without reading its name. This may be any type of tag
|
||||
/// except for an end tag. If you need to be able to handle end tags, use
|
||||
/// [`read_optional_tag`].
|
||||
pub fn read_tag<'a>(data: &mut Cursor<&'a [u8]>) -> Result<BaseNbtTag<'a>, Error> {
|
||||
let mut tapes = Tapes::new();
|
||||
let mut stack = ParsingStack::new();
|
||||
|
@ -117,7 +119,8 @@ pub fn read_tag<'a>(data: &mut Cursor<&'a [u8]>) -> Result<BaseNbtTag<'a>, Error
|
|||
|
||||
Ok(BaseNbtTag { tapes })
|
||||
}
|
||||
/// Read any NBT tag, without reading its name. This may be any type of tag, including an end tag.
|
||||
/// Read any NBT tag, without reading its name. This may be any type of tag,
|
||||
/// including an end tag.
|
||||
///
|
||||
/// Returns `Ok(None)` if there is no data.
|
||||
pub fn read_optional_tag<'a>(data: &mut Cursor<&'a [u8]>) -> Result<Option<BaseNbtTag<'a>>, Error> {
|
||||
|
@ -242,8 +245,8 @@ impl Debug for BaseNbt<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
/// A nameless NBT container. This only contains a compound tag. This contains a `TagAllocator`,
|
||||
/// so it can exist independently from a [`BaseNbt`].
|
||||
/// A nameless NBT container. This only contains a compound tag. This contains a
|
||||
/// `TagAllocator`, so it can exist independently from a [`BaseNbt`].
|
||||
pub struct BaseNbtCompound<'a> {
|
||||
tapes: Tapes<'a>,
|
||||
}
|
||||
|
@ -710,14 +713,16 @@ mod tests {
|
|||
#[test]
|
||||
fn list_of_empty_lists() {
|
||||
// found from fuzzing
|
||||
// BaseNbt { name: m"", tag: NbtTag::NbtCompound { m"": NbtTag::List(List::List([List::Empty])) } }
|
||||
// BaseNbt { name: m"", tag: NbtTag::NbtCompound { m"":
|
||||
// NbtTag::List(List::List([List::Empty])) } }
|
||||
let data = [10, 0, 0, 9, 0, 0, 9, 0, 0, 0, 1, 0, 9, 0, 0, 0, 0];
|
||||
let nbt = super::read(&mut Cursor::new(&data)).unwrap().unwrap();
|
||||
nbt.as_compound().to_owned();
|
||||
}
|
||||
#[test]
|
||||
fn list_of_byte_arrays() {
|
||||
// BaseNbt { name: m"", tag: NbtCompound { values: [(m"", List(List([List::ByteArray([])])))] } }
|
||||
// BaseNbt { name: m"", tag: NbtCompound { values: [(m"",
|
||||
// List(List([List::ByteArray([])])))] } }
|
||||
let data = [10, 0, 0, 9, 0, 0, 9, 0, 0, 0, 1, 7, 0, 0, 0, 0, 0];
|
||||
let nbt = super::read(&mut Cursor::new(&data)).unwrap().unwrap();
|
||||
nbt.as_compound().to_owned();
|
||||
|
|
|
@ -166,7 +166,8 @@ impl TapeElement {
|
|||
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.
|
||||
/// 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)
|
||||
}
|
||||
|
@ -176,10 +177,12 @@ impl TapeElement {
|
|||
}
|
||||
|
||||
impl TapeElement {
|
||||
/// Returns how much we should increment the tape index to get to the next tag.
|
||||
/// 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.
|
||||
/// 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::Compound | TapeTagKind::ListList | TapeTagKind::CompoundList => {
|
||||
|
|
|
@ -95,18 +95,21 @@ pub fn write_string(data: &mut Vec<u8>, value: &Mutf8Str) {
|
|||
}
|
||||
}
|
||||
/// Write a string to a Vec<u8> without checking if the Vec has enough capacity.
|
||||
/// This is unsafe because it can cause a buffer overflow if the Vec doesn't have enough capacity.
|
||||
/// This is unsafe because it can cause a buffer overflow if the Vec doesn't
|
||||
/// have enough capacity.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// You must reserve enough capacity (2 + value.len()) in the Vec before calling this function.
|
||||
/// You must reserve enough capacity (2 + value.len()) in the Vec before calling
|
||||
/// this function.
|
||||
#[inline]
|
||||
pub unsafe fn write_string_unchecked(data: &mut Vec<u8>, value: &Mutf8Str) {
|
||||
extend_unchecked(data, &(value.len() as u16).to_be_bytes());
|
||||
extend_unchecked(data, value.as_bytes());
|
||||
}
|
||||
|
||||
/// Extend a Vec<u8> with a slice of u8 without checking if the Vec has enough capacity.
|
||||
/// Extend a Vec<u8> with a slice of u8 without checking if the Vec has enough
|
||||
/// capacity.
|
||||
///
|
||||
/// This optimization is barely measurable, but it does make it slightly faster!
|
||||
///
|
||||
|
@ -129,15 +132,16 @@ pub unsafe fn push_unchecked(data: &mut Vec<u8>, value: u8) {
|
|||
data.set_len(len + 1);
|
||||
}
|
||||
|
||||
/// Convert a slice of any type into a slice of u8. This will probably return the data as little
|
||||
/// endian! Use [`slice_into_u8_big_endian`] to get big endian (the endianness that's used in NBT).
|
||||
/// Convert a slice of any type into a slice of u8. This will probably return
|
||||
/// the data as little endian! Use [`slice_into_u8_big_endian`] to get big
|
||||
/// endian (the endianness that's used in NBT).
|
||||
#[inline]
|
||||
pub fn slice_into_u8_native_endian<T>(s: &[T]) -> &[u8] {
|
||||
unsafe { slice::from_raw_parts(s.as_ptr() as *const u8, mem::size_of_val(s)) }
|
||||
}
|
||||
|
||||
/// Convert a slice of any type into a Vec<u8>. This will return the data as big endian (the
|
||||
/// endianness that's used in NBT).
|
||||
/// Convert a slice of any type into a Vec<u8>. This will return the data as big
|
||||
/// endian (the endianness that's used in NBT).
|
||||
#[inline]
|
||||
pub fn slice_into_u8_big_endian<T: SwappableNumber>(s: &[T]) -> Vec<u8> {
|
||||
swap_endianness_as_u8::<T>(slice_into_u8_native_endian(s))
|
||||
|
|
|
@ -20,9 +20,8 @@ mod traits;
|
|||
|
||||
pub use error::{DeserializeError, Error};
|
||||
pub use mutf8::Mutf8Str;
|
||||
pub use traits::{Deserialize, FromNbtTag, Serialize, ToNbtTag};
|
||||
|
||||
pub use simdnbt_derive::*;
|
||||
pub use traits::{Deserialize, FromNbtTag, Serialize, ToNbtTag};
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
|
|
@ -9,7 +9,8 @@ use std::{
|
|||
|
||||
use simd_cesu8::mutf8;
|
||||
|
||||
/// A MUTF-8 string slice. This is how strings are represented internally in NBT.
|
||||
/// A MUTF-8 string slice. This is how strings are represented internally in
|
||||
/// NBT.
|
||||
#[derive(Eq, PartialEq)]
|
||||
pub struct Mutf8Str {
|
||||
pub(crate) slice: [u8],
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use std::mem::{self, MaybeUninit};
|
||||
|
||||
use super::{list::NbtList, NbtTag};
|
||||
use crate::{
|
||||
common::{push_unchecked, read_string, write_string_unchecked, END_ID, MAX_DEPTH},
|
||||
error::NonRootError,
|
||||
|
@ -8,8 +9,6 @@ use crate::{
|
|||
Mutf8Str, ToNbtTag,
|
||||
};
|
||||
|
||||
use super::{list::NbtList, NbtTag};
|
||||
|
||||
/// A list of named tags. The order of the tags is preserved.
|
||||
#[derive(Debug, Default, Clone, PartialEq)]
|
||||
pub struct NbtCompound {
|
||||
|
@ -81,8 +80,8 @@ impl NbtCompound {
|
|||
for (name, tag) in &self.values {
|
||||
// reserve 4 bytes extra so we can avoid reallocating for small tags
|
||||
data.reserve(1 + 2 + name.len() + 4);
|
||||
// SAFETY: We just reserved enough space for the tag ID, the name length, the name, and
|
||||
// 4 bytes of tag data.
|
||||
// SAFETY: We just reserved enough space for the tag ID, the name length, the
|
||||
// name, and 4 bytes of tag data.
|
||||
unsafe {
|
||||
push_unchecked(data, tag.id());
|
||||
write_string_unchecked(data, name);
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
use super::{compound::NbtCompound, MAX_DEPTH};
|
||||
use crate::{
|
||||
common::{
|
||||
read_i8_array, read_int_array, read_long_array, read_string, read_u8_array,
|
||||
read_with_u32_length, slice_i8_into_u8, slice_into_u8_big_endian, extend_unchecked,
|
||||
push_unchecked, write_string, write_u32, write_with_u32_length, BYTE_ARRAY_ID, BYTE_ID,
|
||||
COMPOUND_ID, DOUBLE_ID, END_ID, FLOAT_ID, INT_ARRAY_ID, INT_ID, LIST_ID, LONG_ARRAY_ID,
|
||||
LONG_ID, SHORT_ID, STRING_ID,
|
||||
extend_unchecked, push_unchecked, read_i8_array, read_int_array, read_long_array,
|
||||
read_string, read_u8_array, read_with_u32_length, slice_i8_into_u8,
|
||||
slice_into_u8_big_endian, write_string, write_u32, write_with_u32_length, BYTE_ARRAY_ID,
|
||||
BYTE_ID, COMPOUND_ID, DOUBLE_ID, END_ID, FLOAT_ID, INT_ARRAY_ID, INT_ID, LIST_ID,
|
||||
LONG_ARRAY_ID, LONG_ID, SHORT_ID, STRING_ID,
|
||||
},
|
||||
error::NonRootError,
|
||||
mutf8::Mutf8String,
|
||||
|
@ -12,8 +13,6 @@ use crate::{
|
|||
swap_endianness::swap_endianness,
|
||||
};
|
||||
|
||||
use super::{compound::NbtCompound, MAX_DEPTH};
|
||||
|
||||
/// A list of NBT tags of a single type.
|
||||
#[repr(u8)]
|
||||
#[derive(Debug, Default, Clone, PartialEq)]
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
//! The owned variant of NBT. This is useful if you're writing NBT or if you can't keep a reference
|
||||
//! to the original data.
|
||||
//! The owned variant of NBT. This is useful if you're writing NBT or if you
|
||||
//! can't keep a reference to the original data.
|
||||
|
||||
mod compound;
|
||||
mod list;
|
||||
|
||||
use std::{io::Cursor, ops::Deref};
|
||||
|
||||
pub use self::{compound::NbtCompound, list::NbtList};
|
||||
use crate::{
|
||||
common::{
|
||||
extend_unchecked, push_unchecked, read_int_array, read_long_array, read_string,
|
||||
|
@ -19,20 +20,19 @@ use crate::{
|
|||
Error, Mutf8Str,
|
||||
};
|
||||
|
||||
pub use self::{compound::NbtCompound, list::NbtList};
|
||||
|
||||
/// Read a normal root NBT compound. This is either empty or has a name and compound tag.
|
||||
/// Read a normal root NBT compound. This is either empty or has a name and
|
||||
/// compound tag.
|
||||
///
|
||||
/// Returns `Ok(Nbt::None)` if there is no data.
|
||||
pub fn read(data: &mut Cursor<&[u8]>) -> Result<Nbt, Error> {
|
||||
let mut reader = ReaderFromCursor::new(data);
|
||||
Nbt::read(&mut reader)
|
||||
}
|
||||
/// Read a root NBT compound, but without reading the name. This is used in Minecraft when reading
|
||||
/// NBT over the network.
|
||||
/// Read a root NBT compound, but without reading the name. This is used in
|
||||
/// Minecraft when reading NBT over the network.
|
||||
///
|
||||
/// This is similar to [`read_tag`], but returns an [`Nbt`] instead (guaranteeing it'll be either
|
||||
/// empty or a compound).
|
||||
/// This is similar to [`read_tag`], but returns an [`Nbt`] instead
|
||||
/// (guaranteeing it'll be either empty or a compound).
|
||||
pub fn read_unnamed(data: &mut Cursor<&[u8]>) -> Result<Nbt, Error> {
|
||||
let mut reader = ReaderFromCursor::new(data);
|
||||
Nbt::read_unnamed(&mut reader)
|
||||
|
@ -42,13 +42,15 @@ pub fn read_compound(data: &mut Cursor<&[u8]>) -> Result<NbtCompound, NonRootErr
|
|||
let mut reader = ReaderFromCursor::new(data);
|
||||
NbtCompound::read(&mut reader)
|
||||
}
|
||||
/// Read an NBT tag, without reading its name. This may be any type of tag except for an end tag. If you need to be able to
|
||||
/// handle end tags, use [`read_optional_tag`].
|
||||
/// Read an NBT tag, without reading its name. This may be any type of tag
|
||||
/// except for an end tag. If you need to be able to handle end tags, use
|
||||
/// [`read_optional_tag`].
|
||||
pub fn read_tag(data: &mut Cursor<&[u8]>) -> Result<NbtTag, NonRootError> {
|
||||
let mut reader = ReaderFromCursor::new(data);
|
||||
NbtTag::read(&mut reader)
|
||||
}
|
||||
/// Read any NBT tag, without reading its name. This may be any type of tag, including an end tag.
|
||||
/// Read any NBT tag, without reading its name. This may be any type of tag,
|
||||
/// including an end tag.
|
||||
///
|
||||
/// Returns `Ok(None)` if there is no data.
|
||||
pub fn read_optional_tag(data: &mut Cursor<&[u8]>) -> Result<Option<NbtTag>, NonRootError> {
|
||||
|
@ -75,7 +77,8 @@ impl Nbt {
|
|||
Self::Some(BaseNbt { name, tag })
|
||||
}
|
||||
|
||||
/// Reads NBT from the given data. Returns `Ok(Nbt::None)` if there is no data.
|
||||
/// Reads NBT from the given data. Returns `Ok(Nbt::None)` if there is no
|
||||
/// data.
|
||||
fn read(data: &mut Reader<'_>) -> Result<Nbt, Error> {
|
||||
let root_type = data.read_u8().map_err(|_| Error::UnexpectedEof)?;
|
||||
if root_type == END_ID {
|
||||
|
@ -322,8 +325,9 @@ impl NbtTag {
|
|||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This function is unsafe because it doesn't check that there's enough space in the data.
|
||||
/// 4 bytes MUST be reserved before calling this function.
|
||||
/// This function is unsafe because it doesn't check that there's enough
|
||||
/// space in the data. 4 bytes MUST be reserved before calling this
|
||||
/// function.
|
||||
#[inline]
|
||||
unsafe fn write_without_tag_type_unchecked(&self, data: &mut Vec<u8>) {
|
||||
match self {
|
||||
|
|
|
@ -260,8 +260,8 @@ fn swap_endianness_64bit(bytes: &mut [u8], num: usize) {
|
|||
}
|
||||
}
|
||||
|
||||
/// Swap the endianness of the given array (unless we're on a big-endian system) in-place depending
|
||||
/// on the width of the given type.
|
||||
/// Swap the endianness of the given array (unless we're on a big-endian system)
|
||||
/// in-place depending on the width of the given type.
|
||||
fn swap_endianness_from_type<T: SwappableNumber>(items: &mut [u8]) {
|
||||
let item_width = mem::size_of::<T>();
|
||||
let length = items.len() / item_width;
|
||||
|
@ -298,7 +298,8 @@ pub fn swap_endianness<T: SwappableNumber>(data: &[u8]) -> Vec<T> {
|
|||
let mut vec_u8: Vec<u8> = {
|
||||
let ptr = vec_t.as_mut_ptr() as *mut u8;
|
||||
mem::forget(vec_t);
|
||||
// SAFETY: the new capacity is correct since we checked that data.len() is a multiple of width_of_t
|
||||
// SAFETY: the new capacity is correct since we checked that data.len() is a
|
||||
// multiple of width_of_t
|
||||
unsafe { Vec::from_raw_parts(ptr, 0, data.len()) }
|
||||
};
|
||||
vec_u8.extend_from_slice(data);
|
||||
|
|
Loading…
Add table
Reference in a new issue