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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#![doc(
html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg",
html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg",
html_root_url = "https://docs.rs/hex-literal/0.3.3"
)]
mod comments;
extern crate proc_macro;
use std::vec::IntoIter;
use proc_macro::{Delimiter, Group, Literal, Punct, Spacing, TokenStream, TokenTree};
use crate::comments::{Exclude, ExcludingComments};
fn ignore_groups(mut input: TokenStream) -> TokenStream {
let mut tokens = input.clone().into_iter();
loop {
if let Some(TokenTree::Group(group)) = tokens.next() {
if group.delimiter() == Delimiter::None {
input = group.stream();
continue;
}
}
return input;
}
}
struct TokenTreeIter {
buf: ExcludingComments<IntoIter<u8>>,
is_punct: bool,
}
impl TokenTreeIter {
fn new(input: Literal) -> Self {
let mut buf: Vec<u8> = input.to_string().into();
match buf.as_slice() {
[b'"', .., b'"'] => (),
_ => panic!("expected string literals"),
};
buf.pop();
let mut iter = buf.into_iter().exclude_comments();
iter.next();
Self {
buf: iter,
is_punct: false,
}
}
fn next_hex_val(&mut self) -> Option<u8> {
loop {
let v = self.buf.next()?;
let n = match v {
b'0'..=b'9' => v - 48,
b'A'..=b'F' => v - 55,
b'a'..=b'f' => v - 87,
b' ' | b'\r' | b'\n' | b'\t' => continue,
_ => panic!("encountered invalid character"),
};
return Some(n);
}
}
}
impl Iterator for TokenTreeIter {
type Item = TokenTree;
fn next(&mut self) -> Option<TokenTree> {
let v = if self.is_punct {
TokenTree::Punct(Punct::new(',', Spacing::Alone))
} else {
let p1 = self.next_hex_val()?;
let p2 = match self.next_hex_val() {
Some(v) => v,
None => panic!("expected even number of hex characters"),
};
let val = (p1 << 4) + p2;
TokenTree::Literal(Literal::u8_suffixed(val))
};
self.is_punct = !self.is_punct;
Some(v)
}
}
#[proc_macro]
pub fn hex(input: TokenStream) -> TokenStream {
let mut out_ts = TokenStream::new();
for tt in ignore_groups(input) {
let iter = match tt {
TokenTree::Literal(literal) => TokenTreeIter::new(literal),
_ => panic!("expected string literals"),
};
out_ts.extend(iter);
}
TokenStream::from(TokenTree::Group(Group::new(Delimiter::Bracket, out_ts)))
}