byte_strings_proc_macro/
as_bytes.rs1::cfg_if::cfg_if![ if #[cfg(feature = "proc-macro-hygiene")]
2{
3 #[cfg(any())]
4 mod objective {
5 macro_rules! as_bytes {(
6 $input_str_literal:expr
7 ) => (
8 b"_"
9 )}
10 }
11
12 #[doc(hidden)]
13 #[proc_macro]
14 pub fn as_bytes (
15 input: proc_macro::TokenStream,
16 ) -> proc_macro::TokenStream
17 {
18 let input_expr = syn::parse_macro_input!(input as syn::Expr);
19
20 match input_expr {
21 syn::Expr::Lit(
24 syn::ExprLit {
25 lit: syn::Lit::ByteStr(_),
26 ..
27 }
28 ) => proc_macro::TokenStream::from(quote::quote! {
29 input_expr
30 }),
31
32 syn::Expr::Lit(
35 syn::ExprLit {
36 lit: syn::Lit::Str(input_str_literal),
37 attrs: _,
38 }
39 ) => {
40 proc_macro::TokenStream::from(
41 proc_macro::TokenTree::Literal(
42 proc_macro::Literal::byte_string(
43 input_str_literal.value().as_bytes()
44 )
45 )
46 )
47 },
48
49 _ => throw!(input_expr.span()=>
51 "expected a string literal (or a byte string literal)"
52 ),
53 }
54 }
55}
56else
57{
58 #[cfg(any())]
59 mod objective {
60 macro_rules! const_as_bytes {(
61 const $const_literal_name:ident = as_bytes!(
62 $input_str_literal:expr
63 );
64 ) => (
65 const $const_literal_name: &[u8; _] = b"_";
66 )}
67 }
68
69 struct ConstAsBytes {
70 const_literal_name: syn::Ident,
71 input_str_literal: syn::Expr,
72 }
73
74 impl Parse for ConstAsBytes
75 {
76 fn parse (input: syn::parse::ParseStream) -> syn::parse::Result<Self>
77 {
78 macro_rules! parse_token {[$tt:tt] => (
79 input.parse::<syn::Token![$tt]>()?
80 )}
81
82 parse_token![ const ];
83 let const_literal_name: syn::Ident = input.parse()?;
84 parse_token![ = ];
85 input.parse::<kw::as_bytes>()?;
86 parse_token![ ! ];
87
88 let input_str_literal: syn::Expr = syn::group::
89 parse_parens(&input)?
90 .content
91 .parse()?
92 ;
93 parse_token![ ; ];
94 Ok(ConstAsBytes {
95 const_literal_name,
96 input_str_literal,
97 })
98 }
99 }
100
101 #[proc_macro]
102 pub fn const_as_bytes (
103 input: proc_macro::TokenStream,
104 ) -> proc_macro::TokenStream
105 {
106 let ConstAsBytes {
107 const_literal_name,
108 input_str_literal: input_expr,
109 } = syn::parse_macro_input!(input);
110
111 let expr_span = input_expr.span().clone();
112
113 let (bytes, attrs) = match input_expr {
114 syn::Expr::Lit(
117 syn::ExprLit {
118 lit: syn::Lit::ByteStr(_),
119 ..
120 }
121 ) => return proc_macro::TokenStream::from(quote::quote! {
122 const #const_literal_name: &'static str = #input_expr;
123 }),
124
125 syn::Expr::Lit(
128 syn::ExprLit {
129 lit: syn::Lit::Str(input_str_literal),
130 attrs,
131 }
132 ) => (input_str_literal.value().into_bytes(), attrs),
133
134 _ => throw!(input_expr.span()=>
136 "expected a string literal (or a byte string literal)"
137 ),
138 };
139
140 let len = syn::Expr::
141 Lit(syn::ExprLit {
142 attrs: vec![],
143
144 lit: syn::Lit::Int(syn::LitInt::new(
145 bytes.len() as u64,
147
148 syn::IntSuffix::Usize,
150
151 expr_span.clone(),
153 ))
154 })
155 ;
156
157 let bytes = syn::Expr::
158 Lit(syn::ExprLit {
159 attrs,
160
161 lit: syn::Lit::ByteStr(syn::LitByteStr::new(
162 &bytes,
164
165 expr_span.clone(),
167 ))
168 })
169 ;
170
171 proc_macro::TokenStream::from(quote::quote! {
172 const #const_literal_name: &'static [u8; #len] = #bytes;
173 })
174 }
175}];