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