| # C++ bindings for Rust standard library (`std`) types | |
| When generating C++ bindings for a Rust crate (via `cpp_api_from_rust`) bindings | |
| to the Rust standard library types (`std`, `alloc`, and `core`) are | |
| automatically generated for those types under the namespaces `rs::std`, | |
| `rs::alloc`, and `rs::core`. | |
| ## Working with `String` in C++ {#string} | |
| Rust's `String` becomes `rs::std::string::String` in C++ (also spelled | |
| `rs::alloc::string::String`). It can be constructed from a C++ string literal: | |
| ```c++ | |
| rs::std::string::String s("hello, world!"); | |
| ``` | |
| An existing `std::string_view` (or `absl::string_view`) can be converted to a | |
| Rust `String` using `rs::StrRef::FromUtf8`: | |
| ```c++ | |
| void AcceptsStringView(std::string_view view) { | |
| std::optional<rs::StrRef> str_ref = rs::StrRef::FromUtf8(view); | |
| if (!str_ref.has_value()) { | |
| return; | |
| } | |
| rs::std::string::String s(*str_ref); | |
| // Continue on with using your Rust String... | |
| } | |
| ``` | |
| An instance of `String` can be converted back to a `std::string` by calling | |
| `.as_str()` and using the resulting `rs::StrRef` to construct a `std::string`: | |
| ```c++ | |
| std::string s2(s.as_str()); | |
| EXPECT_EQ(s2, "hello, world!"); | |
| ``` | |
| `rs::StrRef` supports implicit conversion to `std::string_view` to make this | |
| work. | |
| A Rust method that takes an `&mut String` such as: | |
| ```rust | |
| pub fn append_to_rust_string(val: &mut String, s: &str) { | |
| val.push_str(s); | |
| } | |
| ``` | |
| becomes a C++ method taking a reference to a `rs::std::string::String`: | |
| ```c++ | |
| // You could just as easily call `push_str` directly. It receives Crubit | |
| // bindings. We use a wrapper method here for expository purposes. | |
| void append_to_rust_string(rs::std::string::String& val, rs::StrRef s); | |
| ``` | |
| Allowing for C++ to call it: | |
| ```c++ | |
| append_to_rust_string(s, " I'm a neat addition"); | |
| ``` | |
| ## `Result` | |
| The Rust `Result<T, E>` generic receives C++ bindings as `rs::Result<T, E>`, so | |
| long as both `T` and `E` are non-ZST types supported by Crubit. | |
| `rs::Result<T, E>` has a similar API to | |
| [`std::expected`](https://en.cppreference.com/cpp/utility/expected). | |
| (Alternatively, it has a similar API to | |
| [`std::optional`](https://en.cppreference.com/cpp/utility/optional), but with an | |
| additional error payload.) If `has_value()` returns `false`, then `error()` will | |
| return a reference to the error payload of type `E`. | |
| ```c++ | |
| if (myresult.has_value()) { | |
| Foo(*myresult); | |
| } else { | |
| Foo(myresult.error()); | |
| } | |
| ``` | |
| A more complete description of the API is in the common `ResultBase` public base | |
| class: support/rs_std/result.h | |
| ## `Option` | |
| The Rust `Option<T>` generic receives C++ bindings as `rs::Option<T>`, so long | |
| as `T` is a non-ZST type supported by Crubit. It has a similar API to | |
| [`std::optional`](https://en.cppreference.com/cpp/utility/optional), and | |
| implicitly converts to and from `std::optional`. | |
| Unlike `std::optional`, `rs::Option` has no `operator bool`, so check for a | |
| value with `has_value()` rather than `if (myoption)`. Conversion to | |
| `std::optional` is only available from an rvalue, so either convert the result | |
| of a call directly or `std::move` an existing `rs::Option`: | |
| ```c++ | |
| if (myoption.has_value()) { | |
| Foo(*myoption); | |
| } | |
| std::optional<int32_t> converted = std::move(myoption); | |
| std::optional<int32_t> direct = rust_crate::find_index(name); | |
| ``` | |
| A more complete description of the API is in the common `OptionBase` public base | |
| class: support/rs_std/option.h | |
| ## `Tuple` | |
| A Rust tuple `(T1, T2, ...)` receives C++ bindings as `rs::Tuple<T1, T2, ...>`. | |
| It can be constructed from its elements (including with brace-initialization, | |
| e.g. `{a, b}`) when all elements are move-constructible in C++, or converted | |
| from a `std::tuple<T1, T2, ...>`. Elements are accessed with `rs::get<I>` or | |
| structured bindings: | |
| ```c++ | |
| rs::Tuple<int32_t, int32_t> pair = {1, 2}; | |
| auto [first, second] = pair; | |
| ``` | |
| The support header is support/rs_std/tuple.h. | |
| ## `Vec` | |
| The Rust `Vec<T>` generic receives C++ bindings as `rs::Vec<T>`, so long as `T` | |
| is a type supported by Crubit. Each `rs::Vec<T>` is a generated specialization | |
| that inherits its public API from the common `VecBase<T>` base class in | |
| support/rs_std/vec.h. The API is modeled on | |
| [`std::vector`](https://en.cppreference.com/cpp/container/vector), with a few | |
| differences noted below. | |
| `rs::Vec<T>` is a real Rust `Vec` under the hood: it has the same layout, and | |
| its buffer is allocated and freed through Rust's global allocator. A `Vec` | |
| created in C++ can therefore be handed to Rust (and vice versa) without any | |
| copying or conversion. | |
| ### Element access and iteration | |
| `rs::Vec<T>` provides the usual contiguous-container accessors: | |
| * `size()`, `capacity()`, `empty()` | |
| * `data()` (returns a pointer to the contiguous element buffer) | |
| * `operator[]`, `front()`, `back()` -- these are **bounds-checked** and abort | |
| the process on misuse (e.g. an out-of-range index or `front()` on an empty | |
| vector), mirroring the panicking behavior of Rust's `Vec`. | |
| * `begin()` / `end()`, `cbegin()` / `cend()`, `rbegin()` / `rend()`, | |
| `crbegin()` / `crend()` | |
| Iterators are raw pointers, so `rs::Vec<T>` works with range-based `for` loops | |
| and standard algorithms, and satisfies `std::ranges::contiguous_range`. This | |
| also makes it implicitly convertible to `std::span<const T>` / `std::span<T>` | |
| and, by extension, to `rs::SliceRef<const T>` / `rs::SliceRef<T>`: | |
| ```c++ | |
| rs::Vec<int32_t> v = my_crate::return_vec(); | |
| for (int32_t& x : v) { | |
| x += 1; | |
| } | |
| int32_t sum = std::accumulate(v.begin(), v.end(), 0); | |
| std::span<const int32_t> span = v; | |
| rs::SliceRef<const int32_t> slice = v; | |
| ``` | |
| ### Modifying a `Vec` from C++ | |
| Elements can be added, removed, and constructed in place from C++: | |
| ```c++ | |
| rs::Vec<int32_t> v; | |
| v.reserve(3); // Total capacity, like std::vector::reserve. | |
| v.push_back(1); | |
| v.push_back(2); | |
| v.emplace_back(3); // Constructs in place; returns a T&. | |
| v.insert(0, 0); // Inserts at *index* 0, shifting the rest right. | |
| v.pop_back(); // Removes and destroys the last element. | |
| v.clear(); // Destroys all elements but keeps the buffer. | |
| ``` | |
| Differences from `std::vector` worth knowing about: | |
| * `insert(index, value)` takes an index rather than an iterator (as in Rust's | |
| `Vec::insert`). | |
| * `reserve(new_cap)` has `std::vector::reserve` semantics: it ensures the | |
| *total* capacity is at least `new_cap`. To request room for `n` *additional* | |
| elements (Rust's `Vec::reserve(additional)` semantics), use | |
| `reserve_additional_capacity(n)` instead. | |
| * Only the operations listed above are currently supported. In particular, | |
| there is no `erase`, `resize`, or range `insert`. For other operations, | |
| write a small Rust helper function and call it through its Crubit bindings. | |
| ## Availability of generic `rs_std` specializations | |
| Generic standard library types such as `rs::Option<T>`, `rs::Result<T, E>`, | |
| `rs::Tuple<Ts...>`, and `rs::Vec<T>` are only defined for type arguments that | |
| are actually used in a Crubit-bound Rust API. The support headers (`option.h`, | |
| `result.h`, `tuple.h`, `vec.h`) provide only the generic base implementations | |
| (`OptionBase`, `ResultBase`, `VecBase`, etc.) and leave the primary template | |
| uninstantiable; the concrete specialization for a given set of type arguments is | |
| emitted into the generated header of a crate whose public API mentions that | |
| instantiation. Attempting to use one of these templates with type arguments that | |
| do not appear in any of the Rust APIs you depend on is a compile-time error. | |
| ## Callables (`Fn`, `FnMut`, `FnOnce`) {#callables} | |
| Rust function traits and callable parameters receive bindings through | |
| `rs::FnRef` and `rs::Fn`: | |
| * **`rs::FnRef<Sig>`** (`support/rs_std/fn_ref.h`): | |
| Non-owning, borrowed view of a callable corresponding to `&dyn Fn` or `&mut | |
| dyn FnMut` (or generic `impl Fn` / `impl FnMut`). Does not allocate on the | |
| heap. | |
| * **`rs::Fn<Sig>`** (`support/rs_std/fn.h`): Owning, | |
| heap-allocated callable corresponding to `Box<dyn Fn>`, `Box<dyn FnMut>`, or | |
| `Box<dyn FnOnce>` (or generic `impl FnOnce + 'static`). `rs::Fn<Sig &&>` | |
| corresponds to `FnOnce` and must be invoked via `std::move(f)(...)`. | |
| * **`rs::DynCallable<Sig>`** | |
| (`support/rs_std/dyn_callable.h`): Move-only wrapper for | |
| Rust `Box<dyn Trait>` objects received in C++, implicitly convertible to | |
| `absl::AnyInvocable<Sig>`. | |
| See [Callbacks](http://crubit.rs/types/callbacks) for the complete guide and | |
| examples. | |
| ## `Box` | |
| The Rust `Box<T>`, `Pin<Box<T>>`, `Box<[T]>`, and `Box<str>` types receive C++ | |
| bindings as `rs::Box<T>`, `rs::PinBox<T>`, `rs::SliceBox<T>`, and `rs::StrBox`. | |
| See [Box types](../types/box.md) for more details. |