| <!-- <internal link> --> |
| |
| # Non-Rust-Movable Types |
| |
| WARNING: This is early documentation for an unreleased feature, only currently |
| available in `:wrapper` mode. The documentation is a WIP. |
| |
| Many, if not most, types in C++ are not Rust-movable. That is, you cannot |
| initialize them using `let x = y`, you cannot assign them using `x = y`, and you |
| cannot otherwise relocate the bits in memory, such as by `std::mem::swap`. |
| |
| In general, it's better to make these types Rust-movable. See [Rust-movable |
| classes](classes_and_structs.md#rust_movable) and [Making types |
| Rust-movable](cookbook.md#rust_movable). |
| |
| If the class cannot be made Rust-movable, then it will be given a less ergonomic |
| interface, using the `Ctor` trait. |
| |
| ## What is the `Ctor` trait? |
| |
| NOTE: The API documentation and source code is at |
| support/ctor.rs |
| |
| `Ctor<Output=T, Error=E>` is a trait for implementing **lazily evaluated |
| values**. These values are constructed in-place, in a C++-compatible way, and |
| pinned. |
| |
| However, `Ctor` is not a lazily-initialized value itself. It is a value |
| initialization procedure, which returns `T` upon success and `E` upon failure. |
| So a `Ctor` creates a value upon request, which is why we describe it as lazy. |
| |
| Since exceptions are disabled at Google, we currently only work with |
| `Error=Infallible`, and for exposition will omit the error type. |
| |
| Functions accepting and returning a non-Rust movable value in C++ will accept |
| and return an `impl Ctor` in Rust, as so: |
| |
| ```rust |
| pub fn accepts_value(x: impl Ctor<Output=CppType, ...>) {...} |
| pub fn returns() -> impl Ctor<Output=CppType, ...> {...} |
| ``` |
| |
| The easiest way to work with these types in Rust is to box them into a |
| `Pin<Box<T>>` using `Box::emplace()`. Then they can be passed by value using |
| `mov!(x)` (similar to `std::move` in C++), and by mutable reference using |
| `.as_mut()`. For example: |
| |
| ```rust |
| use ctor::{Emplace, mov}; // gives Box::emplace and mov!(). |
| let mut x /* : Pin<Box<T>> */ = Box::emplace(returns()); |
| |
| takes_mutable_reference(x.as_mut()); |
| takes_const_reference(&x); |
| |
| accepts_value(mov!(x)); |
| ``` |
| |
| NOTE: The call to `returns()` does not construct a value of type `CppType`, it |
| merely returns a `Ctor<Output=CppType>`, which is a procedure to lazily create |
| such a value. A `CppType` is created only when the `Ctor` is executed as part of |
| the `Box::emplace(...)` expression in the caller. |
| |
| If you happen to be *directly* passing a return value into a parameter, you can |
| avoid the intermediate boxed value: |
| |
| ```rust |
| accepts(returns()); |
| ``` |
| |
| If you want to avoid heap allocations in general, you will need to use the more |
| advanced features of `ctor.rs`. |
| |
| <!-- TODO(b/432107690): Move advanced docs to a sibling file. --> |