Change rs_bindings_from_cc to use new_string (layout-compatible) instead of string_wrapper (bridging) when generating bindings for C++ std::string, controlled by a new feature flag `layout_compatible_string`. When the flag is enabled, this ensures that in contexts requiring layout compatibility (pointers, references, template arguments, and struct fields), `std::string` is mapped to `new_string` instead of the bridge-based `string_wrapper` (or being erased in case of fields). Refactor generate_function_thunk_impl in generate_function_thunk.rs to use pre-calculated RsTypeKinds instead of recalculating them. This ensures C++ thunks and Rust FFI declarations agree on the type layout, preventing segfaults caused by mismatch. Propagate the `use_layout_compatible_string` option (derived from target features) through the bindings generator: - In `missing_feature_descriptions` to avoid false positive "unsupported" errors for template instantiations containing `std::string` when the flag is enabled. - In `rs_type_kind` query to use target features of the current target by default. - In function pointer type resolution in `rs_type_kind.rs`. Update `test_helpers` in `support/cc_std_impl/test/string` to enable `layout_compatible_string` via `aspect_hints` and verify it compiles and passes tests. PiperOrigin-RevId: 963505149
Crubit is a bidirectional bindings generator for C++ and Rust, with the goal of integrating the C++ and Rust ecosystems.
See the status page for an overview of the current supported features.
{{#tab name=“Calling Rust from C++”}}
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; } }
{{#tab name=“Calling C++ from Rust”}}
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 cc_std::std::unique_ptr; use ffi_11::{c_double, 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: c_double = u.balance; println!("User {} has balance {}", u.id, balance); } let new_user: unique_ptr<User> = CreateUser("Alice".into(), 456);
We have detailed walkthroughs on how to use C++ from Rust, or Rust from C++, using Crubit, as well as copy-pastable example code. The example code also includes spanshots of what the generated bindings look like.
examples/rust/examples/cpp/| Nightly | Stable |
|---|---|