• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
declared_type_params(&self) -> IdentSet24     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.
used_type_params(&self) -> IdentSet34     pub fn used_type_params(&self) -> IdentSet {
35         self.type_params_matching(|f| !f.skip, |v| !v.skip)
36     }
37 
type_params_matching<F, V>(&self, field_filter: F, variant_filter: V) -> IdentSet where F: Fn(&&Field<'_>) -> bool, V: Fn(&&Variant<'_>) -> bool,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
type_params_in_fields<'b, F>( &'b self, fields: &'b Fields<Field<'a>>, field_filter: F, declared: &IdentSet, ) -> IdentSet where F: Fn(&&'b Field<'_>) -> bool,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.
declare_errors(&self) -> ErrorDeclaration80     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.
check_errors(&self) -> ErrorCheck<'_>85     pub fn check_errors(&self) -> ErrorCheck<'_> {
86         ErrorCheck::default()
87     }
88 
89     /// Generate local variable declarations for all fields.
local_declarations(&self) -> TokenStream90     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 
post_transform_call(&self) -> Option<TokenStream>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.
fallback_decl(&self) -> TokenStream105     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 
require_fields(&self) -> TokenStream110     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 
initializers(&self) -> TokenStream130     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.
core_loop(&self) -> TokenStream135     pub(in crate::codegen) fn core_loop(&self) -> TokenStream {
136         self.make_field_ctx().core_loop()
137     }
138 
make_field_ctx(&'a self) -> FieldsGen<'a>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