Use a derive macro to generate message sending cast implementations

This commit is contained in:
lcdr
2020-06-10 20:02:57 +02:00
parent 82cdcf25c1
commit 993943ffe5
9 changed files with 164 additions and 95 deletions

1
.gitignore vendored
View File

@@ -1 +1,2 @@
target/*
lu_packets_derive/target*

10
Cargo.lock generated
View File

@@ -23,6 +23,16 @@ name = "lu_packets"
version = "0.1.0"
dependencies = [
"endio 0.2.0 (git+https://github.com/lcdr/endio?rev=cb5020f6749a301ae925592f9ad1920919894ddb)",
"lu_packets_derive 0.1.0",
]
[[package]]
name = "lu_packets_derive"
version = "0.1.0"
dependencies = [
"proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.30 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]

View File

@@ -8,3 +8,4 @@ repository = "https://github.com/lcdr/lu_packets/"
[dependencies]
endio = { git = "https://github.com/lcdr/endio", rev = "cb5020f6749a301ae925592f9ad1920919894ddb" }
lu_packets_derive = { path = "lu_packets_derive" }

45
lu_packets_derive/Cargo.lock generated Normal file
View File

@@ -0,0 +1,45 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "lu_packets_derive"
version = "0.1.0"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "proc-macro2"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "beae6331a816b1f65d04c45b078fd8e6c93e8071771f41b8163255bbd8d7c8fa"
dependencies = [
"unicode-xid",
]
[[package]]
name = "quote"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37"
dependencies = [
"proc-macro2",
]
[[package]]
name = "syn"
version = "1.0.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5304cfdf27365b7585c25d4af91b35016ed21ef88f17ced89c7093b43dba8b6"
dependencies = [
"proc-macro2",
"quote",
"unicode-xid",
]
[[package]]
name = "unicode-xid"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"

View File

@@ -0,0 +1,15 @@
[package]
name = "lu_packets_derive"
version = "0.1.0"
authors = ["lcdr"]
edition = "2018"
license = "AGPL-3.0-or-later"
repository = "https://github.com/lcdr/lu_packets/"
[lib]
proc-macro = true
[dependencies]
proc-macro2 = "1.0"
quote = "1.0"
syn = "1.0"

View File

@@ -0,0 +1,42 @@
use quote::quote;
use syn::{parse_macro_input, Data, DeriveInput, Fields};
#[proc_macro_derive(FromVariants)]
pub fn derive_deserialize(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let data = match &input.data {
Data::Enum(data) => data,
_ => panic!("only enums are supported"),
};
let name = &input.ident;
let mut impls = vec![];
for v in &data.variants {
let variant = &v.ident;
let fields = match &v.fields {
Fields::Named(_) => panic!("use a tuple or unit variant"),
Fields::Unit => { continue }
Fields::Unnamed(fields) => fields,
};
if fields.unnamed.len() != 1 {
panic!("use exactly one tuple argument");
}
let first = fields.unnamed.first().unwrap();
let variant_ty = &first.ty;
let impl_ = quote! {
impl ::std::convert::From<#variant_ty> for Message {
fn from(msg: #variant_ty) -> Self {
#name::#variant(msg).into()
}
}
};
impls.push(impl_);
}
(quote! {
#(#impls)*
}).into()
}

View File

@@ -2,50 +2,26 @@ use std::io::Result as Res;
use endio::{LEWrite, Serialize};
use endio::LittleEndian as LE;
use lu_packets_derive::FromVariants;
use crate::common::{LuStr33, LuWStr33, ServiceId};
use crate::general::client::{GeneralMessage, Handshake};
use crate::common::{LuStr33, LuWStr33};
pub type LuMessage = crate::general::client::LuMessage<ClientMessage>;
pub type Message = crate::raknet::client::Message<LuMessage>;
impl From<GeneralMessage> for Message {
fn from(msg: GeneralMessage) -> Self {
LuMessage::General(msg).into()
}
}
impl From<Handshake> for Message {
fn from(msg: Handshake) -> Self {
GeneralMessage::Handshake(msg).into()
}
}
#[derive(Debug, Serialize)]
#[repr(u16)]
pub enum LuMessage {
General(GeneralMessage) = ServiceId::General as u16,
Client(ClientMessage) = ServiceId::Client as u16,
}
impl From<LuMessage> for Message {
fn from(msg: LuMessage) -> Self {
Message::UserMessage(msg)
}
}
#[derive(Debug)]
#[non_exhaustive]
#[repr(u32)]
pub enum ClientMessage {
LoginResponse(LoginResponse),
}
impl From<ClientMessage> for Message {
fn from(msg: ClientMessage) -> Self {
LuMessage::Client(msg).into()
}
}
#[derive(Debug, FromVariants)]
#[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>,
@@ -75,12 +51,6 @@ pub enum LoginResponse {
InvalidUsernamePassword = 6,
}
impl From<LoginResponse> for Message {
fn from(msg: LoginResponse) -> Self {
ClientMessage::LoginResponse(msg).into()
}
}
impl<'a, W: LEWrite> Serialize<LE, W> for &'a LoginResponse
where u8: Serialize<LE, W>,
u16: Serialize<LE, W>,

View File

@@ -5,6 +5,27 @@ use endio::LittleEndian as LE;
use crate::common::ServiceId;
pub type Message<C> = crate::raknet::client::Message<LuMessage<C>>;
#[derive(Debug, Serialize)]
#[repr(u16)]
pub enum LuMessage<C> {
General(GeneralMessage) = ServiceId::General as u16,
Client(C) = ServiceId::Client as u16,
}
impl<C> From<LuMessage<C>> for Message<C> {
fn from(msg: LuMessage<C>) -> Self {
Message::UserMessage(msg)
}
}
impl<C> From<GeneralMessage> for Message<C> {
fn from(msg: GeneralMessage) -> Self {
LuMessage::General(msg).into()
}
}
#[derive(Debug)]
#[non_exhaustive]
#[repr(u32)]
@@ -13,6 +34,18 @@ pub enum GeneralMessage {
DisconnectNotify(DisconnectNotify),
}
impl<C> From<Handshake> for Message<C> {
fn from(msg: Handshake) -> Self {
GeneralMessage::Handshake(msg).into()
}
}
impl<C> From<DisconnectNotify> for Message<C> {
fn from(msg: DisconnectNotify) -> Self {
GeneralMessage::DisconnectNotify(msg).into()
}
}
impl<'a, W: LEWrite> Serialize<LE, W> for &'a GeneralMessage
where u8: Serialize<LE, W>,
u32: Serialize<LE, W>,

View File

@@ -2,44 +2,20 @@ use std::io::Result as Res;
use endio::{LEWrite, Serialize};
use endio::LittleEndian as LE;
use lu_packets_derive::FromVariants;
use crate::common::{ObjId, LuWStr33, ServiceId, ZoneId};
use crate::general::client::{DisconnectNotify, GeneralMessage, Handshake};
use crate::common::{ObjId, LuWStr33, ZoneId};
pub type LuMessage = crate::general::client::LuMessage<ClientMessage>;
pub type Message = crate::raknet::client::Message<LuMessage>;
impl From<GeneralMessage> for Message {
fn from(msg: GeneralMessage) -> Self {
LuMessage::General(msg).into()
impl From<ClientMessage> for Message {
fn from(msg: ClientMessage) -> Self {
LuMessage::Client(msg).into()
}
}
impl From<Handshake> for Message {
fn from(msg: Handshake) -> Self {
GeneralMessage::Handshake(msg).into()
}
}
impl From<DisconnectNotify> for Message {
fn from(msg: DisconnectNotify) -> Self {
GeneralMessage::DisconnectNotify(msg).into()
}
}
#[derive(Debug, Serialize)]
#[repr(u16)]
pub enum LuMessage {
General(GeneralMessage) = ServiceId::General as u16,
Client(ClientMessage) = ServiceId::Client as u16,
}
impl From<LuMessage> for Message {
fn from(msg: LuMessage) -> Self {
Message::UserMessage(msg)
}
}
#[derive(Debug)]
#[derive(Debug, FromVariants)]
#[non_exhaustive]
#[repr(u32)]
pub enum ClientMessage {
@@ -48,12 +24,6 @@ pub enum ClientMessage {
CharacterDeleteResponse(CharacterDeleteResponse) = 11,
}
impl From<ClientMessage> for Message {
fn from(msg: ClientMessage) -> Self {
LuMessage::Client(msg).into()
}
}
impl<'a, W: LEWrite> Serialize<LE, W> for &'a ClientMessage
where u8: Serialize<LE, W>,
u32: Serialize<LE, W>,
@@ -85,12 +55,6 @@ pub struct CharacterListResponse {
pub chars: Vec<CharListChar>,
}
impl From<CharacterListResponse> for Message {
fn from(msg: CharacterListResponse) -> Self {
ClientMessage::CharacterListResponse(msg).into()
}
}
impl<'a, W: LEWrite> Serialize<LE, W> for &'a CharacterListResponse
where u8: Serialize<LE, W>,
&'a CharListChar: Serialize<LE, W> {
@@ -170,19 +134,7 @@ pub enum CharacterCreateResponse {
CustomNameInUse,
}
impl From<CharacterCreateResponse> for Message {
fn from(msg: CharacterCreateResponse) -> Self {
ClientMessage::CharacterCreateResponse(msg).into()
}
}
#[derive(Debug, Serialize)]
pub struct CharacterDeleteResponse {
pub success: bool,
}
impl From<CharacterDeleteResponse> for Message {
fn from(msg: CharacterDeleteResponse) -> Self {
ClientMessage::CharacterDeleteResponse(msg).into()
}
}