diff --git a/Cargo.toml b/Cargo.toml index e8aaad0..447dc48 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -69,4 +69,4 @@ rayon = "1" num = "0.4" [workspace] -members = ["serde_nbt", "packet_inspector"] +members = ["packet_inspector"] diff --git a/serde_nbt/Cargo.toml b/serde_nbt/Cargo.toml deleted file mode 100644 index 9a063bf..0000000 --- a/serde_nbt/Cargo.toml +++ /dev/null @@ -1,23 +0,0 @@ -[package] -name = "serde_nbt" -description = "A Serde library for Minecraft's Named Binary Tag (NBT) format." -documentation = "https://docs.rs/serde_nbt/" -repository = "https://github.com/rj00a/valence/tree/main/serde_nbt" -readme = "README.md" -license = "MIT" -keywords = ["nbt", "minecraft", "serde", "serialization"] -version = "0.1.0" -authors = ["Ryan Johnson "] -edition = "2021" - -[dependencies] -byteorder = "1.4.3" -cesu8 = "1.1.0" -indexmap = { version = "1.9.1", features = ["serde"] } -serde = "1" -smallvec = { version = "1.9.0", features = ["union"] } - -[dev-dependencies] -hematite-nbt = "0.5.2" -serde_json = "1.0.85" -pretty_assertions = "1.2.1" diff --git a/serde_nbt/README.md b/serde_nbt/README.md deleted file mode 100644 index a5d9b44..0000000 --- a/serde_nbt/README.md +++ /dev/null @@ -1,4 +0,0 @@ -A Serde library for serializing and deserializing -Minecraft's [Named Binary Tag](https://minecraft.fandom.com/wiki/NBT_format) (NBT) format. - -For more information, see the documentation [here](https://docs.rs/serde_nbt). diff --git a/serde_nbt/src/array.rs b/serde_nbt/src/array.rs deleted file mode 100644 index 5ac5003..0000000 --- a/serde_nbt/src/array.rs +++ /dev/null @@ -1,101 +0,0 @@ -use std::fmt::Formatter; -use std::marker::PhantomData; - -use serde::de::value::SeqAccessDeserializer; -use serde::de::{EnumAccess, IgnoredAny, SeqAccess, VariantAccess, Visitor}; -use serde::{Deserialize, Deserializer, Serialize, Serializer}; - -use crate::{ - ARRAY_ENUM_NAME, BYTE_ARRAY_VARIANT_NAME, INT_ARRAY_VARIANT_NAME, LONG_ARRAY_VARIANT_NAME, -}; - -macro_rules! def_mod { - ($index:literal, $mod_name:ident, $display_name:literal, $variant_name:ident) => { - /// Provides (de)serialization support for the NBT type - #[doc = concat!(" \"", $display_name, "\".")] - /// - /// This module is intended to be the target of serde's `#[serde(with = - /// "module")]` field attribute. - /// - /// The target field must serialize and deserialize as a seq. - /// - /// # Examples - /// - /// ``` - /// use serde::{Deserialize, Serialize}; - /// use serde_nbt::binary::to_writer; - /// - /// #[derive(Serialize, Deserialize)] - /// struct MyStruct { - /// #[serde(with = "serde_nbt::int_array")] - /// array: Vec, - /// } - /// - /// let s = MyStruct { - /// array: vec![1, 2, 3], - /// }; - /// - /// let mut buf = Vec::new(); - /// to_writer(&mut buf, &s).unwrap(); - /// ``` - pub mod $mod_name { - use super::*; - - pub fn serialize(array: &T, serializer: S) -> Result - where - T: Serialize, - S: Serializer, - { - serializer.serialize_newtype_variant(ARRAY_ENUM_NAME, $index, $variant_name, array) - } - - pub fn deserialize<'de, T, D>(deserializer: D) -> Result - where - T: Deserialize<'de>, - D: Deserializer<'de>, - { - struct ArrayVisitor(PhantomData); - - impl<'de, T: Deserialize<'de>> Visitor<'de> for ArrayVisitor { - type Value = T; - - fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result { - write!( - formatter, - concat!("an NBT ", $display_name, " encoded as an enum or seq") - ) - } - - fn visit_seq(self, seq: A) -> Result - where - A: SeqAccess<'de>, - { - T::deserialize(SeqAccessDeserializer::new(seq)) - } - - fn visit_enum(self, data: A) -> Result - where - A: EnumAccess<'de>, - { - // Ignore the variant name. - let (_, variant) = data.variant::()?; - - variant.newtype_variant() - } - } - - let variants = &[ - BYTE_ARRAY_VARIANT_NAME, - INT_ARRAY_VARIANT_NAME, - LONG_ARRAY_VARIANT_NAME, - ]; - - deserializer.deserialize_enum(ARRAY_ENUM_NAME, variants, ArrayVisitor(PhantomData)) - } - } - }; -} - -def_mod!(0, byte_array, "byte array", BYTE_ARRAY_VARIANT_NAME); -def_mod!(1, int_array, "int array", INT_ARRAY_VARIANT_NAME); -def_mod!(2, long_array, "long array", LONG_ARRAY_VARIANT_NAME); diff --git a/serde_nbt/src/binary/de.rs b/serde_nbt/src/binary/de.rs deleted file mode 100644 index 2097bba..0000000 --- a/serde_nbt/src/binary/de.rs +++ /dev/null @@ -1,24 +0,0 @@ -use std::io::Read; - -pub use root::RootDeserializer as Deserializer; -use serde::de::DeserializeOwned; - -use crate::Error; - -mod array; -mod compound; -mod list; -mod payload; -mod root; - -/// Reads uncompressed NBT binary data from the provided reader. -/// -/// The name of the root compound is discarded. If you need access to it, see -/// [`Deserializer`]. -pub fn from_reader(reader: R) -> Result -where - R: Read, - T: DeserializeOwned, -{ - T::deserialize(&mut Deserializer::new(reader, false)) -} diff --git a/serde_nbt/src/binary/de/array.rs b/serde_nbt/src/binary/de/array.rs deleted file mode 100644 index e1c7689..0000000 --- a/serde_nbt/src/binary/de/array.rs +++ /dev/null @@ -1,157 +0,0 @@ -use std::io::Read; - -use byteorder::{BigEndian, ReadBytesExt}; -use serde::de::value::StrDeserializer; -use serde::de::{DeserializeSeed, Error as _, SeqAccess, Unexpected, Visitor}; -use serde::{de, forward_to_deserialize_any, Deserializer}; - -use crate::binary::de::payload::PayloadDeserializer; -use crate::{ - ArrayType, Error, BYTE_ARRAY_VARIANT_NAME, INT_ARRAY_VARIANT_NAME, LONG_ARRAY_VARIANT_NAME, -}; - -pub struct EnumAccess<'r, R: ?Sized> { - pub(super) reader: &'r mut R, - pub(super) array_type: ArrayType, -} - -impl<'de: 'r, 'r, R: Read + ?Sized> de::EnumAccess<'de> for EnumAccess<'r, R> { - type Error = Error; - type Variant = VariantAccess<'r, R>; - - fn variant_seed(self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error> - where - V: DeserializeSeed<'de>, - { - let variant_name = match self.array_type { - ArrayType::Byte => BYTE_ARRAY_VARIANT_NAME, - ArrayType::Int => INT_ARRAY_VARIANT_NAME, - ArrayType::Long => LONG_ARRAY_VARIANT_NAME, - }; - - Ok(( - seed.deserialize(StrDeserializer::::new(variant_name))?, - VariantAccess { - reader: self.reader, - array_type: self.array_type, - }, - )) - } -} - -pub struct VariantAccess<'r, R: ?Sized> { - reader: &'r mut R, - array_type: ArrayType, -} - -impl<'de: 'r, 'r, R: Read + ?Sized> de::VariantAccess<'de> for VariantAccess<'r, R> { - type Error = Error; - - fn unit_variant(self) -> Result<(), Self::Error> { - Err(Error::invalid_type( - Unexpected::NewtypeVariant, - &"unit variant", - )) - } - - fn newtype_variant_seed(self, seed: T) -> Result - where - T: DeserializeSeed<'de>, - { - seed.deserialize(ArrayDeserializer { - reader: self.reader, - array_type: self.array_type, - }) - } - - fn tuple_variant(self, _len: usize, _visitor: V) -> Result - where - V: Visitor<'de>, - { - Err(Error::invalid_type( - Unexpected::NewtypeVariant, - &"tuple variant", - )) - } - - fn struct_variant( - self, - _fields: &'static [&'static str], - _visitor: V, - ) -> Result - where - V: Visitor<'de>, - { - Err(Error::invalid_type( - Unexpected::NewtypeVariant, - &"struct variant", - )) - } -} - -struct ArrayDeserializer<'r, R: ?Sized> { - reader: &'r mut R, - array_type: ArrayType, -} - -impl<'de: 'r, 'r, R: Read + ?Sized> Deserializer<'de> for ArrayDeserializer<'r, R> { - type Error = Error; - - forward_to_deserialize_any! { - bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string - bytes byte_buf option unit unit_struct newtype_struct seq tuple - tuple_struct map struct enum identifier ignored_any - } - - fn deserialize_any(self, visitor: V) -> Result - where - V: Visitor<'de>, - { - let len = self.reader.read_i32::()?; - - if len < 0 { - return Err(Error::new_static("array with negative length")); - } - - visitor.visit_seq(ArraySeqAccess { - reader: self.reader, - array_type: self.array_type, - remaining: len, - }) - } - - fn is_human_readable(&self) -> bool { - false - } -} - -struct ArraySeqAccess<'r, R: ?Sized> { - reader: &'r mut R, - array_type: ArrayType, - remaining: i32, -} - -impl<'de: 'r, 'r, R: Read + ?Sized> SeqAccess<'de> for ArraySeqAccess<'r, R> { - type Error = Error; - - fn next_element_seed(&mut self, seed: T) -> Result, Self::Error> - where - T: DeserializeSeed<'de>, - { - if self.remaining > 0 { - self.remaining -= 1; - - seed.deserialize(PayloadDeserializer { - reader: self.reader, - tag: self.array_type.element_tag(), - }) - .map(Some) - } else { - Ok(None) - } - } - - fn size_hint(&self) -> Option { - Some(self.remaining as usize) - } -} diff --git a/serde_nbt/src/binary/de/compound.rs b/serde_nbt/src/binary/de/compound.rs deleted file mode 100644 index 80ca98d..0000000 --- a/serde_nbt/src/binary/de/compound.rs +++ /dev/null @@ -1,76 +0,0 @@ -use std::io::Read; - -use byteorder::ReadBytesExt; -use serde::de; -use serde::de::DeserializeSeed; - -use crate::binary::de::payload::PayloadDeserializer; -use crate::{Error, Tag}; - -pub struct MapAccess<'r, R: ?Sized> { - reader: &'r mut R, - value_tag: Tag, - /// Provides error context when deserializing structs. - fields: &'static [&'static str], -} - -impl<'r, R: Read + ?Sized> MapAccess<'r, R> { - pub fn new(reader: &'r mut R, fields: &'static [&'static str]) -> Self { - Self { - reader, - value_tag: Tag::End, - fields, - } - } -} - -impl<'de: 'r, 'r, R: Read + ?Sized> de::MapAccess<'de> for MapAccess<'r, R> { - type Error = Error; - - fn next_key_seed(&mut self, seed: K) -> Result, Self::Error> - where - K: DeserializeSeed<'de>, - { - self.value_tag = Tag::from_u8(self.reader.read_u8()?)?; - - if self.value_tag == Tag::End { - return Ok(None); - } - - seed.deserialize(PayloadDeserializer { - reader: self.reader, - tag: Tag::String, - }) - .map(Some) - .map_err(|e| match self.fields { - [f, ..] => e.field(*f), - [] => e, - }) - } - - fn next_value_seed(&mut self, seed: V) -> Result - where - V: DeserializeSeed<'de>, - { - if self.value_tag == Tag::End { - return Err(Error::new_static("end of compound?")); - } - - let field = match self.fields { - [field, rest @ ..] => { - self.fields = rest; - Some(*field) - } - [] => None, - }; - - seed.deserialize(PayloadDeserializer { - reader: self.reader, - tag: self.value_tag, - }) - .map_err(|e| match field { - Some(f) => e.field(f), - None => e, - }) - } -} diff --git a/serde_nbt/src/binary/de/list.rs b/serde_nbt/src/binary/de/list.rs deleted file mode 100644 index 4014015..0000000 --- a/serde_nbt/src/binary/de/list.rs +++ /dev/null @@ -1,38 +0,0 @@ -use std::io::Read; - -use serde::de; -use serde::de::DeserializeSeed; - -use crate::binary::de::payload::PayloadDeserializer; -use crate::{Error, Tag}; - -pub(super) struct SeqAccess<'r, R: ?Sized> { - pub reader: &'r mut R, - pub element_tag: Tag, - pub remaining: u32, -} - -impl<'de: 'r, 'r, R: Read + ?Sized> de::SeqAccess<'de> for SeqAccess<'r, R> { - type Error = Error; - - fn next_element_seed(&mut self, seed: T) -> Result, Self::Error> - where - T: DeserializeSeed<'de>, - { - if self.remaining > 0 { - self.remaining -= 1; - - seed.deserialize(PayloadDeserializer { - reader: self.reader, - tag: self.element_tag, - }) - .map(Some) - } else { - Ok(None) - } - } - - fn size_hint(&self) -> Option { - Some(self.remaining as usize) - } -} diff --git a/serde_nbt/src/binary/de/payload.rs b/serde_nbt/src/binary/de/payload.rs deleted file mode 100644 index d5af761..0000000 --- a/serde_nbt/src/binary/de/payload.rs +++ /dev/null @@ -1,130 +0,0 @@ -use std::borrow::Cow; -use std::io::Read; - -use byteorder::{BigEndian, ReadBytesExt}; -use cesu8::from_java_cesu8; -use serde::de::Visitor; -use serde::{de, forward_to_deserialize_any}; -use smallvec::SmallVec; - -use crate::binary::de::array::EnumAccess; -use crate::binary::de::compound::MapAccess; -use crate::binary::de::list::SeqAccess; -use crate::{ArrayType, Error, Tag, CESU8_DECODE_ERROR}; - -pub(super) struct PayloadDeserializer<'w, R: ?Sized> { - pub reader: &'w mut R, - /// The type of payload to be deserialized. - pub tag: Tag, -} - -impl<'de: 'w, 'w, R: Read + ?Sized> de::Deserializer<'de> for PayloadDeserializer<'w, R> { - type Error = Error; - - forward_to_deserialize_any! { - i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string - bytes byte_buf unit unit_struct newtype_struct seq tuple - tuple_struct map enum identifier ignored_any - } - - fn deserialize_any(self, visitor: V) -> Result - where - V: Visitor<'de>, - { - match self.tag { - Tag::End => unreachable!("invalid payload tag"), - Tag::Byte => visitor.visit_i8(self.reader.read_i8()?), - Tag::Short => visitor.visit_i16(self.reader.read_i16::()?), - Tag::Int => visitor.visit_i32(self.reader.read_i32::()?), - Tag::Long => visitor.visit_i64(self.reader.read_i64::()?), - Tag::Float => visitor.visit_f32(self.reader.read_f32::()?), - Tag::Double => visitor.visit_f64(self.reader.read_f64::()?), - Tag::ByteArray => visitor.visit_enum(EnumAccess { - reader: self.reader, - array_type: ArrayType::Byte, - }), - Tag::String => { - let mut buf = SmallVec::<[u8; 128]>::new(); - for _ in 0..self.reader.read_u16::()? { - buf.push(self.reader.read_u8()?); - } - - match from_java_cesu8(&buf).map_err(|_| Error::new_static(CESU8_DECODE_ERROR))? { - Cow::Borrowed(s) => visitor.visit_str(s), - Cow::Owned(string) => visitor.visit_string(string), - } - } - Tag::List => { - let element_tag = Tag::from_u8(self.reader.read_u8()?)?; - let len = self.reader.read_i32::()?; - - if len < 0 { - return Err(Error::new_static("list with negative length")); - } - - if element_tag == Tag::End && len != 0 { - return Err(Error::new_static( - "list with TAG_End element type must have length zero", - )); - } - - visitor.visit_seq(SeqAccess { - reader: self.reader, - element_tag, - remaining: len as u32, - }) - } - Tag::Compound => visitor.visit_map(MapAccess::new(self.reader, &[])), - Tag::IntArray => visitor.visit_enum(EnumAccess { - reader: self.reader, - array_type: ArrayType::Int, - }), - Tag::LongArray => visitor.visit_enum(EnumAccess { - reader: self.reader, - array_type: ArrayType::Long, - }), - } - } - - fn deserialize_bool(self, visitor: V) -> Result - where - V: Visitor<'de>, - { - if self.tag == Tag::Byte { - match self.reader.read_i8()? { - 0 => visitor.visit_bool(false), - 1 => visitor.visit_bool(true), - n => visitor.visit_i8(n), - } - } else { - self.deserialize_any(visitor) - } - } - - fn deserialize_option(self, visitor: V) -> Result - where - V: Visitor<'de>, - { - visitor.visit_some(self) - } - - fn deserialize_struct( - self, - _name: &'static str, - fields: &'static [&'static str], - visitor: V, - ) -> Result - where - V: Visitor<'de>, - { - if self.tag == Tag::Compound { - visitor.visit_map(MapAccess::new(self.reader, fields)) - } else { - self.deserialize_any(visitor) - } - } - - fn is_human_readable(&self) -> bool { - false - } -} diff --git a/serde_nbt/src/binary/de/root.rs b/serde_nbt/src/binary/de/root.rs deleted file mode 100644 index b296393..0000000 --- a/serde_nbt/src/binary/de/root.rs +++ /dev/null @@ -1,111 +0,0 @@ -use std::borrow::Cow; -use std::io::Read; - -use byteorder::{BigEndian, ReadBytesExt}; -use cesu8::from_java_cesu8; -use serde::de::Visitor; -use serde::{forward_to_deserialize_any, Deserializer}; -use smallvec::SmallVec; - -use crate::binary::de::payload::PayloadDeserializer; -use crate::{Error, Tag, CESU8_DECODE_ERROR}; - -/// A serde [`Deserializer`] for the binary representation of NBT. -#[non_exhaustive] -pub struct RootDeserializer { - /// The reader to deserialize from. - pub reader: R, - /// The name of the root compound that was deserialized. If - /// [`Self::save_root_name`] is false, then deserialization will not - /// update this value. - pub root_name: String, - /// Whether or not the root name should be saved to [`Self::root_name`] - /// during deserialization. - pub save_root_name: bool, -} - -impl RootDeserializer { - /// Constructs a new deserializer - /// - /// [`Self::root_name`] is set to the empty string. - pub fn new(reader: R, save_root_name: bool) -> Self { - Self { - reader, - root_name: String::new(), - save_root_name, - } - } - - fn read_name(&mut self) -> Result { - let tag = Tag::from_u8(self.reader.read_u8()?)?; - - if tag != Tag::Compound { - return Err(Error::new_owned(format!( - "unexpected tag `{tag}` (root value must be a compound)" - ))); - } - - if self.save_root_name { - let mut buf = SmallVec::<[u8; 128]>::new(); - for _ in 0..self.reader.read_u16::()? { - buf.push(self.reader.read_u8()?); - } - - match from_java_cesu8(&buf).map_err(|_| Error::new_static(CESU8_DECODE_ERROR))? { - Cow::Borrowed(s) => s.clone_into(&mut self.root_name), - Cow::Owned(s) => self.root_name = s, - } - } else { - for _ in 0..self.reader.read_u16::()? { - self.reader.read_u8()?; - } - } - - Ok(tag) - } -} - -impl<'de: 'a, 'a, R: Read> Deserializer<'de> for &'a mut RootDeserializer { - type Error = Error; - - forward_to_deserialize_any! { - bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string - bytes byte_buf option unit unit_struct newtype_struct seq tuple - tuple_struct map enum identifier ignored_any - } - - fn deserialize_any(self, visitor: V) -> Result - where - V: Visitor<'de>, - { - let tag = self.read_name()?; - - PayloadDeserializer { - reader: &mut self.reader, - tag, - } - .deserialize_any(visitor) - } - - fn deserialize_struct( - self, - name: &'static str, - fields: &'static [&'static str], - visitor: V, - ) -> Result - where - V: Visitor<'de>, - { - let tag = self.read_name()?; - - PayloadDeserializer { - reader: &mut self.reader, - tag, - } - .deserialize_struct(name, fields, visitor) - } - - fn is_human_readable(&self) -> bool { - false - } -} diff --git a/serde_nbt/src/binary/ser.rs b/serde_nbt/src/binary/ser.rs deleted file mode 100644 index f9a4ea3..0000000 --- a/serde_nbt/src/binary/ser.rs +++ /dev/null @@ -1,43 +0,0 @@ -use std::io::Write; - -use byteorder::{BigEndian, WriteBytesExt}; -use cesu8::to_java_cesu8; -pub use root::RootSerializer as Serializer; -use serde::{ser, Serialize}; - -use crate::{Error, Result}; - -mod map; -mod payload; -mod root; -mod seq; -mod structs; - -/// Writes uncompressed NBT binary data to the provided writer. -/// -/// Note that serialization will fail if the provided value does not serialize -/// as a compound (a map or struct). This is because the NBT format requires the -/// root value to be a named compound. -/// -/// The name of the root compound will be `""`. If you want to use a different -/// name, see [`Serializer`]. -pub fn to_writer(writer: W, value: &T) -> Result<()> -where - W: Write, - T: Serialize + ?Sized, -{ - value.serialize(&mut Serializer::new(writer, "")) -} - -type Impossible = ser::Impossible<(), Error>; - -fn write_string(mut writer: impl Write, string: &str) -> Result<()> { - let data = to_java_cesu8(string); - match data.len().try_into() { - Ok(len) => writer.write_u16::(len)?, - Err(_) => return Err(Error::new_static("string byte length exceeds u16::MAX")), - }; - - writer.write_all(&data)?; - Ok(()) -} diff --git a/serde_nbt/src/binary/ser/map.rs b/serde_nbt/src/binary/ser/map.rs deleted file mode 100644 index ac99dba..0000000 --- a/serde_nbt/src/binary/ser/map.rs +++ /dev/null @@ -1,243 +0,0 @@ -use std::io::Write; - -use byteorder::WriteBytesExt; -use serde::{ser, Serialize, Serializer}; - -use crate::binary::ser::payload::PayloadSerializer; -use crate::binary::ser::Impossible; -use crate::{Error, Tag}; - -pub struct SerializeMap<'w, W: ?Sized> { - pub(super) writer: &'w mut W, -} - -impl<'w, W: Write + ?Sized> ser::SerializeMap for SerializeMap<'w, W> { - type Ok = (); - type Error = Error; - - fn serialize_key(&mut self, _key: &T) -> Result<(), Error> - where - T: Serialize, - { - Err(Error::new_static( - "map keys cannot be serialized individually", - )) - } - - fn serialize_value(&mut self, _value: &T) -> Result<(), Error> - where - T: Serialize, - { - Err(Error::new_static( - "map values cannot be serialized individually", - )) - } - - fn serialize_entry( - &mut self, - key: &K, - value: &V, - ) -> Result<(), Self::Error> - where - K: Serialize, - V: Serialize, - { - key.serialize(MapEntrySerializer { - writer: self.writer, - value, - }) - } - - fn end(self) -> Result { - Ok(self.writer.write_u8(Tag::End as u8)?) - } -} - -struct MapEntrySerializer<'w, 'v, W: ?Sized, V: ?Sized> { - writer: &'w mut W, - value: &'v V, -} - -macro_rules! non_string_map_key { - ($typ:literal) => { - Err(Error::new_static(concat!( - "map keys must be strings (got ", - $typ, - ")" - ))) - }; -} - -impl Serializer for MapEntrySerializer<'_, '_, W, V> { - type Ok = (); - type Error = Error; - type SerializeSeq = Impossible; - type SerializeTuple = Impossible; - type SerializeTupleStruct = Impossible; - type SerializeTupleVariant = Impossible; - type SerializeMap = Impossible; - type SerializeStruct = Impossible; - type SerializeStructVariant = Impossible; - - fn serialize_bool(self, _v: bool) -> Result { - non_string_map_key!("bool") - } - - fn serialize_i8(self, _v: i8) -> Result { - non_string_map_key!("i8") - } - - fn serialize_i16(self, _v: i16) -> Result { - non_string_map_key!("i16") - } - - fn serialize_i32(self, _v: i32) -> Result { - non_string_map_key!("i32") - } - - fn serialize_i64(self, _v: i64) -> Result { - non_string_map_key!("i64") - } - - fn serialize_u8(self, _v: u8) -> Result { - non_string_map_key!("u8") - } - - fn serialize_u16(self, _v: u16) -> Result { - non_string_map_key!("u16") - } - - fn serialize_u32(self, _v: u32) -> Result { - non_string_map_key!("u32") - } - - fn serialize_u64(self, _v: u64) -> Result { - non_string_map_key!("u64") - } - - fn serialize_f32(self, _v: f32) -> Result { - non_string_map_key!("f32") - } - - fn serialize_f64(self, _v: f64) -> Result { - non_string_map_key!("f64") - } - - fn serialize_char(self, _v: char) -> Result { - non_string_map_key!("char") - } - - fn serialize_str(self, v: &str) -> Result { - self.value - .serialize(&mut PayloadSerializer::named(self.writer, v)) - .map_err(|e| e.field(v)) - } - - fn serialize_bytes(self, _v: &[u8]) -> Result { - non_string_map_key!("&[u8]") - } - - fn serialize_none(self) -> Result { - non_string_map_key!("None") - } - - fn serialize_some(self, _value: &T) -> Result - where - T: Serialize, - { - non_string_map_key!("Some") - } - - fn serialize_unit(self) -> Result { - non_string_map_key!("()") - } - - fn serialize_unit_struct(self, _name: &'static str) -> Result { - non_string_map_key!("unit struct") - } - - fn serialize_unit_variant( - self, - _name: &'static str, - _variant_index: u32, - _variant: &'static str, - ) -> Result { - non_string_map_key!("unit variant") - } - - fn serialize_newtype_struct( - self, - _name: &'static str, - _value: &T, - ) -> Result - where - T: Serialize, - { - non_string_map_key!("newtype struct") - } - - fn serialize_newtype_variant( - self, - _name: &'static str, - _variant_index: u32, - _variant: &'static str, - _value: &T, - ) -> Result - where - T: Serialize, - { - non_string_map_key!("newtype variant") - } - - fn serialize_seq(self, _len: Option) -> Result { - non_string_map_key!("seq") - } - - fn serialize_tuple(self, _len: usize) -> Result { - non_string_map_key!("tuple") - } - - fn serialize_tuple_struct( - self, - _name: &'static str, - _len: usize, - ) -> Result { - non_string_map_key!("tuple struct") - } - - fn serialize_tuple_variant( - self, - _name: &'static str, - _variant_index: u32, - _variant: &'static str, - _len: usize, - ) -> Result { - non_string_map_key!("tuple variant") - } - - fn serialize_map(self, _len: Option) -> Result { - non_string_map_key!("map") - } - - fn serialize_struct( - self, - _name: &'static str, - _len: usize, - ) -> Result { - non_string_map_key!("struct") - } - - fn serialize_struct_variant( - self, - _name: &'static str, - _variant_index: u32, - _variant: &'static str, - _len: usize, - ) -> Result { - non_string_map_key!("struct variant") - } - - fn is_human_readable(&self) -> bool { - false - } -} diff --git a/serde_nbt/src/binary/ser/payload.rs b/serde_nbt/src/binary/ser/payload.rs deleted file mode 100644 index 74064ea..0000000 --- a/serde_nbt/src/binary/ser/payload.rs +++ /dev/null @@ -1,334 +0,0 @@ -use std::io::Write; - -use byteorder::{BigEndian, WriteBytesExt}; -use serde::{Serialize, Serializer}; - -use crate::binary::ser::map::SerializeMap; -use crate::binary::ser::seq::SerializeSeq; -use crate::binary::ser::structs::SerializeStruct; -use crate::binary::ser::{write_string, Impossible}; -use crate::{ArrayType, Error, Tag}; - -pub struct PayloadSerializer<'w, 'n, W: ?Sized> { - writer: &'w mut W, - state: State<'n>, -} - -#[derive(Clone, Copy)] -enum State<'n> { - Named(&'n str), - FirstListElement { len: i32, written_tag: Tag }, - SeqElement { element_type: Tag }, - Array(ArrayType), -} - -impl<'w, 'n, W: Write + ?Sized> PayloadSerializer<'w, 'n, W> { - pub(super) fn named(writer: &'w mut W, name: &'n str) -> Self { - Self { - writer, - state: State::Named(name), - } - } - - pub(super) fn first_list_element(writer: &'w mut W, len: i32) -> Self { - Self { - writer, - state: State::FirstListElement { - len, - written_tag: Tag::End, - }, - } - } - - pub(super) fn seq_element(writer: &'w mut W, element_type: Tag) -> Self { - Self { - writer, - state: State::SeqElement { element_type }, - } - } - - pub(super) fn written_tag(&self) -> Option { - match self.state { - State::FirstListElement { written_tag, .. } if written_tag != Tag::End => { - Some(written_tag) - } - _ => None, - } - } - - fn check_state(&mut self, tag: Tag) -> Result<(), Error> { - match &mut self.state { - State::Named(name) => { - self.writer.write_u8(tag as u8)?; - write_string(&mut *self.writer, name)?; - } - State::FirstListElement { len, written_tag } => { - self.writer.write_u8(tag as u8)?; - self.writer.write_i32::(*len)?; - *written_tag = tag; - } - State::SeqElement { element_type } => { - if tag != *element_type { - return Err(Error::new_owned(format!( - "list/array elements must be homogeneous (got {tag}, expected \ - {element_type})" - ))); - } - } - State::Array(array_type) => { - let msg = match array_type { - ArrayType::Byte => "a byte array", - ArrayType::Int => "an int array", - ArrayType::Long => "a long array", - }; - - return Err(Error::new_owned(format!( - "expected a seq for {msg}, got {tag} instead" - ))); - } - } - - Ok(()) - } -} - -macro_rules! unsupported { - ($typ:literal) => { - Err(Error::new_static(concat!($typ, " is not supported"))) - }; -} - -impl<'a, W: Write + ?Sized> Serializer for &'a mut PayloadSerializer<'_, '_, W> { - type Ok = (); - type Error = Error; - type SerializeSeq = SerializeSeq<'a, W>; - type SerializeTuple = Impossible; - type SerializeTupleStruct = Impossible; - type SerializeTupleVariant = Impossible; - type SerializeMap = SerializeMap<'a, W>; - type SerializeStruct = SerializeStruct<'a, W>; - type SerializeStructVariant = Impossible; - - fn serialize_bool(self, v: bool) -> Result { - self.check_state(Tag::Byte)?; - Ok(self.writer.write_i8(v as i8)?) - } - - fn serialize_i8(self, v: i8) -> Result { - self.check_state(Tag::Byte)?; - Ok(self.writer.write_i8(v)?) - } - - fn serialize_i16(self, v: i16) -> Result { - self.check_state(Tag::Short)?; - Ok(self.writer.write_i16::(v)?) - } - - fn serialize_i32(self, v: i32) -> Result { - self.check_state(Tag::Int)?; - Ok(self.writer.write_i32::(v)?) - } - - fn serialize_i64(self, v: i64) -> Result { - self.check_state(Tag::Long)?; - Ok(self.writer.write_i64::(v)?) - } - - fn serialize_u8(self, _v: u8) -> Result { - unsupported!("u8") - } - - fn serialize_u16(self, _v: u16) -> Result { - unsupported!("u16") - } - - fn serialize_u32(self, _v: u32) -> Result { - unsupported!("u32") - } - - fn serialize_u64(self, _v: u64) -> Result { - unsupported!("u64") - } - - fn serialize_f32(self, v: f32) -> Result { - self.check_state(Tag::Float)?; - Ok(self.writer.write_f32::(v)?) - } - - fn serialize_f64(self, v: f64) -> Result { - self.check_state(Tag::Double)?; - Ok(self.writer.write_f64::(v)?) - } - - fn serialize_char(self, _v: char) -> Result { - unsupported!("char") - } - - fn serialize_str(self, v: &str) -> Result { - self.check_state(Tag::String)?; - write_string(&mut *self.writer, v) - } - - fn serialize_bytes(self, _v: &[u8]) -> Result { - unsupported!("&[u8]") - } - - fn serialize_none(self) -> Result { - Ok(()) - } - - fn serialize_some(self, value: &T) -> Result - where - T: Serialize, - { - value.serialize(self) - } - - fn serialize_unit(self) -> Result { - unsupported!("()") - } - - fn serialize_unit_struct(self, _name: &'static str) -> Result { - unsupported!("unit struct") - } - - fn serialize_unit_variant( - self, - _name: &'static str, - _variant_index: u32, - _variant: &'static str, - ) -> Result { - unsupported!("unit variant") - } - - fn serialize_newtype_struct( - self, - _name: &'static str, - _value: &T, - ) -> Result - where - T: Serialize, - { - unsupported!("newtype struct") - } - - fn serialize_newtype_variant( - self, - name: &'static str, - _variant_index: u32, - variant: &'static str, - value: &T, - ) -> Result - where - T: Serialize, - { - let (array_tag, array_type) = match (name, variant) { - (crate::ARRAY_ENUM_NAME, crate::BYTE_ARRAY_VARIANT_NAME) => { - (Tag::ByteArray, ArrayType::Byte) - } - (crate::ARRAY_ENUM_NAME, crate::INT_ARRAY_VARIANT_NAME) => { - (Tag::IntArray, ArrayType::Int) - } - (crate::ARRAY_ENUM_NAME, crate::LONG_ARRAY_VARIANT_NAME) => { - (Tag::LongArray, ArrayType::Long) - } - _ => return unsupported!("newtype variant"), - }; - - self.check_state(array_tag)?; - - value.serialize(&mut PayloadSerializer { - writer: self.writer, - state: State::Array(array_type), - }) - } - - fn serialize_seq(self, len: Option) -> Result { - if let State::Array(array_type) = self.state { - let len = match len { - Some(len) => len, - None => return Err(Error::new_static("array length must be known up front")), - }; - - match len.try_into() { - Ok(len) => { - self.writer.write_i32::(len)?; - Ok(SerializeSeq::array( - self.writer, - array_type.element_tag(), - len, - )) - } - Err(_) => Err(Error::new_static("length of array exceeds i32::MAX")), - } - } else { - self.check_state(Tag::List)?; - - let len = match len { - Some(len) => len, - None => return Err(Error::new_static("list length must be known up front")), - }; - - match len.try_into() { - Ok(len) => Ok(SerializeSeq::list(self.writer, len)), - Err(_) => Err(Error::new_static("length of list exceeds i32::MAX")), - } - } - } - - fn serialize_tuple(self, _len: usize) -> Result { - unsupported!("tuple") - } - - fn serialize_tuple_struct( - self, - _name: &'static str, - _len: usize, - ) -> Result { - unsupported!("tuple struct") - } - - fn serialize_tuple_variant( - self, - _name: &'static str, - _variant_index: u32, - _variant: &'static str, - _len: usize, - ) -> Result { - unsupported!("tuple variant") - } - - fn serialize_map(self, _len: Option) -> Result { - self.check_state(Tag::Compound)?; - - Ok(SerializeMap { - writer: self.writer, - }) - } - - fn serialize_struct( - self, - _name: &'static str, - _len: usize, - ) -> Result { - self.check_state(Tag::Compound)?; - - Ok(SerializeStruct { - writer: self.writer, - }) - } - - fn serialize_struct_variant( - self, - _name: &'static str, - _variant_index: u32, - _variant: &'static str, - _len: usize, - ) -> Result { - unsupported!("struct variant") - } - - fn is_human_readable(&self) -> bool { - false - } -} diff --git a/serde_nbt/src/binary/ser/root.rs b/serde_nbt/src/binary/ser/root.rs deleted file mode 100644 index ff32e0c..0000000 --- a/serde_nbt/src/binary/ser/root.rs +++ /dev/null @@ -1,222 +0,0 @@ -use std::io::Write; - -use byteorder::WriteBytesExt; -use serde::{Serialize, Serializer}; - -use crate::binary::ser::map::SerializeMap; -use crate::binary::ser::structs::SerializeStruct; -use crate::binary::ser::{write_string, Impossible}; -use crate::{Error, Tag}; - -/// A serde [`Serializer`] for the binary representation of NBT. -#[non_exhaustive] -pub struct RootSerializer<'n, W> { - /// The writer to serialize to. - pub writer: W, - /// The name of the root compound to serialize. - /// - /// The empty string `""` is acceptable. - pub root_name: &'n str, -} - -impl<'n, W: Write> RootSerializer<'n, W> { - /// Constructs a new serializer. - pub fn new(writer: W, root_name: &'n str) -> Self { - Self { writer, root_name } - } - - fn write_header(&mut self) -> Result<(), Error> { - self.writer.write_u8(Tag::Compound as u8)?; - write_string(&mut self.writer, self.root_name) - } -} - -macro_rules! not_compound { - ($typ:literal) => { - Err(Error::new_static(concat!( - "root value must be a map or struct (got ", - $typ, - ")" - ))) - }; -} - -impl<'a, W: Write> Serializer for &'a mut RootSerializer<'_, W> { - type Ok = (); - type Error = Error; - type SerializeSeq = Impossible; - type SerializeTuple = Impossible; - type SerializeTupleStruct = Impossible; - type SerializeTupleVariant = Impossible; - type SerializeMap = SerializeMap<'a, W>; - type SerializeStruct = SerializeStruct<'a, W>; - type SerializeStructVariant = Impossible; - - fn serialize_bool(self, _v: bool) -> Result { - not_compound!("bool") - } - - fn serialize_i8(self, _v: i8) -> Result { - not_compound!("i8") - } - - fn serialize_i16(self, _v: i16) -> Result { - not_compound!("i16") - } - - fn serialize_i32(self, _v: i32) -> Result { - not_compound!("i32") - } - - fn serialize_i64(self, _v: i64) -> Result { - not_compound!("i64") - } - - fn serialize_u8(self, _v: u8) -> Result { - not_compound!("u8") - } - - fn serialize_u16(self, _v: u16) -> Result { - not_compound!("u16") - } - - fn serialize_u32(self, _v: u32) -> Result { - not_compound!("u32") - } - - fn serialize_u64(self, _v: u64) -> Result { - not_compound!("u64") - } - - fn serialize_f32(self, _v: f32) -> Result { - not_compound!("f32") - } - - fn serialize_f64(self, _v: f64) -> Result { - not_compound!("f64") - } - - fn serialize_char(self, _v: char) -> Result { - not_compound!("char") - } - - fn serialize_str(self, _v: &str) -> Result { - not_compound!("str") - } - - fn serialize_bytes(self, _v: &[u8]) -> Result { - not_compound!("&[u8]") - } - - fn serialize_none(self) -> Result { - not_compound!("None") - } - - fn serialize_some(self, _value: &T) -> Result - where - T: Serialize, - { - not_compound!("Some") - } - - fn serialize_unit(self) -> Result { - not_compound!("()") - } - - fn serialize_unit_struct(self, _name: &'static str) -> Result { - not_compound!("unit struct") - } - - fn serialize_unit_variant( - self, - _name: &'static str, - _variant_index: u32, - _variant: &'static str, - ) -> Result { - not_compound!("unit variant") - } - - fn serialize_newtype_struct( - self, - _name: &'static str, - _value: &T, - ) -> Result - where - T: Serialize, - { - not_compound!("newtype struct") - } - - fn serialize_newtype_variant( - self, - _name: &'static str, - _variant_index: u32, - _variant: &'static str, - _value: &T, - ) -> Result - where - T: Serialize, - { - not_compound!("newtype variant") - } - - fn serialize_seq(self, _len: Option) -> Result { - not_compound!("seq") - } - - fn serialize_tuple(self, _len: usize) -> Result { - not_compound!("tuple") - } - - fn serialize_tuple_struct( - self, - _name: &'static str, - _len: usize, - ) -> Result { - not_compound!("tuple struct") - } - - fn serialize_tuple_variant( - self, - _name: &'static str, - _variant_index: u32, - _variant: &'static str, - _len: usize, - ) -> Result { - not_compound!("tuple variant") - } - - fn serialize_map(self, _len: Option) -> Result { - self.write_header()?; - - Ok(SerializeMap { - writer: &mut self.writer, - }) - } - - fn serialize_struct( - self, - _name: &'static str, - _len: usize, - ) -> Result { - self.write_header()?; - - Ok(SerializeStruct { - writer: &mut self.writer, - }) - } - - fn serialize_struct_variant( - self, - _name: &'static str, - _variant_index: u32, - _variant: &'static str, - _len: usize, - ) -> Result { - not_compound!("struct variant") - } - - fn is_human_readable(&self) -> bool { - false - } -} diff --git a/serde_nbt/src/binary/ser/seq.rs b/serde_nbt/src/binary/ser/seq.rs deleted file mode 100644 index ab2eb2f..0000000 --- a/serde_nbt/src/binary/ser/seq.rs +++ /dev/null @@ -1,120 +0,0 @@ -use std::io::Write; - -use byteorder::{BigEndian, WriteBytesExt}; -use serde::{ser, Serialize}; - -use crate::binary::ser::payload::PayloadSerializer; -use crate::{Error, Tag}; - -pub struct SerializeSeq<'w, W: ?Sized> { - writer: &'w mut W, - element_tag: Tag, - remaining: i32, - list_or_array: ListOrArray, -} - -#[derive(Copy, Clone)] -enum ListOrArray { - List, - Array, -} - -impl ListOrArray { - pub const fn name(self) -> &'static str { - match self { - ListOrArray::List => "list", - ListOrArray::Array => "array", - } - } -} - -impl<'w, W: Write + ?Sized> SerializeSeq<'w, W> { - pub(super) fn list(writer: &'w mut W, length: i32) -> Self { - Self { - writer, - element_tag: Tag::End, - remaining: length, - list_or_array: ListOrArray::List, - } - } - - pub(super) fn array(writer: &'w mut W, element_tag: Tag, length: i32) -> Self { - Self { - writer, - element_tag, - remaining: length, - list_or_array: ListOrArray::Array, - } - } -} - -impl ser::SerializeSeq for SerializeSeq<'_, W> { - type Ok = (); - type Error = Error; - - fn serialize_element(&mut self, value: &T) -> Result<(), Self::Error> - where - T: Serialize, - { - if self.remaining <= 0 { - return Err(Error::new_owned(format!( - "attempt to serialize more {} elements than specified", - self.list_or_array.name() - ))); - } - - match self.list_or_array { - ListOrArray::List => { - if self.element_tag == Tag::End { - let mut ser = - PayloadSerializer::first_list_element(self.writer, self.remaining); - - value.serialize(&mut ser)?; - - self.element_tag = ser.written_tag().expect("tag must have been written"); - } else { - value.serialize(&mut PayloadSerializer::seq_element( - self.writer, - self.element_tag, - ))?; - } - } - ListOrArray::Array => { - value.serialize(&mut PayloadSerializer::seq_element( - self.writer, - self.element_tag, - ))?; - } - } - - self.remaining -= 1; - Ok(()) - } - - fn end(self) -> Result { - if self.remaining > 0 { - return Err(Error::new_owned(format!( - "{} {} element(s) left to serialize", - self.remaining, - self.list_or_array.name() - ))); - } - - match self.list_or_array { - ListOrArray::List => { - // Were any elements written? - if self.element_tag == Tag::End { - // Element type - self.writer.write_u8(Tag::End as u8)?; - // List length. - self.writer.write_i32::(0)?; - } - } - ListOrArray::Array => { - // Array length should be written by the serializer already. - } - } - - Ok(()) - } -} diff --git a/serde_nbt/src/binary/ser/structs.rs b/serde_nbt/src/binary/ser/structs.rs deleted file mode 100644 index f596774..0000000 --- a/serde_nbt/src/binary/ser/structs.rs +++ /dev/null @@ -1,33 +0,0 @@ -use std::io::Write; - -use byteorder::WriteBytesExt; -use serde::{ser, Serialize}; - -use crate::binary::ser::payload::PayloadSerializer; -use crate::{Error, Tag}; - -pub struct SerializeStruct<'w, W: ?Sized> { - pub(super) writer: &'w mut W, -} - -impl ser::SerializeStruct for SerializeStruct<'_, W> { - type Ok = (); - type Error = Error; - - fn serialize_field( - &mut self, - key: &'static str, - value: &T, - ) -> Result<(), Self::Error> - where - T: Serialize, - { - value - .serialize(&mut PayloadSerializer::named(self.writer, key)) - .map_err(|e| e.field(key)) - } - - fn end(self) -> Result { - Ok(self.writer.write_u8(Tag::End as u8)?) - } -} diff --git a/serde_nbt/src/error.rs b/serde_nbt/src/error.rs deleted file mode 100644 index e564dd7..0000000 --- a/serde_nbt/src/error.rs +++ /dev/null @@ -1,130 +0,0 @@ -use std::error::Error as StdError; -use std::fmt::Display; -use std::iter::FusedIterator; -use std::{fmt, io}; - -use serde::{de, ser}; - -/// Errors that can occur when serializing or deserializing. -/// -/// The error type maintains a backtrace through the NBT value which caused the -/// error. This is used in the `Display` impl on the error. -#[derive(Debug)] -pub struct Error { - /// Box this to keep the error as small as possible. We don't want to - /// slow down the common case where no error occurs. - inner: Box, -} - -#[derive(Debug)] -struct ErrorInner { - trace: Vec, - cause: Cause, -} - -#[derive(Debug)] -enum Cause { - Io(io::Error), - // catch-all errors - Owned(Box), - Static(&'static str), -} - -impl Error { - pub(crate) fn new_owned(msg: impl Into>) -> Self { - Self { - inner: Box::new(ErrorInner { - trace: Vec::new(), - cause: Cause::Owned(msg.into()), - }), - } - } - - pub(crate) fn new_static(msg: &'static str) -> Self { - Self { - inner: Box::new(ErrorInner { - trace: Vec::new(), - cause: Cause::Static(msg), - }), - } - } - - pub(crate) fn field(mut self, ctx: impl Into) -> Self { - self.inner.trace.push(ctx.into()); - self - } - - /// Returns an iterator through the nested fields of an NBT compound to the - /// location where the error occurred. - /// - /// The iterator's `Item` is the name of the current field. - pub fn trace( - &self, - ) -> impl DoubleEndedIterator + ExactSizeIterator + FusedIterator + Clone + '_ - { - self.inner.trace.iter().rev().map(|s| s.as_str()) - } -} - -impl Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let len = self.inner.trace.len(); - - if len > 0 { - write!(f, "(")?; - for (i, ctx) in self.trace().enumerate() { - write!(f, "{ctx}")?; - - if i != len - 1 { - write!(f, " → ")?; - } - } - write!(f, ") ")?; - } - - match &self.inner.cause { - Cause::Io(e) => e.fmt(f), - Cause::Owned(s) => write!(f, "{s}"), - Cause::Static(s) => write!(f, "{s}"), - } - } -} - -impl StdError for Error { - fn source(&self) -> Option<&(dyn StdError + 'static)> { - match &self.inner.cause { - Cause::Io(e) => Some(e), - Cause::Owned(_) => None, - Cause::Static(_) => None, - } - } -} - -impl ser::Error for Error { - fn custom(msg: T) -> Self - where - T: Display, - { - Error::new_owned(format!("{msg}")) - } -} - -impl de::Error for Error { - fn custom(msg: T) -> Self - where - T: Display, - { - Error::new_owned(format!("{msg}")) - } -} - -impl From for Error { - fn from(e: io::Error) -> Self { - Self { - inner: Box::new(ErrorInner { - trace: Vec::new(), - cause: Cause::Io(e), - }), - } - } -} diff --git a/serde_nbt/src/lib.rs b/serde_nbt/src/lib.rs deleted file mode 100644 index abc949f..0000000 --- a/serde_nbt/src/lib.rs +++ /dev/null @@ -1,210 +0,0 @@ -//! A [serde] library for the serialization and deserialization of Minecraft's -//! [Named Binary Tag] (NBT) format. -//! -//! [serde]: https://docs.rs/serde/latest/serde/ -//! [Named Binary Tag]: https://minecraft.fandom.com/wiki/NBT_format -//! -//! # Examples -//! -//! Write an NBT compound to a byte buffer. -//! -//! ``` -//! use serde::Serialize; -//! use serde_nbt::binary::to_writer; -//! -//! #[derive(Serialize)] -//! struct Example { -//! boolean: bool, -//! string: String, -//! list_of_float: Vec, -//! #[serde(with = "serde_nbt::int_array")] -//! int_array: Vec, -//! } -//! -//! let example = Example { -//! boolean: true, -//! string: "abc123".to_owned(), -//! list_of_float: vec![3.1415, 2.7182, 1.4142], -//! int_array: vec![7, 8, 9], -//! }; -//! -//! let mut buf = Vec::new(); -//! to_writer(&mut buf, &example).unwrap(); -//! ``` -//! -//! Sometimes the structure of the NBT data is not known ahead of time. For -//! this, you can use [`Value`]. -//! -//! ``` -//! use serde_nbt::binary::from_reader; -//! use serde_nbt::{Compound, Value}; -//! -//! let some_bytes = [10, 0, 0, 3, 0, 3, 105, 110, 116, 0, 0, 222, 173, 0]; -//! let reader = &mut some_bytes.as_slice(); -//! -//! let value: Value = from_reader(reader).unwrap(); -//! -//! let expected_value = Value::Compound(Compound::from_iter([( -//! "int".to_owned(), -//! Value::Int(0xdead), -//! )])); -//! -//! assert_eq!(value, expected_value); -//! ``` - -use std::fmt; -use std::fmt::{Display, Formatter}; - -pub use array::*; -pub use error::*; -use serde::de::Visitor; -use serde::{Deserialize, Deserializer}; -pub use value::*; - -mod array; -mod error; -mod value; - -#[cfg(test)] -mod tests; - -/// (De)serialization support for the binary representation of NBT. -pub mod binary { - pub use de::*; - pub use ser::*; - - mod de; - mod ser; -} - -pub type Result = std::result::Result; - -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -enum Tag { - End, - Byte, - Short, - Int, - Long, - Float, - Double, - ByteArray, - String, - List, - Compound, - IntArray, - LongArray, -} - -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] -enum ArrayType { - Byte, - Int, - Long, -} - -impl ArrayType { - pub const fn element_tag(self) -> Tag { - match self { - ArrayType::Byte => Tag::Byte, - ArrayType::Int => Tag::Int, - ArrayType::Long => Tag::Long, - } - } -} - -impl<'de> Deserialize<'de> for ArrayType { - fn deserialize(deserializer: D) -> std::result::Result - where - D: Deserializer<'de>, - { - struct ArrayTypeVisitor; - - impl<'de> Visitor<'de> for ArrayTypeVisitor { - type Value = ArrayType; - - fn expecting(&self, formatter: &mut Formatter) -> fmt::Result { - write!(formatter, "a u8 or string encoding an NBT array type") - } - - fn visit_u8(self, v: u8) -> std::result::Result - where - E: serde::de::Error, - { - match v { - 0 => Ok(ArrayType::Byte), - 1 => Ok(ArrayType::Int), - 2 => Ok(ArrayType::Long), - i => Err(E::custom(format!("invalid array type index `{i}`"))), - } - } - - fn visit_str(self, v: &str) -> std::result::Result - where - E: serde::de::Error, - { - match v { - BYTE_ARRAY_VARIANT_NAME => Ok(ArrayType::Byte), - INT_ARRAY_VARIANT_NAME => Ok(ArrayType::Int), - LONG_ARRAY_VARIANT_NAME => Ok(ArrayType::Long), - s => Err(E::custom(format!("invalid array type `{s}`"))), - } - } - } - - deserializer.deserialize_u8(ArrayTypeVisitor) - } -} - -impl Tag { - pub fn from_u8(id: u8) -> Result { - match id { - 0 => Ok(Tag::End), - 1 => Ok(Tag::Byte), - 2 => Ok(Tag::Short), - 3 => Ok(Tag::Int), - 4 => Ok(Tag::Long), - 5 => Ok(Tag::Float), - 6 => Ok(Tag::Double), - 7 => Ok(Tag::ByteArray), - 8 => Ok(Tag::String), - 9 => Ok(Tag::List), - 10 => Ok(Tag::Compound), - 11 => Ok(Tag::IntArray), - 12 => Ok(Tag::LongArray), - _ => Err(Error::new_owned(format!("invalid tag byte `{id}`"))), - } - } -} - -impl Display for Tag { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - let name = match self { - Tag::End => "end", - Tag::Byte => "byte", - Tag::Short => "short", - Tag::Int => "int", - Tag::Long => "long", - Tag::Float => "float", - Tag::Double => "double", - Tag::ByteArray => "byte array", - Tag::String => "string", - Tag::List => "list", - Tag::Compound => "compound", - Tag::IntArray => "int array", - Tag::LongArray => "long array", - }; - - write!(f, "{name}") - } -} - -/// Error message for cesu-8 decoding failures. -const CESU8_DECODE_ERROR: &str = "could not convert CESU-8 data to UTF-8"; - -/// The name of the enum used to encode arrays. -const ARRAY_ENUM_NAME: &str = "__array__"; - -const BYTE_ARRAY_VARIANT_NAME: &str = "__byte_array__"; -const INT_ARRAY_VARIANT_NAME: &str = "__int_array__"; -const LONG_ARRAY_VARIANT_NAME: &str = "__long_array__"; diff --git a/serde_nbt/src/tests.rs b/serde_nbt/src/tests.rs deleted file mode 100644 index e106d9e..0000000 --- a/serde_nbt/src/tests.rs +++ /dev/null @@ -1,205 +0,0 @@ -use pretty_assertions::assert_eq; -use serde::{Deserialize, Serialize}; - -use crate::binary::{from_reader, to_writer, Deserializer, Serializer}; -use crate::{byte_array, int_array, long_array, Compound, List, Value}; - -const ROOT_NAME: &str = "The root name‽"; - -#[derive(PartialEq, Debug, Serialize, Deserialize)] -struct Struct { - byte: i8, - list_of_int: Vec, - list_of_string: Vec, - string: String, - inner: Inner, - #[serde(with = "int_array")] - int_array: Vec, - #[serde(with = "byte_array")] - byte_array: Vec, - #[serde(with = "long_array")] - long_array: Vec, - some_int: Option, - none_int: Option, -} - -#[derive(PartialEq, Debug, Serialize, Deserialize)] -struct Inner { - int: i32, - long: i64, - float: f32, - double: f64, -} - -impl Struct { - pub fn new() -> Self { - Self { - byte: 123, - list_of_int: vec![3, -7, 5], - list_of_string: vec!["foo".to_owned(), "bar".to_owned(), "baz".to_owned()], - string: "aé日".to_owned(), - inner: Inner { - int: i32::MIN, - long: i64::MAX, - float: 1e10_f32, - double: f64::NEG_INFINITY, - }, - int_array: vec![5, -9, i32::MIN, 0, i32::MAX], - byte_array: vec![0, 1, 2], - long_array: vec![123, 456, 789], - some_int: Some(321), - none_int: None, - } - } - - pub fn value() -> Value { - Value::Compound( - Compound::from_iter([ - ("byte".into(), 123_i8.into()), - ("list_of_int".into(), List::Int(vec![3, -7, 5]).into()), - ( - "list_of_string".into(), - List::String(vec!["foo".into(), "bar".into(), "baz".into()]).into(), - ), - ("string".into(), "aé日".into()), - ( - "inner".into(), - Compound::from_iter([ - ("int".into(), i32::MIN.into()), - ("long".into(), i64::MAX.into()), - ("float".into(), 1e10_f32.into()), - ("double".into(), f64::NEG_INFINITY.into()), - ]) - .into(), - ), - ( - "int_array".into(), - vec![5, -9, i32::MIN, 0, i32::MAX].into(), - ), - ("byte_array".into(), vec![0_i8, 1, 2].into()), - ("long_array".into(), vec![123_i64, 456, 789].into()), - ("some_int".into(), 321.into()), - ]) - .into(), - ) - } -} - -#[test] -fn round_trip_binary_struct() { - let mut buf = Vec::new(); - - let struct_ = Struct::new(); - - struct_ - .serialize(&mut Serializer::new(&mut buf, ROOT_NAME)) - .unwrap(); - - let reader = &mut buf.as_slice(); - - let mut de = Deserializer::new(reader, true); - - let struct_de = Struct::deserialize(&mut de).unwrap(); - - assert_eq!(struct_, struct_de); - assert_eq!(de.root_name, ROOT_NAME); -} - -#[test] -fn round_trip_binary_value() { - let mut buf = Vec::new(); - - let value = Struct::value(); - - value - .serialize(&mut Serializer::new(&mut buf, ROOT_NAME)) - .unwrap(); - - let reader = &mut buf.as_slice(); - - let mut de = Deserializer::new(reader, true); - - let value_de = Value::deserialize(&mut de).unwrap(); - - assert_eq!(value, value_de); - assert_eq!(de.root_name, ROOT_NAME); -} - -#[test] -fn to_hematite() { - let mut buf = Vec::new(); - - let struct_ = Struct::new(); - - struct_ - .serialize(&mut Serializer::new(&mut buf, ROOT_NAME)) - .unwrap(); - - let struct_de: Struct = nbt::from_reader(&mut buf.as_slice()).unwrap(); - - assert_eq!(struct_, struct_de); -} - -#[test] -fn root_requires_compound() { - let mut buf = Vec::new(); - assert!(123 - .serialize(&mut Serializer::new(&mut buf, ROOT_NAME)) - .is_err()); -} - -#[test] -fn mismatched_array_element() { - #[derive(Serialize)] - struct Struct { - #[serde(with = "byte_array")] - data: Vec, - } - - let struct_ = Struct { - data: vec![1, 2, 3], - }; - - let mut buf = Vec::new(); - assert!(struct_ - .serialize(&mut Serializer::new(&mut buf, ROOT_NAME)) - .is_err()); -} - -#[test] -fn struct_to_value() { - let mut buf = Vec::new(); - - let struct_ = Struct::new(); - - to_writer(&mut buf, &struct_).unwrap(); - - let val: Value = from_reader(&mut buf.as_slice()).unwrap(); - - assert_eq!(val, Struct::value()); -} - -#[test] -fn value_to_struct() { - let mut buf = Vec::new(); - - to_writer(&mut buf, &Struct::value()).unwrap(); - - let struct_: Struct = from_reader(&mut buf.as_slice()).unwrap(); - - assert_eq!(struct_, Struct::new()); -} - -#[test] -fn value_from_json() { - let mut struct_ = Struct::new(); - - // JSON numbers only allow finite floats. - struct_.inner.double = 12345.0; - - let string = serde_json::to_string_pretty(&struct_).unwrap(); - - let struct_de: Struct = serde_json::from_str(&string).unwrap(); - - assert_eq!(struct_, struct_de); -} diff --git a/serde_nbt/src/value.rs b/serde_nbt/src/value.rs deleted file mode 100644 index 8e69e01..0000000 --- a/serde_nbt/src/value.rs +++ /dev/null @@ -1,539 +0,0 @@ -use std::borrow::Cow; -use std::fmt; - -use indexmap::IndexMap; -use serde::de::{DeserializeSeed, EnumAccess, Error, MapAccess, SeqAccess, VariantAccess, Visitor}; -use serde::{Deserialize, Deserializer, Serialize, Serializer}; - -use crate::{byte_array, int_array, long_array, ArrayType}; - -/// An arbitrary NBT value. -/// -/// Note that `Value`s at the root level other than [`Value::Compound`] will -/// fail to serialize because NBT requires that the root value be a compound. -/// -/// At the root level you may want to use [`Compound`] instead. -#[derive(Clone, PartialEq, Debug)] -pub enum Value { - Byte(i8), - Short(i16), - Int(i32), - Long(i64), - Float(f32), - Double(f64), - ByteArray(Vec), - String(String), - List(List), - Compound(Compound), - IntArray(Vec), - LongArray(Vec), -} - -/// An arbitrary NBT compound. -/// -/// This is a convenient type alias for the [`IndexMap`] type. -pub type Compound = IndexMap; - -/// An NBT list value. -/// -/// NBT lists are homogeneous, meaning each list element must be of the same -/// type. This is opposed to a format like JSON where lists can be -/// heterogeneous: -/// -/// ```json -/// [42, "hello", {}] -/// ``` -/// -/// Every possible element type has its own variant in this enum. As a result, -/// heterogeneous lists are unrepresentable. -#[derive(Clone, PartialEq, Debug)] -pub enum List { - Byte(Vec), - Short(Vec), - Int(Vec), - Long(Vec), - Float(Vec), - Double(Vec), - ByteArray(Vec>), - String(Vec), - List(Vec), - Compound(Vec), - IntArray(Vec>), - LongArray(Vec>), -} - -impl List { - pub fn len(&self) -> usize { - match self { - List::Byte(l) => l.len(), - List::Short(l) => l.len(), - List::Int(l) => l.len(), - List::Long(l) => l.len(), - List::Float(l) => l.len(), - List::Double(l) => l.len(), - List::ByteArray(l) => l.len(), - List::String(l) => l.len(), - List::List(l) => l.len(), - List::Compound(l) => l.len(), - List::IntArray(l) => l.len(), - List::LongArray(l) => l.len(), - } - } - - pub fn is_empty(&self) -> bool { - self.len() == 0 - } -} - -impl From for Value { - fn from(v: i8) -> Self { - Self::Byte(v) - } -} - -impl From for Value { - fn from(v: i16) -> Self { - Self::Short(v) - } -} - -impl From for Value { - fn from(v: i32) -> Self { - Self::Int(v) - } -} - -impl From for Value { - fn from(v: i64) -> Self { - Self::Long(v) - } -} - -impl From for Value { - fn from(v: f32) -> Self { - Self::Float(v) - } -} - -impl From for Value { - fn from(v: f64) -> Self { - Self::Double(v) - } -} - -impl From> for Value { - fn from(v: Vec) -> Self { - Self::ByteArray(v) - } -} - -impl From for Value { - fn from(v: String) -> Self { - Self::String(v) - } -} - -impl<'a> From<&'a str> for Value { - fn from(v: &'a str) -> Self { - Self::String(v.to_owned()) - } -} - -impl<'a> From> for Value { - fn from(v: Cow<'a, str>) -> Self { - Self::String(v.into_owned()) - } -} - -impl From for Value { - fn from(v: List) -> Self { - Self::List(v) - } -} - -impl From for Value { - fn from(v: Compound) -> Self { - Self::Compound(v) - } -} - -impl From> for Value { - fn from(v: Vec) -> Self { - Self::IntArray(v) - } -} - -impl From> for Value { - fn from(v: Vec) -> Self { - Self::LongArray(v) - } -} - -impl From> for List { - fn from(v: Vec) -> Self { - List::Byte(v) - } -} - -impl From> for List { - fn from(v: Vec) -> Self { - List::Short(v) - } -} - -impl From> for List { - fn from(v: Vec) -> Self { - List::Int(v) - } -} - -impl From> for List { - fn from(v: Vec) -> Self { - List::Long(v) - } -} - -impl From> for List { - fn from(v: Vec) -> Self { - List::Float(v) - } -} - -impl From> for List { - fn from(v: Vec) -> Self { - List::Double(v) - } -} - -impl From>> for List { - fn from(v: Vec>) -> Self { - List::ByteArray(v) - } -} - -impl From> for List { - fn from(v: Vec) -> Self { - List::String(v) - } -} - -impl From> for List { - fn from(v: Vec) -> Self { - List::List(v) - } -} - -impl From> for List { - fn from(v: Vec) -> Self { - List::Compound(v) - } -} - -impl From>> for List { - fn from(v: Vec>) -> Self { - List::IntArray(v) - } -} - -impl From>> for List { - fn from(v: Vec>) -> Self { - List::LongArray(v) - } -} - -impl Serialize for Value { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - match self { - Value::Byte(v) => v.serialize(serializer), - Value::Short(v) => v.serialize(serializer), - Value::Int(v) => v.serialize(serializer), - Value::Long(v) => v.serialize(serializer), - Value::Float(v) => v.serialize(serializer), - Value::Double(v) => v.serialize(serializer), - Value::ByteArray(v) => byte_array::serialize(v, serializer), - Value::String(v) => v.serialize(serializer), - Value::List(v) => v.serialize(serializer), - Value::Compound(v) => v.serialize(serializer), - Value::IntArray(v) => int_array::serialize(v, serializer), - Value::LongArray(v) => long_array::serialize(v, serializer), - } - } -} - -impl Serialize for List { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - match self { - List::Byte(l) => l.serialize(serializer), - List::Short(l) => l.serialize(serializer), - List::Int(l) => l.serialize(serializer), - List::Long(l) => l.serialize(serializer), - List::Float(l) => l.serialize(serializer), - List::Double(l) => l.serialize(serializer), - List::ByteArray(l) => l.serialize(serializer), - List::String(l) => l.serialize(serializer), - List::List(l) => l.serialize(serializer), - List::Compound(l) => l.serialize(serializer), - List::IntArray(l) => l.serialize(serializer), - List::LongArray(l) => l.serialize(serializer), - } - } -} - -impl<'de> Deserialize<'de> for Value { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - deserializer.deserialize_any(ValueVisitor) - } -} - -struct ValueVisitor; - -impl<'de> Visitor<'de> for ValueVisitor { - type Value = Value; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - write!(formatter, "a representable NBT value") - } - - fn visit_i8(self, v: i8) -> Result - where - E: Error, - { - Ok(Value::Byte(v)) - } - - fn visit_i16(self, v: i16) -> Result - where - E: Error, - { - Ok(Value::Short(v)) - } - - fn visit_i32(self, v: i32) -> Result - where - E: Error, - { - Ok(Value::Int(v)) - } - - fn visit_i64(self, v: i64) -> Result - where - E: Error, - { - Ok(Value::Long(v)) - } - - fn visit_f32(self, v: f32) -> Result - where - E: Error, - { - Ok(Value::Float(v)) - } - - fn visit_f64(self, v: f64) -> Result - where - E: Error, - { - Ok(Value::Double(v)) - } - - fn visit_str(self, v: &str) -> Result - where - E: Error, - { - Ok(Value::String(v.to_owned())) - } - - fn visit_string(self, v: String) -> Result - where - E: Error, - { - Ok(Value::String(v)) - } - - fn visit_seq(self, seq: A) -> Result - where - A: SeqAccess<'de>, - { - ListVisitor.visit_seq(seq).map(Value::List) - } - - fn visit_map(self, map: A) -> Result - where - A: MapAccess<'de>, - { - visit_map(map).map(Value::Compound) - } - - fn visit_enum(self, data: A) -> Result - where - A: EnumAccess<'de>, - { - let (array_type, variant) = data.variant()?; - - Ok(match array_type { - ArrayType::Byte => Value::ByteArray(variant.newtype_variant()?), - ArrayType::Int => Value::IntArray(variant.newtype_variant()?), - ArrayType::Long => Value::LongArray(variant.newtype_variant()?), - }) - } -} - -impl<'de> Deserialize<'de> for List { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - deserializer.deserialize_seq(ListVisitor) - } -} - -struct ListVisitor; - -impl<'de> Visitor<'de> for ListVisitor { - type Value = List; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - write!(formatter, "an NBT list") - } - - fn visit_seq(self, mut seq: A) -> Result - where - A: SeqAccess<'de>, - { - let mut list = List::Byte(Vec::new()); - - while seq - .next_element_seed(DeserializeListElement(&mut list))? - .is_some() - {} - - Ok(list) - } -} - -struct DeserializeListElement<'a>(&'a mut List); - -impl<'de, 'a> DeserializeSeed<'de> for DeserializeListElement<'a> { - type Value = (); - - fn deserialize(self, deserializer: D) -> Result - where - D: Deserializer<'de>, - { - deserializer.deserialize_any(self) - } -} - -macro_rules! visit { - ($self:expr, $variant:ident, $value:expr, $error:ty) => { - if $self.0.is_empty() { - *$self.0 = List::$variant(vec![$value]); - Ok(()) - } else if let List::$variant(elems) = $self.0 { - elems.push($value); - Ok(()) - } else { - Err(<$error>::custom("NBT lists must be homogenous")) - } - }; -} - -impl<'de, 'a> Visitor<'de> for DeserializeListElement<'a> { - type Value = (); - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - write!(formatter, "a valid NBT list element") - } - - fn visit_i8(self, v: i8) -> Result - where - E: Error, - { - visit!(self, Byte, v, E) - } - - fn visit_i16(self, v: i16) -> Result - where - E: Error, - { - visit!(self, Short, v, E) - } - - fn visit_i32(self, v: i32) -> Result - where - E: Error, - { - visit!(self, Int, v, E) - } - - fn visit_i64(self, v: i64) -> Result - where - E: Error, - { - visit!(self, Long, v, E) - } - - fn visit_f32(self, v: f32) -> Result - where - E: Error, - { - visit!(self, Float, v, E) - } - - fn visit_f64(self, v: f64) -> Result - where - E: Error, - { - visit!(self, Double, v, E) - } - - fn visit_str(self, v: &str) -> Result - where - E: Error, - { - visit!(self, String, v.to_owned(), E) - } - - fn visit_string(self, v: String) -> Result - where - E: Error, - { - visit!(self, String, v, E) - } - - fn visit_seq(self, seq: A) -> Result - where - A: SeqAccess<'de>, - { - visit!(self, List, ListVisitor.visit_seq(seq)?, A::Error) - } - - fn visit_map(self, map: A) -> Result - where - A: MapAccess<'de>, - { - visit!(self, Compound, visit_map(map)?, A::Error) - } -} - -fn visit_map<'de, A>(mut map: A) -> Result -where - A: MapAccess<'de>, -{ - let mut compound = Compound::new(); - - while let Some((k, v)) = map.next_entry()? { - compound.insert(k, v); - } - - Ok(compound) -}