I have a macro that expands to a function definition, and works fine for various cases. But some expansions contain unsafe code and some don't. Like this contrived example:
extern crate core;
use core::ptr;
struct Stuff(i32);
fn extract_boring(s: &Stuff) -> i32 { s.0 }
unsafe fn extract_daring(s: &Stuff) -> i32 { ptr::read(s).0 }
macro_rules! doubler {
($name: ident @ $extract: ident) => {
unsafe fn $name(stuff: &Stuff) -> i32 {
$extract(stuff) + $extract(stuff)
}
};
}
doubler!(boring @ extract_boring);
doubler!(daring @ extract_daring);
fn main() {
let s1 = Stuff(12);
let s2 = Stuff(21);
unsafe {
println!("{}", boring(&s1));
println!("{}", daring(&s2));
}
}
This compiles and works fine, but some safe code has to be marked unsafe. What can I do?
- Write two macros with the same body. But I really want to avoid duplicating the body (which is a lot more complicated in reality), that's why I'm using a macro in the first place.
- Make the unsafe keyword conditional in the macro expansion. But the list of fragment specifiers I found including visibility qualifiers doesn't seem to cover that.
- Limit the macro to the function body as an expression. But the actual body has a somewhat complicated control flow with return statements. I can replace these with labeled break statements in a fake loop, but it just looks like do-not-repeat-yourself taken a step too far.
Am I missing something?