length_is/length_of
This commit is contained in:
		
							parent
							
								
									cccb8b1439
								
							
						
					
					
						commit
						d0f1de9b0c
					
				@ -16,6 +16,8 @@ enum AttrMeta {
 | 
				
			|||||||
    Utf8,
 | 
					    Utf8,
 | 
				
			||||||
    Utf16,
 | 
					    Utf16,
 | 
				
			||||||
    NoDebug,
 | 
					    NoDebug,
 | 
				
			||||||
 | 
					    LengthIs(syn::Ident),
 | 
				
			||||||
 | 
					    LengthOf(syn::Ident),
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug)]
 | 
					#[derive(Debug)]
 | 
				
			||||||
@ -237,9 +239,9 @@ fn generate_debug_impl(name: syn::Ident, attrs: &Vec<AttrType>) -> proc_macro2::
 | 
				
			|||||||
                    AttrMeta::NoDebug => quote! {
 | 
					                    AttrMeta::NoDebug => quote! {
 | 
				
			||||||
                        write!(f, "    {} [{}; {}]: [...]\n", #ident_str, #type_str, #len)?;
 | 
					                        write!(f, "    {} [{}; {}]: [...]\n", #ident_str, #type_str, #len)?;
 | 
				
			||||||
                    },
 | 
					                    },
 | 
				
			||||||
                    AttrMeta::None => quote! {
 | 
					                    _ => quote! {
 | 
				
			||||||
                        write!(f, "    {} [{}; {}]: {:?}\n", #ident_str, #type_str, #len, self.#name.to_vec())?;
 | 
					                        write!(f, "    {} [{}; {}]: {:?}\n", #ident_str, #type_str, #len, self.#name.to_vec())?;
 | 
				
			||||||
                    }
 | 
					                    },
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
@ -306,6 +308,8 @@ fn get_struct_fields(fields: Iter<Field>) -> Result<Vec<AttrType>, TokenStream>
 | 
				
			|||||||
                "utf8" => AttrMeta::Utf8,
 | 
					                "utf8" => AttrMeta::Utf8,
 | 
				
			||||||
                "utf16" => AttrMeta::Utf16,
 | 
					                "utf16" => AttrMeta::Utf16,
 | 
				
			||||||
                "nodebug" => AttrMeta::NoDebug,
 | 
					                "nodebug" => AttrMeta::NoDebug,
 | 
				
			||||||
 | 
					                "length_is" => AttrMeta::LengthIs(attr.parse_args::<syn::Ident>().unwrap()),
 | 
				
			||||||
 | 
					                "length_of" => AttrMeta::LengthOf(attr.parse_args::<syn::Ident>().unwrap()),
 | 
				
			||||||
                _ => AttrMeta::None
 | 
					                _ => AttrMeta::None
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -404,9 +408,130 @@ pub fn pso_packet(attr: TokenStream, item: TokenStream) -> TokenStream {
 | 
				
			|||||||
    q.into()
 | 
					    q.into()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn generate_psomessage_from_bytes(attrs: &Vec<AttrType>) -> (Vec<proc_macro2::TokenStream>, Vec<proc_macro2::TokenStream>) {
 | 
				
			||||||
 | 
					    //let mut from_bytes = Vec::new();
 | 
				
			||||||
 | 
					    let mut assignment = Vec::new();
 | 
				
			||||||
 | 
					    let mut structure_creation = Vec::new();
 | 
				
			||||||
 | 
					    for attr in attrs {
 | 
				
			||||||
 | 
					        let (assignment_element, creation_element) = match attr {
 | 
				
			||||||
 | 
					            AttrType::Value(ty, name, meta) => {
 | 
				
			||||||
 | 
					                let temp_name = syn::Ident::new(&("_".to_string() + &name.to_string()), name.span());
 | 
				
			||||||
 | 
					                let type_str = ty.path.segments[0].ident.to_string();
 | 
				
			||||||
 | 
					                if type_str == "Vec" {
 | 
				
			||||||
 | 
					                    let vec_type = match &ty.path.segments[0].arguments {
 | 
				
			||||||
 | 
					                        syn::PathArguments::AngleBracketed(arg) => {
 | 
				
			||||||
 | 
					                            match &arg.args[0] {
 | 
				
			||||||
 | 
					                                syn::GenericArgument::Type(typ) => {
 | 
				
			||||||
 | 
					                                    match &typ {
 | 
				
			||||||
 | 
					                                        syn::Type::Path(path) => {
 | 
				
			||||||
 | 
					                                            Some(path.path.segments[0].ident.clone())
 | 
				
			||||||
 | 
					                                        }
 | 
				
			||||||
 | 
					                                        _ => None
 | 
				
			||||||
 | 
					                                    }
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                                _ => None,
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        _ => None
 | 
				
			||||||
 | 
					                    }.unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    let length_variable = match meta {
 | 
				
			||||||
 | 
					                        AttrMeta::LengthIs(ident) => syn::Ident::new(&("_".to_string() + &ident.to_string()), ident.span()),
 | 
				
			||||||
 | 
					                        _ => panic!("{} does not have a length specified", name),
 | 
				
			||||||
 | 
					                    };
 | 
				
			||||||
 | 
					                    let assignment = quote! {
 | 
				
			||||||
 | 
					                        let mut #temp_name = Vec::new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        for _ in 0..#length_variable  {
 | 
				
			||||||
 | 
					                            #temp_name.push(<#vec_type as PSOPacketData>::from_bytes(&mut cur)?);
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    };
 | 
				
			||||||
 | 
					                    let creation = quote! {
 | 
				
			||||||
 | 
					                        #name: #temp_name,
 | 
				
			||||||
 | 
					                    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    (assignment, creation)
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else {
 | 
				
			||||||
 | 
					                    let assignment = quote! {
 | 
				
			||||||
 | 
					                        let #temp_name = <#ty as PSOPacketData>::from_bytes(&mut cur)?;
 | 
				
			||||||
 | 
					                    };
 | 
				
			||||||
 | 
					                    let creation = quote! {
 | 
				
			||||||
 | 
					                        #name: #temp_name,
 | 
				
			||||||
 | 
					                    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    (assignment, creation)
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            AttrType::Array(ty, name, len, _) => {
 | 
				
			||||||
 | 
					                let temp_name = syn::Ident::new(&("_".to_string() + &name.to_string()), name.span());
 | 
				
			||||||
 | 
					                let assignment = quote! {
 | 
				
			||||||
 | 
					                    let #temp_name = {
 | 
				
			||||||
 | 
					                        let mut arr = [#ty::default(); #len];
 | 
				
			||||||
 | 
					                        for e in arr.iter_mut() {
 | 
				
			||||||
 | 
					                            *e = #ty::from_bytes(&mut cur)?
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        arr
 | 
				
			||||||
 | 
					                    };
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					                let creation = quote! {
 | 
				
			||||||
 | 
					                    #name: #temp_name,
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					                (assignment, creation)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        assignment.push(assignment_element);
 | 
				
			||||||
 | 
					        structure_creation.push(creation_element);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    (assignment, structure_creation)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn generate_psomessage_as_bytes(attrs: &Vec<AttrType>) -> Vec<proc_macro2::TokenStream> {
 | 
				
			||||||
 | 
					    let mut as_bytes = Vec::new();
 | 
				
			||||||
 | 
					    for attr in attrs {
 | 
				
			||||||
 | 
					        let element = match attr {
 | 
				
			||||||
 | 
					            AttrType::Value(ty, name, meta) => {
 | 
				
			||||||
 | 
					                let type_str = ty.path.segments[0].ident.to_string();
 | 
				
			||||||
 | 
					                if type_str == "Vec" {
 | 
				
			||||||
 | 
					                    quote! {
 | 
				
			||||||
 | 
					                        for i in self.#name.iter()  {
 | 
				
			||||||
 | 
					                            buf.extend_from_slice(&PSOPacketData::as_bytes(i));
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else {
 | 
				
			||||||
 | 
					                    if let AttrMeta::LengthOf(ident) = meta {
 | 
				
			||||||
 | 
					                        quote! {
 | 
				
			||||||
 | 
					                            buf.extend_from_slice(&PSOPacketData::as_bytes(&(self.#ident.len() as #ty)));
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    else {
 | 
				
			||||||
 | 
					                        quote! {
 | 
				
			||||||
 | 
					                            buf.extend_from_slice(&PSOPacketData::as_bytes(&self.#name));
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            AttrType::Array(_ty, name, len, _) => {
 | 
				
			||||||
 | 
					                quote! {
 | 
				
			||||||
 | 
					                    for i in 0..#len {
 | 
				
			||||||
 | 
					                        buf.extend_from_slice(&self.#name[i].as_bytes());
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        as_bytes.push(element);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    as_bytes
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn generate_psomessage_impl(msg_cmd: u8, name: syn::Ident, attrs: &Vec<AttrType>) -> proc_macro2::TokenStream {
 | 
					fn generate_psomessage_impl(msg_cmd: u8, name: syn::Ident, attrs: &Vec<AttrType>) -> proc_macro2::TokenStream {
 | 
				
			||||||
    let from_bytes = generate_from_bytes(&attrs);
 | 
					    let (assignment, struct_creation)= generate_psomessage_from_bytes(&attrs);
 | 
				
			||||||
    let as_bytes = generate_as_bytes(&attrs);
 | 
					    let as_bytes = generate_psomessage_as_bytes(&attrs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    quote! {
 | 
					    quote! {
 | 
				
			||||||
        impl PSOMessage for #name {
 | 
					        impl PSOMessage for #name {
 | 
				
			||||||
@ -430,8 +555,9 @@ fn generate_psomessage_impl(msg_cmd: u8, name: syn::Ident, attrs: &Vec<AttrType>
 | 
				
			|||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                let mut cur = std::io::Cursor::new(subbuf);
 | 
					                let mut cur = std::io::Cursor::new(subbuf);
 | 
				
			||||||
 | 
					                #(#assignment)*
 | 
				
			||||||
                let result = Ok(#name {
 | 
					                let result = Ok(#name {
 | 
				
			||||||
                    #(#from_bytes)*
 | 
					                    #(#struct_creation)*
 | 
				
			||||||
                });
 | 
					                });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                result
 | 
					                result
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										38
									
								
								src/lib.rs
									
									
									
									
									
								
							
							
						
						
									
										38
									
								
								src/lib.rs
									
									
									
									
									
								
							@ -580,4 +580,42 @@ mod test {
 | 
				
			|||||||
        let data = SixDee::from_bytes(&pkt);
 | 
					        let data = SixDee::from_bytes(&pkt);
 | 
				
			||||||
        assert!(pkt == data.unwrap().as_bytes());
 | 
					        assert!(pkt == data.unwrap().as_bytes());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn test_message_length() {
 | 
				
			||||||
 | 
					        #[pso_message(0x23)]
 | 
				
			||||||
 | 
					        struct Lengths {
 | 
				
			||||||
 | 
					            a: u8,
 | 
				
			||||||
 | 
					            #[length_of(d)]
 | 
				
			||||||
 | 
					            b: u8,
 | 
				
			||||||
 | 
					            c: u8,
 | 
				
			||||||
 | 
					            #[length_is(b)]
 | 
				
			||||||
 | 
					            d: Vec<u8>,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let pkt = Lengths {
 | 
				
			||||||
 | 
					            client: 1,
 | 
				
			||||||
 | 
					            target: 2,
 | 
				
			||||||
 | 
					            a: 12,
 | 
				
			||||||
 | 
					            b: 23,
 | 
				
			||||||
 | 
					            c: 34,
 | 
				
			||||||
 | 
					            d: vec![9,9,9],
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let mut data = pkt.as_bytes();
 | 
				
			||||||
 | 
					        assert!(data == vec![35, 3, 1, 2, 12, 3, 34, 9, 9, 9, 0, 0]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        data[10] = 8;
 | 
				
			||||||
 | 
					        data[5] = 4;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let l = Lengths::from_bytes(&mut std::io::Cursor::new(data)).unwrap();
 | 
				
			||||||
 | 
					        assert!(l == Lengths {
 | 
				
			||||||
 | 
					            client: 1,
 | 
				
			||||||
 | 
					            target: 2,
 | 
				
			||||||
 | 
					            a: 12,
 | 
				
			||||||
 | 
					            b: 4,
 | 
				
			||||||
 | 
					            c: 34,
 | 
				
			||||||
 | 
					            d: vec![9,9,9,8],
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,7 +1,7 @@
 | 
				
			|||||||
#![allow(unused_must_use)]
 | 
					#![allow(unused_must_use)]
 | 
				
			||||||
use std::io::{SeekFrom};
 | 
					use std::io::{SeekFrom};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use psopacket::pso_message;
 | 
					use psopacket::{pso_message, PSOPacketData};
 | 
				
			||||||
use crate::{PSOPacketData, PacketParseError};
 | 
					use crate::{PSOPacketData, PacketParseError};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user