1
0
Fork 0
mirror of https://github.com/azalea-rs/simdnbt.git synced 2025-08-02 07:26:04 +00:00

use a mutable slice and read without byteorder

This commit is contained in:
mat 2024-01-20 22:02:23 -06:00
parent ecb0c42f1f
commit bdeed25d85
12 changed files with 216 additions and 71 deletions

View file

@ -18,10 +18,10 @@ The difference is that the "borrow" variant requires you to keep a reference to
```rust,no_run
use std::borrow::Cow;
use std::io::Cursor;
use simdnbt::borrow::Nbt;
use simdnbt::borrow::{cursor::McCursor, Nbt};
fn example(item_bytes: &[u8]) {
let nbt = Nbt::read(&mut Cursor::new(item_bytes))
let nbt = Nbt::read(&mut McCursor::new(item_bytes))
.unwrap()
.unwrap();
let skyblock_id: Cow<str> = nbt

View file

@ -5,6 +5,7 @@ use std::{
use criterion::{black_box, criterion_group, criterion_main, Criterion, Throughput};
use flate2::read::GzDecoder;
use simdnbt::borrow::cursor::McCursor;
pub fn bench_read_file(filename: &str, c: &mut Criterion) {
let mut file = File::open(format!("tests/{filename}")).unwrap();
@ -35,7 +36,7 @@ pub fn bench_read_file(filename: &str, c: &mut Criterion) {
// })
// });
let nbt = simdnbt::borrow::Nbt::read(&mut Cursor::new(input))
let nbt = simdnbt::borrow::Nbt::read(&mut McCursor::new(input))
.unwrap()
.unwrap();
group.bench_function("simdnbt_borrow_write", |b| {

View file

@ -6,6 +6,7 @@ use std::{
use criterion::{black_box, criterion_group, criterion_main, Criterion, Throughput};
use flate2::read::GzDecoder;
use simdnbt::borrow::cursor::McCursor;
pub fn bench_read_file(filename: &str, c: &mut Criterion) {
let mut file = File::open(format!("tests/{filename}")).unwrap();
@ -33,7 +34,7 @@ pub fn bench_read_file(filename: &str, c: &mut Criterion) {
graphite_items_from_nbt(graphite_binary::nbt::decode::read(&mut &input[..]).unwrap())
.unwrap();
let simdnbt_nbt = simdnbt_items_from_nbt(
simdnbt::borrow::Nbt::read(&mut Cursor::new(input))
simdnbt::borrow::Nbt::read(&mut McCursor::new(input))
.unwrap()
.unwrap(),
)
@ -63,7 +64,7 @@ pub fn bench_read_file(filename: &str, c: &mut Criterion) {
group.bench_function("simdnbt_parse", |b| {
b.iter(|| {
let input = black_box(input);
let nbt = black_box(simdnbt::borrow::Nbt::read(&mut Cursor::new(input)));
let nbt = black_box(simdnbt::borrow::Nbt::read(&mut McCursor::new(input)));
let nbt = nbt.unwrap().unwrap();
black_box(simdnbt_items_from_nbt(nbt));
})

View file

@ -1,5 +1,6 @@
use criterion::{black_box, criterion_group, criterion_main, Criterion, Throughput};
use flate2::read::GzDecoder;
use simdnbt::borrow::cursor::McCursor;
use std::{
fs::File,
io::{Cursor, Read},
@ -19,19 +20,18 @@ fn bench_file(filename: &str, c: &mut Criterion) {
decoded_src = contents;
}
let mut decoded_src_stream = Cursor::new(&decoded_src[..]);
let mut group = c.benchmark_group(format!("nbt/{filename}"));
group.throughput(Throughput::Bytes(decoded_src.len() as u64));
group.bench_function("Decode", |b| {
b.iter(|| {
let mut decoded_src_stream = McCursor::new(&decoded_src[..]);
black_box(simdnbt::borrow::Nbt::read(&mut decoded_src_stream).unwrap());
decoded_src_stream.set_position(0);
})
});
let mut decoded_src_stream = McCursor::new(&decoded_src[..]);
let nbt = simdnbt::borrow::Nbt::read(&mut decoded_src_stream)
.unwrap()
.unwrap();

View file

@ -1,6 +1,6 @@
use std::{collections::HashMap, hint::black_box, io::Cursor};
use simdnbt::{Deserialize, Serialize};
use simdnbt::{borrow::cursor::McCursor, Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct Item {
@ -68,7 +68,7 @@ fn main() {
let input = black_box(include_bytes!("../tests/realworld.nbt"));
for _ in 0..1 {
let nbt = simdnbt::borrow::Nbt::read(&mut Cursor::new(input));
let nbt = simdnbt::borrow::Nbt::read(&mut McCursor::new(input));
let nbt = black_box(nbt.unwrap().unwrap());
let data = Base::from_nbt(&nbt).unwrap();
@ -76,7 +76,7 @@ fn main() {
// roundtrip
let mut new_nbt_bytes = Vec::new();
data.clone().to_nbt().write(&mut new_nbt_bytes);
let new_nbt = simdnbt::borrow::Nbt::read(&mut Cursor::new(&new_nbt_bytes[..]))
let new_nbt = simdnbt::borrow::Nbt::read(&mut McCursor::new(&new_nbt_bytes[..]))
.unwrap()
.unwrap();
let new_data = Base::from_nbt(&new_nbt).unwrap();

View file

@ -1,6 +1,6 @@
use std::{collections::HashMap, hint::black_box, io::Cursor};
use simdnbt::borrow::{BaseNbt, Nbt};
use simdnbt::borrow::{cursor::McCursor, BaseNbt, Nbt};
#[derive(Clone, PartialEq, Debug)]
pub struct Item {
@ -103,7 +103,7 @@ fn main() {
let input = black_box(include_bytes!("../tests/realworld.nbt"));
for _ in 0..1 {
let nbt = Nbt::read(&mut Cursor::new(input));
let nbt = Nbt::read(&mut McCursor::new(input));
let nbt = black_box(nbt.unwrap().unwrap());
black_box(items_from_nbt(nbt));
}

View file

@ -10,7 +10,7 @@ use crate::{
Error, Mutf8Str,
};
use super::{list::NbtList, NbtTag};
use super::{cursor::McCursor, list::NbtList, NbtTag};
/// A list of named tags. The order of the tags is preserved.
#[derive(Debug, Default, PartialEq, Clone)]
@ -23,11 +23,11 @@ impl<'a> NbtCompound<'a> {
Self { values }
}
pub fn read(data: &mut Cursor<&'a [u8]>) -> Result<Self, Error> {
pub fn read(data: &mut McCursor<'a>) -> Result<Self, Error> {
Self::read_with_depth(data, 0)
}
pub fn read_with_depth(data: &mut Cursor<&'a [u8]>, depth: usize) -> Result<Self, Error> {
pub fn read_with_depth(data: &mut McCursor<'a>, depth: usize) -> Result<Self, Error> {
if depth > MAX_DEPTH {
return Err(Error::MaxDepthExceeded);
}
@ -37,7 +37,7 @@ impl<'a> NbtCompound<'a> {
if tag_type == END_ID {
break;
}
let tag_name = read_string(data)?;
let tag_name = data.read_string()?;
values.push((tag_name, NbtTag::read_with_type(data, tag_type, depth)?));
}

View file

@ -0,0 +1,138 @@
use crate::{
common::{read_u8_array, slice_u8_into_i8},
raw_list::RawList,
Error, Mutf8Str,
};
pub struct McCursor<'a> {
slice: &'a [u8],
}
impl<'a> McCursor<'a> {
pub fn new(slice: &'a [u8]) -> Self {
Self { slice }
}
#[inline(always)]
fn try_read_exact(&mut self, n: usize) -> Result<&'a [u8], Error> {
if n > self.slice.len() {
return Err(Error::UnexpectedEof);
}
// SAFETY: `[ptr; mid]` and `[mid; len]` are inside `self`, which
// fulfills the requirements of `split_at_unchecked`.
let (a, b) = unsafe { self.slice.split_at_unchecked(n) };
self.slice = b;
Ok(a)
}
#[inline]
pub fn advance(&mut self, n: usize) -> Result<(), Error> {
if n > self.slice.len() {
return Err(Error::UnexpectedEof);
}
self.slice = &self.slice[n..];
Ok(())
}
#[inline]
pub fn read_i8(&mut self) -> Result<i8, Error> {
Ok(<i8>::from_be_bytes(unsafe {
*(self.try_read_exact(core::mem::size_of::<i8>())?.as_ptr()
as *const [u8; core::mem::size_of::<i8>()])
}))
}
#[inline]
pub fn read_u8(&mut self) -> Result<u8, Error> {
self.read_i8().map(|x| x as u8)
}
#[inline]
pub fn read_i16(&mut self) -> Result<i16, Error> {
Ok(<i16>::from_be_bytes(unsafe {
*(self.try_read_exact(core::mem::size_of::<i16>())?.as_ptr()
as *const [u8; core::mem::size_of::<i16>()])
}))
}
#[inline]
pub fn read_i32(&mut self) -> Result<i32, Error> {
Ok(<i32>::from_be_bytes(unsafe {
*(self.try_read_exact(core::mem::size_of::<i32>())?.as_ptr()
as *const [u8; core::mem::size_of::<i32>()])
}))
}
#[inline]
pub fn read_u32(&mut self) -> Result<u32, Error> {
self.read_i32().map(|x| x as u32)
}
#[inline]
pub fn read_i64(&mut self) -> Result<i64, Error> {
Ok(<i64>::from_be_bytes(unsafe {
*(self.try_read_exact(core::mem::size_of::<i64>())?.as_ptr()
as *const [u8; core::mem::size_of::<i64>()])
}))
}
#[inline]
pub fn read_f32(&mut self) -> Result<f32, Error> {
Ok(<f32>::from_be_bytes(unsafe {
*(self.try_read_exact(core::mem::size_of::<f32>())?.as_ptr()
as *const [u8; core::mem::size_of::<f32>()])
}))
}
#[inline]
pub fn read_f64(&mut self) -> Result<f64, Error> {
Ok(<f64>::from_be_bytes(unsafe {
*(self.try_read_exact(core::mem::size_of::<f64>())?.as_ptr()
as *const [u8; core::mem::size_of::<f64>()])
}))
}
pub fn read_with_u32_length<'b>(&mut self, width: usize) -> Result<&'a [u8], Error> {
let length = self.read_i32()?;
let length_in_bytes = length as usize * width;
// make sure we don't read more than the length
if self.slice.len() < length_in_bytes {
return Err(Error::UnexpectedEof);
}
let (a, b) = self.slice.split_at(length_in_bytes);
self.slice = b;
Ok(a)
}
pub fn read_with_u16_length<'b>(&mut self, width: usize) -> Result<&'a [u8], Error> {
let length = self.read_i16()? as u16;
let length_in_bytes = length as usize * width;
// make sure we don't read more than the length
if self.slice.len() < length_in_bytes {
return Err(Error::UnexpectedEof);
}
self.try_read_exact(length_in_bytes)
}
pub fn read_string(&mut self) -> Result<&'a Mutf8Str, Error> {
let data = self.read_with_u16_length(1)?;
Ok(Mutf8Str::from_slice(data))
}
pub fn read_int_array(&mut self) -> Result<RawList<'a, i32>, Error> {
let array_bytes = self.read_with_u32_length(4)?;
Ok(RawList::new(array_bytes))
}
pub fn read_long_array(&mut self) -> Result<RawList<'a, i64>, Error> {
let array_bytes = self.read_with_u32_length(8)?;
Ok(RawList::new(array_bytes))
}
pub fn read_u8_array(&mut self) -> Result<&'a [u8], Error> {
self.read_with_u32_length(1)
}
pub fn read_i8_array(&mut self) -> Result<&'a [i8], Error> {
Ok(slice_u8_into_i8(self.read_u8_array()?))
}
}

View file

@ -13,7 +13,7 @@ use crate::{
Error, Mutf8Str,
};
use super::{read_u32, NbtCompound, MAX_DEPTH};
use super::{cursor::McCursor, read_u32, NbtCompound, MAX_DEPTH};
/// A list of NBT tags of a single type.
#[repr(u8)]
@ -35,42 +35,42 @@ pub enum NbtList<'a> {
LongArray(Vec<RawList<'a, i64>>) = LONG_ARRAY_ID,
}
impl<'a> NbtList<'a> {
pub fn read(data: &mut Cursor<&'a [u8]>, depth: usize) -> Result<Self, Error> {
pub fn read(data: &mut McCursor<'a>, depth: usize) -> Result<Self, Error> {
if depth > MAX_DEPTH {
return Err(Error::MaxDepthExceeded);
}
let tag_type = data.read_u8().map_err(|_| Error::UnexpectedEof)?;
Ok(match tag_type {
END_ID => {
data.set_position(data.position() + 4);
data.advance(4);
NbtList::Empty
}
BYTE_ID => NbtList::Byte(read_i8_array(data)?),
SHORT_ID => NbtList::Short(RawList::new(read_with_u32_length(data, 2)?)),
INT_ID => NbtList::Int(RawList::new(read_with_u32_length(data, 4)?)),
LONG_ID => NbtList::Long(RawList::new(read_with_u32_length(data, 8)?)),
FLOAT_ID => NbtList::Float(RawList::new(read_with_u32_length(data, 4)?)),
DOUBLE_ID => NbtList::Double(RawList::new(read_with_u32_length(data, 8)?)),
BYTE_ID => NbtList::Byte(data.read_i8_array()?),
SHORT_ID => NbtList::Short(RawList::new(data.read_with_u32_length(2)?)),
INT_ID => NbtList::Int(RawList::new(data.read_with_u32_length(4)?)),
LONG_ID => NbtList::Long(RawList::new(data.read_with_u32_length(8)?)),
FLOAT_ID => NbtList::Float(RawList::new(data.read_with_u32_length(4)?)),
DOUBLE_ID => NbtList::Double(RawList::new(data.read_with_u32_length(8)?)),
BYTE_ARRAY_ID => NbtList::ByteArray({
let length = read_u32(data)?;
let length = data.read_u32()?;
// arbitrary number to prevent big allocations
let mut arrays = Vec::with_capacity(length.min(128) as usize);
for _ in 0..length {
arrays.push(read_u8_array(data)?)
arrays.push(data.read_u8_array()?)
}
arrays
}),
STRING_ID => NbtList::String({
let length = read_u32(data)?;
let length = data.read_u32()?;
// 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)?)
strings.push(data.read_string()?)
}
strings
}),
LIST_ID => NbtList::List({
let length = read_u32(data)?;
let length = data.read_u32()?;
// arbitrary number to prevent big allocations
let mut lists = Vec::with_capacity(length.min(128) as usize);
for _ in 0..length {
@ -79,7 +79,7 @@ impl<'a> NbtList<'a> {
lists
}),
COMPOUND_ID => NbtList::Compound({
let length = read_u32(data)?;
let length = data.read_u32()?;
// arbitrary number to prevent big allocations
let mut compounds = Vec::with_capacity(length.min(128) as usize);
for _ in 0..length {
@ -88,20 +88,20 @@ impl<'a> NbtList<'a> {
compounds
}),
INT_ARRAY_ID => NbtList::IntArray({
let length = read_u32(data)?;
let length = data.read_u32()?;
// arbitrary number to prevent big allocations
let mut arrays = Vec::with_capacity(length.min(128) as usize);
for _ in 0..length {
arrays.push(read_int_array(data)?)
arrays.push(data.read_int_array()?)
}
arrays
}),
LONG_ARRAY_ID => NbtList::LongArray({
let length = read_u32(data)?;
let length = data.read_u32()?;
// arbitrary number to prevent big allocations
let mut arrays = Vec::with_capacity(length.min(128) as usize);
for _ in 0..length {
arrays.push(read_long_array(data)?)
arrays.push(data.read_long_array()?)
}
arrays
}),

View file

@ -1,6 +1,7 @@
//! 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;
pub mod cursor;
mod list;
use std::{io::Cursor, ops::Deref};
@ -17,6 +18,7 @@ use crate::{
Error, Mutf8Str,
};
use self::cursor::McCursor;
pub use self::{compound::NbtCompound, list::NbtList};
/// A complete NBT container. This contains a name and a compound tag.
@ -35,7 +37,7 @@ pub enum Nbt<'a> {
impl<'a> Nbt<'a> {
/// Reads NBT from the given data. Returns `Ok(None)` if there is no data.
pub fn read(data: &mut Cursor<&'a [u8]>) -> Result<Nbt<'a>, Error> {
pub fn read(data: &mut McCursor<'a>) -> Result<Nbt<'a>, Error> {
let root_type = data.read_u8().map_err(|_| Error::UnexpectedEof)?;
if root_type == END_ID {
return Ok(Nbt::None);
@ -43,7 +45,7 @@ impl<'a> Nbt<'a> {
if root_type != COMPOUND_ID {
return Err(Error::InvalidRootType(root_type));
}
let name = read_string(data)?;
let name = data.read_string()?;
let tag = NbtCompound::read_with_depth(data, 0)?;
Ok(Nbt::Some(BaseNbt { name, tag }))
@ -128,49 +130,45 @@ impl<'a> NbtTag<'a> {
unsafe { *<*const _>::from(self).cast::<u8>() }
}
fn read_with_type(
data: &mut Cursor<&'a [u8]>,
tag_type: u8,
depth: usize,
) -> Result<Self, Error> {
fn read_with_type(data: &mut McCursor<'a>, tag_type: u8, depth: usize) -> Result<Self, Error> {
match tag_type {
BYTE_ID => Ok(NbtTag::Byte(
data.read_i8().map_err(|_| Error::UnexpectedEof)?,
)),
SHORT_ID => Ok(NbtTag::Short(
data.read_i16::<BE>().map_err(|_| Error::UnexpectedEof)?,
data.read_i16().map_err(|_| Error::UnexpectedEof)?,
)),
INT_ID => Ok(NbtTag::Int(
data.read_i32::<BE>().map_err(|_| Error::UnexpectedEof)?,
data.read_i32().map_err(|_| Error::UnexpectedEof)?,
)),
LONG_ID => Ok(NbtTag::Long(
data.read_i64::<BE>().map_err(|_| Error::UnexpectedEof)?,
data.read_i64().map_err(|_| Error::UnexpectedEof)?,
)),
FLOAT_ID => Ok(NbtTag::Float(
data.read_f32::<BE>().map_err(|_| Error::UnexpectedEof)?,
data.read_f32().map_err(|_| Error::UnexpectedEof)?,
)),
DOUBLE_ID => Ok(NbtTag::Double(
data.read_f64::<BE>().map_err(|_| Error::UnexpectedEof)?,
data.read_f64().map_err(|_| Error::UnexpectedEof)?,
)),
BYTE_ARRAY_ID => Ok(NbtTag::ByteArray(read_with_u32_length(data, 1)?)),
STRING_ID => Ok(NbtTag::String(read_string(data)?)),
BYTE_ARRAY_ID => Ok(NbtTag::ByteArray(data.read_with_u32_length(1)?)),
STRING_ID => Ok(NbtTag::String(data.read_string()?)),
LIST_ID => Ok(NbtTag::List(NbtList::read(data, depth + 1)?)),
COMPOUND_ID => Ok(NbtTag::Compound(NbtCompound::read_with_depth(
data,
depth + 1,
)?)),
INT_ARRAY_ID => Ok(NbtTag::IntArray(read_int_array(data)?)),
LONG_ARRAY_ID => Ok(NbtTag::LongArray(read_long_array(data)?)),
INT_ARRAY_ID => Ok(NbtTag::IntArray(data.read_int_array()?)),
LONG_ARRAY_ID => Ok(NbtTag::LongArray(data.read_long_array()?)),
_ => Err(Error::UnknownTagId(tag_type)),
}
}
pub fn read(data: &mut Cursor<&'a [u8]>) -> Result<Self, Error> {
pub fn read(data: &mut McCursor<'a>) -> Result<Self, Error> {
let tag_type = data.read_u8().map_err(|_| Error::UnexpectedEof)?;
Self::read_with_type(data, tag_type, 0)
}
pub fn read_optional(data: &mut Cursor<&'a [u8]>) -> Result<Option<Self>, Error> {
pub fn read_optional(data: &mut McCursor<'a>) -> Result<Option<Self>, Error> {
let tag_type = data.read_u8().map_err(|_| Error::UnexpectedEof)?;
if tag_type == END_ID {
return Ok(None);
@ -282,7 +280,7 @@ mod tests {
#[test]
fn hello_world() {
let nbt = Nbt::read(&mut Cursor::new(include_bytes!(
let nbt = Nbt::read(&mut McCursor::new(include_bytes!(
"../../tests/hello_world.nbt"
)))
.unwrap()
@ -302,7 +300,9 @@ mod tests {
let mut decoded_src_decoder = GzDecoder::new(&mut src_slice);
let mut decoded_src = Vec::new();
decoded_src_decoder.read_to_end(&mut decoded_src).unwrap();
let nbt = Nbt::read(&mut Cursor::new(&decoded_src)).unwrap().unwrap();
let nbt = Nbt::read(&mut McCursor::new(&decoded_src))
.unwrap()
.unwrap();
assert_eq!(nbt.int("PersistentId"), Some(1946940766));
assert_eq!(nbt.list("Rotation").unwrap().floats().unwrap().len(), 2);
@ -315,7 +315,9 @@ mod tests {
let mut decoded_src_decoder = GzDecoder::new(&mut src_slice);
let mut decoded_src = Vec::new();
decoded_src_decoder.read_to_end(&mut decoded_src).unwrap();
let nbt = Nbt::read(&mut Cursor::new(&decoded_src)).unwrap().unwrap();
let nbt = Nbt::read(&mut McCursor::new(&decoded_src))
.unwrap()
.unwrap();
assert_eq!(nbt.float("foodExhaustionLevel").unwrap() as u32, 2);
assert_eq!(nbt.list("Rotation").unwrap().floats().unwrap().len(), 2);
@ -328,11 +330,13 @@ mod tests {
let mut decoded_src_decoder = GzDecoder::new(&mut src_slice);
let mut decoded_src = Vec::new();
decoded_src_decoder.read_to_end(&mut decoded_src).unwrap();
let nbt = Nbt::read(&mut Cursor::new(&decoded_src)).unwrap().unwrap();
let nbt = Nbt::read(&mut McCursor::new(&decoded_src))
.unwrap()
.unwrap();
let mut out = Vec::new();
nbt.write(&mut out);
let nbt = Nbt::read(&mut Cursor::new(&out)).unwrap().unwrap();
let nbt = Nbt::read(&mut McCursor::new(&out)).unwrap().unwrap();
assert_eq!(nbt.float("foodExhaustionLevel").unwrap() as u32, 2);
assert_eq!(nbt.list("Rotation").unwrap().floats().unwrap().len(), 2);
@ -340,7 +344,7 @@ mod tests {
#[test]
fn inttest_1023() {
let nbt = Nbt::read(&mut Cursor::new(include_bytes!(
let nbt = Nbt::read(&mut McCursor::new(include_bytes!(
"../../tests/inttest1023.nbt"
)))
.unwrap()
@ -368,7 +372,7 @@ mod tests {
}
data.write_u8(END_ID).unwrap();
let nbt = Nbt::read(&mut Cursor::new(&data)).unwrap().unwrap();
let nbt = Nbt::read(&mut McCursor::new(&data)).unwrap().unwrap();
let ints = nbt.list("").unwrap().ints().unwrap();
for (i, &item) in ints.iter().enumerate() {
assert_eq!(i as i32, item);
@ -390,7 +394,7 @@ mod tests {
}
data.write_u8(END_ID).unwrap();
let nbt = Nbt::read(&mut Cursor::new(&data)).unwrap().unwrap();
let nbt = Nbt::read(&mut McCursor::new(&data)).unwrap().unwrap();
let ints = nbt.list("").unwrap().ints().unwrap();
for (i, &item) in ints.iter().enumerate() {
assert_eq!(i as i32, item);
@ -412,7 +416,7 @@ mod tests {
}
data.write_u8(END_ID).unwrap();
let nbt = Nbt::read(&mut Cursor::new(&data)).unwrap().unwrap();
let nbt = Nbt::read(&mut McCursor::new(&data)).unwrap().unwrap();
let ints = nbt.list("").unwrap().longs().unwrap();
for (i, &item) in ints.iter().enumerate() {
assert_eq!(i as i64, item);
@ -426,13 +430,13 @@ mod tests {
// let mut out = Vec::new();
// out.write_u8(COMPOUND_ID).unwrap();
// out.write_u16::<BE>(0).unwrap();
// out.write_u16(0).unwrap();
// out.write_u8(LIST_ID).unwrap();
// out.write_u16::<BE>(0).unwrap();
// out.write_u16(0).unwrap();
// out.write_u8(INT_ID).unwrap();
// out.write_i32::<BE>(1023).unwrap();
// out.write_i32(1023).unwrap();
// for i in 0..1023 {
// out.write_i32::<BE>(i).unwrap();
// out.write_i32(i).unwrap();
// }
// out.write_u8(END_ID).unwrap();
@ -443,11 +447,11 @@ mod tests {
// fn generate_stringtest() {
// let mut out = Vec::new();
// out.write_u8(COMPOUND_ID).unwrap();
// out.write_u16::<BE>(0).unwrap();
// out.write_u16(0).unwrap();
// out.write_u8(LIST_ID).unwrap();
// out.write_u16::<BE>(0).unwrap();
// out.write_u16(0).unwrap();
// out.write_u8(STRING_ID).unwrap();
// out.write_i32::<BE>(16).unwrap();
// out.write_i32(16).unwrap();
// out.extend_from_slice(&std::fs::read("tests/stringtest.nbt").unwrap().as_slice()[13..]);
// out.write_u8(END_ID).unwrap();
// std::fs::write("tests/stringtest2.nbt", out).unwrap();

View file

@ -104,7 +104,7 @@ pub fn read_long_array<'a>(data: &mut Cursor<&'a [u8]>) -> Result<RawList<'a, i6
Ok(RawList::new(array_bytes))
}
fn slice_u8_into_i8(s: &[u8]) -> &[i8] {
pub(crate) fn slice_u8_into_i8(s: &[u8]) -> &[i8] {
unsafe { slice::from_raw_parts(s.as_ptr() as *const i8, s.len()) }
}

View file

@ -2,6 +2,7 @@
#![feature(portable_simd)]
#![feature(array_chunks)]
#![feature(split_array)]
#![feature(slice_split_at_unchecked)]
pub mod borrow;
mod common;