mirror of
https://github.com/italicsjenga/valence.git
synced 2025-01-11 07:11:30 +11:00
Move serde_nbt
to a separate repo.
It is located at https://github.com/valence-rs/serde_nbt
This commit is contained in:
parent
63f49ad5c0
commit
4c5179de18
|
@ -69,4 +69,4 @@ rayon = "1"
|
|||
num = "0.4"
|
||||
|
||||
[workspace]
|
||||
members = ["serde_nbt", "packet_inspector"]
|
||||
members = ["packet_inspector"]
|
||||
|
|
|
@ -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 <ryanj00a@gmail.com>"]
|
||||
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"
|
|
@ -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).
|
|
@ -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<i32>,
|
||||
/// }
|
||||
///
|
||||
/// 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<T, S>(array: &T, serializer: S) -> Result<S::Ok, S::Error>
|
||||
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<T, D::Error>
|
||||
where
|
||||
T: Deserialize<'de>,
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
struct ArrayVisitor<T>(PhantomData<T>);
|
||||
|
||||
impl<'de, T: Deserialize<'de>> Visitor<'de> for ArrayVisitor<T> {
|
||||
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<A>(self, seq: A) -> Result<Self::Value, A::Error>
|
||||
where
|
||||
A: SeqAccess<'de>,
|
||||
{
|
||||
T::deserialize(SeqAccessDeserializer::new(seq))
|
||||
}
|
||||
|
||||
fn visit_enum<A>(self, data: A) -> Result<Self::Value, A::Error>
|
||||
where
|
||||
A: EnumAccess<'de>,
|
||||
{
|
||||
// Ignore the variant name.
|
||||
let (_, variant) = data.variant::<IgnoredAny>()?;
|
||||
|
||||
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);
|
|
@ -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<R, T>(reader: R) -> Result<T, Error>
|
||||
where
|
||||
R: Read,
|
||||
T: DeserializeOwned,
|
||||
{
|
||||
T::deserialize(&mut Deserializer::new(reader, false))
|
||||
}
|
|
@ -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<V>(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::<Error>::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<T>(self, seed: T) -> Result<T::Value, Self::Error>
|
||||
where
|
||||
T: DeserializeSeed<'de>,
|
||||
{
|
||||
seed.deserialize(ArrayDeserializer {
|
||||
reader: self.reader,
|
||||
array_type: self.array_type,
|
||||
})
|
||||
}
|
||||
|
||||
fn tuple_variant<V>(self, _len: usize, _visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
Err(Error::invalid_type(
|
||||
Unexpected::NewtypeVariant,
|
||||
&"tuple variant",
|
||||
))
|
||||
}
|
||||
|
||||
fn struct_variant<V>(
|
||||
self,
|
||||
_fields: &'static [&'static str],
|
||||
_visitor: V,
|
||||
) -> Result<V::Value, Self::Error>
|
||||
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<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
let len = self.reader.read_i32::<BigEndian>()?;
|
||||
|
||||
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<T>(&mut self, seed: T) -> Result<Option<T::Value>, 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<usize> {
|
||||
Some(self.remaining as usize)
|
||||
}
|
||||
}
|
|
@ -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<K>(&mut self, seed: K) -> Result<Option<K::Value>, 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<V>(&mut self, seed: V) -> Result<V::Value, Self::Error>
|
||||
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,
|
||||
})
|
||||
}
|
||||
}
|
|
@ -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<T>(&mut self, seed: T) -> Result<Option<T::Value>, 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<usize> {
|
||||
Some(self.remaining as usize)
|
||||
}
|
||||
}
|
|
@ -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<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
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::<BigEndian>()?),
|
||||
Tag::Int => visitor.visit_i32(self.reader.read_i32::<BigEndian>()?),
|
||||
Tag::Long => visitor.visit_i64(self.reader.read_i64::<BigEndian>()?),
|
||||
Tag::Float => visitor.visit_f32(self.reader.read_f32::<BigEndian>()?),
|
||||
Tag::Double => visitor.visit_f64(self.reader.read_f64::<BigEndian>()?),
|
||||
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::<BigEndian>()? {
|
||||
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::<BigEndian>()?;
|
||||
|
||||
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<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
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<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
visitor.visit_some(self)
|
||||
}
|
||||
|
||||
fn deserialize_struct<V>(
|
||||
self,
|
||||
_name: &'static str,
|
||||
fields: &'static [&'static str],
|
||||
visitor: V,
|
||||
) -> Result<V::Value, Self::Error>
|
||||
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
|
||||
}
|
||||
}
|
|
@ -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<R> {
|
||||
/// 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<R: Read> RootDeserializer<R> {
|
||||
/// 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<Tag, Error> {
|
||||
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::<BigEndian>()? {
|
||||
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::<BigEndian>()? {
|
||||
self.reader.read_u8()?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(tag)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de: 'a, 'a, R: Read> Deserializer<'de> for &'a mut RootDeserializer<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 enum identifier ignored_any
|
||||
}
|
||||
|
||||
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
let tag = self.read_name()?;
|
||||
|
||||
PayloadDeserializer {
|
||||
reader: &mut self.reader,
|
||||
tag,
|
||||
}
|
||||
.deserialize_any(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_struct<V>(
|
||||
self,
|
||||
name: &'static str,
|
||||
fields: &'static [&'static str],
|
||||
visitor: V,
|
||||
) -> Result<V::Value, Self::Error>
|
||||
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
|
||||
}
|
||||
}
|
|
@ -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<W, T>(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::<BigEndian>(len)?,
|
||||
Err(_) => return Err(Error::new_static("string byte length exceeds u16::MAX")),
|
||||
};
|
||||
|
||||
writer.write_all(&data)?;
|
||||
Ok(())
|
||||
}
|
|
@ -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<T: ?Sized>(&mut self, _key: &T) -> Result<(), Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
Err(Error::new_static(
|
||||
"map keys cannot be serialized individually",
|
||||
))
|
||||
}
|
||||
|
||||
fn serialize_value<T: ?Sized>(&mut self, _value: &T) -> Result<(), Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
Err(Error::new_static(
|
||||
"map values cannot be serialized individually",
|
||||
))
|
||||
}
|
||||
|
||||
fn serialize_entry<K: ?Sized, V: ?Sized>(
|
||||
&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<Self::Ok, Self::Error> {
|
||||
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<W: Write + ?Sized, V: Serialize + ?Sized> 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<Self::Ok, Self::Error> {
|
||||
non_string_map_key!("bool")
|
||||
}
|
||||
|
||||
fn serialize_i8(self, _v: i8) -> Result<Self::Ok, Self::Error> {
|
||||
non_string_map_key!("i8")
|
||||
}
|
||||
|
||||
fn serialize_i16(self, _v: i16) -> Result<Self::Ok, Self::Error> {
|
||||
non_string_map_key!("i16")
|
||||
}
|
||||
|
||||
fn serialize_i32(self, _v: i32) -> Result<Self::Ok, Self::Error> {
|
||||
non_string_map_key!("i32")
|
||||
}
|
||||
|
||||
fn serialize_i64(self, _v: i64) -> Result<Self::Ok, Self::Error> {
|
||||
non_string_map_key!("i64")
|
||||
}
|
||||
|
||||
fn serialize_u8(self, _v: u8) -> Result<Self::Ok, Self::Error> {
|
||||
non_string_map_key!("u8")
|
||||
}
|
||||
|
||||
fn serialize_u16(self, _v: u16) -> Result<Self::Ok, Self::Error> {
|
||||
non_string_map_key!("u16")
|
||||
}
|
||||
|
||||
fn serialize_u32(self, _v: u32) -> Result<Self::Ok, Self::Error> {
|
||||
non_string_map_key!("u32")
|
||||
}
|
||||
|
||||
fn serialize_u64(self, _v: u64) -> Result<Self::Ok, Self::Error> {
|
||||
non_string_map_key!("u64")
|
||||
}
|
||||
|
||||
fn serialize_f32(self, _v: f32) -> Result<Self::Ok, Self::Error> {
|
||||
non_string_map_key!("f32")
|
||||
}
|
||||
|
||||
fn serialize_f64(self, _v: f64) -> Result<Self::Ok, Self::Error> {
|
||||
non_string_map_key!("f64")
|
||||
}
|
||||
|
||||
fn serialize_char(self, _v: char) -> Result<Self::Ok, Self::Error> {
|
||||
non_string_map_key!("char")
|
||||
}
|
||||
|
||||
fn serialize_str(self, v: &str) -> Result<Self::Ok, Self::Error> {
|
||||
self.value
|
||||
.serialize(&mut PayloadSerializer::named(self.writer, v))
|
||||
.map_err(|e| e.field(v))
|
||||
}
|
||||
|
||||
fn serialize_bytes(self, _v: &[u8]) -> Result<Self::Ok, Self::Error> {
|
||||
non_string_map_key!("&[u8]")
|
||||
}
|
||||
|
||||
fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
|
||||
non_string_map_key!("None")
|
||||
}
|
||||
|
||||
fn serialize_some<T: ?Sized>(self, _value: &T) -> Result<Self::Ok, Self::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
non_string_map_key!("Some")
|
||||
}
|
||||
|
||||
fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
|
||||
non_string_map_key!("()")
|
||||
}
|
||||
|
||||
fn serialize_unit_struct(self, _name: &'static str) -> Result<Self::Ok, Self::Error> {
|
||||
non_string_map_key!("unit struct")
|
||||
}
|
||||
|
||||
fn serialize_unit_variant(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_variant_index: u32,
|
||||
_variant: &'static str,
|
||||
) -> Result<Self::Ok, Self::Error> {
|
||||
non_string_map_key!("unit variant")
|
||||
}
|
||||
|
||||
fn serialize_newtype_struct<T: ?Sized>(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_value: &T,
|
||||
) -> Result<Self::Ok, Self::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
non_string_map_key!("newtype struct")
|
||||
}
|
||||
|
||||
fn serialize_newtype_variant<T: ?Sized>(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_variant_index: u32,
|
||||
_variant: &'static str,
|
||||
_value: &T,
|
||||
) -> Result<Self::Ok, Self::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
non_string_map_key!("newtype variant")
|
||||
}
|
||||
|
||||
fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
|
||||
non_string_map_key!("seq")
|
||||
}
|
||||
|
||||
fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple, Self::Error> {
|
||||
non_string_map_key!("tuple")
|
||||
}
|
||||
|
||||
fn serialize_tuple_struct(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_len: usize,
|
||||
) -> Result<Self::SerializeTupleStruct, Self::Error> {
|
||||
non_string_map_key!("tuple struct")
|
||||
}
|
||||
|
||||
fn serialize_tuple_variant(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_variant_index: u32,
|
||||
_variant: &'static str,
|
||||
_len: usize,
|
||||
) -> Result<Self::SerializeTupleVariant, Self::Error> {
|
||||
non_string_map_key!("tuple variant")
|
||||
}
|
||||
|
||||
fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
|
||||
non_string_map_key!("map")
|
||||
}
|
||||
|
||||
fn serialize_struct(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_len: usize,
|
||||
) -> Result<Self::SerializeStruct, Self::Error> {
|
||||
non_string_map_key!("struct")
|
||||
}
|
||||
|
||||
fn serialize_struct_variant(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_variant_index: u32,
|
||||
_variant: &'static str,
|
||||
_len: usize,
|
||||
) -> Result<Self::SerializeStructVariant, Self::Error> {
|
||||
non_string_map_key!("struct variant")
|
||||
}
|
||||
|
||||
fn is_human_readable(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
|
@ -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<Tag> {
|
||||
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::<BigEndian>(*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::Ok, Self::Error> {
|
||||
self.check_state(Tag::Byte)?;
|
||||
Ok(self.writer.write_i8(v as i8)?)
|
||||
}
|
||||
|
||||
fn serialize_i8(self, v: i8) -> Result<Self::Ok, Self::Error> {
|
||||
self.check_state(Tag::Byte)?;
|
||||
Ok(self.writer.write_i8(v)?)
|
||||
}
|
||||
|
||||
fn serialize_i16(self, v: i16) -> Result<Self::Ok, Self::Error> {
|
||||
self.check_state(Tag::Short)?;
|
||||
Ok(self.writer.write_i16::<BigEndian>(v)?)
|
||||
}
|
||||
|
||||
fn serialize_i32(self, v: i32) -> Result<Self::Ok, Self::Error> {
|
||||
self.check_state(Tag::Int)?;
|
||||
Ok(self.writer.write_i32::<BigEndian>(v)?)
|
||||
}
|
||||
|
||||
fn serialize_i64(self, v: i64) -> Result<Self::Ok, Self::Error> {
|
||||
self.check_state(Tag::Long)?;
|
||||
Ok(self.writer.write_i64::<BigEndian>(v)?)
|
||||
}
|
||||
|
||||
fn serialize_u8(self, _v: u8) -> Result<Self::Ok, Self::Error> {
|
||||
unsupported!("u8")
|
||||
}
|
||||
|
||||
fn serialize_u16(self, _v: u16) -> Result<Self::Ok, Self::Error> {
|
||||
unsupported!("u16")
|
||||
}
|
||||
|
||||
fn serialize_u32(self, _v: u32) -> Result<Self::Ok, Self::Error> {
|
||||
unsupported!("u32")
|
||||
}
|
||||
|
||||
fn serialize_u64(self, _v: u64) -> Result<Self::Ok, Self::Error> {
|
||||
unsupported!("u64")
|
||||
}
|
||||
|
||||
fn serialize_f32(self, v: f32) -> Result<Self::Ok, Self::Error> {
|
||||
self.check_state(Tag::Float)?;
|
||||
Ok(self.writer.write_f32::<BigEndian>(v)?)
|
||||
}
|
||||
|
||||
fn serialize_f64(self, v: f64) -> Result<Self::Ok, Self::Error> {
|
||||
self.check_state(Tag::Double)?;
|
||||
Ok(self.writer.write_f64::<BigEndian>(v)?)
|
||||
}
|
||||
|
||||
fn serialize_char(self, _v: char) -> Result<Self::Ok, Self::Error> {
|
||||
unsupported!("char")
|
||||
}
|
||||
|
||||
fn serialize_str(self, v: &str) -> Result<Self::Ok, Self::Error> {
|
||||
self.check_state(Tag::String)?;
|
||||
write_string(&mut *self.writer, v)
|
||||
}
|
||||
|
||||
fn serialize_bytes(self, _v: &[u8]) -> Result<Self::Ok, Self::Error> {
|
||||
unsupported!("&[u8]")
|
||||
}
|
||||
|
||||
fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn serialize_some<T: ?Sized>(self, value: &T) -> Result<Self::Ok, Self::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
value.serialize(self)
|
||||
}
|
||||
|
||||
fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
|
||||
unsupported!("()")
|
||||
}
|
||||
|
||||
fn serialize_unit_struct(self, _name: &'static str) -> Result<Self::Ok, Self::Error> {
|
||||
unsupported!("unit struct")
|
||||
}
|
||||
|
||||
fn serialize_unit_variant(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_variant_index: u32,
|
||||
_variant: &'static str,
|
||||
) -> Result<Self::Ok, Self::Error> {
|
||||
unsupported!("unit variant")
|
||||
}
|
||||
|
||||
fn serialize_newtype_struct<T: ?Sized>(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_value: &T,
|
||||
) -> Result<Self::Ok, Self::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
unsupported!("newtype struct")
|
||||
}
|
||||
|
||||
fn serialize_newtype_variant<T: ?Sized>(
|
||||
self,
|
||||
name: &'static str,
|
||||
_variant_index: u32,
|
||||
variant: &'static str,
|
||||
value: &T,
|
||||
) -> Result<Self::Ok, Self::Error>
|
||||
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<usize>) -> Result<Self::SerializeSeq, Self::Error> {
|
||||
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::<BigEndian>(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<Self::SerializeTuple, Self::Error> {
|
||||
unsupported!("tuple")
|
||||
}
|
||||
|
||||
fn serialize_tuple_struct(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_len: usize,
|
||||
) -> Result<Self::SerializeTupleStruct, Self::Error> {
|
||||
unsupported!("tuple struct")
|
||||
}
|
||||
|
||||
fn serialize_tuple_variant(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_variant_index: u32,
|
||||
_variant: &'static str,
|
||||
_len: usize,
|
||||
) -> Result<Self::SerializeTupleVariant, Self::Error> {
|
||||
unsupported!("tuple variant")
|
||||
}
|
||||
|
||||
fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
|
||||
self.check_state(Tag::Compound)?;
|
||||
|
||||
Ok(SerializeMap {
|
||||
writer: self.writer,
|
||||
})
|
||||
}
|
||||
|
||||
fn serialize_struct(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_len: usize,
|
||||
) -> Result<Self::SerializeStruct, Self::Error> {
|
||||
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<Self::SerializeStructVariant, Self::Error> {
|
||||
unsupported!("struct variant")
|
||||
}
|
||||
|
||||
fn is_human_readable(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
|
@ -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<Self::Ok, Self::Error> {
|
||||
not_compound!("bool")
|
||||
}
|
||||
|
||||
fn serialize_i8(self, _v: i8) -> Result<Self::Ok, Self::Error> {
|
||||
not_compound!("i8")
|
||||
}
|
||||
|
||||
fn serialize_i16(self, _v: i16) -> Result<Self::Ok, Self::Error> {
|
||||
not_compound!("i16")
|
||||
}
|
||||
|
||||
fn serialize_i32(self, _v: i32) -> Result<Self::Ok, Self::Error> {
|
||||
not_compound!("i32")
|
||||
}
|
||||
|
||||
fn serialize_i64(self, _v: i64) -> Result<Self::Ok, Self::Error> {
|
||||
not_compound!("i64")
|
||||
}
|
||||
|
||||
fn serialize_u8(self, _v: u8) -> Result<Self::Ok, Self::Error> {
|
||||
not_compound!("u8")
|
||||
}
|
||||
|
||||
fn serialize_u16(self, _v: u16) -> Result<Self::Ok, Self::Error> {
|
||||
not_compound!("u16")
|
||||
}
|
||||
|
||||
fn serialize_u32(self, _v: u32) -> Result<Self::Ok, Self::Error> {
|
||||
not_compound!("u32")
|
||||
}
|
||||
|
||||
fn serialize_u64(self, _v: u64) -> Result<Self::Ok, Self::Error> {
|
||||
not_compound!("u64")
|
||||
}
|
||||
|
||||
fn serialize_f32(self, _v: f32) -> Result<Self::Ok, Self::Error> {
|
||||
not_compound!("f32")
|
||||
}
|
||||
|
||||
fn serialize_f64(self, _v: f64) -> Result<Self::Ok, Self::Error> {
|
||||
not_compound!("f64")
|
||||
}
|
||||
|
||||
fn serialize_char(self, _v: char) -> Result<Self::Ok, Self::Error> {
|
||||
not_compound!("char")
|
||||
}
|
||||
|
||||
fn serialize_str(self, _v: &str) -> Result<Self::Ok, Self::Error> {
|
||||
not_compound!("str")
|
||||
}
|
||||
|
||||
fn serialize_bytes(self, _v: &[u8]) -> Result<Self::Ok, Self::Error> {
|
||||
not_compound!("&[u8]")
|
||||
}
|
||||
|
||||
fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
|
||||
not_compound!("None")
|
||||
}
|
||||
|
||||
fn serialize_some<T: ?Sized>(self, _value: &T) -> Result<Self::Ok, Self::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
not_compound!("Some")
|
||||
}
|
||||
|
||||
fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
|
||||
not_compound!("()")
|
||||
}
|
||||
|
||||
fn serialize_unit_struct(self, _name: &'static str) -> Result<Self::Ok, Self::Error> {
|
||||
not_compound!("unit struct")
|
||||
}
|
||||
|
||||
fn serialize_unit_variant(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_variant_index: u32,
|
||||
_variant: &'static str,
|
||||
) -> Result<Self::Ok, Self::Error> {
|
||||
not_compound!("unit variant")
|
||||
}
|
||||
|
||||
fn serialize_newtype_struct<T: ?Sized>(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_value: &T,
|
||||
) -> Result<Self::Ok, Self::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
not_compound!("newtype struct")
|
||||
}
|
||||
|
||||
fn serialize_newtype_variant<T: ?Sized>(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_variant_index: u32,
|
||||
_variant: &'static str,
|
||||
_value: &T,
|
||||
) -> Result<Self::Ok, Self::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
not_compound!("newtype variant")
|
||||
}
|
||||
|
||||
fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
|
||||
not_compound!("seq")
|
||||
}
|
||||
|
||||
fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple, Self::Error> {
|
||||
not_compound!("tuple")
|
||||
}
|
||||
|
||||
fn serialize_tuple_struct(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_len: usize,
|
||||
) -> Result<Self::SerializeTupleStruct, Self::Error> {
|
||||
not_compound!("tuple struct")
|
||||
}
|
||||
|
||||
fn serialize_tuple_variant(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_variant_index: u32,
|
||||
_variant: &'static str,
|
||||
_len: usize,
|
||||
) -> Result<Self::SerializeTupleVariant, Self::Error> {
|
||||
not_compound!("tuple variant")
|
||||
}
|
||||
|
||||
fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
|
||||
self.write_header()?;
|
||||
|
||||
Ok(SerializeMap {
|
||||
writer: &mut self.writer,
|
||||
})
|
||||
}
|
||||
|
||||
fn serialize_struct(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_len: usize,
|
||||
) -> Result<Self::SerializeStruct, Self::Error> {
|
||||
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<Self::SerializeStructVariant, Self::Error> {
|
||||
not_compound!("struct variant")
|
||||
}
|
||||
|
||||
fn is_human_readable(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
|
@ -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<W: Write + ?Sized> ser::SerializeSeq for SerializeSeq<'_, W> {
|
||||
type Ok = ();
|
||||
type Error = Error;
|
||||
|
||||
fn serialize_element<T: ?Sized>(&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<Self::Ok, Self::Error> {
|
||||
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::<BigEndian>(0)?;
|
||||
}
|
||||
}
|
||||
ListOrArray::Array => {
|
||||
// Array length should be written by the serializer already.
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -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<W: Write + ?Sized> ser::SerializeStruct for SerializeStruct<'_, W> {
|
||||
type Ok = ();
|
||||
type Error = Error;
|
||||
|
||||
fn serialize_field<T: ?Sized>(
|
||||
&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<Self::Ok, Self::Error> {
|
||||
Ok(self.writer.write_u8(Tag::End as u8)?)
|
||||
}
|
||||
}
|
|
@ -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<ErrorInner>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct ErrorInner {
|
||||
trace: Vec<String>,
|
||||
cause: Cause,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Cause {
|
||||
Io(io::Error),
|
||||
// catch-all errors
|
||||
Owned(Box<str>),
|
||||
Static(&'static str),
|
||||
}
|
||||
|
||||
impl Error {
|
||||
pub(crate) fn new_owned(msg: impl Into<Box<str>>) -> 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<String>) -> 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<Item = &str> + 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<T>(msg: T) -> Self
|
||||
where
|
||||
T: Display,
|
||||
{
|
||||
Error::new_owned(format!("{msg}"))
|
||||
}
|
||||
}
|
||||
|
||||
impl de::Error for Error {
|
||||
fn custom<T>(msg: T) -> Self
|
||||
where
|
||||
T: Display,
|
||||
{
|
||||
Error::new_owned(format!("{msg}"))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<io::Error> for Error {
|
||||
fn from(e: io::Error) -> Self {
|
||||
Self {
|
||||
inner: Box::new(ErrorInner {
|
||||
trace: Vec::new(),
|
||||
cause: Cause::Io(e),
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<f32>,
|
||||
//! #[serde(with = "serde_nbt::int_array")]
|
||||
//! int_array: Vec<i32>,
|
||||
//! }
|
||||
//!
|
||||
//! 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<T> = std::result::Result<T, Error>;
|
||||
|
||||
#[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<D>(deserializer: D) -> std::result::Result<Self, D::Error>
|
||||
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<E>(self, v: u8) -> std::result::Result<Self::Value, E>
|
||||
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<E>(self, v: &str) -> std::result::Result<Self::Value, E>
|
||||
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<Self> {
|
||||
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__";
|
|
@ -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<i32>,
|
||||
list_of_string: Vec<String>,
|
||||
string: String,
|
||||
inner: Inner,
|
||||
#[serde(with = "int_array")]
|
||||
int_array: Vec<i32>,
|
||||
#[serde(with = "byte_array")]
|
||||
byte_array: Vec<i8>,
|
||||
#[serde(with = "long_array")]
|
||||
long_array: Vec<i64>,
|
||||
some_int: Option<i32>,
|
||||
none_int: Option<i32>,
|
||||
}
|
||||
|
||||
#[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<i32>,
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
|
@ -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<i8>),
|
||||
String(String),
|
||||
List(List),
|
||||
Compound(Compound),
|
||||
IntArray(Vec<i32>),
|
||||
LongArray(Vec<i64>),
|
||||
}
|
||||
|
||||
/// An arbitrary NBT compound.
|
||||
///
|
||||
/// This is a convenient type alias for the [`IndexMap`] type.
|
||||
pub type Compound = IndexMap<String, Value>;
|
||||
|
||||
/// 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<i8>),
|
||||
Short(Vec<i16>),
|
||||
Int(Vec<i32>),
|
||||
Long(Vec<i64>),
|
||||
Float(Vec<f32>),
|
||||
Double(Vec<f64>),
|
||||
ByteArray(Vec<Vec<i8>>),
|
||||
String(Vec<String>),
|
||||
List(Vec<List>),
|
||||
Compound(Vec<Compound>),
|
||||
IntArray(Vec<Vec<i32>>),
|
||||
LongArray(Vec<Vec<i64>>),
|
||||
}
|
||||
|
||||
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<i8> for Value {
|
||||
fn from(v: i8) -> Self {
|
||||
Self::Byte(v)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<i16> for Value {
|
||||
fn from(v: i16) -> Self {
|
||||
Self::Short(v)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<i32> for Value {
|
||||
fn from(v: i32) -> Self {
|
||||
Self::Int(v)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<i64> for Value {
|
||||
fn from(v: i64) -> Self {
|
||||
Self::Long(v)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<f32> for Value {
|
||||
fn from(v: f32) -> Self {
|
||||
Self::Float(v)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<f64> for Value {
|
||||
fn from(v: f64) -> Self {
|
||||
Self::Double(v)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<i8>> for Value {
|
||||
fn from(v: Vec<i8>) -> Self {
|
||||
Self::ByteArray(v)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> 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<Cow<'a, str>> for Value {
|
||||
fn from(v: Cow<'a, str>) -> Self {
|
||||
Self::String(v.into_owned())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<List> for Value {
|
||||
fn from(v: List) -> Self {
|
||||
Self::List(v)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Compound> for Value {
|
||||
fn from(v: Compound) -> Self {
|
||||
Self::Compound(v)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<i32>> for Value {
|
||||
fn from(v: Vec<i32>) -> Self {
|
||||
Self::IntArray(v)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<i64>> for Value {
|
||||
fn from(v: Vec<i64>) -> Self {
|
||||
Self::LongArray(v)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<i8>> for List {
|
||||
fn from(v: Vec<i8>) -> Self {
|
||||
List::Byte(v)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<i16>> for List {
|
||||
fn from(v: Vec<i16>) -> Self {
|
||||
List::Short(v)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<i32>> for List {
|
||||
fn from(v: Vec<i32>) -> Self {
|
||||
List::Int(v)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<i64>> for List {
|
||||
fn from(v: Vec<i64>) -> Self {
|
||||
List::Long(v)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<f32>> for List {
|
||||
fn from(v: Vec<f32>) -> Self {
|
||||
List::Float(v)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<f64>> for List {
|
||||
fn from(v: Vec<f64>) -> Self {
|
||||
List::Double(v)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<Vec<i8>>> for List {
|
||||
fn from(v: Vec<Vec<i8>>) -> Self {
|
||||
List::ByteArray(v)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<String>> for List {
|
||||
fn from(v: Vec<String>) -> Self {
|
||||
List::String(v)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<List>> for List {
|
||||
fn from(v: Vec<List>) -> Self {
|
||||
List::List(v)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<Compound>> for List {
|
||||
fn from(v: Vec<Compound>) -> Self {
|
||||
List::Compound(v)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<Vec<i32>>> for List {
|
||||
fn from(v: Vec<Vec<i32>>) -> Self {
|
||||
List::IntArray(v)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<Vec<i64>>> for List {
|
||||
fn from(v: Vec<Vec<i64>>) -> Self {
|
||||
List::LongArray(v)
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for Value {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
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<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
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<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
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<E>(self, v: i8) -> Result<Self::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
Ok(Value::Byte(v))
|
||||
}
|
||||
|
||||
fn visit_i16<E>(self, v: i16) -> Result<Self::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
Ok(Value::Short(v))
|
||||
}
|
||||
|
||||
fn visit_i32<E>(self, v: i32) -> Result<Self::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
Ok(Value::Int(v))
|
||||
}
|
||||
|
||||
fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
Ok(Value::Long(v))
|
||||
}
|
||||
|
||||
fn visit_f32<E>(self, v: f32) -> Result<Self::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
Ok(Value::Float(v))
|
||||
}
|
||||
|
||||
fn visit_f64<E>(self, v: f64) -> Result<Self::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
Ok(Value::Double(v))
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
Ok(Value::String(v.to_owned()))
|
||||
}
|
||||
|
||||
fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
Ok(Value::String(v))
|
||||
}
|
||||
|
||||
fn visit_seq<A>(self, seq: A) -> Result<Self::Value, A::Error>
|
||||
where
|
||||
A: SeqAccess<'de>,
|
||||
{
|
||||
ListVisitor.visit_seq(seq).map(Value::List)
|
||||
}
|
||||
|
||||
fn visit_map<A>(self, map: A) -> Result<Self::Value, A::Error>
|
||||
where
|
||||
A: MapAccess<'de>,
|
||||
{
|
||||
visit_map(map).map(Value::Compound)
|
||||
}
|
||||
|
||||
fn visit_enum<A>(self, data: A) -> Result<Self::Value, A::Error>
|
||||
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<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
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<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
|
||||
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<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
|
||||
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<E>(self, v: i8) -> Result<Self::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
visit!(self, Byte, v, E)
|
||||
}
|
||||
|
||||
fn visit_i16<E>(self, v: i16) -> Result<Self::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
visit!(self, Short, v, E)
|
||||
}
|
||||
|
||||
fn visit_i32<E>(self, v: i32) -> Result<Self::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
visit!(self, Int, v, E)
|
||||
}
|
||||
|
||||
fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
visit!(self, Long, v, E)
|
||||
}
|
||||
|
||||
fn visit_f32<E>(self, v: f32) -> Result<Self::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
visit!(self, Float, v, E)
|
||||
}
|
||||
|
||||
fn visit_f64<E>(self, v: f64) -> Result<Self::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
visit!(self, Double, v, E)
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
visit!(self, String, v.to_owned(), E)
|
||||
}
|
||||
|
||||
fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
visit!(self, String, v, E)
|
||||
}
|
||||
|
||||
fn visit_seq<A>(self, seq: A) -> Result<Self::Value, A::Error>
|
||||
where
|
||||
A: SeqAccess<'de>,
|
||||
{
|
||||
visit!(self, List, ListVisitor.visit_seq(seq)?, A::Error)
|
||||
}
|
||||
|
||||
fn visit_map<A>(self, map: A) -> Result<Self::Value, A::Error>
|
||||
where
|
||||
A: MapAccess<'de>,
|
||||
{
|
||||
visit!(self, Compound, visit_map(map)?, A::Error)
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_map<'de, A>(mut map: A) -> Result<Compound, A::Error>
|
||||
where
|
||||
A: MapAccess<'de>,
|
||||
{
|
||||
let mut compound = Compound::new();
|
||||
|
||||
while let Some((k, v)) = map.next_entry()? {
|
||||
compound.insert(k, v);
|
||||
}
|
||||
|
||||
Ok(compound)
|
||||
}
|
Loading…
Reference in a new issue