|
@ -6,8 +6,10 @@ |
|
|
extern crate proc_macro;
|
|
|
extern crate proc_macro;
|
|
|
|
|
|
|
|
|
use proc_macro::TokenStream;
|
|
|
use proc_macro::TokenStream;
|
|
|
use syn::{parse_macro_input, ItemStruct, NestedMeta, DeriveInput, Field};
|
|
|
|
|
|
|
|
|
use syn::{parse_macro_input, ItemStruct, DeriveInput, Field};
|
|
|
use syn::punctuated::Iter;
|
|
|
use syn::punctuated::Iter;
|
|
|
|
|
|
use syn::punctuated::Punctuated;
|
|
|
|
|
|
use syn::parse::Parse;
|
|
|
use quote::quote;
|
|
|
use quote::quote;
|
|
|
|
|
|
|
|
|
#[derive(Debug, PartialEq)]
|
|
|
#[derive(Debug, PartialEq)]
|
|
@ -308,7 +310,7 @@ fn get_struct_fields(fields: Iter<Field>) -> Result<Vec<AttrType>, TokenStream> |
|
|
}
|
|
|
}
|
|
|
let mut attr_meta = AttrMeta::None;
|
|
|
let mut attr_meta = AttrMeta::None;
|
|
|
for attr in &field.attrs {
|
|
|
for attr in &field.attrs {
|
|
|
attr_meta = match attr.path.segments[0].ident.to_string().as_str() {
|
|
|
|
|
|
|
|
|
attr_meta = match attr.path().segments[0].ident.to_string().as_str() {
|
|
|
"utf8" => AttrMeta::Utf8,
|
|
|
"utf8" => AttrMeta::Utf8,
|
|
|
"utf16" => AttrMeta::Utf16,
|
|
|
"utf16" => AttrMeta::Utf16,
|
|
|
"nodebug" => AttrMeta::NoDebug,
|
|
|
"nodebug" => AttrMeta::NoDebug,
|
|
@ -345,35 +347,52 @@ fn get_struct_fields(fields: Iter<Field>) -> Result<Vec<AttrType>, TokenStream> |
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[proc_macro_attribute]
|
|
|
|
|
|
pub fn pso_packet(attr: TokenStream, item: TokenStream) -> TokenStream {
|
|
|
|
|
|
let args = parse_macro_input!(attr as syn::AttributeArgs);
|
|
|
|
|
|
let mut cmd = 0;
|
|
|
|
|
|
let mut flag = true;
|
|
|
|
|
|
let mut manual_flag = false;
|
|
|
|
|
|
for a in args {
|
|
|
|
|
|
match &a {
|
|
|
|
|
|
NestedMeta::Lit(lit) => {
|
|
|
|
|
|
if let syn::Lit::Int(litint) = lit {
|
|
|
|
|
|
cmd = litint.base10_parse().unwrap();
|
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
|
|
struct PSOPacketAttrs {
|
|
|
|
|
|
cmd: u16,
|
|
|
|
|
|
flag: bool,
|
|
|
|
|
|
manual_flag: bool,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl Parse for PSOPacketAttrs {
|
|
|
|
|
|
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
|
|
|
|
|
|
let vars = Punctuated::<syn::Expr, syn::Token![,]>::parse_terminated(input)?;
|
|
|
|
|
|
|
|
|
|
|
|
let (cmd, flag, manual_flag) = vars
|
|
|
|
|
|
.into_iter()
|
|
|
|
|
|
.fold((None, true, false), |mut acc, attr| {
|
|
|
|
|
|
match attr {
|
|
|
|
|
|
syn::Expr::Lit(lit) => {
|
|
|
|
|
|
if let syn::Lit::Int(int) = lit.lit {
|
|
|
|
|
|
acc.0 = int.base10_parse().ok();
|
|
|
}
|
|
|
}
|
|
|
},
|
|
|
},
|
|
|
NestedMeta::Meta(k) => {
|
|
|
|
|
|
if let syn::Meta::Path(syn::Path {segments, ..}) = k {
|
|
|
|
|
|
match segments[0].ident.to_string().as_str() {
|
|
|
|
|
|
"no_flag" => flag = false,
|
|
|
|
|
|
"manual_flag" => {
|
|
|
|
|
|
flag = false;
|
|
|
|
|
|
manual_flag = true;
|
|
|
|
|
|
},
|
|
|
|
|
|
_ => {
|
|
|
|
|
|
return syn::Error::new(segments[0].ident.span(), "unknown macro param").to_compile_error().into();
|
|
|
|
|
|
|
|
|
syn::Expr::Path(path) => {
|
|
|
|
|
|
if path.path.is_ident("no_flag") {
|
|
|
|
|
|
acc.1 = false;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if path.path.is_ident("manual_flag") {
|
|
|
|
|
|
acc.1 = false;
|
|
|
|
|
|
acc.2 = true;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
},
|
|
|
|
|
|
|
|
|
_ => {},
|
|
|
}
|
|
|
}
|
|
|
|
|
|
acc
|
|
|
|
|
|
});
|
|
|
|
|
|
Ok(PSOPacketAttrs {
|
|
|
|
|
|
cmd: cmd.unwrap(),
|
|
|
|
|
|
flag,
|
|
|
|
|
|
manual_flag
|
|
|
|
|
|
})
|
|
|
}
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[proc_macro_attribute]
|
|
|
|
|
|
pub fn pso_packet(attr: TokenStream, item: TokenStream) -> TokenStream {
|
|
|
|
|
|
let args = parse_macro_input!(attr as PSOPacketAttrs);
|
|
|
|
|
|
|
|
|
let pkt_struct = parse_macro_input!(item as ItemStruct);
|
|
|
let pkt_struct = parse_macro_input!(item as ItemStruct);
|
|
|
let attrs = match get_struct_fields(pkt_struct.fields.iter()) {
|
|
|
let attrs = match get_struct_fields(pkt_struct.fields.iter()) {
|
|
@ -381,7 +400,7 @@ pub fn pso_packet(attr: TokenStream, item: TokenStream) -> TokenStream { |
|
|
Err(err) => return err
|
|
|
Err(err) => return err
|
|
|
};
|
|
|
};
|
|
|
|
|
|
|
|
|
if manual_flag {
|
|
|
|
|
|
|
|
|
if args.manual_flag {
|
|
|
match &attrs[0] {
|
|
|
match &attrs[0] {
|
|
|
AttrType::Array(_, ident, _, _) => {
|
|
|
AttrType::Array(_, ident, _, _) => {
|
|
|
if ident.to_string() != "flag" {
|
|
|
if ident.to_string() != "flag" {
|
|
@ -397,7 +416,7 @@ pub fn pso_packet(attr: TokenStream, item: TokenStream) -> TokenStream { |
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
let struct_def = generate_struct_def(pkt_struct.ident.clone(), &attrs);
|
|
|
let struct_def = generate_struct_def(pkt_struct.ident.clone(), &attrs);
|
|
|
let psopacket_impl = generate_psopacket_impl(cmd, pkt_struct.ident.clone(), &attrs, flag);
|
|
|
|
|
|
|
|
|
let psopacket_impl = generate_psopacket_impl(args.cmd, pkt_struct.ident.clone(), &attrs, args.flag);
|
|
|
let debug_impl = generate_debug_impl(pkt_struct.ident.clone(), &attrs);
|
|
|
let debug_impl = generate_debug_impl(pkt_struct.ident.clone(), &attrs);
|
|
|
let partialeq_impl = generate_partialeq_impl(pkt_struct.ident.clone(), &attrs);
|
|
|
let partialeq_impl = generate_partialeq_impl(pkt_struct.ident.clone(), &attrs);
|
|
|
|
|
|
|
|
@ -588,18 +607,10 @@ fn generate_psomessage_impl(msg_cmd: u8, name: syn::Ident, attrs: &Vec<AttrType> |
|
|
|
|
|
|
|
|
#[proc_macro_attribute]
|
|
|
#[proc_macro_attribute]
|
|
|
pub fn pso_message(attr: TokenStream, item: TokenStream) -> TokenStream {
|
|
|
pub fn pso_message(attr: TokenStream, item: TokenStream) -> TokenStream {
|
|
|
let args = parse_macro_input!(attr as syn::AttributeArgs);
|
|
|
|
|
|
let mut cmd = 0;
|
|
|
|
|
|
for a in args {
|
|
|
|
|
|
if let NestedMeta::Lit(lit) = a {
|
|
|
|
|
|
if let syn::Lit::Int(litint) = lit {
|
|
|
|
|
|
cmd = litint.base10_parse().unwrap();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let cmd = parse_macro_input!(attr as syn::LitInt).base10_parse().unwrap();
|
|
|
let pkt_struct = parse_macro_input!(item as ItemStruct);
|
|
|
let pkt_struct = parse_macro_input!(item as ItemStruct);
|
|
|
let mut attrs = match get_struct_fields(pkt_struct.fields.iter()) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let mut fields = match get_struct_fields(pkt_struct.fields.iter()) {
|
|
|
Ok(a) => a,
|
|
|
Ok(a) => a,
|
|
|
Err(err) => return err
|
|
|
Err(err) => return err
|
|
|
};
|
|
|
};
|
|
@ -617,13 +628,13 @@ pub fn pso_message(attr: TokenStream, item: TokenStream) -> TokenStream { |
|
|
segments: punctuated
|
|
|
segments: punctuated
|
|
|
}
|
|
|
}
|
|
|
};
|
|
|
};
|
|
|
attrs.insert(0, AttrType::Value(u8tpath.clone(), syn::Ident::new("target", proc_macro2::Span::call_site()), AttrMeta::None));
|
|
|
|
|
|
attrs.insert(0, AttrType::Value(u8tpath, syn::Ident::new("client", proc_macro2::Span::call_site()), AttrMeta::None));
|
|
|
|
|
|
|
|
|
fields.insert(0, AttrType::Value(u8tpath.clone(), syn::Ident::new("target", proc_macro2::Span::call_site()), AttrMeta::None));
|
|
|
|
|
|
fields.insert(0, AttrType::Value(u8tpath, syn::Ident::new("client", proc_macro2::Span::call_site()), AttrMeta::None));
|
|
|
|
|
|
|
|
|
let struct_def = generate_struct_def(pkt_struct.ident.clone(), &attrs);
|
|
|
|
|
|
let psopacket_impl = generate_psomessage_impl(cmd, pkt_struct.ident.clone(), &attrs);
|
|
|
|
|
|
let debug_impl = generate_debug_impl(pkt_struct.ident.clone(), &attrs);
|
|
|
|
|
|
let partialeq_impl = generate_partialeq_impl(pkt_struct.ident.clone(), &attrs);
|
|
|
|
|
|
|
|
|
let struct_def = generate_struct_def(pkt_struct.ident.clone(), &fields);
|
|
|
|
|
|
let psopacket_impl = generate_psomessage_impl(cmd, pkt_struct.ident.clone(), &fields);
|
|
|
|
|
|
let debug_impl = generate_debug_impl(pkt_struct.ident.clone(), &fields);
|
|
|
|
|
|
let partialeq_impl = generate_partialeq_impl(pkt_struct.ident.clone(), &fields);
|
|
|
|
|
|
|
|
|
let q = quote!{
|
|
|
let q = quote!{
|
|
|
#[derive(Clone)]
|
|
|
#[derive(Clone)]
|
|
@ -636,19 +647,7 @@ pub fn pso_message(attr: TokenStream, item: TokenStream) -> TokenStream { |
|
|
q.into()
|
|
|
q.into()
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
#[proc_macro_derive(PSOPacketData)]
|
|
|
|
|
|
pub fn pso_packet_data(input: TokenStream) -> TokenStream {
|
|
|
|
|
|
let derive = parse_macro_input!(input as DeriveInput);
|
|
|
|
|
|
|
|
|
|
|
|
let name = derive.ident;
|
|
|
|
|
|
|
|
|
|
|
|
let fields = if let syn::Data::Struct(strct) = derive.data {
|
|
|
|
|
|
strct.fields
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
|
|
|
|
|
return syn::Error::new(name.span(), "PSOPacketData only works on structs").to_compile_error().into();
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn pso_packet_data_struct(name: syn::Ident, fields: syn::Fields) -> TokenStream {
|
|
|
let attrs = match get_struct_fields(fields.iter()) {
|
|
|
let attrs = match get_struct_fields(fields.iter()) {
|
|
|
Ok(a) => a,
|
|
|
Ok(a) => a,
|
|
|
Err(err) => return err
|
|
|
Err(err) => return err
|
|
@ -684,3 +683,75 @@ pub fn pso_packet_data(input: TokenStream) -> TokenStream { |
|
|
|
|
|
|
|
|
q.into()
|
|
|
q.into()
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn pso_packet_data_enum<'a>(name: syn::Ident, repr_type: syn::Ident, variants: impl Iterator<Item = &'a syn::Variant> + Clone) -> TokenStream {
|
|
|
|
|
|
let value_to_variant = variants
|
|
|
|
|
|
.clone()
|
|
|
|
|
|
.enumerate()
|
|
|
|
|
|
.map(|(i, variant)| {
|
|
|
|
|
|
let variant = &variant.ident;
|
|
|
|
|
|
quote! {
|
|
|
|
|
|
#i => #name::#variant,
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
.collect::<Vec<_>>();
|
|
|
|
|
|
|
|
|
|
|
|
let variant_to_value = variants
|
|
|
|
|
|
.enumerate()
|
|
|
|
|
|
.map(|(i, variant)| {
|
|
|
|
|
|
let variant = &variant.ident;
|
|
|
|
|
|
quote! {
|
|
|
|
|
|
#name::#variant => #repr_type::to_le_bytes(#i as #repr_type).to_vec(),
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
.collect::<Vec<_>>();
|
|
|
|
|
|
let impl_pso_data_packet = quote! {
|
|
|
|
|
|
impl PSOPacketData for #name {
|
|
|
|
|
|
fn from_bytes<R: std::io::Read + std::io::Seek>(mut cur: &mut R) -> Result<Self, PacketParseError> {
|
|
|
|
|
|
let mut buf = #repr_type::default().to_le_bytes();
|
|
|
|
|
|
cur.read_exact(&mut buf).unwrap();
|
|
|
|
|
|
let value = #repr_type::from_le_bytes(buf);
|
|
|
|
|
|
|
|
|
|
|
|
Ok(match value as usize {
|
|
|
|
|
|
#(#value_to_variant)*
|
|
|
|
|
|
_ => return Err(PacketParseError::InvalidValue)
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn as_bytes(&self) -> Vec<#repr_type> {
|
|
|
|
|
|
match self {
|
|
|
|
|
|
#(#variant_to_value)*
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
impl_pso_data_packet.into()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[proc_macro_derive(PSOPacketData)]
|
|
|
|
|
|
pub fn pso_packet_data(input: TokenStream) -> TokenStream {
|
|
|
|
|
|
let derive = parse_macro_input!(input as DeriveInput);
|
|
|
|
|
|
|
|
|
|
|
|
let name = derive.ident;
|
|
|
|
|
|
|
|
|
|
|
|
if let syn::Data::Struct(strct) = derive.data {
|
|
|
|
|
|
pso_packet_data_struct(name, strct.fields)
|
|
|
|
|
|
}
|
|
|
|
|
|
else if let syn::Data::Enum(enm) = derive.data {
|
|
|
|
|
|
let repr_type = derive.attrs.iter().fold(None, |mut repr_type, attr| {
|
|
|
|
|
|
if attr.path().is_ident("repr") {
|
|
|
|
|
|
attr.parse_nested_meta(|meta| {
|
|
|
|
|
|
repr_type = Some(meta.path.get_ident().cloned().unwrap());
|
|
|
|
|
|
Ok(())
|
|
|
|
|
|
}).unwrap();
|
|
|
|
|
|
}
|
|
|
|
|
|
repr_type
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
pso_packet_data_enum(name, repr_type.unwrap(), enm.variants.iter())
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
|
|
|
|
|
syn::Error::new(name.span(), "PSOPacketData only works on structs and enums").to_compile_error().into()
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|