mirror of
https://github.com/italicsjenga/valence.git
synced 2025-01-27 14:06:34 +11:00
Add documentation to serde_nbt
This commit is contained in:
parent
27033c758e
commit
5d8f7a49da
19 changed files with 105 additions and 20 deletions
23
serde_nbt/Cargo.toml
Normal file
23
serde_nbt/Cargo.toml
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
[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"
|
|
@ -11,6 +11,33 @@ use crate::{
|
||||||
|
|
||||||
macro_rules! def_mod {
|
macro_rules! def_mod {
|
||||||
($index:literal, $mod_name:ident, $display_name:literal, $variant_name:ident) => {
|
($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 {
|
pub mod $mod_name {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
|
@ -11,6 +11,10 @@ mod list;
|
||||||
mod payload;
|
mod payload;
|
||||||
mod root;
|
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>
|
pub fn from_reader<R, T>(reader: R) -> Result<T, Error>
|
||||||
where
|
where
|
||||||
R: Read,
|
R: Read,
|
|
@ -10,14 +10,24 @@ use smallvec::SmallVec;
|
||||||
use crate::binary::de::payload::PayloadDeserializer;
|
use crate::binary::de::payload::PayloadDeserializer;
|
||||||
use crate::{Error, Tag, CESU8_DECODE_ERROR};
|
use crate::{Error, Tag, CESU8_DECODE_ERROR};
|
||||||
|
|
||||||
|
/// A serde [`Deserializer`] for the binary representation of NBT.
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub struct RootDeserializer<R> {
|
pub struct RootDeserializer<R> {
|
||||||
|
/// The reader to deserialize from.
|
||||||
pub reader: R,
|
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,
|
pub root_name: String,
|
||||||
|
/// Whether or not the root name should be saved to [`Self::root_name`]
|
||||||
|
/// during deserialization.
|
||||||
pub save_root_name: bool,
|
pub save_root_name: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R: Read> RootDeserializer<R> {
|
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 {
|
pub fn new(reader: R, save_root_name: bool) -> Self {
|
||||||
Self {
|
Self {
|
||||||
reader,
|
reader,
|
|
@ -13,6 +13,14 @@ mod root;
|
||||||
mod seq;
|
mod seq;
|
||||||
mod structs;
|
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<()>
|
pub fn to_writer<W, T>(writer: W, value: &T) -> Result<()>
|
||||||
where
|
where
|
||||||
W: Write,
|
W: Write,
|
|
@ -130,7 +130,7 @@ impl<W: Write + ?Sized, V: Serialize + ?Sized> Serializer for MapEntrySerializer
|
||||||
fn serialize_str(self, v: &str) -> Result<Self::Ok, Self::Error> {
|
fn serialize_str(self, v: &str) -> Result<Self::Ok, Self::Error> {
|
||||||
self.value
|
self.value
|
||||||
.serialize(&mut PayloadSerializer::named(self.writer, v))
|
.serialize(&mut PayloadSerializer::named(self.writer, v))
|
||||||
.map_err(|e| e.field(format!("{v}")))
|
.map_err(|e| e.field(v))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_bytes(self, _v: &[u8]) -> Result<Self::Ok, Self::Error> {
|
fn serialize_bytes(self, _v: &[u8]) -> Result<Self::Ok, Self::Error> {
|
|
@ -60,7 +60,7 @@ impl<'w, 'n, W: Write + ?Sized> PayloadSerializer<'w, 'n, W> {
|
||||||
match &mut self.state {
|
match &mut self.state {
|
||||||
State::Named(name) => {
|
State::Named(name) => {
|
||||||
self.writer.write_u8(tag as u8)?;
|
self.writer.write_u8(tag as u8)?;
|
||||||
write_string(&mut *self.writer, *name)?;
|
write_string(&mut *self.writer, name)?;
|
||||||
}
|
}
|
||||||
State::FirstListElement { len, written_tag } => {
|
State::FirstListElement { len, written_tag } => {
|
||||||
self.writer.write_u8(tag as u8)?;
|
self.writer.write_u8(tag as u8)?;
|
|
@ -8,13 +8,19 @@ use crate::binary::ser::structs::SerializeStruct;
|
||||||
use crate::binary::ser::{write_string, Impossible};
|
use crate::binary::ser::{write_string, Impossible};
|
||||||
use crate::{Error, Tag};
|
use crate::{Error, Tag};
|
||||||
|
|
||||||
|
/// A serde [`Serializer`] for the binary representation of NBT.
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub struct RootSerializer<'n, W> {
|
pub struct RootSerializer<'n, W> {
|
||||||
|
/// The writer to serialize to.
|
||||||
pub writer: W,
|
pub writer: W,
|
||||||
|
/// The name of the root compound to serialize.
|
||||||
|
///
|
||||||
|
/// The empty string `""` is acceptable.
|
||||||
pub root_name: &'n str,
|
pub root_name: &'n str,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'n, W: Write> RootSerializer<'n, W> {
|
impl<'n, W: Write> RootSerializer<'n, W> {
|
||||||
|
/// Constructs a new serializer.
|
||||||
pub fn new(writer: W, root_name: &'n str) -> Self {
|
pub fn new(writer: W, root_name: &'n str) -> Self {
|
||||||
Self { writer, root_name }
|
Self { writer, root_name }
|
||||||
}
|
}
|
|
@ -5,6 +5,10 @@ use std::{fmt, io};
|
||||||
|
|
||||||
use serde::{de, ser};
|
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)]
|
#[derive(Debug)]
|
||||||
pub struct Error {
|
pub struct Error {
|
||||||
/// Box this to keep the error as small as possible. We don't want to
|
/// Box this to keep the error as small as possible. We don't want to
|
||||||
|
@ -50,6 +54,10 @@ impl Error {
|
||||||
self
|
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(
|
pub fn trace(
|
||||||
&self,
|
&self,
|
||||||
) -> impl DoubleEndedIterator<Item = &str> + ExactSizeIterator + FusedIterator + Clone + '_
|
) -> impl DoubleEndedIterator<Item = &str> + ExactSizeIterator + FusedIterator + Clone + '_
|
|
@ -1,3 +1,9 @@
|
||||||
|
//! 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
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::fmt::{Display, Formatter};
|
use std::fmt::{Display, Formatter};
|
||||||
|
|
||||||
|
@ -145,8 +151,10 @@ impl Display for Tag {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Error message for cesu-8 decoding failures.
|
||||||
const CESU8_DECODE_ERROR: &str = "could not convert CESU-8 data to UTF-8";
|
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 ARRAY_ENUM_NAME: &str = "__array__";
|
||||||
|
|
||||||
const BYTE_ARRAY_VARIANT_NAME: &str = "__byte_array__";
|
const BYTE_ARRAY_VARIANT_NAME: &str = "__byte_array__";
|
|
@ -7,7 +7,12 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||||
|
|
||||||
use crate::{byte_array, int_array, long_array, ArrayType};
|
use crate::{byte_array, int_array, long_array, ArrayType};
|
||||||
|
|
||||||
/// Represents an arbitrary NBT value.
|
/// 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)]
|
#[derive(Clone, PartialEq, Debug)]
|
||||||
pub enum Value {
|
pub enum Value {
|
||||||
Byte(i8),
|
Byte(i8),
|
||||||
|
@ -24,6 +29,9 @@ pub enum Value {
|
||||||
LongArray(Vec<i64>),
|
LongArray(Vec<i64>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An arbitrary NBT compound.
|
||||||
|
///
|
||||||
|
/// This is a convenient type alias for the [`IndexMap`] type.
|
||||||
pub type Compound = IndexMap<String, Value>;
|
pub type Compound = IndexMap<String, Value>;
|
||||||
|
|
||||||
/// An NBT list value.
|
/// An NBT list value.
|
|
@ -1,17 +0,0 @@
|
||||||
[package]
|
|
||||||
name = "valence_nbt"
|
|
||||||
version = "0.1.0"
|
|
||||||
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", "const_generics"] }
|
|
||||||
|
|
||||||
[dev-dependencies]
|
|
||||||
hematite-nbt = "0.5"
|
|
||||||
serde_json = "1.0.85"
|
|
||||||
pretty_assertions = "1.2.1"
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue