我有一个枚举,表示8080处理器上的所有可能指令。一条指令的长度可以为1、2或3个字节,具体取决于它是否具有与之关联的信息以及信息量。例如:
#[allow(non_camel_case_types)]
enum Instruction {
None,
NOP,
LXI_B_D16(u8, u8),
STAX_B,
INX_B,
MVI_B_D8(u8),
MVI_C_D8(u8),
RRC,
LXI_D_D16(u8, u8),
MVI_D_D8(u8),
RAL,
DCR_E,
MVI_E_D8(u8),
LXI_H_D16(u8, u8),
SHLD(u16),
LHLD(u16),
// ...
}
在为指令分配内存地址时,我通过二进制文件逐条指令进行迭代,使用每条指令的长度来确保我的循环不会在指令中途停留并给我垃圾。我使用一个巨大的match表达式来执行此操作,该表达式返回一个包含正确指令及其长度的元组:
match value {
0x00 => (Instruction::NOP, 1),
0x01 => (Instruction::LXI_B_D16(d1, d2), 3),
0x02 => (Instruction::STAX_B, 1),
0x05 => (Instruction::DCR_B, 1),
0x06 => (Instruction::MVI_B_D8(d1), 2),
0x07 => (Instruction::RLC, 1),
0x0e => (Instruction::MVI_C_D8(d1), 2),
0x0f => (Instruction::RRC, 1),
0x11 => (Instruction::LXI_D_D16(d1, d2), 3),
0x19 => (Instruction::DAD_D, 1),
// ...
}
这很丑陋,但是我不想将此长度数字关联到类型中,因为它仅在解析文件时才非常重要。
看来我应该能够从变体的形状中推断出一条指令的长度。任何不带参数的东西的长度为1,带一个u8参数的任何东西的长度为2,带一个u16或两个u8参数的任何东西的长度为3。
我还无法确定如何以编程方式获得此形状。例如,我无法像数组或向量那样调用len()
。
我不认为这是How to get the number of elements in an enum as a constant value?的副本,因为我不是在寻找一种方法来获取枚举中变体的数量,而是任何单个变体的参数的数量< / em>。
答案 0 :(得分:1)
如评论中所述,您可以编写一个宏来为您编写代码。
在懒惰的利益,我已经简化枚举定义总是rquire括号。这不是必需的,只是简化了我的工作。
一旦通过宏解析了枚举,我们就可以生成一个impl块,其功能与每个变体匹配。我们将每个变量的参数传递给内部宏,该宏为我们执行计数。该函数返回在每个变体的元素数:
macro_rules! instructions {
(enum $ename:ident {
$($vname:ident ( $($vty: ty),* )),*
}) => {
enum $ename {
$($vname ( $($vty),* )),*
}
impl $ename {
fn len(&self) -> usize {
match self {
$($ename::$vname(..) => instructions!(@count ($($vty),*))),*
}
}
}
};
(@count ()) => (0);
(@count ($a:ty)) => (1);
(@count ($a:ty, $b:ty)) => (2);
(@count ($a:ty, $b:ty, $c:ty)) => (3);
}
instructions! {
enum Instruction {
None(),
One(u8),
Two(u8, u8),
Three(u8, u8, u8)
}
}
fn main() {
println!("{}", Instruction::None().len());
println!("{}", Instruction::One(1).len());
println!("{}", Instruction::Two(1,2).len());
println!("{}", Instruction::Three(1,2,3).len());
}
您可能还写a custom derive
macro,做同样的功能。
另请参阅: