mirror of
https://github.com/lcdr/lu_packets.git
synced 2026-01-07 08:59:29 -06:00
Generalize derive macro for arbitrary padding
This commit is contained in:
@@ -5,6 +5,7 @@ mod service_message_d;
|
||||
mod service_message_s;
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
use syn::{DeriveInput, Lit, LitInt, Meta};
|
||||
|
||||
#[proc_macro_derive(FromVariants)]
|
||||
pub fn derive_from_variants(input: TokenStream) -> TokenStream {
|
||||
@@ -21,12 +22,34 @@ pub fn derive_gm_type(input: TokenStream) -> TokenStream {
|
||||
gm_type::derive(input)
|
||||
}
|
||||
|
||||
#[proc_macro_derive(ServiceMessageD)]
|
||||
#[proc_macro_derive(ServiceMessageD, attributes(disc_padding))]
|
||||
pub fn derive_service_message_d(input: TokenStream) -> TokenStream {
|
||||
service_message_d::derive(input)
|
||||
}
|
||||
|
||||
#[proc_macro_derive(ServiceMessageS)]
|
||||
#[proc_macro_derive(ServiceMessageS, attributes(disc_padding))]
|
||||
pub fn derive_service_message_s(input: TokenStream) -> TokenStream {
|
||||
service_message_s::derive(input)
|
||||
}
|
||||
|
||||
fn get_disc_padding(input: &DeriveInput) -> Option<LitInt> {
|
||||
for attr in &input.attrs {
|
||||
if !attr.path.is_ident("disc_padding") {
|
||||
continue;
|
||||
}
|
||||
let meta = match attr.parse_meta() {
|
||||
Err(_) => panic!("encountered unparseable disc_padding attribute"),
|
||||
Ok(x) => x,
|
||||
};
|
||||
let lit = match meta {
|
||||
Meta::NameValue(x) => x.lit,
|
||||
_ => panic!("disc_padding needs to be name=value"),
|
||||
};
|
||||
let int_lit = match lit {
|
||||
Lit::Int(x) => x,
|
||||
_ => panic!("disc_padding needs to be an integer"),
|
||||
};
|
||||
return Some(int_lit);
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
use proc_macro2::{Ident, TokenStream};
|
||||
use quote::quote;
|
||||
use syn::{parse_macro_input, parse_quote, Data, DataEnum, DeriveInput, Fields};
|
||||
use syn::{parse_macro_input, parse_quote, Data, DataEnum, DeriveInput, Fields, LitInt};
|
||||
|
||||
use crate::get_disc_padding;
|
||||
|
||||
pub fn derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
let input = parse_macro_input!(input as DeriveInput);
|
||||
@@ -10,7 +12,8 @@ pub fn derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
};
|
||||
let name = &input.ident;
|
||||
|
||||
let deser_code = gen_deser_code_enum(data, &name);
|
||||
let disc_padding = get_disc_padding(&input);
|
||||
let deser_code = gen_deser_code_enum(data, &name, disc_padding);
|
||||
let deser_impl = &mut input.generics.clone();
|
||||
deser_impl.params.push(parse_quote!(__READER: ::std::io::Read));
|
||||
let (deser_impl, _, _) = deser_impl.split_for_impl();
|
||||
@@ -42,7 +45,7 @@ fn gen_deser_code_fields(fields: &Fields) -> TokenStream {
|
||||
}
|
||||
}
|
||||
|
||||
fn gen_deser_code_enum(data: &DataEnum, name: &Ident) -> TokenStream {
|
||||
fn gen_deser_code_enum(data: &DataEnum, name: &Ident, padding: Option<LitInt>) -> TokenStream {
|
||||
let last_disc: syn::ExprLit = parse_quote! { 0 };
|
||||
let mut last_disc = &last_disc.into();
|
||||
let mut disc_offset = 0;
|
||||
@@ -58,9 +61,16 @@ fn gen_deser_code_enum(data: &DataEnum, name: &Ident) -> TokenStream {
|
||||
disc_offset += 1;
|
||||
arms.push(arm);
|
||||
}
|
||||
let read_padding = match padding {
|
||||
Some(x) => quote! {
|
||||
let mut padding = [0; #x];
|
||||
::std::io::Read::read_exact(reader, &mut padding)?;
|
||||
},
|
||||
None => quote! { },
|
||||
};
|
||||
quote! {
|
||||
let disc: u32 = ::endio::LERead::read(reader)?;
|
||||
let _padding: u8 = ::endio::LERead::read(reader)?;
|
||||
#read_padding
|
||||
Ok(match disc {
|
||||
#(#arms)*
|
||||
_ => return ::std::result::Result::Err(::std::io::Error::new(::std::io::ErrorKind::InvalidData, format!("invalid discriminant value for {}: {}", stringify!(#name), disc)))
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
use proc_macro2::{Ident, Span, TokenStream};
|
||||
use quote::quote;
|
||||
use syn::{parse_macro_input, parse_quote, Data, DataEnum, DeriveInput, Fields, Generics};
|
||||
use syn::{parse_macro_input, parse_quote, Data, DataEnum, DeriveInput, Fields, LitInt, Generics};
|
||||
|
||||
use crate::get_disc_padding;
|
||||
|
||||
pub fn derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
let input = parse_macro_input!(input as DeriveInput);
|
||||
@@ -10,7 +12,8 @@ pub fn derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
};
|
||||
let name = &input.ident;
|
||||
|
||||
let ser_code = gen_ser_code_enum(data, &name, &input.generics);
|
||||
let disc_padding = get_disc_padding(&input);
|
||||
let ser_code = gen_ser_code_enum(data, &name, disc_padding, &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));
|
||||
@@ -48,7 +51,7 @@ fn gen_ser_code_fields(fields: &Fields) -> TokenStream {
|
||||
}
|
||||
}
|
||||
|
||||
fn gen_ser_code_enum(data: &DataEnum, name: &Ident, generics: &Generics) -> TokenStream {
|
||||
fn gen_ser_code_enum(data: &DataEnum, name: &Ident, padding: Option<LitInt>, generics: &Generics) -> TokenStream {
|
||||
let mut arms = vec![];
|
||||
for f in &data.variants {
|
||||
let ident = &f.ident;
|
||||
@@ -56,10 +59,17 @@ fn gen_ser_code_enum(data: &DataEnum, name: &Ident, generics: &Generics) -> Toke
|
||||
let expanded = quote! { #name::#ident #ser_fields };
|
||||
arms.push(expanded);
|
||||
}
|
||||
let write_padding = match padding {
|
||||
Some(x) => quote! {
|
||||
let mut padding = [0; #x];
|
||||
::std::io::Write::write_all(writer, &padding)?;
|
||||
},
|
||||
None => quote! { },
|
||||
};
|
||||
quote! {
|
||||
let disc = unsafe { *(self as *const #name #generics as *const u32) };
|
||||
::endio::LEWrite::write(writer, disc)?;
|
||||
::endio::LEWrite::write(writer, 0u8)?;
|
||||
#write_padding
|
||||
match self {
|
||||
#(#arms)*
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ impl From<ClientMessage> for Message {
|
||||
}
|
||||
|
||||
#[derive(Debug, FromVariants, ServiceMessageS)]
|
||||
#[non_exhaustive]
|
||||
#[disc_padding=1]
|
||||
#[repr(u32)]
|
||||
pub enum ClientMessage {
|
||||
LoginResponse(LoginResponse),
|
||||
|
||||
@@ -16,6 +16,7 @@ pub enum LuMessage {
|
||||
}
|
||||
|
||||
#[derive(Debug, ServiceMessageD)]
|
||||
#[disc_padding=1]
|
||||
#[repr(u32)]
|
||||
pub enum AuthMessage {
|
||||
LoginRequest(LoginRequest)
|
||||
|
||||
@@ -3,77 +3,24 @@ use std::io::Result as Res;
|
||||
|
||||
use endio::{Deserialize, LERead};
|
||||
use endio::LittleEndian as LE;
|
||||
use lu_packets_derive::ServiceMessageD;
|
||||
|
||||
use crate::common::{err, LuWStr33, ObjId};
|
||||
use crate::common::{LuWStr33, ObjId};
|
||||
|
||||
enum ChatId {
|
||||
GeneralChatMessage = 1,
|
||||
PrivateChatMessage = 2,
|
||||
AddFriendResponse = 8,
|
||||
#[derive(Debug, ServiceMessageD)]
|
||||
#[disc_padding=9]
|
||||
#[repr(u32)]
|
||||
pub enum ChatMessage {
|
||||
GeneralChatMessage(GeneralChatMessage) = 1,
|
||||
PrivateChatMessage(PrivateChatMessage) = 2,
|
||||
AddFriendResponse(AddFriendResponse) = 8,
|
||||
GetFriendsList = 10,
|
||||
GetIgnoreList = 13,
|
||||
TeamInviteResponse = 16,
|
||||
TeamLeave = 18,
|
||||
TeamInviteResponse(TeamInviteResponse) = 16,
|
||||
TeamLeave(TeamLeave) = 18,
|
||||
TeamGetStatus = 21,
|
||||
RequestMinimumChatMode = 50,
|
||||
RequestMinimumChatModePrivate = 51,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ChatMessage {
|
||||
GeneralChatMessage(GeneralChatMessage),
|
||||
PrivateChatMessage(PrivateChatMessage),
|
||||
AddFriendResponse(AddFriendResponse),
|
||||
GetFriendsList,
|
||||
GetIgnoreList,
|
||||
TeamInviteResponse(TeamInviteResponse),
|
||||
TeamLeave,
|
||||
TeamGetStatus,
|
||||
RequestMinimumChatMode(RequestMinimumChatMode),
|
||||
RequestMinimumChatModePrivate(RequestMinimumChatModePrivate),
|
||||
}
|
||||
|
||||
impl<R: Read+LERead> Deserialize<LE, R> for ChatMessage
|
||||
where u8: Deserialize<LE, R>,
|
||||
u32: Deserialize<LE, R>,
|
||||
u64: Deserialize<LE, R>,
|
||||
GeneralChatMessage: Deserialize<LE, R>,
|
||||
PrivateChatMessage: Deserialize<LE, R>,
|
||||
AddFriendResponse: Deserialize<LE, R>,
|
||||
TeamInviteResponse: Deserialize<LE, R>,
|
||||
RequestMinimumChatMode: Deserialize<LE, R>,
|
||||
RequestMinimumChatModePrivate: Deserialize<LE, R> {
|
||||
fn deserialize(reader: &mut R) -> Res<Self> {
|
||||
let packet_id: u32 = LERead::read(reader)?;
|
||||
let _padding: u8 = LERead::read(reader)?;
|
||||
let routed_obj_id: u64 = LERead::read(reader)?;
|
||||
assert_eq!(routed_obj_id, 0);
|
||||
Ok(if packet_id == ChatId::GeneralChatMessage as u32 {
|
||||
Self::GeneralChatMessage(LERead::read(reader)?)
|
||||
} else if packet_id == ChatId::PrivateChatMessage as u32 {
|
||||
Self::PrivateChatMessage(LERead::read(reader)?)
|
||||
} else if packet_id == ChatId::AddFriendResponse as u32 {
|
||||
Self::AddFriendResponse(LERead::read(reader)?)
|
||||
} else if packet_id == ChatId::GetFriendsList as u32 {
|
||||
Self::GetFriendsList
|
||||
} else if packet_id == ChatId::GetIgnoreList as u32 {
|
||||
Self::GetIgnoreList
|
||||
} else if packet_id == ChatId::TeamGetStatus as u32 {
|
||||
Self::TeamGetStatus
|
||||
} else if packet_id == ChatId::TeamInviteResponse as u32 {
|
||||
Self::TeamInviteResponse(LERead::read(reader)?)
|
||||
} else if packet_id == ChatId::TeamLeave as u32 {
|
||||
let mut unused = [0; 66];
|
||||
Read::read(reader, &mut unused)?;
|
||||
Self::TeamLeave
|
||||
} else if packet_id == ChatId::RequestMinimumChatMode as u32 {
|
||||
Self::RequestMinimumChatMode(LERead::read(reader)?)
|
||||
} else if packet_id == ChatId::RequestMinimumChatModePrivate as u32 {
|
||||
Self::RequestMinimumChatModePrivate(LERead::read(reader)?)
|
||||
} else {
|
||||
return err("chat id", packet_id);
|
||||
})
|
||||
}
|
||||
RequestMinimumChatMode(RequestMinimumChatMode) = 50,
|
||||
RequestMinimumChatModePrivate(RequestMinimumChatModePrivate) = 51,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -189,6 +136,11 @@ pub struct TeamInviteResponse {
|
||||
pub sender: ObjId,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct TeamLeave {
|
||||
pub unused: LuWStr33,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct RequestMinimumChatMode {
|
||||
pub chat_channel: u8, // todo: separate type?
|
||||
|
||||
@@ -28,7 +28,7 @@ impl<C> From<GeneralMessage> for Message<C> {
|
||||
}
|
||||
|
||||
#[derive(Debug, ServiceMessageS)]
|
||||
#[non_exhaustive]
|
||||
#[disc_padding=1]
|
||||
#[repr(u32)]
|
||||
pub enum GeneralMessage {
|
||||
Handshake(Handshake),
|
||||
|
||||
@@ -7,6 +7,7 @@ use lu_packets_derive::ServiceMessageD;
|
||||
use crate::common::ServiceId;
|
||||
|
||||
#[derive(Debug, ServiceMessageD)]
|
||||
#[disc_padding=1]
|
||||
#[repr(u32)]
|
||||
pub enum GeneralMessage {
|
||||
Handshake(Handshake)
|
||||
|
||||
@@ -18,6 +18,7 @@ impl From<ClientMessage> for Message {
|
||||
|
||||
#[derive(Debug, FromVariants, ServiceMessageS)]
|
||||
#[non_exhaustive]
|
||||
#[disc_padding=1]
|
||||
#[repr(u32)]
|
||||
pub enum ClientMessage {
|
||||
CharacterListResponse(CharacterListResponse) = 6,
|
||||
|
||||
@@ -26,6 +26,7 @@ pub enum LuMessage {
|
||||
}
|
||||
|
||||
#[derive(Debug, ServiceMessageD)]
|
||||
#[disc_padding=1]
|
||||
#[repr(u32)]
|
||||
pub enum WorldMessage {
|
||||
ClientValidation(ClientValidation) = 1,
|
||||
|
||||
Reference in New Issue
Block a user