aboutsummaryrefslogtreecommitdiff
path: root/book/src/binding/box.md
blob: dc478999cab2a2f992b7464e4a7c68aa3594e0c5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
{{#title rust::Box<T> — Rust ♡ C++}}
# rust::Box\<T\>

### Public API:

```cpp,hidelines=...
// rust/cxx.h
...
...#include <type_traits>
...
...namespace rust {

template <typename T>
class Box final {
public:
  using element_type = T;
  using const_pointer =
      typename std::add_pointer<typename std::add_const<T>::type>::type;
  using pointer = typename std::add_pointer<T>::type;

  Box(Box &&) noexcept;
  ~Box() noexcept;

  explicit Box(const T &);
  explicit Box(T &&);

  Box &operator=(Box &&) noexcept;

  const T *operator->() const noexcept;
  const T &operator*() const noexcept;
  T *operator->() noexcept;
  T &operator*() noexcept;

  template <typename... Fields>
  static Box in_place(Fields &&...);

  void swap(Box &) noexcept;

  // Important: requires that `raw` came from an into_raw call. Do not
  // pass a pointer from `new` or any other source.
  static Box from_raw(T *) noexcept;

  T *into_raw() noexcept;
};
...
...} // namespace rust
```

### Restrictions:

Box\<T\> does not support T being an opaque C++ type. You should use
[UniquePtr\<T\>](uniqueptr.md) or [SharedPtr\<T\>](sharedptr.md) instead for
transferring ownership of opaque C++ types on the language boundary.

If T is an opaque Rust type, the Rust type is required to be [Sized] i.e. size
known at compile time. In the future we may introduce support for dynamically
sized opaque Rust types.

[Sized]: https://doc.rust-lang.org/std/marker/trait.Sized.html

## Example

This program uses a Box to pass ownership of some opaque piece of Rust state
over to C++ and then back to a Rust callback, which is a useful pattern for
implementing [async functions over FFI](../async.md).

```rust,noplayground
// src/main.rs

use std::io::Write;

#[cxx::bridge]
mod ffi {
    extern "Rust" {
        type File;
    }

    unsafe extern "C++" {
        include!("example/include/example.h");

        fn f(
            callback: fn(Box<File>, fst: &str, snd: &str),
            out: Box<File>,
        );
    }
}

pub struct File(std::fs::File);

fn main() {
    let out = std::fs::File::create("example.log").unwrap();

    ffi::f(
        |mut out, fst, snd| { let _ = write!(out.0, "{}{}\n", fst, snd); },
        Box::new(File(out)),
    );
}
```

```cpp
// include/example.h

#pragma once
#include "example/src/main.rs.h"
#include "rust/cxx.h"

void f(rust::Fn<void(rust::Box<File>, rust::Str, rust::Str)> callback,
       rust::Box<File> out);
```

```cpp
// include/example.cc

#include "example/include/example.h"

void f(rust::Fn<void(rust::Box<File>, rust::Str, rust::Str)> callback,
       rust::Box<File> out) {
  callback(std::move(out), "fearless", "concurrency");
}
```