Skip to content

Commit 123f70a

Browse files
authored
Merge pull request #482 from dtolnay/book
Book content
2 parents f47403f + 7a39745 commit 123f70a

30 files changed

+3578
-2
lines changed

book/book.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,7 @@ cname = "cxx.rs"
1616
git-repository-url = "https://github.com/dtolnay/cxx"
1717
playground = { copyable = false }
1818
print = { enable = false }
19+
20+
[output.html.redirect]
21+
"binding/index.html" = "../bindings.html"
22+
"build/index.html" = "../building.html"

book/src/SUMMARY.md

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,35 @@
11
# Summary
22

3-
[Rust ❤️ C++](about.md)
3+
- [Rust ❤️ C++](index.md)
4+
5+
- [Core concepts](concepts.md)
6+
7+
- [Tutorial](tutorial.md)
8+
9+
- [Other Rust–C++ interop tools](context.md)
10+
11+
- [Multi-language build system options](building.md)
12+
- [Cargo](build/cargo.md)
13+
- [Bazel](build/bazel.md)
14+
- [CMake](build/cmake.md)
15+
- [More...](build/other.md)
16+
17+
- [Reference: the bridge module](reference.md)
18+
- [extern "Rust"](extern-rust.md)
19+
- [extern "C++"](extern-c++.md)
20+
- [Shared types](shared.md)
21+
- [Attributes](attributes.md)
22+
- [Async functions](async.md)
23+
- [Error handling](binding/result.md)
24+
25+
- [Reference: built-in bindings](bindings.md)
26+
- [String — rust::String](binding/string.md)
27+
- [&str — rust::Str](binding/str.md)
28+
- [&&#91;T&#93; &mdash; rust::Slice\<const T\>](binding/slice.md)
29+
- [CxxString &mdash; std::string](binding/cxxstring.md)
30+
- [Box\<T\> &mdash; rust::Box\<T\>](binding/box.md)
31+
- [UniquePtr\<T\> &mdash; std::unique\_ptr\<T\>](binding/uniqueptr.md)
32+
- [Vec\<T\> &mdash; rust::Vec\<T\>](binding/vec.md)
33+
- [CxxVector\<T\> &mdash; std::vector\<T\>](binding/cxxvector.md)
34+
- [Function pointers](binding/fn.md)
35+
- [Result\<T\>](binding/result.md)

book/src/about.md

Lines changed: 0 additions & 1 deletion
This file was deleted.

book/src/async.md

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
{{#title Async functions — Rust ♡ C++}}
2+
# Async functions
3+
4+
Direct FFI of async functions is absolutely in scope for CXX (on C++20 and up)
5+
but is not implemented yet in the current release. We are aiming for an
6+
implementation that is as easy as:
7+
8+
```rust,noplayground
9+
#[cxx::bridge]
10+
mod ffi {
11+
unsafe extern "C++" {
12+
async fn doThing(arg: Arg) -> Ret;
13+
}
14+
}
15+
```
16+
17+
```cpp,hidelines
18+
rust::Future<Ret> doThing(Arg arg) {
19+
auto v1 = co_await f();
20+
auto v2 = co_await g(arg);
21+
co_return v1 + v2;
22+
}
23+
```
24+
25+
## Workaround
26+
27+
For now the recommended approach is to handle the return codepath over a oneshot
28+
channel (such as [`futures::channel::oneshot`]) represented in an opaque Rust
29+
type on the FFI.
30+
31+
[`futures::channel::oneshot`]: https://docs.rs/futures/0.3.8/futures/channel/oneshot/index.html
32+
33+
```rust,noplayground
34+
// bridge.rs
35+
36+
use futures::channel::oneshot;
37+
38+
#[cxx::bridge]
39+
mod ffi {
40+
extern "Rust" {
41+
type DoThingContext;
42+
}
43+
44+
unsafe extern "C++" {
45+
include!("path/to/bridge_shim.h");
46+
47+
fn shim_doThing(
48+
arg: Arg,
49+
done: fn(Box<DoThingContext>, ret: Ret),
50+
ctx: Box<DoThingContext>,
51+
);
52+
}
53+
}
54+
55+
struct DoThingContext(oneshot::Sender<Ret>);
56+
57+
pub async fn do_thing(arg: Arg) -> Ret {
58+
let (tx, rx) = oneshot::channel();
59+
let context = Box::new(DoThingContext(tx));
60+
61+
ffi::shim_doThing(
62+
arg,
63+
|tx, ret| { let _ = tx.0.send(ret); },
64+
context,
65+
);
66+
67+
rx.await.unwrap()
68+
}
69+
```
70+
71+
```cpp
72+
// bridge_shim.cc
73+
74+
#include "path/to/bridge.rs.h"
75+
#include "rust/cxx.h"
76+
77+
void shim_doThing(
78+
Arg arg,
79+
rust::Fn<void(rust::Box<DoThingContext> ctx, Ret ret)> done,
80+
rust::Box<DoThingContext> ctx) noexcept {
81+
doThing(arg)
82+
.then([done, ctx(std::move(ctx))](auto &&res) mutable {
83+
(*done)(std::move(ctx), std::move(res));
84+
});
85+
}
86+
```

book/src/attributes.md

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
{{#title Attributes — Rust ♡ C++}}
2+
# Attributes
3+
4+
## namespace
5+
6+
The top-level cxx::bridge attribute macro takes an optional `namespace` argument
7+
to control the C++ namespace into which to emit extern Rust items and the
8+
namespace in which to expect to find the extern C++ items.
9+
10+
```rust,noplayground
11+
#[cxx::bridge(namespace = "path::of::my::company")]
12+
mod ffi {
13+
extern "Rust" {
14+
type MyType; // emitted to path::of::my::company::MyType
15+
}
16+
17+
extern "C++" {
18+
type TheirType; // refers to path::of::my::company::TheirType
19+
}
20+
}
21+
```
22+
23+
Additionally, a `#[namespace = "..."]` attribute may be used inside the bridge
24+
module on any extern block or individual item. An item will inherit the
25+
namespace specified on its surrounding extern block if any, otherwise the
26+
namespace specified with the top level cxx::bridge attribute if any, otherwise
27+
the global namespace.
28+
29+
```rust,noplayground
30+
#[cxx::bridge(namespace = "third_priority")]
31+
mod ffi {
32+
#[namespace = "second_priority"]
33+
extern "Rust" {
34+
fn f();
35+
36+
#[namespace = "first_priority"]
37+
fn g();
38+
}
39+
40+
extern "Rust" {
41+
fn h();
42+
}
43+
}
44+
```
45+
46+
The above would result in functions `::second_priority::f`,
47+
`::first_priority::g`, `::third_priority::h`.
48+
49+
## rust\_name, cxx\_name
50+
51+
Sometimes you want the Rust name of a function to differ from its C++ name.
52+
Importantly, this enables binding multiple overloads of the same C++ function
53+
name using distinct Rust names.
54+
55+
```rust,noplayground
56+
#[cxx::bridge]
57+
mod ffi {
58+
unsafe extern "C++" {
59+
#[rust_name = "i32_overloaded_function"]
60+
fn cOverloadedFunction(x: i32) -> String;
61+
#[rust_name = "str_overloaded_function"]
62+
fn cOverloadedFunction(x: &str) -> String;
63+
}
64+
}
65+
```
66+
67+
The `#[rust_name = "..."]` attribute replaces the name that Rust should use for
68+
this function, and an analogous `#[cxx_name = "..."]` attribute replaces the
69+
name that C++ should use.
70+
71+
Either of the two attributes may be used on extern "Rust" as well as extern
72+
"C++" functions, according to which one you find clearer in context.
73+
74+
Support for renaming type names and enum variants is not implemented yet.

book/src/binding/box.md

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
{{#title rust::Box<T> — Rust ♡ C++}}
2+
# rust::Box\<T\>
3+
4+
### Public API:
5+
6+
```cpp,hidelines
7+
// rust/cxx.h
8+
#
9+
# #include <type_traits>
10+
#
11+
# namespace rust {
12+
13+
template <typename T>
14+
class Box final {
15+
public:
16+
using value_type = T;
17+
using const_pointer =
18+
typename std::add_pointer<typename std::add_const<T>::type>::type;
19+
using pointer = typename std::add_pointer<T>::type;
20+
21+
Box(const Box &);
22+
Box(Box &&) noexcept;
23+
~Box() noexcept;
24+
25+
explicit Box(const T &);
26+
explicit Box(T &&);
27+
28+
Box &operator=(const Box &);
29+
Box &operator=(Box &&) noexcept;
30+
31+
const T *operator->() const noexcept;
32+
const T &operator*() const noexcept;
33+
T *operator->() noexcept;
34+
T &operator*() noexcept;
35+
36+
template <typename... Fields>
37+
static Box in_place(Fields &&...);
38+
39+
// Important: requires that `raw` came from an into_raw call. Do not
40+
// pass a pointer from `new` or any other source.
41+
static Box from_raw(T *) noexcept;
42+
43+
T *into_raw() noexcept;
44+
};
45+
#
46+
# } // namespace rust
47+
```
48+
49+
### Restrictions:
50+
51+
Box\<T\> does not support T being an opaque C++ type. You should use
52+
[UniquePtr\<T\>](uniqueptr.md) instead for transferring ownership of opaque C++
53+
types on the language boundary.
54+
55+
If T is an opaque Rust type, the Rust type is required to be [Sized] i.e. size
56+
known at compile time. In the future we may introduce support for dynamically
57+
sized opaque Rust types.
58+
59+
[Sized]: https://doc.rust-lang.org/std/marker/trait.Sized.html
60+
61+
## Example
62+
63+
This program uses a Box to pass ownership of some opaque piece of Rust state
64+
over to C++ and then back to a Rust callback, which is a useful pattern for
65+
implementing [async functions over FFI](../async.md).
66+
67+
```rust,noplayground
68+
// src/main.rs
69+
70+
use std::io::Write;
71+
72+
#[cxx::bridge]
73+
mod ffi {
74+
extern "Rust" {
75+
type File;
76+
}
77+
78+
unsafe extern "C++" {
79+
include!("example/include/example.h");
80+
81+
fn f(
82+
callback: fn(Box<File>, fst: &str, snd: &str),
83+
out: Box<File>,
84+
);
85+
}
86+
}
87+
88+
pub struct File(std::fs::File);
89+
90+
fn main() {
91+
let out = std::fs::File::create("example.log").unwrap();
92+
93+
ffi::f(
94+
|mut out, fst, snd| { let _ = write!(out.0, "{}{}\n", fst, snd); },
95+
Box::new(File(out)),
96+
);
97+
}
98+
```
99+
100+
```cpp
101+
// include/example.h
102+
103+
#pragma once
104+
#include "example/src/main.rs.h"
105+
#include "rust/cxx.h"
106+
107+
void f(rust::Fn<void(rust::Box<File>, rust::Str, rust::Str)> callback,
108+
rust::Box<File> out);
109+
```
110+
111+
```cpp
112+
// include/example.cc
113+
114+
#include "example/include/example.h"
115+
116+
void f(rust::Fn<void(rust::Box<File>, rust::Str, rust::Str)> callback,
117+
rust::Box<File> out) {
118+
callback(std::move(out), "fearless", "concurrency");
119+
}
120+
```

0 commit comments

Comments
 (0)