mirror of
https://github.com/pezkuwichain/serde.git
synced 2026-06-13 12:31:02 +00:00
Auto merge of #367 - dtolnay:default, r=oli-obk
Simplify implementation of #[serde(default=...)]
This commit is contained in:
+20
-22
@@ -212,13 +212,24 @@ pub struct FieldAttrs {
|
|||||||
skip_serializing_field: bool,
|
skip_serializing_field: bool,
|
||||||
skip_deserializing_field: bool,
|
skip_deserializing_field: bool,
|
||||||
skip_serializing_if: Option<ast::Path>,
|
skip_serializing_if: Option<ast::Path>,
|
||||||
default_expr_if_missing: Option<P<ast::Expr>>,
|
default: FieldDefault,
|
||||||
serialize_with: Option<ast::Path>,
|
serialize_with: Option<ast::Path>,
|
||||||
deserialize_with: Option<ast::Path>,
|
deserialize_with: Option<ast::Path>,
|
||||||
ser_bound: Option<Vec<ast::WherePredicate>>,
|
ser_bound: Option<Vec<ast::WherePredicate>>,
|
||||||
de_bound: Option<Vec<ast::WherePredicate>>,
|
de_bound: Option<Vec<ast::WherePredicate>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Represents the default to use for a field when deserializing.
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub enum FieldDefault {
|
||||||
|
/// Field must always be specified because it does not have a default.
|
||||||
|
None,
|
||||||
|
/// The default is given by `std::default::Default::default()`.
|
||||||
|
Default,
|
||||||
|
/// The default is given by this function.
|
||||||
|
Path(ast::Path),
|
||||||
|
}
|
||||||
|
|
||||||
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,
|
pub fn from_field(cx: &ExtCtxt,
|
||||||
@@ -236,7 +247,7 @@ impl FieldAttrs {
|
|||||||
skip_serializing_field: false,
|
skip_serializing_field: false,
|
||||||
skip_deserializing_field: false,
|
skip_deserializing_field: false,
|
||||||
skip_serializing_if: None,
|
skip_serializing_if: None,
|
||||||
default_expr_if_missing: None,
|
default: FieldDefault::None,
|
||||||
serialize_with: None,
|
serialize_with: None,
|
||||||
deserialize_with: None,
|
deserialize_with: None,
|
||||||
ser_bound: None,
|
ser_bound: None,
|
||||||
@@ -266,17 +277,13 @@ impl FieldAttrs {
|
|||||||
|
|
||||||
// Parse `#[serde(default)]`
|
// Parse `#[serde(default)]`
|
||||||
ast::MetaItemKind::Word(ref name) if name == &"default" => {
|
ast::MetaItemKind::Word(ref name) if name == &"default" => {
|
||||||
let default_expr = builder.expr().default();
|
field_attrs.default = FieldDefault::Default;
|
||||||
field_attrs.default_expr_if_missing = Some(default_expr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse `#[serde(default="...")]`
|
// Parse `#[serde(default="...")]`
|
||||||
ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"default" => {
|
ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"default" => {
|
||||||
let wrapped_expr = wrap_default(
|
let path = try!(parse_lit_into_path(cx, name, lit));
|
||||||
try!(parse_lit_into_path(cx, name, lit)),
|
field_attrs.default = FieldDefault::Path(path);
|
||||||
);
|
|
||||||
|
|
||||||
field_attrs.default_expr_if_missing = Some(wrapped_expr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse `#[serde(skip_serializing)]`
|
// Parse `#[serde(skip_serializing)]`
|
||||||
@@ -290,9 +297,8 @@ impl FieldAttrs {
|
|||||||
|
|
||||||
// Initialize field to Default::default() unless a different
|
// Initialize field to Default::default() unless a different
|
||||||
// default is specified by `#[serde(default="...")]`
|
// default is specified by `#[serde(default="...")]`
|
||||||
if field_attrs.default_expr_if_missing.is_none() {
|
if field_attrs.default == FieldDefault::None {
|
||||||
let default_expr = builder.expr().default();
|
field_attrs.default = FieldDefault::Default;
|
||||||
field_attrs.default_expr_if_missing = Some(default_expr);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -363,8 +369,8 @@ impl FieldAttrs {
|
|||||||
self.skip_serializing_if.as_ref()
|
self.skip_serializing_if.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn default_expr_if_missing(&self) -> Option<&P<ast::Expr>> {
|
pub fn default(&self) -> &FieldDefault {
|
||||||
self.default_expr_if_missing.as_ref()
|
&self.default
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn serialize_with(&self) -> Option<&ast::Path> {
|
pub fn serialize_with(&self) -> Option<&ast::Path> {
|
||||||
@@ -584,11 +590,3 @@ fn parse_lit_into_where(cx: &ExtCtxt, name: &str, lit: &ast::Lit) -> Result<Vec<
|
|||||||
Ok(where_clause.predicates)
|
Ok(where_clause.predicates)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This function wraps the expression in `#[serde(default="...")]` in a function to prevent it
|
|
||||||
/// from accessing the internal `Deserialize` state.
|
|
||||||
fn wrap_default(path: ast::Path) -> P<ast::Expr> {
|
|
||||||
AstBuilder::new().expr().call()
|
|
||||||
.build_path(path)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -60,13 +60,13 @@ pub fn with_bound<F>(
|
|||||||
filter: F,
|
filter: F,
|
||||||
bound: &ast::Path,
|
bound: &ast::Path,
|
||||||
) -> Result<ast::Generics, Error>
|
) -> Result<ast::Generics, Error>
|
||||||
where F: Fn(&ast::StructField, &attr::FieldAttrs) -> bool,
|
where F: Fn(&attr::FieldAttrs) -> bool,
|
||||||
{
|
{
|
||||||
Ok(builder.from_generics(generics.clone())
|
Ok(builder.from_generics(generics.clone())
|
||||||
.with_predicates(
|
.with_predicates(
|
||||||
try!(all_fields_with_attrs(cx, item))
|
try!(all_fields_with_attrs(cx, item))
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|&&(ref field, ref attrs)| filter(field, attrs))
|
.filter(|&&(_, ref attrs)| filter(attrs))
|
||||||
.map(|&(ref field, _)| &field.ty)
|
.map(|&(ref field, _)| &field.ty)
|
||||||
// TODO this filter can be removed later, see comment on function
|
// TODO this filter can be removed later, see comment on function
|
||||||
.filter(|ty| contains_generic(ty, generics))
|
.filter(|ty| contains_generic(ty, generics))
|
||||||
|
|||||||
+12
-18
@@ -134,7 +134,7 @@ fn build_impl_generics(
|
|||||||
// deserialized by us so we do not generate a bound. Fields with a `bound`
|
// deserialized by us so we do not generate a bound. Fields with a `bound`
|
||||||
// attribute specify their own bound so we do not generate one. All other fields
|
// attribute specify their own bound so we do not generate one. All other fields
|
||||||
// may need a `T: Deserialize` bound where T is the type of the field.
|
// may need a `T: Deserialize` bound where T is the type of the field.
|
||||||
fn needs_deserialize_bound(_: &ast::StructField, attrs: &attr::FieldAttrs) -> bool {
|
fn needs_deserialize_bound(attrs: &attr::FieldAttrs) -> bool {
|
||||||
!attrs.skip_deserializing_field()
|
!attrs.skip_deserializing_field()
|
||||||
&& attrs.deserialize_with().is_none()
|
&& attrs.deserialize_with().is_none()
|
||||||
&& attrs.de_bound().is_none()
|
&& attrs.de_bound().is_none()
|
||||||
@@ -142,21 +142,8 @@ fn needs_deserialize_bound(_: &ast::StructField, attrs: &attr::FieldAttrs) -> bo
|
|||||||
|
|
||||||
// Fields with a `default` attribute (not `default=...`), and fields with a
|
// Fields with a `default` attribute (not `default=...`), and fields with a
|
||||||
// `skip_deserializing` attribute that do not also have `default=...`.
|
// `skip_deserializing` attribute that do not also have `default=...`.
|
||||||
fn requires_default(field: &ast::StructField, attrs: &attr::FieldAttrs) -> bool {
|
fn requires_default(attrs: &attr::FieldAttrs) -> bool {
|
||||||
for meta_items in field.attrs.iter().filter_map(attr::get_serde_meta_items) {
|
attrs.default() == &attr::FieldDefault::Default
|
||||||
for meta_item in meta_items {
|
|
||||||
match meta_item.node {
|
|
||||||
ast::MetaItemKind::Word(ref name) if name == &"default" => {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
ast::MetaItemKind::NameValue(ref name, _) if name == &"default" => {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
attrs.skip_deserializing_field()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_body(
|
fn deserialize_body(
|
||||||
@@ -1234,9 +1221,16 @@ fn expr_is_missing(
|
|||||||
cx: &ExtCtxt,
|
cx: &ExtCtxt,
|
||||||
attrs: &attr::FieldAttrs,
|
attrs: &attr::FieldAttrs,
|
||||||
) -> P<ast::Expr> {
|
) -> P<ast::Expr> {
|
||||||
if let Some(expr) = attrs.default_expr_if_missing() {
|
match *attrs.default() {
|
||||||
return expr.clone();
|
attr::FieldDefault::Default => {
|
||||||
|
return quote_expr!(cx, ::std::default::Default::default());
|
||||||
|
}
|
||||||
|
attr::FieldDefault::Path(ref path) => {
|
||||||
|
return quote_expr!(cx, $path());
|
||||||
|
}
|
||||||
|
attr::FieldDefault::None => { /* below */ }
|
||||||
}
|
}
|
||||||
|
|
||||||
let name = attrs.name().deserialize_name_expr();
|
let name = attrs.name().deserialize_name_expr();
|
||||||
match attrs.deserialize_with() {
|
match attrs.deserialize_with() {
|
||||||
None => {
|
None => {
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ fn build_impl_generics(
|
|||||||
// serialized by us so we do not generate a bound. Fields with a `bound`
|
// serialized by us so we do not generate a bound. Fields with a `bound`
|
||||||
// attribute specify their own bound so we do not generate one. All other fields
|
// attribute specify their own bound so we do not generate one. All other fields
|
||||||
// may need a `T: Serialize` bound where T is the type of the field.
|
// may need a `T: Serialize` bound where T is the type of the field.
|
||||||
fn needs_serialize_bound(_: &ast::StructField, attrs: &attr::FieldAttrs) -> bool {
|
fn needs_serialize_bound(attrs: &attr::FieldAttrs) -> bool {
|
||||||
!attrs.skip_serializing_field()
|
!attrs.skip_serializing_field()
|
||||||
&& attrs.serialize_with().is_none()
|
&& attrs.serialize_with().is_none()
|
||||||
&& attrs.ser_bound().is_none()
|
&& attrs.ser_bound().is_none()
|
||||||
|
|||||||
Reference in New Issue
Block a user