refactor(codegen): Add VariantAttrs
This commit is contained in:
parent
d0ee5b0b4b
commit
365e5129af
@ -49,6 +49,57 @@ impl ContainerAttrs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Represents variant attribute information
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct VariantAttrs {
|
||||||
|
ident: ast::Ident,
|
||||||
|
name: Option<ast::Lit>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VariantAttrs {
|
||||||
|
pub fn from_variant(cx: &ExtCtxt, variant: &ast::Variant) -> Result<Self, Error> {
|
||||||
|
let mut variant_attrs = VariantAttrs {
|
||||||
|
ident: variant.node.name,
|
||||||
|
name: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
for meta_items in variant.node.attrs.iter().filter_map(get_serde_meta_items) {
|
||||||
|
for meta_item in meta_items {
|
||||||
|
match meta_item.node {
|
||||||
|
// Parse `#[serde(rename="foo")]`
|
||||||
|
ast::MetaNameValue(ref name, ref lit) if name == &"rename" => {
|
||||||
|
variant_attrs.name = Some(lit.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => {
|
||||||
|
cx.span_err(
|
||||||
|
meta_item.span,
|
||||||
|
&format!("unknown serde variant attribute `{}`",
|
||||||
|
meta_item_to_string(meta_item)));
|
||||||
|
|
||||||
|
return Err(Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(variant_attrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the string expression of the field ident.
|
||||||
|
pub fn ident_expr(&self) -> P<ast::Expr> {
|
||||||
|
AstBuilder::new().expr().str(self.ident)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the field name for the field when serializing.
|
||||||
|
pub fn name_expr(&self) -> P<ast::Expr> {
|
||||||
|
match self.name {
|
||||||
|
Some(ref name) => AstBuilder::new().expr().build_lit(P(name.clone())),
|
||||||
|
None => self.ident_expr(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Represents field attribute information
|
/// Represents field attribute information
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct FieldAttrs {
|
pub struct FieldAttrs {
|
||||||
@ -124,22 +175,16 @@ impl FieldAttrs {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_variant(variant: &ast::Variant) -> Self {
|
/// Return the string expression of the field ident.
|
||||||
FieldAttrs {
|
pub fn ident_expr(&self) -> P<ast::Expr> {
|
||||||
ident: variant.node.name,
|
AstBuilder::new().expr().str(self.ident)
|
||||||
name: None,
|
|
||||||
skip_serializing_field: false,
|
|
||||||
skip_serializing_field_if_empty: false,
|
|
||||||
skip_serializing_field_if_none: false,
|
|
||||||
use_default: false,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the default field name for the field.
|
/// Return the field name for the field when serializing.
|
||||||
pub fn name_expr(&self) -> P<ast::Expr> {
|
pub fn name_expr(&self) -> P<ast::Expr> {
|
||||||
match self.name {
|
match self.name {
|
||||||
Some(ref name) => AstBuilder::new().expr().build_lit(P(name.clone())),
|
Some(ref name) => AstBuilder::new().expr().build_lit(P(name.clone())),
|
||||||
None => AstBuilder::new().expr().str(self.ident),
|
None => self.ident_expr(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -550,9 +550,14 @@ fn deserialize_item_enum(
|
|||||||
let variant_visitor = deserialize_field_visitor(
|
let variant_visitor = deserialize_field_visitor(
|
||||||
cx,
|
cx,
|
||||||
builder,
|
builder,
|
||||||
enum_def.variants.iter()
|
try!(
|
||||||
.map(|variant| attr::FieldAttrs::from_variant(variant))
|
enum_def.variants.iter()
|
||||||
.collect(),
|
.map(|variant| {
|
||||||
|
let attrs = try!(attr::VariantAttrs::from_variant(cx, variant));
|
||||||
|
Ok(attrs.name_expr())
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
),
|
||||||
container_attrs,
|
container_attrs,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -790,11 +795,11 @@ fn deserialize_struct_variant(
|
|||||||
fn deserialize_field_visitor(
|
fn deserialize_field_visitor(
|
||||||
cx: &ExtCtxt,
|
cx: &ExtCtxt,
|
||||||
builder: &aster::AstBuilder,
|
builder: &aster::AstBuilder,
|
||||||
field_attrs: Vec<attr::FieldAttrs>,
|
field_names: Vec<P<ast::Expr>>,
|
||||||
container_attrs: &attr::ContainerAttrs,
|
container_attrs: &attr::ContainerAttrs,
|
||||||
) -> 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_attrs.len())
|
let field_idents: Vec<ast::Ident> = (0 .. field_names.len())
|
||||||
.map(|i| builder.id(format!("__field{}", i)))
|
.map(|i| builder.id(format!("__field{}", i)))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
@ -832,10 +837,9 @@ fn deserialize_field_visitor(
|
|||||||
|
|
||||||
// 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_names.iter())
|
||||||
.map(|(field_ident, field_attrs)| {
|
.map(|(field_ident, field_name)| {
|
||||||
let expr = &field_attrs.name_expr();
|
quote_arm!(cx, $field_name => { Ok(__Field::$field_ident) })
|
||||||
quote_arm!(cx, $expr => { Ok(__Field::$field_ident) })
|
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
@ -916,7 +920,14 @@ fn deserialize_struct_visitor(
|
|||||||
let field_visitor = deserialize_field_visitor(
|
let field_visitor = deserialize_field_visitor(
|
||||||
cx,
|
cx,
|
||||||
builder,
|
builder,
|
||||||
try!(attr::get_struct_field_attrs(cx, fields)),
|
try!(
|
||||||
|
fields.iter()
|
||||||
|
.map(|field| {
|
||||||
|
let attrs = try!(attr::FieldAttrs::from_field(cx, field));
|
||||||
|
Ok(attrs.name_expr())
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
),
|
||||||
container_attrs
|
container_attrs
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -990,13 +1001,13 @@ fn deserialize_map(
|
|||||||
|
|
||||||
let field_attrs = try!(attr::get_struct_field_attrs(cx, fields));
|
let field_attrs = try!(attr::get_struct_field_attrs(cx, fields));
|
||||||
|
|
||||||
let extract_values: Vec<P<ast::Stmt>> = field_names.iter()
|
let extract_values = field_names.iter()
|
||||||
.zip(field_attrs.iter())
|
.zip(field_attrs.iter())
|
||||||
.map(|(field_name, field_attr)| {
|
.map(|(field_name, field_attr)| {
|
||||||
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 name = &field_attr.name_expr();
|
let name = field_attr.name_expr();
|
||||||
quote_expr!(cx, try!(visitor.missing_field($name)))
|
quote_expr!(cx, try!(visitor.missing_field($name)))
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1007,7 +1018,7 @@ fn deserialize_map(
|
|||||||
};
|
};
|
||||||
).unwrap()
|
).unwrap()
|
||||||
})
|
})
|
||||||
.collect();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let result = builder.expr().struct_path(struct_path)
|
let result = builder.expr().struct_path(struct_path)
|
||||||
.with_id_exprs(
|
.with_id_exprs(
|
||||||
|
@ -310,7 +310,8 @@ fn serialize_variant(
|
|||||||
) -> Result<ast::Arm, Error> {
|
) -> Result<ast::Arm, Error> {
|
||||||
let type_name = builder.expr().str(type_ident);
|
let type_name = builder.expr().str(type_ident);
|
||||||
let variant_ident = variant.node.name;
|
let variant_ident = variant.node.name;
|
||||||
let variant_name = builder.expr().str(variant_ident);
|
let variant_attrs = try!(attr::VariantAttrs::from_variant(cx, variant));
|
||||||
|
let variant_name = variant_attrs.name_expr();
|
||||||
|
|
||||||
match variant.node.data {
|
match variant.node.data {
|
||||||
ast::VariantData::Unit(_) => {
|
ast::VariantData::Unit(_) => {
|
||||||
|
@ -29,6 +29,12 @@ struct Rename {
|
|||||||
a2: i32,
|
a2: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
enum RenameEnumVariant {
|
||||||
|
#[serde(rename="bruce_wayne")]
|
||||||
|
Batman,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Deserialize, Serialize)]
|
#[derive(Debug, PartialEq, Deserialize, Serialize)]
|
||||||
struct SkipSerializingFields<A: default::Default> {
|
struct SkipSerializingFields<A: default::Default> {
|
||||||
a: i8,
|
a: i8,
|
||||||
@ -156,6 +162,16 @@ fn test_rename() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_rename_enum_variant() {
|
||||||
|
assert_tokens(
|
||||||
|
&RenameEnumVariant::Batman,
|
||||||
|
vec![
|
||||||
|
Token::EnumUnit("RenameEnumVariant", "bruce_wayne"),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_skip_serializing_fields() {
|
fn test_skip_serializing_fields() {
|
||||||
assert_ser_tokens(
|
assert_ser_tokens(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user