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}