Compare commits

...

26 Commits

Author SHA1 Message Date
Erick Tryzelaar 72de877ec3 Merge pull request #173 from erickt/update
Update aster, quasi, and syntex
2015-10-17 20:03:15 -07:00
Erick Tryzelaar f872b3fb4b fix(cargo): Update aster, quasi, and syntex 2015-10-17 19:44:07 -07:00
Erick Tryzelaar ddc33ee747 cleanup(whitespace): Fix some whitespace issues 2015-10-14 08:52:25 -07:00
Erick Tryzelaar 612e384b03 Merge pull request #171 from oli-obk/fix_skip_empty_field_ser
$value_expr starting with a & took address of resulting bool
2015-10-12 13:41:23 -07:00
Oliver Schneider 1c88856fc8 $value_expr starting with a & took address of resulting bool 2015-10-12 11:04:50 +02:00
Erick Tryzelaar 534e6d1f4c Merge pull request #167 from pwoolcoc/patch-1
Fix code block end marker
2015-10-06 11:50:54 -07:00
Paul Woolcock 7ad31a01dd Fix code block end marker
Looks like someone accidentally removed the `\`\`\`` from the end of a code block, causing the `Serialization without Macros` section to be formatted like code
2015-10-06 14:04:54 -04:00
Erick Tryzelaar 00cd2900e7 Merge pull request #155 from erickt/skip
Add skip serializing fields if empty or none
2015-10-05 14:51:46 -07:00
Erick Tryzelaar 05a238fac4 Merge pull request #164 from serde-rs/oli-obk-patch-1
add link to the README from the docs
2015-10-05 14:49:46 -07:00
Oliver Schneider 310db21d64 add link to the README from the docs
The small starting page in the docs was noted at https://users.rust-lang.org/t/lets-talk-about-ecosystem-documentation/2791/25
2015-10-05 15:57:01 +02:00
Erick Tryzelaar 72af0896e8 docs(codegen): Document annotations 2015-09-07 16:59:11 -07:00
Erick Tryzelaar c4392ff256 feat(codegen): Add more attributes to skip serializing
These attributes are `#[serde(skip_serializing_if_none)]` and
`#[serde(skip_serializing_if_empty)]`.
2015-09-07 16:58:52 -07:00
Erick Tryzelaar c68ab508c0 refactor(codegen): Simplify parsing attributes 2015-09-07 16:58:52 -07:00
Erick Tryzelaar 76cca814f0 docs(readme): Improve the readme 2015-09-07 16:58:46 -07:00
Erick Tryzelaar 22b69fc5c9 docs(serde): Fix typo 2015-09-07 13:02:53 -07:00
Homu a1bd0c1667 Auto merge of #153 - erickt:doc, r=erickt
Start documenting everything
2015-09-03 00:54:55 +09:00
Erick Tryzelaar 48ea75fddc Bump version
This is because I removed some public, but unused things
2015-09-02 08:54:01 -07:00
Erick Tryzelaar 4b49f716b9 Document serde::de::impls. 2015-09-02 08:36:14 -07:00
Erick Tryzelaar 55f5f397d7 Document serde::de::value 2015-09-02 08:36:14 -07:00
Erick Tryzelaar 4be4f60f21 Document serde::de::mod. 2015-09-02 08:36:14 -07:00
Erick Tryzelaar 9a8037bbf2 Remove unused Enum{Seq,Map}Visitor 2015-09-02 08:36:14 -07:00
Erick Tryzelaar c7f1af90b2 Document serde::iter 2015-09-02 08:36:14 -07:00
Erick Tryzelaar 902d3a0aa5 Document serde::bytes. 2015-09-02 08:36:14 -07:00
Erick Tryzelaar c14eb28223 Remove unused buf module. 2015-09-02 08:36:14 -07:00
Erick Tryzelaar 2722a04e52 Document serde::ser::impls 2015-09-02 08:36:14 -07:00
Erick Tryzelaar 5dbcd7957a Start documenting everything, starting with serde::ser. 2015-09-01 08:02:17 -07:00
18 changed files with 833 additions and 452 deletions
+43 -6
View File
@@ -17,8 +17,8 @@ Documentation is available at:
* [serde\_json](https://serde-rs.github.io/serde/serde_json/serde_json/index.html) * [serde\_json](https://serde-rs.github.io/serde/serde_json/serde_json/index.html)
* [serde\_codegen](https://serde-rs.github.io/serde/serde_codegen/serde_codegen/index.html) * [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 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 deserializing to JSON. Serde comes with some powerful code generation libraries
@@ -76,6 +76,9 @@ When run, it produces:
Point { x: 1, y: 2 } 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 Stable Rust is a little more complicated because it does not yet support
compiler plugins. Instead we need to use the code generation library compiler plugins. Instead we need to use the code generation library
[syntex](https://github.com/erickt/rust-syntex) for this: [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. 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 Serialization without Macros
============================ ============================
@@ -311,6 +328,8 @@ as a named map. Its visitor uses a simple state machine to iterate through all
the fields: the fields:
```rust ```rust
extern crate serde;
struct Point { struct Point {
x: i32, x: i32,
y: 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: before, we need to generate:
```rust ```rust
extern crate serde;
struct Point {
x: i32,
y: i32,
}
enum PointField { enum PointField {
X, X,
Y, Y,
@@ -507,11 +533,7 @@ impl serde::Deserialize for PointField {
deserializer.visit(PointFieldVisitor) deserializer.visit(PointFieldVisitor)
} }
} }
```
This is then used in our actual deserializer:
```rust
impl serde::Deserialize for Point { impl serde::Deserialize for Point {
fn deserialize<D>(deserializer: &mut D) -> Result<Point, D::Error> fn deserialize<D>(deserializer: &mut D) -> Result<Point, D::Error>
where D: serde::de::Deserializer 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 Serialization Formats Using Serde
================================= =================================
+2 -3
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "serde" name = "serde"
version = "0.5.3" version = "0.6.1"
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"] authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
license = "MIT/Apache-2.0" license = "MIT/Apache-2.0"
description = "A generic serialization/deserialization framework" description = "A generic serialization/deserialization framework"
@@ -10,8 +10,7 @@ readme = "../README.md"
keywords = ["serde", "serialization"] keywords = ["serde", "serialization"]
[dependencies] [dependencies]
num = "*" num = "^0.1.27"
[features] [features]
nightly = [] nightly = []
-94
View File
@@ -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
View File
@@ -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)] #[derive(Clone, Eq, Hash, PartialEq, PartialOrd, Ord)]
pub struct ByteBuf { pub struct ByteBuf {
bytes: Vec<u8>, bytes: Vec<u8>,
} }
impl ByteBuf { impl ByteBuf {
/// Construct a new, empty `ByteBuf`.
pub fn new() -> Self { pub fn new() -> Self {
ByteBuf { ByteBuf {
bytes: Vec::new(), bytes: Vec::new(),
} }
} }
/// Construct a new, empty `ByteBuf` with the specified capacity.
pub fn with_capacity(cap: usize) -> Self { pub fn with_capacity(cap: usize) -> Self {
ByteBuf { ByteBuf {
bytes: Vec::with_capacity(cap) 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; pub struct ByteBufVisitor;
impl de::Visitor for ByteBufVisitor { impl de::Visitor for ByteBufVisitor {
+22 -8
View File
@@ -1,3 +1,5 @@
//! This module contains `Deserialize` and `Visitor` implementations.
use std::borrow::Cow; use std::borrow::Cow;
use std::collections::{ use std::collections::{
BinaryHeap, BinaryHeap,
@@ -39,6 +41,7 @@ use de::{
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
/// A visitor that produces a `()`.
pub struct UnitVisitor; pub struct UnitVisitor;
impl Visitor for UnitVisitor { impl Visitor for UnitVisitor {
@@ -67,6 +70,7 @@ impl Deserialize for () {
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
/// A visitor that produces a `bool`.
pub struct BoolVisitor; pub struct BoolVisitor;
impl Visitor for 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> { pub struct PrimitiveVisitor<T> {
marker: PhantomData<T>, marker: PhantomData<T>,
} }
impl<T> PrimitiveVisitor<T> { impl<T> PrimitiveVisitor<T> {
/// Construct a new `PrimitiveVisitor`.
#[inline] #[inline]
pub fn new() -> Self { pub fn new() -> Self {
PrimitiveVisitor { PrimitiveVisitor {
@@ -300,7 +306,7 @@ impl<T> Deserialize for Option<T> where T: Deserialize {
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
macro_rules! set_impl { macro_rules! seq_impl {
( (
$ty:ty, $ty:ty,
< $($constraints:ident),* >, < $($constraints:ident),* >,
@@ -310,11 +316,13 @@ macro_rules! set_impl {
$with_capacity:expr, $with_capacity:expr,
$insert:expr $insert:expr
) => { ) => {
/// A visitor that produces a sequence.
pub struct $visitor_name<T> { pub struct $visitor_name<T> {
marker: PhantomData<T>, marker: PhantomData<T>,
} }
impl<T> $visitor_name<T> { impl<T> $visitor_name<T> {
/// Construct a new sequence visitor.
pub fn new() -> Self { pub fn new() -> Self {
$visitor_name { $visitor_name {
marker: PhantomData, marker: PhantomData,
@@ -362,7 +370,7 @@ macro_rules! set_impl {
} }
} }
set_impl!( seq_impl!(
BinaryHeap<T>, BinaryHeap<T>,
<Deserialize, Ord>, <Deserialize, Ord>,
BinaryHeapVisitor, BinaryHeapVisitor,
@@ -371,7 +379,7 @@ set_impl!(
BinaryHeap::with_capacity(visitor.size_hint().0), BinaryHeap::with_capacity(visitor.size_hint().0),
BinaryHeap::push); BinaryHeap::push);
set_impl!( seq_impl!(
BTreeSet<T>, BTreeSet<T>,
<Deserialize, Eq, Ord>, <Deserialize, Eq, Ord>,
BTreeSetVisitor, BTreeSetVisitor,
@@ -381,7 +389,7 @@ set_impl!(
BTreeSet::insert); BTreeSet::insert);
#[cfg(feature = "nightly")] #[cfg(feature = "nightly")]
set_impl!( seq_impl!(
EnumSet<T>, EnumSet<T>,
<Deserialize, CLike>, <Deserialize, CLike>,
EnumSetVisitor, EnumSetVisitor,
@@ -390,7 +398,7 @@ set_impl!(
EnumSet::new(), EnumSet::new(),
EnumSet::insert); EnumSet::insert);
set_impl!( seq_impl!(
LinkedList<T>, LinkedList<T>,
<Deserialize>, <Deserialize>,
LinkedListVisitor, LinkedListVisitor,
@@ -399,7 +407,7 @@ set_impl!(
LinkedList::new(), LinkedList::new(),
LinkedList::push_back); LinkedList::push_back);
set_impl!( seq_impl!(
HashSet<T>, HashSet<T>,
<Deserialize, Eq, Hash>, <Deserialize, Eq, Hash>,
HashSetVisitor, HashSetVisitor,
@@ -408,7 +416,7 @@ set_impl!(
HashSet::with_capacity(visitor.size_hint().0), HashSet::with_capacity(visitor.size_hint().0),
HashSet::insert); HashSet::insert);
set_impl!( seq_impl!(
Vec<T>, Vec<T>,
<Deserialize>, <Deserialize>,
VecVisitor, VecVisitor,
@@ -417,7 +425,7 @@ set_impl!(
Vec::with_capacity(visitor.size_hint().0), Vec::with_capacity(visitor.size_hint().0),
Vec::push); Vec::push);
set_impl!( seq_impl!(
VecDeque<T>, VecDeque<T>,
<Deserialize>, <Deserialize>,
VecDequeVisitor, VecDequeVisitor,
@@ -433,6 +441,7 @@ struct ArrayVisitor0<T> {
} }
impl<T> ArrayVisitor0<T> { impl<T> ArrayVisitor0<T> {
/// Construct a `ArrayVisitor0<T>`.
pub fn new() -> Self { pub fn new() -> Self {
ArrayVisitor0 { ArrayVisitor0 {
marker: PhantomData, marker: PhantomData,
@@ -477,6 +486,7 @@ macro_rules! array_impls {
} }
impl<T> $visitor<T> { impl<T> $visitor<T> {
/// Construct a `ArrayVisitor*<T>`.
pub fn new() -> Self { pub fn new() -> Self {
$visitor { $visitor {
marker: PhantomData marker: PhantomData
@@ -566,6 +576,7 @@ macro_rules! tuple_impls {
() => {}; () => {};
($($len:expr => $visitor:ident => ($($name:ident),+),)+) => { ($($len:expr => $visitor:ident => ($($name:ident),+),)+) => {
$( $(
/// Construct a tuple visitor.
pub struct $visitor<$($name,)+> { pub struct $visitor<$($name,)+> {
marker: PhantomData<($($name,)+)>, marker: PhantomData<($($name,)+)>,
} }
@@ -573,6 +584,7 @@ macro_rules! tuple_impls {
impl< impl<
$($name: Deserialize,)+ $($name: Deserialize,)+
> $visitor<$($name,)+> { > $visitor<$($name,)+> {
/// Construct a `TupleVisitor*<T>`.
pub fn new() -> Self { pub fn new() -> Self {
$visitor { marker: PhantomData } $visitor { marker: PhantomData }
} }
@@ -643,11 +655,13 @@ macro_rules! map_impl {
$with_capacity:expr, $with_capacity:expr,
$insert:expr $insert:expr
) => { ) => {
/// A visitor that produces a map.
pub struct $visitor_name<K, V> { pub struct $visitor_name<K, V> {
marker: PhantomData<$ty>, marker: PhantomData<$ty>,
} }
impl<K, V> $visitor_name<K, V> { impl<K, V> $visitor_name<K, V> {
/// Construct a `MapVisitor*<T>`.
pub fn new() -> Self { pub fn new() -> Self {
$visitor_name { $visitor_name {
marker: PhantomData, marker: PhantomData,
+112 -18
View File
@@ -34,40 +34,100 @@ pub trait Error: Sized {
/// `Type` represents all the primitive types that can be deserialized. This is used by /// `Type` represents all the primitive types that can be deserialized. This is used by
/// `Error::kind_mismatch`. /// `Error::kind_mismatch`.
pub enum Type { pub enum Type {
/// Represents a `bool` type.
Bool, Bool,
/// Represents a `usize` type.
Usize, Usize,
/// Represents a `u8` type.
U8, U8,
/// Represents a `u16` type.
U16, U16,
/// Represents a `u32` type.
U32, U32,
/// Represents a `u64` type.
U64, U64,
/// Represents a `isize` type.
Isize, Isize,
/// Represents a `i8` type.
I8, I8,
/// Represents a `i16` type.
I16, I16,
/// Represents a `i32` type.
I32, I32,
/// Represents a `i64` type.
I64, I64,
/// Represents a `f32` type.
F32, F32,
/// Represents a `f64` type.
F64, F64,
/// Represents a `char` type.
Char, Char,
/// Represents a `&str` type.
Str, Str,
/// Represents a `String` type.
String, String,
/// Represents a `()` type.
Unit, Unit,
/// Represents an `Option<T>` type.
Option, Option,
/// Represents a sequence type.
Seq, Seq,
/// Represents a map type.
Map, Map,
/// Represents a unit struct type.
UnitStruct, UnitStruct,
/// Represents a newtype type.
NewtypeStruct, NewtypeStruct,
/// Represents a tuple struct type.
TupleStruct, TupleStruct,
/// Represents a struct type.
Struct, Struct,
/// Represents a tuple type.
Tuple, Tuple,
/// Represents an `enum` type.
Enum, Enum,
/// Represents a struct variant.
StructVariant, StructVariant,
/// Represents a tuple variant.
TupleVariant, TupleVariant,
/// Represents a unit variant.
UnitVariant, UnitVariant,
/// Represents a `&[u8]` type.
Bytes, Bytes,
} }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
/// `Deserialize` represents a type that can be deserialized.
pub trait Deserialize: Sized { pub trait Deserialize: Sized {
/// Deserialize this value given this `Deserializer`. /// Deserialize this value given this `Deserializer`.
fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error> 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 /// supporting the `visit_*` types is that it does not allow for deserializing into a generic
/// `json::Value`-esque type. /// `json::Value`-esque type.
pub trait Deserializer { pub trait Deserializer {
/// The error type that can be returned if some error occurs during deserialization.
type Error: Error; type Error: Error;
/// This method walks a visitor through a value as it is being deserialized. /// 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 { pub trait Visitor {
/// The value produced by this visitor.
type Value: Deserialize; type Value: Deserialize;
/// `visit_bool` deserializes a `bool` into a `Value`.
fn visit_bool<E>(&mut self, _v: bool) -> Result<Self::Value, E> fn visit_bool<E>(&mut self, _v: bool) -> Result<Self::Value, E>
where E: Error, where E: Error,
{ {
Err(Error::type_mismatch(Type::Bool)) 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> fn visit_isize<E>(&mut self, v: isize) -> Result<Self::Value, E>
where E: Error, where E: Error,
{ {
self.visit_i64(v as i64) 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> fn visit_i8<E>(&mut self, v: i8) -> Result<Self::Value, E>
where E: Error, where E: Error,
{ {
self.visit_i64(v as i64) 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> fn visit_i16<E>(&mut self, v: i16) -> Result<Self::Value, E>
where E: Error, where E: Error,
{ {
self.visit_i64(v as i64) 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> fn visit_i32<E>(&mut self, v: i32) -> Result<Self::Value, E>
where E: Error, where E: Error,
{ {
self.visit_i64(v as i64) 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> fn visit_i64<E>(&mut self, _v: i64) -> Result<Self::Value, E>
where E: Error, where E: Error,
{ {
Err(Error::type_mismatch(Type::I64)) 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> fn visit_usize<E>(&mut self, v: usize) -> Result<Self::Value, E>
where E: Error, where E: Error,
{ {
self.visit_u64(v as u64) 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> fn visit_u8<E>(&mut self, v: u8) -> Result<Self::Value, E>
where E: Error, where E: Error,
{ {
self.visit_u64(v as u64) 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> fn visit_u16<E>(&mut self, v: u16) -> Result<Self::Value, E>
where E: Error, where E: Error,
{ {
self.visit_u64(v as u64) 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> fn visit_u32<E>(&mut self, v: u32) -> Result<Self::Value, E>
where E: Error, where E: Error,
{ {
self.visit_u64(v as u64) 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> fn visit_u64<E>(&mut self, _v: u64) -> Result<Self::Value, E>
where E: Error, where E: Error,
{ {
Err(Error::type_mismatch(Type::U64)) 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> fn visit_f32<E>(&mut self, v: f32) -> Result<Self::Value, E>
where E: Error, where E: Error,
{ {
self.visit_f64(v as f64) 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> fn visit_f64<E>(&mut self, _v: f64) -> Result<Self::Value, E>
where E: Error, where E: Error,
{ {
Err(Error::type_mismatch(Type::F64)) Err(Error::type_mismatch(Type::F64))
} }
/// `visit_char` deserializes a `char` into a `Value`.
#[inline] #[inline]
fn visit_char<E>(&mut self, v: char) -> Result<Self::Value, E> fn visit_char<E>(&mut self, v: char) -> Result<Self::Value, E>
where E: Error, where E: Error,
@@ -439,12 +516,14 @@ pub trait Visitor {
self.visit_string(v.to_string()) 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> fn visit_str<E>(&mut self, _v: &str) -> Result<Self::Value, E>
where E: Error, where E: Error,
{ {
Err(Error::type_mismatch(Type::Str)) Err(Error::type_mismatch(Type::Str))
} }
/// `visit_string` deserializes a `String` into a `Value`.
#[inline] #[inline]
fn visit_string<E>(&mut self, v: String) -> Result<Self::Value, E> fn visit_string<E>(&mut self, v: String) -> Result<Self::Value, E>
where E: Error, where E: Error,
@@ -452,12 +531,14 @@ pub trait Visitor {
self.visit_str(&v) self.visit_str(&v)
} }
/// `visit_unit` deserializes a `()` into a `Value`.
fn visit_unit<E>(&mut self) -> Result<Self::Value, E> fn visit_unit<E>(&mut self) -> Result<Self::Value, E>
where E: Error, where E: Error,
{ {
Err(Error::type_mismatch(Type::Unit)) Err(Error::type_mismatch(Type::Unit))
} }
/// `visit_unit_struct` deserializes a unit struct into a `Value`.
#[inline] #[inline]
fn visit_unit_struct<E>(&mut self, _name: &'static str) -> Result<Self::Value, E> fn visit_unit_struct<E>(&mut self, _name: &'static str) -> Result<Self::Value, E>
where E: Error, where E: Error,
@@ -465,42 +546,49 @@ pub trait Visitor {
self.visit_unit() self.visit_unit()
} }
/// `visit_none` deserializes a none value into a `Value`.
fn visit_none<E>(&mut self) -> Result<Self::Value, E> fn visit_none<E>(&mut self) -> Result<Self::Value, E>
where E: Error, where E: Error,
{ {
Err(Error::type_mismatch(Type::Option)) 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> fn visit_some<D>(&mut self, _deserializer: &mut D) -> Result<Self::Value, D::Error>
where D: Deserializer, where D: Deserializer,
{ {
Err(Error::type_mismatch(Type::Option)) 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> fn visit_newtype_struct<D>(&mut self, _deserializer: &mut D) -> Result<Self::Value, D::Error>
where D: Deserializer, where D: Deserializer,
{ {
Err(Error::type_mismatch(Type::NewtypeStruct)) 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> fn visit_seq<V>(&mut self, _visitor: V) -> Result<Self::Value, V::Error>
where V: SeqVisitor, where V: SeqVisitor,
{ {
Err(Error::type_mismatch(Type::Seq)) 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> fn visit_map<V>(&mut self, _visitor: V) -> Result<Self::Value, V::Error>
where V: MapVisitor, where V: MapVisitor,
{ {
Err(Error::type_mismatch(Type::Map)) 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> fn visit_bytes<E>(&mut self, _v: &[u8]) -> Result<Self::Value, E>
where E: Error, where E: Error,
{ {
Err(Error::type_mismatch(Type::Bytes)) 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> fn visit_byte_buf<E>(&mut self, v: Vec<u8>) -> Result<Self::Value, E>
where E: Error, 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 { pub trait SeqVisitor {
/// The error type that can be returned if some error occurs during deserialization.
type Error: Error; 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> fn visit<T>(&mut self) -> Result<Option<T>, Self::Error>
where T: Deserialize; where T: Deserialize;
/// This signals to the `SeqVisitor` that the `Visitor` does not expect any more items.
fn end(&mut self) -> Result<(), Self::Error>; fn end(&mut self) -> Result<(), Self::Error>;
/// Return the lower and upper bound of items remaining in the sequence.
#[inline] #[inline]
fn size_hint(&self) -> (usize, Option<usize>) { fn size_hint(&self) -> (usize, Option<usize>) {
(0, None) (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 { pub trait MapVisitor {
/// The error type that can be returned if some error occurs during deserialization.
type Error: Error; 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] #[inline]
fn visit<K, V>(&mut self) -> Result<Option<(K, V)>, Self::Error> fn visit<K, V>(&mut self) -> Result<Option<(K, V)>, Self::Error>
where K: Deserialize, 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> fn visit_key<K>(&mut self) -> Result<Option<K>, Self::Error>
where K: Deserialize; 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> fn visit_value<V>(&mut self) -> Result<V, Self::Error>
where V: Deserialize; where V: Deserialize;
/// This signals to the `MapVisitor` that the `Visitor` does not expect any more items.
fn end(&mut self) -> Result<(), Self::Error>; fn end(&mut self) -> Result<(), Self::Error>;
/// Return the lower and upper bound of items remaining in the sequence.
#[inline] #[inline]
fn size_hint(&self) -> (usize, Option<usize>) { fn size_hint(&self) -> (usize, Option<usize>) {
(0, None) (0, None)
} }
/// Report that there
fn missing_field<V>(&mut self, field: &'static str) -> Result<V, Self::Error> fn missing_field<V>(&mut self, field: &'static str) -> Result<V, Self::Error>
where V: Deserialize, 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 /// `EnumVisitor` is a visitor that is created by the `Deserialize` and passed to the
/// `Deserializer` in order to deserialize enums. /// `Deserializer` in order to deserialize enums.
pub trait EnumVisitor { pub trait EnumVisitor {
/// The value produced by this visitor.
type Value; type Value;
/// Visit the specific variant with the `VariantVisitor`.
fn visit<V>(&mut self, visitor: V) -> Result<Self::Value, V::Error> fn visit<V>(&mut self, visitor: V) -> Result<Self::Value, V::Error>
where V: VariantVisitor; where V: VariantVisitor;
} }
@@ -636,6 +747,7 @@ pub trait EnumVisitor {
/// `VariantVisitor` is a visitor that is created by the `Deserializer` and passed to the /// `VariantVisitor` is a visitor that is created by the `Deserializer` and passed to the
/// `Deserialize` in order to deserialize a specific enum variant. /// `Deserialize` in order to deserialize a specific enum variant.
pub trait VariantVisitor { pub trait VariantVisitor {
/// The error type that can be returned if some error occurs during deserialization.
type Error: Error; type Error: Error;
/// `visit_variant` is called to identify which variant to deserialize. /// `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) (**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;
}
+20
View File
@@ -1,3 +1,5 @@
//! This module supports deserializing from primitives with the `ValueDeserializer` trait.
use std::collections::{ use std::collections::{
BTreeMap, BTreeMap,
BTreeSet, BTreeSet,
@@ -16,11 +18,19 @@ use bytes;
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
/// This represents all the possible errors that can occur using the `ValueDeserializer`.
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub enum Error { pub enum Error {
/// The value had some syntatic error.
SyntaxError, SyntaxError,
/// EOF while deserializing a value.
EndOfStreamError, EndOfStreamError,
/// Unknown field in struct.
UnknownFieldError(String), UnknownFieldError(String),
/// Struct is missing a field.
MissingFieldError(&'static str), MissingFieldError(&'static str),
} }
@@ -33,9 +43,12 @@ impl de::Error for Error {
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
/// This trait converts primitive types into a deserializer.
pub trait ValueDeserializer { pub trait ValueDeserializer {
/// The actual deserializer type.
type Deserializer: de::Deserializer<Error=Error>; type Deserializer: de::Deserializer<Error=Error>;
/// Convert this value into a deserializer.
fn into_deserializer(self) -> Self::Deserializer; fn into_deserializer(self) -> Self::Deserializer;
} }
@@ -72,6 +85,7 @@ impl de::Deserializer for UnitDeserializer {
macro_rules! primitive_deserializer { macro_rules! primitive_deserializer {
($ty:ty, $name:ident, $method:ident) => { ($ty:ty, $name:ident, $method:ident) => {
/// A helper deserializer that deserializes a number.
pub struct $name(Option<$ty>); pub struct $name(Option<$ty>);
impl ValueDeserializer for $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> { pub struct SeqDeserializer<I> {
iter: I, iter: I,
len: usize, len: usize,
} }
impl<I> SeqDeserializer<I> { impl<I> SeqDeserializer<I> {
/// Construct a new `SeqDeserializer<I>`.
pub fn new(iter: I, len: usize) -> Self { pub fn new(iter: I, len: usize) -> Self {
SeqDeserializer { SeqDeserializer {
iter: iter, 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> pub struct MapDeserializer<I, K, V>
where I: Iterator<Item=(K, V)>, where I: Iterator<Item=(K, V)>,
K: ValueDeserializer, K: ValueDeserializer,
@@ -323,6 +340,7 @@ impl<I, K, V> MapDeserializer<I, K, V>
K: ValueDeserializer, K: ValueDeserializer,
V: ValueDeserializer, V: ValueDeserializer,
{ {
/// Construct a new `MapDeserializer<I, K, V>`.
pub fn new(iter: I, len: usize) -> Self { pub fn new(iter: I, len: usize) -> Self {
MapDeserializer { MapDeserializer {
iter: iter, 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]>); pub struct BytesDeserializer<'a> (Option<&'a [u8]>);
impl<'a> de::Deserializer for BytesDeserializer<'a> { 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>>); pub struct ByteBufDeserializer(Option<Vec<u8>>);
impl de::Deserializer for ByteBufDeserializer { impl de::Deserializer for ByteBufDeserializer {
+4
View File
@@ -1,6 +1,9 @@
//! Module that contains helper iterators.
use std::io; use std::io;
use std::iter::Peekable; 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>>> { pub struct LineColIterator<Iter: Iterator<Item=io::Result<u8>>> {
iter: Iter, iter: Iter,
line: usize, line: usize,
@@ -8,6 +11,7 @@ pub struct LineColIterator<Iter: Iterator<Item=io::Result<u8>>> {
} }
impl<Iter: Iterator<Item=io::Result<u8>>> LineColIterator<Iter> { impl<Iter: Iterator<Item=io::Result<u8>>> LineColIterator<Iter> {
/// Construct a new `LineColIterator<Iter>`.
pub fn new(iter: Iter) -> LineColIterator<Iter> { pub fn new(iter: Iter) -> LineColIterator<Iter> {
LineColIterator { LineColIterator {
iter: iter, iter: iter,
+6
View File
@@ -5,9 +5,15 @@
//! handshake protocol between serializers and serializees can be completely optimized away, //! 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 //! leaving serde to perform roughly the same speed as a hand written serializer for a specific
//! type. //! 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")] #![doc(html_root_url="https://serde-rs.github.io/serde/serde")]
#![cfg_attr(feature = "nightly", feature(collections, core, enumset, nonzero, step_trait, zero_one))] #![cfg_attr(feature = "nightly", feature(collections, core, enumset, nonzero, step_trait, zero_one))]
#![deny(missing_docs)]
extern crate num; extern crate num;
#[cfg(feature = "nightly")] #[cfg(feature = "nightly")]
+49
View File
@@ -1,3 +1,5 @@
//! Implementations for all of Rust's builtin types.
use std::borrow::Cow; use std::borrow::Cow;
use std::collections::{ use std::collections::{
BinaryHeap, 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> { pub struct SeqIteratorVisitor<Iter> {
iter: Iter, iter: Iter,
len: Option<usize>, len: Option<usize>,
@@ -125,6 +148,7 @@ pub struct SeqIteratorVisitor<Iter> {
impl<T, Iter> SeqIteratorVisitor<Iter> impl<T, Iter> SeqIteratorVisitor<Iter>
where Iter: Iterator<Item=T> where Iter: Iterator<Item=T>
{ {
/// Construct a new `SeqIteratorVisitor<Iter>`.
#[inline] #[inline]
pub fn new(iter: Iter, len: Option<usize>) -> SeqIteratorVisitor<Iter> { pub fn new(iter: Iter, len: Option<usize>) -> SeqIteratorVisitor<Iter> {
SeqIteratorVisitor { SeqIteratorVisitor {
@@ -332,12 +356,14 @@ macro_rules! tuple_impls {
} }
)+) => { )+) => {
$( $(
/// A tuple visitor.
pub struct $TupleVisitor<'a, $($T: 'a),+> { pub struct $TupleVisitor<'a, $($T: 'a),+> {
tuple: &'a ($($T,)+), tuple: &'a ($($T,)+),
state: u8, state: u8,
} }
impl<'a, $($T: 'a),+> $TupleVisitor<'a, $($T),+> { impl<'a, $($T: 'a),+> $TupleVisitor<'a, $($T),+> {
/// Construct a new, empty `TupleVisitor`.
pub fn new(tuple: &'a ($($T,)+)) -> $TupleVisitor<'a, $($T),+> { pub fn new(tuple: &'a ($($T,)+)) -> $TupleVisitor<'a, $($T),+> {
$TupleVisitor { $TupleVisitor {
tuple: tuple, 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> { pub struct MapIteratorVisitor<Iter> {
iter: Iter, iter: Iter,
len: Option<usize>, len: Option<usize>,
@@ -497,6 +545,7 @@ pub struct MapIteratorVisitor<Iter> {
impl<K, V, Iter> MapIteratorVisitor<Iter> impl<K, V, Iter> MapIteratorVisitor<Iter>
where Iter: Iterator<Item=(K, V)> where Iter: Iterator<Item=(K, V)>
{ {
/// Construct a new `MapIteratorVisitor<Iter>`.
#[inline] #[inline]
pub fn new(iter: Iter, len: Option<usize>) -> MapIteratorVisitor<Iter> { pub fn new(iter: Iter, len: Option<usize>) -> MapIteratorVisitor<Iter> {
MapIteratorVisitor { MapIteratorVisitor {
+63
View File
@@ -4,14 +4,18 @@ pub mod impls;
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
/// A trait that describes a type that can be serialized by a `Serializer`.
pub trait Serialize { pub trait Serialize {
/// Serializes this value into this serializer.
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error> fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
where S: Serializer; where S: Serializer;
} }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
/// A trait that describes a type that can serialize a stream of values into the underlying format.
pub trait Serializer { pub trait Serializer {
/// The error type that can be returned if some error occurs during serialization.
type Error; type Error;
/// `visit_bool` serializes a `bool` value. /// `visit_bool` serializes a `bool` value.
@@ -110,13 +114,20 @@ pub trait Serializer {
self.visit_seq(impls::SeqIteratorVisitor::new(value.iter(), Some(value.len()))) self.visit_seq(impls::SeqIteratorVisitor::new(value.iter(), Some(value.len())))
} }
/// Serializes a `()` value.
fn visit_unit(&mut self) -> Result<(), Self::Error>; fn visit_unit(&mut self) -> Result<(), Self::Error>;
/// Serializes a unit struct value.
///
/// By default, unit structs are serialized as a `()`.
#[inline] #[inline]
fn visit_unit_struct(&mut self, _name: &'static str) -> Result<(), Self::Error> { fn visit_unit_struct(&mut self, _name: &'static str) -> Result<(), Self::Error> {
self.visit_unit() self.visit_unit()
} }
/// Serializes a unit variant, otherwise known as a variant with no arguments.
///
/// By default, unit variants are serialized as a `()`.
#[inline] #[inline]
fn visit_unit_variant(&mut self, fn visit_unit_variant(&mut self,
_name: &'static str, _name: &'static str,
@@ -155,17 +166,27 @@ pub trait Serializer {
Some(value)) Some(value))
} }
/// Serializes a `None` value.
fn visit_none(&mut self) -> Result<(), Self::Error>; fn visit_none(&mut self) -> Result<(), Self::Error>;
/// Serializes a `Some(...)` value.
fn visit_some<V>(&mut self, value: V) -> Result<(), Self::Error> fn visit_some<V>(&mut self, value: V) -> Result<(), Self::Error>
where V: Serialize; 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> fn visit_seq<V>(&mut self, visitor: V) -> Result<(), Self::Error>
where V: SeqVisitor; where V: SeqVisitor;
/// Serializes a sequence element.
fn visit_seq_elt<T>(&mut self, value: T) -> Result<(), Self::Error> fn visit_seq_elt<T>(&mut self, value: T) -> Result<(), Self::Error>
where T: Serialize; where T: Serialize;
/// Serializes a tuple.
///
/// By default this serializes a tuple as a sequence.
#[inline] #[inline]
fn visit_tuple<V>(&mut self, visitor: V) -> Result<(), Self::Error> fn visit_tuple<V>(&mut self, visitor: V) -> Result<(), Self::Error>
where V: SeqVisitor, where V: SeqVisitor,
@@ -173,6 +194,9 @@ pub trait Serializer {
self.visit_seq(visitor) self.visit_seq(visitor)
} }
/// Serializes a tuple element.
///
/// By default, tuples are serialized as a sequence.
#[inline] #[inline]
fn visit_tuple_elt<T>(&mut self, value: T) -> Result<(), Self::Error> fn visit_tuple_elt<T>(&mut self, value: T) -> Result<(), Self::Error>
where T: Serialize where T: Serialize
@@ -180,6 +204,9 @@ pub trait Serializer {
self.visit_seq_elt(value) self.visit_seq_elt(value)
} }
/// Serializes a tuple struct.
///
/// By default, tuple structs are serialized as a tuple.
#[inline] #[inline]
fn visit_tuple_struct<V>(&mut self, fn visit_tuple_struct<V>(&mut self,
_name: &'static str, _name: &'static str,
@@ -189,6 +216,9 @@ pub trait Serializer {
self.visit_tuple(visitor) self.visit_tuple(visitor)
} }
/// Serializes a tuple struct element.
///
/// By default, tuple struct elements are serialized as a tuple element.
#[inline] #[inline]
fn visit_tuple_struct_elt<T>(&mut self, value: T) -> Result<(), Self::Error> fn visit_tuple_struct_elt<T>(&mut self, value: T) -> Result<(), Self::Error>
where T: Serialize where T: Serialize
@@ -196,6 +226,9 @@ pub trait Serializer {
self.visit_tuple_elt(value) self.visit_tuple_elt(value)
} }
/// Serializes a tuple variant.
///
/// By default, tuple variants are serialized as a tuple struct.
#[inline] #[inline]
fn visit_tuple_variant<V>(&mut self, fn visit_tuple_variant<V>(&mut self,
_name: &'static str, _name: &'static str,
@@ -207,6 +240,9 @@ pub trait Serializer {
self.visit_tuple_struct(variant, visitor) self.visit_tuple_struct(variant, visitor)
} }
/// Serializes a tuple element.
///
/// By default, tuples are serialized as a sequence.
#[inline] #[inline]
fn visit_tuple_variant_elt<T>(&mut self, value: T) -> Result<(), Self::Error> fn visit_tuple_variant_elt<T>(&mut self, value: T) -> Result<(), Self::Error>
where T: Serialize where T: Serialize
@@ -214,13 +250,21 @@ pub trait Serializer {
self.visit_tuple_struct_elt(value) 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> fn visit_map<V>(&mut self, visitor: V) -> Result<(), Self::Error>
where V: MapVisitor; 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> fn visit_map_elt<K, V>(&mut self, key: K, value: V) -> Result<(), Self::Error>
where K: Serialize, where K: Serialize,
V: Serialize; V: Serialize;
/// Serializes a struct.
///
/// By default, structs are serialized as a map with the field name as the key.
#[inline] #[inline]
fn visit_struct<V>(&mut self, fn visit_struct<V>(&mut self,
_name: &'static str, _name: &'static str,
@@ -230,6 +274,9 @@ pub trait Serializer {
self.visit_map(visitor) 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] #[inline]
fn visit_struct_elt<V>(&mut self, fn visit_struct_elt<V>(&mut self,
key: &'static str, key: &'static str,
@@ -239,6 +286,9 @@ pub trait Serializer {
self.visit_map_elt(key, value) self.visit_map_elt(key, value)
} }
/// Serializes a struct variant.
///
/// By default, struct variants are serialized as a struct.
#[inline] #[inline]
fn visit_struct_variant<V>(&mut self, fn visit_struct_variant<V>(&mut self,
_name: &'static str, _name: &'static str,
@@ -250,6 +300,9 @@ pub trait Serializer {
self.visit_struct(variant, visitor) self.visit_struct(variant, visitor)
} }
/// Serializes an element of a struct variant.
///
/// By default, struct variant elements are serialized as a struct element.
#[inline] #[inline]
fn visit_struct_variant_elt<V>(&mut self, fn visit_struct_variant_elt<V>(&mut self,
key: &'static str, 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 { 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> fn visit<S>(&mut self, serializer: &mut S) -> Result<Option<()>, S::Error>
where S: Serializer; 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 { 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> fn visit<S>(&mut self, serializer: &mut S) -> Result<Option<()>, S::Error>
where S: Serializer; where S: Serializer;
+8 -8
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "serde_codegen" name = "serde_codegen"
version = "0.5.3" version = "0.6.1"
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"] authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
license = "MIT/Apache-2.0" license = "MIT/Apache-2.0"
description = "Macros to auto-generate implementations for the serde framework" 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"] with-syntex = ["quasi/with-syntex", "quasi_codegen", "quasi_codegen/with-syntex", "syntex", "syntex_syntax"]
[build-dependencies] [build-dependencies]
quasi_codegen = { verision = "*", optional = true } quasi_codegen = { verision = "^0.3.4", optional = true }
syntex = { version = "*", optional = true } syntex = { version = "^0.18.0", optional = true }
[dependencies] [dependencies]
aster = { version = "*", default-features = false } aster = { version = "^0.5.0", default-features = false }
quasi = { verision = "*", default-features = false } quasi = { verision = "^0.3.5", default-features = false }
quasi_macros = { version = "*", optional = true } quasi_macros = { version = "^0.3.5", optional = true }
syntex = { version = "*", optional = true } syntex = { version = "^0.17.0", optional = true }
syntex_syntax = { version = "*", optional = true } syntex_syntax = { version = "^0.18.0", optional = true }
+168 -43
View File
@@ -2,10 +2,14 @@ use std::collections::HashMap;
use std::collections::HashSet; use std::collections::HashSet;
use syntax::ast; use syntax::ast;
use syntax::attr;
use syntax::ext::base::ExtCtxt; use syntax::ext::base::ExtCtxt;
use syntax::ptr::P; use syntax::ptr::P;
use aster;
/// Represents field name information /// Represents field name information
#[derive(Debug)]
pub enum FieldNames { pub enum FieldNames {
Global(P<ast::Expr>), Global(P<ast::Expr>),
Format{ Format{
@@ -15,43 +19,16 @@ pub enum FieldNames {
} }
/// Represents field attribute information /// Represents field attribute information
#[derive(Debug)]
pub struct FieldAttrs { pub struct FieldAttrs {
skip_serializing_field: bool, skip_serializing_field: bool,
skip_serializing_field_if_empty: bool,
skip_serializing_field_if_none: bool,
names: FieldNames, names: FieldNames,
use_default: bool, use_default: bool,
} }
impl FieldAttrs { 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. /// Return a set of formats that the field has attributes for.
pub fn formats(&self) -> HashSet<P<ast::Expr>> { pub fn formats(&self) -> HashSet<P<ast::Expr>> {
match self.names { match self.names {
@@ -70,22 +47,21 @@ impl FieldAttrs {
/// ///
/// The resulting expression assumes that `S` refers to a type /// The resulting expression assumes that `S` refers to a type
/// that implements `Serializer`. /// 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 { match self.names {
FieldNames::Global(x) => x, FieldNames::Global(ref name) => name.clone(),
FieldNames::Format{formats, default} => { FieldNames::Format { ref formats, ref default } => {
let arms = formats.iter() let arms = formats.iter()
.map(|(fmt, lit)| { .map(|(fmt, lit)| {
quote_arm!(cx, $fmt => { $lit }) quote_arm!(cx, $fmt => { $lit })
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
quote_expr!(cx, quote_expr!(cx,
{ match S::format() {
match S::format() { $arms
$arms _ => { $default }
_ => { $default } }
} )
})
}, },
} }
} }
@@ -94,17 +70,17 @@ impl FieldAttrs {
pub fn default_key_expr(&self) -> &P<ast::Expr> { pub fn default_key_expr(&self) -> &P<ast::Expr> {
match self.names { match self.names {
FieldNames::Global(ref expr) => expr, 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. /// Return the field name for the field in the specified format.
pub fn key_expr(&self, format: &P<ast::Expr>) -> &P<ast::Expr> { pub fn key_expr(&self, format: &P<ast::Expr>) -> &P<ast::Expr> {
match self.names { match self.names {
FieldNames::Global(ref expr) => FieldNames::Global(ref expr) => expr,
expr, FieldNames::Format { ref formats, ref default } => {
FieldNames::Format{ref formats, ref default} =>
formats.get(format).unwrap_or(default) formats.get(format).unwrap_or(default)
}
} }
} }
@@ -117,4 +93,153 @@ impl FieldAttrs {
pub fn skip_serializing_field(&self) -> bool { pub fn skip_serializing_field(&self) -> bool {
self.skip_serializing_field 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 -64
View File
@@ -4,12 +4,11 @@ use aster;
use syntax::ast::{ use syntax::ast::{
self, self,
Ident,
MetaItem,
Item,
Expr,
StructDef,
EnumDef, EnumDef,
Expr,
Ident,
Item,
MetaItem,
}; };
use syntax::codemap::Span; use syntax::codemap::Span;
use syntax::ext::base::{Annotatable, ExtCtxt}; use syntax::ext::base::{Annotatable, ExtCtxt};
@@ -87,14 +86,14 @@ fn deserialize_body(
ty: P<ast::Ty>, ty: P<ast::Ty>,
) -> P<ast::Expr> { ) -> P<ast::Expr> {
match item.node { match item.node {
ast::ItemStruct(ref struct_def, _) => { ast::ItemStruct(ref variant_data, _) => {
deserialize_item_struct( deserialize_item_struct(
cx, cx,
builder, builder,
item, item,
impl_generics, impl_generics,
ty, ty,
struct_def, variant_data,
) )
} }
ast::ItemEnum(ref enum_def, _) => { ast::ItemEnum(ref enum_def, _) => {
@@ -117,27 +116,17 @@ fn deserialize_item_struct(
item: &Item, item: &Item,
impl_generics: &ast::Generics, impl_generics: &ast::Generics,
ty: P<ast::Ty>, ty: P<ast::Ty>,
struct_def: &ast::StructDef, variant_data: &ast::VariantData,
) -> P<ast::Expr> { ) -> P<ast::Expr> {
let mut named_fields = vec![]; match *variant_data {
let mut unnamed_fields = 0; ast::VariantData::Unit(_) => {
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) => {
deserialize_unit_struct( deserialize_unit_struct(
cx, cx,
&builder, &builder,
item.ident, item.ident,
) )
} }
(true, 1) => { ast::VariantData::Tuple(ref fields, _) if fields.len() == 1 => {
deserialize_newtype_struct( deserialize_newtype_struct(
cx, cx,
&builder, &builder,
@@ -146,29 +135,34 @@ fn deserialize_item_struct(
ty, 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( deserialize_tuple_struct(
cx, cx,
&builder, &builder,
item.ident, item.ident,
impl_generics, impl_generics,
ty, 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( deserialize_struct(
cx, cx,
&builder, &builder,
item.ident, item.ident,
impl_generics, impl_generics,
ty, ty,
struct_def, fields,
) )
} }
(false, _) => {
cx.bug("struct has named and unnamed fields")
}
} }
} }
@@ -422,9 +416,9 @@ fn deserialize_struct_as_seq(
cx: &ExtCtxt, cx: &ExtCtxt,
builder: &aster::AstBuilder, builder: &aster::AstBuilder,
struct_path: ast::Path, struct_path: ast::Path,
struct_def: &StructDef, fields: &[ast::StructField],
) -> P<ast::Expr> { ) -> 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| { .map(|i| {
let name = builder.id(format!("__field{}", i)); let name = builder.id(format!("__field{}", i));
quote_stmt!(cx, quote_stmt!(cx,
@@ -440,13 +434,13 @@ fn deserialize_struct_as_seq(
let result = builder.expr().struct_path(struct_path) let result = builder.expr().struct_path(struct_path)
.with_id_exprs( .with_id_exprs(
struct_def.fields.iter() fields.iter()
.enumerate() .enumerate()
.map(|(i, field)| { .map(|(i, field)| {
( (
match field.node.kind { match field.node.kind {
ast::NamedField(name, _) => name.clone(), 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)), builder.expr().id(format!("__field{}", i)),
) )
@@ -469,7 +463,7 @@ fn deserialize_struct(
type_ident: Ident, type_ident: Ident,
impl_generics: &ast::Generics, impl_generics: &ast::Generics,
ty: P<ast::Ty>, ty: P<ast::Ty>,
struct_def: &StructDef, fields: &[ast::StructField],
) -> P<ast::Expr> { ) -> P<ast::Expr> {
let where_clause = &impl_generics.where_clause; let where_clause = &impl_generics.where_clause;
@@ -486,14 +480,14 @@ fn deserialize_struct(
cx, cx,
builder, builder,
type_path.clone(), type_path.clone(),
struct_def fields,
); );
let (field_visitor, fields_stmt, visit_map_expr) = deserialize_struct_visitor( let (field_visitor, fields_stmt, visit_map_expr) = deserialize_struct_visitor(
cx, cx,
builder, builder,
struct_def, type_path.clone(),
type_path.clone() fields,
); );
let type_name = builder.expr().str(type_ident); let type_name = builder.expr().str(type_ident);
@@ -543,11 +537,13 @@ fn deserialize_item_enum(
cx, cx,
builder, builder,
enum_def.variants.iter() enum_def.variants.iter()
.map(|variant| .map(|variant| {
attr::FieldAttrs::new( let expr = builder.expr().str(variant.node.name);
false, attr::FieldAttrsBuilder::new(builder)
true, .name(expr)
builder.expr().str(variant.node.name))) .default()
.build()
})
.collect() .collect()
); );
@@ -591,7 +587,7 @@ fn deserialize_item_enum(
impl_generics, impl_generics,
vec![deserializer_ty_param(builder)], vec![deserializer_ty_param(builder)],
vec![deserializer_ty_arg(builder)], vec![deserializer_ty_arg(builder)],
); );
quote_expr!(cx, { quote_expr!(cx, {
$variant_visitor $variant_visitor
@@ -626,20 +622,20 @@ fn deserialize_variant(
) -> P<ast::Expr> { ) -> P<ast::Expr> {
let variant_ident = variant.node.name; let variant_ident = variant.node.name;
match variant.node.kind { match *variant.node.data {
ast::TupleVariantKind(ref args) if args.is_empty() => { ast::VariantData::Unit(_) => {
quote_expr!(cx, { quote_expr!(cx, {
try!(visitor.visit_unit()); try!(visitor.visit_unit());
Ok($type_ident::$variant_ident) 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, { quote_expr!(cx, {
let val = try!(visitor.visit_newtype()); let val = try!(visitor.visit_newtype());
Ok($type_ident::$variant_ident(val)) Ok($type_ident::$variant_ident(val))
}) })
} }
ast::TupleVariantKind(ref args) => { ast::VariantData::Tuple(ref fields, _) => {
deserialize_tuple_variant( deserialize_tuple_variant(
cx, cx,
builder, builder,
@@ -647,10 +643,10 @@ fn deserialize_variant(
variant_ident, variant_ident,
generics, generics,
ty, ty,
args.len(), fields.len(),
) )
} }
ast::StructVariantKind(ref struct_def) => { ast::VariantData::Struct(ref fields, _) => {
deserialize_struct_variant( deserialize_struct_variant(
cx, cx,
builder, builder,
@@ -658,7 +654,7 @@ fn deserialize_variant(
variant_ident, variant_ident,
generics, generics,
ty, ty,
struct_def, fields,
) )
} }
} }
@@ -681,7 +677,7 @@ fn deserialize_tuple_variant(
generics, generics,
vec![deserializer_ty_param(builder)], vec![deserializer_ty_param(builder)],
vec![deserializer_ty_arg(builder)], vec![deserializer_ty_arg(builder)],
); );
let visit_seq_expr = deserialize_seq( let visit_seq_expr = deserialize_seq(
cx, cx,
@@ -714,7 +710,7 @@ fn deserialize_struct_variant(
variant_ident: ast::Ident, variant_ident: ast::Ident,
generics: &ast::Generics, generics: &ast::Generics,
ty: P<ast::Ty>, ty: P<ast::Ty>,
struct_def: &ast::StructDef, fields: &[ast::StructField],
) -> P<ast::Expr> { ) -> P<ast::Expr> {
let where_clause = &generics.where_clause; let where_clause = &generics.where_clause;
@@ -727,14 +723,14 @@ fn deserialize_struct_variant(
cx, cx,
builder, builder,
type_path.clone(), type_path.clone(),
struct_def fields,
); );
let (field_visitor, fields_stmt, field_expr) = deserialize_struct_visitor( let (field_visitor, fields_stmt, field_expr) = deserialize_struct_visitor(
cx, cx,
builder, builder,
struct_def, type_path,
type_path fields,
); );
let (visitor_item, visitor_ty, visitor_expr, visitor_generics) = let (visitor_item, visitor_ty, visitor_expr, visitor_generics) =
@@ -743,7 +739,7 @@ fn deserialize_struct_variant(
generics, generics,
vec![deserializer_ty_param(builder)], vec![deserializer_ty_param(builder)],
vec![deserializer_ty_arg(builder)], vec![deserializer_ty_arg(builder)],
); );
quote_expr!(cx, { quote_expr!(cx, {
$field_visitor $field_visitor
@@ -789,7 +785,7 @@ fn deserialize_field_visitor(
.enum_("__Field") .enum_("__Field")
.with_variants( .with_variants(
field_idents.iter().map(|field_ident| { field_idents.iter().map(|field_ident| {
builder.variant(field_ident).tuple().build() builder.variant(field_ident).unit()
}) })
) )
.build(); .build();
@@ -925,25 +921,25 @@ fn deserialize_field_visitor(
fn deserialize_struct_visitor( fn deserialize_struct_visitor(
cx: &ExtCtxt, cx: &ExtCtxt,
builder: &aster::AstBuilder, builder: &aster::AstBuilder,
struct_def: &ast::StructDef,
struct_path: ast::Path, struct_path: ast::Path,
fields: &[ast::StructField],
) -> (Vec<P<ast::Item>>, P<ast::Stmt>, P<ast::Expr>) { ) -> (Vec<P<ast::Item>>, P<ast::Stmt>, P<ast::Expr>) {
let field_visitor = deserialize_field_visitor( let field_visitor = deserialize_field_visitor(
cx, cx,
builder, builder,
field::struct_field_attrs(cx, builder, struct_def), field::struct_field_attrs(cx, builder, fields),
); );
let visit_map_expr = deserialize_map( let visit_map_expr = deserialize_map(
cx, cx,
builder, builder,
struct_path, struct_path,
struct_def, fields,
); );
let fields_expr = builder.expr().addr_of().slice() let fields_expr = builder.expr().addr_of().slice()
.with_exprs( .with_exprs(
struct_def.fields.iter() fields.iter()
.map(|field| { .map(|field| {
match field.node.kind { match field.node.kind {
ast::NamedField(name, _) => builder.expr().str(name), ast::NamedField(name, _) => builder.expr().str(name),
@@ -964,10 +960,10 @@ fn deserialize_map(
cx: &ExtCtxt, cx: &ExtCtxt,
builder: &aster::AstBuilder, builder: &aster::AstBuilder,
struct_path: ast::Path, struct_path: ast::Path,
struct_def: &StructDef, fields: &[ast::StructField],
) -> P<ast::Expr> { ) -> P<ast::Expr> {
// Create the field names for the fields. // 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))) .map(|i| builder.id(format!("__field{}", i)))
.collect(); .collect();
@@ -988,7 +984,7 @@ fn deserialize_map(
.collect(); .collect();
let extract_values: Vec<P<ast::Stmt>> = field_names.iter() 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)| { .map(|(field_name, field_attr)| {
let missing_expr = if field_attr.use_default() { let missing_expr = if field_attr.use_default() {
quote_expr!(cx, ::std::default::Default::default()) quote_expr!(cx, ::std::default::Default::default())
@@ -1025,7 +1021,7 @@ fn deserialize_map(
let result = builder.expr().struct_path(struct_path) let result = builder.expr().struct_path(struct_path)
.with_id_exprs( .with_id_exprs(
struct_def.fields.iter() fields.iter()
.zip(field_names.iter()) .zip(field_names.iter())
.map(|(field, field_name)| { .map(|(field, field_name)| {
( (
+7 -137
View File
@@ -1,147 +1,17 @@
use std::collections::HashMap; use syntax::ast;
use syntax::ext::base::ExtCtxt;
use aster; use aster;
use attr::{FieldAttrs, FieldAttrsBuilder};
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))
}
pub fn struct_field_attrs( pub fn struct_field_attrs(
cx: &ExtCtxt, _cx: &ExtCtxt,
builder: &aster::AstBuilder, builder: &aster::AstBuilder,
struct_def: &ast::StructDef, fields: &[ast::StructField],
) -> Vec<FieldAttrs> { ) -> Vec<FieldAttrs> {
struct_def.fields.iter() fields.iter()
.map(|field| { .map(|field| {
match field_attrs(builder, field) { FieldAttrsBuilder::new(builder).field(field).build()
(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))
}
}
}) })
.collect() .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")
}
}
}
+90 -67
View File
@@ -5,7 +5,6 @@ use syntax::ast::{
MetaItem, MetaItem,
Item, Item,
Expr, Expr,
StructDef,
}; };
use syntax::ast; use syntax::ast;
use syntax::codemap::Span; use syntax::codemap::Span;
@@ -82,14 +81,14 @@ fn serialize_body(
ty: P<ast::Ty>, ty: P<ast::Ty>,
) -> P<ast::Expr> { ) -> P<ast::Expr> {
match item.node { match item.node {
ast::ItemStruct(ref struct_def, _) => { ast::ItemStruct(ref variant_data, _) => {
serialize_item_struct( serialize_item_struct(
cx, cx,
builder, builder,
item, item,
impl_generics, impl_generics,
ty, ty,
struct_def, variant_data,
) )
} }
ast::ItemEnum(ref enum_def, _) => { ast::ItemEnum(ref enum_def, _) => {
@@ -112,57 +111,51 @@ fn serialize_item_struct(
item: &Item, item: &Item,
impl_generics: &ast::Generics, impl_generics: &ast::Generics,
ty: P<ast::Ty>, ty: P<ast::Ty>,
struct_def: &ast::StructDef, variant_data: &ast::VariantData,
) -> P<ast::Expr> { ) -> P<ast::Expr> {
let mut named_fields = vec![]; match *variant_data {
let mut unnamed_fields = 0; ast::VariantData::Unit(_) => {
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) => {
serialize_unit_struct( serialize_unit_struct(
cx, cx,
&builder, &builder,
item.ident, item.ident,
) )
} }
(true, 1) => { ast::VariantData::Tuple(ref fields, _) if fields.len() == 1 => {
serialize_newtype_struct( serialize_newtype_struct(
cx, cx,
&builder, &builder,
item.ident, 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( serialize_tuple_struct(
cx, cx,
&builder, &builder,
item.ident, item.ident,
impl_generics, impl_generics,
ty, 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( serialize_struct(
cx, cx,
&builder, &builder,
item.ident, item.ident,
impl_generics, impl_generics,
ty, ty,
struct_def, fields,
named_fields,
) )
} }
(false, _) => {
cx.bug("struct has named and unnamed fields")
}
} }
} }
@@ -225,8 +218,7 @@ fn serialize_struct(
type_ident: Ident, type_ident: Ident,
impl_generics: &ast::Generics, impl_generics: &ast::Generics,
ty: P<ast::Ty>, ty: P<ast::Ty>,
struct_def: &StructDef, fields: &[ast::StructField],
fields: Vec<Ident>,
) -> P<ast::Expr> { ) -> P<ast::Expr> {
let (visitor_struct, visitor_impl) = serialize_struct_visitor( let (visitor_struct, visitor_impl) = serialize_struct_visitor(
cx, cx,
@@ -236,9 +228,12 @@ fn serialize_struct(
.ref_() .ref_()
.lifetime("'__a") .lifetime("'__a")
.build_ty(ty.clone()), .build_ty(ty.clone()),
struct_def, fields,
impl_generics, 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); let type_name = builder.expr().str(type_ident);
@@ -297,8 +292,8 @@ fn serialize_variant(
let variant_ident = variant.node.name; let variant_ident = variant.node.name;
let variant_name = builder.expr().str(variant_ident); let variant_name = builder.expr().str(variant_ident);
match variant.node.kind { match *variant.node.data {
ast::TupleVariantKind(ref args) if args.is_empty() => { ast::VariantData::Unit(_) => {
let pat = builder.pat().enum_() let pat = builder.pat().enum_()
.id(type_ident).id(variant_ident).build() .id(type_ident).id(variant_ident).build()
.build(); .build();
@@ -314,7 +309,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.id("__simple_value");
let field = builder.pat().ref_id(field); let field = builder.pat().ref_id(field);
let pat = builder.pat().enum_() let pat = builder.pat().enum_()
@@ -333,14 +328,17 @@ fn serialize_variant(
} }
) )
}, },
ast::TupleVariantKind(ref args) => { ast::VariantData::Tuple(ref fields, _) => {
let fields: Vec<ast::Ident> = (0 .. args.len()) let field_names: Vec<ast::Ident> = (0 .. fields.len())
.map(|i| builder.id(format!("__field{}", i))) .map(|i| builder.id(format!("__field{}", i)))
.collect(); .collect();
let pat = builder.pat().enum_() let pat = builder.pat().enum_()
.id(type_ident).id(variant_ident).build() .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(); .build();
let expr = serialize_tuple_variant( let expr = serialize_tuple_variant(
@@ -351,22 +349,22 @@ fn serialize_variant(
variant_name, variant_name,
generics, generics,
ty, ty,
args,
fields, fields,
field_names,
); );
quote_arm!(cx, $pat => { $expr }) quote_arm!(cx, $pat => { $expr })
} }
ast::StructVariantKind(ref struct_def) => { ast::VariantData::Struct(ref fields, _) => {
let fields: Vec<_> = (0 .. struct_def.fields.len()) let field_names: Vec<_> = (0 .. fields.len())
.map(|i| builder.id(format!("__field{}", i))) .map(|i| builder.id(format!("__field{}", i)))
.collect(); .collect();
let pat = builder.pat().struct_() let pat = builder.pat().struct_()
.id(type_ident).id(variant_ident).build() .id(type_ident).id(variant_ident).build()
.with_pats( .with_pats(
fields.iter() field_names.iter()
.zip(struct_def.fields.iter()) .zip(fields.iter())
.map(|(id, field)| { .map(|(id, field)| {
let name = match field.node.kind { let name = match field.node.kind {
ast::NamedField(name, _) => name, ast::NamedField(name, _) => name,
@@ -388,8 +386,8 @@ fn serialize_variant(
variant_name, variant_name,
generics, generics,
ty, ty,
struct_def,
fields, fields,
field_names,
); );
quote_arm!(cx, $pat => { $expr }) quote_arm!(cx, $pat => { $expr })
@@ -405,16 +403,16 @@ fn serialize_tuple_variant(
variant_name: P<ast::Expr>, variant_name: P<ast::Expr>,
generics: &ast::Generics, generics: &ast::Generics,
structure_ty: P<ast::Ty>, structure_ty: P<ast::Ty>,
args: &[ast::VariantArg], fields: &[ast::StructField],
fields: Vec<Ident>, field_names: Vec<Ident>,
) -> P<ast::Expr> { ) -> P<ast::Expr> {
let variant_ty = builder.ty().tuple() let variant_ty = builder.ty().tuple()
.with_tys( .with_tys(
args.iter().map(|arg| { fields.iter().map(|field| {
builder.ty() builder.ty()
.ref_() .ref_()
.lifetime("'__a") .lifetime("'__a")
.build_ty(arg.ty.clone()) .build_ty(field.node.ty.clone())
}) })
) )
.build(); .build();
@@ -424,13 +422,13 @@ fn serialize_tuple_variant(
builder, builder,
structure_ty.clone(), structure_ty.clone(),
variant_ty, variant_ty,
args.len(), fields.len(),
generics, generics,
); );
let value_expr = builder.expr().tuple() let value_expr = builder.expr().tuple()
.with_exprs( .with_exprs(
fields.iter().map(|field| { field_names.iter().map(|field| {
builder.expr().id(field) builder.expr().id(field)
}) })
) )
@@ -455,12 +453,12 @@ fn serialize_struct_variant(
variant_name: P<ast::Expr>, variant_name: P<ast::Expr>,
generics: &ast::Generics, generics: &ast::Generics,
structure_ty: P<ast::Ty>, structure_ty: P<ast::Ty>,
struct_def: &ast::StructDef, fields: &[ast::StructField],
fields: Vec<Ident>, field_names: Vec<Ident>,
) -> P<ast::Expr> { ) -> P<ast::Expr> {
let value_ty = builder.ty().tuple() let value_ty = builder.ty().tuple()
.with_tys( .with_tys(
struct_def.fields.iter().map(|field| { fields.iter().map(|field| {
builder.ty() builder.ty()
.ref_() .ref_()
.lifetime("'__a") .lifetime("'__a")
@@ -471,7 +469,7 @@ fn serialize_struct_variant(
let value_expr = builder.expr().tuple() let value_expr = builder.expr().tuple()
.with_exprs( .with_exprs(
fields.iter().map(|field| { field_names.iter().map(|field| {
builder.expr().id(field) builder.expr().id(field)
}) })
) )
@@ -482,9 +480,9 @@ fn serialize_struct_variant(
builder, builder,
structure_ty.clone(), structure_ty.clone(),
value_ty, value_ty,
struct_def, fields,
generics, generics,
(0 .. fields.len()).map(|i| { (0 .. field_names.len()).map(|i| {
builder.expr() builder.expr()
.tup_field(i) .tup_field(i)
.field("value").self_() .field("value").self_()
@@ -574,29 +572,37 @@ fn serialize_struct_visitor<I>(
builder: &aster::AstBuilder, builder: &aster::AstBuilder,
structure_ty: P<ast::Ty>, structure_ty: P<ast::Ty>,
variant_ty: P<ast::Ty>, variant_ty: P<ast::Ty>,
struct_def: &StructDef, fields: &[ast::StructField],
generics: &ast::Generics, generics: &ast::Generics,
value_exprs: I, value_exprs: I,
) -> (P<ast::Item>, P<ast::Item>) ) -> (P<ast::Item>, P<ast::Item>)
where I: Iterator<Item=P<ast::Expr>>, 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() let field_attrs = struct_field_attrs(cx, builder, fields);
.fold(0, |sum, field| {
sum + if field.skip_serializing_field() { 1 } else { 0 }
});
let arms: Vec<ast::Arm> = field_attrs.into_iter() let arms: Vec<ast::Arm> = field_attrs.iter()
.zip(value_exprs) .zip(value_exprs.iter())
.filter(|&(ref field, _)| !field.skip_serializing_field()) .filter(|&(ref field, _)| !field.skip_serializing_field())
.enumerate() .enumerate()
.map(|(i, (field, value_expr))| { .map(|(i, (ref field, value_expr))| {
let key_expr = field.serializer_key_expr(cx); 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, quote_arm!(cx,
$i => { $i => {
self.state += 1; self.state += 1;
Ok( $stmt
return Ok(
Some( Some(
try!( try!(
serializer.visit_struct_elt( serializer.visit_struct_elt(
@@ -605,7 +611,7 @@ fn serialize_struct_visitor<I>(
) )
) )
) )
) );
} }
) )
}) })
@@ -622,6 +628,21 @@ fn serialize_struct_visitor<I>(
.strip_bounds() .strip_bounds()
.build(); .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, quote_item!(cx,
struct Visitor $visitor_impl_generics $where_clause { struct Visitor $visitor_impl_generics $where_clause {
@@ -640,9 +661,11 @@ fn serialize_struct_visitor<I>(
fn visit<S>(&mut self, serializer: &mut S) -> ::std::result::Result<Option<()>, S::Error> fn visit<S>(&mut self, serializer: &mut S) -> ::std::result::Result<Option<()>, S::Error>
where S: ::serde::ser::Serializer, where S: ::serde::ser::Serializer,
{ {
match self.state { loop {
$arms match self.state {
_ => Ok(None) $arms
_ => { return Ok(None); }
}
} }
} }
+3 -3
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "serde_macros" name = "serde_macros"
version = "0.5.3" version = "0.6.1"
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"] authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
license = "MIT/Apache-2.0" license = "MIT/Apache-2.0"
description = "Macros to auto-generate implementations for the serde framework" 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"] } serde_codegen = { version = "*", path = "../serde_codegen", default-features = false, features = ["nightly"] }
[dev-dependencies] [dev-dependencies]
num = "*" num = "^0.1.27"
rustc-serialize = "*" rustc-serialize = "^0.3.16"
serde = { version = "*", path = "../serde", features = ["nightly"] } serde = { version = "*", path = "../serde", features = ["nightly"] }
+172
View File
@@ -39,6 +39,20 @@ struct SkipSerializingFields<A: default::Default> {
b: A, 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] #[test]
fn test_default() { fn test_default() {
assert_de_tokens( 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,
]
);
}