|
|
@ -6,7 +6,8 @@ |
|
|
|
extern crate proc_macro;
|
|
|
|
|
|
|
|
use proc_macro::TokenStream;
|
|
|
|
use syn::{parse_macro_input, ItemStruct, NestedMeta};
|
|
|
|
use syn::{parse_macro_input, ItemStruct, NestedMeta, DeriveInput, Field};
|
|
|
|
use syn::punctuated::Iter;
|
|
|
|
use quote::quote;
|
|
|
|
|
|
|
|
#[derive(Debug, PartialEq)]
|
|
|
@ -45,7 +46,7 @@ fn generate_struct_def(name: syn::Ident, attrs: &Vec<AttrType>) -> proc_macro2:: |
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn generate_psopacket_impl(pkt_cmd: u16, name: syn::Ident, attrs: &Vec<AttrType>, include_flag: bool) -> proc_macro2::TokenStream {
|
|
|
|
fn generate_from_bytes(attrs: &Vec<AttrType>) -> Vec<proc_macro2::TokenStream> {
|
|
|
|
let mut from_bytes = Vec::new();
|
|
|
|
for attr in attrs {
|
|
|
|
let element = match attr {
|
|
|
@ -100,7 +101,10 @@ fn generate_psopacket_impl(pkt_cmd: u16, name: syn::Ident, attrs: &Vec<AttrType> |
|
|
|
};
|
|
|
|
from_bytes.push(element);
|
|
|
|
}
|
|
|
|
from_bytes
|
|
|
|
}
|
|
|
|
|
|
|
|
fn generate_as_bytes(attrs: &Vec<AttrType>) -> Vec<proc_macro2::TokenStream> {
|
|
|
|
let mut as_bytes = Vec::new();
|
|
|
|
for attr in attrs {
|
|
|
|
let element = match attr {
|
|
|
@ -130,6 +134,13 @@ fn generate_psopacket_impl(pkt_cmd: u16, name: syn::Ident, attrs: &Vec<AttrType> |
|
|
|
};
|
|
|
|
as_bytes.push(element);
|
|
|
|
}
|
|
|
|
as_bytes
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn generate_psopacket_impl(pkt_cmd: u16, name: syn::Ident, attrs: &Vec<AttrType>, include_flag: bool) -> proc_macro2::TokenStream {
|
|
|
|
let from_bytes = generate_from_bytes(&attrs);
|
|
|
|
let as_bytes = generate_as_bytes(&attrs);
|
|
|
|
|
|
|
|
quote! {
|
|
|
|
impl PSOPacket for #name {
|
|
|
@ -280,38 +291,14 @@ fn generate_partialeq_impl(name: syn::Ident, attrs: &Vec<AttrType>) -> proc_macr |
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
#[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;
|
|
|
|
for a in args {
|
|
|
|
match &a {
|
|
|
|
NestedMeta::Lit(lit) => {
|
|
|
|
if let syn::Lit::Int(litint) = lit {
|
|
|
|
cmd = litint.base10_parse().unwrap();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
NestedMeta::Meta(k) => {
|
|
|
|
if let syn::Meta::Path(syn::Path {segments, ..}) = k {
|
|
|
|
match segments[0].ident.to_string().as_str() {
|
|
|
|
"no_flag" => flag = false,
|
|
|
|
_ => {
|
|
|
|
return syn::Error::new(segments[0].ident.span(), "unknown macro param").to_compile_error().into();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn get_struct_fields(fields: Iter<Field>) -> Result<Vec<AttrType>, TokenStream> {
|
|
|
|
let mut attrs = Vec::new();
|
|
|
|
let pkt_struct = parse_macro_input!(item as ItemStruct);
|
|
|
|
|
|
|
|
let mut must_be_last = false;
|
|
|
|
for field in pkt_struct.fields.iter() {
|
|
|
|
for field in fields {
|
|
|
|
if must_be_last {
|
|
|
|
return syn::Error::new(field.ident.as_ref().unwrap().span(), "variables can not follow Vec or String").to_compile_error().into();
|
|
|
|
return Err(syn::Error::new(field.ident.as_ref().unwrap().span(), "variables can not follow Vec or String").to_compile_error().into());
|
|
|
|
}
|
|
|
|
let mut attr_meta = AttrMeta::None;
|
|
|
|
for attr in &field.attrs {
|
|
|
@ -346,6 +333,40 @@ pub fn pso_packet(attr: TokenStream, item: TokenStream) -> TokenStream { |
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(attrs)
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[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;
|
|
|
|
for a in args {
|
|
|
|
match &a {
|
|
|
|
NestedMeta::Lit(lit) => {
|
|
|
|
if let syn::Lit::Int(litint) = lit {
|
|
|
|
cmd = litint.base10_parse().unwrap();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
NestedMeta::Meta(k) => {
|
|
|
|
if let syn::Meta::Path(syn::Path {segments, ..}) = k {
|
|
|
|
match segments[0].ident.to_string().as_str() {
|
|
|
|
"no_flag" => flag = false,
|
|
|
|
_ => {
|
|
|
|
return syn::Error::new(segments[0].ident.span(), "unknown macro param").to_compile_error().into();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let pkt_struct = parse_macro_input!(item as ItemStruct);
|
|
|
|
let attrs = match get_struct_fields(pkt_struct.fields.iter()) {
|
|
|
|
Ok(a) => a,
|
|
|
|
Err(err) => return err
|
|
|
|
};
|
|
|
|
|
|
|
|
let struct_def = generate_struct_def(pkt_struct.ident.clone(), &attrs);
|
|
|
|
let psopacket_impl = generate_psopacket_impl(cmd, pkt_struct.ident.clone(), &attrs, flag);
|
|
|
@ -362,3 +383,44 @@ pub fn pso_packet(attr: TokenStream, item: TokenStream) -> TokenStream { |
|
|
|
|
|
|
|
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();
|
|
|
|
};
|
|
|
|
|
|
|
|
let attrs = match get_struct_fields(fields.iter()) {
|
|
|
|
Ok(a) => a,
|
|
|
|
Err(err) => return err
|
|
|
|
};
|
|
|
|
|
|
|
|
let from_bytes = generate_from_bytes(&attrs);
|
|
|
|
let as_bytes = generate_as_bytes(&attrs);
|
|
|
|
|
|
|
|
let impl_pso_data_packet = quote! {
|
|
|
|
impl PSOPacketData for #name {
|
|
|
|
fn from_bytes<R: Read>(mut cur: &mut R) -> Result<Self, PacketParseError> {
|
|
|
|
Ok(#name {
|
|
|
|
#(#from_bytes)*
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
fn as_bytes(&self) -> Vec<u8> {
|
|
|
|
let mut buf = Vec::new();
|
|
|
|
#(#as_bytes)*
|
|
|
|
buf
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
impl_pso_data_packet.into()
|
|
|
|
}
|