create macro to not duplicate as much code and improve the PackageId parsing with it

This commit is contained in:
OMGeeky
2024-11-17 17:22:45 +01:00
parent ef8f7e8383
commit a5f94bc4ab
13 changed files with 287 additions and 183 deletions

47
mc-rust-server-macros/Cargo.lock generated Normal file
View File

@@ -0,0 +1,47 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "mc-rust-server-macros"
version = "0.1.0"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "proc-macro2"
version = "1.0.89"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
dependencies = [
"proc-macro2",
]
[[package]]
name = "syn"
version = "2.0.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"

View File

@@ -0,0 +1,14 @@
[package]
name = "mc-rust-server-macros"
version = "0.1.0"
edition = "2021"
[lib]
name = "mc_rust_server_macros"
path = "src/lib.rs"
proc-macro = true
[dependencies]
quote = "*"
syn = { version = "*", features = ["extra-traits"] }
proc-macro2 = "*"

View File

@@ -0,0 +1,9 @@
extern crate proc_macro;
use syn::{parse_macro_input, DeriveInput};
#[proc_macro_derive(McProtocol, attributes(protocol_read, protocol_write))]
pub fn proc_macro_protocol(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
mc_protocol::proc_macro_protocol(parse_macro_input!(input as DeriveInput)).into()
}
mod mc_protocol;

View File

@@ -0,0 +1,78 @@
use proc_macro2::{Ident, TokenStream};
use quote::quote;
use syn::parse::Parse;
use syn::{Data, DeriveInput, Lit, Token};
pub fn proc_macro_protocol(input: DeriveInput) -> TokenStream {
match input.data {
Data::Enum(e) => {
let variants = e.variants.into_iter();
let mut variant_data = vec![];
for v in variants {
let attr = v.attrs.into_iter().find_map(|a| {
if a.path().is_ident("protocol_read") {
Some(a.parse_args::<ProtocolAttribute>().ok()?)
} else {
None
}
});
if let Some(attr) = attr {
variant_data.push(ProtocolVariant {
attr,
ident: v.ident,
})
}
}
let variant_match = variant_data.into_iter().map(|v| {
let state = v.attr.state;
let id = v.attr.packet_id;
let name = v.ident;
quote! {(#state, #id)=>Self::#name (read_protocol_data(stream).await?)}
});
let variants_match = quote! {#(#variant_match),*};
let enum_name = input.ident;
quote! {
#[automatically_derived]
impl #enum_name {
pub async fn read_protocol_data<T:AsyncRead + AsyncWrite + Unpin>(
protocol_id: VarInt,
connection_state: ConnectionState,
stream: &mut RWStreamWithLimit<'_, T>,
)-> Result<IncomingPackageContent, String> {
Ok(match (connection_state, protocol_id.to_rs()){
#variants_match,
(other_state, other_id) => {
return Err(format!("Unrecognized protocol+state combination: {:?}/{}", other_state, other_id));
}
})
}
}
}
}
_ => {
panic!("This macro is only supported for Enums")
}
}
}
#[derive(Debug)]
struct ProtocolVariant {
attr: ProtocolAttribute,
ident: Ident,
}
#[derive(Debug)]
struct ProtocolAttribute {
state: syn::ExprPath,
packet_id: Lit,
}
impl Parse for ProtocolAttribute {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
let state = input.parse()?;
input.parse::<Token![,]>()?;
let packet_id = input.parse()?;
Ok(ProtocolAttribute { state, packet_id })
}
}