diff --git a/serde_macros/src/de.rs b/serde_macros/src/de.rs index 99f0dd52..a47ad0ab 100644 --- a/serde_macros/src/de.rs +++ b/serde_macros/src/de.rs @@ -596,7 +596,7 @@ fn deserialize_struct_visitor( let field_visitor = deserialize_field_visitor( cx, builder, - field::struct_field_strs(cx, builder, struct_def), + field::struct_field_strs(cx, builder, struct_def, field::Direction::Deserialize), ); let visit_map_expr = deserialize_map( diff --git a/serde_macros/src/field.rs b/serde_macros/src/field.rs index 7ca6f1fe..baa79009 100644 --- a/serde_macros/src/field.rs +++ b/serde_macros/src/field.rs @@ -5,7 +5,19 @@ use syntax::ptr::P; use aster; -fn field_rename(field: &ast::StructField) -> Option<&ast::Lit> { +pub enum Direction { + Serialize, + Deserialize, +} + +fn field_rename<'a>( + field: &'a ast::StructField, + direction: &Direction, +) -> Option<&'a ast::Lit> { + let dir_attr = match *direction { + Direction::Serialize => "rename_serialize", + Direction::Deserialize => "rename_deserialize", + }; field.node.attrs.iter() .find(|sa| { if let ast::MetaList(ref n, _) = sa.node.value.node { @@ -19,7 +31,7 @@ fn field_rename(field: &ast::StructField) -> Option<&ast::Lit> { attr::mark_used(&sa); vals.iter().fold(None, |v, mi| { if let ast::MetaNameValue(ref n, ref lit) = mi.node { - if n == &"rename" { + if n == &"rename" || n == &dir_attr { Some(lit) } else { v @@ -38,10 +50,11 @@ pub fn struct_field_strs( cx: &ExtCtxt, builder: &aster::AstBuilder, struct_def: &ast::StructDef, + direction: Direction, ) -> Vec> { struct_def.fields.iter() .map(|field| { - match field_rename(field) { + match field_rename(field, &direction) { Some(rename) => builder.expr().build_lit(P(rename.clone())), None => { match field.node.kind { diff --git a/serde_macros/src/ser.rs b/serde_macros/src/ser.rs index e6150890..d9c58d02 100644 --- a/serde_macros/src/ser.rs +++ b/serde_macros/src/ser.rs @@ -13,7 +13,7 @@ use syntax::ptr::P; use aster; -use field::struct_field_strs; +use field::{Direction, struct_field_strs}; pub fn expand_derive_serialize( cx: &mut ExtCtxt, @@ -517,7 +517,7 @@ fn serialize_struct_visitor( { let len = struct_def.fields.len(); - let key_exprs = struct_field_strs(cx, builder, struct_def); + let key_exprs = struct_field_strs(cx, builder, struct_def, Direction::Serialize); let arms: Vec = key_exprs.iter() .zip(value_exprs) diff --git a/tests/test_annotations.rs b/tests/test_annotations.rs index af603df3..2bc9a336 100644 --- a/tests/test_annotations.rs +++ b/tests/test_annotations.rs @@ -20,6 +20,13 @@ struct Rename { a2: i32, } +#[derive(Debug, PartialEq, Serialize, Deserialize)] +struct DirectionRename { + a1: i32, + #[serde(rename_serialize="a3", rename_deserialize="a4")] + a2: i32, +} + #[test] fn test_default() { let deserialized_value: Default = json::from_str(&"{\"a1\":1,\"a2\":2}").unwrap(); @@ -38,3 +45,13 @@ fn test_rename() { let deserialized_value: Rename = json::from_str(&serialized_value).unwrap(); assert_eq!(value, deserialized_value); } + +#[test] +fn test_direction_rename() { + let value = DirectionRename { a1: 1, a2: 2 }; + let serialized_value = json::to_string(&value).unwrap(); + assert_eq!(serialized_value, "{\"a1\":1,\"a3\":2}"); + + let deserialized_value = json::from_str("{\"a1\":1,\"a4\":2}").unwrap(); + assert_eq!(value, deserialized_value); +}