mirror of
https://github.com/serde-rs/serde.git
synced 2025-10-02 15:25:38 +00:00
Merge pull request #238 from erickt/skip4
Add codegen expr magic for default, skip serializing, and alternative serializers
This commit is contained in:
commit
7adf624dee
43
README.md
43
README.md
@ -670,23 +670,36 @@ Annotations
|
|||||||
`serde_codegen` and `serde_macros` support annotations that help to customize
|
`serde_codegen` and `serde_macros` support annotations that help to customize
|
||||||
how types are serialized. Here are the supported annotations:
|
how types are serialized. Here are the supported annotations:
|
||||||
|
|
||||||
|
Container Annotations:
|
||||||
|
|
||||||
|
| Annotation | Function |
|
||||||
|
| ---------- | -------- |
|
||||||
|
| `#[serde(rename="name")` | Serialize and deserialize this container with the given name |
|
||||||
|
| `#[serde(rename(serialize="name1"))` | Serialize this container with the given name |
|
||||||
|
| `#[serde(rename(deserialize="name1"))` | Deserialize this container with the given name |
|
||||||
|
| `#[serde(deny_unknown_fields)` | Always error during serialization when encountering unknown fields. When absent, unknown fields are ignored for self-describing formats like JSON. |
|
||||||
|
|
||||||
|
Variant Annotations:
|
||||||
|
|
||||||
|
| Annotation | Function |
|
||||||
|
| ---------- | -------- |
|
||||||
|
| `#[serde(rename="name")` | Serialize and deserialize this variant with the given name |
|
||||||
|
| `#[serde(rename(serialize="name1"))` | Serialize this variant with the given name |
|
||||||
|
| `#[serde(rename(deserialize="name1"))` | Deserialize this variant with the given name |
|
||||||
|
|
||||||
Field Annotations:
|
Field Annotations:
|
||||||
|
|
||||||
| Annotation | Function |
|
| Annotation | Function |
|
||||||
| ---------- | -------- |
|
| ---------- | -------- |
|
||||||
| `#[serde(rename(json="name1", xml="name2"))` | Serialize this field with the given name for the given formats |
|
| `#[serde(rename="name")` | Serialize and deserialize this field with the given name |
|
||||||
| `#[serde(default)` | If the value is not specified, use the `Default::default()` |
|
| `#[serde(rename(serialize="name1"))` | Serialize this field with the given name |
|
||||||
| `#[serde(rename="name")` | Serialize this field with the given name |
|
| `#[serde(rename(deserialize="name1"))` | Deserialize this field with the given name |
|
||||||
| `#[serde(skip_serializing)` | Do not serialize this value |
|
| `#[serde(default)` | If the value is not specified, use the `Default::default()` |
|
||||||
| `#[serde(skip_serializing_if_empty)` | Do not serialize this value if `$value.is_empty()` is `true` |
|
| `#[serde(default="$path")` | Call the path to a function `fn() -> T` to build the value |
|
||||||
| `#[serde(skip_serializing_if_none)` | Do not serialize this value if `$value.is_none()` is `true` |
|
| `#[serde(skip_serializing)` | Do not serialize this value |
|
||||||
|
| `#[serde(skip_serializing_if="$path")` | Do not serialize this value if this function `fn(&T) -> bool` returns `false` |
|
||||||
Structure Annotations:
|
| `#[serde(serialize_with="$path")` | Call a function `fn<T, S>(&T, &mut S) -> Result<(), S::Error> where S: Serializer` to serialize this value |
|
||||||
|
| `#[serde(deserialize_with="$path")` | Call a function `fn<T, D>(&mut D) -> Result<T, D::Error> where D: Deserializer` to deserialize this value |
|
||||||
| Annotation | Function |
|
|
||||||
| ---------- | -------- |
|
|
||||||
| `#[serde(deny_unknown_fields)` | Always error during serialization when encountering unknown fields. When absent, unknown fields are ignored for self-describing formats like JSON. |
|
|
||||||
|
|
||||||
|
|
||||||
Serialization Formats Using Serde
|
Serialization Formats Using Serde
|
||||||
=================================
|
=================================
|
||||||
|
@ -1,7 +1,13 @@
|
|||||||
use syntax::ast;
|
use std::rc::Rc;
|
||||||
|
use syntax::ast::{self, TokenTree};
|
||||||
use syntax::attr;
|
use syntax::attr;
|
||||||
|
use syntax::codemap::Span;
|
||||||
use syntax::ext::base::ExtCtxt;
|
use syntax::ext::base::ExtCtxt;
|
||||||
use syntax::print::pprust::meta_item_to_string;
|
use syntax::fold::Folder;
|
||||||
|
use syntax::parse::parser::PathParsingMode;
|
||||||
|
use syntax::parse::token;
|
||||||
|
use syntax::parse;
|
||||||
|
use syntax::print::pprust::{lit_to_string, meta_item_to_string};
|
||||||
use syntax::ptr::P;
|
use syntax::ptr::P;
|
||||||
|
|
||||||
use aster::AstBuilder;
|
use aster::AstBuilder;
|
||||||
@ -165,14 +171,21 @@ pub struct FieldAttrs {
|
|||||||
serialize_name: Option<ast::Lit>,
|
serialize_name: Option<ast::Lit>,
|
||||||
deserialize_name: Option<ast::Lit>,
|
deserialize_name: Option<ast::Lit>,
|
||||||
skip_serializing_field: bool,
|
skip_serializing_field: bool,
|
||||||
skip_serializing_field_if_empty: bool,
|
skip_serializing_field_if: Option<P<ast::Expr>>,
|
||||||
skip_serializing_field_if_none: bool,
|
default_expr_if_missing: Option<P<ast::Expr>>,
|
||||||
use_default: bool,
|
serialize_with: Option<P<ast::Expr>>,
|
||||||
|
deserialize_with: Option<P<ast::Expr>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FieldAttrs {
|
impl FieldAttrs {
|
||||||
/// Extract out the `#[serde(...)]` attributes from a struct field.
|
/// Extract out the `#[serde(...)]` attributes from a struct field.
|
||||||
pub fn from_field(cx: &ExtCtxt, field: &ast::StructField) -> Result<Self, Error> {
|
pub fn from_field(cx: &ExtCtxt,
|
||||||
|
container_ty: &P<ast::Ty>,
|
||||||
|
generics: &ast::Generics,
|
||||||
|
field: &ast::StructField,
|
||||||
|
is_enum: bool) -> Result<Self, Error> {
|
||||||
|
let builder = AstBuilder::new();
|
||||||
|
|
||||||
let field_ident = match field.node.ident() {
|
let field_ident = match field.node.ident() {
|
||||||
Some(ident) => ident,
|
Some(ident) => ident,
|
||||||
None => { cx.span_bug(field.span, "struct field has no name?") }
|
None => { cx.span_bug(field.span, "struct field has no name?") }
|
||||||
@ -183,9 +196,10 @@ impl FieldAttrs {
|
|||||||
serialize_name: None,
|
serialize_name: None,
|
||||||
deserialize_name: None,
|
deserialize_name: None,
|
||||||
skip_serializing_field: false,
|
skip_serializing_field: false,
|
||||||
skip_serializing_field_if_empty: false,
|
skip_serializing_field_if: None,
|
||||||
skip_serializing_field_if_none: false,
|
default_expr_if_missing: None,
|
||||||
use_default: false,
|
serialize_with: None,
|
||||||
|
deserialize_with: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
for meta_items in field.node.attrs.iter().filter_map(get_serde_meta_items) {
|
for meta_items in field.node.attrs.iter().filter_map(get_serde_meta_items) {
|
||||||
@ -206,7 +220,17 @@ impl FieldAttrs {
|
|||||||
|
|
||||||
// Parse `#[serde(default)]`
|
// Parse `#[serde(default)]`
|
||||||
ast::MetaItemKind::Word(ref name) if name == &"default" => {
|
ast::MetaItemKind::Word(ref name) if name == &"default" => {
|
||||||
field_attrs.use_default = true;
|
let default_expr = builder.expr().default();
|
||||||
|
field_attrs.default_expr_if_missing = Some(default_expr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse `#[serde(default="...")]`
|
||||||
|
ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"default" => {
|
||||||
|
let wrapped_expr = wrap_default(
|
||||||
|
try!(parse_lit_into_path(cx, name, lit)),
|
||||||
|
);
|
||||||
|
|
||||||
|
field_attrs.default_expr_if_missing = Some(wrapped_expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse `#[serde(skip_serializing)]`
|
// Parse `#[serde(skip_serializing)]`
|
||||||
@ -214,14 +238,41 @@ impl FieldAttrs {
|
|||||||
field_attrs.skip_serializing_field = true;
|
field_attrs.skip_serializing_field = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse `#[serde(skip_serializing_if_none)]`
|
// Parse `#[serde(skip_serializing_if="...")]`
|
||||||
ast::MetaItemKind::Word(ref name) if name == &"skip_serializing_if_none" => {
|
ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"skip_serializing_if" => {
|
||||||
field_attrs.skip_serializing_field_if_none = true;
|
let expr = wrap_skip_serializing(
|
||||||
|
field_ident,
|
||||||
|
try!(parse_lit_into_path(cx, name, lit)),
|
||||||
|
is_enum,
|
||||||
|
);
|
||||||
|
|
||||||
|
field_attrs.skip_serializing_field_if = Some(expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse `#[serde(skip_serializing_if_empty)]`
|
// Parse `#[serde(serialize_with="...")]`
|
||||||
ast::MetaItemKind::Word(ref name) if name == &"skip_serializing_if_empty" => {
|
ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"serialize_with" => {
|
||||||
field_attrs.skip_serializing_field_if_empty = true;
|
let expr = wrap_serialize_with(
|
||||||
|
cx,
|
||||||
|
container_ty,
|
||||||
|
generics,
|
||||||
|
field_ident,
|
||||||
|
try!(parse_lit_into_path(cx, name, lit)),
|
||||||
|
is_enum,
|
||||||
|
);
|
||||||
|
|
||||||
|
field_attrs.serialize_with = Some(expr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse `#[serde(deserialize_with="...")]`
|
||||||
|
ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"deserialize_with" => {
|
||||||
|
let expr = wrap_deserialize_with(
|
||||||
|
cx,
|
||||||
|
&field.node.ty,
|
||||||
|
generics,
|
||||||
|
try!(parse_lit_into_path(cx, name, lit)),
|
||||||
|
);
|
||||||
|
|
||||||
|
field_attrs.deserialize_with = Some(expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
@ -261,8 +312,18 @@ impl FieldAttrs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Predicate for using a field's default value
|
/// Predicate for using a field's default value
|
||||||
pub fn use_default(&self) -> bool {
|
pub fn expr_is_missing(&self) -> P<ast::Expr> {
|
||||||
self.use_default
|
match self.default_expr_if_missing {
|
||||||
|
Some(ref expr) => expr.clone(),
|
||||||
|
None => {
|
||||||
|
let name = self.ident_expr();
|
||||||
|
AstBuilder::new().expr()
|
||||||
|
.try()
|
||||||
|
.method_call("missing_field").id("visitor")
|
||||||
|
.with_arg(name)
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Predicate for ignoring a field when serializing a value
|
/// Predicate for ignoring a field when serializing a value
|
||||||
@ -270,20 +331,28 @@ impl FieldAttrs {
|
|||||||
self.skip_serializing_field
|
self.skip_serializing_field
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn skip_serializing_field_if_empty(&self) -> bool {
|
pub fn skip_serializing_field_if(&self) -> Option<&P<ast::Expr>> {
|
||||||
self.skip_serializing_field_if_empty
|
self.skip_serializing_field_if.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn skip_serializing_field_if_none(&self) -> bool {
|
pub fn serialize_with(&self) -> Option<&P<ast::Expr>> {
|
||||||
self.skip_serializing_field_if_none
|
self.serialize_with.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deserialize_with(&self) -> Option<&P<ast::Expr>> {
|
||||||
|
self.deserialize_with.as_ref()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Extract out the `#[serde(...)]` attributes from a struct field.
|
/// Extract out the `#[serde(...)]` attributes from a struct field.
|
||||||
pub fn get_struct_field_attrs(cx: &ExtCtxt,
|
pub fn get_struct_field_attrs(cx: &ExtCtxt,
|
||||||
fields: &[ast::StructField]) -> Result<Vec<FieldAttrs>, Error> {
|
container_ty: &P<ast::Ty>,
|
||||||
|
generics: &ast::Generics,
|
||||||
|
fields: &[ast::StructField],
|
||||||
|
is_enum: bool) -> Result<Vec<FieldAttrs>, Error> {
|
||||||
fields.iter()
|
fields.iter()
|
||||||
.map(|field| FieldAttrs::from_field(cx, field))
|
.map(|field| FieldAttrs::from_field(cx, container_ty, generics, field, is_enum))
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -325,3 +394,239 @@ fn get_serde_meta_items(attr: &ast::Attribute) -> Option<&[P<ast::MetaItem>]> {
|
|||||||
_ => None
|
_ => None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This syntax folder rewrites tokens to say their spans are coming from a macro context.
|
||||||
|
struct Respanner<'a, 'b: 'a> {
|
||||||
|
cx: &'a ExtCtxt<'b>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b> Folder for Respanner<'a, 'b> {
|
||||||
|
fn fold_tt(&mut self, tt: &TokenTree) -> TokenTree {
|
||||||
|
match *tt {
|
||||||
|
TokenTree::Token(span, ref tok) => {
|
||||||
|
TokenTree::Token(
|
||||||
|
self.new_span(span),
|
||||||
|
self.fold_token(tok.clone())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
TokenTree::Delimited(span, ref delimed) => {
|
||||||
|
TokenTree::Delimited(
|
||||||
|
self.new_span(span),
|
||||||
|
Rc::new(ast::Delimited {
|
||||||
|
delim: delimed.delim,
|
||||||
|
open_span: delimed.open_span,
|
||||||
|
tts: self.fold_tts(&delimed.tts),
|
||||||
|
close_span: delimed.close_span,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
TokenTree::Sequence(span, ref seq) => {
|
||||||
|
TokenTree::Sequence(
|
||||||
|
self.new_span(span),
|
||||||
|
Rc::new(ast::SequenceRepetition {
|
||||||
|
tts: self.fold_tts(&seq.tts),
|
||||||
|
separator: seq.separator.clone().map(|tok| self.fold_token(tok)),
|
||||||
|
..**seq
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_span(&mut self, span: Span) -> Span {
|
||||||
|
Span {
|
||||||
|
lo: span.lo,
|
||||||
|
hi: span.hi,
|
||||||
|
expn_id: self.cx.backtrace(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_lit_into_path(cx: &ExtCtxt, name: &str, lit: &ast::Lit) -> Result<ast::Path, Error> {
|
||||||
|
let source: &str = match lit.node {
|
||||||
|
ast::LitKind::Str(ref source, _) => &source,
|
||||||
|
_ => {
|
||||||
|
cx.span_err(
|
||||||
|
lit.span,
|
||||||
|
&format!("serde annotation `{}` must be a string, not `{}`",
|
||||||
|
name,
|
||||||
|
lit_to_string(lit)));
|
||||||
|
|
||||||
|
return Err(Error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// If we just parse the string into an expression, any syntax errors in the source will only
|
||||||
|
// have spans that point inside the string, and not back to the attribute. So to have better
|
||||||
|
// error reporting, we'll first parse the string into a token tree. Then we'll update those
|
||||||
|
// spans to say they're coming from a macro context that originally came from the attribute,
|
||||||
|
// and then finally parse them into an expression.
|
||||||
|
let tts = parse::parse_tts_from_source_str(
|
||||||
|
format!("<serde {} expansion>", name),
|
||||||
|
source.to_owned(),
|
||||||
|
cx.cfg(),
|
||||||
|
cx.parse_sess());
|
||||||
|
|
||||||
|
// Respan the spans to say they are all coming from this macro.
|
||||||
|
let tts = Respanner { cx: cx }.fold_tts(&tts);
|
||||||
|
|
||||||
|
let mut parser = parse::new_parser_from_tts(cx.parse_sess(), cx.cfg(), tts);
|
||||||
|
|
||||||
|
let path = match parser.parse_path(PathParsingMode::LifetimeAndTypesWithoutColons) {
|
||||||
|
Ok(path) => path,
|
||||||
|
Err(mut e) => {
|
||||||
|
e.emit();
|
||||||
|
return Err(Error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Make sure to error out if there are trailing characters in the stream.
|
||||||
|
match parser.expect(&token::Eof) {
|
||||||
|
Ok(()) => { }
|
||||||
|
Err(mut e) => {
|
||||||
|
e.emit();
|
||||||
|
return Err(Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This function wraps the expression in `#[serde(default="...")]` in a function to prevent it
|
||||||
|
/// from accessing the internal `Deserialize` state.
|
||||||
|
fn wrap_default(path: ast::Path) -> P<ast::Expr> {
|
||||||
|
AstBuilder::new().expr().call()
|
||||||
|
.build_path(path)
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This function wraps the expression in `#[serde(skip_serializing_if="...")]` in a trait to
|
||||||
|
/// prevent it from accessing the internal `Serialize` state.
|
||||||
|
fn wrap_skip_serializing(field_ident: ast::Ident,
|
||||||
|
path: ast::Path,
|
||||||
|
is_enum: bool) -> P<ast::Expr> {
|
||||||
|
let builder = AstBuilder::new();
|
||||||
|
|
||||||
|
let expr = builder.expr()
|
||||||
|
.field(field_ident)
|
||||||
|
.field("value")
|
||||||
|
.self_();
|
||||||
|
|
||||||
|
let expr = if is_enum {
|
||||||
|
expr
|
||||||
|
} else {
|
||||||
|
builder.expr().ref_().build(expr)
|
||||||
|
};
|
||||||
|
|
||||||
|
builder.expr().call()
|
||||||
|
.build_path(path)
|
||||||
|
.arg().build(expr)
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This function wraps the expression in `#[serde(serialize_with="...")]` in a trait to
|
||||||
|
/// prevent it from accessing the internal `Serialize` state.
|
||||||
|
fn wrap_serialize_with(cx: &ExtCtxt,
|
||||||
|
container_ty: &P<ast::Ty>,
|
||||||
|
generics: &ast::Generics,
|
||||||
|
field_ident: ast::Ident,
|
||||||
|
path: ast::Path,
|
||||||
|
is_enum: bool) -> P<ast::Expr> {
|
||||||
|
let builder = AstBuilder::new();
|
||||||
|
|
||||||
|
let expr = builder.expr()
|
||||||
|
.field(field_ident)
|
||||||
|
.self_();
|
||||||
|
|
||||||
|
let expr = if is_enum {
|
||||||
|
expr
|
||||||
|
} else {
|
||||||
|
builder.expr().ref_().build(expr)
|
||||||
|
};
|
||||||
|
|
||||||
|
let expr = builder.expr().call()
|
||||||
|
.build_path(path)
|
||||||
|
.arg().build(expr)
|
||||||
|
.arg()
|
||||||
|
.id("serializer")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
let where_clause = &generics.where_clause;
|
||||||
|
|
||||||
|
quote_expr!(cx, {
|
||||||
|
trait __SerdeSerializeWith {
|
||||||
|
fn __serde_serialize_with<S>(&self, serializer: &mut S) -> Result<(), S::Error>
|
||||||
|
where S: ::serde::ser::Serializer;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> __SerdeSerializeWith for &'a T
|
||||||
|
where T: 'a + __SerdeSerializeWith,
|
||||||
|
{
|
||||||
|
fn __serde_serialize_with<S>(&self, serializer: &mut S) -> Result<(), S::Error>
|
||||||
|
where S: ::serde::ser::Serializer
|
||||||
|
{
|
||||||
|
(**self).__serde_serialize_with(serializer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl $generics __SerdeSerializeWith for $container_ty $where_clause {
|
||||||
|
fn __serde_serialize_with<S>(&self, serializer: &mut S) -> Result<(), S::Error>
|
||||||
|
where S: ::serde::ser::Serializer
|
||||||
|
{
|
||||||
|
$expr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct __SerdeSerializeWithStruct<'a, T: 'a> {
|
||||||
|
value: &'a T,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> ::serde::ser::Serialize for __SerdeSerializeWithStruct<'a, T>
|
||||||
|
where T: 'a + __SerdeSerializeWith
|
||||||
|
{
|
||||||
|
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
|
||||||
|
where S: ::serde::ser::Serializer
|
||||||
|
{
|
||||||
|
self.value.__serde_serialize_with(serializer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
__SerdeSerializeWithStruct {
|
||||||
|
value: &self.value,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This function wraps the expression in `#[serde(deserialize_with="...")]` in a trait to prevent
|
||||||
|
/// it from accessing the internal `Deserialize` state.
|
||||||
|
fn wrap_deserialize_with(cx: &ExtCtxt,
|
||||||
|
field_ty: &P<ast::Ty>,
|
||||||
|
generics: &ast::Generics,
|
||||||
|
path: ast::Path) -> P<ast::Expr> {
|
||||||
|
// Quasi-quoting doesn't do a great job of expanding generics into paths, so manually build it.
|
||||||
|
let ty_path = AstBuilder::new().path()
|
||||||
|
.segment("__SerdeDeserializeWithStruct")
|
||||||
|
.with_generics(generics.clone())
|
||||||
|
.build()
|
||||||
|
.build();
|
||||||
|
|
||||||
|
let where_clause = &generics.where_clause;
|
||||||
|
|
||||||
|
quote_expr!(cx, {
|
||||||
|
struct __SerdeDeserializeWithStruct $generics $where_clause {
|
||||||
|
value: $field_ty,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl $generics ::serde::de::Deserialize for $ty_path $where_clause {
|
||||||
|
fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error>
|
||||||
|
where D: ::serde::de::Deserializer
|
||||||
|
{
|
||||||
|
let value = try!($path(deserializer));
|
||||||
|
Ok(__SerdeDeserializeWithStruct { value: value })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let value: $ty_path = try!(visitor.visit_value());
|
||||||
|
Ok(value.value)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
@ -503,8 +503,11 @@ fn deserialize_struct(
|
|||||||
cx,
|
cx,
|
||||||
builder,
|
builder,
|
||||||
type_path.clone(),
|
type_path.clone(),
|
||||||
|
&ty,
|
||||||
|
impl_generics,
|
||||||
fields,
|
fields,
|
||||||
container_attrs
|
container_attrs,
|
||||||
|
false,
|
||||||
));
|
));
|
||||||
|
|
||||||
let type_name = container_attrs.deserialize_name_expr();
|
let type_name = container_attrs.deserialize_name_expr();
|
||||||
@ -756,8 +759,11 @@ fn deserialize_struct_variant(
|
|||||||
cx,
|
cx,
|
||||||
builder,
|
builder,
|
||||||
type_path,
|
type_path,
|
||||||
|
&ty,
|
||||||
|
generics,
|
||||||
fields,
|
fields,
|
||||||
container_attrs,
|
container_attrs,
|
||||||
|
true,
|
||||||
));
|
));
|
||||||
|
|
||||||
let (visitor_item, visitor_ty, visitor_expr, visitor_generics) = try!(deserialize_visitor(
|
let (visitor_item, visitor_ty, visitor_expr, visitor_generics) = try!(deserialize_visitor(
|
||||||
@ -918,20 +924,29 @@ fn deserialize_struct_visitor(
|
|||||||
cx: &ExtCtxt,
|
cx: &ExtCtxt,
|
||||||
builder: &aster::AstBuilder,
|
builder: &aster::AstBuilder,
|
||||||
struct_path: ast::Path,
|
struct_path: ast::Path,
|
||||||
|
container_ty: &P<ast::Ty>,
|
||||||
|
generics: &ast::Generics,
|
||||||
fields: &[ast::StructField],
|
fields: &[ast::StructField],
|
||||||
container_attrs: &attr::ContainerAttrs,
|
container_attrs: &attr::ContainerAttrs,
|
||||||
|
is_enum: bool,
|
||||||
) -> Result<(Vec<P<ast::Item>>, ast::Stmt, P<ast::Expr>), Error> {
|
) -> Result<(Vec<P<ast::Item>>, ast::Stmt, P<ast::Expr>), Error> {
|
||||||
|
let field_exprs = fields.iter()
|
||||||
|
.map(|field| {
|
||||||
|
let field_attrs = try!(
|
||||||
|
attr::FieldAttrs::from_field(cx,
|
||||||
|
container_ty,
|
||||||
|
generics,
|
||||||
|
field,
|
||||||
|
is_enum)
|
||||||
|
);
|
||||||
|
Ok(field_attrs.deserialize_name_expr())
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
let field_visitor = deserialize_field_visitor(
|
let field_visitor = deserialize_field_visitor(
|
||||||
cx,
|
cx,
|
||||||
builder,
|
builder,
|
||||||
try!(
|
try!(field_exprs),
|
||||||
fields.iter()
|
|
||||||
.map(|field| {
|
|
||||||
let attrs = try!(attr::FieldAttrs::from_field(cx, field));
|
|
||||||
Ok(attrs.deserialize_name_expr())
|
|
||||||
})
|
|
||||||
.collect()
|
|
||||||
),
|
|
||||||
container_attrs
|
container_attrs
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -939,8 +954,11 @@ fn deserialize_struct_visitor(
|
|||||||
cx,
|
cx,
|
||||||
builder,
|
builder,
|
||||||
struct_path,
|
struct_path,
|
||||||
|
container_ty,
|
||||||
|
generics,
|
||||||
fields,
|
fields,
|
||||||
container_attrs,
|
container_attrs,
|
||||||
|
is_enum,
|
||||||
));
|
));
|
||||||
|
|
||||||
let fields_expr = builder.expr().ref_().slice()
|
let fields_expr = builder.expr().ref_().slice()
|
||||||
@ -968,14 +986,23 @@ fn deserialize_map(
|
|||||||
cx: &ExtCtxt,
|
cx: &ExtCtxt,
|
||||||
builder: &aster::AstBuilder,
|
builder: &aster::AstBuilder,
|
||||||
struct_path: ast::Path,
|
struct_path: ast::Path,
|
||||||
|
container_ty: &P<ast::Ty>,
|
||||||
|
generics: &ast::Generics,
|
||||||
fields: &[ast::StructField],
|
fields: &[ast::StructField],
|
||||||
container_attrs: &attr::ContainerAttrs,
|
container_attrs: &attr::ContainerAttrs,
|
||||||
|
is_enum: bool,
|
||||||
) -> Result<P<ast::Expr>, Error> {
|
) -> Result<P<ast::Expr>, Error> {
|
||||||
// Create the field names for the fields.
|
// Create the field names for the fields.
|
||||||
let field_names: Vec<ast::Ident> = (0 .. 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();
|
||||||
|
|
||||||
|
let field_attrs: Vec<_> = try!(
|
||||||
|
fields.iter()
|
||||||
|
.map(|field| attr::FieldAttrs::from_field(cx, container_ty, generics, field, is_enum))
|
||||||
|
.collect()
|
||||||
|
);
|
||||||
|
|
||||||
// Declare each field.
|
// Declare each field.
|
||||||
let let_values: Vec<ast::Stmt> = field_names.iter()
|
let let_values: Vec<ast::Stmt> = field_names.iter()
|
||||||
.map(|field_name| quote_stmt!(cx, let mut $field_name = None;).unwrap())
|
.map(|field_name| quote_stmt!(cx, let mut $field_name = None;).unwrap())
|
||||||
@ -992,37 +1019,36 @@ fn deserialize_map(
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Match arms to extract a value for a field.
|
// Match arms to extract a value for a field.
|
||||||
let value_arms: Vec<ast::Arm> = field_names.iter()
|
let value_arms = field_attrs.iter().zip(field_names.iter())
|
||||||
.map(|field_name| {
|
.map(|(field_attr, field_name)| {
|
||||||
|
let expr = match field_attr.deserialize_with() {
|
||||||
|
Some(expr) => expr.clone(),
|
||||||
|
None => quote_expr!(cx, visitor.visit_value()),
|
||||||
|
};
|
||||||
|
|
||||||
quote_arm!(cx,
|
quote_arm!(cx,
|
||||||
__Field::$field_name => {
|
__Field::$field_name => {
|
||||||
$field_name = Some(try!(visitor.visit_value()));
|
$field_name = Some(try!($expr));
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.chain(ignored_arm.into_iter())
|
.chain(ignored_arm.into_iter())
|
||||||
.collect();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let field_attrs = try!(attr::get_struct_field_attrs(cx, fields));
|
let extract_values = field_attrs.iter().zip(field_names.iter())
|
||||||
|
.map(|(field_attr, field_name)| {
|
||||||
|
let missing_expr = field_attr.expr_is_missing();
|
||||||
|
|
||||||
let extract_values = field_names.iter()
|
Ok(quote_stmt!(cx,
|
||||||
.zip(field_attrs.iter())
|
|
||||||
.map(|(field_name, field_attr)| {
|
|
||||||
let missing_expr = if field_attr.use_default() {
|
|
||||||
quote_expr!(cx, ::std::default::Default::default())
|
|
||||||
} else {
|
|
||||||
let name = field_attr.ident_expr();
|
|
||||||
quote_expr!(cx, try!(visitor.missing_field($name)))
|
|
||||||
};
|
|
||||||
|
|
||||||
quote_stmt!(cx,
|
|
||||||
let $field_name = match $field_name {
|
let $field_name = match $field_name {
|
||||||
Some($field_name) => $field_name,
|
Some($field_name) => $field_name,
|
||||||
None => $missing_expr
|
None => $missing_expr
|
||||||
};
|
};
|
||||||
).unwrap()
|
).unwrap())
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Result<Vec<_>, _>>();
|
||||||
|
|
||||||
|
let extract_values = try!(extract_values);
|
||||||
|
|
||||||
let result = builder.expr().struct_path(struct_path)
|
let result = builder.expr().struct_path(struct_path)
|
||||||
.with_id_exprs(
|
.with_id_exprs(
|
||||||
|
@ -33,14 +33,30 @@ pub fn expand_derive_serialize(
|
|||||||
|
|
||||||
let builder = aster::AstBuilder::new().span(span);
|
let builder = aster::AstBuilder::new().span(span);
|
||||||
|
|
||||||
|
let impl_item = match serialize_item(cx, &builder, &item) {
|
||||||
|
Ok(item) => item,
|
||||||
|
Err(Error) => {
|
||||||
|
// An error occured, but it should have been reported already.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
push(Annotatable::Item(impl_item))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_item(
|
||||||
|
cx: &ExtCtxt,
|
||||||
|
builder: &aster::AstBuilder,
|
||||||
|
item: &Item,
|
||||||
|
) -> Result<P<ast::Item>, Error> {
|
||||||
let generics = match item.node {
|
let generics = match item.node {
|
||||||
ast::ItemKind::Struct(_, ref generics) => generics,
|
ast::ItemKind::Struct(_, ref generics) => generics,
|
||||||
ast::ItemKind::Enum(_, ref generics) => generics,
|
ast::ItemKind::Enum(_, ref generics) => generics,
|
||||||
_ => {
|
_ => {
|
||||||
cx.span_err(
|
cx.span_err(
|
||||||
meta_item.span,
|
item.span,
|
||||||
"`#[derive(Serialize)]` may only be applied to structs and enums");
|
"`#[derive(Serialize)]` may only be applied to structs and enums");
|
||||||
return;
|
return Err(Error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -54,17 +70,15 @@ pub fn expand_derive_serialize(
|
|||||||
.segment(item.ident).with_generics(impl_generics.clone()).build()
|
.segment(item.ident).with_generics(impl_generics.clone()).build()
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
let body = match serialize_body(cx, &builder, &item, &impl_generics, ty.clone()) {
|
let body = try!(serialize_body(cx,
|
||||||
Ok(body) => body,
|
&builder,
|
||||||
Err(Error) => {
|
&item,
|
||||||
// An error occured, but it should have been reported already.
|
&impl_generics,
|
||||||
return;
|
ty.clone()));
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let where_clause = &impl_generics.where_clause;
|
let where_clause = &impl_generics.where_clause;
|
||||||
|
|
||||||
let impl_item = quote_item!(cx,
|
Ok(quote_item!(cx,
|
||||||
impl $impl_generics ::serde::ser::Serialize for $ty $where_clause {
|
impl $impl_generics ::serde::ser::Serialize for $ty $where_clause {
|
||||||
fn serialize<__S>(&self, serializer: &mut __S) -> ::std::result::Result<(), __S::Error>
|
fn serialize<__S>(&self, serializer: &mut __S) -> ::std::result::Result<(), __S::Error>
|
||||||
where __S: ::serde::ser::Serializer,
|
where __S: ::serde::ser::Serializer,
|
||||||
@ -72,9 +86,7 @@ pub fn expand_derive_serialize(
|
|||||||
$body
|
$body
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
).unwrap();
|
).unwrap())
|
||||||
|
|
||||||
push(Annotatable::Item(impl_item))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_body(
|
fn serialize_body(
|
||||||
@ -207,6 +219,7 @@ fn serialize_tuple_struct(
|
|||||||
.ref_()
|
.ref_()
|
||||||
.lifetime("'__a")
|
.lifetime("'__a")
|
||||||
.build_ty(ty.clone()),
|
.build_ty(ty.clone()),
|
||||||
|
builder.id("serialize_tuple_struct_elt"),
|
||||||
fields,
|
fields,
|
||||||
impl_generics,
|
impl_generics,
|
||||||
);
|
);
|
||||||
@ -232,11 +245,6 @@ fn serialize_struct(
|
|||||||
fields: &[ast::StructField],
|
fields: &[ast::StructField],
|
||||||
container_attrs: &attr::ContainerAttrs,
|
container_attrs: &attr::ContainerAttrs,
|
||||||
) -> Result<P<ast::Expr>, Error> {
|
) -> Result<P<ast::Expr>, Error> {
|
||||||
let value_exprs = fields.iter().map(|field| {
|
|
||||||
let name = field.node.ident().expect("struct has unnamed field");
|
|
||||||
quote_expr!(cx, &self.value.$name)
|
|
||||||
});
|
|
||||||
|
|
||||||
let (visitor_struct, visitor_impl) = try!(serialize_struct_visitor(
|
let (visitor_struct, visitor_impl) = try!(serialize_struct_visitor(
|
||||||
cx,
|
cx,
|
||||||
builder,
|
builder,
|
||||||
@ -245,9 +253,10 @@ fn serialize_struct(
|
|||||||
.ref_()
|
.ref_()
|
||||||
.lifetime("'__a")
|
.lifetime("'__a")
|
||||||
.build_ty(ty.clone()),
|
.build_ty(ty.clone()),
|
||||||
|
builder.id("serialize_struct_elt"),
|
||||||
fields,
|
fields,
|
||||||
impl_generics,
|
impl_generics,
|
||||||
value_exprs,
|
false,
|
||||||
));
|
));
|
||||||
|
|
||||||
let type_name = container_attrs.serialize_name_expr();
|
let type_name = container_attrs.serialize_name_expr();
|
||||||
@ -272,22 +281,23 @@ fn serialize_item_enum(
|
|||||||
enum_def: &ast::EnumDef,
|
enum_def: &ast::EnumDef,
|
||||||
container_attrs: &attr::ContainerAttrs,
|
container_attrs: &attr::ContainerAttrs,
|
||||||
) -> Result<P<ast::Expr>, Error> {
|
) -> Result<P<ast::Expr>, Error> {
|
||||||
let mut arms = vec![];
|
let arms: Vec<_> = try!(
|
||||||
|
enum_def.variants.iter()
|
||||||
for (variant_index, variant) in enum_def.variants.iter().enumerate() {
|
.enumerate()
|
||||||
let arm = try!(serialize_variant(
|
.map(|(variant_index, variant)| {
|
||||||
cx,
|
serialize_variant(
|
||||||
builder,
|
cx,
|
||||||
type_ident,
|
builder,
|
||||||
impl_generics,
|
type_ident,
|
||||||
ty.clone(),
|
impl_generics,
|
||||||
variant,
|
ty.clone(),
|
||||||
variant_index,
|
variant,
|
||||||
container_attrs,
|
variant_index,
|
||||||
));
|
container_attrs,
|
||||||
|
)
|
||||||
arms.push(arm);
|
})
|
||||||
}
|
.collect()
|
||||||
|
);
|
||||||
|
|
||||||
Ok(quote_expr!(cx,
|
Ok(quote_expr!(cx,
|
||||||
match *self {
|
match *self {
|
||||||
@ -404,13 +414,13 @@ fn serialize_variant(
|
|||||||
let expr = try!(serialize_struct_variant(
|
let expr = try!(serialize_struct_variant(
|
||||||
cx,
|
cx,
|
||||||
builder,
|
builder,
|
||||||
type_name,
|
|
||||||
variant_index,
|
variant_index,
|
||||||
variant_name,
|
variant_name,
|
||||||
generics,
|
generics,
|
||||||
ty,
|
ty,
|
||||||
fields,
|
fields,
|
||||||
field_names,
|
field_names,
|
||||||
|
container_attrs,
|
||||||
));
|
));
|
||||||
|
|
||||||
Ok(quote_arm!(cx,
|
Ok(quote_arm!(cx,
|
||||||
@ -447,6 +457,7 @@ fn serialize_tuple_variant(
|
|||||||
builder,
|
builder,
|
||||||
structure_ty.clone(),
|
structure_ty.clone(),
|
||||||
variant_ty,
|
variant_ty,
|
||||||
|
builder.id("serialize_tuple_variant_elt"),
|
||||||
fields.len(),
|
fields.len(),
|
||||||
generics,
|
generics,
|
||||||
);
|
);
|
||||||
@ -473,55 +484,89 @@ fn serialize_tuple_variant(
|
|||||||
fn serialize_struct_variant(
|
fn serialize_struct_variant(
|
||||||
cx: &ExtCtxt,
|
cx: &ExtCtxt,
|
||||||
builder: &aster::AstBuilder,
|
builder: &aster::AstBuilder,
|
||||||
type_name: P<ast::Expr>,
|
|
||||||
variant_index: usize,
|
variant_index: usize,
|
||||||
variant_name: P<ast::Expr>,
|
variant_name: P<ast::Expr>,
|
||||||
generics: &ast::Generics,
|
generics: &ast::Generics,
|
||||||
structure_ty: P<ast::Ty>,
|
ty: P<ast::Ty>,
|
||||||
fields: &[ast::StructField],
|
fields: &[ast::StructField],
|
||||||
field_names: Vec<Ident>,
|
field_names: Vec<Ident>,
|
||||||
|
container_attrs: &attr::ContainerAttrs,
|
||||||
) -> Result<P<ast::Expr>, Error> {
|
) -> Result<P<ast::Expr>, Error> {
|
||||||
let value_ty = builder.ty().tuple()
|
let variant_generics = builder.generics()
|
||||||
.with_tys(
|
.with(generics.clone())
|
||||||
|
.add_lifetime_bound("'__serde_variant")
|
||||||
|
.lifetime_name("'__serde_variant")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
let variant_struct = builder.item().struct_("__VariantStruct")
|
||||||
|
.with_generics(variant_generics.clone())
|
||||||
|
.with_fields(
|
||||||
fields.iter().map(|field| {
|
fields.iter().map(|field| {
|
||||||
builder.ty()
|
builder.struct_field(field.node.ident().expect("struct has unnamed fields"))
|
||||||
|
.with_attrs(field.node.attrs.iter().cloned())
|
||||||
|
.ty()
|
||||||
.ref_()
|
.ref_()
|
||||||
.lifetime("'__a")
|
.lifetime("'__serde_variant")
|
||||||
.build_ty(field.node.ty.clone())
|
.build_ty(field.node.ty.clone())
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
.field("__serde_container_ty")
|
||||||
|
.ty().phantom_data().build(ty.clone())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
let value_expr = builder.expr().tuple()
|
let variant_expr = builder.expr().struct_id("__VariantStruct")
|
||||||
.with_exprs(
|
.with_id_exprs(
|
||||||
field_names.iter().map(|field| {
|
fields.iter()
|
||||||
builder.expr().id(field)
|
.zip(field_names.iter())
|
||||||
})
|
.map(|(field, field_name)| {
|
||||||
|
(
|
||||||
|
field.node.ident().expect("struct has unnamed fields"),
|
||||||
|
builder.expr().id(field_name),
|
||||||
|
)
|
||||||
|
})
|
||||||
)
|
)
|
||||||
|
.field("__serde_container_ty").path()
|
||||||
|
.global()
|
||||||
|
.id("std").id("marker")
|
||||||
|
.segment("PhantomData")
|
||||||
|
.with_ty(ty.clone())
|
||||||
|
.build()
|
||||||
|
.build()
|
||||||
|
.build();
|
||||||
|
|
||||||
|
let variant_ty = builder.ty().path()
|
||||||
|
.segment("__VariantStruct")
|
||||||
|
.with_generics(variant_generics.clone())
|
||||||
|
.build()
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
let (visitor_struct, visitor_impl) = try!(serialize_struct_visitor(
|
let (visitor_struct, visitor_impl) = try!(serialize_struct_visitor(
|
||||||
cx,
|
cx,
|
||||||
builder,
|
builder,
|
||||||
structure_ty.clone(),
|
variant_ty.clone(),
|
||||||
value_ty,
|
variant_ty.clone(),
|
||||||
|
builder.id("serialize_struct_variant_elt"),
|
||||||
fields,
|
fields,
|
||||||
generics,
|
&variant_generics,
|
||||||
(0 .. field_names.len()).map(|i| {
|
true,
|
||||||
builder.expr()
|
|
||||||
.tup_field(i)
|
|
||||||
.field("value").self_()
|
|
||||||
})
|
|
||||||
));
|
));
|
||||||
|
|
||||||
|
let container_name = container_attrs.serialize_name_expr();
|
||||||
|
|
||||||
Ok(quote_expr!(cx, {
|
Ok(quote_expr!(cx, {
|
||||||
|
$variant_struct
|
||||||
$visitor_struct
|
$visitor_struct
|
||||||
$visitor_impl
|
$visitor_impl
|
||||||
serializer.serialize_struct_variant($type_name, $variant_index, $variant_name, Visitor {
|
serializer.serialize_struct_variant(
|
||||||
value: $value_expr,
|
$container_name,
|
||||||
state: 0,
|
$variant_index,
|
||||||
_structure_ty: ::std::marker::PhantomData::<&$structure_ty>,
|
$variant_name,
|
||||||
})
|
Visitor {
|
||||||
|
value: $variant_expr,
|
||||||
|
state: 0,
|
||||||
|
_structure_ty: ::std::marker::PhantomData,
|
||||||
|
},
|
||||||
|
)
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -530,20 +575,21 @@ fn serialize_tuple_struct_visitor(
|
|||||||
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>,
|
||||||
|
serializer_method: ast::Ident,
|
||||||
fields: usize,
|
fields: usize,
|
||||||
generics: &ast::Generics
|
generics: &ast::Generics
|
||||||
) -> (P<ast::Item>, P<ast::Item>) {
|
) -> (P<ast::Item>, P<ast::Item>) {
|
||||||
let arms: Vec<ast::Arm> = (0 .. fields)
|
let arms: Vec<ast::Arm> = (0 .. fields)
|
||||||
.map(|i| {
|
.map(|i| {
|
||||||
let expr = builder.expr()
|
let expr = builder.expr().method_call(serializer_method)
|
||||||
.tup_field(i)
|
.id("serializer")
|
||||||
.field("value").self_();
|
.arg().ref_().tup_field(i).field("value").self_()
|
||||||
|
.build();
|
||||||
|
|
||||||
quote_arm!(cx,
|
quote_arm!(cx,
|
||||||
$i => {
|
$i => {
|
||||||
self.state += 1;
|
self.state += 1;
|
||||||
let v = try!(serializer.serialize_tuple_struct_elt(&$expr));
|
Ok(Some(try!($expr)))
|
||||||
Ok(Some(v))
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@ -592,51 +638,48 @@ fn serialize_tuple_struct_visitor(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_struct_visitor<I>(
|
fn serialize_struct_visitor(
|
||||||
cx: &ExtCtxt,
|
cx: &ExtCtxt,
|
||||||
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>,
|
||||||
|
serializer_method: ast::Ident,
|
||||||
fields: &[ast::StructField],
|
fields: &[ast::StructField],
|
||||||
generics: &ast::Generics,
|
generics: &ast::Generics,
|
||||||
value_exprs: I,
|
is_enum: bool,
|
||||||
) -> Result<(P<ast::Item>, P<ast::Item>), Error>
|
) -> Result<(P<ast::Item>, P<ast::Item>), Error> {
|
||||||
where I: Iterator<Item=P<ast::Expr>>,
|
let field_attrs = try!(
|
||||||
{
|
attr::get_struct_field_attrs(cx, &structure_ty, generics, fields, is_enum)
|
||||||
let value_exprs = value_exprs.collect::<Vec<_>>();
|
);
|
||||||
|
|
||||||
let field_attrs = try!(attr::get_struct_field_attrs(cx, fields));
|
let arms: Vec<ast::Arm> = fields.iter().zip(field_attrs.iter())
|
||||||
|
.filter(|&(_, ref field_attr)| !field_attr.skip_serializing_field())
|
||||||
let arms: Vec<ast::Arm> = field_attrs.iter()
|
|
||||||
.zip(value_exprs.iter())
|
|
||||||
.filter(|&(ref field, _)| !field.skip_serializing_field())
|
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(i, (ref field, value_expr))| {
|
.map(|(i, (ref field, ref field_attr))| {
|
||||||
let key_expr = field.serialize_name_expr();
|
let name = field.node.ident().expect("struct has unnamed field");
|
||||||
|
|
||||||
let stmt = if field.skip_serializing_field_if_empty() {
|
let key_expr = field_attr.serialize_name_expr();
|
||||||
quote_stmt!(cx, if ($value_expr).is_empty() { continue; })
|
|
||||||
} else if field.skip_serializing_field_if_none() {
|
let stmt = if let Some(expr) = field_attr.skip_serializing_field_if() {
|
||||||
quote_stmt!(cx, if ($value_expr).is_none() { continue; })
|
Some(quote_stmt!(cx, if $expr { continue; }))
|
||||||
} else {
|
} else {
|
||||||
quote_stmt!(cx, {})
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let field_expr = match field_attr.serialize_with() {
|
||||||
|
Some(expr) => expr.clone(),
|
||||||
|
None => quote_expr!(cx, &self.value.$name),
|
||||||
|
};
|
||||||
|
|
||||||
|
let expr = quote_expr!(cx,
|
||||||
|
serializer.$serializer_method($key_expr, $field_expr)
|
||||||
|
);
|
||||||
|
|
||||||
quote_arm!(cx,
|
quote_arm!(cx,
|
||||||
$i => {
|
$i => {
|
||||||
self.state += 1;
|
self.state += 1;
|
||||||
$stmt
|
$stmt
|
||||||
|
return Ok(Some(try!($expr)));
|
||||||
return Ok(
|
|
||||||
Some(
|
|
||||||
try!(
|
|
||||||
serializer.serialize_struct_elt(
|
|
||||||
$key_expr,
|
|
||||||
$value_expr,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@ -654,16 +697,15 @@ fn serialize_struct_visitor<I>(
|
|||||||
.build();
|
.build();
|
||||||
|
|
||||||
let len = field_attrs.iter()
|
let len = field_attrs.iter()
|
||||||
.zip(value_exprs.iter())
|
.filter(|field_attr| !field_attr.skip_serializing_field())
|
||||||
.map(|(field, value_expr)| {
|
.map(|field_attr| {
|
||||||
if field.skip_serializing_field() {
|
match field_attr.skip_serializing_field_if() {
|
||||||
quote_expr!(cx, 0)
|
Some(expr) => {
|
||||||
} else if field.skip_serializing_field_if_empty() {
|
quote_expr!(cx, if $expr { 0 } else { 1 })
|
||||||
quote_expr!(cx, if ($value_expr).is_empty() { 0 } else { 1 })
|
}
|
||||||
} else if field.skip_serializing_field_if_none() {
|
None => {
|
||||||
quote_expr!(cx, if ($value_expr).is_none() { 0 } else { 1 })
|
quote_expr!(cx, 1)
|
||||||
} else {
|
}
|
||||||
quote_expr!(cx, 1)
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.fold(quote_expr!(cx, 0), |sum, expr| quote_expr!(cx, $sum + $expr));
|
.fold(quote_expr!(cx, 0), |sum, expr| quote_expr!(cx, $sum + $expr));
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use std::default;
|
use std::default::Default;
|
||||||
|
use serde::{Serialize, Serializer, Deserialize, Deserializer};
|
||||||
|
|
||||||
use token::{
|
use token::{
|
||||||
Error,
|
Error,
|
||||||
@ -9,19 +10,201 @@ use token::{
|
|||||||
assert_de_tokens_error
|
assert_de_tokens_error
|
||||||
};
|
};
|
||||||
|
|
||||||
|
trait Trait: Sized {
|
||||||
|
fn my_default() -> Self;
|
||||||
|
|
||||||
|
fn should_skip(&self) -> bool;
|
||||||
|
|
||||||
|
fn serialize_with<S>(&self, ser: &mut S) -> Result<(), S::Error>
|
||||||
|
where S: Serializer;
|
||||||
|
|
||||||
|
fn deserialize_with<D>(de: &mut D) -> Result<Self, D::Error>
|
||||||
|
where D: Deserializer;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Trait for i32 {
|
||||||
|
fn my_default() -> Self { 123 }
|
||||||
|
|
||||||
|
fn should_skip(&self) -> bool { *self == 123 }
|
||||||
|
|
||||||
|
fn serialize_with<S>(&self, ser: &mut S) -> Result<(), S::Error>
|
||||||
|
where S: Serializer
|
||||||
|
{
|
||||||
|
if *self == 123 {
|
||||||
|
true.serialize(ser)
|
||||||
|
} else {
|
||||||
|
false.serialize(ser)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize_with<D>(de: &mut D) -> Result<Self, D::Error>
|
||||||
|
where D: Deserializer
|
||||||
|
{
|
||||||
|
if try!(Deserialize::deserialize(de)) {
|
||||||
|
Ok(123)
|
||||||
|
} else {
|
||||||
|
Ok(2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
struct Default {
|
struct DefaultStruct<A, B: Default, C> where C: Trait {
|
||||||
a1: i32,
|
a1: A,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
a2: i32,
|
a2: B,
|
||||||
|
#[serde(default="Trait::my_default")]
|
||||||
|
a3: C,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_default_struct() {
|
||||||
|
assert_de_tokens(
|
||||||
|
&DefaultStruct { a1: 1, a2: 2, a3: 3 },
|
||||||
|
vec![
|
||||||
|
Token::StructStart("DefaultStruct", Some(3)),
|
||||||
|
|
||||||
|
Token::StructSep,
|
||||||
|
Token::Str("a1"),
|
||||||
|
Token::I32(1),
|
||||||
|
|
||||||
|
Token::StructSep,
|
||||||
|
Token::Str("a2"),
|
||||||
|
Token::I32(2),
|
||||||
|
|
||||||
|
Token::StructSep,
|
||||||
|
Token::Str("a3"),
|
||||||
|
Token::I32(3),
|
||||||
|
|
||||||
|
Token::StructEnd,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_de_tokens(
|
||||||
|
&DefaultStruct { a1: 1, a2: 0, a3: 123 },
|
||||||
|
vec![
|
||||||
|
Token::StructStart("DefaultStruct", Some(1)),
|
||||||
|
|
||||||
|
Token::StructSep,
|
||||||
|
Token::Str("a1"),
|
||||||
|
Token::I32(1),
|
||||||
|
|
||||||
|
Token::StructEnd,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
enum DefaultEnum<A, B: Default, C> where C: Trait {
|
||||||
|
Struct {
|
||||||
|
a1: A,
|
||||||
|
#[serde(default)]
|
||||||
|
a2: B,
|
||||||
|
#[serde(default="Trait::my_default")]
|
||||||
|
a3: C,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_default_enum() {
|
||||||
|
assert_de_tokens(
|
||||||
|
&DefaultEnum::Struct { a1: 1, a2: 2, a3: 3 },
|
||||||
|
vec![
|
||||||
|
Token::EnumMapStart("DefaultEnum", "Struct", Some(3)),
|
||||||
|
|
||||||
|
Token::EnumMapSep,
|
||||||
|
Token::Str("a1"),
|
||||||
|
Token::I32(1),
|
||||||
|
|
||||||
|
Token::EnumMapSep,
|
||||||
|
Token::Str("a2"),
|
||||||
|
Token::I32(2),
|
||||||
|
|
||||||
|
Token::EnumMapSep,
|
||||||
|
Token::Str("a3"),
|
||||||
|
Token::I32(3),
|
||||||
|
|
||||||
|
Token::EnumMapEnd,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_de_tokens(
|
||||||
|
&DefaultEnum::Struct { a1: 1, a2: 0, a3: 123 },
|
||||||
|
vec![
|
||||||
|
Token::EnumMapStart("DefaultEnum", "Struct", Some(3)),
|
||||||
|
|
||||||
|
Token::EnumMapSep,
|
||||||
|
Token::Str("a1"),
|
||||||
|
Token::I32(1),
|
||||||
|
|
||||||
|
Token::EnumMapEnd,
|
||||||
|
]
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
struct DisallowUnknown {
|
struct DenyUnknown {
|
||||||
a1: i32,
|
a1: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ignore_unknown() {
|
||||||
|
// 'Default' allows unknown. Basic smoke test of ignore...
|
||||||
|
assert_de_tokens(
|
||||||
|
&DefaultStruct { a1: 1, a2: 2, a3: 3 },
|
||||||
|
vec![
|
||||||
|
Token::StructStart("DefaultStruct", Some(5)),
|
||||||
|
|
||||||
|
Token::StructSep,
|
||||||
|
Token::Str("whoops1"),
|
||||||
|
Token::I32(2),
|
||||||
|
|
||||||
|
Token::StructSep,
|
||||||
|
Token::Str("a1"),
|
||||||
|
Token::I32(1),
|
||||||
|
|
||||||
|
Token::StructSep,
|
||||||
|
Token::Str("whoops2"),
|
||||||
|
Token::SeqStart(Some(1)),
|
||||||
|
Token::SeqSep,
|
||||||
|
Token::I32(2),
|
||||||
|
Token::SeqEnd,
|
||||||
|
|
||||||
|
Token::StructSep,
|
||||||
|
Token::Str("a2"),
|
||||||
|
Token::I32(2),
|
||||||
|
|
||||||
|
Token::StructSep,
|
||||||
|
Token::Str("whoops3"),
|
||||||
|
Token::I32(2),
|
||||||
|
|
||||||
|
Token::StructSep,
|
||||||
|
Token::Str("a3"),
|
||||||
|
Token::I32(3),
|
||||||
|
|
||||||
|
Token::StructEnd,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_de_tokens_error::<DenyUnknown>(
|
||||||
|
vec![
|
||||||
|
Token::StructStart("DenyUnknown", Some(2)),
|
||||||
|
|
||||||
|
Token::StructSep,
|
||||||
|
Token::Str("a1"),
|
||||||
|
Token::I32(1),
|
||||||
|
|
||||||
|
Token::StructSep,
|
||||||
|
Token::Str("whoops"),
|
||||||
|
Token::I32(2),
|
||||||
|
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
Error::UnknownFieldError("whoops".to_owned())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
#[serde(rename="Superhero")]
|
#[serde(rename="Superhero")]
|
||||||
struct RenameStruct {
|
struct RenameStruct {
|
||||||
@ -38,6 +221,60 @@ struct RenameStructSerializeDeserialize {
|
|||||||
a2: i32,
|
a2: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_rename_struct() {
|
||||||
|
assert_tokens(
|
||||||
|
&RenameStruct { a1: 1, a2: 2 },
|
||||||
|
vec![
|
||||||
|
Token::StructStart("Superhero", Some(2)),
|
||||||
|
|
||||||
|
Token::StructSep,
|
||||||
|
Token::Str("a1"),
|
||||||
|
Token::I32(1),
|
||||||
|
|
||||||
|
Token::StructSep,
|
||||||
|
Token::Str("a3"),
|
||||||
|
Token::I32(2),
|
||||||
|
|
||||||
|
Token::StructEnd,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_ser_tokens(
|
||||||
|
&RenameStructSerializeDeserialize { a1: 1, a2: 2 },
|
||||||
|
&[
|
||||||
|
Token::StructStart("SuperheroSer", Some(2)),
|
||||||
|
|
||||||
|
Token::StructSep,
|
||||||
|
Token::Str("a1"),
|
||||||
|
Token::I32(1),
|
||||||
|
|
||||||
|
Token::StructSep,
|
||||||
|
Token::Str("a4"),
|
||||||
|
Token::I32(2),
|
||||||
|
|
||||||
|
Token::StructEnd,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_de_tokens(
|
||||||
|
&RenameStructSerializeDeserialize { a1: 1, a2: 2 },
|
||||||
|
vec![
|
||||||
|
Token::StructStart("SuperheroDe", Some(2)),
|
||||||
|
|
||||||
|
Token::StructSep,
|
||||||
|
Token::Str("a1"),
|
||||||
|
Token::I32(1),
|
||||||
|
|
||||||
|
Token::StructSep,
|
||||||
|
Token::Str("a5"),
|
||||||
|
Token::I32(2),
|
||||||
|
|
||||||
|
Token::StructEnd,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
#[serde(rename="Superhero")]
|
#[serde(rename="Superhero")]
|
||||||
enum RenameEnum {
|
enum RenameEnum {
|
||||||
@ -65,170 +302,6 @@ enum RenameEnumSerializeDeserialize<A> {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Deserialize, Serialize)]
|
|
||||||
struct SkipSerializingFields<A: default::Default> {
|
|
||||||
a: i8,
|
|
||||||
#[serde(skip_serializing, 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(
|
|
||||||
&Default { a1: 1, a2: 2 },
|
|
||||||
vec![
|
|
||||||
Token::StructStart("Default", Some(2)),
|
|
||||||
|
|
||||||
Token::MapSep,
|
|
||||||
Token::Str("a1"),
|
|
||||||
Token::I32(1),
|
|
||||||
|
|
||||||
Token::MapSep,
|
|
||||||
Token::Str("a2"),
|
|
||||||
Token::I32(2),
|
|
||||||
|
|
||||||
Token::MapEnd,
|
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_de_tokens(
|
|
||||||
&Default { a1: 1, a2: 0 },
|
|
||||||
vec![
|
|
||||||
Token::StructStart("Default", Some(1)),
|
|
||||||
|
|
||||||
Token::MapSep,
|
|
||||||
Token::Str("a1"),
|
|
||||||
Token::I32(1),
|
|
||||||
|
|
||||||
Token::MapEnd,
|
|
||||||
]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_ignore_unknown() {
|
|
||||||
// 'Default' allows unknown. Basic smoke test of ignore...
|
|
||||||
assert_de_tokens(
|
|
||||||
&Default { a1: 1, a2: 2},
|
|
||||||
vec![
|
|
||||||
Token::StructStart("Default", Some(5)),
|
|
||||||
|
|
||||||
Token::MapSep,
|
|
||||||
Token::Str("whoops1"),
|
|
||||||
Token::I32(2),
|
|
||||||
|
|
||||||
Token::MapSep,
|
|
||||||
Token::Str("a1"),
|
|
||||||
Token::I32(1),
|
|
||||||
|
|
||||||
Token::MapSep,
|
|
||||||
Token::Str("whoops2"),
|
|
||||||
Token::SeqStart(Some(1)),
|
|
||||||
Token::SeqSep,
|
|
||||||
Token::I32(2),
|
|
||||||
Token::SeqEnd,
|
|
||||||
|
|
||||||
Token::MapSep,
|
|
||||||
Token::Str("a2"),
|
|
||||||
Token::I32(2),
|
|
||||||
|
|
||||||
Token::MapSep,
|
|
||||||
Token::Str("whoops3"),
|
|
||||||
Token::I32(2),
|
|
||||||
|
|
||||||
Token::MapEnd,
|
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_de_tokens_error::<DisallowUnknown>(
|
|
||||||
vec![
|
|
||||||
Token::StructStart("DisallowUnknown", Some(2)),
|
|
||||||
|
|
||||||
Token::MapSep,
|
|
||||||
Token::Str("a1"),
|
|
||||||
Token::I32(1),
|
|
||||||
|
|
||||||
Token::MapSep,
|
|
||||||
Token::Str("whoops"),
|
|
||||||
Token::I32(2),
|
|
||||||
|
|
||||||
Token::MapEnd,
|
|
||||||
],
|
|
||||||
Error::UnknownFieldError("whoops".to_owned())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_rename_struct() {
|
|
||||||
assert_tokens(
|
|
||||||
&RenameStruct { a1: 1, a2: 2 },
|
|
||||||
vec![
|
|
||||||
Token::StructStart("Superhero", Some(2)),
|
|
||||||
|
|
||||||
Token::MapSep,
|
|
||||||
Token::Str("a1"),
|
|
||||||
Token::I32(1),
|
|
||||||
|
|
||||||
Token::MapSep,
|
|
||||||
Token::Str("a3"),
|
|
||||||
Token::I32(2),
|
|
||||||
|
|
||||||
Token::MapEnd,
|
|
||||||
]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_rename_struct_serialize_deserialize() {
|
|
||||||
assert_ser_tokens(
|
|
||||||
&RenameStructSerializeDeserialize { a1: 1, a2: 2 },
|
|
||||||
&[
|
|
||||||
Token::StructStart("SuperheroSer", Some(2)),
|
|
||||||
|
|
||||||
Token::MapSep,
|
|
||||||
Token::Str("a1"),
|
|
||||||
Token::I32(1),
|
|
||||||
|
|
||||||
Token::MapSep,
|
|
||||||
Token::Str("a4"),
|
|
||||||
Token::I32(2),
|
|
||||||
|
|
||||||
Token::MapEnd,
|
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_de_tokens(
|
|
||||||
&RenameStructSerializeDeserialize { a1: 1, a2: 2 },
|
|
||||||
vec![
|
|
||||||
Token::StructStart("SuperheroDe", Some(2)),
|
|
||||||
|
|
||||||
Token::MapSep,
|
|
||||||
Token::Str("a1"),
|
|
||||||
Token::I32(1),
|
|
||||||
|
|
||||||
Token::MapSep,
|
|
||||||
Token::Str("a5"),
|
|
||||||
Token::I32(2),
|
|
||||||
|
|
||||||
Token::MapEnd,
|
|
||||||
]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_rename_enum() {
|
fn test_rename_enum() {
|
||||||
assert_tokens(
|
assert_tokens(
|
||||||
@ -241,7 +314,7 @@ fn test_rename_enum() {
|
|||||||
assert_tokens(
|
assert_tokens(
|
||||||
&RenameEnum::Superman(0),
|
&RenameEnum::Superman(0),
|
||||||
vec![
|
vec![
|
||||||
Token::EnumNewtype("Superhero", "clark_kent"),
|
Token::EnumNewType("Superhero", "clark_kent"),
|
||||||
Token::I8(0),
|
Token::I8(0),
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
@ -251,13 +324,13 @@ fn test_rename_enum() {
|
|||||||
vec![
|
vec![
|
||||||
Token::EnumSeqStart("Superhero", "diana_prince", Some(2)),
|
Token::EnumSeqStart("Superhero", "diana_prince", Some(2)),
|
||||||
|
|
||||||
Token::SeqSep,
|
Token::EnumSeqSep,
|
||||||
Token::I8(0),
|
Token::I8(0),
|
||||||
|
|
||||||
Token::SeqSep,
|
Token::EnumSeqSep,
|
||||||
Token::I8(1),
|
Token::I8(1),
|
||||||
|
|
||||||
Token::SeqEnd,
|
Token::EnumSeqEnd,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -266,17 +339,14 @@ fn test_rename_enum() {
|
|||||||
vec![
|
vec![
|
||||||
Token::EnumMapStart("Superhero", "barry_allan", Some(1)),
|
Token::EnumMapStart("Superhero", "barry_allan", Some(1)),
|
||||||
|
|
||||||
Token::MapSep,
|
Token::EnumMapSep,
|
||||||
Token::Str("b"),
|
Token::Str("b"),
|
||||||
Token::I32(1),
|
Token::I32(1),
|
||||||
|
|
||||||
Token::MapEnd,
|
Token::EnumMapEnd,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_enum_serialize_deserialize() {
|
|
||||||
assert_ser_tokens(
|
assert_ser_tokens(
|
||||||
&RenameEnumSerializeDeserialize::Robin {
|
&RenameEnumSerializeDeserialize::Robin {
|
||||||
a: 0,
|
a: 0,
|
||||||
@ -285,15 +355,15 @@ fn test_enum_serialize_deserialize() {
|
|||||||
&[
|
&[
|
||||||
Token::EnumMapStart("SuperheroSer", "dick_grayson", Some(2)),
|
Token::EnumMapStart("SuperheroSer", "dick_grayson", Some(2)),
|
||||||
|
|
||||||
Token::MapSep,
|
Token::EnumMapSep,
|
||||||
Token::Str("a"),
|
Token::Str("a"),
|
||||||
Token::I8(0),
|
Token::I8(0),
|
||||||
|
|
||||||
Token::MapSep,
|
Token::EnumMapSep,
|
||||||
Token::Str("c"),
|
Token::Str("c"),
|
||||||
Token::Str(""),
|
Token::Str(""),
|
||||||
|
|
||||||
Token::MapEnd,
|
Token::EnumMapEnd,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -305,208 +375,325 @@ fn test_enum_serialize_deserialize() {
|
|||||||
vec![
|
vec![
|
||||||
Token::EnumMapStart("SuperheroDe", "jason_todd", Some(2)),
|
Token::EnumMapStart("SuperheroDe", "jason_todd", Some(2)),
|
||||||
|
|
||||||
Token::MapSep,
|
Token::EnumMapSep,
|
||||||
Token::Str("a"),
|
Token::Str("a"),
|
||||||
Token::I8(0),
|
Token::I8(0),
|
||||||
|
|
||||||
Token::MapSep,
|
Token::EnumMapSep,
|
||||||
Token::Str("d"),
|
Token::Str("d"),
|
||||||
Token::Str(""),
|
Token::Str(""),
|
||||||
|
|
||||||
Token::MapEnd,
|
Token::EnumMapEnd,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Serialize)]
|
||||||
|
struct SkipSerializingStruct<'a, B, C> where C: Trait {
|
||||||
|
a: &'a i8,
|
||||||
|
#[serde(skip_serializing)]
|
||||||
|
b: B,
|
||||||
|
#[serde(skip_serializing_if="Trait::should_skip")]
|
||||||
|
c: C,
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_skip_serializing_fields() {
|
fn test_skip_serializing_struct() {
|
||||||
|
let a = 1;
|
||||||
assert_ser_tokens(
|
assert_ser_tokens(
|
||||||
&SkipSerializingFields {
|
&SkipSerializingStruct {
|
||||||
a: 1,
|
a: &a,
|
||||||
|
b: 2,
|
||||||
|
c: 3,
|
||||||
|
},
|
||||||
|
&[
|
||||||
|
Token::StructStart("SkipSerializingStruct", Some(2)),
|
||||||
|
|
||||||
|
Token::StructSep,
|
||||||
|
Token::Str("a"),
|
||||||
|
Token::I8(1),
|
||||||
|
|
||||||
|
Token::StructSep,
|
||||||
|
Token::Str("c"),
|
||||||
|
Token::I32(3),
|
||||||
|
|
||||||
|
Token::StructEnd,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_ser_tokens(
|
||||||
|
&SkipSerializingStruct {
|
||||||
|
a: &a,
|
||||||
|
b: 2,
|
||||||
|
c: 123,
|
||||||
|
},
|
||||||
|
&[
|
||||||
|
Token::StructStart("SkipSerializingStruct", Some(1)),
|
||||||
|
|
||||||
|
Token::StructSep,
|
||||||
|
Token::Str("a"),
|
||||||
|
Token::I8(1),
|
||||||
|
|
||||||
|
Token::StructEnd,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Serialize)]
|
||||||
|
enum SkipSerializingEnum<'a, B, C> where C: Trait {
|
||||||
|
Struct {
|
||||||
|
a: &'a i8,
|
||||||
|
#[serde(skip_serializing)]
|
||||||
|
_b: B,
|
||||||
|
#[serde(skip_serializing_if="Trait::should_skip")]
|
||||||
|
c: C,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_skip_serializing_enum() {
|
||||||
|
let a = 1;
|
||||||
|
assert_ser_tokens(
|
||||||
|
&SkipSerializingEnum::Struct {
|
||||||
|
a: &a,
|
||||||
|
_b: 2,
|
||||||
|
c: 3,
|
||||||
|
},
|
||||||
|
&[
|
||||||
|
Token::EnumMapStart("SkipSerializingEnum", "Struct", Some(2)),
|
||||||
|
|
||||||
|
Token::EnumMapSep,
|
||||||
|
Token::Str("a"),
|
||||||
|
Token::I8(1),
|
||||||
|
|
||||||
|
Token::EnumMapSep,
|
||||||
|
Token::Str("c"),
|
||||||
|
Token::I32(3),
|
||||||
|
|
||||||
|
Token::EnumMapEnd,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_ser_tokens(
|
||||||
|
&SkipSerializingEnum::Struct {
|
||||||
|
a: &a,
|
||||||
|
_b: 2,
|
||||||
|
c: 123,
|
||||||
|
},
|
||||||
|
&[
|
||||||
|
Token::EnumMapStart("SkipSerializingEnum", "Struct", Some(1)),
|
||||||
|
|
||||||
|
Token::EnumMapSep,
|
||||||
|
Token::Str("a"),
|
||||||
|
Token::I8(1),
|
||||||
|
|
||||||
|
Token::EnumMapEnd,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Serialize)]
|
||||||
|
struct SerializeWithStruct<'a, B> where B: Trait {
|
||||||
|
a: &'a i8,
|
||||||
|
#[serde(serialize_with="Trait::serialize_with")]
|
||||||
|
b: B,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_serialize_with_struct() {
|
||||||
|
let a = 1;
|
||||||
|
assert_ser_tokens(
|
||||||
|
&SerializeWithStruct {
|
||||||
|
a: &a,
|
||||||
b: 2,
|
b: 2,
|
||||||
},
|
},
|
||||||
&[
|
&[
|
||||||
Token::StructStart("SkipSerializingFields", Some(1)),
|
Token::StructStart("SerializeWithStruct", Some(2)),
|
||||||
|
|
||||||
Token::MapSep,
|
Token::StructSep,
|
||||||
Token::Str("a"),
|
Token::Str("a"),
|
||||||
Token::I8(1),
|
Token::I8(1),
|
||||||
|
|
||||||
Token::MapEnd,
|
Token::StructSep,
|
||||||
|
Token::Str("b"),
|
||||||
|
Token::Bool(false),
|
||||||
|
|
||||||
|
Token::StructEnd,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_de_tokens(
|
assert_ser_tokens(
|
||||||
&SkipSerializingFields {
|
&SerializeWithStruct {
|
||||||
a: 1,
|
a: &a,
|
||||||
b: 0,
|
b: 123,
|
||||||
},
|
},
|
||||||
vec![
|
&[
|
||||||
Token::StructStart("SkipSerializingFields", Some(1)),
|
Token::StructStart("SerializeWithStruct", Some(2)),
|
||||||
|
|
||||||
Token::MapSep,
|
Token::StructSep,
|
||||||
Token::Str("a"),
|
Token::Str("a"),
|
||||||
Token::I8(1),
|
Token::I8(1),
|
||||||
|
|
||||||
Token::MapEnd,
|
Token::StructSep,
|
||||||
|
Token::Str("b"),
|
||||||
|
Token::Bool(true),
|
||||||
|
|
||||||
|
Token::StructEnd,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Serialize)]
|
||||||
|
enum SerializeWithEnum<'a, B> where B: Trait {
|
||||||
|
Struct {
|
||||||
|
a: &'a i8,
|
||||||
|
#[serde(serialize_with="Trait::serialize_with")]
|
||||||
|
b: B,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_skip_serializing_fields_if_empty() {
|
fn test_serialize_with_enum() {
|
||||||
|
let a = 1;
|
||||||
assert_ser_tokens(
|
assert_ser_tokens(
|
||||||
&SkipSerializingIfEmptyFields::<i32> {
|
&SerializeWithEnum::Struct {
|
||||||
a: 1,
|
a: &a,
|
||||||
b: vec![],
|
b: 2,
|
||||||
},
|
},
|
||||||
&[
|
&[
|
||||||
Token::StructStart("SkipSerializingIfEmptyFields", Some(1)),
|
Token::EnumMapStart("SerializeWithEnum", "Struct", Some(2)),
|
||||||
|
|
||||||
Token::MapSep,
|
Token::EnumMapSep,
|
||||||
Token::Str("a"),
|
Token::Str("a"),
|
||||||
Token::I8(1),
|
Token::I8(1),
|
||||||
|
|
||||||
Token::MapEnd,
|
Token::EnumMapSep,
|
||||||
]
|
Token::Str("b"),
|
||||||
);
|
Token::Bool(false),
|
||||||
|
|
||||||
assert_de_tokens(
|
Token::EnumMapEnd,
|
||||||
&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(
|
assert_ser_tokens(
|
||||||
&SkipSerializingIfEmptyFields {
|
&SerializeWithEnum::Struct {
|
||||||
a: 1,
|
a: &a,
|
||||||
b: vec![2],
|
b: 123,
|
||||||
},
|
},
|
||||||
&[
|
&[
|
||||||
Token::StructStart("SkipSerializingIfEmptyFields", Some(2)),
|
Token::EnumMapStart("SerializeWithEnum", "Struct", Some(2)),
|
||||||
|
|
||||||
Token::MapSep,
|
Token::EnumMapSep,
|
||||||
Token::Str("a"),
|
Token::Str("a"),
|
||||||
Token::I8(1),
|
Token::I8(1),
|
||||||
|
|
||||||
Token::MapSep,
|
Token::EnumMapSep,
|
||||||
Token::Str("b"),
|
Token::Str("b"),
|
||||||
Token::SeqStart(Some(1)),
|
Token::Bool(true),
|
||||||
Token::SeqSep,
|
|
||||||
Token::I32(2),
|
|
||||||
Token::SeqEnd,
|
|
||||||
|
|
||||||
Token::MapEnd,
|
Token::EnumMapEnd,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
assert_de_tokens(
|
#[derive(Debug, PartialEq, Deserialize)]
|
||||||
&SkipSerializingIfEmptyFields {
|
struct DeserializeWithStruct<B> where B: Trait {
|
||||||
a: 1,
|
a: i8,
|
||||||
b: vec![2],
|
#[serde(deserialize_with="Trait::deserialize_with")]
|
||||||
},
|
b: B,
|
||||||
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]
|
#[test]
|
||||||
fn test_skip_serializing_fields_if_none() {
|
fn test_deserialize_with_struct() {
|
||||||
assert_ser_tokens(
|
assert_de_tokens(
|
||||||
&SkipSerializingIfNoneFields::<i32> {
|
&DeserializeWithStruct {
|
||||||
a: 1,
|
a: 1,
|
||||||
b: None,
|
b: 2,
|
||||||
},
|
},
|
||||||
&[
|
vec![
|
||||||
Token::StructStart("SkipSerializingIfNoneFields", Some(1)),
|
Token::StructStart("DeserializeWithStruct", Some(2)),
|
||||||
|
|
||||||
Token::MapSep,
|
Token::StructSep,
|
||||||
Token::Str("a"),
|
Token::Str("a"),
|
||||||
Token::I8(1),
|
Token::I8(1),
|
||||||
|
|
||||||
Token::MapEnd,
|
Token::StructSep,
|
||||||
|
Token::Str("b"),
|
||||||
|
Token::Bool(false),
|
||||||
|
|
||||||
|
Token::StructEnd,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_de_tokens(
|
assert_de_tokens(
|
||||||
&SkipSerializingIfNoneFields::<i32> {
|
&DeserializeWithStruct {
|
||||||
a: 1,
|
a: 1,
|
||||||
b: None,
|
b: 123,
|
||||||
},
|
},
|
||||||
vec![
|
vec![
|
||||||
Token::StructStart("SkipSerializingIfNoneFields", Some(1)),
|
Token::StructStart("DeserializeWithStruct", Some(2)),
|
||||||
|
|
||||||
Token::MapSep,
|
Token::StructSep,
|
||||||
Token::Str("a"),
|
Token::Str("a"),
|
||||||
Token::I8(1),
|
Token::I8(1),
|
||||||
|
|
||||||
Token::MapEnd,
|
Token::StructSep,
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
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::Str("b"),
|
||||||
Token::Option(true),
|
Token::Bool(true),
|
||||||
Token::I32(2),
|
|
||||||
|
|
||||||
Token::MapEnd,
|
Token::StructEnd,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
}
|
||||||
assert_de_tokens(
|
|
||||||
&SkipSerializingIfNoneFields {
|
#[derive(Debug, PartialEq, Deserialize)]
|
||||||
a: 1,
|
enum DeserializeWithEnum<B> where B: Trait {
|
||||||
b: Some(2),
|
Struct {
|
||||||
},
|
a: i8,
|
||||||
vec![
|
#[serde(deserialize_with="Trait::deserialize_with")]
|
||||||
Token::StructStart("SkipSerializingIfNoneFields", Some(2)),
|
b: B,
|
||||||
|
}
|
||||||
Token::MapSep,
|
}
|
||||||
Token::Str("a"),
|
|
||||||
Token::I8(1),
|
#[test]
|
||||||
|
fn test_deserialize_with_enum() {
|
||||||
Token::MapSep,
|
assert_de_tokens(
|
||||||
Token::Str("b"),
|
&DeserializeWithEnum::Struct {
|
||||||
Token::Option(true),
|
a: 1,
|
||||||
Token::I32(2),
|
b: 2,
|
||||||
|
},
|
||||||
Token::MapEnd,
|
vec![
|
||||||
|
Token::EnumMapStart("DeserializeWithEnum", "Struct", Some(2)),
|
||||||
|
|
||||||
|
Token::EnumMapSep,
|
||||||
|
Token::Str("a"),
|
||||||
|
Token::I8(1),
|
||||||
|
|
||||||
|
Token::EnumMapSep,
|
||||||
|
Token::Str("b"),
|
||||||
|
Token::Bool(false),
|
||||||
|
|
||||||
|
Token::EnumMapEnd,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_de_tokens(
|
||||||
|
&DeserializeWithEnum::Struct {
|
||||||
|
a: 1,
|
||||||
|
b: 123,
|
||||||
|
},
|
||||||
|
vec![
|
||||||
|
Token::EnumMapStart("DeserializeWithEnum", "Struct", Some(2)),
|
||||||
|
|
||||||
|
Token::EnumMapSep,
|
||||||
|
Token::Str("a"),
|
||||||
|
Token::I8(1),
|
||||||
|
|
||||||
|
Token::EnumMapSep,
|
||||||
|
Token::Str("b"),
|
||||||
|
Token::Bool(true),
|
||||||
|
|
||||||
|
Token::EnumMapEnd,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -184,27 +184,27 @@ declare_tests! {
|
|||||||
],
|
],
|
||||||
TupleStruct(1, 2, 3) => vec![
|
TupleStruct(1, 2, 3) => vec![
|
||||||
Token::TupleStructStart("TupleStruct", Some(3)),
|
Token::TupleStructStart("TupleStruct", Some(3)),
|
||||||
Token::SeqSep,
|
Token::TupleSeqSep,
|
||||||
Token::I32(1),
|
Token::I32(1),
|
||||||
|
|
||||||
Token::SeqSep,
|
Token::TupleSeqSep,
|
||||||
Token::I32(2),
|
Token::I32(2),
|
||||||
|
|
||||||
Token::SeqSep,
|
Token::TupleSeqSep,
|
||||||
Token::I32(3),
|
Token::I32(3),
|
||||||
Token::SeqEnd,
|
Token::TupleSeqEnd,
|
||||||
],
|
],
|
||||||
TupleStruct(1, 2, 3) => vec![
|
TupleStruct(1, 2, 3) => vec![
|
||||||
Token::TupleStructStart("TupleStruct", None),
|
Token::TupleStructStart("TupleStruct", None),
|
||||||
Token::SeqSep,
|
Token::TupleSeqSep,
|
||||||
Token::I32(1),
|
Token::I32(1),
|
||||||
|
|
||||||
Token::SeqSep,
|
Token::TupleSeqSep,
|
||||||
Token::I32(2),
|
Token::I32(2),
|
||||||
|
|
||||||
Token::SeqSep,
|
Token::TupleSeqSep,
|
||||||
Token::I32(3),
|
Token::I32(3),
|
||||||
Token::SeqEnd,
|
Token::TupleSeqEnd,
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
test_btreeset {
|
test_btreeset {
|
||||||
@ -495,18 +495,18 @@ declare_tests! {
|
|||||||
],
|
],
|
||||||
Struct { a: 1, b: 2, c: 3 } => vec![
|
Struct { a: 1, b: 2, c: 3 } => vec![
|
||||||
Token::StructStart("Struct", Some(3)),
|
Token::StructStart("Struct", Some(3)),
|
||||||
Token::MapSep,
|
Token::StructSep,
|
||||||
Token::Str("a"),
|
Token::Str("a"),
|
||||||
Token::I32(1),
|
Token::I32(1),
|
||||||
|
|
||||||
Token::MapSep,
|
Token::StructSep,
|
||||||
Token::Str("b"),
|
Token::Str("b"),
|
||||||
Token::I32(2),
|
Token::I32(2),
|
||||||
|
|
||||||
Token::MapSep,
|
Token::StructSep,
|
||||||
Token::Str("c"),
|
Token::Str("c"),
|
||||||
Token::I32(3),
|
Token::I32(3),
|
||||||
Token::MapEnd,
|
Token::StructEnd,
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
test_enum_unit {
|
test_enum_unit {
|
||||||
@ -516,39 +516,39 @@ declare_tests! {
|
|||||||
}
|
}
|
||||||
test_enum_simple {
|
test_enum_simple {
|
||||||
Enum::Simple(1) => vec![
|
Enum::Simple(1) => vec![
|
||||||
Token::EnumNewtype("Enum", "Simple"),
|
Token::EnumNewType("Enum", "Simple"),
|
||||||
Token::I32(1),
|
Token::I32(1),
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
test_enum_seq {
|
test_enum_seq {
|
||||||
Enum::Seq(1, 2, 3) => vec![
|
Enum::Seq(1, 2, 3) => vec![
|
||||||
Token::EnumSeqStart("Enum", "Seq", Some(3)),
|
Token::EnumSeqStart("Enum", "Seq", Some(3)),
|
||||||
Token::SeqSep,
|
Token::EnumSeqSep,
|
||||||
Token::I32(1),
|
Token::I32(1),
|
||||||
|
|
||||||
Token::SeqSep,
|
Token::EnumSeqSep,
|
||||||
Token::I32(2),
|
Token::I32(2),
|
||||||
|
|
||||||
Token::SeqSep,
|
Token::EnumSeqSep,
|
||||||
Token::I32(3),
|
Token::I32(3),
|
||||||
Token::SeqEnd,
|
Token::EnumSeqEnd,
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
test_enum_map {
|
test_enum_map {
|
||||||
Enum::Map { a: 1, b: 2, c: 3 } => vec![
|
Enum::Map { a: 1, b: 2, c: 3 } => vec![
|
||||||
Token::EnumMapStart("Enum", "Map", Some(3)),
|
Token::EnumMapStart("Enum", "Map", Some(3)),
|
||||||
Token::MapSep,
|
Token::EnumMapSep,
|
||||||
Token::Str("a"),
|
Token::Str("a"),
|
||||||
Token::I32(1),
|
Token::I32(1),
|
||||||
|
|
||||||
Token::MapSep,
|
Token::EnumMapSep,
|
||||||
Token::Str("b"),
|
Token::Str("b"),
|
||||||
Token::I32(2),
|
Token::I32(2),
|
||||||
|
|
||||||
Token::MapSep,
|
Token::EnumMapSep,
|
||||||
Token::Str("c"),
|
Token::Str("c"),
|
||||||
Token::I32(3),
|
Token::I32(3),
|
||||||
Token::MapEnd,
|
Token::EnumMapEnd,
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
test_enum_unit_usize {
|
test_enum_unit_usize {
|
||||||
|
@ -123,7 +123,7 @@ pub struct GenericStruct<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct GenericNewtypeStruct<T>(T);
|
pub struct GenericNewTypeStruct<T>(T);
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct GenericTupleStruct<T, U>(T, U);
|
pub struct GenericTupleStruct<T, U>(T, U);
|
||||||
@ -131,7 +131,7 @@ pub struct GenericTupleStruct<T, U>(T, U);
|
|||||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
pub enum GenericEnum<T, U> {
|
pub enum GenericEnum<T, U> {
|
||||||
Unit,
|
Unit,
|
||||||
Newtype(T),
|
NewType(T),
|
||||||
Seq(T, U),
|
Seq(T, U),
|
||||||
Map { x: T, y: U },
|
Map { x: T, y: U },
|
||||||
}
|
}
|
||||||
@ -153,16 +153,16 @@ fn test_ser_named_tuple() {
|
|||||||
&SerNamedTuple(&a, &mut b, c),
|
&SerNamedTuple(&a, &mut b, c),
|
||||||
&[
|
&[
|
||||||
Token::TupleStructStart("SerNamedTuple", Some(3)),
|
Token::TupleStructStart("SerNamedTuple", Some(3)),
|
||||||
Token::SeqSep,
|
Token::TupleSeqSep,
|
||||||
Token::I32(5),
|
Token::I32(5),
|
||||||
|
|
||||||
Token::SeqSep,
|
Token::TupleSeqSep,
|
||||||
Token::I32(6),
|
Token::I32(6),
|
||||||
|
|
||||||
Token::SeqSep,
|
Token::TupleSeqSep,
|
||||||
Token::I32(7),
|
Token::I32(7),
|
||||||
|
|
||||||
Token::SeqEnd,
|
Token::TupleSeqEnd,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -172,7 +172,7 @@ fn test_de_named_tuple() {
|
|||||||
assert_de_tokens(
|
assert_de_tokens(
|
||||||
&DeNamedTuple(5, 6, 7),
|
&DeNamedTuple(5, 6, 7),
|
||||||
vec![
|
vec![
|
||||||
Token::TupleStructStart("DeNamedTuple", Some(3)),
|
Token::SeqStart(Some(3)),
|
||||||
Token::SeqSep,
|
Token::SeqSep,
|
||||||
Token::I32(5),
|
Token::I32(5),
|
||||||
|
|
||||||
@ -185,6 +185,23 @@ fn test_de_named_tuple() {
|
|||||||
Token::SeqEnd,
|
Token::SeqEnd,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
assert_de_tokens(
|
||||||
|
&DeNamedTuple(5, 6, 7),
|
||||||
|
vec![
|
||||||
|
Token::TupleStructStart("DeNamedTuple", Some(3)),
|
||||||
|
Token::TupleSeqSep,
|
||||||
|
Token::I32(5),
|
||||||
|
|
||||||
|
Token::TupleSeqSep,
|
||||||
|
Token::I32(6),
|
||||||
|
|
||||||
|
Token::TupleSeqSep,
|
||||||
|
Token::I32(7),
|
||||||
|
|
||||||
|
Token::TupleSeqEnd,
|
||||||
|
]
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -202,19 +219,19 @@ fn test_ser_named_map() {
|
|||||||
&[
|
&[
|
||||||
Token::StructStart("SerNamedMap", Some(3)),
|
Token::StructStart("SerNamedMap", Some(3)),
|
||||||
|
|
||||||
Token::MapSep,
|
Token::StructSep,
|
||||||
Token::Str("a"),
|
Token::Str("a"),
|
||||||
Token::I32(5),
|
Token::I32(5),
|
||||||
|
|
||||||
Token::MapSep,
|
Token::StructSep,
|
||||||
Token::Str("b"),
|
Token::Str("b"),
|
||||||
Token::I32(6),
|
Token::I32(6),
|
||||||
|
|
||||||
Token::MapSep,
|
Token::StructSep,
|
||||||
Token::Str("c"),
|
Token::Str("c"),
|
||||||
Token::I32(7),
|
Token::I32(7),
|
||||||
|
|
||||||
Token::MapEnd,
|
Token::StructEnd,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -230,19 +247,19 @@ fn test_de_named_map() {
|
|||||||
vec![
|
vec![
|
||||||
Token::StructStart("DeNamedMap", Some(3)),
|
Token::StructStart("DeNamedMap", Some(3)),
|
||||||
|
|
||||||
Token::MapSep,
|
Token::StructSep,
|
||||||
Token::Str("a"),
|
Token::Str("a"),
|
||||||
Token::I32(5),
|
Token::I32(5),
|
||||||
|
|
||||||
Token::MapSep,
|
Token::StructSep,
|
||||||
Token::Str("b"),
|
Token::Str("b"),
|
||||||
Token::I32(6),
|
Token::I32(6),
|
||||||
|
|
||||||
Token::MapSep,
|
Token::StructSep,
|
||||||
Token::Str("c"),
|
Token::Str("c"),
|
||||||
Token::I32(7),
|
Token::I32(7),
|
||||||
|
|
||||||
Token::MapEnd,
|
Token::StructEnd,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -278,19 +295,19 @@ fn test_ser_enum_seq() {
|
|||||||
&[
|
&[
|
||||||
Token::EnumSeqStart("SerEnum", "Seq", Some(4)),
|
Token::EnumSeqStart("SerEnum", "Seq", Some(4)),
|
||||||
|
|
||||||
Token::SeqSep,
|
Token::EnumSeqSep,
|
||||||
Token::I8(1),
|
Token::I8(1),
|
||||||
|
|
||||||
Token::SeqSep,
|
Token::EnumSeqSep,
|
||||||
Token::I32(2),
|
Token::I32(2),
|
||||||
|
|
||||||
Token::SeqSep,
|
Token::EnumSeqSep,
|
||||||
Token::I32(3),
|
Token::I32(3),
|
||||||
|
|
||||||
Token::SeqSep,
|
Token::EnumSeqSep,
|
||||||
Token::I32(5),
|
Token::I32(5),
|
||||||
|
|
||||||
Token::SeqEnd,
|
Token::EnumSeqEnd,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -316,23 +333,23 @@ fn test_ser_enum_map() {
|
|||||||
&[
|
&[
|
||||||
Token::EnumMapStart("SerEnum", "Map", Some(4)),
|
Token::EnumMapStart("SerEnum", "Map", Some(4)),
|
||||||
|
|
||||||
Token::MapSep,
|
Token::EnumMapSep,
|
||||||
Token::Str("a"),
|
Token::Str("a"),
|
||||||
Token::I8(1),
|
Token::I8(1),
|
||||||
|
|
||||||
Token::MapSep,
|
Token::EnumMapSep,
|
||||||
Token::Str("b"),
|
Token::Str("b"),
|
||||||
Token::I32(2),
|
Token::I32(2),
|
||||||
|
|
||||||
Token::MapSep,
|
Token::EnumMapSep,
|
||||||
Token::Str("c"),
|
Token::Str("c"),
|
||||||
Token::I32(3),
|
Token::I32(3),
|
||||||
|
|
||||||
Token::MapSep,
|
Token::EnumMapSep,
|
||||||
Token::Str("e"),
|
Token::Str("e"),
|
||||||
Token::I32(5),
|
Token::I32(5),
|
||||||
|
|
||||||
Token::MapEnd,
|
Token::EnumMapEnd,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -368,19 +385,19 @@ fn test_de_enum_seq() {
|
|||||||
vec![
|
vec![
|
||||||
Token::EnumSeqStart("DeEnum", "Seq", Some(4)),
|
Token::EnumSeqStart("DeEnum", "Seq", Some(4)),
|
||||||
|
|
||||||
Token::SeqSep,
|
Token::EnumSeqSep,
|
||||||
Token::I8(1),
|
Token::I8(1),
|
||||||
|
|
||||||
Token::SeqSep,
|
Token::EnumSeqSep,
|
||||||
Token::I32(2),
|
Token::I32(2),
|
||||||
|
|
||||||
Token::SeqSep,
|
Token::EnumSeqSep,
|
||||||
Token::I32(3),
|
Token::I32(3),
|
||||||
|
|
||||||
Token::SeqSep,
|
Token::EnumSeqSep,
|
||||||
Token::I32(5),
|
Token::I32(5),
|
||||||
|
|
||||||
Token::SeqEnd,
|
Token::EnumSeqEnd,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -406,23 +423,23 @@ fn test_de_enum_map() {
|
|||||||
vec![
|
vec![
|
||||||
Token::EnumMapStart("DeEnum", "Map", Some(4)),
|
Token::EnumMapStart("DeEnum", "Map", Some(4)),
|
||||||
|
|
||||||
Token::MapSep,
|
Token::EnumMapSep,
|
||||||
Token::Str("a"),
|
Token::Str("a"),
|
||||||
Token::I8(1),
|
Token::I8(1),
|
||||||
|
|
||||||
Token::MapSep,
|
Token::EnumMapSep,
|
||||||
Token::Str("b"),
|
Token::Str("b"),
|
||||||
Token::I32(2),
|
Token::I32(2),
|
||||||
|
|
||||||
Token::MapSep,
|
Token::EnumMapSep,
|
||||||
Token::Str("c"),
|
Token::Str("c"),
|
||||||
Token::I32(3),
|
Token::I32(3),
|
||||||
|
|
||||||
Token::MapSep,
|
Token::EnumMapSep,
|
||||||
Token::Str("e"),
|
Token::Str("e"),
|
||||||
Token::I32(5),
|
Token::I32(5),
|
||||||
|
|
||||||
Token::MapEnd,
|
Token::EnumMapEnd,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -434,7 +451,7 @@ fn test_lifetimes() {
|
|||||||
assert_ser_tokens(
|
assert_ser_tokens(
|
||||||
&Lifetimes::LifetimeSeq(&value),
|
&Lifetimes::LifetimeSeq(&value),
|
||||||
&[
|
&[
|
||||||
Token::EnumNewtype("Lifetimes", "LifetimeSeq"),
|
Token::EnumNewType("Lifetimes", "LifetimeSeq"),
|
||||||
Token::I32(5),
|
Token::I32(5),
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
@ -442,7 +459,7 @@ fn test_lifetimes() {
|
|||||||
assert_ser_tokens(
|
assert_ser_tokens(
|
||||||
&Lifetimes::NoLifetimeSeq(5),
|
&Lifetimes::NoLifetimeSeq(5),
|
||||||
&[
|
&[
|
||||||
Token::EnumNewtype("Lifetimes", "NoLifetimeSeq"),
|
Token::EnumNewType("Lifetimes", "NoLifetimeSeq"),
|
||||||
Token::I32(5),
|
Token::I32(5),
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
@ -452,11 +469,11 @@ fn test_lifetimes() {
|
|||||||
&[
|
&[
|
||||||
Token::EnumMapStart("Lifetimes", "LifetimeMap", Some(1)),
|
Token::EnumMapStart("Lifetimes", "LifetimeMap", Some(1)),
|
||||||
|
|
||||||
Token::MapSep,
|
Token::EnumMapSep,
|
||||||
Token::Str("a"),
|
Token::Str("a"),
|
||||||
Token::I32(5),
|
Token::I32(5),
|
||||||
|
|
||||||
Token::MapEnd,
|
Token::EnumMapEnd,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -465,11 +482,11 @@ fn test_lifetimes() {
|
|||||||
&[
|
&[
|
||||||
Token::EnumMapStart("Lifetimes", "NoLifetimeMap", Some(1)),
|
Token::EnumMapStart("Lifetimes", "NoLifetimeMap", Some(1)),
|
||||||
|
|
||||||
Token::MapSep,
|
Token::EnumMapSep,
|
||||||
Token::Str("a"),
|
Token::Str("a"),
|
||||||
Token::I32(5),
|
Token::I32(5),
|
||||||
|
|
||||||
Token::MapEnd,
|
Token::EnumMapEnd,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -481,11 +498,11 @@ fn test_generic_struct() {
|
|||||||
vec![
|
vec![
|
||||||
Token::StructStart("GenericStruct", Some(1)),
|
Token::StructStart("GenericStruct", Some(1)),
|
||||||
|
|
||||||
Token::MapSep,
|
Token::StructSep,
|
||||||
Token::Str("x"),
|
Token::Str("x"),
|
||||||
Token::U32(5),
|
Token::U32(5),
|
||||||
|
|
||||||
Token::MapEnd,
|
Token::StructEnd,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -493,9 +510,9 @@ fn test_generic_struct() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_generic_newtype_struct() {
|
fn test_generic_newtype_struct() {
|
||||||
assert_tokens(
|
assert_tokens(
|
||||||
&GenericNewtypeStruct(5u32),
|
&GenericNewTypeStruct(5u32),
|
||||||
vec![
|
vec![
|
||||||
Token::StructNewtype("GenericNewtypeStruct"),
|
Token::StructNewType("GenericNewTypeStruct"),
|
||||||
Token::U32(5),
|
Token::U32(5),
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
@ -508,13 +525,13 @@ fn test_generic_tuple_struct() {
|
|||||||
vec![
|
vec![
|
||||||
Token::TupleStructStart("GenericTupleStruct", Some(2)),
|
Token::TupleStructStart("GenericTupleStruct", Some(2)),
|
||||||
|
|
||||||
Token::SeqSep,
|
Token::TupleSeqSep,
|
||||||
Token::U32(5),
|
Token::U32(5),
|
||||||
|
|
||||||
Token::SeqSep,
|
Token::TupleSeqSep,
|
||||||
Token::U32(6),
|
Token::U32(6),
|
||||||
|
|
||||||
Token::SeqEnd,
|
Token::TupleSeqEnd,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -532,9 +549,9 @@ fn test_generic_enum_unit() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_generic_enum_newtype() {
|
fn test_generic_enum_newtype() {
|
||||||
assert_tokens(
|
assert_tokens(
|
||||||
&GenericEnum::Newtype::<u32, u32>(5),
|
&GenericEnum::NewType::<u32, u32>(5),
|
||||||
vec![
|
vec![
|
||||||
Token::EnumNewtype("GenericEnum", "Newtype"),
|
Token::EnumNewType("GenericEnum", "NewType"),
|
||||||
Token::U32(5),
|
Token::U32(5),
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
@ -547,13 +564,13 @@ fn test_generic_enum_seq() {
|
|||||||
vec![
|
vec![
|
||||||
Token::EnumSeqStart("GenericEnum", "Seq", Some(2)),
|
Token::EnumSeqStart("GenericEnum", "Seq", Some(2)),
|
||||||
|
|
||||||
Token::SeqSep,
|
Token::EnumSeqSep,
|
||||||
Token::U32(5),
|
Token::U32(5),
|
||||||
|
|
||||||
Token::SeqSep,
|
Token::EnumSeqSep,
|
||||||
Token::U32(6),
|
Token::U32(6),
|
||||||
|
|
||||||
Token::SeqEnd,
|
Token::EnumSeqEnd,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -565,15 +582,15 @@ fn test_generic_enum_map() {
|
|||||||
vec![
|
vec![
|
||||||
Token::EnumMapStart("GenericEnum", "Map", Some(2)),
|
Token::EnumMapStart("GenericEnum", "Map", Some(2)),
|
||||||
|
|
||||||
Token::MapSep,
|
Token::EnumMapSep,
|
||||||
Token::Str("x"),
|
Token::Str("x"),
|
||||||
Token::U32(5),
|
Token::U32(5),
|
||||||
|
|
||||||
Token::MapSep,
|
Token::EnumMapSep,
|
||||||
Token::Str("y"),
|
Token::Str("y"),
|
||||||
Token::U32(6),
|
Token::U32(6),
|
||||||
|
|
||||||
Token::MapEnd,
|
Token::EnumMapEnd,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -76,11 +76,11 @@ declare_ser_tests! {
|
|||||||
}
|
}
|
||||||
test_result {
|
test_result {
|
||||||
Ok::<i32, i32>(0) => &[
|
Ok::<i32, i32>(0) => &[
|
||||||
Token::EnumNewtype("Result", "Ok"),
|
Token::EnumNewType("Result", "Ok"),
|
||||||
Token::I32(0),
|
Token::I32(0),
|
||||||
],
|
],
|
||||||
Err::<i32, i32>(1) => &[
|
Err::<i32, i32>(1) => &[
|
||||||
Token::EnumNewtype("Result", "Err"),
|
Token::EnumNewType("Result", "Err"),
|
||||||
Token::I32(1),
|
Token::I32(1),
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
@ -214,56 +214,56 @@ declare_ser_tests! {
|
|||||||
test_tuple_struct {
|
test_tuple_struct {
|
||||||
TupleStruct(1, 2, 3) => &[
|
TupleStruct(1, 2, 3) => &[
|
||||||
Token::TupleStructStart("TupleStruct", Some(3)),
|
Token::TupleStructStart("TupleStruct", Some(3)),
|
||||||
Token::SeqSep,
|
Token::TupleSeqSep,
|
||||||
Token::I32(1),
|
Token::I32(1),
|
||||||
|
|
||||||
Token::SeqSep,
|
Token::TupleSeqSep,
|
||||||
Token::I32(2),
|
Token::I32(2),
|
||||||
|
|
||||||
Token::SeqSep,
|
Token::TupleSeqSep,
|
||||||
Token::I32(3),
|
Token::I32(3),
|
||||||
Token::SeqEnd,
|
Token::TupleSeqEnd,
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
test_struct {
|
test_struct {
|
||||||
Struct { a: 1, b: 2, c: 3 } => &[
|
Struct { a: 1, b: 2, c: 3 } => &[
|
||||||
Token::StructStart("Struct", Some(3)),
|
Token::StructStart("Struct", Some(3)),
|
||||||
Token::MapSep,
|
Token::StructSep,
|
||||||
Token::Str("a"),
|
Token::Str("a"),
|
||||||
Token::I32(1),
|
Token::I32(1),
|
||||||
|
|
||||||
Token::MapSep,
|
Token::StructSep,
|
||||||
Token::Str("b"),
|
Token::Str("b"),
|
||||||
Token::I32(2),
|
Token::I32(2),
|
||||||
|
|
||||||
Token::MapSep,
|
Token::StructSep,
|
||||||
Token::Str("c"),
|
Token::Str("c"),
|
||||||
Token::I32(3),
|
Token::I32(3),
|
||||||
Token::MapEnd,
|
Token::StructEnd,
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
test_enum {
|
test_enum {
|
||||||
Enum::Unit => &[Token::EnumUnit("Enum", "Unit")],
|
Enum::Unit => &[Token::EnumUnit("Enum", "Unit")],
|
||||||
Enum::One(42) => &[Token::EnumNewtype("Enum", "One"), Token::I32(42)],
|
Enum::One(42) => &[Token::EnumNewType("Enum", "One"), Token::I32(42)],
|
||||||
Enum::Seq(1, 2) => &[
|
Enum::Seq(1, 2) => &[
|
||||||
Token::EnumSeqStart("Enum", "Seq", Some(2)),
|
Token::EnumSeqStart("Enum", "Seq", Some(2)),
|
||||||
Token::SeqSep,
|
Token::EnumSeqSep,
|
||||||
Token::I32(1),
|
Token::I32(1),
|
||||||
|
|
||||||
Token::SeqSep,
|
Token::EnumSeqSep,
|
||||||
Token::I32(2),
|
Token::I32(2),
|
||||||
Token::SeqEnd,
|
Token::EnumSeqEnd,
|
||||||
],
|
],
|
||||||
Enum::Map { a: 1, b: 2 } => &[
|
Enum::Map { a: 1, b: 2 } => &[
|
||||||
Token::EnumMapStart("Enum", "Map", Some(2)),
|
Token::EnumMapStart("Enum", "Map", Some(2)),
|
||||||
Token::MapSep,
|
Token::EnumMapSep,
|
||||||
Token::Str("a"),
|
Token::Str("a"),
|
||||||
Token::I32(1),
|
Token::I32(1),
|
||||||
|
|
||||||
Token::MapSep,
|
Token::EnumMapSep,
|
||||||
Token::Str("b"),
|
Token::Str("b"),
|
||||||
Token::I32(2),
|
Token::I32(2),
|
||||||
Token::MapEnd,
|
Token::EnumMapEnd,
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
test_num_bigint {
|
test_num_bigint {
|
||||||
|
@ -2,7 +2,8 @@ use std::fmt;
|
|||||||
use std::iter;
|
use std::iter;
|
||||||
use std::error;
|
use std::error;
|
||||||
|
|
||||||
use serde::{ser, de};
|
use serde::ser::{self, Serialize};
|
||||||
|
use serde::de;
|
||||||
use serde::de::value::{self, ValueDeserializer};
|
use serde::de::value::{self, ValueDeserializer};
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Debug)]
|
#[derive(Clone, PartialEq, Debug)]
|
||||||
@ -30,23 +31,35 @@ pub enum Token<'a> {
|
|||||||
Unit,
|
Unit,
|
||||||
UnitStruct(&'a str),
|
UnitStruct(&'a str),
|
||||||
|
|
||||||
StructNewtype(&'a str),
|
StructNewType(&'a str),
|
||||||
|
|
||||||
EnumStart(&'a str),
|
EnumStart(&'a str),
|
||||||
EnumUnit(&'a str, &'a str),
|
EnumUnit(&'a str, &'a str),
|
||||||
EnumNewtype(&'a str, &'a str),
|
EnumNewType(&'a str, &'a str),
|
||||||
EnumSeqStart(&'a str, &'a str, Option<usize>),
|
|
||||||
EnumMapStart(&'a str, &'a str, Option<usize>),
|
|
||||||
|
|
||||||
SeqStart(Option<usize>),
|
SeqStart(Option<usize>),
|
||||||
TupleStructStart(&'a str, Option<usize>),
|
|
||||||
SeqSep,
|
SeqSep,
|
||||||
SeqEnd,
|
SeqEnd,
|
||||||
|
|
||||||
|
TupleStructStart(&'a str, Option<usize>),
|
||||||
|
TupleSeqSep,
|
||||||
|
TupleSeqEnd,
|
||||||
|
|
||||||
MapStart(Option<usize>),
|
MapStart(Option<usize>),
|
||||||
StructStart(&'a str, Option<usize>),
|
|
||||||
MapSep,
|
MapSep,
|
||||||
MapEnd,
|
MapEnd,
|
||||||
|
|
||||||
|
StructStart(&'a str, Option<usize>),
|
||||||
|
StructSep,
|
||||||
|
StructEnd,
|
||||||
|
|
||||||
|
EnumSeqStart(&'a str, &'a str, Option<usize>),
|
||||||
|
EnumSeqSep,
|
||||||
|
EnumSeqEnd,
|
||||||
|
|
||||||
|
EnumMapStart(&'a str, &'a str, Option<usize>),
|
||||||
|
EnumMapSep,
|
||||||
|
EnumMapEnd,
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
@ -102,7 +115,7 @@ impl<'a, I> ser::Serializer for Serializer<I>
|
|||||||
value: T) -> Result<(), Error>
|
value: T) -> Result<(), Error>
|
||||||
where T: ser::Serialize,
|
where T: ser::Serialize,
|
||||||
{
|
{
|
||||||
assert_eq!(self.tokens.next(), Some(&Token::EnumNewtype(name, variant)));
|
assert_eq!(self.tokens.next(), Some(&Token::EnumNewType(name, variant)));
|
||||||
value.serialize(self)
|
value.serialize(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -218,43 +231,65 @@ impl<'a, I> ser::Serializer for Serializer<I>
|
|||||||
self.visit_sequence(visitor)
|
self.visit_sequence(visitor)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn serialize_seq_elt<T>(&mut self, value: T) -> Result<(), Error>
|
||||||
|
where T: ser::Serialize
|
||||||
|
{
|
||||||
|
assert_eq!(self.tokens.next(), Some(&Token::SeqSep));
|
||||||
|
value.serialize(self)
|
||||||
|
}
|
||||||
|
|
||||||
fn serialize_newtype_struct<T>(&mut self,
|
fn serialize_newtype_struct<T>(&mut self,
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
value: T) -> Result<(), Error>
|
value: T) -> Result<(), Error>
|
||||||
where T: ser::Serialize,
|
where T: ser::Serialize,
|
||||||
{
|
{
|
||||||
assert_eq!(self.tokens.next(), Some(&Token::StructNewtype(name)));
|
assert_eq!(self.tokens.next(), Some(&Token::StructNewType(name)));
|
||||||
value.serialize(self)
|
value.serialize(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_tuple_struct<V>(&mut self, name: &str, visitor: V) -> Result<(), Error>
|
fn serialize_tuple_struct<V>(&mut self, name: &str, mut visitor: V) -> Result<(), Error>
|
||||||
where V: ser::SeqVisitor
|
where V: ser::SeqVisitor
|
||||||
{
|
{
|
||||||
let len = visitor.len();
|
let len = visitor.len();
|
||||||
|
|
||||||
assert_eq!(self.tokens.next(), Some(&Token::TupleStructStart(name, len)));
|
assert_eq!(self.tokens.next(), Some(&Token::TupleStructStart(name, len)));
|
||||||
|
|
||||||
self.visit_sequence(visitor)
|
while let Some(()) = try!(visitor.visit(self)) { }
|
||||||
|
|
||||||
|
assert_eq!(self.tokens.next(), Some(&Token::TupleSeqEnd));
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_tuple_struct_elt<T>(&mut self, value: T) -> Result<(), Error>
|
||||||
|
where T: ser::Serialize,
|
||||||
|
{
|
||||||
|
assert_eq!(self.tokens.next(), Some(&Token::TupleSeqSep));
|
||||||
|
value.serialize(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_tuple_variant<V>(&mut self,
|
fn serialize_tuple_variant<V>(&mut self,
|
||||||
name: &str,
|
name: &str,
|
||||||
_variant_index: usize,
|
_variant_index: usize,
|
||||||
variant: &str,
|
variant: &str,
|
||||||
visitor: V) -> Result<(), Error>
|
mut visitor: V) -> Result<(), Error>
|
||||||
where V: ser::SeqVisitor
|
where V: ser::SeqVisitor
|
||||||
{
|
{
|
||||||
let len = visitor.len();
|
let len = visitor.len();
|
||||||
|
|
||||||
assert_eq!(self.tokens.next(), Some(&Token::EnumSeqStart(name, variant, len)));
|
assert_eq!(self.tokens.next(), Some(&Token::EnumSeqStart(name, variant, len)));
|
||||||
|
|
||||||
self.visit_sequence(visitor)
|
while let Some(()) = try!(visitor.visit(self)) { }
|
||||||
|
|
||||||
|
assert_eq!(self.tokens.next(), Some(&Token::EnumSeqEnd));
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_seq_elt<T>(&mut self, value: T) -> Result<(), Error>
|
fn serialize_tuple_variant_elt<T>(&mut self, value: T) -> Result<(), Error>
|
||||||
where T: ser::Serialize
|
where T: ser::Serialize,
|
||||||
{
|
{
|
||||||
assert_eq!(self.tokens.next(), Some(&Token::SeqSep));
|
assert_eq!(self.tokens.next(), Some(&Token::EnumSeqSep));
|
||||||
value.serialize(self)
|
value.serialize(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -268,35 +303,61 @@ impl<'a, I> ser::Serializer for Serializer<I>
|
|||||||
self.visit_mapping(visitor)
|
self.visit_mapping(visitor)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_struct<V>(&mut self, name: &str, visitor: V) -> Result<(), Error>
|
fn serialize_map_elt<K, V>(&mut self, key: K, value: V) -> Result<(), Error>
|
||||||
|
where K: ser::Serialize,
|
||||||
|
V: ser::Serialize,
|
||||||
|
{
|
||||||
|
assert_eq!(self.tokens.next(), Some(&Token::MapSep));
|
||||||
|
|
||||||
|
try!(key.serialize(self));
|
||||||
|
value.serialize(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_struct<V>(&mut self, name: &str, mut visitor: V) -> Result<(), Error>
|
||||||
where V: ser::MapVisitor
|
where V: ser::MapVisitor
|
||||||
{
|
{
|
||||||
let len = visitor.len();
|
let len = visitor.len();
|
||||||
|
|
||||||
assert_eq!(self.tokens.next(), Some(&Token::StructStart(name, len)));
|
assert_eq!(self.tokens.next(), Some(&Token::StructStart(name, len)));
|
||||||
|
|
||||||
self.visit_mapping(visitor)
|
while let Some(()) = try!(visitor.visit(self)) { }
|
||||||
|
|
||||||
|
assert_eq!(self.tokens.next(), Some(&Token::StructEnd));
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_struct_elt<T>(&mut self, key: &'static str, value: T) -> Result<(), Error>
|
||||||
|
where T: ser::Serialize,
|
||||||
|
{
|
||||||
|
assert_eq!(self.tokens.next(), Some(&Token::StructSep));
|
||||||
|
|
||||||
|
try!(key.serialize(self));
|
||||||
|
value.serialize(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_struct_variant<V>(&mut self,
|
fn serialize_struct_variant<V>(&mut self,
|
||||||
name: &str,
|
name: &str,
|
||||||
_variant_index: usize,
|
_variant_index: usize,
|
||||||
variant: &str,
|
variant: &str,
|
||||||
visitor: V) -> Result<(), Error>
|
mut visitor: V) -> Result<(), Error>
|
||||||
where V: ser::MapVisitor
|
where V: ser::MapVisitor
|
||||||
{
|
{
|
||||||
let len = visitor.len();
|
let len = visitor.len();
|
||||||
|
|
||||||
assert_eq!(self.tokens.next(), Some(&Token::EnumMapStart(name, variant, len)));
|
assert_eq!(self.tokens.next(), Some(&Token::EnumMapStart(name, variant, len)));
|
||||||
|
|
||||||
self.visit_mapping(visitor)
|
while let Some(()) = try!(visitor.visit(self)) { }
|
||||||
|
|
||||||
|
assert_eq!(self.tokens.next(), Some(&Token::EnumMapEnd));
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_map_elt<K, V>(&mut self, key: K, value: V) -> Result<(), Error>
|
fn serialize_struct_variant_elt<T>(&mut self, key: &'static str, value: T) -> Result<(), Error>
|
||||||
where K: ser::Serialize,
|
where T: ser::Serialize,
|
||||||
V: ser::Serialize,
|
|
||||||
{
|
{
|
||||||
assert_eq!(self.tokens.next(), Some(&Token::MapSep));
|
assert_eq!(self.tokens.next(), Some(&Token::EnumMapSep));
|
||||||
|
|
||||||
try!(key.serialize(self));
|
try!(key.serialize(self));
|
||||||
value.serialize(self)
|
value.serialize(self)
|
||||||
@ -383,6 +444,24 @@ impl<I> Deserializer<I>
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn visit_tuple_seq<V>(&mut self, len: Option<usize>, mut visitor: V) -> Result<V::Value, Error>
|
||||||
|
where V: de::Visitor,
|
||||||
|
{
|
||||||
|
visitor.visit_seq(DeserializerTupleSeqVisitor {
|
||||||
|
de: self,
|
||||||
|
len: len,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_variant_seq<V>(&mut self, len: Option<usize>, mut visitor: V) -> Result<V::Value, Error>
|
||||||
|
where V: de::Visitor,
|
||||||
|
{
|
||||||
|
visitor.visit_seq(DeserializerVariantSeqVisitor {
|
||||||
|
de: self,
|
||||||
|
len: len,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fn visit_map<V>(&mut self, len: Option<usize>, mut visitor: V) -> Result<V::Value, Error>
|
fn visit_map<V>(&mut self, len: Option<usize>, mut visitor: V) -> Result<V::Value, Error>
|
||||||
where V: de::Visitor,
|
where V: de::Visitor,
|
||||||
{
|
{
|
||||||
@ -391,6 +470,24 @@ impl<I> Deserializer<I>
|
|||||||
len: len,
|
len: len,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn visit_struct<V>(&mut self, len: Option<usize>, mut visitor: V) -> Result<V::Value, Error>
|
||||||
|
where V: de::Visitor,
|
||||||
|
{
|
||||||
|
visitor.visit_map(DeserializerStructVisitor {
|
||||||
|
de: self,
|
||||||
|
len: len,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_variant_map<V>(&mut self, len: Option<usize>, mut visitor: V) -> Result<V::Value, Error>
|
||||||
|
where V: de::Visitor,
|
||||||
|
{
|
||||||
|
visitor.visit_map(DeserializerVariantMapVisitor {
|
||||||
|
de: self,
|
||||||
|
len: len,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I> de::Deserializer for Deserializer<I>
|
impl<I> de::Deserializer for Deserializer<I>
|
||||||
@ -429,7 +526,6 @@ impl<I> de::Deserializer for Deserializer<I>
|
|||||||
Some(Token::MapStart(len)) | Some(Token::StructStart(_, len)) => {
|
Some(Token::MapStart(len)) | Some(Token::StructStart(_, len)) => {
|
||||||
self.visit_map(len, visitor)
|
self.visit_map(len, visitor)
|
||||||
}
|
}
|
||||||
//Some(Token::Name(_)) => self.visit(visitor),
|
|
||||||
Some(token) => Err(Error::UnexpectedToken(token)),
|
Some(token) => Err(Error::UnexpectedToken(token)),
|
||||||
None => Err(Error::EndOfStreamError),
|
None => Err(Error::EndOfStreamError),
|
||||||
}
|
}
|
||||||
@ -473,7 +569,7 @@ impl<I> de::Deserializer for Deserializer<I>
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
Some(&Token::EnumUnit(n, _))
|
Some(&Token::EnumUnit(n, _))
|
||||||
| Some(&Token::EnumNewtype(n, _))
|
| Some(&Token::EnumNewType(n, _))
|
||||||
| Some(&Token::EnumSeqStart(n, _, _))
|
| Some(&Token::EnumSeqStart(n, _, _))
|
||||||
| Some(&Token::EnumMapStart(n, _, _)) if name == n => {
|
| Some(&Token::EnumMapStart(n, _, _)) if name == n => {
|
||||||
visitor.visit(DeserializerVariantVisitor {
|
visitor.visit(DeserializerVariantVisitor {
|
||||||
@ -506,12 +602,12 @@ impl<I> de::Deserializer for Deserializer<I>
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_newtype_struct<V>(&mut self,
|
fn deserialize_newtype_struct<V>(&mut self,
|
||||||
name: &str,
|
name: &str,
|
||||||
mut visitor: V) -> Result<V::Value, Error>
|
mut visitor: V) -> Result<V::Value, Error>
|
||||||
where V: de::Visitor,
|
where V: de::Visitor,
|
||||||
{
|
{
|
||||||
match self.tokens.peek() {
|
match self.tokens.peek() {
|
||||||
Some(&Token::StructNewtype(n)) => {
|
Some(&Token::StructNewType(n)) => {
|
||||||
self.tokens.next();
|
self.tokens.next();
|
||||||
if name == n {
|
if name == n {
|
||||||
visitor.visit_newtype_struct(self)
|
visitor.visit_newtype_struct(self)
|
||||||
@ -525,9 +621,9 @@ impl<I> de::Deserializer for Deserializer<I>
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_tuple_struct<V>(&mut self,
|
fn deserialize_tuple_struct<V>(&mut self,
|
||||||
name: &str,
|
name: &str,
|
||||||
len: usize,
|
len: usize,
|
||||||
mut visitor: V) -> Result<V::Value, Error>
|
mut visitor: V) -> Result<V::Value, Error>
|
||||||
where V: de::Visitor,
|
where V: de::Visitor,
|
||||||
{
|
{
|
||||||
match self.tokens.peek() {
|
match self.tokens.peek() {
|
||||||
@ -542,7 +638,7 @@ impl<I> de::Deserializer for Deserializer<I>
|
|||||||
Some(&Token::TupleStructStart(n, _)) => {
|
Some(&Token::TupleStructStart(n, _)) => {
|
||||||
self.tokens.next();
|
self.tokens.next();
|
||||||
if name == n {
|
if name == n {
|
||||||
self.visit_seq(Some(len), visitor)
|
self.visit_tuple_seq(Some(len), visitor)
|
||||||
} else {
|
} else {
|
||||||
Err(Error::InvalidName(n))
|
Err(Error::InvalidName(n))
|
||||||
}
|
}
|
||||||
@ -557,16 +653,16 @@ impl<I> de::Deserializer for Deserializer<I>
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_struct<V>(&mut self,
|
fn deserialize_struct<V>(&mut self,
|
||||||
name: &str,
|
name: &str,
|
||||||
fields: &'static [&'static str],
|
fields: &'static [&'static str],
|
||||||
visitor: V) -> Result<V::Value, Error>
|
visitor: V) -> Result<V::Value, Error>
|
||||||
where V: de::Visitor,
|
where V: de::Visitor,
|
||||||
{
|
{
|
||||||
match self.tokens.peek() {
|
match self.tokens.peek() {
|
||||||
Some(&Token::StructStart(n, _)) => {
|
Some(&Token::StructStart(n, _)) => {
|
||||||
self.tokens.next();
|
self.tokens.next();
|
||||||
if name == n {
|
if name == n {
|
||||||
self.visit_map(Some(fields.len()), visitor)
|
self.visit_struct(Some(fields.len()), visitor)
|
||||||
} else {
|
} else {
|
||||||
Err(Error::InvalidName(n))
|
Err(Error::InvalidName(n))
|
||||||
}
|
}
|
||||||
@ -628,6 +724,96 @@ impl<'a, I> de::SeqVisitor for DeserializerSeqVisitor<'a, I>
|
|||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
struct DeserializerTupleSeqVisitor<'a, I: 'a> where I: Iterator<Item=Token<'static>> {
|
||||||
|
de: &'a mut Deserializer<I>,
|
||||||
|
len: Option<usize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, I> de::SeqVisitor for DeserializerTupleSeqVisitor<'a, I>
|
||||||
|
where I: Iterator<Item=Token<'static>>,
|
||||||
|
{
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn visit<T>(&mut self) -> Result<Option<T>, Error>
|
||||||
|
where T: de::Deserialize,
|
||||||
|
{
|
||||||
|
match self.de.tokens.peek() {
|
||||||
|
Some(&Token::TupleSeqSep) => {
|
||||||
|
self.de.tokens.next();
|
||||||
|
self.len = self.len.map(|len| len - 1);
|
||||||
|
Ok(Some(try!(de::Deserialize::deserialize(self.de))))
|
||||||
|
}
|
||||||
|
Some(&Token::TupleSeqEnd) => Ok(None),
|
||||||
|
Some(_) => {
|
||||||
|
let token = self.de.tokens.next().unwrap();
|
||||||
|
Err(Error::UnexpectedToken(token))
|
||||||
|
}
|
||||||
|
None => Err(Error::EndOfStreamError),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn end(&mut self) -> Result<(), Error> {
|
||||||
|
//assert_eq!(self.len.unwrap_or(0), 0);
|
||||||
|
match self.de.tokens.next() {
|
||||||
|
Some(Token::TupleSeqEnd) => Ok(()),
|
||||||
|
Some(token) => Err(Error::UnexpectedToken(token)),
|
||||||
|
None => Err(Error::EndOfStreamError),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
|
let len = self.len.unwrap_or(0);
|
||||||
|
(len, self.len)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
struct DeserializerVariantSeqVisitor<'a, I: 'a> where I: Iterator<Item=Token<'static>> {
|
||||||
|
de: &'a mut Deserializer<I>,
|
||||||
|
len: Option<usize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, I> de::SeqVisitor for DeserializerVariantSeqVisitor<'a, I>
|
||||||
|
where I: Iterator<Item=Token<'static>>,
|
||||||
|
{
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn visit<T>(&mut self) -> Result<Option<T>, Error>
|
||||||
|
where T: de::Deserialize,
|
||||||
|
{
|
||||||
|
match self.de.tokens.peek() {
|
||||||
|
Some(&Token::EnumSeqSep) => {
|
||||||
|
self.de.tokens.next();
|
||||||
|
self.len = self.len.map(|len| len - 1);
|
||||||
|
Ok(Some(try!(de::Deserialize::deserialize(self.de))))
|
||||||
|
}
|
||||||
|
Some(&Token::EnumSeqEnd) => Ok(None),
|
||||||
|
Some(_) => {
|
||||||
|
let token = self.de.tokens.next().unwrap();
|
||||||
|
Err(Error::UnexpectedToken(token))
|
||||||
|
}
|
||||||
|
None => Err(Error::EndOfStreamError),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn end(&mut self) -> Result<(), Error> {
|
||||||
|
//assert_eq!(self.len.unwrap_or(0), 0);
|
||||||
|
match self.de.tokens.next() {
|
||||||
|
Some(Token::EnumSeqEnd) => Ok(()),
|
||||||
|
Some(token) => Err(Error::UnexpectedToken(token)),
|
||||||
|
None => Err(Error::EndOfStreamError),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
|
let len = self.len.unwrap_or(0);
|
||||||
|
(len, self.len)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
struct DeserializerMapVisitor<'a, I: 'a> where I: Iterator<Item=Token<'static>> {
|
struct DeserializerMapVisitor<'a, I: 'a> where I: Iterator<Item=Token<'static>> {
|
||||||
de: &'a mut Deserializer<I>,
|
de: &'a mut Deserializer<I>,
|
||||||
len: Option<usize>,
|
len: Option<usize>,
|
||||||
@ -679,6 +865,57 @@ impl<'a, I> de::MapVisitor for DeserializerMapVisitor<'a, I>
|
|||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
struct DeserializerStructVisitor<'a, I: 'a> where I: Iterator<Item=Token<'static>> {
|
||||||
|
de: &'a mut Deserializer<I>,
|
||||||
|
len: Option<usize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, I> de::MapVisitor for DeserializerStructVisitor<'a, I>
|
||||||
|
where I: Iterator<Item=Token<'static>>,
|
||||||
|
{
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn visit_key<K>(&mut self) -> Result<Option<K>, Error>
|
||||||
|
where K: de::Deserialize,
|
||||||
|
{
|
||||||
|
match self.de.tokens.peek() {
|
||||||
|
Some(&Token::StructSep) => {
|
||||||
|
self.de.tokens.next();
|
||||||
|
self.len = self.len.map(|len| if len > 0 { len - 1} else { 0 });
|
||||||
|
Ok(Some(try!(de::Deserialize::deserialize(self.de))))
|
||||||
|
}
|
||||||
|
Some(&Token::StructEnd) => Ok(None),
|
||||||
|
Some(_) => {
|
||||||
|
let token = self.de.tokens.next().unwrap();
|
||||||
|
Err(Error::UnexpectedToken(token))
|
||||||
|
}
|
||||||
|
None => Err(Error::EndOfStreamError),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_value<V>(&mut self) -> Result<V, Error>
|
||||||
|
where V: de::Deserialize,
|
||||||
|
{
|
||||||
|
Ok(try!(de::Deserialize::deserialize(self.de)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn end(&mut self) -> Result<(), Error> {
|
||||||
|
//assert_eq!(self.len.unwrap_or(0), 0);
|
||||||
|
match self.de.tokens.next() {
|
||||||
|
Some(Token::StructEnd) => Ok(()),
|
||||||
|
Some(token) => Err(Error::UnexpectedToken(token)),
|
||||||
|
None => Err(Error::EndOfStreamError),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
|
let len = self.len.unwrap_or(0);
|
||||||
|
(len, self.len)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
struct DeserializerVariantVisitor<'a, I: 'a> where I: Iterator<Item=Token<'static>> {
|
struct DeserializerVariantVisitor<'a, I: 'a> where I: Iterator<Item=Token<'static>> {
|
||||||
de: &'a mut Deserializer<I>,
|
de: &'a mut Deserializer<I>,
|
||||||
}
|
}
|
||||||
@ -693,7 +930,7 @@ impl<'a, I> de::VariantVisitor for DeserializerVariantVisitor<'a, I>
|
|||||||
{
|
{
|
||||||
match self.de.tokens.peek() {
|
match self.de.tokens.peek() {
|
||||||
Some(&Token::EnumUnit(_, v))
|
Some(&Token::EnumUnit(_, v))
|
||||||
| Some(&Token::EnumNewtype(_, v))
|
| Some(&Token::EnumNewType(_, v))
|
||||||
| Some(&Token::EnumSeqStart(_, v, _))
|
| Some(&Token::EnumSeqStart(_, v, _))
|
||||||
| Some(&Token::EnumMapStart(_, v, _)) => {
|
| Some(&Token::EnumMapStart(_, v, _)) => {
|
||||||
let mut de = ValueDeserializer::<Error>::into_deserializer(v);
|
let mut de = ValueDeserializer::<Error>::into_deserializer(v);
|
||||||
@ -724,7 +961,7 @@ impl<'a, I> de::VariantVisitor for DeserializerVariantVisitor<'a, I>
|
|||||||
where T: de::Deserialize,
|
where T: de::Deserialize,
|
||||||
{
|
{
|
||||||
match self.de.tokens.peek() {
|
match self.de.tokens.peek() {
|
||||||
Some(&Token::EnumNewtype(_, _)) => {
|
Some(&Token::EnumNewType(_, _)) => {
|
||||||
self.de.tokens.next();
|
self.de.tokens.next();
|
||||||
de::Deserialize::deserialize(self.de)
|
de::Deserialize::deserialize(self.de)
|
||||||
}
|
}
|
||||||
@ -744,6 +981,15 @@ impl<'a, I> de::VariantVisitor for DeserializerVariantVisitor<'a, I>
|
|||||||
Some(&Token::EnumSeqStart(_, _, Some(enum_len))) => {
|
Some(&Token::EnumSeqStart(_, _, Some(enum_len))) => {
|
||||||
let token = self.de.tokens.next().unwrap();
|
let token = self.de.tokens.next().unwrap();
|
||||||
|
|
||||||
|
if len == enum_len {
|
||||||
|
self.de.visit_variant_seq(Some(len), visitor)
|
||||||
|
} else {
|
||||||
|
Err(Error::UnexpectedToken(token))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(&Token::SeqStart(Some(enum_len))) => {
|
||||||
|
let token = self.de.tokens.next().unwrap();
|
||||||
|
|
||||||
if len == enum_len {
|
if len == enum_len {
|
||||||
self.de.visit_seq(Some(len), visitor)
|
self.de.visit_seq(Some(len), visitor)
|
||||||
} else {
|
} else {
|
||||||
@ -766,6 +1012,15 @@ impl<'a, I> de::VariantVisitor for DeserializerVariantVisitor<'a, I>
|
|||||||
Some(&Token::EnumMapStart(_, _, Some(enum_len))) => {
|
Some(&Token::EnumMapStart(_, _, Some(enum_len))) => {
|
||||||
let token = self.de.tokens.next().unwrap();
|
let token = self.de.tokens.next().unwrap();
|
||||||
|
|
||||||
|
if fields.len() == enum_len {
|
||||||
|
self.de.visit_variant_map(Some(fields.len()), visitor)
|
||||||
|
} else {
|
||||||
|
Err(Error::UnexpectedToken(token))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(&Token::MapStart(Some(enum_len))) => {
|
||||||
|
let token = self.de.tokens.next().unwrap();
|
||||||
|
|
||||||
if fields.len() == enum_len {
|
if fields.len() == enum_len {
|
||||||
self.de.visit_map(Some(fields.len()), visitor)
|
self.de.visit_map(Some(fields.len()), visitor)
|
||||||
} else {
|
} else {
|
||||||
@ -780,6 +1035,57 @@ impl<'a, I> de::VariantVisitor for DeserializerVariantVisitor<'a, I>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
struct DeserializerVariantMapVisitor<'a, I: 'a> where I: Iterator<Item=Token<'static>> {
|
||||||
|
de: &'a mut Deserializer<I>,
|
||||||
|
len: Option<usize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, I> de::MapVisitor for DeserializerVariantMapVisitor<'a, I>
|
||||||
|
where I: Iterator<Item=Token<'static>>,
|
||||||
|
{
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn visit_key<K>(&mut self) -> Result<Option<K>, Error>
|
||||||
|
where K: de::Deserialize,
|
||||||
|
{
|
||||||
|
match self.de.tokens.peek() {
|
||||||
|
Some(&Token::EnumMapSep) => {
|
||||||
|
self.de.tokens.next();
|
||||||
|
self.len = self.len.map(|len| if len > 0 { len - 1} else { 0 });
|
||||||
|
Ok(Some(try!(de::Deserialize::deserialize(self.de))))
|
||||||
|
}
|
||||||
|
Some(&Token::EnumMapEnd) => Ok(None),
|
||||||
|
Some(_) => {
|
||||||
|
let token = self.de.tokens.next().unwrap();
|
||||||
|
Err(Error::UnexpectedToken(token))
|
||||||
|
}
|
||||||
|
None => Err(Error::EndOfStreamError),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_value<V>(&mut self) -> Result<V, Error>
|
||||||
|
where V: de::Deserialize,
|
||||||
|
{
|
||||||
|
Ok(try!(de::Deserialize::deserialize(self.de)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn end(&mut self) -> Result<(), Error> {
|
||||||
|
//assert_eq!(self.len.unwrap_or(0), 0);
|
||||||
|
match self.de.tokens.next() {
|
||||||
|
Some(Token::EnumMapEnd) => Ok(()),
|
||||||
|
Some(token) => Err(Error::UnexpectedToken(token)),
|
||||||
|
None => Err(Error::EndOfStreamError),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
|
let len = self.len.unwrap_or(0);
|
||||||
|
(len, self.len)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
pub fn assert_ser_tokens<T>(value: &T, tokens: &[Token])
|
pub fn assert_ser_tokens<T>(value: &T, tokens: &[Token])
|
||||||
|
Loading…
x
Reference in New Issue
Block a user