Add `#[serde(skip_serializing)] to skip serializing some fields

Closes #99
This commit is contained in:
Erick Tryzelaar
2015-07-23 08:07:49 -07:00
parent 447d08bd91
commit b1cb5379de
5 changed files with 58 additions and 12 deletions
+15 -2
View File
@@ -16,14 +16,20 @@ pub enum FieldNames {
/// Represents field attribute information /// Represents field attribute information
pub struct FieldAttrs { pub struct FieldAttrs {
skip_serializing_field: bool,
names: FieldNames, names: FieldNames,
use_default: bool, use_default: bool,
} }
impl FieldAttrs { impl FieldAttrs {
/// Create a FieldAttr with a single default field name /// Create a FieldAttr with a single default field name
pub fn new(default_value: bool, name: P<ast::Expr>) -> FieldAttrs { pub fn new(
skip_serializing_field: bool,
default_value: bool,
name: P<ast::Expr>,
) -> FieldAttrs {
FieldAttrs { FieldAttrs {
skip_serializing_field: skip_serializing_field,
names: FieldNames::Global(name), names: FieldNames::Global(name),
use_default: default_value, use_default: default_value,
} }
@@ -31,12 +37,14 @@ impl FieldAttrs {
/// Create a FieldAttr with format specific field names /// Create a FieldAttr with format specific field names
pub fn new_with_formats( pub fn new_with_formats(
skip_serializing_field: bool,
default_value: bool, default_value: bool,
default_name: P<ast::Expr>, default_name: P<ast::Expr>,
formats: HashMap<P<ast::Expr>, P<ast::Expr>>, formats: HashMap<P<ast::Expr>, P<ast::Expr>>,
) -> FieldAttrs { ) -> FieldAttrs {
FieldAttrs { FieldAttrs {
names: FieldNames::Format { skip_serializing_field: skip_serializing_field,
names: FieldNames::Format {
formats: formats, formats: formats,
default: default_name, default: default_name,
}, },
@@ -104,4 +112,9 @@ impl FieldAttrs {
pub fn use_default(&self) -> bool { pub fn use_default(&self) -> bool {
self.use_default self.use_default
} }
/// Predicate for ignoring a field when serializing a value
pub fn skip_serializing_field(&self) -> bool {
self.skip_serializing_field
}
} }
+1
View File
@@ -483,6 +483,7 @@ fn deserialize_item_enum(
enum_def.variants.iter() enum_def.variants.iter()
.map(|variant| .map(|variant|
attr::FieldAttrs::new( attr::FieldAttrs::new(
false,
true, true,
builder.expr().str(variant.node.name))) builder.expr().str(variant.node.name)))
.collect() .collect()
+24 -10
View File
@@ -58,10 +58,18 @@ fn default_value(mi: &ast::MetaItem) -> bool {
} }
} }
fn skip_serializing_field(mi: &ast::MetaItem) -> bool {
if let ast::MetaItem_::MetaWord(ref n) = mi.node {
n == &"skip_serializing"
} else {
false
}
}
fn field_attrs<'a>( fn field_attrs<'a>(
builder: &aster::AstBuilder, builder: &aster::AstBuilder,
field: &'a ast::StructField, field: &'a ast::StructField,
) -> (Rename<'a>, bool) { ) -> (Rename<'a>, bool, bool) {
field.node.attrs.iter() field.node.attrs.iter()
.find(|sa| { .find(|sa| {
if let ast::MetaList(ref n, _) = sa.node.value.node { if let ast::MetaList(ref n, _) = sa.node.value.node {
@@ -73,15 +81,18 @@ fn field_attrs<'a>(
.and_then(|sa| { .and_then(|sa| {
if let ast::MetaList(_, ref vals) = sa.node.value.node { if let ast::MetaList(_, ref vals) = sa.node.value.node {
attr::mark_used(&sa); attr::mark_used(&sa);
Some((vals.iter() Some((
.fold(None, |v, mi| v.or(rename(builder, mi))) vals.iter()
.unwrap_or(Rename::None), .fold(None, |v, mi| v.or(rename(builder, mi)))
vals.iter().any(|mi| default_value(mi)))) .unwrap_or(Rename::None),
vals.iter().any(|mi| default_value(mi)),
vals.iter().any(|mi| skip_serializing_field(mi)),
))
} else { } else {
Some((Rename::None, false)) Some((Rename::None, false, false))
} }
}) })
.unwrap_or((Rename::None, false)) .unwrap_or((Rename::None, false, false))
} }
pub fn struct_field_attrs( pub fn struct_field_attrs(
@@ -92,23 +103,26 @@ pub fn struct_field_attrs(
struct_def.fields.iter() struct_def.fields.iter()
.map(|field| { .map(|field| {
match field_attrs(builder, field) { match field_attrs(builder, field) {
(Rename::Global(rename), default_value) => (Rename::Global(rename), default_value, skip_serializing_field) =>
FieldAttrs::new( FieldAttrs::new(
skip_serializing_field,
default_value, default_value,
builder.expr().build_lit(P(rename.clone()))), builder.expr().build_lit(P(rename.clone()))),
(Rename::Format(renames), default_value) => { (Rename::Format(renames), default_value, skip_serializing_field) => {
let mut res = HashMap::new(); let mut res = HashMap::new();
res.extend( res.extend(
renames.into_iter() renames.into_iter()
.map(|(k,v)| .map(|(k,v)|
(k, builder.expr().build_lit(P(v.clone()))))); (k, builder.expr().build_lit(P(v.clone())))));
FieldAttrs::new_with_formats( FieldAttrs::new_with_formats(
skip_serializing_field,
default_value, default_value,
default_field_name(cx, builder, field.node.kind), default_field_name(cx, builder, field.node.kind),
res) res)
}, },
(Rename::None, default_value) => { (Rename::None, default_value, skip_serializing_field) => {
FieldAttrs::new( FieldAttrs::new(
skip_serializing_field,
default_value, default_value,
default_field_name(cx, builder, field.node.kind)) default_field_name(cx, builder, field.node.kind))
} }
+1
View File
@@ -550,6 +550,7 @@ fn serialize_struct_visitor<I>(
let arms: Vec<ast::Arm> = field_attrs.into_iter() let arms: Vec<ast::Arm> = field_attrs.into_iter()
.zip(value_exprs) .zip(value_exprs)
.filter(|&(ref field, _)| !field.skip_serializing_field())
.enumerate() .enumerate()
.map(|(i, (field, value_expr))| { .map(|(i, (field, value_expr))| {
let key_expr = field.serializer_key_expr(cx); let key_expr = field.serializer_key_expr(cx);
+17
View File
@@ -1,3 +1,4 @@
use std::default;
use serde_json; use serde_json;
#[derive(Debug, PartialEq, Serialize, Deserialize)] #[derive(Debug, PartialEq, Serialize, Deserialize)]
@@ -30,6 +31,12 @@ enum SerEnum<A> {
}, },
} }
#[derive(Debug, PartialEq, Deserialize, Serialize)]
struct SkipSerializingFields<A: default::Default> {
a: i8,
#[serde(skip_serializing, default)]
b: A,
}
#[test] #[test]
fn test_default() { fn test_default() {
@@ -71,3 +78,13 @@ fn test_enum_format_rename() {
let deserialized_value = serde_json::from_str(ans).unwrap(); let deserialized_value = serde_json::from_str(ans).unwrap();
assert_eq!(value, deserialized_value); assert_eq!(value, deserialized_value);
} }
#[test]
fn test_skip_serializing_fields() {
let value = SkipSerializingFields { a: 1, b: 2 };
let serialized_value = serde_json::to_string(&value).unwrap();
assert_eq!(serialized_value, "{\"a\":1}");
let deserialized_value: SkipSerializingFields<_> = serde_json::from_str(&serialized_value).unwrap();
assert_eq!(SkipSerializingFields { a: 1, b: 0 }, deserialized_value);
}