1 extern crate proc_macro;
2 
3 use proc_macro::{Delimiter, Group, Literal, Punct, Spacing, TokenStream, TokenTree};
4 
5 /// Expand a `str` literal into a byte array.
6 #[proc_macro]
str(input: TokenStream) -> TokenStream7 pub 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 /// The same as `str` but appends a `'\n'`.
19 #[proc_macro]
str_nl(input: TokenStream) -> TokenStream20 pub 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 
convert_str(input: TokenStream) -> Vec<TokenTree>33 fn 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 
to_string(lit: Literal) -> String51 fn 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 }
99