darling_core/codegen/
trait_impl.rs
1use proc_macro2::TokenStream;
2use quote::quote;
3use syn::{Generics, Ident};
4
5use crate::ast::{Data, Fields};
6use crate::codegen::{
7 error::{ErrorCheck, ErrorDeclaration},
8 DefaultExpression, Field, FieldsGen, PostfixTransform, Variant,
9};
10use crate::usage::{CollectTypeParams, IdentSet, Purpose};
11
12#[derive(Debug)]
13pub 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
22impl<'a> TraitImpl<'a> {
23 pub fn declared_type_params(&self) -> IdentSet {
25 self.generics
26 .type_params()
27 .map(|tp| tp.ident.clone())
28 .collect()
29 }
30
31 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 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
78impl<'a> TraitImpl<'a> {
79 pub fn declare_errors(&self) -> ErrorDeclaration {
81 ErrorDeclaration::default()
82 }
83
84 pub fn check_errors(&self) -> ErrorCheck<'_> {
86 ErrorCheck::default()
87 }
88
89 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 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 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 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}