darling_core/codegen/
attrs_field.rs1use quote::{quote, quote_spanned, ToTokens, TokenStreamExt};
2use syn::spanned::Spanned;
3
4use crate::options::{ForwardAttrsFilter, ForwardedField};
5
6#[derive(Default)]
7pub struct ForwardAttrs<'a> {
8 pub filter: Option<&'a ForwardAttrsFilter>,
9 pub field: Option<&'a ForwardedField>,
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<'a>(&'a self) -> Option<impl 'a + ToTokens> {
41 self.field.map(|f| f.as_initializer())
42 }
43}
44
45pub struct Declaration<'a>(pub &'a ForwardedField);
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 ForwardedField);
58
59impl ToTokens for ValuePopulator<'_> {
60 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
61 let ForwardedField { 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 MatchArms<'a>(&'a ForwardAttrs<'a>);
71
72impl ToTokens for MatchArms<'_> {
73 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
74 if !self.0.will_forward_any() {
75 tokens.append_all(quote!(_ => continue));
76 return;
77 }
78
79 let push_command = quote!(__fwd_attrs.push(__attr.clone()));
80
81 tokens.append_all(
82 match self
83 .0
84 .filter
85 .expect("Can only forward attributes if filter is defined")
86 {
87 ForwardAttrsFilter::All => quote!(_ => #push_command),
88 ForwardAttrsFilter::Only(idents) => {
89 let names = idents.to_strings();
90 quote! {
91 #(#names)|* => #push_command,
92 _ => continue,
93 }
94 }
95 },
96 );
97 }
98}