aboutsummaryrefslogtreecommitdiff
path: root/azalea-nbt/src
diff options
context:
space:
mode:
authormat <github@matdoes.dev>2022-04-24 17:37:57 -0500
committermat <github@matdoes.dev>2022-04-24 17:37:57 -0500
commit3e507f0db4020eaf406ba69aae3d4dc1301d29ac (patch)
treeca6c127c9db6dfd14511e98944fc031fe5f1e43a /azalea-nbt/src
parent9f576c5600ba9a244bc0d433bb7de174284066a2 (diff)
parentb7641ff308aab7840d2a2253ae50f8ee496b2a97 (diff)
downloadazalea-drasl-3e507f0db4020eaf406ba69aae3d4dc1301d29ac.tar.xz
Merge branch 'main' into auth
Diffstat (limited to 'azalea-nbt/src')
-rwxr-xr-x[-rw-r--r--]azalea-nbt/src/decode.rs35
-rwxr-xr-x[-rw-r--r--]azalea-nbt/src/encode.rs231
-rwxr-xr-x[-rw-r--r--]azalea-nbt/src/error.rs11
-rwxr-xr-x[-rw-r--r--]azalea-nbt/src/lib.rs0
-rwxr-xr-x[-rw-r--r--]azalea-nbt/src/tag.rs108
5 files changed, 301 insertions, 84 deletions
diff --git a/azalea-nbt/src/decode.rs b/azalea-nbt/src/decode.rs
index 41689a46..3e2f7adb 100644..100755
--- a/azalea-nbt/src/decode.rs
+++ b/azalea-nbt/src/decode.rs
@@ -11,16 +11,17 @@ async fn read_string<R>(stream: &mut R) -> Result<String, Error>
where
R: AsyncRead + std::marker::Unpin,
{
- let length = stream.read_u16().await.map_err(|_| Error::InvalidTag)?;
+ let length = stream.read_u16().await?;
let mut buf = Vec::with_capacity(length as usize);
for _ in 0..length {
- buf.push(stream.read_u8().await.map_err(|_| Error::InvalidTag)?);
+ buf.push(stream.read_u8().await?);
}
- String::from_utf8(buf).map_err(|_| Error::InvalidTag)
+ Ok(String::from_utf8(buf)?)
}
impl Tag {
+ #[inline]
#[async_recursion]
async fn read_known<R>(stream: &mut R, id: u8) -> Result<Tag, Error>
where
@@ -31,26 +32,26 @@ impl Tag {
// a TAG_Compound, and is not named despite being in a TAG_Compound
0 => Tag::End,
// A single signed byte
- 1 => Tag::Byte(stream.read_i8().await.map_err(|_| Error::InvalidTag)?),
+ 1 => Tag::Byte(stream.read_i8().await?),
// A single signed, big endian 16 bit integer
- 2 => Tag::Short(stream.read_i16().await.map_err(|_| Error::InvalidTag)?),
+ 2 => Tag::Short(stream.read_i16().await?),
// A single signed, big endian 32 bit integer
- 3 => Tag::Int(stream.read_i32().await.map_err(|_| Error::InvalidTag)?),
+ 3 => Tag::Int(stream.read_i32().await?),
// A single signed, big endian 64 bit integer
- 4 => Tag::Long(stream.read_i64().await.map_err(|_| Error::InvalidTag)?),
+ 4 => Tag::Long(stream.read_i64().await?),
// A single, big endian IEEE-754 single-precision floating point
// number (NaN possible)
- 5 => Tag::Float(stream.read_f32().await.map_err(|_| Error::InvalidTag)?),
+ 5 => Tag::Float(stream.read_f32().await?),
// A single, big endian IEEE-754 double-precision floating point
// number (NaN possible)
- 6 => Tag::Double(stream.read_f64().await.map_err(|_| Error::InvalidTag)?),
+ 6 => Tag::Double(stream.read_f64().await?),
// A length-prefixed array of signed bytes. The prefix is a signed
// integer (thus 4 bytes)
7 => {
- let length = stream.read_i32().await.map_err(|_| Error::InvalidTag)?;
+ let length = stream.read_i32().await?;
let mut bytes = Vec::with_capacity(length as usize);
for _ in 0..length {
- bytes.push(stream.read_i8().await.map_err(|_| Error::InvalidTag)?);
+ bytes.push(stream.read_i8().await?);
}
Tag::ByteArray(bytes)
}
@@ -67,8 +68,8 @@ impl Tag {
// another reference implementation by Mojang uses 1 instead;
// parsers should accept any type if the length is <= 0).
9 => {
- let type_id = stream.read_u8().await.map_err(|_| Error::InvalidTag)?;
- let length = stream.read_i32().await.map_err(|_| Error::InvalidTag)?;
+ let type_id = stream.read_u8().await?;
+ let length = stream.read_i32().await?;
let mut list = Vec::with_capacity(length as usize);
for _ in 0..length {
list.push(Tag::read_known(stream, type_id).await?);
@@ -94,20 +95,20 @@ impl Tag {
// signed integer (thus 4 bytes) and indicates the number of 4 byte
// integers.
11 => {
- let length = stream.read_i32().await.map_err(|_| Error::InvalidTag)?;
+ let length = stream.read_i32().await?;
let mut ints = Vec::with_capacity(length as usize);
for _ in 0..length {
- ints.push(stream.read_i32().await.map_err(|_| Error::InvalidTag)?);
+ ints.push(stream.read_i32().await?);
}
Tag::IntArray(ints)
}
// A length-prefixed array of signed longs. The prefix is a signed
// integer (thus 4 bytes) and indicates the number of 8 byte longs.
12 => {
- let length = stream.read_i32().await.map_err(|_| Error::InvalidTag)?;
+ let length = stream.read_i32().await?;
let mut longs = Vec::with_capacity(length as usize);
for _ in 0..length {
- longs.push(stream.read_i64().await.map_err(|_| Error::InvalidTag)?);
+ longs.push(stream.read_i64().await?);
}
Tag::LongArray(longs)
}
diff --git a/azalea-nbt/src/encode.rs b/azalea-nbt/src/encode.rs
index 9ce4faf4..20d13793 100644..100755
--- a/azalea-nbt/src/encode.rs
+++ b/azalea-nbt/src/encode.rs
@@ -2,96 +2,197 @@ use crate::Error;
use crate::Tag;
use byteorder::{WriteBytesExt, BE};
use flate2::write::{GzEncoder, ZlibEncoder};
+use std::collections::HashMap;
use std::io::Write;
+// who needs friends when you've got code that runs in nanoseconds?
+
#[inline]
fn write_string(writer: &mut dyn Write, string: &str) -> Result<(), Error> {
- writer
- .write_i16::<BE>(string.len() as i16)
- .map_err(|_| Error::WriteError)?;
- writer
- .write_all(string.as_bytes())
- .map_err(|_| Error::WriteError)?;
+ writer.write_i16::<BE>(string.len() as i16)?;
+ writer.write_all(string.as_bytes())?;
Ok(())
}
-impl Tag {
- pub fn write_without_end(&self, writer: &mut dyn Write) -> Result<(), Error> {
- match self {
+#[inline]
+fn write_compound(
+ writer: &mut dyn Write,
+ value: &HashMap<String, Tag>,
+ end_tag: bool,
+) -> Result<(), Error> {
+ for (key, tag) in value {
+ match tag {
Tag::End => {}
- Tag::Byte(value) => writer.write_i8(*value).map_err(|_| Error::WriteError)?,
- Tag::Short(value) => writer
- .write_i16::<BE>(*value)
- .map_err(|_| Error::WriteError)?,
- Tag::Int(value) => writer
- .write_i32::<BE>(*value)
- .map_err(|_| Error::WriteError)?,
- Tag::Long(value) => writer
- .write_i64::<BE>(*value)
- .map_err(|_| Error::WriteError)?,
- Tag::Float(value) => writer
- .write_f32::<BE>(*value)
- .map_err(|_| Error::WriteError)?,
- Tag::Double(value) => writer
- .write_f64::<BE>(*value)
- .map_err(|_| Error::WriteError)?,
+ Tag::Byte(value) => {
+ writer.write_u8(1)?;
+ write_string(writer, key)?;
+ writer.write_i8(*value)?
+ }
+ Tag::Short(value) => {
+ writer.write_u8(2)?;
+ write_string(writer, key)?;
+ writer.write_i16::<BE>(*value)?
+ }
+ Tag::Int(value) => {
+ writer.write_u8(3)?;
+ write_string(writer, key)?;
+ writer.write_i32::<BE>(*value)?
+ }
+ Tag::Long(value) => {
+ writer.write_u8(4)?;
+ write_string(writer, key)?;
+ writer.write_i64::<BE>(*value)?
+ }
+ Tag::Float(value) => {
+ writer.write_u8(5)?;
+ write_string(writer, key)?;
+ writer.write_f32::<BE>(*value)?
+ }
+ Tag::Double(value) => {
+ writer.write_u8(6)?;
+ write_string(writer, key)?;
+ writer.write_f64::<BE>(*value)?
+ }
Tag::ByteArray(value) => {
- writer
- .write_i32::<BE>(value.len() as i32)
- .map_err(|_| Error::WriteError)?;
+ writer.write_u8(7)?;
+ write_string(writer, key)?;
+ writer.write_i32::<BE>(value.len() as i32)?;
for &byte in value {
- writer.write_i8(byte).map_err(|_| Error::WriteError)?;
+ writer.write_i8(byte)?;
}
}
Tag::String(value) => {
- write_string(writer, value)?;
+ writer.write_u8(8)?;
+ write_string(writer, key)?;
+ write_string(writer, value)?
}
Tag::List(value) => {
- // we just get the type from the first item, or default the type to END
- if value.is_empty() {
- writer.write_i8(0).map_err(|_| Error::WriteError)?;
- writer.write_i32::<BE>(0).map_err(|_| Error::WriteError)?;
- } else {
- let type_id = value[0].id();
- writer.write_u8(type_id).map_err(|_| Error::WriteError)?;
- writer
- .write_i32::<BE>(value.len() as i32)
- .map_err(|_| Error::WriteError)?;
- for tag in value {
- tag.write_without_end(writer)?;
- }
- }
+ writer.write_u8(9)?;
+ write_string(writer, key)?;
+ write_list(writer, value)?
}
Tag::Compound(value) => {
- for (key, tag) in value {
- writer.write_u8(tag.id()).map_err(|_| Error::WriteError)?;
- write_string(writer, key)?;
- tag.write_without_end(writer)?;
- }
- writer
- .write_u8(Tag::End.id())
- .map_err(|_| Error::WriteError)?;
+ writer.write_u8(10)?;
+ write_string(writer, key)?;
+ write_compound(writer, value, true)?
}
Tag::IntArray(value) => {
- writer
- .write_i32::<BE>(value.len() as i32)
- .map_err(|_| Error::WriteError)?;
+ writer.write_u8(11)?;
+ write_string(writer, key)?;
+ writer.write_i32::<BE>(value.len() as i32)?;
for &int in value {
- writer.write_i32::<BE>(int).map_err(|_| Error::WriteError)?;
+ writer.write_i32::<BE>(int)?;
}
}
Tag::LongArray(value) => {
- writer
- .write_i32::<BE>(value.len() as i32)
- .map_err(|_| Error::WriteError)?;
+ writer.write_u8(12)?;
+ write_string(writer, key)?;
+ writer.write_i32::<BE>(value.len() as i32)?;
for &long in value {
- writer
- .write_i64::<BE>(long)
- .map_err(|_| Error::WriteError)?;
+ writer.write_i64::<BE>(long)?;
+ }
+ }
+ }
+ }
+ if end_tag {
+ writer.write_u8(Tag::End.id())?;
+ }
+ return Ok(());
+}
+
+#[inline]
+fn write_list(writer: &mut dyn Write, value: &[Tag]) -> Result<(), Error> {
+ // we just get the type from the first item, or default the type to END
+ if value.is_empty() {
+ writer.write_all(&[0; 5])?;
+ } else {
+ let first_tag = &value[0];
+ writer.write_u8(first_tag.id())?;
+ writer.write_i32::<BE>(value.len() as i32)?;
+ match first_tag {
+ Tag::Int(_) => {
+ for tag in value {
+ writer.write_i32::<BE>(
+ *tag.as_int().expect("List of Int should only contains Int"),
+ )?;
+ }
+ }
+ Tag::String(_) => {
+ for tag in value {
+ write_string(
+ writer,
+ tag.as_string()
+ .expect("List of String should only contain String"),
+ )?;
+ }
+ }
+ Tag::Compound(_) => {
+ for tag in value {
+ write_compound(
+ writer,
+ tag.as_compound()
+ .expect("List of Compound should only contain Compound"),
+ true,
+ )?;
+ }
+ }
+ _ => {
+ for tag in value {
+ tag.write_without_end(writer)?;
}
}
}
+ }
+
+ Ok(())
+}
+
+#[inline]
+fn write_bytearray(writer: &mut dyn Write, value: &Vec<i8>) -> Result<(), Error> {
+ writer.write_i32::<BE>(value.len() as i32)?;
+ for &byte in value {
+ writer.write_i8(byte)?;
+ }
+ Ok(())
+}
+
+#[inline]
+fn write_intarray(writer: &mut dyn Write, value: &Vec<i32>) -> Result<(), Error> {
+ writer.write_i32::<BE>(value.len() as i32)?;
+ for &int in value {
+ writer.write_i32::<BE>(int)?;
+ }
+ Ok(())
+}
+
+#[inline]
+fn write_longarray(writer: &mut dyn Write, value: &Vec<i64>) -> Result<(), Error> {
+ writer.write_i32::<BE>(value.len() as i32)?;
+ for &long in value {
+ writer.write_i64::<BE>(long)?;
+ }
+ Ok(())
+}
+
+impl Tag {
+ #[inline]
+ pub fn write_without_end(&self, writer: &mut dyn Write) -> Result<(), Error> {
+ match self {
+ Tag::End => {}
+ Tag::Byte(value) => writer.write_i8(*value)?,
+ Tag::Short(value) => writer.write_i16::<BE>(*value)?,
+ Tag::Int(value) => writer.write_i32::<BE>(*value)?,
+ Tag::Long(value) => writer.write_i64::<BE>(*value)?,
+ Tag::Float(value) => writer.write_f32::<BE>(*value)?,
+ Tag::Double(value) => writer.write_f64::<BE>(*value)?,
+ Tag::ByteArray(value) => write_bytearray(writer, value)?,
+ Tag::String(value) => write_string(writer, value)?,
+ Tag::List(value) => write_list(writer, value)?,
+ Tag::Compound(value) => write_compound(writer, value, true)?,
+ Tag::IntArray(value) => write_intarray(writer, value)?,
+ Tag::LongArray(value) => write_longarray(writer, value)?,
+ }
Ok(())
}
@@ -99,11 +200,7 @@ impl Tag {
pub fn write(&self, writer: &mut impl Write) -> Result<(), Error> {
match self {
Tag::Compound(value) => {
- for (key, tag) in value {
- writer.write_u8(tag.id()).map_err(|_| Error::WriteError)?;
- write_string(writer, key)?;
- tag.write_without_end(writer)?;
- }
+ write_compound(writer, value, false)?;
Ok(())
}
_ => Err(Error::InvalidTag),
diff --git a/azalea-nbt/src/error.rs b/azalea-nbt/src/error.rs
index 05ff15e0..219921e4 100644..100755
--- a/azalea-nbt/src/error.rs
+++ b/azalea-nbt/src/error.rs
@@ -14,3 +14,14 @@ impl std::fmt::Display for Error {
}
}
}
+
+impl From<std::io::Error> for Error {
+ fn from(_: std::io::Error) -> Self {
+ Error::WriteError
+ }
+}
+impl From<std::string::FromUtf8Error> for Error {
+ fn from(_: std::string::FromUtf8Error) -> Self {
+ Error::WriteError
+ }
+}
diff --git a/azalea-nbt/src/lib.rs b/azalea-nbt/src/lib.rs
index d14fd929..d14fd929 100644..100755
--- a/azalea-nbt/src/lib.rs
+++ b/azalea-nbt/src/lib.rs
diff --git a/azalea-nbt/src/tag.rs b/azalea-nbt/src/tag.rs
index f11b8889..61bd15ba 100644..100755
--- a/azalea-nbt/src/tag.rs
+++ b/azalea-nbt/src/tag.rs
@@ -36,4 +36,112 @@ impl Tag {
Tag::LongArray(_) => 12,
}
}
+
+ #[inline]
+ pub fn as_byte(&self) -> Option<&i8> {
+ if let Tag::Byte(v) = self {
+ Some(v)
+ } else {
+ None
+ }
+ }
+
+ #[inline]
+ pub fn as_short(&self) -> Option<&i16> {
+ if let Tag::Short(v) = self {
+ Some(v)
+ } else {
+ None
+ }
+ }
+
+ #[inline]
+ pub fn as_int(&self) -> Option<&i32> {
+ if let Tag::Int(v) = self {
+ Some(v)
+ } else {
+ None
+ }
+ }
+
+ #[inline]
+ pub fn as_long(&self) -> Option<&i64> {
+ if let Tag::Long(v) = self {
+ Some(v)
+ } else {
+ None
+ }
+ }
+
+ #[inline]
+ pub fn as_float(&self) -> Option<&f32> {
+ if let Tag::Float(v) = self {
+ Some(v)
+ } else {
+ None
+ }
+ }
+
+ #[inline]
+ pub fn as_double(&self) -> Option<&f64> {
+ if let Tag::Double(v) = self {
+ Some(v)
+ } else {
+ None
+ }
+ }
+
+ #[inline]
+ pub fn as_string(&self) -> Option<&str> {
+ if let Tag::String(v) = self {
+ Some(v)
+ } else {
+ None
+ }
+ }
+
+ #[inline]
+ pub fn as_compound(&self) -> Option<&HashMap<String, Tag>> {
+ if let Tag::Compound(v) = self {
+ Some(v)
+ } else {
+ None
+ }
+ }
+
+ #[inline]
+ pub fn as_bytearray(&self) -> Option<&Vec<i8>> {
+ if let Tag::ByteArray(v) = self {
+ Some(v)
+ } else {
+ None
+ }
+ }
+
+ #[inline]
+ pub fn as_intarray(&self) -> Option<&Vec<i32>> {
+ if let Tag::IntArray(v) = self {
+ Some(v)
+ } else {
+ None
+ }
+ }
+
+ #[inline]
+ pub fn as_longarray(&self) -> Option<&Vec<i64>> {
+ if let Tag::LongArray(v) = self {
+ Some(v)
+ } else {
+ None
+ }
+ }
+
+ #[inline]
+ pub fn as_list(&self) -> Option<&[Tag]> {
+ if let Tag::List(v) = self {
+ Some(v)
+ } else {
+ None
+ }
+ }
}