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, then the bindings for the function use the corresponding Rust type.
- Similarly, if a parameter or return type is a pointer type, then the bindings for the function use the corresponding Rust pointer type.
- If the type is a user-defined type, such as a struct or enum, 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.
Example
Given the following Rust crate:
// Part of the Crubit project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
pub fn add_two_integers(x: i32, y: i32) -> i32 {
x + y
}
Crubit will generate the following function declaration, which calls into accompanying glue code:
// Part of the Crubit project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// Automatically @generated C++ bindings for the following Rust crate:
// example_crate_golden
// Features: custom_ffi_types, non_unpin_ctor, std_unique_ptr, std_vector,
// supported
// clang-format off
#ifndef THIRD_PARTY_CRUBIT_EXAMPLES_RUST_FUNCTION_EXAMPLE_CRATE_GOLDEN
#define THIRD_PARTY_CRUBIT_EXAMPLES_RUST_FUNCTION_EXAMPLE_CRATE_GOLDEN
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wreturn-type-c-linkage"
#include <cstdint>
namespace example_crate {
// Generated from:
// examples/rust/function/example.rs;l=5
std::int32_t add_two_integers(std::int32_t x, std::int32_t y);
namespace __crubit_internal {
extern "C" std::int32_t __crubit_thunk_add_utwo_uintegers(std::int32_t,
std::int32_t);
}
inline std::int32_t add_two_integers(std::int32_t x, std::int32_t y) {
return __crubit_internal::__crubit_thunk_add_utwo_uintegers(x, y);
}
} // namespace example_crate
#pragma clang diagnostic pop
#endif // THIRD_PARTY_CRUBIT_EXAMPLES_RUST_FUNCTION_EXAMPLE_CRATE_GOLDEN
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
mutreference 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++:
#![allow(unused)]
fn main() {
fn foo(&self) {}
fn foo(_: &mut i32) {}
fn foo(_: &i32, _: &i32) {}
}
However, none of the below will receive bindings:
#![allow(unused)]
fn main() {
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 still not supported, and references which are bound to
some lifetime (e.g. 'static) are also still not supported.
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.