mirror of
https://github.com/pezkuwichain/serde.git
synced 2026-04-29 05:57:55 +00:00
Support custom paths in container attribute serde(default="...")
This commit is contained in:
@@ -90,7 +90,7 @@ impl Name {
|
|||||||
pub struct Item {
|
pub struct Item {
|
||||||
name: Name,
|
name: Name,
|
||||||
deny_unknown_fields: bool,
|
deny_unknown_fields: bool,
|
||||||
default: bool,
|
default: Default,
|
||||||
ser_bound: Option<Vec<syn::WherePredicate>>,
|
ser_bound: Option<Vec<syn::WherePredicate>>,
|
||||||
de_bound: Option<Vec<syn::WherePredicate>>,
|
de_bound: Option<Vec<syn::WherePredicate>>,
|
||||||
tag: EnumTag,
|
tag: EnumTag,
|
||||||
@@ -134,7 +134,7 @@ impl Item {
|
|||||||
let mut ser_name = Attr::none(cx, "rename");
|
let mut ser_name = Attr::none(cx, "rename");
|
||||||
let mut de_name = Attr::none(cx, "rename");
|
let mut de_name = Attr::none(cx, "rename");
|
||||||
let mut deny_unknown_fields = BoolAttr::none(cx, "deny_unknown_fields");
|
let mut deny_unknown_fields = BoolAttr::none(cx, "deny_unknown_fields");
|
||||||
let mut default = BoolAttr::none(cx, "default");
|
let mut default = Attr::none(cx, "default");
|
||||||
let mut ser_bound = Attr::none(cx, "bound");
|
let mut ser_bound = Attr::none(cx, "bound");
|
||||||
let mut de_bound = Attr::none(cx, "bound");
|
let mut de_bound = Attr::none(cx, "bound");
|
||||||
let mut untagged = BoolAttr::none(cx, "untagged");
|
let mut untagged = BoolAttr::none(cx, "untagged");
|
||||||
@@ -168,11 +168,27 @@ impl Item {
|
|||||||
// Parse `#[serde(default)]`
|
// Parse `#[serde(default)]`
|
||||||
MetaItem(Word(ref name)) if name == "default" => {
|
MetaItem(Word(ref name)) if name == "default" => {
|
||||||
match item.body {
|
match item.body {
|
||||||
syn::Body::Struct(_) => {
|
syn::Body::Struct(syn::VariantData::Struct(_)) => {
|
||||||
default.set_true();
|
default.set(Default::Default);
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
cx.error("#[serde(default)] can only be used on structs")
|
cx.error("#[serde(default)] can only be used on structs \
|
||||||
|
with named fields")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse `#[serde(default="...")]`
|
||||||
|
MetaItem(NameValue(ref name, ref lit)) if name == "default" => {
|
||||||
|
if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) {
|
||||||
|
match item.body {
|
||||||
|
syn::Body::Struct(syn::VariantData::Struct(_)) => {
|
||||||
|
default.set(Default::Path(path));
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
cx.error("#[serde(default = \"...\")] can only be used \
|
||||||
|
on structs with named fields")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -295,7 +311,7 @@ impl Item {
|
|||||||
deserialize: de_name.get().unwrap_or_else(|| item.ident.to_string()),
|
deserialize: de_name.get().unwrap_or_else(|| item.ident.to_string()),
|
||||||
},
|
},
|
||||||
deny_unknown_fields: deny_unknown_fields.get(),
|
deny_unknown_fields: deny_unknown_fields.get(),
|
||||||
default: default.get(),
|
default: default.get().unwrap_or(Default::None),
|
||||||
ser_bound: ser_bound.get(),
|
ser_bound: ser_bound.get(),
|
||||||
de_bound: de_bound.get(),
|
de_bound: de_bound.get(),
|
||||||
tag: tag,
|
tag: tag,
|
||||||
@@ -310,8 +326,8 @@ impl Item {
|
|||||||
self.deny_unknown_fields
|
self.deny_unknown_fields
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn default(&self) -> bool {
|
pub fn default(&self) -> &Default {
|
||||||
self.default
|
&self.default
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ser_bound(&self) -> Option<&[syn::WherePredicate]> {
|
pub fn ser_bound(&self) -> Option<&[syn::WherePredicate]> {
|
||||||
@@ -410,7 +426,7 @@ pub struct Field {
|
|||||||
skip_serializing: bool,
|
skip_serializing: bool,
|
||||||
skip_deserializing: bool,
|
skip_deserializing: bool,
|
||||||
skip_serializing_if: Option<syn::Path>,
|
skip_serializing_if: Option<syn::Path>,
|
||||||
default: FieldDefault,
|
default: Default,
|
||||||
serialize_with: Option<syn::Path>,
|
serialize_with: Option<syn::Path>,
|
||||||
deserialize_with: Option<syn::Path>,
|
deserialize_with: Option<syn::Path>,
|
||||||
ser_bound: Option<Vec<syn::WherePredicate>>,
|
ser_bound: Option<Vec<syn::WherePredicate>>,
|
||||||
@@ -419,7 +435,7 @@ pub struct Field {
|
|||||||
|
|
||||||
/// Represents the default to use for a field when deserializing.
|
/// Represents the default to use for a field when deserializing.
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum FieldDefault {
|
pub enum Default {
|
||||||
/// Field must always be specified because it does not have a default.
|
/// Field must always be specified because it does not have a default.
|
||||||
None,
|
None,
|
||||||
/// The default is given by `std::default::Default::default()`.
|
/// The default is given by `std::default::Default::default()`.
|
||||||
@@ -468,13 +484,13 @@ impl Field {
|
|||||||
|
|
||||||
// Parse `#[serde(default)]`
|
// Parse `#[serde(default)]`
|
||||||
MetaItem(Word(ref name)) if name == "default" => {
|
MetaItem(Word(ref name)) if name == "default" => {
|
||||||
default.set(FieldDefault::Default);
|
default.set(Default::Default);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse `#[serde(default="...")]`
|
// Parse `#[serde(default="...")]`
|
||||||
MetaItem(NameValue(ref name, ref lit)) if name == "default" => {
|
MetaItem(NameValue(ref name, ref lit)) if name == "default" => {
|
||||||
if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) {
|
if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) {
|
||||||
default.set(FieldDefault::Path(path));
|
default.set(Default::Path(path));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -552,7 +568,7 @@ impl Field {
|
|||||||
// Is skip_deserializing, initialize the field to Default::default()
|
// Is skip_deserializing, initialize the field to Default::default()
|
||||||
// unless a different default is specified by `#[serde(default="...")]`
|
// unless a different default is specified by `#[serde(default="...")]`
|
||||||
if skip_deserializing.0.value.is_some() {
|
if skip_deserializing.0.value.is_some() {
|
||||||
default.set_if_none(FieldDefault::Default);
|
default.set_if_none(Default::Default);
|
||||||
}
|
}
|
||||||
|
|
||||||
Field {
|
Field {
|
||||||
@@ -563,7 +579,7 @@ impl Field {
|
|||||||
skip_serializing: skip_serializing.get(),
|
skip_serializing: skip_serializing.get(),
|
||||||
skip_deserializing: skip_deserializing.get(),
|
skip_deserializing: skip_deserializing.get(),
|
||||||
skip_serializing_if: skip_serializing_if.get(),
|
skip_serializing_if: skip_serializing_if.get(),
|
||||||
default: default.get().unwrap_or(FieldDefault::None),
|
default: default.get().unwrap_or(Default::None),
|
||||||
serialize_with: serialize_with.get(),
|
serialize_with: serialize_with.get(),
|
||||||
deserialize_with: deserialize_with.get(),
|
deserialize_with: deserialize_with.get(),
|
||||||
ser_bound: ser_bound.get(),
|
ser_bound: ser_bound.get(),
|
||||||
@@ -587,7 +603,7 @@ impl Field {
|
|||||||
self.skip_serializing_if.as_ref()
|
self.skip_serializing_if.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn default(&self) -> &FieldDefault {
|
pub fn default(&self) -> &Default {
|
||||||
&self.default
|
&self.default
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -157,6 +157,30 @@ pub fn with_bound<F>(item: &Item,
|
|||||||
generics
|
generics
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn with_self_bound(item: &Item,
|
||||||
|
generics: &syn::Generics,
|
||||||
|
bound: &syn::Path)
|
||||||
|
-> syn::Generics
|
||||||
|
{
|
||||||
|
let mut generics = generics.clone();
|
||||||
|
generics.where_clause.predicates.push(
|
||||||
|
syn::WherePredicate::BoundPredicate(syn::WhereBoundPredicate {
|
||||||
|
bound_lifetimes: Vec::new(),
|
||||||
|
// the type that is being bounded e.g. MyStruct<'a, T>
|
||||||
|
bounded_ty: type_of_item(item),
|
||||||
|
// the bound e.g. Default
|
||||||
|
bounds: vec![syn::TyParamBound::Trait(
|
||||||
|
syn::PolyTraitRef {
|
||||||
|
bound_lifetimes: Vec::new(),
|
||||||
|
trait_ref: bound.clone(),
|
||||||
|
},
|
||||||
|
syn::TraitBoundModifier::None
|
||||||
|
)],
|
||||||
|
})
|
||||||
|
);
|
||||||
|
generics
|
||||||
|
}
|
||||||
|
|
||||||
pub fn with_lifetime_bound(generics: &syn::Generics,
|
pub fn with_lifetime_bound(generics: &syn::Generics,
|
||||||
lifetime: &str)
|
lifetime: &str)
|
||||||
-> syn::Generics {
|
-> syn::Generics {
|
||||||
@@ -179,3 +203,26 @@ pub fn with_lifetime_bound(generics: &syn::Generics,
|
|||||||
generics
|
generics
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn type_of_item(item: &Item) -> syn::Ty {
|
||||||
|
syn::Ty::Path(None, syn::Path {
|
||||||
|
global: false,
|
||||||
|
segments: vec![
|
||||||
|
syn::PathSegment {
|
||||||
|
ident: item.ident.clone(),
|
||||||
|
parameters: syn::PathParameters::AngleBracketed(syn::AngleBracketedParameterData {
|
||||||
|
lifetimes: item.generics
|
||||||
|
.lifetimes
|
||||||
|
.iter()
|
||||||
|
.map(|def| def.lifetime.clone())
|
||||||
|
.collect(),
|
||||||
|
types: item.generics
|
||||||
|
.ty_params
|
||||||
|
.iter()
|
||||||
|
.map(|param| syn::Ty::Path(None, param.ident.clone().into()))
|
||||||
|
.collect(),
|
||||||
|
bindings: Vec::new(),
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
+44
-31
@@ -46,11 +46,19 @@ fn build_generics(item: &Item) -> syn::Generics {
|
|||||||
match item.attrs.de_bound() {
|
match item.attrs.de_bound() {
|
||||||
Some(predicates) => bound::with_where_predicates(&generics, predicates),
|
Some(predicates) => bound::with_where_predicates(&generics, predicates),
|
||||||
None => {
|
None => {
|
||||||
|
let generics = match *item.attrs.default() {
|
||||||
|
attr::Default::Default => {
|
||||||
|
bound::with_self_bound(item, &generics, &path!(_serde::export::Default))
|
||||||
|
}
|
||||||
|
attr::Default::None | attr::Default::Path(_) => generics,
|
||||||
|
};
|
||||||
|
|
||||||
let generics =
|
let generics =
|
||||||
bound::with_bound(item,
|
bound::with_bound(item,
|
||||||
&generics,
|
&generics,
|
||||||
needs_deserialize_bound,
|
needs_deserialize_bound,
|
||||||
&path!(_serde::Deserialize));
|
&path!(_serde::Deserialize));
|
||||||
|
|
||||||
bound::with_bound(item,
|
bound::with_bound(item,
|
||||||
&generics,
|
&generics,
|
||||||
requires_default,
|
requires_default,
|
||||||
@@ -70,7 +78,7 @@ fn needs_deserialize_bound(attrs: &attr::Field) -> bool {
|
|||||||
// 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(attrs: &attr::Field) -> bool {
|
fn requires_default(attrs: &attr::Field) -> bool {
|
||||||
attrs.default() == &attr::FieldDefault::Default
|
attrs.default() == &attr::Default::Default
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_body(item: &Item, generics: &syn::Generics) -> Tokens {
|
fn deserialize_body(item: &Item, generics: &syn::Generics) -> Tokens {
|
||||||
@@ -168,7 +176,7 @@ fn deserialize_tuple(ident: &syn::Ident,
|
|||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
let visit_seq = deserialize_seq(ident, &type_path, generics, fields, false);
|
let visit_seq = deserialize_seq(ident, &type_path, generics, fields, false, item_attrs);
|
||||||
|
|
||||||
let visitor_expr = quote! {
|
let visitor_expr = quote! {
|
||||||
__Visitor { marker: _serde::export::PhantomData::<#ident #ty_generics> }
|
__Visitor { marker: _serde::export::PhantomData::<#ident #ty_generics> }
|
||||||
@@ -222,7 +230,8 @@ fn deserialize_seq(ident: &syn::Ident,
|
|||||||
type_path: &Tokens,
|
type_path: &Tokens,
|
||||||
generics: &syn::Generics,
|
generics: &syn::Generics,
|
||||||
fields: &[Field],
|
fields: &[Field],
|
||||||
is_struct: bool)
|
is_struct: bool,
|
||||||
|
item_attrs: &attr::Item)
|
||||||
-> Tokens {
|
-> Tokens {
|
||||||
let vars = (0..fields.len()).map(field_i as fn(_) -> _);
|
let vars = (0..fields.len()).map(field_i as fn(_) -> _);
|
||||||
|
|
||||||
@@ -235,7 +244,7 @@ fn deserialize_seq(ident: &syn::Ident,
|
|||||||
let let_values = vars.clone().zip(fields)
|
let let_values = vars.clone().zip(fields)
|
||||||
.map(|(var, field)| {
|
.map(|(var, field)| {
|
||||||
if field.attrs.skip_deserializing() {
|
if field.attrs.skip_deserializing() {
|
||||||
let default = expr_is_missing(&field.attrs, false, "");
|
let default = expr_is_missing(&field, item_attrs);
|
||||||
quote! {
|
quote! {
|
||||||
let #var = #default;
|
let #var = #default;
|
||||||
}
|
}
|
||||||
@@ -337,7 +346,7 @@ fn deserialize_struct(ident: &syn::Ident,
|
|||||||
None => format!("struct {}", ident),
|
None => format!("struct {}", ident),
|
||||||
};
|
};
|
||||||
|
|
||||||
let visit_seq = deserialize_seq(ident, &type_path, generics, fields, true);
|
let visit_seq = deserialize_seq(ident, &type_path, generics, fields, true, item_attrs);
|
||||||
|
|
||||||
let (field_visitor, fields_stmt, visit_map) =
|
let (field_visitor, fields_stmt, visit_map) =
|
||||||
deserialize_struct_visitor(ident, type_path, generics, fields, item_attrs);
|
deserialize_struct_visitor(ident, type_path, generics, fields, item_attrs);
|
||||||
@@ -1012,11 +1021,7 @@ fn deserialize_map(ident: &syn::Ident,
|
|||||||
let extract_values = fields_names.iter()
|
let extract_values = fields_names.iter()
|
||||||
.filter(|&&(field, _)| !field.attrs.skip_deserializing())
|
.filter(|&&(field, _)| !field.attrs.skip_deserializing())
|
||||||
.map(|&(field, ref name)| {
|
.map(|&(field, ref name)| {
|
||||||
// Use the ident as field name, since the user can rename the field
|
let missing_expr = expr_is_missing(&field, item_attrs);
|
||||||
// in the attributes using `#[serde(rename = "name")]`, but we need
|
|
||||||
// the original (in code) name of the field.
|
|
||||||
let ident = field.ident.clone().expect("struct contains unnamed fields");
|
|
||||||
let missing_expr = expr_is_missing(&field.attrs, item_attrs.default(), ident.as_ref());
|
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
let #name = match #name {
|
let #name = match #name {
|
||||||
@@ -1030,21 +1035,29 @@ fn deserialize_map(ident: &syn::Ident,
|
|||||||
.map(|&(field, ref name)| {
|
.map(|&(field, ref name)| {
|
||||||
let ident = field.ident.clone().expect("struct contains unnamed fields");
|
let ident = field.ident.clone().expect("struct contains unnamed fields");
|
||||||
let value = if field.attrs.skip_deserializing() {
|
let value = if field.attrs.skip_deserializing() {
|
||||||
expr_is_missing(&field.attrs, item_attrs.default(), ident.as_ref())
|
expr_is_missing(&field, item_attrs)
|
||||||
} else {
|
} else {
|
||||||
quote!(#name)
|
quote!(#name)
|
||||||
};
|
};
|
||||||
quote!(#ident: #value)
|
quote!(#ident: #value)
|
||||||
});
|
});
|
||||||
|
|
||||||
let default = if item_attrs.default() {
|
let let_default = match *item_attrs.default() {
|
||||||
quote!(
|
attr::Default::Default => {
|
||||||
let default: #struct_path = _serde::export::Default::default();
|
Some(quote!(
|
||||||
)
|
let __default: Self::Value = _serde::export::Default::default();
|
||||||
} else {
|
))
|
||||||
|
}
|
||||||
|
attr::Default::Path(ref path) => {
|
||||||
|
Some(quote!(
|
||||||
|
let __default: Self::Value = #path();
|
||||||
|
))
|
||||||
|
}
|
||||||
|
attr::Default::None => {
|
||||||
// We don't need the default value, to prevent an unused variable warning
|
// We don't need the default value, to prevent an unused variable warning
|
||||||
// we'll leave the line empty.
|
// we'll leave the line empty.
|
||||||
quote!()
|
None
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
@@ -1052,7 +1065,7 @@ fn deserialize_map(ident: &syn::Ident,
|
|||||||
|
|
||||||
#match_keys
|
#match_keys
|
||||||
|
|
||||||
#default
|
#let_default
|
||||||
|
|
||||||
#(#extract_values)*
|
#(#extract_values)*
|
||||||
|
|
||||||
@@ -1097,27 +1110,27 @@ fn wrap_deserialize_with(ident: &syn::Ident,
|
|||||||
(wrapper, wrapper_ty)
|
(wrapper, wrapper_ty)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expr_is_missing(attrs: &attr::Field, use_default: bool, field_name: &str) -> Tokens {
|
fn expr_is_missing(field: &Field, item_attrs: &attr::Item) -> Tokens {
|
||||||
match *attrs.default() {
|
match *field.attrs.default() {
|
||||||
attr::FieldDefault::Default => {
|
attr::Default::Default => {
|
||||||
return quote!(_serde::export::Default::default());
|
return quote!(_serde::export::Default::default());
|
||||||
}
|
}
|
||||||
attr::FieldDefault::Path(ref path) => {
|
attr::Default::Path(ref path) => {
|
||||||
return quote!(#path());
|
return quote!(#path());
|
||||||
}
|
}
|
||||||
attr::FieldDefault::None => { /* below */ }
|
attr::Default::None => { /* below */ }
|
||||||
}
|
}
|
||||||
|
|
||||||
if use_default {
|
match *item_attrs.default() {
|
||||||
// Field name without the qoutes.
|
attr::Default::Default | attr::Default::Path(_) => {
|
||||||
let field_name = quote::Ident::new(field_name);
|
let ident = &field.ident;
|
||||||
return quote!(
|
return quote!(__default.#ident);
|
||||||
default.#field_name
|
}
|
||||||
)
|
attr::Default::None => { /* below */ }
|
||||||
}
|
}
|
||||||
|
|
||||||
let name = attrs.name().deserialize_name();
|
let name = field.attrs.name().deserialize_name();
|
||||||
match attrs.deserialize_with() {
|
match field.attrs.deserialize_with() {
|
||||||
None => {
|
None => {
|
||||||
quote! {
|
quote! {
|
||||||
try!(_serde::de::private::missing_field(#name))
|
try!(_serde::de::private::missing_field(#name))
|
||||||
|
|||||||
@@ -43,13 +43,13 @@ struct StructDenyUnknown {
|
|||||||
|
|
||||||
#[derive(PartialEq, Debug, Deserialize)]
|
#[derive(PartialEq, Debug, Deserialize)]
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
struct StructDefault {
|
struct StructDefault<T> {
|
||||||
a: i32,
|
a: i32,
|
||||||
b: String,
|
b: T,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for StructDefault {
|
impl Default for StructDefault<String> {
|
||||||
fn default() -> StructDefault {
|
fn default() -> Self {
|
||||||
StructDefault {
|
StructDefault {
|
||||||
a: 100,
|
a: 100,
|
||||||
b: "default".to_string(),
|
b: "default".to_string(),
|
||||||
|
|||||||
Reference in New Issue
Block a user