1extern crate proc_macro;
2
3use std::io::{Error as IOError};
4use byteorder::{ByteOrder, WriteBytesExt, BE, LE};
5use failure::Fail;
6use quote::{ToTokens, quote};
7use proc_macro::TokenStream;
8use proc_macro_hack::proc_macro_hack;
9use syn::{parse_macro_input, Error as SynError, Expr, IntSuffix, FloatSuffix, Lit, LitInt, LitFloat, Token, UnOp};
10use syn::parse::{Parse, ParseStream};
11use syn::punctuated::Punctuated;
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14enum Endianness {
15 LE,
16 BE,
17}
18
19#[cfg(not(feature = "default-big-endian"))]
20const DEFAULT_ENDIANNESS: Endianness = Endianness::LE;
21
22#[cfg(feature = "default-big-endian")]
23const DEFAULT_ENDIANNESS: Endianness = Endianness::BE;
24
25#[derive(Debug, Fail)]
26enum Error {
27 #[fail(display = "Unsupported prefixed expression in the macro: {} [+] {}", _0, _1)]
28 UnsupportedPrefixedExpression(String, String),
29 #[fail(display = "Unsupported expression in the macro: {}", _0)]
30 UnsupportedExpression(String),
31 #[fail(display = "Unsupported literal in the macro: {}", _0)]
32 UnsupportedLit(String),
33 #[fail(display = "Unsupported numeric suffix in the macro: {}", _0)]
34 UnsupportedNumberSuffix(String),
35 #[fail(display = "Failed to parse the input as a comma-separated list: {}", _0)]
36 InvalidInput(#[cause] SynError),
37 #[fail(display = "Failed to parse endianness: {}", _0)]
38 InvalidEndianness(String),
39 #[fail(display = "Failed to write a suffixed value: {}, negative: {}, given suffix: {}, requested suffix: {}", _0, _1, _2, _3)]
40 IncompatibleNumberSuffix(String, bool, String, String),
41 #[fail(display = "Failed to write a value: {}", _0)]
42 IO(#[cause] IOError),
43}
44
45impl From<SynError> for Error {
46
47 fn from(from: SynError) -> Self {
48 Error::InvalidInput(from)
49 }
50}
51
52impl From<IOError> for Error {
53
54 fn from(from: IOError) -> Self {
55 Error::IO(from)
56 }
57}
58
59impl Error {
60
61 pub fn unsupported_expression(expr: Expr) -> Self {
62 Error::UnsupportedExpression(expr.into_token_stream().to_string())
63 }
64
65 pub fn unsupported_lit(lit: Lit) -> Self {
66 Error::UnsupportedLit(lit.into_token_stream().to_string())
67 }
68
69 pub fn unsupported_prefixed_expression(op: UnOp, expr: Expr) -> Self {
70 Error::UnsupportedPrefixedExpression(op.into_token_stream().to_string(), expr.into_token_stream().to_string())
71 }
72}
73
74fn int_to_suffix(negative: bool, int: &LitInt) -> Result<IntSuffix, Error> {
75 let num_bits = int.value();
76 let s = if negative {
77 match () {
78 () if num_bits > 0x80000000 => IntSuffix::I64,
79 () if num_bits > 0x8000 => IntSuffix::I32,
80 () if num_bits > 0x80 => IntSuffix::I16,
81 () => IntSuffix::I8,
82 }
83 } else {
84 match () {
85 () if num_bits > 0xFFFFFFFF => IntSuffix::U64,
86 () if num_bits > 0xFFFF => IntSuffix::U32,
87 () if num_bits > 0xFF => IntSuffix::U16,
88 () => IntSuffix::U8,
89 }
90 };
91 let s = match (s, int.suffix()) {
92 (s, IntSuffix::None) => s,
94 (IntSuffix::U8 , IntSuffix::U8 ) => IntSuffix::U8 ,
96 (IntSuffix::U8 , IntSuffix::U16) => IntSuffix::U16,
97 (IntSuffix::U8 , IntSuffix::U32) => IntSuffix::U32,
98 (IntSuffix::U8 , IntSuffix::U64) => IntSuffix::U64,
99 (IntSuffix::U16, IntSuffix::U16) => IntSuffix::U16,
100 (IntSuffix::U16, IntSuffix::U32) => IntSuffix::U32,
101 (IntSuffix::U16, IntSuffix::U64) => IntSuffix::U64,
102 (IntSuffix::U32, IntSuffix::U32) => IntSuffix::U32,
103 (IntSuffix::U32, IntSuffix::U64) => IntSuffix::U64,
104 (IntSuffix::U64, IntSuffix::U64) => IntSuffix::U64,
105 (IntSuffix::I8 , IntSuffix::I8 ) => IntSuffix::I8 ,
107 (IntSuffix::I8 , IntSuffix::I16) => IntSuffix::I16,
108 (IntSuffix::I8 , IntSuffix::I32) => IntSuffix::I32,
109 (IntSuffix::I8 , IntSuffix::I64) => IntSuffix::I64,
110 (IntSuffix::I16, IntSuffix::I16) => IntSuffix::I16,
111 (IntSuffix::I16, IntSuffix::I32) => IntSuffix::I32,
112 (IntSuffix::I16, IntSuffix::I64) => IntSuffix::I64,
113 (IntSuffix::I32, IntSuffix::I32) => IntSuffix::I32,
114 (IntSuffix::I32, IntSuffix::I64) => IntSuffix::I64,
115 (IntSuffix::I64, IntSuffix::I64) => IntSuffix::I64,
116 (IntSuffix::U8 , IntSuffix::I8 ) if num_bits < 0x80 => IntSuffix::I8 ,
118 (IntSuffix::U16, IntSuffix::I16) if num_bits < 0x8000 => IntSuffix::I16,
119 (IntSuffix::U32, IntSuffix::I32) if num_bits < 0x80000000 => IntSuffix::I32,
120 (IntSuffix::U64, IntSuffix::I64) if num_bits < 0x8000000000000000 => IntSuffix::I64,
121 (IntSuffix::U8 , IntSuffix::I16) => IntSuffix::I16,
122 (IntSuffix::U8 , IntSuffix::I32) => IntSuffix::I32,
123 (IntSuffix::U8 , IntSuffix::I64) => IntSuffix::I64,
124 (IntSuffix::U16, IntSuffix::I32) => IntSuffix::I32,
125 (IntSuffix::U16, IntSuffix::I64) => IntSuffix::I64,
126 (IntSuffix::U32, IntSuffix::I64) => IntSuffix::I64,
127 (given, requested) => {
129 return Err(Error::IncompatibleNumberSuffix(
130 int.into_token_stream().to_string(),
131 negative,
132 format!("{:?}", given),
133 format!("{:?}", requested),
134 ));
135 },
136 };
137 Ok(s)
138}
139
140fn bytify_implementation_int<O: ByteOrder>(negative: bool, int: LitInt, output: &mut Vec<u8>) -> Result<(), Error> {
141 let num_bits = int.value();
142 let num_bits_suffix = int_to_suffix(negative, &int)?;
143 match num_bits_suffix {
144 IntSuffix::U8 => {
145 output.write_u8(num_bits as u8)?;
146 },
147 IntSuffix::I8 => {
148 if negative {
149 output.write_u8((!(num_bits as u8)).wrapping_add(1))?;
150 } else {
151 output.write_u8( num_bits as u8)?;
152 }
153 },
154 IntSuffix::U16 => {
155 output.write_u16::<O>(num_bits as u16)?;
156 },
157 IntSuffix::I16 => {
158 if negative {
159 output.write_u16::<O>((!(num_bits as u16)).wrapping_add(1))?;
160 } else {
161 output.write_u16::<O>( num_bits as u16)?;
162 }
163 },
164 IntSuffix::U32 => {
165 output.write_u32::<O>(num_bits as u32)?;
166 },
167 IntSuffix::I32 => {
168 if negative {
169 output.write_u32::<O>((!(num_bits as u32)).wrapping_add(1))?;
170 } else {
171 output.write_u32::<O>( num_bits as u32)?;
172 }
173 },
174 IntSuffix::U64 => {
175 output.write_u64::<O>(num_bits as u64)?;
176 },
177 IntSuffix::I64 => {
178 if negative {
179 output.write_u64::<O>((!(num_bits as u64)).wrapping_add(1))?;
180 } else {
181 output.write_u64::<O>( num_bits as u64)?;
182 }
183 },
184 s => {
186 return Err(Error::UnsupportedNumberSuffix(format!("{:?}", s)));
187 },
188 }
189 Ok(())
190}
191
192fn float_to_suffix(negative: bool, float: &LitFloat) -> Result<FloatSuffix, Error> {
193 let num_bits = float.value();
194 let s = if num_bits > 3.40282347e+38 {
195 FloatSuffix::F64
196 } else {
197 FloatSuffix::F32
198 };
199 let s = match (s, float.suffix()) {
200 (s, FloatSuffix::None) => s,
202 (FloatSuffix::F32, FloatSuffix::F64) => FloatSuffix::F64,
204 (given, requested) => {
206 return Err(Error::IncompatibleNumberSuffix(
207 float.into_token_stream().to_string(),
208 negative,
209 format!("{:?}", given),
210 format!("{:?}", requested),
211 ));
212 },
213 };
214 Ok(s)
215}
216
217fn bytify_implementation_float<O: ByteOrder>(negative: bool, float: LitFloat, output: &mut Vec<u8>) -> Result<(), Error> {
218 let num_bits = float.value();
219 let num_bits_suffix = float_to_suffix(negative, &float)?;
220 match num_bits_suffix {
221 FloatSuffix::F32 => {
222 if negative {
223 output.write_f32::<O>(-(num_bits as f32))?;
224 } else {
225 output.write_f32::<O>( num_bits as f32 )?;
226 }
227 },
228 FloatSuffix::F64 => {
229 if negative {
230 output.write_f64::<O>(-num_bits)?;
231 } else {
232 output.write_f64::<O>( num_bits)?;
233 }
234 },
235 s => {
237 return Err(Error::UnsupportedNumberSuffix(format!("{:?}", s)));
238 },
239 }
240 Ok(())
241}
242
243fn bytify_implementation_element<O: ByteOrder>(lit: Lit, output: &mut Vec<u8>) -> Result<(), Error> {
244 match lit {
245 Lit::Char(c) => {
246 let offset = output.len();
247 output.resize(c.value().len_utf8() + offset, 0u8);
248 c.value().encode_utf8(&mut output[offset ..]);
249 },
250 Lit::Str(string) => {
251 output.extend_from_slice(string.value().as_bytes());
252 },
253 Lit::Int(int) => {
254 bytify_implementation_int::<O>(false, int, output)?;
255 },
256 Lit::Float(float) => {
257 bytify_implementation_float::<O>(false, float, output)?;
258 },
259 lit => {
260 return Err(Error::unsupported_lit(lit));
261 },
262 }
263 Ok(())
264}
265
266#[derive(Debug)]
267struct MyMacroInput {
268 list: Punctuated<Expr, Token![,]>,
269}
270
271impl Parse for MyMacroInput {
272
273 fn parse(input: ParseStream) -> Result<Self, SynError> {
274 Ok(MyMacroInput {
275 list: input.parse_terminated(Expr::parse)?,
276 })
277 }
278}
279
280fn bytify_implementation(input: MyMacroInput) -> Result<TokenStream, Error> {
281 let mut output: Vec<u8> = Vec::new();
282 for expr in input.list {
283 let (
284 endianness,
285 expr,
286 ) = match expr {
287 Expr::Type(tpe_expr) => {
288 let expr = *tpe_expr.expr;
289 let endianness = match tpe_expr.ty.into_token_stream().to_string().as_str() {
290 "BE" | "be" => Endianness::BE,
291 "LE" | "le" => Endianness::LE,
292 invalid => {
293 return Err(Error::InvalidEndianness(invalid.to_string()));
294 },
295 };
296 (endianness, expr)
297 },
298 expr => {
299 (DEFAULT_ENDIANNESS, expr)
300 },
301 };
302 match expr {
303 Expr::Lit(lit_expr) => {
304 if endianness == Endianness::BE {
305 bytify_implementation_element::<BE>(lit_expr.lit, &mut output)?;
306 } else {
307 bytify_implementation_element::<LE>(lit_expr.lit, &mut output)?;
308 }
309 },
310 Expr::Unary(unary_expr) => {
311 match unary_expr.op {
312 UnOp::Neg(op) => {
313 match *unary_expr.expr {
314 Expr::Lit(lit_expr) => {
315 match lit_expr.lit {
316 Lit::Int(int) => {
317 if endianness == Endianness::BE {
318 bytify_implementation_int::<BE>(true, int, &mut output)?;
319 } else {
320 bytify_implementation_int::<LE>(true, int, &mut output)?;
321 }
322 },
323 Lit::Float(float) => {
324 if endianness == Endianness::BE {
325 bytify_implementation_float::<BE>(true, float, &mut output)?;
326 } else {
327 bytify_implementation_float::<LE>(true, float, &mut output)?;
328 }
329 },
330 lit => {
331 return Err(Error::unsupported_lit(lit));
332 },
333 }
334 },
335 expr => {
336 return Err(Error::unsupported_prefixed_expression(UnOp::Neg(op), expr));
337 },
338 }
339 },
340 op => {
341 return Err(Error::unsupported_prefixed_expression(op, *unary_expr.expr));
342 },
343 }
344 },
345 expr => {
346 return Err(Error::unsupported_expression(expr));
347 },
348 }
349 }
350 Ok(quote! {
351 [
352 #(#output),*
353 ]
354 }.into())
355}
356
357#[proc_macro_hack]
358pub fn bytify(input: TokenStream) -> TokenStream {
359 let input = parse_macro_input!(input as MyMacroInput);
360 bytify_implementation(input).unwrap_or_else(|err| panic!("{}", err))
361}