Reputation: 21
Currently I am working on the actor model, and I am using macro to build different messages, such as actor msg and system msg, based on the keyword.
workload
to create a dummy workload to mock the computation process, it needs two args, payload: usize
, and op: OpCode(OperationType)
.
create-actor
to create actors, two args are count: uszie
, and name: String
.
Workload and SystemCommand can be converted Into
TypedMessage.
#[macro_export]
macro_rules! build_msg {
($binary: expr, $arg1:tt, $arg2:expr) => {
{
let keyword: &str = $binary;
match keyword {
"workload" => {
let msg: TypedMessage = Workload::new($arg1 as usize, $arg2 as OpCode).into();
msg
}
"create-actor" => {
let name: &str = arg2;
let msg:TypedMessage = SystemCommand::CreateActor($arg1 as usize, $name.to_owned()).into();
msg
}
_ => {
panic!("Unknow Keyword, or number of vars not match with Keyword");
}
}
}
};
}
However, I get an error: mismatched types
expected struct String
, found enum messages::OpCode
.
#[test]
fn macro_build_msg_test() {
let wl_macro_1: TypedMessage = build_msg!("workload", 2, OpCode::AddOp); <- Problem here: OpCode::AddOp
assert_eq!(wl_macro_1, Workload::new(2, OpCode::AddOp).into());
}
Based on the keyword
and match
, it should get into the different branch. So the args should be converted to the corresponding types. Why I get this error? How could I solve it?
Upvotes: 1
Views: 372
Reputation: 60682
You don't want your macro to create a match
with all the possibilities because all arms of the match
would have to be valid for all types of inputs. Instead you should generate different code depending on the initial field:
macro_rules! build_msg {
("workload", $arg1:expr, $arg2:expr) => { {
let msg: TypedMessage = Workload::new($arg1, $arg2).into();
msg
} };
("create-actor", $arg1:expr, $arg2:expr) => { {
let msg: TypedMessage = SystemCommand::CreateActor($arg1, $arg2.to_owned()).into();
msg
} };
}
You can use it just as before: build_msg!("workload", 2, OpCode::AddOp);
If the types are incorrect, or the first argument is not literally "workload"
or "create-actor"
, you'll get compile-time error.
Upvotes: 0
Reputation: 3380
The problem is that, in your code, $arg2:expr
has to have two different types at the same time, which is why you get an error saying as much.
You seem to want to combine different commands with their arguments and have tried to exploit some superficial resemblance between workload
and create-actor
, such as the number of parameters and their type. It is better to not try to rely on this and package a command with its arguments into one thing. You can do this with an enum:
enum Command {
Workload { payload: usize, op: OperationType },
CreateActor { count: usize, name: String },
}
Then you can match against the enum variants.
Finally, I don't see why you are trying to use a macro; maybe a normal function will do?
Upvotes: 0