mirror of
https://github.com/pezkuwichain/serde.git
synced 2026-04-23 08:18:03 +00:00
Compare commits
34 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f3f098e7f5 | |||
| 09822c99cc | |||
| 966b104d48 | |||
| 59e0d5e081 | |||
| c687ee60ff | |||
| af6fbba9b8 | |||
| a577574cfe | |||
| 7521db7b0b | |||
| 72de877ec3 | |||
| f872b3fb4b | |||
| ddc33ee747 | |||
| 612e384b03 | |||
| 1c88856fc8 | |||
| 534e6d1f4c | |||
| 7ad31a01dd | |||
| 00cd2900e7 | |||
| 05a238fac4 | |||
| 310db21d64 | |||
| 72af0896e8 | |||
| c4392ff256 | |||
| c68ab508c0 | |||
| 76cca814f0 | |||
| 22b69fc5c9 | |||
| a1bd0c1667 | |||
| 48ea75fddc | |||
| 4b49f716b9 | |||
| 55f5f397d7 | |||
| 4be4f60f21 | |||
| 9a8037bbf2 | |||
| c7f1af90b2 | |||
| 902d3a0aa5 | |||
| c14eb28223 | |||
| 2722a04e52 | |||
| 5dbcd7957a |
@@ -17,8 +17,8 @@ Documentation is available at:
|
||||
* [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)
|
||||
|
||||
Using Serde
|
||||
===========
|
||||
Using Serde with Nightly Rust and serde\_macros
|
||||
===============================================
|
||||
|
||||
Here is a simple example that demonstrates how to use Serde by serializing and
|
||||
deserializing to JSON. Serde comes with some powerful code generation libraries
|
||||
@@ -76,6 +76,9 @@ When run, it produces:
|
||||
Point { x: 1, y: 2 }
|
||||
```
|
||||
|
||||
Using Serde with Stable Rust, syntex, and serde\_codegen
|
||||
========================================================
|
||||
|
||||
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:
|
||||
@@ -215,6 +218,20 @@ include!(concat!(env!("OUT_DIR"), "/main.rs"));
|
||||
|
||||
The `src/main.rs.in` is the same as before.
|
||||
|
||||
Then to run with stable:
|
||||
|
||||
```
|
||||
% cargo build
|
||||
...
|
||||
```
|
||||
|
||||
Or with nightly:
|
||||
|
||||
```rust
|
||||
% cargo build --features nightly --no-default-features
|
||||
...
|
||||
```
|
||||
|
||||
Serialization without Macros
|
||||
============================
|
||||
|
||||
@@ -311,6 +328,8 @@ as a named map. Its visitor uses a simple state machine to iterate through all
|
||||
the fields:
|
||||
|
||||
```rust
|
||||
extern crate serde;
|
||||
|
||||
struct Point {
|
||||
x: i32,
|
||||
y: i32,
|
||||
@@ -479,6 +498,13 @@ deserializes an enum variant from a string. So for our `Point` example from
|
||||
before, we need to generate:
|
||||
|
||||
```rust
|
||||
extern crate serde;
|
||||
|
||||
struct Point {
|
||||
x: i32,
|
||||
y: i32,
|
||||
}
|
||||
|
||||
enum PointField {
|
||||
X,
|
||||
Y,
|
||||
@@ -507,11 +533,7 @@ impl serde::Deserialize for PointField {
|
||||
deserializer.visit(PointFieldVisitor)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This is then used in our actual deserializer:
|
||||
|
||||
```rust
|
||||
impl serde::Deserialize for Point {
|
||||
fn deserialize<D>(deserializer: &mut D) -> Result<Point, D::Error>
|
||||
where D: serde::de::Deserializer
|
||||
@@ -557,6 +579,21 @@ impl serde::de::Visitor for PointVisitor {
|
||||
}
|
||||
```
|
||||
|
||||
Annotations
|
||||
===========
|
||||
|
||||
`serde_codegen` and `serde_macros` support annotations that help to customize
|
||||
how types are serialized. Here are the supported annotations:
|
||||
|
||||
| Annotation | Function |
|
||||
| ---------- | -------- |
|
||||
| `#[serde(rename(json="name1", xml="name2"))` | Serialize this field with the given name for the given formats |
|
||||
| `#[serde(default)` | If the value is not specified, use the `Default::default()` |
|
||||
| `#[serde(rename="name")` | Serialize this field with the given name |
|
||||
| `#[serde(skip_serializing)` | Do not serialize this value |
|
||||
| `#[serde(skip_serializing_if_empty)` | Do not serialize this value if `$value.is_empty()` is `true` |
|
||||
| `#[serde(skip_serializing_if_none)` | Do not serialize this value if `$value.is_none()` is `true` |
|
||||
|
||||
Serialization Formats Using Serde
|
||||
=================================
|
||||
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
target
|
||||
Cargo.lock
|
||||
@@ -0,0 +1,18 @@
|
||||
[package]
|
||||
name = "serde-syntex-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 = "^0.6.4", optional = true }
|
||||
syntex = "^0.22.0"
|
||||
|
||||
[dependencies]
|
||||
serde = "^0.6.1"
|
||||
serde_json = "^0.6.0"
|
||||
serde_macros = { version = "^0.6.1", optional = true }
|
||||
@@ -0,0 +1,20 @@
|
||||
This example demonstrates how to use Serde with Syntex. On stable or nightly
|
||||
with Syntex, it can be built with:
|
||||
|
||||
```
|
||||
% multirust run stable cargo run
|
||||
Running `target/debug/serde-syntex-example`
|
||||
{"x":1,"y":2}
|
||||
Point { x: 1, y: 2 }
|
||||
|
||||
% multirust run nightly cargo run
|
||||
Running `target/debug/serde-syntex-example`
|
||||
{"x":1,"y":2}
|
||||
Point { x: 1, y: 2 }
|
||||
```
|
||||
|
||||
On nightly, it can use a plugin with:
|
||||
|
||||
```
|
||||
% multirust run nightly cargo run --features nightly --no-default-features
|
||||
```
|
||||
@@ -0,0 +1,29 @@
|
||||
#[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();
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
#![cfg_attr(nightly, feature(custom_derive, plugin))]
|
||||
#![cfg_attr(nightly, 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"));
|
||||
@@ -0,0 +1,16 @@
|
||||
#[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);
|
||||
}
|
||||
+2
-3
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "serde"
|
||||
version = "0.5.3"
|
||||
version = "0.6.1"
|
||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
|
||||
license = "MIT/Apache-2.0"
|
||||
description = "A generic serialization/deserialization framework"
|
||||
@@ -10,8 +10,7 @@ readme = "../README.md"
|
||||
keywords = ["serde", "serialization"]
|
||||
|
||||
[dependencies]
|
||||
num = "*"
|
||||
num = "^0.1.27"
|
||||
|
||||
[features]
|
||||
nightly = []
|
||||
|
||||
|
||||
@@ -1,94 +0,0 @@
|
||||
use std::cmp;
|
||||
use std::io;
|
||||
use std::slice;
|
||||
|
||||
trait IntoBufRead {
|
||||
type IntoBuf: io::BufRead + BufReadExt;
|
||||
|
||||
fn into_buf_read(self) -> Self::IntoBuf;
|
||||
}
|
||||
|
||||
trait BufReadExt {
|
||||
fn get_buf(&self) -> &[u8];
|
||||
fn read_u8(&mut self) -> io::Result<Option<u8>>;
|
||||
}
|
||||
|
||||
struct SliceReader<'a> {
|
||||
buf: &'a [u8],
|
||||
}
|
||||
|
||||
impl<'a> io::Read for SliceReader<'a> {
|
||||
#[inline]
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
let amt = cmp::min(buf.len(), self.buf.len());
|
||||
let (a, b) = self.buf.split_at(amt);
|
||||
slice::bytes::copy_memory(buf, a);
|
||||
*self.buf = b;
|
||||
Ok(amt)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> io::BufRead for SliceReader<'a> {
|
||||
fn fill_buf(&mut self) -> io::Result<&[u8]> { Ok(*self) }
|
||||
fn consume(&mut self, amt: usize) { *self.buf = &self.buf[amt..]; }
|
||||
}
|
||||
|
||||
impl<'a> BufReadExt for SliceReader<'a> {
|
||||
fn get_buf(&self) -> &[u8] { self.buf }
|
||||
fn read_u8(&mut self) -> io::Result<Option<u8>> {
|
||||
let byte = self.buf.get(0);
|
||||
*self.buf = &self.buf[1..];
|
||||
byte
|
||||
}
|
||||
}
|
||||
|
||||
struct BufReader<R> {
|
||||
inner: R,
|
||||
buf: io::Cursor<Vec<u8>>,
|
||||
}
|
||||
|
||||
impl<R> BufReader<R> where R: io::Read {
|
||||
fn new(inner: R) -> Self {
|
||||
BufferedReader::with_capacity(io::DEFAULT_BUF_SIZE, inner)
|
||||
}
|
||||
|
||||
fn new(cap: usize, inner: R) -> Self {
|
||||
BufferedReader {
|
||||
inner: inner,
|
||||
buf: io::Cursor::new(Vec::with_capacity(cap)),
|
||||
}
|
||||
}
|
||||
|
||||
fn into_inner(self) -> R {
|
||||
self.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> Read for BufReader<R> where R: io::Read {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
// If we don't have any buffered data and we're doing a massive read
|
||||
// (larger than our internal buffer), bypass our internal buffer
|
||||
// entirely.
|
||||
if self.buf.get_ref().len() == self.buf.position() as usize &&
|
||||
buf.len() >= self.buf.get_ref().capacity() {
|
||||
return self.inner.read(buf);
|
||||
}
|
||||
try!(self.fill_buf());
|
||||
self.buf.read(buf)
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> BufReadExt for BufReader<R> {
|
||||
fn get_buf(&self) -> &[u8] {
|
||||
self.buf.get_ref()
|
||||
}
|
||||
|
||||
fn read_u8(&mut self) -> io::Result<Option<u8>> {
|
||||
if self.buf.get_ref().len() == self.buf.position() as usize {
|
||||
|
||||
}
|
||||
let byte = self.buf.get(0);
|
||||
*self.buf = &self.buf[1..];
|
||||
byte
|
||||
}
|
||||
}
|
||||
+4
-1
@@ -60,19 +60,21 @@ impl<'a> ser::Serialize for Bytes<'a> {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// `ByteBuf` wraps a `Vec<u8>` in order to hook into serialize and from deserialize a byte array.
|
||||
/// `ByteBuf` wraps a `Vec<u8>` and serializes as a byte array.
|
||||
#[derive(Clone, Eq, Hash, PartialEq, PartialOrd, Ord)]
|
||||
pub struct ByteBuf {
|
||||
bytes: Vec<u8>,
|
||||
}
|
||||
|
||||
impl ByteBuf {
|
||||
/// Construct a new, empty `ByteBuf`.
|
||||
pub fn new() -> Self {
|
||||
ByteBuf {
|
||||
bytes: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Construct a new, empty `ByteBuf` with the specified capacity.
|
||||
pub fn with_capacity(cap: usize) -> Self {
|
||||
ByteBuf {
|
||||
bytes: Vec::with_capacity(cap)
|
||||
@@ -142,6 +144,7 @@ impl ser::Serialize for ByteBuf {
|
||||
}
|
||||
}
|
||||
|
||||
/// This type implements the `serde::de::Visitor` trait for a `ByteBuf`.
|
||||
pub struct ByteBufVisitor;
|
||||
|
||||
impl de::Visitor for ByteBufVisitor {
|
||||
|
||||
+22
-8
@@ -1,3 +1,5 @@
|
||||
//! This module contains `Deserialize` and `Visitor` implementations.
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::collections::{
|
||||
BinaryHeap,
|
||||
@@ -39,6 +41,7 @@ use de::{
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// A visitor that produces a `()`.
|
||||
pub struct UnitVisitor;
|
||||
|
||||
impl Visitor for UnitVisitor {
|
||||
@@ -67,6 +70,7 @@ impl Deserialize for () {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// A visitor that produces a `bool`.
|
||||
pub struct BoolVisitor;
|
||||
|
||||
impl Visitor for BoolVisitor {
|
||||
@@ -113,11 +117,13 @@ macro_rules! impl_deserialize_num_method {
|
||||
}
|
||||
}
|
||||
|
||||
/// A visitor that produces a primitive type.
|
||||
pub struct PrimitiveVisitor<T> {
|
||||
marker: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T> PrimitiveVisitor<T> {
|
||||
/// Construct a new `PrimitiveVisitor`.
|
||||
#[inline]
|
||||
pub fn new() -> Self {
|
||||
PrimitiveVisitor {
|
||||
@@ -300,7 +306,7 @@ impl<T> Deserialize for Option<T> where T: Deserialize {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
macro_rules! set_impl {
|
||||
macro_rules! seq_impl {
|
||||
(
|
||||
$ty:ty,
|
||||
< $($constraints:ident),* >,
|
||||
@@ -310,11 +316,13 @@ macro_rules! set_impl {
|
||||
$with_capacity:expr,
|
||||
$insert:expr
|
||||
) => {
|
||||
/// A visitor that produces a sequence.
|
||||
pub struct $visitor_name<T> {
|
||||
marker: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T> $visitor_name<T> {
|
||||
/// Construct a new sequence visitor.
|
||||
pub fn new() -> Self {
|
||||
$visitor_name {
|
||||
marker: PhantomData,
|
||||
@@ -362,7 +370,7 @@ macro_rules! set_impl {
|
||||
}
|
||||
}
|
||||
|
||||
set_impl!(
|
||||
seq_impl!(
|
||||
BinaryHeap<T>,
|
||||
<Deserialize, Ord>,
|
||||
BinaryHeapVisitor,
|
||||
@@ -371,7 +379,7 @@ set_impl!(
|
||||
BinaryHeap::with_capacity(visitor.size_hint().0),
|
||||
BinaryHeap::push);
|
||||
|
||||
set_impl!(
|
||||
seq_impl!(
|
||||
BTreeSet<T>,
|
||||
<Deserialize, Eq, Ord>,
|
||||
BTreeSetVisitor,
|
||||
@@ -381,7 +389,7 @@ set_impl!(
|
||||
BTreeSet::insert);
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
set_impl!(
|
||||
seq_impl!(
|
||||
EnumSet<T>,
|
||||
<Deserialize, CLike>,
|
||||
EnumSetVisitor,
|
||||
@@ -390,7 +398,7 @@ set_impl!(
|
||||
EnumSet::new(),
|
||||
EnumSet::insert);
|
||||
|
||||
set_impl!(
|
||||
seq_impl!(
|
||||
LinkedList<T>,
|
||||
<Deserialize>,
|
||||
LinkedListVisitor,
|
||||
@@ -399,7 +407,7 @@ set_impl!(
|
||||
LinkedList::new(),
|
||||
LinkedList::push_back);
|
||||
|
||||
set_impl!(
|
||||
seq_impl!(
|
||||
HashSet<T>,
|
||||
<Deserialize, Eq, Hash>,
|
||||
HashSetVisitor,
|
||||
@@ -408,7 +416,7 @@ set_impl!(
|
||||
HashSet::with_capacity(visitor.size_hint().0),
|
||||
HashSet::insert);
|
||||
|
||||
set_impl!(
|
||||
seq_impl!(
|
||||
Vec<T>,
|
||||
<Deserialize>,
|
||||
VecVisitor,
|
||||
@@ -417,7 +425,7 @@ set_impl!(
|
||||
Vec::with_capacity(visitor.size_hint().0),
|
||||
Vec::push);
|
||||
|
||||
set_impl!(
|
||||
seq_impl!(
|
||||
VecDeque<T>,
|
||||
<Deserialize>,
|
||||
VecDequeVisitor,
|
||||
@@ -433,6 +441,7 @@ struct ArrayVisitor0<T> {
|
||||
}
|
||||
|
||||
impl<T> ArrayVisitor0<T> {
|
||||
/// Construct a `ArrayVisitor0<T>`.
|
||||
pub fn new() -> Self {
|
||||
ArrayVisitor0 {
|
||||
marker: PhantomData,
|
||||
@@ -477,6 +486,7 @@ macro_rules! array_impls {
|
||||
}
|
||||
|
||||
impl<T> $visitor<T> {
|
||||
/// Construct a `ArrayVisitor*<T>`.
|
||||
pub fn new() -> Self {
|
||||
$visitor {
|
||||
marker: PhantomData
|
||||
@@ -566,6 +576,7 @@ macro_rules! tuple_impls {
|
||||
() => {};
|
||||
($($len:expr => $visitor:ident => ($($name:ident),+),)+) => {
|
||||
$(
|
||||
/// Construct a tuple visitor.
|
||||
pub struct $visitor<$($name,)+> {
|
||||
marker: PhantomData<($($name,)+)>,
|
||||
}
|
||||
@@ -573,6 +584,7 @@ macro_rules! tuple_impls {
|
||||
impl<
|
||||
$($name: Deserialize,)+
|
||||
> $visitor<$($name,)+> {
|
||||
/// Construct a `TupleVisitor*<T>`.
|
||||
pub fn new() -> Self {
|
||||
$visitor { marker: PhantomData }
|
||||
}
|
||||
@@ -643,11 +655,13 @@ macro_rules! map_impl {
|
||||
$with_capacity:expr,
|
||||
$insert:expr
|
||||
) => {
|
||||
/// A visitor that produces a map.
|
||||
pub struct $visitor_name<K, V> {
|
||||
marker: PhantomData<$ty>,
|
||||
}
|
||||
|
||||
impl<K, V> $visitor_name<K, V> {
|
||||
/// Construct a `MapVisitor*<T>`.
|
||||
pub fn new() -> Self {
|
||||
$visitor_name {
|
||||
marker: PhantomData,
|
||||
|
||||
+112
-18
@@ -34,40 +34,100 @@ pub trait Error: Sized {
|
||||
/// `Type` represents all the primitive types that can be deserialized. This is used by
|
||||
/// `Error::kind_mismatch`.
|
||||
pub enum Type {
|
||||
/// Represents a `bool` type.
|
||||
Bool,
|
||||
|
||||
/// Represents a `usize` type.
|
||||
Usize,
|
||||
|
||||
/// Represents a `u8` type.
|
||||
U8,
|
||||
|
||||
/// Represents a `u16` type.
|
||||
U16,
|
||||
|
||||
/// Represents a `u32` type.
|
||||
U32,
|
||||
|
||||
/// Represents a `u64` type.
|
||||
U64,
|
||||
|
||||
/// Represents a `isize` type.
|
||||
Isize,
|
||||
|
||||
/// Represents a `i8` type.
|
||||
I8,
|
||||
|
||||
/// Represents a `i16` type.
|
||||
I16,
|
||||
|
||||
/// Represents a `i32` type.
|
||||
I32,
|
||||
|
||||
/// Represents a `i64` type.
|
||||
I64,
|
||||
|
||||
/// Represents a `f32` type.
|
||||
F32,
|
||||
|
||||
/// Represents a `f64` type.
|
||||
F64,
|
||||
|
||||
/// Represents a `char` type.
|
||||
Char,
|
||||
|
||||
/// Represents a `&str` type.
|
||||
Str,
|
||||
|
||||
/// Represents a `String` type.
|
||||
String,
|
||||
|
||||
/// Represents a `()` type.
|
||||
Unit,
|
||||
|
||||
/// Represents an `Option<T>` type.
|
||||
Option,
|
||||
|
||||
/// Represents a sequence type.
|
||||
Seq,
|
||||
|
||||
/// Represents a map type.
|
||||
Map,
|
||||
|
||||
/// Represents a unit struct type.
|
||||
UnitStruct,
|
||||
|
||||
/// Represents a newtype type.
|
||||
NewtypeStruct,
|
||||
|
||||
/// Represents a tuple struct type.
|
||||
TupleStruct,
|
||||
|
||||
/// Represents a struct type.
|
||||
Struct,
|
||||
|
||||
/// Represents a tuple type.
|
||||
Tuple,
|
||||
|
||||
/// Represents an `enum` type.
|
||||
Enum,
|
||||
|
||||
/// Represents a struct variant.
|
||||
StructVariant,
|
||||
|
||||
/// Represents a tuple variant.
|
||||
TupleVariant,
|
||||
|
||||
/// Represents a unit variant.
|
||||
UnitVariant,
|
||||
|
||||
/// Represents a `&[u8]` type.
|
||||
Bytes,
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// `Deserialize` represents a type that can be deserialized.
|
||||
pub trait Deserialize: Sized {
|
||||
/// Deserialize this value given this `Deserializer`.
|
||||
fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error>
|
||||
@@ -89,6 +149,7 @@ pub trait Deserialize: Sized {
|
||||
/// supporting the `visit_*` types is that it does not allow for deserializing into a generic
|
||||
/// `json::Value`-esque type.
|
||||
pub trait Deserializer {
|
||||
/// The error type that can be returned if some error occurs during deserialization.
|
||||
type Error: Error;
|
||||
|
||||
/// This method walks a visitor through a value as it is being deserialized.
|
||||
@@ -349,87 +410,103 @@ pub trait Deserializer {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// This trait represents a visitor that walks through a deserializer.
|
||||
pub trait Visitor {
|
||||
/// The value produced by this visitor.
|
||||
type Value: Deserialize;
|
||||
|
||||
/// `visit_bool` deserializes a `bool` into a `Value`.
|
||||
fn visit_bool<E>(&mut self, _v: bool) -> Result<Self::Value, E>
|
||||
where E: Error,
|
||||
{
|
||||
Err(Error::type_mismatch(Type::Bool))
|
||||
}
|
||||
|
||||
/// `visit_isize` deserializes a `isize` into a `Value`.
|
||||
fn visit_isize<E>(&mut self, v: isize) -> Result<Self::Value, E>
|
||||
where E: Error,
|
||||
{
|
||||
self.visit_i64(v as i64)
|
||||
}
|
||||
|
||||
/// `visit_i8` deserializes a `i8` into a `Value`.
|
||||
fn visit_i8<E>(&mut self, v: i8) -> Result<Self::Value, E>
|
||||
where E: Error,
|
||||
{
|
||||
self.visit_i64(v as i64)
|
||||
}
|
||||
|
||||
/// `visit_i16` deserializes a `i16` into a `Value`.
|
||||
fn visit_i16<E>(&mut self, v: i16) -> Result<Self::Value, E>
|
||||
where E: Error,
|
||||
{
|
||||
self.visit_i64(v as i64)
|
||||
}
|
||||
|
||||
/// `visit_i32` deserializes a `i32` into a `Value`.
|
||||
fn visit_i32<E>(&mut self, v: i32) -> Result<Self::Value, E>
|
||||
where E: Error,
|
||||
{
|
||||
self.visit_i64(v as i64)
|
||||
}
|
||||
|
||||
/// `visit_i64` deserializes a `i64` into a `Value`.
|
||||
fn visit_i64<E>(&mut self, _v: i64) -> Result<Self::Value, E>
|
||||
where E: Error,
|
||||
{
|
||||
Err(Error::type_mismatch(Type::I64))
|
||||
}
|
||||
|
||||
/// `visit_usize` deserializes a `usize` into a `Value`.
|
||||
fn visit_usize<E>(&mut self, v: usize) -> Result<Self::Value, E>
|
||||
where E: Error,
|
||||
{
|
||||
self.visit_u64(v as u64)
|
||||
}
|
||||
|
||||
/// `visit_u8` deserializes a `u8` into a `Value`.
|
||||
fn visit_u8<E>(&mut self, v: u8) -> Result<Self::Value, E>
|
||||
where E: Error,
|
||||
{
|
||||
self.visit_u64(v as u64)
|
||||
}
|
||||
|
||||
/// `visit_u16` deserializes a `u16` into a `Value`.
|
||||
fn visit_u16<E>(&mut self, v: u16) -> Result<Self::Value, E>
|
||||
where E: Error,
|
||||
{
|
||||
self.visit_u64(v as u64)
|
||||
}
|
||||
|
||||
/// `visit_u32` deserializes a `u32` into a `Value`.
|
||||
fn visit_u32<E>(&mut self, v: u32) -> Result<Self::Value, E>
|
||||
where E: Error,
|
||||
{
|
||||
self.visit_u64(v as u64)
|
||||
}
|
||||
|
||||
/// `visit_u64` deserializes a `u64` into a `Value`.
|
||||
fn visit_u64<E>(&mut self, _v: u64) -> Result<Self::Value, E>
|
||||
where E: Error,
|
||||
{
|
||||
Err(Error::type_mismatch(Type::U64))
|
||||
}
|
||||
|
||||
/// `visit_f32` deserializes a `f32` into a `Value`.
|
||||
fn visit_f32<E>(&mut self, v: f32) -> Result<Self::Value, E>
|
||||
where E: Error,
|
||||
{
|
||||
self.visit_f64(v as f64)
|
||||
}
|
||||
|
||||
/// `visit_f64` deserializes a `f64` into a `Value`.
|
||||
fn visit_f64<E>(&mut self, _v: f64) -> Result<Self::Value, E>
|
||||
where E: Error,
|
||||
{
|
||||
Err(Error::type_mismatch(Type::F64))
|
||||
}
|
||||
|
||||
/// `visit_char` deserializes a `char` into a `Value`.
|
||||
#[inline]
|
||||
fn visit_char<E>(&mut self, v: char) -> Result<Self::Value, E>
|
||||
where E: Error,
|
||||
@@ -439,12 +516,14 @@ pub trait Visitor {
|
||||
self.visit_string(v.to_string())
|
||||
}
|
||||
|
||||
/// `visit_str` deserializes a `&str` into a `Value`.
|
||||
fn visit_str<E>(&mut self, _v: &str) -> Result<Self::Value, E>
|
||||
where E: Error,
|
||||
{
|
||||
Err(Error::type_mismatch(Type::Str))
|
||||
}
|
||||
|
||||
/// `visit_string` deserializes a `String` into a `Value`.
|
||||
#[inline]
|
||||
fn visit_string<E>(&mut self, v: String) -> Result<Self::Value, E>
|
||||
where E: Error,
|
||||
@@ -452,12 +531,14 @@ pub trait Visitor {
|
||||
self.visit_str(&v)
|
||||
}
|
||||
|
||||
/// `visit_unit` deserializes a `()` into a `Value`.
|
||||
fn visit_unit<E>(&mut self) -> Result<Self::Value, E>
|
||||
where E: Error,
|
||||
{
|
||||
Err(Error::type_mismatch(Type::Unit))
|
||||
}
|
||||
|
||||
/// `visit_unit_struct` deserializes a unit struct into a `Value`.
|
||||
#[inline]
|
||||
fn visit_unit_struct<E>(&mut self, _name: &'static str) -> Result<Self::Value, E>
|
||||
where E: Error,
|
||||
@@ -465,42 +546,49 @@ pub trait Visitor {
|
||||
self.visit_unit()
|
||||
}
|
||||
|
||||
/// `visit_none` deserializes a none value into a `Value`.
|
||||
fn visit_none<E>(&mut self) -> Result<Self::Value, E>
|
||||
where E: Error,
|
||||
{
|
||||
Err(Error::type_mismatch(Type::Option))
|
||||
}
|
||||
|
||||
/// `visit_some` deserializes a value into a `Value`.
|
||||
fn visit_some<D>(&mut self, _deserializer: &mut D) -> Result<Self::Value, D::Error>
|
||||
where D: Deserializer,
|
||||
{
|
||||
Err(Error::type_mismatch(Type::Option))
|
||||
}
|
||||
|
||||
/// `visit_newtype_struct` deserializes a value into a `Value`.
|
||||
fn visit_newtype_struct<D>(&mut self, _deserializer: &mut D) -> Result<Self::Value, D::Error>
|
||||
where D: Deserializer,
|
||||
{
|
||||
Err(Error::type_mismatch(Type::NewtypeStruct))
|
||||
}
|
||||
|
||||
/// `visit_bool` deserializes a `SeqVisitor` into a `Value`.
|
||||
fn visit_seq<V>(&mut self, _visitor: V) -> Result<Self::Value, V::Error>
|
||||
where V: SeqVisitor,
|
||||
{
|
||||
Err(Error::type_mismatch(Type::Seq))
|
||||
}
|
||||
|
||||
/// `visit_map` deserializes a `MapVisitor` into a `Value`.
|
||||
fn visit_map<V>(&mut self, _visitor: V) -> Result<Self::Value, V::Error>
|
||||
where V: MapVisitor,
|
||||
{
|
||||
Err(Error::type_mismatch(Type::Map))
|
||||
}
|
||||
|
||||
/// `visit_bytes` deserializes a `&[u8]` into a `Value`.
|
||||
fn visit_bytes<E>(&mut self, _v: &[u8]) -> Result<Self::Value, E>
|
||||
where E: Error,
|
||||
{
|
||||
Err(Error::type_mismatch(Type::Bytes))
|
||||
}
|
||||
|
||||
/// `visit_byte_buf` deserializes a `Vec<u8>` into a `Value`.
|
||||
fn visit_byte_buf<E>(&mut self, v: Vec<u8>) -> Result<Self::Value, E>
|
||||
where E: Error,
|
||||
{
|
||||
@@ -510,14 +598,23 @@ pub trait Visitor {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// `SeqVisitor` visits each item in a sequence.
|
||||
///
|
||||
/// This is a trait that a `Deserializer` passes to a `Visitor` implementation, which deserializes
|
||||
/// each item in a sequence.
|
||||
pub trait SeqVisitor {
|
||||
/// The error type that can be returned if some error occurs during deserialization.
|
||||
type Error: Error;
|
||||
|
||||
/// This returns a `Ok(Some(value))` for the next value in the sequence, or `Ok(None)` if there
|
||||
/// are no more remaining items.
|
||||
fn visit<T>(&mut self) -> Result<Option<T>, Self::Error>
|
||||
where T: Deserialize;
|
||||
|
||||
/// This signals to the `SeqVisitor` that the `Visitor` does not expect any more items.
|
||||
fn end(&mut self) -> Result<(), Self::Error>;
|
||||
|
||||
/// Return the lower and upper bound of items remaining in the sequence.
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
(0, None)
|
||||
@@ -547,9 +644,15 @@ impl<'a, V> SeqVisitor for &'a mut V where V: SeqVisitor {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// `MapVisitor` visits each item in a sequence.
|
||||
///
|
||||
/// This is a trait that a `Deserializer` passes to a `Visitor` implementation.
|
||||
pub trait MapVisitor {
|
||||
/// The error type that can be returned if some error occurs during deserialization.
|
||||
type Error: Error;
|
||||
|
||||
/// This returns a `Ok(Some((key, value)))` for the next (key-value) pair in the map, or
|
||||
/// `Ok(None)` if there are no more remaining items.
|
||||
#[inline]
|
||||
fn visit<K, V>(&mut self) -> Result<Option<(K, V)>, Self::Error>
|
||||
where K: Deserialize,
|
||||
@@ -564,19 +667,25 @@ pub trait MapVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
/// This returns a `Ok(Some(key))` for the next key in the map, or `Ok(None)` if there are no
|
||||
/// more remaining items.
|
||||
fn visit_key<K>(&mut self) -> Result<Option<K>, Self::Error>
|
||||
where K: Deserialize;
|
||||
|
||||
/// This returns a `Ok(value)` for the next value in the map.
|
||||
fn visit_value<V>(&mut self) -> Result<V, Self::Error>
|
||||
where V: Deserialize;
|
||||
|
||||
/// This signals to the `MapVisitor` that the `Visitor` does not expect any more items.
|
||||
fn end(&mut self) -> Result<(), Self::Error>;
|
||||
|
||||
/// Return the lower and upper bound of items remaining in the sequence.
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
(0, None)
|
||||
}
|
||||
|
||||
/// Report that there
|
||||
fn missing_field<V>(&mut self, field: &'static str) -> Result<V, Self::Error>
|
||||
where V: Deserialize,
|
||||
{
|
||||
@@ -625,8 +734,10 @@ impl<'a, V_> MapVisitor for &'a mut V_ where V_: MapVisitor {
|
||||
/// `EnumVisitor` is a visitor that is created by the `Deserialize` and passed to the
|
||||
/// `Deserializer` in order to deserialize enums.
|
||||
pub trait EnumVisitor {
|
||||
/// The value produced by this visitor.
|
||||
type Value;
|
||||
|
||||
/// Visit the specific variant with the `VariantVisitor`.
|
||||
fn visit<V>(&mut self, visitor: V) -> Result<Self::Value, V::Error>
|
||||
where V: VariantVisitor;
|
||||
}
|
||||
@@ -636,6 +747,7 @@ pub trait EnumVisitor {
|
||||
/// `VariantVisitor` is a visitor that is created by the `Deserializer` and passed to the
|
||||
/// `Deserialize` in order to deserialize a specific enum variant.
|
||||
pub trait VariantVisitor {
|
||||
/// The error type that can be returned if some error occurs during deserialization.
|
||||
type Error: Error;
|
||||
|
||||
/// `visit_variant` is called to identify which variant to deserialize.
|
||||
@@ -711,21 +823,3 @@ impl<'a, T> VariantVisitor for &'a mut T where T: VariantVisitor {
|
||||
(**self).visit_struct(fields, visitor)
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
pub trait EnumSeqVisitor {
|
||||
type Value;
|
||||
|
||||
fn visit<V>(&mut self, visitor: V) -> Result<Self::Value, V::Error>
|
||||
where V: SeqVisitor;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
pub trait EnumMapVisitor {
|
||||
type Value;
|
||||
|
||||
fn visit<V>(&mut self, visitor: V) -> Result<Self::Value, V::Error>
|
||||
where V: MapVisitor;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
//! This module supports deserializing from primitives with the `ValueDeserializer` trait.
|
||||
|
||||
use std::collections::{
|
||||
BTreeMap,
|
||||
BTreeSet,
|
||||
@@ -16,11 +18,19 @@ use bytes;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// This represents all the possible errors that can occur using the `ValueDeserializer`.
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum Error {
|
||||
/// The value had some syntatic error.
|
||||
SyntaxError,
|
||||
|
||||
/// EOF while deserializing a value.
|
||||
EndOfStreamError,
|
||||
|
||||
/// Unknown field in struct.
|
||||
UnknownFieldError(String),
|
||||
|
||||
/// Struct is missing a field.
|
||||
MissingFieldError(&'static str),
|
||||
}
|
||||
|
||||
@@ -33,9 +43,12 @@ impl de::Error for Error {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// This trait converts primitive types into a deserializer.
|
||||
pub trait ValueDeserializer {
|
||||
/// The actual deserializer type.
|
||||
type Deserializer: de::Deserializer<Error=Error>;
|
||||
|
||||
/// Convert this value into a deserializer.
|
||||
fn into_deserializer(self) -> Self::Deserializer;
|
||||
}
|
||||
|
||||
@@ -72,6 +85,7 @@ impl de::Deserializer for UnitDeserializer {
|
||||
|
||||
macro_rules! primitive_deserializer {
|
||||
($ty:ty, $name:ident, $method:ident) => {
|
||||
/// A helper deserializer that deserializes a number.
|
||||
pub struct $name(Option<$ty>);
|
||||
|
||||
impl ValueDeserializer for $ty {
|
||||
@@ -212,12 +226,14 @@ impl<'a> de::VariantVisitor for StringDeserializer {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// A helper deserializer that deserializes a sequence.
|
||||
pub struct SeqDeserializer<I> {
|
||||
iter: I,
|
||||
len: usize,
|
||||
}
|
||||
|
||||
impl<I> SeqDeserializer<I> {
|
||||
/// Construct a new `SeqDeserializer<I>`.
|
||||
pub fn new(iter: I, len: usize) -> Self {
|
||||
SeqDeserializer {
|
||||
iter: iter,
|
||||
@@ -308,6 +324,7 @@ impl<T> ValueDeserializer for HashSet<T>
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// A helper deserializer that deserializes a map.
|
||||
pub struct MapDeserializer<I, K, V>
|
||||
where I: Iterator<Item=(K, V)>,
|
||||
K: ValueDeserializer,
|
||||
@@ -323,6 +340,7 @@ impl<I, K, V> MapDeserializer<I, K, V>
|
||||
K: ValueDeserializer,
|
||||
V: ValueDeserializer,
|
||||
{
|
||||
/// Construct a new `MapDeserializer<I, K, V>`.
|
||||
pub fn new(iter: I, len: usize) -> Self {
|
||||
MapDeserializer {
|
||||
iter: iter,
|
||||
@@ -429,6 +447,7 @@ impl<'a> ValueDeserializer for bytes::Bytes<'a>
|
||||
}
|
||||
}
|
||||
|
||||
/// A helper deserializer that deserializes a `&[u8]`.
|
||||
pub struct BytesDeserializer<'a> (Option<&'a [u8]>);
|
||||
|
||||
impl<'a> de::Deserializer for BytesDeserializer<'a> {
|
||||
@@ -456,6 +475,7 @@ impl ValueDeserializer for bytes::ByteBuf
|
||||
}
|
||||
}
|
||||
|
||||
/// A helper deserializer that deserializes a `Vec<u8>`.
|
||||
pub struct ByteBufDeserializer(Option<Vec<u8>>);
|
||||
|
||||
impl de::Deserializer for ByteBufDeserializer {
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
//! Module that contains helper iterators.
|
||||
|
||||
use std::io;
|
||||
use std::iter::Peekable;
|
||||
|
||||
/// Iterator over a byte stream that tracks the current position's line and column.
|
||||
pub struct LineColIterator<Iter: Iterator<Item=io::Result<u8>>> {
|
||||
iter: Iter,
|
||||
line: usize,
|
||||
@@ -8,6 +11,7 @@ pub struct LineColIterator<Iter: Iterator<Item=io::Result<u8>>> {
|
||||
}
|
||||
|
||||
impl<Iter: Iterator<Item=io::Result<u8>>> LineColIterator<Iter> {
|
||||
/// Construct a new `LineColIterator<Iter>`.
|
||||
pub fn new(iter: Iter) -> LineColIterator<Iter> {
|
||||
LineColIterator {
|
||||
iter: iter,
|
||||
|
||||
@@ -5,9 +5,15 @@
|
||||
//! 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.
|
||||
//!
|
||||
//! 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")]
|
||||
#![cfg_attr(feature = "nightly", feature(collections, core, enumset, nonzero, step_trait, zero_one))]
|
||||
|
||||
#![deny(missing_docs)]
|
||||
|
||||
extern crate num;
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
//! Implementations for all of Rust's builtin types.
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::collections::{
|
||||
BinaryHeap,
|
||||
@@ -117,6 +119,27 @@ impl<T> SeqVisitor for Option<T> where T: Serialize {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// A `serde::Visitor` for sequence iterators.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use serde::{Serialize, Serializer};
|
||||
/// use serde::ser::impls::SeqIteratorVisitor;
|
||||
///
|
||||
/// struct Seq(Vec<u32>);
|
||||
///
|
||||
/// impl Serialize for Seq {
|
||||
/// fn serialize<S>(&self, ser: &mut S) -> Result<(), S::Error>
|
||||
/// where S: Serializer,
|
||||
/// {
|
||||
/// ser.visit_seq(SeqIteratorVisitor::new(
|
||||
/// self.0.iter(),
|
||||
/// Some(self.0.len()),
|
||||
/// ))
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
pub struct SeqIteratorVisitor<Iter> {
|
||||
iter: Iter,
|
||||
len: Option<usize>,
|
||||
@@ -125,6 +148,7 @@ pub struct SeqIteratorVisitor<Iter> {
|
||||
impl<T, Iter> SeqIteratorVisitor<Iter>
|
||||
where Iter: Iterator<Item=T>
|
||||
{
|
||||
/// Construct a new `SeqIteratorVisitor<Iter>`.
|
||||
#[inline]
|
||||
pub fn new(iter: Iter, len: Option<usize>) -> SeqIteratorVisitor<Iter> {
|
||||
SeqIteratorVisitor {
|
||||
@@ -332,12 +356,14 @@ macro_rules! tuple_impls {
|
||||
}
|
||||
)+) => {
|
||||
$(
|
||||
/// A tuple visitor.
|
||||
pub struct $TupleVisitor<'a, $($T: 'a),+> {
|
||||
tuple: &'a ($($T,)+),
|
||||
state: u8,
|
||||
}
|
||||
|
||||
impl<'a, $($T: 'a),+> $TupleVisitor<'a, $($T),+> {
|
||||
/// Construct a new, empty `TupleVisitor`.
|
||||
pub fn new(tuple: &'a ($($T,)+)) -> $TupleVisitor<'a, $($T),+> {
|
||||
$TupleVisitor {
|
||||
tuple: tuple,
|
||||
@@ -489,6 +515,28 @@ tuple_impls! {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// A `serde::Visitor` for (key, value) map iterators.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::HashMap;
|
||||
/// use serde::{Serialize, Serializer};
|
||||
/// use serde::ser::impls::MapIteratorVisitor;
|
||||
///
|
||||
/// struct Map(HashMap<u32, u32>);
|
||||
///
|
||||
/// impl Serialize for Map {
|
||||
/// fn serialize<S>(&self, ser: &mut S) -> Result<(), S::Error>
|
||||
/// where S: Serializer,
|
||||
/// {
|
||||
/// ser.visit_map(MapIteratorVisitor::new(
|
||||
/// self.0.iter(),
|
||||
/// Some(self.0.len()),
|
||||
/// ))
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
pub struct MapIteratorVisitor<Iter> {
|
||||
iter: Iter,
|
||||
len: Option<usize>,
|
||||
@@ -497,6 +545,7 @@ pub struct MapIteratorVisitor<Iter> {
|
||||
impl<K, V, Iter> MapIteratorVisitor<Iter>
|
||||
where Iter: Iterator<Item=(K, V)>
|
||||
{
|
||||
/// Construct a new `MapIteratorVisitor<Iter>`.
|
||||
#[inline]
|
||||
pub fn new(iter: Iter, len: Option<usize>) -> MapIteratorVisitor<Iter> {
|
||||
MapIteratorVisitor {
|
||||
|
||||
@@ -4,14 +4,18 @@ pub mod impls;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// A trait that describes a type that can be serialized by a `Serializer`.
|
||||
pub trait Serialize {
|
||||
/// Serializes this value into this serializer.
|
||||
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
|
||||
where S: Serializer;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// A trait that describes a type that can serialize a stream of values into the underlying format.
|
||||
pub trait Serializer {
|
||||
/// The error type that can be returned if some error occurs during serialization.
|
||||
type Error;
|
||||
|
||||
/// `visit_bool` serializes a `bool` value.
|
||||
@@ -110,13 +114,20 @@ pub trait Serializer {
|
||||
self.visit_seq(impls::SeqIteratorVisitor::new(value.iter(), Some(value.len())))
|
||||
}
|
||||
|
||||
/// Serializes a `()` value.
|
||||
fn visit_unit(&mut self) -> Result<(), Self::Error>;
|
||||
|
||||
/// Serializes a unit struct value.
|
||||
///
|
||||
/// By default, unit structs are serialized as a `()`.
|
||||
#[inline]
|
||||
fn visit_unit_struct(&mut self, _name: &'static str) -> Result<(), Self::Error> {
|
||||
self.visit_unit()
|
||||
}
|
||||
|
||||
/// Serializes a unit variant, otherwise known as a variant with no arguments.
|
||||
///
|
||||
/// By default, unit variants are serialized as a `()`.
|
||||
#[inline]
|
||||
fn visit_unit_variant(&mut self,
|
||||
_name: &'static str,
|
||||
@@ -155,17 +166,27 @@ pub trait Serializer {
|
||||
Some(value))
|
||||
}
|
||||
|
||||
/// Serializes a `None` value.
|
||||
fn visit_none(&mut self) -> Result<(), Self::Error>;
|
||||
|
||||
/// Serializes a `Some(...)` value.
|
||||
fn visit_some<V>(&mut self, value: V) -> Result<(), Self::Error>
|
||||
where V: Serialize;
|
||||
|
||||
/// Serializes a sequence.
|
||||
///
|
||||
/// Callees of this method need to construct a `SeqVisitor`, which iterates through each item
|
||||
/// in the sequence.
|
||||
fn visit_seq<V>(&mut self, visitor: V) -> Result<(), Self::Error>
|
||||
where V: SeqVisitor;
|
||||
|
||||
/// Serializes a sequence element.
|
||||
fn visit_seq_elt<T>(&mut self, value: T) -> Result<(), Self::Error>
|
||||
where T: Serialize;
|
||||
|
||||
/// Serializes a tuple.
|
||||
///
|
||||
/// By default this serializes a tuple as a sequence.
|
||||
#[inline]
|
||||
fn visit_tuple<V>(&mut self, visitor: V) -> Result<(), Self::Error>
|
||||
where V: SeqVisitor,
|
||||
@@ -173,6 +194,9 @@ pub trait Serializer {
|
||||
self.visit_seq(visitor)
|
||||
}
|
||||
|
||||
/// Serializes a tuple element.
|
||||
///
|
||||
/// By default, tuples are serialized as a sequence.
|
||||
#[inline]
|
||||
fn visit_tuple_elt<T>(&mut self, value: T) -> Result<(), Self::Error>
|
||||
where T: Serialize
|
||||
@@ -180,6 +204,9 @@ pub trait Serializer {
|
||||
self.visit_seq_elt(value)
|
||||
}
|
||||
|
||||
/// Serializes a tuple struct.
|
||||
///
|
||||
/// By default, tuple structs are serialized as a tuple.
|
||||
#[inline]
|
||||
fn visit_tuple_struct<V>(&mut self,
|
||||
_name: &'static str,
|
||||
@@ -189,6 +216,9 @@ pub trait Serializer {
|
||||
self.visit_tuple(visitor)
|
||||
}
|
||||
|
||||
/// Serializes a tuple struct element.
|
||||
///
|
||||
/// By default, tuple struct elements are serialized as a tuple element.
|
||||
#[inline]
|
||||
fn visit_tuple_struct_elt<T>(&mut self, value: T) -> Result<(), Self::Error>
|
||||
where T: Serialize
|
||||
@@ -196,6 +226,9 @@ pub trait Serializer {
|
||||
self.visit_tuple_elt(value)
|
||||
}
|
||||
|
||||
/// Serializes a tuple variant.
|
||||
///
|
||||
/// By default, tuple variants are serialized as a tuple struct.
|
||||
#[inline]
|
||||
fn visit_tuple_variant<V>(&mut self,
|
||||
_name: &'static str,
|
||||
@@ -207,6 +240,9 @@ pub trait Serializer {
|
||||
self.visit_tuple_struct(variant, visitor)
|
||||
}
|
||||
|
||||
/// Serializes a tuple element.
|
||||
///
|
||||
/// By default, tuples are serialized as a sequence.
|
||||
#[inline]
|
||||
fn visit_tuple_variant_elt<T>(&mut self, value: T) -> Result<(), Self::Error>
|
||||
where T: Serialize
|
||||
@@ -214,13 +250,21 @@ pub trait Serializer {
|
||||
self.visit_tuple_struct_elt(value)
|
||||
}
|
||||
|
||||
/// Serializes a map.
|
||||
///
|
||||
/// Callees of this method need to construct a `MapVisitor`, which iterates through each item
|
||||
/// in the map.
|
||||
fn visit_map<V>(&mut self, visitor: V) -> Result<(), Self::Error>
|
||||
where V: MapVisitor;
|
||||
|
||||
/// Serializes a map element (key-value pair).
|
||||
fn visit_map_elt<K, V>(&mut self, key: K, value: V) -> Result<(), Self::Error>
|
||||
where K: Serialize,
|
||||
V: Serialize;
|
||||
|
||||
/// Serializes a struct.
|
||||
///
|
||||
/// By default, structs are serialized as a map with the field name as the key.
|
||||
#[inline]
|
||||
fn visit_struct<V>(&mut self,
|
||||
_name: &'static str,
|
||||
@@ -230,6 +274,9 @@ pub trait Serializer {
|
||||
self.visit_map(visitor)
|
||||
}
|
||||
|
||||
/// Serializes an element of a struct.
|
||||
///
|
||||
/// By default, struct elements are serialized as a map element with the field name as the key.
|
||||
#[inline]
|
||||
fn visit_struct_elt<V>(&mut self,
|
||||
key: &'static str,
|
||||
@@ -239,6 +286,9 @@ pub trait Serializer {
|
||||
self.visit_map_elt(key, value)
|
||||
}
|
||||
|
||||
/// Serializes a struct variant.
|
||||
///
|
||||
/// By default, struct variants are serialized as a struct.
|
||||
#[inline]
|
||||
fn visit_struct_variant<V>(&mut self,
|
||||
_name: &'static str,
|
||||
@@ -250,6 +300,9 @@ pub trait Serializer {
|
||||
self.visit_struct(variant, visitor)
|
||||
}
|
||||
|
||||
/// Serializes an element of a struct variant.
|
||||
///
|
||||
/// By default, struct variant elements are serialized as a struct element.
|
||||
#[inline]
|
||||
fn visit_struct_variant_elt<V>(&mut self,
|
||||
key: &'static str,
|
||||
@@ -268,7 +321,12 @@ pub trait Serializer {
|
||||
}
|
||||
}
|
||||
|
||||
/// A trait that is used by a `Serialize` to iterate through a sequence.
|
||||
pub trait SeqVisitor {
|
||||
/// Serializes a sequence item in the serializer.
|
||||
///
|
||||
/// This returns `Ok(Some(()))` when there are more items to serialize, or `Ok(None)` when
|
||||
/// complete.
|
||||
fn visit<S>(&mut self, serializer: &mut S) -> Result<Option<()>, S::Error>
|
||||
where S: Serializer;
|
||||
|
||||
@@ -279,7 +337,12 @@ pub trait SeqVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
/// A trait that is used by a `Serialize` to iterate through a map.
|
||||
pub trait MapVisitor {
|
||||
/// Serializes a map item in the serializer.
|
||||
///
|
||||
/// This returns `Ok(Some(()))` when there are more items to serialize, or `Ok(None)` when
|
||||
/// complete.
|
||||
fn visit<S>(&mut self, serializer: &mut S) -> Result<Option<()>, S::Error>
|
||||
where S: Serializer;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "serde_codegen"
|
||||
version = "0.5.3"
|
||||
version = "0.6.5"
|
||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
|
||||
license = "MIT/Apache-2.0"
|
||||
description = "Macros to auto-generate implementations for the serde framework"
|
||||
@@ -15,12 +15,12 @@ nightly = ["quasi_macros"]
|
||||
with-syntex = ["quasi/with-syntex", "quasi_codegen", "quasi_codegen/with-syntex", "syntex", "syntex_syntax"]
|
||||
|
||||
[build-dependencies]
|
||||
quasi_codegen = { verision = "*", optional = true }
|
||||
syntex = { version = "*", optional = true }
|
||||
quasi_codegen = { verision = "^0.3.8", optional = true }
|
||||
syntex = { version = "^0.22.0", optional = true }
|
||||
|
||||
[dependencies]
|
||||
aster = { version = "*", default-features = false }
|
||||
quasi = { verision = "*", default-features = false }
|
||||
quasi_macros = { version = "*", optional = true }
|
||||
syntex = { version = "*", optional = true }
|
||||
syntex_syntax = { version = "*", optional = true }
|
||||
aster = { version = "^0.8.0", default-features = false }
|
||||
quasi = { verision = "^0.3.8", default-features = false }
|
||||
quasi_macros = { version = "^0.3.8", optional = true }
|
||||
syntex = { version = "^0.22.0", optional = true }
|
||||
syntex_syntax = { version = "^0.22.0", optional = true }
|
||||
|
||||
+168
-43
@@ -2,10 +2,14 @@ use std::collections::HashMap;
|
||||
use std::collections::HashSet;
|
||||
|
||||
use syntax::ast;
|
||||
use syntax::attr;
|
||||
use syntax::ext::base::ExtCtxt;
|
||||
use syntax::ptr::P;
|
||||
|
||||
use aster;
|
||||
|
||||
/// Represents field name information
|
||||
#[derive(Debug)]
|
||||
pub enum FieldNames {
|
||||
Global(P<ast::Expr>),
|
||||
Format{
|
||||
@@ -15,43 +19,16 @@ pub enum FieldNames {
|
||||
}
|
||||
|
||||
/// Represents field attribute information
|
||||
#[derive(Debug)]
|
||||
pub struct FieldAttrs {
|
||||
skip_serializing_field: bool,
|
||||
skip_serializing_field_if_empty: bool,
|
||||
skip_serializing_field_if_none: bool,
|
||||
names: FieldNames,
|
||||
use_default: bool,
|
||||
}
|
||||
|
||||
impl FieldAttrs {
|
||||
/// Create a FieldAttr with a single default field name
|
||||
pub fn new(
|
||||
skip_serializing_field: bool,
|
||||
default_value: bool,
|
||||
name: P<ast::Expr>,
|
||||
) -> FieldAttrs {
|
||||
FieldAttrs {
|
||||
skip_serializing_field: skip_serializing_field,
|
||||
names: FieldNames::Global(name),
|
||||
use_default: default_value,
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a FieldAttr with format specific field names
|
||||
pub fn new_with_formats(
|
||||
skip_serializing_field: bool,
|
||||
default_value: bool,
|
||||
default_name: P<ast::Expr>,
|
||||
formats: HashMap<P<ast::Expr>, P<ast::Expr>>,
|
||||
) -> FieldAttrs {
|
||||
FieldAttrs {
|
||||
skip_serializing_field: skip_serializing_field,
|
||||
names: FieldNames::Format {
|
||||
formats: formats,
|
||||
default: default_name,
|
||||
},
|
||||
use_default: default_value,
|
||||
}
|
||||
}
|
||||
|
||||
/// Return a set of formats that the field has attributes for.
|
||||
pub fn formats(&self) -> HashSet<P<ast::Expr>> {
|
||||
match self.names {
|
||||
@@ -70,22 +47,21 @@ impl FieldAttrs {
|
||||
///
|
||||
/// The resulting expression assumes that `S` refers to a type
|
||||
/// that implements `Serializer`.
|
||||
pub fn serializer_key_expr(self, cx: &ExtCtxt) -> P<ast::Expr> {
|
||||
pub fn serializer_key_expr(&self, cx: &ExtCtxt) -> P<ast::Expr> {
|
||||
match self.names {
|
||||
FieldNames::Global(x) => x,
|
||||
FieldNames::Format{formats, default} => {
|
||||
FieldNames::Global(ref name) => name.clone(),
|
||||
FieldNames::Format { ref formats, ref default } => {
|
||||
let arms = formats.iter()
|
||||
.map(|(fmt, lit)| {
|
||||
quote_arm!(cx, $fmt => { $lit })
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
quote_expr!(cx,
|
||||
{
|
||||
match S::format() {
|
||||
$arms
|
||||
_ => { $default }
|
||||
}
|
||||
})
|
||||
match S::format() {
|
||||
$arms
|
||||
_ => { $default }
|
||||
}
|
||||
)
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -94,17 +70,17 @@ impl FieldAttrs {
|
||||
pub fn default_key_expr(&self) -> &P<ast::Expr> {
|
||||
match self.names {
|
||||
FieldNames::Global(ref expr) => expr,
|
||||
FieldNames::Format{formats: _, ref default} => default
|
||||
FieldNames::Format{formats: _, ref default} => default,
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the field name for the field in the specified format.
|
||||
pub fn key_expr(&self, format: &P<ast::Expr>) -> &P<ast::Expr> {
|
||||
match self.names {
|
||||
FieldNames::Global(ref expr) =>
|
||||
expr,
|
||||
FieldNames::Format{ref formats, ref default} =>
|
||||
FieldNames::Global(ref expr) => expr,
|
||||
FieldNames::Format { ref formats, ref default } => {
|
||||
formats.get(format).unwrap_or(default)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,4 +93,153 @@ impl FieldAttrs {
|
||||
pub fn skip_serializing_field(&self) -> bool {
|
||||
self.skip_serializing_field
|
||||
}
|
||||
|
||||
pub fn skip_serializing_field_if_empty(&self) -> bool {
|
||||
self.skip_serializing_field_if_empty
|
||||
}
|
||||
|
||||
pub fn skip_serializing_field_if_none(&self) -> bool {
|
||||
self.skip_serializing_field_if_none
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FieldAttrsBuilder<'a> {
|
||||
builder: &'a aster::AstBuilder,
|
||||
skip_serializing_field: bool,
|
||||
skip_serializing_field_if_empty: bool,
|
||||
skip_serializing_field_if_none: bool,
|
||||
name: Option<P<ast::Expr>>,
|
||||
format_rename: HashMap<P<ast::Expr>, P<ast::Expr>>,
|
||||
use_default: bool,
|
||||
}
|
||||
|
||||
impl<'a> FieldAttrsBuilder<'a> {
|
||||
pub fn new(builder: &'a aster::AstBuilder) -> FieldAttrsBuilder<'a> {
|
||||
FieldAttrsBuilder {
|
||||
builder: builder,
|
||||
skip_serializing_field: false,
|
||||
skip_serializing_field_if_empty: false,
|
||||
skip_serializing_field_if_none: false,
|
||||
name: None,
|
||||
format_rename: HashMap::new(),
|
||||
use_default: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn field(mut self, field: &ast::StructField) -> FieldAttrsBuilder<'a> {
|
||||
match field.node.kind {
|
||||
ast::NamedField(name, _) => {
|
||||
self.name = Some(self.builder.expr().str(name));
|
||||
}
|
||||
ast::UnnamedField(_) => { }
|
||||
};
|
||||
|
||||
self.attrs(&field.node.attrs)
|
||||
}
|
||||
|
||||
pub fn attrs(self, attrs: &[ast::Attribute]) -> FieldAttrsBuilder<'a> {
|
||||
attrs.iter().fold(self, FieldAttrsBuilder::attr)
|
||||
}
|
||||
|
||||
pub fn attr(self, attr: &ast::Attribute) -> FieldAttrsBuilder<'a> {
|
||||
match attr.node.value.node {
|
||||
ast::MetaList(ref name, ref items) if name == &"serde" => {
|
||||
attr::mark_used(&attr);
|
||||
items.iter().fold(self, FieldAttrsBuilder::meta_item)
|
||||
}
|
||||
_ => {
|
||||
self
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn meta_item(mut self, meta_item: &P<ast::MetaItem>) -> FieldAttrsBuilder<'a> {
|
||||
match meta_item.node {
|
||||
ast::MetaNameValue(ref name, ref lit) if name == &"rename" => {
|
||||
let expr = self.builder.expr().build_lit(P(lit.clone()));
|
||||
|
||||
self.name(expr)
|
||||
}
|
||||
ast::MetaList(ref name, ref items) if name == &"rename" => {
|
||||
for item in items {
|
||||
match item.node {
|
||||
ast::MetaNameValue(ref name, ref lit) => {
|
||||
let name = self.builder.expr().str(name);
|
||||
let expr = self.builder.expr().build_lit(P(lit.clone()));
|
||||
|
||||
self = self.format_rename(name, expr);
|
||||
}
|
||||
_ => { }
|
||||
}
|
||||
}
|
||||
self
|
||||
}
|
||||
ast::MetaWord(ref name) if name == &"default" => {
|
||||
self.default()
|
||||
}
|
||||
ast::MetaWord(ref name) if name == &"skip_serializing" => {
|
||||
self.skip_serializing_field()
|
||||
}
|
||||
ast::MetaWord(ref name) if name == &"skip_serializing_if_empty" => {
|
||||
self.skip_serializing_field_if_empty()
|
||||
}
|
||||
ast::MetaWord(ref name) if name == &"skip_serializing_if_none" => {
|
||||
self.skip_serializing_field_if_none()
|
||||
}
|
||||
_ => {
|
||||
// Ignore unknown meta variables for now.
|
||||
self
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn skip_serializing_field(mut self) -> FieldAttrsBuilder<'a> {
|
||||
self.skip_serializing_field = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn skip_serializing_field_if_empty(mut self) -> FieldAttrsBuilder<'a> {
|
||||
self.skip_serializing_field_if_empty = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn skip_serializing_field_if_none(mut self) -> FieldAttrsBuilder<'a> {
|
||||
self.skip_serializing_field_if_none = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn name(mut self, name: P<ast::Expr>) -> FieldAttrsBuilder<'a> {
|
||||
self.name = Some(name);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn format_rename(mut self, format: P<ast::Expr>, name: P<ast::Expr>) -> FieldAttrsBuilder<'a> {
|
||||
self.format_rename.insert(format, name);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn default(mut self) -> FieldAttrsBuilder<'a> {
|
||||
self.use_default = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(self) -> FieldAttrs {
|
||||
let name = self.name.expect("here");
|
||||
let names = if self.format_rename.is_empty() {
|
||||
FieldNames::Global(name)
|
||||
} else {
|
||||
FieldNames::Format {
|
||||
formats: self.format_rename,
|
||||
default: name,
|
||||
}
|
||||
};
|
||||
|
||||
FieldAttrs {
|
||||
skip_serializing_field: self.skip_serializing_field,
|
||||
skip_serializing_field_if_empty: self.skip_serializing_field_if_empty,
|
||||
skip_serializing_field_if_none: self.skip_serializing_field_if_none,
|
||||
names: names,
|
||||
use_default: self.use_default,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+60
-65
@@ -4,12 +4,11 @@ use aster;
|
||||
|
||||
use syntax::ast::{
|
||||
self,
|
||||
Ident,
|
||||
MetaItem,
|
||||
Item,
|
||||
Expr,
|
||||
StructDef,
|
||||
EnumDef,
|
||||
Expr,
|
||||
Ident,
|
||||
Item,
|
||||
MetaItem,
|
||||
};
|
||||
use syntax::codemap::Span;
|
||||
use syntax::ext::base::{Annotatable, ExtCtxt};
|
||||
@@ -66,7 +65,6 @@ pub fn expand_derive_deserialize(
|
||||
let where_clause = &impl_generics.where_clause;
|
||||
|
||||
let impl_item = quote_item!(cx,
|
||||
#[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,
|
||||
@@ -87,14 +85,14 @@ fn deserialize_body(
|
||||
ty: P<ast::Ty>,
|
||||
) -> P<ast::Expr> {
|
||||
match item.node {
|
||||
ast::ItemStruct(ref struct_def, _) => {
|
||||
ast::ItemStruct(ref variant_data, _) => {
|
||||
deserialize_item_struct(
|
||||
cx,
|
||||
builder,
|
||||
item,
|
||||
impl_generics,
|
||||
ty,
|
||||
struct_def,
|
||||
variant_data,
|
||||
)
|
||||
}
|
||||
ast::ItemEnum(ref enum_def, _) => {
|
||||
@@ -117,27 +115,17 @@ fn deserialize_item_struct(
|
||||
item: &Item,
|
||||
impl_generics: &ast::Generics,
|
||||
ty: P<ast::Ty>,
|
||||
struct_def: &ast::StructDef,
|
||||
variant_data: &ast::VariantData,
|
||||
) -> P<ast::Expr> {
|
||||
let mut named_fields = vec![];
|
||||
let mut unnamed_fields = 0;
|
||||
|
||||
for field in struct_def.fields.iter() {
|
||||
match field.node.kind {
|
||||
ast::NamedField(name, _) => { named_fields.push(name); }
|
||||
ast::UnnamedField(_) => { unnamed_fields += 1; }
|
||||
}
|
||||
}
|
||||
|
||||
match (named_fields.is_empty(), unnamed_fields) {
|
||||
(true, 0) => {
|
||||
match *variant_data {
|
||||
ast::VariantData::Unit(_) => {
|
||||
deserialize_unit_struct(
|
||||
cx,
|
||||
&builder,
|
||||
item.ident,
|
||||
)
|
||||
}
|
||||
(true, 1) => {
|
||||
ast::VariantData::Tuple(ref fields, _) if fields.len() == 1 => {
|
||||
deserialize_newtype_struct(
|
||||
cx,
|
||||
&builder,
|
||||
@@ -146,29 +134,34 @@ fn deserialize_item_struct(
|
||||
ty,
|
||||
)
|
||||
}
|
||||
(true, _) => {
|
||||
ast::VariantData::Tuple(ref fields, _) => {
|
||||
if fields.iter().any(|field| !field.node.kind.is_unnamed()) {
|
||||
cx.bug("tuple struct has named fields")
|
||||
}
|
||||
|
||||
deserialize_tuple_struct(
|
||||
cx,
|
||||
&builder,
|
||||
item.ident,
|
||||
impl_generics,
|
||||
ty,
|
||||
unnamed_fields,
|
||||
fields.len(),
|
||||
)
|
||||
}
|
||||
(false, 0) => {
|
||||
ast::VariantData::Struct(ref fields, _) => {
|
||||
if fields.iter().any(|field| field.node.kind.is_unnamed()) {
|
||||
cx.bug("struct has unnamed fields")
|
||||
}
|
||||
|
||||
deserialize_struct(
|
||||
cx,
|
||||
&builder,
|
||||
item.ident,
|
||||
impl_generics,
|
||||
ty,
|
||||
struct_def,
|
||||
fields,
|
||||
)
|
||||
}
|
||||
(false, _) => {
|
||||
cx.bug("struct has named and unnamed fields")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -422,9 +415,9 @@ fn deserialize_struct_as_seq(
|
||||
cx: &ExtCtxt,
|
||||
builder: &aster::AstBuilder,
|
||||
struct_path: ast::Path,
|
||||
struct_def: &StructDef,
|
||||
fields: &[ast::StructField],
|
||||
) -> P<ast::Expr> {
|
||||
let let_values: Vec<P<ast::Stmt>> = (0 .. struct_def.fields.len())
|
||||
let let_values: Vec<P<ast::Stmt>> = (0 .. fields.len())
|
||||
.map(|i| {
|
||||
let name = builder.id(format!("__field{}", i));
|
||||
quote_stmt!(cx,
|
||||
@@ -440,13 +433,13 @@ fn deserialize_struct_as_seq(
|
||||
|
||||
let result = builder.expr().struct_path(struct_path)
|
||||
.with_id_exprs(
|
||||
struct_def.fields.iter()
|
||||
fields.iter()
|
||||
.enumerate()
|
||||
.map(|(i, field)| {
|
||||
(
|
||||
match field.node.kind {
|
||||
ast::NamedField(name, _) => name.clone(),
|
||||
ast::UnnamedField(_) => panic!("struct contains unnamed fields"),
|
||||
ast::UnnamedField(_) => cx.bug("struct contains unnamed fields"),
|
||||
},
|
||||
builder.expr().id(format!("__field{}", i)),
|
||||
)
|
||||
@@ -469,7 +462,7 @@ fn deserialize_struct(
|
||||
type_ident: Ident,
|
||||
impl_generics: &ast::Generics,
|
||||
ty: P<ast::Ty>,
|
||||
struct_def: &StructDef,
|
||||
fields: &[ast::StructField],
|
||||
) -> P<ast::Expr> {
|
||||
let where_clause = &impl_generics.where_clause;
|
||||
|
||||
@@ -486,14 +479,14 @@ fn deserialize_struct(
|
||||
cx,
|
||||
builder,
|
||||
type_path.clone(),
|
||||
struct_def
|
||||
fields,
|
||||
);
|
||||
|
||||
let (field_visitor, fields_stmt, visit_map_expr) = deserialize_struct_visitor(
|
||||
cx,
|
||||
builder,
|
||||
struct_def,
|
||||
type_path.clone()
|
||||
type_path.clone(),
|
||||
fields,
|
||||
);
|
||||
|
||||
let type_name = builder.expr().str(type_ident);
|
||||
@@ -543,11 +536,13 @@ fn deserialize_item_enum(
|
||||
cx,
|
||||
builder,
|
||||
enum_def.variants.iter()
|
||||
.map(|variant|
|
||||
attr::FieldAttrs::new(
|
||||
false,
|
||||
true,
|
||||
builder.expr().str(variant.node.name)))
|
||||
.map(|variant| {
|
||||
let expr = builder.expr().str(variant.node.name);
|
||||
attr::FieldAttrsBuilder::new(builder)
|
||||
.name(expr)
|
||||
.default()
|
||||
.build()
|
||||
})
|
||||
.collect()
|
||||
);
|
||||
|
||||
@@ -591,7 +586,7 @@ fn deserialize_item_enum(
|
||||
impl_generics,
|
||||
vec![deserializer_ty_param(builder)],
|
||||
vec![deserializer_ty_arg(builder)],
|
||||
);
|
||||
);
|
||||
|
||||
quote_expr!(cx, {
|
||||
$variant_visitor
|
||||
@@ -626,20 +621,20 @@ fn deserialize_variant(
|
||||
) -> P<ast::Expr> {
|
||||
let variant_ident = variant.node.name;
|
||||
|
||||
match variant.node.kind {
|
||||
ast::TupleVariantKind(ref args) if args.is_empty() => {
|
||||
match variant.node.data {
|
||||
ast::VariantData::Unit(_) => {
|
||||
quote_expr!(cx, {
|
||||
try!(visitor.visit_unit());
|
||||
Ok($type_ident::$variant_ident)
|
||||
})
|
||||
}
|
||||
ast::TupleVariantKind(ref args) if args.len() == 1 => {
|
||||
ast::VariantData::Tuple(ref args, _) if args.len() == 1 => {
|
||||
quote_expr!(cx, {
|
||||
let val = try!(visitor.visit_newtype());
|
||||
Ok($type_ident::$variant_ident(val))
|
||||
})
|
||||
}
|
||||
ast::TupleVariantKind(ref args) => {
|
||||
ast::VariantData::Tuple(ref fields, _) => {
|
||||
deserialize_tuple_variant(
|
||||
cx,
|
||||
builder,
|
||||
@@ -647,10 +642,10 @@ fn deserialize_variant(
|
||||
variant_ident,
|
||||
generics,
|
||||
ty,
|
||||
args.len(),
|
||||
fields.len(),
|
||||
)
|
||||
}
|
||||
ast::StructVariantKind(ref struct_def) => {
|
||||
ast::VariantData::Struct(ref fields, _) => {
|
||||
deserialize_struct_variant(
|
||||
cx,
|
||||
builder,
|
||||
@@ -658,7 +653,7 @@ fn deserialize_variant(
|
||||
variant_ident,
|
||||
generics,
|
||||
ty,
|
||||
struct_def,
|
||||
fields,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -681,7 +676,7 @@ fn deserialize_tuple_variant(
|
||||
generics,
|
||||
vec![deserializer_ty_param(builder)],
|
||||
vec![deserializer_ty_arg(builder)],
|
||||
);
|
||||
);
|
||||
|
||||
let visit_seq_expr = deserialize_seq(
|
||||
cx,
|
||||
@@ -714,7 +709,7 @@ fn deserialize_struct_variant(
|
||||
variant_ident: ast::Ident,
|
||||
generics: &ast::Generics,
|
||||
ty: P<ast::Ty>,
|
||||
struct_def: &ast::StructDef,
|
||||
fields: &[ast::StructField],
|
||||
) -> P<ast::Expr> {
|
||||
let where_clause = &generics.where_clause;
|
||||
|
||||
@@ -727,14 +722,14 @@ fn deserialize_struct_variant(
|
||||
cx,
|
||||
builder,
|
||||
type_path.clone(),
|
||||
struct_def
|
||||
fields,
|
||||
);
|
||||
|
||||
let (field_visitor, fields_stmt, field_expr) = deserialize_struct_visitor(
|
||||
cx,
|
||||
builder,
|
||||
struct_def,
|
||||
type_path
|
||||
type_path,
|
||||
fields,
|
||||
);
|
||||
|
||||
let (visitor_item, visitor_ty, visitor_expr, visitor_generics) =
|
||||
@@ -743,7 +738,7 @@ fn deserialize_struct_variant(
|
||||
generics,
|
||||
vec![deserializer_ty_param(builder)],
|
||||
vec![deserializer_ty_arg(builder)],
|
||||
);
|
||||
);
|
||||
|
||||
quote_expr!(cx, {
|
||||
$field_visitor
|
||||
@@ -789,7 +784,7 @@ fn deserialize_field_visitor(
|
||||
.enum_("__Field")
|
||||
.with_variants(
|
||||
field_idents.iter().map(|field_ident| {
|
||||
builder.variant(field_ident).tuple().build()
|
||||
builder.variant(field_ident).unit()
|
||||
})
|
||||
)
|
||||
.build();
|
||||
@@ -925,25 +920,25 @@ fn deserialize_field_visitor(
|
||||
fn deserialize_struct_visitor(
|
||||
cx: &ExtCtxt,
|
||||
builder: &aster::AstBuilder,
|
||||
struct_def: &ast::StructDef,
|
||||
struct_path: ast::Path,
|
||||
fields: &[ast::StructField],
|
||||
) -> (Vec<P<ast::Item>>, P<ast::Stmt>, P<ast::Expr>) {
|
||||
let field_visitor = deserialize_field_visitor(
|
||||
cx,
|
||||
builder,
|
||||
field::struct_field_attrs(cx, builder, struct_def),
|
||||
field::struct_field_attrs(cx, builder, fields),
|
||||
);
|
||||
|
||||
let visit_map_expr = deserialize_map(
|
||||
cx,
|
||||
builder,
|
||||
struct_path,
|
||||
struct_def,
|
||||
fields,
|
||||
);
|
||||
|
||||
let fields_expr = builder.expr().addr_of().slice()
|
||||
.with_exprs(
|
||||
struct_def.fields.iter()
|
||||
fields.iter()
|
||||
.map(|field| {
|
||||
match field.node.kind {
|
||||
ast::NamedField(name, _) => builder.expr().str(name),
|
||||
@@ -964,10 +959,10 @@ fn deserialize_map(
|
||||
cx: &ExtCtxt,
|
||||
builder: &aster::AstBuilder,
|
||||
struct_path: ast::Path,
|
||||
struct_def: &StructDef,
|
||||
fields: &[ast::StructField],
|
||||
) -> P<ast::Expr> {
|
||||
// Create the field names for the fields.
|
||||
let field_names: Vec<ast::Ident> = (0 .. struct_def.fields.len())
|
||||
let field_names: Vec<ast::Ident> = (0 .. fields.len())
|
||||
.map(|i| builder.id(format!("__field{}", i)))
|
||||
.collect();
|
||||
|
||||
@@ -988,7 +983,7 @@ fn deserialize_map(
|
||||
.collect();
|
||||
|
||||
let extract_values: Vec<P<ast::Stmt>> = field_names.iter()
|
||||
.zip(field::struct_field_attrs(cx, builder, struct_def).iter())
|
||||
.zip(field::struct_field_attrs(cx, builder, fields).iter())
|
||||
.map(|(field_name, field_attr)| {
|
||||
let missing_expr = if field_attr.use_default() {
|
||||
quote_expr!(cx, ::std::default::Default::default())
|
||||
@@ -1025,7 +1020,7 @@ fn deserialize_map(
|
||||
|
||||
let result = builder.expr().struct_path(struct_path)
|
||||
.with_id_exprs(
|
||||
struct_def.fields.iter()
|
||||
fields.iter()
|
||||
.zip(field_names.iter())
|
||||
.map(|(field, field_name)| {
|
||||
(
|
||||
|
||||
+7
-137
@@ -1,147 +1,17 @@
|
||||
use std::collections::HashMap;
|
||||
use syntax::ast;
|
||||
use syntax::ext::base::ExtCtxt;
|
||||
|
||||
use aster;
|
||||
|
||||
use syntax::ast;
|
||||
use syntax::attr;
|
||||
use syntax::ext::base::ExtCtxt;
|
||||
use syntax::ptr::P;
|
||||
|
||||
use attr::FieldAttrs;
|
||||
|
||||
enum Rename<'a> {
|
||||
None,
|
||||
Global(&'a ast::Lit),
|
||||
Format(HashMap<P<ast::Expr>, &'a ast::Lit>)
|
||||
}
|
||||
|
||||
fn rename<'a>(
|
||||
builder: &aster::AstBuilder,
|
||||
mi: &'a ast::MetaItem,
|
||||
) -> Option<Rename<'a>>
|
||||
{
|
||||
match mi.node {
|
||||
ast::MetaNameValue(ref n, ref lit) => {
|
||||
if n == &"rename" {
|
||||
Some(Rename::Global(lit))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
ast::MetaList(ref n, ref items) => {
|
||||
if n == &"rename" {
|
||||
let mut m = HashMap::new();
|
||||
m.extend(
|
||||
items.iter()
|
||||
.filter_map(
|
||||
|item|
|
||||
match item.node {
|
||||
ast::MetaNameValue(ref n, ref lit) =>
|
||||
Some((builder.expr().str(n),
|
||||
lit)),
|
||||
_ => None
|
||||
}));
|
||||
Some(Rename::Format(m))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
fn default_value(mi: &ast::MetaItem) -> bool {
|
||||
if let ast::MetaItem_::MetaWord(ref n) = mi.node {
|
||||
n == &"default"
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn skip_serializing_field(mi: &ast::MetaItem) -> bool {
|
||||
if let ast::MetaItem_::MetaWord(ref n) = mi.node {
|
||||
n == &"skip_serializing"
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn field_attrs<'a>(
|
||||
builder: &aster::AstBuilder,
|
||||
field: &'a ast::StructField,
|
||||
) -> (Rename<'a>, bool, bool) {
|
||||
field.node.attrs.iter()
|
||||
.find(|sa| {
|
||||
if let ast::MetaList(ref n, _) = sa.node.value.node {
|
||||
n == &"serde"
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
.and_then(|sa| {
|
||||
if let ast::MetaList(_, ref vals) = sa.node.value.node {
|
||||
attr::mark_used(&sa);
|
||||
Some((
|
||||
vals.iter()
|
||||
.fold(None, |v, mi| v.or(rename(builder, mi)))
|
||||
.unwrap_or(Rename::None),
|
||||
vals.iter().any(|mi| default_value(mi)),
|
||||
vals.iter().any(|mi| skip_serializing_field(mi)),
|
||||
))
|
||||
} else {
|
||||
Some((Rename::None, false, false))
|
||||
}
|
||||
})
|
||||
.unwrap_or((Rename::None, false, false))
|
||||
}
|
||||
use attr::{FieldAttrs, FieldAttrsBuilder};
|
||||
|
||||
pub fn struct_field_attrs(
|
||||
cx: &ExtCtxt,
|
||||
_cx: &ExtCtxt,
|
||||
builder: &aster::AstBuilder,
|
||||
struct_def: &ast::StructDef,
|
||||
fields: &[ast::StructField],
|
||||
) -> Vec<FieldAttrs> {
|
||||
struct_def.fields.iter()
|
||||
fields.iter()
|
||||
.map(|field| {
|
||||
match field_attrs(builder, field) {
|
||||
(Rename::Global(rename), default_value, skip_serializing_field) =>
|
||||
FieldAttrs::new(
|
||||
skip_serializing_field,
|
||||
default_value,
|
||||
builder.expr().build_lit(P(rename.clone()))),
|
||||
(Rename::Format(renames), default_value, skip_serializing_field) => {
|
||||
let mut res = HashMap::new();
|
||||
res.extend(
|
||||
renames.into_iter()
|
||||
.map(|(k,v)|
|
||||
(k, builder.expr().build_lit(P(v.clone())))));
|
||||
FieldAttrs::new_with_formats(
|
||||
skip_serializing_field,
|
||||
default_value,
|
||||
default_field_name(cx, builder, field.node.kind),
|
||||
res)
|
||||
},
|
||||
(Rename::None, default_value, skip_serializing_field) => {
|
||||
FieldAttrs::new(
|
||||
skip_serializing_field,
|
||||
default_value,
|
||||
default_field_name(cx, builder, field.node.kind))
|
||||
}
|
||||
}
|
||||
FieldAttrsBuilder::new(builder).field(field).build()
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn default_field_name(
|
||||
cx: &ExtCtxt,
|
||||
builder: &aster::AstBuilder,
|
||||
kind: ast::StructFieldKind,
|
||||
) -> P<ast::Expr> {
|
||||
match kind {
|
||||
ast::NamedField(name, _) => {
|
||||
builder.expr().str(name)
|
||||
}
|
||||
ast::UnnamedField(_) => {
|
||||
cx.bug("struct has named and unnamed fields")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ extern crate syntex_syntax as syntax;
|
||||
extern crate syntax;
|
||||
|
||||
#[cfg(not(feature = "with-syntex"))]
|
||||
extern crate rustc;
|
||||
extern crate rustc_plugin;
|
||||
|
||||
#[cfg(feature = "with-syntex")]
|
||||
include!(concat!(env!("OUT_DIR"), "/lib.rs"));
|
||||
@@ -60,7 +60,7 @@ pub fn register(reg: &mut syntex::Registry) {
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "with-syntex"))]
|
||||
pub fn register(reg: &mut rustc::plugin::Registry) {
|
||||
pub fn register(reg: &mut rustc_plugin::Registry) {
|
||||
reg.register_syntax_extension(
|
||||
syntax::parse::token::intern("derive_Serialize"),
|
||||
syntax::ext::base::MultiDecorator(
|
||||
|
||||
+90
-68
@@ -5,7 +5,6 @@ use syntax::ast::{
|
||||
MetaItem,
|
||||
Item,
|
||||
Expr,
|
||||
StructDef,
|
||||
};
|
||||
use syntax::ast;
|
||||
use syntax::codemap::Span;
|
||||
@@ -61,7 +60,6 @@ pub fn expand_derive_serialize(
|
||||
let where_clause = &impl_generics.where_clause;
|
||||
|
||||
let impl_item = quote_item!(cx,
|
||||
#[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,
|
||||
@@ -82,14 +80,14 @@ fn serialize_body(
|
||||
ty: P<ast::Ty>,
|
||||
) -> P<ast::Expr> {
|
||||
match item.node {
|
||||
ast::ItemStruct(ref struct_def, _) => {
|
||||
ast::ItemStruct(ref variant_data, _) => {
|
||||
serialize_item_struct(
|
||||
cx,
|
||||
builder,
|
||||
item,
|
||||
impl_generics,
|
||||
ty,
|
||||
struct_def,
|
||||
variant_data,
|
||||
)
|
||||
}
|
||||
ast::ItemEnum(ref enum_def, _) => {
|
||||
@@ -112,57 +110,51 @@ fn serialize_item_struct(
|
||||
item: &Item,
|
||||
impl_generics: &ast::Generics,
|
||||
ty: P<ast::Ty>,
|
||||
struct_def: &ast::StructDef,
|
||||
variant_data: &ast::VariantData,
|
||||
) -> P<ast::Expr> {
|
||||
let mut named_fields = vec![];
|
||||
let mut unnamed_fields = 0;
|
||||
|
||||
for field in struct_def.fields.iter() {
|
||||
match field.node.kind {
|
||||
ast::NamedField(name, _) => { named_fields.push(name); }
|
||||
ast::UnnamedField(_) => { unnamed_fields += 1; }
|
||||
}
|
||||
}
|
||||
|
||||
match (named_fields.is_empty(), unnamed_fields) {
|
||||
(true, 0) => {
|
||||
match *variant_data {
|
||||
ast::VariantData::Unit(_) => {
|
||||
serialize_unit_struct(
|
||||
cx,
|
||||
&builder,
|
||||
item.ident,
|
||||
)
|
||||
}
|
||||
(true, 1) => {
|
||||
ast::VariantData::Tuple(ref fields, _) if fields.len() == 1 => {
|
||||
serialize_newtype_struct(
|
||||
cx,
|
||||
&builder,
|
||||
item.ident,
|
||||
)
|
||||
}
|
||||
(true, _) => {
|
||||
ast::VariantData::Tuple(ref fields, _) => {
|
||||
if fields.iter().any(|field| !field.node.kind.is_unnamed()) {
|
||||
cx.bug("tuple struct has named fields")
|
||||
}
|
||||
|
||||
serialize_tuple_struct(
|
||||
cx,
|
||||
&builder,
|
||||
item.ident,
|
||||
impl_generics,
|
||||
ty,
|
||||
unnamed_fields,
|
||||
fields.len(),
|
||||
)
|
||||
}
|
||||
(false, 0) => {
|
||||
ast::VariantData::Struct(ref fields, _) => {
|
||||
if fields.iter().any(|field| field.node.kind.is_unnamed()) {
|
||||
cx.bug("struct has unnamed fields")
|
||||
}
|
||||
|
||||
serialize_struct(
|
||||
cx,
|
||||
&builder,
|
||||
item.ident,
|
||||
impl_generics,
|
||||
ty,
|
||||
struct_def,
|
||||
named_fields,
|
||||
fields,
|
||||
)
|
||||
}
|
||||
(false, _) => {
|
||||
cx.bug("struct has named and unnamed fields")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -225,8 +217,7 @@ fn serialize_struct(
|
||||
type_ident: Ident,
|
||||
impl_generics: &ast::Generics,
|
||||
ty: P<ast::Ty>,
|
||||
struct_def: &StructDef,
|
||||
fields: Vec<Ident>,
|
||||
fields: &[ast::StructField],
|
||||
) -> P<ast::Expr> {
|
||||
let (visitor_struct, visitor_impl) = serialize_struct_visitor(
|
||||
cx,
|
||||
@@ -236,9 +227,12 @@ fn serialize_struct(
|
||||
.ref_()
|
||||
.lifetime("'__a")
|
||||
.build_ty(ty.clone()),
|
||||
struct_def,
|
||||
fields,
|
||||
impl_generics,
|
||||
fields.iter().map(|field| quote_expr!(cx, &self.value.$field)),
|
||||
fields.iter().map(|field| {
|
||||
let name = field.node.ident().expect("struct has unnamed field");
|
||||
quote_expr!(cx, &self.value.$name)
|
||||
})
|
||||
);
|
||||
|
||||
let type_name = builder.expr().str(type_ident);
|
||||
@@ -297,8 +291,8 @@ fn serialize_variant(
|
||||
let variant_ident = variant.node.name;
|
||||
let variant_name = builder.expr().str(variant_ident);
|
||||
|
||||
match variant.node.kind {
|
||||
ast::TupleVariantKind(ref args) if args.is_empty() => {
|
||||
match variant.node.data {
|
||||
ast::VariantData::Unit(_) => {
|
||||
let pat = builder.pat().enum_()
|
||||
.id(type_ident).id(variant_ident).build()
|
||||
.build();
|
||||
@@ -314,7 +308,7 @@ fn serialize_variant(
|
||||
}
|
||||
)
|
||||
},
|
||||
ast::TupleVariantKind(ref args) if args.len() == 1 => {
|
||||
ast::VariantData::Tuple(ref fields, _) if fields.len() == 1 => {
|
||||
let field = builder.id("__simple_value");
|
||||
let field = builder.pat().ref_id(field);
|
||||
let pat = builder.pat().enum_()
|
||||
@@ -333,14 +327,17 @@ fn serialize_variant(
|
||||
}
|
||||
)
|
||||
},
|
||||
ast::TupleVariantKind(ref args) => {
|
||||
let fields: Vec<ast::Ident> = (0 .. args.len())
|
||||
ast::VariantData::Tuple(ref fields, _) => {
|
||||
let field_names: Vec<ast::Ident> = (0 .. fields.len())
|
||||
.map(|i| builder.id(format!("__field{}", i)))
|
||||
.collect();
|
||||
|
||||
let pat = builder.pat().enum_()
|
||||
.id(type_ident).id(variant_ident).build()
|
||||
.with_pats(fields.iter().map(|field| builder.pat().ref_id(field)))
|
||||
.with_pats(
|
||||
field_names.iter()
|
||||
.map(|field| builder.pat().ref_id(field))
|
||||
)
|
||||
.build();
|
||||
|
||||
let expr = serialize_tuple_variant(
|
||||
@@ -351,22 +348,22 @@ fn serialize_variant(
|
||||
variant_name,
|
||||
generics,
|
||||
ty,
|
||||
args,
|
||||
fields,
|
||||
field_names,
|
||||
);
|
||||
|
||||
quote_arm!(cx, $pat => { $expr })
|
||||
}
|
||||
ast::StructVariantKind(ref struct_def) => {
|
||||
let fields: Vec<_> = (0 .. struct_def.fields.len())
|
||||
ast::VariantData::Struct(ref fields, _) => {
|
||||
let field_names: Vec<_> = (0 .. fields.len())
|
||||
.map(|i| builder.id(format!("__field{}", i)))
|
||||
.collect();
|
||||
|
||||
let pat = builder.pat().struct_()
|
||||
.id(type_ident).id(variant_ident).build()
|
||||
.with_pats(
|
||||
fields.iter()
|
||||
.zip(struct_def.fields.iter())
|
||||
field_names.iter()
|
||||
.zip(fields.iter())
|
||||
.map(|(id, field)| {
|
||||
let name = match field.node.kind {
|
||||
ast::NamedField(name, _) => name,
|
||||
@@ -388,8 +385,8 @@ fn serialize_variant(
|
||||
variant_name,
|
||||
generics,
|
||||
ty,
|
||||
struct_def,
|
||||
fields,
|
||||
field_names,
|
||||
);
|
||||
|
||||
quote_arm!(cx, $pat => { $expr })
|
||||
@@ -405,16 +402,16 @@ fn serialize_tuple_variant(
|
||||
variant_name: P<ast::Expr>,
|
||||
generics: &ast::Generics,
|
||||
structure_ty: P<ast::Ty>,
|
||||
args: &[ast::VariantArg],
|
||||
fields: Vec<Ident>,
|
||||
fields: &[ast::StructField],
|
||||
field_names: Vec<Ident>,
|
||||
) -> P<ast::Expr> {
|
||||
let variant_ty = builder.ty().tuple()
|
||||
.with_tys(
|
||||
args.iter().map(|arg| {
|
||||
fields.iter().map(|field| {
|
||||
builder.ty()
|
||||
.ref_()
|
||||
.lifetime("'__a")
|
||||
.build_ty(arg.ty.clone())
|
||||
.build_ty(field.node.ty.clone())
|
||||
})
|
||||
)
|
||||
.build();
|
||||
@@ -424,13 +421,13 @@ fn serialize_tuple_variant(
|
||||
builder,
|
||||
structure_ty.clone(),
|
||||
variant_ty,
|
||||
args.len(),
|
||||
fields.len(),
|
||||
generics,
|
||||
);
|
||||
|
||||
let value_expr = builder.expr().tuple()
|
||||
.with_exprs(
|
||||
fields.iter().map(|field| {
|
||||
field_names.iter().map(|field| {
|
||||
builder.expr().id(field)
|
||||
})
|
||||
)
|
||||
@@ -455,12 +452,12 @@ fn serialize_struct_variant(
|
||||
variant_name: P<ast::Expr>,
|
||||
generics: &ast::Generics,
|
||||
structure_ty: P<ast::Ty>,
|
||||
struct_def: &ast::StructDef,
|
||||
fields: Vec<Ident>,
|
||||
fields: &[ast::StructField],
|
||||
field_names: Vec<Ident>,
|
||||
) -> P<ast::Expr> {
|
||||
let value_ty = builder.ty().tuple()
|
||||
.with_tys(
|
||||
struct_def.fields.iter().map(|field| {
|
||||
fields.iter().map(|field| {
|
||||
builder.ty()
|
||||
.ref_()
|
||||
.lifetime("'__a")
|
||||
@@ -471,7 +468,7 @@ fn serialize_struct_variant(
|
||||
|
||||
let value_expr = builder.expr().tuple()
|
||||
.with_exprs(
|
||||
fields.iter().map(|field| {
|
||||
field_names.iter().map(|field| {
|
||||
builder.expr().id(field)
|
||||
})
|
||||
)
|
||||
@@ -482,9 +479,9 @@ fn serialize_struct_variant(
|
||||
builder,
|
||||
structure_ty.clone(),
|
||||
value_ty,
|
||||
struct_def,
|
||||
fields,
|
||||
generics,
|
||||
(0 .. fields.len()).map(|i| {
|
||||
(0 .. field_names.len()).map(|i| {
|
||||
builder.expr()
|
||||
.tup_field(i)
|
||||
.field("value").self_()
|
||||
@@ -574,29 +571,37 @@ fn serialize_struct_visitor<I>(
|
||||
builder: &aster::AstBuilder,
|
||||
structure_ty: P<ast::Ty>,
|
||||
variant_ty: P<ast::Ty>,
|
||||
struct_def: &StructDef,
|
||||
fields: &[ast::StructField],
|
||||
generics: &ast::Generics,
|
||||
value_exprs: I,
|
||||
) -> (P<ast::Item>, P<ast::Item>)
|
||||
where I: Iterator<Item=P<ast::Expr>>,
|
||||
{
|
||||
let field_attrs = struct_field_attrs(cx, builder, struct_def);
|
||||
let value_exprs = value_exprs.collect::<Vec<_>>();
|
||||
|
||||
let len = struct_def.fields.len() - field_attrs.iter()
|
||||
.fold(0, |sum, field| {
|
||||
sum + if field.skip_serializing_field() { 1 } else { 0 }
|
||||
});
|
||||
let field_attrs = struct_field_attrs(cx, builder, fields);
|
||||
|
||||
let arms: Vec<ast::Arm> = field_attrs.into_iter()
|
||||
.zip(value_exprs)
|
||||
let arms: Vec<ast::Arm> = field_attrs.iter()
|
||||
.zip(value_exprs.iter())
|
||||
.filter(|&(ref field, _)| !field.skip_serializing_field())
|
||||
.enumerate()
|
||||
.map(|(i, (field, value_expr))| {
|
||||
.map(|(i, (ref field, value_expr))| {
|
||||
let key_expr = field.serializer_key_expr(cx);
|
||||
|
||||
let stmt = if field.skip_serializing_field_if_empty() {
|
||||
quote_stmt!(cx, if ($value_expr).is_empty() { continue; })
|
||||
} else if field.skip_serializing_field_if_none() {
|
||||
quote_stmt!(cx, if ($value_expr).is_none() { continue; })
|
||||
} else {
|
||||
quote_stmt!(cx, {})
|
||||
};
|
||||
|
||||
quote_arm!(cx,
|
||||
$i => {
|
||||
self.state += 1;
|
||||
Ok(
|
||||
$stmt
|
||||
|
||||
return Ok(
|
||||
Some(
|
||||
try!(
|
||||
serializer.visit_struct_elt(
|
||||
@@ -605,7 +610,7 @@ fn serialize_struct_visitor<I>(
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
)
|
||||
})
|
||||
@@ -622,6 +627,21 @@ fn serialize_struct_visitor<I>(
|
||||
.strip_bounds()
|
||||
.build();
|
||||
|
||||
let len = field_attrs.iter()
|
||||
.zip(value_exprs.iter())
|
||||
.map(|(field, value_expr)| {
|
||||
if field.skip_serializing_field() {
|
||||
quote_expr!(cx, 0)
|
||||
} else if field.skip_serializing_field_if_empty() {
|
||||
quote_expr!(cx, if ($value_expr).is_empty() { 0 } else { 1 })
|
||||
} else if field.skip_serializing_field_if_none() {
|
||||
quote_expr!(cx, if ($value_expr).is_none() { 0 } else { 1 })
|
||||
} else {
|
||||
quote_expr!(cx, 1)
|
||||
}
|
||||
})
|
||||
.fold(quote_expr!(cx, 0), |sum, expr| quote_expr!(cx, $sum + $expr));
|
||||
|
||||
(
|
||||
quote_item!(cx,
|
||||
struct Visitor $visitor_impl_generics $where_clause {
|
||||
@@ -640,9 +660,11 @@ fn serialize_struct_visitor<I>(
|
||||
fn visit<S>(&mut self, serializer: &mut S) -> ::std::result::Result<Option<()>, S::Error>
|
||||
where S: ::serde::ser::Serializer,
|
||||
{
|
||||
match self.state {
|
||||
$arms
|
||||
_ => Ok(None)
|
||||
loop {
|
||||
match self.state {
|
||||
$arms
|
||||
_ => { return Ok(None); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "serde_macros"
|
||||
version = "0.5.3"
|
||||
version = "0.6.5"
|
||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
|
||||
license = "MIT/Apache-2.0"
|
||||
description = "Macros to auto-generate implementations for the serde framework"
|
||||
@@ -16,6 +16,6 @@ plugin = true
|
||||
serde_codegen = { version = "*", path = "../serde_codegen", default-features = false, features = ["nightly"] }
|
||||
|
||||
[dev-dependencies]
|
||||
num = "*"
|
||||
rustc-serialize = "*"
|
||||
num = "^0.1.27"
|
||||
rustc-serialize = "^0.3.16"
|
||||
serde = { version = "*", path = "../serde", features = ["nightly"] }
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#![feature(plugin_registrar, rustc_private)]
|
||||
|
||||
extern crate serde_codegen;
|
||||
extern crate rustc;
|
||||
extern crate rustc_plugin;
|
||||
|
||||
#[plugin_registrar]
|
||||
#[doc(hidden)]
|
||||
pub fn plugin_registrar(reg: &mut rustc::plugin::Registry) {
|
||||
pub fn plugin_registrar(reg: &mut rustc_plugin::Registry) {
|
||||
serde_codegen::register(reg);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "serde_tests"
|
||||
version = "0.5.0"
|
||||
version = "0.6.2"
|
||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
|
||||
license = "MIT/Apache-2.0"
|
||||
description = "A generic serialization/deserialization framework"
|
||||
@@ -11,15 +11,15 @@ keywords = ["serialization"]
|
||||
build = "build.rs"
|
||||
|
||||
[build-dependencies]
|
||||
syntex = { version = "*" }
|
||||
syntex_syntax = { version = "*" }
|
||||
syntex = { version = "^0.22.0" }
|
||||
syntex_syntax = { version = "^0.22.0" }
|
||||
serde_codegen = { version = "*", path = "../serde_codegen", features = ["with-syntex"] }
|
||||
|
||||
[dev-dependencies]
|
||||
num = "*"
|
||||
rustc-serialize = "*"
|
||||
num = "^0.1.27"
|
||||
rustc-serialize = "^0.3.16"
|
||||
serde = { version = "*", path = "../serde" }
|
||||
syntex = "*"
|
||||
syntex = "^0.22.0"
|
||||
|
||||
[[test]]
|
||||
name = "test"
|
||||
|
||||
@@ -39,6 +39,20 @@ struct SkipSerializingFields<A: default::Default> {
|
||||
b: A,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Deserialize, Serialize)]
|
||||
struct SkipSerializingIfEmptyFields<A: default::Default> {
|
||||
a: i8,
|
||||
#[serde(skip_serializing_if_empty, default)]
|
||||
b: Vec<A>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Deserialize, Serialize)]
|
||||
struct SkipSerializingIfNoneFields<A: default::Default> {
|
||||
a: i8,
|
||||
#[serde(skip_serializing_if_none, default)]
|
||||
b: Option<A>,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_default() {
|
||||
assert_de_tokens(
|
||||
@@ -169,3 +183,161 @@ fn test_skip_serializing_fields() {
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_skip_serializing_fields_if_empty() {
|
||||
assert_ser_tokens(
|
||||
&SkipSerializingIfEmptyFields::<i32> {
|
||||
a: 1,
|
||||
b: vec![],
|
||||
},
|
||||
&[
|
||||
Token::StructStart("SkipSerializingIfEmptyFields", Some(1)),
|
||||
|
||||
Token::MapSep,
|
||||
Token::Str("a"),
|
||||
Token::I8(1),
|
||||
|
||||
Token::MapEnd,
|
||||
]
|
||||
);
|
||||
|
||||
assert_de_tokens(
|
||||
&SkipSerializingIfEmptyFields::<i32> {
|
||||
a: 1,
|
||||
b: vec![],
|
||||
},
|
||||
vec![
|
||||
Token::StructStart("SkipSerializingIfEmptyFields", Some(1)),
|
||||
|
||||
Token::MapSep,
|
||||
Token::Str("a"),
|
||||
Token::I8(1),
|
||||
|
||||
Token::MapEnd,
|
||||
]
|
||||
);
|
||||
|
||||
assert_ser_tokens(
|
||||
&SkipSerializingIfEmptyFields {
|
||||
a: 1,
|
||||
b: vec![2],
|
||||
},
|
||||
&[
|
||||
Token::StructStart("SkipSerializingIfEmptyFields", Some(2)),
|
||||
|
||||
Token::MapSep,
|
||||
Token::Str("a"),
|
||||
Token::I8(1),
|
||||
|
||||
Token::MapSep,
|
||||
Token::Str("b"),
|
||||
Token::SeqStart(Some(1)),
|
||||
Token::SeqSep,
|
||||
Token::I32(2),
|
||||
Token::SeqEnd,
|
||||
|
||||
Token::MapEnd,
|
||||
]
|
||||
);
|
||||
|
||||
assert_de_tokens(
|
||||
&SkipSerializingIfEmptyFields {
|
||||
a: 1,
|
||||
b: vec![2],
|
||||
},
|
||||
vec![
|
||||
Token::StructStart("SkipSerializingIfEmptyFields", Some(2)),
|
||||
|
||||
Token::MapSep,
|
||||
Token::Str("a"),
|
||||
Token::I8(1),
|
||||
|
||||
Token::MapSep,
|
||||
Token::Str("b"),
|
||||
Token::SeqStart(Some(1)),
|
||||
Token::SeqSep,
|
||||
Token::I32(2),
|
||||
Token::SeqEnd,
|
||||
|
||||
Token::MapEnd,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_skip_serializing_fields_if_none() {
|
||||
assert_ser_tokens(
|
||||
&SkipSerializingIfNoneFields::<i32> {
|
||||
a: 1,
|
||||
b: None,
|
||||
},
|
||||
&[
|
||||
Token::StructStart("SkipSerializingIfNoneFields", Some(1)),
|
||||
|
||||
Token::MapSep,
|
||||
Token::Str("a"),
|
||||
Token::I8(1),
|
||||
|
||||
Token::MapEnd,
|
||||
]
|
||||
);
|
||||
|
||||
assert_de_tokens(
|
||||
&SkipSerializingIfNoneFields::<i32> {
|
||||
a: 1,
|
||||
b: None,
|
||||
},
|
||||
vec![
|
||||
Token::StructStart("SkipSerializingIfNoneFields", Some(1)),
|
||||
|
||||
Token::MapSep,
|
||||
Token::Str("a"),
|
||||
Token::I8(1),
|
||||
|
||||
Token::MapEnd,
|
||||
]
|
||||
);
|
||||
|
||||
assert_ser_tokens(
|
||||
&SkipSerializingIfNoneFields {
|
||||
a: 1,
|
||||
b: Some(2),
|
||||
},
|
||||
&[
|
||||
Token::StructStart("SkipSerializingIfNoneFields", Some(2)),
|
||||
|
||||
Token::MapSep,
|
||||
Token::Str("a"),
|
||||
Token::I8(1),
|
||||
|
||||
Token::MapSep,
|
||||
Token::Str("b"),
|
||||
Token::Option(true),
|
||||
Token::I32(2),
|
||||
|
||||
Token::MapEnd,
|
||||
]
|
||||
);
|
||||
|
||||
assert_de_tokens(
|
||||
&SkipSerializingIfNoneFields {
|
||||
a: 1,
|
||||
b: Some(2),
|
||||
},
|
||||
vec![
|
||||
Token::StructStart("SkipSerializingIfNoneFields", Some(2)),
|
||||
|
||||
Token::MapSep,
|
||||
Token::Str("a"),
|
||||
Token::I8(1),
|
||||
|
||||
Token::MapSep,
|
||||
Token::Str("b"),
|
||||
Token::Option(true),
|
||||
Token::I32(2),
|
||||
|
||||
Token::MapEnd,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user