I have a macro for generating structs and I want to use this macro inside function to pass args into it:
fn test(opcode: u32) -> Vec<u8> {
packet! {
@option[opcode=opcode]
struct Income {
name: String,
age: u64,
}
}
Income { name: String::from("Name"), age: 12345 }.to_binary()
}
but when I try to compile I got an error:
error[E0434]: can't capture dynamic environment in a fn item
--> src/main.rs:189:24
|
189 | @option[opcode=opcode]
| ^^^^^^
|
= help: use the `|| { ... }` closure form instead
so I tried to follow the hint and refactor the code into:
fn test(opcode: u32) -> Vec<u8> {
packet! {
@option[opcode=|| opcode]
struct Income {
name: String,
age: u64,
}
}
Income { name: String::from("Name"), age: 12345 }.to_binary()
}
but error still there.
This is full code of my macro:
#[macro_export]
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, 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);
std::io::Read::read_to_end(&mut decoder, &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();
$(
let size = body.len() + OUTCOMING_OPCODE_LENGTH;
byteorder::WriteBytesExt::write_u16::<byteorder::BigEndian>(
&mut header,
size as u16,
).unwrap();
byteorder::WriteBytesExt::write_u32::<byteorder::LittleEndian>(
&mut header,
$opcode_value as u32
).unwrap();
)?
header
}
$(
pub fn unpack(&mut self) -> PacketOutcome {
($opcode_value as u32, self.to_binary())
}
)?
}
};
}
This is sandbox to reproduce the issue.
Could somebody explain what I did wrong and how to fix the issue ?