1extern crate proc_macro;
2
3use proc_macro::TokenStream;
4use quote::{format_ident, quote};
5use syn::{parse::{Parse, ParseStream}, parse_macro_input, Expr, Ident, Token, Type};
6
7struct ReadFieldInput {
8 reader: Expr,
9 _comma1: Token![,],
10 enum_name: Ident,
11 _colon2: Token![::],
12 variant: Ident,
13 _comma2: Token![,],
14 output_type: Type,
15}
16
17impl Parse for ReadFieldInput {
18 fn parse(input: ParseStream) -> syn::Result<Self> {
19 Ok(ReadFieldInput {
20 reader: input.parse()?,
21 _comma1: input.parse()?,
22 enum_name: input.parse()?,
23 _colon2: input.parse()?,
24 variant: input.parse()?,
25 _comma2: input.parse()?,
26 output_type: input.parse()?,
27 })
28 }
29}
30
31#[proc_macro]
33pub fn read_field(input: TokenStream) -> TokenStream {
34 let ReadFieldInput {
35 reader,
36 enum_name,
37 variant,
38 output_type,
39 ..
40 } = parse_macro_input!(input as ReadFieldInput);
41
42 let output_type = quote!(#output_type).to_string();
43
44 let method = format_ident!("read_{}", output_type);
45
46 let generated = if output_type == "u8" {
47 quote! {{
48 use byteorder::{LittleEndian, BigEndian, ReadBytesExt};
49
50 #reader.#method().map_err(|_| {
51 #enum_name::#variant("Failed to parse version number".to_string())
52 })
53 }}
54 } else {
55 quote! {{
56 use byteorder::{LittleEndian, BigEndian, ReadBytesExt};
57
58 #reader.#method::<LittleEndian>().map_err(|_| {
59 #enum_name::#variant("Failed to parse version number".to_string())
60 })
61 }}
62 };
63
64 generated.into()
65}