darling_core/codegen/
attrs_field.rs
1use quote::{quote, quote_spanned, ToTokens, TokenStreamExt};
2use syn::spanned::Spanned;
3
4use crate::options::{AttrsField, ForwardAttrsFilter};
5
6#[derive(Default)]
7pub struct ForwardAttrs<'a> {
8 pub filter: Option<&'a ForwardAttrsFilter>,
9 pub field: Option<&'a AttrsField>,
10}
11
12impl ForwardAttrs<'_> {
13 pub fn will_forward_any(&self) -> bool {
16 if let Some(filter) = self.filter {
17 !filter.is_empty() && self.field.is_some()
18 } else {
19 false
20 }
21 }
22
23 pub fn as_declaration(&self) -> Option<Declaration<'_>> {
25 self.field.map(Declaration)
26 }
27
28 pub fn as_match_arms(&self) -> MatchArms<'_> {
30 MatchArms(self)
31 }
32
33 pub fn as_value_populator(&self) -> Option<ValuePopulator<'_>> {
36 self.field.map(ValuePopulator)
37 }
38
39 pub fn as_initializer(&self) -> Option<Initializer<'_>> {
41 self.field.map(Initializer)
42 }
43}
44
45pub struct Declaration<'a>(pub &'a AttrsField);
46
47impl ToTokens for Declaration<'_> {
48 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
49 let ident = &self.0.ident;
50 tokens.append_all(quote! {
51 let mut __fwd_attrs: ::darling::export::Vec<::darling::export::syn::Attribute> = vec![];
52 let mut #ident: ::darling::export::Option<_> = None;
53 });
54 }
55}
56
57pub struct ValuePopulator<'a>(pub &'a AttrsField);
58
59impl ToTokens for ValuePopulator<'_> {
60 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
61 let AttrsField { ident, with } = self.0;
62 let initializer_expr = match with {
63 Some(with) => quote_spanned!(with.span()=> __errors.handle(#with(__fwd_attrs))),
64 None => quote!(::darling::export::Some(__fwd_attrs)),
65 };
66 tokens.append_all(quote!(#ident = #initializer_expr;));
67 }
68}
69
70pub struct Initializer<'a>(pub &'a AttrsField);
71
72impl ToTokens for Initializer<'_> {
73 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
74 let ident = &self.0.ident;
75 tokens.append_all(quote!(#ident: #ident.expect("Errors were already checked"),));
76 }
77}
78
79pub struct MatchArms<'a>(&'a ForwardAttrs<'a>);
80
81impl ToTokens for MatchArms<'_> {
82 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
83 if !self.0.will_forward_any() {
84 tokens.append_all(quote!(_ => continue));
85 return;
86 }
87
88 let push_command = quote!(__fwd_attrs.push(__attr.clone()));
89
90 tokens.append_all(
91 match self
92 .0
93 .filter
94 .expect("Can only forward attributes if filter is defined")
95 {
96 ForwardAttrsFilter::All => quote!(_ => #push_command),
97 ForwardAttrsFilter::Only(idents) => {
98 let names = idents.to_strings();
99 quote! {
100 #(#names)|* => #push_command,
101 _ => continue,
102 }
103 }
104 },
105 );
106 }
107}