Merge pull request #238 from erickt/skip4

Add codegen expr magic for default, skip serializing, and alternative serializers
This commit is contained in:
Erick Tryzelaar 2016-02-21 15:38:31 -08:00
commit 7adf624dee
9 changed files with 1511 additions and 615 deletions

View File

@ -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
=================================

View File

@ -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)
})
}

View File

@ -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(

View File

@ -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));

View File

@ -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,
]
);
}

View File

@ -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 {

View File

@ -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,
]
);
}

View File

@ -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 {

View File

@ -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])