mclib-macros 0.0.1

Proc-macro for mclib
Documentation
use darling::FromDeriveInput;
use proc_macro::TokenStream;
use syn::__private::quote::quote;
use syn::{parse_macro_input, DeriveInput};

#[proc_macro_derive(MCType)]
pub fn derive_type(input: TokenStream) -> TokenStream {
    let input = parse_macro_input!(input);
    let DeriveInput { ident, data, .. } = input;

    let data = if let syn::Data::Struct(data) = data {
        data
    } else {
        unimplemented!()
    };

    let fields_pack = data.fields.iter().map(|f| {
        let name = &f.ident;
        quote! {
            result.extend(MCType::pack(&self.#name));
        }
    });

    let fields_unpack = data.fields.iter().map(|f| {
        let name = &f.ident;
        quote! {
            #name: MCType::unpack(src),
        }
    });

    let expanded = quote! {
        impl MCType for #ident {
            fn pack(&self) -> Vec<u8> {
                let mut result = Vec::new();
                #(#fields_pack)*
                result
            }

            fn unpack(src: &mut dyn Read) -> Self {
                Self {
                    #(#fields_unpack)*
                }
            }
        }
    };

    expanded.into()
}

#[derive(FromDeriveInput, Default)]
#[darling(attributes(packet))]
struct Opts {
    packet_id: i32,
}

#[proc_macro_derive(MCPacket, attributes(packet))]
pub fn derive_packet(input: TokenStream) -> TokenStream {
    let input = parse_macro_input!(input);
    let opts = Opts::from_derive_input(&input).unwrap();
    let DeriveInput { ident, data, .. } = input;

    let packet_id = opts.packet_id;

    let data = if let syn::Data::Struct(data) = data {
        data
    } else {
        unimplemented!()
    };

    let fields_pack = data.fields.iter().map(|f| {
        let name = &f.ident;
        quote! {
            body.extend(MCType::pack(&self.#name));
        }
    });

    let fields_unpack = data.fields.iter().map(|f| {
        let name = &f.ident;
        quote! {
            #name: MCType::unpack(src),
        }
    });

    let expanded = quote! {
        impl MCPacket for #ident {
            fn packet_id(&self) -> i32 {
                #packet_id
            }

            fn pack(&self) -> Vec<u8> {
                let mut body = Vec::new();
                body.extend(MCVarInt::from(self.packet_id()).pack());
                #(#fields_pack)*
                let mut result = Vec::new();
                result.extend(MCVarInt::from(body.len() as i32).pack());
                result.extend(body);
                result
            }

            fn unpack(src: &mut dyn std::io::Read) -> Self {
                Self {
                    #(#fields_unpack)*
                }
            }
        }
    };

    expanded.into()
}