1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#![no_std]
#![forbid(unsafe_code)]
use proc_macro2::{Group, Literal, Punct, Spacing, TokenStream, TokenTree};
use quote::quote_spanned;
use syn::{parse2, LitByteStr};
#[proc_macro]
pub fn expand(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
_expand(input.into()).into()
}
fn _expand(input: TokenStream) -> TokenStream {
let mut input = input.into_iter();
let mut output = TokenStream::new();
loop {
match input.next() {
Some(TokenTree::Group(t)) => {
output.extend(Some(TokenTree::Group(Group::new(
t.delimiter(),
_expand(t.stream()),
))));
}
Some(TokenTree::Punct(t)) if t.as_char() == '@' => {
let tt = if let Some(tt) = input.next() {
tt
} else {
output.extend(Some(TokenTree::Punct(t)));
break;
};
let mut xs = if let Ok(t) = parse2::<LitByteStr>(tt.clone().into()) {
t.value().into_iter()
} else {
output.extend(Some(TokenTree::Punct(t)));
output.extend(Some(tt));
continue;
};
if let Some(x) = xs.next() {
output.extend(Some(TokenTree::Literal(Literal::u8_suffixed(x))));
} else {
output.extend(quote_spanned! { tt.span() =>
compile_error!("can't expand an empty byte string")
});
break;
}
for x in xs {
output.extend(Some(TokenTree::Punct(Punct::new(',', Spacing::Alone))));
output.extend(Some(TokenTree::Literal(Literal::u8_suffixed(x))));
}
}
Some(t) => {
output.extend(Some(t));
}
None => break,
}
}
output
}