derive PSOPacketData macro
This commit is contained in:
		
							parent
							
								
									60584e0957
								
							
						
					
					
						commit
						94af546d7a
					
				| @ -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() | ||||
| } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user