Module quartz_nbt::serde

source ·
Expand description

When the serde feature is enabled, this module provides Serializer and Deserializer implementations to link this crate into the serde data model.

§Example

use quartz_nbt::{
    io::Flavor,
    serde::{serialize, deserialize}
};

#[derive(Serialize, Deserialize, PartialEq, Debug)]
pub struct Entity {
    name: String,
    health: f32,
    position: (f64, f64)
}

let entity = Entity {
    name: "Ferris".to_owned(),
    health: 100.0,
    position: (1.0, -2.0)
};

let serialized: Vec<u8> = serialize(
    &entity,
    None, // Name of the root tag
    Flavor::Uncompressed
).unwrap();
let (deserialized, _root_name) = deserialize(
    &serialized,
    Flavor::Uncompressed
).unwrap();

assert_eq!(entity, deserialized);

§Arrays

By default, all sequential types (vectors, arrays, tuples, etc.) are serialized as tag lists. If you wish to have a type serialized as a byte array, int array, or long array, you can opt-into that by wrapping the type in Array. An example is shown below.

use quartz_nbt::{
    compound,
    io::{self, Flavor},
    serde::{Array, serialize}
};
use std::io::Cursor;

#[derive(Serialize)]
struct Arrays {
    int_array: Array<Vec<i32>>,
    bytes: Array<[i8; 3]>
}

let arrays = Arrays {
    int_array: Array::from(vec![1i32, -2i32, 3i32]),
    bytes: Array::from([-32i8, -64, -128])
};

let repr = compound! {
    "int_array": [I; 1, -2, 3],
    "bytes": [B; -32, -64, -128]
};

let serialized: Vec<u8> = serialize(
    &arrays,
    None,
    Flavor::Uncompressed
).unwrap();

assert_eq!(
    repr,
    io::read_nbt(&mut Cursor::new(serialized), Flavor::Uncompressed).unwrap().0
);

§Enum Representation

All enum types can be represented in NBT, however not all types are efficiently representable. Unit variants are serialized according to their index in the enum, while all other variant types are serialized as compounds. Although we do not currently support serializing unit variants by name, we will likely add this feature in future versions, and already support deserializing unit variants by name.

use quartz_nbt::{
    compound,
    io::{self, Flavor},
    serde::serialize
};
use std::io::Cursor;

#[derive(Serialize)]
enum MyEnum {
    Unit,
    Newtype(i32),
    Tuple(String, String),
    Struct {
        a: i32,
        b: f32
    }
}

#[derive(Serialize)]
struct AllVariants {
    unit: MyEnum,
    newtype: MyEnum,
    tuple: MyEnum,
    strukt: MyEnum
}

let data = AllVariants {
    unit: MyEnum::Unit,
    newtype: MyEnum::Newtype(10),
    tuple: MyEnum::Tuple("foo".to_owned(), "bar".to_owned()),
    strukt: MyEnum::Struct {
        a: -1,
        b: 4.669201
    }
};

let repr = compound! {
    "unit": 0i32,
    "newtype": {
        "Newtype": 10i32
    },
    "tuple": {
        "Tuple": ["foo", "bar"]
    },
    "strukt": {
        "Struct": {
            "a": -1i32,
            "b": 4.669201f32
        }
    }
};

let serialized: Vec<u8> = serialize(
    &data,
    None,
    Flavor::Uncompressed
).unwrap();

assert_eq!(
    repr,
    io::read_nbt(&mut Cursor::new(serialized), Flavor::Uncompressed).unwrap().0
);

§Borrowing Data

With some inventive coding techniques, we were able to allow for borrowing data during deserialization, for free, without significantly changing the original serde API. This feature can only be taken advantage of by using deserialize_from_buffer, which requires that the input is in the form of a slice of uncompressed, binary NBT data.

Note that although you can borrow bytes for free, because NBT uses Java’s CESU-8 encoding, attempting to borrow a string may fail if it is not UTF-8, hence it is recommended to use a Cow with the attribute #[serde(borrow)] in case the string needs to be re-encoded into an owned value.

use quartz_nbt::{
    compound,
    io::{self, Flavor},
    serde::deserialize_from_buffer
};
use std::{
    borrow::Cow,
    io::Cursor
};

#[derive(Deserialize, PartialEq, Debug)]
struct Borrowed<'a> {
    bytes: &'a [u8], // Bytes must be borrowed as unsigned
    #[serde(borrow)]
    string: Cow<'a, str>
}

let repr = compound! {
    "bytes": [B; 2, 3, 5, 7, 11],
    "string": "this is utf-8"
};

let mut bin_nbt = Cursor::new(Vec::<u8>::new());
io::write_nbt(&mut bin_nbt, None, &repr, Flavor::Uncompressed).unwrap();
let bin_nbt = bin_nbt.into_inner();

const PRIMES: &[u8] = &[2, 3, 5, 7, 11];

assert_eq!(
    deserialize_from_buffer::<Borrowed<'_>>(&bin_nbt).unwrap().0,
    Borrowed {
        bytes: PRIMES,
        string: Cow::Borrowed("this is utf-8")
    }
);

Structs§

  • A transparent wrapper around sequential types to allow the NBT serializer to automatically select an appropriate array type, favoring specialized array types like IntArray and ByteArray. You can construct an array using Array::from.
  • The deserializer type for reading binary NBT data.
  • This struct serves as a transparent wrapper around other sealed types to allow for blanket implementations of Serialize.

Functions§

  • Deserializes the given type from binary NBT data.
  • Deserializes the given type from binary NBT data read from the given reader.
  • Deserializes the given type from uncompressed, binary NBT data, allowing for the type to borrow from the given buffer.
  • Serializes the given value as binary NBT data, returning the resulting Vec. The value must be a struct or non-unit enum variant, else the serializer will return with an error.
  • Serializes the given value as binary NBT data, writing to the given writer.
  • Similar to serialize_into, but elides checks for homogeneity on sequential types and maximum array and string length checks. This means that there are some T for which this method will write invalid NBT data to the given writer.
  • Similar to serialize, but elides homogeneity checks on sequential types and maximum array and string length checks. This means that there are some T for which this method will return invalid NBT data.

Type Aliases§

  • The serializer type for writing binary NBT data.
  • An alternative serializer type for writing binary NBT data which elides checks for sequence homogeneity. Using this type could result in bogus NBT data.