| # C++ bindings for Rust functions | |
| C++ code can call functions defined in Rust, provided that the parameter and | |
| return types are supported by Crubit: | |
| * If a parameter or return type is a | |
| [fundamental type](../cpp/fundamental_types.md), then the bindings for the | |
| function use the corresponding C++ type. | |
| * Similarly, if a parameter or return type is a | |
| [pointer type](../cpp/pointer_types.md), then the bindings for the function | |
| use the corresponding C++ pointer type. | |
| * If the type is a user-defined type, such as a [struct](struct.md) or | |
| [enum](enums.md), then the bindings for the function use the bindings for | |
| that type. | |
| As a special case, functions also support reference parameters to supported | |
| types, with some restrictions to ensure safety. See [References](#references). | |
| ## Example | |
| Given the following Rust crate: | |
| ```live-snippet | |
| cs/file:examples/rust/function/example.rs function:add_two_integers | |
| ``` | |
| Crubit will generate the following function declaration, which calls into | |
| accompanying glue code: | |
| ```live-snippet | |
| cs/file:examples/rust/function/example_generated.h function:add_two_integers | |
| ``` | |
| ## `unsafe` functions | |
| C++ 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. | |
| ## References | |
| 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: | |
| * All references must have an unbound parameter lifetime – not `'static`, for | |
| example. | |
| * Only the parameter itself can be a reference type. References to references, | |
| vectors of references, etc. are still unsupported. | |
| * If there is a `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++: | |
| ```rust {.good} | |
| fn foo(&self) {} | |
| fn foo(_: &mut i32) {} | |
| fn foo(_: &i32, _: &i32) {} | |
| ``` | |
| However, none of the below will receive bindings: | |
| ```rust {.bad} | |
| 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. | |
| ## Slice parameters | |
| 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: | |
| ```rust {.good} | |
| 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: | |
| ```rust {.bad} | |
| 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`. | |
| ## Generic functions | |
| 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...) &&>` | |
| ## Callbacks (`Fn`, `FnMut`, `FnOnce`) {#callbacks} | |
| 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](callbacks.md) for full | |
| details. |