英文:
Procedural macro to auto-generate match
问题
I am writing a toy virtual machine, where I need to decode instructions. I have an Instruction
trait with some methods and concrete instructions implement this trait. Also, I have a decode function which just takes a byte and matches it to return a specific instruction corresponding to the byte given.
pub struct FirstInstruction { ... }
pub struct SecondInstruction { ... }
pub struct ThirdInstruction { ... }
pub fn decode(byte: u8) -> Box<dyn Instruction> {
match byte {
0x1 => Box::new(FirstInstruction::new()),
0x2 => Box::new(SecondInstruction::new()),
0x3 => Box::new(ThirdInstruction::new()),
}
}
I was wondering how to write a procedural macro that would allow me to auto-generate the decode function. At the same time, it will get the byte to match in its arguments like this:
#[instruction(0x1)]
pub struct FirstInstruction { ... }
#[instruction(0x2)]
pub struct SecondInstruction { ... }
#[instruction(0x3)]
pub struct ThirdInstruction { ... }
pub fn decode(byte: u8) -> Box<dyn Instruction> {
// Autogenerated
}
I understand that from the practical standpoint this whole thing can be useless. I am just curious about how it can be implemented using macros, if it is even possible.
I tried to read about how to write procedural macros, but I don't understand how one can accumulate information about all structs with the specific attribute and then generate a whole new function.
英文:
I am writing a toy virtual machine, where I need to decode instructions. I have an Instruction
trait with some methods and concrete instructions implement this trait. Also, I have a decode function which just takes a byte and matches it to return a specific instruction corresponding to the byte given.
pub struct FirstInstruction { ... }
pub struct SecondInstruction { ... }
pub struct ThirdInstruction { ... }
pub fn decode(byte: u8) -> Box<dyn Instruction> {
match byte {
0x1 => Box::new(FirstInstruction::new()),
0x2 => Box::new(SecondInstruction::new()),
0x3 => Box::new(ThirdInstruction::new()),
}
}
I was wondering how to write a procedural macro that would allow me to auto-generate the decode function. At the same time, it will get the byte to match in its arguments like this:
#[instruction(0x1)]
pub struct FirstInstruction { ... }
#[instruction(0x2)]
pub struct SecondInstruction { ... }
#[instruction(0x3)]
pub struct ThirdInstruction { ... }
pub fn decode(byte: u8) -> Box<dyn Instruction> {
// Autogenerated
}
I understand that from the practical standpoint this whole thing can be useless. I am just curious about how it can be implemented using macros, if it is even possible.
I tried to read about how to write procedural macros, but I don't understand how one can accumulate information about all structs with the specific attribute and then generate a whole new function.
答案1
得分: 1
在一天结束时,我发现这很难实现。
我决定坚持使用一个简单的宏来生成`decode`函数:
```Rust
macro_rules! register_instructions {
{
$(
$code_value:expr => $struct_name:ty
),*
} => {
pub fn decode(code: &[u8]) -> Box<dyn Instruction> {
let instruction_code = code[0];
match instruction_code {
$($code_value => Box::new(<$struct_name>::new(code))),*,
_ => panic!("Invalid instruction"),
}
}
}
}
现在它看起来是这样的:
register_instructions! {
0x01 => AddInstruction,
0x02 => SubInstruction,
0x03 => MulInstruction,
0x04 => DivInstruction,
0x05 => JumpInstruction,
0x06 => LoadInstruction,
0x07 => FinishInstruction,
0x08 => OutInstruction,
0x09 => EqualInstruction,
0x0A => LessInstruction,
0x0B => LessEqualInstruction,
0x0C => LoadAbsoluteInstruction
}
英文:
At the end of the day I found out that this is pretty hard to implement.
I decided to stick to a simple macro that would generate the decode
function:
macro_rules! register_instructions {
{
$(
$code_value:expr => $struct_name:ty
),*
} => {
pub fn decode(code: &[u8]) -> Box<dyn Instruction> {
let instruction_code = code[0];
match instruction_code {
$($code_value => Box::new(<$struct_name>::new(code))),*,
_ => panic!("Invalid instruction"),
}
}
}
}
Now it looks like this:
register_instructions! {
0x01 => AddInstruction,
0x02 => SubInstruction,
0x03 => MulInstruction,
0x04 => DivInstruction,
0x05 => JumpInstruction,
0x06 => LoadInstruction,
0x07 => FinishInstruction,
0x08 => OutInstruction,
0x09 => EqualInstruction,
0x0A => LessInstruction,
0x0B => LessEqualInstruction,
0x0C => LoadAbsoluteInstruction
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论