paste_impl/
enum_hack.rs

1use proc_macro::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree};
2use std::collections::hash_map::DefaultHasher;
3use std::hash::{Hash, Hasher};
4use std::iter::FromIterator;
5
6pub fn wrap(output: TokenStream) -> TokenStream {
7    let mut hasher = DefaultHasher::default();
8    output.to_string().hash(&mut hasher);
9    let mangled_name = format!("_paste_{}", hasher.finish());
10    let ident = Ident::new(&mangled_name, Span::call_site());
11
12    // #[derive(paste::EnumHack)]
13    // enum #ident {
14    //     Value = (stringify! {
15    //         #output
16    //     }, 0).1,
17    // }
18    TokenStream::from_iter(vec![
19        TokenTree::Punct(Punct::new('#', Spacing::Alone)),
20        TokenTree::Group(Group::new(
21            Delimiter::Bracket,
22            TokenStream::from_iter(vec![
23                TokenTree::Ident(Ident::new("derive", Span::call_site())),
24                TokenTree::Group(Group::new(
25                    Delimiter::Parenthesis,
26                    TokenStream::from_iter(vec![
27                        TokenTree::Ident(Ident::new("paste", Span::call_site())),
28                        TokenTree::Punct(Punct::new(':', Spacing::Joint)),
29                        TokenTree::Punct(Punct::new(':', Spacing::Alone)),
30                        TokenTree::Ident(Ident::new("EnumHack", Span::call_site())),
31                    ]),
32                )),
33            ]),
34        )),
35        TokenTree::Ident(Ident::new("enum", Span::call_site())),
36        TokenTree::Ident(ident),
37        TokenTree::Group(Group::new(
38            Delimiter::Brace,
39            TokenStream::from_iter(vec![
40                TokenTree::Ident(Ident::new("Value", Span::call_site())),
41                TokenTree::Punct(Punct::new('=', Spacing::Alone)),
42                TokenTree::Group(Group::new(
43                    Delimiter::Parenthesis,
44                    TokenStream::from_iter(vec![
45                        TokenTree::Ident(Ident::new("stringify", Span::call_site())),
46                        TokenTree::Punct(Punct::new('!', Spacing::Alone)),
47                        TokenTree::Group(Group::new(Delimiter::Brace, output)),
48                        TokenTree::Punct(Punct::new(',', Spacing::Alone)),
49                        TokenTree::Literal(Literal::usize_unsuffixed(0)),
50                    ]),
51                )),
52                TokenTree::Punct(Punct::new('.', Spacing::Alone)),
53                TokenTree::Literal(Literal::usize_unsuffixed(1)),
54                TokenTree::Punct(Punct::new(',', Spacing::Alone)),
55            ]),
56        )),
57    ])
58}
59
60pub fn extract(input: TokenStream) -> TokenStream {
61    let mut tokens = input.into_iter();
62    let _ = tokens.next().expect("enum");
63    let _ = tokens.next().expect("#ident");
64    let mut braces = match tokens.next().expect("{...}") {
65        TokenTree::Group(group) => group.stream().into_iter(),
66        _ => unreachable!("{...}"),
67    };
68    let _ = braces.next().expect("Value");
69    let _ = braces.next().expect("=");
70    let mut parens = match braces.next().expect("(...)") {
71        TokenTree::Group(group) => group.stream().into_iter(),
72        _ => unreachable!("(...)"),
73    };
74    let _ = parens.next().expect("stringify");
75    let _ = parens.next().expect("!");
76    let token_stream = match parens.next().expect("{...}") {
77        TokenTree::Group(group) => group.stream(),
78        _ => unreachable!("{...}"),
79    };
80    let _ = parens.next().expect(",");
81    let _ = parens.next().expect("0");
82    let _ = braces.next().expect(".");
83    let _ = braces.next().expect("1");
84    let _ = braces.next().expect(",");
85    token_stream
86}