From a6d172111b9917a55d80b9d44666d8f9f976a1ba Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 8 Apr 2017 22:42:42 -0700 Subject: [PATCH 1/7] Derive for remote types --- serde_codegen_internals/src/ast.rs | 11 +- serde_codegen_internals/src/attr.rs | 28 +++ serde_codegen_internals/src/check.rs | 20 ++ serde_codegen_internals/src/lib.rs | 1 + serde_derive/src/de.rs | 354 +++++++++++++++++---------- serde_derive/src/ser.rs | 264 ++++++++++++-------- test_suite/tests/test_remote.rs | 184 ++++++++++++++ 7 files changed, 620 insertions(+), 242 deletions(-) create mode 100644 serde_codegen_internals/src/check.rs create mode 100644 test_suite/tests/test_remote.rs diff --git a/serde_codegen_internals/src/ast.rs b/serde_codegen_internals/src/ast.rs index 0a50691e..462d061f 100644 --- a/serde_codegen_internals/src/ast.rs +++ b/serde_codegen_internals/src/ast.rs @@ -1,5 +1,6 @@ use syn; use attr; +use check; use Ctxt; pub struct Item<'a> { @@ -62,12 +63,14 @@ impl<'a> Item<'a> { } } - Item { + let item = Item { ident: item.ident.clone(), attrs: attrs, body: body, generics: &item.generics, - } + }; + check::check(cx, &item); + item } } @@ -81,6 +84,10 @@ impl<'a> Body<'a> { Body::Struct(_, ref fields) => Box::new(fields.iter()), } } + + pub fn has_getter(&self) -> bool { + self.all_fields().any(|f| f.attrs.getter().is_some()) + } } fn enum_from_ast<'a>(cx: &Ctxt, variants: &'a [syn::Variant]) -> Vec> { diff --git a/serde_codegen_internals/src/attr.rs b/serde_codegen_internals/src/attr.rs index 9e957ad9..cb4ddd8a 100644 --- a/serde_codegen_internals/src/attr.rs +++ b/serde_codegen_internals/src/attr.rs @@ -102,6 +102,7 @@ pub struct Item { tag: EnumTag, from_type: Option, into_type: Option, + remote: Option, } /// Styles of representing an enum. @@ -151,6 +152,7 @@ impl Item { let mut content = Attr::none(cx, "content"); let mut from_type = Attr::none(cx, "from"); let mut into_type = Attr::none(cx, "into"); + let mut remote = Attr::none(cx, "remote"); for meta_items in item.attrs.iter().filter_map(get_serde_meta_items) { for meta_item in meta_items { @@ -290,6 +292,13 @@ impl Item { } } + // Parse `#[serde(remote = "...")]` + MetaItem(NameValue(ref name, ref lit)) if name == "remote" => { + if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) { + remote.set(path); + } + } + MetaItem(ref meta_item) => { cx.error(format!("unknown serde container attribute `{}`", meta_item.name())); @@ -361,6 +370,7 @@ impl Item { tag: tag, from_type: from_type.get(), into_type: into_type.get(), + remote: remote.get(), } } @@ -399,6 +409,10 @@ impl Item { pub fn into_type(&self) -> Option<&syn::Ty> { self.into_type.as_ref() } + + pub fn remote(&self) -> Option<&syn::Path> { + self.remote.as_ref() + } } /// Represents variant attribute information @@ -531,6 +545,7 @@ pub struct Field { ser_bound: Option>, de_bound: Option>, borrowed_lifetimes: BTreeSet, + getter: Option, } /// Represents the default to use for a field when deserializing. @@ -558,6 +573,7 @@ impl Field { let mut ser_bound = Attr::none(cx, "bound"); let mut de_bound = Attr::none(cx, "bound"); let mut borrowed_lifetimes = Attr::none(cx, "borrow"); + let mut getter = Attr::none(cx, "getter"); let ident = match field.ident { Some(ref ident) => ident.to_string(), @@ -676,6 +692,13 @@ impl Field { } } + // Parse `#[serde(getter = "...")]` + MetaItem(NameValue(ref name, ref lit)) if name == "getter" => { + if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) { + getter.set(path); + } + } + MetaItem(ref meta_item) => { cx.error(format!("unknown serde field attribute `{}`", meta_item.name())); } @@ -737,6 +760,7 @@ impl Field { ser_bound: ser_bound.get(), de_bound: de_bound.get(), borrowed_lifetimes: borrowed_lifetimes, + getter: getter.get(), } } @@ -788,6 +812,10 @@ impl Field { pub fn borrowed_lifetimes(&self) -> &BTreeSet { &self.borrowed_lifetimes } + + pub fn getter(&self) -> Option<&syn::Path> { + self.getter.as_ref() + } } type SerAndDe = (Option, Option); diff --git a/serde_codegen_internals/src/check.rs b/serde_codegen_internals/src/check.rs new file mode 100644 index 00000000..fd4d4e7d --- /dev/null +++ b/serde_codegen_internals/src/check.rs @@ -0,0 +1,20 @@ +use ast::{Body, Item}; +use Ctxt; + +/// Cross-cutting checks that require looking at more than a single attrs +/// object. Simpler checks should happen when parsing and building the attrs. +pub fn check(cx: &Ctxt, item: &Item) { + match item.body { + Body::Enum(_) => { + if item.body.has_getter() { + cx.error("#[serde(getter = \"...\")] is not allowed in an enum"); + } + } + Body::Struct(_, _) => { + if item.body.has_getter() && item.attrs.remote().is_none() { + cx.error("#[serde(getter = \"...\")] can only be used in structs \ + that have #[serde(remote = \"...\")]"); + } + } + } +} diff --git a/serde_codegen_internals/src/lib.rs b/serde_codegen_internals/src/lib.rs index d5baf00b..6353330b 100644 --- a/serde_codegen_internals/src/lib.rs +++ b/serde_codegen_internals/src/lib.rs @@ -9,3 +9,4 @@ mod ctxt; pub use ctxt::Ctxt; mod case; +mod check; diff --git a/serde_derive/src/de.rs b/serde_derive/src/de.rs index 5c84a649..e1abbd16 100644 --- a/serde_derive/src/de.rs +++ b/serde_derive/src/de.rs @@ -14,17 +14,25 @@ pub fn expand_derive_deserialize(item: &syn::DeriveInput) -> Result(__deserializer: __D) -> _serde::export::Result<#remote #ty_generics, __D::Error> + where __D: _serde::Deserializer<'de> + { + #body + } + } + } + } else { + let (de_impl_generics, _, ty_generics, where_clause) = split_with_de_lifetime(¶ms); + quote! { #[automatically_derived] impl #de_impl_generics _serde::Deserialize<'de> for #ident #ty_generics #where_clause { fn deserialize<__D>(__deserializer: __D) -> _serde::export::Result @@ -33,13 +41,72 @@ pub fn expand_derive_deserialize(item: &syn::DeriveInput) -> Result, + + /// At least one field has a serde(getter) attribute, implying that the + /// remote type has a private field. + has_getter: bool, +} + +impl Parameters { + fn new(item: &Item) -> Self { + let local = item.ident.clone(); + let this = match item.attrs.remote() { + Some(remote) => remote.clone(), + None => item.ident.clone().into(), + }; + let generics = build_generics(item); + let borrowed = borrowed_lifetimes(item); + let has_getter = item.body.has_getter(); + + Parameters { + local: local, + this: this, + generics: generics, + borrowed: borrowed, + has_getter: has_getter, + } + } + + /// Type name to use in error messages and `&'static str` arguments to + /// various Deserializer methods. + fn type_name(&self) -> &str { + self.this.segments.last().unwrap().ident.as_ref() + } + + fn de_lifetime_def(&self) -> syn::LifetimeDef { + syn::LifetimeDef { + attrs: Vec::new(), + lifetime: syn::Lifetime::new("'de"), + bounds: self.borrowed.iter().cloned().collect(), + } + } } // All the generics in the input, plus a bound `T: Deserialize` for each generic @@ -109,14 +176,13 @@ fn deserialize_body(item: &Item, params: &Parameters) -> Fragment { } else { match item.body { Body::Enum(ref variants) => { - deserialize_item_enum(&item.ident, params, variants, &item.attrs) + deserialize_item_enum(params, variants, &item.attrs) } Body::Struct(Style::Struct, ref fields) => { if fields.iter().any(|field| field.ident.is_none()) { panic!("struct has unnamed fields"); } - deserialize_struct(&item.ident, - None, + deserialize_struct(None, params, fields, &item.attrs, @@ -127,14 +193,13 @@ fn deserialize_body(item: &Item, params: &Parameters) -> Fragment { if fields.iter().any(|field| field.ident.is_some()) { panic!("tuple struct has named fields"); } - deserialize_tuple(&item.ident, - None, + deserialize_tuple(None, params, fields, &item.attrs, None) } - Body::Struct(Style::Unit, _) => deserialize_unit_struct(&item.ident, &item.attrs), + Body::Struct(Style::Unit, _) => deserialize_unit_struct(params, &item.attrs), } } } @@ -147,33 +212,34 @@ fn deserialize_from(from_type: &syn::Ty) -> Fragment { } } -fn deserialize_unit_struct(ident: &syn::Ident, item_attrs: &attr::Item) -> Fragment { +fn deserialize_unit_struct(params: &Parameters, item_attrs: &attr::Item) -> Fragment { + let this = ¶ms.this; let type_name = item_attrs.name().deserialize_name(); - let expecting = format!("unit struct {}", ident); + let expecting = format!("unit struct {}", params.type_name()); quote_block! { struct __Visitor; impl<'de> _serde::de::Visitor<'de> for __Visitor { - type Value = #ident; + type Value = #this; fn expecting(&self, formatter: &mut _serde::export::fmt::Formatter) -> _serde::export::fmt::Result { _serde::export::fmt::Formatter::write_str(formatter, #expecting) } #[inline] - fn visit_unit<__E>(self) -> _serde::export::Result<#ident, __E> + fn visit_unit<__E>(self) -> _serde::export::Result where __E: _serde::de::Error { - _serde::export::Ok(#ident) + _serde::export::Ok(#this) } #[inline] - fn visit_seq<__V>(self, _: __V) -> _serde::export::Result<#ident, __V::Error> + fn visit_seq<__V>(self, _: __V) -> _serde::export::Result where __V: _serde::de::SeqVisitor<'de> { - _serde::export::Ok(#ident) + _serde::export::Ok(#this) } } @@ -181,38 +247,48 @@ fn deserialize_unit_struct(ident: &syn::Ident, item_attrs: &attr::Item) -> Fragm } } -fn deserialize_tuple(ident: &syn::Ident, - variant_ident: Option<&syn::Ident>, +fn deserialize_tuple(variant_ident: Option<&syn::Ident>, params: &Parameters, fields: &[Field], item_attrs: &attr::Item, deserializer: Option) -> Fragment { + let this = ¶ms.this; let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = split_with_de_lifetime(params); + // If there are getters (implying private fields), construct the local type + // and use an `Into` conversion to get the remote type. If there are no + // getters then construct the target type directly. + let construct = if params.has_getter { + let local = ¶ms.local; + quote!(#local) + } else { + quote!(#this) + }; + let is_enum = variant_ident.is_some(); let type_path = match variant_ident { - Some(variant_ident) => quote!(#ident::#variant_ident), - None => quote!(#ident), + Some(variant_ident) => quote!(#construct::#variant_ident), + None => construct, }; let expecting = match variant_ident { - Some(variant_ident) => format!("tuple variant {}::{}", ident, variant_ident), - None => format!("tuple struct {}", ident), + Some(variant_ident) => format!("tuple variant {}::{}", params.type_name(), variant_ident), + None => format!("tuple struct {}", params.type_name()), }; let nfields = fields.len(); let visit_newtype_struct = if !is_enum && nfields == 1 { - Some(deserialize_newtype_struct(ident, &type_path, params, &fields[0])) + Some(deserialize_newtype_struct(&type_path, params, &fields[0])) } else { None }; - let visit_seq = Stmts(deserialize_seq(ident, &type_path, params, fields, false, item_attrs)); + let visit_seq = Stmts(deserialize_seq(&type_path, params, fields, false, item_attrs)); let visitor_expr = quote! { __Visitor { - marker: _serde::export::PhantomData::<#ident #ty_generics>, + marker: _serde::export::PhantomData::<#this #ty_generics>, lifetime: _serde::export::PhantomData, } }; @@ -237,12 +313,12 @@ fn deserialize_tuple(ident: &syn::Ident, quote_block! { struct __Visitor #de_impl_generics #where_clause { - marker: _serde::export::PhantomData<#ident #ty_generics>, + marker: _serde::export::PhantomData<#this #ty_generics>, lifetime: _serde::export::PhantomData<&'de ()>, } impl #de_impl_generics _serde::de::Visitor<'de> for __Visitor #de_ty_generics #where_clause { - type Value = #ident #ty_generics; + type Value = #this #ty_generics; fn expecting(&self, formatter: &mut _serde::export::fmt::Formatter) -> _serde::export::fmt::Result { _serde::export::fmt::Formatter::write_str(formatter, #expecting) @@ -262,8 +338,7 @@ fn deserialize_tuple(ident: &syn::Ident, } } -fn deserialize_seq(ident: &syn::Ident, - type_path: &Tokens, +fn deserialize_seq(type_path: &Tokens, params: &Parameters, fields: &[Field], is_struct: bool, @@ -292,7 +367,7 @@ fn deserialize_seq(ident: &syn::Ident, } Some(path) => { let (wrapper, wrapper_ty) = wrap_deserialize_with( - ident, params, field.ty, path); + params, field.ty, path); quote!({ #wrapper _serde::export::Option::map( @@ -314,7 +389,7 @@ fn deserialize_seq(ident: &syn::Ident, } }); - let result = if is_struct { + let mut result = if is_struct { let names = fields.iter().map(|f| &f.ident); quote! { #type_path { #( #names: #vars ),* } @@ -325,14 +400,20 @@ fn deserialize_seq(ident: &syn::Ident, } }; + if params.has_getter { + let this = ¶ms.this; + result = quote! { + _serde::export::Into::<#this>::into(#result) + }; + } + quote_block! { #(#let_values)* _serde::export::Ok(#result) } } -fn deserialize_newtype_struct(ident: &syn::Ident, - type_path: &Tokens, +fn deserialize_newtype_struct(type_path: &Tokens, params: &Parameters, field: &Field) -> Tokens { @@ -345,25 +426,33 @@ fn deserialize_newtype_struct(ident: &syn::Ident, } Some(path) => { let (wrapper, wrapper_ty) = - wrap_deserialize_with(ident, params, field.ty, path); + wrap_deserialize_with(params, field.ty, path); quote!({ #wrapper try!(<#wrapper_ty as _serde::Deserialize>::deserialize(__e)).value }) } }; + + let mut result = quote!(#type_path(#value)); + if params.has_getter { + let this = ¶ms.this; + result = quote! { + _serde::export::Into::<#this>::into(#result) + }; + } + quote! { #[inline] fn visit_newtype_struct<__E>(self, __e: __E) -> _serde::export::Result where __E: _serde::Deserializer<'de> { - _serde::export::Ok(#type_path(#value)) + _serde::export::Ok(#result) } } } -fn deserialize_struct(ident: &syn::Ident, - variant_ident: Option<&syn::Ident>, +fn deserialize_struct(variant_ident: Option<&syn::Ident>, params: &Parameters, fields: &[Field], item_attrs: &attr::Item, @@ -372,28 +461,39 @@ fn deserialize_struct(ident: &syn::Ident, let is_enum = variant_ident.is_some(); let is_untagged = deserializer.is_some(); + let this = ¶ms.this; let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = split_with_de_lifetime(params); + // If there are getters (implying private fields), construct the local type + // and use an `Into` conversion to get the remote type. If there are no + // getters then construct the target type directly. + let construct = if params.has_getter { + let local = ¶ms.local; + quote!(#local) + } else { + quote!(#this) + }; + let type_path = match variant_ident { - Some(variant_ident) => quote!(#ident::#variant_ident), - None => quote!(#ident), + Some(variant_ident) => quote!(#construct::#variant_ident), + None => construct, }; let expecting = match variant_ident { - Some(variant_ident) => format!("struct variant {}::{}", ident, variant_ident), - None => format!("struct {}", ident), + Some(variant_ident) => format!("struct variant {}::{}", params.type_name(), variant_ident), + None => format!("struct {}", params.type_name()), }; - let visit_seq = Stmts(deserialize_seq(ident, &type_path, params, fields, true, item_attrs)); + let visit_seq = Stmts(deserialize_seq(&type_path, params, fields, true, item_attrs)); let (field_visitor, fields_stmt, visit_map) = - deserialize_struct_visitor(ident, type_path, params, fields, item_attrs); + deserialize_struct_visitor(type_path, params, fields, item_attrs); let field_visitor = Stmts(field_visitor); let fields_stmt = Stmts(fields_stmt); let visit_map = Stmts(visit_map); let visitor_expr = quote! { __Visitor { - marker: _serde::export::PhantomData::<#ident #ty_generics>, + marker: _serde::export::PhantomData::<#this #ty_generics>, lifetime: _serde::export::PhantomData, } }; @@ -437,12 +537,12 @@ fn deserialize_struct(ident: &syn::Ident, #field_visitor struct __Visitor #de_impl_generics #where_clause { - marker: _serde::export::PhantomData<#ident #ty_generics>, + marker: _serde::export::PhantomData<#this #ty_generics>, lifetime: _serde::export::PhantomData<&'de ()>, } impl #de_impl_generics _serde::de::Visitor<'de> for __Visitor #de_ty_generics #where_clause { - type Value = #ident #ty_generics; + type Value = #this #ty_generics; fn expecting(&self, formatter: &mut _serde::export::fmt::Formatter) -> _serde::export::fmt::Result { _serde::export::fmt::Formatter::write_str(formatter, #expecting) @@ -464,46 +564,43 @@ fn deserialize_struct(ident: &syn::Ident, } } -fn deserialize_item_enum(ident: &syn::Ident, - params: &Parameters, +fn deserialize_item_enum(params: &Parameters, variants: &[Variant], item_attrs: &attr::Item) -> Fragment { match *item_attrs.tag() { attr::EnumTag::External => { - deserialize_externally_tagged_enum(ident, params, variants, item_attrs) + deserialize_externally_tagged_enum(params, variants, item_attrs) } attr::EnumTag::Internal { ref tag } => { - deserialize_internally_tagged_enum(ident, - params, + deserialize_internally_tagged_enum(params, variants, item_attrs, tag) } attr::EnumTag::Adjacent { ref tag, ref content } => { - deserialize_adjacently_tagged_enum(ident, - params, + deserialize_adjacently_tagged_enum(params, variants, item_attrs, tag, content) } attr::EnumTag::None => { - deserialize_untagged_enum(ident, params, variants, item_attrs) + deserialize_untagged_enum(params, variants, item_attrs) } } } -fn deserialize_externally_tagged_enum(ident: &syn::Ident, - params: &Parameters, +fn deserialize_externally_tagged_enum(params: &Parameters, variants: &[Variant], item_attrs: &attr::Item) -> Fragment { + let this = ¶ms.this; let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = split_with_de_lifetime(params); let type_name = item_attrs.name().deserialize_name(); - let expecting = format!("enum {}", ident); + let expecting = format!("enum {}", params.type_name()); let variant_names_idents: Vec<_> = variants.iter() .enumerate() @@ -527,8 +624,7 @@ fn deserialize_externally_tagged_enum(ident: &syn::Ident, .map(|(i, variant)| { let variant_name = field_i(i); - let block = Match(deserialize_externally_tagged_variant(ident, - params, + let block = Match(deserialize_externally_tagged_variant(params, variant, item_attrs)); @@ -561,12 +657,12 @@ fn deserialize_externally_tagged_enum(ident: &syn::Ident, #variant_visitor struct __Visitor #de_impl_generics #where_clause { - marker: _serde::export::PhantomData<#ident #ty_generics>, + marker: _serde::export::PhantomData<#this #ty_generics>, lifetime: _serde::export::PhantomData<&'de ()>, } impl #de_impl_generics _serde::de::Visitor<'de> for __Visitor #de_ty_generics #where_clause { - type Value = #ident #ty_generics; + type Value = #this #ty_generics; fn expecting(&self, formatter: &mut _serde::export::fmt::Formatter) -> _serde::export::fmt::Result { _serde::export::fmt::Formatter::write_str(formatter, #expecting) @@ -583,14 +679,13 @@ fn deserialize_externally_tagged_enum(ident: &syn::Ident, _serde::Deserializer::deserialize_enum(__deserializer, #type_name, VARIANTS, __Visitor { - marker: _serde::export::PhantomData::<#ident #ty_generics>, + marker: _serde::export::PhantomData::<#this #ty_generics>, lifetime: _serde::export::PhantomData, }) } } -fn deserialize_internally_tagged_enum(ident: &syn::Ident, - params: &Parameters, +fn deserialize_internally_tagged_enum(params: &Parameters, variants: &[Variant], item_attrs: &attr::Item, tag: &str) @@ -618,7 +713,6 @@ fn deserialize_internally_tagged_enum(ident: &syn::Ident, let variant_name = field_i(i); let block = Match(deserialize_internally_tagged_variant( - ident, params, variant, item_attrs, @@ -645,13 +739,13 @@ fn deserialize_internally_tagged_enum(ident: &syn::Ident, } } -fn deserialize_adjacently_tagged_enum(ident: &syn::Ident, - params: &Parameters, +fn deserialize_adjacently_tagged_enum(params: &Parameters, variants: &[Variant], item_attrs: &attr::Item, tag: &str, content: &str) -> Fragment { + let this = ¶ms.this; let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = split_with_de_lifetime(params); let variant_names_idents: Vec<_> = variants.iter() @@ -676,7 +770,6 @@ fn deserialize_adjacently_tagged_enum(ident: &syn::Ident, let variant_index = field_i(i); let block = Match(deserialize_untagged_variant( - ident, params, variant, item_attrs, @@ -689,7 +782,7 @@ fn deserialize_adjacently_tagged_enum(ident: &syn::Ident, }) .collect(); - let expecting = format!("adjacently tagged enum {}", ident); + let expecting = format!("adjacently tagged enum {}", params.type_name()); let type_name = item_attrs.name().deserialize_name(); let tag_or_content = quote! { @@ -724,7 +817,7 @@ fn deserialize_adjacently_tagged_enum(ident: &syn::Ident, let variant_index = field_i(i); let variant_ident = &variant.ident; quote! { - __Field::#variant_index => _serde::export::Ok(#ident::#variant_ident), + __Field::#variant_index => _serde::export::Ok(#this::#variant_ident), } }); missing_content = quote! { @@ -755,12 +848,12 @@ fn deserialize_adjacently_tagged_enum(ident: &syn::Ident, struct __Seed #de_impl_generics #where_clause { field: __Field, - marker: _serde::export::PhantomData<#ident #ty_generics>, + marker: _serde::export::PhantomData<#this #ty_generics>, lifetime: _serde::export::PhantomData<&'de ()>, } impl #de_impl_generics _serde::de::DeserializeSeed<'de> for __Seed #de_ty_generics #where_clause { - type Value = #ident #ty_generics; + type Value = #this #ty_generics; fn deserialize<__D>(self, __deserializer: __D) -> _serde::export::Result where __D: _serde::Deserializer<'de> @@ -772,12 +865,12 @@ fn deserialize_adjacently_tagged_enum(ident: &syn::Ident, } struct __Visitor #de_impl_generics #where_clause { - marker: _serde::export::PhantomData<#ident #ty_generics>, + marker: _serde::export::PhantomData<#this #ty_generics>, lifetime: _serde::export::PhantomData<&'de ()>, } impl #de_impl_generics _serde::de::Visitor<'de> for __Visitor #de_ty_generics #where_clause { - type Value = #ident #ty_generics; + type Value = #this #ty_generics; fn expecting(&self, formatter: &mut _serde::export::fmt::Formatter) -> _serde::export::fmt::Result { _serde::export::fmt::Formatter::write_str(formatter, #expecting) @@ -878,14 +971,13 @@ fn deserialize_adjacently_tagged_enum(ident: &syn::Ident, const FIELDS: &'static [&'static str] = &[#tag, #content]; _serde::Deserializer::deserialize_struct(__deserializer, #type_name, FIELDS, __Visitor { - marker: _serde::export::PhantomData::<#ident #ty_generics>, + marker: _serde::export::PhantomData::<#this #ty_generics>, lifetime: _serde::export::PhantomData, }) } } -fn deserialize_untagged_enum(ident: &syn::Ident, - params: &Parameters, +fn deserialize_untagged_enum(params: &Parameters, variants: &[Variant], item_attrs: &attr::Item) -> Fragment { @@ -893,7 +985,6 @@ fn deserialize_untagged_enum(ident: &syn::Ident, .filter(|variant| !variant.attrs.skip_deserializing()) .map(|variant| { Expr(deserialize_untagged_variant( - ident, params, variant, item_attrs, @@ -907,7 +998,7 @@ fn deserialize_untagged_enum(ident: &syn::Ident, // largest number of fields. I'm not sure I like that. Maybe it would be // better to save all the errors and combine them into one message that // explains why none of the variants matched. - let fallthrough_msg = format!("data did not match any variant of untagged enum {}", ident); + let fallthrough_msg = format!("data did not match any variant of untagged enum {}", params.type_name()); quote_block! { let __content = try!(<_serde::private::de::Content as _serde::Deserialize>::deserialize(__deserializer)); @@ -922,8 +1013,7 @@ fn deserialize_untagged_enum(ident: &syn::Ident, } } -fn deserialize_externally_tagged_variant(ident: &syn::Ident, - params: &Parameters, +fn deserialize_externally_tagged_variant(params: &Parameters, variant: &Variant, item_attrs: &attr::Item) -> Fragment { @@ -931,28 +1021,26 @@ fn deserialize_externally_tagged_variant(ident: &syn::Ident, match variant.style { Style::Unit => { + let this = ¶ms.this; quote_block! { try!(_serde::de::VariantVisitor::visit_unit(__visitor)); - _serde::export::Ok(#ident::#variant_ident) + _serde::export::Ok(#this::#variant_ident) } } Style::Newtype => { - deserialize_externally_tagged_newtype_variant(ident, - variant_ident, + deserialize_externally_tagged_newtype_variant(variant_ident, params, &variant.fields[0]) } Style::Tuple => { - deserialize_tuple(ident, - Some(variant_ident), + deserialize_tuple(Some(variant_ident), params, &variant.fields, item_attrs, None) } Style::Struct => { - deserialize_struct(ident, - Some(variant_ident), + deserialize_struct(Some(variant_ident), params, &variant.fields, item_attrs, @@ -961,8 +1049,7 @@ fn deserialize_externally_tagged_variant(ident: &syn::Ident, } } -fn deserialize_internally_tagged_variant(ident: &syn::Ident, - params: &Parameters, +fn deserialize_internally_tagged_variant(params: &Parameters, variant: &Variant, item_attrs: &attr::Item, deserializer: Tokens) @@ -971,16 +1058,16 @@ fn deserialize_internally_tagged_variant(ident: &syn::Ident, match variant.style { Style::Unit => { - let type_name = ident.as_ref(); + let this = ¶ms.this; + let type_name = params.type_name(); let variant_name = variant.ident.as_ref(); quote_block! { try!(_serde::Deserializer::deserialize(#deserializer, _serde::private::de::InternallyTaggedUnitVisitor::new(#type_name, #variant_name))); - _serde::export::Ok(#ident::#variant_ident) + _serde::export::Ok(#this::#variant_ident) } } Style::Newtype | Style::Struct => { - deserialize_untagged_variant(ident, - params, + deserialize_untagged_variant(params, variant, item_attrs, deserializer) @@ -989,8 +1076,7 @@ fn deserialize_internally_tagged_variant(ident: &syn::Ident, } } -fn deserialize_untagged_variant(ident: &syn::Ident, - params: &Parameters, +fn deserialize_untagged_variant(params: &Parameters, variant: &Variant, item_attrs: &attr::Item, deserializer: Tokens) @@ -999,7 +1085,8 @@ fn deserialize_untagged_variant(ident: &syn::Ident, match variant.style { Style::Unit => { - let type_name = ident.as_ref(); + let this = ¶ms.this; + let type_name = params.type_name(); let variant_name = variant.ident.as_ref(); quote_expr! { _serde::export::Result::map( @@ -1007,27 +1094,24 @@ fn deserialize_untagged_variant(ident: &syn::Ident, #deserializer, _serde::private::de::UntaggedUnitVisitor::new(#type_name, #variant_name) ), - |()| #ident::#variant_ident) + |()| #this::#variant_ident) } } Style::Newtype => { - deserialize_untagged_newtype_variant(ident, - variant_ident, + deserialize_untagged_newtype_variant(variant_ident, params, &variant.fields[0], deserializer) } Style::Tuple => { - deserialize_tuple(ident, - Some(variant_ident), + deserialize_tuple(Some(variant_ident), params, &variant.fields, item_attrs, Some(deserializer)) } Style::Struct => { - deserialize_struct(ident, - Some(variant_ident), + deserialize_struct(Some(variant_ident), params, &variant.fields, item_attrs, @@ -1036,56 +1120,56 @@ fn deserialize_untagged_variant(ident: &syn::Ident, } } -fn deserialize_externally_tagged_newtype_variant(ident: &syn::Ident, - variant_ident: &syn::Ident, +fn deserialize_externally_tagged_newtype_variant(variant_ident: &syn::Ident, params: &Parameters, field: &Field) -> Fragment { + let this = ¶ms.this; match field.attrs.deserialize_with() { None => { let field_ty = &field.ty; quote_expr! { _serde::export::Result::map( _serde::de::VariantVisitor::visit_newtype::<#field_ty>(__visitor), - #ident::#variant_ident) + #this::#variant_ident) } } Some(path) => { let (wrapper, wrapper_ty) = - wrap_deserialize_with(ident, params, field.ty, path); + wrap_deserialize_with(params, field.ty, path); quote_block! { #wrapper _serde::export::Result::map( _serde::de::VariantVisitor::visit_newtype::<#wrapper_ty>(__visitor), - |__wrapper| #ident::#variant_ident(__wrapper.value)) + |__wrapper| #this::#variant_ident(__wrapper.value)) } } } } -fn deserialize_untagged_newtype_variant(ident: &syn::Ident, - variant_ident: &syn::Ident, +fn deserialize_untagged_newtype_variant(variant_ident: &syn::Ident, params: &Parameters, field: &Field, deserializer: Tokens) -> Fragment { + let this = ¶ms.this; match field.attrs.deserialize_with() { None => { let field_ty = &field.ty; quote_expr! { _serde::export::Result::map( <#field_ty as _serde::Deserialize>::deserialize(#deserializer), - #ident::#variant_ident) + #this::#variant_ident) } } Some(path) => { let (wrapper, wrapper_ty) = - wrap_deserialize_with(ident, params, field.ty, path); + wrap_deserialize_with(params, field.ty, path); quote_block! { #wrapper _serde::export::Result::map( <#wrapper_ty as _serde::Deserialize>::deserialize(#deserializer), - |__wrapper| #ident::#variant_ident(__wrapper.value)) + |__wrapper| #this::#variant_ident(__wrapper.value)) } } } @@ -1203,8 +1287,7 @@ fn deserialize_field_visitor(fields: Vec<(String, Ident)>, } } -fn deserialize_struct_visitor(ident: &syn::Ident, - struct_path: Tokens, +fn deserialize_struct_visitor(struct_path: Tokens, params: &Parameters, fields: &[Field], item_attrs: &attr::Item) @@ -1224,13 +1307,12 @@ fn deserialize_struct_visitor(ident: &syn::Ident, let field_visitor = deserialize_field_visitor(field_names_idents, item_attrs, false); - let visit_map = deserialize_map(ident, struct_path, params, fields, item_attrs); + let visit_map = deserialize_map(struct_path, params, fields, item_attrs); (field_visitor, fields_stmt, visit_map) } -fn deserialize_map(ident: &syn::Ident, - struct_path: Tokens, +fn deserialize_map(struct_path: Tokens, params: &Parameters, fields: &[Field], item_attrs: &attr::Item) @@ -1266,7 +1348,7 @@ fn deserialize_map(ident: &syn::Ident, } Some(path) => { let (wrapper, wrapper_ty) = wrap_deserialize_with( - ident, params, field.ty, path); + params, field.ty, path); quote!({ #wrapper try!(_serde::de::MapVisitor::visit_value::<#wrapper_ty>(&mut __visitor)).value @@ -1354,6 +1436,14 @@ fn deserialize_map(ident: &syn::Ident, } }; + let mut result = quote!(#struct_path { #(#result),* }); + if params.has_getter { + let this = ¶ms.this; + result = quote! { + _serde::export::Into::<#this>::into(#result) + }; + } + quote_block! { #(#let_values)* @@ -1363,7 +1453,7 @@ fn deserialize_map(ident: &syn::Ident, #(#extract_values)* - _serde::export::Ok(#struct_path { #(#result),* }) + _serde::export::Ok(#result) } } @@ -1373,17 +1463,17 @@ fn field_i(i: usize) -> Ident { /// 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(ident: &syn::Ident, - params: &Parameters, +fn wrap_deserialize_with(params: &Parameters, field_ty: &syn::Ty, deserialize_with: &syn::Path) -> (Tokens, Tokens) { + let this = ¶ms.this; let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = split_with_de_lifetime(params); let wrapper = quote! { struct __DeserializeWith #de_impl_generics #where_clause { value: #field_ty, - phantom: _serde::export::PhantomData<#ident #ty_generics>, + phantom: _serde::export::PhantomData<#this #ty_generics>, lifetime: _serde::export::PhantomData<&'de ()>, } @@ -1444,11 +1534,7 @@ struct DeImplGenerics<'a>(&'a Parameters); impl<'a> ToTokens for DeImplGenerics<'a> { fn to_tokens(&self, tokens: &mut Tokens) { let mut generics = self.0.generics.clone(); - generics.lifetimes.insert(0, syn::LifetimeDef { - attrs: Vec::new(), - lifetime: syn::Lifetime::new("'de"), - bounds: self.0.borrowed.iter().cloned().collect(), - }); + generics.lifetimes.insert(0, self.0.de_lifetime_def()); let (impl_generics, _, _) = generics.split_for_impl(); impl_generics.to_tokens(tokens); } diff --git a/serde_derive/src/ser.rs b/serde_derive/src/ser.rs index 51826928..179c5d99 100644 --- a/serde_derive/src/ser.rs +++ b/serde_derive/src/ser.rs @@ -12,15 +12,23 @@ pub fn expand_derive_serialize(item: &syn::DeriveInput) -> Result(__self: &#remote #ty_generics, __serializer: __S) -> _serde::export::Result<__S::Ok, __S::Error> + where __S: _serde::Serializer + { + #body + } + } + } + } else { + quote! { #[automatically_derived] impl #impl_generics _serde::Serialize for #ident #ty_generics #where_clause { fn serialize<__S>(&self, __serializer: __S) -> _serde::export::Result<__S::Ok, __S::Error> @@ -29,10 +37,61 @@ pub fn expand_derive_serialize(item: &syn::DeriveInput) -> Result Self { + let self_var = if item.attrs.remote().is_some() { + Ident::new("__self") + } else { + Ident::new("self") + }; + + let this = match item.attrs.remote() { + Some(remote) => remote.clone(), + None => item.ident.clone().into(), + }; + + let generics = build_generics(item); + + Parameters { + self_var: self_var, + this: this, + generics: generics, + } + } + + /// Type name to use in error messages and `&'static str` arguments to + /// various Serializer methods. + fn type_name(&self) -> &str { + self.this.segments.last().unwrap().ident.as_ref() + } +} + // All the generics in the input, plus a bound `T: Serialize` for each generic // field type that will be serialized by us. fn build_generics(item: &Item) -> syn::Generics { @@ -60,38 +119,39 @@ fn needs_serialize_bound(attrs: &attr::Field) -> bool { !attrs.skip_serializing() && attrs.serialize_with().is_none() && attrs.ser_bound().is_none() } -fn serialize_body(item: &Item, generics: &syn::Generics) -> Fragment { +fn serialize_body(item: &Item, params: &Parameters) -> Fragment { if let Some(into_type) = item.attrs.into_type() { - serialize_into(into_type) + serialize_into(params, into_type) } else { match item.body { Body::Enum(ref variants) => { - serialize_item_enum(&item.ident, generics, variants, &item.attrs) + serialize_item_enum(params, variants, &item.attrs) } Body::Struct(Style::Struct, ref fields) => { if fields.iter().any(|field| field.ident.is_none()) { panic!("struct has unnamed fields"); } - serialize_struct(&item.ident, generics, fields, &item.attrs) + serialize_struct(params, fields, &item.attrs) } Body::Struct(Style::Tuple, ref fields) => { if fields.iter().any(|field| field.ident.is_some()) { panic!("tuple struct has named fields"); } - serialize_tuple_struct(&item.ident, generics, fields, &item.attrs) + serialize_tuple_struct(params, fields, &item.attrs) } Body::Struct(Style::Newtype, ref fields) => { - serialize_newtype_struct(&item.ident, generics, &fields[0], &item.attrs) + serialize_newtype_struct(params, &fields[0], &item.attrs) } Body::Struct(Style::Unit, _) => serialize_unit_struct(&item.attrs), } } } -fn serialize_into(into_type: &syn::Ty) -> Fragment { +fn serialize_into(params: &Parameters, into_type: &syn::Ty) -> Fragment { + let self_var = ¶ms.self_var; quote_block! { _serde::Serialize::serialize( - &>::into(_serde::export::Clone::clone(self)), + &_serde::export::Into::<#into_type>::into(_serde::export::Clone::clone(#self_var)), __serializer) } } @@ -104,16 +164,15 @@ fn serialize_unit_struct(item_attrs: &attr::Item) -> Fragment { } } -fn serialize_newtype_struct(ident: &syn::Ident, - generics: &syn::Generics, +fn serialize_newtype_struct(params: &Parameters, field: &Field, item_attrs: &attr::Item) -> Fragment { let type_name = item_attrs.name().serialize_name(); - let mut field_expr = quote!(&self.0); + let mut field_expr = get_field(params, field, 0); if let Some(path) = field.attrs.serialize_with() { - field_expr = wrap_serialize_with(ident, generics, field.ty, path, field_expr); + field_expr = wrap_serialize_with(params, field.ty, path, field_expr); } quote_expr! { @@ -121,15 +180,13 @@ fn serialize_newtype_struct(ident: &syn::Ident, } } -fn serialize_tuple_struct(ident: &syn::Ident, - generics: &syn::Generics, +fn serialize_tuple_struct(params: &Parameters, fields: &[Field], item_attrs: &attr::Item) -> Fragment { let serialize_stmts = - serialize_tuple_struct_visitor(ident, - fields, - generics, + serialize_tuple_struct_visitor(fields, + params, false, quote!(_serde::ser::SerializeTupleStruct::serialize_field)); @@ -144,15 +201,13 @@ fn serialize_tuple_struct(ident: &syn::Ident, } } -fn serialize_struct(ident: &syn::Ident, - generics: &syn::Generics, +fn serialize_struct(params: &Parameters, fields: &[Field], item_attrs: &attr::Item) -> Fragment { let serialize_fields = - serialize_struct_visitor(ident, - fields, - generics, + serialize_struct_visitor(fields, + params, false, quote!(_serde::ser::SerializeStruct::serialize_field)); @@ -165,12 +220,13 @@ fn serialize_struct(ident: &syn::Ident, let let_mut = mut_if(serialized_fields.peek().is_some()); let len = serialized_fields.map(|field| { - let ident = field.ident.clone().expect("struct has unnamed fields"); - let field_expr = quote!(&self.#ident); - match field.attrs.skip_serializing_if() { - Some(path) => quote!(if #path(#field_expr) { 0 } else { 1 }), None => quote!(1), + Some(path) => { + let ident = field.ident.clone().expect("struct has unnamed fields"); + let field_expr = get_field(params, field, ident); + quote!(if #path(#field_expr) { 0 } else { 1 }) + } } }) .fold(quote!(0), |sum, expr| quote!(#sum + #expr)); @@ -182,16 +238,16 @@ fn serialize_struct(ident: &syn::Ident, } } -fn serialize_item_enum(ident: &syn::Ident, - generics: &syn::Generics, +fn serialize_item_enum(params: &Parameters, variants: &[Variant], item_attrs: &attr::Item) -> Fragment { + let self_var = ¶ms.self_var; + let arms: Vec<_> = variants.iter() .enumerate() .map(|(variant_index, variant)| { - serialize_variant(ident, - generics, + serialize_variant(params, variant, variant_index, item_attrs) @@ -199,23 +255,23 @@ fn serialize_item_enum(ident: &syn::Ident, .collect(); quote_expr! { - match *self { + match *#self_var { #(#arms)* } } } -fn serialize_variant(ident: &syn::Ident, - generics: &syn::Generics, +fn serialize_variant(params: &Parameters, variant: &Variant, variant_index: usize, item_attrs: &attr::Item) -> Tokens { + let this = ¶ms.this; let variant_ident = variant.ident.clone(); if variant.attrs.skip_serializing() { let skipped_msg = format!("the enum variant {}::{} cannot be serialized", - ident, variant_ident); + params.type_name(), variant_ident); let skipped_err = quote! { _serde::export::Err(_serde::ser::Error::custom(#skipped_msg)) }; @@ -225,26 +281,26 @@ fn serialize_variant(ident: &syn::Ident, Style::Struct => quote!( {..} ), }; quote! { - #ident::#variant_ident #fields_pat => #skipped_err, + #this::#variant_ident #fields_pat => #skipped_err, } } else { // variant wasn't skipped let case = match variant.style { Style::Unit => { quote! { - #ident::#variant_ident + #this::#variant_ident } } Style::Newtype => { quote! { - #ident::#variant_ident(ref __field0) + #this::#variant_ident(ref __field0) } } Style::Tuple => { let field_names = (0..variant.fields.len()) .map(|i| Ident::new(format!("__field{}", i))); quote! { - #ident::#variant_ident(#(ref #field_names),*) + #this::#variant_ident(#(ref #field_names),*) } } Style::Struct => { @@ -252,35 +308,32 @@ fn serialize_variant(ident: &syn::Ident, .iter() .map(|f| f.ident.clone().expect("struct variant has unnamed fields")); quote! { - #ident::#variant_ident { #(ref #fields),* } + #this::#variant_ident { #(ref #fields),* } } } }; let body = Match(match *item_attrs.tag() { attr::EnumTag::External => { - serialize_externally_tagged_variant(ident, - generics, + serialize_externally_tagged_variant(params, variant, variant_index, item_attrs) } attr::EnumTag::Internal { ref tag } => { - serialize_internally_tagged_variant(ident, - generics, + serialize_internally_tagged_variant(params, variant, item_attrs, tag) } attr::EnumTag::Adjacent { ref tag, ref content } => { - serialize_adjacently_tagged_variant(ident, - generics, + serialize_adjacently_tagged_variant(params, variant, item_attrs, tag, content) } - attr::EnumTag::None => serialize_untagged_variant(ident, generics, variant, item_attrs), + attr::EnumTag::None => serialize_untagged_variant(params, variant, item_attrs), }); quote! { @@ -289,8 +342,7 @@ fn serialize_variant(ident: &syn::Ident, } } -fn serialize_externally_tagged_variant(ident: &syn::Ident, - generics: &syn::Generics, +fn serialize_externally_tagged_variant(params: &Parameters, variant: &Variant, variant_index: usize, item_attrs: &attr::Item) @@ -313,7 +365,7 @@ fn serialize_externally_tagged_variant(ident: &syn::Ident, let field = &variant.fields[0]; let mut field_expr = quote!(__field0); if let Some(path) = field.attrs.serialize_with() { - field_expr = wrap_serialize_with(ident, generics, field.ty, path, field_expr); + field_expr = wrap_serialize_with(params, field.ty, path, field_expr); } quote_expr! { @@ -332,8 +384,7 @@ fn serialize_externally_tagged_variant(ident: &syn::Ident, variant_index: variant_index, variant_name: variant_name, }, - ident, - generics, + params, &variant.fields) } Style::Struct => { @@ -341,16 +392,14 @@ fn serialize_externally_tagged_variant(ident: &syn::Ident, variant_index: variant_index, variant_name: variant_name, }, - ident, - generics, + params, &variant.fields, &type_name) } } } -fn serialize_internally_tagged_variant(ident: &syn::Ident, - generics: &syn::Generics, +fn serialize_internally_tagged_variant(params: &Parameters, variant: &Variant, item_attrs: &attr::Item, tag: &str) @@ -358,7 +407,7 @@ fn serialize_internally_tagged_variant(ident: &syn::Ident, let type_name = item_attrs.name().serialize_name(); let variant_name = variant.attrs.name().serialize_name(); - let enum_ident_str = ident.as_ref(); + let enum_ident_str = params.type_name(); let variant_ident_str = variant.ident.as_ref(); match variant.style { @@ -375,7 +424,7 @@ fn serialize_internally_tagged_variant(ident: &syn::Ident, let field = &variant.fields[0]; let mut field_expr = quote!(__field0); if let Some(path) = field.attrs.serialize_with() { - field_expr = wrap_serialize_with(ident, generics, field.ty, path, field_expr); + field_expr = wrap_serialize_with(params, field.ty, path, field_expr); } quote_expr! { @@ -394,8 +443,7 @@ fn serialize_internally_tagged_variant(ident: &syn::Ident, tag: tag, variant_name: variant_name, }, - ident, - generics, + params, &variant.fields, &type_name) } @@ -403,13 +451,13 @@ fn serialize_internally_tagged_variant(ident: &syn::Ident, } } -fn serialize_adjacently_tagged_variant(ident: &syn::Ident, - generics: &syn::Generics, +fn serialize_adjacently_tagged_variant(params: &Parameters, variant: &Variant, item_attrs: &attr::Item, tag: &str, content: &str) -> Fragment { + let this = ¶ms.this; let type_name = item_attrs.name().serialize_name(); let variant_name = variant.attrs.name().serialize_name(); @@ -427,7 +475,7 @@ fn serialize_adjacently_tagged_variant(ident: &syn::Ident, let field = &variant.fields[0]; let mut field_expr = quote!(__field0); if let Some(path) = field.attrs.serialize_with() { - field_expr = wrap_serialize_with(ident, generics, field.ty, path, field_expr); + field_expr = wrap_serialize_with(params, field.ty, path, field_expr); } quote_expr! { @@ -436,14 +484,12 @@ fn serialize_adjacently_tagged_variant(ident: &syn::Ident, } Style::Tuple => { serialize_tuple_variant(TupleVariant::Untagged, - ident, - generics, + params, &variant.fields) } Style::Struct => { serialize_struct_variant(StructVariant::Untagged, - ident, - generics, + params, &variant.fields, &variant_name) } @@ -466,15 +512,15 @@ fn serialize_adjacently_tagged_variant(ident: &syn::Ident, } }; - let (_, ty_generics, where_clause) = generics.split_for_impl(); + let (_, ty_generics, where_clause) = params.generics.split_for_impl(); - let wrapper_generics = bound::with_lifetime_bound(generics, "'__a"); + let wrapper_generics = bound::with_lifetime_bound(¶ms.generics, "'__a"); let (wrapper_impl_generics, wrapper_ty_generics, _) = wrapper_generics.split_for_impl(); quote_block! { struct __AdjacentlyTagged #wrapper_generics #where_clause { data: (#(&'__a #fields_ty,)*), - phantom: _serde::export::PhantomData<#ident #ty_generics>, + phantom: _serde::export::PhantomData<#this #ty_generics>, } impl #wrapper_impl_generics _serde::Serialize for __AdjacentlyTagged #wrapper_ty_generics #where_clause { @@ -493,14 +539,13 @@ fn serialize_adjacently_tagged_variant(ident: &syn::Ident, try!(_serde::ser::SerializeStruct::serialize_field( &mut __struct, #content, &__AdjacentlyTagged { data: (#(#fields_ident,)*), - phantom: _serde::export::PhantomData::<#ident #ty_generics>, + phantom: _serde::export::PhantomData::<#this #ty_generics>, })); _serde::ser::SerializeStruct::end(__struct) } } -fn serialize_untagged_variant(ident: &syn::Ident, - generics: &syn::Generics, +fn serialize_untagged_variant(params: &Parameters, variant: &Variant, item_attrs: &attr::Item) -> Fragment { @@ -514,7 +559,7 @@ fn serialize_untagged_variant(ident: &syn::Ident, let field = &variant.fields[0]; let mut field_expr = quote!(__field0); if let Some(path) = field.attrs.serialize_with() { - field_expr = wrap_serialize_with(ident, generics, field.ty, path, field_expr); + field_expr = wrap_serialize_with(params, field.ty, path, field_expr); } quote_expr! { @@ -522,13 +567,12 @@ fn serialize_untagged_variant(ident: &syn::Ident, } } Style::Tuple => { - serialize_tuple_variant(TupleVariant::Untagged, ident, generics, &variant.fields) + serialize_tuple_variant(TupleVariant::Untagged, params, &variant.fields) } Style::Struct => { let type_name = item_attrs.name().serialize_name(); serialize_struct_variant(StructVariant::Untagged, - ident, - generics, + params, &variant.fields, &type_name) } @@ -545,8 +589,7 @@ enum TupleVariant { } fn serialize_tuple_variant(context: TupleVariant, - ident: &syn::Ident, - generics: &syn::Generics, + params: &Parameters, fields: &[Field]) -> Fragment { let method = match context { @@ -557,7 +600,7 @@ fn serialize_tuple_variant(context: TupleVariant, }; let serialize_stmts = - serialize_tuple_struct_visitor(ident, fields, generics, true, method); + serialize_tuple_struct_visitor(fields, params, true, method); let len = serialize_stmts.len(); let let_mut = mut_if(len > 0); @@ -597,8 +640,7 @@ enum StructVariant<'a> { } fn serialize_struct_variant<'a>(context: StructVariant<'a>, - ident: &syn::Ident, - generics: &syn::Generics, + params: &Parameters, fields: &[Field], name: &str) -> Fragment { @@ -610,7 +652,7 @@ fn serialize_struct_variant<'a>(context: StructVariant<'a>, StructVariant::Untagged => quote!(_serde::ser::SerializeStruct::serialize_field), }; - let serialize_fields = serialize_struct_visitor(ident, fields, generics, true, method); + let serialize_fields = serialize_struct_visitor(fields, params, true, method); let mut serialized_fields = fields.iter() .filter(|&field| !field.attrs.skip_serializing()) @@ -672,9 +714,8 @@ fn serialize_struct_variant<'a>(context: StructVariant<'a>, } } -fn serialize_tuple_struct_visitor(ident: &syn::Ident, - fields: &[Field], - generics: &syn::Generics, +fn serialize_tuple_struct_visitor(fields: &[Field], + params: &Parameters, is_enum: bool, func: Tokens) -> Vec { @@ -685,8 +726,7 @@ fn serialize_tuple_struct_visitor(ident: &syn::Ident, let id = Ident::new(format!("__field{}", i)); quote!(#id) } else { - let i = Ident::new(i); - quote!(&self.#i) + get_field(params, field, i) }; let skip = field.attrs @@ -695,7 +735,7 @@ fn serialize_tuple_struct_visitor(ident: &syn::Ident, if let Some(path) = field.attrs.serialize_with() { field_expr = - wrap_serialize_with(ident, generics, field.ty, path, field_expr); + wrap_serialize_with(params, field.ty, path, field_expr); } let ser = quote! { @@ -710,9 +750,8 @@ fn serialize_tuple_struct_visitor(ident: &syn::Ident, .collect() } -fn serialize_struct_visitor(ident: &syn::Ident, - fields: &[Field], - generics: &syn::Generics, +fn serialize_struct_visitor(fields: &[Field], + params: &Parameters, is_enum: bool, func: Tokens) -> Vec { @@ -723,7 +762,7 @@ fn serialize_struct_visitor(ident: &syn::Ident, let mut field_expr = if is_enum { quote!(#field_ident) } else { - quote!(&self.#field_ident) + get_field(params, field, field_ident) }; let key_expr = field.attrs.name().serialize_name(); @@ -734,7 +773,7 @@ fn serialize_struct_visitor(ident: &syn::Ident, if let Some(path) = field.attrs.serialize_with() { field_expr = - wrap_serialize_with(ident, generics, field.ty, path, field_expr) + wrap_serialize_with(params, field.ty, path, field_expr) } let ser = quote! { @@ -749,21 +788,21 @@ fn serialize_struct_visitor(ident: &syn::Ident, .collect() } -fn wrap_serialize_with(ident: &syn::Ident, - generics: &syn::Generics, +fn wrap_serialize_with(params: &Parameters, field_ty: &syn::Ty, serialize_with: &syn::Path, value: Tokens) -> Tokens { - let (_, ty_generics, where_clause) = generics.split_for_impl(); + let this = ¶ms.this; + let (_, ty_generics, where_clause) = params.generics.split_for_impl(); - let wrapper_generics = bound::with_lifetime_bound(generics, "'__a"); + let wrapper_generics = bound::with_lifetime_bound(¶ms.generics, "'__a"); let (wrapper_impl_generics, wrapper_ty_generics, _) = wrapper_generics.split_for_impl(); quote!({ struct __SerializeWith #wrapper_impl_generics #where_clause { value: &'__a #field_ty, - phantom: _serde::export::PhantomData<#ident #ty_generics>, + phantom: _serde::export::PhantomData<#this #ty_generics>, } impl #wrapper_impl_generics _serde::Serialize for __SerializeWith #wrapper_ty_generics #where_clause { @@ -776,7 +815,7 @@ fn wrap_serialize_with(ident: &syn::Ident, &__SerializeWith { value: #value, - phantom: _serde::export::PhantomData::<#ident #ty_generics>, + phantom: _serde::export::PhantomData::<#this #ty_generics>, } }) } @@ -790,3 +829,16 @@ fn wrap_serialize_with(ident: &syn::Ident, fn mut_if(is_mut: bool) -> Option { if is_mut { Some(quote!(mut)) } else { None } } + +fn get_field(params: &Parameters, field: &Field, ident: I) -> Tokens + where I: Into +{ + let self_var = ¶ms.self_var; + match field.attrs.getter() { + None => { + let ident = ident.into(); + quote!(&#self_var.#ident) + } + Some(getter) => quote!(&#getter(#self_var)), + } +} diff --git a/test_suite/tests/test_remote.rs b/test_suite/tests/test_remote.rs new file mode 100644 index 00000000..4f21a09a --- /dev/null +++ b/test_suite/tests/test_remote.rs @@ -0,0 +1,184 @@ +#[macro_use] +extern crate serde_derive; + +extern crate serde; + +mod remote { + pub struct Unit; + + pub struct PrimitivePriv(u8); + + pub struct PrimitivePub(pub u8); + + pub struct NewtypePriv(Unit); + + pub struct NewtypePub(pub Unit); + + pub struct TuplePriv(u8, Unit); + + pub struct TuplePub(pub u8, pub Unit); + + pub struct StructPriv { + a: u8, + b: Unit, + } + + pub struct StructPub { + pub a: u8, + pub b: Unit, + } + + impl PrimitivePriv { + pub fn new(a: u8) -> Self { + PrimitivePriv(a) + } + + pub fn get(&self) -> u8 { + self.0 + } + } + + impl NewtypePriv { + pub fn new(a: Unit) -> Self { + NewtypePriv(a) + } + + pub fn get(&self) -> &Unit { + &self.0 + } + } + + impl TuplePriv { + pub fn new(a: u8, b: Unit) -> Self { + TuplePriv(a, b) + } + + pub fn first(&self) -> u8 { + self.0 + } + + pub fn second(&self) -> &Unit { + &self.1 + } + } + + impl StructPriv { + pub fn new(a: u8, b: Unit) -> Self { + StructPriv { a: a, b: b } + } + + pub fn a(&self) -> u8 { + self.a + } + + pub fn b(&self) -> &Unit { + &self.b + } + } +} + +#[derive(Serialize, Deserialize)] +struct Test { + #[serde(with = "UnitDef")] + unit: remote::Unit, + + #[serde(with = "PrimitivePrivDef")] + primitive_priv: remote::PrimitivePriv, + + #[serde(with = "PrimitivePubDef")] + primitive_pub: remote::PrimitivePub, + + #[serde(with = "NewtypePrivDef")] + newtype_priv: remote::NewtypePriv, + + #[serde(with = "NewtypePubDef")] + newtype_pub: remote::NewtypePub, + + #[serde(with = "TuplePrivDef")] + tuple_priv: remote::TuplePriv, + + #[serde(with = "TuplePubDef")] + tuple_pub: remote::TuplePub, + + #[serde(with = "StructPrivDef")] + struct_priv: remote::StructPriv, + + #[serde(with = "StructPubDef")] + struct_pub: remote::StructPub, +} + +#[derive(Serialize, Deserialize)] +#[serde(remote = "remote::Unit")] +struct UnitDef; + +#[derive(Serialize, Deserialize)] +#[serde(remote = "remote::PrimitivePriv")] +struct PrimitivePrivDef(#[serde(getter = "remote::PrimitivePriv::get")] u8); + +#[derive(Serialize, Deserialize)] +#[serde(remote = "remote::PrimitivePub")] +struct PrimitivePubDef(u8); + +#[derive(Serialize, Deserialize)] +#[serde(remote = "remote::NewtypePriv")] +struct NewtypePrivDef(#[serde(getter = "remote::NewtypePriv::get", with = "UnitDef")] remote::Unit); + +#[derive(Serialize, Deserialize)] +#[serde(remote = "remote::NewtypePub")] +struct NewtypePubDef(#[serde(with = "UnitDef")] remote::Unit); + +#[derive(Serialize, Deserialize)] +#[serde(remote = "remote::TuplePriv")] +struct TuplePrivDef( + #[serde(getter = "remote::TuplePriv::first")] u8, + #[serde(getter = "remote::TuplePriv::second", with = "UnitDef")] remote::Unit); + +#[derive(Serialize, Deserialize)] +#[serde(remote = "remote::TuplePub")] +struct TuplePubDef(u8, #[serde(with = "UnitDef")] remote::Unit); + +#[derive(Serialize, Deserialize)] +#[serde(remote = "remote::StructPriv")] +struct StructPrivDef { + #[serde(getter = "remote::StructPriv::a")] + a: u8, + + #[serde(getter = "remote::StructPriv::b")] + #[serde(with= "UnitDef")] + b: remote::Unit, +} + +#[derive(Serialize, Deserialize)] +#[serde(remote = "remote::StructPub")] +struct StructPubDef { + #[allow(dead_code)] + a: u8, + + #[allow(dead_code)] + #[serde(with= "UnitDef")] + b: remote::Unit, +} + +impl From for remote::PrimitivePriv { + fn from(def: PrimitivePrivDef) -> Self { + remote::PrimitivePriv::new(def.0) + } +} + +impl From for remote::NewtypePriv { + fn from(def: NewtypePrivDef) -> Self { + remote::NewtypePriv::new(def.0) + } +} + +impl From for remote::TuplePriv { + fn from(def: TuplePrivDef) -> Self { + remote::TuplePriv::new(def.0, def.1) + } +} + +impl From for remote::StructPriv { + fn from(def: StructPrivDef) -> Self { + remote::StructPriv::new(def.a, def.b) + } +} From 9d8987bde88b48b2f0668f80bdcdd140ddd4fd0f Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 9 Apr 2017 10:59:54 -0700 Subject: [PATCH 2/7] Require getters to return the correct type --- serde/src/private/ser.rs | 6 +++++ serde_derive/src/ser.rs | 5 +++- .../tests/compile-fail/remote/wrong_getter.rs | 23 +++++++++++++++++++ 3 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 test_suite/tests/compile-fail/remote/wrong_getter.rs diff --git a/serde/src/private/ser.rs b/serde/src/private/ser.rs index c8d09d0b..333cb742 100644 --- a/serde/src/private/ser.rs +++ b/serde/src/private/ser.rs @@ -8,6 +8,12 @@ use self::content::{SerializeTupleVariantAsMapValue, SerializeStructVariantAsMap #[cfg(feature = "std")] use std::error; +/// Used to check that serde(getter) attributes return the expected type. +/// Not public API. +pub fn constrain(t: &T) -> &T { + t +} + /// Not public API. pub fn serialize_tagged_newtype(serializer: S, type_ident: &'static str, diff --git a/serde_derive/src/ser.rs b/serde_derive/src/ser.rs index 179c5d99..39c479c2 100644 --- a/serde_derive/src/ser.rs +++ b/serde_derive/src/ser.rs @@ -839,6 +839,9 @@ fn get_field(params: &Parameters, field: &Field, ident: I) -> Tokens let ident = ident.into(); quote!(&#self_var.#ident) } - Some(getter) => quote!(&#getter(#self_var)), + Some(getter) => { + let ty = field.ty; + quote!(_serde::private::ser::constrain::<#ty>(&#getter(#self_var))) + } } } diff --git a/test_suite/tests/compile-fail/remote/wrong_getter.rs b/test_suite/tests/compile-fail/remote/wrong_getter.rs new file mode 100644 index 00000000..f767263d --- /dev/null +++ b/test_suite/tests/compile-fail/remote/wrong_getter.rs @@ -0,0 +1,23 @@ +#[macro_use] +extern crate serde_derive; + +mod remote { + pub struct S { + a: u8, + } + + impl S { + pub fn get(&self) -> u16 { + self.a as u16 + } + } +} + +#[derive(Serialize)] //~ ERROR: mismatched types +#[serde(remote = "remote::S")] +struct S { + #[serde(getter = "remote::S::get")] + a: u8, //~^^^^ expected u8, found u16 +} + +fn main() {} From 5ec317a899ceed3596c7085b18238172f34126c1 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 9 Apr 2017 11:11:27 -0700 Subject: [PATCH 3/7] More compile-fail tests for remote derive --- .../tests/compile-fail/remote/bad_getter.rs | 17 +++++++++++++++++ .../tests/compile-fail/remote/bad_remote.rs | 16 ++++++++++++++++ .../tests/compile-fail/remote/enum_getter.rs | 19 +++++++++++++++++++ .../compile-fail/remote/nonremote_getter.rs | 16 ++++++++++++++++ 4 files changed, 68 insertions(+) create mode 100644 test_suite/tests/compile-fail/remote/bad_getter.rs create mode 100644 test_suite/tests/compile-fail/remote/bad_remote.rs create mode 100644 test_suite/tests/compile-fail/remote/enum_getter.rs create mode 100644 test_suite/tests/compile-fail/remote/nonremote_getter.rs diff --git a/test_suite/tests/compile-fail/remote/bad_getter.rs b/test_suite/tests/compile-fail/remote/bad_getter.rs new file mode 100644 index 00000000..3495a10b --- /dev/null +++ b/test_suite/tests/compile-fail/remote/bad_getter.rs @@ -0,0 +1,17 @@ +#[macro_use] +extern crate serde_derive; + +mod remote { + pub struct S { + a: u8, + } +} + +#[derive(Serialize)] //~ ERROR: proc-macro derive panicked +#[serde(remote = "remote::S")] +struct S { + #[serde(getter = "~~~")] //~^^^ HELP: failed to parse path: "~~~" + a: u8, +} + +fn main() {} diff --git a/test_suite/tests/compile-fail/remote/bad_remote.rs b/test_suite/tests/compile-fail/remote/bad_remote.rs new file mode 100644 index 00000000..5ef17670 --- /dev/null +++ b/test_suite/tests/compile-fail/remote/bad_remote.rs @@ -0,0 +1,16 @@ +#[macro_use] +extern crate serde_derive; + +mod remote { + pub struct S { + a: u8, + } +} + +#[derive(Serialize)] //~ ERROR: proc-macro derive panicked +#[serde(remote = "~~~")] //~^ HELP: failed to parse path: "~~~" +struct S { + a: u8, +} + +fn main() {} diff --git a/test_suite/tests/compile-fail/remote/enum_getter.rs b/test_suite/tests/compile-fail/remote/enum_getter.rs new file mode 100644 index 00000000..e012cbe1 --- /dev/null +++ b/test_suite/tests/compile-fail/remote/enum_getter.rs @@ -0,0 +1,19 @@ +#[macro_use] +extern crate serde_derive; + +mod remote { + pub enum E { + A { a: u8 } + } +} + +#[derive(Serialize)] //~ ERROR: proc-macro derive panicked +#[serde(remote = "remote::E")] +pub enum E { + A { + #[serde(getter = "get_a")] //~^^^^ HELP: #[serde(getter = "...")] is not allowed in an enum + a: u8, + } +} + +fn main() {} diff --git a/test_suite/tests/compile-fail/remote/nonremote_getter.rs b/test_suite/tests/compile-fail/remote/nonremote_getter.rs new file mode 100644 index 00000000..11271e5a --- /dev/null +++ b/test_suite/tests/compile-fail/remote/nonremote_getter.rs @@ -0,0 +1,16 @@ +#[macro_use] +extern crate serde_derive; + +#[derive(Serialize)] //~ ERROR: proc-macro derive panicked +struct S { + #[serde(getter = "S::get")] //~^^ HELP: #[serde(getter = "...")] can only be used in structs that have #[serde(remote = "...")] + a: u8, +} + +impl S { + fn get(&self) -> u8 { + self.a + } +} + +fn main() {} From 2deacf8eaad547c0aa415b0a07998fddaf0cb702 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 10 Apr 2017 12:12:00 -0700 Subject: [PATCH 4/7] Detect incorrect remote type without getter --- serde_derive/src/ser.rs | 21 +++++++++++++++---- .../tests/compile-fail/remote/wrong_ser.rs | 16 ++++++++++++++ 2 files changed, 33 insertions(+), 4 deletions(-) create mode 100644 test_suite/tests/compile-fail/remote/wrong_ser.rs diff --git a/serde_derive/src/ser.rs b/serde_derive/src/ser.rs index 39c479c2..7b893e44 100644 --- a/serde_derive/src/ser.rs +++ b/serde_derive/src/ser.rs @@ -61,11 +61,15 @@ struct Parameters { /// Generics including any explicit and inferred bounds for the impl. generics: syn::Generics, + + /// Type has a `serde(remote = "...")` attribute. + is_remote: bool, } impl Parameters { fn new(item: &Item) -> Self { - let self_var = if item.attrs.remote().is_some() { + let is_remote = item.attrs.remote().is_some(); + let self_var = if is_remote { Ident::new("__self") } else { Ident::new("self") @@ -82,6 +86,7 @@ impl Parameters { self_var: self_var, this: this, generics: generics, + is_remote: is_remote, } } @@ -834,14 +839,22 @@ fn get_field(params: &Parameters, field: &Field, ident: I) -> Tokens where I: Into { let self_var = ¶ms.self_var; - match field.attrs.getter() { - None => { + match (params.is_remote, field.attrs.getter()) { + (false, None) => { let ident = ident.into(); quote!(&#self_var.#ident) } - Some(getter) => { + (true, None) => { + let ty = field.ty; + let ident = ident.into(); + quote!(_serde::private::ser::constrain::<#ty>(&#self_var.#ident)) + } + (true, Some(getter)) => { let ty = field.ty; quote!(_serde::private::ser::constrain::<#ty>(&#getter(#self_var))) } + (false, Some(_)) => { + unreachable!("getter is only allowed for remote impls"); + } } } diff --git a/test_suite/tests/compile-fail/remote/wrong_ser.rs b/test_suite/tests/compile-fail/remote/wrong_ser.rs new file mode 100644 index 00000000..bd4ca1a2 --- /dev/null +++ b/test_suite/tests/compile-fail/remote/wrong_ser.rs @@ -0,0 +1,16 @@ +#[macro_use] +extern crate serde_derive; + +mod remote { + pub struct S { + pub a: u16, + } +} + +#[derive(Serialize)] //~ ERROR: mismatched types +#[serde(remote = "remote::S")] +struct S { + a: u8, //~^^^ expected u8, found u16 +} + +fn main() {} From ad5bf04c4e983f7663ae58e3728e93610b3ce3f3 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 10 Apr 2017 12:15:40 -0700 Subject: [PATCH 5/7] Test for incorrect remote type deserializing --- test_suite/tests/compile-fail/remote/wrong_de.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 test_suite/tests/compile-fail/remote/wrong_de.rs diff --git a/test_suite/tests/compile-fail/remote/wrong_de.rs b/test_suite/tests/compile-fail/remote/wrong_de.rs new file mode 100644 index 00000000..58a05e19 --- /dev/null +++ b/test_suite/tests/compile-fail/remote/wrong_de.rs @@ -0,0 +1,12 @@ +#[macro_use] +extern crate serde_derive; + +mod remote { + pub struct S(pub u16); +} + +#[derive(Deserialize)] //~ ERROR: mismatched types +#[serde(remote = "remote::S")] +struct S(u8); //~^^ expected u16, found u8 + +fn main() {} From 174867295b8f7e9af18556bd7dd16b3d1fa9ba1e Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 10 Apr 2017 12:22:51 -0700 Subject: [PATCH 6/7] Test missing field in remote struct --- .../tests/compile-fail/remote/missing_field.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 test_suite/tests/compile-fail/remote/missing_field.rs diff --git a/test_suite/tests/compile-fail/remote/missing_field.rs b/test_suite/tests/compile-fail/remote/missing_field.rs new file mode 100644 index 00000000..3be802a6 --- /dev/null +++ b/test_suite/tests/compile-fail/remote/missing_field.rs @@ -0,0 +1,17 @@ +#[macro_use] +extern crate serde_derive; + +mod remote { + pub struct S { + pub a: u8, + pub b: u8, + } +} + +#[derive(Serialize, Deserialize)] //~ ERROR: missing field `b` in initializer of `remote::S` +#[serde(remote = "remote::S")] +struct S { + a: u8, //~^^^ ERROR: missing field `b` in initializer of `remote::S` +} + +fn main() {} From 6a6606cd64e04c47dc370218b59f6ada201e2b70 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 10 Apr 2017 12:23:02 -0700 Subject: [PATCH 7/7] Test unknown field in remote struct --- .../tests/compile-fail/remote/unknown_field.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 test_suite/tests/compile-fail/remote/unknown_field.rs diff --git a/test_suite/tests/compile-fail/remote/unknown_field.rs b/test_suite/tests/compile-fail/remote/unknown_field.rs new file mode 100644 index 00000000..8f2fa481 --- /dev/null +++ b/test_suite/tests/compile-fail/remote/unknown_field.rs @@ -0,0 +1,16 @@ +#[macro_use] +extern crate serde_derive; + +mod remote { + pub struct S { + pub a: u8, + } +} + +#[derive(Serialize, Deserialize)] +#[serde(remote = "remote::S")] +struct S { + b: u8, //~^^^ ERROR: no field `b` on type `&remote::S` +} + +fn main() {}