blob: 682837ec77f94f42d0f787cd95109b254d9ded90 [file] [log] [blame] [view] [edit]
<!-- <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. -->