mirror of
https://github.com/serde-rs/serde.git
synced 2025-09-30 06:21:26 +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
|
||||
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:
|
||||
|
||||
| Annotation | Function |
|
||||
| ---------- | -------- |
|
||||
| `#[serde(rename(json="name1", xml="name2"))` | Serialize this field with the given name for the given formats |
|
||||
| `#[serde(default)` | If the value is not specified, use the `Default::default()` |
|
||||
| `#[serde(rename="name")` | Serialize this field with the given name |
|
||||
| `#[serde(skip_serializing)` | Do not serialize this value |
|
||||
| `#[serde(skip_serializing_if_empty)` | Do not serialize this value if `$value.is_empty()` is `true` |
|
||||
| `#[serde(skip_serializing_if_none)` | Do not serialize this value if `$value.is_none()` is `true` |
|
||||
|
||||
Structure Annotations:
|
||||
|
||||
| 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. |
|
||||
|
||||
| Annotation | Function |
|
||||
| ---------- | -------- |
|
||||
| `#[serde(rename="name")` | Serialize and deserialize this field with the given name |
|
||||
| `#[serde(rename(serialize="name1"))` | Serialize this field with the given name |
|
||||
| `#[serde(rename(deserialize="name1"))` | Deserialize this field with the given name |
|
||||
| `#[serde(default)` | If the value is not specified, use the `Default::default()` |
|
||||
| `#[serde(default="$path")` | Call the path to a function `fn() -> T` to build the value |
|
||||
| `#[serde(skip_serializing)` | Do not serialize this value |
|
||||
| `#[serde(skip_serializing_if="$path")` | Do not serialize this value if this function `fn(&T) -> bool` returns `false` |
|
||||
| `#[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 |
|
||||
|
||||
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::codemap::Span;
|
||||
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 aster::AstBuilder;
|
||||
@ -165,14 +171,21 @@ pub struct FieldAttrs {
|
||||
serialize_name: Option<ast::Lit>,
|
||||
deserialize_name: Option<ast::Lit>,
|
||||
skip_serializing_field: bool,
|
||||
skip_serializing_field_if_empty: bool,
|
||||
skip_serializing_field_if_none: bool,
|
||||
use_default: bool,
|
||||
skip_serializing_field_if: Option<P<ast::Expr>>,
|
||||
default_expr_if_missing: Option<P<ast::Expr>>,
|
||||
serialize_with: Option<P<ast::Expr>>,
|
||||
deserialize_with: Option<P<ast::Expr>>,
|
||||
}
|
||||
|
||||
impl FieldAttrs {
|
||||
/// 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() {
|
||||
Some(ident) => ident,
|
||||
None => { cx.span_bug(field.span, "struct field has no name?") }
|
||||
@ -183,9 +196,10 @@ impl FieldAttrs {
|
||||
serialize_name: None,
|
||||
deserialize_name: None,
|
||||
skip_serializing_field: false,
|
||||
skip_serializing_field_if_empty: false,
|
||||
skip_serializing_field_if_none: false,
|
||||
use_default: false,
|
||||
skip_serializing_field_if: None,
|
||||
default_expr_if_missing: None,
|
||||
serialize_with: None,
|
||||
deserialize_with: None,
|
||||
};
|
||||
|
||||
for meta_items in field.node.attrs.iter().filter_map(get_serde_meta_items) {
|
||||
@ -206,7 +220,17 @@ impl FieldAttrs {
|
||||
|
||||
// Parse `#[serde(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)]`
|
||||
@ -214,14 +238,41 @@ impl FieldAttrs {
|
||||
field_attrs.skip_serializing_field = true;
|
||||
}
|
||||
|
||||
// Parse `#[serde(skip_serializing_if_none)]`
|
||||
ast::MetaItemKind::Word(ref name) if name == &"skip_serializing_if_none" => {
|
||||
field_attrs.skip_serializing_field_if_none = true;
|
||||
// Parse `#[serde(skip_serializing_if="...")]`
|
||||
ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"skip_serializing_if" => {
|
||||
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)]`
|
||||
ast::MetaItemKind::Word(ref name) if name == &"skip_serializing_if_empty" => {
|
||||
field_attrs.skip_serializing_field_if_empty = true;
|
||||
// Parse `#[serde(serialize_with="...")]`
|
||||
ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"serialize_with" => {
|
||||
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
|
||||
pub fn use_default(&self) -> bool {
|
||||
self.use_default
|
||||
pub fn expr_is_missing(&self) -> P<ast::Expr> {
|
||||
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
|
||||
@ -270,20 +331,28 @@ impl FieldAttrs {
|
||||
self.skip_serializing_field
|
||||
}
|
||||
|
||||
pub fn skip_serializing_field_if_empty(&self) -> bool {
|
||||
self.skip_serializing_field_if_empty
|
||||
pub fn skip_serializing_field_if(&self) -> Option<&P<ast::Expr>> {
|
||||
self.skip_serializing_field_if.as_ref()
|
||||
}
|
||||
|
||||
pub fn skip_serializing_field_if_none(&self) -> bool {
|
||||
self.skip_serializing_field_if_none
|
||||
pub fn serialize_with(&self) -> Option<&P<ast::Expr>> {
|
||||
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.
|
||||
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()
|
||||
.map(|field| FieldAttrs::from_field(cx, field))
|
||||
.map(|field| FieldAttrs::from_field(cx, container_ty, generics, field, is_enum))
|
||||
.collect()
|
||||
}
|
||||
|
||||
@ -325,3 +394,239 @@ fn get_serde_meta_items(attr: &ast::Attribute) -> Option<&[P<ast::MetaItem>]> {
|
||||
_ => 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,
|
||||
builder,
|
||||
type_path.clone(),
|
||||
&ty,
|
||||
impl_generics,
|
||||
fields,
|
||||
container_attrs
|
||||
container_attrs,
|
||||
false,
|
||||
));
|
||||
|
||||
let type_name = container_attrs.deserialize_name_expr();
|
||||
@ -756,8 +759,11 @@ fn deserialize_struct_variant(
|
||||
cx,
|
||||
builder,
|
||||
type_path,
|
||||
&ty,
|
||||
generics,
|
||||
fields,
|
||||
container_attrs,
|
||||
true,
|
||||
));
|
||||
|
||||
let (visitor_item, visitor_ty, visitor_expr, visitor_generics) = try!(deserialize_visitor(
|
||||
@ -918,20 +924,29 @@ fn deserialize_struct_visitor(
|
||||
cx: &ExtCtxt,
|
||||
builder: &aster::AstBuilder,
|
||||
struct_path: ast::Path,
|
||||
container_ty: &P<ast::Ty>,
|
||||
generics: &ast::Generics,
|
||||
fields: &[ast::StructField],
|
||||
container_attrs: &attr::ContainerAttrs,
|
||||
is_enum: bool,
|
||||
) -> 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(
|
||||
cx,
|
||||
builder,
|
||||
try!(
|
||||
fields.iter()
|
||||
.map(|field| {
|
||||
let attrs = try!(attr::FieldAttrs::from_field(cx, field));
|
||||
Ok(attrs.deserialize_name_expr())
|
||||
})
|
||||
.collect()
|
||||
),
|
||||
try!(field_exprs),
|
||||
container_attrs
|
||||
);
|
||||
|
||||
@ -939,8 +954,11 @@ fn deserialize_struct_visitor(
|
||||
cx,
|
||||
builder,
|
||||
struct_path,
|
||||
container_ty,
|
||||
generics,
|
||||
fields,
|
||||
container_attrs,
|
||||
is_enum,
|
||||
));
|
||||
|
||||
let fields_expr = builder.expr().ref_().slice()
|
||||
@ -968,14 +986,23 @@ fn deserialize_map(
|
||||
cx: &ExtCtxt,
|
||||
builder: &aster::AstBuilder,
|
||||
struct_path: ast::Path,
|
||||
container_ty: &P<ast::Ty>,
|
||||
generics: &ast::Generics,
|
||||
fields: &[ast::StructField],
|
||||
container_attrs: &attr::ContainerAttrs,
|
||||
is_enum: bool,
|
||||
) -> Result<P<ast::Expr>, Error> {
|
||||
// Create the field names for the fields.
|
||||
let field_names: Vec<ast::Ident> = (0 .. fields.len())
|
||||
.map(|i| builder.id(format!("__field{}", i)))
|
||||
.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.
|
||||
let let_values: Vec<ast::Stmt> = field_names.iter()
|
||||
.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.
|
||||
let value_arms: Vec<ast::Arm> = field_names.iter()
|
||||
.map(|field_name| {
|
||||
let value_arms = field_attrs.iter().zip(field_names.iter())
|
||||
.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,
|
||||
__Field::$field_name => {
|
||||
$field_name = Some(try!(visitor.visit_value()));
|
||||
$field_name = Some(try!($expr));
|
||||
}
|
||||
)
|
||||
})
|
||||
.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()
|
||||
.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,
|
||||
Ok(quote_stmt!(cx,
|
||||
let $field_name = match $field_name {
|
||||
Some($field_name) => $field_name,
|
||||
None => $missing_expr
|
||||
};
|
||||
).unwrap()
|
||||
).unwrap())
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
.collect::<Result<Vec<_>, _>>();
|
||||
|
||||
let extract_values = try!(extract_values);
|
||||
|
||||
let result = builder.expr().struct_path(struct_path)
|
||||
.with_id_exprs(
|
||||
|
@ -33,14 +33,30 @@ pub fn expand_derive_serialize(
|
||||
|
||||
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 {
|
||||
ast::ItemKind::Struct(_, ref generics) => generics,
|
||||
ast::ItemKind::Enum(_, ref generics) => generics,
|
||||
_ => {
|
||||
cx.span_err(
|
||||
meta_item.span,
|
||||
item.span,
|
||||
"`#[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()
|
||||
.build();
|
||||
|
||||
let body = match serialize_body(cx, &builder, &item, &impl_generics, ty.clone()) {
|
||||
Ok(body) => body,
|
||||
Err(Error) => {
|
||||
// An error occured, but it should have been reported already.
|
||||
return;
|
||||
}
|
||||
};
|
||||
let body = try!(serialize_body(cx,
|
||||
&builder,
|
||||
&item,
|
||||
&impl_generics,
|
||||
ty.clone()));
|
||||
|
||||
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 {
|
||||
fn serialize<__S>(&self, serializer: &mut __S) -> ::std::result::Result<(), __S::Error>
|
||||
where __S: ::serde::ser::Serializer,
|
||||
@ -72,9 +86,7 @@ pub fn expand_derive_serialize(
|
||||
$body
|
||||
}
|
||||
}
|
||||
).unwrap();
|
||||
|
||||
push(Annotatable::Item(impl_item))
|
||||
).unwrap())
|
||||
}
|
||||
|
||||
fn serialize_body(
|
||||
@ -207,6 +219,7 @@ fn serialize_tuple_struct(
|
||||
.ref_()
|
||||
.lifetime("'__a")
|
||||
.build_ty(ty.clone()),
|
||||
builder.id("serialize_tuple_struct_elt"),
|
||||
fields,
|
||||
impl_generics,
|
||||
);
|
||||
@ -232,11 +245,6 @@ fn serialize_struct(
|
||||
fields: &[ast::StructField],
|
||||
container_attrs: &attr::ContainerAttrs,
|
||||
) -> 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(
|
||||
cx,
|
||||
builder,
|
||||
@ -245,9 +253,10 @@ fn serialize_struct(
|
||||
.ref_()
|
||||
.lifetime("'__a")
|
||||
.build_ty(ty.clone()),
|
||||
builder.id("serialize_struct_elt"),
|
||||
fields,
|
||||
impl_generics,
|
||||
value_exprs,
|
||||
false,
|
||||
));
|
||||
|
||||
let type_name = container_attrs.serialize_name_expr();
|
||||
@ -272,22 +281,23 @@ fn serialize_item_enum(
|
||||
enum_def: &ast::EnumDef,
|
||||
container_attrs: &attr::ContainerAttrs,
|
||||
) -> Result<P<ast::Expr>, Error> {
|
||||
let mut arms = vec![];
|
||||
|
||||
for (variant_index, variant) in enum_def.variants.iter().enumerate() {
|
||||
let arm = try!(serialize_variant(
|
||||
cx,
|
||||
builder,
|
||||
type_ident,
|
||||
impl_generics,
|
||||
ty.clone(),
|
||||
variant,
|
||||
variant_index,
|
||||
container_attrs,
|
||||
));
|
||||
|
||||
arms.push(arm);
|
||||
}
|
||||
let arms: Vec<_> = try!(
|
||||
enum_def.variants.iter()
|
||||
.enumerate()
|
||||
.map(|(variant_index, variant)| {
|
||||
serialize_variant(
|
||||
cx,
|
||||
builder,
|
||||
type_ident,
|
||||
impl_generics,
|
||||
ty.clone(),
|
||||
variant,
|
||||
variant_index,
|
||||
container_attrs,
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
);
|
||||
|
||||
Ok(quote_expr!(cx,
|
||||
match *self {
|
||||
@ -404,13 +414,13 @@ fn serialize_variant(
|
||||
let expr = try!(serialize_struct_variant(
|
||||
cx,
|
||||
builder,
|
||||
type_name,
|
||||
variant_index,
|
||||
variant_name,
|
||||
generics,
|
||||
ty,
|
||||
fields,
|
||||
field_names,
|
||||
container_attrs,
|
||||
));
|
||||
|
||||
Ok(quote_arm!(cx,
|
||||
@ -447,6 +457,7 @@ fn serialize_tuple_variant(
|
||||
builder,
|
||||
structure_ty.clone(),
|
||||
variant_ty,
|
||||
builder.id("serialize_tuple_variant_elt"),
|
||||
fields.len(),
|
||||
generics,
|
||||
);
|
||||
@ -473,55 +484,89 @@ fn serialize_tuple_variant(
|
||||
fn serialize_struct_variant(
|
||||
cx: &ExtCtxt,
|
||||
builder: &aster::AstBuilder,
|
||||
type_name: P<ast::Expr>,
|
||||
variant_index: usize,
|
||||
variant_name: P<ast::Expr>,
|
||||
generics: &ast::Generics,
|
||||
structure_ty: P<ast::Ty>,
|
||||
ty: P<ast::Ty>,
|
||||
fields: &[ast::StructField],
|
||||
field_names: Vec<Ident>,
|
||||
container_attrs: &attr::ContainerAttrs,
|
||||
) -> Result<P<ast::Expr>, Error> {
|
||||
let value_ty = builder.ty().tuple()
|
||||
.with_tys(
|
||||
let variant_generics = builder.generics()
|
||||
.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| {
|
||||
builder.ty()
|
||||
builder.struct_field(field.node.ident().expect("struct has unnamed fields"))
|
||||
.with_attrs(field.node.attrs.iter().cloned())
|
||||
.ty()
|
||||
.ref_()
|
||||
.lifetime("'__a")
|
||||
.lifetime("'__serde_variant")
|
||||
.build_ty(field.node.ty.clone())
|
||||
})
|
||||
)
|
||||
.field("__serde_container_ty")
|
||||
.ty().phantom_data().build(ty.clone())
|
||||
.build();
|
||||
|
||||
let value_expr = builder.expr().tuple()
|
||||
.with_exprs(
|
||||
field_names.iter().map(|field| {
|
||||
builder.expr().id(field)
|
||||
})
|
||||
let variant_expr = builder.expr().struct_id("__VariantStruct")
|
||||
.with_id_exprs(
|
||||
fields.iter()
|
||||
.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();
|
||||
|
||||
let (visitor_struct, visitor_impl) = try!(serialize_struct_visitor(
|
||||
cx,
|
||||
builder,
|
||||
structure_ty.clone(),
|
||||
value_ty,
|
||||
variant_ty.clone(),
|
||||
variant_ty.clone(),
|
||||
builder.id("serialize_struct_variant_elt"),
|
||||
fields,
|
||||
generics,
|
||||
(0 .. field_names.len()).map(|i| {
|
||||
builder.expr()
|
||||
.tup_field(i)
|
||||
.field("value").self_()
|
||||
})
|
||||
&variant_generics,
|
||||
true,
|
||||
));
|
||||
|
||||
let container_name = container_attrs.serialize_name_expr();
|
||||
|
||||
Ok(quote_expr!(cx, {
|
||||
$variant_struct
|
||||
$visitor_struct
|
||||
$visitor_impl
|
||||
serializer.serialize_struct_variant($type_name, $variant_index, $variant_name, Visitor {
|
||||
value: $value_expr,
|
||||
state: 0,
|
||||
_structure_ty: ::std::marker::PhantomData::<&$structure_ty>,
|
||||
})
|
||||
serializer.serialize_struct_variant(
|
||||
$container_name,
|
||||
$variant_index,
|
||||
$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,
|
||||
structure_ty: P<ast::Ty>,
|
||||
variant_ty: P<ast::Ty>,
|
||||
serializer_method: ast::Ident,
|
||||
fields: usize,
|
||||
generics: &ast::Generics
|
||||
) -> (P<ast::Item>, P<ast::Item>) {
|
||||
let arms: Vec<ast::Arm> = (0 .. fields)
|
||||
.map(|i| {
|
||||
let expr = builder.expr()
|
||||
.tup_field(i)
|
||||
.field("value").self_();
|
||||
let expr = builder.expr().method_call(serializer_method)
|
||||
.id("serializer")
|
||||
.arg().ref_().tup_field(i).field("value").self_()
|
||||
.build();
|
||||
|
||||
quote_arm!(cx,
|
||||
$i => {
|
||||
self.state += 1;
|
||||
let v = try!(serializer.serialize_tuple_struct_elt(&$expr));
|
||||
Ok(Some(v))
|
||||
Ok(Some(try!($expr)))
|
||||
}
|
||||
)
|
||||
})
|
||||
@ -592,51 +638,48 @@ fn serialize_tuple_struct_visitor(
|
||||
)
|
||||
}
|
||||
|
||||
fn serialize_struct_visitor<I>(
|
||||
fn serialize_struct_visitor(
|
||||
cx: &ExtCtxt,
|
||||
builder: &aster::AstBuilder,
|
||||
structure_ty: P<ast::Ty>,
|
||||
variant_ty: P<ast::Ty>,
|
||||
serializer_method: ast::Ident,
|
||||
fields: &[ast::StructField],
|
||||
generics: &ast::Generics,
|
||||
value_exprs: I,
|
||||
) -> Result<(P<ast::Item>, P<ast::Item>), Error>
|
||||
where I: Iterator<Item=P<ast::Expr>>,
|
||||
{
|
||||
let value_exprs = value_exprs.collect::<Vec<_>>();
|
||||
is_enum: bool,
|
||||
) -> Result<(P<ast::Item>, P<ast::Item>), Error> {
|
||||
let field_attrs = try!(
|
||||
attr::get_struct_field_attrs(cx, &structure_ty, generics, fields, is_enum)
|
||||
);
|
||||
|
||||
let field_attrs = try!(attr::get_struct_field_attrs(cx, fields));
|
||||
|
||||
let arms: Vec<ast::Arm> = field_attrs.iter()
|
||||
.zip(value_exprs.iter())
|
||||
.filter(|&(ref field, _)| !field.skip_serializing_field())
|
||||
let arms: Vec<ast::Arm> = fields.iter().zip(field_attrs.iter())
|
||||
.filter(|&(_, ref field_attr)| !field_attr.skip_serializing_field())
|
||||
.enumerate()
|
||||
.map(|(i, (ref field, value_expr))| {
|
||||
let key_expr = field.serialize_name_expr();
|
||||
.map(|(i, (ref field, ref field_attr))| {
|
||||
let name = field.node.ident().expect("struct has unnamed field");
|
||||
|
||||
let stmt = if field.skip_serializing_field_if_empty() {
|
||||
quote_stmt!(cx, if ($value_expr).is_empty() { continue; })
|
||||
} else if field.skip_serializing_field_if_none() {
|
||||
quote_stmt!(cx, if ($value_expr).is_none() { continue; })
|
||||
let key_expr = field_attr.serialize_name_expr();
|
||||
|
||||
let stmt = if let Some(expr) = field_attr.skip_serializing_field_if() {
|
||||
Some(quote_stmt!(cx, if $expr { continue; }))
|
||||
} 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,
|
||||
$i => {
|
||||
self.state += 1;
|
||||
$stmt
|
||||
|
||||
return Ok(
|
||||
Some(
|
||||
try!(
|
||||
serializer.serialize_struct_elt(
|
||||
$key_expr,
|
||||
$value_expr,
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
return Ok(Some(try!($expr)));
|
||||
}
|
||||
)
|
||||
})
|
||||
@ -654,16 +697,15 @@ fn serialize_struct_visitor<I>(
|
||||
.build();
|
||||
|
||||
let len = field_attrs.iter()
|
||||
.zip(value_exprs.iter())
|
||||
.map(|(field, value_expr)| {
|
||||
if field.skip_serializing_field() {
|
||||
quote_expr!(cx, 0)
|
||||
} else if field.skip_serializing_field_if_empty() {
|
||||
quote_expr!(cx, if ($value_expr).is_empty() { 0 } else { 1 })
|
||||
} else if field.skip_serializing_field_if_none() {
|
||||
quote_expr!(cx, if ($value_expr).is_none() { 0 } else { 1 })
|
||||
} else {
|
||||
quote_expr!(cx, 1)
|
||||
.filter(|field_attr| !field_attr.skip_serializing_field())
|
||||
.map(|field_attr| {
|
||||
match field_attr.skip_serializing_field_if() {
|
||||
Some(expr) => {
|
||||
quote_expr!(cx, if $expr { 0 } else { 1 })
|
||||
}
|
||||
None => {
|
||||
quote_expr!(cx, 1)
|
||||
}
|
||||
}
|
||||
})
|
||||
.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::{
|
||||
Error,
|
||||
@ -9,19 +10,201 @@ use token::{
|
||||
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)]
|
||||
struct Default {
|
||||
a1: i32,
|
||||
struct DefaultStruct<A, B: Default, C> where C: Trait {
|
||||
a1: A,
|
||||
#[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)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
struct DisallowUnknown {
|
||||
struct DenyUnknown {
|
||||
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)]
|
||||
#[serde(rename="Superhero")]
|
||||
struct RenameStruct {
|
||||
@ -38,6 +221,60 @@ struct RenameStructSerializeDeserialize {
|
||||
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)]
|
||||
#[serde(rename="Superhero")]
|
||||
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]
|
||||
fn test_rename_enum() {
|
||||
assert_tokens(
|
||||
@ -241,7 +314,7 @@ fn test_rename_enum() {
|
||||
assert_tokens(
|
||||
&RenameEnum::Superman(0),
|
||||
vec![
|
||||
Token::EnumNewtype("Superhero", "clark_kent"),
|
||||
Token::EnumNewType("Superhero", "clark_kent"),
|
||||
Token::I8(0),
|
||||
]
|
||||
);
|
||||
@ -251,13 +324,13 @@ fn test_rename_enum() {
|
||||
vec![
|
||||
Token::EnumSeqStart("Superhero", "diana_prince", Some(2)),
|
||||
|
||||
Token::SeqSep,
|
||||
Token::EnumSeqSep,
|
||||
Token::I8(0),
|
||||
|
||||
Token::SeqSep,
|
||||
Token::EnumSeqSep,
|
||||
Token::I8(1),
|
||||
|
||||
Token::SeqEnd,
|
||||
Token::EnumSeqEnd,
|
||||
]
|
||||
);
|
||||
|
||||
@ -266,17 +339,14 @@ fn test_rename_enum() {
|
||||
vec![
|
||||
Token::EnumMapStart("Superhero", "barry_allan", Some(1)),
|
||||
|
||||
Token::MapSep,
|
||||
Token::EnumMapSep,
|
||||
Token::Str("b"),
|
||||
Token::I32(1),
|
||||
|
||||
Token::MapEnd,
|
||||
Token::EnumMapEnd,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_enum_serialize_deserialize() {
|
||||
assert_ser_tokens(
|
||||
&RenameEnumSerializeDeserialize::Robin {
|
||||
a: 0,
|
||||
@ -285,15 +355,15 @@ fn test_enum_serialize_deserialize() {
|
||||
&[
|
||||
Token::EnumMapStart("SuperheroSer", "dick_grayson", Some(2)),
|
||||
|
||||
Token::MapSep,
|
||||
Token::EnumMapSep,
|
||||
Token::Str("a"),
|
||||
Token::I8(0),
|
||||
|
||||
Token::MapSep,
|
||||
Token::EnumMapSep,
|
||||
Token::Str("c"),
|
||||
Token::Str(""),
|
||||
|
||||
Token::MapEnd,
|
||||
Token::EnumMapEnd,
|
||||
]
|
||||
);
|
||||
|
||||
@ -305,208 +375,325 @@ fn test_enum_serialize_deserialize() {
|
||||
vec![
|
||||
Token::EnumMapStart("SuperheroDe", "jason_todd", Some(2)),
|
||||
|
||||
Token::MapSep,
|
||||
Token::EnumMapSep,
|
||||
Token::Str("a"),
|
||||
Token::I8(0),
|
||||
|
||||
Token::MapSep,
|
||||
Token::EnumMapSep,
|
||||
Token::Str("d"),
|
||||
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]
|
||||
fn test_skip_serializing_fields() {
|
||||
fn test_skip_serializing_struct() {
|
||||
let a = 1;
|
||||
assert_ser_tokens(
|
||||
&SkipSerializingFields {
|
||||
a: 1,
|
||||
&SkipSerializingStruct {
|
||||
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,
|
||||
},
|
||||
&[
|
||||
Token::StructStart("SkipSerializingFields", Some(1)),
|
||||
Token::StructStart("SerializeWithStruct", Some(2)),
|
||||
|
||||
Token::MapSep,
|
||||
Token::StructSep,
|
||||
Token::Str("a"),
|
||||
Token::I8(1),
|
||||
|
||||
Token::MapEnd,
|
||||
Token::StructSep,
|
||||
Token::Str("b"),
|
||||
Token::Bool(false),
|
||||
|
||||
Token::StructEnd,
|
||||
]
|
||||
);
|
||||
|
||||
assert_de_tokens(
|
||||
&SkipSerializingFields {
|
||||
a: 1,
|
||||
b: 0,
|
||||
assert_ser_tokens(
|
||||
&SerializeWithStruct {
|
||||
a: &a,
|
||||
b: 123,
|
||||
},
|
||||
vec![
|
||||
Token::StructStart("SkipSerializingFields", Some(1)),
|
||||
&[
|
||||
Token::StructStart("SerializeWithStruct", Some(2)),
|
||||
|
||||
Token::MapSep,
|
||||
Token::StructSep,
|
||||
Token::Str("a"),
|
||||
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]
|
||||
fn test_skip_serializing_fields_if_empty() {
|
||||
fn test_serialize_with_enum() {
|
||||
let a = 1;
|
||||
assert_ser_tokens(
|
||||
&SkipSerializingIfEmptyFields::<i32> {
|
||||
a: 1,
|
||||
b: vec![],
|
||||
&SerializeWithEnum::Struct {
|
||||
a: &a,
|
||||
b: 2,
|
||||
},
|
||||
&[
|
||||
Token::StructStart("SkipSerializingIfEmptyFields", Some(1)),
|
||||
Token::EnumMapStart("SerializeWithEnum", "Struct", Some(2)),
|
||||
|
||||
Token::MapSep,
|
||||
Token::EnumMapSep,
|
||||
Token::Str("a"),
|
||||
Token::I8(1),
|
||||
|
||||
Token::MapEnd,
|
||||
]
|
||||
);
|
||||
Token::EnumMapSep,
|
||||
Token::Str("b"),
|
||||
Token::Bool(false),
|
||||
|
||||
assert_de_tokens(
|
||||
&SkipSerializingIfEmptyFields::<i32> {
|
||||
a: 1,
|
||||
b: vec![],
|
||||
},
|
||||
vec![
|
||||
Token::StructStart("SkipSerializingIfEmptyFields", Some(1)),
|
||||
|
||||
Token::MapSep,
|
||||
Token::Str("a"),
|
||||
Token::I8(1),
|
||||
|
||||
Token::MapEnd,
|
||||
Token::EnumMapEnd,
|
||||
]
|
||||
);
|
||||
|
||||
assert_ser_tokens(
|
||||
&SkipSerializingIfEmptyFields {
|
||||
a: 1,
|
||||
b: vec![2],
|
||||
&SerializeWithEnum::Struct {
|
||||
a: &a,
|
||||
b: 123,
|
||||
},
|
||||
&[
|
||||
Token::StructStart("SkipSerializingIfEmptyFields", Some(2)),
|
||||
Token::EnumMapStart("SerializeWithEnum", "Struct", Some(2)),
|
||||
|
||||
Token::MapSep,
|
||||
Token::EnumMapSep,
|
||||
Token::Str("a"),
|
||||
Token::I8(1),
|
||||
|
||||
Token::MapSep,
|
||||
Token::EnumMapSep,
|
||||
Token::Str("b"),
|
||||
Token::SeqStart(Some(1)),
|
||||
Token::SeqSep,
|
||||
Token::I32(2),
|
||||
Token::SeqEnd,
|
||||
Token::Bool(true),
|
||||
|
||||
Token::MapEnd,
|
||||
Token::EnumMapEnd,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
assert_de_tokens(
|
||||
&SkipSerializingIfEmptyFields {
|
||||
a: 1,
|
||||
b: vec![2],
|
||||
},
|
||||
vec![
|
||||
Token::StructStart("SkipSerializingIfEmptyFields", Some(2)),
|
||||
|
||||
Token::MapSep,
|
||||
Token::Str("a"),
|
||||
Token::I8(1),
|
||||
|
||||
Token::MapSep,
|
||||
Token::Str("b"),
|
||||
Token::SeqStart(Some(1)),
|
||||
Token::SeqSep,
|
||||
Token::I32(2),
|
||||
Token::SeqEnd,
|
||||
|
||||
Token::MapEnd,
|
||||
]
|
||||
);
|
||||
#[derive(Debug, PartialEq, Deserialize)]
|
||||
struct DeserializeWithStruct<B> where B: Trait {
|
||||
a: i8,
|
||||
#[serde(deserialize_with="Trait::deserialize_with")]
|
||||
b: B,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_skip_serializing_fields_if_none() {
|
||||
assert_ser_tokens(
|
||||
&SkipSerializingIfNoneFields::<i32> {
|
||||
fn test_deserialize_with_struct() {
|
||||
assert_de_tokens(
|
||||
&DeserializeWithStruct {
|
||||
a: 1,
|
||||
b: None,
|
||||
b: 2,
|
||||
},
|
||||
&[
|
||||
Token::StructStart("SkipSerializingIfNoneFields", Some(1)),
|
||||
vec![
|
||||
Token::StructStart("DeserializeWithStruct", Some(2)),
|
||||
|
||||
Token::MapSep,
|
||||
Token::StructSep,
|
||||
Token::Str("a"),
|
||||
Token::I8(1),
|
||||
|
||||
Token::MapEnd,
|
||||
Token::StructSep,
|
||||
Token::Str("b"),
|
||||
Token::Bool(false),
|
||||
|
||||
Token::StructEnd,
|
||||
]
|
||||
);
|
||||
|
||||
assert_de_tokens(
|
||||
&SkipSerializingIfNoneFields::<i32> {
|
||||
&DeserializeWithStruct {
|
||||
a: 1,
|
||||
b: None,
|
||||
b: 123,
|
||||
},
|
||||
vec![
|
||||
Token::StructStart("SkipSerializingIfNoneFields", Some(1)),
|
||||
Token::StructStart("DeserializeWithStruct", Some(2)),
|
||||
|
||||
Token::MapSep,
|
||||
Token::StructSep,
|
||||
Token::Str("a"),
|
||||
Token::I8(1),
|
||||
|
||||
Token::MapEnd,
|
||||
]
|
||||
);
|
||||
|
||||
assert_ser_tokens(
|
||||
&SkipSerializingIfNoneFields {
|
||||
a: 1,
|
||||
b: Some(2),
|
||||
},
|
||||
&[
|
||||
Token::StructStart("SkipSerializingIfNoneFields", Some(2)),
|
||||
|
||||
Token::MapSep,
|
||||
Token::Str("a"),
|
||||
Token::I8(1),
|
||||
|
||||
Token::MapSep,
|
||||
Token::StructSep,
|
||||
Token::Str("b"),
|
||||
Token::Option(true),
|
||||
Token::I32(2),
|
||||
Token::Bool(true),
|
||||
|
||||
Token::MapEnd,
|
||||
]
|
||||
);
|
||||
|
||||
assert_de_tokens(
|
||||
&SkipSerializingIfNoneFields {
|
||||
a: 1,
|
||||
b: Some(2),
|
||||
},
|
||||
vec![
|
||||
Token::StructStart("SkipSerializingIfNoneFields", Some(2)),
|
||||
|
||||
Token::MapSep,
|
||||
Token::Str("a"),
|
||||
Token::I8(1),
|
||||
|
||||
Token::MapSep,
|
||||
Token::Str("b"),
|
||||
Token::Option(true),
|
||||
Token::I32(2),
|
||||
|
||||
Token::MapEnd,
|
||||
Token::StructEnd,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Deserialize)]
|
||||
enum DeserializeWithEnum<B> where B: Trait {
|
||||
Struct {
|
||||
a: i8,
|
||||
#[serde(deserialize_with="Trait::deserialize_with")]
|
||||
b: B,
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_deserialize_with_enum() {
|
||||
assert_de_tokens(
|
||||
&DeserializeWithEnum::Struct {
|
||||
a: 1,
|
||||
b: 2,
|
||||
},
|
||||
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![
|
||||
Token::TupleStructStart("TupleStruct", Some(3)),
|
||||
Token::SeqSep,
|
||||
Token::TupleSeqSep,
|
||||
Token::I32(1),
|
||||
|
||||
Token::SeqSep,
|
||||
Token::TupleSeqSep,
|
||||
Token::I32(2),
|
||||
|
||||
Token::SeqSep,
|
||||
Token::TupleSeqSep,
|
||||
Token::I32(3),
|
||||
Token::SeqEnd,
|
||||
Token::TupleSeqEnd,
|
||||
],
|
||||
TupleStruct(1, 2, 3) => vec![
|
||||
Token::TupleStructStart("TupleStruct", None),
|
||||
Token::SeqSep,
|
||||
Token::TupleSeqSep,
|
||||
Token::I32(1),
|
||||
|
||||
Token::SeqSep,
|
||||
Token::TupleSeqSep,
|
||||
Token::I32(2),
|
||||
|
||||
Token::SeqSep,
|
||||
Token::TupleSeqSep,
|
||||
Token::I32(3),
|
||||
Token::SeqEnd,
|
||||
Token::TupleSeqEnd,
|
||||
],
|
||||
}
|
||||
test_btreeset {
|
||||
@ -495,18 +495,18 @@ declare_tests! {
|
||||
],
|
||||
Struct { a: 1, b: 2, c: 3 } => vec![
|
||||
Token::StructStart("Struct", Some(3)),
|
||||
Token::MapSep,
|
||||
Token::StructSep,
|
||||
Token::Str("a"),
|
||||
Token::I32(1),
|
||||
|
||||
Token::MapSep,
|
||||
Token::StructSep,
|
||||
Token::Str("b"),
|
||||
Token::I32(2),
|
||||
|
||||
Token::MapSep,
|
||||
Token::StructSep,
|
||||
Token::Str("c"),
|
||||
Token::I32(3),
|
||||
Token::MapEnd,
|
||||
Token::StructEnd,
|
||||
],
|
||||
}
|
||||
test_enum_unit {
|
||||
@ -516,39 +516,39 @@ declare_tests! {
|
||||
}
|
||||
test_enum_simple {
|
||||
Enum::Simple(1) => vec![
|
||||
Token::EnumNewtype("Enum", "Simple"),
|
||||
Token::EnumNewType("Enum", "Simple"),
|
||||
Token::I32(1),
|
||||
],
|
||||
}
|
||||
test_enum_seq {
|
||||
Enum::Seq(1, 2, 3) => vec![
|
||||
Token::EnumSeqStart("Enum", "Seq", Some(3)),
|
||||
Token::SeqSep,
|
||||
Token::EnumSeqSep,
|
||||
Token::I32(1),
|
||||
|
||||
Token::SeqSep,
|
||||
Token::EnumSeqSep,
|
||||
Token::I32(2),
|
||||
|
||||
Token::SeqSep,
|
||||
Token::EnumSeqSep,
|
||||
Token::I32(3),
|
||||
Token::SeqEnd,
|
||||
Token::EnumSeqEnd,
|
||||
],
|
||||
}
|
||||
test_enum_map {
|
||||
Enum::Map { a: 1, b: 2, c: 3 } => vec![
|
||||
Token::EnumMapStart("Enum", "Map", Some(3)),
|
||||
Token::MapSep,
|
||||
Token::EnumMapSep,
|
||||
Token::Str("a"),
|
||||
Token::I32(1),
|
||||
|
||||
Token::MapSep,
|
||||
Token::EnumMapSep,
|
||||
Token::Str("b"),
|
||||
Token::I32(2),
|
||||
|
||||
Token::MapSep,
|
||||
Token::EnumMapSep,
|
||||
Token::Str("c"),
|
||||
Token::I32(3),
|
||||
Token::MapEnd,
|
||||
Token::EnumMapEnd,
|
||||
],
|
||||
}
|
||||
test_enum_unit_usize {
|
||||
|
@ -123,7 +123,7 @@ pub struct GenericStruct<T> {
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct GenericNewtypeStruct<T>(T);
|
||||
pub struct GenericNewTypeStruct<T>(T);
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct GenericTupleStruct<T, U>(T, U);
|
||||
@ -131,7 +131,7 @@ pub struct GenericTupleStruct<T, U>(T, U);
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum GenericEnum<T, U> {
|
||||
Unit,
|
||||
Newtype(T),
|
||||
NewType(T),
|
||||
Seq(T, U),
|
||||
Map { x: T, y: U },
|
||||
}
|
||||
@ -153,16 +153,16 @@ fn test_ser_named_tuple() {
|
||||
&SerNamedTuple(&a, &mut b, c),
|
||||
&[
|
||||
Token::TupleStructStart("SerNamedTuple", Some(3)),
|
||||
Token::SeqSep,
|
||||
Token::TupleSeqSep,
|
||||
Token::I32(5),
|
||||
|
||||
Token::SeqSep,
|
||||
Token::TupleSeqSep,
|
||||
Token::I32(6),
|
||||
|
||||
Token::SeqSep,
|
||||
Token::TupleSeqSep,
|
||||
Token::I32(7),
|
||||
|
||||
Token::SeqEnd,
|
||||
Token::TupleSeqEnd,
|
||||
],
|
||||
);
|
||||
}
|
||||
@ -172,7 +172,7 @@ fn test_de_named_tuple() {
|
||||
assert_de_tokens(
|
||||
&DeNamedTuple(5, 6, 7),
|
||||
vec![
|
||||
Token::TupleStructStart("DeNamedTuple", Some(3)),
|
||||
Token::SeqStart(Some(3)),
|
||||
Token::SeqSep,
|
||||
Token::I32(5),
|
||||
|
||||
@ -185,6 +185,23 @@ fn test_de_named_tuple() {
|
||||
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]
|
||||
@ -202,19 +219,19 @@ fn test_ser_named_map() {
|
||||
&[
|
||||
Token::StructStart("SerNamedMap", Some(3)),
|
||||
|
||||
Token::MapSep,
|
||||
Token::StructSep,
|
||||
Token::Str("a"),
|
||||
Token::I32(5),
|
||||
|
||||
Token::MapSep,
|
||||
Token::StructSep,
|
||||
Token::Str("b"),
|
||||
Token::I32(6),
|
||||
|
||||
Token::MapSep,
|
||||
Token::StructSep,
|
||||
Token::Str("c"),
|
||||
Token::I32(7),
|
||||
|
||||
Token::MapEnd,
|
||||
Token::StructEnd,
|
||||
]
|
||||
);
|
||||
}
|
||||
@ -230,19 +247,19 @@ fn test_de_named_map() {
|
||||
vec![
|
||||
Token::StructStart("DeNamedMap", Some(3)),
|
||||
|
||||
Token::MapSep,
|
||||
Token::StructSep,
|
||||
Token::Str("a"),
|
||||
Token::I32(5),
|
||||
|
||||
Token::MapSep,
|
||||
Token::StructSep,
|
||||
Token::Str("b"),
|
||||
Token::I32(6),
|
||||
|
||||
Token::MapSep,
|
||||
Token::StructSep,
|
||||
Token::Str("c"),
|
||||
Token::I32(7),
|
||||
|
||||
Token::MapEnd,
|
||||
Token::StructEnd,
|
||||
]
|
||||
);
|
||||
}
|
||||
@ -278,19 +295,19 @@ fn test_ser_enum_seq() {
|
||||
&[
|
||||
Token::EnumSeqStart("SerEnum", "Seq", Some(4)),
|
||||
|
||||
Token::SeqSep,
|
||||
Token::EnumSeqSep,
|
||||
Token::I8(1),
|
||||
|
||||
Token::SeqSep,
|
||||
Token::EnumSeqSep,
|
||||
Token::I32(2),
|
||||
|
||||
Token::SeqSep,
|
||||
Token::EnumSeqSep,
|
||||
Token::I32(3),
|
||||
|
||||
Token::SeqSep,
|
||||
Token::EnumSeqSep,
|
||||
Token::I32(5),
|
||||
|
||||
Token::SeqEnd,
|
||||
Token::EnumSeqEnd,
|
||||
],
|
||||
);
|
||||
}
|
||||
@ -316,23 +333,23 @@ fn test_ser_enum_map() {
|
||||
&[
|
||||
Token::EnumMapStart("SerEnum", "Map", Some(4)),
|
||||
|
||||
Token::MapSep,
|
||||
Token::EnumMapSep,
|
||||
Token::Str("a"),
|
||||
Token::I8(1),
|
||||
|
||||
Token::MapSep,
|
||||
Token::EnumMapSep,
|
||||
Token::Str("b"),
|
||||
Token::I32(2),
|
||||
|
||||
Token::MapSep,
|
||||
Token::EnumMapSep,
|
||||
Token::Str("c"),
|
||||
Token::I32(3),
|
||||
|
||||
Token::MapSep,
|
||||
Token::EnumMapSep,
|
||||
Token::Str("e"),
|
||||
Token::I32(5),
|
||||
|
||||
Token::MapEnd,
|
||||
Token::EnumMapEnd,
|
||||
],
|
||||
);
|
||||
}
|
||||
@ -368,19 +385,19 @@ fn test_de_enum_seq() {
|
||||
vec![
|
||||
Token::EnumSeqStart("DeEnum", "Seq", Some(4)),
|
||||
|
||||
Token::SeqSep,
|
||||
Token::EnumSeqSep,
|
||||
Token::I8(1),
|
||||
|
||||
Token::SeqSep,
|
||||
Token::EnumSeqSep,
|
||||
Token::I32(2),
|
||||
|
||||
Token::SeqSep,
|
||||
Token::EnumSeqSep,
|
||||
Token::I32(3),
|
||||
|
||||
Token::SeqSep,
|
||||
Token::EnumSeqSep,
|
||||
Token::I32(5),
|
||||
|
||||
Token::SeqEnd,
|
||||
Token::EnumSeqEnd,
|
||||
],
|
||||
);
|
||||
}
|
||||
@ -406,23 +423,23 @@ fn test_de_enum_map() {
|
||||
vec![
|
||||
Token::EnumMapStart("DeEnum", "Map", Some(4)),
|
||||
|
||||
Token::MapSep,
|
||||
Token::EnumMapSep,
|
||||
Token::Str("a"),
|
||||
Token::I8(1),
|
||||
|
||||
Token::MapSep,
|
||||
Token::EnumMapSep,
|
||||
Token::Str("b"),
|
||||
Token::I32(2),
|
||||
|
||||
Token::MapSep,
|
||||
Token::EnumMapSep,
|
||||
Token::Str("c"),
|
||||
Token::I32(3),
|
||||
|
||||
Token::MapSep,
|
||||
Token::EnumMapSep,
|
||||
Token::Str("e"),
|
||||
Token::I32(5),
|
||||
|
||||
Token::MapEnd,
|
||||
Token::EnumMapEnd,
|
||||
],
|
||||
);
|
||||
}
|
||||
@ -434,7 +451,7 @@ fn test_lifetimes() {
|
||||
assert_ser_tokens(
|
||||
&Lifetimes::LifetimeSeq(&value),
|
||||
&[
|
||||
Token::EnumNewtype("Lifetimes", "LifetimeSeq"),
|
||||
Token::EnumNewType("Lifetimes", "LifetimeSeq"),
|
||||
Token::I32(5),
|
||||
]
|
||||
);
|
||||
@ -442,7 +459,7 @@ fn test_lifetimes() {
|
||||
assert_ser_tokens(
|
||||
&Lifetimes::NoLifetimeSeq(5),
|
||||
&[
|
||||
Token::EnumNewtype("Lifetimes", "NoLifetimeSeq"),
|
||||
Token::EnumNewType("Lifetimes", "NoLifetimeSeq"),
|
||||
Token::I32(5),
|
||||
]
|
||||
);
|
||||
@ -452,11 +469,11 @@ fn test_lifetimes() {
|
||||
&[
|
||||
Token::EnumMapStart("Lifetimes", "LifetimeMap", Some(1)),
|
||||
|
||||
Token::MapSep,
|
||||
Token::EnumMapSep,
|
||||
Token::Str("a"),
|
||||
Token::I32(5),
|
||||
|
||||
Token::MapEnd,
|
||||
Token::EnumMapEnd,
|
||||
]
|
||||
);
|
||||
|
||||
@ -465,11 +482,11 @@ fn test_lifetimes() {
|
||||
&[
|
||||
Token::EnumMapStart("Lifetimes", "NoLifetimeMap", Some(1)),
|
||||
|
||||
Token::MapSep,
|
||||
Token::EnumMapSep,
|
||||
Token::Str("a"),
|
||||
Token::I32(5),
|
||||
|
||||
Token::MapEnd,
|
||||
Token::EnumMapEnd,
|
||||
]
|
||||
);
|
||||
}
|
||||
@ -481,11 +498,11 @@ fn test_generic_struct() {
|
||||
vec![
|
||||
Token::StructStart("GenericStruct", Some(1)),
|
||||
|
||||
Token::MapSep,
|
||||
Token::StructSep,
|
||||
Token::Str("x"),
|
||||
Token::U32(5),
|
||||
|
||||
Token::MapEnd,
|
||||
Token::StructEnd,
|
||||
]
|
||||
);
|
||||
}
|
||||
@ -493,9 +510,9 @@ fn test_generic_struct() {
|
||||
#[test]
|
||||
fn test_generic_newtype_struct() {
|
||||
assert_tokens(
|
||||
&GenericNewtypeStruct(5u32),
|
||||
&GenericNewTypeStruct(5u32),
|
||||
vec![
|
||||
Token::StructNewtype("GenericNewtypeStruct"),
|
||||
Token::StructNewType("GenericNewTypeStruct"),
|
||||
Token::U32(5),
|
||||
]
|
||||
);
|
||||
@ -508,13 +525,13 @@ fn test_generic_tuple_struct() {
|
||||
vec![
|
||||
Token::TupleStructStart("GenericTupleStruct", Some(2)),
|
||||
|
||||
Token::SeqSep,
|
||||
Token::TupleSeqSep,
|
||||
Token::U32(5),
|
||||
|
||||
Token::SeqSep,
|
||||
Token::TupleSeqSep,
|
||||
Token::U32(6),
|
||||
|
||||
Token::SeqEnd,
|
||||
Token::TupleSeqEnd,
|
||||
]
|
||||
);
|
||||
}
|
||||
@ -532,9 +549,9 @@ fn test_generic_enum_unit() {
|
||||
#[test]
|
||||
fn test_generic_enum_newtype() {
|
||||
assert_tokens(
|
||||
&GenericEnum::Newtype::<u32, u32>(5),
|
||||
&GenericEnum::NewType::<u32, u32>(5),
|
||||
vec![
|
||||
Token::EnumNewtype("GenericEnum", "Newtype"),
|
||||
Token::EnumNewType("GenericEnum", "NewType"),
|
||||
Token::U32(5),
|
||||
]
|
||||
);
|
||||
@ -547,13 +564,13 @@ fn test_generic_enum_seq() {
|
||||
vec![
|
||||
Token::EnumSeqStart("GenericEnum", "Seq", Some(2)),
|
||||
|
||||
Token::SeqSep,
|
||||
Token::EnumSeqSep,
|
||||
Token::U32(5),
|
||||
|
||||
Token::SeqSep,
|
||||
Token::EnumSeqSep,
|
||||
Token::U32(6),
|
||||
|
||||
Token::SeqEnd,
|
||||
Token::EnumSeqEnd,
|
||||
]
|
||||
);
|
||||
}
|
||||
@ -565,15 +582,15 @@ fn test_generic_enum_map() {
|
||||
vec![
|
||||
Token::EnumMapStart("GenericEnum", "Map", Some(2)),
|
||||
|
||||
Token::MapSep,
|
||||
Token::EnumMapSep,
|
||||
Token::Str("x"),
|
||||
Token::U32(5),
|
||||
|
||||
Token::MapSep,
|
||||
Token::EnumMapSep,
|
||||
Token::Str("y"),
|
||||
Token::U32(6),
|
||||
|
||||
Token::MapEnd,
|
||||
Token::EnumMapEnd,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
@ -76,11 +76,11 @@ declare_ser_tests! {
|
||||
}
|
||||
test_result {
|
||||
Ok::<i32, i32>(0) => &[
|
||||
Token::EnumNewtype("Result", "Ok"),
|
||||
Token::EnumNewType("Result", "Ok"),
|
||||
Token::I32(0),
|
||||
],
|
||||
Err::<i32, i32>(1) => &[
|
||||
Token::EnumNewtype("Result", "Err"),
|
||||
Token::EnumNewType("Result", "Err"),
|
||||
Token::I32(1),
|
||||
],
|
||||
}
|
||||
@ -214,56 +214,56 @@ declare_ser_tests! {
|
||||
test_tuple_struct {
|
||||
TupleStruct(1, 2, 3) => &[
|
||||
Token::TupleStructStart("TupleStruct", Some(3)),
|
||||
Token::SeqSep,
|
||||
Token::TupleSeqSep,
|
||||
Token::I32(1),
|
||||
|
||||
Token::SeqSep,
|
||||
Token::TupleSeqSep,
|
||||
Token::I32(2),
|
||||
|
||||
Token::SeqSep,
|
||||
Token::TupleSeqSep,
|
||||
Token::I32(3),
|
||||
Token::SeqEnd,
|
||||
Token::TupleSeqEnd,
|
||||
],
|
||||
}
|
||||
test_struct {
|
||||
Struct { a: 1, b: 2, c: 3 } => &[
|
||||
Token::StructStart("Struct", Some(3)),
|
||||
Token::MapSep,
|
||||
Token::StructSep,
|
||||
Token::Str("a"),
|
||||
Token::I32(1),
|
||||
|
||||
Token::MapSep,
|
||||
Token::StructSep,
|
||||
Token::Str("b"),
|
||||
Token::I32(2),
|
||||
|
||||
Token::MapSep,
|
||||
Token::StructSep,
|
||||
Token::Str("c"),
|
||||
Token::I32(3),
|
||||
Token::MapEnd,
|
||||
Token::StructEnd,
|
||||
],
|
||||
}
|
||||
test_enum {
|
||||
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) => &[
|
||||
Token::EnumSeqStart("Enum", "Seq", Some(2)),
|
||||
Token::SeqSep,
|
||||
Token::EnumSeqSep,
|
||||
Token::I32(1),
|
||||
|
||||
Token::SeqSep,
|
||||
Token::EnumSeqSep,
|
||||
Token::I32(2),
|
||||
Token::SeqEnd,
|
||||
Token::EnumSeqEnd,
|
||||
],
|
||||
Enum::Map { a: 1, b: 2 } => &[
|
||||
Token::EnumMapStart("Enum", "Map", Some(2)),
|
||||
Token::MapSep,
|
||||
Token::EnumMapSep,
|
||||
Token::Str("a"),
|
||||
Token::I32(1),
|
||||
|
||||
Token::MapSep,
|
||||
Token::EnumMapSep,
|
||||
Token::Str("b"),
|
||||
Token::I32(2),
|
||||
Token::MapEnd,
|
||||
Token::EnumMapEnd,
|
||||
],
|
||||
}
|
||||
test_num_bigint {
|
||||
|
@ -2,7 +2,8 @@ use std::fmt;
|
||||
use std::iter;
|
||||
use std::error;
|
||||
|
||||
use serde::{ser, de};
|
||||
use serde::ser::{self, Serialize};
|
||||
use serde::de;
|
||||
use serde::de::value::{self, ValueDeserializer};
|
||||
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
@ -30,23 +31,35 @@ pub enum Token<'a> {
|
||||
Unit,
|
||||
UnitStruct(&'a str),
|
||||
|
||||
StructNewtype(&'a str),
|
||||
StructNewType(&'a str),
|
||||
|
||||
EnumStart(&'a str),
|
||||
EnumUnit(&'a str, &'a str),
|
||||
EnumNewtype(&'a str, &'a str),
|
||||
EnumSeqStart(&'a str, &'a str, Option<usize>),
|
||||
EnumMapStart(&'a str, &'a str, Option<usize>),
|
||||
EnumNewType(&'a str, &'a str),
|
||||
|
||||
SeqStart(Option<usize>),
|
||||
TupleStructStart(&'a str, Option<usize>),
|
||||
SeqSep,
|
||||
SeqEnd,
|
||||
|
||||
TupleStructStart(&'a str, Option<usize>),
|
||||
TupleSeqSep,
|
||||
TupleSeqEnd,
|
||||
|
||||
MapStart(Option<usize>),
|
||||
StructStart(&'a str, Option<usize>),
|
||||
MapSep,
|
||||
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>
|
||||
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)
|
||||
}
|
||||
|
||||
@ -218,43 +231,65 @@ impl<'a, I> ser::Serializer for Serializer<I>
|
||||
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,
|
||||
name: &'static str,
|
||||
value: T) -> Result<(), Error>
|
||||
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)
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
let len = visitor.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,
|
||||
name: &str,
|
||||
_variant_index: usize,
|
||||
variant: &str,
|
||||
visitor: V) -> Result<(), Error>
|
||||
name: &str,
|
||||
_variant_index: usize,
|
||||
variant: &str,
|
||||
mut visitor: V) -> Result<(), Error>
|
||||
where V: ser::SeqVisitor
|
||||
{
|
||||
let len = visitor.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>
|
||||
where T: ser::Serialize
|
||||
fn serialize_tuple_variant_elt<T>(&mut self, value: T) -> Result<(), Error>
|
||||
where T: ser::Serialize,
|
||||
{
|
||||
assert_eq!(self.tokens.next(), Some(&Token::SeqSep));
|
||||
assert_eq!(self.tokens.next(), Some(&Token::EnumSeqSep));
|
||||
value.serialize(self)
|
||||
}
|
||||
|
||||
@ -268,35 +303,61 @@ impl<'a, I> ser::Serializer for Serializer<I>
|
||||
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
|
||||
{
|
||||
let len = visitor.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,
|
||||
name: &str,
|
||||
_variant_index: usize,
|
||||
variant: &str,
|
||||
visitor: V) -> Result<(), Error>
|
||||
name: &str,
|
||||
_variant_index: usize,
|
||||
variant: &str,
|
||||
mut visitor: V) -> Result<(), Error>
|
||||
where V: ser::MapVisitor
|
||||
{
|
||||
let len = visitor.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>
|
||||
where K: ser::Serialize,
|
||||
V: ser::Serialize,
|
||||
fn serialize_struct_variant_elt<T>(&mut self, key: &'static str, value: T) -> Result<(), Error>
|
||||
where T: ser::Serialize,
|
||||
{
|
||||
assert_eq!(self.tokens.next(), Some(&Token::MapSep));
|
||||
assert_eq!(self.tokens.next(), Some(&Token::EnumMapSep));
|
||||
|
||||
try!(key.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>
|
||||
where V: de::Visitor,
|
||||
{
|
||||
@ -391,6 +470,24 @@ impl<I> Deserializer<I>
|
||||
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>
|
||||
@ -429,7 +526,6 @@ impl<I> de::Deserializer for Deserializer<I>
|
||||
Some(Token::MapStart(len)) | Some(Token::StructStart(_, len)) => {
|
||||
self.visit_map(len, visitor)
|
||||
}
|
||||
//Some(Token::Name(_)) => self.visit(visitor),
|
||||
Some(token) => Err(Error::UnexpectedToken(token)),
|
||||
None => Err(Error::EndOfStreamError),
|
||||
}
|
||||
@ -473,7 +569,7 @@ impl<I> de::Deserializer for Deserializer<I>
|
||||
})
|
||||
}
|
||||
Some(&Token::EnumUnit(n, _))
|
||||
| Some(&Token::EnumNewtype(n, _))
|
||||
| Some(&Token::EnumNewType(n, _))
|
||||
| Some(&Token::EnumSeqStart(n, _, _))
|
||||
| Some(&Token::EnumMapStart(n, _, _)) if name == n => {
|
||||
visitor.visit(DeserializerVariantVisitor {
|
||||
@ -506,12 +602,12 @@ impl<I> de::Deserializer for Deserializer<I>
|
||||
}
|
||||
|
||||
fn deserialize_newtype_struct<V>(&mut self,
|
||||
name: &str,
|
||||
mut visitor: V) -> Result<V::Value, Error>
|
||||
name: &str,
|
||||
mut visitor: V) -> Result<V::Value, Error>
|
||||
where V: de::Visitor,
|
||||
{
|
||||
match self.tokens.peek() {
|
||||
Some(&Token::StructNewtype(n)) => {
|
||||
Some(&Token::StructNewType(n)) => {
|
||||
self.tokens.next();
|
||||
if name == n {
|
||||
visitor.visit_newtype_struct(self)
|
||||
@ -525,9 +621,9 @@ impl<I> de::Deserializer for Deserializer<I>
|
||||
}
|
||||
|
||||
fn deserialize_tuple_struct<V>(&mut self,
|
||||
name: &str,
|
||||
len: usize,
|
||||
mut visitor: V) -> Result<V::Value, Error>
|
||||
name: &str,
|
||||
len: usize,
|
||||
mut visitor: V) -> Result<V::Value, Error>
|
||||
where V: de::Visitor,
|
||||
{
|
||||
match self.tokens.peek() {
|
||||
@ -542,7 +638,7 @@ impl<I> de::Deserializer for Deserializer<I>
|
||||
Some(&Token::TupleStructStart(n, _)) => {
|
||||
self.tokens.next();
|
||||
if name == n {
|
||||
self.visit_seq(Some(len), visitor)
|
||||
self.visit_tuple_seq(Some(len), visitor)
|
||||
} else {
|
||||
Err(Error::InvalidName(n))
|
||||
}
|
||||
@ -557,16 +653,16 @@ impl<I> de::Deserializer for Deserializer<I>
|
||||
}
|
||||
|
||||
fn deserialize_struct<V>(&mut self,
|
||||
name: &str,
|
||||
fields: &'static [&'static str],
|
||||
visitor: V) -> Result<V::Value, Error>
|
||||
name: &str,
|
||||
fields: &'static [&'static str],
|
||||
visitor: V) -> Result<V::Value, Error>
|
||||
where V: de::Visitor,
|
||||
{
|
||||
match self.tokens.peek() {
|
||||
Some(&Token::StructStart(n, _)) => {
|
||||
self.tokens.next();
|
||||
if name == n {
|
||||
self.visit_map(Some(fields.len()), visitor)
|
||||
self.visit_struct(Some(fields.len()), visitor)
|
||||
} else {
|
||||
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>> {
|
||||
de: &'a mut Deserializer<I>,
|
||||
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>> {
|
||||
de: &'a mut Deserializer<I>,
|
||||
}
|
||||
@ -693,7 +930,7 @@ impl<'a, I> de::VariantVisitor for DeserializerVariantVisitor<'a, I>
|
||||
{
|
||||
match self.de.tokens.peek() {
|
||||
Some(&Token::EnumUnit(_, v))
|
||||
| Some(&Token::EnumNewtype(_, v))
|
||||
| Some(&Token::EnumNewType(_, v))
|
||||
| Some(&Token::EnumSeqStart(_, v, _))
|
||||
| Some(&Token::EnumMapStart(_, 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,
|
||||
{
|
||||
match self.de.tokens.peek() {
|
||||
Some(&Token::EnumNewtype(_, _)) => {
|
||||
Some(&Token::EnumNewType(_, _)) => {
|
||||
self.de.tokens.next();
|
||||
de::Deserialize::deserialize(self.de)
|
||||
}
|
||||
@ -744,6 +981,15 @@ impl<'a, I> de::VariantVisitor for DeserializerVariantVisitor<'a, I>
|
||||
Some(&Token::EnumSeqStart(_, _, Some(enum_len))) => {
|
||||
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 {
|
||||
self.de.visit_seq(Some(len), visitor)
|
||||
} else {
|
||||
@ -766,6 +1012,15 @@ impl<'a, I> de::VariantVisitor for DeserializerVariantVisitor<'a, I>
|
||||
Some(&Token::EnumMapStart(_, _, Some(enum_len))) => {
|
||||
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 {
|
||||
self.de.visit_map(Some(fields.len()), visitor)
|
||||
} 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])
|
||||
|
Loading…
x
Reference in New Issue
Block a user