@@ -9,83 +9,20 @@ mod prelude;
9
9
mod reflective;
10
10
11
11
use prelude:: * ;
12
- use reflective:: { ReflectiveInput , ReflectiveInputType } ;
12
+ use reflective:: ReflectiveInput ;
13
13
14
14
// Only proc macros can be exported in `proc_macro` crates.
15
15
#[ proc_macro_derive( Reflective ) ]
16
16
pub fn derive_reflective ( input : TokenStream ) -> TokenStream {
17
17
// ^---------- TokenStream is provided by `proc_macro` which is
18
18
// automatically added to all `[lib] proc_macro = true`
19
19
// crates.
20
- use ReflectiveInputType as RIT ;
21
20
22
21
let data = parse_macro_input ! ( input as ReflectiveInput ) ;
23
22
// ^----------------- This concise syntax is why we implemented `syn::parse::Parse`
24
23
// for `ReflectiveInput`.
25
- let item_name = & data. 0 . ident ;
26
-
27
- let get_item = |fn_name : TokenStream2 , iter_fields : Box < dyn Iterator < Item = String > > | {
28
- // ^-------------------- ^---------- Boxing since it's dynamically dispatched.
29
- // | You can do it without a callback, this just saves code
30
- // | writing.
31
- // |
32
- // |> This could be any token stream. It's unhygenic so we should be careful what
33
- // we call it with as it's supposed to be an indentifier. Fortunately, due to
34
- // everything working in the rust compiler, we'd get Rust compiler errors in case
35
- // we call it with something wrong. That's why it's important to have integration
36
- // tests with proc macros since they can quickly get complicated and mistakes like
37
- // this could be missed.
38
- //
39
- // NOTE: Notice how it's `TokenStream2` instead of `TokenStream`. This is because
40
- // the `quote` crate works with `TokenStream2` and the reason is that the
41
- // `proc_macro2` crate doesn't require the user to have a proc macro crate. This is
42
- // useful for making libraries that work with proc macro code without being proc
43
- // macros themselves (since you can only export proc macros in proc macro crates).
44
-
45
- // This syntax is very similar to the traditional declarative macro syntax. The main
46
- // difference is instead of `$` we use `#`. Additionally we can use variables from our
47
- // #[proc_macro] function like so: `#variable`.
48
- quote ! {
49
- impl #item_name {
50
- pub const fn #fn_name( ) -> & ' static [ & ' static str ] {
51
- // ^------- We can even substitute identifiers.
52
-
53
- & [ #( #iter_fields) , * ]
54
- // ^- ********** --- `#(),*` expands similarly to how a declarative macro would
55
- // be expanded.
56
- }
57
- }
58
- }
59
- } ;
60
-
61
- match data. get_input_items ( ) {
62
- RIT :: Fields ( fields) => get_item (
63
- quote ! ( get_fields) ,
64
- //^--------------- we need to quote the identifier to use it.
65
- Box :: new ( fields. iter ( ) . flat_map ( |f| & f. ident ) . map ( Ident :: to_string) ) ,
66
- // ^------- You can do it with `filter_map()` as well. `flat_map()`
67
- // is just more powerful though, since it combines: mapping,
68
- // filtering and flattening into one callback.
69
- //
70
- // Also, we flat_map it since the struct could also just be a tuple
71
- // struct so `Field.ident` is `Option<Ident>` because of it.
72
- ) ,
73
- RIT :: Variants ( variants) => get_item (
74
- quote ! ( get_variants) ,
75
- Box :: new ( variants. iter ( ) . map ( |v| v. ident . to_string ( ) ) ) ,
76
- ) ,
77
- RIT :: UnionFields ( union) => get_item (
78
- quote ! ( get_fields) ,
79
- Box :: new (
80
- union
81
- . named
82
- . iter ( )
83
- . flat_map ( |f| & f. ident )
84
- . map ( Ident :: to_string) ,
85
- ) ,
86
- ) ,
87
- }
88
- . into ( )
89
24
//^-- Notice how we convert the `proc_macro2::TokenStream` output of `quote!` to
90
25
// `proc_macro::TokenStream`.
26
+
27
+ data. into_token_stream ( ) . into ( )
91
28
}
0 commit comments