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] 7 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] 20 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 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 51 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