I would like to pattern match a complex constant based on one of its fields. You can match on a constant using a PathPattern, but selecting a constant field of another constant is not allowed.
Is it possible to write a macro take the result of a constant expression and compile time "inline" it such that the generated code is a valid LiteralPattern?
Consider this working code:
pub struct Instruction {
code: u8,
width: usize,
}
pub const CMP_REG_U8: Instruction = Instruction { code: 3, width: 3 };
pub const CMP_REG_U32: Instruction = Instruction { code: 4, width: 6 };
pub const INVALID: Instruction = Instruction { code: 0, width: 0 };
fn main() {
let opcode = 3u8;
let inst = match opcode {
3 => CMP_REG_U8,
4 => CMP_REG_U32,
_ => INVALID,
};
println!("inst.code: {} inst.width: {}", inst.code, inst.width);
}
I'd like to be able to write essentially this:
let inst = match opcode {
CMP_REG_U8.code => CMP_REG_U8,
CMP_REG_U32.code => CMP_REG_U32,
_ => INVALID,
};
This way I don't have to put magic numbers in my match statement, nor repeat them a second time.
I do realise I can use guards:
let inst = match opcode {
x if x == CMP_REG_U8.code => CMP_REG_U8,
x if x == CMP_REG_U32.code => CMP_REG_U32,
_ => INVALID,
};
...but this seems a little verbose and I'm concerned about how to convince the compiler to give me a jump table implementation. (Imagine instead of just returning the instruction, we want to execute a snippet of code and be able to reference the associated data like inst.width with no performance penalty compared to hardcoding the value as a literal.)
So bottom line, is it possible to solve this with a macro that "literalises" a constant?
let inst = match opcode {
as_literal!(CMP_REG_U8.code) => exec_op(CMP_REG_U8),
as_literal!(CMP_REG_U32.code) => exec_op(CMP_REG_U32),
_ => INVALID,
};
This way the match arms would all be hardcoded integers which should make it super easy for the compiler to inline whatever exec_op does, recognising width and so forth as constants in that context, and do a computed goto or whatever to go there.
I've heard macros in Rust only allow you to do things you could have typed yourself. However, I could certainly have typed 3 instead of CMP_REG_U8.code -- the question is if Rust can do it for me. It would need to solve this at compile time for the generated pattern to be valid in a match.