mirror of
https://github.com/pezkuwichain/serde.git
synced 2026-06-12 20:11:02 +00:00
feat(codegen): Remove {Ser,Deser}ializer::format
This feature has never been used, and it's complicating the implementation of #207. We could restore this functionality if there is ever interest in it. Closes #211.
This commit is contained in:
@@ -424,15 +424,6 @@ pub trait Deserializer {
|
|||||||
{
|
{
|
||||||
self.deserialize(visitor)
|
self.deserialize(visitor)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Specify a format string for the deserializer.
|
|
||||||
///
|
|
||||||
/// The deserializer format is used to determine which format
|
|
||||||
/// specific field attributes should be used with the
|
|
||||||
/// deserializer.
|
|
||||||
fn format() -> &'static str {
|
|
||||||
""
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|||||||
@@ -327,14 +327,6 @@ pub trait Serializer {
|
|||||||
{
|
{
|
||||||
self.serialize_struct_elt(key, value)
|
self.serialize_struct_elt(key, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Specify a format string for the serializer.
|
|
||||||
///
|
|
||||||
/// The serializer format is used to determine which format
|
|
||||||
/// specific field attributes should be used with the serializer.
|
|
||||||
fn format() -> &'static str {
|
|
||||||
""
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A trait that is used by a `Serialize` to iterate through a sequence.
|
/// A trait that is used by a `Serialize` to iterate through a sequence.
|
||||||
|
|||||||
+12
-97
@@ -1,6 +1,3 @@
|
|||||||
use std::collections::HashMap;
|
|
||||||
use std::collections::HashSet;
|
|
||||||
|
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
use syntax::attr;
|
use syntax::attr;
|
||||||
use syntax::ext::base::ExtCtxt;
|
use syntax::ext::base::ExtCtxt;
|
||||||
@@ -11,16 +8,6 @@ use aster::AstBuilder;
|
|||||||
|
|
||||||
use error::Error;
|
use error::Error;
|
||||||
|
|
||||||
/// Represents field name information
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum FieldNames {
|
|
||||||
Global(P<ast::Expr>),
|
|
||||||
Format {
|
|
||||||
formats: HashMap<P<ast::Expr>, P<ast::Expr>>,
|
|
||||||
default: P<ast::Expr>,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Represents container (e.g. struct) attribute information
|
/// Represents container (e.g. struct) attribute information
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ContainerAttrs {
|
pub struct ContainerAttrs {
|
||||||
@@ -65,18 +52,17 @@ impl ContainerAttrs {
|
|||||||
/// Represents field attribute information
|
/// Represents field attribute information
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct FieldAttrs {
|
pub struct FieldAttrs {
|
||||||
|
ident: ast::Ident,
|
||||||
|
name: Option<ast::Lit>,
|
||||||
skip_serializing_field: bool,
|
skip_serializing_field: bool,
|
||||||
skip_serializing_field_if_empty: bool,
|
skip_serializing_field_if_empty: bool,
|
||||||
skip_serializing_field_if_none: bool,
|
skip_serializing_field_if_none: bool,
|
||||||
names: FieldNames,
|
|
||||||
use_default: bool,
|
use_default: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FieldAttrs {
|
impl FieldAttrs {
|
||||||
/// Extract out the `#[serde(...)]` attributes from a struct field.
|
/// Extract out the `#[serde(...)]` attributes from a struct field.
|
||||||
pub fn from_field(cx: &ExtCtxt, field: &ast::StructField) -> Result<Self, Error> {
|
pub fn from_field(cx: &ExtCtxt, field: &ast::StructField) -> Result<Self, Error> {
|
||||||
let builder = AstBuilder::new();
|
|
||||||
|
|
||||||
let field_ident = match field.node.ident() {
|
let field_ident = match field.node.ident() {
|
||||||
Some(ident) => ident,
|
Some(ident) => ident,
|
||||||
None => { cx.span_bug(field.span, "struct field has no name?") }
|
None => { cx.span_bug(field.span, "struct field has no name?") }
|
||||||
@@ -85,8 +71,7 @@ impl FieldAttrs {
|
|||||||
let mut skip_serializing_field = false;
|
let mut skip_serializing_field = false;
|
||||||
let mut skip_serializing_field_if_empty = false;
|
let mut skip_serializing_field_if_empty = false;
|
||||||
let mut skip_serializing_field_if_none = false;
|
let mut skip_serializing_field_if_none = false;
|
||||||
let mut field_name = builder.expr().str(field_ident);
|
let mut field_name = None;
|
||||||
let mut format_rename = HashMap::new();
|
|
||||||
let mut use_default = false;
|
let mut use_default = false;
|
||||||
|
|
||||||
for meta_items in field.node.attrs.iter().filter_map(get_serde_meta_items) {
|
for meta_items in field.node.attrs.iter().filter_map(get_serde_meta_items) {
|
||||||
@@ -94,21 +79,7 @@ impl FieldAttrs {
|
|||||||
match meta_item.node {
|
match meta_item.node {
|
||||||
// Parse `#[serde(rename="foo")]`
|
// Parse `#[serde(rename="foo")]`
|
||||||
ast::MetaNameValue(ref name, ref lit) if name == &"rename" => {
|
ast::MetaNameValue(ref name, ref lit) if name == &"rename" => {
|
||||||
field_name = builder.expr().build_lit(P(lit.clone()));
|
field_name = Some(lit.clone());
|
||||||
}
|
|
||||||
|
|
||||||
// Parse `#[serde(rename(xml="foo", token="bar"))]`
|
|
||||||
ast::MetaList(ref name, ref meta_items) if name == &"rename" => {
|
|
||||||
for meta_item in meta_items {
|
|
||||||
match meta_item.node {
|
|
||||||
ast::MetaNameValue(ref name, ref lit) => {
|
|
||||||
let name = builder.expr().str(name);
|
|
||||||
let expr = builder.expr().build_lit(P(lit.clone()));
|
|
||||||
format_rename.insert(name, expr);
|
|
||||||
}
|
|
||||||
_ => { }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse `#[serde(default)]`
|
// Parse `#[serde(default)]`
|
||||||
@@ -143,88 +114,32 @@ impl FieldAttrs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let names = if format_rename.is_empty() {
|
|
||||||
FieldNames::Global(field_name)
|
|
||||||
} else {
|
|
||||||
FieldNames::Format {
|
|
||||||
formats: format_rename,
|
|
||||||
default: field_name,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(FieldAttrs {
|
Ok(FieldAttrs {
|
||||||
|
ident: field_ident,
|
||||||
|
name: field_name,
|
||||||
skip_serializing_field: skip_serializing_field,
|
skip_serializing_field: skip_serializing_field,
|
||||||
skip_serializing_field_if_empty: skip_serializing_field_if_empty,
|
skip_serializing_field_if_empty: skip_serializing_field_if_empty,
|
||||||
skip_serializing_field_if_none: skip_serializing_field_if_none,
|
skip_serializing_field_if_none: skip_serializing_field_if_none,
|
||||||
names: names,
|
|
||||||
use_default: use_default,
|
use_default: use_default,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_variant(variant: &ast::Variant) -> Self {
|
pub fn from_variant(variant: &ast::Variant) -> Self {
|
||||||
let name = AstBuilder::new().expr().str(variant.node.name);
|
|
||||||
|
|
||||||
FieldAttrs {
|
FieldAttrs {
|
||||||
|
ident: variant.node.name,
|
||||||
|
name: None,
|
||||||
skip_serializing_field: false,
|
skip_serializing_field: false,
|
||||||
skip_serializing_field_if_empty: false,
|
skip_serializing_field_if_empty: false,
|
||||||
skip_serializing_field_if_none: false,
|
skip_serializing_field_if_none: false,
|
||||||
names: FieldNames::Global(name),
|
|
||||||
use_default: false,
|
use_default: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return a set of formats that the field has attributes for.
|
|
||||||
pub fn formats(&self) -> HashSet<P<ast::Expr>> {
|
|
||||||
match self.names {
|
|
||||||
FieldNames::Format { ref formats, .. } => {
|
|
||||||
let mut set = HashSet::new();
|
|
||||||
for (fmt, _) in formats.iter() {
|
|
||||||
set.insert(fmt.clone());
|
|
||||||
};
|
|
||||||
set
|
|
||||||
},
|
|
||||||
_ => HashSet::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return an expression for the field key name for serialisation.
|
|
||||||
///
|
|
||||||
/// The resulting expression assumes that `S` refers to a type
|
|
||||||
/// that implements `Serializer`.
|
|
||||||
pub fn serializer_key_expr(&self, cx: &ExtCtxt) -> P<ast::Expr> {
|
|
||||||
match self.names {
|
|
||||||
FieldNames::Global(ref name) => name.clone(),
|
|
||||||
FieldNames::Format { ref formats, ref default } => {
|
|
||||||
let arms = formats.iter()
|
|
||||||
.map(|(fmt, lit)| {
|
|
||||||
quote_arm!(cx, $fmt => { $lit })
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
quote_expr!(cx,
|
|
||||||
match S::format() {
|
|
||||||
$arms
|
|
||||||
_ => { $default }
|
|
||||||
}
|
|
||||||
)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return the default field name for the field.
|
/// Return the default field name for the field.
|
||||||
pub fn default_key_expr(&self) -> &P<ast::Expr> {
|
pub fn name_expr(&self) -> P<ast::Expr> {
|
||||||
match self.names {
|
match self.name {
|
||||||
FieldNames::Global(ref expr) => expr,
|
Some(ref name) => AstBuilder::new().expr().build_lit(P(name.clone())),
|
||||||
FieldNames::Format { ref default, .. } => default,
|
None => AstBuilder::new().expr().str(self.ident),
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return the field name for the field in the specified format.
|
|
||||||
pub fn key_expr(&self, format: &P<ast::Expr>) -> &P<ast::Expr> {
|
|
||||||
match self.names {
|
|
||||||
FieldNames::Global(ref expr) => expr,
|
|
||||||
FieldNames::Format { ref formats, ref default } => {
|
|
||||||
formats.get(format).unwrap_or(default)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+10
-73
@@ -1,5 +1,3 @@
|
|||||||
use std::collections::HashSet;
|
|
||||||
|
|
||||||
use aster;
|
use aster;
|
||||||
|
|
||||||
use syntax::ast::{
|
use syntax::ast::{
|
||||||
@@ -832,18 +830,11 @@ fn deserialize_field_visitor(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
// A set of all the formats that have specialized field attributes
|
|
||||||
let formats = field_attrs.iter()
|
|
||||||
.fold(HashSet::new(), |mut set, field_expr| {
|
|
||||||
set.extend(field_expr.formats());
|
|
||||||
set
|
|
||||||
});
|
|
||||||
|
|
||||||
// Match arms to extract a field from a string
|
// Match arms to extract a field from a string
|
||||||
let default_field_arms: Vec<_> = field_idents.iter()
|
let default_field_arms: Vec<_> = field_idents.iter()
|
||||||
.zip(field_attrs.iter())
|
.zip(field_attrs.iter())
|
||||||
.map(|(field_ident, field_expr)| {
|
.map(|(field_ident, field_attrs)| {
|
||||||
let expr = field_expr.default_key_expr();
|
let expr = &field_attrs.name_expr();
|
||||||
quote_arm!(cx, $expr => { Ok(__Field::$field_ident) })
|
quote_arm!(cx, $expr => { Ok(__Field::$field_ident) })
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
@@ -854,49 +845,12 @@ fn deserialize_field_visitor(
|
|||||||
quote_expr!(cx, Err(::serde::de::Error::unknown_field(value)))
|
quote_expr!(cx, Err(::serde::de::Error::unknown_field(value)))
|
||||||
};
|
};
|
||||||
|
|
||||||
let str_body = if formats.is_empty() {
|
let str_body = quote_expr!(cx,
|
||||||
// No formats specific attributes, so no match on format required
|
match value {
|
||||||
quote_expr!(cx,
|
$default_field_arms
|
||||||
match value {
|
_ => $fallthrough_arm_expr
|
||||||
$default_field_arms
|
}
|
||||||
_ => { $fallthrough_arm_expr }
|
);
|
||||||
})
|
|
||||||
} else {
|
|
||||||
let field_arms: Vec<_> = formats.iter()
|
|
||||||
.map(|fmt| {
|
|
||||||
field_idents.iter()
|
|
||||||
.zip(field_attrs.iter())
|
|
||||||
.map(|(field_ident, field_expr)| {
|
|
||||||
let expr = field_expr.key_expr(fmt);
|
|
||||||
quote_arm!(cx, $expr => { Ok(__Field::$field_ident) })
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let fmt_matches: Vec<_> = formats.iter()
|
|
||||||
.zip(field_arms.iter())
|
|
||||||
.map(|(ref fmt, ref arms)| {
|
|
||||||
quote_arm!(cx, $fmt => {
|
|
||||||
match value {
|
|
||||||
$arms
|
|
||||||
_ => {
|
|
||||||
$fallthrough_arm_expr
|
|
||||||
}
|
|
||||||
}})
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
quote_expr!(cx,
|
|
||||||
match __D::format() {
|
|
||||||
$fmt_matches
|
|
||||||
_ => match value {
|
|
||||||
$default_field_arms
|
|
||||||
_ => $fallthrough_arm_expr
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
let impl_item = quote_item!(cx,
|
let impl_item = quote_item!(cx,
|
||||||
impl ::serde::de::Deserialize for __Field {
|
impl ::serde::de::Deserialize for __Field {
|
||||||
@@ -1042,25 +996,8 @@ fn deserialize_map(
|
|||||||
let missing_expr = if field_attr.use_default() {
|
let missing_expr = if field_attr.use_default() {
|
||||||
quote_expr!(cx, ::std::default::Default::default())
|
quote_expr!(cx, ::std::default::Default::default())
|
||||||
} else {
|
} else {
|
||||||
let formats = field_attr.formats();
|
let name = &field_attr.name_expr();
|
||||||
let arms : Vec<_> = formats.iter()
|
quote_expr!(cx, try!(visitor.missing_field($name)))
|
||||||
.map(|format| {
|
|
||||||
let key_expr = field_attr.key_expr(format);
|
|
||||||
quote_arm!(cx, $format => { $key_expr })
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
let default = field_attr.default_key_expr();
|
|
||||||
if arms.is_empty() {
|
|
||||||
quote_expr!(cx, try!(visitor.missing_field($default)))
|
|
||||||
} else {
|
|
||||||
quote_expr!(
|
|
||||||
cx,
|
|
||||||
try!(visitor.missing_field(
|
|
||||||
match __D::format() {
|
|
||||||
$arms
|
|
||||||
_ => { $default }
|
|
||||||
})))
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
quote_stmt!(cx,
|
quote_stmt!(cx,
|
||||||
|
|||||||
@@ -612,7 +612,7 @@ fn serialize_struct_visitor<I>(
|
|||||||
.filter(|&(ref field, _)| !field.skip_serializing_field())
|
.filter(|&(ref field, _)| !field.skip_serializing_field())
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(i, (ref field, value_expr))| {
|
.map(|(i, (ref field, value_expr))| {
|
||||||
let key_expr = field.serializer_key_expr(cx);
|
let key_expr = field.name_expr();
|
||||||
|
|
||||||
let stmt = if field.skip_serializing_field_if_empty() {
|
let stmt = if field.skip_serializing_field_if_empty() {
|
||||||
quote_stmt!(cx, if ($value_expr).is_empty() { continue; })
|
quote_stmt!(cx, if ($value_expr).is_empty() { continue; })
|
||||||
|
|||||||
@@ -29,22 +29,6 @@ struct Rename {
|
|||||||
a2: i32,
|
a2: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
|
||||||
struct FormatRename {
|
|
||||||
a1: i32,
|
|
||||||
#[serde(rename(xml= "a4", token="a5"))]
|
|
||||||
a2: i32,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Deserialize, Serialize)]
|
|
||||||
enum SerEnum<A> {
|
|
||||||
Map {
|
|
||||||
a: i8,
|
|
||||||
#[serde(rename(xml= "c", token="d"))]
|
|
||||||
b: A,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Deserialize, Serialize)]
|
#[derive(Debug, PartialEq, Deserialize, Serialize)]
|
||||||
struct SkipSerializingFields<A: default::Default> {
|
struct SkipSerializingFields<A: default::Default> {
|
||||||
a: i8,
|
a: i8,
|
||||||
@@ -172,49 +156,6 @@ fn test_rename() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_format_rename() {
|
|
||||||
assert_tokens(
|
|
||||||
&FormatRename { a1: 1, a2: 2 },
|
|
||||||
vec![
|
|
||||||
Token::StructStart("FormatRename", Some(2)),
|
|
||||||
|
|
||||||
Token::MapSep,
|
|
||||||
Token::Str("a1"),
|
|
||||||
Token::I32(1),
|
|
||||||
|
|
||||||
Token::MapSep,
|
|
||||||
Token::Str("a5"),
|
|
||||||
Token::I32(2),
|
|
||||||
|
|
||||||
Token::MapEnd,
|
|
||||||
]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_enum_format_rename() {
|
|
||||||
assert_tokens(
|
|
||||||
&SerEnum::Map {
|
|
||||||
a: 0,
|
|
||||||
b: String::new(),
|
|
||||||
},
|
|
||||||
vec![
|
|
||||||
Token::EnumMapStart("SerEnum", "Map", Some(2)),
|
|
||||||
|
|
||||||
Token::MapSep,
|
|
||||||
Token::Str("a"),
|
|
||||||
Token::I8(0),
|
|
||||||
|
|
||||||
Token::MapSep,
|
|
||||||
Token::Str("d"),
|
|
||||||
Token::Str(""),
|
|
||||||
|
|
||||||
Token::MapEnd,
|
|
||||||
]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_skip_serializing_fields() {
|
fn test_skip_serializing_fields() {
|
||||||
assert_ser_tokens(
|
assert_ser_tokens(
|
||||||
|
|||||||
@@ -301,10 +301,6 @@ impl<'a, I> ser::Serializer for Serializer<I>
|
|||||||
try!(key.serialize(self));
|
try!(key.serialize(self));
|
||||||
value.serialize(self)
|
value.serialize(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn format() -> &'static str {
|
|
||||||
"token"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -583,10 +579,6 @@ impl<I> de::Deserializer for Deserializer<I>
|
|||||||
None => Err(Error::EndOfStreamError),
|
None => Err(Error::EndOfStreamError),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn format() -> &'static str {
|
|
||||||
"token"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|||||||
Reference in New Issue
Block a user