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:
Erick Tryzelaar 2016-02-07 22:03:01 -08:00
parent 5d4f9ce72b
commit d0ee5b0b4b
7 changed files with 23 additions and 255 deletions

View File

@ -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 {
""
}
}
///////////////////////////////////////////////////////////////////////////////

View File

@ -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.

View File

@ -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),
}
}

View File

@ -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,

View File

@ -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; })

View File

@ -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(

View File

@ -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"
}
}
//////////////////////////////////////////////////////////////////////////