Browse Source

length_is/length_of

pull/3/head
jake 4 years ago
parent
commit
d0f1de9b0c
  1. 136
      psopacket/src/lib.rs
  2. 38
      src/lib.rs
  3. 2
      src/packet/messages.rs

136
psopacket/src/lib.rs

@ -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

@ -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],
});
}
}

2
src/packet/messages.rs

@ -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…
Cancel
Save