Allowed serde(tag="...") on structs

Added test test_internally_tagged_struct
Renamed EnumTag to TagType as it now also used for structs 
Modified serialize_struct_as_struct
This commit is contained in:
Johannes Willbold
2018-12-27 17:57:29 +01:00
parent 5c24f0f0f3
commit 414fd694c0
5 changed files with 80 additions and 37 deletions
+14 -21
View File
@@ -120,7 +120,7 @@ pub struct Container {
rename_all: RenameRule,
ser_bound: Option<Vec<syn::WherePredicate>>,
de_bound: Option<Vec<syn::WherePredicate>>,
tag: EnumTag,
tag: TagType,
type_from: Option<syn::Type>,
type_into: Option<syn::Type>,
remote: Option<syn::Path>,
@@ -129,7 +129,7 @@ pub struct Container {
}
/// Styles of representing an enum.
pub enum EnumTag {
pub enum TagType {
/// The default.
///
/// ```json
@@ -358,17 +358,10 @@ impl Container {
Meta(NameValue(ref m)) if m.ident == "tag" => {
if let Ok(s) = get_lit_str(cx, &m.ident, &m.ident, &m.lit) {
match item.data {
syn::Data::Enum(_) => {
syn::Data::Enum(_) |
syn::Data::Struct(_, ..) => {
internal_tag.set(&m.ident, s.value());
}
syn::Data::Struct(syn::DataStruct {
ref struct_token, ..
}) => {
cx.error_spanned_by(
struct_token,
"#[serde(tag = \"...\")] can only be used on enums",
);
}
syn::Data::Union(syn::DataUnion {
ref union_token, ..
}) => {
@@ -505,7 +498,7 @@ impl Container {
self.de_bound.as_ref().map(|vec| &vec[..])
}
pub fn tag(&self) -> &EnumTag {
pub fn tag(&self) -> &TagType {
&self.tag
}
@@ -540,14 +533,14 @@ fn decide_tag(
untagged: BoolAttr,
internal_tag: Attr<String>,
content: Attr<String>,
) -> EnumTag {
) -> TagType {
match (
untagged.0.get_with_tokens(),
internal_tag.get_with_tokens(),
content.get_with_tokens(),
) {
(None, None, None) => EnumTag::External,
(Some(_), None, None) => EnumTag::None,
(None, None, None) => TagType::External,
(Some(_), None, None) => TagType::None,
(None, Some((_, tag)), None) => {
// Check that there are no tuple variants.
if let syn::Data::Enum(ref data) = item.data {
@@ -567,7 +560,7 @@ fn decide_tag(
}
}
}
EnumTag::Internal { tag: tag }
TagType::Internal { tag: tag }
}
(Some((untagged_tokens, _)), Some((tag_tokens, _)), None) => {
cx.error_spanned_by(
@@ -578,14 +571,14 @@ fn decide_tag(
tag_tokens,
"enum cannot be both untagged and internally tagged",
);
EnumTag::External // doesn't matter, will error
TagType::External // doesn't matter, will error
}
(None, None, Some((content_tokens, _))) => {
cx.error_spanned_by(
content_tokens,
"#[serde(tag = \"...\", content = \"...\")] must be used together",
);
EnumTag::External
TagType::External
}
(Some((untagged_tokens, _)), None, Some((content_tokens, _))) => {
cx.error_spanned_by(
@@ -596,9 +589,9 @@ fn decide_tag(
content_tokens,
"untagged enum cannot have #[serde(content = \"...\")]",
);
EnumTag::External
TagType::External
}
(None, Some((_, tag)), Some((_, content))) => EnumTag::Adjacent {
(None, Some((_, tag)), Some((_, content))) => TagType::Adjacent {
tag: tag,
content: content,
},
@@ -615,7 +608,7 @@ fn decide_tag(
content_tokens,
"untagged enum cannot have #[serde(tag = \"...\", content = \"...\")]",
);
EnumTag::External
TagType::External
}
}
}
+6 -6
View File
@@ -1,5 +1,5 @@
use internals::ast::{Container, Data, Field, Style};
use internals::attr::{EnumTag, Identifier};
use internals::attr::{TagType, Identifier};
use internals::{Ctxt, Derive};
use syn::{Member, Type};
@@ -127,7 +127,7 @@ fn check_identifier(cx: &Ctxt, cont: &Container) {
}
// Variant with `other` attribute cannot appear in untagged enum
(_, Identifier::No, true, &EnumTag::None) => {
(_, Identifier::No, true, &TagType::None) => {
cx.error_spanned_by(
variant.original,
"#[serde(other)] cannot appear on untagged enum",
@@ -276,8 +276,8 @@ fn check_internal_tag_field_name_conflict(cx: &Ctxt, cont: &Container) {
};
let tag = match *cont.attrs.tag() {
EnumTag::Internal { ref tag } => tag.as_str(),
EnumTag::External | EnumTag::Adjacent { .. } | EnumTag::None => return,
TagType::Internal { ref tag } => tag.as_str(),
TagType::External | TagType::Adjacent { .. } | TagType::None => return,
};
let diagnose_conflict = || {
@@ -312,11 +312,11 @@ fn check_internal_tag_field_name_conflict(cx: &Ctxt, cont: &Container) {
/// contents tag must differ, for the same reason.
fn check_adjacent_tag_conflict(cx: &Ctxt, cont: &Container) {
let (type_tag, content_tag) = match *cont.attrs.tag() {
EnumTag::Adjacent {
TagType::Adjacent {
ref tag,
ref content,
} => (tag, content),
EnumTag::Internal { .. } | EnumTag::External | EnumTag::None => return,
TagType::Internal { .. } | TagType::External | TagType::None => return,
};
if type_tag == content_tag {