mirror of
https://github.com/Squareville/lu_packets.git
synced 2026-05-02 19:29:14 -05:00
Use a derive macro for service message serialization
This commit is contained in:
@@ -2,6 +2,7 @@ mod from_variants;
|
||||
mod game_message;
|
||||
mod gm_deserialize;
|
||||
mod service_message_d;
|
||||
mod service_message_s;
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
|
||||
@@ -21,6 +22,11 @@ pub fn derive_gm_deserialize(input: TokenStream) -> TokenStream {
|
||||
}
|
||||
|
||||
#[proc_macro_derive(ServiceMessageD)]
|
||||
pub fn derive_service_message(input: TokenStream) -> TokenStream {
|
||||
pub fn derive_service_message_d(input: TokenStream) -> TokenStream {
|
||||
service_message_d::derive(input)
|
||||
}
|
||||
|
||||
#[proc_macro_derive(ServiceMessageS)]
|
||||
pub fn derive_service_message_s(input: TokenStream) -> TokenStream {
|
||||
service_message_s::derive(input)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
use proc_macro2::{Ident, Span, TokenStream};
|
||||
use quote::quote;
|
||||
use syn::{parse_macro_input, parse_quote, Data, DataEnum, DeriveInput, Fields, Generics};
|
||||
|
||||
pub fn derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
let input = parse_macro_input!(input as DeriveInput);
|
||||
let data = match &input.data {
|
||||
Data::Enum(data) => data,
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
let name = &input.ident;
|
||||
|
||||
let ser_code = gen_ser_code_enum(data, &name, &input.generics);
|
||||
let ser_impl = &mut input.generics.clone();
|
||||
ser_impl.params.push(parse_quote!('__LIFETIME));
|
||||
ser_impl.params.push(parse_quote!(__WRITER: ::std::io::Write));
|
||||
let (ser_impl, _, _) = ser_impl.split_for_impl();
|
||||
|
||||
let (_, ty_generics, where_clause) = input.generics.split_for_impl();
|
||||
|
||||
(quote! {
|
||||
impl #ser_impl ::endio::Serialize<::endio::LE, __WRITER> for &'__LIFETIME #name #ty_generics #where_clause {
|
||||
fn serialize(self, writer: &mut __WRITER) -> ::std::io::Result<()> {
|
||||
#ser_code
|
||||
}
|
||||
}
|
||||
}).into()
|
||||
}
|
||||
|
||||
fn gen_ser_code_fields(fields: &Fields) -> TokenStream {
|
||||
match fields {
|
||||
Fields::Named(_) => unimplemented!(),
|
||||
Fields::Unnamed(fields) => {
|
||||
let mut index = String::from("a");
|
||||
let mut pat = vec![];
|
||||
let mut ser = vec![];
|
||||
for _ in &fields.unnamed {
|
||||
let ident = Ident::new(&index, Span::call_site());
|
||||
pat.push(quote! { #ident, });
|
||||
ser.push(quote! { ::endio::LEWrite::write(writer, #ident)?; });
|
||||
index += "a";
|
||||
}
|
||||
quote! { ( #(#pat)* ) => { #(#ser)* } }
|
||||
}
|
||||
Fields::Unit => {
|
||||
quote! { => {} }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn gen_ser_code_enum(data: &DataEnum, name: &Ident, generics: &Generics) -> TokenStream {
|
||||
let mut arms = vec![];
|
||||
for f in &data.variants {
|
||||
let ident = &f.ident;
|
||||
let ser_fields = gen_ser_code_fields(&f.fields);
|
||||
let expanded = quote! { #name::#ident #ser_fields };
|
||||
arms.push(expanded);
|
||||
}
|
||||
quote! {
|
||||
let disc = unsafe { *(self as *const #name #generics as *const u32) };
|
||||
::endio::LEWrite::write(writer, disc)?;
|
||||
::endio::LEWrite::write(writer, 0u8)?;
|
||||
match self {
|
||||
#(#arms)*
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
+2
-19
@@ -2,7 +2,7 @@ use std::io::Result as Res;
|
||||
|
||||
use endio::{LEWrite, Serialize};
|
||||
use endio::LittleEndian as LE;
|
||||
use lu_packets_derive::FromVariants;
|
||||
use lu_packets_derive::{FromVariants, ServiceMessageS};
|
||||
|
||||
use crate::common::{LuStr33, LuWStr33};
|
||||
|
||||
@@ -15,30 +15,13 @@ impl From<ClientMessage> for Message {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, FromVariants)]
|
||||
#[derive(Debug, FromVariants, ServiceMessageS)]
|
||||
#[non_exhaustive]
|
||||
#[repr(u32)]
|
||||
pub enum ClientMessage {
|
||||
LoginResponse(LoginResponse),
|
||||
}
|
||||
|
||||
impl<'a, W: LEWrite> Serialize<LE, W> for &'a ClientMessage
|
||||
where u8: Serialize<LE, W>,
|
||||
u32: Serialize<LE, W>,
|
||||
&'a LoginResponse: Serialize<LE, W> {
|
||||
fn serialize(self, writer: &mut W) -> Res<()> {
|
||||
let disc = unsafe { *(self as *const ClientMessage as *const u32) };
|
||||
writer.write(disc)?;
|
||||
writer.write(0u8)?;
|
||||
match self {
|
||||
ClientMessage::LoginResponse(message) => {
|
||||
writer.write(message)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[non_exhaustive]
|
||||
#[repr(u8)]
|
||||
|
||||
+2
-22
@@ -2,6 +2,7 @@ use std::io::Result as Res;
|
||||
|
||||
use endio::{LEWrite, Serialize};
|
||||
use endio::LittleEndian as LE;
|
||||
use lu_packets_derive::ServiceMessageS;
|
||||
|
||||
use crate::common::ServiceId;
|
||||
|
||||
@@ -26,7 +27,7 @@ impl<C> From<GeneralMessage> for Message<C> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, ServiceMessageS)]
|
||||
#[non_exhaustive]
|
||||
#[repr(u32)]
|
||||
pub enum GeneralMessage {
|
||||
@@ -46,27 +47,6 @@ impl<C> From<DisconnectNotify> for Message<C> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, W: LEWrite> Serialize<LE, W> for &'a GeneralMessage
|
||||
where u8: Serialize<LE, W>,
|
||||
u32: Serialize<LE, W>,
|
||||
&'a Handshake: Serialize<LE, W>,
|
||||
&'a DisconnectNotify: Serialize<LE, W> {
|
||||
fn serialize(self, writer: &mut W) -> Res<()> {
|
||||
let disc = unsafe { *(self as *const GeneralMessage as *const u32) };
|
||||
writer.write(disc)?;
|
||||
writer.write(0u8)?;
|
||||
match self {
|
||||
GeneralMessage::Handshake(msg) => {
|
||||
writer.write(msg)?;
|
||||
}
|
||||
GeneralMessage::DisconnectNotify(msg) => {
|
||||
writer.write(msg)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Handshake {
|
||||
pub network_version: u32,
|
||||
|
||||
+2
-27
@@ -2,7 +2,7 @@ use std::io::Result as Res;
|
||||
|
||||
use endio::{LEWrite, Serialize};
|
||||
use endio::LittleEndian as LE;
|
||||
use lu_packets_derive::FromVariants;
|
||||
use lu_packets_derive::{FromVariants, ServiceMessageS};
|
||||
|
||||
use crate::common::{ObjId, LuWStr33, ZoneId};
|
||||
|
||||
@@ -15,7 +15,7 @@ impl From<ClientMessage> for Message {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, FromVariants)]
|
||||
#[derive(Debug, FromVariants, ServiceMessageS)]
|
||||
#[non_exhaustive]
|
||||
#[repr(u32)]
|
||||
pub enum ClientMessage {
|
||||
@@ -24,31 +24,6 @@ pub enum ClientMessage {
|
||||
CharacterDeleteResponse(CharacterDeleteResponse) = 11,
|
||||
}
|
||||
|
||||
impl<'a, W: LEWrite> Serialize<LE, W> for &'a ClientMessage
|
||||
where u8: Serialize<LE, W>,
|
||||
u32: Serialize<LE, W>,
|
||||
&'a CharacterListResponse: Serialize<LE, W>,
|
||||
&'a CharacterCreateResponse: Serialize<LE, W>,
|
||||
&'a CharacterDeleteResponse: Serialize<LE, W> {
|
||||
fn serialize(self, writer: &mut W) -> Res<()> {
|
||||
let disc = unsafe { *(self as *const ClientMessage as *const u32) };
|
||||
writer.write(disc)?;
|
||||
writer.write(0u8)?;
|
||||
match self {
|
||||
ClientMessage::CharacterListResponse(msg) => {
|
||||
writer.write(msg)?;
|
||||
}
|
||||
ClientMessage::CharacterCreateResponse(msg) => {
|
||||
writer.write(msg)?;
|
||||
}
|
||||
ClientMessage::CharacterDeleteResponse(msg) => {
|
||||
writer.write(msg)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CharacterListResponse {
|
||||
pub selected_char: u8,
|
||||
|
||||
Reference in New Issue
Block a user