mirror of
https://github.com/azalea-rs/simdnbt.git
synced 2025-08-02 15:36:03 +00:00
simplify some code
This commit is contained in:
parent
0dd09fd76e
commit
5daf7c60e7
5 changed files with 133 additions and 194 deletions
|
@ -14,9 +14,10 @@ thiserror = "1.0.47"
|
|||
[dev-dependencies]
|
||||
criterion = { version = "^0.5.1", features = ["html_reports"] }
|
||||
graphite_binary = "0.1.0"
|
||||
valence_nbt = "0.6.1"
|
||||
valence_nbt = { version = "0.6.1", features = ["binary"] }
|
||||
fastnbt = "2.4.4"
|
||||
azalea-nbt = { git = "https://github.com/mat-1/azalea" }
|
||||
hematite-nbt = { version = "0.5.2", default-features = false }
|
||||
|
||||
[profile.release]
|
||||
lto = true
|
||||
|
|
|
@ -7,7 +7,7 @@ use criterion::{black_box, criterion_group, criterion_main, Criterion, Throughpu
|
|||
use flate2::read::GzDecoder;
|
||||
|
||||
pub fn bench_read_file(filename: &str, c: &mut Criterion) {
|
||||
let mut file = File::open(filename).unwrap();
|
||||
let mut file = File::open(format!("tests/{filename}")).unwrap();
|
||||
let mut contents = Vec::new();
|
||||
file.read_to_end(&mut contents).unwrap();
|
||||
let mut src = &contents[..];
|
||||
|
@ -21,54 +21,70 @@ pub fn bench_read_file(filename: &str, c: &mut Criterion) {
|
|||
}
|
||||
let input = input.as_slice();
|
||||
|
||||
let mut group = c.benchmark_group(filename);
|
||||
let mut group = c.benchmark_group(format!("compare/{filename}"));
|
||||
group.throughput(Throughput::Bytes(input.len() as u64));
|
||||
|
||||
group.bench_function("azalea_parse", |b| {
|
||||
b.iter(|| {
|
||||
let input = black_box(input);
|
||||
let nbt = black_box(azalea_nbt::Nbt::read(&mut Cursor::new(input)).unwrap());
|
||||
black_box(
|
||||
nbt.as_compound()
|
||||
.unwrap()
|
||||
.get("")
|
||||
.unwrap()
|
||||
.as_compound()
|
||||
.unwrap()
|
||||
.get("PersistentId")
|
||||
.unwrap()
|
||||
.as_int()
|
||||
.unwrap(),
|
||||
);
|
||||
let nbt = azalea_nbt::Nbt::read(&mut Cursor::new(input)).unwrap();
|
||||
black_box(nbt);
|
||||
// black_box(
|
||||
// nbt.as_compound()
|
||||
// .unwrap()
|
||||
// .get("")
|
||||
// .unwrap()
|
||||
// .as_compound()
|
||||
// .unwrap()
|
||||
// .get("PersistentId")
|
||||
// .unwrap()
|
||||
// .as_int()
|
||||
// .unwrap(),
|
||||
// );
|
||||
})
|
||||
});
|
||||
|
||||
group.bench_function("graphite_parse", |b| {
|
||||
b.iter(|| {
|
||||
let input = black_box(input);
|
||||
let nbt = black_box(graphite_binary::nbt::decode::read(&mut &input[..]).unwrap());
|
||||
// black_box(nbt);
|
||||
black_box(nbt.find_root("PersistentId").unwrap().as_int());
|
||||
let nbt = graphite_binary::nbt::decode::read(&mut &input[..]).unwrap();
|
||||
black_box(nbt);
|
||||
// black_box(nbt.find_root("PersistentId").unwrap().as_int());
|
||||
})
|
||||
});
|
||||
|
||||
group.bench_function("simdnbt_parse", |b| {
|
||||
b.iter(|| {
|
||||
let input = black_box(input);
|
||||
let nbt = black_box(simdnbt::Nbt::new(&mut Cursor::new(input)));
|
||||
let nbt = nbt.unwrap().unwrap();
|
||||
// black_box(nbt);
|
||||
black_box(nbt.int("PersistentId").unwrap());
|
||||
let nbt = simdnbt::Nbt::new(&mut Cursor::new(input)).unwrap().unwrap();
|
||||
black_box(nbt);
|
||||
// black_box(nbt.int("PersistentId").unwrap());
|
||||
})
|
||||
});
|
||||
|
||||
// group.bench_function("valence_parse", |b| {
|
||||
// b.iter(|| {
|
||||
// let input = black_box(input);
|
||||
// let nbt = valence_nbt::from_binary_slice(&mut &input[..]).unwrap();
|
||||
// black_box(nbt);
|
||||
// })
|
||||
// });
|
||||
group.bench_function("valence_parse", |b| {
|
||||
b.iter(|| {
|
||||
let input = black_box(input);
|
||||
let nbt = valence_nbt::Compound::from_binary(&mut &input[..]).unwrap();
|
||||
black_box(nbt);
|
||||
})
|
||||
});
|
||||
|
||||
group.bench_function("fastnbt_parse", |b| {
|
||||
b.iter(|| {
|
||||
let input = black_box(input);
|
||||
let nbt: fastnbt::Value = fastnbt::from_bytes(input).unwrap();
|
||||
black_box(nbt);
|
||||
})
|
||||
});
|
||||
|
||||
group.bench_function("hematite_parse", |b| {
|
||||
b.iter(|| {
|
||||
let input = black_box(input);
|
||||
let nbt = nbt::Blob::from_reader(&mut Cursor::new(input)).unwrap();
|
||||
black_box(nbt);
|
||||
})
|
||||
});
|
||||
|
||||
// // writing
|
||||
|
||||
|
@ -103,14 +119,14 @@ pub fn bench_read_file(filename: &str, c: &mut Criterion) {
|
|||
}
|
||||
|
||||
fn bench(c: &mut Criterion) {
|
||||
// bench_read_file("tests/hello_world.nbt", c);
|
||||
// bench_read_file("tests/bigtest.nbt", c);
|
||||
bench_read_file("tests/simple_player.dat", c);
|
||||
// bench_read_file("tests/complex_player.dat", c);
|
||||
// bench_read_file("tests/level.dat", c);
|
||||
// bench_read_file("tests/stringtest.nbt", c);
|
||||
// bench_read_file("tests/inttest.nbt", c);
|
||||
// bench_read_file("hello_world.nbt", c);
|
||||
// bench_read_file("bigtest.nbt", c);
|
||||
bench_read_file("simple_player.dat", c);
|
||||
// bench_read_file("complex_player.dat", c);
|
||||
// bench_read_file("level.dat", c);
|
||||
// bench_read_file("stringtest.nbt", c);
|
||||
// bench_read_file("inttest.nbt", c);
|
||||
}
|
||||
|
||||
criterion_group!(benches, bench);
|
||||
criterion_main!(benches);
|
||||
criterion_group!(compare, bench);
|
||||
criterion_main!(compare);
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
use azalea_nbt::Nbt;
|
||||
use criterion::{black_box, criterion_group, criterion_main, Criterion, Throughput};
|
||||
use flate2::read::GzDecoder;
|
||||
use std::{
|
||||
|
@ -7,7 +6,7 @@ use std::{
|
|||
};
|
||||
|
||||
fn bench_file(filename: &str, c: &mut Criterion) {
|
||||
let mut file = File::open(filename).unwrap();
|
||||
let mut file = File::open(format!("tests/{filename}")).unwrap();
|
||||
let mut contents = Vec::new();
|
||||
file.read_to_end(&mut contents).unwrap();
|
||||
let mut src = &contents[..];
|
||||
|
@ -22,26 +21,17 @@ fn bench_file(filename: &str, c: &mut Criterion) {
|
|||
|
||||
let mut decoded_src_stream = Cursor::new(&decoded_src[..]);
|
||||
|
||||
let nbt = Nbt::read(&mut decoded_src_stream).unwrap();
|
||||
decoded_src_stream.set_position(0);
|
||||
|
||||
let mut group = c.benchmark_group(filename);
|
||||
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(|| {
|
||||
black_box(Nbt::read(&mut decoded_src_stream).unwrap());
|
||||
black_box(simdnbt::Nbt::new(&mut decoded_src_stream).unwrap());
|
||||
decoded_src_stream.set_position(0);
|
||||
})
|
||||
});
|
||||
|
||||
group.bench_function("Encode", |b| {
|
||||
b.iter(|| {
|
||||
nbt.write(&mut black_box(Vec::new()));
|
||||
})
|
||||
});
|
||||
|
||||
// group.bench_function("Get", |b| {
|
||||
// b.iter(|| {
|
||||
// let level = nbt
|
||||
|
@ -60,16 +50,16 @@ fn bench_file(filename: &str, c: &mut Criterion) {
|
|||
}
|
||||
|
||||
fn bench(c: &mut Criterion) {
|
||||
// bench_file("tests/bigtest.nbt", c);
|
||||
// bench_file("tests/simple_player.dat", c);
|
||||
// bench_file("tests/complex_player.dat", c);
|
||||
// bench_file("tests/level.dat", c);
|
||||
// bench_file("tests/stringtest.nbt", c);
|
||||
// bench_file("tests/inttest16.nbt", c);
|
||||
// bench_file("bigtest.nbt", c);
|
||||
// bench_file("simple_player.dat", c);
|
||||
bench_file("complex_player.dat", c);
|
||||
// bench_file("level.dat", c);
|
||||
// bench_file("stringtest.nbt", c);
|
||||
// bench_file("inttest16.nbt", c);
|
||||
|
||||
// bench_file("tests/inttest1023.nbt", c);
|
||||
// bench_file("tests/inttest3.nbt", c);
|
||||
// bench_file("inttest1023.nbt", c);
|
||||
// bench_file("inttest3.nbt", c);
|
||||
}
|
||||
|
||||
criterion_group!(benches, bench);
|
||||
criterion_main!(benches);
|
||||
criterion_group!(nbt, bench);
|
||||
criterion_main!(nbt);
|
||||
|
|
196
src/lib.rs
196
src/lib.rs
|
@ -1,3 +1,12 @@
|
|||
/// an unnecessarily fast nbt decoder.
|
||||
///
|
||||
/// ```
|
||||
/// use simdnbt::Nbt;
|
||||
///
|
||||
/// let nbt = Nbt::new(&mut std::io::Cursor::new(include_bytes!("../tests/hello_world.nbt"))).unwrap().unwrap();
|
||||
/// assert_eq!(nbt.name().to_str(), "hello world");
|
||||
/// assert_eq!(nbt.string("name").unwrap().to_str().as_ref(), "Bananrama");
|
||||
/// ```
|
||||
mod error;
|
||||
mod mutf8;
|
||||
|
||||
|
@ -25,10 +34,7 @@ impl<'a> Deref for Nbt<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn read_with_u16_length<'a>(
|
||||
data: &mut Cursor<&'a [u8]>,
|
||||
width: usize,
|
||||
) -> Result<&'a [u8], Error> {
|
||||
fn read_with_u16_length<'a>(data: &mut Cursor<&'a [u8]>, width: usize) -> Result<&'a [u8], Error> {
|
||||
let length = data.read_u16::<BE>()?;
|
||||
let length_in_bytes = length as usize * width;
|
||||
// make sure we don't read more than the length
|
||||
|
@ -40,10 +46,7 @@ pub fn read_with_u16_length<'a>(
|
|||
Ok(&data.get_ref()[start_position..start_position + length_in_bytes])
|
||||
}
|
||||
|
||||
pub fn read_with_u32_length<'a>(
|
||||
data: &mut Cursor<&'a [u8]>,
|
||||
width: usize,
|
||||
) -> Result<&'a [u8], Error> {
|
||||
fn read_with_u32_length<'a>(data: &mut Cursor<&'a [u8]>, width: usize) -> Result<&'a [u8], Error> {
|
||||
let length = data.read_u32::<BE>()?;
|
||||
let length_in_bytes = length as usize * width;
|
||||
// make sure we don't read more than the length
|
||||
|
@ -55,7 +58,7 @@ pub fn read_with_u32_length<'a>(
|
|||
Ok(&data.get_ref()[start_position..start_position + length_in_bytes])
|
||||
}
|
||||
|
||||
pub fn read_string<'a>(data: &mut Cursor<&'a [u8]>) -> Result<&'a Mutf8Str, Error> {
|
||||
fn read_string<'a>(data: &mut Cursor<&'a [u8]>) -> Result<&'a Mutf8Str, Error> {
|
||||
let data = read_with_u16_length(data, 1)?;
|
||||
Ok(Mutf8Str::from_slice(data))
|
||||
}
|
||||
|
@ -76,27 +79,27 @@ impl<'a> Nbt<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub const END_ID: u8 = 0;
|
||||
pub const BYTE_ID: u8 = 1;
|
||||
pub const SHORT_ID: u8 = 2;
|
||||
pub const INT_ID: u8 = 3;
|
||||
pub const LONG_ID: u8 = 4;
|
||||
pub const FLOAT_ID: u8 = 5;
|
||||
pub const DOUBLE_ID: u8 = 6;
|
||||
pub const BYTE_ARRAY_ID: u8 = 7;
|
||||
pub const STRING_ID: u8 = 8;
|
||||
pub const LIST_ID: u8 = 9;
|
||||
pub const COMPOUND_ID: u8 = 10;
|
||||
pub const INT_ARRAY_ID: u8 = 11;
|
||||
pub const LONG_ARRAY_ID: u8 = 12;
|
||||
const END_ID: u8 = 0;
|
||||
const BYTE_ID: u8 = 1;
|
||||
const SHORT_ID: u8 = 2;
|
||||
const INT_ID: u8 = 3;
|
||||
const LONG_ID: u8 = 4;
|
||||
const FLOAT_ID: u8 = 5;
|
||||
const DOUBLE_ID: u8 = 6;
|
||||
const BYTE_ARRAY_ID: u8 = 7;
|
||||
const STRING_ID: u8 = 8;
|
||||
const LIST_ID: u8 = 9;
|
||||
const COMPOUND_ID: u8 = 10;
|
||||
const INT_ARRAY_ID: u8 = 11;
|
||||
const LONG_ARRAY_ID: u8 = 12;
|
||||
|
||||
const MAX_DEPTH: usize = 512;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct CompoundTag<'a> {
|
||||
values: Vec<(&'a Mutf8Str, Tag<'a>)>,
|
||||
}
|
||||
|
||||
const MAX_DEPTH: usize = 512;
|
||||
|
||||
impl<'a> CompoundTag<'a> {
|
||||
fn new(data: &mut Cursor<&'a [u8]>, depth: usize) -> Result<Self, Error> {
|
||||
if depth > MAX_DEPTH {
|
||||
|
@ -133,6 +136,7 @@ impl<'a> CompoundTag<'a> {
|
|||
Ok(Self { values })
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get(&self, name: &str) -> Option<&Tag<'a>> {
|
||||
let name = Mutf8Str::from_str(name);
|
||||
let name = name.as_ref();
|
||||
|
@ -157,148 +161,76 @@ impl<'a> CompoundTag<'a> {
|
|||
}
|
||||
|
||||
pub fn byte(&self, name: &str) -> Option<i8> {
|
||||
let name = Mutf8Str::from_str(name);
|
||||
let name = name.as_ref();
|
||||
for (key, value) in &self.values {
|
||||
if key == &name {
|
||||
if let Tag::Byte(value) = value {
|
||||
return Some(*value);
|
||||
}
|
||||
}
|
||||
match self.get(name) {
|
||||
Some(Tag::Byte(byte)) => Some(*byte),
|
||||
_ => None,
|
||||
}
|
||||
None
|
||||
}
|
||||
pub fn short(&self, name: &str) -> Option<i16> {
|
||||
let name = Mutf8Str::from_str(name);
|
||||
let name = name.as_ref();
|
||||
for (key, value) in &self.values {
|
||||
if key == &name {
|
||||
if let Tag::Short(value) = value {
|
||||
return Some(*value);
|
||||
}
|
||||
}
|
||||
match self.get(name) {
|
||||
Some(Tag::Short(short)) => Some(*short),
|
||||
_ => None,
|
||||
}
|
||||
None
|
||||
}
|
||||
pub fn int(&self, name: &str) -> Option<i32> {
|
||||
let name = Mutf8Str::from_str(name);
|
||||
let name = name.as_ref();
|
||||
for (key, value) in &self.values {
|
||||
if key == &name {
|
||||
if let Tag::Int(value) = value {
|
||||
return Some(*value);
|
||||
}
|
||||
}
|
||||
match self.get(name) {
|
||||
Some(Tag::Int(int)) => Some(*int),
|
||||
_ => None,
|
||||
}
|
||||
None
|
||||
}
|
||||
pub fn long(&self, name: &str) -> Option<i64> {
|
||||
let name = Mutf8Str::from_str(name);
|
||||
let name = name.as_ref();
|
||||
for (key, value) in &self.values {
|
||||
if key == &name {
|
||||
if let Tag::Long(value) = value {
|
||||
return Some(*value);
|
||||
}
|
||||
}
|
||||
match self.get(name) {
|
||||
Some(Tag::Long(long)) => Some(*long),
|
||||
_ => None,
|
||||
}
|
||||
None
|
||||
}
|
||||
pub fn float(&self, name: &str) -> Option<f32> {
|
||||
let name = Mutf8Str::from_str(name);
|
||||
let name = name.as_ref();
|
||||
for (key, value) in &self.values {
|
||||
if key == &name {
|
||||
if let Tag::Float(value) = value {
|
||||
return Some(*value);
|
||||
}
|
||||
}
|
||||
match self.get(name) {
|
||||
Some(Tag::Float(float)) => Some(*float),
|
||||
_ => None,
|
||||
}
|
||||
None
|
||||
}
|
||||
pub fn double(&self, name: &str) -> Option<&f64> {
|
||||
let name = Mutf8Str::from_str(name);
|
||||
let name = name.as_ref();
|
||||
for (key, value) in &self.values {
|
||||
if key == &name {
|
||||
if let Tag::Double(value) = value {
|
||||
return Some(value);
|
||||
}
|
||||
}
|
||||
match self.get(name) {
|
||||
Some(Tag::Double(double)) => Some(double),
|
||||
_ => None,
|
||||
}
|
||||
None
|
||||
}
|
||||
pub fn byte_array(&self, name: &str) -> Option<&[u8]> {
|
||||
let name = Mutf8Str::from_str(name);
|
||||
let name = name.as_ref();
|
||||
for (key, value) in &self.values {
|
||||
if key == &name {
|
||||
if let Tag::ByteArray(value) = value {
|
||||
return Some(value);
|
||||
}
|
||||
}
|
||||
match self.get(name) {
|
||||
Some(Tag::ByteArray(byte_array)) => Some(byte_array),
|
||||
_ => None,
|
||||
}
|
||||
None
|
||||
}
|
||||
pub fn string(&self, name: &str) -> Option<&Mutf8Str> {
|
||||
let name = Mutf8Str::from_str(name);
|
||||
let name = name.as_ref();
|
||||
for (key, value) in &self.values {
|
||||
if key == &name {
|
||||
if let Tag::String(value) = value {
|
||||
return Some(value);
|
||||
}
|
||||
}
|
||||
match self.get(name) {
|
||||
Some(Tag::String(string)) => Some(string),
|
||||
_ => None,
|
||||
}
|
||||
None
|
||||
}
|
||||
pub fn list(&self, name: &str) -> Option<&ListTag<'a>> {
|
||||
let name = Mutf8Str::from_str(name);
|
||||
let name = name.as_ref();
|
||||
for (key, value) in &self.values {
|
||||
if key == &name {
|
||||
if let Tag::List(value) = value {
|
||||
return Some(value);
|
||||
}
|
||||
}
|
||||
match self.get(name) {
|
||||
Some(Tag::List(list)) => Some(list),
|
||||
_ => None,
|
||||
}
|
||||
None
|
||||
}
|
||||
pub fn compound(&self, name: &str) -> Option<&CompoundTag<'a>> {
|
||||
let name = Mutf8Str::from_str(name);
|
||||
let name = name.as_ref();
|
||||
for (key, value) in &self.values {
|
||||
if key == &name {
|
||||
if let Tag::Compound(value) = value {
|
||||
return Some(value);
|
||||
}
|
||||
}
|
||||
match self.get(name) {
|
||||
Some(Tag::Compound(compound)) => Some(compound),
|
||||
_ => None,
|
||||
}
|
||||
None
|
||||
}
|
||||
pub fn int_array(&self, name: &str) -> Option<&[i32]> {
|
||||
let name = Mutf8Str::from_str(name);
|
||||
let name = name.as_ref();
|
||||
for (key, value) in &self.values {
|
||||
if key == &name {
|
||||
if let Tag::IntArray(value) = value {
|
||||
return Some(value);
|
||||
}
|
||||
}
|
||||
match self.get(name) {
|
||||
Some(Tag::IntArray(int_array)) => Some(int_array),
|
||||
_ => None,
|
||||
}
|
||||
None
|
||||
}
|
||||
pub fn long_array(&self, name: &str) -> Option<&[i64]> {
|
||||
let name = Mutf8Str::from_str(name);
|
||||
let name = name.as_ref();
|
||||
for (key, value) in &self.values {
|
||||
if key == &name {
|
||||
if let Tag::LongArray(value) = value {
|
||||
return Some(value);
|
||||
}
|
||||
}
|
||||
match self.get(name) {
|
||||
Some(Tag::LongArray(long_array)) => Some(long_array),
|
||||
_ => None,
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> impl Iterator<Item = (&Mutf8Str, &Tag<'a>)> {
|
||||
|
|
Binary file not shown.
Loading…
Add table
Reference in a new issue