Adds serializer format specific field names
Allows different field names to be used for different external formats. Field names are specified using the `rename` field attribute, e.g: #[serde(rename(xml= "a4", json="a5"))] Reverts #62 Addresses #61
This commit is contained in:
parent
af752ddcb5
commit
a935ebe8b9
@ -1,3 +1,5 @@
|
|||||||
|
use std::collections::HashSet;
|
||||||
|
|
||||||
use syntax::ast::{
|
use syntax::ast::{
|
||||||
Ident,
|
Ident,
|
||||||
MetaItem,
|
MetaItem,
|
||||||
@ -353,7 +355,8 @@ fn deserialize_item_enum(
|
|||||||
cx,
|
cx,
|
||||||
builder,
|
builder,
|
||||||
enum_def.variants.iter()
|
enum_def.variants.iter()
|
||||||
.map(|variant| builder.expr().str(variant.node.name))
|
.map(|variant|
|
||||||
|
field::FieldLit::Global(builder.expr().str(variant.node.name)))
|
||||||
.collect()
|
.collect()
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -531,7 +534,7 @@ fn deserialize_struct_variant(
|
|||||||
fn deserialize_field_visitor(
|
fn deserialize_field_visitor(
|
||||||
cx: &ExtCtxt,
|
cx: &ExtCtxt,
|
||||||
builder: &aster::AstBuilder,
|
builder: &aster::AstBuilder,
|
||||||
field_exprs: Vec<P<ast::Expr>>,
|
field_exprs: Vec<field::FieldLit>,
|
||||||
) -> Vec<P<ast::Item>> {
|
) -> Vec<P<ast::Item>> {
|
||||||
// Create the field names for the fields.
|
// Create the field names for the fields.
|
||||||
let field_idents: Vec<ast::Ident> = (0 .. field_exprs.len())
|
let field_idents: Vec<ast::Ident> = (0 .. field_exprs.len())
|
||||||
@ -548,14 +551,80 @@ fn deserialize_field_visitor(
|
|||||||
)
|
)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
|
||||||
|
let fmts = field_exprs.iter()
|
||||||
|
.fold(HashSet::new(), |mut set, field_expr|
|
||||||
|
match field_expr {
|
||||||
|
&field::FieldLit::Format{ref formats, default: _} => {
|
||||||
|
for (fmt, _) in formats.iter() {
|
||||||
|
set.insert(fmt.clone());
|
||||||
|
};
|
||||||
|
set
|
||||||
|
},
|
||||||
|
_ => set
|
||||||
|
});
|
||||||
|
|
||||||
// Match arms to extract a field from a string
|
// Match arms to extract a field from a string
|
||||||
let field_arms: Vec<_> = field_idents.iter()
|
let default_field_arms: Vec<_> = field_idents.iter()
|
||||||
.zip(field_exprs.into_iter())
|
.zip(field_exprs.iter())
|
||||||
.map(|(field_ident, field_expr)| {
|
.map(|(field_ident, field_expr)| {
|
||||||
quote_arm!(cx, $field_expr => { Ok(__Field::$field_ident) })
|
match field_expr {
|
||||||
|
&field::FieldLit::Global(ref expr) =>
|
||||||
|
quote_arm!(cx, $expr => { Ok(__Field::$field_ident) }),
|
||||||
|
&field::FieldLit::Format{formats: _, ref default} =>
|
||||||
|
quote_arm!(cx, $default => { Ok(__Field::$field_ident)})
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
let body = if fmts.is_empty() {
|
||||||
|
quote_expr!(cx,
|
||||||
|
match value {
|
||||||
|
$default_field_arms,
|
||||||
|
_ => Err(::serde::de::Error::unknown_field_error(value)),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
let field_arms : Vec<_> = fmts.iter()
|
||||||
|
.map(|fmt| {
|
||||||
|
field_idents.iter()
|
||||||
|
.zip(field_exprs.iter())
|
||||||
|
.map(|(field_ident, field_expr)| {
|
||||||
|
match field_expr {
|
||||||
|
&field::FieldLit::Global(ref expr) =>
|
||||||
|
quote_arm!(cx,
|
||||||
|
$expr => { Ok(__Field::$field_ident) }),
|
||||||
|
&field::FieldLit::Format{ref formats, ref default} => {
|
||||||
|
let expr = formats.get(fmt).unwrap_or(default);
|
||||||
|
quote_arm!(cx,
|
||||||
|
$expr => { Ok(__Field::$field_ident) })}}
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let fmt_matches : Vec<_> = fmts.iter()
|
||||||
|
.zip(field_arms.iter())
|
||||||
|
.map(|(ref fmt, ref arms)| {
|
||||||
|
quote_arm!(cx, $fmt => {
|
||||||
|
match value {
|
||||||
|
$arms,
|
||||||
|
_ => {
|
||||||
|
Err(::serde::de::Error::unknown_field_error(value))
|
||||||
|
}
|
||||||
|
}})
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
quote_expr!(cx,
|
||||||
|
match D::fmt() {
|
||||||
|
$fmt_matches,
|
||||||
|
_ => match value {
|
||||||
|
$default_field_arms,
|
||||||
|
_ => Err(::serde::de::Error::unknown_field_error(value)),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
vec![
|
vec![
|
||||||
field_enum,
|
field_enum,
|
||||||
|
|
||||||
@ -565,22 +634,26 @@ fn deserialize_field_visitor(
|
|||||||
fn deserialize<D>(deserializer: &mut D) -> ::std::result::Result<__Field, D::Error>
|
fn deserialize<D>(deserializer: &mut D) -> ::std::result::Result<__Field, D::Error>
|
||||||
where D: ::serde::de::Deserializer,
|
where D: ::serde::de::Deserializer,
|
||||||
{
|
{
|
||||||
struct __FieldVisitor;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
impl ::serde::de::Visitor for __FieldVisitor {
|
struct __FieldVisitor<D> {
|
||||||
|
phantom: PhantomData<D>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D> ::serde::de::Visitor for __FieldVisitor<D>
|
||||||
|
where D: ::serde::de::Deserializer
|
||||||
|
{
|
||||||
type Value = __Field;
|
type Value = __Field;
|
||||||
|
|
||||||
fn visit_str<E>(&mut self, value: &str) -> ::std::result::Result<__Field, E>
|
fn visit_str<E>(&mut self, value: &str) -> ::std::result::Result<__Field, E>
|
||||||
where E: ::serde::de::Error,
|
where E: ::serde::de::Error,
|
||||||
{
|
{
|
||||||
match value {
|
$body
|
||||||
$field_arms
|
|
||||||
_ => Err(::serde::de::Error::unknown_field_error(value)),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
deserializer.visit(__FieldVisitor)
|
deserializer.visit(
|
||||||
|
__FieldVisitor::<D>{ phantom: PhantomData })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
).unwrap(),
|
).unwrap(),
|
||||||
@ -596,7 +669,7 @@ fn deserialize_struct_visitor(
|
|||||||
let field_visitor = deserialize_field_visitor(
|
let field_visitor = deserialize_field_visitor(
|
||||||
cx,
|
cx,
|
||||||
builder,
|
builder,
|
||||||
field::struct_field_strs(cx, builder, struct_def, field::Direction::Deserialize),
|
field::struct_field_strs(cx, builder, struct_def),
|
||||||
);
|
);
|
||||||
|
|
||||||
let visit_map_expr = deserialize_map(
|
let visit_map_expr = deserialize_map(
|
||||||
@ -639,11 +712,16 @@ fn deserialize_map(
|
|||||||
let extract_values: Vec<P<ast::Stmt>> = field_names.iter()
|
let extract_values: Vec<P<ast::Stmt>> = field_names.iter()
|
||||||
.zip(struct_def.fields.iter())
|
.zip(struct_def.fields.iter())
|
||||||
.map(|(field_name, field)| {
|
.map(|(field_name, field)| {
|
||||||
let rename = field::field_rename(field, &field::Direction::Deserialize);
|
let rename = field::field_rename(builder, field);
|
||||||
let name_str = match (rename, field.node.kind) {
|
let name_str = match (rename, field.node.kind) {
|
||||||
(Some(rename), _) => builder.expr().build_lit(P(rename.clone())),
|
(field::Rename::Global(rename), _)
|
||||||
(None, ast::NamedField(name, _)) => builder.expr().str(name),
|
=> builder.expr().build_lit(P(rename.clone())),
|
||||||
(None, ast::UnnamedField(_)) => panic!("struct contains unnamed fields"),
|
(field::Rename::None, ast::NamedField(name, _))
|
||||||
|
=> builder.expr().str(name),
|
||||||
|
(field::Rename::None, ast::UnnamedField(_))
|
||||||
|
=> panic!("struct contains unnamed fields"),
|
||||||
|
(field::Rename::Format(renames), _)
|
||||||
|
=> builder.expr().str("fixme"),
|
||||||
};
|
};
|
||||||
|
|
||||||
let missing_expr = if field::default_value(field) {
|
let missing_expr = if field::default_value(field) {
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
use syntax::attr;
|
use syntax::attr;
|
||||||
use syntax::ext::base::ExtCtxt;
|
use syntax::ext::base::ExtCtxt;
|
||||||
@ -5,19 +7,17 @@ use syntax::ptr::P;
|
|||||||
|
|
||||||
use aster;
|
use aster;
|
||||||
|
|
||||||
pub enum Direction {
|
pub enum Rename<'a> {
|
||||||
Serialize,
|
None,
|
||||||
Deserialize,
|
Global(&'a ast::Lit),
|
||||||
|
// Format(HashMap<InternedString, &'a ast::Lit>)
|
||||||
|
Format(HashMap<P<ast::Expr>, &'a ast::Lit>)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn field_rename<'a>(
|
pub fn field_rename<'a>(
|
||||||
|
builder: &aster::AstBuilder,
|
||||||
field: &'a ast::StructField,
|
field: &'a ast::StructField,
|
||||||
direction: &Direction,
|
) -> Rename<'a> {
|
||||||
) -> Option<&'a ast::Lit> {
|
|
||||||
let dir_attr = match *direction {
|
|
||||||
Direction::Serialize => "rename_serialize",
|
|
||||||
Direction::Deserialize => "rename_deserialize",
|
|
||||||
};
|
|
||||||
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 {
|
||||||
@ -30,34 +30,89 @@ pub fn field_rename<'a>(
|
|||||||
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);
|
||||||
vals.iter().fold(None, |v, mi| {
|
vals.iter().fold(None, |v, mi| {
|
||||||
if let ast::MetaNameValue(ref n, ref lit) = mi.node {
|
match mi.node {
|
||||||
if n == &"rename" || n == &dir_attr {
|
ast::MetaNameValue(ref n, ref lit) => {
|
||||||
Some(lit)
|
if n == &"rename" {
|
||||||
|
Some(Rename::Global(lit))
|
||||||
} else {
|
} else {
|
||||||
v
|
v
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
ast::MetaList(ref n, ref items) => {
|
||||||
|
if n == &"rename" {
|
||||||
|
let mut m = HashMap::new();
|
||||||
|
m.extend(
|
||||||
|
items.iter()
|
||||||
|
.filter_map(
|
||||||
|
|item|
|
||||||
|
match item.node {
|
||||||
|
ast::MetaNameValue(ref n, ref lit) =>
|
||||||
|
Some((// (n.to_owned(), lit)
|
||||||
|
builder.expr().str(n),
|
||||||
|
lit
|
||||||
|
)),
|
||||||
|
_ => None
|
||||||
|
}));
|
||||||
|
Some(Rename::Format(m))
|
||||||
} else {
|
} else {
|
||||||
v
|
v
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
_ => {v}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
.unwrap_or(Rename::None)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum FieldLit {
|
||||||
|
Global(P<ast::Expr>),
|
||||||
|
Format{
|
||||||
|
formats: HashMap<P<ast::Expr>, P<ast::Expr>>,
|
||||||
|
default: P<ast::Expr>,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn struct_field_strs(
|
pub fn struct_field_strs(
|
||||||
cx: &ExtCtxt,
|
cx: &ExtCtxt,
|
||||||
builder: &aster::AstBuilder,
|
builder: &aster::AstBuilder,
|
||||||
struct_def: &ast::StructDef,
|
struct_def: &ast::StructDef,
|
||||||
direction: Direction,
|
) -> Vec<FieldLit> {
|
||||||
) -> Vec<P<ast::Expr>> {
|
|
||||||
struct_def.fields.iter()
|
struct_def.fields.iter()
|
||||||
.map(|field| {
|
.map(|field| {
|
||||||
match field_rename(field, &direction) {
|
match field_rename(builder, field) {
|
||||||
Some(rename) => builder.expr().build_lit(P(rename.clone())),
|
Rename::Global(rename) =>
|
||||||
None => {
|
FieldLit::Global(
|
||||||
match field.node.kind {
|
builder.expr().build_lit(P(rename.clone()))),
|
||||||
|
Rename::Format(renames) => {
|
||||||
|
let mut res = HashMap::new();
|
||||||
|
res.extend(
|
||||||
|
renames.into_iter()
|
||||||
|
.map(|(k,v)|
|
||||||
|
(k, builder.expr().build_lit(P(v.clone())))));
|
||||||
|
FieldLit::Format{
|
||||||
|
formats: res,
|
||||||
|
default: default_field(cx, builder, field.node.kind),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Rename::None => {
|
||||||
|
FieldLit::Global(
|
||||||
|
default_field(cx, builder, field.node.kind))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_field(
|
||||||
|
cx: &ExtCtxt,
|
||||||
|
builder: &aster::AstBuilder,
|
||||||
|
kind: ast::StructFieldKind,
|
||||||
|
) -> P<ast::Expr> {
|
||||||
|
match kind {
|
||||||
ast::NamedField(name, _) => {
|
ast::NamedField(name, _) => {
|
||||||
builder.expr().str(name)
|
builder.expr().str(name)
|
||||||
}
|
}
|
||||||
@ -66,10 +121,7 @@ pub fn struct_field_strs(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn default_value(field: &ast::StructField) -> bool {
|
pub fn default_value(field: &ast::StructField) -> bool {
|
||||||
field.node.attrs.iter()
|
field.node.attrs.iter()
|
||||||
|
@ -13,7 +13,7 @@ use syntax::ptr::P;
|
|||||||
|
|
||||||
use aster;
|
use aster;
|
||||||
|
|
||||||
use field::{Direction, struct_field_strs};
|
use field::{FieldLit, struct_field_strs};
|
||||||
|
|
||||||
pub fn expand_derive_serialize(
|
pub fn expand_derive_serialize(
|
||||||
cx: &mut ExtCtxt,
|
cx: &mut ExtCtxt,
|
||||||
@ -517,12 +517,29 @@ fn serialize_struct_visitor<I>(
|
|||||||
{
|
{
|
||||||
let len = struct_def.fields.len();
|
let len = struct_def.fields.len();
|
||||||
|
|
||||||
let key_exprs = struct_field_strs(cx, builder, struct_def, Direction::Serialize);
|
let key_exprs = struct_field_strs(cx, builder, struct_def);
|
||||||
|
|
||||||
let arms: Vec<ast::Arm> = key_exprs.iter()
|
let arms: Vec<ast::Arm> = key_exprs.into_iter()
|
||||||
.zip(value_exprs)
|
.zip(value_exprs)
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(i, (key_expr, value_expr))| {
|
.map(|(i, (field, value_expr))| {
|
||||||
|
let key_expr = match field {
|
||||||
|
FieldLit::Global(x) => x,
|
||||||
|
FieldLit::Format{formats, default} => {
|
||||||
|
let arms = formats.iter()
|
||||||
|
.map(|(fmt, lit)| {
|
||||||
|
quote_arm!(cx, $fmt => { $lit })
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
quote_expr!(cx,
|
||||||
|
{
|
||||||
|
match S::fmt() {
|
||||||
|
$arms,
|
||||||
|
_ => $default
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
};
|
||||||
quote_arm!(cx,
|
quote_arm!(cx,
|
||||||
$i => {
|
$i => {
|
||||||
self.state += 1;
|
self.state += 1;
|
||||||
|
@ -113,6 +113,10 @@ pub trait Deserializer {
|
|||||||
{
|
{
|
||||||
self.visit(visitor)
|
self.visit(visitor)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn fmt() -> &'static str {
|
||||||
|
""
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -463,6 +463,11 @@ impl<Iter> de::Deserializer for Deserializer<Iter>
|
|||||||
Err(self.error(ErrorCode::ExpectedSomeValue))
|
Err(self.error(ErrorCode::ExpectedSomeValue))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn fmt() -> &'static str {
|
||||||
|
"json"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SeqVisitor<'a, Iter: 'a + Iterator<Item=io::Result<u8>>> {
|
struct SeqVisitor<'a, Iter: 'a + Iterator<Item=io::Result<u8>>> {
|
||||||
|
@ -256,6 +256,11 @@ impl<W, F> ser::Serializer for Serializer<W, F>
|
|||||||
try!(self.formatter.colon(&mut self.writer));
|
try!(self.formatter.colon(&mut self.writer));
|
||||||
value.serialize(self)
|
value.serialize(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn fmt() -> &'static str {
|
||||||
|
"json"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Formatter {
|
pub trait Formatter {
|
||||||
|
@ -571,6 +571,11 @@ impl ser::Serializer for Serializer {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn fmt() -> &'static str {
|
||||||
|
"value"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Deserializer {
|
pub struct Deserializer {
|
||||||
@ -677,6 +682,11 @@ impl de::Deserializer for Deserializer {
|
|||||||
None => Ok(value)
|
None => Ok(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn fmt() -> &'static str {
|
||||||
|
"value"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SeqDeserializer<'a> {
|
struct SeqDeserializer<'a> {
|
||||||
|
@ -179,6 +179,10 @@ pub trait Serializer {
|
|||||||
fn visit_map_elt<K, V>(&mut self, key: K, value: V) -> Result<(), Self::Error>
|
fn visit_map_elt<K, V>(&mut self, key: K, value: V) -> Result<(), Self::Error>
|
||||||
where K: Serialize,
|
where K: Serialize,
|
||||||
V: Serialize;
|
V: Serialize;
|
||||||
|
|
||||||
|
fn fmt() -> &'static str {
|
||||||
|
""
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait SeqVisitor {
|
pub trait SeqVisitor {
|
||||||
|
@ -21,9 +21,9 @@ struct Rename {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
struct DirectionRename {
|
struct FormatRename {
|
||||||
a1: i32,
|
a1: i32,
|
||||||
#[serde(rename_serialize="a3", rename_deserialize="a4")]
|
#[serde(rename(xml= "a4", json="a5"))]
|
||||||
a2: i32,
|
a2: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,11 +47,11 @@ fn test_rename() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_direction_rename() {
|
fn test_format_rename() {
|
||||||
let value = DirectionRename { a1: 1, a2: 2 };
|
let value = FormatRename { a1: 1, a2: 2 };
|
||||||
let serialized_value = json::to_string(&value).unwrap();
|
let serialized_value = json::to_string(&value).unwrap();
|
||||||
assert_eq!(serialized_value, "{\"a1\":1,\"a3\":2}");
|
assert_eq!(serialized_value, "{\"a1\":1,\"a5\":2}");
|
||||||
|
|
||||||
let deserialized_value = json::from_str("{\"a1\":1,\"a4\":2}").unwrap();
|
let deserialized_value = json::from_str("{\"a1\":1,\"a5\":2}").unwrap();
|
||||||
assert_eq!(value, deserialized_value);
|
assert_eq!(value, deserialized_value);
|
||||||
}
|
}
|
||||||
|
@ -1024,7 +1024,7 @@ fn test_missing_field() {
|
|||||||
fn test_missing_renamed_field() {
|
fn test_missing_renamed_field() {
|
||||||
#[derive(Debug, PartialEq, Deserialize)]
|
#[derive(Debug, PartialEq, Deserialize)]
|
||||||
struct Foo {
|
struct Foo {
|
||||||
#[serde(rename_deserialize="y")]
|
#[serde(rename="y")]
|
||||||
x: Option<u32>,
|
x: Option<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1042,3 +1042,26 @@ fn test_missing_renamed_field() {
|
|||||||
))).unwrap();
|
))).unwrap();
|
||||||
assert_eq!(value, Foo { x: Some(5) });
|
assert_eq!(value, Foo { x: Some(5) });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_missing_fmt_renamed_field() {
|
||||||
|
#[derive(Debug, PartialEq, Deserialize)]
|
||||||
|
struct Foo {
|
||||||
|
#[serde(rename(json="y", value="z"))]
|
||||||
|
x: Option<u32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
let value: Foo = from_str("{}").unwrap();
|
||||||
|
assert_eq!(value, Foo { x: None });
|
||||||
|
|
||||||
|
let value: Foo = from_str("{\"y\": 5}").unwrap();
|
||||||
|
assert_eq!(value, Foo { x: Some(5) });
|
||||||
|
|
||||||
|
let value: Foo = from_value(Value::Object(treemap!())).unwrap();
|
||||||
|
assert_eq!(value, Foo { x: None });
|
||||||
|
|
||||||
|
let value : Foo = from_value(Value::Object(treemap!(
|
||||||
|
"z".to_string() => Value::I64(5)
|
||||||
|
))).unwrap();
|
||||||
|
assert_eq!(value, Foo { x: Some(5) });
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user