mirror of
https://github.com/serde-rs/serde.git
synced 2025-09-30 22:41:31 +00:00
Derive deserialize_from for tuples and structs
This adds a new "deserialize_from" feature (default off) that opts into deriving deserialize_from with #[derive(Deserialize)].
This commit is contained in:
parent
bc221abb04
commit
e354dd0c7f
@ -14,6 +14,10 @@ include = ["Cargo.toml", "src/**/*.rs", "README.md", "LICENSE-APACHE", "LICENSE-
|
||||
[badges]
|
||||
travis-ci = { repository = "serde-rs/serde" }
|
||||
|
||||
[features]
|
||||
default = []
|
||||
deserialize_from = []
|
||||
|
||||
[lib]
|
||||
name = "serde_derive"
|
||||
proc-macro = true
|
||||
|
@ -25,7 +25,7 @@ pub fn expand_derive_deserialize(input: &syn::DeriveInput) -> Result<Tokens, Str
|
||||
let params = Parameters::new(&cont);
|
||||
let (de_impl_generics, _, ty_generics, where_clause) = split_with_de_lifetime(¶ms);
|
||||
let dummy_const = Ident::new(format!("_IMPL_DESERIALIZE_FOR_{}", ident));
|
||||
let body = Stmts(deserialize_body(&cont, ¶ms));
|
||||
let main_body = Stmts(deserialize_body(&cont, ¶ms));
|
||||
let delife = params.borrowed.de_lifetime();
|
||||
|
||||
let impl_block = if let Some(remote) = cont.attrs.remote() {
|
||||
@ -35,19 +35,34 @@ pub fn expand_derive_deserialize(input: &syn::DeriveInput) -> Result<Tokens, Str
|
||||
#vis fn deserialize<__D>(__deserializer: __D) -> _serde::export::Result<#remote #ty_generics, __D::Error>
|
||||
where __D: _serde::Deserializer<#delife>
|
||||
{
|
||||
#body
|
||||
#main_body
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let from_body = deserialize_from_body(&cont, ¶ms);
|
||||
let from_impl = from_body.map(|from_body| {
|
||||
let from_body = Stmts(from_body);
|
||||
|
||||
quote! {
|
||||
fn deserialize_from<__D>(&mut self, __deserializer: __D) -> _serde::export::Result<(), __D::Error>
|
||||
where __D: _serde::Deserializer<#delife>
|
||||
{
|
||||
#from_body
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
quote! {
|
||||
#[automatically_derived]
|
||||
impl #de_impl_generics _serde::Deserialize<#delife> for #ident #ty_generics #where_clause {
|
||||
fn deserialize<__D>(__deserializer: __D) -> _serde::export::Result<Self, __D::Error>
|
||||
where __D: _serde::Deserializer<#delife>
|
||||
{
|
||||
#body
|
||||
#main_body
|
||||
}
|
||||
|
||||
#from_impl
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -245,6 +260,30 @@ fn deserialize_body(cont: &Container, params: &Parameters) -> Fragment {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "deserialize_from")]
|
||||
fn deserialize_from_body(cont: &Container, params: &Parameters) -> Option<Fragment> {
|
||||
if let (None, attr::Identifier::No) = (cont.attrs.from_type(), cont.attrs.identifier()) {
|
||||
match cont.body {
|
||||
Body::Enum(_) => None,
|
||||
Body::Struct(Style::Struct, ref fields) => {
|
||||
deserialize_from_struct(None, params, fields, &cont.attrs, None, Untagged::No)
|
||||
}
|
||||
Body::Struct(Style::Tuple, ref fields) |
|
||||
Body::Struct(Style::Newtype, ref fields) => {
|
||||
deserialize_from_tuple(None, params, fields, &cont.attrs, None)
|
||||
}
|
||||
Body::Struct(Style::Unit, _) => None,
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "deserialize_from"))]
|
||||
fn deserialize_from_body(_cont: &Container, _params: &Parameters) -> Option<Fragment> {
|
||||
None
|
||||
}
|
||||
|
||||
fn deserialize_from(from_type: &syn::Ty) -> Fragment {
|
||||
quote_block! {
|
||||
_serde::export::Result::map(
|
||||
@ -376,6 +415,110 @@ fn deserialize_tuple(
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "deserialize_from")]
|
||||
fn deserialize_from_tuple(
|
||||
variant_ident: Option<&syn::Ident>,
|
||||
params: &Parameters,
|
||||
fields: &[Field],
|
||||
cattrs: &attr::Container,
|
||||
deserializer: Option<Tokens>,
|
||||
) -> Option<Fragment> {
|
||||
let this = ¶ms.this;
|
||||
let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = split_with_de_lifetime(params,);
|
||||
let delife = params.borrowed.de_lifetime();
|
||||
|
||||
// If there are getters (implying private fields), construct the local type
|
||||
// and use an `Into` conversion to get the remote type. If there are no
|
||||
// getters then construct the target type directly.
|
||||
let construct = if params.has_getter {
|
||||
let local = ¶ms.local;
|
||||
quote!(#local)
|
||||
} else {
|
||||
quote!(#this)
|
||||
};
|
||||
|
||||
let is_enum = variant_ident.is_some();
|
||||
let type_path = match variant_ident {
|
||||
Some(variant_ident) => quote!(#construct::#variant_ident),
|
||||
None => construct,
|
||||
};
|
||||
let expecting = match variant_ident {
|
||||
Some(variant_ident) => format!("tuple variant {}::{}", params.type_name(), variant_ident),
|
||||
None => format!("tuple struct {}", params.type_name()),
|
||||
};
|
||||
|
||||
let nfields = fields.len();
|
||||
|
||||
let visit_newtype_struct = if !is_enum && nfields == 1 {
|
||||
Some(deserialize_from_newtype_struct(&type_path, params, &fields[0]))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let visit_seq = Stmts(deserialize_from_seq(params, fields, cattrs));
|
||||
|
||||
let visitor_expr = quote! {
|
||||
__Visitor {
|
||||
dest: self,
|
||||
lifetime: _serde::export::PhantomData,
|
||||
}
|
||||
};
|
||||
|
||||
let dispatch = if let Some(deserializer) = deserializer {
|
||||
quote!(_serde::Deserializer::deserialize_tuple(#deserializer, #nfields, #visitor_expr))
|
||||
} else if is_enum {
|
||||
quote!(_serde::de::VariantAccess::tuple_variant(__variant, #nfields, #visitor_expr))
|
||||
} else if nfields == 1 {
|
||||
let type_name = cattrs.name().deserialize_name();
|
||||
quote!(_serde::Deserializer::deserialize_newtype_struct(__deserializer, #type_name, #visitor_expr))
|
||||
} else {
|
||||
let type_name = cattrs.name().deserialize_name();
|
||||
quote!(_serde::Deserializer::deserialize_tuple_struct(__deserializer, #type_name, #nfields, #visitor_expr))
|
||||
};
|
||||
|
||||
let all_skipped = fields
|
||||
.iter()
|
||||
.all(|field| field.attrs.skip_deserializing());
|
||||
let visitor_var = if all_skipped {
|
||||
quote!(_)
|
||||
} else {
|
||||
quote!(mut __seq)
|
||||
};
|
||||
|
||||
if params.has_getter {
|
||||
None
|
||||
} else {
|
||||
let de_from_impl_generics = de_impl_generics.with_dest();
|
||||
let de_from_ty_generics = de_ty_generics.with_dest();
|
||||
let dest_life = dest_lifetime();
|
||||
Some(quote_block! {
|
||||
struct __Visitor #de_from_impl_generics #where_clause {
|
||||
dest: &#dest_life mut #this #ty_generics,
|
||||
lifetime: _serde::export::PhantomData<&#delife ()>,
|
||||
}
|
||||
|
||||
impl #de_from_impl_generics _serde::de::Visitor<#delife> for __Visitor #de_from_ty_generics #where_clause {
|
||||
type Value = ();
|
||||
|
||||
fn expecting(&self, formatter: &mut _serde::export::Formatter) -> _serde::export::fmt::Result {
|
||||
_serde::export::Formatter::write_str(formatter, #expecting)
|
||||
}
|
||||
|
||||
#visit_newtype_struct
|
||||
|
||||
#[inline]
|
||||
fn visit_seq<__A>(self, #visitor_var: __A) -> _serde::export::Result<Self::Value, __A::Error>
|
||||
where __A: _serde::de::SeqAccess<#delife>
|
||||
{
|
||||
#visit_seq
|
||||
}
|
||||
}
|
||||
|
||||
#dispatch
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn deserialize_seq(
|
||||
type_path: &Tokens,
|
||||
params: &Parameters,
|
||||
@ -453,6 +596,70 @@ fn deserialize_seq(
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "deserialize_from")]
|
||||
fn deserialize_from_seq(
|
||||
params: &Parameters,
|
||||
fields: &[Field],
|
||||
cattrs: &attr::Container,
|
||||
) -> Fragment {
|
||||
let vars = (0..fields.len()).map(field_i as fn(_) -> _);
|
||||
|
||||
let deserialized_count = fields
|
||||
.iter()
|
||||
.filter(|field| !field.attrs.skip_deserializing())
|
||||
.count();
|
||||
let expecting = format!("tuple of {} elements", deserialized_count);
|
||||
|
||||
let mut index_in_seq = 0usize;
|
||||
let write_values = vars.clone().zip(fields).enumerate()
|
||||
.map(|(field_index, (_, field))| {
|
||||
// If there's no field name, assume we're a tuple-struct and use a numeric index
|
||||
let field_name = field.ident.clone()
|
||||
.unwrap_or_else(|| Ident::new(field_index.to_string()));
|
||||
|
||||
if field.attrs.skip_deserializing() {
|
||||
let default = Expr(expr_is_missing(&field, cattrs));
|
||||
quote! {
|
||||
self.dest.#field_name = #default;
|
||||
}
|
||||
} else {
|
||||
let handle_none = quote! {
|
||||
if visit.is_none() {
|
||||
return _serde::export::Err(_serde::de::Error::invalid_length(#index_in_seq, &#expecting));
|
||||
}
|
||||
};
|
||||
let write = match field.attrs.deserialize_with() {
|
||||
None => {
|
||||
quote! {
|
||||
let visit = try!(_serde::de::SeqAccess::next_element_seed(&mut __seq,
|
||||
_serde::private::de::DeserializeFromSeed(&mut self.dest.#field_name)));
|
||||
#handle_none
|
||||
}
|
||||
}
|
||||
Some(path) => {
|
||||
let (wrapper, wrapper_ty) = wrap_deserialize_field_with(
|
||||
params, field.ty, path);
|
||||
quote!({
|
||||
#wrapper
|
||||
let visit = _serde::export::Option::map(
|
||||
try!(_serde::de::SeqAccess::next_element::<#wrapper_ty>(&mut __seq)),
|
||||
|__wrap| __wrap.value);
|
||||
#handle_none
|
||||
self.dest.#field_name = visit.unwrap();
|
||||
})
|
||||
}
|
||||
};
|
||||
index_in_seq += 1;
|
||||
write
|
||||
}
|
||||
});
|
||||
|
||||
quote_block! {
|
||||
#(#write_values)*
|
||||
_serde::export::Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn deserialize_newtype_struct(type_path: &Tokens, params: &Parameters, field: &Field) -> Tokens {
|
||||
let delife = params.borrowed.de_lifetime();
|
||||
|
||||
@ -490,6 +697,63 @@ fn deserialize_newtype_struct(type_path: &Tokens, params: &Parameters, field: &F
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "deserialize_from")]
|
||||
fn deserialize_from_newtype_struct(
|
||||
type_path: &Tokens,
|
||||
params: &Parameters,
|
||||
field: &Field
|
||||
) -> Tokens {
|
||||
let delife = params.borrowed.de_lifetime();
|
||||
|
||||
// FIXME: can we reject this condition earlier so we don't have to handle it?
|
||||
// If there's conversions that we need to do, we can't do this properly.
|
||||
if field.attrs.deserialize_with().is_some() || params.has_getter {
|
||||
let value = match field.attrs.deserialize_with() {
|
||||
None => {
|
||||
let field_ty = &field.ty;
|
||||
quote! {
|
||||
try!(<#field_ty as _serde::Deserialize>::deserialize(__e))
|
||||
}
|
||||
}
|
||||
Some(path) => {
|
||||
let (wrapper, wrapper_ty) = wrap_deserialize_field_with(params, field.ty, path);
|
||||
quote!({
|
||||
#wrapper
|
||||
try!(<#wrapper_ty as _serde::Deserialize>::deserialize(__e)).value
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
let mut result = quote!(#type_path(#value));
|
||||
if params.has_getter {
|
||||
let this = ¶ms.this;
|
||||
result = quote! {
|
||||
_serde::export::Into::<#this>::into(#result)
|
||||
};
|
||||
}
|
||||
|
||||
quote! {
|
||||
#[inline]
|
||||
fn visit_newtype_struct<__E>(self, __e: __E) -> _serde::export::Result<Self::Value, __E::Error>
|
||||
where __E: _serde::Deserializer<#delife>
|
||||
{
|
||||
*self.dest = #result;
|
||||
_serde::export::Ok(())
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// No conversions, just recurse on the field.
|
||||
quote! {
|
||||
#[inline]
|
||||
fn visit_newtype_struct<__E>(self, __e: __E) -> _serde::export::Result<Self::Value, __E::Error>
|
||||
where __E: _serde::Deserializer<#delife>
|
||||
{
|
||||
_serde::Deserialize::deserialize_from(&mut self.dest.0, __e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum Untagged {
|
||||
Yes,
|
||||
No,
|
||||
@ -612,6 +876,121 @@ fn deserialize_struct(
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "deserialize_from")]
|
||||
fn deserialize_from_struct(
|
||||
variant_ident: Option<&syn::Ident>,
|
||||
params: &Parameters,
|
||||
fields: &[Field],
|
||||
cattrs: &attr::Container,
|
||||
deserializer: Option<Tokens>,
|
||||
untagged: Untagged,
|
||||
) -> Option<Fragment> {
|
||||
let is_enum = variant_ident.is_some();
|
||||
|
||||
let this = ¶ms.this;
|
||||
let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = split_with_de_lifetime(params,);
|
||||
let delife = params.borrowed.de_lifetime();
|
||||
|
||||
let expecting = match variant_ident {
|
||||
Some(variant_ident) => format!("struct variant {}::{}", params.type_name(), variant_ident),
|
||||
None => format!("struct {}", params.type_name()),
|
||||
};
|
||||
|
||||
let visit_seq = Stmts(deserialize_from_seq(params, fields, cattrs));
|
||||
|
||||
let (field_visitor, fields_stmt, visit_map) =
|
||||
deserialize_from_struct_visitor(params, fields, cattrs);
|
||||
let field_visitor = Stmts(field_visitor);
|
||||
let fields_stmt = Stmts(fields_stmt);
|
||||
let visit_map = Stmts(visit_map);
|
||||
|
||||
let visitor_expr = quote! {
|
||||
__Visitor {
|
||||
dest: self,
|
||||
lifetime: _serde::export::PhantomData,
|
||||
}
|
||||
};
|
||||
let dispatch = if let Some(deserializer) = deserializer {
|
||||
quote! {
|
||||
_serde::Deserializer::deserialize_any(#deserializer, #visitor_expr)
|
||||
}
|
||||
} else if is_enum {
|
||||
quote! {
|
||||
_serde::de::VariantAccess::struct_variant(__variant, FIELDS, #visitor_expr)
|
||||
}
|
||||
} else {
|
||||
let type_name = cattrs.name().deserialize_name();
|
||||
quote! {
|
||||
_serde::Deserializer::deserialize_struct(__deserializer, #type_name, FIELDS, #visitor_expr)
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
let all_skipped = fields
|
||||
.iter()
|
||||
.all(|field| field.attrs.skip_deserializing());
|
||||
let visitor_var = if all_skipped {
|
||||
quote!(_)
|
||||
} else {
|
||||
quote!(mut __seq)
|
||||
};
|
||||
|
||||
// untagged struct variants do not get a visit_seq method
|
||||
let visit_seq = match untagged {
|
||||
Untagged::Yes => None,
|
||||
Untagged::No => {
|
||||
Some(quote! {
|
||||
#[inline]
|
||||
fn visit_seq<__A>(self, #visitor_var: __A) -> _serde::export::Result<Self::Value, __A::Error>
|
||||
where __A: _serde::de::SeqAccess<#delife>
|
||||
{
|
||||
#visit_seq
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
if params.has_getter {
|
||||
None
|
||||
} else {
|
||||
let de_from_impl_generics = de_impl_generics.with_dest();
|
||||
let de_from_ty_generics = de_ty_generics.with_dest();
|
||||
let dest_life = dest_lifetime();
|
||||
|
||||
Some(quote_block! {
|
||||
#field_visitor
|
||||
|
||||
struct __Visitor #de_from_impl_generics #where_clause {
|
||||
dest: &#dest_life mut #this #ty_generics,
|
||||
lifetime: _serde::export::PhantomData<&#delife ()>,
|
||||
}
|
||||
|
||||
impl #de_from_impl_generics _serde::de::Visitor<#delife> for __Visitor #de_from_ty_generics #where_clause {
|
||||
type Value = ();
|
||||
|
||||
fn expecting(&self, formatter: &mut _serde::export::Formatter) -> _serde::export::fmt::Result {
|
||||
_serde::export::Formatter::write_str(formatter, #expecting)
|
||||
}
|
||||
|
||||
#visit_seq
|
||||
|
||||
#[inline]
|
||||
#[allow(unreachable_code)]
|
||||
fn visit_map<__A>(self, mut __map: __A) -> _serde::export::Result<Self::Value, __A::Error>
|
||||
where __A: _serde::de::MapAccess<#delife>
|
||||
{
|
||||
#visit_map
|
||||
}
|
||||
}
|
||||
|
||||
#fields_stmt
|
||||
|
||||
#dispatch
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn deserialize_enum(
|
||||
params: &Parameters,
|
||||
variants: &[Variant],
|
||||
@ -1740,6 +2119,176 @@ fn deserialize_map(
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "deserialize_from")]
|
||||
fn deserialize_from_struct_visitor(
|
||||
params: &Parameters,
|
||||
fields: &[Field],
|
||||
cattrs: &attr::Container,
|
||||
) -> (Fragment, Fragment, Fragment) {
|
||||
let field_names_idents: Vec<_> = fields
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|&(_, field)| !field.attrs.skip_deserializing())
|
||||
.map(|(i, field)| (field.attrs.name().deserialize_name(), field_i(i)),)
|
||||
.collect();
|
||||
|
||||
let fields_stmt = {
|
||||
let field_names = field_names_idents.iter().map(|&(ref name, _)| name);
|
||||
quote_block! {
|
||||
const FIELDS: &'static [&'static str] = &[ #(#field_names),* ];
|
||||
}
|
||||
};
|
||||
|
||||
let field_visitor = deserialize_generated_identifier(field_names_idents, cattrs, false);
|
||||
|
||||
let visit_map = deserialize_from_map(params, fields, cattrs);
|
||||
|
||||
(field_visitor, fields_stmt, visit_map)
|
||||
}
|
||||
|
||||
#[cfg(feature = "deserialize_from")]
|
||||
fn deserialize_from_map(
|
||||
params: &Parameters,
|
||||
fields: &[Field],
|
||||
cattrs: &attr::Container,
|
||||
) -> Fragment {
|
||||
// Create the field names for the fields.
|
||||
let fields_names: Vec<_> = fields
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, field)| (field, field_i(i)))
|
||||
.collect();
|
||||
|
||||
// For deserialize_from, declare booleans for each field that will be deserialized.
|
||||
let let_flags = fields_names
|
||||
.iter()
|
||||
.filter(|&&(field, _)| !field.attrs.skip_deserializing())
|
||||
.map(
|
||||
|&(_, ref name)| {
|
||||
quote! {
|
||||
let mut #name: bool = false;
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// Match arms to extract a value for a field.
|
||||
let value_arms_from = fields_names.iter()
|
||||
.filter(|&&(field, _)| !field.attrs.skip_deserializing())
|
||||
.map(|&(field, ref name)| {
|
||||
let deser_name = field.attrs.name().deserialize_name();
|
||||
let field_name = &field.ident;
|
||||
|
||||
let visit = match field.attrs.deserialize_with() {
|
||||
None => {
|
||||
quote! {
|
||||
try!(_serde::de::MapAccess::next_value_seed(&mut __map, _serde::private::de::DeserializeFromSeed(&mut self.dest.#field_name)))
|
||||
}
|
||||
}
|
||||
Some(path) => {
|
||||
let (wrapper, wrapper_ty) = wrap_deserialize_field_with(
|
||||
params, field.ty, path);
|
||||
quote!({
|
||||
#wrapper
|
||||
self.dest.#field_name = try!(_serde::de::MapAccess::next_value::<#wrapper_ty>(&mut __map)).value
|
||||
})
|
||||
}
|
||||
};
|
||||
quote! {
|
||||
__Field::#name => {
|
||||
if #name {
|
||||
return _serde::export::Err(<__A::Error as _serde::de::Error>::duplicate_field(#deser_name));
|
||||
}
|
||||
#visit;
|
||||
#name = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Visit ignored values to consume them
|
||||
let ignored_arm = if cattrs.deny_unknown_fields() {
|
||||
None
|
||||
} else {
|
||||
Some(quote! {
|
||||
_ => { let _ = try!(_serde::de::MapAccess::next_value::<_serde::de::IgnoredAny>(&mut __map)); }
|
||||
})
|
||||
};
|
||||
|
||||
let all_skipped = fields
|
||||
.iter()
|
||||
.all(|field| field.attrs.skip_deserializing());
|
||||
|
||||
let match_keys = if cattrs.deny_unknown_fields() && all_skipped {
|
||||
quote! {
|
||||
// FIXME: Once we drop support for Rust 1.15:
|
||||
// let _serde::export::None::<__Field> = try!(_serde::de::MapAccess::next_key(&mut __map));
|
||||
_serde::export::Option::map(
|
||||
try!(_serde::de::MapAccess::next_key::<__Field>(&mut __map)),
|
||||
|__impossible| match __impossible {});
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
while let _serde::export::Some(__key) = try!(_serde::de::MapAccess::next_key::<__Field>(&mut __map)) {
|
||||
match __key {
|
||||
#(#value_arms_from)*
|
||||
#ignored_arm
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let check_flags = fields_names
|
||||
.iter()
|
||||
.filter(|&&(field, _)| !field.attrs.skip_deserializing())
|
||||
.map(
|
||||
|&(field, ref name)| {
|
||||
let missing_expr = Expr(expr_is_missing(&field, cattrs));
|
||||
let field_name = &field.ident;
|
||||
quote! {
|
||||
if !#name {
|
||||
self.dest.#field_name = #missing_expr;
|
||||
};
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
let this = ¶ms.this;
|
||||
let (_, _, ty_generics, _) = split_with_de_lifetime(params,);
|
||||
|
||||
let let_default = match *cattrs.default() {
|
||||
attr::Default::Default => {
|
||||
Some(
|
||||
quote!(
|
||||
let __default: #this #ty_generics = _serde::export::Default::default();
|
||||
),
|
||||
)
|
||||
}
|
||||
attr::Default::Path(ref path) => {
|
||||
Some(
|
||||
quote!(
|
||||
let __default: #this #ty_generics = #path();
|
||||
),
|
||||
)
|
||||
}
|
||||
attr::Default::None => {
|
||||
// We don't need the default value, to prevent an unused variable warning
|
||||
// we'll leave the line empty.
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
quote_block! {
|
||||
#(#let_flags)*
|
||||
|
||||
#match_keys
|
||||
|
||||
#let_default
|
||||
|
||||
#(#check_flags)*
|
||||
|
||||
_serde::export::Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn field_i(i: usize) -> Ident {
|
||||
Ident::new(format!("__field{}", i))
|
||||
}
|
||||
@ -1878,6 +2427,8 @@ fn expr_is_missing(field: &Field, cattrs: &attr::Container) -> Fragment {
|
||||
}
|
||||
|
||||
struct DeImplGenerics<'a>(&'a Parameters);
|
||||
#[cfg(feature = "deserialize_from")]
|
||||
struct DeFromImplGenerics<'a>(&'a Parameters);
|
||||
|
||||
impl<'a> ToTokens for DeImplGenerics<'a> {
|
||||
fn to_tokens(&self, tokens: &mut Tokens) {
|
||||
@ -1890,7 +2441,38 @@ impl<'a> ToTokens for DeImplGenerics<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "deserialize_from")]
|
||||
impl<'a> ToTokens for DeFromImplGenerics<'a> {
|
||||
fn to_tokens(&self, tokens: &mut Tokens) {
|
||||
let dest_lifetime = dest_lifetime();
|
||||
let mut generics = self.0.generics.clone();
|
||||
|
||||
// Add lifetime for `&'dest mut Self, and `'a: 'dest`
|
||||
for lifetime in &mut generics.lifetimes {
|
||||
lifetime.bounds.push(dest_lifetime.lifetime.clone());
|
||||
}
|
||||
for generic in &mut generics.ty_params {
|
||||
generic.bounds.push(syn::TyParamBound::Region(dest_lifetime.lifetime.clone()));
|
||||
}
|
||||
generics.lifetimes.insert(0, dest_lifetime);
|
||||
if let Some(de_lifetime) = self.0.borrowed.de_lifetime_def() {
|
||||
generics.lifetimes.insert(0, de_lifetime);
|
||||
}
|
||||
let (impl_generics, _, _) = generics.split_for_impl();
|
||||
impl_generics.to_tokens(tokens);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "deserialize_from")]
|
||||
impl<'a> DeImplGenerics<'a> {
|
||||
fn with_dest(self) -> DeFromImplGenerics<'a> {
|
||||
DeFromImplGenerics(self.0)
|
||||
}
|
||||
}
|
||||
|
||||
struct DeTyGenerics<'a>(&'a Parameters);
|
||||
#[cfg(feature = "deserialize_from")]
|
||||
struct DeFromTyGenerics<'a>(&'a Parameters);
|
||||
|
||||
impl<'a> ToTokens for DeTyGenerics<'a> {
|
||||
fn to_tokens(&self, tokens: &mut Tokens) {
|
||||
@ -1905,6 +2487,34 @@ impl<'a> ToTokens for DeTyGenerics<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "deserialize_from")]
|
||||
impl<'a> ToTokens for DeFromTyGenerics<'a> {
|
||||
fn to_tokens(&self, tokens: &mut Tokens) {
|
||||
let mut generics = self.0.generics.clone();
|
||||
generics.lifetimes.insert(0, dest_lifetime());
|
||||
|
||||
if self.0.borrowed.de_lifetime_def().is_some() {
|
||||
generics
|
||||
.lifetimes
|
||||
.insert(0, syn::LifetimeDef::new("'de"));
|
||||
}
|
||||
let (_, ty_generics, _) = generics.split_for_impl();
|
||||
ty_generics.to_tokens(tokens);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "deserialize_from")]
|
||||
impl<'a> DeTyGenerics<'a> {
|
||||
fn with_dest(self) -> DeFromTyGenerics<'a> {
|
||||
DeFromTyGenerics(self.0)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "deserialize_from")]
|
||||
fn dest_lifetime() -> syn::LifetimeDef {
|
||||
syn::LifetimeDef::new("'dest")
|
||||
}
|
||||
|
||||
fn split_with_de_lifetime(params: &Parameters,)
|
||||
-> (DeImplGenerics, DeTyGenerics, syn::TyGenerics, &syn::WhereClause) {
|
||||
let de_impl_generics = DeImplGenerics(¶ms);
|
||||
|
Loading…
x
Reference in New Issue
Block a user