diff --git a/README.md b/README.md index 722e1d6c..58f152e3 100644 --- a/README.md +++ b/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, &mut S) -> Result<(), S::Error> where S: Serializer` to serialize this value | +| `#[serde(deserialize_with="$path")` | Call a function `fn(&mut D) -> Result where D: Deserializer` to deserialize this value | Serialization Formats Using Serde ================================= diff --git a/serde_codegen/src/attr.rs b/serde_codegen/src/attr.rs index 376d3444..a082fcbf 100644 --- a/serde_codegen/src/attr.rs +++ b/serde_codegen/src/attr.rs @@ -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, deserialize_name: Option, skip_serializing_field: bool, - skip_serializing_field_if_empty: bool, - skip_serializing_field_if_none: bool, - use_default: bool, + skip_serializing_field_if: Option>, + default_expr_if_missing: Option>, + serialize_with: Option>, + deserialize_with: Option>, } impl FieldAttrs { /// Extract out the `#[serde(...)]` attributes from a struct field. - pub fn from_field(cx: &ExtCtxt, field: &ast::StructField) -> Result { + pub fn from_field(cx: &ExtCtxt, + container_ty: &P, + generics: &ast::Generics, + field: &ast::StructField, + is_enum: bool) -> Result { + 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 { + 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> { + 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> { + self.serialize_with.as_ref() + } + + pub fn deserialize_with(&self) -> Option<&P> { + 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, Error> { + container_ty: &P, + generics: &ast::Generics, + fields: &[ast::StructField], + is_enum: bool) -> Result, 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]> { _ => 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 { + 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!("", 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 { + 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 { + 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, + generics: &ast::Generics, + field_ident: ast::Ident, + path: ast::Path, + is_enum: bool) -> P { + 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(&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(&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(&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(&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, + generics: &ast::Generics, + path: ast::Path) -> P { + // 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(deserializer: &mut D) -> Result + 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) + }) +} diff --git a/serde_codegen/src/de.rs b/serde_codegen/src/de.rs index 298c856d..bc53153e 100644 --- a/serde_codegen/src/de.rs +++ b/serde_codegen/src/de.rs @@ -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, + generics: &ast::Generics, fields: &[ast::StructField], container_attrs: &attr::ContainerAttrs, + is_enum: bool, ) -> Result<(Vec>, ast::Stmt, P), 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, + generics: &ast::Generics, fields: &[ast::StructField], container_attrs: &attr::ContainerAttrs, + is_enum: bool, ) -> Result, Error> { // Create the field names for the fields. let field_names: Vec = (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 = 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 = 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::>(); - 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::>(); + .collect::, _>>(); + + let extract_values = try!(extract_values); let result = builder.expr().struct_path(struct_path) .with_id_exprs( diff --git a/serde_codegen/src/ser.rs b/serde_codegen/src/ser.rs index ab59071a..b1e1641f 100644 --- a/serde_codegen/src/ser.rs +++ b/serde_codegen/src/ser.rs @@ -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, 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, 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, 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, variant_index: usize, variant_name: P, generics: &ast::Generics, - structure_ty: P, + ty: P, fields: &[ast::StructField], field_names: Vec, + container_attrs: &attr::ContainerAttrs, ) -> Result, 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, variant_ty: P, + serializer_method: ast::Ident, fields: usize, generics: &ast::Generics ) -> (P, P) { let arms: Vec = (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( +fn serialize_struct_visitor( cx: &ExtCtxt, builder: &aster::AstBuilder, structure_ty: P, variant_ty: P, + serializer_method: ast::Ident, fields: &[ast::StructField], generics: &ast::Generics, - value_exprs: I, -) -> Result<(P, P), Error> - where I: Iterator>, -{ - let value_exprs = value_exprs.collect::>(); + is_enum: bool, +) -> Result<(P, P), 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 = field_attrs.iter() - .zip(value_exprs.iter()) - .filter(|&(ref field, _)| !field.skip_serializing_field()) + let arms: Vec = 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( .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)); diff --git a/serde_tests/tests/test_annotations.rs b/serde_tests/tests/test_annotations.rs index 82f1265e..cdefac86 100644 --- a/serde_tests/tests/test_annotations.rs +++ b/serde_tests/tests/test_annotations.rs @@ -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(&self, ser: &mut S) -> Result<(), S::Error> + where S: Serializer; + + fn deserialize_with(de: &mut D) -> Result + where D: Deserializer; +} + +impl Trait for i32 { + fn my_default() -> Self { 123 } + + fn should_skip(&self) -> bool { *self == 123 } + + fn serialize_with(&self, ser: &mut S) -> Result<(), S::Error> + where S: Serializer + { + if *self == 123 { + true.serialize(ser) + } else { + false.serialize(ser) + } + } + + fn deserialize_with(de: &mut D) -> Result + where D: Deserializer + { + if try!(Deserialize::deserialize(de)) { + Ok(123) + } else { + Ok(2) + } + } +} + #[derive(Debug, PartialEq, Serialize, Deserialize)] -struct Default { - a1: i32, +struct DefaultStruct 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 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::( + 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 { }, } -#[derive(Debug, PartialEq, Deserialize, Serialize)] -struct SkipSerializingFields { - a: i8, - #[serde(skip_serializing, default)] - b: A, -} - -#[derive(Debug, PartialEq, Deserialize, Serialize)] -struct SkipSerializingIfEmptyFields { - a: i8, - #[serde(skip_serializing_if_empty, default)] - b: Vec, -} - -#[derive(Debug, PartialEq, Deserialize, Serialize)] -struct SkipSerializingIfNoneFields { - a: i8, - #[serde(skip_serializing_if_none, default)] - b: Option, -} - -#[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::( - 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:: { - 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:: { - 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 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:: { +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:: { + &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 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, ] ); } diff --git a/serde_tests/tests/test_de.rs b/serde_tests/tests/test_de.rs index 395e7645..dcc6e8f0 100644 --- a/serde_tests/tests/test_de.rs +++ b/serde_tests/tests/test_de.rs @@ -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 { diff --git a/serde_tests/tests/test_macros.rs b/serde_tests/tests/test_macros.rs index f8396fb7..842fa670 100644 --- a/serde_tests/tests/test_macros.rs +++ b/serde_tests/tests/test_macros.rs @@ -123,7 +123,7 @@ pub struct GenericStruct { } #[derive(Debug, PartialEq, Serialize, Deserialize)] -pub struct GenericNewtypeStruct(T); +pub struct GenericNewTypeStruct(T); #[derive(Debug, PartialEq, Serialize, Deserialize)] pub struct GenericTupleStruct(T, U); @@ -131,7 +131,7 @@ pub struct GenericTupleStruct(T, U); #[derive(Debug, PartialEq, Serialize, Deserialize)] pub enum GenericEnum { 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::(5), + &GenericEnum::NewType::(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, ] ); } diff --git a/serde_tests/tests/test_ser.rs b/serde_tests/tests/test_ser.rs index 77bf3eb8..e08d8c14 100644 --- a/serde_tests/tests/test_ser.rs +++ b/serde_tests/tests/test_ser.rs @@ -76,11 +76,11 @@ declare_ser_tests! { } test_result { Ok::(0) => &[ - Token::EnumNewtype("Result", "Ok"), + Token::EnumNewType("Result", "Ok"), Token::I32(0), ], Err::(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 { diff --git a/serde_tests/tests/token.rs b/serde_tests/tests/token.rs index 1b14a7d3..40810d47 100644 --- a/serde_tests/tests/token.rs +++ b/serde_tests/tests/token.rs @@ -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), - EnumMapStart(&'a str, &'a str, Option), + EnumNewType(&'a str, &'a str), SeqStart(Option), - TupleStructStart(&'a str, Option), SeqSep, SeqEnd, + TupleStructStart(&'a str, Option), + TupleSeqSep, + TupleSeqEnd, + MapStart(Option), - StructStart(&'a str, Option), MapSep, MapEnd, + + StructStart(&'a str, Option), + StructSep, + StructEnd, + + EnumSeqStart(&'a str, &'a str, Option), + EnumSeqSep, + EnumSeqEnd, + + EnumMapStart(&'a str, &'a str, Option), + EnumMapSep, + EnumMapEnd, } ////////////////////////////////////////////////////////////////////////////// @@ -102,7 +115,7 @@ impl<'a, I> ser::Serializer for Serializer 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 self.visit_sequence(visitor) } + fn serialize_seq_elt(&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(&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(&mut self, name: &str, visitor: V) -> Result<(), Error> + fn serialize_tuple_struct(&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(&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(&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(&mut self, value: T) -> Result<(), Error> - where T: ser::Serialize + fn serialize_tuple_variant_elt(&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 self.visit_mapping(visitor) } - fn serialize_struct(&mut self, name: &str, visitor: V) -> Result<(), Error> + fn serialize_map_elt(&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(&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(&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(&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(&mut self, key: K, value: V) -> Result<(), Error> - where K: ser::Serialize, - V: ser::Serialize, + fn serialize_struct_variant_elt(&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 Deserializer }) } + fn visit_tuple_seq(&mut self, len: Option, mut visitor: V) -> Result + where V: de::Visitor, + { + visitor.visit_seq(DeserializerTupleSeqVisitor { + de: self, + len: len, + }) + } + + fn visit_variant_seq(&mut self, len: Option, mut visitor: V) -> Result + where V: de::Visitor, + { + visitor.visit_seq(DeserializerVariantSeqVisitor { + de: self, + len: len, + }) + } + fn visit_map(&mut self, len: Option, mut visitor: V) -> Result where V: de::Visitor, { @@ -391,6 +470,24 @@ impl Deserializer len: len, }) } + + fn visit_struct(&mut self, len: Option, mut visitor: V) -> Result + where V: de::Visitor, + { + visitor.visit_map(DeserializerStructVisitor { + de: self, + len: len, + }) + } + + fn visit_variant_map(&mut self, len: Option, mut visitor: V) -> Result + where V: de::Visitor, + { + visitor.visit_map(DeserializerVariantMapVisitor { + de: self, + len: len, + }) + } } impl de::Deserializer for Deserializer @@ -429,7 +526,6 @@ impl de::Deserializer for Deserializer 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 de::Deserializer for Deserializer }) } 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 de::Deserializer for Deserializer } fn deserialize_newtype_struct(&mut self, - name: &str, - mut visitor: V) -> Result + name: &str, + mut visitor: V) -> Result 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 de::Deserializer for Deserializer } fn deserialize_tuple_struct(&mut self, - name: &str, - len: usize, - mut visitor: V) -> Result + name: &str, + len: usize, + mut visitor: V) -> Result where V: de::Visitor, { match self.tokens.peek() { @@ -542,7 +638,7 @@ impl de::Deserializer for Deserializer 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 de::Deserializer for Deserializer } fn deserialize_struct(&mut self, - name: &str, - fields: &'static [&'static str], - visitor: V) -> Result + name: &str, + fields: &'static [&'static str], + visitor: V) -> Result 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> { + de: &'a mut Deserializer, + len: Option, +} + +impl<'a, I> de::SeqVisitor for DeserializerTupleSeqVisitor<'a, I> + where I: Iterator>, +{ + type Error = Error; + + fn visit(&mut self) -> Result, 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) { + let len = self.len.unwrap_or(0); + (len, self.len) + } +} + +////////////////////////////////////////////////////////////////////////// + +struct DeserializerVariantSeqVisitor<'a, I: 'a> where I: Iterator> { + de: &'a mut Deserializer, + len: Option, +} + +impl<'a, I> de::SeqVisitor for DeserializerVariantSeqVisitor<'a, I> + where I: Iterator>, +{ + type Error = Error; + + fn visit(&mut self) -> Result, 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) { + let len = self.len.unwrap_or(0); + (len, self.len) + } +} + +////////////////////////////////////////////////////////////////////////// + struct DeserializerMapVisitor<'a, I: 'a> where I: Iterator> { de: &'a mut Deserializer, len: Option, @@ -679,6 +865,57 @@ impl<'a, I> de::MapVisitor for DeserializerMapVisitor<'a, I> ////////////////////////////////////////////////////////////////////////// +struct DeserializerStructVisitor<'a, I: 'a> where I: Iterator> { + de: &'a mut Deserializer, + len: Option, +} + +impl<'a, I> de::MapVisitor for DeserializerStructVisitor<'a, I> + where I: Iterator>, +{ + type Error = Error; + + fn visit_key(&mut self) -> Result, 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(&mut self) -> Result + 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) { + let len = self.len.unwrap_or(0); + (len, self.len) + } +} + +////////////////////////////////////////////////////////////////////////// + struct DeserializerVariantVisitor<'a, I: 'a> where I: Iterator> { de: &'a mut Deserializer, } @@ -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::::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> { + de: &'a mut Deserializer, + len: Option, +} + +impl<'a, I> de::MapVisitor for DeserializerVariantMapVisitor<'a, I> + where I: Iterator>, +{ + type Error = Error; + + fn visit_key(&mut self) -> Result, 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(&mut self) -> Result + 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) { + let len = self.len.unwrap_or(0); + (len, self.len) + } +} + ////////////////////////////////////////////////////////////////////////////// pub fn assert_ser_tokens(value: &T, tokens: &[Token])