Compare commits

...

59 Commits

Author SHA1 Message Date
David Tolnay 5fb73073bd Release 0.8.3 2016-08-19 13:11:59 -04:00
David Tolnay 63d484d50c Merge pull request #510 from serde-rs/clippy
Re-enable clippy
2016-08-19 13:01:24 -04:00
David Tolnay f3f29f81bc Fix new lints 2016-08-19 12:46:45 -04:00
David Tolnay 621588b258 Revert "Disable clippy until Manishearth/rust-clippy#1174 is fixed"
This reverts commit 2bc1d62e50.
2016-08-19 11:47:31 -04:00
Homu 7aba920dec Auto merge of #509 - serde-rs:cow, r=oli-obk
Fix codegen with lifetimes but no type parameters

Fixes #507.
2016-08-20 00:16:54 +09:00
David Tolnay a732b9bad3 Fix codegen with lifetimes but no type parameters 2016-08-19 11:12:38 -04:00
Oliver Schneider 6723da67b3 Merge pull request #506 from serde-rs/https
HTTPS for serde.rs
2016-08-19 10:57:52 +02:00
David Tolnay 2d99a50c27 HTTPS for serde.rs 2016-08-18 17:08:05 -04:00
David Tolnay 01f6115d73 Merge pull request #503 from serde-rs/stack
Set RUST_MIN_STACK if unset
2016-08-18 16:09:09 -04:00
David Tolnay a4eb9d5788 Merge pull request #499 from serde-rs/ord
Simplify BTreeMapVisitor trait bounds
2016-08-18 15:44:03 -04:00
David Tolnay 6f77ea58fd Merge branch origin/master into origin/stack 2016-08-18 15:26:14 -04:00
David Tolnay 2cb55e8cb9 Merge branch origin/master into origin/ord 2016-08-18 15:25:47 -04:00
David Tolnay 671f5ebd07 Path override to prevent compiletest from seeing 2 versions of serde 2016-08-18 15:05:07 -04:00
David Tolnay 2bc1d62e50 Disable clippy until Manishearth/rust-clippy#1174 is fixed 2016-08-18 14:51:25 -04:00
David Tolnay 1796536962 Update syntex to 0.41 2016-08-18 14:33:14 -04:00
David Tolnay dba1377d1f Set RUST_MIN_STACK if unset 2016-08-18 13:55:58 -04:00
Oliver Schneider ce66b230e3 Merge pull request #502 from serde-rs/help
Getting help
2016-08-18 17:08:30 +02:00
David Tolnay affc81b1d6 Getting help 2016-08-18 10:56:41 -04:00
Oliver Schneider c3ec05f410 Merge pull request #501 from serde-rs/readme
Condense readme and link to serde.rs
2016-08-18 13:22:53 +02:00
David Tolnay 332d59f362 Condense readme and link to serde.rs 2016-08-18 01:11:36 -04:00
David Tolnay d98172f330 Simplify BTreeMapVisitor trait bounds
`Ord` implies `Eq`.
2016-08-17 23:11:38 -04:00
David Tolnay e0c9bd4b87 Remove doc-upload 2016-08-13 19:15:48 -07:00
David Tolnay 33d26c6d38 Remove CNAME
This is now managed by github.com/serde-rs/docs.
2016-08-13 17:54:56 -07:00
David Tolnay 0557a7feac Point links to docs.serde.rs 2016-08-13 15:01:57 -07:00
Oliver Schneider d46db730ff Merge pull request #490 from bluss/patch-1
Adjust doc(html_root_url)
2016-08-12 15:59:18 +02:00
bluss 07b1acc9f5 Adjust doc(html_root_url)
The URL does not need to contain the crate name. With this URL rustdoc can generate correct external doc links.
2016-08-12 15:53:07 +02:00
David Tolnay 85864e6ccb Bump remaining versions to 0.8.1 2016-08-11 09:16:29 -07:00
David Tolnay 1f31bb2db9 Merge pull request #489 from oli-obk/docs
fix an example in the README
2016-08-11 08:41:59 -07:00
Oliver Schneider 6b5bd24edd fix an example in the README (thanks @nox) 2016-08-11 13:57:43 +02:00
Oliver Schneider 8c2359f9c3 also publish build.rs 2016-08-11 11:38:44 +02:00
Oliver Schneider f59ec44a0b Merge pull request #488 from oli-obk/codegen_stack_overflow_hack
use a thread in the build script of serde_codegen to allow env vars to control the stack size
2016-08-11 11:28:53 +02:00
Oliver Schneider b7446db511 reintroduce path dependencies 2016-08-11 11:02:19 +02:00
Oliver Schneider 8bd7acc9fc use a thread in the build script of serde_codegen to allow env vars to control the stack size 2016-08-09 13:08:16 +02:00
Homu d120539310 Auto merge of #478 - serde-rs:visitor, r=oli-obk
Simplify generated visitors

Neither `__FieldVisitor` nor `__Visitor` need the `__D: Deserializer` type parameter.
2016-08-08 19:52:36 +09:00
Oliver Schneider 82098f4e49 Merge pull request #476 from serde-rs/duration
Serialize and Deserialize for std::time::Duration
2016-08-04 09:29:14 +02:00
Oliver Schneider 1c55f58093 Merge pull request #479 from serde-rs/nestser
Remove unnecessary nesting from generated impls
2016-08-04 09:08:59 +02:00
Oliver Schneider df3c3cb555 Merge pull request #477 from serde-rs/iter
Fix clippy lint about looping over iter()
2016-08-04 08:48:35 +02:00
David Tolnay c539563687 Remove unnecessary nesting fron generated Deserialize implementations 2016-08-03 21:08:17 -07:00
David Tolnay 69de46f9e0 Remove unnecessary nesting from generated Serialize implementations 2016-08-03 20:40:57 -07:00
David Tolnay d5102a7afd Simplify generated visitors 2016-08-03 19:56:47 -07:00
David Tolnay c4b5a42615 Serialize and Deserialize for std::time::Duration 2016-08-03 19:33:31 -07:00
David Tolnay d0502b93ef Fix clippy lint about looping over iter() 2016-08-03 19:32:51 -07:00
David Tolnay b289edd4a4 Merge pull request #475 from serde-rs/skeptic
use skeptic to test the readme and fix readme for 0.8
2016-08-03 07:49:30 -07:00
Oliver Schneider 3a687e5369 fix untestable docs 2016-08-03 16:04:11 +02:00
Oliver Schneider 8c30ec9698 fix doc bugs found by skeptic 2016-08-03 16:00:30 +02:00
Oliver Schneider e40b9e9814 fix skeptic 2016-08-03 16:00:20 +02:00
Erick Tryzelaar 22d0bdae8a tests(readme): Use skeptic to test the readme 2016-08-03 15:44:47 +02:00
David Tolnay 84fa3fba58 Fix feature name in serde-syntex-example readme 2016-07-31 15:47:46 -07:00
Oliver Schneider 85001608e0 Merge pull request #473 from serde-rs/docs
Generate docs from 'docs' branch instead of master
2016-07-31 12:04:12 +02:00
David Tolnay 09fe2dbba5 Generate docs from 'docs' branch instead of master 2016-07-30 16:45:47 -07:00
Oliver Schneider b6ed82dd7d Merge pull request #472 from serde-rs/exact
Use exact dependencies on other serde crates
2016-07-30 21:12:20 +02:00
David Tolnay 5bbeedadf2 Constrain only the two important dependencies 2016-07-30 08:43:33 -07:00
David Tolnay d786de6696 Use exact dependencies on other serde crates 2016-07-29 15:12:54 -07:00
David Tolnay 5d24d6cfb4 Merge pull request #471 from serde-rs/example
Re-enable serde-syntex-example build in Travis
2016-07-29 10:06:20 -07:00
David Tolnay c8c22c036f Re-enable serde-syntex-example build in Travis 2016-07-29 09:53:44 -07:00
David Tolnay b7f30d7f82 Use build() instead of unwrap() for the Builders
Fixes #429.
2016-07-29 09:48:55 -07:00
David Tolnay 4bf5a15d7e Merge pull request #469 from killercup/patch-1
Set explicit versions in Readme
2016-07-28 05:23:56 -07:00
Pascal Hertleif f394f25956 Set explicit versions in Readme 2016-07-28 10:34:55 +02:00
David Tolnay 9d96f95ddd Remove old upgrading tips 2016-07-27 23:51:48 -07:00
28 changed files with 515 additions and 1047 deletions
-7
View File
@@ -1,7 +0,0 @@
paths = [
"serde",
"serde_codegen",
"serde_codegen_internals",
"serde_macros",
"serde_test",
]
+2 -4
View File
@@ -25,13 +25,11 @@ script:
- (cd testing && travis-cargo --skip nightly test)
- (cd testing && travis-cargo --only nightly test -- --features unstable-testing)
- (cd serde_macros && travis-cargo --only nightly test -- --features unstable-testing)
#- (cd examples/serde-syntex-example && travis-cargo --skip nightly run)
#- (cd examples/serde-syntex-example && travis-cargo --only nightly run -- --no-default-features --features unstable)
- (cd examples/serde-syntex-example && travis-cargo --skip nightly run)
- (cd examples/serde-syntex-example && travis-cargo --only nightly run -- --no-default-features --features unstable)
- (cd serde && travis-cargo --only stable doc)
after_success:
- (cd serde && travis-cargo --only stable doc-upload)
- (cd testing && travis-cargo --only stable coveralls --no-sudo)
env:
global:
- TRAVIS_CARGO_NIGHTLY_FEATURE=""
- secure: Jcd11Jy0xLyacBUB+oKOaxKBm9iZNInenRDtNBY8GKOtqF5fHUfEjgDf538hwRl5L0FP7DLr8oK0IHmzA7lPjJxlzoKVKV3IM7bRZEYzW5DMonf/lcliuGte7SH0NVFhifM87T8HI2hjGdAb+7+m34siBR7M3AY/XjLInrvUFvY=
+34 -797
View File
@@ -1,214 +1,21 @@
Serde Rust Serialization Framework
==================================
# Serde   [![Build Status](https://api.travis-ci.org/serde-rs/serde.svg?branch=master)](https://travis-ci.org/serde-rs/serde) [![Coverage Status](https://coveralls.io/repos/serde-rs/serde/badge.svg?branch=master&service=github)](https://coveralls.io/github/serde-rs/serde?branch=master) [![Latest Version](https://img.shields.io/crates/v/serde.svg)](https://crates.io/crates/serde) [![Clippy Linting Result](https://clippy.bashy.io/github/serde-rs/serde/master/badge.svg)](https://clippy.bashy.io/github/serde-rs/serde/master/log)
[![Build Status](https://api.travis-ci.org/serde-rs/serde.svg?branch=master)](https://travis-ci.org/serde-rs/serde)
[![Coverage Status](https://coveralls.io/repos/serde-rs/serde/badge.svg?branch=master&service=github)](https://coveralls.io/github/serde-rs/serde?branch=master)
[![Latest Version](https://img.shields.io/crates/v/serde.svg)](https://crates.io/crates/serde)
[![Clippy Linting Result](https://clippy.bashy.io/github/serde-rs/serde/master/badge.svg)](https://clippy.bashy.io/github/serde-rs/serde/master/log)
**Serde is a framework for *ser*ializing and *de*serializing Rust data structures efficiently and generically.**
Serde is a powerful framework that enables serialization libraries to
generically serialize Rust data structures without the overhead of runtime type
information. In many situations, the handshake protocol between serializers and
serializees can be completely optimized away, leaving Serde to perform roughly
the same speed as a hand written serializer for a specific type.
---
[Documentation](https://serde-rs.github.io/serde/serde/index.html)
You may be looking for:
Simple Serde Example
====================
- [An overview of Serde](https://serde.rs/)
- [Data formats supported by Serde](https://serde.rs/#data-formats)
- [Setting up `#[derive(Serialize, Deserialize)]`](https://serde.rs/codegen.html)
- [Examples](https://serde.rs/examples.html)
- [API documentation](https://docs.serde.rs/serde/)
Here is a simple example that uses
[serde_json](https://github.com/serde-rs/json), which uses Serde under the
covers, to generate and parse JSON. First, lets start off with the `Cargo.toml`
file:
```toml
[package]
name = "serde_example"
version = "0.1.0"
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
[dependencies]
serde_json = "*"
```
Next, the `src/main.rs` file itself:
```rust,ignore
extern crate serde_json;
use std::collections::HashMap;
use serde_json::Value;
use serde_json::builder::{ArrayBuilder, ObjectBuilder};
fn main() {
// Serde has support for many of the builtin Rust types, like arrays..:
let v = vec![1, 2];
let serialized = serde_json::to_string(&v).unwrap();
println!("serialized vec: {:?}", serialized);
let deserialized: Vec<u32> = serde_json::from_str(&serialized).unwrap();
println!("deserialized vec: {:?}", deserialized);
// ... and maps:
let mut map = HashMap::new();
map.insert("x".to_string(), 1);
map.insert("y".to_string(), 2);
let serialized = serde_json::to_string(&map).unwrap();
println!("serialized map: {:?}", serialized);
let deserialized: HashMap<String, u32> = serde_json::from_str(&serialized).unwrap();
println!("deserialized map: {:?}", deserialized);
// It also can handle complex objects:
let value = ObjectBuilder::new()
.insert("int", 1)
.insert("string", "a string")
.insert("array", ArrayBuilder::new()
.push(1)
.push(2)
.unwrap())
.unwrap();
let serialized = serde_json::to_string(&value).unwrap();
println!("serialized value: {:?}", serialized);
let deserialized: serde_json::Value = serde_json::from_str(&serialized).unwrap();
println!("deserialized value: {:?}", deserialized);
}
```
This produces the following output when run:
```sh
% cargo run
serialized vec: "[1,2]"
deserialized vec: [1, 2]
serialized map: "{\"y\":2,\"x\":1}"
deserialized map: {"y": 2, "x": 1}
serialized value: "{\"array\":[1,2],\"int\":1,\"string\":\"a string\"}"
deserialized value: {"array":[1,2],"int":1,"string":"a string"}
```
Using Serde with Stable Rust and serde\_codegen
===============================================
The example before used `serde_json::Value` as the in-memory representation of
the JSON value, but it's also possible for Serde to serialize to and from
regular Rust types. However, the code to do this can be a bit complicated to
write. So instead, Serde also has some powerful code generation libraries that
work with Stable and Nightly Rust that eliminate much of the complexity of hand
rolling serialization and deserialization for a given type.
First lets see how we would use Stable Rust, which is currently a tad more
complicated than Nightly Rust due to having to work around compiler plugins
being unstable. We will use `serde_codegen` which is based on the code
generation library [syntex](https://github.com/serde-rs/syntex). First we need
to setup the `Cargo.toml` that builds the project:
```toml
[package]
name = "serde_example"
version = "0.1.0"
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
build = "build.rs"
[build-dependencies]
serde_codegen = "*"
[dependencies]
serde = "*"
serde_json = "*"
```
Next, we define our source file, `src/main.rs.in`. Note this is a different
extension than usual because we need to do code generation:
```rust,ignore
#[derive(Serialize, Deserialize, Debug)]
struct Point {
x: 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).unwrap();
println!("{:?}", deserialized);
}
```
To finish up the main source code, we define a very simple `src/main.rs` that
uses the generated code.
`src/main.rs`:
```rust,ignore
extern crate serde;
extern crate serde_json;
include!(concat!(env!("OUT_DIR"), "/main.rs"));
```
The last step is to actually drive the code generation, with the `build.rs` script:
```rust,ignore
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");
serde_codegen::expand(&src, &dst).unwrap();
}
```
All this produces this when run:
```sh
% 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.
Using Serde with Nightly Rust and serde\_macros
===============================================
The prior example is a bit more complicated than it needs to be due to compiler
plugins being unstable. However, if you are already using Nightly Rust, you can
use `serde_macros`, which has a much simpler interface. First, here is the new
`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 = "*"
```
Note that it doesn't need a build script. Now the `src/main.rs`, which enables
the plugin feature, and registers the `serde_macros` plugin:
## Serde in action
```rust
#![feature(custom_derive, plugin)]
#![feature(plugin, custom_derive)]
#![plugin(serde_macros)]
extern crate serde_json;
@@ -222,611 +29,41 @@ struct Point {
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).unwrap();
println!("{:?}", deserialized);
}
```
This also produces the same output:
```sh
% cargo run
{"x":1,"y":2}
Point { x: 1, y: 2 }
```
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 }
[dependencies]
serde = "*"
serde_json = "*"
serde_macros = { version = "*", optional = true }
```
`build.rs`:
```rust,ignore
#[cfg(not(feature = "serde_macros"))]
mod inner {
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");
serde_codegen::expand(&src, &dst).unwrap();
}
}
#[cfg(feature = "serde_macros")]
mod inner {
pub fn main() {}
}
fn main() {
inner::main();
}
```
`src/main.rs`:
```rust,ignore
#![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.
Then to run with stable:
```sh
% cargo build
...
```
Or with nightly:
```sh
% cargo build --features nightly --no-default-features
...
```
Serialization without Macros
============================
Under the covers, Serde extensively uses the Visitor pattern to thread state
between the
[Serializer](http://serde-rs.github.io/serde/serde/serde/ser/trait.Serializer.html)
and
[Serialize](http://serde-rs.github.io/serde/serde/serde/ser/trait.Serialize.html)
without the two having specific information about each other's concrete type.
This has many of the same benefits as frameworks that use runtime type
information without the overhead. In fact, when compiling with optimizations,
Rust is able to remove most or all the visitor state, and generate code that's
nearly as fast as a hand written serializer format for a specific type.
To see it in action, lets look at how a simple type like `i32` is serialized.
The
[Serializer](http://serde-rs.github.io/serde/serde/serde/ser/trait.Serializer.html)
is threaded through the type:
```rust,ignore
impl serde::Serialize for i32 {
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
where S: serde::Serializer,
{
serializer.serialize_i32(*self)
}
}
```
As you can see it's pretty simple. More complex types like `BTreeMap` need to
pass a
[MapVisitor](http://serde-rs.github.io/serde/serde/serde/ser/trait.MapVisitor.html)
to the
[Serializer](http://serde-rs.github.io/serde/serde/serde/ser/trait.Serializer.html)
in order to walk through the type:
```rust,ignore
impl<K, V> Serialize for BTreeMap<K, V>
where K: Serialize + Ord,
V: Serialize,
{
#[inline]
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
where S: Serializer,
{
serializer.serialize_map(MapIteratorVisitor::new(self.iter(), Some(self.len())))
}
}
pub struct MapIteratorVisitor<Iter> {
iter: Iter,
len: Option<usize>,
}
impl<K, V, Iter> MapIteratorVisitor<Iter>
where Iter: Iterator<Item=(K, V)>
{
#[inline]
pub fn new(iter: Iter, len: Option<usize>) -> MapIteratorVisitor<Iter> {
MapIteratorVisitor {
iter: iter,
len: len,
}
}
}
impl<K, V, I> MapVisitor for MapIteratorVisitor<I>
where K: Serialize,
V: Serialize,
I: Iterator<Item=(K, V)>,
{
#[inline]
fn visit<S>(&mut self, serializer: &mut S) -> Result<Option<()>, S::Error>
where S: Serializer,
{
match self.iter.next() {
Some((key, value)) => {
let value = try!(serializer.serialize_map_elt(key, value));
Ok(Some(value))
}
None => Ok(None)
}
}
#[inline]
fn len(&self) -> Option<usize> {
self.len
}
}
```
Serializing structs follow this same pattern. In fact, structs are represented
as a named map. Its visitor uses a simple state machine to iterate through all
the fields:
```rust
extern crate serde;
extern crate serde_json;
struct Point {
x: i32,
y: i32,
}
impl serde::Serialize for Point {
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
where S: serde::Serializer
{
serializer.serialize_struct("Point", PointMapVisitor {
value: self,
state: 0,
})
}
}
struct PointMapVisitor<'a> {
value: &'a Point,
state: u8,
}
impl<'a> serde::ser::MapVisitor for PointMapVisitor<'a> {
fn visit<S>(&mut self, serializer: &mut S) -> Result<Option<()>, S::Error>
where S: serde::Serializer
{
match self.state {
0 => {
self.state += 1;
Ok(Some(try!(serializer.serialize_struct_elt("x", &self.value.x))))
}
1 => {
self.state += 1;
Ok(Some(try!(serializer.serialize_struct_elt("y", &self.value.y))))
}
_ => {
Ok(None)
}
}
}
}
fn main() {
let point = Point { x: 1, y: 2 };
// Convert the Point to a JSON string.
let serialized = serde_json::to_string(&point).unwrap();
println!("{}", serialized);
}
```
Deserialization without Macros
==============================
Deserialization is a little more complicated since there's a bit more error
handling that needs to occur. Let's start with the simple `i32`
[Deserialize](http://serde-rs.github.io/serde/serde/serde/de/trait.Deserialize.html)
implementation. It passes a
[Visitor](http://serde-rs.github.io/serde/serde/serde/de/trait.Visitor.html) to the
[Deserializer](http://serde-rs.github.io/serde/serde/serde/de/trait.Deserializer.html).
The [Visitor](http://serde-rs.github.io/serde/serde/serde/de/trait.Visitor.html)
can create the `i32` from a variety of different types:
```rust,ignore
impl Deserialize for i32 {
fn deserialize<D>(deserializer: &mut D) -> Result<i32, D::Error>
where D: serde::Deserializer,
{
deserializer.deserialize(I32Visitor)
}
}
struct I32Visitor;
impl serde::de::Visitor for I32Visitor {
type Value = i32;
fn visit_i16<E>(&mut self, value: i16) -> Result<i32, E>
where E: Error,
{
self.visit_i32(value as i32)
}
fn visit_i32<E>(&mut self, value: i32) -> Result<i32, E>
where E: Error,
{
Ok(value)
}
...
```
Since it's possible for this type to get passed an unexpected type, we need a
way to error out. This is done by way of the
[Error](http://serde-rs.github.io/serde/serde/serde/de/trait.Error.html) trait,
which allows a
[Deserialize](http://serde-rs.github.io/serde/serde/serde/de/trait.Deserialize.html)
to generate an error for a few common error conditions. Here's how it could be used:
```rust,ignore
...
fn visit_string<E>(&mut self, _: String) -> Result<i32, E>
where E: Error,
{
Err(serde::de::Error::custom("expect a string"))
}
...
```
Maps follow a similar pattern as before, and use a
[MapVisitor](http://serde-rs.github.io/serde/serde/serde/de/trait.MapVisitor.html)
to walk through the values generated by the
[Deserializer](http://serde-rs.github.io/serde/serde/serde/de/trait.Deserializer.html).
```rust,ignore
impl<K, V> serde::Deserialize for BTreeMap<K, V>
where K: serde::Deserialize + Eq + Ord,
V: serde::Deserialize,
{
fn deserialize<D>(deserializer: &mut D) -> Result<BTreeMap<K, V>, D::Error>
where D: serde::Deserializer,
{
deserializer.deserialize(BTreeMapVisitor::new())
}
}
pub struct BTreeMapVisitor<K, V> {
marker: PhantomData<BTreeMap<K, V>>,
}
impl<K, V> BTreeMapVisitor<K, V> {
pub fn new() -> Self {
BTreeMapVisitor {
marker: PhantomData,
}
}
}
impl<K, V> serde::de::Visitor for BTreeMapVisitor<K, V>
where K: serde::de::Deserialize + Ord,
V: serde::de::Deserialize
{
type Value = BTreeMap<K, V>;
fn visit_unit<E>(&mut self) -> Result<BTreeMap<K, V>, E>
where E: Error,
{
Ok(BTreeMap::new())
}
fn visit_map<V_>(&mut self, mut visitor: V_) -> Result<BTreeMap<K, V>, V_::Error>
where V_: MapVisitor,
{
let mut values = BTreeMap::new();
while let Some((key, value)) = try!(visitor.visit()) {
values.insert(key, value);
}
try!(visitor.end());
Ok(values)
}
}
```
Deserializing structs goes a step further in order to support not allocating a
`String` to hold the field names. This is done by custom field enum that
deserializes an enum variant from a string. So for our `Point` example from
before, we need to generate:
```rust
extern crate serde;
extern crate serde_json;
#[derive(Debug)]
struct Point {
x: i32,
y: i32,
}
enum PointField {
X,
Y,
}
impl serde::Deserialize for PointField {
fn deserialize<D>(deserializer: &mut D) -> Result<PointField, D::Error>
where D: serde::de::Deserializer
{
struct PointFieldVisitor;
impl serde::de::Visitor for PointFieldVisitor {
type Value = PointField;
fn visit_str<E>(&mut self, value: &str) -> Result<PointField, E>
where E: serde::de::Error
{
match value {
"x" => Ok(PointField::X),
"y" => Ok(PointField::Y),
_ => Err(serde::de::Error::custom("expected x or y")),
}
}
}
deserializer.deserialize(PointFieldVisitor)
}
}
impl serde::Deserialize for Point {
fn deserialize<D>(deserializer: &mut D) -> Result<Point, D::Error>
where D: serde::de::Deserializer
{
static FIELDS: &'static [&'static str] = &["x", "y"];
deserializer.deserialize_struct("Point", FIELDS, PointVisitor)
}
}
struct PointVisitor;
impl serde::de::Visitor for PointVisitor {
type Value = Point;
fn visit_map<V>(&mut self, mut visitor: V) -> Result<Point, V::Error>
where V: serde::de::MapVisitor
{
let mut x = None;
let mut y = None;
loop {
match try!(visitor.visit_key()) {
Some(PointField::X) => { x = Some(try!(visitor.visit_value())); }
Some(PointField::Y) => { y = Some(try!(visitor.visit_value())); }
None => { break; }
}
}
let x = match x {
Some(x) => x,
None => try!(visitor.missing_field("x")),
};
let y = match y {
Some(y) => y,
None => try!(visitor.missing_field("y")),
};
try!(visitor.end());
Ok(Point{ x: x, y: y })
}
}
fn main() {
let serialized = "{\"x\":1,\"y\":2}";
// Prints serialized = {"x":1,"y":2}
println!("serialized = {}", serialized);
// Convert the JSON string back to a Point.
let deserialized: Point = serde_json::from_str(&serialized).unwrap();
println!("{:?}", deserialized);
// Prints deserialized = Point { x: 1, y: 2 }
println!("deserialized = {:?}", deserialized);
}
```
Design Considerations and tradeoffs for Serializers and Deserializers
=====================================================================
## Getting help
Serde serialization and deserialization implementations are written in such a
way that they err on being able to represent more values, and also provide
better error messages when they are passed an incorrect type to deserialize
from. For example, by default, it is a syntax error to deserialize a `String`
into an `Option<String>`. This is implemented such that it is possible to
distinguish between the values `None` and `Some(())`, if the serialization
format supports option types.
Serde developers live in the #serde channel on
[`irc.mozilla.org`](https://wiki.mozilla.org/IRC). The #rust channel is also a
good resource with generally faster response time but less specific knowledge
about Serde. If IRC is not your thing, we are happy to respond to [GitHub
issues](https://github.com/serde-rs/serde/issues/new) as well.
However, many formats do not have option types, and represents optional values
as either a `null`, or some other value. Serde `Serializer`s and
`Deserializer`s can opt-in support for this. For serialization, this is pretty
easy. Simply implement these methods:
## License
```rust,ignore
...
Serde is licensed under either of
fn visit_none(&mut self) -> Result<(), Self::Error> {
self.visit_unit()
}
* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
http://www.apache.org/licenses/LICENSE-2.0)
* MIT license ([LICENSE-MIT](LICENSE-MIT) or
http://opensource.org/licenses/MIT)
fn visit_some<T>(&mut self, value: T) -> Result<(), Self::Error> {
value.serialize(self)
}
...
```
at your option.
For deserialization, this can be implemented by way of the
`Deserializer::visit_option` hook, which presumes that there is some ability to peek at what is the
next value in the serialized token stream. This following example is from
[serde_tests::TokenDeserializer](https://github.com/serde-rs/serde/blob/master/serde_tests/tests/token.rs#L435-L454),
where it checks to see if the next value is an `Option`, a `()`, or some other
value:
### Contribution
```rust,ignore
...
fn visit_option<V>(&mut self, mut visitor: V) -> Result<V::Value, Error>
where V: de::Visitor,
{
match self.tokens.peek() {
Some(&Token::Option(false)) => {
self.tokens.next();
visitor.visit_none()
}
Some(&Token::Option(true)) => {
self.tokens.next();
visitor.visit_some(self)
}
Some(&Token::Unit) => {
self.tokens.next();
visitor.visit_none()
}
Some(_) => visitor.visit_some(self),
None => Err(Error::EndOfStreamError),
}
}
...
```
Annotations
===========
`serde_codegen` and `serde_macros` support annotations that help to customize
how types are serialized. Here are the supported annotations:
Container Annotations:
| Annotation | Function |
| ---------- | -------- |
| `#[serde(rename="name")]` | Serialize and deserialize this container with the given name |
| `#[serde(rename(serialize="name1"))]` | Serialize this container with the given name |
| `#[serde(rename(deserialize="name1"))]` | Deserialize this container with the given name |
| `#[serde(deny_unknown_fields)]` | Always error during serialization when encountering unknown fields. When absent, unknown fields are ignored for self-describing formats like JSON. |
| `#[serde(bound="T: MyTrait")]` | Where-clause for the Serialize and Deserialize impls. This replaces any bounds inferred by Serde. |
| `#[serde(bound(serialize="T: MyTrait"))]` | Where-clause for the Serialize impl. |
| `#[serde(bound(deserialize="T: MyTrait"))]` | Where-clause for the Deserialize impl. |
Variant Annotations:
| Annotation | Function |
| ---------- | -------- |
| `#[serde(rename="name")]` | Serialize and deserialize this variant with the given name |
| `#[serde(rename(serialize="name1"))]` | Serialize this variant with the given name |
| `#[serde(rename(deserialize="name1"))]` | Deserialize this variant with the given name |
Field Annotations:
| Annotation | Function |
| ---------- | -------- |
| `#[serde(rename="name")]` | Serialize and deserialize this field with the given name |
| `#[serde(rename(serialize="name1"))]` | Serialize this field with the given name |
| `#[serde(rename(deserialize="name1"))]` | Deserialize this field with the given name |
| `#[serde(default)]` | If the value is not specified, use the `Default::default()` |
| `#[serde(default="$path")]` | Call the path to a function `fn() -> T` to build the value |
| `#[serde(skip_serializing)]` | Do not serialize this value |
| `#[serde(skip_deserializing)]` | Always use `Default::default()` or `#[serde(default="$path")]` instead of deserializing this value |
| `#[serde(skip_serializing_if="$path")]` | Do not serialize this value if this function `fn(&T) -> bool` returns `true` |
| `#[serde(serialize_with="$path")]` | Call a function `fn<S>(&T, &mut S) -> Result<(), S::Error> where S: Serializer` to serialize this value of type `T` |
| `#[serde(deserialize_with="$path")]` | Call a function `fn<D>(&mut D) -> Result<T, D::Error> where D: Deserializer` to deserialize this value of type `T` |
| `#[serde(bound="T: MyTrait")]` | Where-clause for the Serialize and Deserialize impls. This replaces any bounds inferred by Serde for the current field. |
| `#[serde(bound(serialize="T: MyTrait"))]` | Where-clause for the Serialize impl. |
| `#[serde(bound(deserialize="T: MyTrait"))]` | Where-clause for the Deserialize impl. |
Using in `no_std` crates
========================
The core `serde` package defines a number of features to enable usage in a
variety of freestanding environments. Enable any or none of the following
features, and use `default-features = false` in your `Cargo.toml`:
- `alloc` (implies `nightly`)
- `collections` (implies `alloc` and `nightly`)
- `std` (default)
If you only use `default-features = false`, you will receive a stock `no_std`
serde with no support for any of the collection types.
Upgrading from Serde 0.6
========================
* `#[serde(skip_serializing_if_none)]` was replaced with `#[serde(skip_serializing_if="Option::is_none")]`.
* `#[serde(skip_serializing_if_empty)]` was replaced with `#[serde(skip_serializing_if="Vec::is_empty")]`.
Serialization Formats Using Serde
=================================
| Format | Name |
| ------ | ---- |
| Bincode | [bincode](https://crates.io/crates/bincode) |
| env vars | [envy](https://crates.io/crates/envy) |
| Hjson | [serde\_hjson](https://crates.io/crates/serde-hjson) |
| JSON | [serde\_json](https://crates.io/crates/serde_json) |
| MessagePack | [rmp](https://crates.io/crates/rmp) |
| XML | [serde\_xml](https://github.com/serde-rs/xml) |
| YAML | [serde\_yaml](https://github.com/dtolnay/serde-yaml) |
Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in Serde by you, as defined in the Apache-2.0 license, shall be
dual licensed as above, without any additional terms or conditions.
+4 -4
View File
@@ -9,9 +9,9 @@ default = ["serde_codegen"]
unstable = ["serde_macros"]
[build-dependencies]
serde_codegen = { version = "^0.7", optional = true }
serde_codegen = { version = "^0.8", optional = true, path = "../../serde_codegen" }
[dependencies]
serde = "^0.7"
serde_json = "^0.7"
serde_macros = { version = "^0.7", optional = true }
serde = "^0.8"
serde_json = "^0.8"
serde_macros = { version = "^0.8", optional = true, path = "../../serde_macros" }
+1 -1
View File
@@ -16,5 +16,5 @@ Point { x: 1, y: 2 }
On nightly, it can use a plugin with:
```
% rustup run nightly cargo run --features nightly --no-default-features
% rustup run nightly cargo run --features unstable --no-default-features
```
+3 -2
View File
@@ -1,11 +1,12 @@
[package]
name = "serde"
version = "0.8.0"
version = "0.8.3"
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
license = "MIT/Apache-2.0"
description = "A generic serialization/deserialization framework"
homepage = "https://serde.rs"
repository = "https://github.com/serde-rs/serde"
documentation = "https://serde-rs.github.io/serde/serde/"
documentation = "https://docs.serde.rs/serde/"
readme = "../README.md"
keywords = ["serde", "serialization"]
include = ["Cargo.toml", "src/**/*.rs"]
+133 -1
View File
@@ -53,6 +53,9 @@ use alloc::arc::Arc;
#[cfg(all(feature = "unstable", feature = "alloc", not(feature = "std")))]
use alloc::boxed::Box;
#[cfg(feature = "std")]
use std::time::Duration;
#[cfg(feature = "unstable")]
use core::nonzero::{NonZero, Zeroable};
@@ -788,7 +791,7 @@ macro_rules! map_impl {
#[cfg(any(feature = "std", feature = "collections"))]
map_impl!(
BTreeMap<K, V>,
BTreeMapVisitor<K: Deserialize + Eq + Ord,
BTreeMapVisitor<K: Deserialize + Ord,
V: Deserialize>,
visitor,
BTreeMap::new(),
@@ -982,6 +985,135 @@ impl<'a, T: ?Sized> Deserialize for Cow<'a, T> where T: ToOwned, T::Owned: Deser
///////////////////////////////////////////////////////////////////////////////
// This is a cleaned-up version of the impl generated by:
//
// #[derive(Deserialize)]
// #[serde(deny_unknown_fields)]
// struct Duration {
// secs: u64,
// nanos: u32,
// }
#[cfg(feature = "std")]
impl Deserialize for Duration {
fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error>
where D: Deserializer,
{
enum Field { Secs, Nanos };
impl Deserialize for Field {
fn deserialize<D>(deserializer: &mut D) -> Result<Field, D::Error>
where D: Deserializer,
{
struct FieldVisitor;
impl Visitor for FieldVisitor {
type Value = Field;
fn visit_usize<E>(&mut self, value: usize) -> Result<Field, E>
where E: Error,
{
match value {
0usize => Ok(Field::Secs),
1usize => Ok(Field::Nanos),
_ => Err(Error::invalid_value("expected a field")),
}
}
fn visit_str<E>(&mut self, value: &str) -> Result<Field, E>
where E: Error,
{
match value {
"secs" => Ok(Field::Secs),
"nanos" => Ok(Field::Nanos),
_ => Err(Error::unknown_field(value)),
}
}
fn visit_bytes<E>(&mut self, value: &[u8]) -> Result<Field, E>
where E: Error,
{
match value {
b"secs" => Ok(Field::Secs),
b"nanos" => Ok(Field::Nanos),
_ => {
let value = String::from_utf8_lossy(value);
Err(Error::unknown_field(&value))
}
}
}
}
deserializer.deserialize_struct_field(FieldVisitor)
}
}
struct DurationVisitor;
impl Visitor for DurationVisitor {
type Value = Duration;
fn visit_seq<V>(&mut self, mut visitor: V) -> Result<Duration, V::Error>
where V: SeqVisitor,
{
let secs: u64 = match try!(visitor.visit()) {
Some(value) => value,
None => {
try!(visitor.end());
return Err(Error::invalid_length(0));
}
};
let nanos: u32 = match try!(visitor.visit()) {
Some(value) => value,
None => {
try!(visitor.end());
return Err(Error::invalid_length(1));
}
};
try!(visitor.end());
Ok(Duration::new(secs, nanos))
}
fn visit_map<V>(&mut self, mut visitor: V) -> Result<Duration, V::Error>
where V: MapVisitor,
{
let mut secs: Option<u64> = None;
let mut nanos: Option<u32> = None;
while let Some(key) = try!(visitor.visit_key::<Field>()) {
match key {
Field::Secs => {
if secs.is_some() {
return Err(<V::Error as Error>::duplicate_field("secs"));
}
secs = Some(try!(visitor.visit_value()));
}
Field::Nanos => {
if nanos.is_some() {
return Err(<V::Error as Error>::duplicate_field("nanos"));
}
nanos = Some(try!(visitor.visit_value()));
}
}
}
try!(visitor.end());
let secs = match secs {
Some(secs) => secs,
None => try!(visitor.missing_field("secs")),
};
let nanos = match nanos {
Some(nanos) => nanos,
None => try!(visitor.missing_field("nanos")),
};
Ok(Duration::new(secs, nanos))
}
}
const FIELDS: &'static [&'static str] = &["secs", "nanos"];
deserializer.deserialize_struct("Duration", FIELDS, DurationVisitor)
}
}
///////////////////////////////////////////////////////////////////////////////
#[cfg(feature = "unstable")]
impl<T> Deserialize for NonZero<T> where T: Deserialize + PartialEq + Zeroable + Zero {
fn deserialize<D>(deserializer: &mut D) -> Result<NonZero<T>, D::Error> where D: Deserializer {
+1 -1
View File
@@ -128,7 +128,7 @@ impl fmt::Display for Error {
write!(formatter, "Unknown variant: {}", variant)
}
Error::UnknownField(ref field) => write!(formatter, "Unknown field: {}", field),
Error::MissingField(ref field) => write!(formatter, "Missing field: {}", field),
Error::MissingField(field) => write!(formatter, "Missing field: {}", field),
}
}
}
+1 -1
View File
@@ -9,7 +9,7 @@
//! For a detailed tutorial on the different ways to use serde please check out the
//! [github repository](https://github.com/serde-rs/serde)
#![doc(html_root_url="https://serde-rs.github.io/serde/serde")]
#![doc(html_root_url="https://docs.serde.rs")]
#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(feature = "unstable", feature(reflect_marker, unicode, nonzero, plugin, step_trait, zero_one))]
#![cfg_attr(feature = "alloc", feature(alloc))]
+18 -2
View File
@@ -50,6 +50,8 @@ use std::path;
use std::rc::Rc;
#[cfg(all(feature = "alloc", not(feature = "std")))]
use alloc::rc::Rc;
#[cfg(feature = "std")]
use std::time::Duration;
#[cfg(feature = "std")]
use std::sync::Arc;
@@ -157,7 +159,7 @@ impl<T> Serialize for [T]
where S: Serializer,
{
let mut state = try!(serializer.serialize_seq(Some(self.len())));
for e in self.iter() {
for e in self {
try!(serializer.serialize_seq_elt(&mut state, e));
}
serializer.serialize_seq_end(state)
@@ -174,7 +176,7 @@ macro_rules! array_impls {
where S: Serializer,
{
let mut state = try!(serializer.serialize_seq_fixed_size($len));
for e in self.iter() {
for e in self {
try!(serializer.serialize_seq_elt(&mut state, e));
}
serializer.serialize_seq_end(state)
@@ -624,6 +626,20 @@ impl<T, E> Serialize for Result<T, E> where T: Serialize, E: Serialize {
///////////////////////////////////////////////////////////////////////////////
#[cfg(feature = "std")]
impl Serialize for Duration {
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
where S: Serializer,
{
let mut state = try!(serializer.serialize_struct("Duration", 2));
try!(serializer.serialize_struct_elt(&mut state, "secs", self.as_secs()));
try!(serializer.serialize_struct_elt(&mut state, "nanos", self.subsec_nanos()));
serializer.serialize_struct_end(state)
}
}
///////////////////////////////////////////////////////////////////////////////
#[cfg(all(feature = "std", feature = "unstable"))]
impl Serialize for net::IpAddr {
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
+11 -10
View File
@@ -1,11 +1,12 @@
[package]
name = "serde_codegen"
version = "0.8.0"
version = "0.8.3"
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
license = "MIT/Apache-2.0"
description = "Macros to auto-generate implementations for the serde framework"
homepage = "https://serde.rs"
repository = "https://github.com/serde-rs/serde"
documentation = "https://github.com/serde-rs/serde"
documentation = "https://serde.rs/codegen.html"
keywords = ["serde", "serialization"]
build = "build.rs"
include = ["Cargo.toml", "build.rs", "src/**/*.rs", "src/lib.rs.in"]
@@ -24,14 +25,14 @@ with-syntex = [
]
[build-dependencies]
quasi_codegen = { version = "^0.16.0", optional = true }
syntex = { version = "^0.39.0", optional = true }
quasi_codegen = { version = "^0.17.0", optional = true }
syntex = { version = "^0.41.0", optional = true }
[dependencies]
aster = { version = "^0.22.0", default-features = false }
aster = { version = "^0.24.0", default-features = false }
clippy = { version = "^0.*", optional = true }
quasi = { version = "^0.16.0", default-features = false }
quasi_macros = { version = "^0.16.0", optional = true }
serde_codegen_internals = { version = "0.5.0", default-features = false }
syntex = { version = "^0.39.0", optional = true }
syntex_syntax = { version = "^0.39.0", optional = true }
quasi = { version = "^0.17.0", default-features = false }
quasi_macros = { version = "^0.17.0", optional = true }
serde_codegen_internals = { version = "=0.6.1", default-features = false, path = "../serde_codegen_internals" }
syntex = { version = "^0.41.0", optional = true }
syntex_syntax = { version = "^0.41.0", optional = true }
+8 -5
View File
@@ -4,14 +4,17 @@ mod inner {
use std::env;
use std::path::Path;
use std::thread::spawn;
pub fn main() {
let out_dir = env::var_os("OUT_DIR").unwrap();
// put everything into a thread, so users can use `RUST_MIN_STACK` to increase the amount of stack
spawn(|| {
let out_dir = env::var_os("OUT_DIR").unwrap();
let src = Path::new("src/lib.rs.in");
let dst = Path::new(&out_dir).join("lib.rs");
quasi_codegen::expand(&src, &dst).unwrap();
let src = Path::new("src/lib.rs.in");
let dst = Path::new(&out_dir).join("lib.rs");
quasi_codegen::expand(&src, &dst).unwrap();
}).join().unwrap()
}
}
+75 -127
View File
@@ -76,10 +76,8 @@ fn deserialize_item(
#[automatically_derived]
impl $impl_generics _serde::de::Deserialize for $ty $where_clause {
fn deserialize<__D>(deserializer: &mut __D) -> ::std::result::Result<$ty, __D::Error>
where __D: _serde::de::Deserializer,
{
$body
}
where __D: _serde::de::Deserializer
$body
}
};
).unwrap()
@@ -136,7 +134,7 @@ fn deserialize_body(
item: &Item,
impl_generics: &ast::Generics,
ty: P<ast::Ty>,
) -> P<ast::Expr> {
) -> P<ast::Block> {
match item.body {
Body::Enum(ref variants) => {
deserialize_item_enum(
@@ -192,31 +190,24 @@ fn deserialize_body(
// Build `__Visitor<A, B, ...>(PhantomData<A>, PhantomData<B>, ...)`
fn deserialize_visitor(
builder: &aster::AstBuilder,
trait_generics: &ast::Generics,
forward_ty_params: Vec<ast::TyParam>,
forward_tys: Vec<P<ast::Ty>>
) -> (P<ast::Item>, P<ast::Ty>, P<ast::Expr>, ast::Generics) {
if trait_generics.ty_params.is_empty() && forward_tys.is_empty() {
generics: &ast::Generics,
) -> (P<ast::Item>, P<ast::Ty>, P<ast::Expr>) {
if generics.lifetimes.is_empty() && generics.ty_params.is_empty() {
(
builder.item().tuple_struct("__Visitor").build(),
builder.item().unit_struct("__Visitor"),
builder.ty().id("__Visitor"),
builder.expr().id("__Visitor"),
trait_generics.clone(),
)
} else {
let placeholders : Vec<_> = trait_generics.ty_params.iter()
let placeholders : Vec<_> = generics.ty_params.iter()
.map(|t| builder.ty().id(t.ident))
.collect();
let mut trait_generics = trait_generics.clone();
let mut ty_params = forward_ty_params.clone();
ty_params.extend(trait_generics.ty_params.into_vec());
trait_generics.ty_params = P::from_vec(ty_params);
(
builder.item().tuple_struct("__Visitor")
.generics().with(trait_generics.clone()).build()
.generics().with(generics.clone()).build()
.with_tys({
let lifetimes = trait_generics.lifetimes.iter()
let lifetimes = generics.lifetimes.iter()
.map(|lifetime_def| {
builder.ty()
.phantom_data()
@@ -225,7 +216,7 @@ fn deserialize_visitor(
.unit()
});
let ty_params = trait_generics.ty_params.iter()
let ty_params = generics.ty_params.iter()
.map(|ty_param| {
builder.ty()
.phantom_data()
@@ -236,48 +227,31 @@ fn deserialize_visitor(
})
.build(),
builder.ty().path()
.segment("__Visitor").with_generics(trait_generics.clone()).build()
.segment("__Visitor").with_generics(generics.clone()).build()
.build(),
builder.expr().call()
.path().segment("__Visitor")
.with_tys(forward_tys)
.with_tys(placeholders)
.build().build()
.with_args({
let len = trait_generics.lifetimes.len() + trait_generics.ty_params.len();
let len = generics.lifetimes.len() + generics.ty_params.len();
(0 .. len).map(|_| builder.expr().phantom_data())
})
.build(),
trait_generics,
)
}
}
fn deserializer_ty_param(builder: &aster::AstBuilder) -> ast::TyParam {
builder.ty_param("__D")
.trait_bound(builder.path()
.segment("_serde").build()
.segment("de").build()
.id("Deserializer")
.build())
.build()
.build()
}
fn deserializer_ty_arg(builder: &aster::AstBuilder) -> P<ast::Ty>{
builder.ty().id("__D")
}
fn deserialize_unit_struct(
cx: &ExtCtxt,
builder: &aster::AstBuilder,
type_ident: Ident,
item_attrs: &attr::Item,
) -> P<ast::Expr> {
) -> P<ast::Block> {
let type_name = name_expr(builder, item_attrs.name());
quote_expr!(cx, {
quote_block!(cx, {
struct __Visitor;
impl _serde::de::Visitor for __Visitor {
@@ -300,7 +274,7 @@ fn deserialize_unit_struct(
}
deserializer.deserialize_unit_struct($type_name, __Visitor)
})
}).unwrap()
}
fn deserialize_tuple(
@@ -312,14 +286,12 @@ fn deserialize_tuple(
ty: P<ast::Ty>,
fields: &[Field],
item_attrs: &attr::Item,
) -> P<ast::Expr> {
) -> P<ast::Block> {
let where_clause = &impl_generics.where_clause;
let (visitor_item, visitor_ty, visitor_expr, visitor_generics) = deserialize_visitor(
let (visitor_item, visitor_ty, visitor_expr) = deserialize_visitor(
builder,
impl_generics,
vec![deserializer_ty_param(builder)],
vec![deserializer_ty_arg(builder)],
);
let is_enum = variant_ident.is_some();
@@ -343,7 +315,7 @@ fn deserialize_tuple(
None
};
let visit_seq_expr = deserialize_seq(
let visit_seq = deserialize_seq(
cx,
builder,
type_ident,
@@ -366,24 +338,22 @@ fn deserialize_tuple(
deserializer.deserialize_tuple_struct($type_name, $nfields, $visitor_expr))
};
quote_expr!(cx, {
quote_block!(cx, {
$visitor_item
impl $visitor_generics _serde::de::Visitor for $visitor_ty $where_clause {
impl $impl_generics _serde::de::Visitor for $visitor_ty $where_clause {
type Value = $ty;
$visit_newtype_struct
#[inline]
fn visit_seq<__V>(&mut self, mut visitor: __V) -> ::std::result::Result<$ty, __V::Error>
where __V: _serde::de::SeqVisitor,
{
$visit_seq_expr
}
where __V: _serde::de::SeqVisitor
$visit_seq
}
$dispatch
})
}).unwrap()
}
fn deserialize_seq(
@@ -394,7 +364,7 @@ fn deserialize_seq(
impl_generics: &ast::Generics,
fields: &[Field],
is_struct: bool,
) -> P<ast::Expr> {
) -> P<ast::Block> {
let mut index_in_seq = 0usize;
let let_values: Vec<_> = fields.iter()
.enumerate()
@@ -461,13 +431,13 @@ fn deserialize_seq(
.build()
};
quote_expr!(cx, {
quote_block!(cx, {
$let_values
try!(visitor.end());
Ok($result)
})
}).unwrap()
}
fn deserialize_newtype_struct(
@@ -513,14 +483,12 @@ fn deserialize_struct(
ty: P<ast::Ty>,
fields: &[Field],
item_attrs: &attr::Item,
) -> P<ast::Expr> {
) -> P<ast::Block> {
let where_clause = &impl_generics.where_clause;
let (visitor_item, visitor_ty, visitor_expr, visitor_generics) = deserialize_visitor(
let (visitor_item, visitor_ty, visitor_expr) = deserialize_visitor(
builder,
&impl_generics,
vec![deserializer_ty_param(builder)],
vec![deserializer_ty_arg(builder)],
impl_generics,
);
let type_path = match variant_ident {
@@ -528,7 +496,7 @@ fn deserialize_struct(
None => builder.path().id(type_ident).build(),
};
let visit_seq_expr = deserialize_seq(
let visit_seq = deserialize_seq(
cx,
builder,
type_ident,
@@ -538,7 +506,7 @@ fn deserialize_struct(
true,
);
let (field_visitor, fields_stmt, visit_map_expr) = deserialize_struct_visitor(
let (field_visitor, fields_stmt, visit_map) = deserialize_struct_visitor(
cx,
builder,
type_ident,
@@ -558,33 +526,29 @@ fn deserialize_struct(
deserializer.deserialize_struct($type_name, FIELDS, $visitor_expr))
};
quote_expr!(cx, {
quote_block!(cx, {
$field_visitor
$visitor_item
impl $visitor_generics _serde::de::Visitor for $visitor_ty $where_clause {
impl $impl_generics _serde::de::Visitor for $visitor_ty $where_clause {
type Value = $ty;
#[inline]
fn visit_seq<__V>(&mut self, mut visitor: __V) -> ::std::result::Result<$ty, __V::Error>
where __V: _serde::de::SeqVisitor,
{
$visit_seq_expr
}
where __V: _serde::de::SeqVisitor
$visit_seq
#[inline]
fn visit_map<__V>(&mut self, mut visitor: __V) -> ::std::result::Result<$ty, __V::Error>
where __V: _serde::de::MapVisitor,
{
$visit_map_expr
}
where __V: _serde::de::MapVisitor
$visit_map
}
$fields_stmt
$dispatch
})
}).unwrap()
}
fn deserialize_item_enum(
@@ -595,7 +559,7 @@ fn deserialize_item_enum(
ty: P<ast::Ty>,
variants: &[Variant],
item_attrs: &attr::Item
) -> P<ast::Expr> {
) -> P<ast::Block> {
let where_clause = &impl_generics.where_clause;
let type_name = name_expr(builder, item_attrs.name());
@@ -633,7 +597,7 @@ fn deserialize_item_enum(
.id("__Field").id(format!("__field{}", i))
.build();
let expr = deserialize_variant(
let block = deserialize_variant(
cx,
builder,
type_ident,
@@ -643,24 +607,22 @@ fn deserialize_item_enum(
item_attrs,
);
let arm = quote_arm!(cx, $variant_name => { $expr });
let arm = quote_arm!(cx, $variant_name => $block);
variant_arms.push(arm);
}
variant_arms.extend(ignored_arm.into_iter());
let (visitor_item, visitor_ty, visitor_expr, visitor_generics) = deserialize_visitor(
let (visitor_item, visitor_ty, visitor_expr) = deserialize_visitor(
builder,
impl_generics,
vec![deserializer_ty_param(builder)],
vec![deserializer_ty_arg(builder)],
);
quote_expr!(cx, {
quote_block!(cx, {
$variant_visitor
$visitor_item
impl $visitor_generics _serde::de::EnumVisitor for $visitor_ty $where_clause {
impl $impl_generics _serde::de::EnumVisitor for $visitor_ty $where_clause {
type Value = $ty;
fn visit<__V>(&mut self, mut visitor: __V) -> ::std::result::Result<$ty, __V::Error>
@@ -675,7 +637,7 @@ fn deserialize_item_enum(
$variants_stmt
deserializer.deserialize_enum($type_name, VARIANTS, $visitor_expr)
})
}).unwrap()
}
fn deserialize_variant(
@@ -686,15 +648,15 @@ fn deserialize_variant(
ty: P<ast::Ty>,
variant: &Variant,
item_attrs: &attr::Item,
) -> P<ast::Expr> {
) -> P<ast::Block> {
let variant_ident = variant.ident;
match variant.style {
Style::Unit => {
quote_expr!(cx, {
quote_block!(cx, {
try!(visitor.visit_unit());
Ok($type_ident::$variant_ident)
})
}).unwrap()
}
Style::Newtype => {
deserialize_newtype_variant(
@@ -740,7 +702,7 @@ fn deserialize_newtype_variant(
variant_ident: Ident,
impl_generics: &ast::Generics,
field: &Field,
) -> P<ast::Expr> {
) -> P<ast::Block> {
let visit = match field.attrs.deserialize_with() {
None => {
let field_ty = &field.ty;
@@ -756,7 +718,9 @@ fn deserialize_newtype_variant(
})
}
};
quote_expr!(cx, Ok($type_ident::$variant_ident($visit)))
quote_block!(cx, {
Ok($type_ident::$variant_ident($visit))
}).unwrap()
}
fn deserialize_field_visitor(
@@ -805,17 +769,15 @@ fn deserialize_field_visitor(
let fallthrough_index_arm_expr = if !is_variant && !item_attrs.deny_unknown_fields() {
quote_expr!(cx, Ok(__Field::__ignore))
} else {
quote_expr!(cx, {
Err(_serde::de::Error::invalid_value($index_error_msg))
})
quote_expr!(cx, Err(_serde::de::Error::invalid_value($index_error_msg)))
};
let index_body = quote_expr!(cx,
let index_body = quote_block!(cx, {
match value {
$index_field_arms
_ => $fallthrough_index_arm_expr
}
);
}).unwrap();
// Convert the field names into byte strings.
let str_field_names: Vec<_> = field_names.iter()
@@ -835,12 +797,12 @@ fn deserialize_field_visitor(
quote_expr!(cx, Err(_serde::de::Error::$unknown_ident(value)))
};
let str_body = quote_expr!(cx,
let str_body = quote_block!(cx, {
match value {
$str_field_arms
_ => $fallthrough_str_arm_expr
}
);
}).unwrap();
// Convert the field names into byte strings.
let bytes_field_names: Vec<_> = field_names.iter()
@@ -866,12 +828,12 @@ fn deserialize_field_visitor(
})
};
let bytes_body = quote_expr!(cx,
let bytes_body = quote_block!(cx, {
match value {
$bytes_field_arms
_ => $fallthrough_bytes_arm_expr
}
);
}).unwrap();
let impl_item = quote_item!(cx,
impl _serde::de::Deserialize for __Field {
@@ -879,39 +841,25 @@ fn deserialize_field_visitor(
fn deserialize<__D>(deserializer: &mut __D) -> ::std::result::Result<__Field, __D::Error>
where __D: _serde::de::Deserializer,
{
struct __FieldVisitor<__D> {
phantom: ::std::marker::PhantomData<__D>
}
struct __FieldVisitor;
impl<__D> _serde::de::Visitor for __FieldVisitor<__D>
where __D: _serde::de::Deserializer
{
impl _serde::de::Visitor for __FieldVisitor {
type Value = __Field;
fn visit_usize<__E>(&mut self, value: usize) -> ::std::result::Result<__Field, __E>
where __E: _serde::de::Error,
{
$index_body
}
where __E: _serde::de::Error
$index_body
fn visit_str<__E>(&mut self, value: &str) -> ::std::result::Result<__Field, __E>
where __E: _serde::de::Error,
{
$str_body
}
where __E: _serde::de::Error
$str_body
fn visit_bytes<__E>(&mut self, value: &[u8]) -> ::std::result::Result<__Field, __E>
where __E: _serde::de::Error,
{
$bytes_body
}
where __E: _serde::de::Error
$bytes_body
}
deserializer.deserialize_struct_field(
__FieldVisitor::<__D>{
phantom: ::std::marker::PhantomData
}
)
deserializer.deserialize_struct_field(__FieldVisitor)
}
}
).unwrap();
@@ -927,7 +875,7 @@ fn deserialize_struct_visitor(
impl_generics: &ast::Generics,
fields: &[Field],
item_attrs: &attr::Item,
) -> (Vec<P<ast::Item>>, ast::Stmt, P<ast::Expr>) {
) -> (Vec<P<ast::Item>>, ast::Stmt, P<ast::Block>) {
let field_exprs = fields.iter()
.map(|field| field.attrs.name().deserialize_name())
.collect();
@@ -940,7 +888,7 @@ fn deserialize_struct_visitor(
false,
);
let visit_map_expr = deserialize_map(
let visit_map = deserialize_map(
cx,
builder,
type_ident,
@@ -968,7 +916,7 @@ fn deserialize_struct_visitor(
const FIELDS: &'static [&'static str] = $fields_expr;
).unwrap();
(field_visitor, fields_stmt, visit_map_expr)
(field_visitor, fields_stmt, visit_map)
}
fn deserialize_map(
@@ -979,7 +927,7 @@ fn deserialize_map(
impl_generics: &ast::Generics,
fields: &[Field],
item_attrs: &attr::Item,
) -> P<ast::Expr> {
) -> P<ast::Block> {
// Create the field names for the fields.
let fields_names = fields.iter()
.enumerate()
@@ -1086,7 +1034,7 @@ fn deserialize_map(
)
.build();
quote_expr!(cx, {
quote_block!(cx, {
$let_values
while let Some(key) = try!(visitor.visit_key::<__Field>()) {
@@ -1102,7 +1050,7 @@ fn deserialize_map(
$extract_values
Ok($result)
})
}).unwrap()
}
/// This function wraps the expression in `#[serde(deserialize_with="...")]` in
+36
View File
@@ -0,0 +1,36 @@
use std::env;
use std::ffi::OsStr;
use std::ops::Drop;
pub fn set_if_unset<K, V>(k: K, v: V) -> TmpEnv<K>
where K: AsRef<OsStr>,
V: AsRef<OsStr>,
{
match env::var(&k) {
Ok(_) => TmpEnv::WasAlreadySet,
Err(_) => {
env::set_var(&k, v);
TmpEnv::WasNotSet { k: k }
}
}
}
#[must_use]
pub enum TmpEnv<K>
where K: AsRef<OsStr>,
{
WasAlreadySet,
WasNotSet {
k: K,
}
}
impl<K> Drop for TmpEnv<K>
where K: AsRef<OsStr>,
{
fn drop(&mut self) {
if let TmpEnv::WasNotSet { ref k } = *self {
env::remove_var(k);
}
}
}
+38 -24
View File
@@ -35,48 +35,62 @@ include!(concat!(env!("OUT_DIR"), "/lib.rs"));
#[cfg(not(feature = "with-syntex"))]
include!("lib.rs.in");
#[cfg(feature = "with-syntex")]
mod env;
#[cfg(feature = "with-syntex")]
pub fn expand<S, D>(src: S, dst: D) -> Result<(), syntex::Error>
where S: AsRef<Path>,
D: AsRef<Path>,
{
use syntax::{ast, fold};
let src = src.as_ref().to_owned();
let dst = dst.as_ref().to_owned();
/// Strip the serde attributes from the crate.
#[cfg(feature = "with-syntex")]
fn strip_attributes(krate: ast::Crate) -> ast::Crate {
/// Helper folder that strips the serde attributes after the extensions have been expanded.
struct StripAttributeFolder;
let expand_thread = move || {
use syntax::{ast, fold};
impl fold::Folder for StripAttributeFolder {
fn fold_attribute(&mut self, attr: ast::Attribute) -> Option<ast::Attribute> {
match attr.node.value.node {
ast::MetaItemKind::List(ref n, _) if n == &"serde" => { return None; }
_ => {}
/// Strip the serde attributes from the crate.
#[cfg(feature = "with-syntex")]
fn strip_attributes(krate: ast::Crate) -> ast::Crate {
/// Helper folder that strips the serde attributes after the extensions have been expanded.
struct StripAttributeFolder;
impl fold::Folder for StripAttributeFolder {
fn fold_attribute(&mut self, attr: ast::Attribute) -> Option<ast::Attribute> {
match attr.node.value.node {
ast::MetaItemKind::List(ref n, _) if n == &"serde" => { return None; }
_ => {}
}
Some(attr)
}
Some(attr)
fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
fold::noop_fold_mac(mac, self)
}
}
fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
fold::noop_fold_mac(mac, self)
}
fold::Folder::fold_crate(&mut StripAttributeFolder, krate)
}
fold::Folder::fold_crate(&mut StripAttributeFolder, krate)
}
let mut reg = syntex::Registry::new();
let mut reg = syntex::Registry::new();
reg.add_attr("feature(custom_derive)");
reg.add_attr("feature(custom_attribute)");
reg.add_attr("feature(custom_derive)");
reg.add_attr("feature(custom_attribute)");
reg.add_decorator("derive_Serialize", ser::expand_derive_serialize);
reg.add_decorator("derive_Deserialize", de::expand_derive_deserialize);
reg.add_decorator("derive_Serialize", ser::expand_derive_serialize);
reg.add_decorator("derive_Deserialize", de::expand_derive_deserialize);
reg.add_post_expansion_pass(strip_attributes);
reg.add_post_expansion_pass(strip_attributes);
reg.expand("", src, dst)
};
reg.expand("", src.as_ref(), dst.as_ref())
// 16 MB stack unless otherwise specified
let _tmp_env = env::set_if_unset("RUST_MIN_STACK", "16777216");
use std::thread;
thread::spawn(expand_thread).join().unwrap()
}
#[cfg(not(feature = "with-syntex"))]
+36 -39
View File
@@ -70,10 +70,8 @@ fn serialize_item(
#[automatically_derived]
impl $impl_generics _serde::ser::Serialize for $ty $where_clause {
fn serialize<__S>(&self, _serializer: &mut __S) -> ::std::result::Result<(), __S::Error>
where __S: _serde::ser::Serializer,
{
$body
}
where __S: _serde::ser::Serializer
$body
}
};
).unwrap()
@@ -119,7 +117,7 @@ fn serialize_body(
item: &Item,
impl_generics: &ast::Generics,
ty: P<ast::Ty>,
) -> P<ast::Expr> {
) -> P<ast::Block> {
match item.body {
Body::Enum(ref variants) => {
serialize_item_enum(
@@ -179,12 +177,12 @@ fn serialize_unit_struct(
cx: &ExtCtxt,
builder: &aster::AstBuilder,
item_attrs: &attr::Item,
) -> P<ast::Expr> {
) -> P<ast::Block> {
let type_name = name_expr(builder, item_attrs.name());
quote_expr!(cx,
quote_block!(cx, {
_serializer.serialize_unit_struct($type_name)
)
}).unwrap()
}
fn serialize_newtype_struct(
@@ -194,7 +192,7 @@ fn serialize_newtype_struct(
item_ty: P<ast::Ty>,
field: &Field,
item_attrs: &attr::Item,
) -> P<ast::Expr> {
) -> P<ast::Block> {
let type_name = name_expr(builder, item_attrs.name());
let mut field_expr = quote_expr!(cx, &self.0);
@@ -203,9 +201,9 @@ fn serialize_newtype_struct(
&item_ty, impl_generics, &field.ty, path, field_expr);
}
quote_expr!(cx,
quote_block!(cx, {
_serializer.serialize_newtype_struct($type_name, $field_expr)
)
}).unwrap()
}
fn serialize_tuple_struct(
@@ -215,7 +213,7 @@ fn serialize_tuple_struct(
ty: P<ast::Ty>,
fields: &[Field],
item_attrs: &attr::Item,
) -> P<ast::Expr> {
) -> P<ast::Block> {
let serialize_stmts = serialize_tuple_struct_visitor(
cx,
builder,
@@ -229,11 +227,11 @@ fn serialize_tuple_struct(
let type_name = name_expr(builder, item_attrs.name());
let len = serialize_stmts.len();
quote_expr!(cx, {
quote_block!(cx, {
let mut state = try!(_serializer.serialize_tuple_struct($type_name, $len));
$serialize_stmts
_serializer.serialize_tuple_struct_end(state)
})
}).unwrap()
}
fn serialize_struct(
@@ -243,7 +241,7 @@ fn serialize_struct(
ty: P<ast::Ty>,
fields: &[Field],
item_attrs: &attr::Item,
) -> P<ast::Expr> {
) -> P<ast::Block> {
let serialize_fields = serialize_struct_visitor(
cx,
builder,
@@ -268,11 +266,11 @@ fn serialize_struct(
})
.fold(quote_expr!(cx, 0), |sum, expr| quote_expr!(cx, $sum + $expr));
quote_expr!(cx, {
quote_block!(cx, {
let mut state = try!(_serializer.serialize_struct($type_name, $len));
$serialize_fields
_serializer.serialize_struct_end(state)
})
}).unwrap()
}
fn serialize_item_enum(
@@ -283,7 +281,7 @@ fn serialize_item_enum(
ty: P<ast::Ty>,
variants: &[Variant],
item_attrs: &attr::Item,
) -> P<ast::Expr> {
) -> P<ast::Block> {
let arms: Vec<_> =
variants.iter()
.enumerate()
@@ -301,11 +299,11 @@ fn serialize_item_enum(
})
.collect();
quote_expr!(cx,
quote_block!(cx, {
match *self {
$arms
}
)
}).unwrap()
}
fn serialize_variant(
@@ -326,18 +324,17 @@ fn serialize_variant(
match variant.style {
Style::Unit => {
quote_arm!(cx,
$type_ident::$variant_ident => {
$type_ident::$variant_ident =>
_serde::ser::Serializer::serialize_unit_variant(
_serializer,
$type_name,
$variant_index,
$variant_name,
)
}
),
)
},
Style::Newtype => {
let expr = serialize_newtype_variant(
let block = serialize_newtype_variant(
cx,
builder,
type_name,
@@ -349,7 +346,7 @@ fn serialize_variant(
);
quote_arm!(cx,
$type_ident::$variant_ident(ref __simple_value) => { $expr }
$type_ident::$variant_ident(ref __simple_value) => $block
)
},
Style::Tuple => {
@@ -365,7 +362,7 @@ fn serialize_variant(
)
.build();
let expr = serialize_tuple_variant(
let block = serialize_tuple_variant(
cx,
builder,
type_name,
@@ -377,12 +374,12 @@ fn serialize_variant(
);
quote_arm!(cx,
$pat => { $expr }
$pat => $block
)
}
Style::Struct => {
let mut pat = builder.pat().struct_().id(type_ident).id(variant_ident).build();
for field in variant.fields.iter() {
for field in &variant.fields {
let name = match field.ident {
Some(name) => name,
None => cx.span_bug(field.span, "struct variant has unnamed fields"),
@@ -395,7 +392,7 @@ fn serialize_variant(
}
let pat = pat.build();
let expr = serialize_struct_variant(
let block = serialize_struct_variant(
cx,
builder,
variant_index,
@@ -407,7 +404,7 @@ fn serialize_variant(
);
quote_arm!(cx,
$pat => { $expr }
$pat => $block
)
}
}
@@ -422,14 +419,14 @@ fn serialize_newtype_variant(
item_ty: P<ast::Ty>,
generics: &ast::Generics,
field: &Field,
) -> P<ast::Expr> {
) -> P<ast::Block> {
let mut field_expr = quote_expr!(cx, __simple_value);
if let Some(path) = field.attrs.serialize_with() {
field_expr = wrap_serialize_with(cx, builder,
&item_ty, generics, &field.ty, path, field_expr);
}
quote_expr!(cx,
quote_block!(cx, {
_serde::ser::Serializer::serialize_newtype_variant(
_serializer,
$type_name,
@@ -437,7 +434,7 @@ fn serialize_newtype_variant(
$variant_name,
$field_expr,
)
)
}).unwrap()
}
fn serialize_tuple_variant(
@@ -449,7 +446,7 @@ fn serialize_tuple_variant(
generics: &ast::Generics,
structure_ty: P<ast::Ty>,
fields: &[Field],
) -> P<ast::Expr> {
) -> P<ast::Block> {
let serialize_stmts = serialize_tuple_struct_visitor(
cx,
builder,
@@ -462,11 +459,11 @@ fn serialize_tuple_variant(
let len = serialize_stmts.len();
quote_expr!(cx, {
quote_block!(cx, {
let mut state = try!(_serializer.serialize_tuple_variant($type_name, $variant_index, $variant_name, $len));
$serialize_stmts
_serializer.serialize_tuple_variant_end(state)
})
}).unwrap()
}
fn serialize_struct_variant(
@@ -478,7 +475,7 @@ fn serialize_struct_variant(
ty: P<ast::Ty>,
fields: &[Field],
item_attrs: &attr::Item,
) -> P<ast::Expr> {
) -> P<ast::Block> {
let serialize_fields = serialize_struct_visitor(
cx,
@@ -504,7 +501,7 @@ fn serialize_struct_variant(
})
.fold(quote_expr!(cx, 0), |sum, expr| quote_expr!(cx, $sum + $expr));
quote_expr!(cx, {
quote_block!(cx, {
let mut state = try!(_serializer.serialize_struct_variant(
$item_name,
$variant_index,
@@ -513,7 +510,7 @@ fn serialize_struct_variant(
));
$serialize_fields
_serializer.serialize_struct_variant_end(state)
})
}).unwrap()
}
fn serialize_tuple_struct_visitor(
+5 -4
View File
@@ -1,11 +1,12 @@
[package]
name = "serde_codegen_internals"
version = "0.5.0"
version = "0.6.1"
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
license = "MIT/Apache-2.0"
description = "AST representation used by Serde codegen. Unstable."
homepage = "https://serde.rs"
repository = "https://github.com/serde-rs/serde"
documentation = "https://github.com/serde-rs/serde"
documentation = "https://docs.serde.rs/serde_codegen_internals/"
keywords = ["serde", "serialization"]
include = ["Cargo.toml", "src/**/*.rs"]
@@ -16,5 +17,5 @@ with-syntex = ["syntex_syntax", "syntex_errors"]
[dependencies]
clippy = { version = "^0.*", optional = true }
syntex_syntax = { version = "^0.39.0", optional = true }
syntex_errors = { version = "^0.39.0", optional = true }
syntex_syntax = { version = "^0.41.0", optional = true }
syntex_errors = { version = "^0.41.0", optional = true }
+7 -5
View File
@@ -449,12 +449,14 @@ impl Field {
}
}
type SerAndDe<T> = (Option<Spanned<T>>, Option<Spanned<T>>);
fn get_ser_and_de<T, F>(
cx: &ExtCtxt,
attribute: &'static str,
items: &[P<ast::MetaItem>],
f: F
) -> Result<(Option<Spanned<T>>, Option<Spanned<T>>), ()>
) -> Result<SerAndDe<T>, ()>
where F: Fn(&ExtCtxt, &str, &ast::Lit) -> Result<T, ()>,
{
let mut ser_item = Attr::none(cx, attribute);
@@ -492,21 +494,21 @@ fn get_ser_and_de<T, F>(
fn get_renames(
cx: &ExtCtxt,
items: &[P<ast::MetaItem>],
) -> Result<(Option<Spanned<InternedString>>, Option<Spanned<InternedString>>), ()> {
) -> Result<SerAndDe<InternedString>, ()> {
get_ser_and_de(cx, "rename", items, get_str_from_lit)
}
fn get_where_predicates(
cx: &ExtCtxt,
items: &[P<ast::MetaItem>],
) -> Result<(Option<Spanned<Vec<ast::WherePredicate>>>, Option<Spanned<Vec<ast::WherePredicate>>>), ()> {
) -> Result<SerAndDe<Vec<ast::WherePredicate>>, ()> {
get_ser_and_de(cx, "bound", items, parse_lit_into_where)
}
pub fn get_serde_meta_items(attr: &ast::Attribute) -> Option<&[P<ast::MetaItem>]> {
match attr.node.value.node {
ast::MetaItemKind::List(ref name, ref items) if name == &"serde" => {
attr::mark_used(&attr);
attr::mark_used(attr);
Some(items)
}
_ => None
@@ -570,7 +572,7 @@ fn get_str_from_lit(cx: &ExtCtxt, name: &str, lit: &ast::Lit) -> Result<Interned
name,
lit_to_string(lit)));
return Err(());
Err(())
}
}
}
+2
View File
@@ -0,0 +1,2 @@
# To prevent compiletest from seeing two versions of serde
paths = ["../serde"]
+24 -8
View File
@@ -1,37 +1,53 @@
[package]
name = "serde_macros"
version = "0.8.0"
version = "0.8.3"
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
license = "MIT/Apache-2.0"
description = "Macros to auto-generate implementations for the serde framework"
homepage = "https://serde.rs"
repository = "https://github.com/serde-rs/serde"
documentation = "https://github.com/serde-rs/serde"
documentation = "https://serde.rs/codegen.html"
keywords = ["serde", "serialization"]
include = ["Cargo.toml", "src/**/*.rs"]
include = ["Cargo.toml", "src/**/*.rs", "build.rs"]
build = "build.rs"
[lib]
name = "serde_macros"
plugin = true
[features]
unstable-testing = ["clippy", "serde/unstable-testing", "serde_codegen/unstable-testing"]
unstable-testing = [
"clippy",
"skeptic",
"serde_json",
"serde/unstable-testing",
"serde_codegen/unstable-testing"
]
[build-dependencies]
skeptic = { version = "^0.6.0", optional = true }
[dependencies]
clippy = { version = "^0.*", optional = true }
serde_codegen = { version = "0.8.0", default-features = false, features = ["unstable"] }
serde_codegen = { version = "=0.8.3", default-features = false, features = ["unstable"], path = "../serde_codegen" }
skeptic = { version = "^0.6.0", optional = true }
serde_json = { version = "0.8.0", optional = true }
[dev-dependencies]
clippy = "^0.*"
compiletest_rs = "^0.2.0"
fnv = "1.0"
rustc-serialize = "^0.3.16"
serde = "0.8.0"
serde_test = "0.8.0"
serde = { version = "0.8.3", path = "../serde" }
serde_test = { version = "0.8.3", path = "../serde_test" }
[[test]]
name = "test"
path = "tests/test.rs"
[[test]]
name = "skeptic"
path = "tests/skeptic.rs"
[[bench]]
name = "bench"
path = "benches/bench.rs"
+18
View File
@@ -0,0 +1,18 @@
#[cfg(feature = "unstable-testing")]
mod inner {
extern crate skeptic;
pub fn main() {
println!("cargo:rerun-if-changed=../README.md");
skeptic::generate_doc_tests(&["../README.md"]);
}
}
#[cfg(not(feature = "unstable-testing"))]
mod inner {
pub fn main() {}
}
fn main() {
inner::main()
}
+3
View File
@@ -0,0 +1,3 @@
#![cfg(feature = "unstable-testing")]
include!(concat!(env!("OUT_DIR"), "/skeptic-tests.rs"));
+1
View File
@@ -6,3 +6,4 @@ extern crate test;
include!("../../testing/tests/test.rs.in");
mod compile_tests;
mod skeptic;
+4 -3
View File
@@ -1,14 +1,15 @@
[package]
name = "serde_test"
version = "0.8.0"
version = "0.8.3"
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
license = "MIT/Apache-2.0"
description = "Token De/Serializer for testing De/Serialize implementations"
homepage = "https://serde.rs"
repository = "https://github.com/serde-rs/serde"
documentation = "https://serde-rs.github.io/serde/serde/"
documentation = "https://docs.serde.rs/serde_test/"
readme = "../README.md"
keywords = ["serde", "serialization"]
include = ["Cargo.toml", "src/**/*.rs"]
[dependencies]
serde = "0.8.0"
serde = { version = "0.8.3", path = "../serde" }
+3 -2
View File
@@ -1,11 +1,12 @@
[package]
name = "serde_testing"
version = "0.8.0"
version = "0.8.3"
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
license = "MIT/Apache-2.0"
description = "A generic serialization/deserialization framework"
homepage = "https://serde.rs"
repository = "https://github.com/serde-rs/serde"
documentation = "http://serde-rs.github.io/serde/serde"
documentation = "https://docs.serde.rs/serde/"
readme = "README.md"
keywords = ["serialization"]
build = "build.rs"
+23
View File
@@ -1,6 +1,7 @@
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
use std::net;
use std::path::PathBuf;
use std::time::Duration;
use serde::Deserialize;
@@ -745,6 +746,28 @@ declare_tests! {
Token::SeqEnd,
],
}
test_duration {
Duration::new(1, 2) => &[
Token::StructStart("Duration", 2),
Token::StructSep,
Token::Str("secs"),
Token::U64(1),
Token::StructSep,
Token::Str("nanos"),
Token::U32(2),
Token::StructEnd,
],
Duration::new(1, 2) => &[
Token::SeqStart(Some(2)),
Token::SeqSep,
Token::I64(1),
Token::SeqSep,
Token::I64(2),
Token::SeqEnd,
],
}
test_net_ipv4addr {
"1.2.3.4".parse::<net::Ipv4Addr>().unwrap() => &[Token::Str("1.2.3.4")],
}
+10
View File
@@ -6,6 +6,7 @@ extern crate serde;
use self::serde::ser::{Serialize, Serializer};
use self::serde::de::{Deserialize, Deserializer};
use std::borrow::Cow;
use std::marker::PhantomData;
//////////////////////////////////////////////////////////////////////////
@@ -177,6 +178,15 @@ fn test_gen() {
e: E,
}
assert::<WithTraits2<X, X>>();
#[derive(Serialize, Deserialize)]
struct CowStr<'a>(Cow<'a, str>);
assert::<CowStr>();
#[derive(Serialize, Deserialize)]
#[serde(bound(deserialize = "T::Owned: Deserialize"))]
struct CowT<'a, T: ?Sized + 'a + ToOwned>(Cow<'a, T>);
assert::<CowT<str>>();
}
//////////////////////////////////////////////////////////////////////////
+14
View File
@@ -2,6 +2,7 @@ use std::collections::{BTreeMap, HashMap, HashSet};
use std::net;
use std::path::{Path, PathBuf};
use std::str;
use std::time::Duration;
extern crate serde_test;
use self::serde_test::{
@@ -324,6 +325,19 @@ declare_ser_tests! {
Token::SeqEnd,
],
}
test_duration {
Duration::new(1, 2) => &[
Token::StructStart("Duration", 2),
Token::StructSep,
Token::Str("secs"),
Token::U64(1),
Token::StructSep,
Token::Str("nanos"),
Token::U32(2),
Token::StructEnd,
],
}
test_net_ipv4addr {
"1.2.3.4".parse::<net::Ipv4Addr>().unwrap() => &[Token::Str("1.2.3.4")],
}