1 use proc_macro::{Ident, TokenStream, TokenTree};
2 use std::iter;
3 
4 macro_rules! quote {
5     () => {
6         ::proc_macro::TokenStream::new()
7     };
8     ($($tt:tt)*) => {{
9         let mut tokens = ::proc_macro::TokenStream::new();
10         quote_each_token!(tokens $($tt)*);
11         tokens
12     }};
13 }
14 
15 macro_rules! quote_each_token {
16     ($tokens:ident # $var:ident $($rest:tt)*) => {
17         $crate::quote::Tokens::extend(&mut $tokens, &$var);
18         quote_each_token!($tokens $($rest)*);
19     };
20     ($tokens:ident $ident:ident $($rest:tt)*) => {
21         <::proc_macro::TokenStream as ::std::iter::Extend<_>>::extend(
22             &mut $tokens,
23             ::std::iter::once(
24                 ::proc_macro::TokenTree::Ident(
25                     ::proc_macro::Ident::new(
26                         stringify!($ident),
27                         ::proc_macro::Span::call_site(),
28                     ),
29                 ),
30             ),
31         );
32         quote_each_token!($tokens $($rest)*);
33     };
34     ($tokens:ident ( $($inner:tt)* ) $($rest:tt)*) => {
35         <::proc_macro::TokenStream as ::std::iter::Extend<_>>::extend(
36             &mut $tokens,
37             ::std::iter::once(
38                 ::proc_macro::TokenTree::Group(
39                     ::proc_macro::Group::new(
40                         ::proc_macro::Delimiter::Parenthesis,
41                         quote!($($inner)*),
42                     ),
43                 ),
44             ),
45         );
46         quote_each_token!($tokens $($rest)*);
47     };
48     ($tokens:ident [ $($inner:tt)* ] $($rest:tt)*) => {
49         <::proc_macro::TokenStream as ::std::iter::Extend<_>>::extend(
50             &mut $tokens,
51             ::std::iter::once(
52                 ::proc_macro::TokenTree::Group(
53                     ::proc_macro::Group::new(
54                         ::proc_macro::Delimiter::Bracket,
55                         quote!($($inner)*),
56                     ),
57                 ),
58             ),
59         );
60         quote_each_token!($tokens $($rest)*);
61     };
62     ($tokens:ident { $($inner:tt)* } $($rest:tt)*) => {
63         <::proc_macro::TokenStream as ::std::iter::Extend<_>>::extend(
64             &mut $tokens,
65             ::std::iter::once(
66                 ::proc_macro::TokenTree::Group(
67                     ::proc_macro::Group::new(
68                         ::proc_macro::Delimiter::Brace,
69                         quote!($($inner)*),
70                     ),
71                 ),
72             ),
73         );
74         quote_each_token!($tokens $($rest)*);
75     };
76     ($tokens:ident $punct:tt $($rest:tt)*) => {
77         <::proc_macro::TokenStream as ::std::iter::Extend<_>>::extend(
78             &mut $tokens,
79             stringify!($punct).parse::<::proc_macro::TokenStream>(),
80         );
81         quote_each_token!($tokens $($rest)*);
82     };
83     ($tokens:ident) => {};
84 }
85 
86 pub trait Tokens {
extend(tokens: &mut TokenStream, var: &Self)87     fn extend(tokens: &mut TokenStream, var: &Self);
88 }
89 
90 impl Tokens for Ident {
extend(tokens: &mut TokenStream, var: &Self)91     fn extend(tokens: &mut TokenStream, var: &Self) {
92         tokens.extend(iter::once(TokenTree::Ident(var.clone())));
93     }
94 }
95 
96 impl Tokens for TokenStream {
extend(tokens: &mut TokenStream, var: &Self)97     fn extend(tokens: &mut TokenStream, var: &Self) {
98         tokens.extend(var.clone());
99     }
100 }
101 
102 impl<T: Tokens> Tokens for Option<T> {
extend(tokens: &mut TokenStream, var: &Self)103     fn extend(tokens: &mut TokenStream, var: &Self) {
104         if let Some(var) = var {
105             T::extend(tokens, var);
106         }
107     }
108 }
109 
110 impl<T: Tokens> Tokens for &T {
extend(tokens: &mut TokenStream, var: &Self)111     fn extend(tokens: &mut TokenStream, var: &Self) {
112         T::extend(tokens, var);
113     }
114 }
115