diff options
| author | mat <github@matdoes.dev> | 2022-04-26 22:58:18 +0000 |
|---|---|---|
| committer | mat <github@matdoes.dev> | 2022-04-26 22:58:18 +0000 |
| commit | dd24110019c0ded21e064b2273acc326173c84f5 (patch) | |
| tree | 5d958ce932379a8b2548e01ccd09d08accce5450 /azalea-protocol/packet-macros/src | |
| parent | 5736a790d34cb55202521fcfe807bea6eb5f07c7 (diff) | |
| download | azalea-drasl-dd24110019c0ded21e064b2273acc326173c84f5.tar.xz | |
add derive mcbufreadable/writable
Diffstat (limited to 'azalea-protocol/packet-macros/src')
| -rwxr-xr-x | azalea-protocol/packet-macros/src/lib.rs | 112 |
1 files changed, 112 insertions, 0 deletions
diff --git a/azalea-protocol/packet-macros/src/lib.rs b/azalea-protocol/packet-macros/src/lib.rs index 45df7e81..089d1594 100755 --- a/azalea-protocol/packet-macros/src/lib.rs +++ b/azalea-protocol/packet-macros/src/lib.rs @@ -6,6 +6,118 @@ use syn::{ parse_macro_input, DeriveInput, FieldsNamed, Ident, LitInt, Token, }; +#[proc_macro_derive(McBufReadable, attributes(varint))] +pub fn derive_mcbufreadable(input: TokenStream) -> TokenStream { + let DeriveInput { ident, data, .. } = parse_macro_input!(input); + + let fields = match data { + syn::Data::Struct(syn::DataStruct { fields, .. }) => fields, + _ => panic!("#[derive(*Packet)] can only be used on structs"), + }; + let FieldsNamed { named, .. } = match fields { + syn::Fields::Named(f) => f, + _ => panic!("#[derive(*Packet)] can only be used on structs with named fields"), + }; + + let read_fields = named + .iter() + .map(|f| { + let field_name = &f.ident; + let field_type = &f.ty; + // do a different buf.write_* for each field depending on the type + // if it's a string, use buf.write_string + match field_type { + syn::Type::Path(_) => { + if f.attrs.iter().any(|a| a.path.is_ident("varint")) { + quote! { + let #field_name = crate::mc_buf::McBufVarintReadable::varint_read_into(buf).await?; + } + } else { + quote! { + let #field_name = crate::mc_buf::McBufReadable::read_into(buf).await?; + } + } + } + _ => panic!( + "Error reading field {}: {}", + field_name.clone().unwrap(), + field_type.to_token_stream() + ), + } + }) + .collect::<Vec<_>>(); + let read_field_names = named.iter().map(|f| &f.ident).collect::<Vec<_>>(); + + quote! { + #[async_trait::async_trait] + + impl crate::mc_buf::McBufReadable for #ident { + async fn read_into<R>(buf: &mut R) -> Result<Self, String> + where + R: AsyncRead + std::marker::Unpin + std::marker::Send, + { + #(#read_fields)* + Ok(#ident { + #(#read_field_names: #read_field_names),* + }) + } + } + } + .into() +} + +#[proc_macro_derive(McBufWritable, attributes(varint))] +pub fn derive_mcbufwritable(input: TokenStream) -> TokenStream { + let DeriveInput { ident, data, .. } = parse_macro_input!(input); + + let fields = match data { + syn::Data::Struct(syn::DataStruct { fields, .. }) => fields, + _ => panic!("#[derive(*Packet)] can only be used on structs"), + }; + let FieldsNamed { named, .. } = match fields { + syn::Fields::Named(f) => f, + _ => panic!("#[derive(*Packet)] can only be used on structs with named fields"), + }; + + let write_fields = named + .iter() + .map(|f| { + let field_name = &f.ident; + let field_type = &f.ty; + // do a different buf.write_* for each field depending on the type + // if it's a string, use buf.write_string + match field_type { + syn::Type::Path(_) => { + if f.attrs.iter().any(|attr| attr.path.is_ident("varint")) { + quote! { + crate::mc_buf::McBufVarintWritable::varint_write_into(&self.#field_name, buf)?; + } + } else { + quote! { + crate::mc_buf::McBufWritable::write_into(&self.#field_name, buf)?; + } + } + } + _ => panic!( + "Error writing field {}: {}", + field_name.clone().unwrap(), + field_type.to_token_stream() + ), + } + }) + .collect::<Vec<_>>(); + + quote! { + impl crate::mc_buf::McBufWritable for #ident { + fn write_into(&self, buf: &mut Vec<u8>) -> Result<(), std::io::Error> { + #(#write_fields)* + Ok(()) + } + } + } + .into() +} + fn as_packet_derive(input: TokenStream, state: proc_macro2::TokenStream) -> TokenStream { let DeriveInput { ident, data, .. } = parse_macro_input!(input); |
