mirror of
https://github.com/azalea-rs/simdnbt.git
synced 2025-08-02 07:26:04 +00:00
implement thin slices
This commit is contained in:
parent
39b68ea725
commit
c69dc2300e
14 changed files with 409 additions and 93 deletions
|
@ -7,6 +7,7 @@ use crate::{
|
|||
read_string, unchecked_extend, unchecked_push, unchecked_write_string, write_string,
|
||||
END_ID, MAX_DEPTH,
|
||||
},
|
||||
thin_slices::{Slice16Bit, Slice32Bit},
|
||||
Error, Mutf8Str,
|
||||
};
|
||||
|
||||
|
@ -15,7 +16,7 @@ use super::{list::NbtList, tag_alloc::TagAllocator, NbtTag};
|
|||
/// A list of named tags. The order of the tags is preserved.
|
||||
#[derive(Debug, Default, PartialEq, Clone)]
|
||||
pub struct NbtCompound<'a> {
|
||||
values: &'a [(&'a Mutf8Str, NbtTag<'a>)],
|
||||
values: Slice32Bit<'a, [(Slice16Bit<'a, Mutf8Str>, NbtTag<'a>)]>,
|
||||
}
|
||||
|
||||
impl<'a> NbtCompound<'a> {
|
||||
|
@ -35,7 +36,8 @@ impl<'a> NbtCompound<'a> {
|
|||
let mut tags = alloc.get().named.start(depth);
|
||||
|
||||
let mut tags_buffer = unsafe {
|
||||
MaybeUninit::<[MaybeUninit<(&Mutf8Str, NbtTag<'a>)>; 4]>::uninit().assume_init()
|
||||
MaybeUninit::<[MaybeUninit<(Slice16Bit<Mutf8Str>, NbtTag<'a>)>; 4]>::uninit()
|
||||
.assume_init()
|
||||
};
|
||||
let mut tags_buffer_len: usize = 0;
|
||||
|
||||
|
@ -90,9 +92,9 @@ impl<'a> NbtCompound<'a> {
|
|||
}
|
||||
|
||||
pub fn write(&self, data: &mut Vec<u8>) {
|
||||
for (name, tag) in self.values {
|
||||
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);
|
||||
data.reserve(1 + 2 + name.len() as usize + 4);
|
||||
// SAFETY: We just reserved enough space for the tag ID, the name length, the name, and
|
||||
// 4 bytes of tag data.
|
||||
unsafe {
|
||||
|
@ -154,8 +156,8 @@ impl<'a> NbtCompound<'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 {
|
||||
if key == &name {
|
||||
for (key, value) in &*self.values {
|
||||
if &**key == name {
|
||||
return Some(value);
|
||||
}
|
||||
}
|
||||
|
@ -166,8 +168,8 @@ impl<'a> NbtCompound<'a> {
|
|||
pub fn contains(&self, name: &str) -> bool {
|
||||
let name = Mutf8Str::from_str(name);
|
||||
let name = name.as_ref();
|
||||
for (key, _) in self.values {
|
||||
if key == &name {
|
||||
for (key, _) in &*self.values {
|
||||
if &**key == name {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -212,9 +214,9 @@ impl<'a> NbtCompound<'a> {
|
|||
}
|
||||
|
||||
pub fn iter(&self) -> impl Iterator<Item = (&Mutf8Str, &NbtTag<'a>)> {
|
||||
self.values.iter().map(|(k, v)| (*k, v))
|
||||
self.values.iter().map(|(k, v)| (&**k, v))
|
||||
}
|
||||
pub fn len(&self) -> usize {
|
||||
pub fn len(&self) -> u32 {
|
||||
self.values.len()
|
||||
}
|
||||
pub fn is_empty(&self) -> bool {
|
||||
|
@ -226,7 +228,7 @@ impl<'a> NbtCompound<'a> {
|
|||
values: self
|
||||
.values
|
||||
.iter()
|
||||
.map(|(k, v)| ((*k).to_owned(), v.to_owned()))
|
||||
.map(|(k, v)| ((**k).to_owned(), v.to_owned()))
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ use crate::{
|
|||
FLOAT_ID, INT_ARRAY_ID, INT_ID, LIST_ID, LONG_ARRAY_ID, LONG_ID, SHORT_ID, STRING_ID,
|
||||
},
|
||||
raw_list::RawList,
|
||||
thin_slices::{Slice16Bit, Slice32Bit},
|
||||
Error, Mutf8Str,
|
||||
};
|
||||
|
||||
|
@ -21,18 +22,18 @@ use super::{read_u32, tag_alloc::TagAllocator, NbtCompound, MAX_DEPTH};
|
|||
pub enum NbtList<'a> {
|
||||
#[default]
|
||||
Empty = END_ID,
|
||||
Byte(&'a [i8]) = BYTE_ID,
|
||||
Byte(Slice32Bit<'a, [i8]>) = BYTE_ID,
|
||||
Short(RawList<'a, i16>) = SHORT_ID,
|
||||
Int(RawList<'a, i32>) = INT_ID,
|
||||
Long(RawList<'a, i64>) = LONG_ID,
|
||||
Float(RawList<'a, f32>) = FLOAT_ID,
|
||||
Double(RawList<'a, f64>) = DOUBLE_ID,
|
||||
ByteArray(&'a [&'a [u8]]) = BYTE_ARRAY_ID,
|
||||
String(&'a [&'a Mutf8Str]) = STRING_ID,
|
||||
List(&'a [NbtList<'a>]) = LIST_ID,
|
||||
Compound(&'a [NbtCompound<'a>]) = COMPOUND_ID,
|
||||
IntArray(&'a [RawList<'a, i32>]) = INT_ARRAY_ID,
|
||||
LongArray(&'a [RawList<'a, i64>]) = LONG_ARRAY_ID,
|
||||
ByteArray(Slice32Bit<'a, [Slice32Bit<'a, [u8]>]>) = BYTE_ARRAY_ID,
|
||||
String(Slice32Bit<'a, [Slice16Bit<'a, Mutf8Str>]>) = STRING_ID,
|
||||
List(Slice32Bit<'a, [NbtList<'a>]>) = LIST_ID,
|
||||
Compound(Slice32Bit<'a, [NbtCompound<'a>]>) = COMPOUND_ID,
|
||||
IntArray(Slice32Bit<'a, [RawList<'a, i32>]>) = INT_ARRAY_ID,
|
||||
LongArray(Slice32Bit<'a, [RawList<'a, i64>]>) = LONG_ARRAY_ID,
|
||||
}
|
||||
impl<'a> NbtList<'a> {
|
||||
pub fn read(
|
||||
|
@ -158,7 +159,7 @@ impl<'a> NbtList<'a> {
|
|||
unchecked_push(data, COMPOUND_ID);
|
||||
unchecked_extend(data, &(compounds.len() as u32).to_be_bytes());
|
||||
}
|
||||
for compound in *compounds {
|
||||
for compound in &**compounds {
|
||||
compound.write(data);
|
||||
}
|
||||
return;
|
||||
|
@ -195,13 +196,13 @@ impl<'a> NbtList<'a> {
|
|||
}
|
||||
NbtList::String(strings) => {
|
||||
write_u32(data, strings.len() as u32);
|
||||
for string in *strings {
|
||||
for string in &**strings {
|
||||
write_string(data, string);
|
||||
}
|
||||
}
|
||||
NbtList::List(lists) => {
|
||||
write_u32(data, lists.len() as u32);
|
||||
for list in *lists {
|
||||
for list in &**lists {
|
||||
list.write(data);
|
||||
}
|
||||
}
|
||||
|
@ -210,13 +211,13 @@ impl<'a> NbtList<'a> {
|
|||
}
|
||||
NbtList::IntArray(int_arrays) => {
|
||||
write_u32(data, int_arrays.len() as u32);
|
||||
for array in *int_arrays {
|
||||
for array in &**int_arrays {
|
||||
write_with_u32_length(data, 4, array.as_big_endian());
|
||||
}
|
||||
}
|
||||
NbtList::LongArray(long_arrays) => {
|
||||
write_u32(data, long_arrays.len() as u32);
|
||||
for array in *long_arrays {
|
||||
for array in &**long_arrays {
|
||||
write_with_u32_length(data, 8, array.as_big_endian());
|
||||
}
|
||||
}
|
||||
|
@ -269,13 +270,13 @@ impl<'a> NbtList<'a> {
|
|||
_ => None,
|
||||
}
|
||||
}
|
||||
pub fn byte_arrays(&self) -> Option<&[&[u8]]> {
|
||||
pub fn byte_arrays(&self) -> Option<&[Slice32Bit<'a, [u8]>]> {
|
||||
match self {
|
||||
NbtList::ByteArray(byte_arrays) => Some(byte_arrays),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
pub fn strings(&self) -> Option<&[&Mutf8Str]> {
|
||||
pub fn strings(&self) -> Option<&[Slice16Bit<Mutf8Str>]> {
|
||||
match self {
|
||||
NbtList::String(strings) => Some(strings),
|
||||
_ => None,
|
||||
|
@ -319,7 +320,7 @@ impl<'a> NbtList<'a> {
|
|||
byte_arrays.iter().map(|array| array.to_vec()).collect(),
|
||||
),
|
||||
NbtList::String(strings) => crate::owned::NbtList::String(
|
||||
strings.iter().map(|&string| string.to_owned()).collect(),
|
||||
strings.iter().map(|&string| (*string).to_owned()).collect(),
|
||||
),
|
||||
NbtList::List(lists) => {
|
||||
crate::owned::NbtList::List(lists.iter().map(|list| list.to_owned()).collect())
|
||||
|
|
|
@ -15,6 +15,7 @@ use crate::{
|
|||
LIST_ID, LONG_ARRAY_ID, LONG_ID, MAX_DEPTH, SHORT_ID, STRING_ID,
|
||||
},
|
||||
raw_list::RawList,
|
||||
thin_slices::{Slice16Bit, Slice32Bit},
|
||||
Error, Mutf8Str,
|
||||
};
|
||||
|
||||
|
@ -24,7 +25,7 @@ pub use self::{compound::NbtCompound, list::NbtList};
|
|||
/// A complete NBT container. This contains a name and a compound tag.
|
||||
#[derive(Debug)]
|
||||
pub struct BaseNbt<'a> {
|
||||
name: &'a Mutf8Str,
|
||||
name: Slice16Bit<'a, Mutf8Str>,
|
||||
tag: NbtCompound<'a>,
|
||||
// we need to keep this around so it's not deallocated
|
||||
_tag_alloc: TagAllocator<'a>,
|
||||
|
@ -89,7 +90,7 @@ impl<'a> Nbt<'a> {
|
|||
|
||||
impl<'a> BaseNbt<'a> {
|
||||
/// Get the name of the NBT compound. This is often an empty string.
|
||||
pub fn name(&self) -> &'a Mutf8Str {
|
||||
pub fn name(&self) -> Slice16Bit<'a, Mutf8Str> {
|
||||
self.name
|
||||
}
|
||||
}
|
||||
|
@ -113,7 +114,7 @@ impl<'a> Deref for BaseNbt<'a> {
|
|||
impl<'a> BaseNbt<'a> {
|
||||
pub fn write(&self, data: &mut Vec<u8>) {
|
||||
data.push(COMPOUND_ID);
|
||||
write_string(data, self.name);
|
||||
write_string(data, &self.name);
|
||||
self.tag.write(data);
|
||||
data.push(END_ID);
|
||||
}
|
||||
|
@ -128,8 +129,8 @@ pub enum NbtTag<'a> {
|
|||
Long(i64),
|
||||
Float(f32),
|
||||
Double(f64),
|
||||
ByteArray(&'a [u8]),
|
||||
String(&'a Mutf8Str),
|
||||
ByteArray(Slice32Bit<'a, [u8]>),
|
||||
String(Slice16Bit<'a, Mutf8Str>),
|
||||
List(NbtList<'a>),
|
||||
Compound(NbtCompound<'a>),
|
||||
IntArray(RawList<'a, i32>),
|
||||
|
@ -293,7 +294,7 @@ impl<'a> NbtTag<'a> {
|
|||
NbtTag::Float(float) => crate::owned::NbtTag::Float(*float),
|
||||
NbtTag::Double(double) => crate::owned::NbtTag::Double(*double),
|
||||
NbtTag::ByteArray(byte_array) => crate::owned::NbtTag::ByteArray(byte_array.to_vec()),
|
||||
NbtTag::String(string) => crate::owned::NbtTag::String((*string).to_owned()),
|
||||
NbtTag::String(string) => crate::owned::NbtTag::String((&**string).to_owned()),
|
||||
NbtTag::List(list) => crate::owned::NbtTag::List(list.to_owned()),
|
||||
NbtTag::Compound(compound) => crate::owned::NbtTag::Compound(compound.to_owned()),
|
||||
NbtTag::IntArray(int_array) => crate::owned::NbtTag::IntArray(int_array.to_vec()),
|
||||
|
|
|
@ -22,7 +22,11 @@ use std::{
|
|||
ptr::NonNull,
|
||||
};
|
||||
|
||||
use crate::{raw_list::RawList, Mutf8Str};
|
||||
use crate::{
|
||||
raw_list::RawList,
|
||||
thin_slices::{Slice16Bit, Slice32Bit},
|
||||
Mutf8Str,
|
||||
};
|
||||
|
||||
use super::{NbtCompound, NbtList, NbtTag};
|
||||
|
||||
|
@ -44,7 +48,7 @@ impl<'a> TagAllocator<'a> {
|
|||
|
||||
#[derive(Default)]
|
||||
pub struct TagAllocatorImpl<'a> {
|
||||
pub named: IndividualTagAllocator<(&'a Mutf8Str, NbtTag<'a>)>,
|
||||
pub named: IndividualTagAllocator<(Slice16Bit<'a, Mutf8Str>, NbtTag<'a>)>,
|
||||
|
||||
// so remember earlier when i said the depth thing is only necessary because compounds aren't
|
||||
// length prefixed? ... well soooo i decided to make arrays store per-depth separately too to
|
||||
|
@ -52,8 +56,8 @@ pub struct TagAllocatorImpl<'a> {
|
|||
// a lot
|
||||
pub unnamed_list: IndividualTagAllocator<NbtList<'a>>,
|
||||
pub unnamed_compound: IndividualTagAllocator<NbtCompound<'a>>,
|
||||
pub unnamed_bytearray: IndividualTagAllocator<&'a [u8]>,
|
||||
pub unnamed_string: IndividualTagAllocator<&'a Mutf8Str>,
|
||||
pub unnamed_bytearray: IndividualTagAllocator<Slice32Bit<'a, [u8]>>,
|
||||
pub unnamed_string: IndividualTagAllocator<Slice16Bit<'a, Mutf8Str>>,
|
||||
pub unnamed_intarray: IndividualTagAllocator<RawList<'a, i32>>,
|
||||
pub unnamed_longarray: IndividualTagAllocator<RawList<'a, i64>>,
|
||||
}
|
||||
|
@ -87,7 +91,11 @@ where
|
|||
|
||||
start_allocating_tags(alloc)
|
||||
}
|
||||
pub fn finish<'a>(&mut self, alloc: ContiguousTagsAllocator<T>, depth: usize) -> &'a [T] {
|
||||
pub fn finish<'a>(
|
||||
&mut self,
|
||||
alloc: ContiguousTagsAllocator<T>,
|
||||
depth: usize,
|
||||
) -> Slice32Bit<'a, [T]> {
|
||||
finish_allocating_tags(alloc, &mut self.current[depth], &mut self.previous[depth])
|
||||
}
|
||||
}
|
||||
|
@ -121,16 +129,17 @@ fn finish_allocating_tags<'a, T>(
|
|||
alloc: ContiguousTagsAllocator<T>,
|
||||
current_alloc: &mut TagsAllocation<T>,
|
||||
previous_allocs: &mut Vec<TagsAllocation<T>>,
|
||||
) -> &'a [T] {
|
||||
) -> Slice32Bit<'a, [T]> {
|
||||
let slice = unsafe {
|
||||
std::slice::from_raw_parts(
|
||||
Slice32Bit::new(
|
||||
alloc
|
||||
.alloc
|
||||
.ptr
|
||||
.as_ptr()
|
||||
.add(alloc.alloc.len)
|
||||
.sub(alloc.size),
|
||||
alloc.size,
|
||||
.sub(alloc.size)
|
||||
.cast(),
|
||||
alloc.size as u32,
|
||||
)
|
||||
};
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ use std::{io::Cursor, mem, slice};
|
|||
use crate::{
|
||||
raw_list::RawList,
|
||||
swap_endianness::{swap_endianness_as_u8, SwappableNumber},
|
||||
thin_slices::{Slice16Bit, Slice32Bit},
|
||||
Error, Mutf8Str,
|
||||
};
|
||||
|
||||
|
@ -54,7 +55,7 @@ pub fn read_u16(data: &mut Cursor<&[u8]>) -> Result<u16, Error> {
|
|||
pub fn read_with_u16_length<'a>(
|
||||
data: &mut Cursor<&'a [u8]>,
|
||||
width: usize,
|
||||
) -> Result<&'a [u8], Error> {
|
||||
) -> Result<Slice16Bit<'a, [u8]>, Error> {
|
||||
let length = read_u16(data)?;
|
||||
let length_in_bytes = length as usize * width;
|
||||
// make sure we don't read more than the length
|
||||
|
@ -63,14 +64,17 @@ pub fn read_with_u16_length<'a>(
|
|||
}
|
||||
let start_position = data.position() as usize;
|
||||
data.set_position(data.position() + length_in_bytes as u64);
|
||||
Ok(&data.get_ref()[start_position..start_position + length_in_bytes])
|
||||
Ok(Slice16Bit::new(
|
||||
data.get_ref().as_ptr().wrapping_add(start_position),
|
||||
length_in_bytes as u16,
|
||||
))
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
pub fn read_with_u32_length<'a>(
|
||||
data: &mut Cursor<&'a [u8]>,
|
||||
width: usize,
|
||||
) -> Result<&'a [u8], Error> {
|
||||
) -> Result<Slice32Bit<'a, [u8]>, Error> {
|
||||
let length = read_u32(data)?;
|
||||
let length_in_bytes = length as usize * width;
|
||||
// make sure we don't read more than the length
|
||||
|
@ -79,19 +83,23 @@ pub fn read_with_u32_length<'a>(
|
|||
}
|
||||
let start_position = data.position() as usize;
|
||||
data.set_position(data.position() + length_in_bytes as u64);
|
||||
Ok(&data.get_ref()[start_position..start_position + length_in_bytes])
|
||||
// Ok(&data.get_ref()[start_position..start_position + length_in_bytes])
|
||||
Ok(Slice32Bit::new(
|
||||
data.get_ref().as_ptr().wrapping_add(start_position),
|
||||
length_in_bytes as u32,
|
||||
))
|
||||
}
|
||||
|
||||
pub fn read_string<'a>(data: &mut Cursor<&'a [u8]>) -> Result<&'a Mutf8Str, Error> {
|
||||
pub fn read_string<'a>(data: &mut Cursor<&'a [u8]>) -> Result<Slice16Bit<'a, Mutf8Str>, Error> {
|
||||
let data = read_with_u16_length(data, 1)?;
|
||||
Ok(Mutf8Str::from_slice(data))
|
||||
Ok(Mutf8Str::from_slice_16bit(data))
|
||||
}
|
||||
|
||||
pub fn read_u8_array<'a>(data: &mut Cursor<&'a [u8]>) -> Result<&'a [u8], Error> {
|
||||
pub fn read_u8_array<'a>(data: &mut Cursor<&'a [u8]>) -> Result<Slice32Bit<'a, [u8]>, Error> {
|
||||
read_with_u32_length(data, 1)
|
||||
}
|
||||
pub fn read_i8_array<'a>(data: &mut Cursor<&'a [u8]>) -> Result<&'a [i8], Error> {
|
||||
Ok(slice_u8_into_i8(read_u8_array(data)?))
|
||||
pub fn read_i8_array<'a>(data: &mut Cursor<&'a [u8]>) -> Result<Slice32Bit<'a, [i8]>, Error> {
|
||||
Ok(slice_32bit_u8_into_i8(read_u8_array(data)?))
|
||||
}
|
||||
|
||||
pub fn read_int_array<'a>(data: &mut Cursor<&'a [u8]>) -> Result<RawList<'a, i32>, Error> {
|
||||
|
@ -107,11 +115,17 @@ pub fn read_long_array<'a>(data: &mut Cursor<&'a [u8]>) -> Result<RawList<'a, i6
|
|||
fn slice_u8_into_i8(s: &[u8]) -> &[i8] {
|
||||
unsafe { slice::from_raw_parts(s.as_ptr() as *const i8, s.len()) }
|
||||
}
|
||||
|
||||
pub fn slice_i8_into_u8(s: &[i8]) -> &[u8] {
|
||||
unsafe { slice::from_raw_parts(s.as_ptr() as *const u8, s.len()) }
|
||||
}
|
||||
|
||||
fn slice_32bit_u8_into_i8(s: Slice32Bit<[u8]>) -> Slice32Bit<[i8]> {
|
||||
Slice32Bit::new(s.as_ptr(), s.len())
|
||||
}
|
||||
fn slice_32bit_i8_into_u8(s: Slice32Bit<[i8]>) -> Slice32Bit<[u8]> {
|
||||
Slice32Bit::new(s.as_ptr(), s.len())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn write_with_u32_length(data: &mut Vec<u8>, width: usize, value: &[u8]) {
|
||||
let length = value.len() / width;
|
||||
|
@ -170,14 +184,17 @@ pub unsafe fn unchecked_push(data: &mut Vec<u8>, value: u8) {
|
|||
/// 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)) }
|
||||
pub fn slice_into_u8_native_endian<T>(s: Slice32Bit<'_, [T]>) -> Slice32Bit<'_, [u8]> {
|
||||
Slice32Bit::new(
|
||||
s.as_ptr() as *const u8,
|
||||
s.len() * mem::size_of::<T>() as u32,
|
||||
)
|
||||
}
|
||||
|
||||
/// 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> {
|
||||
pub fn slice_into_u8_big_endian<T: SwappableNumber>(s: Slice32Bit<'_, [T]>) -> Vec<u8> {
|
||||
swap_endianness_as_u8::<T>(slice_into_u8_native_endian(s))
|
||||
}
|
||||
|
||||
|
@ -189,18 +206,24 @@ mod tests {
|
|||
#[cfg(target_endian = "little")]
|
||||
#[test]
|
||||
fn test_slice_into_u8_native_endian() {
|
||||
assert_eq!(slice_into_u8_native_endian(&[1u16, 2u16]), [1, 0, 2, 0]);
|
||||
assert_eq!(
|
||||
slice_into_u8_native_endian(&[1u32, 2u32]),
|
||||
[1, 0, 0, 0, 2, 0, 0, 0]
|
||||
slice_into_u8_native_endian([1u16, 2u16].as_slice().into()),
|
||||
[1, 0, 2, 0].as_slice().into()
|
||||
);
|
||||
assert_eq!(
|
||||
slice_into_u8_native_endian([1u32, 2u32].as_slice().into()),
|
||||
[1, 0, 0, 0, 2, 0, 0, 0].as_slice().into()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_slice_into_u8_big_endian() {
|
||||
assert_eq!(slice_into_u8_big_endian(&[1u16, 2u16]), [0, 1, 0, 2]);
|
||||
assert_eq!(
|
||||
slice_into_u8_big_endian(&[1u32, 2u32]),
|
||||
slice_into_u8_big_endian([1u16, 2u16].as_slice().into()),
|
||||
[0, 1, 0, 2]
|
||||
);
|
||||
assert_eq!(
|
||||
slice_into_u8_big_endian([1u32, 2u32].as_slice().into()),
|
||||
[0, 0, 0, 1, 0, 0, 0, 2]
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#![doc = include_str!("../README.md")]
|
||||
#![feature(portable_simd)]
|
||||
#![feature(array_chunks)]
|
||||
#![feature(ptr_metadata)]
|
||||
|
||||
pub mod borrow;
|
||||
mod common;
|
||||
|
@ -9,6 +10,7 @@ mod mutf8;
|
|||
pub mod owned;
|
||||
pub mod raw_list;
|
||||
pub mod swap_endianness;
|
||||
mod thin_slices;
|
||||
mod traits;
|
||||
|
||||
pub use error::{DeserializeError, Error};
|
||||
|
|
|
@ -7,6 +7,8 @@ use std::{
|
|||
simd::prelude::*,
|
||||
};
|
||||
|
||||
use crate::thin_slices::Slice16Bit;
|
||||
|
||||
/// A M-UTF8 string slice. This is how strings are represented internally in NBT.
|
||||
#[derive(Eq, PartialEq)]
|
||||
pub struct Mutf8Str {
|
||||
|
@ -87,6 +89,11 @@ impl Mutf8Str {
|
|||
unsafe { mem::transmute::<&[u8], &Mutf8Str>(slice) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn from_slice_16bit(slice: Slice16Bit<[u8]>) -> Slice16Bit<Mutf8Str> {
|
||||
Slice16Bit::new(slice.as_ptr(), slice.len())
|
||||
}
|
||||
|
||||
// we can't implement FromStr on Cow<Mutf8Str>
|
||||
#[allow(clippy::should_implement_trait)]
|
||||
#[inline]
|
||||
|
|
|
@ -48,7 +48,7 @@ impl NbtCompound {
|
|||
if tag_type == END_ID {
|
||||
break;
|
||||
}
|
||||
let tag_name = read_string(data)?.to_owned();
|
||||
let tag_name: Mutf8String = (*read_string(data)?).to_owned();
|
||||
let tag = NbtTag::read_with_type(data, tag_type, depth)?;
|
||||
|
||||
tags_buffer[tags_buffer_len] = MaybeUninit::new((tag_name, tag));
|
||||
|
|
|
@ -47,7 +47,7 @@ impl NbtList {
|
|||
data.set_position(data.position() + 4);
|
||||
NbtList::Empty
|
||||
}
|
||||
BYTE_ID => NbtList::Byte(read_i8_array(data)?.to_owned()),
|
||||
BYTE_ID => NbtList::Byte(read_i8_array(data)?.to_vec()),
|
||||
SHORT_ID => NbtList::Short(swap_endianness(read_with_u32_length(data, 2)?)),
|
||||
INT_ID => NbtList::Int(swap_endianness(read_with_u32_length(data, 4)?)),
|
||||
LONG_ID => NbtList::Long(swap_endianness(read_with_u32_length(data, 8)?)),
|
||||
|
@ -67,7 +67,7 @@ impl NbtList {
|
|||
// arbitrary number to prevent big allocations
|
||||
let mut strings = Vec::with_capacity(length.min(128) as usize);
|
||||
for _ in 0..length {
|
||||
strings.push(read_string(data)?.to_owned())
|
||||
strings.push((*read_string(data)?).to_owned())
|
||||
}
|
||||
strings
|
||||
}),
|
||||
|
@ -135,19 +135,23 @@ impl NbtList {
|
|||
write_with_u32_length(data, 1, slice_i8_into_u8(bytes));
|
||||
}
|
||||
NbtList::Short(shorts) => {
|
||||
write_with_u32_length(data, 2, &slice_into_u8_big_endian(shorts));
|
||||
write_with_u32_length(data, 2, &slice_into_u8_big_endian(shorts.as_slice().into()));
|
||||
}
|
||||
NbtList::Int(ints) => {
|
||||
write_with_u32_length(data, 4, &slice_into_u8_big_endian(ints));
|
||||
write_with_u32_length(data, 4, &slice_into_u8_big_endian(ints.as_slice().into()));
|
||||
}
|
||||
NbtList::Long(longs) => {
|
||||
write_with_u32_length(data, 8, &slice_into_u8_big_endian(longs));
|
||||
write_with_u32_length(data, 8, &slice_into_u8_big_endian(longs.as_slice().into()));
|
||||
}
|
||||
NbtList::Float(floats) => {
|
||||
write_with_u32_length(data, 4, &slice_into_u8_big_endian(floats));
|
||||
write_with_u32_length(data, 4, &slice_into_u8_big_endian(floats.as_slice().into()));
|
||||
}
|
||||
NbtList::Double(doubles) => {
|
||||
write_with_u32_length(data, 8, &slice_into_u8_big_endian(doubles));
|
||||
write_with_u32_length(
|
||||
data,
|
||||
8,
|
||||
&slice_into_u8_big_endian(doubles.as_slice().into()),
|
||||
);
|
||||
}
|
||||
NbtList::ByteArray(byte_arrays) => {
|
||||
write_u32(data, byte_arrays.len() as u32);
|
||||
|
@ -173,13 +177,21 @@ impl NbtList {
|
|||
NbtList::IntArray(int_arrays) => {
|
||||
write_u32(data, int_arrays.len() as u32);
|
||||
for array in int_arrays {
|
||||
write_with_u32_length(data, 4, &slice_into_u8_big_endian(array));
|
||||
write_with_u32_length(
|
||||
data,
|
||||
4,
|
||||
&slice_into_u8_big_endian(array.as_slice().into()),
|
||||
);
|
||||
}
|
||||
}
|
||||
NbtList::LongArray(long_arrays) => {
|
||||
write_u32(data, long_arrays.len() as u32);
|
||||
for array in long_arrays {
|
||||
write_with_u32_length(data, 8, &slice_into_u8_big_endian(array));
|
||||
write_with_u32_length(
|
||||
data,
|
||||
8,
|
||||
&slice_into_u8_big_endian(array.as_slice().into()),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ impl Nbt {
|
|||
if root_type != COMPOUND_ID {
|
||||
return Err(Error::InvalidRootType(root_type));
|
||||
}
|
||||
let name = read_string(data)?.to_owned();
|
||||
let name = (*read_string(data)?).to_owned();
|
||||
let tag = NbtCompound::read_with_depth(data, 0)?;
|
||||
|
||||
Ok(Nbt::Some(BaseNbt { name, tag }))
|
||||
|
@ -247,8 +247,8 @@ impl NbtTag {
|
|||
DOUBLE_ID => Ok(NbtTag::Double(
|
||||
data.read_f64::<BE>().map_err(|_| Error::UnexpectedEof)?,
|
||||
)),
|
||||
BYTE_ARRAY_ID => Ok(NbtTag::ByteArray(read_with_u32_length(data, 1)?.to_owned())),
|
||||
STRING_ID => Ok(NbtTag::String(read_string(data)?.to_owned())),
|
||||
BYTE_ARRAY_ID => Ok(NbtTag::ByteArray(read_with_u32_length(data, 1)?.to_vec())),
|
||||
STRING_ID => Ok(NbtTag::String((*read_string(data)?).to_owned())),
|
||||
LIST_ID => Ok(NbtTag::List(NbtList::read(data, depth + 1)?)),
|
||||
COMPOUND_ID => Ok(NbtTag::Compound(NbtCompound::read_with_depth(
|
||||
data,
|
||||
|
@ -319,13 +319,13 @@ impl NbtTag {
|
|||
unsafe {
|
||||
unchecked_extend(data, &int_array.len().to_be_bytes());
|
||||
}
|
||||
data.extend_from_slice(&slice_into_u8_big_endian(int_array));
|
||||
data.extend_from_slice(&slice_into_u8_big_endian(int_array.as_slice().into()));
|
||||
}
|
||||
NbtTag::LongArray(long_array) => {
|
||||
unsafe {
|
||||
unchecked_extend(data, &long_array.len().to_be_bytes());
|
||||
}
|
||||
data.extend_from_slice(&slice_into_u8_big_endian(long_array));
|
||||
data.extend_from_slice(&slice_into_u8_big_endian(long_array.as_slice().into()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,24 +1,35 @@
|
|||
use std::{marker::PhantomData, mem};
|
||||
use std::{
|
||||
fmt::{self, Debug},
|
||||
marker::PhantomData,
|
||||
mem,
|
||||
};
|
||||
|
||||
use crate::swap_endianness::{swap_endianness, swap_endianness_as_u8, SwappableNumber};
|
||||
use crate::{
|
||||
swap_endianness::{swap_endianness, swap_endianness_as_u8, SwappableNumber},
|
||||
thin_slices::Slice32Bit,
|
||||
};
|
||||
|
||||
/// A list of numbers that's kept as big-endian in memory.
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
// #[derive(Debug, PartialEq, Clone)]
|
||||
#[repr(transparent)]
|
||||
pub struct RawList<'a, T> {
|
||||
data: &'a [u8],
|
||||
data: Slice32Bit<'a, [u8]>,
|
||||
_marker: PhantomData<T>,
|
||||
}
|
||||
impl<'a, T> RawList<'a, T> {
|
||||
pub fn new(data: &'a [u8]) -> Self {
|
||||
pub fn new(data: Slice32Bit<'a, [u8]>) -> Self {
|
||||
Self {
|
||||
data,
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
pub fn new_from_slice(data: &'a [u8]) -> Self {
|
||||
Self::new(Slice32Bit::new(data.as_ptr(), data.len() as u32))
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.data.len() / mem::size_of::<T>()
|
||||
(self.data.len() / mem::size_of::<T>() as u32) as usize
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
|
@ -39,7 +50,7 @@ impl<T: SwappableNumber> RawList<'_, T> {
|
|||
}
|
||||
|
||||
pub fn as_big_endian(&self) -> &[u8] {
|
||||
self.data
|
||||
&self.data
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -65,3 +76,25 @@ where
|
|||
self.to_vec().into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Debug for RawList<'_, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
self.data.fmt(f)
|
||||
}
|
||||
}
|
||||
impl<T> PartialEq for RawList<'_, T>
|
||||
where
|
||||
T: PartialEq + Copy + SwappableNumber,
|
||||
{
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.to_vec() == other.to_vec()
|
||||
}
|
||||
}
|
||||
impl<T> Clone for RawList<'_, T> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
data: self.data.clone(),
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
use std::{mem, simd::prelude::*};
|
||||
|
||||
use crate::thin_slices::Slice32Bit;
|
||||
|
||||
mod private {
|
||||
pub trait Sealed {}
|
||||
|
||||
|
@ -274,7 +276,7 @@ fn swap_endianness_from_type<T: SwappableNumber>(items: &mut [u8]) {
|
|||
|
||||
/// Swaps the endianness of the given data and return it as a `Vec<u8>`.
|
||||
#[inline]
|
||||
pub fn swap_endianness_as_u8<T: SwappableNumber>(data: &[u8]) -> Vec<u8> {
|
||||
pub fn swap_endianness_as_u8<T: SwappableNumber>(data: Slice32Bit<'_, [u8]>) -> Vec<u8> {
|
||||
let mut items = data.to_vec();
|
||||
swap_endianness_from_type::<T>(&mut items);
|
||||
|
||||
|
@ -282,22 +284,22 @@ pub fn swap_endianness_as_u8<T: SwappableNumber>(data: &[u8]) -> Vec<u8> {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn swap_endianness<T: SwappableNumber>(data: &[u8]) -> Vec<T> {
|
||||
let width_of_t = mem::size_of::<T>();
|
||||
pub fn swap_endianness<T: SwappableNumber>(data: Slice32Bit<'_, [u8]>) -> Vec<T> {
|
||||
let width_of_t = mem::size_of::<T>() as u32;
|
||||
let length_of_vec_t = data.len() / width_of_t;
|
||||
|
||||
// the data must be a multiple of the item width, otherwise it's UB
|
||||
assert_eq!(data.len() % width_of_t, 0);
|
||||
|
||||
// have the vec be of T initially so it's aligned
|
||||
let mut vec_t = Vec::<T>::with_capacity(length_of_vec_t);
|
||||
let mut vec_t = Vec::<T>::with_capacity(length_of_vec_t as usize);
|
||||
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
|
||||
unsafe { Vec::from_raw_parts(ptr, 0, data.len()) }
|
||||
unsafe { Vec::from_raw_parts(ptr, 0, data.len() as usize) }
|
||||
};
|
||||
vec_u8.extend_from_slice(data);
|
||||
vec_u8.extend_from_slice(&data);
|
||||
|
||||
swap_endianness_from_type::<T>(&mut vec_u8);
|
||||
|
||||
|
@ -306,7 +308,7 @@ pub fn swap_endianness<T: SwappableNumber>(data: &[u8]) -> Vec<T> {
|
|||
let ptr = vec_u8.as_mut_ptr() as *mut T;
|
||||
mem::forget(vec_u8);
|
||||
// SAFETY: The length won't be greater than the length of the original data
|
||||
unsafe { Vec::from_raw_parts(ptr, length_of_vec_t, length_of_vec_t) }
|
||||
unsafe { Vec::from_raw_parts(ptr, length_of_vec_t as usize, length_of_vec_t as usize) }
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -316,21 +318,21 @@ mod tests {
|
|||
#[test]
|
||||
fn test_swap_endianness_u16() {
|
||||
assert_eq!(
|
||||
swap_endianness_as_u8::<u16>(&[1, 2, 3, 4, 5, 6, 7, 8]),
|
||||
swap_endianness_as_u8::<u16>([1, 2, 3, 4, 5, 6, 7, 8].as_slice().into()),
|
||||
[2, 1, 4, 3, 6, 5, 8, 7]
|
||||
);
|
||||
}
|
||||
#[test]
|
||||
fn test_swap_endianness_u32() {
|
||||
assert_eq!(
|
||||
swap_endianness_as_u8::<u32>(&[1, 2, 3, 4, 5, 6, 7, 8]),
|
||||
swap_endianness_as_u8::<u32>([1, 2, 3, 4, 5, 6, 7, 8].as_slice().into()),
|
||||
[4, 3, 2, 1, 8, 7, 6, 5]
|
||||
);
|
||||
}
|
||||
#[test]
|
||||
fn test_swap_endianness_u64() {
|
||||
assert_eq!(
|
||||
swap_endianness_as_u8::<u64>(&[1, 2, 3, 4, 5, 6, 7, 8]),
|
||||
swap_endianness_as_u8::<u64>([1, 2, 3, 4, 5, 6, 7, 8].as_slice().into()),
|
||||
[8, 7, 6, 5, 4, 3, 2, 1]
|
||||
);
|
||||
}
|
||||
|
@ -338,7 +340,11 @@ mod tests {
|
|||
#[test]
|
||||
fn test_swap_endianness_u64_vec() {
|
||||
assert_eq!(
|
||||
swap_endianness::<u64>(&[1, 2, 3, 4, 5, 6, 7, 8, 8, 7, 6, 5, 4, 3, 2, 1]),
|
||||
swap_endianness::<u64>(
|
||||
[1, 2, 3, 4, 5, 6, 7, 8, 8, 7, 6, 5, 4, 3, 2, 1]
|
||||
.as_slice()
|
||||
.into()
|
||||
),
|
||||
vec![
|
||||
u64::from_le_bytes([8, 7, 6, 5, 4, 3, 2, 1]),
|
||||
u64::from_le_bytes([1, 2, 3, 4, 5, 6, 7, 8])
|
||||
|
|
220
simdnbt/src/thin_slices.rs
Normal file
220
simdnbt/src/thin_slices.rs
Normal file
|
@ -0,0 +1,220 @@
|
|||
use std::{
|
||||
fmt::{self, Debug, Pointer},
|
||||
marker::PhantomData,
|
||||
ops::Deref,
|
||||
ptr::Pointee,
|
||||
};
|
||||
|
||||
#[repr(packed(2))]
|
||||
pub struct Slice16Bit<'a, T>
|
||||
where
|
||||
T: ?Sized + Pointee,
|
||||
<T as Pointee>::Metadata: From<usize>,
|
||||
{
|
||||
ptr: *const u8,
|
||||
len: u16,
|
||||
_marker: PhantomData<&'a T>,
|
||||
}
|
||||
|
||||
#[repr(packed(4))]
|
||||
pub struct Slice32Bit<'a, T>
|
||||
where
|
||||
T: ?Sized + Pointee,
|
||||
<T as Pointee>::Metadata: From<usize>,
|
||||
{
|
||||
ptr: *const u8,
|
||||
len: u32,
|
||||
_marker: PhantomData<&'a T>,
|
||||
}
|
||||
|
||||
impl<'a, T> Slice32Bit<'a, T>
|
||||
where
|
||||
T: ?Sized + Pointee,
|
||||
<T as Pointee>::Metadata: From<usize>,
|
||||
{
|
||||
pub fn new(ptr: *const u8, len: u32) -> Self {
|
||||
Self {
|
||||
ptr,
|
||||
len,
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
pub fn len(&self) -> u32 {
|
||||
self.len
|
||||
}
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.len == 0
|
||||
}
|
||||
pub fn as_ptr(&self) -> *const u8 {
|
||||
self.ptr
|
||||
}
|
||||
}
|
||||
impl<T> Deref for Slice32Bit<'_, T>
|
||||
where
|
||||
T: ?Sized + Pointee,
|
||||
<T as Pointee>::Metadata: From<usize>,
|
||||
{
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
// self.ptr.with_metadata_of(&self.len).as_ptr()
|
||||
let p = std::ptr::from_raw_parts(self.ptr as *const (), (self.len as usize).into());
|
||||
unsafe { &*(p as *const T) }
|
||||
}
|
||||
}
|
||||
impl<T> Debug for Slice32Bit<'_, T>
|
||||
where
|
||||
T: ?Sized + Pointee,
|
||||
<T as Pointee>::Metadata: From<usize>,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
(&**self).fmt(f)
|
||||
}
|
||||
}
|
||||
impl<T> PartialEq for Slice32Bit<'_, T>
|
||||
where
|
||||
T: PartialEq,
|
||||
T: ?Sized + Pointee,
|
||||
<T as Pointee>::Metadata: From<usize>,
|
||||
{
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
(&**self).eq(&**other)
|
||||
}
|
||||
}
|
||||
impl<T> Clone for Slice32Bit<'_, T>
|
||||
where
|
||||
T: ?Sized + Pointee,
|
||||
<T as Pointee>::Metadata: From<usize>,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
ptr: self.ptr,
|
||||
len: self.len,
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<T> Copy for Slice32Bit<'_, T>
|
||||
where
|
||||
T: ?Sized + Pointee,
|
||||
<T as Pointee>::Metadata: From<usize>,
|
||||
{
|
||||
}
|
||||
impl<T> Default for Slice32Bit<'_, T>
|
||||
where
|
||||
T: ?Sized + Pointee,
|
||||
<T as Pointee>::Metadata: From<usize>,
|
||||
{
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
ptr: std::ptr::null(),
|
||||
len: 0,
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<'a, T> From<&'a [T]> for Slice32Bit<'a, [T]> {
|
||||
fn from(slice: &'a [T]) -> Self {
|
||||
Self {
|
||||
ptr: slice.as_ptr() as *const u8,
|
||||
len: slice.len() as u32,
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Slice16Bit<'a, T>
|
||||
where
|
||||
T: ?Sized + Pointee,
|
||||
<T as Pointee>::Metadata: From<usize>,
|
||||
{
|
||||
pub fn new(ptr: *const u8, len: u16) -> Self {
|
||||
Self {
|
||||
ptr,
|
||||
len,
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
pub fn len(&self) -> u16 {
|
||||
self.len
|
||||
}
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.len == 0
|
||||
}
|
||||
pub fn as_ptr(&self) -> *const u8 {
|
||||
self.ptr
|
||||
}
|
||||
}
|
||||
impl<T> Deref for Slice16Bit<'_, T>
|
||||
where
|
||||
T: ?Sized + Pointee,
|
||||
<T as Pointee>::Metadata: From<usize>,
|
||||
{
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
// self.ptr.with_metadata_of(&self.len).as_ptr()
|
||||
let p = std::ptr::from_raw_parts(self.ptr as *const (), (self.len as usize).into());
|
||||
unsafe { &*(p as *const T) }
|
||||
}
|
||||
}
|
||||
impl<T> Debug for Slice16Bit<'_, T>
|
||||
where
|
||||
T: ?Sized + Pointee,
|
||||
<T as Pointee>::Metadata: From<usize>,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
(&**self).fmt(f)
|
||||
}
|
||||
}
|
||||
impl<T> PartialEq for Slice16Bit<'_, T>
|
||||
where
|
||||
T: PartialEq,
|
||||
T: ?Sized + Pointee,
|
||||
<T as Pointee>::Metadata: From<usize>,
|
||||
{
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
(&**self).eq(&**other)
|
||||
}
|
||||
}
|
||||
impl<T> Clone for Slice16Bit<'_, T>
|
||||
where
|
||||
T: ?Sized + Pointee,
|
||||
<T as Pointee>::Metadata: From<usize>,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
ptr: self.ptr,
|
||||
len: self.len,
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<T> Copy for Slice16Bit<'_, T>
|
||||
where
|
||||
T: ?Sized + Pointee,
|
||||
<T as Pointee>::Metadata: From<usize>,
|
||||
{
|
||||
}
|
||||
impl<T> Default for Slice16Bit<'_, T>
|
||||
where
|
||||
T: ?Sized + Pointee,
|
||||
<T as Pointee>::Metadata: From<usize>,
|
||||
{
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
ptr: std::ptr::null(),
|
||||
len: 0,
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<'a, T> From<&'a [T]> for Slice16Bit<'a, [T]> {
|
||||
fn from(slice: &'a [T]) -> Self {
|
||||
Self {
|
||||
ptr: slice.as_ptr() as *const u8,
|
||||
len: slice.len() as u16,
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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.len());
|
||||
let mut hashmap = HashMap::with_capacity(compound.len() as usize);
|
||||
|
||||
for (k, v) in compound.iter() {
|
||||
let k_str = k.to_str();
|
||||
|
|
Loading…
Add table
Reference in a new issue