C++ code can call functions defined in Rust, provided that the parameter and return types are supported by Crubit:
As a special case, functions also support reference parameters to supported types, with some restrictions to ensure safety. See References.
Given the following Rust crate:
cs/file:examples/rust/function/example.rs function:add_two_integers
Crubit will generate the following function declaration, which calls into accompanying glue code:
cs/file:examples/rust/function/example_generated.h function:add_two_integers
unsafe functionsC++ does not have an unsafe marker at this time. In the future, Crubit may introduce a way to mark unsafe functions to help increase the reliability of C++ callers.
In general, Rust references are not exposed to C++. However, some Rust functions which accept reference parameters do get mapped to C++ functions accepting C++ references:
'static, for example.mut reference parameter, it is the only reference parameter.This set of rules is intended to describe a safe subset of Rust functions, which do not introduce substantial aliasing risk to a mixed C++/Rust codebase.
For example, the following Rust functions will receive C++ bindings, and can be called from C++:
fn foo(&self) {} fn foo(_: &mut i32) {} fn foo(_: &i32, _: &i32) {}
However, none of the below will receive bindings:
fn foo(_: &'static i32) {} // 'static lifetime is bound fn foo(_: &&i32) {} // Reference in non-parameter type fn foo(_: &mut i32, _: &i32) {} // More than one reference, one of which is mut fn foo(_: &'a i32) {} // 'a is not a lifetime parameter of `foo`
Returned references are mapped to C++ references (for self borrows) or C++ pointers, depending on the lifetime.
If you wish to accept more than one reference/pointer in C++, a raw pointer (*const T, *mut T) can be used instead. However, all of the usual unsafe caveats apply.
Rust slice parameters (&[T], &mut [T], &str) map to rs::SliceRef<const T>, rs::SliceRef<T>, and rs::StrRef in C++.
C++ callers can pass absl::Span<const T>, std::span<const T>, or contiguous containers like std::vector<T> and std::array<T, N> directly to satisfy &[T] slice parameters with no conversion boilerplate:
fn process_text(_: &str) {} // C++ callers can pass "hello" or std::string_view fn process_bytes(_: &[u8]) {} // C++ callers can pass absl::Span<const uint8_t>, std::span, "hello", or std::string_view fn process_items(_: &[i32]) {} // C++ callers can pass absl::Span<const int32_t>, std::span, std::vector, etc.
However, mutable slices cannot be implicitly constructed from read-only views or string literals:
fn process_mut_bytes(_: &mut [u8]) {} // Cannot pass string literals or const spans to mutable byte slices
&[T]: Maps to rs::SliceRef<const T> (crubit/support/rs_std/slice_ref.h). Converts implicitly from absl::Span<const T>, absl::Span<T>, std::span<const T>, std::span<T>, std::vector<T>, and std::array<T, N>.&mut [T]: Maps to rs::SliceRef<T> (crubit/support/rs_std/slice_ref.h). Converts implicitly from mutable std::span<T> and absl::Span<T>, or construct via rs::SliceRef(ptr, size).&str: Maps to rs::StrRef (crubit/support/rs_std/str_ref.h). Converts from string literals and std::string_view.&[u8]: Maps to rs::SliceRef<const uint8_t>. In addition to absl::Span and std::span, also converts from string literals and std::string_view.Crubit doesn't support generating bindings for arbitrary generic functions. Nevertheless, a small set of generic type parameters is supported by using canonical substitutions which are defined as follows:
| Generic constraints | Canonical substitution |
|---|---|
T: AsMut<U> | &mut U |
T: AsRef<U> | &U |
T: Into<U> | U |
F: Fn(Args...) -> R | rs::FnRef<R(Args...) const> |
F: FnMut(Args...) -> R | rs::FnRef<R(Args...)> |
F: FnOnce(Args...) -> R + 'static | rs::Fn<R(Args...) &&> |
Fn, FnMut, FnOnce)Rust functions can accept callbacks as borrowed trait objects (&dyn Fn, &mut dyn FnMut), owned boxes (Box<dyn Fn>, Box<dyn FnMut>, Box<dyn FnOnce>), or generic impl Trait parameters:
&dyn Fn(...) / impl Fn(...): Maps to rs::FnRef<... const> (borrowed, no allocation).&mut dyn FnMut(...) / impl FnMut(...): Maps to rs::FnRef<...> (borrowed, no allocation).impl FnOnce(...) (without 'static): Maps to rs::FnRef<...> (borrowed, no allocation).Box<dyn Fn(...)>: Maps to rs::Fn<... const> (owned).Box<dyn FnMut(...)>: Maps to rs::Fn<...> (owned mutable).Box<dyn FnOnce(...)> / impl FnOnce(...) + 'static: Maps to rs::Fn<... &&> (owned, single-use).C++ callers can satisfy these parameters by passing C++ lambdas, function pointers, or absl::AnyInvocable. See Callbacks for full details.