mclib_macros/
lib.rs

1use darling::FromDeriveInput;
2use proc_macro::TokenStream;
3use syn::__private::quote::quote;
4use syn::{parse_macro_input, DeriveInput};
5
6#[proc_macro_derive(MCType)]
7pub fn derive_type(input: TokenStream) -> TokenStream {
8    let input = parse_macro_input!(input);
9    let DeriveInput { ident, data, .. } = input;
10
11    let data = if let syn::Data::Struct(data) = data {
12        data
13    } else {
14        unimplemented!()
15    };
16
17    let fields_pack = data.fields.iter().map(|f| {
18        let name = &f.ident;
19        quote! {
20            result.extend(MCType::pack(&self.#name));
21        }
22    });
23
24    let fields_unpack = data.fields.iter().map(|f| {
25        let name = &f.ident;
26        quote! {
27            #name: MCType::unpack(src),
28        }
29    });
30
31    let expanded = quote! {
32        impl MCType for #ident {
33            fn pack(&self) -> Vec<u8> {
34                let mut result = Vec::new();
35                #(#fields_pack)*
36                result
37            }
38
39            fn unpack(src: &mut dyn Read) -> Self {
40                Self {
41                    #(#fields_unpack)*
42                }
43            }
44        }
45    };
46
47    expanded.into()
48}
49
50#[derive(FromDeriveInput, Default)]
51#[darling(attributes(packet))]
52struct Opts {
53    packet_id: i32,
54}
55
56#[proc_macro_derive(MCPacket, attributes(packet))]
57pub fn derive_packet(input: TokenStream) -> TokenStream {
58    let input = parse_macro_input!(input);
59    let opts = Opts::from_derive_input(&input).unwrap();
60    let DeriveInput { ident, data, .. } = input;
61
62    let packet_id = opts.packet_id;
63
64    let data = if let syn::Data::Struct(data) = data {
65        data
66    } else {
67        unimplemented!()
68    };
69
70    let fields_pack = data.fields.iter().map(|f| {
71        let name = &f.ident;
72        quote! {
73            body.extend(MCType::pack(&self.#name));
74        }
75    });
76
77    let fields_unpack = data.fields.iter().map(|f| {
78        let name = &f.ident;
79        quote! {
80            #name: MCType::unpack(src),
81        }
82    });
83
84    let expanded = quote! {
85        impl MCPacket for #ident {
86            fn packet_id(&self) -> i32 {
87                #packet_id
88            }
89
90            fn pack(&self) -> Vec<u8> {
91                let mut body = Vec::new();
92                body.extend(MCVarInt::from(self.packet_id()).pack());
93                #(#fields_pack)*
94                let mut result = Vec::new();
95                result.extend(MCVarInt::from(body.len() as i32).pack());
96                result.extend(body);
97                result
98            }
99
100            fn unpack(src: &mut dyn std::io::Read) -> Self {
101                Self {
102                    #(#fields_unpack)*
103                }
104            }
105        }
106    };
107
108    expanded.into()
109}