Trait nbt::serialize::NbtFmt [] [src]

pub trait NbtFmt {
    type Into: Sized = Self;
    fn to_bare_nbt<W>(&self, dst: &mut W) -> Result<()> where W: Write;
    fn read_bare_nbt<R>(src: &mut R) -> Result<Self::Into> where R: Read;

    fn to_nbt<W, S>(&self, dst: &mut W, name: S) -> Result<()> where W: Write, S: AsRef<str> { ... }
    fn tag() -> u8 { ... }
    fn is_bare() -> bool { ... }
}

A trait indicating that the type has a Named Binary Tag representation.

Keep in mind that not all Rust types (notably unsigned integers) have an obvious NBT representation, and so structs that implement this trait may have to convert them to one that does.

Usage with Derive

A compiler plugin is available in the nbt_macros package to enable automatic derivation of NBT encoding/decoding for types. This is heavily recommended over implementing this trait by hand. Usage is generally as simple as the following:

#![feature(plugin, custom_derive)]
#![plugin(nbt_macros)]
 
extern crate nbt;
 
use nbt::serialize::{NbtFmt, to_writer};
 
#[derive(NbtFmt)]
struct MyMob {
    name: String,
    health: i8
}

fn main() {
    let mut bytes = Vec::new();
    let mob = MyMob { name: "Dr. Evil".to_string(), health: 240 };

    to_writer(&mut bytes, &mob).unwrap();
}

The package's documentation provides more detailed usage.

Manual Implementation

While it is not advisable to implement NbtFmt by hand, the code below is similar to what the automated derivation produces:

extern crate nbt;

use std::io::Cursor;
use nbt::serialize::*;

#[derive(Debug, PartialEq)]
struct MyMob {
    name: String,
    health: i8
}

impl NbtFmt for MyMob {
    type Into = MyMob;

    fn to_bare_nbt<W>(&self, dst: &mut W) -> nbt::Result<()>
       where W: std::io::Write
    {
        try!(self.name.to_nbt(dst, "name"));
        try!(self.health.to_nbt(dst, "health"));

        close_nbt(dst)
    }

    fn read_bare_nbt<R>(src: &mut R) -> nbt::Result<MyMob>
       where R: std::io::Read
    {
        let mut __name: String = Default::default();
        let mut __health: i8 = Default::default();

        loop {
            let (t, n) = try!(emit_next_header(src));

            if t == 0x00 { break; } // i.e. Tag_End

            match &n[..] {
                "name" => {
                    __name = try!(read_bare_nbt(src));
                },
                "health" => {
                    __health = try!(read_bare_nbt(src));
                },
                e => {
                    return Err(nbt::Error::UnexpectedField(e.to_string()));
                },
            };
        }

        Ok(MyMob { name: __name, health: __health })
    }
}

fn main() {
    let mut bytes = Vec::new();
    let mob = MyMob { name: "Dr. Evil".to_string(), health: 240 };

    to_writer(&mut bytes, &mob).unwrap();
    let read_mob: MyMob = from_reader(&mut Cursor::new(bytes.clone())).unwrap();

    assert_eq!(&mob, &read_mob);
}

Associated Types

type Into: Sized = Self

Required Methods

fn to_bare_nbt<W>(&self, dst: &mut W) -> Result<()> where W: Write

Convert this type to NBT format using the specified io::Write destination, but does not serialize its identifying NBT tag or name.

fn read_bare_nbt<R>(src: &mut R) -> Result<Self::Into> where R: Read

Reads from the specified io::Read source bytes that can be coverted into an instance of this type.

Provided Methods

fn to_nbt<W, S>(&self, dst: &mut W, name: S) -> Result<()> where W: Write, S: AsRef<str>

Convert this type to NBT format using the specified io::Write destination, incuding its tag and a given name.

fn tag() -> u8

Indicates the NBT tag that this type corresponds to. Most custom types (usually structs) will advertise the default, 0x0a, which is the default.

fn is_bare() -> bool

Indicates whether this type is "bare", in that it must be wrapped in an NBT Compound before serialization. By default this is false, since most imeplementations will be Compound-like objects. Primitive NBT types (i8, i16, String, etc.) return true.

Implementors