byte_array_literals/
lib.rs1extern crate proc_macro;
2
3use proc_macro::{Delimiter, Group, Literal, Punct, Spacing, TokenStream, TokenTree};
4
5#[proc_macro]
7pub fn str(input: TokenStream) -> TokenStream {
8 let rv = convert_str(input);
9
10 vec![TokenTree::Group(Group::new(
11 Delimiter::Bracket,
12 rv.into_iter().collect(),
13 ))]
14 .into_iter()
15 .collect()
16}
17
18#[proc_macro]
20pub fn str_nl(input: TokenStream) -> TokenStream {
21 let mut rv = convert_str(input);
22
23 rv.push(TokenTree::Literal(Literal::u8_suffixed(b'\n')));
24
25 vec![TokenTree::Group(Group::new(
26 Delimiter::Bracket,
27 rv.into_iter().collect(),
28 ))]
29 .into_iter()
30 .collect()
31}
32
33fn convert_str(input: TokenStream) -> Vec<TokenTree> {
34 let mut it = input.into_iter();
35
36 let mut tokens = Vec::new();
37 match it.next() {
38 Some(TokenTree::Literal(l)) => {
39 for b in to_string(l).into_bytes() {
40 tokens.push(TokenTree::Literal(Literal::u8_suffixed(b)));
41 tokens.push(TokenTree::Punct(Punct::new(',', Spacing::Alone)));
42 }
43 }
44 _ => panic!(),
45 }
46
47 assert!(it.next().is_none());
48 tokens
49}
50
51fn to_string(lit: Literal) -> String {
52 let formatted = lit.to_string();
53
54 let mut it = formatted.chars();
55 assert_eq!(it.next(), Some('"'));
56
57 let mut rv = String::new();
58 loop {
59 match it.next() {
60 Some('"') => match it.next() {
61 Some(_) => panic!(),
62 None => break,
63 },
64 Some('\\') => match it.next() {
65 Some('x') => {
66 let hi = it.next().unwrap().to_digit(16).unwrap();
67 let lo = it.next().unwrap().to_digit(16).unwrap();
68 let v = (hi << 16) | lo;
69 rv.push(v as u8 as char);
70 }
71 Some('u') => {
72 assert_eq!(it.next(), Some('{'));
73 let mut c = it.next().unwrap();
74 let mut ch = 0;
75 while let Some(v) = c.to_digit(16) {
76 ch *= 16;
77 ch |= v;
78 c = it.next().unwrap();
79 }
80 assert_eq!(c, '}');
81 rv.push(::std::char::from_u32(ch).unwrap());
82 }
83 Some('0') => rv.push('\0'),
84 Some('\\') => rv.push('\\'),
85 Some('\"') => rv.push('\"'),
86 Some('r') => rv.push('\r'),
87 Some('n') => rv.push('\n'),
88 Some('t') => rv.push('\t'),
89 Some(_) => panic!(),
90 None => panic!(),
91 },
92 Some(c) => rv.push(c),
93 None => panic!(),
94 }
95 }
96
97 rv
98}