Skip to main content

sga_macros/
lib.rs

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/// This is a macro which automates creating a custom error if there is a parse error, and reads the specified uint and int type from the buffer, only as a Little Endian.
32#[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}