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
#![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.2"
)]
mod comments;
extern crate proc_macro;
use std::{iter::FromIterator, 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: TokenStream) -> Self {
let mut ts = ignore_groups(input).into_iter();
let input_str = match (ts.next(), ts.next()) {
(Some(TokenTree::Literal(literal)), None) => literal.to_string(),
_ => panic!("expected single string literal"),
};
let mut buf: Vec<u8> = input_str.into();
match buf.as_slice() {
[b'"', .., b'"'] => (),
_ => panic!("expected single string literal"),
};
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 ts = TokenStream::from_iter(TokenTreeIter::new(input));
TokenStream::from(TokenTree::Group(Group::new(Delimiter::Bracket, ts)))
}