mirror of
https://github.com/pezkuwichain/serde.git
synced 2026-04-27 13:27:56 +00:00
Implement serialize_with for variants
As discussed in #1013, serialize_with functions attached to variants receive an argument for each inner value contained within the variant. Internally such a function is wired up to the serializer as if the variant were a newtype variant.
This commit is contained in:
@@ -510,6 +510,8 @@ pub struct Variant {
|
||||
skip_deserializing: bool,
|
||||
skip_serializing: bool,
|
||||
other: bool,
|
||||
serialize_with: Option<syn::Path>,
|
||||
deserialize_with: Option<syn::Path>,
|
||||
}
|
||||
|
||||
impl Variant {
|
||||
@@ -520,6 +522,8 @@ impl Variant {
|
||||
let mut skip_serializing = BoolAttr::none(cx, "skip_serializing");
|
||||
let mut rename_all = Attr::none(cx, "rename_all");
|
||||
let mut other = BoolAttr::none(cx, "other");
|
||||
let mut serialize_with = Attr::none(cx, "serialize_with");
|
||||
let mut deserialize_with = Attr::none(cx, "deserialize_with");
|
||||
|
||||
for meta_items in variant.attrs.iter().filter_map(get_serde_meta_items) {
|
||||
for meta_item in meta_items {
|
||||
@@ -569,6 +573,20 @@ impl Variant {
|
||||
other.set_true();
|
||||
}
|
||||
|
||||
// Parse `#[serde(serialize_with = "...")]`
|
||||
MetaItem(NameValue(ref name, ref lit)) if name == "serialize_with" => {
|
||||
if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) {
|
||||
serialize_with.set(path);
|
||||
}
|
||||
}
|
||||
|
||||
// Parse `#[serde(deserialize_with = "...")]`
|
||||
MetaItem(NameValue(ref name, ref lit)) if name == "deserialize_with" => {
|
||||
if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) {
|
||||
deserialize_with.set(path);
|
||||
}
|
||||
}
|
||||
|
||||
MetaItem(ref meta_item) => {
|
||||
cx.error(format!("unknown serde variant attribute `{}`", meta_item.name()));
|
||||
}
|
||||
@@ -595,6 +613,8 @@ impl Variant {
|
||||
skip_deserializing: skip_deserializing.get(),
|
||||
skip_serializing: skip_serializing.get(),
|
||||
other: other.get(),
|
||||
serialize_with: serialize_with.get(),
|
||||
deserialize_with: deserialize_with.get(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -626,6 +646,14 @@ impl Variant {
|
||||
pub fn other(&self) -> bool {
|
||||
self.other
|
||||
}
|
||||
|
||||
pub fn serialize_with(&self) -> Option<&syn::Path> {
|
||||
self.serialize_with.as_ref()
|
||||
}
|
||||
|
||||
pub fn deserialize_with(&self) -> Option<&syn::Path> {
|
||||
self.deserialize_with.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents field attribute information
|
||||
|
||||
@@ -15,6 +15,7 @@ use Ctxt;
|
||||
pub fn check(cx: &Ctxt, cont: &Container) {
|
||||
check_getter(cx, cont);
|
||||
check_identifier(cx, cont);
|
||||
check_variant_skip_attrs(cx, cont);
|
||||
}
|
||||
|
||||
/// Getters are only allowed inside structs (not enums) with the `remote`
|
||||
@@ -94,3 +95,40 @@ fn check_identifier(cx: &Ctxt, cont: &Container) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Skip-(de)serializing attributes are not allowed on variants marked
|
||||
/// (de)serialize_with.
|
||||
fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) {
|
||||
let variants = match cont.body {
|
||||
Body::Enum(ref variants) => variants,
|
||||
Body::Struct(_, _) => {
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
for variant in variants.iter() {
|
||||
if variant.attrs.serialize_with().is_some() {
|
||||
if variant.attrs.skip_serializing() {
|
||||
cx.error(format!("variant `{}` cannot have both #[serde(serialize_with)] and \
|
||||
#[serde(skip_serializing)]", variant.ident));
|
||||
}
|
||||
|
||||
for (i, field) in variant.fields.iter().enumerate() {
|
||||
let ident = field.ident.as_ref().map_or_else(|| format!("{}", i),
|
||||
|ident| format!("`{}`", ident));
|
||||
|
||||
if field.attrs.skip_serializing() {
|
||||
cx.error(format!("variant `{}` cannot have both #[serde(serialize_with)] and \
|
||||
a field {} marked with #[serde(skip_serializing)]",
|
||||
variant.ident, ident));
|
||||
}
|
||||
|
||||
if field.attrs.skip_serializing_if().is_some() {
|
||||
cx.error(format!("variant `{}` cannot have both #[serde(serialize_with)] and \
|
||||
a field {} marked with #[serde(skip_serializing_if)]",
|
||||
variant.ident, ident));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user