1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
//! Macro implementation for using #[derive(Parsable)]
extern crate proc_macro;

use proc_macro::{TokenStream};
use syn::{DeriveInput, Data};
use quote::quote;

/// Macro generator
#[proc_macro_derive(Parsable)]
pub fn derive_parsable(struc: TokenStream) -> TokenStream {
    let ast: &DeriveInput = &syn::parse(struc).unwrap();
    let name = &ast.ident;
    if let Data::Struct(data_struct) = &ast.data {
        let mut p_fields_gen = vec![];
        let mut d_fields_gen = vec![];
        for field in &data_struct.fields {
            let field_ident = &field.ident.clone().expect("Expected named field");
            let field_type = &field.ty;
            p_fields_gen.push(
                quote! {
                    #field_ident: <#field_type>::parse(data)?
                }
            );
            d_fields_gen.push(
                quote! {
                    self.#field_ident.dump(data)?;
                }
            );
        }
        let final_gen = quote! {
            impl Parsable for #name {
                fn parse(data: &mut dyn std::io::Read) -> std::io::Result<Self> {
                    Ok(Self{
                        #(#p_fields_gen),*
                    })
                }

                fn dump(&self, data: &mut dyn std::io::Write) -> std::io::Result<usize> {
                    let mut write_count: usize = 0;
                    #(write_count += #d_fields_gen;)*
                    Ok(write_count)
                }
            }
        };
        return final_gen.into();
    } else {
        panic!("Expected Parsable auto-trait to be applied to struct");
    }
}