length_is/length_of
This commit is contained in:
parent
cccb8b1439
commit
d0f1de9b0c
@ -16,6 +16,8 @@ enum AttrMeta {
|
||||
Utf8,
|
||||
Utf16,
|
||||
NoDebug,
|
||||
LengthIs(syn::Ident),
|
||||
LengthOf(syn::Ident),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -237,9 +239,9 @@ fn generate_debug_impl(name: syn::Ident, attrs: &Vec<AttrType>) -> proc_macro2::
|
||||
AttrMeta::NoDebug => quote! {
|
||||
write!(f, " {} [{}; {}]: [...]\n", #ident_str, #type_str, #len)?;
|
||||
},
|
||||
AttrMeta::None => quote! {
|
||||
_ => quote! {
|
||||
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,
|
||||
"utf16" => AttrMeta::Utf16,
|
||||
"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
|
||||
}
|
||||
}
|
||||
@ -404,9 +408,130 @@ pub fn pso_packet(attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||
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 {
|
||||
let from_bytes = generate_from_bytes(&attrs);
|
||||
let as_bytes = generate_as_bytes(&attrs);
|
||||
let (assignment, struct_creation)= generate_psomessage_from_bytes(&attrs);
|
||||
let as_bytes = generate_psomessage_as_bytes(&attrs);
|
||||
|
||||
quote! {
|
||||
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);
|
||||
#(#assignment)*
|
||||
let result = Ok(#name {
|
||||
#(#from_bytes)*
|
||||
#(#struct_creation)*
|
||||
});
|
||||
|
||||
result
|
||||
|
38
src/lib.rs
38
src/lib.rs
@ -580,4 +580,42 @@ mod test {
|
||||
let data = SixDee::from_bytes(&pkt);
|
||||
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)]
|
||||
use std::io::{SeekFrom};
|
||||
|
||||
use psopacket::pso_message;
|
||||
use psopacket::{pso_message, PSOPacketData};
|
||||
use crate::{PSOPacketData, PacketParseError};
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user