minceraft_derive/
lib.rs

1// very much WIP
2extern crate proc_macro;
3use proc_macro::{TokenStream};
4use quote::{quote, quote_spanned};
5use syn::{parse_macro_input, spanned::Spanned, LitInt, AttrStyle};
6
7#[proc_macro_derive(Packet, attributes(id))]
8pub fn derive_packet(input: TokenStream) -> TokenStream {
9	let ast: syn::DeriveInput = parse_macro_input!(input);
10	let name = ast.ident;
11
12	let attrs = ast.attrs;
13
14	let mut id = Option::<LitInt>::None;
15
16	for i in attrs {
17		if let AttrStyle::Outer = i.style {
18			id = Some(i.parse_args().unwrap());
19		}
20	}
21	
22	let id = id.unwrap();
23	
24
25	let fields = if let syn::Data::Struct(syn::DataStruct {
26        fields: syn::Fields::Named(ref fields),
27        ..
28    }) = ast.data
29    {
30        fields
31    } else {
32        panic!("Only support structs")
33    };
34	
35	let recurse_encoder = fields.named.iter().map(|f| {
36		let name = &f.ident;
37		quote_spanned! {f.span()=>
38			self.#name.write_to(w)?;
39		}
40	});
41	let stream_encoder = quote! {
42		#(#recurse_encoder)*
43	};
44
45	let recurse_decoder_types = fields.named.iter().map(|f| {
46		let ty = &f.ty;
47		let name = &f.ident;
48		quote_spanned! {f.span()=>
49			let #name = #ty::read_from(r)?;
50		}
51	});
52	let stream_decoder_types = quote! {
53		#(#recurse_decoder_types)*
54	};
55
56	let recurse_decoder_names = fields.named.iter().map(|f| {
57		let name = &f.ident;
58		quote_spanned! {f.span()=>
59			#name,
60		}
61	});
62	let stream_decoder_names = quote! {
63		#(#recurse_decoder_names)*
64	};
65
66	let extended = quote! {
67		use minceraft::net::types::{Encoder, Decoder};
68		impl Encoder for #name {
69			fn write_to(&self, w: &mut impl std::io::Write) -> anyhow::Result<()> {
70				#stream_encoder
71				Ok(())
72			}
73		}
74		
75		impl Decoder for #name {
76			fn read_from(r: &mut impl std::io::Read) -> anyhow::Result<Self> {
77				#stream_decoder_types
78
79				Ok(Self {
80					#stream_decoder_names
81				})
82			}
83		}
84
85		use minceraft::net::types::VarInt;
86		impl Packet for #name {
87			const ID: VarInt = VarInt(#id);
88		}
89	};
90	TokenStream::from(extended)
91}