Crubit is a bidirectional bindings generator for C++ and Rust, allowing users to:
Vec, Result, Option, std::vector, std::unique_ptr, std::shared_ptr, and more!Consider the following Rust library:
pub struct Account { pub id: u64, pub balance: f64, } impl std::fmt::Display for Account { ... } // Takes shared references, mapped to const references in C++. pub fn calculate_interest(account: &Account, rate: f64) -> f64 { ... } // Takes a string slice, mapped to rs_std::StrRef in C++. pub fn is_valid_username(username: &str) -> bool { ... }
You can call these Rust functions from C++:
#include "path/to/account.h" #include <iostream> void demo() { account::Account my_account{.id = 123, .balance = 1000.0}; double interest = account::calculate_interest(my_account, 0.05); // my_account is printable because Account implements Display in Rust! std::cout << my_account << std::endl; if (account::is_valid_username("bob")) { std::cout << "Valid user" << std::endl; } }
Consider the following C++ header:
#include <string_view> #include <optional> #include <memory> struct User { int id; double balance; }; std::optional<User> FindUser(int id); std::unique_ptr<User> CreateUser(std::string_view name, int id);
You can call these C++ functions from Rust:
use cpp_std::unique_ptr; use ffi_11::c_int; use user_api::{CreateUser, FindUser, User}; let id: c_int = 123; let user: Option<User> = FindUser(id); if let Some(u) = user { let balance: f64 = u.balance; println!("User {} has balance {}", u.id, balance); } let new_user: unique_ptr<User> = CreateUser("Alice".into(), 456);
extern "C", pass structs and enums by value, and match the memory layout of Rust structs and enums that aren’t #[repr(C)].&str, Option, Result, tuples, smart pointers, std::vector/Vec, callbacks, absl::Status, and more map to their natural counterparts. See the status page for the full table.Display, Clone, and Default become the matching C++ operators and special member functions. In the other direction, C++ operator overloads and special member functions become the matching Rust traits, such as PartialEq, Add, Clone, and Drop.Option, and other types carry their bounds and invariants across the boundary instead of degrading to raw pointers. See Memory Safety for the details.Crubit runs as part of your build, so that the bindings always match the code they wrap. Pick your build system:
| Build system | C++ calling Rust (cpp_api_from_rust) | Rust calling C++ (rust_api_from_cpp) |
|---|---|---|
| Bazel | Supported (example) | Supported |
| CMake | Supported (example) | Not yet |
| Other | Through the cargo cpp_api_from_rust subcommand | Not yet |
Crubit works with nightly Rust toolchains and with the two most recent stable releases, as long as the rustc-dev component is installed (see the test matrix below). There are no binary releases yet; pin a commit of this repository. Build System Integrations covers toolchain requirements and how to set up each build system.
Add a cpp_api_from_rust or rust_api_from_cpp target next to your library, and start calling it from the other language. Each direction has a walkthrough that explains what the generated API looks like and how to customize it, plus copy-pastable examples that include snapshots of the generated bindings:
examples/rust/.examples/cpp/.| Nightly | Stable |
|---|---|