I have a macros where I try to parse structures like this:
packet! {
@option[opcode=100]
@option[no_size: true]
@option[compressed: true]
struct Income {
name: String,
age: u64,
is_cool: bool,
}
}
I use next pattern to detect the structures:
$(@option[opcode=$opcode_value:expr])?
$(@option[no_size:$no_size:expr])?
$(@option[compressed:$compressed_value:expr])?
$(#[$outer:meta])*
$vis:vis struct $PacketStruct:ident {
$($field_name:ident: $field_type:ty),*$(,)?
}
$($PacketStructImpl: item)*
The issue with current macros implementation is that $opcode_value
should be integer, but for some reason it expected by macros to be bool
, so on compile I got next error:
error[E0308]: mismatched types
--> src/main.rs:189:20
|
189 | @option[opcode=100]
| ^^^ expected `bool`, found integer
This is full code of the macros:
macro_rules! packet {
(
$(@option[opcode=$opcode_value:expr])?
$(@option[no_size:$no_size:expr])?
$(@option[compressed:$compressed_value:expr])?
$(#[$outer:meta])*
$vis:vis struct $PacketStruct:ident {
$($field_name:ident: $field_type:ty),*$(,)?
}
$($PacketStructImpl: item)*
) => {
$(#[$outer])*
#[derive(Clone, PartialEq, Debug, Default)]
$vis struct $PacketStruct {
$($field_name: $field_type),*
}
$($PacketStructImpl)*
impl $PacketStruct {
// income
pub fn from_binary(buffer: &Vec<u8>) -> Self {
let mut omit_bytes: usize = INCOMING_HEADER_LENGTH;
$(
if $no_size {
// because no_size packets are only on login server
omit_bytes = 1;
}
)?
$(
if $compressed_value {
// 4 bytes uncompressed + 2 bytes used by zlib
omit_bytes += 6;
}
)?
let mut internal_buffer: Vec<u8> = Vec::new();
$(
if $compressed_value {
let data = &buffer[omit_bytes..];
let mut decoder = flate2::read::DeflateDecoder::new(data);
decoder.read_to_end(&mut internal_buffer).unwrap();
}
)?
let buffer = if internal_buffer.is_empty() {
buffer[omit_bytes..].to_vec()
} else {
internal_buffer
};
let mut reader = std::io::Cursor::new(&buffer);
Self {
$(
$field_name: BinaryConverter::read_from(
&mut reader
).unwrap()
),*
}
}
// outcome
pub fn to_binary(&mut self) -> Vec<u8> {
let mut packet = Vec::new();
$(
BinaryConverter::write_into(
&mut self.$field_name,
&mut packet
).unwrap();
)*
let header = Self::_build_header(&packet);
[header, packet].concat()
}
fn _build_header(body: &Vec<u8>) -> Vec<u8> {
let mut header: Vec<u8> = Vec::new();
$(
if $no_size {
header.write_u8($opcode_value).unwrap();
}
)?
$(
if $opcode_value {
let size = body.len() + OUTCOMING_OPCODE_LENGTH;
header.write_u16::<BigEndian>(size as u16).unwrap();
header.write_u32::<LittleEndian>($opcode_value).unwrap();
}
)?
header
}
$(
pub fn unpack(&mut self) -> PacketOutcome {
($opcode_value as u32, self.to_binary())
}
)?
}
};
}
This is sandbox that reproducing the issue.
Could somebody explain how to fix an issue and why this happen ?