diff --git a/lu_packets_derive/src/replica_serde.rs b/lu_packets_derive/src/replica_serde.rs index a7b9f492..fff7faa4 100644 --- a/lu_packets_derive/src/replica_serde.rs +++ b/lu_packets_derive/src/replica_serde.rs @@ -1,6 +1,9 @@ use proc_macro2::{Ident, Span, TokenStream}; use quote::quote; -use syn::{parse_macro_input, parse_quote, Attribute, Data, DataEnum, DeriveInput, Field, Fields, Generics, Lit, LitInt, Meta, NestedMeta}; +use syn::{ + Attribute, Data, DataEnum, DeriveInput, Field, Fields, Lit, LitInt, Meta, NestedMeta, + parse_macro_input, parse_quote, +}; pub fn derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let input = parse_macro_input!(input as DeriveInput); @@ -10,14 +13,14 @@ pub fn derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream { match &input.data { Data::Struct(data) => { deser_code = gen_deser_code_struct(&data.fields); - ser_code = gen_ser_code_struct(&data.fields, &name); - }, + ser_code = gen_ser_code_struct(&data.fields, name); + } Data::Enum(data) => { let ty = get_enum_type(&input); let pre_disc_padding = get_pre_disc_padding(&input); let post_disc_padding = get_post_disc_padding(&input); - deser_code = gen_deser_code_enum(data, &name, &ty, &pre_disc_padding, &post_disc_padding); - ser_code = gen_ser_code_enum(data, &name, &ty, &pre_disc_padding, &post_disc_padding, &input.generics); + deser_code = gen_deser_code_enum(data, name, &ty, &pre_disc_padding, &post_disc_padding); + ser_code = gen_ser_code_enum(data, name, &ty, &pre_disc_padding, &post_disc_padding); } Data::Union(_) => unimplemented!(), } @@ -182,7 +185,7 @@ fn gen_ser_code_struct(fields: &Fields, name: &Ident) -> TokenStream { } } -fn gen_ser_code_enum(data: &DataEnum, name: &Ident, ty: &Ident, pre_disc_padding: &Option, post_disc_padding: &Option, generics: &Generics) -> TokenStream { +fn gen_ser_code_enum(data: &DataEnum, name: &Ident, ty: &Ident, pre_disc_padding: &Option, post_disc_padding: &Option) -> TokenStream { let mut arms = vec![]; for f in &data.variants { let ident = &f.ident; @@ -194,7 +197,7 @@ fn gen_ser_code_enum(data: &DataEnum, name: &Ident, ty: &Ident, pre_disc_padding let write_post_padding = gen_write_padding(post_disc_padding); quote! { #write_pre_padding - let disc = unsafe { *(self as *const #name #generics as *const #ty) }; + let disc = unsafe { *::std::ptr::from_ref(self).cast::<#ty>() }; ::endio::LEWrite::write(writer, disc)?; #write_post_padding match self { diff --git a/src/auth/client/mod.rs b/src/auth/client/mod.rs index 4de770c3..40443b54 100644 --- a/src/auth/client/mod.rs +++ b/src/auth/client/mod.rs @@ -1,14 +1,17 @@ //! Client-received auth messages. -use std::io::{Error, ErrorKind::InvalidData, Result as Res, Read}; +use std::{ + io::{Error, ErrorKind::InvalidData, Read, Result as Res}, + ptr, +}; -use endio::{LEWrite, LERead, Deserialize, Serialize}; -use endio::LittleEndian as LE; -use lu_packets_derive::MessageFromVariants; -use lu_packets_derive::VariantTests; +use endio::{Deserialize, LERead, LEWrite, LittleEndian as LE, Serialize}; +use lu_packets_derive::{MessageFromVariants, VariantTests}; -use crate::common::{LuString3, LuString33, LuString37, LuVarWString, LuWString33, ServiceId}; -use crate::general::client::{DisconnectNotify, Handshake, GeneralMessage}; -use crate::world::server::Language; +use crate::{ + common::{LuString3, LuString33, LuString37, LuVarWString, LuWString33, ServiceId}, + general::client::{DisconnectNotify, GeneralMessage, Handshake}, + world::server::Language, +}; /// All messages that can be received by a client from an auth server. pub type Message = crate::raknet::client::Message; @@ -128,7 +131,10 @@ where &'a LuVarWString: Serialize, { fn serialize(self, writer: &mut W) -> Res<()> { - let disc = unsafe { *(self as *const LoginResponse as *const u8) }; + // SAFETY: Because `LoginResponse` is marked `repr(u8)`, its layout is a `repr(C)` `union` + // between `repr(C)` structs, each of which has the `u8` discriminant as its first + // field, so we can read the discriminant without offsetting the pointer. + let disc = unsafe { *ptr::from_ref(self).cast::() }; writer.write(disc)?; match self { LoginResponse::Ok { events, version, session_key, redirect_address, chat_server_address, cdn_key, cdn_ticket, language, country_code, just_upgraded_from_ftp, is_ftp, time_remaining_in_ftp, stamps } => { diff --git a/src/world/client/mod.rs b/src/world/client/mod.rs index 81138021..61e6d6f1 100644 --- a/src/world/client/mod.rs +++ b/src/world/client/mod.rs @@ -1,17 +1,18 @@ //! Client-received world messages. -use std::io::{Error, ErrorKind::InvalidData, Read, Write}; -use std::io::Result as Res; +use std::{ + io::{Error, ErrorKind::InvalidData, Read, Result as Res, Write}, + ptr, +}; -use endio::{Deserialize, LERead, LEWrite, Serialize}; -use endio::LittleEndian as LE; +use endio::{Deserialize, LERead, LEWrite, LittleEndian as LE, Serialize}; use lu_packets_derive::{MessageFromVariants, VariantTests}; -use crate::chat::ChatChannel; -use crate::chat::client::ChatMessage; -use crate::common::{ObjId, LuString33, LuWString33, LuWString42, LVec, ServiceId}; -use crate::general::client::{DisconnectNotify, Handshake, GeneralMessage}; -use super::{Lot, lnv::LuNameValue, Vector3, ZoneId}; -use super::gm::client::SubjectGameMessage; +use super::{Lot, Vector3, ZoneId, gm::client::SubjectGameMessage, lnv::LuNameValue}; +use crate::{ + chat::{ChatChannel, client::ChatMessage}, + common::{LVec, LuString33, LuWString33, LuWString42, ObjId, ServiceId}, + general::client::{DisconnectNotify, GeneralMessage, Handshake}, +}; /// All messages that can be received by a client from a world server. pub type Message = crate::raknet::client::Message; @@ -378,9 +379,12 @@ impl Deserialize for AddFriendResponse { } } -impl<'a, W: Write> Serialize for &'a AddFriendResponse { +impl Serialize for &AddFriendResponse { fn serialize(self, writer: &mut W) -> Res<()> { - let disc = unsafe { *(&self.response_type as *const AddFriendResponseType as *const u8) }; + // SAFETY: Because `AddFriendResponseType` is marked `repr(u8)`, its layout is a `repr(C)` `union` + // between `repr(C)` structs, each of which has the `u8` discriminant as its first + // field, so we can read the discriminant without offsetting the pointer. + let disc = unsafe { *ptr::from_ref(self).cast::() }; LEWrite::write(writer, disc)?; let mut is_online_x = &false; let mut sender_id_x = &0;