diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
commit | 26a029d407be480d791972afb5975cf62c9360a6 (patch) | |
tree | f435a8308119effd964b339f76abb83a57c29483 /third_party/rust/serde_derive/src | |
parent | Initial commit. (diff) | |
download | firefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz firefox-26a029d407be480d791972afb5975cf62c9360a6.zip |
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/serde_derive/src')
17 files changed, 8578 insertions, 0 deletions
diff --git a/third_party/rust/serde_derive/src/bound.rs b/third_party/rust/serde_derive/src/bound.rs new file mode 100644 index 0000000000..fe8ccfff5b --- /dev/null +++ b/third_party/rust/serde_derive/src/bound.rs @@ -0,0 +1,408 @@ +use crate::internals::ast::{Container, Data}; +use crate::internals::{attr, ungroup}; +use proc_macro2::Span; +use std::collections::HashSet; +use syn::punctuated::{Pair, Punctuated}; +use syn::Token; + +// Remove the default from every type parameter because in the generated impls +// they look like associated types: "error: associated type bindings are not +// allowed here". +pub fn without_defaults(generics: &syn::Generics) -> syn::Generics { + syn::Generics { + params: generics + .params + .iter() + .map(|param| match param { + syn::GenericParam::Type(param) => syn::GenericParam::Type(syn::TypeParam { + eq_token: None, + default: None, + ..param.clone() + }), + _ => param.clone(), + }) + .collect(), + ..generics.clone() + } +} + +pub fn with_where_predicates( + generics: &syn::Generics, + predicates: &[syn::WherePredicate], +) -> syn::Generics { + let mut generics = generics.clone(); + generics + .make_where_clause() + .predicates + .extend(predicates.iter().cloned()); + generics +} + +pub fn with_where_predicates_from_fields( + cont: &Container, + generics: &syn::Generics, + from_field: fn(&attr::Field) -> Option<&[syn::WherePredicate]>, +) -> syn::Generics { + let predicates = cont + .data + .all_fields() + .filter_map(|field| from_field(&field.attrs)) + .flat_map(<[syn::WherePredicate]>::to_vec); + + let mut generics = generics.clone(); + generics.make_where_clause().predicates.extend(predicates); + generics +} + +pub fn with_where_predicates_from_variants( + cont: &Container, + generics: &syn::Generics, + from_variant: fn(&attr::Variant) -> Option<&[syn::WherePredicate]>, +) -> syn::Generics { + let variants = match &cont.data { + Data::Enum(variants) => variants, + Data::Struct(_, _) => { + return generics.clone(); + } + }; + + let predicates = variants + .iter() + .filter_map(|variant| from_variant(&variant.attrs)) + .flat_map(<[syn::WherePredicate]>::to_vec); + + let mut generics = generics.clone(); + generics.make_where_clause().predicates.extend(predicates); + generics +} + +// Puts the given bound on any generic type parameters that are used in fields +// for which filter returns true. +// +// For example, the following struct needs the bound `A: Serialize, B: +// Serialize`. +// +// struct S<'b, A, B: 'b, C> { +// a: A, +// b: Option<&'b B> +// #[serde(skip_serializing)] +// c: C, +// } +pub fn with_bound( + cont: &Container, + generics: &syn::Generics, + filter: fn(&attr::Field, Option<&attr::Variant>) -> bool, + bound: &syn::Path, +) -> syn::Generics { + struct FindTyParams<'ast> { + // Set of all generic type parameters on the current struct (A, B, C in + // the example). Initialized up front. + all_type_params: HashSet<syn::Ident>, + + // Set of generic type parameters used in fields for which filter + // returns true (A and B in the example). Filled in as the visitor sees + // them. + relevant_type_params: HashSet<syn::Ident>, + + // Fields whose type is an associated type of one of the generic type + // parameters. + associated_type_usage: Vec<&'ast syn::TypePath>, + } + + impl<'ast> FindTyParams<'ast> { + fn visit_field(&mut self, field: &'ast syn::Field) { + if let syn::Type::Path(ty) = ungroup(&field.ty) { + if let Some(Pair::Punctuated(t, _)) = ty.path.segments.pairs().next() { + if self.all_type_params.contains(&t.ident) { + self.associated_type_usage.push(ty); + } + } + } + self.visit_type(&field.ty); + } + + fn visit_path(&mut self, path: &'ast syn::Path) { + if let Some(seg) = path.segments.last() { + if seg.ident == "PhantomData" { + // Hardcoded exception, because PhantomData<T> implements + // Serialize and Deserialize whether or not T implements it. + return; + } + } + if path.leading_colon.is_none() && path.segments.len() == 1 { + let id = &path.segments[0].ident; + if self.all_type_params.contains(id) { + self.relevant_type_params.insert(id.clone()); + } + } + for segment in &path.segments { + self.visit_path_segment(segment); + } + } + + // Everything below is simply traversing the syntax tree. + + fn visit_type(&mut self, ty: &'ast syn::Type) { + match ty { + #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] + syn::Type::Array(ty) => self.visit_type(&ty.elem), + syn::Type::BareFn(ty) => { + for arg in &ty.inputs { + self.visit_type(&arg.ty); + } + self.visit_return_type(&ty.output); + } + syn::Type::Group(ty) => self.visit_type(&ty.elem), + syn::Type::ImplTrait(ty) => { + for bound in &ty.bounds { + self.visit_type_param_bound(bound); + } + } + syn::Type::Macro(ty) => self.visit_macro(&ty.mac), + syn::Type::Paren(ty) => self.visit_type(&ty.elem), + syn::Type::Path(ty) => { + if let Some(qself) = &ty.qself { + self.visit_type(&qself.ty); + } + self.visit_path(&ty.path); + } + syn::Type::Ptr(ty) => self.visit_type(&ty.elem), + syn::Type::Reference(ty) => self.visit_type(&ty.elem), + syn::Type::Slice(ty) => self.visit_type(&ty.elem), + syn::Type::TraitObject(ty) => { + for bound in &ty.bounds { + self.visit_type_param_bound(bound); + } + } + syn::Type::Tuple(ty) => { + for elem in &ty.elems { + self.visit_type(elem); + } + } + + syn::Type::Infer(_) | syn::Type::Never(_) | syn::Type::Verbatim(_) => {} + + _ => {} + } + } + + fn visit_path_segment(&mut self, segment: &'ast syn::PathSegment) { + self.visit_path_arguments(&segment.arguments); + } + + fn visit_path_arguments(&mut self, arguments: &'ast syn::PathArguments) { + match arguments { + syn::PathArguments::None => {} + syn::PathArguments::AngleBracketed(arguments) => { + for arg in &arguments.args { + match arg { + #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] + syn::GenericArgument::Type(arg) => self.visit_type(arg), + syn::GenericArgument::AssocType(arg) => self.visit_type(&arg.ty), + syn::GenericArgument::Lifetime(_) + | syn::GenericArgument::Const(_) + | syn::GenericArgument::AssocConst(_) + | syn::GenericArgument::Constraint(_) => {} + _ => {} + } + } + } + syn::PathArguments::Parenthesized(arguments) => { + for argument in &arguments.inputs { + self.visit_type(argument); + } + self.visit_return_type(&arguments.output); + } + } + } + + fn visit_return_type(&mut self, return_type: &'ast syn::ReturnType) { + match return_type { + syn::ReturnType::Default => {} + syn::ReturnType::Type(_, output) => self.visit_type(output), + } + } + + fn visit_type_param_bound(&mut self, bound: &'ast syn::TypeParamBound) { + match bound { + #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] + syn::TypeParamBound::Trait(bound) => self.visit_path(&bound.path), + syn::TypeParamBound::Lifetime(_) | syn::TypeParamBound::Verbatim(_) => {} + _ => {} + } + } + + // Type parameter should not be considered used by a macro path. + // + // struct TypeMacro<T> { + // mac: T!(), + // marker: PhantomData<T>, + // } + fn visit_macro(&mut self, _mac: &'ast syn::Macro) {} + } + + let all_type_params = generics + .type_params() + .map(|param| param.ident.clone()) + .collect(); + + let mut visitor = FindTyParams { + all_type_params, + relevant_type_params: HashSet::new(), + associated_type_usage: Vec::new(), + }; + match &cont.data { + Data::Enum(variants) => { + for variant in variants { + let relevant_fields = variant + .fields + .iter() + .filter(|field| filter(&field.attrs, Some(&variant.attrs))); + for field in relevant_fields { + visitor.visit_field(field.original); + } + } + } + Data::Struct(_, fields) => { + for field in fields.iter().filter(|field| filter(&field.attrs, None)) { + visitor.visit_field(field.original); + } + } + } + + let relevant_type_params = visitor.relevant_type_params; + let associated_type_usage = visitor.associated_type_usage; + let new_predicates = generics + .type_params() + .map(|param| param.ident.clone()) + .filter(|id| relevant_type_params.contains(id)) + .map(|id| syn::TypePath { + qself: None, + path: id.into(), + }) + .chain(associated_type_usage.into_iter().cloned()) + .map(|bounded_ty| { + syn::WherePredicate::Type(syn::PredicateType { + lifetimes: None, + // the type parameter that is being bounded e.g. T + bounded_ty: syn::Type::Path(bounded_ty), + colon_token: <Token![:]>::default(), + // the bound e.g. Serialize + bounds: vec![syn::TypeParamBound::Trait(syn::TraitBound { + paren_token: None, + modifier: syn::TraitBoundModifier::None, + lifetimes: None, + path: bound.clone(), + })] + .into_iter() + .collect(), + }) + }); + + let mut generics = generics.clone(); + generics + .make_where_clause() + .predicates + .extend(new_predicates); + generics +} + +pub fn with_self_bound( + cont: &Container, + generics: &syn::Generics, + bound: &syn::Path, +) -> syn::Generics { + let mut generics = generics.clone(); + generics + .make_where_clause() + .predicates + .push(syn::WherePredicate::Type(syn::PredicateType { + lifetimes: None, + // the type that is being bounded e.g. MyStruct<'a, T> + bounded_ty: type_of_item(cont), + colon_token: <Token![:]>::default(), + // the bound e.g. Default + bounds: vec![syn::TypeParamBound::Trait(syn::TraitBound { + paren_token: None, + modifier: syn::TraitBoundModifier::None, + lifetimes: None, + path: bound.clone(), + })] + .into_iter() + .collect(), + })); + generics +} + +pub fn with_lifetime_bound(generics: &syn::Generics, lifetime: &str) -> syn::Generics { + let bound = syn::Lifetime::new(lifetime, Span::call_site()); + let def = syn::LifetimeParam { + attrs: Vec::new(), + lifetime: bound.clone(), + colon_token: None, + bounds: Punctuated::new(), + }; + + let params = Some(syn::GenericParam::Lifetime(def)) + .into_iter() + .chain(generics.params.iter().cloned().map(|mut param| { + match &mut param { + syn::GenericParam::Lifetime(param) => { + param.bounds.push(bound.clone()); + } + syn::GenericParam::Type(param) => { + param + .bounds + .push(syn::TypeParamBound::Lifetime(bound.clone())); + } + syn::GenericParam::Const(_) => {} + } + param + })) + .collect(); + + syn::Generics { + params, + ..generics.clone() + } +} + +fn type_of_item(cont: &Container) -> syn::Type { + syn::Type::Path(syn::TypePath { + qself: None, + path: syn::Path { + leading_colon: None, + segments: vec![syn::PathSegment { + ident: cont.ident.clone(), + arguments: syn::PathArguments::AngleBracketed( + syn::AngleBracketedGenericArguments { + colon2_token: None, + lt_token: <Token![<]>::default(), + args: cont + .generics + .params + .iter() + .map(|param| match param { + syn::GenericParam::Type(param) => { + syn::GenericArgument::Type(syn::Type::Path(syn::TypePath { + qself: None, + path: param.ident.clone().into(), + })) + } + syn::GenericParam::Lifetime(param) => { + syn::GenericArgument::Lifetime(param.lifetime.clone()) + } + syn::GenericParam::Const(_) => { + panic!("Serde does not support const generics yet"); + } + }) + .collect(), + gt_token: <Token![>]>::default(), + }, + ), + }] + .into_iter() + .collect(), + }, + }) +} diff --git a/third_party/rust/serde_derive/src/de.rs b/third_party/rust/serde_derive/src/de.rs new file mode 100644 index 0000000000..e3b737c61c --- /dev/null +++ b/third_party/rust/serde_derive/src/de.rs @@ -0,0 +1,3148 @@ +use crate::fragment::{Expr, Fragment, Match, Stmts}; +use crate::internals::ast::{Container, Data, Field, Style, Variant}; +use crate::internals::{attr, replace_receiver, ungroup, Ctxt, Derive}; +use crate::{bound, dummy, pretend, this}; +use proc_macro2::{Literal, Span, TokenStream}; +use quote::{quote, quote_spanned, ToTokens}; +use std::collections::BTreeSet; +use std::ptr; +use syn::punctuated::Punctuated; +use syn::spanned::Spanned; +use syn::{parse_quote, Ident, Index, Member}; + +pub fn expand_derive_deserialize(input: &mut syn::DeriveInput) -> syn::Result<TokenStream> { + replace_receiver(input); + + let ctxt = Ctxt::new(); + let cont = match Container::from_ast(&ctxt, input, Derive::Deserialize) { + Some(cont) => cont, + None => return Err(ctxt.check().unwrap_err()), + }; + precondition(&ctxt, &cont); + ctxt.check()?; + + let ident = &cont.ident; + let params = Parameters::new(&cont); + let (de_impl_generics, _, ty_generics, where_clause) = split_with_de_lifetime(¶ms); + let body = Stmts(deserialize_body(&cont, ¶ms)); + let delife = params.borrowed.de_lifetime(); + let serde = cont.attrs.serde_path(); + + let impl_block = if let Some(remote) = cont.attrs.remote() { + let vis = &input.vis; + let used = pretend::pretend_used(&cont, params.is_packed); + quote! { + impl #de_impl_generics #ident #ty_generics #where_clause { + #vis fn deserialize<__D>(__deserializer: __D) -> #serde::__private::Result<#remote #ty_generics, __D::Error> + where + __D: #serde::Deserializer<#delife>, + { + #used + #body + } + } + } + } else { + let fn_deserialize_in_place = deserialize_in_place_body(&cont, ¶ms); + + quote! { + #[automatically_derived] + impl #de_impl_generics #serde::Deserialize<#delife> for #ident #ty_generics #where_clause { + fn deserialize<__D>(__deserializer: __D) -> #serde::__private::Result<Self, __D::Error> + where + __D: #serde::Deserializer<#delife>, + { + #body + } + + #fn_deserialize_in_place + } + } + }; + + Ok(dummy::wrap_in_const( + cont.attrs.custom_serde_path(), + impl_block, + )) +} + +fn precondition(cx: &Ctxt, cont: &Container) { + precondition_sized(cx, cont); + precondition_no_de_lifetime(cx, cont); +} + +fn precondition_sized(cx: &Ctxt, cont: &Container) { + if let Data::Struct(_, fields) = &cont.data { + if let Some(last) = fields.last() { + if let syn::Type::Slice(_) = ungroup(last.ty) { + cx.error_spanned_by( + cont.original, + "cannot deserialize a dynamically sized struct", + ); + } + } + } +} + +fn precondition_no_de_lifetime(cx: &Ctxt, cont: &Container) { + if let BorrowedLifetimes::Borrowed(_) = borrowed_lifetimes(cont) { + for param in cont.generics.lifetimes() { + if param.lifetime.to_string() == "'de" { + cx.error_spanned_by( + ¶m.lifetime, + "cannot deserialize when there is a lifetime parameter called 'de", + ); + return; + } + } + } +} + +struct Parameters { + /// Name of the type the `derive` is on. + local: syn::Ident, + + /// Path to the type the impl is for. Either a single `Ident` for local + /// types (does not include generic parameters) or `some::remote::Path` for + /// remote types. + this_type: syn::Path, + + /// Same as `this_type` but using `::<T>` for generic parameters for use in + /// expression position. + this_value: syn::Path, + + /// Generics including any explicit and inferred bounds for the impl. + generics: syn::Generics, + + /// Lifetimes borrowed from the deserializer. These will become bounds on + /// the `'de` lifetime of the deserializer. + borrowed: BorrowedLifetimes, + + /// At least one field has a serde(getter) attribute, implying that the + /// remote type has a private field. + has_getter: bool, + + /// Type has a repr(packed) attribute. + is_packed: bool, +} + +impl Parameters { + fn new(cont: &Container) -> Self { + let local = cont.ident.clone(); + let this_type = this::this_type(cont); + let this_value = this::this_value(cont); + let borrowed = borrowed_lifetimes(cont); + let generics = build_generics(cont, &borrowed); + let has_getter = cont.data.has_getter(); + let is_packed = cont.attrs.is_packed(); + + Parameters { + local, + this_type, + this_value, + generics, + borrowed, + has_getter, + is_packed, + } + } + + /// Type name to use in error messages and `&'static str` arguments to + /// various Deserializer methods. + fn type_name(&self) -> String { + self.this_type.segments.last().unwrap().ident.to_string() + } +} + +// All the generics in the input, plus a bound `T: Deserialize` for each generic +// field type that will be deserialized by us, plus a bound `T: Default` for +// each generic field type that will be set to a default value. +fn build_generics(cont: &Container, borrowed: &BorrowedLifetimes) -> syn::Generics { + let generics = bound::without_defaults(cont.generics); + + let generics = bound::with_where_predicates_from_fields(cont, &generics, attr::Field::de_bound); + + let generics = + bound::with_where_predicates_from_variants(cont, &generics, attr::Variant::de_bound); + + match cont.attrs.de_bound() { + Some(predicates) => bound::with_where_predicates(&generics, predicates), + None => { + let generics = match *cont.attrs.default() { + attr::Default::Default => bound::with_self_bound( + cont, + &generics, + &parse_quote!(_serde::__private::Default), + ), + attr::Default::None | attr::Default::Path(_) => generics, + }; + + let delife = borrowed.de_lifetime(); + let generics = bound::with_bound( + cont, + &generics, + needs_deserialize_bound, + &parse_quote!(_serde::Deserialize<#delife>), + ); + + bound::with_bound( + cont, + &generics, + requires_default, + &parse_quote!(_serde::__private::Default), + ) + } + } +} + +// Fields with a `skip_deserializing` or `deserialize_with` attribute, or which +// belong to a variant with a `skip_deserializing` or `deserialize_with` +// attribute, are not 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 may need a `T: Deserialize` bound where T is the type of the +// field. +fn needs_deserialize_bound(field: &attr::Field, variant: Option<&attr::Variant>) -> bool { + !field.skip_deserializing() + && field.deserialize_with().is_none() + && field.de_bound().is_none() + && variant.map_or(true, |variant| { + !variant.skip_deserializing() + && variant.deserialize_with().is_none() + && variant.de_bound().is_none() + }) +} + +// Fields with a `default` attribute (not `default=...`), and fields with a +// `skip_deserializing` attribute that do not also have `default=...`. +fn requires_default(field: &attr::Field, _variant: Option<&attr::Variant>) -> bool { + if let attr::Default::Default = *field.default() { + true + } else { + false + } +} + +enum BorrowedLifetimes { + Borrowed(BTreeSet<syn::Lifetime>), + Static, +} + +impl BorrowedLifetimes { + fn de_lifetime(&self) -> syn::Lifetime { + match *self { + BorrowedLifetimes::Borrowed(_) => syn::Lifetime::new("'de", Span::call_site()), + BorrowedLifetimes::Static => syn::Lifetime::new("'static", Span::call_site()), + } + } + + fn de_lifetime_param(&self) -> Option<syn::LifetimeParam> { + match self { + BorrowedLifetimes::Borrowed(bounds) => Some(syn::LifetimeParam { + attrs: Vec::new(), + lifetime: syn::Lifetime::new("'de", Span::call_site()), + colon_token: None, + bounds: bounds.iter().cloned().collect(), + }), + BorrowedLifetimes::Static => None, + } + } +} + +// The union of lifetimes borrowed by each field of the container. +// +// These turn into bounds on the `'de` lifetime of the Deserialize impl. If +// lifetimes `'a` and `'b` are borrowed but `'c` is not, the impl is: +// +// impl<'de: 'a + 'b, 'a, 'b, 'c> Deserialize<'de> for S<'a, 'b, 'c> +// +// If any borrowed lifetime is `'static`, then `'de: 'static` would be redundant +// and we use plain `'static` instead of `'de`. +fn borrowed_lifetimes(cont: &Container) -> BorrowedLifetimes { + let mut lifetimes = BTreeSet::new(); + for field in cont.data.all_fields() { + if !field.attrs.skip_deserializing() { + lifetimes.extend(field.attrs.borrowed_lifetimes().iter().cloned()); + } + } + if lifetimes.iter().any(|b| b.to_string() == "'static") { + BorrowedLifetimes::Static + } else { + BorrowedLifetimes::Borrowed(lifetimes) + } +} + +fn deserialize_body(cont: &Container, params: &Parameters) -> Fragment { + if cont.attrs.transparent() { + deserialize_transparent(cont, params) + } else if let Some(type_from) = cont.attrs.type_from() { + deserialize_from(type_from) + } else if let Some(type_try_from) = cont.attrs.type_try_from() { + deserialize_try_from(type_try_from) + } else if let attr::Identifier::No = cont.attrs.identifier() { + match &cont.data { + Data::Enum(variants) => deserialize_enum(params, variants, &cont.attrs), + Data::Struct(Style::Struct, fields) => { + deserialize_struct(params, fields, &cont.attrs, StructForm::Struct) + } + Data::Struct(Style::Tuple, fields) | Data::Struct(Style::Newtype, fields) => { + deserialize_tuple(params, fields, &cont.attrs, TupleForm::Tuple) + } + Data::Struct(Style::Unit, _) => deserialize_unit_struct(params, &cont.attrs), + } + } else { + match &cont.data { + Data::Enum(variants) => deserialize_custom_identifier(params, variants, &cont.attrs), + Data::Struct(_, _) => unreachable!("checked in serde_derive_internals"), + } + } +} + +#[cfg(feature = "deserialize_in_place")] +fn deserialize_in_place_body(cont: &Container, params: &Parameters) -> Option<Stmts> { + // Only remote derives have getters, and we do not generate + // deserialize_in_place for remote derives. + assert!(!params.has_getter); + + if cont.attrs.transparent() + || cont.attrs.type_from().is_some() + || cont.attrs.type_try_from().is_some() + || cont.attrs.identifier().is_some() + || cont + .data + .all_fields() + .all(|f| f.attrs.deserialize_with().is_some()) + { + return None; + } + + let code = match &cont.data { + Data::Struct(Style::Struct, fields) => { + deserialize_struct_in_place(params, fields, &cont.attrs)? + } + Data::Struct(Style::Tuple, fields) | Data::Struct(Style::Newtype, fields) => { + deserialize_tuple_in_place(params, fields, &cont.attrs) + } + Data::Enum(_) | Data::Struct(Style::Unit, _) => { + return None; + } + }; + + let delife = params.borrowed.de_lifetime(); + let stmts = Stmts(code); + + let fn_deserialize_in_place = quote_block! { + fn deserialize_in_place<__D>(__deserializer: __D, __place: &mut Self) -> _serde::__private::Result<(), __D::Error> + where + __D: _serde::Deserializer<#delife>, + { + #stmts + } + }; + + Some(Stmts(fn_deserialize_in_place)) +} + +#[cfg(not(feature = "deserialize_in_place"))] +fn deserialize_in_place_body(_cont: &Container, _params: &Parameters) -> Option<Stmts> { + None +} + +fn deserialize_transparent(cont: &Container, params: &Parameters) -> Fragment { + let fields = match &cont.data { + Data::Struct(_, fields) => fields, + Data::Enum(_) => unreachable!(), + }; + + let this_value = ¶ms.this_value; + let transparent_field = fields.iter().find(|f| f.attrs.transparent()).unwrap(); + + let path = match transparent_field.attrs.deserialize_with() { + Some(path) => quote!(#path), + None => { + let span = transparent_field.original.span(); + quote_spanned!(span=> _serde::Deserialize::deserialize) + } + }; + + let assign = fields.iter().map(|field| { + let member = &field.member; + if ptr::eq(field, transparent_field) { + quote!(#member: __transparent) + } else { + let value = match field.attrs.default() { + attr::Default::Default => quote!(_serde::__private::Default::default()), + attr::Default::Path(path) => quote!(#path()), + attr::Default::None => quote!(_serde::__private::PhantomData), + }; + quote!(#member: #value) + } + }); + + quote_block! { + _serde::__private::Result::map( + #path(__deserializer), + |__transparent| #this_value { #(#assign),* }) + } +} + +fn deserialize_from(type_from: &syn::Type) -> Fragment { + quote_block! { + _serde::__private::Result::map( + <#type_from as _serde::Deserialize>::deserialize(__deserializer), + _serde::__private::From::from) + } +} + +fn deserialize_try_from(type_try_from: &syn::Type) -> Fragment { + quote_block! { + _serde::__private::Result::and_then( + <#type_try_from as _serde::Deserialize>::deserialize(__deserializer), + |v| _serde::__private::TryFrom::try_from(v).map_err(_serde::de::Error::custom)) + } +} + +fn deserialize_unit_struct(params: &Parameters, cattrs: &attr::Container) -> Fragment { + let this_type = ¶ms.this_type; + let this_value = ¶ms.this_value; + let type_name = cattrs.name().deserialize_name(); + let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = + split_with_de_lifetime(params); + let delife = params.borrowed.de_lifetime(); + + let expecting = format!("unit struct {}", params.type_name()); + let expecting = cattrs.expecting().unwrap_or(&expecting); + + quote_block! { + #[doc(hidden)] + struct __Visitor #de_impl_generics #where_clause { + marker: _serde::__private::PhantomData<#this_type #ty_generics>, + lifetime: _serde::__private::PhantomData<&#delife ()>, + } + + impl #de_impl_generics _serde::de::Visitor<#delife> for __Visitor #de_ty_generics #where_clause { + type Value = #this_type #ty_generics; + + fn expecting(&self, __formatter: &mut _serde::__private::Formatter) -> _serde::__private::fmt::Result { + _serde::__private::Formatter::write_str(__formatter, #expecting) + } + + #[inline] + fn visit_unit<__E>(self) -> _serde::__private::Result<Self::Value, __E> + where + __E: _serde::de::Error, + { + _serde::__private::Ok(#this_value) + } + } + + _serde::Deserializer::deserialize_unit_struct( + __deserializer, + #type_name, + __Visitor { + marker: _serde::__private::PhantomData::<#this_type #ty_generics>, + lifetime: _serde::__private::PhantomData, + }, + ) + } +} + +enum TupleForm<'a> { + Tuple, + /// Contains a variant name + ExternallyTagged(&'a syn::Ident), + /// Contains a variant name and an intermediate deserializer from which actual + /// deserialization will be performed + Untagged(&'a syn::Ident, TokenStream), +} + +fn deserialize_tuple( + params: &Parameters, + fields: &[Field], + cattrs: &attr::Container, + form: TupleForm, +) -> Fragment { + assert!(!cattrs.has_flatten()); + + let field_count = fields + .iter() + .filter(|field| !field.attrs.skip_deserializing()) + .count(); + + let this_type = ¶ms.this_type; + let this_value = ¶ms.this_value; + 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_value) + }; + + let type_path = match form { + TupleForm::Tuple => construct, + TupleForm::ExternallyTagged(variant_ident) | TupleForm::Untagged(variant_ident, _) => { + quote!(#construct::#variant_ident) + } + }; + let expecting = match form { + TupleForm::Tuple => format!("tuple struct {}", params.type_name()), + TupleForm::ExternallyTagged(variant_ident) | TupleForm::Untagged(variant_ident, _) => { + format!("tuple variant {}::{}", params.type_name(), variant_ident) + } + }; + let expecting = cattrs.expecting().unwrap_or(&expecting); + + let nfields = fields.len(); + + let visit_newtype_struct = match form { + TupleForm::Tuple if nfields == 1 => { + Some(deserialize_newtype_struct(&type_path, params, &fields[0])) + } + _ => None, + }; + + let visit_seq = Stmts(deserialize_seq( + &type_path, params, fields, false, cattrs, expecting, + )); + + let visitor_expr = quote! { + __Visitor { + marker: _serde::__private::PhantomData::<#this_type #ty_generics>, + lifetime: _serde::__private::PhantomData, + } + }; + let dispatch = match form { + TupleForm::Tuple if nfields == 1 => { + let type_name = cattrs.name().deserialize_name(); + quote! { + _serde::Deserializer::deserialize_newtype_struct(__deserializer, #type_name, #visitor_expr) + } + } + TupleForm::Tuple => { + let type_name = cattrs.name().deserialize_name(); + quote! { + _serde::Deserializer::deserialize_tuple_struct(__deserializer, #type_name, #field_count, #visitor_expr) + } + } + TupleForm::ExternallyTagged(_) => quote! { + _serde::de::VariantAccess::tuple_variant(__variant, #field_count, #visitor_expr) + }, + TupleForm::Untagged(_, deserializer) => quote! { + _serde::Deserializer::deserialize_tuple(#deserializer, #field_count, #visitor_expr) + }, + }; + + let visitor_var = if field_count == 0 { + quote!(_) + } else { + quote!(mut __seq) + }; + + quote_block! { + #[doc(hidden)] + struct __Visitor #de_impl_generics #where_clause { + marker: _serde::__private::PhantomData<#this_type #ty_generics>, + lifetime: _serde::__private::PhantomData<&#delife ()>, + } + + impl #de_impl_generics _serde::de::Visitor<#delife> for __Visitor #de_ty_generics #where_clause { + type Value = #this_type #ty_generics; + + fn expecting(&self, __formatter: &mut _serde::__private::Formatter) -> _serde::__private::fmt::Result { + _serde::__private::Formatter::write_str(__formatter, #expecting) + } + + #visit_newtype_struct + + #[inline] + fn visit_seq<__A>(self, #visitor_var: __A) -> _serde::__private::Result<Self::Value, __A::Error> + where + __A: _serde::de::SeqAccess<#delife>, + { + #visit_seq + } + } + + #dispatch + } +} + +#[cfg(feature = "deserialize_in_place")] +fn deserialize_tuple_in_place( + params: &Parameters, + fields: &[Field], + cattrs: &attr::Container, +) -> Fragment { + assert!(!cattrs.has_flatten()); + + let field_count = fields + .iter() + .filter(|field| !field.attrs.skip_deserializing()) + .count(); + + let this_type = ¶ms.this_type; + let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = + split_with_de_lifetime(params); + let delife = params.borrowed.de_lifetime(); + + let expecting = format!("tuple struct {}", params.type_name()); + let expecting = cattrs.expecting().unwrap_or(&expecting); + + let nfields = fields.len(); + + let visit_newtype_struct = if nfields == 1 { + // We do not generate deserialize_in_place if every field has a + // deserialize_with. + assert!(fields[0].attrs.deserialize_with().is_none()); + + Some(quote! { + #[inline] + fn visit_newtype_struct<__E>(self, __e: __E) -> _serde::__private::Result<Self::Value, __E::Error> + where + __E: _serde::Deserializer<#delife>, + { + _serde::Deserialize::deserialize_in_place(__e, &mut self.place.0) + } + }) + } else { + None + }; + + let visit_seq = Stmts(deserialize_seq_in_place(params, fields, cattrs, expecting)); + + let visitor_expr = quote! { + __Visitor { + place: __place, + lifetime: _serde::__private::PhantomData, + } + }; + + let type_name = cattrs.name().deserialize_name(); + let dispatch = if nfields == 1 { + quote!(_serde::Deserializer::deserialize_newtype_struct(__deserializer, #type_name, #visitor_expr)) + } else { + quote!(_serde::Deserializer::deserialize_tuple_struct(__deserializer, #type_name, #field_count, #visitor_expr)) + }; + + let visitor_var = if field_count == 0 { + quote!(_) + } else { + quote!(mut __seq) + }; + + let in_place_impl_generics = de_impl_generics.in_place(); + let in_place_ty_generics = de_ty_generics.in_place(); + let place_life = place_lifetime(); + + quote_block! { + #[doc(hidden)] + struct __Visitor #in_place_impl_generics #where_clause { + place: &#place_life mut #this_type #ty_generics, + lifetime: _serde::__private::PhantomData<&#delife ()>, + } + + impl #in_place_impl_generics _serde::de::Visitor<#delife> for __Visitor #in_place_ty_generics #where_clause { + type Value = (); + + fn expecting(&self, __formatter: &mut _serde::__private::Formatter) -> _serde::__private::fmt::Result { + _serde::__private::Formatter::write_str(__formatter, #expecting) + } + + #visit_newtype_struct + + #[inline] + fn visit_seq<__A>(self, #visitor_var: __A) -> _serde::__private::Result<Self::Value, __A::Error> + where + __A: _serde::de::SeqAccess<#delife>, + { + #visit_seq + } + } + + #dispatch + } +} + +fn deserialize_seq( + type_path: &TokenStream, + params: &Parameters, + fields: &[Field], + is_struct: bool, + cattrs: &attr::Container, + expecting: &str, +) -> 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 = if deserialized_count == 1 { + format!("{} with 1 element", expecting) + } else { + format!("{} with {} elements", expecting, deserialized_count) + }; + let expecting = cattrs.expecting().unwrap_or(&expecting); + + let mut index_in_seq = 0_usize; + let let_values = vars.clone().zip(fields).map(|(var, field)| { + if field.attrs.skip_deserializing() { + let default = Expr(expr_is_missing(field, cattrs)); + quote! { + let #var = #default; + } + } else { + let visit = match field.attrs.deserialize_with() { + None => { + let field_ty = field.ty; + let span = field.original.span(); + let func = + quote_spanned!(span=> _serde::de::SeqAccess::next_element::<#field_ty>); + quote!(#func(&mut __seq)?) + } + Some(path) => { + let (wrapper, wrapper_ty) = wrap_deserialize_field_with(params, field.ty, path); + quote!({ + #wrapper + _serde::__private::Option::map( + _serde::de::SeqAccess::next_element::<#wrapper_ty>(&mut __seq)?, + |__wrap| __wrap.value) + }) + } + }; + let value_if_none = expr_is_missing_seq(None, index_in_seq, field, cattrs, expecting); + let assign = quote! { + let #var = match #visit { + _serde::__private::Some(__value) => __value, + _serde::__private::None => #value_if_none, + }; + }; + index_in_seq += 1; + assign + } + }); + + let mut result = if is_struct { + let names = fields.iter().map(|f| &f.member); + quote! { + #type_path { #( #names: #vars ),* } + } + } else { + quote! { + #type_path ( #(#vars),* ) + } + }; + + if params.has_getter { + let this_type = ¶ms.this_type; + let (_, ty_generics, _) = params.generics.split_for_impl(); + result = quote! { + _serde::__private::Into::<#this_type #ty_generics>::into(#result) + }; + } + + let let_default = match cattrs.default() { + attr::Default::Default => Some(quote!( + let __default: Self::Value = _serde::__private::Default::default(); + )), + attr::Default::Path(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'll leave the line empty. + None + } + }; + + quote_block! { + #let_default + #(#let_values)* + _serde::__private::Ok(#result) + } +} + +#[cfg(feature = "deserialize_in_place")] +fn deserialize_seq_in_place( + params: &Parameters, + fields: &[Field], + cattrs: &attr::Container, + expecting: &str, +) -> Fragment { + let deserialized_count = fields + .iter() + .filter(|field| !field.attrs.skip_deserializing()) + .count(); + let expecting = if deserialized_count == 1 { + format!("{} with 1 element", expecting) + } else { + format!("{} with {} elements", expecting, deserialized_count) + }; + let expecting = cattrs.expecting().unwrap_or(&expecting); + + let mut index_in_seq = 0usize; + let write_values = fields.iter().map(|field| { + let member = &field.member; + + if field.attrs.skip_deserializing() { + let default = Expr(expr_is_missing(field, cattrs)); + quote! { + self.place.#member = #default; + } + } else { + let value_if_none = expr_is_missing_seq(Some(quote!(self.place.#member = )), index_in_seq, field, cattrs, expecting); + let write = match field.attrs.deserialize_with() { + None => { + quote! { + if let _serde::__private::None = _serde::de::SeqAccess::next_element_seed(&mut __seq, + _serde::__private::de::InPlaceSeed(&mut self.place.#member))? + { + #value_if_none; + } + } + } + Some(path) => { + let (wrapper, wrapper_ty) = wrap_deserialize_field_with(params, field.ty, path); + quote!({ + #wrapper + match _serde::de::SeqAccess::next_element::<#wrapper_ty>(&mut __seq)? { + _serde::__private::Some(__wrap) => { + self.place.#member = __wrap.value; + } + _serde::__private::None => { + #value_if_none; + } + } + }) + } + }; + index_in_seq += 1; + write + } + }); + + let this_type = ¶ms.this_type; + let (_, ty_generics, _) = params.generics.split_for_impl(); + let let_default = match cattrs.default() { + attr::Default::Default => Some(quote!( + let __default: #this_type #ty_generics = _serde::__private::Default::default(); + )), + attr::Default::Path(path) => Some(quote!( + let __default: #this_type #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_default + #(#write_values)* + _serde::__private::Ok(()) + } +} + +fn deserialize_newtype_struct( + type_path: &TokenStream, + params: &Parameters, + field: &Field, +) -> TokenStream { + let delife = params.borrowed.de_lifetime(); + let field_ty = field.ty; + + let value = match field.attrs.deserialize_with() { + None => { + let span = field.original.span(); + let func = quote_spanned!(span=> <#field_ty as _serde::Deserialize>::deserialize); + quote! { + #func(__e)? + } + } + Some(path) => { + quote! { + #path(__e)? + } + } + }; + + let mut result = quote!(#type_path(__field0)); + if params.has_getter { + let this_type = ¶ms.this_type; + let (_, ty_generics, _) = params.generics.split_for_impl(); + result = quote! { + _serde::__private::Into::<#this_type #ty_generics>::into(#result) + }; + } + + quote! { + #[inline] + fn visit_newtype_struct<__E>(self, __e: __E) -> _serde::__private::Result<Self::Value, __E::Error> + where + __E: _serde::Deserializer<#delife>, + { + let __field0: #field_ty = #value; + _serde::__private::Ok(#result) + } + } +} + +enum StructForm<'a> { + Struct, + /// Contains a variant name + ExternallyTagged(&'a syn::Ident), + /// Contains a variant name and an intermediate deserializer from which actual + /// deserialization will be performed + InternallyTagged(&'a syn::Ident, TokenStream), + /// Contains a variant name and an intermediate deserializer from which actual + /// deserialization will be performed + Untagged(&'a syn::Ident, TokenStream), +} + +fn deserialize_struct( + params: &Parameters, + fields: &[Field], + cattrs: &attr::Container, + form: StructForm, +) -> Fragment { + let this_type = ¶ms.this_type; + let this_value = ¶ms.this_value; + 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_value) + }; + + let type_path = match form { + StructForm::Struct => construct, + StructForm::ExternallyTagged(variant_ident) + | StructForm::InternallyTagged(variant_ident, _) + | StructForm::Untagged(variant_ident, _) => quote!(#construct::#variant_ident), + }; + let expecting = match form { + StructForm::Struct => format!("struct {}", params.type_name()), + StructForm::ExternallyTagged(variant_ident) + | StructForm::InternallyTagged(variant_ident, _) + | StructForm::Untagged(variant_ident, _) => { + format!("struct variant {}::{}", params.type_name(), variant_ident) + } + }; + let expecting = cattrs.expecting().unwrap_or(&expecting); + + let field_names_idents: Vec<_> = fields + .iter() + .enumerate() + // Skip fields that shouldn't be deserialized or that were flattened, + // so they don't appear in the storage in their literal form + .filter(|&(_, field)| !field.attrs.skip_deserializing() && !field.attrs.flatten()) + .map(|(i, field)| { + ( + field.attrs.name().deserialize_name(), + field_i(i), + field.attrs.aliases(), + ) + }) + .collect(); + let field_visitor = deserialize_field_identifier(&field_names_idents, cattrs); + + // untagged struct variants do not get a visit_seq method. The same applies to + // structs that only have a map representation. + let visit_seq = match form { + StructForm::Untagged(..) => None, + _ if cattrs.has_flatten() => None, + _ => { + let mut_seq = if field_names_idents.is_empty() { + quote!(_) + } else { + quote!(mut __seq) + }; + + let visit_seq = Stmts(deserialize_seq( + &type_path, params, fields, true, cattrs, expecting, + )); + + Some(quote! { + #[inline] + fn visit_seq<__A>(self, #mut_seq: __A) -> _serde::__private::Result<Self::Value, __A::Error> + where + __A: _serde::de::SeqAccess<#delife>, + { + #visit_seq + } + }) + } + }; + let visit_map = Stmts(deserialize_map(&type_path, params, fields, cattrs)); + + let visitor_seed = match form { + StructForm::ExternallyTagged(..) if cattrs.has_flatten() => Some(quote! { + impl #de_impl_generics _serde::de::DeserializeSeed<#delife> for __Visitor #de_ty_generics #where_clause { + type Value = #this_type #ty_generics; + + fn deserialize<__D>(self, __deserializer: __D) -> _serde::__private::Result<Self::Value, __D::Error> + where + __D: _serde::Deserializer<#delife>, + { + _serde::Deserializer::deserialize_map(__deserializer, self) + } + } + }), + _ => None, + }; + + let fields_stmt = if cattrs.has_flatten() { + None + } else { + let field_names = field_names_idents + .iter() + .flat_map(|&(_, _, aliases)| aliases); + + Some(quote! { + #[doc(hidden)] + const FIELDS: &'static [&'static str] = &[ #(#field_names),* ]; + }) + }; + + let visitor_expr = quote! { + __Visitor { + marker: _serde::__private::PhantomData::<#this_type #ty_generics>, + lifetime: _serde::__private::PhantomData, + } + }; + let dispatch = match form { + StructForm::Struct if cattrs.has_flatten() => quote! { + _serde::Deserializer::deserialize_map(__deserializer, #visitor_expr) + }, + StructForm::Struct => { + let type_name = cattrs.name().deserialize_name(); + quote! { + _serde::Deserializer::deserialize_struct(__deserializer, #type_name, FIELDS, #visitor_expr) + } + } + StructForm::ExternallyTagged(_) if cattrs.has_flatten() => quote! { + _serde::de::VariantAccess::newtype_variant_seed(__variant, #visitor_expr) + }, + StructForm::ExternallyTagged(_) => quote! { + _serde::de::VariantAccess::struct_variant(__variant, FIELDS, #visitor_expr) + }, + StructForm::InternallyTagged(_, deserializer) => quote! { + _serde::Deserializer::deserialize_any(#deserializer, #visitor_expr) + }, + StructForm::Untagged(_, deserializer) => quote! { + _serde::Deserializer::deserialize_any(#deserializer, #visitor_expr) + }, + }; + + quote_block! { + #field_visitor + + #[doc(hidden)] + struct __Visitor #de_impl_generics #where_clause { + marker: _serde::__private::PhantomData<#this_type #ty_generics>, + lifetime: _serde::__private::PhantomData<&#delife ()>, + } + + impl #de_impl_generics _serde::de::Visitor<#delife> for __Visitor #de_ty_generics #where_clause { + type Value = #this_type #ty_generics; + + fn expecting(&self, __formatter: &mut _serde::__private::Formatter) -> _serde::__private::fmt::Result { + _serde::__private::Formatter::write_str(__formatter, #expecting) + } + + #visit_seq + + #[inline] + fn visit_map<__A>(self, mut __map: __A) -> _serde::__private::Result<Self::Value, __A::Error> + where + __A: _serde::de::MapAccess<#delife>, + { + #visit_map + } + } + + #visitor_seed + + #fields_stmt + + #dispatch + } +} + +#[cfg(feature = "deserialize_in_place")] +fn deserialize_struct_in_place( + params: &Parameters, + fields: &[Field], + cattrs: &attr::Container, +) -> Option<Fragment> { + // for now we do not support in_place deserialization for structs that + // are represented as map. + if cattrs.has_flatten() { + return None; + } + + let this_type = ¶ms.this_type; + let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = + split_with_de_lifetime(params); + let delife = params.borrowed.de_lifetime(); + + let expecting = format!("struct {}", params.type_name()); + let expecting = cattrs.expecting().unwrap_or(&expecting); + + 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), + field.attrs.aliases(), + ) + }) + .collect(); + + let field_visitor = deserialize_field_identifier(&field_names_idents, cattrs); + + let mut_seq = if field_names_idents.is_empty() { + quote!(_) + } else { + quote!(mut __seq) + }; + let visit_seq = Stmts(deserialize_seq_in_place(params, fields, cattrs, expecting)); + let visit_map = Stmts(deserialize_map_in_place(params, fields, cattrs)); + let field_names = field_names_idents + .iter() + .flat_map(|&(_, _, aliases)| aliases); + let type_name = cattrs.name().deserialize_name(); + + let in_place_impl_generics = de_impl_generics.in_place(); + let in_place_ty_generics = de_ty_generics.in_place(); + let place_life = place_lifetime(); + + Some(quote_block! { + #field_visitor + + #[doc(hidden)] + struct __Visitor #in_place_impl_generics #where_clause { + place: &#place_life mut #this_type #ty_generics, + lifetime: _serde::__private::PhantomData<&#delife ()>, + } + + impl #in_place_impl_generics _serde::de::Visitor<#delife> for __Visitor #in_place_ty_generics #where_clause { + type Value = (); + + fn expecting(&self, __formatter: &mut _serde::__private::Formatter) -> _serde::__private::fmt::Result { + _serde::__private::Formatter::write_str(__formatter, #expecting) + } + + #[inline] + fn visit_seq<__A>(self, #mut_seq: __A) -> _serde::__private::Result<Self::Value, __A::Error> + where + __A: _serde::de::SeqAccess<#delife>, + { + #visit_seq + } + + #[inline] + fn visit_map<__A>(self, mut __map: __A) -> _serde::__private::Result<Self::Value, __A::Error> + where + __A: _serde::de::MapAccess<#delife>, + { + #visit_map + } + } + + #[doc(hidden)] + const FIELDS: &'static [&'static str] = &[ #(#field_names),* ]; + + _serde::Deserializer::deserialize_struct(__deserializer, #type_name, FIELDS, __Visitor { + place: __place, + lifetime: _serde::__private::PhantomData, + }) + }) +} + +fn deserialize_enum( + params: &Parameters, + variants: &[Variant], + cattrs: &attr::Container, +) -> Fragment { + // The variants have already been checked (in ast.rs) that all untagged variants appear at the end + match variants.iter().position(|var| var.attrs.untagged()) { + Some(variant_idx) => { + let (tagged, untagged) = variants.split_at(variant_idx); + let tagged_frag = Expr(deserialize_homogeneous_enum(params, tagged, cattrs)); + deserialize_untagged_enum_after(params, untagged, cattrs, Some(tagged_frag)) + } + None => deserialize_homogeneous_enum(params, variants, cattrs), + } +} + +fn deserialize_homogeneous_enum( + params: &Parameters, + variants: &[Variant], + cattrs: &attr::Container, +) -> Fragment { + match cattrs.tag() { + attr::TagType::External => deserialize_externally_tagged_enum(params, variants, cattrs), + attr::TagType::Internal { tag } => { + deserialize_internally_tagged_enum(params, variants, cattrs, tag) + } + attr::TagType::Adjacent { tag, content } => { + deserialize_adjacently_tagged_enum(params, variants, cattrs, tag, content) + } + attr::TagType::None => deserialize_untagged_enum(params, variants, cattrs), + } +} + +fn prepare_enum_variant_enum( + variants: &[Variant], + cattrs: &attr::Container, +) -> (TokenStream, Stmts) { + let mut deserialized_variants = variants + .iter() + .enumerate() + .filter(|&(_, variant)| !variant.attrs.skip_deserializing()); + + let variant_names_idents: Vec<_> = deserialized_variants + .clone() + .map(|(i, variant)| { + ( + variant.attrs.name().deserialize_name(), + field_i(i), + variant.attrs.aliases(), + ) + }) + .collect(); + + let fallthrough = deserialized_variants + .position(|(_, variant)| variant.attrs.other()) + .map(|other_idx| { + let ignore_variant = variant_names_idents[other_idx].1.clone(); + quote!(_serde::__private::Ok(__Field::#ignore_variant)) + }); + + let variants_stmt = { + let variant_names = variant_names_idents.iter().map(|(name, _, _)| name); + quote! { + #[doc(hidden)] + const VARIANTS: &'static [&'static str] = &[ #(#variant_names),* ]; + } + }; + + let variant_visitor = Stmts(deserialize_generated_identifier( + &variant_names_idents, + cattrs, + true, + None, + fallthrough, + )); + + (variants_stmt, variant_visitor) +} + +fn deserialize_externally_tagged_enum( + params: &Parameters, + variants: &[Variant], + cattrs: &attr::Container, +) -> Fragment { + let this_type = ¶ms.this_type; + let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = + split_with_de_lifetime(params); + let delife = params.borrowed.de_lifetime(); + + let type_name = cattrs.name().deserialize_name(); + let expecting = format!("enum {}", params.type_name()); + let expecting = cattrs.expecting().unwrap_or(&expecting); + + let (variants_stmt, variant_visitor) = prepare_enum_variant_enum(variants, cattrs); + + // Match arms to extract a variant from a string + let variant_arms = variants + .iter() + .enumerate() + .filter(|&(_, variant)| !variant.attrs.skip_deserializing()) + .map(|(i, variant)| { + let variant_name = field_i(i); + + let block = Match(deserialize_externally_tagged_variant( + params, variant, cattrs, + )); + + quote! { + (__Field::#variant_name, __variant) => #block + } + }); + + let all_skipped = variants + .iter() + .all(|variant| variant.attrs.skip_deserializing()); + let match_variant = if all_skipped { + // This is an empty enum like `enum Impossible {}` or an enum in which + // all variants have `#[serde(skip_deserializing)]`. + quote! { + // FIXME: Once feature(exhaustive_patterns) is stable: + // let _serde::__private::Err(__err) = _serde::de::EnumAccess::variant::<__Field>(__data); + // _serde::__private::Err(__err) + _serde::__private::Result::map( + _serde::de::EnumAccess::variant::<__Field>(__data), + |(__impossible, _)| match __impossible {}) + } + } else { + quote! { + match _serde::de::EnumAccess::variant(__data)? { + #(#variant_arms)* + } + } + }; + + quote_block! { + #variant_visitor + + #[doc(hidden)] + struct __Visitor #de_impl_generics #where_clause { + marker: _serde::__private::PhantomData<#this_type #ty_generics>, + lifetime: _serde::__private::PhantomData<&#delife ()>, + } + + impl #de_impl_generics _serde::de::Visitor<#delife> for __Visitor #de_ty_generics #where_clause { + type Value = #this_type #ty_generics; + + fn expecting(&self, __formatter: &mut _serde::__private::Formatter) -> _serde::__private::fmt::Result { + _serde::__private::Formatter::write_str(__formatter, #expecting) + } + + fn visit_enum<__A>(self, __data: __A) -> _serde::__private::Result<Self::Value, __A::Error> + where + __A: _serde::de::EnumAccess<#delife>, + { + #match_variant + } + } + + #variants_stmt + + _serde::Deserializer::deserialize_enum( + __deserializer, + #type_name, + VARIANTS, + __Visitor { + marker: _serde::__private::PhantomData::<#this_type #ty_generics>, + lifetime: _serde::__private::PhantomData, + }, + ) + } +} + +fn deserialize_internally_tagged_enum( + params: &Parameters, + variants: &[Variant], + cattrs: &attr::Container, + tag: &str, +) -> Fragment { + let (variants_stmt, variant_visitor) = prepare_enum_variant_enum(variants, cattrs); + + // Match arms to extract a variant from a string + let variant_arms = variants + .iter() + .enumerate() + .filter(|&(_, variant)| !variant.attrs.skip_deserializing()) + .map(|(i, variant)| { + let variant_name = field_i(i); + + let block = Match(deserialize_internally_tagged_variant( + params, + variant, + cattrs, + quote!(__deserializer), + )); + + quote! { + __Field::#variant_name => #block + } + }); + + let expecting = format!("internally tagged enum {}", params.type_name()); + let expecting = cattrs.expecting().unwrap_or(&expecting); + + quote_block! { + #variant_visitor + + #variants_stmt + + let (__tag, __content) = _serde::Deserializer::deserialize_any( + __deserializer, + _serde::__private::de::TaggedContentVisitor::<__Field>::new(#tag, #expecting))?; + let __deserializer = _serde::__private::de::ContentDeserializer::<__D::Error>::new(__content); + + match __tag { + #(#variant_arms)* + } + } +} + +fn deserialize_adjacently_tagged_enum( + params: &Parameters, + variants: &[Variant], + cattrs: &attr::Container, + tag: &str, + content: &str, +) -> Fragment { + let this_type = ¶ms.this_type; + let this_value = ¶ms.this_value; + let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = + split_with_de_lifetime(params); + let delife = params.borrowed.de_lifetime(); + + let (variants_stmt, variant_visitor) = prepare_enum_variant_enum(variants, cattrs); + + let variant_arms: &Vec<_> = &variants + .iter() + .enumerate() + .filter(|&(_, variant)| !variant.attrs.skip_deserializing()) + .map(|(i, variant)| { + let variant_index = field_i(i); + + let block = Match(deserialize_untagged_variant( + params, + variant, + cattrs, + quote!(__deserializer), + )); + + quote! { + __Field::#variant_index => #block + } + }) + .collect(); + + let rust_name = params.type_name(); + let expecting = format!("adjacently tagged enum {}", rust_name); + let expecting = cattrs.expecting().unwrap_or(&expecting); + let type_name = cattrs.name().deserialize_name(); + let deny_unknown_fields = cattrs.deny_unknown_fields(); + + // If unknown fields are allowed, we pick the visitor that can step over + // those. Otherwise we pick the visitor that fails on unknown keys. + let field_visitor_ty = if deny_unknown_fields { + quote! { _serde::__private::de::TagOrContentFieldVisitor } + } else { + quote! { _serde::__private::de::TagContentOtherFieldVisitor } + }; + + let tag_or_content = quote! { + #field_visitor_ty { + tag: #tag, + content: #content, + } + }; + + let variant_seed = quote! { + _serde::__private::de::AdjacentlyTaggedEnumVariantSeed::<__Field> { + enum_name: #rust_name, + variants: VARIANTS, + fields_enum: _serde::__private::PhantomData + } + }; + + let mut missing_content = quote! { + _serde::__private::Err(<__A::Error as _serde::de::Error>::missing_field(#content)) + }; + let mut missing_content_fallthrough = quote!(); + let missing_content_arms = variants + .iter() + .enumerate() + .filter(|&(_, variant)| !variant.attrs.skip_deserializing()) + .filter_map(|(i, variant)| { + let variant_index = field_i(i); + let variant_ident = &variant.ident; + + let arm = match variant.style { + Style::Unit => quote! { + _serde::__private::Ok(#this_value::#variant_ident) + }, + Style::Newtype if variant.attrs.deserialize_with().is_none() => { + let span = variant.original.span(); + let func = quote_spanned!(span=> _serde::__private::de::missing_field); + quote! { + #func(#content).map(#this_value::#variant_ident) + } + } + _ => { + missing_content_fallthrough = quote!(_ => #missing_content); + return None; + } + }; + Some(quote! { + __Field::#variant_index => #arm, + }) + }) + .collect::<Vec<_>>(); + if !missing_content_arms.is_empty() { + missing_content = quote! { + match __field { + #(#missing_content_arms)* + #missing_content_fallthrough + } + }; + } + + // Advance the map by one key, returning early in case of error. + let next_key = quote! { + _serde::de::MapAccess::next_key_seed(&mut __map, #tag_or_content)? + }; + + let variant_from_map = quote! { + _serde::de::MapAccess::next_value_seed(&mut __map, #variant_seed)? + }; + + // When allowing unknown fields, we want to transparently step through keys + // we don't care about until we find `tag`, `content`, or run out of keys. + let next_relevant_key = if deny_unknown_fields { + next_key + } else { + quote!({ + let mut __rk : _serde::__private::Option<_serde::__private::de::TagOrContentField> = _serde::__private::None; + while let _serde::__private::Some(__k) = #next_key { + match __k { + _serde::__private::de::TagContentOtherField::Other => { + let _ = _serde::de::MapAccess::next_value::<_serde::de::IgnoredAny>(&mut __map)?; + continue; + }, + _serde::__private::de::TagContentOtherField::Tag => { + __rk = _serde::__private::Some(_serde::__private::de::TagOrContentField::Tag); + break; + } + _serde::__private::de::TagContentOtherField::Content => { + __rk = _serde::__private::Some(_serde::__private::de::TagOrContentField::Content); + break; + } + } + } + + __rk + }) + }; + + // Step through remaining keys, looking for duplicates of previously-seen + // keys. When unknown fields are denied, any key that isn't a duplicate will + // at this point immediately produce an error. + let visit_remaining_keys = quote! { + match #next_relevant_key { + _serde::__private::Some(_serde::__private::de::TagOrContentField::Tag) => { + _serde::__private::Err(<__A::Error as _serde::de::Error>::duplicate_field(#tag)) + } + _serde::__private::Some(_serde::__private::de::TagOrContentField::Content) => { + _serde::__private::Err(<__A::Error as _serde::de::Error>::duplicate_field(#content)) + } + _serde::__private::None => _serde::__private::Ok(__ret), + } + }; + + let finish_content_then_tag = if variant_arms.is_empty() { + quote! { + match #variant_from_map {} + } + } else { + quote! { + let __ret = match #variant_from_map { + // Deserialize the buffered content now that we know the variant. + #(#variant_arms)* + }?; + // Visit remaining keys, looking for duplicates. + #visit_remaining_keys + } + }; + + quote_block! { + #variant_visitor + + #variants_stmt + + #[doc(hidden)] + struct __Seed #de_impl_generics #where_clause { + field: __Field, + marker: _serde::__private::PhantomData<#this_type #ty_generics>, + lifetime: _serde::__private::PhantomData<&#delife ()>, + } + + impl #de_impl_generics _serde::de::DeserializeSeed<#delife> for __Seed #de_ty_generics #where_clause { + type Value = #this_type #ty_generics; + + fn deserialize<__D>(self, __deserializer: __D) -> _serde::__private::Result<Self::Value, __D::Error> + where + __D: _serde::Deserializer<#delife>, + { + match self.field { + #(#variant_arms)* + } + } + } + + #[doc(hidden)] + struct __Visitor #de_impl_generics #where_clause { + marker: _serde::__private::PhantomData<#this_type #ty_generics>, + lifetime: _serde::__private::PhantomData<&#delife ()>, + } + + impl #de_impl_generics _serde::de::Visitor<#delife> for __Visitor #de_ty_generics #where_clause { + type Value = #this_type #ty_generics; + + fn expecting(&self, __formatter: &mut _serde::__private::Formatter) -> _serde::__private::fmt::Result { + _serde::__private::Formatter::write_str(__formatter, #expecting) + } + + fn visit_map<__A>(self, mut __map: __A) -> _serde::__private::Result<Self::Value, __A::Error> + where + __A: _serde::de::MapAccess<#delife>, + { + // Visit the first relevant key. + match #next_relevant_key { + // First key is the tag. + _serde::__private::Some(_serde::__private::de::TagOrContentField::Tag) => { + // Parse the tag. + let __field = #variant_from_map; + // Visit the second key. + match #next_relevant_key { + // Second key is a duplicate of the tag. + _serde::__private::Some(_serde::__private::de::TagOrContentField::Tag) => { + _serde::__private::Err(<__A::Error as _serde::de::Error>::duplicate_field(#tag)) + } + // Second key is the content. + _serde::__private::Some(_serde::__private::de::TagOrContentField::Content) => { + let __ret = _serde::de::MapAccess::next_value_seed(&mut __map, + __Seed { + field: __field, + marker: _serde::__private::PhantomData, + lifetime: _serde::__private::PhantomData, + })?; + // Visit remaining keys, looking for duplicates. + #visit_remaining_keys + } + // There is no second key; might be okay if the we have a unit variant. + _serde::__private::None => #missing_content + } + } + // First key is the content. + _serde::__private::Some(_serde::__private::de::TagOrContentField::Content) => { + // Buffer up the content. + let __content = _serde::de::MapAccess::next_value::<_serde::__private::de::Content>(&mut __map)?; + // Visit the second key. + match #next_relevant_key { + // Second key is the tag. + _serde::__private::Some(_serde::__private::de::TagOrContentField::Tag) => { + let __deserializer = _serde::__private::de::ContentDeserializer::<__A::Error>::new(__content); + #finish_content_then_tag + } + // Second key is a duplicate of the content. + _serde::__private::Some(_serde::__private::de::TagOrContentField::Content) => { + _serde::__private::Err(<__A::Error as _serde::de::Error>::duplicate_field(#content)) + } + // There is no second key. + _serde::__private::None => { + _serde::__private::Err(<__A::Error as _serde::de::Error>::missing_field(#tag)) + } + } + } + // There is no first key. + _serde::__private::None => { + _serde::__private::Err(<__A::Error as _serde::de::Error>::missing_field(#tag)) + } + } + } + + fn visit_seq<__A>(self, mut __seq: __A) -> _serde::__private::Result<Self::Value, __A::Error> + where + __A: _serde::de::SeqAccess<#delife>, + { + // Visit the first element - the tag. + match _serde::de::SeqAccess::next_element(&mut __seq)? { + _serde::__private::Some(__field) => { + // Visit the second element - the content. + match _serde::de::SeqAccess::next_element_seed( + &mut __seq, + __Seed { + field: __field, + marker: _serde::__private::PhantomData, + lifetime: _serde::__private::PhantomData, + }, + )? { + _serde::__private::Some(__ret) => _serde::__private::Ok(__ret), + // There is no second element. + _serde::__private::None => { + _serde::__private::Err(_serde::de::Error::invalid_length(1, &self)) + } + } + } + // There is no first element. + _serde::__private::None => { + _serde::__private::Err(_serde::de::Error::invalid_length(0, &self)) + } + } + } + } + + #[doc(hidden)] + const FIELDS: &'static [&'static str] = &[#tag, #content]; + _serde::Deserializer::deserialize_struct( + __deserializer, + #type_name, + FIELDS, + __Visitor { + marker: _serde::__private::PhantomData::<#this_type #ty_generics>, + lifetime: _serde::__private::PhantomData, + }, + ) + } +} + +fn deserialize_untagged_enum( + params: &Parameters, + variants: &[Variant], + cattrs: &attr::Container, +) -> Fragment { + let first_attempt = None; + deserialize_untagged_enum_after(params, variants, cattrs, first_attempt) +} + +fn deserialize_untagged_enum_after( + params: &Parameters, + variants: &[Variant], + cattrs: &attr::Container, + first_attempt: Option<Expr>, +) -> Fragment { + let attempts = variants + .iter() + .filter(|variant| !variant.attrs.skip_deserializing()) + .map(|variant| { + Expr(deserialize_untagged_variant( + params, + variant, + cattrs, + quote!(__deserializer), + )) + }); + // TODO this message could be better by saving the errors from the failed + // attempts. The heuristic used by TOML was to count the number of fields + // processed before an error, and use the error that happened after the + // largest number of fields. I'm not sure I like that. Maybe it would be + // better to save all the errors and combine them into one message that + // explains why none of the variants matched. + let fallthrough_msg = format!( + "data did not match any variant of untagged enum {}", + params.type_name() + ); + let fallthrough_msg = cattrs.expecting().unwrap_or(&fallthrough_msg); + + // Ignore any error associated with non-untagged deserialization so that we + // can fall through to the untagged variants. This may be infallible so we + // need to provide the error type. + let first_attempt = first_attempt.map(|expr| { + quote! { + if let _serde::__private::Result::<_, __D::Error>::Ok(__ok) = (|| #expr)() { + return _serde::__private::Ok(__ok); + } + } + }); + + quote_block! { + let __content = <_serde::__private::de::Content as _serde::Deserialize>::deserialize(__deserializer)?; + let __deserializer = _serde::__private::de::ContentRefDeserializer::<__D::Error>::new(&__content); + + #first_attempt + + #( + if let _serde::__private::Ok(__ok) = #attempts { + return _serde::__private::Ok(__ok); + } + )* + + _serde::__private::Err(_serde::de::Error::custom(#fallthrough_msg)) + } +} + +fn deserialize_externally_tagged_variant( + params: &Parameters, + variant: &Variant, + cattrs: &attr::Container, +) -> Fragment { + if let Some(path) = variant.attrs.deserialize_with() { + let (wrapper, wrapper_ty, unwrap_fn) = wrap_deserialize_variant_with(params, variant, path); + return quote_block! { + #wrapper + _serde::__private::Result::map( + _serde::de::VariantAccess::newtype_variant::<#wrapper_ty>(__variant), #unwrap_fn) + }; + } + + let variant_ident = &variant.ident; + + match variant.style { + Style::Unit => { + let this_value = ¶ms.this_value; + quote_block! { + _serde::de::VariantAccess::unit_variant(__variant)?; + _serde::__private::Ok(#this_value::#variant_ident) + } + } + Style::Newtype => deserialize_externally_tagged_newtype_variant( + variant_ident, + params, + &variant.fields[0], + cattrs, + ), + Style::Tuple => deserialize_tuple( + params, + &variant.fields, + cattrs, + TupleForm::ExternallyTagged(variant_ident), + ), + Style::Struct => deserialize_struct( + params, + &variant.fields, + cattrs, + StructForm::ExternallyTagged(variant_ident), + ), + } +} + +// Generates significant part of the visit_seq and visit_map bodies of visitors +// for the variants of internally tagged enum. +fn deserialize_internally_tagged_variant( + params: &Parameters, + variant: &Variant, + cattrs: &attr::Container, + deserializer: TokenStream, +) -> Fragment { + if variant.attrs.deserialize_with().is_some() { + return deserialize_untagged_variant(params, variant, cattrs, deserializer); + } + + let variant_ident = &variant.ident; + + match effective_style(variant) { + Style::Unit => { + let this_value = ¶ms.this_value; + let type_name = params.type_name(); + let variant_name = variant.ident.to_string(); + let default = variant.fields.first().map(|field| { + let default = Expr(expr_is_missing(field, cattrs)); + quote!((#default)) + }); + quote_block! { + _serde::Deserializer::deserialize_any(#deserializer, _serde::__private::de::InternallyTaggedUnitVisitor::new(#type_name, #variant_name))?; + _serde::__private::Ok(#this_value::#variant_ident #default) + } + } + Style::Newtype => deserialize_untagged_newtype_variant( + variant_ident, + params, + &variant.fields[0], + &deserializer, + ), + Style::Struct => deserialize_struct( + params, + &variant.fields, + cattrs, + StructForm::InternallyTagged(variant_ident, deserializer), + ), + Style::Tuple => unreachable!("checked in serde_derive_internals"), + } +} + +fn deserialize_untagged_variant( + params: &Parameters, + variant: &Variant, + cattrs: &attr::Container, + deserializer: TokenStream, +) -> Fragment { + if let Some(path) = variant.attrs.deserialize_with() { + let unwrap_fn = unwrap_to_variant_closure(params, variant, false); + return quote_block! { + _serde::__private::Result::map(#path(#deserializer), #unwrap_fn) + }; + } + + let variant_ident = &variant.ident; + + match effective_style(variant) { + Style::Unit => { + let this_value = ¶ms.this_value; + let type_name = params.type_name(); + let variant_name = variant.ident.to_string(); + let default = variant.fields.first().map(|field| { + let default = Expr(expr_is_missing(field, cattrs)); + quote!((#default)) + }); + quote_expr! { + match _serde::Deserializer::deserialize_any( + #deserializer, + _serde::__private::de::UntaggedUnitVisitor::new(#type_name, #variant_name) + ) { + _serde::__private::Ok(()) => _serde::__private::Ok(#this_value::#variant_ident #default), + _serde::__private::Err(__err) => _serde::__private::Err(__err), + } + } + } + Style::Newtype => deserialize_untagged_newtype_variant( + variant_ident, + params, + &variant.fields[0], + &deserializer, + ), + Style::Tuple => deserialize_tuple( + params, + &variant.fields, + cattrs, + TupleForm::Untagged(variant_ident, deserializer), + ), + Style::Struct => deserialize_struct( + params, + &variant.fields, + cattrs, + StructForm::Untagged(variant_ident, deserializer), + ), + } +} + +fn deserialize_externally_tagged_newtype_variant( + variant_ident: &syn::Ident, + params: &Parameters, + field: &Field, + cattrs: &attr::Container, +) -> Fragment { + let this_value = ¶ms.this_value; + + if field.attrs.skip_deserializing() { + let default = Expr(expr_is_missing(field, cattrs)); + return quote_block! { + _serde::de::VariantAccess::unit_variant(__variant)?; + _serde::__private::Ok(#this_value::#variant_ident(#default)) + }; + } + + match field.attrs.deserialize_with() { + None => { + let field_ty = field.ty; + let span = field.original.span(); + let func = + quote_spanned!(span=> _serde::de::VariantAccess::newtype_variant::<#field_ty>); + quote_expr! { + _serde::__private::Result::map(#func(__variant), #this_value::#variant_ident) + } + } + Some(path) => { + let (wrapper, wrapper_ty) = wrap_deserialize_field_with(params, field.ty, path); + quote_block! { + #wrapper + _serde::__private::Result::map( + _serde::de::VariantAccess::newtype_variant::<#wrapper_ty>(__variant), + |__wrapper| #this_value::#variant_ident(__wrapper.value)) + } + } + } +} + +fn deserialize_untagged_newtype_variant( + variant_ident: &syn::Ident, + params: &Parameters, + field: &Field, + deserializer: &TokenStream, +) -> Fragment { + let this_value = ¶ms.this_value; + let field_ty = field.ty; + match field.attrs.deserialize_with() { + None => { + let span = field.original.span(); + let func = quote_spanned!(span=> <#field_ty as _serde::Deserialize>::deserialize); + quote_expr! { + _serde::__private::Result::map(#func(#deserializer), #this_value::#variant_ident) + } + } + Some(path) => { + quote_block! { + let __value: _serde::__private::Result<#field_ty, _> = #path(#deserializer); + _serde::__private::Result::map(__value, #this_value::#variant_ident) + } + } + } +} + +fn deserialize_generated_identifier( + fields: &[(&str, Ident, &BTreeSet<String>)], + cattrs: &attr::Container, + is_variant: bool, + ignore_variant: Option<TokenStream>, + fallthrough: Option<TokenStream>, +) -> Fragment { + let this_value = quote!(__Field); + let field_idents: &Vec<_> = &fields.iter().map(|(_, ident, _)| ident).collect(); + + let visitor_impl = Stmts(deserialize_identifier( + &this_value, + fields, + is_variant, + fallthrough, + None, + !is_variant && cattrs.has_flatten(), + None, + )); + + let lifetime = if !is_variant && cattrs.has_flatten() { + Some(quote!(<'de>)) + } else { + None + }; + + quote_block! { + #[allow(non_camel_case_types)] + #[doc(hidden)] + enum __Field #lifetime { + #(#field_idents,)* + #ignore_variant + } + + #[doc(hidden)] + struct __FieldVisitor; + + impl<'de> _serde::de::Visitor<'de> for __FieldVisitor { + type Value = __Field #lifetime; + + #visitor_impl + } + + impl<'de> _serde::Deserialize<'de> for __Field #lifetime { + #[inline] + fn deserialize<__D>(__deserializer: __D) -> _serde::__private::Result<Self, __D::Error> + where + __D: _serde::Deserializer<'de>, + { + _serde::Deserializer::deserialize_identifier(__deserializer, __FieldVisitor) + } + } + } +} + +/// Generates enum and its `Deserialize` implementation that represents each +/// non-skipped field of the struct +fn deserialize_field_identifier( + fields: &[(&str, Ident, &BTreeSet<String>)], + cattrs: &attr::Container, +) -> Stmts { + let (ignore_variant, fallthrough) = if cattrs.has_flatten() { + let ignore_variant = quote!(__other(_serde::__private::de::Content<'de>),); + let fallthrough = quote!(_serde::__private::Ok(__Field::__other(__value))); + (Some(ignore_variant), Some(fallthrough)) + } else if cattrs.deny_unknown_fields() { + (None, None) + } else { + let ignore_variant = quote!(__ignore,); + let fallthrough = quote!(_serde::__private::Ok(__Field::__ignore)); + (Some(ignore_variant), Some(fallthrough)) + }; + + Stmts(deserialize_generated_identifier( + fields, + cattrs, + false, + ignore_variant, + fallthrough, + )) +} + +// Generates `Deserialize::deserialize` body for an enum with +// `serde(field_identifier)` or `serde(variant_identifier)` attribute. +fn deserialize_custom_identifier( + params: &Parameters, + variants: &[Variant], + cattrs: &attr::Container, +) -> Fragment { + let is_variant = match cattrs.identifier() { + attr::Identifier::Variant => true, + attr::Identifier::Field => false, + attr::Identifier::No => unreachable!(), + }; + + let this_type = params.this_type.to_token_stream(); + let this_value = params.this_value.to_token_stream(); + + let (ordinary, fallthrough, fallthrough_borrowed) = if let Some(last) = variants.last() { + let last_ident = &last.ident; + if last.attrs.other() { + // Process `serde(other)` attribute. It would always be found on the + // last variant (checked in `check_identifier`), so all preceding + // are ordinary variants. + let ordinary = &variants[..variants.len() - 1]; + let fallthrough = quote!(_serde::__private::Ok(#this_value::#last_ident)); + (ordinary, Some(fallthrough), None) + } else if let Style::Newtype = last.style { + let ordinary = &variants[..variants.len() - 1]; + let fallthrough = |value| { + quote! { + _serde::__private::Result::map( + _serde::Deserialize::deserialize( + _serde::__private::de::IdentifierDeserializer::from(#value) + ), + #this_value::#last_ident) + } + }; + ( + ordinary, + Some(fallthrough(quote!(__value))), + Some(fallthrough(quote!(_serde::__private::de::Borrowed( + __value + )))), + ) + } else { + (variants, None, None) + } + } else { + (variants, None, None) + }; + + let names_idents: Vec<_> = ordinary + .iter() + .map(|variant| { + ( + variant.attrs.name().deserialize_name(), + variant.ident.clone(), + variant.attrs.aliases(), + ) + }) + .collect(); + + let names = names_idents.iter().flat_map(|&(_, _, aliases)| aliases); + + let names_const = if fallthrough.is_some() { + None + } else if is_variant { + let variants = quote! { + #[doc(hidden)] + const VARIANTS: &'static [&'static str] = &[ #(#names),* ]; + }; + Some(variants) + } else { + let fields = quote! { + #[doc(hidden)] + const FIELDS: &'static [&'static str] = &[ #(#names),* ]; + }; + Some(fields) + }; + + let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = + split_with_de_lifetime(params); + let delife = params.borrowed.de_lifetime(); + let visitor_impl = Stmts(deserialize_identifier( + &this_value, + &names_idents, + is_variant, + fallthrough, + fallthrough_borrowed, + false, + cattrs.expecting(), + )); + + quote_block! { + #names_const + + #[doc(hidden)] + struct __FieldVisitor #de_impl_generics #where_clause { + marker: _serde::__private::PhantomData<#this_type #ty_generics>, + lifetime: _serde::__private::PhantomData<&#delife ()>, + } + + impl #de_impl_generics _serde::de::Visitor<#delife> for __FieldVisitor #de_ty_generics #where_clause { + type Value = #this_type #ty_generics; + + #visitor_impl + } + + let __visitor = __FieldVisitor { + marker: _serde::__private::PhantomData::<#this_type #ty_generics>, + lifetime: _serde::__private::PhantomData, + }; + _serde::Deserializer::deserialize_identifier(__deserializer, __visitor) + } +} + +fn deserialize_identifier( + this_value: &TokenStream, + fields: &[(&str, Ident, &BTreeSet<String>)], + is_variant: bool, + fallthrough: Option<TokenStream>, + fallthrough_borrowed: Option<TokenStream>, + collect_other_fields: bool, + expecting: Option<&str>, +) -> Fragment { + let str_mapping = fields.iter().map(|(_, ident, aliases)| { + // `aliases` also contains a main name + quote!(#(#aliases)|* => _serde::__private::Ok(#this_value::#ident)) + }); + let bytes_mapping = fields.iter().map(|(_, ident, aliases)| { + // `aliases` also contains a main name + let aliases = aliases + .iter() + .map(|alias| Literal::byte_string(alias.as_bytes())); + quote!(#(#aliases)|* => _serde::__private::Ok(#this_value::#ident)) + }); + + let expecting = expecting.unwrap_or(if is_variant { + "variant identifier" + } else { + "field identifier" + }); + + let bytes_to_str = if fallthrough.is_some() || collect_other_fields { + None + } else { + Some(quote! { + let __value = &_serde::__private::from_utf8_lossy(__value); + }) + }; + + let ( + value_as_str_content, + value_as_borrowed_str_content, + value_as_bytes_content, + value_as_borrowed_bytes_content, + ) = if collect_other_fields { + ( + Some(quote! { + let __value = _serde::__private::de::Content::String(_serde::__private::ToString::to_string(__value)); + }), + Some(quote! { + let __value = _serde::__private::de::Content::Str(__value); + }), + Some(quote! { + let __value = _serde::__private::de::Content::ByteBuf(__value.to_vec()); + }), + Some(quote! { + let __value = _serde::__private::de::Content::Bytes(__value); + }), + ) + } else { + (None, None, None, None) + }; + + let fallthrough_arm_tokens; + let fallthrough_arm = if let Some(fallthrough) = &fallthrough { + fallthrough + } else if is_variant { + fallthrough_arm_tokens = quote! { + _serde::__private::Err(_serde::de::Error::unknown_variant(__value, VARIANTS)) + }; + &fallthrough_arm_tokens + } else { + fallthrough_arm_tokens = quote! { + _serde::__private::Err(_serde::de::Error::unknown_field(__value, FIELDS)) + }; + &fallthrough_arm_tokens + }; + + let visit_other = if collect_other_fields { + quote! { + fn visit_bool<__E>(self, __value: bool) -> _serde::__private::Result<Self::Value, __E> + where + __E: _serde::de::Error, + { + _serde::__private::Ok(__Field::__other(_serde::__private::de::Content::Bool(__value))) + } + + fn visit_i8<__E>(self, __value: i8) -> _serde::__private::Result<Self::Value, __E> + where + __E: _serde::de::Error, + { + _serde::__private::Ok(__Field::__other(_serde::__private::de::Content::I8(__value))) + } + + fn visit_i16<__E>(self, __value: i16) -> _serde::__private::Result<Self::Value, __E> + where + __E: _serde::de::Error, + { + _serde::__private::Ok(__Field::__other(_serde::__private::de::Content::I16(__value))) + } + + fn visit_i32<__E>(self, __value: i32) -> _serde::__private::Result<Self::Value, __E> + where + __E: _serde::de::Error, + { + _serde::__private::Ok(__Field::__other(_serde::__private::de::Content::I32(__value))) + } + + fn visit_i64<__E>(self, __value: i64) -> _serde::__private::Result<Self::Value, __E> + where + __E: _serde::de::Error, + { + _serde::__private::Ok(__Field::__other(_serde::__private::de::Content::I64(__value))) + } + + fn visit_u8<__E>(self, __value: u8) -> _serde::__private::Result<Self::Value, __E> + where + __E: _serde::de::Error, + { + _serde::__private::Ok(__Field::__other(_serde::__private::de::Content::U8(__value))) + } + + fn visit_u16<__E>(self, __value: u16) -> _serde::__private::Result<Self::Value, __E> + where + __E: _serde::de::Error, + { + _serde::__private::Ok(__Field::__other(_serde::__private::de::Content::U16(__value))) + } + + fn visit_u32<__E>(self, __value: u32) -> _serde::__private::Result<Self::Value, __E> + where + __E: _serde::de::Error, + { + _serde::__private::Ok(__Field::__other(_serde::__private::de::Content::U32(__value))) + } + + fn visit_u64<__E>(self, __value: u64) -> _serde::__private::Result<Self::Value, __E> + where + __E: _serde::de::Error, + { + _serde::__private::Ok(__Field::__other(_serde::__private::de::Content::U64(__value))) + } + + fn visit_f32<__E>(self, __value: f32) -> _serde::__private::Result<Self::Value, __E> + where + __E: _serde::de::Error, + { + _serde::__private::Ok(__Field::__other(_serde::__private::de::Content::F32(__value))) + } + + fn visit_f64<__E>(self, __value: f64) -> _serde::__private::Result<Self::Value, __E> + where + __E: _serde::de::Error, + { + _serde::__private::Ok(__Field::__other(_serde::__private::de::Content::F64(__value))) + } + + fn visit_char<__E>(self, __value: char) -> _serde::__private::Result<Self::Value, __E> + where + __E: _serde::de::Error, + { + _serde::__private::Ok(__Field::__other(_serde::__private::de::Content::Char(__value))) + } + + fn visit_unit<__E>(self) -> _serde::__private::Result<Self::Value, __E> + where + __E: _serde::de::Error, + { + _serde::__private::Ok(__Field::__other(_serde::__private::de::Content::Unit)) + } + } + } else { + let u64_mapping = fields.iter().enumerate().map(|(i, (_, ident, _))| { + let i = i as u64; + quote!(#i => _serde::__private::Ok(#this_value::#ident)) + }); + + let u64_fallthrough_arm_tokens; + let u64_fallthrough_arm = if let Some(fallthrough) = &fallthrough { + fallthrough + } else { + let index_expecting = if is_variant { "variant" } else { "field" }; + let fallthrough_msg = format!("{} index 0 <= i < {}", index_expecting, fields.len()); + u64_fallthrough_arm_tokens = quote! { + _serde::__private::Err(_serde::de::Error::invalid_value( + _serde::de::Unexpected::Unsigned(__value), + &#fallthrough_msg, + )) + }; + &u64_fallthrough_arm_tokens + }; + + quote! { + fn visit_u64<__E>(self, __value: u64) -> _serde::__private::Result<Self::Value, __E> + where + __E: _serde::de::Error, + { + match __value { + #(#u64_mapping,)* + _ => #u64_fallthrough_arm, + } + } + } + }; + + let visit_borrowed = if fallthrough_borrowed.is_some() || collect_other_fields { + let str_mapping = str_mapping.clone(); + let bytes_mapping = bytes_mapping.clone(); + let fallthrough_borrowed_arm = fallthrough_borrowed.as_ref().unwrap_or(fallthrough_arm); + Some(quote! { + fn visit_borrowed_str<__E>(self, __value: &'de str) -> _serde::__private::Result<Self::Value, __E> + where + __E: _serde::de::Error, + { + match __value { + #(#str_mapping,)* + _ => { + #value_as_borrowed_str_content + #fallthrough_borrowed_arm + } + } + } + + fn visit_borrowed_bytes<__E>(self, __value: &'de [u8]) -> _serde::__private::Result<Self::Value, __E> + where + __E: _serde::de::Error, + { + match __value { + #(#bytes_mapping,)* + _ => { + #bytes_to_str + #value_as_borrowed_bytes_content + #fallthrough_borrowed_arm + } + } + } + }) + } else { + None + }; + + quote_block! { + fn expecting(&self, __formatter: &mut _serde::__private::Formatter) -> _serde::__private::fmt::Result { + _serde::__private::Formatter::write_str(__formatter, #expecting) + } + + #visit_other + + fn visit_str<__E>(self, __value: &str) -> _serde::__private::Result<Self::Value, __E> + where + __E: _serde::de::Error, + { + match __value { + #(#str_mapping,)* + _ => { + #value_as_str_content + #fallthrough_arm + } + } + } + + fn visit_bytes<__E>(self, __value: &[u8]) -> _serde::__private::Result<Self::Value, __E> + where + __E: _serde::de::Error, + { + match __value { + #(#bytes_mapping,)* + _ => { + #bytes_to_str + #value_as_bytes_content + #fallthrough_arm + } + } + } + + #visit_borrowed + } +} + +fn deserialize_map( + struct_path: &TokenStream, + 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(); + + // Declare each field that will be deserialized. + let let_values = fields_names + .iter() + .filter(|&&(field, _)| !field.attrs.skip_deserializing() && !field.attrs.flatten()) + .map(|(field, name)| { + let field_ty = field.ty; + quote! { + let mut #name: _serde::__private::Option<#field_ty> = _serde::__private::None; + } + }); + + // Collect contents for flatten fields into a buffer + let let_collect = if cattrs.has_flatten() { + Some(quote! { + let mut __collect = _serde::__private::Vec::<_serde::__private::Option<( + _serde::__private::de::Content, + _serde::__private::de::Content + )>>::new(); + }) + } else { + None + }; + + // Match arms to extract a value for a field. + let value_arms = fields_names + .iter() + .filter(|&&(field, _)| !field.attrs.skip_deserializing() && !field.attrs.flatten()) + .map(|(field, name)| { + let deser_name = field.attrs.name().deserialize_name(); + + let visit = match field.attrs.deserialize_with() { + None => { + let field_ty = field.ty; + let span = field.original.span(); + let func = + quote_spanned!(span=> _serde::de::MapAccess::next_value::<#field_ty>); + quote! { + #func(&mut __map)? + } + } + Some(path) => { + let (wrapper, wrapper_ty) = wrap_deserialize_field_with(params, field.ty, path); + quote!({ + #wrapper + match _serde::de::MapAccess::next_value::<#wrapper_ty>(&mut __map) { + _serde::__private::Ok(__wrapper) => __wrapper.value, + _serde::__private::Err(__err) => { + return _serde::__private::Err(__err); + } + } + }) + } + }; + quote! { + __Field::#name => { + if _serde::__private::Option::is_some(&#name) { + return _serde::__private::Err(<__A::Error as _serde::de::Error>::duplicate_field(#deser_name)); + } + #name = _serde::__private::Some(#visit); + } + } + }); + + // Visit ignored values to consume them + let ignored_arm = if cattrs.has_flatten() { + Some(quote! { + __Field::__other(__name) => { + __collect.push(_serde::__private::Some(( + __name, + _serde::de::MapAccess::next_value(&mut __map)?))); + } + }) + } else if cattrs.deny_unknown_fields() { + None + } else { + Some(quote! { + _ => { let _ = _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 feature(exhaustive_patterns) is stable: + // let _serde::__private::None::<__Field> = _serde::de::MapAccess::next_key(&mut __map)?; + _serde::__private::Option::map( + _serde::de::MapAccess::next_key::<__Field>(&mut __map)?, + |__impossible| match __impossible {}); + } + } else { + quote! { + while let _serde::__private::Some(__key) = _serde::de::MapAccess::next_key::<__Field>(&mut __map)? { + match __key { + #(#value_arms)* + #ignored_arm + } + } + } + }; + + let extract_values = fields_names + .iter() + .filter(|&&(field, _)| !field.attrs.skip_deserializing() && !field.attrs.flatten()) + .map(|(field, name)| { + let missing_expr = Match(expr_is_missing(field, cattrs)); + + quote! { + let #name = match #name { + _serde::__private::Some(#name) => #name, + _serde::__private::None => #missing_expr + }; + } + }); + + let extract_collected = fields_names + .iter() + .filter(|&&(field, _)| field.attrs.flatten() && !field.attrs.skip_deserializing()) + .map(|(field, name)| { + let field_ty = field.ty; + let func = match field.attrs.deserialize_with() { + None => { + let span = field.original.span(); + quote_spanned!(span=> _serde::de::Deserialize::deserialize) + } + Some(path) => quote!(#path), + }; + quote! { + let #name: #field_ty = #func( + _serde::__private::de::FlatMapDeserializer( + &mut __collect, + _serde::__private::PhantomData))?; + } + }); + + let collected_deny_unknown_fields = if cattrs.has_flatten() && cattrs.deny_unknown_fields() { + Some(quote! { + if let _serde::__private::Some(_serde::__private::Some((__key, _))) = + __collect.into_iter().filter(_serde::__private::Option::is_some).next() + { + if let _serde::__private::Some(__key) = __key.as_str() { + return _serde::__private::Err( + _serde::de::Error::custom(format_args!("unknown field `{}`", &__key))); + } else { + return _serde::__private::Err( + _serde::de::Error::custom(format_args!("unexpected map key"))); + } + } + }) + } else { + None + }; + + let result = fields_names.iter().map(|(field, name)| { + let member = &field.member; + if field.attrs.skip_deserializing() { + let value = Expr(expr_is_missing(field, cattrs)); + quote!(#member: #value) + } else { + quote!(#member: #name) + } + }); + + let let_default = match cattrs.default() { + attr::Default::Default => Some(quote!( + let __default: Self::Value = _serde::__private::Default::default(); + )), + attr::Default::Path(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'll leave the line empty. + None + } + }; + + let mut result = quote!(#struct_path { #(#result),* }); + if params.has_getter { + let this_type = ¶ms.this_type; + let (_, ty_generics, _) = params.generics.split_for_impl(); + result = quote! { + _serde::__private::Into::<#this_type #ty_generics>::into(#result) + }; + } + + quote_block! { + #(#let_values)* + + #let_collect + + #match_keys + + #let_default + + #(#extract_values)* + + #(#extract_collected)* + + #collected_deny_unknown_fields + + _serde::__private::Ok(#result) + } +} + +#[cfg(feature = "deserialize_in_place")] +fn deserialize_map_in_place( + params: &Parameters, + fields: &[Field], + cattrs: &attr::Container, +) -> Fragment { + assert!(!cattrs.has_flatten()); + + // Create the field names for the fields. + let fields_names: Vec<_> = fields + .iter() + .enumerate() + .map(|(i, field)| (field, field_i(i))) + .collect(); + + // For deserialize_in_place, declare booleans for each field that will be + // deserialized. + let let_flags = fields_names + .iter() + .filter(|&&(field, _)| !field.attrs.skip_deserializing()) + .map(|(_, 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, name)| { + let deser_name = field.attrs.name().deserialize_name(); + let member = &field.member; + + let visit = match field.attrs.deserialize_with() { + None => { + quote! { + _serde::de::MapAccess::next_value_seed(&mut __map, _serde::__private::de::InPlaceSeed(&mut self.place.#member))? + } + } + Some(path) => { + let (wrapper, wrapper_ty) = wrap_deserialize_field_with(params, field.ty, path); + quote!({ + #wrapper + self.place.#member = match _serde::de::MapAccess::next_value::<#wrapper_ty>(&mut __map) { + _serde::__private::Ok(__wrapper) => __wrapper.value, + _serde::__private::Err(__err) => { + return _serde::__private::Err(__err); + } + }; + }) + } + }; + quote! { + __Field::#name => { + if #name { + return _serde::__private::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 _ = _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 feature(exhaustive_patterns) is stable: + // let _serde::__private::None::<__Field> = _serde::de::MapAccess::next_key(&mut __map)?; + _serde::__private::Option::map( + _serde::de::MapAccess::next_key::<__Field>(&mut __map)?, + |__impossible| match __impossible {}); + } + } else { + quote! { + while let _serde::__private::Some(__key) = _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, name)| { + let missing_expr = expr_is_missing(field, cattrs); + // If missing_expr unconditionally returns an error, don't try + // to assign its value to self.place. + if field.attrs.default().is_none() + && cattrs.default().is_none() + && field.attrs.deserialize_with().is_some() + { + let missing_expr = Stmts(missing_expr); + quote! { + if !#name { + #missing_expr; + } + } + } else { + let member = &field.member; + let missing_expr = Expr(missing_expr); + quote! { + if !#name { + self.place.#member = #missing_expr; + }; + } + } + }); + + let this_type = ¶ms.this_type; + let (_, _, ty_generics, _) = split_with_de_lifetime(params); + + let let_default = match cattrs.default() { + attr::Default::Default => Some(quote!( + let __default: #this_type #ty_generics = _serde::__private::Default::default(); + )), + attr::Default::Path(path) => Some(quote!( + let __default: #this_type #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::__private::Ok(()) + } +} + +fn field_i(i: usize) -> Ident { + Ident::new(&format!("__field{}", i), Span::call_site()) +} + +/// This function wraps the expression in `#[serde(deserialize_with = "...")]` +/// in a trait to prevent it from accessing the internal `Deserialize` state. +fn wrap_deserialize_with( + params: &Parameters, + value_ty: &TokenStream, + deserialize_with: &syn::ExprPath, +) -> (TokenStream, TokenStream) { + let this_type = ¶ms.this_type; + let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = + split_with_de_lifetime(params); + let delife = params.borrowed.de_lifetime(); + + let wrapper = quote! { + #[doc(hidden)] + struct __DeserializeWith #de_impl_generics #where_clause { + value: #value_ty, + phantom: _serde::__private::PhantomData<#this_type #ty_generics>, + lifetime: _serde::__private::PhantomData<&#delife ()>, + } + + impl #de_impl_generics _serde::Deserialize<#delife> for __DeserializeWith #de_ty_generics #where_clause { + fn deserialize<__D>(__deserializer: __D) -> _serde::__private::Result<Self, __D::Error> + where + __D: _serde::Deserializer<#delife>, + { + _serde::__private::Ok(__DeserializeWith { + value: #deserialize_with(__deserializer)?, + phantom: _serde::__private::PhantomData, + lifetime: _serde::__private::PhantomData, + }) + } + } + }; + + let wrapper_ty = quote!(__DeserializeWith #de_ty_generics); + + (wrapper, wrapper_ty) +} + +fn wrap_deserialize_field_with( + params: &Parameters, + field_ty: &syn::Type, + deserialize_with: &syn::ExprPath, +) -> (TokenStream, TokenStream) { + wrap_deserialize_with(params, "e!(#field_ty), deserialize_with) +} + +fn wrap_deserialize_variant_with( + params: &Parameters, + variant: &Variant, + deserialize_with: &syn::ExprPath, +) -> (TokenStream, TokenStream, TokenStream) { + let field_tys = variant.fields.iter().map(|field| field.ty); + let (wrapper, wrapper_ty) = + wrap_deserialize_with(params, "e!((#(#field_tys),*)), deserialize_with); + + let unwrap_fn = unwrap_to_variant_closure(params, variant, true); + + (wrapper, wrapper_ty, unwrap_fn) +} + +// Generates closure that converts single input parameter to the final value. +fn unwrap_to_variant_closure( + params: &Parameters, + variant: &Variant, + with_wrapper: bool, +) -> TokenStream { + let this_value = ¶ms.this_value; + let variant_ident = &variant.ident; + + let (arg, wrapper) = if with_wrapper { + (quote! { __wrap }, quote! { __wrap.value }) + } else { + let field_tys = variant.fields.iter().map(|field| field.ty); + (quote! { __wrap: (#(#field_tys),*) }, quote! { __wrap }) + }; + + let field_access = (0..variant.fields.len()).map(|n| { + Member::Unnamed(Index { + index: n as u32, + span: Span::call_site(), + }) + }); + + match variant.style { + Style::Struct if variant.fields.len() == 1 => { + let member = &variant.fields[0].member; + quote! { + |#arg| #this_value::#variant_ident { #member: #wrapper } + } + } + Style::Struct => { + let members = variant.fields.iter().map(|field| &field.member); + quote! { + |#arg| #this_value::#variant_ident { #(#members: #wrapper.#field_access),* } + } + } + Style::Tuple => quote! { + |#arg| #this_value::#variant_ident(#(#wrapper.#field_access),*) + }, + Style::Newtype => quote! { + |#arg| #this_value::#variant_ident(#wrapper) + }, + Style::Unit => quote! { + |#arg| #this_value::#variant_ident + }, + } +} + +fn expr_is_missing(field: &Field, cattrs: &attr::Container) -> Fragment { + match field.attrs.default() { + attr::Default::Default => { + let span = field.original.span(); + let func = quote_spanned!(span=> _serde::__private::Default::default); + return quote_expr!(#func()); + } + attr::Default::Path(path) => { + return quote_expr!(#path()); + } + attr::Default::None => { /* below */ } + } + + match *cattrs.default() { + attr::Default::Default | attr::Default::Path(_) => { + let member = &field.member; + return quote_expr!(__default.#member); + } + attr::Default::None => { /* below */ } + } + + let name = field.attrs.name().deserialize_name(); + match field.attrs.deserialize_with() { + None => { + let span = field.original.span(); + let func = quote_spanned!(span=> _serde::__private::de::missing_field); + quote_expr! { + #func(#name)? + } + } + Some(_) => { + quote_expr! { + return _serde::__private::Err(<__A::Error as _serde::de::Error>::missing_field(#name)) + } + } + } +} + +fn expr_is_missing_seq( + assign_to: Option<TokenStream>, + index: usize, + field: &Field, + cattrs: &attr::Container, + expecting: &str, +) -> TokenStream { + match field.attrs.default() { + attr::Default::Default => { + let span = field.original.span(); + return quote_spanned!(span=> #assign_to _serde::__private::Default::default()); + } + attr::Default::Path(path) => { + return quote_spanned!(path.span()=> #assign_to #path()); + } + attr::Default::None => { /* below */ } + } + + match *cattrs.default() { + attr::Default::Default | attr::Default::Path(_) => { + let member = &field.member; + quote!(#assign_to __default.#member) + } + attr::Default::None => quote!( + return _serde::__private::Err(_serde::de::Error::invalid_length(#index, &#expecting)) + ), + } +} + +fn effective_style(variant: &Variant) -> Style { + match variant.style { + Style::Newtype if variant.fields[0].attrs.skip_deserializing() => Style::Unit, + other => other, + } +} + +struct DeImplGenerics<'a>(&'a Parameters); +#[cfg(feature = "deserialize_in_place")] +struct InPlaceImplGenerics<'a>(&'a Parameters); + +impl<'a> ToTokens for DeImplGenerics<'a> { + fn to_tokens(&self, tokens: &mut TokenStream) { + let mut generics = self.0.generics.clone(); + if let Some(de_lifetime) = self.0.borrowed.de_lifetime_param() { + generics.params = Some(syn::GenericParam::Lifetime(de_lifetime)) + .into_iter() + .chain(generics.params) + .collect(); + } + let (impl_generics, _, _) = generics.split_for_impl(); + impl_generics.to_tokens(tokens); + } +} + +#[cfg(feature = "deserialize_in_place")] +impl<'a> ToTokens for InPlaceImplGenerics<'a> { + fn to_tokens(&self, tokens: &mut TokenStream) { + let place_lifetime = place_lifetime(); + let mut generics = self.0.generics.clone(); + + // Add lifetime for `&'place mut Self, and `'a: 'place` + for param in &mut generics.params { + match param { + syn::GenericParam::Lifetime(param) => { + param.bounds.push(place_lifetime.lifetime.clone()); + } + syn::GenericParam::Type(param) => { + param.bounds.push(syn::TypeParamBound::Lifetime( + place_lifetime.lifetime.clone(), + )); + } + syn::GenericParam::Const(_) => {} + } + } + generics.params = Some(syn::GenericParam::Lifetime(place_lifetime)) + .into_iter() + .chain(generics.params) + .collect(); + if let Some(de_lifetime) = self.0.borrowed.de_lifetime_param() { + generics.params = Some(syn::GenericParam::Lifetime(de_lifetime)) + .into_iter() + .chain(generics.params) + .collect(); + } + let (impl_generics, _, _) = generics.split_for_impl(); + impl_generics.to_tokens(tokens); + } +} + +#[cfg(feature = "deserialize_in_place")] +impl<'a> DeImplGenerics<'a> { + fn in_place(self) -> InPlaceImplGenerics<'a> { + InPlaceImplGenerics(self.0) + } +} + +struct DeTypeGenerics<'a>(&'a Parameters); +#[cfg(feature = "deserialize_in_place")] +struct InPlaceTypeGenerics<'a>(&'a Parameters); + +fn de_type_generics_to_tokens( + mut generics: syn::Generics, + borrowed: &BorrowedLifetimes, + tokens: &mut TokenStream, +) { + if borrowed.de_lifetime_param().is_some() { + let def = syn::LifetimeParam { + attrs: Vec::new(), + lifetime: syn::Lifetime::new("'de", Span::call_site()), + colon_token: None, + bounds: Punctuated::new(), + }; + // Prepend 'de lifetime to list of generics + generics.params = Some(syn::GenericParam::Lifetime(def)) + .into_iter() + .chain(generics.params) + .collect(); + } + let (_, ty_generics, _) = generics.split_for_impl(); + ty_generics.to_tokens(tokens); +} + +impl<'a> ToTokens for DeTypeGenerics<'a> { + fn to_tokens(&self, tokens: &mut TokenStream) { + de_type_generics_to_tokens(self.0.generics.clone(), &self.0.borrowed, tokens); + } +} + +#[cfg(feature = "deserialize_in_place")] +impl<'a> ToTokens for InPlaceTypeGenerics<'a> { + fn to_tokens(&self, tokens: &mut TokenStream) { + let mut generics = self.0.generics.clone(); + generics.params = Some(syn::GenericParam::Lifetime(place_lifetime())) + .into_iter() + .chain(generics.params) + .collect(); + + de_type_generics_to_tokens(generics, &self.0.borrowed, tokens); + } +} + +#[cfg(feature = "deserialize_in_place")] +impl<'a> DeTypeGenerics<'a> { + fn in_place(self) -> InPlaceTypeGenerics<'a> { + InPlaceTypeGenerics(self.0) + } +} + +#[cfg(feature = "deserialize_in_place")] +fn place_lifetime() -> syn::LifetimeParam { + syn::LifetimeParam { + attrs: Vec::new(), + lifetime: syn::Lifetime::new("'place", Span::call_site()), + colon_token: None, + bounds: Punctuated::new(), + } +} + +fn split_with_de_lifetime( + params: &Parameters, +) -> ( + DeImplGenerics, + DeTypeGenerics, + syn::TypeGenerics, + Option<&syn::WhereClause>, +) { + let de_impl_generics = DeImplGenerics(params); + let de_ty_generics = DeTypeGenerics(params); + let (_, ty_generics, where_clause) = params.generics.split_for_impl(); + (de_impl_generics, de_ty_generics, ty_generics, where_clause) +} diff --git a/third_party/rust/serde_derive/src/dummy.rs b/third_party/rust/serde_derive/src/dummy.rs new file mode 100644 index 0000000000..095f950f3e --- /dev/null +++ b/third_party/rust/serde_derive/src/dummy.rs @@ -0,0 +1,23 @@ +use proc_macro2::TokenStream; +use quote::quote; + +pub fn wrap_in_const(serde_path: Option<&syn::Path>, code: TokenStream) -> TokenStream { + let use_serde = match serde_path { + Some(path) => quote! { + use #path as _serde; + }, + None => quote! { + #[allow(unused_extern_crates, clippy::useless_attribute)] + extern crate serde as _serde; + }, + }; + + quote! { + #[doc(hidden)] + #[allow(non_upper_case_globals, unused_attributes, unused_qualifications)] + const _: () = { + #use_serde + #code + }; + } +} diff --git a/third_party/rust/serde_derive/src/fragment.rs b/third_party/rust/serde_derive/src/fragment.rs new file mode 100644 index 0000000000..6627c26699 --- /dev/null +++ b/third_party/rust/serde_derive/src/fragment.rs @@ -0,0 +1,74 @@ +use proc_macro2::TokenStream; +use quote::ToTokens; +use syn::{token, Token}; + +pub enum Fragment { + /// Tokens that can be used as an expression. + Expr(TokenStream), + /// Tokens that can be used inside a block. The surrounding curly braces are + /// not part of these tokens. + Block(TokenStream), +} + +macro_rules! quote_expr { + ($($tt:tt)*) => { + $crate::fragment::Fragment::Expr(quote!($($tt)*)) + } +} + +macro_rules! quote_block { + ($($tt:tt)*) => { + $crate::fragment::Fragment::Block(quote!($($tt)*)) + } +} + +/// Interpolate a fragment in place of an expression. This involves surrounding +/// Block fragments in curly braces. +pub struct Expr(pub Fragment); +impl ToTokens for Expr { + fn to_tokens(&self, out: &mut TokenStream) { + match &self.0 { + Fragment::Expr(expr) => expr.to_tokens(out), + Fragment::Block(block) => { + token::Brace::default().surround(out, |out| block.to_tokens(out)); + } + } + } +} + +/// Interpolate a fragment as the statements of a block. +pub struct Stmts(pub Fragment); +impl ToTokens for Stmts { + fn to_tokens(&self, out: &mut TokenStream) { + match &self.0 { + Fragment::Expr(expr) => expr.to_tokens(out), + Fragment::Block(block) => block.to_tokens(out), + } + } +} + +/// Interpolate a fragment as the value part of a `match` expression. This +/// involves putting a comma after expressions and curly braces around blocks. +pub struct Match(pub Fragment); +impl ToTokens for Match { + fn to_tokens(&self, out: &mut TokenStream) { + match &self.0 { + Fragment::Expr(expr) => { + expr.to_tokens(out); + <Token![,]>::default().to_tokens(out); + } + Fragment::Block(block) => { + token::Brace::default().surround(out, |out| block.to_tokens(out)); + } + } + } +} + +impl AsRef<TokenStream> for Fragment { + fn as_ref(&self) -> &TokenStream { + match self { + Fragment::Expr(expr) => expr, + Fragment::Block(block) => block, + } + } +} diff --git a/third_party/rust/serde_derive/src/internals/ast.rs b/third_party/rust/serde_derive/src/internals/ast.rs new file mode 100644 index 0000000000..a28d3ae7e9 --- /dev/null +++ b/third_party/rust/serde_derive/src/internals/ast.rs @@ -0,0 +1,216 @@ +//! A Serde ast, parsed from the Syn ast and ready to generate Rust code. + +use crate::internals::{attr, check, Ctxt, Derive}; +use syn::punctuated::Punctuated; +use syn::Token; + +/// A source data structure annotated with `#[derive(Serialize)]` and/or `#[derive(Deserialize)]`, +/// parsed into an internal representation. +pub struct Container<'a> { + /// The struct or enum name (without generics). + pub ident: syn::Ident, + /// Attributes on the structure, parsed for Serde. + pub attrs: attr::Container, + /// The contents of the struct or enum. + pub data: Data<'a>, + /// Any generics on the struct or enum. + pub generics: &'a syn::Generics, + /// Original input. + pub original: &'a syn::DeriveInput, +} + +/// The fields of a struct or enum. +/// +/// Analogous to `syn::Data`. +pub enum Data<'a> { + Enum(Vec<Variant<'a>>), + Struct(Style, Vec<Field<'a>>), +} + +/// A variant of an enum. +pub struct Variant<'a> { + pub ident: syn::Ident, + pub attrs: attr::Variant, + pub style: Style, + pub fields: Vec<Field<'a>>, + pub original: &'a syn::Variant, +} + +/// A field of a struct. +pub struct Field<'a> { + pub member: syn::Member, + pub attrs: attr::Field, + pub ty: &'a syn::Type, + pub original: &'a syn::Field, +} + +#[derive(Copy, Clone)] +pub enum Style { + /// Named fields. + Struct, + /// Many unnamed fields. + Tuple, + /// One unnamed field. + Newtype, + /// No fields. + Unit, +} + +impl<'a> Container<'a> { + /// Convert the raw Syn ast into a parsed container object, collecting errors in `cx`. + pub fn from_ast( + cx: &Ctxt, + item: &'a syn::DeriveInput, + derive: Derive, + ) -> Option<Container<'a>> { + let mut attrs = attr::Container::from_ast(cx, item); + + let mut data = match &item.data { + syn::Data::Enum(data) => Data::Enum(enum_from_ast(cx, &data.variants, attrs.default())), + syn::Data::Struct(data) => { + let (style, fields) = struct_from_ast(cx, &data.fields, None, attrs.default()); + Data::Struct(style, fields) + } + syn::Data::Union(_) => { + cx.error_spanned_by(item, "Serde does not support derive for unions"); + return None; + } + }; + + let mut has_flatten = false; + match &mut data { + Data::Enum(variants) => { + for variant in variants { + variant.attrs.rename_by_rules(attrs.rename_all_rules()); + for field in &mut variant.fields { + if field.attrs.flatten() { + has_flatten = true; + } + field.attrs.rename_by_rules( + variant + .attrs + .rename_all_rules() + .or(attrs.rename_all_fields_rules()), + ); + } + } + } + Data::Struct(_, fields) => { + for field in fields { + if field.attrs.flatten() { + has_flatten = true; + } + field.attrs.rename_by_rules(attrs.rename_all_rules()); + } + } + } + + if has_flatten { + attrs.mark_has_flatten(); + } + + let mut item = Container { + ident: item.ident.clone(), + attrs, + data, + generics: &item.generics, + original: item, + }; + check::check(cx, &mut item, derive); + Some(item) + } +} + +impl<'a> Data<'a> { + pub fn all_fields(&'a self) -> Box<dyn Iterator<Item = &'a Field<'a>> + 'a> { + match self { + Data::Enum(variants) => { + Box::new(variants.iter().flat_map(|variant| variant.fields.iter())) + } + Data::Struct(_, fields) => Box::new(fields.iter()), + } + } + + pub fn has_getter(&self) -> bool { + self.all_fields().any(|f| f.attrs.getter().is_some()) + } +} + +fn enum_from_ast<'a>( + cx: &Ctxt, + variants: &'a Punctuated<syn::Variant, Token![,]>, + container_default: &attr::Default, +) -> Vec<Variant<'a>> { + let variants: Vec<Variant> = variants + .iter() + .map(|variant| { + let attrs = attr::Variant::from_ast(cx, variant); + let (style, fields) = + struct_from_ast(cx, &variant.fields, Some(&attrs), container_default); + Variant { + ident: variant.ident.clone(), + attrs, + style, + fields, + original: variant, + } + }) + .collect(); + + let index_of_last_tagged_variant = variants + .iter() + .rposition(|variant| !variant.attrs.untagged()); + if let Some(index_of_last_tagged_variant) = index_of_last_tagged_variant { + for variant in &variants[..index_of_last_tagged_variant] { + if variant.attrs.untagged() { + cx.error_spanned_by(&variant.ident, "all variants with the #[serde(untagged)] attribute must be placed at the end of the enum"); + } + } + } + + variants +} + +fn struct_from_ast<'a>( + cx: &Ctxt, + fields: &'a syn::Fields, + attrs: Option<&attr::Variant>, + container_default: &attr::Default, +) -> (Style, Vec<Field<'a>>) { + match fields { + syn::Fields::Named(fields) => ( + Style::Struct, + fields_from_ast(cx, &fields.named, attrs, container_default), + ), + syn::Fields::Unnamed(fields) if fields.unnamed.len() == 1 => ( + Style::Newtype, + fields_from_ast(cx, &fields.unnamed, attrs, container_default), + ), + syn::Fields::Unnamed(fields) => ( + Style::Tuple, + fields_from_ast(cx, &fields.unnamed, attrs, container_default), + ), + syn::Fields::Unit => (Style::Unit, Vec::new()), + } +} + +fn fields_from_ast<'a>( + cx: &Ctxt, + fields: &'a Punctuated<syn::Field, Token![,]>, + attrs: Option<&attr::Variant>, + container_default: &attr::Default, +) -> Vec<Field<'a>> { + fields + .iter() + .enumerate() + .map(|(i, field)| Field { + member: match &field.ident { + Some(ident) => syn::Member::Named(ident.clone()), + None => syn::Member::Unnamed(i.into()), + }, + attrs: attr::Field::from_ast(cx, i, field, attrs, container_default), + ty: &field.ty, + original: field, + }) + .collect() +} diff --git a/third_party/rust/serde_derive/src/internals/attr.rs b/third_party/rust/serde_derive/src/internals/attr.rs new file mode 100644 index 0000000000..bb9de328a6 --- /dev/null +++ b/third_party/rust/serde_derive/src/internals/attr.rs @@ -0,0 +1,1881 @@ +use crate::internals::symbol::*; +use crate::internals::{ungroup, Ctxt}; +use proc_macro2::{Spacing, Span, TokenStream, TokenTree}; +use quote::ToTokens; +use std::borrow::Cow; +use std::collections::BTreeSet; +use std::iter::FromIterator; +use syn::meta::ParseNestedMeta; +use syn::parse::ParseStream; +use syn::punctuated::Punctuated; +use syn::{parse_quote, token, Ident, Lifetime, Token}; + +// This module handles parsing of `#[serde(...)]` attributes. The entrypoints +// are `attr::Container::from_ast`, `attr::Variant::from_ast`, and +// `attr::Field::from_ast`. Each returns an instance of the corresponding +// struct. Note that none of them return a Result. Unrecognized, malformed, or +// duplicated attributes result in a span_err but otherwise are ignored. The +// user will see errors simultaneously for all bad attributes in the crate +// rather than just the first. + +pub use crate::internals::case::RenameRule; + +struct Attr<'c, T> { + cx: &'c Ctxt, + name: Symbol, + tokens: TokenStream, + value: Option<T>, +} + +impl<'c, T> Attr<'c, T> { + fn none(cx: &'c Ctxt, name: Symbol) -> Self { + Attr { + cx, + name, + tokens: TokenStream::new(), + value: None, + } + } + + fn set<A: ToTokens>(&mut self, obj: A, value: T) { + let tokens = obj.into_token_stream(); + + if self.value.is_some() { + let msg = format!("duplicate serde attribute `{}`", self.name); + self.cx.error_spanned_by(tokens, msg); + } else { + self.tokens = tokens; + self.value = Some(value); + } + } + + fn set_opt<A: ToTokens>(&mut self, obj: A, value: Option<T>) { + if let Some(value) = value { + self.set(obj, value); + } + } + + fn set_if_none(&mut self, value: T) { + if self.value.is_none() { + self.value = Some(value); + } + } + + fn get(self) -> Option<T> { + self.value + } + + fn get_with_tokens(self) -> Option<(TokenStream, T)> { + match self.value { + Some(v) => Some((self.tokens, v)), + None => None, + } + } +} + +struct BoolAttr<'c>(Attr<'c, ()>); + +impl<'c> BoolAttr<'c> { + fn none(cx: &'c Ctxt, name: Symbol) -> Self { + BoolAttr(Attr::none(cx, name)) + } + + fn set_true<A: ToTokens>(&mut self, obj: A) { + self.0.set(obj, ()); + } + + fn get(&self) -> bool { + self.0.value.is_some() + } +} + +struct VecAttr<'c, T> { + cx: &'c Ctxt, + name: Symbol, + first_dup_tokens: TokenStream, + values: Vec<T>, +} + +impl<'c, T> VecAttr<'c, T> { + fn none(cx: &'c Ctxt, name: Symbol) -> Self { + VecAttr { + cx, + name, + first_dup_tokens: TokenStream::new(), + values: Vec::new(), + } + } + + fn insert<A: ToTokens>(&mut self, obj: A, value: T) { + if self.values.len() == 1 { + self.first_dup_tokens = obj.into_token_stream(); + } + self.values.push(value); + } + + fn at_most_one(mut self) -> Option<T> { + if self.values.len() > 1 { + let dup_token = self.first_dup_tokens; + let msg = format!("duplicate serde attribute `{}`", self.name); + self.cx.error_spanned_by(dup_token, msg); + None + } else { + self.values.pop() + } + } + + fn get(self) -> Vec<T> { + self.values + } +} + +pub struct Name { + serialize: String, + serialize_renamed: bool, + deserialize: String, + deserialize_renamed: bool, + deserialize_aliases: BTreeSet<String>, +} + +fn unraw(ident: &Ident) -> String { + ident.to_string().trim_start_matches("r#").to_owned() +} + +impl Name { + fn from_attrs( + source_name: String, + ser_name: Attr<String>, + de_name: Attr<String>, + de_aliases: Option<VecAttr<String>>, + ) -> Name { + let mut alias_set = BTreeSet::new(); + if let Some(de_aliases) = de_aliases { + for alias_name in de_aliases.get() { + alias_set.insert(alias_name); + } + } + + let ser_name = ser_name.get(); + let ser_renamed = ser_name.is_some(); + let de_name = de_name.get(); + let de_renamed = de_name.is_some(); + Name { + serialize: ser_name.unwrap_or_else(|| source_name.clone()), + serialize_renamed: ser_renamed, + deserialize: de_name.unwrap_or(source_name), + deserialize_renamed: de_renamed, + deserialize_aliases: alias_set, + } + } + + /// Return the container name for the container when serializing. + pub fn serialize_name(&self) -> &str { + &self.serialize + } + + /// Return the container name for the container when deserializing. + pub fn deserialize_name(&self) -> &str { + &self.deserialize + } + + fn deserialize_aliases(&self) -> &BTreeSet<String> { + &self.deserialize_aliases + } +} + +#[derive(Copy, Clone)] +pub struct RenameAllRules { + serialize: RenameRule, + deserialize: RenameRule, +} + +impl RenameAllRules { + /// Returns a new `RenameAllRules` with the individual rules of `self` and + /// `other_rules` joined by `RenameRules::or`. + pub fn or(self, other_rules: Self) -> Self { + Self { + serialize: self.serialize.or(other_rules.serialize), + deserialize: self.deserialize.or(other_rules.deserialize), + } + } +} + +/// Represents struct or enum attribute information. +pub struct Container { + name: Name, + transparent: bool, + deny_unknown_fields: bool, + default: Default, + rename_all_rules: RenameAllRules, + rename_all_fields_rules: RenameAllRules, + ser_bound: Option<Vec<syn::WherePredicate>>, + de_bound: Option<Vec<syn::WherePredicate>>, + tag: TagType, + type_from: Option<syn::Type>, + type_try_from: Option<syn::Type>, + type_into: Option<syn::Type>, + remote: Option<syn::Path>, + identifier: Identifier, + has_flatten: bool, + serde_path: Option<syn::Path>, + is_packed: bool, + /// Error message generated when type can't be deserialized + expecting: Option<String>, + non_exhaustive: bool, +} + +/// Styles of representing an enum. +pub enum TagType { + /// The default. + /// + /// ```json + /// {"variant1": {"key1": "value1", "key2": "value2"}} + /// ``` + External, + + /// `#[serde(tag = "type")]` + /// + /// ```json + /// {"type": "variant1", "key1": "value1", "key2": "value2"} + /// ``` + Internal { tag: String }, + + /// `#[serde(tag = "t", content = "c")]` + /// + /// ```json + /// {"t": "variant1", "c": {"key1": "value1", "key2": "value2"}} + /// ``` + Adjacent { tag: String, content: String }, + + /// `#[serde(untagged)]` + /// + /// ```json + /// {"key1": "value1", "key2": "value2"} + /// ``` + None, +} + +/// Whether this enum represents the fields of a struct or the variants of an +/// enum. +#[derive(Copy, Clone)] +pub enum Identifier { + /// It does not. + No, + + /// This enum represents the fields of a struct. All of the variants must be + /// unit variants, except possibly one which is annotated with + /// `#[serde(other)]` and is a newtype variant. + Field, + + /// This enum represents the variants of an enum. All of the variants must + /// be unit variants. + Variant, +} + +impl Identifier { + #[cfg(feature = "deserialize_in_place")] + pub fn is_some(self) -> bool { + match self { + Identifier::No => false, + Identifier::Field | Identifier::Variant => true, + } + } +} + +impl Container { + /// Extract out the `#[serde(...)]` attributes from an item. + pub fn from_ast(cx: &Ctxt, item: &syn::DeriveInput) -> Self { + let mut ser_name = Attr::none(cx, RENAME); + let mut de_name = Attr::none(cx, RENAME); + let mut transparent = BoolAttr::none(cx, TRANSPARENT); + let mut deny_unknown_fields = BoolAttr::none(cx, DENY_UNKNOWN_FIELDS); + let mut default = Attr::none(cx, DEFAULT); + let mut rename_all_ser_rule = Attr::none(cx, RENAME_ALL); + let mut rename_all_de_rule = Attr::none(cx, RENAME_ALL); + let mut rename_all_fields_ser_rule = Attr::none(cx, RENAME_ALL_FIELDS); + let mut rename_all_fields_de_rule = Attr::none(cx, RENAME_ALL_FIELDS); + let mut ser_bound = Attr::none(cx, BOUND); + let mut de_bound = Attr::none(cx, BOUND); + let mut untagged = BoolAttr::none(cx, UNTAGGED); + let mut internal_tag = Attr::none(cx, TAG); + let mut content = Attr::none(cx, CONTENT); + let mut type_from = Attr::none(cx, FROM); + let mut type_try_from = Attr::none(cx, TRY_FROM); + let mut type_into = Attr::none(cx, INTO); + let mut remote = Attr::none(cx, REMOTE); + let mut field_identifier = BoolAttr::none(cx, FIELD_IDENTIFIER); + let mut variant_identifier = BoolAttr::none(cx, VARIANT_IDENTIFIER); + let mut serde_path = Attr::none(cx, CRATE); + let mut expecting = Attr::none(cx, EXPECTING); + let mut non_exhaustive = false; + + for attr in &item.attrs { + if attr.path() != SERDE { + non_exhaustive |= + matches!(&attr.meta, syn::Meta::Path(path) if path == NON_EXHAUSTIVE); + continue; + } + + if let syn::Meta::List(meta) = &attr.meta { + if meta.tokens.is_empty() { + continue; + } + } + + if let Err(err) = attr.parse_nested_meta(|meta| { + if meta.path == RENAME { + // #[serde(rename = "foo")] + // #[serde(rename(serialize = "foo", deserialize = "bar"))] + let (ser, de) = get_renames(cx, RENAME, &meta)?; + ser_name.set_opt(&meta.path, ser.as_ref().map(syn::LitStr::value)); + de_name.set_opt(&meta.path, de.as_ref().map(syn::LitStr::value)); + } else if meta.path == RENAME_ALL { + // #[serde(rename_all = "foo")] + // #[serde(rename_all(serialize = "foo", deserialize = "bar"))] + let one_name = meta.input.peek(Token![=]); + let (ser, de) = get_renames(cx, RENAME_ALL, &meta)?; + if let Some(ser) = ser { + match RenameRule::from_str(&ser.value()) { + Ok(rename_rule) => rename_all_ser_rule.set(&meta.path, rename_rule), + Err(err) => cx.error_spanned_by(ser, err), + } + } + if let Some(de) = de { + match RenameRule::from_str(&de.value()) { + Ok(rename_rule) => rename_all_de_rule.set(&meta.path, rename_rule), + Err(err) => { + if !one_name { + cx.error_spanned_by(de, err); + } + } + } + } + } else if meta.path == RENAME_ALL_FIELDS { + // #[serde(rename_all_fields = "foo")] + // #[serde(rename_all_fields(serialize = "foo", deserialize = "bar"))] + let one_name = meta.input.peek(Token![=]); + let (ser, de) = get_renames(cx, RENAME_ALL_FIELDS, &meta)?; + + match item.data { + syn::Data::Enum(_) => { + if let Some(ser) = ser { + match RenameRule::from_str(&ser.value()) { + Ok(rename_rule) => { + rename_all_fields_ser_rule.set(&meta.path, rename_rule); + } + Err(err) => cx.error_spanned_by(ser, err), + } + } + if let Some(de) = de { + match RenameRule::from_str(&de.value()) { + Ok(rename_rule) => { + rename_all_fields_de_rule.set(&meta.path, rename_rule); + } + Err(err) => { + if !one_name { + cx.error_spanned_by(de, err); + } + } + } + } + } + syn::Data::Struct(_) => { + let msg = "#[serde(rename_all_fields)] can only be used on enums"; + cx.syn_error(meta.error(msg)); + } + syn::Data::Union(_) => { + let msg = "#[serde(rename_all_fields)] can only be used on enums"; + cx.syn_error(meta.error(msg)); + } + } + } else if meta.path == TRANSPARENT { + // #[serde(transparent)] + transparent.set_true(meta.path); + } else if meta.path == DENY_UNKNOWN_FIELDS { + // #[serde(deny_unknown_fields)] + deny_unknown_fields.set_true(meta.path); + } else if meta.path == DEFAULT { + if meta.input.peek(Token![=]) { + // #[serde(default = "...")] + if let Some(path) = parse_lit_into_expr_path(cx, DEFAULT, &meta)? { + match &item.data { + syn::Data::Struct(syn::DataStruct { fields, .. }) => match fields { + syn::Fields::Named(_) | syn::Fields::Unnamed(_) => { + default.set(&meta.path, Default::Path(path)); + } + syn::Fields::Unit => { + let msg = "#[serde(default = \"...\")] can only be used on structs that have fields"; + cx.syn_error(meta.error(msg)); + } + }, + syn::Data::Enum(_) => { + let msg = "#[serde(default = \"...\")] can only be used on structs"; + cx.syn_error(meta.error(msg)); + } + syn::Data::Union(_) => { + let msg = "#[serde(default = \"...\")] can only be used on structs"; + cx.syn_error(meta.error(msg)); + } + } + } + } else { + // #[serde(default)] + match &item.data { + syn::Data::Struct(syn::DataStruct { fields, .. }) => match fields { + syn::Fields::Named(_) | syn::Fields::Unnamed(_) => { + default.set(meta.path, Default::Default); + } + syn::Fields::Unit => { + let msg = "#[serde(default)] can only be used on structs that have fields"; + cx.error_spanned_by(fields, msg); + } + }, + syn::Data::Enum(_) => { + let msg = "#[serde(default)] can only be used on structs"; + cx.syn_error(meta.error(msg)); + } + syn::Data::Union(_) => { + let msg = "#[serde(default)] can only be used on structs"; + cx.syn_error(meta.error(msg)); + } + } + } + } else if meta.path == BOUND { + // #[serde(bound = "T: SomeBound")] + // #[serde(bound(serialize = "...", deserialize = "..."))] + let (ser, de) = get_where_predicates(cx, &meta)?; + ser_bound.set_opt(&meta.path, ser); + de_bound.set_opt(&meta.path, de); + } else if meta.path == UNTAGGED { + // #[serde(untagged)] + match item.data { + syn::Data::Enum(_) => { + untagged.set_true(&meta.path); + } + syn::Data::Struct(_) => { + let msg = "#[serde(untagged)] can only be used on enums"; + cx.syn_error(meta.error(msg)); + } + syn::Data::Union(_) => { + let msg = "#[serde(untagged)] can only be used on enums"; + cx.syn_error(meta.error(msg)); + } + } + } else if meta.path == TAG { + // #[serde(tag = "type")] + if let Some(s) = get_lit_str(cx, TAG, &meta)? { + match &item.data { + syn::Data::Enum(_) => { + internal_tag.set(&meta.path, s.value()); + } + syn::Data::Struct(syn::DataStruct { fields, .. }) => match fields { + syn::Fields::Named(_) => { + internal_tag.set(&meta.path, s.value()); + } + syn::Fields::Unnamed(_) | syn::Fields::Unit => { + let msg = "#[serde(tag = \"...\")] can only be used on enums and structs with named fields"; + cx.syn_error(meta.error(msg)); + } + }, + syn::Data::Union(_) => { + let msg = "#[serde(tag = \"...\")] can only be used on enums and structs with named fields"; + cx.syn_error(meta.error(msg)); + } + } + } + } else if meta.path == CONTENT { + // #[serde(content = "c")] + if let Some(s) = get_lit_str(cx, CONTENT, &meta)? { + match &item.data { + syn::Data::Enum(_) => { + content.set(&meta.path, s.value()); + } + syn::Data::Struct(_) => { + let msg = "#[serde(content = \"...\")] can only be used on enums"; + cx.syn_error(meta.error(msg)); + } + syn::Data::Union(_) => { + let msg = "#[serde(content = \"...\")] can only be used on enums"; + cx.syn_error(meta.error(msg)); + } + } + } + } else if meta.path == FROM { + // #[serde(from = "Type")] + if let Some(from_ty) = parse_lit_into_ty(cx, FROM, &meta)? { + type_from.set_opt(&meta.path, Some(from_ty)); + } + } else if meta.path == TRY_FROM { + // #[serde(try_from = "Type")] + if let Some(try_from_ty) = parse_lit_into_ty(cx, TRY_FROM, &meta)? { + type_try_from.set_opt(&meta.path, Some(try_from_ty)); + } + } else if meta.path == INTO { + // #[serde(into = "Type")] + if let Some(into_ty) = parse_lit_into_ty(cx, INTO, &meta)? { + type_into.set_opt(&meta.path, Some(into_ty)); + } + } else if meta.path == REMOTE { + // #[serde(remote = "...")] + if let Some(path) = parse_lit_into_path(cx, REMOTE, &meta)? { + if is_primitive_path(&path, "Self") { + remote.set(&meta.path, item.ident.clone().into()); + } else { + remote.set(&meta.path, path); + } + } + } else if meta.path == FIELD_IDENTIFIER { + // #[serde(field_identifier)] + field_identifier.set_true(&meta.path); + } else if meta.path == VARIANT_IDENTIFIER { + // #[serde(variant_identifier)] + variant_identifier.set_true(&meta.path); + } else if meta.path == CRATE { + // #[serde(crate = "foo")] + if let Some(path) = parse_lit_into_path(cx, CRATE, &meta)? { + serde_path.set(&meta.path, path); + } + } else if meta.path == EXPECTING { + // #[serde(expecting = "a message")] + if let Some(s) = get_lit_str(cx, EXPECTING, &meta)? { + expecting.set(&meta.path, s.value()); + } + } else { + let path = meta.path.to_token_stream().to_string().replace(' ', ""); + return Err( + meta.error(format_args!("unknown serde container attribute `{}`", path)) + ); + } + Ok(()) + }) { + cx.syn_error(err); + } + } + + let mut is_packed = false; + for attr in &item.attrs { + if attr.path() == REPR { + let _ = attr.parse_args_with(|input: ParseStream| { + while let Some(token) = input.parse()? { + if let TokenTree::Ident(ident) = token { + is_packed |= ident == "packed"; + } + } + Ok(()) + }); + } + } + + Container { + name: Name::from_attrs(unraw(&item.ident), ser_name, de_name, None), + transparent: transparent.get(), + deny_unknown_fields: deny_unknown_fields.get(), + default: default.get().unwrap_or(Default::None), + rename_all_rules: RenameAllRules { + serialize: rename_all_ser_rule.get().unwrap_or(RenameRule::None), + deserialize: rename_all_de_rule.get().unwrap_or(RenameRule::None), + }, + rename_all_fields_rules: RenameAllRules { + serialize: rename_all_fields_ser_rule.get().unwrap_or(RenameRule::None), + deserialize: rename_all_fields_de_rule.get().unwrap_or(RenameRule::None), + }, + ser_bound: ser_bound.get(), + de_bound: de_bound.get(), + tag: decide_tag(cx, item, untagged, internal_tag, content), + type_from: type_from.get(), + type_try_from: type_try_from.get(), + type_into: type_into.get(), + remote: remote.get(), + identifier: decide_identifier(cx, item, field_identifier, variant_identifier), + has_flatten: false, + serde_path: serde_path.get(), + is_packed, + expecting: expecting.get(), + non_exhaustive, + } + } + + pub fn name(&self) -> &Name { + &self.name + } + + pub fn rename_all_rules(&self) -> RenameAllRules { + self.rename_all_rules + } + + pub fn rename_all_fields_rules(&self) -> RenameAllRules { + self.rename_all_fields_rules + } + + pub fn transparent(&self) -> bool { + self.transparent + } + + pub fn deny_unknown_fields(&self) -> bool { + self.deny_unknown_fields + } + + pub fn default(&self) -> &Default { + &self.default + } + + pub fn ser_bound(&self) -> Option<&[syn::WherePredicate]> { + self.ser_bound.as_ref().map(|vec| &vec[..]) + } + + pub fn de_bound(&self) -> Option<&[syn::WherePredicate]> { + self.de_bound.as_ref().map(|vec| &vec[..]) + } + + pub fn tag(&self) -> &TagType { + &self.tag + } + + pub fn type_from(&self) -> Option<&syn::Type> { + self.type_from.as_ref() + } + + pub fn type_try_from(&self) -> Option<&syn::Type> { + self.type_try_from.as_ref() + } + + pub fn type_into(&self) -> Option<&syn::Type> { + self.type_into.as_ref() + } + + pub fn remote(&self) -> Option<&syn::Path> { + self.remote.as_ref() + } + + pub fn is_packed(&self) -> bool { + self.is_packed + } + + pub fn identifier(&self) -> Identifier { + self.identifier + } + + pub fn has_flatten(&self) -> bool { + self.has_flatten + } + + pub fn mark_has_flatten(&mut self) { + self.has_flatten = true; + } + + pub fn custom_serde_path(&self) -> Option<&syn::Path> { + self.serde_path.as_ref() + } + + pub fn serde_path(&self) -> Cow<syn::Path> { + self.custom_serde_path() + .map_or_else(|| Cow::Owned(parse_quote!(_serde)), Cow::Borrowed) + } + + /// Error message generated when type can't be deserialized. + /// If `None`, default message will be used + pub fn expecting(&self) -> Option<&str> { + self.expecting.as_ref().map(String::as_ref) + } + + pub fn non_exhaustive(&self) -> bool { + self.non_exhaustive + } +} + +fn decide_tag( + cx: &Ctxt, + item: &syn::DeriveInput, + untagged: BoolAttr, + internal_tag: Attr<String>, + content: Attr<String>, +) -> TagType { + match ( + untagged.0.get_with_tokens(), + internal_tag.get_with_tokens(), + content.get_with_tokens(), + ) { + (None, None, None) => TagType::External, + (Some(_), None, None) => TagType::None, + (None, Some((_, tag)), None) => { + // Check that there are no tuple variants. + if let syn::Data::Enum(data) = &item.data { + for variant in &data.variants { + match &variant.fields { + syn::Fields::Named(_) | syn::Fields::Unit => {} + syn::Fields::Unnamed(fields) => { + if fields.unnamed.len() != 1 { + let msg = + "#[serde(tag = \"...\")] cannot be used with tuple variants"; + cx.error_spanned_by(variant, msg); + break; + } + } + } + } + } + TagType::Internal { tag } + } + (Some((untagged_tokens, ())), Some((tag_tokens, _)), None) => { + let msg = "enum cannot be both untagged and internally tagged"; + cx.error_spanned_by(untagged_tokens, msg); + cx.error_spanned_by(tag_tokens, msg); + TagType::External // doesn't matter, will error + } + (None, None, Some((content_tokens, _))) => { + let msg = "#[serde(tag = \"...\", content = \"...\")] must be used together"; + cx.error_spanned_by(content_tokens, msg); + TagType::External + } + (Some((untagged_tokens, ())), None, Some((content_tokens, _))) => { + let msg = "untagged enum cannot have #[serde(content = \"...\")]"; + cx.error_spanned_by(untagged_tokens, msg); + cx.error_spanned_by(content_tokens, msg); + TagType::External + } + (None, Some((_, tag)), Some((_, content))) => TagType::Adjacent { tag, content }, + (Some((untagged_tokens, ())), Some((tag_tokens, _)), Some((content_tokens, _))) => { + let msg = "untagged enum cannot have #[serde(tag = \"...\", content = \"...\")]"; + cx.error_spanned_by(untagged_tokens, msg); + cx.error_spanned_by(tag_tokens, msg); + cx.error_spanned_by(content_tokens, msg); + TagType::External + } + } +} + +fn decide_identifier( + cx: &Ctxt, + item: &syn::DeriveInput, + field_identifier: BoolAttr, + variant_identifier: BoolAttr, +) -> Identifier { + match ( + &item.data, + field_identifier.0.get_with_tokens(), + variant_identifier.0.get_with_tokens(), + ) { + (_, None, None) => Identifier::No, + (_, Some((field_identifier_tokens, ())), Some((variant_identifier_tokens, ()))) => { + let msg = + "#[serde(field_identifier)] and #[serde(variant_identifier)] cannot both be set"; + cx.error_spanned_by(field_identifier_tokens, msg); + cx.error_spanned_by(variant_identifier_tokens, msg); + Identifier::No + } + (syn::Data::Enum(_), Some(_), None) => Identifier::Field, + (syn::Data::Enum(_), None, Some(_)) => Identifier::Variant, + (syn::Data::Struct(syn::DataStruct { struct_token, .. }), Some(_), None) => { + let msg = "#[serde(field_identifier)] can only be used on an enum"; + cx.error_spanned_by(struct_token, msg); + Identifier::No + } + (syn::Data::Union(syn::DataUnion { union_token, .. }), Some(_), None) => { + let msg = "#[serde(field_identifier)] can only be used on an enum"; + cx.error_spanned_by(union_token, msg); + Identifier::No + } + (syn::Data::Struct(syn::DataStruct { struct_token, .. }), None, Some(_)) => { + let msg = "#[serde(variant_identifier)] can only be used on an enum"; + cx.error_spanned_by(struct_token, msg); + Identifier::No + } + (syn::Data::Union(syn::DataUnion { union_token, .. }), None, Some(_)) => { + let msg = "#[serde(variant_identifier)] can only be used on an enum"; + cx.error_spanned_by(union_token, msg); + Identifier::No + } + } +} + +/// Represents variant attribute information +pub struct Variant { + name: Name, + rename_all_rules: RenameAllRules, + ser_bound: Option<Vec<syn::WherePredicate>>, + de_bound: Option<Vec<syn::WherePredicate>>, + skip_deserializing: bool, + skip_serializing: bool, + other: bool, + serialize_with: Option<syn::ExprPath>, + deserialize_with: Option<syn::ExprPath>, + borrow: Option<BorrowAttribute>, + untagged: bool, +} + +struct BorrowAttribute { + path: syn::Path, + lifetimes: Option<BTreeSet<syn::Lifetime>>, +} + +impl Variant { + pub fn from_ast(cx: &Ctxt, variant: &syn::Variant) -> Self { + let mut ser_name = Attr::none(cx, RENAME); + let mut de_name = Attr::none(cx, RENAME); + let mut de_aliases = VecAttr::none(cx, RENAME); + let mut skip_deserializing = BoolAttr::none(cx, SKIP_DESERIALIZING); + let mut skip_serializing = BoolAttr::none(cx, SKIP_SERIALIZING); + let mut rename_all_ser_rule = Attr::none(cx, RENAME_ALL); + let mut rename_all_de_rule = Attr::none(cx, RENAME_ALL); + let mut ser_bound = Attr::none(cx, BOUND); + let mut de_bound = Attr::none(cx, BOUND); + let mut other = BoolAttr::none(cx, OTHER); + let mut serialize_with = Attr::none(cx, SERIALIZE_WITH); + let mut deserialize_with = Attr::none(cx, DESERIALIZE_WITH); + let mut borrow = Attr::none(cx, BORROW); + let mut untagged = BoolAttr::none(cx, UNTAGGED); + + for attr in &variant.attrs { + if attr.path() != SERDE { + continue; + } + + if let syn::Meta::List(meta) = &attr.meta { + if meta.tokens.is_empty() { + continue; + } + } + + if let Err(err) = attr.parse_nested_meta(|meta| { + if meta.path == RENAME { + // #[serde(rename = "foo")] + // #[serde(rename(serialize = "foo", deserialize = "bar"))] + let (ser, de) = get_multiple_renames(cx, &meta)?; + ser_name.set_opt(&meta.path, ser.as_ref().map(syn::LitStr::value)); + for de_value in de { + de_name.set_if_none(de_value.value()); + de_aliases.insert(&meta.path, de_value.value()); + } + } else if meta.path == ALIAS { + // #[serde(alias = "foo")] + if let Some(s) = get_lit_str(cx, ALIAS, &meta)? { + de_aliases.insert(&meta.path, s.value()); + } + } else if meta.path == RENAME_ALL { + // #[serde(rename_all = "foo")] + // #[serde(rename_all(serialize = "foo", deserialize = "bar"))] + let one_name = meta.input.peek(Token![=]); + let (ser, de) = get_renames(cx, RENAME_ALL, &meta)?; + if let Some(ser) = ser { + match RenameRule::from_str(&ser.value()) { + Ok(rename_rule) => rename_all_ser_rule.set(&meta.path, rename_rule), + Err(err) => cx.error_spanned_by(ser, err), + } + } + if let Some(de) = de { + match RenameRule::from_str(&de.value()) { + Ok(rename_rule) => rename_all_de_rule.set(&meta.path, rename_rule), + Err(err) => { + if !one_name { + cx.error_spanned_by(de, err); + } + } + } + } + } else if meta.path == SKIP { + // #[serde(skip)] + skip_serializing.set_true(&meta.path); + skip_deserializing.set_true(&meta.path); + } else if meta.path == SKIP_DESERIALIZING { + // #[serde(skip_deserializing)] + skip_deserializing.set_true(&meta.path); + } else if meta.path == SKIP_SERIALIZING { + // #[serde(skip_serializing)] + skip_serializing.set_true(&meta.path); + } else if meta.path == OTHER { + // #[serde(other)] + other.set_true(&meta.path); + } else if meta.path == BOUND { + // #[serde(bound = "T: SomeBound")] + // #[serde(bound(serialize = "...", deserialize = "..."))] + let (ser, de) = get_where_predicates(cx, &meta)?; + ser_bound.set_opt(&meta.path, ser); + de_bound.set_opt(&meta.path, de); + } else if meta.path == WITH { + // #[serde(with = "...")] + if let Some(path) = parse_lit_into_expr_path(cx, WITH, &meta)? { + let mut ser_path = path.clone(); + ser_path + .path + .segments + .push(Ident::new("serialize", Span::call_site()).into()); + serialize_with.set(&meta.path, ser_path); + let mut de_path = path; + de_path + .path + .segments + .push(Ident::new("deserialize", Span::call_site()).into()); + deserialize_with.set(&meta.path, de_path); + } + } else if meta.path == SERIALIZE_WITH { + // #[serde(serialize_with = "...")] + if let Some(path) = parse_lit_into_expr_path(cx, SERIALIZE_WITH, &meta)? { + serialize_with.set(&meta.path, path); + } + } else if meta.path == DESERIALIZE_WITH { + // #[serde(deserialize_with = "...")] + if let Some(path) = parse_lit_into_expr_path(cx, DESERIALIZE_WITH, &meta)? { + deserialize_with.set(&meta.path, path); + } + } else if meta.path == BORROW { + let borrow_attribute = if meta.input.peek(Token![=]) { + // #[serde(borrow = "'a + 'b")] + let lifetimes = parse_lit_into_lifetimes(cx, &meta)?; + BorrowAttribute { + path: meta.path.clone(), + lifetimes: Some(lifetimes), + } + } else { + // #[serde(borrow)] + BorrowAttribute { + path: meta.path.clone(), + lifetimes: None, + } + }; + match &variant.fields { + syn::Fields::Unnamed(fields) if fields.unnamed.len() == 1 => { + borrow.set(&meta.path, borrow_attribute); + } + _ => { + let msg = "#[serde(borrow)] may only be used on newtype variants"; + cx.error_spanned_by(variant, msg); + } + } + } else if meta.path == UNTAGGED { + untagged.set_true(&meta.path); + } else { + let path = meta.path.to_token_stream().to_string().replace(' ', ""); + return Err( + meta.error(format_args!("unknown serde variant attribute `{}`", path)) + ); + } + Ok(()) + }) { + cx.syn_error(err); + } + } + + Variant { + name: Name::from_attrs(unraw(&variant.ident), ser_name, de_name, Some(de_aliases)), + rename_all_rules: RenameAllRules { + serialize: rename_all_ser_rule.get().unwrap_or(RenameRule::None), + deserialize: rename_all_de_rule.get().unwrap_or(RenameRule::None), + }, + ser_bound: ser_bound.get(), + de_bound: de_bound.get(), + skip_deserializing: skip_deserializing.get(), + skip_serializing: skip_serializing.get(), + other: other.get(), + serialize_with: serialize_with.get(), + deserialize_with: deserialize_with.get(), + borrow: borrow.get(), + untagged: untagged.get(), + } + } + + pub fn name(&self) -> &Name { + &self.name + } + + pub fn aliases(&self) -> &BTreeSet<String> { + self.name.deserialize_aliases() + } + + pub fn rename_by_rules(&mut self, rules: RenameAllRules) { + if !self.name.serialize_renamed { + self.name.serialize = rules.serialize.apply_to_variant(&self.name.serialize); + } + if !self.name.deserialize_renamed { + self.name.deserialize = rules.deserialize.apply_to_variant(&self.name.deserialize); + } + self.name + .deserialize_aliases + .insert(self.name.deserialize.clone()); + } + + pub fn rename_all_rules(&self) -> RenameAllRules { + self.rename_all_rules + } + + pub fn ser_bound(&self) -> Option<&[syn::WherePredicate]> { + self.ser_bound.as_ref().map(|vec| &vec[..]) + } + + pub fn de_bound(&self) -> Option<&[syn::WherePredicate]> { + self.de_bound.as_ref().map(|vec| &vec[..]) + } + + pub fn skip_deserializing(&self) -> bool { + self.skip_deserializing + } + + pub fn skip_serializing(&self) -> bool { + self.skip_serializing + } + + pub fn other(&self) -> bool { + self.other + } + + pub fn serialize_with(&self) -> Option<&syn::ExprPath> { + self.serialize_with.as_ref() + } + + pub fn deserialize_with(&self) -> Option<&syn::ExprPath> { + self.deserialize_with.as_ref() + } + + pub fn untagged(&self) -> bool { + self.untagged + } +} + +/// Represents field attribute information +pub struct Field { + name: Name, + skip_serializing: bool, + skip_deserializing: bool, + skip_serializing_if: Option<syn::ExprPath>, + default: Default, + serialize_with: Option<syn::ExprPath>, + deserialize_with: Option<syn::ExprPath>, + ser_bound: Option<Vec<syn::WherePredicate>>, + de_bound: Option<Vec<syn::WherePredicate>>, + borrowed_lifetimes: BTreeSet<syn::Lifetime>, + getter: Option<syn::ExprPath>, + flatten: bool, + transparent: bool, +} + +/// Represents the default to use for a field when deserializing. +pub enum Default { + /// 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(syn::ExprPath), +} + +impl Default { + pub fn is_none(&self) -> bool { + match self { + Default::None => true, + Default::Default | Default::Path(_) => false, + } + } +} + +impl Field { + /// Extract out the `#[serde(...)]` attributes from a struct field. + pub fn from_ast( + cx: &Ctxt, + index: usize, + field: &syn::Field, + attrs: Option<&Variant>, + container_default: &Default, + ) -> Self { + let mut ser_name = Attr::none(cx, RENAME); + let mut de_name = Attr::none(cx, RENAME); + let mut de_aliases = VecAttr::none(cx, RENAME); + let mut skip_serializing = BoolAttr::none(cx, SKIP_SERIALIZING); + let mut skip_deserializing = BoolAttr::none(cx, SKIP_DESERIALIZING); + let mut skip_serializing_if = Attr::none(cx, SKIP_SERIALIZING_IF); + let mut default = Attr::none(cx, DEFAULT); + let mut serialize_with = Attr::none(cx, SERIALIZE_WITH); + let mut deserialize_with = Attr::none(cx, DESERIALIZE_WITH); + let mut ser_bound = Attr::none(cx, BOUND); + let mut de_bound = Attr::none(cx, BOUND); + let mut borrowed_lifetimes = Attr::none(cx, BORROW); + let mut getter = Attr::none(cx, GETTER); + let mut flatten = BoolAttr::none(cx, FLATTEN); + + let ident = match &field.ident { + Some(ident) => unraw(ident), + None => index.to_string(), + }; + + if let Some(borrow_attribute) = attrs.and_then(|variant| variant.borrow.as_ref()) { + if let Ok(borrowable) = borrowable_lifetimes(cx, &ident, field) { + if let Some(lifetimes) = &borrow_attribute.lifetimes { + for lifetime in lifetimes { + if !borrowable.contains(lifetime) { + let msg = + format!("field `{}` does not have lifetime {}", ident, lifetime); + cx.error_spanned_by(field, msg); + } + } + borrowed_lifetimes.set(&borrow_attribute.path, lifetimes.clone()); + } else { + borrowed_lifetimes.set(&borrow_attribute.path, borrowable); + } + } + } + + for attr in &field.attrs { + if attr.path() != SERDE { + continue; + } + + if let syn::Meta::List(meta) = &attr.meta { + if meta.tokens.is_empty() { + continue; + } + } + + if let Err(err) = attr.parse_nested_meta(|meta| { + if meta.path == RENAME { + // #[serde(rename = "foo")] + // #[serde(rename(serialize = "foo", deserialize = "bar"))] + let (ser, de) = get_multiple_renames(cx, &meta)?; + ser_name.set_opt(&meta.path, ser.as_ref().map(syn::LitStr::value)); + for de_value in de { + de_name.set_if_none(de_value.value()); + de_aliases.insert(&meta.path, de_value.value()); + } + } else if meta.path == ALIAS { + // #[serde(alias = "foo")] + if let Some(s) = get_lit_str(cx, ALIAS, &meta)? { + de_aliases.insert(&meta.path, s.value()); + } + } else if meta.path == DEFAULT { + if meta.input.peek(Token![=]) { + // #[serde(default = "...")] + if let Some(path) = parse_lit_into_expr_path(cx, DEFAULT, &meta)? { + default.set(&meta.path, Default::Path(path)); + } + } else { + // #[serde(default)] + default.set(&meta.path, Default::Default); + } + } else if meta.path == SKIP_SERIALIZING { + // #[serde(skip_serializing)] + skip_serializing.set_true(&meta.path); + } else if meta.path == SKIP_DESERIALIZING { + // #[serde(skip_deserializing)] + skip_deserializing.set_true(&meta.path); + } else if meta.path == SKIP { + // #[serde(skip)] + skip_serializing.set_true(&meta.path); + skip_deserializing.set_true(&meta.path); + } else if meta.path == SKIP_SERIALIZING_IF { + // #[serde(skip_serializing_if = "...")] + if let Some(path) = parse_lit_into_expr_path(cx, SKIP_SERIALIZING_IF, &meta)? { + skip_serializing_if.set(&meta.path, path); + } + } else if meta.path == SERIALIZE_WITH { + // #[serde(serialize_with = "...")] + if let Some(path) = parse_lit_into_expr_path(cx, SERIALIZE_WITH, &meta)? { + serialize_with.set(&meta.path, path); + } + } else if meta.path == DESERIALIZE_WITH { + // #[serde(deserialize_with = "...")] + if let Some(path) = parse_lit_into_expr_path(cx, DESERIALIZE_WITH, &meta)? { + deserialize_with.set(&meta.path, path); + } + } else if meta.path == WITH { + // #[serde(with = "...")] + if let Some(path) = parse_lit_into_expr_path(cx, WITH, &meta)? { + let mut ser_path = path.clone(); + ser_path + .path + .segments + .push(Ident::new("serialize", Span::call_site()).into()); + serialize_with.set(&meta.path, ser_path); + let mut de_path = path; + de_path + .path + .segments + .push(Ident::new("deserialize", Span::call_site()).into()); + deserialize_with.set(&meta.path, de_path); + } + } else if meta.path == BOUND { + // #[serde(bound = "T: SomeBound")] + // #[serde(bound(serialize = "...", deserialize = "..."))] + let (ser, de) = get_where_predicates(cx, &meta)?; + ser_bound.set_opt(&meta.path, ser); + de_bound.set_opt(&meta.path, de); + } else if meta.path == BORROW { + if meta.input.peek(Token![=]) { + // #[serde(borrow = "'a + 'b")] + let lifetimes = parse_lit_into_lifetimes(cx, &meta)?; + if let Ok(borrowable) = borrowable_lifetimes(cx, &ident, field) { + for lifetime in &lifetimes { + if !borrowable.contains(lifetime) { + let msg = format!( + "field `{}` does not have lifetime {}", + ident, lifetime, + ); + cx.error_spanned_by(field, msg); + } + } + borrowed_lifetimes.set(&meta.path, lifetimes); + } + } else { + // #[serde(borrow)] + if let Ok(borrowable) = borrowable_lifetimes(cx, &ident, field) { + borrowed_lifetimes.set(&meta.path, borrowable); + } + } + } else if meta.path == GETTER { + // #[serde(getter = "...")] + if let Some(path) = parse_lit_into_expr_path(cx, GETTER, &meta)? { + getter.set(&meta.path, path); + } + } else if meta.path == FLATTEN { + // #[serde(flatten)] + flatten.set_true(&meta.path); + } else { + let path = meta.path.to_token_stream().to_string().replace(' ', ""); + return Err( + meta.error(format_args!("unknown serde field attribute `{}`", path)) + ); + } + Ok(()) + }) { + cx.syn_error(err); + } + } + + // Is skip_deserializing, initialize the field to Default::default() unless a + // different default is specified by `#[serde(default = "...")]` on + // ourselves or our container (e.g. the struct we are in). + if let Default::None = *container_default { + if skip_deserializing.0.value.is_some() { + default.set_if_none(Default::Default); + } + } + + let mut borrowed_lifetimes = borrowed_lifetimes.get().unwrap_or_default(); + if !borrowed_lifetimes.is_empty() { + // Cow<str> and Cow<[u8]> never borrow by default: + // + // impl<'de, 'a, T: ?Sized> Deserialize<'de> for Cow<'a, T> + // + // A #[serde(borrow)] attribute enables borrowing that corresponds + // roughly to these impls: + // + // impl<'de: 'a, 'a> Deserialize<'de> for Cow<'a, str> + // impl<'de: 'a, 'a> Deserialize<'de> for Cow<'a, [u8]> + if is_cow(&field.ty, is_str) { + let mut path = syn::Path { + leading_colon: None, + segments: Punctuated::new(), + }; + let span = Span::call_site(); + path.segments.push(Ident::new("_serde", span).into()); + path.segments.push(Ident::new("__private", span).into()); + path.segments.push(Ident::new("de", span).into()); + path.segments + .push(Ident::new("borrow_cow_str", span).into()); + let expr = syn::ExprPath { + attrs: Vec::new(), + qself: None, + path, + }; + deserialize_with.set_if_none(expr); + } else if is_cow(&field.ty, is_slice_u8) { + let mut path = syn::Path { + leading_colon: None, + segments: Punctuated::new(), + }; + let span = Span::call_site(); + path.segments.push(Ident::new("_serde", span).into()); + path.segments.push(Ident::new("__private", span).into()); + path.segments.push(Ident::new("de", span).into()); + path.segments + .push(Ident::new("borrow_cow_bytes", span).into()); + let expr = syn::ExprPath { + attrs: Vec::new(), + qself: None, + path, + }; + deserialize_with.set_if_none(expr); + } + } else if is_implicitly_borrowed(&field.ty) { + // Types &str and &[u8] are always implicitly borrowed. No need for + // a #[serde(borrow)]. + collect_lifetimes(&field.ty, &mut borrowed_lifetimes); + } + + Field { + name: Name::from_attrs(ident, ser_name, de_name, Some(de_aliases)), + skip_serializing: skip_serializing.get(), + skip_deserializing: skip_deserializing.get(), + skip_serializing_if: skip_serializing_if.get(), + default: default.get().unwrap_or(Default::None), + serialize_with: serialize_with.get(), + deserialize_with: deserialize_with.get(), + ser_bound: ser_bound.get(), + de_bound: de_bound.get(), + borrowed_lifetimes, + getter: getter.get(), + flatten: flatten.get(), + transparent: false, + } + } + + pub fn name(&self) -> &Name { + &self.name + } + + pub fn aliases(&self) -> &BTreeSet<String> { + self.name.deserialize_aliases() + } + + pub fn rename_by_rules(&mut self, rules: RenameAllRules) { + if !self.name.serialize_renamed { + self.name.serialize = rules.serialize.apply_to_field(&self.name.serialize); + } + if !self.name.deserialize_renamed { + self.name.deserialize = rules.deserialize.apply_to_field(&self.name.deserialize); + } + self.name + .deserialize_aliases + .insert(self.name.deserialize.clone()); + } + + pub fn skip_serializing(&self) -> bool { + self.skip_serializing + } + + pub fn skip_deserializing(&self) -> bool { + self.skip_deserializing + } + + pub fn skip_serializing_if(&self) -> Option<&syn::ExprPath> { + self.skip_serializing_if.as_ref() + } + + pub fn default(&self) -> &Default { + &self.default + } + + pub fn serialize_with(&self) -> Option<&syn::ExprPath> { + self.serialize_with.as_ref() + } + + pub fn deserialize_with(&self) -> Option<&syn::ExprPath> { + self.deserialize_with.as_ref() + } + + pub fn ser_bound(&self) -> Option<&[syn::WherePredicate]> { + self.ser_bound.as_ref().map(|vec| &vec[..]) + } + + pub fn de_bound(&self) -> Option<&[syn::WherePredicate]> { + self.de_bound.as_ref().map(|vec| &vec[..]) + } + + pub fn borrowed_lifetimes(&self) -> &BTreeSet<syn::Lifetime> { + &self.borrowed_lifetimes + } + + pub fn getter(&self) -> Option<&syn::ExprPath> { + self.getter.as_ref() + } + + pub fn flatten(&self) -> bool { + self.flatten + } + + pub fn transparent(&self) -> bool { + self.transparent + } + + pub fn mark_transparent(&mut self) { + self.transparent = true; + } +} + +type SerAndDe<T> = (Option<T>, Option<T>); + +fn get_ser_and_de<'c, T, F, R>( + cx: &'c Ctxt, + attr_name: Symbol, + meta: &ParseNestedMeta, + f: F, +) -> syn::Result<(VecAttr<'c, T>, VecAttr<'c, T>)> +where + T: Clone, + F: Fn(&Ctxt, Symbol, Symbol, &ParseNestedMeta) -> syn::Result<R>, + R: Into<Option<T>>, +{ + let mut ser_meta = VecAttr::none(cx, attr_name); + let mut de_meta = VecAttr::none(cx, attr_name); + + let lookahead = meta.input.lookahead1(); + if lookahead.peek(Token![=]) { + if let Some(both) = f(cx, attr_name, attr_name, meta)?.into() { + ser_meta.insert(&meta.path, both.clone()); + de_meta.insert(&meta.path, both); + } + } else if lookahead.peek(token::Paren) { + meta.parse_nested_meta(|meta| { + if meta.path == SERIALIZE { + if let Some(v) = f(cx, attr_name, SERIALIZE, &meta)?.into() { + ser_meta.insert(&meta.path, v); + } + } else if meta.path == DESERIALIZE { + if let Some(v) = f(cx, attr_name, DESERIALIZE, &meta)?.into() { + de_meta.insert(&meta.path, v); + } + } else { + return Err(meta.error(format_args!( + "malformed {0} attribute, expected `{0}(serialize = ..., deserialize = ...)`", + attr_name, + ))); + } + Ok(()) + })?; + } else { + return Err(lookahead.error()); + } + + Ok((ser_meta, de_meta)) +} + +fn get_renames( + cx: &Ctxt, + attr_name: Symbol, + meta: &ParseNestedMeta, +) -> syn::Result<SerAndDe<syn::LitStr>> { + let (ser, de) = get_ser_and_de(cx, attr_name, meta, get_lit_str2)?; + Ok((ser.at_most_one(), de.at_most_one())) +} + +fn get_multiple_renames( + cx: &Ctxt, + meta: &ParseNestedMeta, +) -> syn::Result<(Option<syn::LitStr>, Vec<syn::LitStr>)> { + let (ser, de) = get_ser_and_de(cx, RENAME, meta, get_lit_str2)?; + Ok((ser.at_most_one(), de.get())) +} + +fn get_where_predicates( + cx: &Ctxt, + meta: &ParseNestedMeta, +) -> syn::Result<SerAndDe<Vec<syn::WherePredicate>>> { + let (ser, de) = get_ser_and_de(cx, BOUND, meta, parse_lit_into_where)?; + Ok((ser.at_most_one(), de.at_most_one())) +} + +fn get_lit_str( + cx: &Ctxt, + attr_name: Symbol, + meta: &ParseNestedMeta, +) -> syn::Result<Option<syn::LitStr>> { + get_lit_str2(cx, attr_name, attr_name, meta) +} + +fn get_lit_str2( + cx: &Ctxt, + attr_name: Symbol, + meta_item_name: Symbol, + meta: &ParseNestedMeta, +) -> syn::Result<Option<syn::LitStr>> { + let expr: syn::Expr = meta.value()?.parse()?; + let mut value = &expr; + while let syn::Expr::Group(e) = value { + value = &e.expr; + } + if let syn::Expr::Lit(syn::ExprLit { + lit: syn::Lit::Str(lit), + .. + }) = value + { + let suffix = lit.suffix(); + if !suffix.is_empty() { + cx.error_spanned_by( + lit, + format!("unexpected suffix `{}` on string literal", suffix), + ); + } + Ok(Some(lit.clone())) + } else { + cx.error_spanned_by( + expr, + format!( + "expected serde {} attribute to be a string: `{} = \"...\"`", + attr_name, meta_item_name + ), + ); + Ok(None) + } +} + +fn parse_lit_into_path( + cx: &Ctxt, + attr_name: Symbol, + meta: &ParseNestedMeta, +) -> syn::Result<Option<syn::Path>> { + let string = match get_lit_str(cx, attr_name, meta)? { + Some(string) => string, + None => return Ok(None), + }; + + Ok(match string.parse() { + Ok(path) => Some(path), + Err(_) => { + cx.error_spanned_by( + &string, + format!("failed to parse path: {:?}", string.value()), + ); + None + } + }) +} + +fn parse_lit_into_expr_path( + cx: &Ctxt, + attr_name: Symbol, + meta: &ParseNestedMeta, +) -> syn::Result<Option<syn::ExprPath>> { + let string = match get_lit_str(cx, attr_name, meta)? { + Some(string) => string, + None => return Ok(None), + }; + + Ok(match string.parse() { + Ok(expr) => Some(expr), + Err(_) => { + cx.error_spanned_by( + &string, + format!("failed to parse path: {:?}", string.value()), + ); + None + } + }) +} + +fn parse_lit_into_where( + cx: &Ctxt, + attr_name: Symbol, + meta_item_name: Symbol, + meta: &ParseNestedMeta, +) -> syn::Result<Vec<syn::WherePredicate>> { + let string = match get_lit_str2(cx, attr_name, meta_item_name, meta)? { + Some(string) => string, + None => return Ok(Vec::new()), + }; + + Ok( + match string.parse_with(Punctuated::<syn::WherePredicate, Token![,]>::parse_terminated) { + Ok(predicates) => Vec::from_iter(predicates), + Err(err) => { + cx.error_spanned_by(string, err); + Vec::new() + } + }, + ) +} + +fn parse_lit_into_ty( + cx: &Ctxt, + attr_name: Symbol, + meta: &ParseNestedMeta, +) -> syn::Result<Option<syn::Type>> { + let string = match get_lit_str(cx, attr_name, meta)? { + Some(string) => string, + None => return Ok(None), + }; + + Ok(match string.parse() { + Ok(ty) => Some(ty), + Err(_) => { + cx.error_spanned_by( + &string, + format!("failed to parse type: {} = {:?}", attr_name, string.value()), + ); + None + } + }) +} + +// Parses a string literal like "'a + 'b + 'c" containing a nonempty list of +// lifetimes separated by `+`. +fn parse_lit_into_lifetimes( + cx: &Ctxt, + meta: &ParseNestedMeta, +) -> syn::Result<BTreeSet<syn::Lifetime>> { + let string = match get_lit_str(cx, BORROW, meta)? { + Some(string) => string, + None => return Ok(BTreeSet::new()), + }; + + if let Ok(lifetimes) = string.parse_with(|input: ParseStream| { + let mut set = BTreeSet::new(); + while !input.is_empty() { + let lifetime: Lifetime = input.parse()?; + if !set.insert(lifetime.clone()) { + cx.error_spanned_by( + &string, + format!("duplicate borrowed lifetime `{}`", lifetime), + ); + } + if input.is_empty() { + break; + } + input.parse::<Token![+]>()?; + } + Ok(set) + }) { + if lifetimes.is_empty() { + cx.error_spanned_by(string, "at least one lifetime must be borrowed"); + } + return Ok(lifetimes); + } + + cx.error_spanned_by( + &string, + format!("failed to parse borrowed lifetimes: {:?}", string.value()), + ); + Ok(BTreeSet::new()) +} + +fn is_implicitly_borrowed(ty: &syn::Type) -> bool { + is_implicitly_borrowed_reference(ty) || is_option(ty, is_implicitly_borrowed_reference) +} + +fn is_implicitly_borrowed_reference(ty: &syn::Type) -> bool { + is_reference(ty, is_str) || is_reference(ty, is_slice_u8) +} + +// Whether the type looks like it might be `std::borrow::Cow<T>` where elem="T". +// This can have false negatives and false positives. +// +// False negative: +// +// use std::borrow::Cow as Pig; +// +// #[derive(Deserialize)] +// struct S<'a> { +// #[serde(borrow)] +// pig: Pig<'a, str>, +// } +// +// False positive: +// +// type str = [i16]; +// +// #[derive(Deserialize)] +// struct S<'a> { +// #[serde(borrow)] +// cow: Cow<'a, str>, +// } +fn is_cow(ty: &syn::Type, elem: fn(&syn::Type) -> bool) -> bool { + let path = match ungroup(ty) { + syn::Type::Path(ty) => &ty.path, + _ => { + return false; + } + }; + let seg = match path.segments.last() { + Some(seg) => seg, + None => { + return false; + } + }; + let args = match &seg.arguments { + syn::PathArguments::AngleBracketed(bracketed) => &bracketed.args, + _ => { + return false; + } + }; + seg.ident == "Cow" + && args.len() == 2 + && match (&args[0], &args[1]) { + (syn::GenericArgument::Lifetime(_), syn::GenericArgument::Type(arg)) => elem(arg), + _ => false, + } +} + +fn is_option(ty: &syn::Type, elem: fn(&syn::Type) -> bool) -> bool { + let path = match ungroup(ty) { + syn::Type::Path(ty) => &ty.path, + _ => { + return false; + } + }; + let seg = match path.segments.last() { + Some(seg) => seg, + None => { + return false; + } + }; + let args = match &seg.arguments { + syn::PathArguments::AngleBracketed(bracketed) => &bracketed.args, + _ => { + return false; + } + }; + seg.ident == "Option" + && args.len() == 1 + && match &args[0] { + syn::GenericArgument::Type(arg) => elem(arg), + _ => false, + } +} + +// Whether the type looks like it might be `&T` where elem="T". This can have +// false negatives and false positives. +// +// False negative: +// +// type Yarn = str; +// +// #[derive(Deserialize)] +// struct S<'a> { +// r: &'a Yarn, +// } +// +// False positive: +// +// type str = [i16]; +// +// #[derive(Deserialize)] +// struct S<'a> { +// r: &'a str, +// } +fn is_reference(ty: &syn::Type, elem: fn(&syn::Type) -> bool) -> bool { + match ungroup(ty) { + syn::Type::Reference(ty) => ty.mutability.is_none() && elem(&ty.elem), + _ => false, + } +} + +fn is_str(ty: &syn::Type) -> bool { + is_primitive_type(ty, "str") +} + +fn is_slice_u8(ty: &syn::Type) -> bool { + match ungroup(ty) { + syn::Type::Slice(ty) => is_primitive_type(&ty.elem, "u8"), + _ => false, + } +} + +fn is_primitive_type(ty: &syn::Type, primitive: &str) -> bool { + match ungroup(ty) { + syn::Type::Path(ty) => ty.qself.is_none() && is_primitive_path(&ty.path, primitive), + _ => false, + } +} + +fn is_primitive_path(path: &syn::Path, primitive: &str) -> bool { + path.leading_colon.is_none() + && path.segments.len() == 1 + && path.segments[0].ident == primitive + && path.segments[0].arguments.is_empty() +} + +// All lifetimes that this type could borrow from a Deserializer. +// +// For example a type `S<'a, 'b>` could borrow `'a` and `'b`. On the other hand +// a type `for<'a> fn(&'a str)` could not borrow `'a` from the Deserializer. +// +// This is used when there is an explicit or implicit `#[serde(borrow)]` +// attribute on the field so there must be at least one borrowable lifetime. +fn borrowable_lifetimes( + cx: &Ctxt, + name: &str, + field: &syn::Field, +) -> Result<BTreeSet<syn::Lifetime>, ()> { + let mut lifetimes = BTreeSet::new(); + collect_lifetimes(&field.ty, &mut lifetimes); + if lifetimes.is_empty() { + let msg = format!("field `{}` has no lifetimes to borrow", name); + cx.error_spanned_by(field, msg); + Err(()) + } else { + Ok(lifetimes) + } +} + +fn collect_lifetimes(ty: &syn::Type, out: &mut BTreeSet<syn::Lifetime>) { + match ty { + #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] + syn::Type::Slice(ty) => { + collect_lifetimes(&ty.elem, out); + } + syn::Type::Array(ty) => { + collect_lifetimes(&ty.elem, out); + } + syn::Type::Ptr(ty) => { + collect_lifetimes(&ty.elem, out); + } + syn::Type::Reference(ty) => { + out.extend(ty.lifetime.iter().cloned()); + collect_lifetimes(&ty.elem, out); + } + syn::Type::Tuple(ty) => { + for elem in &ty.elems { + collect_lifetimes(elem, out); + } + } + syn::Type::Path(ty) => { + if let Some(qself) = &ty.qself { + collect_lifetimes(&qself.ty, out); + } + for seg in &ty.path.segments { + if let syn::PathArguments::AngleBracketed(bracketed) = &seg.arguments { + for arg in &bracketed.args { + match arg { + syn::GenericArgument::Lifetime(lifetime) => { + out.insert(lifetime.clone()); + } + syn::GenericArgument::Type(ty) => { + collect_lifetimes(ty, out); + } + syn::GenericArgument::AssocType(binding) => { + collect_lifetimes(&binding.ty, out); + } + syn::GenericArgument::Const(_) + | syn::GenericArgument::AssocConst(_) + | syn::GenericArgument::Constraint(_) + | _ => {} + } + } + } + } + } + syn::Type::Paren(ty) => { + collect_lifetimes(&ty.elem, out); + } + syn::Type::Group(ty) => { + collect_lifetimes(&ty.elem, out); + } + syn::Type::Macro(ty) => { + collect_lifetimes_from_tokens(ty.mac.tokens.clone(), out); + } + syn::Type::BareFn(_) + | syn::Type::Never(_) + | syn::Type::TraitObject(_) + | syn::Type::ImplTrait(_) + | syn::Type::Infer(_) + | syn::Type::Verbatim(_) => {} + + _ => {} + } +} + +fn collect_lifetimes_from_tokens(tokens: TokenStream, out: &mut BTreeSet<syn::Lifetime>) { + let mut iter = tokens.into_iter(); + while let Some(tt) = iter.next() { + match &tt { + TokenTree::Punct(op) if op.as_char() == '\'' && op.spacing() == Spacing::Joint => { + if let Some(TokenTree::Ident(ident)) = iter.next() { + out.insert(syn::Lifetime { + apostrophe: op.span(), + ident, + }); + } + } + TokenTree::Group(group) => { + let tokens = group.stream(); + collect_lifetimes_from_tokens(tokens, out); + } + _ => {} + } + } +} diff --git a/third_party/rust/serde_derive/src/internals/case.rs b/third_party/rust/serde_derive/src/internals/case.rs new file mode 100644 index 0000000000..8c8c02e757 --- /dev/null +++ b/third_party/rust/serde_derive/src/internals/case.rs @@ -0,0 +1,200 @@ +//! Code to convert the Rust-styled field/variant (e.g. `my_field`, `MyType`) to the +//! case of the source (e.g. `my-field`, `MY_FIELD`). + +use self::RenameRule::*; +use std::fmt::{self, Debug, Display}; + +/// The different possible ways to change case of fields in a struct, or variants in an enum. +#[derive(Copy, Clone, PartialEq)] +pub enum RenameRule { + /// Don't apply a default rename rule. + None, + /// Rename direct children to "lowercase" style. + LowerCase, + /// Rename direct children to "UPPERCASE" style. + UpperCase, + /// Rename direct children to "PascalCase" style, as typically used for + /// enum variants. + PascalCase, + /// Rename direct children to "camelCase" style. + CamelCase, + /// Rename direct children to "snake_case" style, as commonly used for + /// fields. + SnakeCase, + /// Rename direct children to "SCREAMING_SNAKE_CASE" style, as commonly + /// used for constants. + ScreamingSnakeCase, + /// Rename direct children to "kebab-case" style. + KebabCase, + /// Rename direct children to "SCREAMING-KEBAB-CASE" style. + ScreamingKebabCase, +} + +static RENAME_RULES: &[(&str, RenameRule)] = &[ + ("lowercase", LowerCase), + ("UPPERCASE", UpperCase), + ("PascalCase", PascalCase), + ("camelCase", CamelCase), + ("snake_case", SnakeCase), + ("SCREAMING_SNAKE_CASE", ScreamingSnakeCase), + ("kebab-case", KebabCase), + ("SCREAMING-KEBAB-CASE", ScreamingKebabCase), +]; + +impl RenameRule { + pub fn from_str(rename_all_str: &str) -> Result<Self, ParseError> { + for (name, rule) in RENAME_RULES { + if rename_all_str == *name { + return Ok(*rule); + } + } + Err(ParseError { + unknown: rename_all_str, + }) + } + + /// Apply a renaming rule to an enum variant, returning the version expected in the source. + pub fn apply_to_variant(self, variant: &str) -> String { + match self { + None | PascalCase => variant.to_owned(), + LowerCase => variant.to_ascii_lowercase(), + UpperCase => variant.to_ascii_uppercase(), + CamelCase => variant[..1].to_ascii_lowercase() + &variant[1..], + SnakeCase => { + let mut snake = String::new(); + for (i, ch) in variant.char_indices() { + if i > 0 && ch.is_uppercase() { + snake.push('_'); + } + snake.push(ch.to_ascii_lowercase()); + } + snake + } + ScreamingSnakeCase => SnakeCase.apply_to_variant(variant).to_ascii_uppercase(), + KebabCase => SnakeCase.apply_to_variant(variant).replace('_', "-"), + ScreamingKebabCase => ScreamingSnakeCase + .apply_to_variant(variant) + .replace('_', "-"), + } + } + + /// Apply a renaming rule to a struct field, returning the version expected in the source. + pub fn apply_to_field(self, field: &str) -> String { + match self { + None | LowerCase | SnakeCase => field.to_owned(), + UpperCase => field.to_ascii_uppercase(), + PascalCase => { + let mut pascal = String::new(); + let mut capitalize = true; + for ch in field.chars() { + if ch == '_' { + capitalize = true; + } else if capitalize { + pascal.push(ch.to_ascii_uppercase()); + capitalize = false; + } else { + pascal.push(ch); + } + } + pascal + } + CamelCase => { + let pascal = PascalCase.apply_to_field(field); + pascal[..1].to_ascii_lowercase() + &pascal[1..] + } + ScreamingSnakeCase => field.to_ascii_uppercase(), + KebabCase => field.replace('_', "-"), + ScreamingKebabCase => ScreamingSnakeCase.apply_to_field(field).replace('_', "-"), + } + } + + /// Returns the `RenameRule` if it is not `None`, `rule_b` otherwise. + pub fn or(self, rule_b: Self) -> Self { + match self { + None => rule_b, + _ => self, + } + } +} + +pub struct ParseError<'a> { + unknown: &'a str, +} + +impl<'a> Display for ParseError<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str("unknown rename rule `rename_all = ")?; + Debug::fmt(self.unknown, f)?; + f.write_str("`, expected one of ")?; + for (i, (name, _rule)) in RENAME_RULES.iter().enumerate() { + if i > 0 { + f.write_str(", ")?; + } + Debug::fmt(name, f)?; + } + Ok(()) + } +} + +#[test] +fn rename_variants() { + for &(original, lower, upper, camel, snake, screaming, kebab, screaming_kebab) in &[ + ( + "Outcome", "outcome", "OUTCOME", "outcome", "outcome", "OUTCOME", "outcome", "OUTCOME", + ), + ( + "VeryTasty", + "verytasty", + "VERYTASTY", + "veryTasty", + "very_tasty", + "VERY_TASTY", + "very-tasty", + "VERY-TASTY", + ), + ("A", "a", "A", "a", "a", "A", "a", "A"), + ("Z42", "z42", "Z42", "z42", "z42", "Z42", "z42", "Z42"), + ] { + assert_eq!(None.apply_to_variant(original), original); + assert_eq!(LowerCase.apply_to_variant(original), lower); + assert_eq!(UpperCase.apply_to_variant(original), upper); + assert_eq!(PascalCase.apply_to_variant(original), original); + assert_eq!(CamelCase.apply_to_variant(original), camel); + assert_eq!(SnakeCase.apply_to_variant(original), snake); + assert_eq!(ScreamingSnakeCase.apply_to_variant(original), screaming); + assert_eq!(KebabCase.apply_to_variant(original), kebab); + assert_eq!( + ScreamingKebabCase.apply_to_variant(original), + screaming_kebab + ); + } +} + +#[test] +fn rename_fields() { + for &(original, upper, pascal, camel, screaming, kebab, screaming_kebab) in &[ + ( + "outcome", "OUTCOME", "Outcome", "outcome", "OUTCOME", "outcome", "OUTCOME", + ), + ( + "very_tasty", + "VERY_TASTY", + "VeryTasty", + "veryTasty", + "VERY_TASTY", + "very-tasty", + "VERY-TASTY", + ), + ("a", "A", "A", "a", "A", "a", "A"), + ("z42", "Z42", "Z42", "z42", "Z42", "z42", "Z42"), + ] { + assert_eq!(None.apply_to_field(original), original); + assert_eq!(UpperCase.apply_to_field(original), upper); + assert_eq!(PascalCase.apply_to_field(original), pascal); + assert_eq!(CamelCase.apply_to_field(original), camel); + assert_eq!(SnakeCase.apply_to_field(original), original); + assert_eq!(ScreamingSnakeCase.apply_to_field(original), screaming); + assert_eq!(KebabCase.apply_to_field(original), kebab); + assert_eq!(ScreamingKebabCase.apply_to_field(original), screaming_kebab); + } +} diff --git a/third_party/rust/serde_derive/src/internals/check.rs b/third_party/rust/serde_derive/src/internals/check.rs new file mode 100644 index 0000000000..52b0f379fd --- /dev/null +++ b/third_party/rust/serde_derive/src/internals/check.rs @@ -0,0 +1,477 @@ +use crate::internals::ast::{Container, Data, Field, Style}; +use crate::internals::attr::{Default, Identifier, TagType}; +use crate::internals::{ungroup, Ctxt, Derive}; +use syn::{Member, Type}; + +// Cross-cutting checks that require looking at more than a single attrs object. +// Simpler checks should happen when parsing and building the attrs. +pub fn check(cx: &Ctxt, cont: &mut Container, derive: Derive) { + check_default_on_tuple(cx, cont); + check_remote_generic(cx, cont); + check_getter(cx, cont); + check_flatten(cx, cont); + check_identifier(cx, cont); + check_variant_skip_attrs(cx, cont); + check_internal_tag_field_name_conflict(cx, cont); + check_adjacent_tag_conflict(cx, cont); + check_transparent(cx, cont, derive); + check_from_and_try_from(cx, cont); +} + +// If some field of a tuple struct is marked #[serde(default)] then all fields +// after it must also be marked with that attribute, or the struct must have a +// container-level serde(default) attribute. A field's default value is only +// used for tuple fields if the sequence is exhausted at that point; that means +// all subsequent fields will fail to deserialize if they don't have their own +// default. +fn check_default_on_tuple(cx: &Ctxt, cont: &Container) { + if let Default::None = cont.attrs.default() { + if let Data::Struct(Style::Tuple, fields) = &cont.data { + let mut first_default_index = None; + for (i, field) in fields.iter().enumerate() { + // Skipped fields automatically get the #[serde(default)] + // attribute. We are interested only on non-skipped fields here. + if field.attrs.skip_deserializing() { + continue; + } + if let Default::None = field.attrs.default() { + if let Some(first) = first_default_index { + cx.error_spanned_by( + field.ty, + format!("field must have #[serde(default)] because previous field {} has #[serde(default)]", first), + ); + } + continue; + } + if first_default_index.is_none() { + first_default_index = Some(i); + } + } + } + } +} + +// Remote derive definition type must have either all of the generics of the +// remote type: +// +// #[serde(remote = "Generic")] +// struct Generic<T> {…} +// +// or none of them, i.e. defining impls for one concrete instantiation of the +// remote type only: +// +// #[serde(remote = "Generic<T>")] +// struct ConcreteDef {…} +// +fn check_remote_generic(cx: &Ctxt, cont: &Container) { + if let Some(remote) = cont.attrs.remote() { + let local_has_generic = !cont.generics.params.is_empty(); + let remote_has_generic = !remote.segments.last().unwrap().arguments.is_none(); + if local_has_generic && remote_has_generic { + cx.error_spanned_by(remote, "remove generic parameters from this path"); + } + } +} + +// Getters are only allowed inside structs (not enums) with the `remote` +// attribute. +fn check_getter(cx: &Ctxt, cont: &Container) { + match cont.data { + Data::Enum(_) => { + if cont.data.has_getter() { + cx.error_spanned_by( + cont.original, + "#[serde(getter = \"...\")] is not allowed in an enum", + ); + } + } + Data::Struct(_, _) => { + if cont.data.has_getter() && cont.attrs.remote().is_none() { + cx.error_spanned_by( + cont.original, + "#[serde(getter = \"...\")] can only be used in structs that have #[serde(remote = \"...\")]", + ); + } + } + } +} + +// Flattening has some restrictions we can test. +fn check_flatten(cx: &Ctxt, cont: &Container) { + match &cont.data { + Data::Enum(variants) => { + for variant in variants { + for field in &variant.fields { + check_flatten_field(cx, variant.style, field); + } + } + } + Data::Struct(style, fields) => { + for field in fields { + check_flatten_field(cx, *style, field); + } + } + } +} + +fn check_flatten_field(cx: &Ctxt, style: Style, field: &Field) { + if !field.attrs.flatten() { + return; + } + match style { + Style::Tuple => { + cx.error_spanned_by( + field.original, + "#[serde(flatten)] cannot be used on tuple structs", + ); + } + Style::Newtype => { + cx.error_spanned_by( + field.original, + "#[serde(flatten)] cannot be used on newtype structs", + ); + } + _ => {} + } +} + +// The `other` attribute must be used at most once and it must be the last +// variant of an enum. +// +// Inside a `variant_identifier` all variants must be unit variants. Inside a +// `field_identifier` all but possibly one variant must be unit variants. The +// last variant may be a newtype variant which is an implicit "other" case. +fn check_identifier(cx: &Ctxt, cont: &Container) { + let variants = match &cont.data { + Data::Enum(variants) => variants, + Data::Struct(_, _) => return, + }; + + for (i, variant) in variants.iter().enumerate() { + match ( + variant.style, + cont.attrs.identifier(), + variant.attrs.other(), + cont.attrs.tag(), + ) { + // The `other` attribute may not be used in a variant_identifier. + (_, Identifier::Variant, true, _) => { + cx.error_spanned_by( + variant.original, + "#[serde(other)] may not be used on a variant identifier", + ); + } + + // Variant with `other` attribute cannot appear in untagged enum + (_, Identifier::No, true, &TagType::None) => { + cx.error_spanned_by( + variant.original, + "#[serde(other)] cannot appear on untagged enum", + ); + } + + // Variant with `other` attribute must be the last one. + (Style::Unit, Identifier::Field, true, _) | (Style::Unit, Identifier::No, true, _) => { + if i < variants.len() - 1 { + cx.error_spanned_by( + variant.original, + "#[serde(other)] must be on the last variant", + ); + } + } + + // Variant with `other` attribute must be a unit variant. + (_, Identifier::Field, true, _) | (_, Identifier::No, true, _) => { + cx.error_spanned_by( + variant.original, + "#[serde(other)] must be on a unit variant", + ); + } + + // Any sort of variant is allowed if this is not an identifier. + (_, Identifier::No, false, _) => {} + + // Unit variant without `other` attribute is always fine. + (Style::Unit, _, false, _) => {} + + // The last field is allowed to be a newtype catch-all. + (Style::Newtype, Identifier::Field, false, _) => { + if i < variants.len() - 1 { + cx.error_spanned_by( + variant.original, + format!("`{}` must be the last variant", variant.ident), + ); + } + } + + (_, Identifier::Field, false, _) => { + cx.error_spanned_by( + variant.original, + "#[serde(field_identifier)] may only contain unit variants", + ); + } + + (_, Identifier::Variant, false, _) => { + cx.error_spanned_by( + variant.original, + "#[serde(variant_identifier)] may only contain unit variants", + ); + } + } + } +} + +// Skip-(de)serializing attributes are not allowed on variants marked +// (de)serialize_with. +fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) { + let variants = match &cont.data { + Data::Enum(variants) => variants, + Data::Struct(_, _) => return, + }; + + for variant in variants { + if variant.attrs.serialize_with().is_some() { + if variant.attrs.skip_serializing() { + cx.error_spanned_by( + variant.original, + format!( + "variant `{}` cannot have both #[serde(serialize_with)] and #[serde(skip_serializing)]", + variant.ident + ), + ); + } + + for field in &variant.fields { + let member = member_message(&field.member); + + if field.attrs.skip_serializing() { + cx.error_spanned_by( + variant.original, + format!( + "variant `{}` cannot have both #[serde(serialize_with)] and a field {} marked with #[serde(skip_serializing)]", + variant.ident, member + ), + ); + } + + if field.attrs.skip_serializing_if().is_some() { + cx.error_spanned_by( + variant.original, + format!( + "variant `{}` cannot have both #[serde(serialize_with)] and a field {} marked with #[serde(skip_serializing_if)]", + variant.ident, member + ), + ); + } + } + } + + if variant.attrs.deserialize_with().is_some() { + if variant.attrs.skip_deserializing() { + cx.error_spanned_by( + variant.original, + format!( + "variant `{}` cannot have both #[serde(deserialize_with)] and #[serde(skip_deserializing)]", + variant.ident + ), + ); + } + + for field in &variant.fields { + if field.attrs.skip_deserializing() { + let member = member_message(&field.member); + + cx.error_spanned_by( + variant.original, + format!( + "variant `{}` cannot have both #[serde(deserialize_with)] and a field {} marked with #[serde(skip_deserializing)]", + variant.ident, member + ), + ); + } + } + } + } +} + +// The tag of an internally-tagged struct variant must not be the same as either +// one of its fields, as this would result in duplicate keys in the serialized +// output and/or ambiguity in the to-be-deserialized input. +fn check_internal_tag_field_name_conflict(cx: &Ctxt, cont: &Container) { + let variants = match &cont.data { + Data::Enum(variants) => variants, + Data::Struct(_, _) => return, + }; + + let tag = match cont.attrs.tag() { + TagType::Internal { tag } => tag.as_str(), + TagType::External | TagType::Adjacent { .. } | TagType::None => return, + }; + + let diagnose_conflict = || { + cx.error_spanned_by( + cont.original, + format!("variant field name `{}` conflicts with internal tag", tag), + ); + }; + + for variant in variants { + match variant.style { + Style::Struct => { + if variant.attrs.untagged() { + continue; + } + for field in &variant.fields { + let check_ser = + !(field.attrs.skip_serializing() || variant.attrs.skip_serializing()); + let check_de = + !(field.attrs.skip_deserializing() || variant.attrs.skip_deserializing()); + let name = field.attrs.name(); + let ser_name = name.serialize_name(); + + if check_ser && ser_name == tag { + diagnose_conflict(); + return; + } + + for de_name in field.attrs.aliases() { + if check_de && de_name == tag { + diagnose_conflict(); + return; + } + } + } + } + Style::Unit | Style::Newtype | Style::Tuple => {} + } + } +} + +// In the case of adjacently-tagged enums, the type and the contents tag must +// differ, for the same reason. +fn check_adjacent_tag_conflict(cx: &Ctxt, cont: &Container) { + let (type_tag, content_tag) = match cont.attrs.tag() { + TagType::Adjacent { tag, content } => (tag, content), + TagType::Internal { .. } | TagType::External | TagType::None => return, + }; + + if type_tag == content_tag { + cx.error_spanned_by( + cont.original, + format!( + "enum tags `{}` for type and content conflict with each other", + type_tag + ), + ); + } +} + +// Enums and unit structs cannot be transparent. +fn check_transparent(cx: &Ctxt, cont: &mut Container, derive: Derive) { + if !cont.attrs.transparent() { + return; + } + + if cont.attrs.type_from().is_some() { + cx.error_spanned_by( + cont.original, + "#[serde(transparent)] is not allowed with #[serde(from = \"...\")]", + ); + } + + if cont.attrs.type_try_from().is_some() { + cx.error_spanned_by( + cont.original, + "#[serde(transparent)] is not allowed with #[serde(try_from = \"...\")]", + ); + } + + if cont.attrs.type_into().is_some() { + cx.error_spanned_by( + cont.original, + "#[serde(transparent)] is not allowed with #[serde(into = \"...\")]", + ); + } + + let fields = match &mut cont.data { + Data::Enum(_) => { + cx.error_spanned_by( + cont.original, + "#[serde(transparent)] is not allowed on an enum", + ); + return; + } + Data::Struct(Style::Unit, _) => { + cx.error_spanned_by( + cont.original, + "#[serde(transparent)] is not allowed on a unit struct", + ); + return; + } + Data::Struct(_, fields) => fields, + }; + + let mut transparent_field = None; + + for field in fields { + if allow_transparent(field, derive) { + if transparent_field.is_some() { + cx.error_spanned_by( + cont.original, + "#[serde(transparent)] requires struct to have at most one transparent field", + ); + return; + } + transparent_field = Some(field); + } + } + + match transparent_field { + Some(transparent_field) => transparent_field.attrs.mark_transparent(), + None => match derive { + Derive::Serialize => { + cx.error_spanned_by( + cont.original, + "#[serde(transparent)] requires at least one field that is not skipped", + ); + } + Derive::Deserialize => { + cx.error_spanned_by( + cont.original, + "#[serde(transparent)] requires at least one field that is neither skipped nor has a default", + ); + } + }, + } +} + +fn member_message(member: &Member) -> String { + match member { + Member::Named(ident) => format!("`{}`", ident), + Member::Unnamed(i) => format!("#{}", i.index), + } +} + +fn allow_transparent(field: &Field, derive: Derive) -> bool { + if let Type::Path(ty) = ungroup(field.ty) { + if let Some(seg) = ty.path.segments.last() { + if seg.ident == "PhantomData" { + return false; + } + } + } + + match derive { + Derive::Serialize => !field.attrs.skip_serializing(), + Derive::Deserialize => !field.attrs.skip_deserializing() && field.attrs.default().is_none(), + } +} + +fn check_from_and_try_from(cx: &Ctxt, cont: &mut Container) { + if cont.attrs.type_from().is_some() && cont.attrs.type_try_from().is_some() { + cx.error_spanned_by( + cont.original, + "#[serde(from = \"...\")] and #[serde(try_from = \"...\")] conflict with each other", + ); + } +} diff --git a/third_party/rust/serde_derive/src/internals/ctxt.rs b/third_party/rust/serde_derive/src/internals/ctxt.rs new file mode 100644 index 0000000000..a47bfa4102 --- /dev/null +++ b/third_party/rust/serde_derive/src/internals/ctxt.rs @@ -0,0 +1,68 @@ +use quote::ToTokens; +use std::cell::RefCell; +use std::fmt::Display; +use std::thread; + +/// A type to collect errors together and format them. +/// +/// Dropping this object will cause a panic. It must be consumed using `check`. +/// +/// References can be shared since this type uses run-time exclusive mut checking. +#[derive(Default)] +pub struct Ctxt { + // The contents will be set to `None` during checking. This is so that checking can be + // enforced. + errors: RefCell<Option<Vec<syn::Error>>>, +} + +impl Ctxt { + /// Create a new context object. + /// + /// This object contains no errors, but will still trigger a panic if it is not `check`ed. + pub fn new() -> Self { + Ctxt { + errors: RefCell::new(Some(Vec::new())), + } + } + + /// Add an error to the context object with a tokenenizable object. + /// + /// The object is used for spanning in error messages. + pub fn error_spanned_by<A: ToTokens, T: Display>(&self, obj: A, msg: T) { + self.errors + .borrow_mut() + .as_mut() + .unwrap() + // Curb monomorphization from generating too many identical methods. + .push(syn::Error::new_spanned(obj.into_token_stream(), msg)); + } + + /// Add one of Syn's parse errors. + pub fn syn_error(&self, err: syn::Error) { + self.errors.borrow_mut().as_mut().unwrap().push(err); + } + + /// Consume this object, producing a formatted error string if there are errors. + pub fn check(self) -> syn::Result<()> { + let mut errors = self.errors.borrow_mut().take().unwrap().into_iter(); + + let mut combined = match errors.next() { + Some(first) => first, + None => return Ok(()), + }; + + for rest in errors { + combined.combine(rest); + } + + Err(combined) + } +} + +impl Drop for Ctxt { + fn drop(&mut self) { + if !thread::panicking() && self.errors.borrow().is_some() { + panic!("forgot to check for errors"); + } + } +} diff --git a/third_party/rust/serde_derive/src/internals/mod.rs b/third_party/rust/serde_derive/src/internals/mod.rs new file mode 100644 index 0000000000..f98ef08e8c --- /dev/null +++ b/third_party/rust/serde_derive/src/internals/mod.rs @@ -0,0 +1,27 @@ +pub mod ast; +pub mod attr; + +mod case; +mod check; +mod ctxt; +mod receiver; +mod respan; +mod symbol; + +use syn::Type; + +pub use self::ctxt::Ctxt; +pub use self::receiver::replace_receiver; + +#[derive(Copy, Clone)] +pub enum Derive { + Serialize, + Deserialize, +} + +pub fn ungroup(mut ty: &Type) -> &Type { + while let Type::Group(group) = ty { + ty = &group.elem; + } + ty +} diff --git a/third_party/rust/serde_derive/src/internals/receiver.rs b/third_party/rust/serde_derive/src/internals/receiver.rs new file mode 100644 index 0000000000..fa2a77d240 --- /dev/null +++ b/third_party/rust/serde_derive/src/internals/receiver.rs @@ -0,0 +1,292 @@ +use crate::internals::respan::respan; +use proc_macro2::Span; +use quote::ToTokens; +use std::mem; +use syn::punctuated::Punctuated; +use syn::{ + parse_quote, Data, DeriveInput, Expr, ExprPath, GenericArgument, GenericParam, Generics, Macro, + Path, PathArguments, QSelf, ReturnType, Token, Type, TypeParamBound, TypePath, WherePredicate, +}; + +pub fn replace_receiver(input: &mut DeriveInput) { + let self_ty = { + let ident = &input.ident; + let ty_generics = input.generics.split_for_impl().1; + parse_quote!(#ident #ty_generics) + }; + let mut visitor = ReplaceReceiver(&self_ty); + visitor.visit_generics_mut(&mut input.generics); + visitor.visit_data_mut(&mut input.data); +} + +struct ReplaceReceiver<'a>(&'a TypePath); + +impl ReplaceReceiver<'_> { + fn self_ty(&self, span: Span) -> TypePath { + let tokens = self.0.to_token_stream(); + let respanned = respan(tokens, span); + syn::parse2(respanned).unwrap() + } + + fn self_to_qself(&self, qself: &mut Option<QSelf>, path: &mut Path) { + if path.leading_colon.is_some() || path.segments[0].ident != "Self" { + return; + } + + if path.segments.len() == 1 { + self.self_to_expr_path(path); + return; + } + + let span = path.segments[0].ident.span(); + *qself = Some(QSelf { + lt_token: Token![<](span), + ty: Box::new(Type::Path(self.self_ty(span))), + position: 0, + as_token: None, + gt_token: Token![>](span), + }); + + path.leading_colon = Some(**path.segments.pairs().next().unwrap().punct().unwrap()); + + let segments = mem::replace(&mut path.segments, Punctuated::new()); + path.segments = segments.into_pairs().skip(1).collect(); + } + + fn self_to_expr_path(&self, path: &mut Path) { + let self_ty = self.self_ty(path.segments[0].ident.span()); + let variant = mem::replace(path, self_ty.path); + for segment in &mut path.segments { + if let PathArguments::AngleBracketed(bracketed) = &mut segment.arguments { + if bracketed.colon2_token.is_none() && !bracketed.args.is_empty() { + bracketed.colon2_token = Some(<Token![::]>::default()); + } + } + } + if variant.segments.len() > 1 { + path.segments.push_punct(<Token![::]>::default()); + path.segments.extend(variant.segments.into_pairs().skip(1)); + } + } +} + +impl ReplaceReceiver<'_> { + // `Self` -> `Receiver` + fn visit_type_mut(&mut self, ty: &mut Type) { + let span = if let Type::Path(node) = ty { + if node.qself.is_none() && node.path.is_ident("Self") { + node.path.segments[0].ident.span() + } else { + self.visit_type_path_mut(node); + return; + } + } else { + self.visit_type_mut_impl(ty); + return; + }; + *ty = self.self_ty(span).into(); + } + + // `Self::Assoc` -> `<Receiver>::Assoc` + fn visit_type_path_mut(&mut self, ty: &mut TypePath) { + if ty.qself.is_none() { + self.self_to_qself(&mut ty.qself, &mut ty.path); + } + self.visit_type_path_mut_impl(ty); + } + + // `Self::method` -> `<Receiver>::method` + fn visit_expr_path_mut(&mut self, expr: &mut ExprPath) { + if expr.qself.is_none() { + self.self_to_qself(&mut expr.qself, &mut expr.path); + } + self.visit_expr_path_mut_impl(expr); + } + + // Everything below is simply traversing the syntax tree. + + fn visit_type_mut_impl(&mut self, ty: &mut Type) { + match ty { + #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] + Type::Array(ty) => { + self.visit_type_mut(&mut ty.elem); + self.visit_expr_mut(&mut ty.len); + } + Type::BareFn(ty) => { + for arg in &mut ty.inputs { + self.visit_type_mut(&mut arg.ty); + } + self.visit_return_type_mut(&mut ty.output); + } + Type::Group(ty) => self.visit_type_mut(&mut ty.elem), + Type::ImplTrait(ty) => { + for bound in &mut ty.bounds { + self.visit_type_param_bound_mut(bound); + } + } + Type::Macro(ty) => self.visit_macro_mut(&mut ty.mac), + Type::Paren(ty) => self.visit_type_mut(&mut ty.elem), + Type::Path(ty) => { + if let Some(qself) = &mut ty.qself { + self.visit_type_mut(&mut qself.ty); + } + self.visit_path_mut(&mut ty.path); + } + Type::Ptr(ty) => self.visit_type_mut(&mut ty.elem), + Type::Reference(ty) => self.visit_type_mut(&mut ty.elem), + Type::Slice(ty) => self.visit_type_mut(&mut ty.elem), + Type::TraitObject(ty) => { + for bound in &mut ty.bounds { + self.visit_type_param_bound_mut(bound); + } + } + Type::Tuple(ty) => { + for elem in &mut ty.elems { + self.visit_type_mut(elem); + } + } + + Type::Infer(_) | Type::Never(_) | Type::Verbatim(_) => {} + + _ => {} + } + } + + fn visit_type_path_mut_impl(&mut self, ty: &mut TypePath) { + if let Some(qself) = &mut ty.qself { + self.visit_type_mut(&mut qself.ty); + } + self.visit_path_mut(&mut ty.path); + } + + fn visit_expr_path_mut_impl(&mut self, expr: &mut ExprPath) { + if let Some(qself) = &mut expr.qself { + self.visit_type_mut(&mut qself.ty); + } + self.visit_path_mut(&mut expr.path); + } + + fn visit_path_mut(&mut self, path: &mut Path) { + for segment in &mut path.segments { + self.visit_path_arguments_mut(&mut segment.arguments); + } + } + + fn visit_path_arguments_mut(&mut self, arguments: &mut PathArguments) { + match arguments { + PathArguments::None => {} + PathArguments::AngleBracketed(arguments) => { + for arg in &mut arguments.args { + match arg { + #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] + GenericArgument::Type(arg) => self.visit_type_mut(arg), + GenericArgument::AssocType(arg) => self.visit_type_mut(&mut arg.ty), + GenericArgument::Lifetime(_) + | GenericArgument::Const(_) + | GenericArgument::AssocConst(_) + | GenericArgument::Constraint(_) => {} + _ => {} + } + } + } + PathArguments::Parenthesized(arguments) => { + for argument in &mut arguments.inputs { + self.visit_type_mut(argument); + } + self.visit_return_type_mut(&mut arguments.output); + } + } + } + + fn visit_return_type_mut(&mut self, return_type: &mut ReturnType) { + match return_type { + ReturnType::Default => {} + ReturnType::Type(_, output) => self.visit_type_mut(output), + } + } + + fn visit_type_param_bound_mut(&mut self, bound: &mut TypeParamBound) { + match bound { + #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] + TypeParamBound::Trait(bound) => self.visit_path_mut(&mut bound.path), + TypeParamBound::Lifetime(_) | TypeParamBound::Verbatim(_) => {} + _ => {} + } + } + + fn visit_generics_mut(&mut self, generics: &mut Generics) { + for param in &mut generics.params { + match param { + GenericParam::Type(param) => { + for bound in &mut param.bounds { + self.visit_type_param_bound_mut(bound); + } + } + GenericParam::Lifetime(_) | GenericParam::Const(_) => {} + } + } + if let Some(where_clause) = &mut generics.where_clause { + for predicate in &mut where_clause.predicates { + match predicate { + #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] + WherePredicate::Type(predicate) => { + self.visit_type_mut(&mut predicate.bounded_ty); + for bound in &mut predicate.bounds { + self.visit_type_param_bound_mut(bound); + } + } + WherePredicate::Lifetime(_) => {} + _ => {} + } + } + } + } + + fn visit_data_mut(&mut self, data: &mut Data) { + match data { + Data::Struct(data) => { + for field in &mut data.fields { + self.visit_type_mut(&mut field.ty); + } + } + Data::Enum(data) => { + for variant in &mut data.variants { + for field in &mut variant.fields { + self.visit_type_mut(&mut field.ty); + } + } + } + Data::Union(_) => {} + } + } + + fn visit_expr_mut(&mut self, expr: &mut Expr) { + match expr { + Expr::Binary(expr) => { + self.visit_expr_mut(&mut expr.left); + self.visit_expr_mut(&mut expr.right); + } + Expr::Call(expr) => { + self.visit_expr_mut(&mut expr.func); + for arg in &mut expr.args { + self.visit_expr_mut(arg); + } + } + Expr::Cast(expr) => { + self.visit_expr_mut(&mut expr.expr); + self.visit_type_mut(&mut expr.ty); + } + Expr::Field(expr) => self.visit_expr_mut(&mut expr.base), + Expr::Index(expr) => { + self.visit_expr_mut(&mut expr.expr); + self.visit_expr_mut(&mut expr.index); + } + Expr::Paren(expr) => self.visit_expr_mut(&mut expr.expr), + Expr::Path(expr) => self.visit_expr_path_mut(expr), + Expr::Unary(expr) => self.visit_expr_mut(&mut expr.expr), + _ => {} + } + } + + fn visit_macro_mut(&mut self, _mac: &mut Macro) {} +} diff --git a/third_party/rust/serde_derive/src/internals/respan.rs b/third_party/rust/serde_derive/src/internals/respan.rs new file mode 100644 index 0000000000..dcec7017b3 --- /dev/null +++ b/third_party/rust/serde_derive/src/internals/respan.rs @@ -0,0 +1,16 @@ +use proc_macro2::{Group, Span, TokenStream, TokenTree}; + +pub(crate) fn respan(stream: TokenStream, span: Span) -> TokenStream { + stream + .into_iter() + .map(|token| respan_token(token, span)) + .collect() +} + +fn respan_token(mut token: TokenTree, span: Span) -> TokenTree { + if let TokenTree::Group(g) = &mut token { + *g = Group::new(g.delimiter(), respan(g.stream(), span)); + } + token.set_span(span); + token +} diff --git a/third_party/rust/serde_derive/src/internals/symbol.rs b/third_party/rust/serde_derive/src/internals/symbol.rs new file mode 100644 index 0000000000..572391a807 --- /dev/null +++ b/third_party/rust/serde_derive/src/internals/symbol.rs @@ -0,0 +1,71 @@ +use std::fmt::{self, Display}; +use syn::{Ident, Path}; + +#[derive(Copy, Clone)] +pub struct Symbol(&'static str); + +pub const ALIAS: Symbol = Symbol("alias"); +pub const BORROW: Symbol = Symbol("borrow"); +pub const BOUND: Symbol = Symbol("bound"); +pub const CONTENT: Symbol = Symbol("content"); +pub const CRATE: Symbol = Symbol("crate"); +pub const DEFAULT: Symbol = Symbol("default"); +pub const DENY_UNKNOWN_FIELDS: Symbol = Symbol("deny_unknown_fields"); +pub const DESERIALIZE: Symbol = Symbol("deserialize"); +pub const DESERIALIZE_WITH: Symbol = Symbol("deserialize_with"); +pub const EXPECTING: Symbol = Symbol("expecting"); +pub const FIELD_IDENTIFIER: Symbol = Symbol("field_identifier"); +pub const FLATTEN: Symbol = Symbol("flatten"); +pub const FROM: Symbol = Symbol("from"); +pub const GETTER: Symbol = Symbol("getter"); +pub const INTO: Symbol = Symbol("into"); +pub const NON_EXHAUSTIVE: Symbol = Symbol("non_exhaustive"); +pub const OTHER: Symbol = Symbol("other"); +pub const REMOTE: Symbol = Symbol("remote"); +pub const RENAME: Symbol = Symbol("rename"); +pub const RENAME_ALL: Symbol = Symbol("rename_all"); +pub const RENAME_ALL_FIELDS: Symbol = Symbol("rename_all_fields"); +pub const REPR: Symbol = Symbol("repr"); +pub const SERDE: Symbol = Symbol("serde"); +pub const SERIALIZE: Symbol = Symbol("serialize"); +pub const SERIALIZE_WITH: Symbol = Symbol("serialize_with"); +pub const SKIP: Symbol = Symbol("skip"); +pub const SKIP_DESERIALIZING: Symbol = Symbol("skip_deserializing"); +pub const SKIP_SERIALIZING: Symbol = Symbol("skip_serializing"); +pub const SKIP_SERIALIZING_IF: Symbol = Symbol("skip_serializing_if"); +pub const TAG: Symbol = Symbol("tag"); +pub const TRANSPARENT: Symbol = Symbol("transparent"); +pub const TRY_FROM: Symbol = Symbol("try_from"); +pub const UNTAGGED: Symbol = Symbol("untagged"); +pub const VARIANT_IDENTIFIER: Symbol = Symbol("variant_identifier"); +pub const WITH: Symbol = Symbol("with"); + +impl PartialEq<Symbol> for Ident { + fn eq(&self, word: &Symbol) -> bool { + self == word.0 + } +} + +impl<'a> PartialEq<Symbol> for &'a Ident { + fn eq(&self, word: &Symbol) -> bool { + *self == word.0 + } +} + +impl PartialEq<Symbol> for Path { + fn eq(&self, word: &Symbol) -> bool { + self.is_ident(word.0) + } +} + +impl<'a> PartialEq<Symbol> for &'a Path { + fn eq(&self, word: &Symbol) -> bool { + self.is_ident(word.0) + } +} + +impl Display for Symbol { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str(self.0) + } +} diff --git a/third_party/rust/serde_derive/src/lib.rs b/third_party/rust/serde_derive/src/lib.rs new file mode 100644 index 0000000000..8c4a6cacc7 --- /dev/null +++ b/third_party/rust/serde_derive/src/lib.rs @@ -0,0 +1,101 @@ +//! This crate provides Serde's two derive macros. +//! +//! ```edition2021 +//! # use serde_derive::{Deserialize, Serialize}; +//! # +//! #[derive(Serialize, Deserialize)] +//! # struct S; +//! # +//! # fn main() {} +//! ``` +//! +//! Please refer to [https://serde.rs/derive.html] for how to set this up. +//! +//! [https://serde.rs/derive.html]: https://serde.rs/derive.html + +#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.195")] +// Ignored clippy lints +#![allow( + // clippy false positive: https://github.com/rust-lang/rust-clippy/issues/7054 + clippy::branches_sharing_code, + clippy::cognitive_complexity, + // clippy bug: https://github.com/rust-lang/rust-clippy/issues/7575 + clippy::collapsible_match, + clippy::derive_partial_eq_without_eq, + clippy::enum_variant_names, + // clippy bug: https://github.com/rust-lang/rust-clippy/issues/6797 + clippy::manual_map, + clippy::match_like_matches_macro, + clippy::needless_pass_by_value, + clippy::too_many_arguments, + clippy::trivially_copy_pass_by_ref, + clippy::used_underscore_binding, + clippy::wildcard_in_or_patterns, + // clippy bug: https://github.com/rust-lang/rust-clippy/issues/5704 + clippy::unnested_or_patterns, +)] +// Ignored clippy_pedantic lints +#![allow( + clippy::cast_possible_truncation, + clippy::checked_conversions, + clippy::doc_markdown, + clippy::enum_glob_use, + clippy::indexing_slicing, + clippy::items_after_statements, + clippy::let_underscore_untyped, + clippy::manual_assert, + clippy::map_err_ignore, + clippy::match_same_arms, + // clippy bug: https://github.com/rust-lang/rust-clippy/issues/6984 + clippy::match_wildcard_for_single_variants, + clippy::module_name_repetitions, + clippy::must_use_candidate, + clippy::similar_names, + clippy::single_match_else, + clippy::struct_excessive_bools, + clippy::too_many_lines, + clippy::unseparated_literal_suffix, + clippy::unused_self, + clippy::use_self, + clippy::wildcard_imports +)] +#![cfg_attr(all(test, exhaustive), feature(non_exhaustive_omitted_patterns_lint))] + +extern crate proc_macro2; +extern crate quote; +extern crate syn; + +extern crate proc_macro; + +mod internals; + +use proc_macro::TokenStream; +use syn::parse_macro_input; +use syn::DeriveInput; + +#[macro_use] +mod bound; +#[macro_use] +mod fragment; + +mod de; +mod dummy; +mod pretend; +mod ser; +mod this; + +#[proc_macro_derive(Serialize, attributes(serde))] +pub fn derive_serialize(input: TokenStream) -> TokenStream { + let mut input = parse_macro_input!(input as DeriveInput); + ser::expand_derive_serialize(&mut input) + .unwrap_or_else(syn::Error::into_compile_error) + .into() +} + +#[proc_macro_derive(Deserialize, attributes(serde))] +pub fn derive_deserialize(input: TokenStream) -> TokenStream { + let mut input = parse_macro_input!(input as DeriveInput); + de::expand_derive_deserialize(&mut input) + .unwrap_or_else(syn::Error::into_compile_error) + .into() +} diff --git a/third_party/rust/serde_derive/src/pretend.rs b/third_party/rust/serde_derive/src/pretend.rs new file mode 100644 index 0000000000..2c9e779368 --- /dev/null +++ b/third_party/rust/serde_derive/src/pretend.rs @@ -0,0 +1,185 @@ +use crate::internals::ast::{Container, Data, Field, Style, Variant}; +use proc_macro2::TokenStream; +use quote::{format_ident, quote}; + +// Suppress dead_code warnings that would otherwise appear when using a remote +// derive. Other than this pretend code, a struct annotated with remote derive +// never has its fields referenced and an enum annotated with remote derive +// never has its variants constructed. +// +// warning: field is never used: `i` +// --> src/main.rs:4:20 +// | +// 4 | struct StructDef { i: i32 } +// | ^^^^^^ +// +// warning: variant is never constructed: `V` +// --> src/main.rs:8:16 +// | +// 8 | enum EnumDef { V } +// | ^ +// +pub fn pretend_used(cont: &Container, is_packed: bool) -> TokenStream { + let pretend_fields = pretend_fields_used(cont, is_packed); + let pretend_variants = pretend_variants_used(cont); + + quote! { + #pretend_fields + #pretend_variants + } +} + +// For structs with named fields, expands to: +// +// match None::<&T> { +// Some(T { a: __v0, b: __v1 }) => {} +// _ => {} +// } +// +// For packed structs on sufficiently new rustc, expands to: +// +// match None::<&T> { +// Some(__v @ T { a: _, b: _ }) => { +// let _ = addr_of!(__v.a); +// let _ = addr_of!(__v.b); +// } +// _ => {} +// } +// +// For packed structs on older rustc, we assume Sized and !Drop, and expand to: +// +// match None::<T> { +// Some(T { a: __v0, b: __v1 }) => {} +// _ => {} +// } +// +// For enums, expands to the following but only including struct variants: +// +// match None::<&T> { +// Some(T::A { a: __v0 }) => {} +// Some(T::B { b: __v0 }) => {} +// _ => {} +// } +// +fn pretend_fields_used(cont: &Container, is_packed: bool) -> TokenStream { + match &cont.data { + Data::Enum(variants) => pretend_fields_used_enum(cont, variants), + Data::Struct(Style::Struct | Style::Tuple | Style::Newtype, fields) => { + if is_packed { + pretend_fields_used_struct_packed(cont, fields) + } else { + pretend_fields_used_struct(cont, fields) + } + } + Data::Struct(Style::Unit, _) => quote!(), + } +} + +fn pretend_fields_used_struct(cont: &Container, fields: &[Field]) -> TokenStream { + let type_ident = &cont.ident; + let (_, ty_generics, _) = cont.generics.split_for_impl(); + + let members = fields.iter().map(|field| &field.member); + let placeholders = (0usize..).map(|i| format_ident!("__v{}", i)); + + quote! { + match _serde::__private::None::<&#type_ident #ty_generics> { + _serde::__private::Some(#type_ident { #(#members: #placeholders),* }) => {} + _ => {} + } + } +} + +fn pretend_fields_used_struct_packed(cont: &Container, fields: &[Field]) -> TokenStream { + let type_ident = &cont.ident; + let (_, ty_generics, _) = cont.generics.split_for_impl(); + + let members = fields.iter().map(|field| &field.member).collect::<Vec<_>>(); + + quote! { + match _serde::__private::None::<&#type_ident #ty_generics> { + _serde::__private::Some(__v @ #type_ident { #(#members: _),* }) => { + #( + let _ = _serde::__private::ptr::addr_of!(__v.#members); + )* + } + _ => {} + } + } +} + +fn pretend_fields_used_enum(cont: &Container, variants: &[Variant]) -> TokenStream { + let type_ident = &cont.ident; + let (_, ty_generics, _) = cont.generics.split_for_impl(); + + let patterns = variants + .iter() + .filter_map(|variant| match variant.style { + Style::Struct | Style::Tuple | Style::Newtype => { + let variant_ident = &variant.ident; + let members = variant.fields.iter().map(|field| &field.member); + let placeholders = (0usize..).map(|i| format_ident!("__v{}", i)); + Some(quote!(#type_ident::#variant_ident { #(#members: #placeholders),* })) + } + Style::Unit => None, + }) + .collect::<Vec<_>>(); + + quote! { + match _serde::__private::None::<&#type_ident #ty_generics> { + #( + _serde::__private::Some(#patterns) => {} + )* + _ => {} + } + } +} + +// Expands to one of these per enum variant: +// +// match None { +// Some((__v0, __v1,)) => { +// let _ = E::V { a: __v0, b: __v1 }; +// } +// _ => {} +// } +// +fn pretend_variants_used(cont: &Container) -> TokenStream { + let variants = match &cont.data { + Data::Enum(variants) => variants, + Data::Struct(_, _) => { + return quote!(); + } + }; + + let type_ident = &cont.ident; + let (_, ty_generics, _) = cont.generics.split_for_impl(); + let turbofish = ty_generics.as_turbofish(); + + let cases = variants.iter().map(|variant| { + let variant_ident = &variant.ident; + let placeholders = &(0..variant.fields.len()) + .map(|i| format_ident!("__v{}", i)) + .collect::<Vec<_>>(); + + let pat = match variant.style { + Style::Struct => { + let members = variant.fields.iter().map(|field| &field.member); + quote!({ #(#members: #placeholders),* }) + } + Style::Tuple | Style::Newtype => quote!(( #(#placeholders),* )), + Style::Unit => quote!(), + }; + + quote! { + match _serde::__private::None { + _serde::__private::Some((#(#placeholders,)*)) => { + let _ = #type_ident::#variant_ident #turbofish #pat; + } + _ => {} + } + } + }); + + quote!(#(#cases)*) +} diff --git a/third_party/rust/serde_derive/src/ser.rs b/third_party/rust/serde_derive/src/ser.rs new file mode 100644 index 0000000000..3be51ee52d --- /dev/null +++ b/third_party/rust/serde_derive/src/ser.rs @@ -0,0 +1,1359 @@ +use crate::fragment::{Fragment, Match, Stmts}; +use crate::internals::ast::{Container, Data, Field, Style, Variant}; +use crate::internals::{attr, replace_receiver, Ctxt, Derive}; +use crate::{bound, dummy, pretend, this}; +use proc_macro2::{Span, TokenStream}; +use quote::{quote, quote_spanned}; +use syn::spanned::Spanned; +use syn::{parse_quote, Ident, Index, Member}; + +pub fn expand_derive_serialize(input: &mut syn::DeriveInput) -> syn::Result<TokenStream> { + replace_receiver(input); + + let ctxt = Ctxt::new(); + let cont = match Container::from_ast(&ctxt, input, Derive::Serialize) { + Some(cont) => cont, + None => return Err(ctxt.check().unwrap_err()), + }; + precondition(&ctxt, &cont); + ctxt.check()?; + + let ident = &cont.ident; + let params = Parameters::new(&cont); + let (impl_generics, ty_generics, where_clause) = params.generics.split_for_impl(); + let body = Stmts(serialize_body(&cont, ¶ms)); + let serde = cont.attrs.serde_path(); + + let impl_block = if let Some(remote) = cont.attrs.remote() { + let vis = &input.vis; + let used = pretend::pretend_used(&cont, params.is_packed); + quote! { + impl #impl_generics #ident #ty_generics #where_clause { + #vis fn serialize<__S>(__self: &#remote #ty_generics, __serializer: __S) -> #serde::__private::Result<__S::Ok, __S::Error> + where + __S: #serde::Serializer, + { + #used + #body + } + } + } + } else { + quote! { + #[automatically_derived] + impl #impl_generics #serde::Serialize for #ident #ty_generics #where_clause { + fn serialize<__S>(&self, __serializer: __S) -> #serde::__private::Result<__S::Ok, __S::Error> + where + __S: #serde::Serializer, + { + #body + } + } + } + }; + + Ok(dummy::wrap_in_const( + cont.attrs.custom_serde_path(), + impl_block, + )) +} + +fn precondition(cx: &Ctxt, cont: &Container) { + match cont.attrs.identifier() { + attr::Identifier::No => {} + attr::Identifier::Field => { + cx.error_spanned_by(cont.original, "field identifiers cannot be serialized"); + } + attr::Identifier::Variant => { + cx.error_spanned_by(cont.original, "variant identifiers cannot be serialized"); + } + } +} + +struct Parameters { + /// Variable holding the value being serialized. Either `self` for local + /// types or `__self` for remote types. + self_var: Ident, + + /// Path to the type the impl is for. Either a single `Ident` for local + /// types (does not include generic parameters) or `some::remote::Path` for + /// remote types. + this_type: syn::Path, + + /// Same as `this_type` but using `::<T>` for generic parameters for use in + /// expression position. + this_value: syn::Path, + + /// Generics including any explicit and inferred bounds for the impl. + generics: syn::Generics, + + /// Type has a `serde(remote = "...")` attribute. + is_remote: bool, + + /// Type has a repr(packed) attribute. + is_packed: bool, +} + +impl Parameters { + fn new(cont: &Container) -> Self { + let is_remote = cont.attrs.remote().is_some(); + let self_var = if is_remote { + Ident::new("__self", Span::call_site()) + } else { + Ident::new("self", Span::call_site()) + }; + + let this_type = this::this_type(cont); + let this_value = this::this_value(cont); + let is_packed = cont.attrs.is_packed(); + let generics = build_generics(cont); + + Parameters { + self_var, + this_type, + this_value, + generics, + is_remote, + is_packed, + } + } + + /// Type name to use in error messages and `&'static str` arguments to + /// various Serializer methods. + fn type_name(&self) -> String { + self.this_type.segments.last().unwrap().ident.to_string() + } +} + +// All the generics in the input, plus a bound `T: Serialize` for each generic +// field type that will be serialized by us. +fn build_generics(cont: &Container) -> syn::Generics { + let generics = bound::without_defaults(cont.generics); + + let generics = + bound::with_where_predicates_from_fields(cont, &generics, attr::Field::ser_bound); + + let generics = + bound::with_where_predicates_from_variants(cont, &generics, attr::Variant::ser_bound); + + match cont.attrs.ser_bound() { + Some(predicates) => bound::with_where_predicates(&generics, predicates), + None => bound::with_bound( + cont, + &generics, + needs_serialize_bound, + &parse_quote!(_serde::Serialize), + ), + } +} + +// Fields with a `skip_serializing` or `serialize_with` attribute, or which +// belong to a variant with a 'skip_serializing` or `serialize_with` attribute, +// are not 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 +// may need a `T: Serialize` bound where T is the type of the field. +fn needs_serialize_bound(field: &attr::Field, variant: Option<&attr::Variant>) -> bool { + !field.skip_serializing() + && field.serialize_with().is_none() + && field.ser_bound().is_none() + && variant.map_or(true, |variant| { + !variant.skip_serializing() + && variant.serialize_with().is_none() + && variant.ser_bound().is_none() + }) +} + +fn serialize_body(cont: &Container, params: &Parameters) -> Fragment { + if cont.attrs.transparent() { + serialize_transparent(cont, params) + } else if let Some(type_into) = cont.attrs.type_into() { + serialize_into(params, type_into) + } else { + match &cont.data { + Data::Enum(variants) => serialize_enum(params, variants, &cont.attrs), + Data::Struct(Style::Struct, fields) => serialize_struct(params, fields, &cont.attrs), + Data::Struct(Style::Tuple, fields) => { + serialize_tuple_struct(params, fields, &cont.attrs) + } + Data::Struct(Style::Newtype, fields) => { + serialize_newtype_struct(params, &fields[0], &cont.attrs) + } + Data::Struct(Style::Unit, _) => serialize_unit_struct(&cont.attrs), + } + } +} + +fn serialize_transparent(cont: &Container, params: &Parameters) -> Fragment { + let fields = match &cont.data { + Data::Struct(_, fields) => fields, + Data::Enum(_) => unreachable!(), + }; + + let self_var = ¶ms.self_var; + let transparent_field = fields.iter().find(|f| f.attrs.transparent()).unwrap(); + let member = &transparent_field.member; + + let path = match transparent_field.attrs.serialize_with() { + Some(path) => quote!(#path), + None => { + let span = transparent_field.original.span(); + quote_spanned!(span=> _serde::Serialize::serialize) + } + }; + + quote_block! { + #path(&#self_var.#member, __serializer) + } +} + +fn serialize_into(params: &Parameters, type_into: &syn::Type) -> Fragment { + let self_var = ¶ms.self_var; + quote_block! { + _serde::Serialize::serialize( + &_serde::__private::Into::<#type_into>::into(_serde::__private::Clone::clone(#self_var)), + __serializer) + } +} + +fn serialize_unit_struct(cattrs: &attr::Container) -> Fragment { + let type_name = cattrs.name().serialize_name(); + + quote_expr! { + _serde::Serializer::serialize_unit_struct(__serializer, #type_name) + } +} + +fn serialize_newtype_struct( + params: &Parameters, + field: &Field, + cattrs: &attr::Container, +) -> Fragment { + let type_name = cattrs.name().serialize_name(); + + let mut field_expr = get_member( + params, + field, + &Member::Unnamed(Index { + index: 0, + span: Span::call_site(), + }), + ); + if let Some(path) = field.attrs.serialize_with() { + field_expr = wrap_serialize_field_with(params, field.ty, path, &field_expr); + } + + let span = field.original.span(); + let func = quote_spanned!(span=> _serde::Serializer::serialize_newtype_struct); + quote_expr! { + #func(__serializer, #type_name, #field_expr) + } +} + +fn serialize_tuple_struct( + params: &Parameters, + fields: &[Field], + cattrs: &attr::Container, +) -> Fragment { + let serialize_stmts = + serialize_tuple_struct_visitor(fields, params, false, &TupleTrait::SerializeTupleStruct); + + let type_name = cattrs.name().serialize_name(); + + let mut serialized_fields = fields + .iter() + .enumerate() + .filter(|(_, field)| !field.attrs.skip_serializing()) + .peekable(); + + let let_mut = mut_if(serialized_fields.peek().is_some()); + + let len = serialized_fields + .map(|(i, field)| match field.attrs.skip_serializing_if() { + None => quote!(1), + Some(path) => { + let index = syn::Index { + index: i as u32, + span: Span::call_site(), + }; + let field_expr = get_member(params, field, &Member::Unnamed(index)); + quote!(if #path(#field_expr) { 0 } else { 1 }) + } + }) + .fold(quote!(0), |sum, expr| quote!(#sum + #expr)); + + quote_block! { + let #let_mut __serde_state = _serde::Serializer::serialize_tuple_struct(__serializer, #type_name, #len)?; + #(#serialize_stmts)* + _serde::ser::SerializeTupleStruct::end(__serde_state) + } +} + +fn serialize_struct(params: &Parameters, fields: &[Field], cattrs: &attr::Container) -> Fragment { + assert!(fields.len() as u64 <= u64::from(u32::max_value())); + + if cattrs.has_flatten() { + serialize_struct_as_map(params, fields, cattrs) + } else { + serialize_struct_as_struct(params, fields, cattrs) + } +} + +fn serialize_struct_tag_field(cattrs: &attr::Container, struct_trait: &StructTrait) -> TokenStream { + match cattrs.tag() { + attr::TagType::Internal { tag } => { + let type_name = cattrs.name().serialize_name(); + let func = struct_trait.serialize_field(Span::call_site()); + quote! { + #func(&mut __serde_state, #tag, #type_name)?; + } + } + _ => quote! {}, + } +} + +fn serialize_struct_as_struct( + params: &Parameters, + fields: &[Field], + cattrs: &attr::Container, +) -> Fragment { + let serialize_fields = + serialize_struct_visitor(fields, params, false, &StructTrait::SerializeStruct); + + let type_name = cattrs.name().serialize_name(); + + let tag_field = serialize_struct_tag_field(cattrs, &StructTrait::SerializeStruct); + let tag_field_exists = !tag_field.is_empty(); + + let mut serialized_fields = fields + .iter() + .filter(|&field| !field.attrs.skip_serializing()) + .peekable(); + + let let_mut = mut_if(serialized_fields.peek().is_some() || tag_field_exists); + + let len = serialized_fields + .map(|field| match field.attrs.skip_serializing_if() { + None => quote!(1), + Some(path) => { + let field_expr = get_member(params, field, &field.member); + quote!(if #path(#field_expr) { 0 } else { 1 }) + } + }) + .fold( + quote!(#tag_field_exists as usize), + |sum, expr| quote!(#sum + #expr), + ); + + quote_block! { + let #let_mut __serde_state = _serde::Serializer::serialize_struct(__serializer, #type_name, #len)?; + #tag_field + #(#serialize_fields)* + _serde::ser::SerializeStruct::end(__serde_state) + } +} + +fn serialize_struct_as_map( + params: &Parameters, + fields: &[Field], + cattrs: &attr::Container, +) -> Fragment { + let serialize_fields = + serialize_struct_visitor(fields, params, false, &StructTrait::SerializeMap); + + let tag_field = serialize_struct_tag_field(cattrs, &StructTrait::SerializeMap); + let tag_field_exists = !tag_field.is_empty(); + + let mut serialized_fields = fields + .iter() + .filter(|&field| !field.attrs.skip_serializing()) + .peekable(); + + let let_mut = mut_if(serialized_fields.peek().is_some() || tag_field_exists); + + let len = if cattrs.has_flatten() { + quote!(_serde::__private::None) + } else { + let len = serialized_fields + .map(|field| match field.attrs.skip_serializing_if() { + None => quote!(1), + Some(path) => { + let field_expr = get_member(params, field, &field.member); + quote!(if #path(#field_expr) { 0 } else { 1 }) + } + }) + .fold( + quote!(#tag_field_exists as usize), + |sum, expr| quote!(#sum + #expr), + ); + quote!(_serde::__private::Some(#len)) + }; + + quote_block! { + let #let_mut __serde_state = _serde::Serializer::serialize_map(__serializer, #len)?; + #tag_field + #(#serialize_fields)* + _serde::ser::SerializeMap::end(__serde_state) + } +} + +fn serialize_enum(params: &Parameters, variants: &[Variant], cattrs: &attr::Container) -> Fragment { + assert!(variants.len() as u64 <= u64::from(u32::max_value())); + + let self_var = ¶ms.self_var; + + let mut arms: Vec<_> = variants + .iter() + .enumerate() + .map(|(variant_index, variant)| { + serialize_variant(params, variant, variant_index as u32, cattrs) + }) + .collect(); + + if cattrs.remote().is_some() && cattrs.non_exhaustive() { + arms.push(quote! { + ref unrecognized => _serde::__private::Err(_serde::ser::Error::custom(_serde::__private::ser::CannotSerializeVariant(unrecognized))), + }); + } + + quote_expr! { + match *#self_var { + #(#arms)* + } + } +} + +fn serialize_variant( + params: &Parameters, + variant: &Variant, + variant_index: u32, + cattrs: &attr::Container, +) -> TokenStream { + let this_value = ¶ms.this_value; + let variant_ident = &variant.ident; + + if variant.attrs.skip_serializing() { + let skipped_msg = format!( + "the enum variant {}::{} cannot be serialized", + params.type_name(), + variant_ident + ); + let skipped_err = quote! { + _serde::__private::Err(_serde::ser::Error::custom(#skipped_msg)) + }; + let fields_pat = match variant.style { + Style::Unit => quote!(), + Style::Newtype | Style::Tuple => quote!((..)), + Style::Struct => quote!({ .. }), + }; + quote! { + #this_value::#variant_ident #fields_pat => #skipped_err, + } + } else { + // variant wasn't skipped + let case = match variant.style { + Style::Unit => { + quote! { + #this_value::#variant_ident + } + } + Style::Newtype => { + quote! { + #this_value::#variant_ident(ref __field0) + } + } + Style::Tuple => { + let field_names = (0..variant.fields.len()) + .map(|i| Ident::new(&format!("__field{}", i), Span::call_site())); + quote! { + #this_value::#variant_ident(#(ref #field_names),*) + } + } + Style::Struct => { + let members = variant.fields.iter().map(|f| &f.member); + quote! { + #this_value::#variant_ident { #(ref #members),* } + } + } + }; + + let body = Match(match (cattrs.tag(), variant.attrs.untagged()) { + (attr::TagType::External, false) => { + serialize_externally_tagged_variant(params, variant, variant_index, cattrs) + } + (attr::TagType::Internal { tag }, false) => { + serialize_internally_tagged_variant(params, variant, cattrs, tag) + } + (attr::TagType::Adjacent { tag, content }, false) => { + serialize_adjacently_tagged_variant( + params, + variant, + cattrs, + variant_index, + tag, + content, + ) + } + (attr::TagType::None, _) | (_, true) => { + serialize_untagged_variant(params, variant, cattrs) + } + }); + + quote! { + #case => #body + } + } +} + +fn serialize_externally_tagged_variant( + params: &Parameters, + variant: &Variant, + variant_index: u32, + cattrs: &attr::Container, +) -> Fragment { + let type_name = cattrs.name().serialize_name(); + let variant_name = variant.attrs.name().serialize_name(); + + if let Some(path) = variant.attrs.serialize_with() { + let ser = wrap_serialize_variant_with(params, path, variant); + return quote_expr! { + _serde::Serializer::serialize_newtype_variant( + __serializer, + #type_name, + #variant_index, + #variant_name, + #ser, + ) + }; + } + + match effective_style(variant) { + Style::Unit => { + quote_expr! { + _serde::Serializer::serialize_unit_variant( + __serializer, + #type_name, + #variant_index, + #variant_name, + ) + } + } + Style::Newtype => { + let field = &variant.fields[0]; + let mut field_expr = quote!(__field0); + if let Some(path) = field.attrs.serialize_with() { + field_expr = wrap_serialize_field_with(params, field.ty, path, &field_expr); + } + + let span = field.original.span(); + let func = quote_spanned!(span=> _serde::Serializer::serialize_newtype_variant); + quote_expr! { + #func( + __serializer, + #type_name, + #variant_index, + #variant_name, + #field_expr, + ) + } + } + Style::Tuple => serialize_tuple_variant( + TupleVariant::ExternallyTagged { + type_name, + variant_index, + variant_name, + }, + params, + &variant.fields, + ), + Style::Struct => serialize_struct_variant( + StructVariant::ExternallyTagged { + variant_index, + variant_name, + }, + params, + &variant.fields, + type_name, + ), + } +} + +fn serialize_internally_tagged_variant( + params: &Parameters, + variant: &Variant, + cattrs: &attr::Container, + tag: &str, +) -> Fragment { + let type_name = cattrs.name().serialize_name(); + let variant_name = variant.attrs.name().serialize_name(); + + let enum_ident_str = params.type_name(); + let variant_ident_str = variant.ident.to_string(); + + if let Some(path) = variant.attrs.serialize_with() { + let ser = wrap_serialize_variant_with(params, path, variant); + return quote_expr! { + _serde::__private::ser::serialize_tagged_newtype( + __serializer, + #enum_ident_str, + #variant_ident_str, + #tag, + #variant_name, + #ser, + ) + }; + } + + match effective_style(variant) { + Style::Unit => { + quote_block! { + let mut __struct = _serde::Serializer::serialize_struct( + __serializer, #type_name, 1)?; + _serde::ser::SerializeStruct::serialize_field( + &mut __struct, #tag, #variant_name)?; + _serde::ser::SerializeStruct::end(__struct) + } + } + Style::Newtype => { + let field = &variant.fields[0]; + let mut field_expr = quote!(__field0); + if let Some(path) = field.attrs.serialize_with() { + field_expr = wrap_serialize_field_with(params, field.ty, path, &field_expr); + } + + let span = field.original.span(); + let func = quote_spanned!(span=> _serde::__private::ser::serialize_tagged_newtype); + quote_expr! { + #func( + __serializer, + #enum_ident_str, + #variant_ident_str, + #tag, + #variant_name, + #field_expr, + ) + } + } + Style::Struct => serialize_struct_variant( + StructVariant::InternallyTagged { tag, variant_name }, + params, + &variant.fields, + type_name, + ), + Style::Tuple => unreachable!("checked in serde_derive_internals"), + } +} + +fn serialize_adjacently_tagged_variant( + params: &Parameters, + variant: &Variant, + cattrs: &attr::Container, + variant_index: u32, + tag: &str, + content: &str, +) -> Fragment { + let this_type = ¶ms.this_type; + let type_name = cattrs.name().serialize_name(); + let variant_name = variant.attrs.name().serialize_name(); + let serialize_variant = quote! { + &_serde::__private::ser::AdjacentlyTaggedEnumVariant { + enum_name: #type_name, + variant_index: #variant_index, + variant_name: #variant_name, + } + }; + + let inner = Stmts(if let Some(path) = variant.attrs.serialize_with() { + let ser = wrap_serialize_variant_with(params, path, variant); + quote_expr! { + _serde::Serialize::serialize(#ser, __serializer) + } + } else { + match effective_style(variant) { + Style::Unit => { + return quote_block! { + let mut __struct = _serde::Serializer::serialize_struct( + __serializer, #type_name, 1)?; + _serde::ser::SerializeStruct::serialize_field( + &mut __struct, #tag, #serialize_variant)?; + _serde::ser::SerializeStruct::end(__struct) + }; + } + Style::Newtype => { + let field = &variant.fields[0]; + let mut field_expr = quote!(__field0); + if let Some(path) = field.attrs.serialize_with() { + field_expr = wrap_serialize_field_with(params, field.ty, path, &field_expr); + } + + let span = field.original.span(); + let func = quote_spanned!(span=> _serde::ser::SerializeStruct::serialize_field); + return quote_block! { + let mut __struct = _serde::Serializer::serialize_struct( + __serializer, #type_name, 2)?; + _serde::ser::SerializeStruct::serialize_field( + &mut __struct, #tag, #serialize_variant)?; + #func( + &mut __struct, #content, #field_expr)?; + _serde::ser::SerializeStruct::end(__struct) + }; + } + Style::Tuple => { + serialize_tuple_variant(TupleVariant::Untagged, params, &variant.fields) + } + Style::Struct => serialize_struct_variant( + StructVariant::Untagged, + params, + &variant.fields, + variant_name, + ), + } + }); + + let fields_ty = variant.fields.iter().map(|f| &f.ty); + let fields_ident: &[_] = &match variant.style { + Style::Unit => { + if variant.attrs.serialize_with().is_some() { + vec![] + } else { + unreachable!() + } + } + Style::Newtype => vec![Member::Named(Ident::new("__field0", Span::call_site()))], + Style::Tuple => (0..variant.fields.len()) + .map(|i| Member::Named(Ident::new(&format!("__field{}", i), Span::call_site()))) + .collect(), + Style::Struct => variant.fields.iter().map(|f| f.member.clone()).collect(), + }; + + let (_, ty_generics, where_clause) = params.generics.split_for_impl(); + + let wrapper_generics = if fields_ident.is_empty() { + params.generics.clone() + } else { + bound::with_lifetime_bound(¶ms.generics, "'__a") + }; + let (wrapper_impl_generics, wrapper_ty_generics, _) = wrapper_generics.split_for_impl(); + + quote_block! { + #[doc(hidden)] + struct __AdjacentlyTagged #wrapper_generics #where_clause { + data: (#(&'__a #fields_ty,)*), + phantom: _serde::__private::PhantomData<#this_type #ty_generics>, + } + + impl #wrapper_impl_generics _serde::Serialize for __AdjacentlyTagged #wrapper_ty_generics #where_clause { + fn serialize<__S>(&self, __serializer: __S) -> _serde::__private::Result<__S::Ok, __S::Error> + where + __S: _serde::Serializer, + { + // Elements that have skip_serializing will be unused. + #[allow(unused_variables)] + let (#(#fields_ident,)*) = self.data; + #inner + } + } + + let mut __struct = _serde::Serializer::serialize_struct( + __serializer, #type_name, 2)?; + _serde::ser::SerializeStruct::serialize_field( + &mut __struct, #tag, #serialize_variant)?; + _serde::ser::SerializeStruct::serialize_field( + &mut __struct, #content, &__AdjacentlyTagged { + data: (#(#fields_ident,)*), + phantom: _serde::__private::PhantomData::<#this_type #ty_generics>, + })?; + _serde::ser::SerializeStruct::end(__struct) + } +} + +fn serialize_untagged_variant( + params: &Parameters, + variant: &Variant, + cattrs: &attr::Container, +) -> Fragment { + if let Some(path) = variant.attrs.serialize_with() { + let ser = wrap_serialize_variant_with(params, path, variant); + return quote_expr! { + _serde::Serialize::serialize(#ser, __serializer) + }; + } + + match effective_style(variant) { + Style::Unit => { + quote_expr! { + _serde::Serializer::serialize_unit(__serializer) + } + } + Style::Newtype => { + let field = &variant.fields[0]; + let mut field_expr = quote!(__field0); + if let Some(path) = field.attrs.serialize_with() { + field_expr = wrap_serialize_field_with(params, field.ty, path, &field_expr); + } + + let span = field.original.span(); + let func = quote_spanned!(span=> _serde::Serialize::serialize); + quote_expr! { + #func(#field_expr, __serializer) + } + } + Style::Tuple => serialize_tuple_variant(TupleVariant::Untagged, params, &variant.fields), + Style::Struct => { + let type_name = cattrs.name().serialize_name(); + serialize_struct_variant(StructVariant::Untagged, params, &variant.fields, type_name) + } + } +} + +enum TupleVariant<'a> { + ExternallyTagged { + type_name: &'a str, + variant_index: u32, + variant_name: &'a str, + }, + Untagged, +} + +fn serialize_tuple_variant( + context: TupleVariant, + params: &Parameters, + fields: &[Field], +) -> Fragment { + let tuple_trait = match context { + TupleVariant::ExternallyTagged { .. } => TupleTrait::SerializeTupleVariant, + TupleVariant::Untagged => TupleTrait::SerializeTuple, + }; + + let serialize_stmts = serialize_tuple_struct_visitor(fields, params, true, &tuple_trait); + + let mut serialized_fields = fields + .iter() + .enumerate() + .filter(|(_, field)| !field.attrs.skip_serializing()) + .peekable(); + + let let_mut = mut_if(serialized_fields.peek().is_some()); + + let len = serialized_fields + .map(|(i, field)| match field.attrs.skip_serializing_if() { + None => quote!(1), + Some(path) => { + let field_expr = Ident::new(&format!("__field{}", i), Span::call_site()); + quote!(if #path(#field_expr) { 0 } else { 1 }) + } + }) + .fold(quote!(0), |sum, expr| quote!(#sum + #expr)); + + match context { + TupleVariant::ExternallyTagged { + type_name, + variant_index, + variant_name, + } => { + quote_block! { + let #let_mut __serde_state = _serde::Serializer::serialize_tuple_variant( + __serializer, + #type_name, + #variant_index, + #variant_name, + #len)?; + #(#serialize_stmts)* + _serde::ser::SerializeTupleVariant::end(__serde_state) + } + } + TupleVariant::Untagged => { + quote_block! { + let #let_mut __serde_state = _serde::Serializer::serialize_tuple( + __serializer, + #len)?; + #(#serialize_stmts)* + _serde::ser::SerializeTuple::end(__serde_state) + } + } + } +} + +enum StructVariant<'a> { + ExternallyTagged { + variant_index: u32, + variant_name: &'a str, + }, + InternallyTagged { + tag: &'a str, + variant_name: &'a str, + }, + Untagged, +} + +fn serialize_struct_variant( + context: StructVariant, + params: &Parameters, + fields: &[Field], + name: &str, +) -> Fragment { + if fields.iter().any(|field| field.attrs.flatten()) { + return serialize_struct_variant_with_flatten(context, params, fields, name); + } + + let struct_trait = match context { + StructVariant::ExternallyTagged { .. } => StructTrait::SerializeStructVariant, + StructVariant::InternallyTagged { .. } | StructVariant::Untagged => { + StructTrait::SerializeStruct + } + }; + + let serialize_fields = serialize_struct_visitor(fields, params, true, &struct_trait); + + let mut serialized_fields = fields + .iter() + .filter(|&field| !field.attrs.skip_serializing()) + .peekable(); + + let let_mut = mut_if(serialized_fields.peek().is_some()); + + let len = serialized_fields + .map(|field| { + let member = &field.member; + + match field.attrs.skip_serializing_if() { + Some(path) => quote!(if #path(#member) { 0 } else { 1 }), + None => quote!(1), + } + }) + .fold(quote!(0), |sum, expr| quote!(#sum + #expr)); + + match context { + StructVariant::ExternallyTagged { + variant_index, + variant_name, + } => { + quote_block! { + let #let_mut __serde_state = _serde::Serializer::serialize_struct_variant( + __serializer, + #name, + #variant_index, + #variant_name, + #len, + )?; + #(#serialize_fields)* + _serde::ser::SerializeStructVariant::end(__serde_state) + } + } + StructVariant::InternallyTagged { tag, variant_name } => { + quote_block! { + let mut __serde_state = _serde::Serializer::serialize_struct( + __serializer, + #name, + #len + 1, + )?; + _serde::ser::SerializeStruct::serialize_field( + &mut __serde_state, + #tag, + #variant_name, + )?; + #(#serialize_fields)* + _serde::ser::SerializeStruct::end(__serde_state) + } + } + StructVariant::Untagged => { + quote_block! { + let #let_mut __serde_state = _serde::Serializer::serialize_struct( + __serializer, + #name, + #len, + )?; + #(#serialize_fields)* + _serde::ser::SerializeStruct::end(__serde_state) + } + } + } +} + +fn serialize_struct_variant_with_flatten( + context: StructVariant, + params: &Parameters, + fields: &[Field], + name: &str, +) -> Fragment { + let struct_trait = StructTrait::SerializeMap; + let serialize_fields = serialize_struct_visitor(fields, params, true, &struct_trait); + + let mut serialized_fields = fields + .iter() + .filter(|&field| !field.attrs.skip_serializing()) + .peekable(); + + let let_mut = mut_if(serialized_fields.peek().is_some()); + + match context { + StructVariant::ExternallyTagged { + variant_index, + variant_name, + } => { + let this_type = ¶ms.this_type; + let fields_ty = fields.iter().map(|f| &f.ty); + let members = &fields.iter().map(|f| &f.member).collect::<Vec<_>>(); + + let (_, ty_generics, where_clause) = params.generics.split_for_impl(); + let wrapper_generics = bound::with_lifetime_bound(¶ms.generics, "'__a"); + let (wrapper_impl_generics, wrapper_ty_generics, _) = wrapper_generics.split_for_impl(); + + quote_block! { + #[doc(hidden)] + struct __EnumFlatten #wrapper_generics #where_clause { + data: (#(&'__a #fields_ty,)*), + phantom: _serde::__private::PhantomData<#this_type #ty_generics>, + } + + impl #wrapper_impl_generics _serde::Serialize for __EnumFlatten #wrapper_ty_generics #where_clause { + fn serialize<__S>(&self, __serializer: __S) -> _serde::__private::Result<__S::Ok, __S::Error> + where + __S: _serde::Serializer, + { + let (#(#members,)*) = self.data; + let #let_mut __serde_state = _serde::Serializer::serialize_map( + __serializer, + _serde::__private::None)?; + #(#serialize_fields)* + _serde::ser::SerializeMap::end(__serde_state) + } + } + + _serde::Serializer::serialize_newtype_variant( + __serializer, + #name, + #variant_index, + #variant_name, + &__EnumFlatten { + data: (#(#members,)*), + phantom: _serde::__private::PhantomData::<#this_type #ty_generics>, + }) + } + } + StructVariant::InternallyTagged { tag, variant_name } => { + quote_block! { + let #let_mut __serde_state = _serde::Serializer::serialize_map( + __serializer, + _serde::__private::None)?; + _serde::ser::SerializeMap::serialize_entry( + &mut __serde_state, + #tag, + #variant_name, + )?; + #(#serialize_fields)* + _serde::ser::SerializeMap::end(__serde_state) + } + } + StructVariant::Untagged => { + quote_block! { + let #let_mut __serde_state = _serde::Serializer::serialize_map( + __serializer, + _serde::__private::None)?; + #(#serialize_fields)* + _serde::ser::SerializeMap::end(__serde_state) + } + } + } +} + +fn serialize_tuple_struct_visitor( + fields: &[Field], + params: &Parameters, + is_enum: bool, + tuple_trait: &TupleTrait, +) -> Vec<TokenStream> { + fields + .iter() + .enumerate() + .filter(|(_, field)| !field.attrs.skip_serializing()) + .map(|(i, field)| { + let mut field_expr = if is_enum { + let id = Ident::new(&format!("__field{}", i), Span::call_site()); + quote!(#id) + } else { + get_member( + params, + field, + &Member::Unnamed(Index { + index: i as u32, + span: Span::call_site(), + }), + ) + }; + + let skip = field + .attrs + .skip_serializing_if() + .map(|path| quote!(#path(#field_expr))); + + if let Some(path) = field.attrs.serialize_with() { + field_expr = wrap_serialize_field_with(params, field.ty, path, &field_expr); + } + + let span = field.original.span(); + let func = tuple_trait.serialize_element(span); + let ser = quote! { + #func(&mut __serde_state, #field_expr)?; + }; + + match skip { + None => ser, + Some(skip) => quote!(if !#skip { #ser }), + } + }) + .collect() +} + +fn serialize_struct_visitor( + fields: &[Field], + params: &Parameters, + is_enum: bool, + struct_trait: &StructTrait, +) -> Vec<TokenStream> { + fields + .iter() + .filter(|&field| !field.attrs.skip_serializing()) + .map(|field| { + let member = &field.member; + + let mut field_expr = if is_enum { + quote!(#member) + } else { + get_member(params, field, member) + }; + + let key_expr = field.attrs.name().serialize_name(); + + let skip = field + .attrs + .skip_serializing_if() + .map(|path| quote!(#path(#field_expr))); + + if let Some(path) = field.attrs.serialize_with() { + field_expr = wrap_serialize_field_with(params, field.ty, path, &field_expr); + } + + let span = field.original.span(); + let ser = if field.attrs.flatten() { + let func = quote_spanned!(span=> _serde::Serialize::serialize); + quote! { + #func(&#field_expr, _serde::__private::ser::FlatMapSerializer(&mut __serde_state))?; + } + } else { + let func = struct_trait.serialize_field(span); + quote! { + #func(&mut __serde_state, #key_expr, #field_expr)?; + } + }; + + match skip { + None => ser, + Some(skip) => { + if let Some(skip_func) = struct_trait.skip_field(span) { + quote! { + if !#skip { + #ser + } else { + #skip_func(&mut __serde_state, #key_expr)?; + } + } + } else { + quote! { + if !#skip { + #ser + } + } + } + } + } + }) + .collect() +} + +fn wrap_serialize_field_with( + params: &Parameters, + field_ty: &syn::Type, + serialize_with: &syn::ExprPath, + field_expr: &TokenStream, +) -> TokenStream { + wrap_serialize_with(params, serialize_with, &[field_ty], &[quote!(#field_expr)]) +} + +fn wrap_serialize_variant_with( + params: &Parameters, + serialize_with: &syn::ExprPath, + variant: &Variant, +) -> TokenStream { + let field_tys: Vec<_> = variant.fields.iter().map(|field| field.ty).collect(); + let field_exprs: Vec<_> = variant + .fields + .iter() + .map(|field| { + let id = match &field.member { + Member::Named(ident) => ident.clone(), + Member::Unnamed(member) => { + Ident::new(&format!("__field{}", member.index), Span::call_site()) + } + }; + quote!(#id) + }) + .collect(); + wrap_serialize_with( + params, + serialize_with, + field_tys.as_slice(), + field_exprs.as_slice(), + ) +} + +fn wrap_serialize_with( + params: &Parameters, + serialize_with: &syn::ExprPath, + field_tys: &[&syn::Type], + field_exprs: &[TokenStream], +) -> TokenStream { + let this_type = ¶ms.this_type; + let (_, ty_generics, where_clause) = params.generics.split_for_impl(); + + let wrapper_generics = if field_exprs.is_empty() { + params.generics.clone() + } else { + bound::with_lifetime_bound(¶ms.generics, "'__a") + }; + let (wrapper_impl_generics, wrapper_ty_generics, _) = wrapper_generics.split_for_impl(); + + let field_access = (0..field_exprs.len()).map(|n| { + Member::Unnamed(Index { + index: n as u32, + span: Span::call_site(), + }) + }); + + quote!({ + #[doc(hidden)] + struct __SerializeWith #wrapper_impl_generics #where_clause { + values: (#(&'__a #field_tys, )*), + phantom: _serde::__private::PhantomData<#this_type #ty_generics>, + } + + impl #wrapper_impl_generics _serde::Serialize for __SerializeWith #wrapper_ty_generics #where_clause { + fn serialize<__S>(&self, __s: __S) -> _serde::__private::Result<__S::Ok, __S::Error> + where + __S: _serde::Serializer, + { + #serialize_with(#(self.values.#field_access, )* __s) + } + } + + &__SerializeWith { + values: (#(#field_exprs, )*), + phantom: _serde::__private::PhantomData::<#this_type #ty_generics>, + } + }) +} + +// Serialization of an empty struct results in code like: +// +// let mut __serde_state = serializer.serialize_struct("S", 0)?; +// _serde::ser::SerializeStruct::end(__serde_state) +// +// where we want to omit the `mut` to avoid a warning. +fn mut_if(is_mut: bool) -> Option<TokenStream> { + if is_mut { + Some(quote!(mut)) + } else { + None + } +} + +fn get_member(params: &Parameters, field: &Field, member: &Member) -> TokenStream { + let self_var = ¶ms.self_var; + match (params.is_remote, field.attrs.getter()) { + (false, None) => { + if params.is_packed { + quote!(&{#self_var.#member}) + } else { + quote!(&#self_var.#member) + } + } + (true, None) => { + let inner = if params.is_packed { + quote!(&{#self_var.#member}) + } else { + quote!(&#self_var.#member) + }; + let ty = field.ty; + quote!(_serde::__private::ser::constrain::<#ty>(#inner)) + } + (true, Some(getter)) => { + let ty = field.ty; + quote!(_serde::__private::ser::constrain::<#ty>(&#getter(#self_var))) + } + (false, Some(_)) => { + unreachable!("getter is only allowed for remote impls"); + } + } +} + +fn effective_style(variant: &Variant) -> Style { + match variant.style { + Style::Newtype if variant.fields[0].attrs.skip_serializing() => Style::Unit, + other => other, + } +} + +enum StructTrait { + SerializeMap, + SerializeStruct, + SerializeStructVariant, +} + +impl StructTrait { + fn serialize_field(&self, span: Span) -> TokenStream { + match *self { + StructTrait::SerializeMap => { + quote_spanned!(span=> _serde::ser::SerializeMap::serialize_entry) + } + StructTrait::SerializeStruct => { + quote_spanned!(span=> _serde::ser::SerializeStruct::serialize_field) + } + StructTrait::SerializeStructVariant => { + quote_spanned!(span=> _serde::ser::SerializeStructVariant::serialize_field) + } + } + } + + fn skip_field(&self, span: Span) -> Option<TokenStream> { + match *self { + StructTrait::SerializeMap => None, + StructTrait::SerializeStruct => { + Some(quote_spanned!(span=> _serde::ser::SerializeStruct::skip_field)) + } + StructTrait::SerializeStructVariant => { + Some(quote_spanned!(span=> _serde::ser::SerializeStructVariant::skip_field)) + } + } + } +} + +enum TupleTrait { + SerializeTuple, + SerializeTupleStruct, + SerializeTupleVariant, +} + +impl TupleTrait { + fn serialize_element(&self, span: Span) -> TokenStream { + match *self { + TupleTrait::SerializeTuple => { + quote_spanned!(span=> _serde::ser::SerializeTuple::serialize_element) + } + TupleTrait::SerializeTupleStruct => { + quote_spanned!(span=> _serde::ser::SerializeTupleStruct::serialize_field) + } + TupleTrait::SerializeTupleVariant => { + quote_spanned!(span=> _serde::ser::SerializeTupleVariant::serialize_field) + } + } + } +} diff --git a/third_party/rust/serde_derive/src/this.rs b/third_party/rust/serde_derive/src/this.rs new file mode 100644 index 0000000000..941cea40c1 --- /dev/null +++ b/third_party/rust/serde_derive/src/this.rs @@ -0,0 +1,32 @@ +use crate::internals::ast::Container; +use syn::{Path, PathArguments, Token}; + +pub fn this_type(cont: &Container) -> Path { + if let Some(remote) = cont.attrs.remote() { + let mut this = remote.clone(); + for segment in &mut this.segments { + if let PathArguments::AngleBracketed(arguments) = &mut segment.arguments { + arguments.colon2_token = None; + } + } + this + } else { + Path::from(cont.ident.clone()) + } +} + +pub fn this_value(cont: &Container) -> Path { + if let Some(remote) = cont.attrs.remote() { + let mut this = remote.clone(); + for segment in &mut this.segments { + if let PathArguments::AngleBracketed(arguments) = &mut segment.arguments { + if arguments.colon2_token.is_none() { + arguments.colon2_token = Some(Token![::](arguments.lt_token.span)); + } + } + } + this + } else { + Path::from(cont.ident.clone()) + } +} |