1 // The use of fields in debug print commands does not count as "used",
2 // which causes the fields to trigger an unwanted dead code warning.
3 #![allow(dead_code)]
4 
5 //! This example shows how to do struct and field parsing using darling.
6 
7 use darling::{ast, FromDeriveInput, FromField, FromMeta};
8 use proc_macro2::TokenStream;
9 use quote::{quote, ToTokens};
10 use syn::parse_str;
11 
12 /// A speaking volume. Deriving `FromMeta` will cause this to be usable
13 /// as a string value for a meta-item key.
14 #[derive(Debug, Clone, Copy, FromMeta)]
15 #[darling(default)]
16 enum Volume {
17     Normal,
18     Whisper,
19     Shout,
20 }
21 
22 impl Default for Volume {
default() -> Self23     fn default() -> Self {
24         Volume::Normal
25     }
26 }
27 
28 /// Support parsing from a full derive input. Unlike FromMeta, this isn't
29 /// composable; each darling-dependent crate should have its own struct to handle
30 /// when its trait is derived.
31 #[derive(Debug, FromDeriveInput)]
32 // This line says that we want to process all attributes declared with `my_trait`,
33 // and that darling should panic if this receiver is given an enum.
34 #[darling(attributes(my_trait), supports(struct_any))]
35 struct MyInputReceiver {
36     /// The struct ident.
37     ident: syn::Ident,
38 
39     /// The type's generics. You'll need these any time your trait is expected
40     /// to work with types that declare generics.
41     generics: syn::Generics,
42 
43     /// Receives the body of the struct or enum. We don't care about
44     /// struct fields because we previously told darling we only accept structs.
45     data: ast::Data<(), MyFieldReceiver>,
46 
47     /// The Input Receiver demands a volume, so use `Volume::Normal` if the
48     /// caller doesn't provide one.
49     #[darling(default)]
50     volume: Volume,
51 }
52 
53 impl ToTokens for MyInputReceiver {
to_tokens(&self, tokens: &mut TokenStream)54     fn to_tokens(&self, tokens: &mut TokenStream) {
55         let MyInputReceiver {
56             ref ident,
57             ref generics,
58             ref data,
59             volume,
60         } = *self;
61 
62         let (imp, ty, wher) = generics.split_for_impl();
63         let fields = data
64             .as_ref()
65             .take_struct()
66             .expect("Should never be enum")
67             .fields;
68 
69         // Generate the format string which shows each field and its name
70         let fmt_string = fields
71             .iter()
72             .enumerate()
73             .map(|(i, f)| {
74                 // We have to preformat the ident in this case so we can fall back
75                 // to the field index for unnamed fields. It's not easy to read,
76                 // unfortunately.
77                 format!(
78                     "{} = {{}}",
79                     f.ident
80                         .as_ref()
81                         .map(|v| format!("{}", v))
82                         .unwrap_or_else(|| format!("{}", i))
83                 )
84             })
85             .collect::<Vec<_>>()
86             .join(", ");
87 
88         // Generate the actual values to fill the format string.
89         let field_list = fields
90             .into_iter()
91             .enumerate()
92             .map(|(i, f)| {
93                 let field_volume = f.volume.unwrap_or(volume);
94 
95                 // This works with named or indexed fields, so we'll fall back to the index so we can
96                 // write the output as a key-value pair.
97                 let field_ident = f.ident
98                     .as_ref()
99                     .map(|v| quote!(#v))
100                     .unwrap_or_else(|| {
101                         let i = syn::Index::from(i);
102                         quote!(#i)
103                     });
104 
105                 match field_volume {
106                     Volume::Normal => quote!(self.#field_ident),
107                     Volume::Shout => {
108                         quote!(::std::string::ToString::to_string(&self.#field_ident).to_uppercase())
109                     }
110                     Volume::Whisper => {
111                         quote!(::std::string::ToString::to_string(&self.#field_ident).to_lowercase())
112                     }
113                 }
114             })
115             .collect::<Vec<_>>();
116 
117         tokens.extend(quote! {
118             impl #imp Speak for #ident #ty #wher {
119                 fn speak(&self, writer: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
120                     write!(writer, #fmt_string, #(#field_list),*)
121                 }
122             }
123         });
124     }
125 }
126 
127 #[derive(Debug, FromField)]
128 #[darling(attributes(my_trait))]
129 struct MyFieldReceiver {
130     /// Get the ident of the field. For fields in tuple or newtype structs or
131     /// enum bodies, this can be `None`.
132     ident: Option<syn::Ident>,
133 
134     /// This magic field name pulls the type from the input.
135     ty: syn::Type,
136 
137     /// We declare this as an `Option` so that during tokenization we can write
138     /// `field.volume.unwrap_or(derive_input.volume)` to facilitate field-level
139     /// overrides of struct-level settings.
140     ///
141     /// Because this field is an `Option`, we don't need to include `#[darling(default)]`
142     volume: Option<Volume>,
143 }
144 
main()145 fn main() {
146     let input = r#"#[derive(MyTrait)]
147 #[my_trait(volume = "shout")]
148 pub struct Foo {
149     #[my_trait(volume = "whisper")]
150     bar: bool,
151 
152     baz: i64,
153 }"#;
154 
155     let parsed = parse_str(input).unwrap();
156     let receiver = MyInputReceiver::from_derive_input(&parsed).unwrap();
157     let tokens = quote!(#receiver);
158 
159     println!(
160         r#"
161 INPUT:
162 
163 {}
164 
165 PARSED AS:
166 
167 {:?}
168 
169 EMITS:
170 
171 {}
172     "#,
173         input, receiver, tokens
174     );
175 }
176