@@ -211,3 +211,76 @@ Hello, World! My name is Waffles
211
211
```
212
212
213
213
We've done it!
214
+
215
+ ## Custom Attributes
216
+
217
+ In some cases it might make sense to allow users some kind of configuration.
218
+ For example, the user might want to overwrite the name that is printed in the ` hello_world() ` method.
219
+
220
+ This can be achieved with custom attributes:
221
+
222
+ ``` rust,ignore
223
+ #[derive(HelloWorld)]
224
+ #[HelloWorldName = "the best Pancakes"]
225
+ struct Pancakes;
226
+
227
+ fn main() {
228
+ Pancakes::hello_world();
229
+ }
230
+ ```
231
+
232
+ If we try to compile this though, the compiler will respond with an error:
233
+
234
+ ``` bash
235
+ error: The attribute ` HelloWorldName` is currently unknown to the compiler and may have meaning added to it in the future (see issue # 29642)
236
+ ` ` `
237
+
238
+ The compiler needs to know that we' re handling this attribute and to not respond with an error.
239
+ This is done in the `hello-world-derive` crate by adding `attributes` to the `proc_macro_derive` attribute:
240
+
241
+ ```rust,ignore
242
+ #[proc_macro_derive(HelloWorld, attributes(HelloWorldName))]
243
+ pub fn hello_world(input: TokenStream) -> TokenStream
244
+ ```
245
+
246
+ Multiple attributes can be specified that way.
247
+
248
+ ## Raising Errors
249
+
250
+ Let' s assume that we do not want to accept enums as input to our custom derive method.
251
+
252
+ This condition can be easily checked with the help of ` syn` .
253
+ But how do we tell the user, that we do not accept enums?
254
+ The idiomatic way to report errors in procedural macros is to panic:
255
+
256
+ ` ` ` rust,ignore
257
+ fn impl_hello_world(ast: & syn::MacroInput) -> quote::Tokens {
258
+ let name = & ast.ident;
259
+ // Check if derive(HelloWorld) was specified for a struct
260
+ if let syn::Body::Struct(_) = ast.body {
261
+ // Yes, this is a struct
262
+ quote! {
263
+ impl HelloWorld for # name {
264
+ fn hello_world () {
265
+ println! (" Hello, World! My name is {}" , stringify! (# name));
266
+ }
267
+ }
268
+ }
269
+ } else {
270
+ //Nope. This is an Enum. We cannot handle these!
271
+ panic! (" #[derive(HelloWorld)] is only defined for structs, not for enums!" );
272
+ }
273
+ }
274
+ ` ` `
275
+
276
+ If a user now tries to derive ` HelloWorld` from an enum they will be greeted with following, hopefully helpful, error:
277
+
278
+ ` ` ` bash
279
+ error: custom derive attribute panicked
280
+ --> src/main.rs
281
+ |
282
+ | # [derive(HelloWorld)]
283
+ | ^^^^^^^^^^
284
+ |
285
+ = help: message: # [derive(HelloWorld)] is only defined for structs, not for enums!
286
+ ` ` `
0 commit comments