| 1 | use proc_macro2::TokenStream; | 
| 2 | use quote::quote; | 
|---|
| 3 | use syn::{Generics, Ident}; | 
|---|
| 4 |  | 
|---|
| 5 | use crate::ast::{Data, Fields}; | 
|---|
| 6 | use crate::codegen::{ | 
|---|
| 7 | error::{ErrorCheck, ErrorDeclaration}, | 
|---|
| 8 | DefaultExpression, Field, FieldsGen, PostfixTransform, Variant, | 
|---|
| 9 | }; | 
|---|
| 10 | use crate::usage::{CollectTypeParams, IdentSet, Purpose}; | 
|---|
| 11 |  | 
|---|
| 12 | #[ derive(Debug)] | 
|---|
| 13 | pub struct TraitImpl<'a> { | 
|---|
| 14 | pub ident: &'a Ident, | 
|---|
| 15 | pub generics: &'a Generics, | 
|---|
| 16 | pub data: Data<Variant<'a>, Field<'a>>, | 
|---|
| 17 | pub default: Option<DefaultExpression<'a>>, | 
|---|
| 18 | pub post_transform: Option<&'a PostfixTransform>, | 
|---|
| 19 | pub allow_unknown_fields: bool, | 
|---|
| 20 | } | 
|---|
| 21 |  | 
|---|
| 22 | impl<'a> TraitImpl<'a> { | 
|---|
| 23 | /// Get all declared type parameters. | 
|---|
| 24 | pub fn declared_type_params(&self) -> IdentSet { | 
|---|
| 25 | self.generics | 
|---|
| 26 | .type_params() | 
|---|
| 27 | .map(|tp| tp.ident.clone()) | 
|---|
| 28 | .collect() | 
|---|
| 29 | } | 
|---|
| 30 |  | 
|---|
| 31 | /// Get the type parameters which are used by non-skipped, non-magic fields. | 
|---|
| 32 | /// These type parameters will have a `FromMeta` bound applied to them in emitted | 
|---|
| 33 | /// code. | 
|---|
| 34 | pub fn used_type_params(&self) -> IdentSet { | 
|---|
| 35 | self.type_params_matching(|f| !f.skip, |v| !v.skip) | 
|---|
| 36 | } | 
|---|
| 37 |  | 
|---|
| 38 | fn type_params_matching<F, V>(&self, field_filter: F, variant_filter: V) -> IdentSet | 
|---|
| 39 | where | 
|---|
| 40 | F: Fn(&&Field<'_>) -> bool, | 
|---|
| 41 | V: Fn(&&Variant<'_>) -> bool, | 
|---|
| 42 | { | 
|---|
| 43 | let declared = self.declared_type_params(); | 
|---|
| 44 | match self.data { | 
|---|
| 45 | Data::Struct(ref v) => self.type_params_in_fields(v, &field_filter, &declared), | 
|---|
| 46 | Data::Enum(ref v) => { | 
|---|
| 47 | v.iter() | 
|---|
| 48 | .filter(variant_filter) | 
|---|
| 49 | .fold(Default::default(), |mut state, variant| { | 
|---|
| 50 | state.extend(self.type_params_in_fields( | 
|---|
| 51 | &variant.data, | 
|---|
| 52 | &field_filter, | 
|---|
| 53 | &declared, | 
|---|
| 54 | )); | 
|---|
| 55 | state | 
|---|
| 56 | }) | 
|---|
| 57 | } | 
|---|
| 58 | } | 
|---|
| 59 | } | 
|---|
| 60 |  | 
|---|
| 61 | /// Get the type parameters of all fields in a set matching some filter | 
|---|
| 62 | fn type_params_in_fields<'b, F>( | 
|---|
| 63 | &'b self, | 
|---|
| 64 | fields: &'b Fields<Field<'a>>, | 
|---|
| 65 | field_filter: F, | 
|---|
| 66 | declared: &IdentSet, | 
|---|
| 67 | ) -> IdentSet | 
|---|
| 68 | where | 
|---|
| 69 | F: Fn(&&'b Field<'_>) -> bool, | 
|---|
| 70 | { | 
|---|
| 71 | fields | 
|---|
| 72 | .iter() | 
|---|
| 73 | .filter(field_filter) | 
|---|
| 74 | .collect_type_params_cloned(&Purpose::BoundImpl.into(), declared) | 
|---|
| 75 | } | 
|---|
| 76 | } | 
|---|
| 77 |  | 
|---|
| 78 | impl<'a> TraitImpl<'a> { | 
|---|
| 79 | /// Gets the `let` declaration for errors accumulated during parsing. | 
|---|
| 80 | pub fn declare_errors(&self) -> ErrorDeclaration { | 
|---|
| 81 | ErrorDeclaration::default() | 
|---|
| 82 | } | 
|---|
| 83 |  | 
|---|
| 84 | /// Gets the check which performs an early return if errors occurred during parsing. | 
|---|
| 85 | pub fn check_errors(&self) -> ErrorCheck<'_> { | 
|---|
| 86 | ErrorCheck::default() | 
|---|
| 87 | } | 
|---|
| 88 |  | 
|---|
| 89 | /// Generate local variable declarations for all fields. | 
|---|
| 90 | pub(in crate::codegen) fn local_declarations(&self) -> TokenStream { | 
|---|
| 91 | if let Data::Struct(ref vd) = self.data { | 
|---|
| 92 | let vdr = vd.as_ref().map(Field::as_declaration); | 
|---|
| 93 | let decls = vdr.fields.as_slice(); | 
|---|
| 94 | quote!(#(#decls)*) | 
|---|
| 95 | } else { | 
|---|
| 96 | quote!() | 
|---|
| 97 | } | 
|---|
| 98 | } | 
|---|
| 99 |  | 
|---|
| 100 | pub(in crate::codegen) fn post_transform_call(&self) -> Option<TokenStream> { | 
|---|
| 101 | self.post_transform.map(|pt| quote!(#pt)) | 
|---|
| 102 | } | 
|---|
| 103 |  | 
|---|
| 104 | /// Generate local variable declaration and initialization for instance from which missing fields will be taken. | 
|---|
| 105 | pub(in crate::codegen) fn fallback_decl(&self) -> TokenStream { | 
|---|
| 106 | let default = self.default.as_ref().map(DefaultExpression::as_declaration); | 
|---|
| 107 | quote!(#default) | 
|---|
| 108 | } | 
|---|
| 109 |  | 
|---|
| 110 | pub fn require_fields(&self) -> TokenStream { | 
|---|
| 111 | if let Data::Struct(ref vd) = self.data { | 
|---|
| 112 | let check_nones = vd.as_ref().map(Field::as_presence_check); | 
|---|
| 113 | let checks = check_nones.fields.as_slice(); | 
|---|
| 114 |  | 
|---|
| 115 | // If a field was marked `flatten`, now is the time to process any unclaimed meta items | 
|---|
| 116 | // and mark the field as having been seen. | 
|---|
| 117 | let flatten_field_init = vd.fields.iter().find(|f| f.flatten).map(|v| { | 
|---|
| 118 | v.as_flatten_initializer(vd.fields.iter().filter_map(Field::as_name).collect()) | 
|---|
| 119 | }); | 
|---|
| 120 |  | 
|---|
| 121 | quote! { | 
|---|
| 122 | #flatten_field_init | 
|---|
| 123 | #(#checks)* | 
|---|
| 124 | } | 
|---|
| 125 | } else { | 
|---|
| 126 | quote!() | 
|---|
| 127 | } | 
|---|
| 128 | } | 
|---|
| 129 |  | 
|---|
| 130 | pub(in crate::codegen) fn initializers(&self) -> TokenStream { | 
|---|
| 131 | self.make_field_ctx().initializers() | 
|---|
| 132 | } | 
|---|
| 133 |  | 
|---|
| 134 | /// Generate the loop which walks meta items looking for property matches. | 
|---|
| 135 | pub(in crate::codegen) fn core_loop(&self) -> TokenStream { | 
|---|
| 136 | self.make_field_ctx().core_loop() | 
|---|
| 137 | } | 
|---|
| 138 |  | 
|---|
| 139 | fn make_field_ctx(&'a self) -> FieldsGen<'a> { | 
|---|
| 140 | match self.data { | 
|---|
| 141 | Data::Enum(_) => panic!( "Core loop on enums isn't supported"), | 
|---|
| 142 | Data::Struct(ref data) => FieldsGen::new(data, self.allow_unknown_fields), | 
|---|
| 143 | } | 
|---|
| 144 | } | 
|---|
| 145 | } | 
|---|
| 146 |  | 
|---|