How to write a macro in Rust to match any element in the set?

In C, I'm used to having:

if (ELEM(value, a, b, c)) { ... } 

which is a macro with a variable number of arguments to avoid input

 if (value == a || value == b || value == c) { ... } 

An example of C can be seen in the Varargs` ELEM` macro for use with C.

Is this possible in Rust? I guess he would use match . If so, how can variational arguments be used to achieve this?

0
source share
4 answers
 macro_rules! cmp { // Hack for Rust v1.11 and prior. (@as_expr $e:expr) => { $e }; ($lhs:expr, $cmp:tt any $($rhss:expr),*) => { // We do this to bind `$lhs` to a name so we don't evaluate it multiple // times. Use a leading underscore to avoid an unused variable warning // in the degenerate case of no `rhs`s. match $lhs { _lhs => { false || $( cmp!(@as_expr _lhs $cmp $rhss) ) || * // ^- this is used as a *separator* between terms }} }; // Same, but for "all". ($lhs:expr, $cmp:tt all $($rhss:expr),*) => { match $lhs { _lhs => { true && $( cmp!(@as_expr _lhs $cmp $rhss) ) && * }} }; } fn main() { let value = 2; if cmp!(value, == any 1, 2, 3) { println!("true! value: {:?}", value); } if cmp!(value*2, != all 5, 7, 1<<7 - 1) { println!("true! value: {:?}", value); } } 
+4
source

First of all, if your a , b and c are specific values, you can simply use match :

 fn main() { let x = 42; match x { 1 | 2 | 3 => println!("foo"), 42 => println!("bar"), _ => println!("nope"), } } 

If you want to combine variables, you need to write match weapons as follows:

 match x { x if x == a || x == b || x == c => println!("foo"), 42 => println!("bar"), _ => println!("nope"), } 

... basically this is what you want to avoid.

But: direct translation of your C macro is also possible!

 macro_rules! elem { ($val:expr, $($var:expr),*) => { $($val == $var)||* } } fn main() { let y = 42; let x = 42; if elem!(x, 1, 3, y) { println!("{}", x); } } 
+2
source

I cannot write this without a macro using contains in arrays.

 fn main() { if [1, 2, 3, 4].contains(&4) { println!("OK"); } } 

It is difficult to predict what will happen to this during optimization, but if absolute performance is the goal, it would be useful for you to evaluate each approach.

+1
source

Yes, it is possible, the following macro expands for each check.

 macro_rules! elem { ($n:expr, $( $hs:expr ),*) => ($( $n == $hs )||* ); } fn main() { if elem!(4, 1, 2, 3, 4) { println!("OK"); } } 

Thanks to @vfs on #rust in IRC.

0
source

All Articles