Update the README

This commit is contained in:
Erick Tryzelaar
2015-08-09 16:37:01 -07:00
parent 1d538bc59d
commit fd3869d380
+183 -49
View File
@@ -10,78 +10,210 @@ information. In many situations, the handshake protocol between serializers and
serializees can be completely optimized away, leaving Serde to perform roughly serializees can be completely optimized away, leaving Serde to perform roughly
the same speed as a hand written serializer for a specific type. the same speed as a hand written serializer for a specific type.
Documentation is available at http://serde-rs.github.io/serde/serde Documentation is available at:
Making a Type Serializable * [serde](https://serde-rs.github.io/serde/serde/serde/index.html)
========================== * [serde\_json](https://serde-rs.github.io/serde/serde_json/serde_json/index.html)
* [serde\_codegen](https://serde-rs.github.io/serde/serde_codegen/serde_codegen/index.html)
The simplest way to make a type serializable is to use the `serde_macros` Using Serde
syntax extension, which comes with a `#[derive(Serialize, Deserialize)]` ===========
annotation, which automatically generates implementations of
[Serialize](http://serde-rs.github.io/serde/serde/ser/trait.Serialize.html) Here is a simple example that demonstrates how to use Serde by serializing and
and deserializing to JSON. Serde comes with some powerful code generation libraries
[Deserialize](http://serde-rs.github.io/serde/serde/de/trait.Deserialize.html) that work with Stable and Nightly Rust that eliminate much of the complexity of
for the annotated type: hand rolling serialization and deserialization for a given type. First lets see
how we would use Nightly Rust, which is currently a bit simpler than Stable
Rust:
`Cargo.toml`:
```toml
[package]
name = "serde_example_nightly"
version = "0.1.0"
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
[dependencies]
serde = "*"
serde_json = "*"
serde_macros = "*"
```
`src/main.rs`
```rust ```rust
#![feature(custom_derive, plugin)] #![feature(custom_derive, plugin)]
#![plugin(serde_macros)] #![plugin(serde_macros)]
extern crate serde; extern crate serde;
extern crate serde_json;
... #[derive(Serialize, Deserialize, Debug)]
#[derive(Serialize, Deserialize)]
struct Point { struct Point {
x: i32, x: i32,
y: i32, y: i32,
} }
fn main() {
let point = Point { x: 1, y: 2 };
let serialized = serde_json::to_string(&point).unwrap();
println!("{}", serialized);
let deserialized: Point = serde_json::from_str(&serialized_point).unwrap();
println!("{:?}", deserialized);
}
``` ```
Serde bundles a high performance JSON serializer and deserializer, When run, it produces:
[serde_json](http://serde-rs.github.io/serde/serde_json/index.html),
which comes with the helper functions ```
[to_string](http://serde-rs.github.io/serde/serde/json/ser/fn.to_string.html) % cargo run
and {"x":1,"y":2}
[from_str](http://serde-rs.github.io/serde/serde/json/de/fn.from_str.html) Point { x: 1, y: 2 }
that make it easy to go to and from JSON: ```
Stable Rust is a little more complicated because it does not yet support
compiler plugins. Instead we need to use the code generation library
[syntex](https://github.com/erickt/rust-syntex) for this:
```toml
[package]
name = "serde_example"
version = "0.1.0"
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
build = "build.rs"
[build-dependencies]
serde_codegen = "*"
syntex = "*"
[dependencies]
serde = "*"
serde_json = "*"
```
`src/main.rs`:
```rust ```rust
use serde_json; extern crate serde;
extern crate serde_json;
... include!(concat!(env!("OUT_DIR"), "/main.rs"));
let point = Point { x: 1, y: 2 };
let serialized_point = json::to_string(&point).unwrap();
println!("{}", serialized_point); // prints: {"x":1,"y":2}
let deserialize_point: Point = json::from_str(&serialized_point).unwrap();
``` ```
[serde_json](http://serde-rs.github.io/serde/serde_json/index.html) also `src/main.rs.in`:
supports a generic
[Value](http://serde-rs.github.io/serde/serde/json/value/enum.Value.html)
type, which can represent any JSON value. Also, any
[Serialize](http://serde-rs.github.io/serde/serde/ser/trait.Serialize.html)
and
[Deserialize](http://serde-rs.github.io/serde/serde/de/trait.Deserialize.html)
can be converted into a
[Value](http://serde-rs.github.io/serde/serde/json/value/enum.Value.html)
with the methods
[to_value](http://serde-rs.github.io/serde/serde/json/value/fn.to_value.html)
and
[from_value](http://serde-rs.github.io/serde/serde/json/value/fn.from_value.html):
```rust ```rust
let point = Point { x: 1, y: 2 }; #[derive(Serialize, Deserialize, Debug)]
let point_value = json::to_value(&point).unwrap(); struct Point {
x: i32,
y: i32,
}
println!("{}", point_value.find("x")); // prints: Some(1) fn main() {
let point = Point { x: 1, y: 2 };
let serialized = serde_json::to_string(&point).unwrap();
let deserialize_point: Point = json::from_value(point_value).unwrap(); println!("{}", serialized);
let deserialized: Point = serde_json::from_str(&serialized_point).unwrap();
println!("{:?}", deserialized);
}
``` ```
This also produces:
```
% cargo run
{"x":1,"y":2}
Point { x: 1, y: 2 }
```
While this works well with Stable Rust, be aware that the error locations
currently are reported in the generated file instead of in the source file. You
may find it easier to develop with Nightly Rust and `serde\_macros`, then
deploy with Stable Rust and `serde_codegen`. It's possible to combine both
approaches in one setup:
`Cargo.toml`:
```toml
[package]
name = "serde_example"
version = "0.1.0"
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
build = "build.rs"
[features]
default = ["serde_codegen"]
nightly = ["serde_macros"]
[build-dependencies]
serde_codegen = { version = "*", optional = true }
syntex = "*"
[dependencies]
serde = "*"
serde_json = "*"
serde_macros = { version = "*", optional = true }
```
`build.rs`:
```rust
#[cfg(not(feature = "serde_macros"))]
mod inner {
extern crate syntex;
extern crate serde_codegen;
use std::env;
use std::path::Path;
pub fn main() {
let out_dir = env::var_os("OUT_DIR").unwrap();
let src = Path::new("src/main.rs.in");
let dst = Path::new(&out_dir).join("main.rs");
let mut registry = syntex::Registry::new();
serde_codegen::register(&mut registry);
registry.expand("", &src, &dst).unwrap();
}
}
#[cfg(feature = "serde_macros")]
mod inner {
pub fn main() {}
}
fn main() {
inner::main();
}
```
`src/main.rs`:
```rust
#![cfg_attr(feature = "serde_macros", feature(custom_derive, plugin))]
#![cfg_attr(feature = "serde_macros", plugin(serde_macros))]
extern crate serde;
extern crate serde_json;
#[cfg(feature = "serde_macros")]
include!("main.rs.in");
#[cfg(not(feature = "serde_macros"))]
include!(concat!(env!("OUT_DIR"), "/main.rs"));
```
The `src/main.rs.in` is the same as before.
Serialization without Macros Serialization without Macros
============================ ============================
@@ -206,11 +338,11 @@ impl<'a> serde::ser::MapVisitor for PointMapVisitor<'a> {
match self.state { match self.state {
0 => { 0 => {
self.state += 1; self.state += 1;
Ok(Some(try!(serializer.visit_map_elt("x", &self.value.x)))) Ok(Some(try!(serializer.visit_struct_elt("x", &self.value.x))))
} }
1 => { 1 => {
self.state += 1; self.state += 1;
Ok(Some(try!(serializer.visit_map_elt("y", &self.value.y)))) Ok(Some(try!(serializer.visit_struct_elt("y", &self.value.y))))
} }
_ => { _ => {
Ok(None) Ok(None)
@@ -392,7 +524,9 @@ struct PointVisitor;
impl serde::de::Visitor for PointVisitor { impl serde::de::Visitor for PointVisitor {
type Value = Point; type Value = Point;
fn visit_map<V>(&mut self, mut visitor: V) -> Result<Point, V::Error> fn visit_struct<V>(&mut self,
_fields: &[&str],
mut visitor: V) -> Result<Point, V::Error>
where V: serde::de::MapVisitor where V: serde::de::MapVisitor
{ {
let mut x = None; let mut x = None;