Serialization
Add rustc-serialize to your Cargo.toml
file:
[dependencies]
rustc-serialize = "*"
Then annotate all your struct
s that you want to serialize with #[derive(RustcEncodable, RustcDecodable)]
and the compiler will implement the serialization code for you:
extern crate rustc_serialize;
#[derive(RustcEncodable, RustcDecodable, PartialEq)]
struct Entity {
x: f32,
y: f32,
}
#[derive(RustcEncodable, RustcDecodable, PartialEq)]
struct World {
entities: Vec<Entity>
}
fn main() {
let world = World {
entities: vec![Entity {x: 0.0, y: 4.0}, Entity {x: 10.0, y: 20.5}]
};
}
Binary format
Bincode is a binary encoder / decoder implementation in Rust.
Add bincode to your Cargo.toml
file:
[dependencies]
bincode = "*"
And use it like this:
extern crate rustc_serialize;
extern crate bincode;
#[derive(RustcEncodable, RustcDecodable, PartialEq)]
struct Entity {
x: f32,
y: f32,
}
#[derive(RustcEncodable, RustcDecodable, PartialEq)]
struct World {
entities: Vec<Entity>
}
fn main() {
let world = World {
entities: vec![Entity {x: 0.0, y: 4.0}, Entity {x: 10.0, y: 20.5}]
};
let encoded: Vec<u8> = bincode::encode(&world, bincode::SizeLimit::Infinite).unwrap();
let decoded: World = bincode::decode(&encoded[..]).unwrap();
assert!(world == decoded);
}
This example was taken from bincode's README.
Writing to disk
Here is how you can write to and load directly from files:
use std::fs::File;
fn main() {
let world = World { entities: vec![Entity {x: 0.0, y: 4.0}, Entity {x: 10.0, y: 20.5}] };
{
let mut file = File::create("world.bin").unwrap();
bincode::encode_into(&world, &mut file, bincode::SizeLimit::Infinite).unwrap();
}
let mut file = File::open("world.bin").unwrap();
let decoded: World = bincode::decode_from(&mut file, bincode::SizeLimit::Infinite).unwrap();
assert!(world == decoded);
}
Using BufWriter
and BufReader
are just as easy:
use std::fs::File;
use std::io::{BufWriter, BufReader};
fn main() {
let world = World { entities: vec![Entity {x: 0.0, y: 4.0}, Entity {x: 10.0, y: 20.5}] };
{
let mut writer = BufWriter::new(File::create("world.bin").unwrap());
bincode::encode_into(&world, &mut writer, bincode::SizeLimit::Infinite).unwrap();
}
let mut reader = BufReader::new(File::open("world.bin").unwrap());
let decoded: World = bincode::decode_from(&mut reader, bincode::SizeLimit::Infinite).unwrap();
assert!(world == decoded);
}
Compression
Since you can stream the bytes, it is easy to add compressions/decompression:
We are going to use the flate2 library.
Add flate2 to our Cargo.toml
:
[dependencies]
flate2 = "*"
And use it like this:
extern crate flate2;
use std::fs::File;
use std::io::{BufWriter, BufReader};
use flate2::write::ZlibEncoder;
use flate2::read::ZlibDecoder;
use flate2::Compression;
fn main() {
let world = World { entities: vec![Entity {x: 0.0, y: 4.0}, Entity {x: 10.0, y: 20.5}] };
{
let writer = BufWriter::new(File::create("world.bin.gz").unwrap());
let mut encoder = ZlibEncoder::new(writer, Compression::Best);
bincode::encode_into(&world, &mut encoder, bincode::SizeLimit::Infinite).unwrap();
}
let reader = BufReader::new(File::open("world.bin.gz").unwrap());
let mut decoder = ZlibDecoder::new(reader);
let decoded: World = bincode::decode_from(&mut decoder, bincode::SizeLimit::Infinite).unwrap();
assert!(world == decoded);
}
Final remarks
Make sure to read up on SizeLimit
which limits the amount of bytes that can be read or written.
Tested with
$ rustc --version
rustc 1.3.0-nightly (69ca01256 2015-07-23)