Allow borrow attribute on newtype variants

This commit is contained in:
David Tolnay
2017-11-05 11:21:39 -08:00
parent ab68132b1f
commit 40db31691a
5 changed files with 81 additions and 11 deletions
+10 -9
View File
@@ -51,7 +51,7 @@ impl<'a> Container<'a> {
let mut body = match item.body { let mut body = match item.body {
syn::Body::Enum(ref variants) => Body::Enum(enum_from_ast(cx, variants)), syn::Body::Enum(ref variants) => Body::Enum(enum_from_ast(cx, variants)),
syn::Body::Struct(ref variant_data) => { syn::Body::Struct(ref variant_data) => {
let (style, fields) = struct_from_ast(cx, variant_data); let (style, fields) = struct_from_ast(cx, variant_data, None);
Body::Struct(style, fields) Body::Struct(style, fields)
} }
}; };
@@ -103,10 +103,11 @@ fn enum_from_ast<'a>(cx: &Ctxt, variants: &'a [syn::Variant]) -> Vec<Variant<'a>
.iter() .iter()
.map( .map(
|variant| { |variant| {
let (style, fields) = struct_from_ast(cx, &variant.data); let attrs = attr::Variant::from_ast(cx, variant);
let (style, fields) = struct_from_ast(cx, &variant.data, Some(&attrs));
Variant { Variant {
ident: variant.ident.clone(), ident: variant.ident.clone(),
attrs: attr::Variant::from_ast(cx, variant), attrs: attrs,
style: style, style: style,
fields: fields, fields: fields,
} }
@@ -115,18 +116,18 @@ fn enum_from_ast<'a>(cx: &Ctxt, variants: &'a [syn::Variant]) -> Vec<Variant<'a>
.collect() .collect()
} }
fn struct_from_ast<'a>(cx: &Ctxt, data: &'a syn::VariantData) -> (Style, Vec<Field<'a>>) { fn struct_from_ast<'a>(cx: &Ctxt, data: &'a syn::VariantData, attrs: Option<&attr::Variant>) -> (Style, Vec<Field<'a>>) {
match *data { match *data {
syn::VariantData::Struct(ref fields) => (Style::Struct, fields_from_ast(cx, fields)), syn::VariantData::Struct(ref fields) => (Style::Struct, fields_from_ast(cx, fields, attrs)),
syn::VariantData::Tuple(ref fields) if fields.len() == 1 => { syn::VariantData::Tuple(ref fields) if fields.len() == 1 => {
(Style::Newtype, fields_from_ast(cx, fields)) (Style::Newtype, fields_from_ast(cx, fields, attrs))
} }
syn::VariantData::Tuple(ref fields) => (Style::Tuple, fields_from_ast(cx, fields)), syn::VariantData::Tuple(ref fields) => (Style::Tuple, fields_from_ast(cx, fields, attrs)),
syn::VariantData::Unit => (Style::Unit, Vec::new()), syn::VariantData::Unit => (Style::Unit, Vec::new()),
} }
} }
fn fields_from_ast<'a>(cx: &Ctxt, fields: &'a [syn::Field]) -> Vec<Field<'a>> { fn fields_from_ast<'a>(cx: &Ctxt, fields: &'a [syn::Field], attrs: Option<&attr::Variant>) -> Vec<Field<'a>> {
fields fields
.iter() .iter()
.enumerate() .enumerate()
@@ -134,7 +135,7 @@ fn fields_from_ast<'a>(cx: &Ctxt, fields: &'a [syn::Field]) -> Vec<Field<'a>> {
|(i, field)| { |(i, field)| {
Field { Field {
ident: field.ident.clone(), ident: field.ident.clone(),
attrs: attr::Field::from_ast(cx, i, field), attrs: attr::Field::from_ast(cx, i, field, attrs),
ty: &field.ty, ty: &field.ty,
} }
}, },
+23 -2
View File
@@ -512,6 +512,7 @@ pub struct Variant {
other: bool, other: bool,
serialize_with: Option<syn::Path>, serialize_with: Option<syn::Path>,
deserialize_with: Option<syn::Path>, deserialize_with: Option<syn::Path>,
borrow: Option<syn::MetaItem>,
} }
impl Variant { impl Variant {
@@ -524,6 +525,7 @@ impl Variant {
let mut other = BoolAttr::none(cx, "other"); let mut other = BoolAttr::none(cx, "other");
let mut serialize_with = Attr::none(cx, "serialize_with"); let mut serialize_with = Attr::none(cx, "serialize_with");
let mut deserialize_with = Attr::none(cx, "deserialize_with"); let mut deserialize_with = Attr::none(cx, "deserialize_with");
let mut borrow = Attr::none(cx, "borrow");
for meta_items in variant.attrs.iter().filter_map(get_serde_meta_items) { for meta_items in variant.attrs.iter().filter_map(get_serde_meta_items) {
for meta_item in meta_items { for meta_item in meta_items {
@@ -599,6 +601,18 @@ impl Variant {
} }
} }
// Defer `#[serde(borrow)]` and `#[serde(borrow = "'a + 'b")]`
MetaItem(ref mi) if mi.name() == "borrow" => {
match variant.data {
syn::VariantData::Tuple(ref fields) if fields.len() == 1 => {
borrow.set(mi.clone());
}
_ => {
cx.error("#[serde(borrow)] may only be used on newtype variants");
}
}
}
MetaItem(ref meta_item) => { MetaItem(ref meta_item) => {
cx.error(format!("unknown serde variant attribute `{}`", meta_item.name())); cx.error(format!("unknown serde variant attribute `{}`", meta_item.name()));
} }
@@ -627,6 +641,7 @@ impl Variant {
other: other.get(), other: other.get(),
serialize_with: serialize_with.get(), serialize_with: serialize_with.get(),
deserialize_with: deserialize_with.get(), deserialize_with: deserialize_with.get(),
borrow: borrow.get(),
} }
} }
@@ -699,7 +714,7 @@ pub enum Default {
impl Field { impl Field {
/// Extract out the `#[serde(...)]` attributes from a struct field. /// Extract out the `#[serde(...)]` attributes from a struct field.
pub fn from_ast(cx: &Ctxt, index: usize, field: &syn::Field) -> Self { pub fn from_ast(cx: &Ctxt, index: usize, field: &syn::Field, attrs: Option<&Variant>) -> Self {
let mut ser_name = Attr::none(cx, "rename"); let mut ser_name = Attr::none(cx, "rename");
let mut de_name = Attr::none(cx, "rename"); let mut de_name = Attr::none(cx, "rename");
let mut skip_serializing = BoolAttr::none(cx, "skip_serializing"); let mut skip_serializing = BoolAttr::none(cx, "skip_serializing");
@@ -718,7 +733,13 @@ impl Field {
None => index.to_string(), None => index.to_string(),
}; };
for meta_items in field.attrs.iter().filter_map(get_serde_meta_items) { let variant_borrow = attrs
.map(|variant| &variant.borrow)
.unwrap_or(&None)
.as_ref()
.map(|borrow| vec![MetaItem(borrow.clone())]);
for meta_items in field.attrs.iter().filter_map(get_serde_meta_items).chain(variant_borrow) {
for meta_item in meta_items { for meta_item in meta_items {
match meta_item { match meta_item {
// Parse `#[serde(rename = "foo")]` // Parse `#[serde(rename = "foo")]`
@@ -0,0 +1,21 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[macro_use]
extern crate serde_derive;
#[derive(Deserialize)]
struct Str<'a>(&'a str);
#[derive(Deserialize)] //~ ERROR: proc-macro derive panicked
enum Test<'a> {
#[serde(borrow)] //~^^ HELP: duplicate serde attribute `borrow`
S(#[serde(borrow)] Str<'a>)
}
fn main() {}
@@ -0,0 +1,21 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[macro_use]
extern crate serde_derive;
#[derive(Deserialize)]
struct Str<'a>(&'a str);
#[derive(Deserialize)] //~ ERROR: proc-macro derive panicked
enum Test<'a> {
#[serde(borrow)] //~^^ HELP: #[serde(borrow)] may only be used on newtype variants
S { s: Str<'a> }
}
fn main() {}
+6
View File
@@ -357,6 +357,12 @@ fn test_gen() {
s: Str<'a>, s: Str<'a>,
} }
#[derive(Serialize, Deserialize)]
enum BorrowVariant<'a> {
#[serde(borrow, with = "StrDef")]
S(Str<'a>),
}
mod vis { mod vis {
pub struct S; pub struct S;