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