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:
parent
5d4f9ce72b
commit
d0ee5b0b4b
@ -424,15 +424,6 @@ pub trait Deserializer {
|
||||
{
|
||||
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)
|
||||
}
|
||||
|
||||
/// 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.
|
||||
|
@ -1,6 +1,3 @@
|
||||
use std::collections::HashMap;
|
||||
use std::collections::HashSet;
|
||||
|
||||
use syntax::ast;
|
||||
use syntax::attr;
|
||||
use syntax::ext::base::ExtCtxt;
|
||||
@ -11,16 +8,6 @@ use aster::AstBuilder;
|
||||
|
||||
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
|
||||
#[derive(Debug)]
|
||||
pub struct ContainerAttrs {
|
||||
@ -65,18 +52,17 @@ impl ContainerAttrs {
|
||||
/// Represents field attribute information
|
||||
#[derive(Debug)]
|
||||
pub struct FieldAttrs {
|
||||
ident: ast::Ident,
|
||||
name: Option<ast::Lit>,
|
||||
skip_serializing_field: bool,
|
||||
skip_serializing_field_if_empty: bool,
|
||||
skip_serializing_field_if_none: bool,
|
||||
names: FieldNames,
|
||||
use_default: bool,
|
||||
}
|
||||
|
||||
impl FieldAttrs {
|
||||
/// Extract out the `#[serde(...)]` attributes from a struct field.
|
||||
pub fn from_field(cx: &ExtCtxt, field: &ast::StructField) -> Result<Self, Error> {
|
||||
let builder = AstBuilder::new();
|
||||
|
||||
let field_ident = match field.node.ident() {
|
||||
Some(ident) => ident,
|
||||
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_if_empty = false;
|
||||
let mut skip_serializing_field_if_none = false;
|
||||
let mut field_name = builder.expr().str(field_ident);
|
||||
let mut format_rename = HashMap::new();
|
||||
let mut field_name = None;
|
||||
let mut use_default = false;
|
||||
|
||||
for meta_items in field.node.attrs.iter().filter_map(get_serde_meta_items) {
|
||||
@ -94,21 +79,7 @@ impl FieldAttrs {
|
||||
match meta_item.node {
|
||||
// Parse `#[serde(rename="foo")]`
|
||||
ast::MetaNameValue(ref name, ref lit) if name == &"rename" => {
|
||||
field_name = builder.expr().build_lit(P(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);
|
||||
}
|
||||
_ => { }
|
||||
}
|
||||
}
|
||||
field_name = Some(lit.clone());
|
||||
}
|
||||
|
||||
// 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 {
|
||||
ident: field_ident,
|
||||
name: field_name,
|
||||
skip_serializing_field: skip_serializing_field,
|
||||
skip_serializing_field_if_empty: skip_serializing_field_if_empty,
|
||||
skip_serializing_field_if_none: skip_serializing_field_if_none,
|
||||
names: names,
|
||||
use_default: use_default,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn from_variant(variant: &ast::Variant) -> Self {
|
||||
let name = AstBuilder::new().expr().str(variant.node.name);
|
||||
|
||||
FieldAttrs {
|
||||
ident: variant.node.name,
|
||||
name: None,
|
||||
skip_serializing_field: false,
|
||||
skip_serializing_field_if_empty: false,
|
||||
skip_serializing_field_if_none: false,
|
||||
names: FieldNames::Global(name),
|
||||
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.
|
||||
pub fn default_key_expr(&self) -> &P<ast::Expr> {
|
||||
match self.names {
|
||||
FieldNames::Global(ref expr) => expr,
|
||||
FieldNames::Format { ref default, .. } => default,
|
||||
}
|
||||
}
|
||||
|
||||
/// 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)
|
||||
}
|
||||
pub fn name_expr(&self) -> P<ast::Expr> {
|
||||
match self.name {
|
||||
Some(ref name) => AstBuilder::new().expr().build_lit(P(name.clone())),
|
||||
None => AstBuilder::new().expr().str(self.ident),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,3 @@
|
||||
use std::collections::HashSet;
|
||||
|
||||
use aster;
|
||||
|
||||
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
|
||||
let default_field_arms: Vec<_> = field_idents.iter()
|
||||
.zip(field_attrs.iter())
|
||||
.map(|(field_ident, field_expr)| {
|
||||
let expr = field_expr.default_key_expr();
|
||||
.map(|(field_ident, field_attrs)| {
|
||||
let expr = &field_attrs.name_expr();
|
||||
quote_arm!(cx, $expr => { Ok(__Field::$field_ident) })
|
||||
})
|
||||
.collect();
|
||||
@ -854,49 +845,12 @@ fn deserialize_field_visitor(
|
||||
quote_expr!(cx, Err(::serde::de::Error::unknown_field(value)))
|
||||
};
|
||||
|
||||
let str_body = if formats.is_empty() {
|
||||
// No formats specific attributes, so no match on format required
|
||||
quote_expr!(cx,
|
||||
match value {
|
||||
$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 str_body = quote_expr!(cx,
|
||||
match value {
|
||||
$default_field_arms
|
||||
_ => $fallthrough_arm_expr
|
||||
}
|
||||
);
|
||||
|
||||
let impl_item = quote_item!(cx,
|
||||
impl ::serde::de::Deserialize for __Field {
|
||||
@ -1042,25 +996,8 @@ fn deserialize_map(
|
||||
let missing_expr = if field_attr.use_default() {
|
||||
quote_expr!(cx, ::std::default::Default::default())
|
||||
} else {
|
||||
let formats = field_attr.formats();
|
||||
let arms : Vec<_> = formats.iter()
|
||||
.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 }
|
||||
})))
|
||||
}
|
||||
let name = &field_attr.name_expr();
|
||||
quote_expr!(cx, try!(visitor.missing_field($name)))
|
||||
};
|
||||
|
||||
quote_stmt!(cx,
|
||||
|
@ -612,7 +612,7 @@ fn serialize_struct_visitor<I>(
|
||||
.filter(|&(ref field, _)| !field.skip_serializing_field())
|
||||
.enumerate()
|
||||
.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() {
|
||||
quote_stmt!(cx, if ($value_expr).is_empty() { continue; })
|
||||
|
@ -29,22 +29,6 @@ struct Rename {
|
||||
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)]
|
||||
struct SkipSerializingFields<A: default::Default> {
|
||||
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]
|
||||
fn test_skip_serializing_fields() {
|
||||
assert_ser_tokens(
|
||||
|
@ -301,10 +301,6 @@ impl<'a, I> ser::Serializer for Serializer<I>
|
||||
try!(key.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),
|
||||
}
|
||||
}
|
||||
|
||||
fn format() -> &'static str {
|
||||
"token"
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
Loading…
Reference in New Issue
Block a user