Translation of C preprocessor in Rust

I am porting some C code to Rust and this code contains many things like this:

#define CONFIG_FLAG_NUMBER_23 1 #define THIS 10 #define THAT 11 #define THIS_AND_THAT (THIS + THAT) #if CONFIG_FLAG_NUMBER_23 #define THIS_OR_THAT THIS #else #define THIS_OR_THAT THAT #endif #define ROOT_DIR "/root" #define FILE_ONE ROOT_DIR "/file_one" #define FILE_TWO ROOT_DIR "/file_two" 

I decided to remove the macros and replace them with constant expressions, but attempts to do this in Rust were not very successful:

 static CONFIG_FLAG: bool = true; static THIS: int = 10; static THAT: int = 11; static THIS_AND_THAT: int = THIS + THAT; // Okay, it works // 1: Conditions static THIS_OR_THAT: int = CONFIG_FLAG ? THIS : THAT; // Doesn't work, no conditional operator static THIS_OR_THAT: int = if CONFIG_FLAG { THIS } else { THAT }; // Doesn't work, "if" is not basic enough for compile time // 2: Strings static ROOT_DIR: &'static str = "/root"; static FILE_ONE: &'static str = ROOT_DIR + "/file_one"; // Doesn't work, static strs can't be Added static FILE_TWO: String = ROOT_DIR.to_string() + "/file_two"; // Don't even think about allocations in constant expressions! static FILE_THREE: &'static str = concat!(ROOT_DIR, "/file_three"); // Doesn't work, concat! works only with literals 

What would be the right / least painful way to rewrite such code in Rust?

+7
c rust
source share
1 answer

Problem 1: Conditional Expressions
Because configuration flags can be interpreted as integers, they can be used as indexes in option arrays.

 // Configuration flag static CONFIG_FLAG: uint = 1; // Variants of any static type type T = &'static str; static VARIANT1: T = "True"; static VARIANT2: T = "False"; // Now you can select, but you have to invert either flag, or variants, or your brain static SELECTED: T = [VARIANT1, VARIANT2][1 - CONFIG_FLAG]; fn main() { println!("{}", SELECTED); } 

Notes:

CONFIG_FLAG type bool currently does not work in array index due to issue # 5873 ,

 // error: can't cast str to uint static SELECTED: T = [VARIANT1, VARIANT2][1 - CONFIG_FLAG_BOOL as uint]; 

so you need to create another static element and then use it in conditional expressions.

 static CONFIG_FLAG_UINT: uint = CONFIG_FLAG_BOOL as uint; 

Problem 2: concatenating the compilation string pipeline

Simple C macros render Rust macros nicely, so you can use essentially the same approach for string concatenation as in C. The only difference is that you must use concat explicitly! instead of just placing literals next to each other.

 #![feature(macro_rules)] // Define new macro-string with name $name assembled from arguments $arg macro_rules! define_str ( ($name: ident, $($arg: expr), +) => (macro_rules! $name ( () => (concat!($($arg), +)) )); ) // Some strings define_str!(ROOT_DIR, "/root") define_str!(SUB_DIR, ROOT_DIR!(), "/sub") define_str!(FILE_NAME, SUB_DIR!(), "/file") define_str!(NONSENSE, FILE_NAME!(), SUB_DIR!(), ROOT_DIR!()) fn main() { println!("{}", FILE_NAME!()); println!("{}", NONSENSE!()); } 

Notes:
I would like to add !() macro names automatically inside define_str with an additional macro like this,

 macro_rules! add_bang_and_parens ( ($arg: ident) => ($arg!()); ($arg: expr) => ($arg); ) 

but it seems that matching macro templates based on the "types" of arguments is currently not possible.

+4
source share

All Articles