Maik Klein
Maik Klein

Reputation: 16148

Can a macro generate additional data?

foo!(x, y, z);
// expands to
fn xx(self) -> T {..}
fn xy(self) -> T {..}
...
fn xxx(self) -> T {..}
fn xxy(self) -> T {..}
fn xyz(self) -> T {..}
fn xzx(self) -> T {..}
//and so on
...

Is it possible for macros to generate additional data? I would like to implement vector swizzling. There are many combinations for a Vector4. 4 + 2^2 + 3^3 + 4^4 = 291 combinations

I haven't done anything with macros besides simple substitution, so I am wondering if something like that could be expressed or do I need compiler plugins for that?

Upvotes: 4

Views: 223

Answers (1)

Matthieu M.
Matthieu M.

Reputation: 299930

Rust supports 3 methods of code generation:

  • macros declared with macro!
  • procedural macros relying on plugins (unstable)
  • build.rs

The latter is a built-in build script specifically supporting code generation/3rd-party libraries build (such as C libraries).

In your case, you are specifically interesting in the Code Generation part, which is simple enough (quoting the docs):

// build.rs

use std::env;
use std::fs::File;
use std::io::Write;
use std::path::Path;

fn main() {
    let out_dir = env::var("OUT_DIR").unwrap();
    let dest_path = Path::new(&out_dir).join("hello.rs");
    let mut f = File::create(&dest_path).unwrap();

    f.write_all(b"
        pub fn message() -> &'static str {
            \"Hello, World!\"
        }
    ").unwrap();
}

Given this, you can automatically generate any .rs file before the build starts without encountering the macro hygiene issue or having to rely on a nightly compiler.

Upvotes: 1

Related Questions