Embedded Interpreter for Polyglot C++/Rust programming

Imagine a C++ compiler that runs a C++ interpreter at compile time so it can do dynamic code generation (or FFI glue) to call Rust code directly, without hand-writing bindings. That’s exactly the kind of thing a Circle-style compiler or Cling-style integration would make possible.

The Idea

  • The compiler has an embedded interpreter that can run arbitrary C++ at compile time.

  • At compile time, it:

    1. Reads Rust source or crate metadata.

    2. Uses rustc or cargo metadata to extract type signatures.

    3. Generates the C++ ↔ Rust FFI bridge automatically.

    4. Injects those bindings into the final compiled binary.

This means from a C++ programmer’s view, calling Rust looks like a normal function call, but under the hood, the compiler has auto-generated the extern "C" shims.

Hypothetical Syntax (Circle-Style)

 1import <rust/ffi_generator>; // imaginary compile-time helper
 2
 3// At compile-time, parse Rust crate metadata and generate glue.
 4constexpr void load_rust_module(const char* crate_path) {
 5    auto metadata = rust::parse_crate(crate_path);
 6    for (auto& fn : metadata.functions) {
 7        rust::generate_extern(fn);  // emits extern "C" declaration
 8    }
 9}
10
11@meta {
12    load_rust_module("../my_rust_crate");  // Run at compile-time
13}
14
15// Now, call Rust function directly like C++
16int main() {
17    int result = rust_add(3, 4); // Suppose Rust has fn rust_add(i32, i32) -> i32
18    std::cout << "Result: " << result << "\n";
19}

How it would work

  • @meta is Circle’s syntax for compile-time execution of code.
  • rust::parse_crate and rust::generate_extern run in the compiler’s interpreter, generating the actual extern “C” glue declarations.
  • The resulting C++ translation unit now has:
1extern "C" int rust_add(int, int);

Behind the scenes

  1. Rust Side:

You’d expose your Rust code to C via:

1#[no_mangle]
2pub extern "C" fn rust_add(a: i32, b: i32) -> i32 {
3    a + b
4}

Note, I’m still looking at what it would require to generate rust bindings directly in the c++ code, so that any rust function could be called, not just functions that have been exported with #[no_mangle].

  1. C++ Side (Meta): The compiler’s interpreter:
  • Runs cargo metadata or parses rustdoc JSON.
  • Auto-generates C function signatures.
  • Injects them into the C++ compilation unit.
  1. Linking: The compiler links your program against libmy_rust_crate.a.

Why is this powerful Normally you’d write bindings by hand or use bindgen separately, but here:

  • No separate binding step.
  • The compiler runs real C++ code at compile time to integrate Rust code dynamically.
  • You can even imagine generating C++ wrappers for Rust traits, enums, etc.