Repository: dtolnay/cxx (language: rust)

Issue:
Initial commit of book content.
Start of a book, working towards #179.

@dtolnay I'm sure you'll have a ton of edits you'll want to do here, but I hope it's a good start.


Discussion / hints:

Fix patch:
diff --git a/book/book.toml b/book/book.toml
index 0644e056b..066f3a627 100644
--- a/book/book.toml
+++ b/book/book.toml
@@ -16,3 +16,7 @@ cname = "cxx.rs"
 git-repository-url = "https://github.com/dtolnay/cxx"
 playground = { copyable = false }
 print = { enable = false }
+
+[output.html.redirect]
+"binding/index.html" = "../bindings.html"
+"build/index.html" = "../building.html"
diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md
index f3fa924ff..31cbb4624 100644
--- a/book/src/SUMMARY.md
+++ b/book/src/SUMMARY.md
@@ -1,3 +1,35 @@
 # Summary
 
-[Rust ❤️ C++](about.md)
+- [Rust ❤️ C++](index.md)
+
+- [Core concepts](concepts.md)
+
+- [Tutorial](tutorial.md)
+
+- [Other Rust&ndash;C++ interop tools](context.md)
+
+- [Multi-language build system options](building.md)
+    - [Cargo](build/cargo.md)
+    - [Bazel](build/bazel.md)
+    - [CMake](build/cmake.md)
+    - [More...](build/other.md)
+
+- [Reference: the bridge module](reference.md)
+    - [extern "Rust"](extern-rust.md)
+    - [extern "C++"](extern-c++.md)
+    - [Shared types](shared.md)
+    - [Attributes](attributes.md)
+    - [Async functions](async.md)
+    - [Error handling](binding/result.md)
+
+- [Reference: built-in bindings](bindings.md)
+    - [String &mdash; rust::String](binding/string.md)
+    - [&str &mdash; rust::Str](binding/str.md)
+    - [&&#91;T&#93; &mdash; rust::Slice\<const T\>](binding/slice.md)
+    - [CxxString &mdash; std::string](binding/cxxstring.md)
+    - [Box\<T\> &mdash; rust::Box\<T\>](binding/box.md)
+    - [UniquePtr\<T\> &mdash; std::unique\_ptr\<T\>](binding/uniqueptr.md)
+    - [Vec\<T\> &mdash; rust::Vec\<T\>](binding/vec.md)
+    - [CxxVector\<T\> &mdash; std::vector\<T\>](binding/cxxvector.md)
+    - [Function pointers](binding/fn.md)
+    - [Result\<T\>](binding/result.md)
diff --git a/book/src/about.md b/book/src/about.md
deleted file mode 100644
index 6e63bf5ea..000000000
--- a/book/src/about.md
+++ /dev/null
@@ -1,1 +0,0 @@
-### Coming soon
diff --git a/book/src/async.md b/book/src/async.md
new file mode 100644
index 000000000..7574a22c4
--- /dev/null
+++ b/book/src/async.md
@@ -0,0 +1,86 @@
+{{#title Async functions — Rust ♡ C++}}
+# Async functions
+
+Direct FFI of async functions is absolutely in scope for CXX (on C++20 and up)
+but is not implemented yet in the current release. We are aiming for an
+implementation that is as easy as:
+
+```rust,noplayground
+#[cxx::bridge]
+mod ffi {
+    unsafe extern "C++" {
+        async fn doThing(arg: Arg) -> Ret;
+    }
+}
+```
+
+```cpp,hidelines
+rust::Future<Ret> doThing(Arg arg) {
+  auto v1 = co_await f();
+  auto v2 = co_await g(arg);
+  co_return v1 + v2;
+}
+```
+
+## Workaround
+
+For now the recommended approach is to handle the return codepath over a oneshot
+channel (such as [`futures::channel::oneshot`]) represented in an opaque Rust
+type on the FFI.
+
+[`futures::channel::oneshot`]: https://docs.rs/futures/0.3.8/futures/channel/oneshot/index.html
+
+```rust,noplayground
+// bridge.rs
+
+use futures::channel::oneshot;
+
+#[cxx::bridge]
+mod ffi {
+    extern "Rust" {
+        type DoThingContext;
+    }
+
+    unsafe extern "C++" {
+        include!("path/to/bridge_shim.h");
+
+        fn shim_doThing(
+            arg: Arg,
+            done: fn(Box<DoThingContext>, ret: Ret),
+            ctx: Box<DoThingContext>,
+        );
+    }
+}
+
+struct DoThingContext(oneshot::Sender<Ret>);
+
+pub async fn do_thing(arg: Arg) -> Ret {
+    let (tx, rx) = oneshot::channel();
+    let context = Box::new(DoThingContext(tx));
+
+    ffi::shim_doThing(
+        arg,
+        |tx, ret| { let _ = tx.0.send(ret); },
+        context,
+    );
+
+    rx.await.unwrap()
+}
+```
+
+```cpp
+// bridge_shim.cc
+
+#include "path/to/bridge.rs.h"
+#include "rust/cxx.h"
+
+void shim_doThing(
+    Arg arg,
+    rust::Fn<void(rust::Box<DoThingContext> ctx, Ret ret)> done,
+    rust::Box<DoThingContext> ctx) noexcept {
+  doThing(arg)
+      .then([done, ctx(std::move(ctx))](auto &&res) mutable {
+        (*done)(std::move(ctx), std::move(res));
+      });
+}
+```
diff --git a/book/src/attributes.md b/book/src/attributes.md
new file mode 100644
index 000000000..b41515af1
--- /dev/null
+++ b/book/src/attributes.md
@@ -0,0 +1,74 @@
+{{#title Attributes — Rust ♡ C++}}
+# Attributes
+
+## namespace
+
+The top-level cxx::bridge attribute macro takes an optional `namespace` argument
+to control the C++ namespace into which to emit extern Rust items and the
+namespace in which to expect to find the extern C++ items.
+
+```rust,noplayground
+#[cxx::bridge(namespace = "path::of::my::company")]
+mod ffi {
+    extern "Rust" {
+        type MyType;  // emitted to path::of::my::company::MyType
+    }
+
+    extern "C++" {
+        type TheirType;  // refers to path::of::my::company::TheirType
+    }
+}
+```
+
+Additionally, a `#[namespace = "..."]` attribute may be used inside the bridge
+module on any extern block or individual item. An item will inherit the
+namespace specified on its surrounding extern block if any, otherwise the
+namespace specified with the top level cxx::bridge attribute if any, otherwise
+the global namespace.
+
+```rust,noplayground
+#[cxx::bridge(namespace = "third_priority")]
+mod ffi {
+    #[namespace = "second_priority"]
+    extern "Rust" {
+        fn f();
+
+        #[namespace = "first_priority"]
+        fn g();
+    }
+
+    extern "Rust" {
+        fn h();
+    }
+}
+```
+
+The above would result in functions `::second_priority::f`,
+`::first_priority::g`, `::third_priority::h`.
+
+## rust\_name, cxx\_name
+
+Sometimes you want the Rust name of a function to differ from its C++ name.
+Importantly, this enables binding multiple overloads of the same C++ function
+name using distinct Rust names.
+
+```rust,noplayground
+#[cxx::bridge]
+mod ffi {
+    unsafe extern "C++" {
+        #[rust_name = "i32_overloaded_function"]
+        fn cOverloadedFunction(x: i32) -> String;
+        #[rust_name = "str_overloaded_function"]
+        fn cOverloadedFunction(x: &str) -> String;
+    }
+}
+```
+
+The `#[rust_name = "..."]` attribute replaces the name that Rust should use for
+this function, and an analogous `#[cxx_name = "..."]` attribute replaces the
+name that C++ should use.
+
+Either of the two attributes may be used on extern "Rust" as well as extern
+"C++" functions, according to which one you find clearer in context.
+
+Support for renaming type names and enum variants is not implemented yet.
diff --git a/book/src/binding/box.md b/book/src/binding/box.md
new file mode 100644
index 000000000..8bcae588e
--- /dev/null
+++ b/book/src/binding/box.md
@@ -0,0 +1,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 value_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(const Box &);
+  Box(Box &&) noexcept;
+  ~Box() noexcept;
+
+  explicit Box(const T &);
+  explicit Box(T &&);
+
+  Box &operator=(const Box &);
+  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 &&...);
+
+  // 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) 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");
+}
+```
diff --git a/book/src/binding/cxxstring.md b/book/src/binding/cxxstring.md
new file mode 100644
index 000000000..0a643c200
--- /dev/null
+++ b/book/src/binding/cxxstring.md
@@ -0,0 +1,137 @@
+{{#title std::string — Rust ♡ C++}}
+# std::string
+
+The Rust binding of std::string is called **[`CxxString`]**. See the link for
+documentation of the Rust API.
+
+[`CxxString`]: https://docs.rs/cxx/*/cxx/struct.CxxString.html
+
+### Restrictions:
+
+Rust code can never obtain a CxxString by value. C++'s string requires a move
+constructor and may hold internal pointers, which is not compatible with Rust's
+move behavior. Instead in Rust code we will only ever look at a CxxString
+through a reference or smart pointer, as in &CxxString or Pin\<&mut CxxString\>
+or UniquePtr\<CxxString\>.
+
+In order to construct a CxxString on the stack from Rust, you must use the
+[`let_cxx_string!`] macro which will pin the string properly. The code below
+uses this in one place, and the link covers the syntax.
+
+[`let_cxx_string!`]: https://docs.rs/cxx/*/cxx/macro.let_cxx_string.html
+
+## Example
+
+This example uses C++17's std::variant to build a toy JSON type. JSON can hold
+various types including strings, and JSON's object type is a map with string
+keys. The example demonstrates Rust indexing into one of those maps.
+
+```rust,noplayground
+// src/main.rs
+
+use cxx::let_cxx_string;
+
+#[cxx::bridge]
+mod ffi {
+    unsafe extern "C++" {
+        include!("example/include/json.h");
+
+        type json;
+        type object;
+
+        fn isNull(self: &json) -> bool;
+        fn isNumber(self: &json) -> bool;
+        fn isString(self: &json) -> bool;
+        fn isArray(self: &json) -> bool;
+        fn isObject(self: &json) -> bool;
+
+        fn getNumber(self: &json) -> f64;
+        fn getString(self: &json) -> &CxxString;
+        fn getArray(self: &json) -> &CxxVector<json>;
+        fn getObject(self: &json) -> &object;
+
+        #[cxx_name = "at"]  // https://en.cppreference.com/w/cpp/container/map/at
+        fn get<'a>(self: &'a object, key: &CxxString) -> &'a json;
+
+        fn load_config() -> UniquePtr<json>;
+    }
+}
+
+fn main() {
+    let config = ffi::load_config();
+
+    let_cxx_string!(key = "name");
+    println!("{}", config.getObject().get(&key).getString());
+}
+```
+
+```cpp
+// include/json.h
+
+#pragma once
+#include <map>
+#include <memory>
+#include <variant>
+#include <vector>
+
+class json final {
+public:
+  static const json null;
+  using number = double;
+  using string = std::string;
+  using array = std::vector<json>;
+  using object = std::map<string, json>;
+
+  json() noexcept = default;
+  json(const json &) = default;
+  json(json &&) = default;
+  template <typename... T>
+  json(T &&... value) : value(std::forward<T>(value)...) {}
+
+  bool isNull() const;
+  bool isNumber() const;
+  bool isString() const;
+  bool isArray() const;
+  bool isObject() const;
+
+  number getNumber() const;
+  const string &getString() const;
+  const array &getArray() const;
+  const object &getObject() const;
+
+private:
+  std::variant<std::monostate, number, string, array, object> value;
+};
+
+using object = json::object;
+
+std::unique_ptr<json> load_config();
+```
+
+```cpp
+// include/json.cc
+
+#include "example/include/json.h"
+#include <initializer_list>
+#include <utility>
+
+const json json::null{};
+bool json::isNull() const { return std::holds_alternative<std::monostate>(value); }
+bool json::isNumber() const { return std::holds_alternative<number>(value); }
+bool json::isString() const { return std::holds_alternative<string>(value); }
+bool json::isArray() const { return std::holds_alternative<array>(value); }
+bool json::isObject() const { return std::holds_alternative<object>(value); }
+json::number json::getNumber() const { return std::get<number>(value); }
+const json::string &json::getString() const { return std::get<string>(value); }
+const json::array &json::getArray() const { return std::get<array>(value); }
+const json::object &json::getObject() const { return std::get<object>(value); }
+
+std::unique_ptr<json> load_config() {
+  return std::make_unique<json>(
+      std::in_place_type<json::object>,
+      std::initializer_list<std::pair<const std::string, json>>{
+          {"name", "cxx-example"},
+          {"edition", 2018.},
+          {"repository", json::null}});
+}
+```
diff --git a/book/src/binding/cxxvector.md b/book/src/binding/cxxvector.md
new file mode 100644
index 000000000..fd95a2dbd
--- /dev/null
+++ b/book/src/binding/cxxvector.md
@@ -0,0 +1,62 @@
+{{#title std::vector<T> — Rust ♡ C++}}
+# std::vector\<T\>
+
+The Rust binding of std::vector\<T\> is called **[`CxxVector<T>`]**. See the
+link for documentation of the Rust API.
+
+[`CxxVector<T>`]: https://docs.rs/cxx/*/cxx/struct.CxxVector.html
+
+### Restrictions:
+
+Rust code can never obtain a CxxVector by value. Instead in Rust code we will
+only ever look at a vector behind a reference or smart pointer, as in
+&CxxVector\<T\> or UniquePtr\<CxxVector\<T\>\>.
+
+CxxVector\<T\> does not support T being an opaque Rust type. You should use a
+Vec\<T\> (C++ rust::Vec\<T\>) instead for collections of opaque Rust types on
+the language boundary.
+
+## Example
+
+This program involves Rust code converting a `CxxVector<CxxString>` (i.e.
+`std::vector<std::string>`) into a Rust `Vec<String>`.
+
+```rust,noplayground
+// src/main.rs
+
+#![no_main] // main defined in C++ by main.cc
+
+use cxx::{CxxString, CxxVector};
+
+#[cxx::bridge]
+mod ffi {
+    extern "Rust" {
+        fn f(vec: &CxxVector<CxxString>);
+    }
+}
+
+fn f(vec: &CxxVector<CxxString>) {
+    let vec: Vec<String> = vec
+        .iter()
+        .map(|s| s.to_string_lossy().into_owned())
+        .collect();
+    g(&vec);
+}
+
+fn g(vec: &[String]) {
+    println!("{:?}", vec);
+}
+```
+
+```cpp
+// src/main.cc
+
+#include "example/src/main.rs.h"
+#include <string>
+#include <vector>
+
+int main() {
+  std::vector<std::string> vec{"fearless", "concurrency"};
+  f(vec);
+}
+```
diff --git a/book/src/binding/fn.md b/book/src/binding/fn.md
new file mode 100644
index 000000000..2934b0695
--- /dev/null
+++ b/book/src/binding/fn.md
@@ -0,0 +1,34 @@
+{{#title Function pointers — Rust ♡ C++}}
+# Function pointers
+
+### Public API:
+
+```cpp,hidelines
+// rust/cxx.h
+#
+# namespace rust {
+
+template <typename Signature>
+class Fn;
+
+template <typename Ret, typename... Args>
+class Fn<Ret(Args...)> final {
+public:
+  Ret operator()(Args... args) const noexcept;
+  Fn operator*() const noexcept;
+};
+#
+# } // namespace rust
+```
+
+### Restrictions:
+
+Function pointers with a Result return type are not implemented yet.
+
+Passing a function pointer from C++ to Rust is not implemented yet, only from
+Rust to an `extern "C++"` function is implemented.
+
+## Example
+
+Function pointers are commonly useful for implementing [async functions over
+FFI](../async.md). See the example code on that page.
diff --git a/book/src/binding/result.md b/book/src/binding/result.md
new file mode 100644
index 000000000..e49dcf4de
--- /dev/null
+++ b/book/src/binding/result.md
@@ -0,0 +1,148 @@
+{{#title Result<T> — Rust ♡ C++}}
+# Result\<T\>
+
+Result\<T\> is allowed as the return type of an extern function in either
+direction. Its behavior is to translate to/from C++ exceptions. If your codebase
+does not use C++ exceptions, or prefers to represent fallibility using something
+like outcome\<T\>, leaf::result\<T\>, StatusOr\<T\>, etc then you'll need to
+handle the translation of those to Rust Result\<T\> using your own shims for
+now. Better support for this is planned.
+
+If an exception is thrown from an `extern "C++"` function that is *not* declared
+by the CXX bridge to return Result, the program calls C++'s `std::terminate`.
+The behavior is equivalent to the same exception being thrown through a
+`noexcept` C++ function.
+
+If a panic occurs in *any* `extern "Rust"` function, regardless of whether it is
+declared by the CXX bridge to return Result, a message is logged and the program
+calls Rust's `std::process::abort`.
+
+## Returning Result from Rust to C++
+
+An `extern "Rust"` function returning a Result turns into a `throw` in C++ if
+the Rust side produces an error.
+
+Note that the return type written inside of cxx::bridge must be written without
+a second type parameter. Only the Ok type is specified for the purpose of the
+FFI. The Rust *implementation* (outside of the bridge module) may pick any error
+type as long as it has a std::fmt::Display impl.
+
+```rust,noplayground
+# use std::io;
+#
+#[cxx::bridge]
+mod ffi {
+    extern "Rust" {
+        fn fallible1(depth: usize) -> Result<String>;
+        fn fallible2() -> Result<()>;
+    }
+}
+
+fn fallible1(depth: usize) -> anyhow::Result<String> {
+    if depth == 0 {
+        return Err(anyhow::Error::msg("fallible1 requires depth > 0"));
+    }
+    ...
+}
+
+fn fallible2() -> Result<(), io::Error> {
+    ...
+    Ok(())
+}
+```
+
+The exception that gets thrown by CXX on the C++ side is always of type
+`rust::Error` and has the following C++ public API. The `what()` member function
+gives the error message according to the Rust error's std::fmt::Display impl.
+
+```cpp,hidelines
+// rust/cxx.h
+#
+# namespace rust {
+
+class Error final : public std::exception {
+public:
+  Error(const Error &);
+  Error(Error &&) noexcept;
+  ~Error() noexcept;
+
+  Error &operator=(const Error &);
+  Error &operator=(Error &&) noexcept;
+
+  const char *what() const noexcept override;
+};
+#
+# } // namespace rust
+```
+
+## Returning Result from C++ to Rust
+
+An `extern "C++"` function returning a Result turns into a `catch` in C++ that
+converts the exception into an Err for Rust.
+
+Note that the return type written inside of cxx::bridge must be written without
+a second type parameter. Only the Ok type is specified for the purpose of the
+FFI. The resulting error type created by CXX when an `extern "C++"` function
+throws will always be of type **[`cxx::Exception`]**.
+
+[`cxx::Exception`]: https://docs.rs/cxx/*/cxx/struct.Exception.html
+
+```rust,noplayground
+# use std::process;
+#
+#[cxx::bridge]
+mod ffi {
+    unsafe extern "C++" {
+        include!("example/include/example.h");
+        fn fallible1(depth: usize) -> Result<String>;
+        fn fallible2() -> Result<()>;
+    }
+}
+
+fn main() {
+    if let Err(err) = ffi::fallible1(99) {
+        eprintln!("Error: {}", err);
+        process::exit(1);
+    }
+}
+```
+
+The specific set of caught exceptions and the conversion to error message are
+both customizable. The way you do this is by defining a template function
+`rust::behavior::trycatch` with a suitable signature inside any one of the
+headers `include!`'d by your cxx::bridge.
+
+The template signature is required to be:
+
+```cpp,hidelines
+namespace rust {
+namespace behavior {
+
+template <typename Try, typename Fail>
+static void trycatch(Try &&func, Fail &&fail) noexcept;
+
+} // namespace behavior
+} // namespace rust
+```
+
+The default `trycatch` used by CXX if you have not provided your own is the
+following. You must follow the same pattern: invoke `func` with no arguments,
+catch whatever exception(s) you want, and invoke `fail` with the error message
+you'd like for the Rust error to have.
+
+```cpp,hidelines
+# #include <exception>
+#
+# namespace rust {
+# namespace behavior {
+#
+template <typename Try, typename Fail>
+static void trycatch(Try &&func, Fail &&fail) noexcept try {
+  func();
+} catch (const std::exception &e) {
+  fail(e.what());
+}
+#
+# } // namespace behavior
+# } // namespace rust
+```
diff --git a/book/src/binding/slice.md b/book/src/binding/slice.md
new file mode 100644
index 000000000..aacd56b2b
--- /dev/null
+++ b/book/src/binding/slice.md
@@ -0,0 +1,115 @@
+{{#title rust::Slice<T> — Rust ♡ C++}}
+# rust::Slice\<T\>
+
+### Public API:
+
+```cpp,hidelines
+// rust/cxx.h
+#
+# namespace rust {
+
+template <typename T>
+class Slice final {
+public:
+  Slice() noexcept;
+  Slice(const Slice<T> &) noexcept;
+  Slice(T *, size_t count) noexcept;
+
+  Slice &operator=(const Slice<T> &) noexcept;
+
+  T *data() const noexcept;
+  size_t size() const noexcept;
+  size_t length() const noexcept;
+};
+#
+# } // namespace rust
+```
+
+### Restrictions:
+
+Only &amp;\[u8\] i.e. rust::Slice\<const uint8\_t\> is currently implemented.
+Support for arbitrary &amp;\[T\] is coming.
+
+Allowed as function argument or return value. Not supported in shared structs.
+&amp;mut \[T\] is not supported yet.
+
+## Example
+
+This example is a C++ program that constructs a slice containing JSON data (by
+reading from stdin, but it could be from anywhere), then calls into Rust to
+pretty-print that JSON data into a std::string via the [serde_json] and
+[serde_transcode] crates.
+
+[serde_json]: https://github.com/serde-rs/json
+[serde_transcode]: https://github.com/sfackler/serde-transcode
+
+```rust,noplayground
+// src/main.rs
+
+#![no_main] // main defined in C++ by main.cc
+
+use cxx::CxxString;
+use std::io::{self, Write};
+use std::pin::Pin;
+
+#[cxx::bridge]
+mod ffi {
+    extern "Rust" {
+        fn prettify_json(input: &[u8], output: Pin<&mut CxxString>) -> Result<()>;
+    }
+}
+
+struct WriteToCxxString<'a>(Pin<&'a mut CxxString>);
+
+impl<'a> Write for WriteToCxxString<'a> {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        self.0.as_mut().push_bytes(buf);
+        Ok(buf.len())
+    }
+    fn flush(&mut self) -> io::Result<()> {
+        Ok(())
+    }
+}
+
+fn prettify_json(input: &[u8], output: Pin<&mut CxxString>) -> serde_json::Result<()> {
+    let writer = WriteToCxxString(output);
+    let mut deserializer = serde_json::Deserializer::from_slice(input);
+    let mut serializer = serde_json::Serializer::pretty(writer);
+    serde_transcode::transcode(&mut deserializer, &mut serializer)
+}
+```
+
+```cpp
+// src/main.cc
+
+#include "example/src/main.rs.h"
+#include <iostream>
+#include <iterator>
+#include <string>
+#include <vector>
+
+int main() {
+  // Read json from stdin.
+  std::istreambuf_iterator<char> begin{std::cin}, end;
+  std::vector<unsigned char> input{begin, end};
+  rust::Slice<const uint8_t> slice{input.data(), input.size()};
+
+  // Prettify using serde_json and serde_transcode.
+  std::string output;
+  prettify_json(slice, output);
+
+  // Write to stdout.
+  std::cout << output << std::endl;
+}
+```
+
+Testing the example:
+
+```console
+$  echo '{"fearless":"concurrency"}' | cargo run
+    Finished dev [unoptimized + debuginfo] target(s) in 0.02s
+     Running `target/debug/example`
+{
+  "fearless": "concurrency"
+}
+```
diff --git a/book/src/binding/str.md b/book/src/binding/str.md
new file mode 100644
index 000000000..2774754cc
--- /dev/null
+++ b/book/src/binding/str.md
@@ -0,0 +1,101 @@
+{{#title rust::Str — Rust ♡ C++}}
+# rust::Str
+
+### Public API:
+
+```cpp,hidelines
+// rust/cxx.h
+#
+# #include <iosfwd>
+# #include <string>
+#
+# namespace rust {
+
+class Str final {
+public:
+  Str() noexcept;
+  Str(const Str &) noexcept;
+
+  // Throws std::invalid_argument if not utf-8.
+  Str(const std::string &);
+  Str(const char *);
+  Str(const char *, size_t);
+  Str(std::string &&) = delete;
+
+  Str &operator=(const Str &) noexcept;
+
+  explicit operator std::string() const;
+
+  // Note: no null terminator.
+  const char *data() const noexcept;
+  size_t size() const noexcept;
+  size_t length() const noexcept;
+};
+
+std::ostream &operator<<(std::ostream &, const Str &);
+#
+# } // namespace rust
+```
+
+### Notes:
+
+**Be aware that rust::Str behaves like &amp;str i.e. it is a borrow!**&ensp;C++
+needs to be mindful of the lifetimes at play.
+
+Just to reiterate: &amp;str is rust::Str. Do not try to write &amp;str as `const
+rust::Str &`. A language-level C++ reference is not able to capture the fat
+pointer nature of &amp;str.
+
+### Restrictions:
+
+Allowed as function argument or return value. Not supported in shared structs
+yet. `&mut str` is not supported yet, but is also extremely obscure so this is
+fine.
+
+## Example
+
+```rust,noplayground
+// src/main.rs
+
+#[cxx::bridge]
+mod ffi {
+    extern "Rust" {
+        fn r(greeting: &str);
+    }
+
+    unsafe extern "C++" {
+        include!("example/include/greeting.h");
+        fn c(greeting: &str);
+    }
+}
+
+fn r(greeting: &str) {
+    println!("{}", greeting);
+}
+
+fn main() {
+    ffi::c("hello from Rust");
+}
+```
+
+```cpp
+// include/greeting.h
+
+#pragma once
+#include "example/src/main.rs.h"
+#include "rust/cxx.h"
+
+void c(rust::Str greeting);
+```
+
+```cpp
+// src/greeting.cc
+
+#include "example/include/greeting.h"
+#include <iostream>
+
+void c(rust::Str greeting) {
+  std::cout << greeting << std::endl;
+  r("hello from C++");
+}
+```
diff --git a/book/src/binding/string.md b/book/src/binding/string.md
new file mode 100644
index 000000000..ac44fb200
--- /dev/null
+++ b/book/src/binding/string.md
@@ -0,0 +1,94 @@
+{{#title rust::String — Rust ♡ C++}}
+# rust::String
+
+### Public API:
+
+```cpp,hidelines
+// rust/cxx.h
+#
+# #include <iosfwd>
+# #include <string>
+#
+# namespace rust {
+
+class String final {
+public:
+  String() noexcept;
+  String(const String &) noexcept;
+  String(String &&) noexcept;
+  ~String() noexcept;
+
+  // Throws std::invalid_argument if not utf-8.
+  String(const std::string &);
+  String(const char *);
+  String(const char *, size_t);
+
+  String &operator=(const String &) noexcept;
+  String &operator=(String &&) noexcept;
+
+  explicit operator std::string() const;
+
+  // Note: no null terminator.
+  const char *data() const noexcept;
+  size_t size() const noexcept;
+  size_t length() const noexcept;
+};
+
+std::ostream &operator<<(std::ostream &, const String &);
+#
+# } // namespace rust
+```
+
+### Restrictions:
+
+None. Strings may be used as function arguments and function return values, by
+value or by reference, as well as fields of shared structs.
+
+## Example
+
+```rust,noplayground
+// src/main.rs
+
+#[cxx::bridge]
+mod ffi {
+    struct ConcatRequest {
+        fst: String,
+        snd: String,
+    }
+
+    unsafe extern "C++" {
+        include!("example/include/concat.h");
+        fn concat(r: ConcatRequest) -> String;
+    }
+}
+
+fn main() {
+    let concatenated = ffi::concat(ffi::ConcatRequest {
+        fst: "fearless".to_owned(),
+        snd: "concurrency".to_owned(),
+    });
+    println!("concatenated: {:?}", concatenated);
+}
+```
+
+```cpp
+// include/concat.h
+
+#pragma once
+#include "example/src/main.rs.h"
+#include "rust/cxx.h"
+
+rust::String concat(ConcatRequest r);
+```
+
+```cpp
+// src/concat.cc
+
+#include "example/include/concat.h"
+
+rust::String concat(ConcatRequest r) {
+  // The full suite of operator overloads hasn't been added
+  // yet on rust::String, but we can get it done like this:
+  return std::string(r.fst) + std::string(r.snd);
+}
+```
diff --git a/book/src/binding/uniqueptr.md b/book/src/binding/uniqueptr.md
new file mode 100644
index 000000000..eefbc34a3
--- /dev/null
+++ b/book/src/binding/uniqueptr.md
@@ -0,0 +1,63 @@
+{{#title std::unique_ptr<T> — Rust ♡ C++}}
+# std::unique\_ptr\<T\>
+
+The Rust binding of std::unique\_ptr\<T\> is called **[`UniquePtr<T>`]**. See
+the link for documentation of the Rust API.
+
+[`UniquePtr<T>`]: https://docs.rs/cxx/*/cxx/struct.UniquePtr.html
+
+### Restrictions:
+
+Only `std::unique_ptr<T, std::default_delete<T>>` is currently supported. Custom
+deleters may be supported in the future.
+
+UniquePtr\<T\> does not support T being an opaque Rust type. You should use a
+Box\<T\> (C++ [rust::Box\<T\>](box.md)) instead for transferring ownership of
+opaque Rust types on the language boundary.
+
+## Example
+
+UniquePtr is commonly useful for returning opaque C++ objects to Rust. This use
+case was featured in the [*blobstore tutorial*](../tutorial.md).
+
+```rust,noplayground
+// src/main.rs
+
+#[cxx::bridge]
+mod ffi {
+    unsafe extern "C++" {
+        include!("example/include/blobstore.h");
+
+        type BlobstoreClient;
+
+        fn new_blobstore_client() -> UniquePtr<BlobstoreClient>;
+        // ...
+    }
+}
+
+fn main() {
+    let client = ffi::new_blobstore_client();
+    // ...
+}
+```
+
+```cpp
+// include/blobstore.h
+
+#pragma once
+#include <memory>
+
+class BlobstoreClient;
+
+std::unique_ptr<BlobstoreClient> new_blobstore_client();
+```
+
+```cpp
+// src/blobstore.cc
+
+#include "example/include/blobstore.h"
+
+std::unique_ptr<BlobstoreClient> new_blobstore_client() {
+  return std::make_unique<BlobstoreClient>();
+}
+```
diff --git a/book/src/binding/vec.md b/book/src/binding/vec.md
new file mode 100644
index 000000000..f3056fb0f
--- /dev/null
+++ b/book/src/binding/vec.md
@@ -0,0 +1,128 @@
+{{#title rust::Vec<T> — Rust ♡ C++}}
+# rust::Vec\<T\>
+
+### Public API:
+
+```cpp,hidelines
+// rust/cxx.h
+#
+# #include <iterator>
+# #include <type_traits>
+#
+# namespace rust {
+
+template <typename T>
+class Vec final {
+public:
+  using value_type = T;
+
+  Vec() noexcept;
+  Vec(Vec &&) noexcept;
+  ~Vec() noexcept;
+
+  Vec &operator=(Vec &&) noexcept;
+
+  size_t size() const noexcept;
+  bool empty() const noexcept;
+  const T *data() const noexcept;
+  T *data() noexcept;
+
+  const T &operator[](size_t n) const noexcept;
+  const T &at(size_t n) const;
+
+  const T &front() const;
+  const T &back() const;
+
+  void reserve(size_t new_cap);
+  void push_back(const T &value);
+  void push_back(T &&value);
+  template <typename... Args>
+  void emplace_back(Args &&... args);
+
+  class const_iterator final {
+  public:
+    using difference_type = ptrdiff_t;
+    using value_type = typename std::add_const<T>::type;
+    using pointer =
+        typename std::add_pointer<typename std::add_const<T>::type>::type;
+    using reference = typename std::add_lvalue_reference<
+        typename std::add_const<T>::type>::type;
+    using iterator_category = std::forward_iterator_tag;
+
+    const T &operator*() const noexcept;
+    const T *operator->() const noexcept;
+    const_iterator &operator++() noexcept;
+    const_iterator operator++(int) noexcept;
+    bool operator==(const const_iterator &) const noexcept;
+    bool operator!=(const const_iterator &) const noexcept;
+  };
+
+  const_iterator begin() const noexcept;
+  const_iterator end() const noexcept;
+};
+#
+# } // namespace rust
+```
+
+### Restrictions:
+
+Vec\<T\> does not support T being an opaque C++ type. You should use
+CxxVector\<T\> (C++ std::vector\<T\>) instead for collections of opaque C++
+types on the language boundary.
+
+## Example
+
+```rust,noplayground
+// src/main.rs
+
+#[cxx::bridge]
+mod ffi {
+    struct Shared {
+        v: u32,
+    }
+
+    unsafe extern "C++" {
+        include!("example/include/example.h");
+
+        fn f(elements: Vec<Shared>);
+    }
+}
+
+fn main() {
+    let shared = |v| ffi::Shared { v };
+    let elements = vec![shared(3), shared(2), shared(1)];
+    ffi::f(elements);
+}
+```
+
+```cpp
+// include/example.h
+
+#pragma once
+#include "example/src/main.rs.h"
+#include "rust/cxx.h"
+
+void f(rust::Vec<Shared> elements);
+```
+
+```cpp
+// src/example.cc
+
+#include "example/include/example.h"
+#include <algorithm>
+#include <cassert>
+#include <iostream>
+#include <iterator>
+#include <vector>
+
+void f(rust::Vec<Shared> v) {
+  for (auto shared : v) {
+    std::cout << shared.v << std::endl;
+  }
+
+  // Copy the elements to a C++ std::vector using STL algorithm.
+  std::vector<Shared> stdv;
+  std::copy(v.begin(), v.end(), std::back_inserter(stdv));
+  assert(v.size() == stdv.size());
+}
+```
diff --git a/book/src/bindings.md b/book/src/bindings.md
new file mode 100644
index 000000000..f19dc5d13
--- /dev/null
+++ b/book/src/bindings.md
@@ -0,0 +1,54 @@
+{{#title Built-in bindings — Rust ♡ C++}}
+# Built-in bindings reference
+
+In addition to all the primitive types (i32 &lt;=&gt; int32_t), the following
+common types may be used in the fields of shared structs and the arguments and
+returns of extern functions.
+
+<br>
+
+<table>
+<tr><th>name in Rust</th><th>name in C++</th><th>restrictions</th></tr>
+<tr><td style="padding:3px 6px">String</td><td style="padding:3px 6px"><b><a href="binding/string.md">rust::String</a></b></td><td style="padding:3px 6px"></td></tr>
+<tr><td style="padding:3px 6px">&amp;str</td><td style="padding:3px 6px"><b><a href="binding/str.md">rust::Str</a></b></td><td style="padding:3px 6px"></td></tr>
+<tr><td style="padding:3px 6px">&amp;[u8]</td><td style="padding:3px 6px"><b><a href="binding/slice.md">rust::Slice&lt;const&nbsp;uint8_t&gt;</a></b></td><td style="padding:3px 6px"><sup><i>arbitrary &amp;[T] not implemented yet</i></sup></td></tr>
+<tr><td style="padding:3px 6px"><b><a href="binding/cxxstring.md">CxxString</a></b></td><td style="padding:3px 6px">std::string</td><td style="padding:3px 6px"><sup><i>cannot be passed by value</i></sup></td></tr>
+<tr><td style="padding:3px 6px">Box&lt;T&gt;</td><td style="padding:3px 6px"><b><a href="binding/box.md">rust::Box&lt;T&gt;</a></b></td><td style="padding:3px 6px"><sup><i>cannot hold opaque C++ type</i></sup></td></tr>
+<tr><td style="padding:3px 6px"><b><a href="binding/uniqueptr.md">UniquePtr&lt;T&gt;</a></b></td><td style="padding:3px 6px">std::unique_ptr&lt;T&gt;</td><td style="padding:3px 6px"><sup><i>cannot hold opaque Rust type</i></sup></td></tr>
+<tr><td style="padding:3px 6px">Vec&lt;T&gt;</td><td style="padding:3px 6px"><b><a href="binding/vec.md">rust::Vec&lt;T&gt;</a></b></td><td style="padding:3px 6px"><sup><i>cannot hold opaque C++ type</i></sup></td></tr>
+<tr><td style="padding:3px 6px"><b><a href="binding/cxxvector.md">CxxVector&lt;T&gt;</a></b></td><td style="padding:3px 6px">std::vector&lt;T&gt;</td><td style="padding:3px 6px"><sup><i>cannot be passed by value, cannot hold opaque Rust type</i></sup></td></tr>
+<tr><td style="padding:3px 6px">fn(T, U) -&gt; V</td><td style="padding:3px 6px"><b><a href="binding/fn.md">rust::Fn&lt;V(T, U)&gt;</a></b></td><td style="padding:3px 6px"><sup><i>only passing from Rust to C++ is implemented so far</i></sup></td></tr>
+<tr><td style="padding:3px 6px"><b><a href="binding/result.md">Result&lt;T&gt;</a></b></td><td style="padding:3px 6px">throw/catch</td><td style="padding:3px 6px"><sup><i>allowed as return type only</i></sup></td></tr>
+</table>
+
+<br>
+
+The C++ API of the `rust` namespace is defined by the *include/cxx.h* file in
+the CXX GitHub repo. You will need to include this header in your C++ code when
+working with those types. **When using Cargo and the cxx-build crate, the header
+is made available to you at `#include "rust/cxx.h"`.**
+
+The `rust` namespace additionally provides lowercase type aliases of all the
+types mentioned in the table, for use in codebases preferring that style. For
+example `rust::String`, `rust::Vec` may alternatively be written `rust::string`,
+`rust::vec` etc.
+
+## Pending bindings
+
+The following types are intended to be supported "soon" but are just not
+implemented yet. I don't expect any of these to be hard to make work but it's a
+matter of designing a nice API for each in its non-native language.
+
+<br>
+
+<table>
+<tr><th>name in Rust</th><th>name in C++</th></tr>
+<tr><td>&amp;mut [T]</td><td>rust::Slice&lt;T&gt;</td></tr>
+<tr><td>BTreeMap&lt;K, V&gt;</td><td><sup><i>tbd</i></sup></td></tr>
+<tr><td>HashMap&lt;K, V&gt;</td><td><sup><i>tbd</i></sup></td></tr>
+<tr><td>Arc&lt;T&gt;</td><td><sup><i>tbd</i></sup></td></tr>
+<tr><td>Option&lt;T&gt;</td><td><sup><i>tbd</i></sup></td></tr>
+<tr><td><sup><i>tbd</i></sup></td><td>std::map&lt;K, V&gt;</td></tr>
+<tr><td><sup><i>tbd</i></sup></td><td>std::unordered_map&lt;K, V&gt;</td></tr>
+<tr><td><sup><i>tbd</i></sup></td><td>std::shared_ptr&lt;T&gt;</td></tr>
+</table>
diff --git a/book/src/build/bazel.md b/book/src/build/bazel.md
new file mode 100644
index 000000000..08edb19f5
--- /dev/null
+++ b/book/src/build/bazel.md
@@ -0,0 +1,106 @@
+{{#title Bazel, Buck — Rust ♡ C++}}
+## Bazel, Buck, potentially other similar environments
+
+Starlark-based build systems with the ability to compile a code generator and
+invoke it as a `genrule` will run CXX's C++ code generator via its `cxxbridge`
+command line interface.
+
+The tool is packaged as the `cxxbridge-cmd` crate on crates.io or can be built
+from the *gen/cmd/* directory of the CXX GitHub repo.
+
+```console
+$  cargo install cxxbridge-cmd
+
+$  cxxbridge src/bridge.rs --header > path/to/bridge.rs.h
+$  cxxbridge src/bridge.rs > path/to/bridge.rs.cc
+```
+
+The CXX repo maintains working Bazel `BUILD` and Buck `BUCK` targets for the
+complete blobstore tutorial (chapter 3) for your reference, tested in CI. These
+aren't meant to be directly what you use in your codebase, but serve as an
+illustration of one possible working pattern.
+
+```python
+# tools/bazel/rust_cxx_bridge.bzl
+
+load("@bazel_skylib//rules:run_binary.bzl", "run_binary")
+load("@rules_cc//cc:defs.bzl", "cc_library")
+
+def rust_cxx_bridge(name, src, deps = []):
+    native.alias(
+        name = "%s/header" % name,
+        actual = src + ".h",
+    )
+
+    native.alias(
+        name = "%s/source" % name,
+        actual = src + ".cc",
+    )
+
+    run_binary(
+        name = "%s/generated" % name,
+        srcs = [src],
+        outs = [
+            src + ".h",
+            src + ".cc",
+        ],
+        args = [
+            "$(location %s)" % src,
+            "-o",
+            "$(location %s.h)" % src,
+            "-o",
+            "$(location %s.cc)" % src,
+        ],
+        tool = "//:codegen",
+    )
+
+    cc_library(
+        name = name,
+        srcs = [src + ".cc"],
+        deps = deps + [":%s/include" % name],
+    )
+
+    cc_library(
+        name = "%s/include" % name,
+        hdrs = [src + ".h"],
+    )
+```
+
+```python
+# demo/BUILD
+
+load("@rules_cc//cc:defs.bzl", "cc_library")
+load("//tools/bazel:rust.bzl", "rust_binary")
+load("//tools/bazel:rust_cxx_bridge.bzl", "rust_cxx_bridge")
+
+rust_binary(
+    name = "demo",
+    srcs = glob(["src/**/*.rs"]),
+    deps = [
+        ":blobstore-sys",
+        ":bridge",
+        "//:cxx",
+    ],
+)
+
+rust_cxx_bridge(
+    name = "bridge",
+    src = "src/main.rs",
+    deps = [":blobstore-include"],
+)
+
+cc_library(
+    name = "blobstore-sys",
+    srcs = ["src/blobstore.cc"],
+    deps = [
+        ":blobstore-include",
+        ":bridge/include",
+    ],
+)
+
+cc_library(
+    name = "blobstore-include",
+    hdrs = ["include/blobstore.h"],
+    deps = ["//:core"],
+)
+```
diff --git a/book/src/build/cargo.md b/book/src/build/cargo.md
new file mode 100644
index 000000000..82ccfb500
--- /dev/null
+++ b/book/src/build/cargo.md
@@ -0,0 +1,306 @@
+{{#title Cargo-based setup — Rust ♡ C++}}
+# Cargo-based builds
+
+As one aspect of delivering a good Rust&ndash;C++ interop experience, CXX turns
+Cargo into a quite usable build system for C++ projects published as a
+collection of crates.io packages, including a consistent and frictionless
+experience `#include`-ing C++ headers across dependencies.
+
+## Canonical setup
+
+CXX's integration with Cargo is handled through the [cxx-build] crate.
+
+[cxx-build]: https://docs.rs/cxx-build
+
+```toml,hidelines
+## Cargo.toml
+# [package]
+# name = "..."
+# version = "..."
+# edition = "2018"
+
+[dependencies]
+cxx = "1.0"
+
+[build-dependencies]
+cxx-build = "1.0"
+```
+
+The canonical build script is as follows. The indicated line returns a
+[`cc::Build`] instance (from the usual widely used `cc` crate) on which you can
+set up any additional source files and compiler flags as normal.
+
+[`cc::Build`]: https://docs.rs/cc/1.0/cc/struct.Build.html
+
+```rust,noplayground
+// build.rs
+
+fn main() {
+    cxx_build::bridge("src/main.rs")  // returns a cc::Build
+        .file("src/demo.cc")
+        .flag_if_supported("-std=c++11")
+        .compile("cxxbridge-demo");
+
+    println!("cargo:rerun-if-changed=src/main.rs");
+    println!("cargo:rerun-if-changed=src/demo.cc");
+    println!("cargo:rerun-if-changed=include/demo.h");
+}
+```
+
+The `rerun-if-changed` lines are optional but make it so that Cargo does not
+spend time recompiling your C++ code when only non-C++ code has changed since
+the previous Cargo build. By default without any `rerun-if-changed`, Cargo will
+re-execute the build script after *any* file changed in the project.
+
+If stuck, try comparing what you have against the *demo/* directory of the CXX
+GitHub repo, which maintains a working Cargo-based setup for the blobstore
+tutorial (chapter 3).
+
+## Header include paths
+
+With cxx-build, by default your include paths always start with the crate name.
+This applies to both `#include` within your C++ code, and `include!` in the
+`extern "C++"` section of your Rust cxx::bridge.
+
+Your crate name is determined by the `name` entry in Cargo.toml.
+
+For example if your crate is named `yourcratename` and contains a C++ header
+file `path/to/header.h` relative to Cargo.toml, that file will be includable as:
+
+```cpp
+#include "yourcratename/path/to/header.h"
+```
+
+A crate can choose a prefix for its headers that is different from the crate
+name by modifying **[`CFG.include_prefix`][CFG]** from build.rs:
+
+[CFG]: https://docs.rs/cxx-build/*/cxx_build/static.CFG.html
+
+```rust,noplayground
+// build.rs
+
+use cxx_build::CFG;
+
+fn main() {
+    CFG.include_prefix = "my/project";
+
+    cxx_build::bridge(...)...
+}
+```
+
+Subsequently the header located at `path/to/header.h` would now be includable
+as:
+
+```cpp
+#include "my/project/path/to/header.h"
+```
+
+The empty string `""` is a valid include prefix and will make it possible to
+have `#include "path/to/header.h"`. However, if your crate is a library, be
+considerate of possible name collisions that may occur in downstream crates. If
+using an empty include prefix, you'll want to make sure your headers' local path
+within the crate is sufficiently namespaced or unique.
+
+## Including generated code
+
+If your `#[cxx::bridge]` module contains an `extern "Rust"` block i.e. types or
+functions exposed from Rust to C++, or any shared data structures, the
+CXX-generated C++ header declaring those things is available using a `.rs.h`
+extension on the Rust source file's name.
+
+```cpp
+// the header generated from path/to/lib.rs
+#include "yourcratename/path/to/lib.rs.h"
+```
+
+For giggles, it's also available using just a plain `.rs` extension as if you
+were including the Rust file directly. Use whichever you find more palatable.
+
+```cpp
+#include "yourcratename/path/to/lib.rs"
+```
+
+## Including headers from dependencies
+
+You get to include headers from your dependencies, both handwritten ones
+contained as `.h` files in their Cargo package, as well as CXX-generated ones.
+
+It works the same as an include of a local header: use the crate name (or their
+include\_prefix if their crate changed it) followed by the relative path of the
+header within the crate.
+
+```cpp
+#include "dependencycratename/path/to/their/header.h`
+```
+
+Note that cross-crate imports are only made available between **direct
+dependencies**. You must directly depend on the other crate in order to #include
+its headers; a transitive dependency is not sufficient.
+
+Additionally, headers from a direct dependency are only importable if the
+dependency's Cargo.toml manifest contains a `links` key. If not, its headers
+will not be importable from outside of the same crate. See *[the `links`
+manifest key][links]* in the Cargo reference.
+
+[links]: https://doc.rust-lang.org/cargo/reference/build-scripts.html#the-links-manifest-key
+
+<br><br><br>
+
+# Advanced features
+
+The following CFG settings are only relevant to you if you are writing a library
+that needs to support downstream crates `#include`-ing its C++ public headers.
+
+## Publicly exporting header directories
+
+**[`CFG.exported_header_dirs`][CFG]** (vector of absolute paths) defines a set
+of additional directories from which the current crate, directly dependent
+crates, and further crates to which this crate's headers are exported (more
+below) will be able to `#include` headers.
+
+Adding a directory to `exported_header_dirs` is similar to adding it to the
+current build via the `cc` crate's [`Build::include`], but *also* makes the
+directory available to downstream crates that want to `#include` one of the
+headers from your crate. If the dir were added only using `Build::include`, the
+downstream crate including your header would need to manually add the same
+directory to their own build as well.
+
+[`Build::include`]: https://docs.rs/cc/1/cc/struct.Build.html#method.include
+
+When using `exported_header_dirs`, your crate must also set a `links` key for
+itself in Cargo.toml. See [*the `links` manifest key*][links]. The reason is
+that Cargo imposes no ordering on the execution of build scripts without a
+`links` key, which means the downstream crate's build script might otherwise
+execute before yours decides what to put into `exported_header_dirs`.
+
+### Example
+
+One of your crate's headers wants to include a system library, such as `#include
+"Python.h"`.
+
+```rust,noplayground
+// build.rs
+
+use cxx_build::CFG;
+use std::path::PathBuf;
+
+fn main() {
+    let python3 = pkg_config::probe_library("python3").unwrap();
+    let python_include_paths = python3.include_paths.iter().map(PathBuf::as_path);
+    CFG.exported_header_dirs.extend(python_include_paths);
+
+    cxx_build::bridge("src/bridge.rs").compile("demo");
+}
+```
+
+### Example
+
+Your crate wants to rearrange the headers that it exports vs how they're laid
+out locally inside the crate's source directory.
+
+Suppose the crate as published contains a file at `./include/myheader.h` but
+wants it available to downstream crates as `#include "foo/v1/public.h"`.
+
+```rust,noplayground
+// build.rs
+
+use cxx_build::CFG;
+use std::path::Path;
+use std::{env, fs};
+
+fn main() {
+    let out_dir = env::var_os("OUT_DIR").unwrap();
+    let headers = Path::new(&out_dir).join("headers");
+    CFG.exported_header_dirs.push(&headers);
+
+    // We contain `include/myheader.h` locally, but
+    // downstream will use `#include "foo/v1/public.h"`
+    let foo = headers.join("foo").join("v1");
+    fs::create_dir_all(&foo).unwrap();
+    fs::copy("include/myheader.h", foo.join("public.h")).unwrap();
+
+    cxx_build::bridge("src/bridge.rs").compile("demo");
+}
+```
+
+## Publicly exporting dependencies
+
+**[`CFG.exported_header_prefixes`][CFG]** (vector of strings) each refer to the
+`include_prefix` of one of your direct dependencies, or a prefix thereof. They
+describe which of your dependencies participate in your crate's C++ public API,
+as opposed to private use by your crate's implementation.
+
+As a general rule, if one of your headers `#include`s something from one of your
+dependencies, you need to put that dependency's `include_prefix` into
+`CFG.exported_header_prefixes` (*or* their `links` key into
+`CFG.exported_header_links`; see below). On the other hand if only your C++
+implementation files and *not* your headers are importing from the dependency,
+you do not export that dependency.
+
+The significance of exported headers is that if downstream code (crate **𝒜**)
+contains an `#include` of a header from your crate (**ℬ**) and your header
+contains an `#include` of something from your dependency (**𝒞**), the exported
+dependency **𝒞** becomes available during the downstream crate **𝒜**'s build.
+Otherwise the downstream crate **𝒜** doesn't know about **𝒞** and wouldn't be
+able to find what header your header is referring to, and would fail to build.
+
+When using `exported_header_prefixes`, your crate must also set a `links` key
+for itself in Cargo.toml.
+
+### Example
+
+Suppose you have a crate with 5 direct dependencies and the `include_prefix` for
+each one are:
+
+- "crate0"
+- "group/api/crate1"
+- "group/api/crate2"
+- "group/api/contrib/crate3"
+- "detail/crate4"
+
+Your header involves types from the first four so we re-export those as part of
+your public API, while crate4 is only used internally by your cc file not your
+header, so we do not export:
+
+```rust,noplayground
+// build.rs
+
+use cxx_build::CFG;
+
+fn main() {
+    CFG.exported_header_prefixes = vec!["crate0", "group/api"];
+
+    cxx_build::bridge("src/bridge.rs")
+        .file("src/impl.cc")
+        .compile("demo");
+}
+```
+
+<br>
+
+For more fine grained control, there is **[`CFG.exported_header_links`][CFG]**
+(vector of strings) which each refer to the `links` attribute ([*the `links`
+manifest key*][links]) of one of your crate's direct dependencies.
+
+This achieves an equivalent result to `CFG.exported_header_prefixes` by
+re-exporting a C++ dependency as part of your crate's public API, except with
+finer control for cases when multiple crates might be sharing the same
+`include_prefix` and you'd like to export some but not others. Links attributes
+are guaranteed to be unique identifiers by Cargo.
+
+When using `exported_header_links`, your crate must also set a `links` key for
+itself in Cargo.toml.
+
+### Example
+
+```rust,noplayground
+// build.rs
+
+use cxx_build::CFG;
+
+fn main() {
+    CFG.exported_header_links.push("git2");
+
+    cxx_build::bridge("src/bridge.rs").compile("demo");
+}
+```
diff --git a/book/src/build/cmake.md b/book/src/build/cmake.md
new file mode 100644
index 000000000..ed3cb61dd
--- /dev/null
+++ b/book/src/build/cmake.md
@@ -0,0 +1,24 @@
+{{#title CMake — Rust ♡ C++}}
+# CMake
+
+There is not an officially endorsed CMake setup for CXX, but a few developers
+have shared one that they got working. You can try one of these as a starting
+point. If you feel that you have arrived at a CMake setup that is superior to
+what is available in these links, feel free to make a PR adding it to this list.
+
+<br>
+
+---
+
+- **<https://github.com/XiangpengHao/cxx-cmake-example>**
+
+  - Supports cross-language link time optimization (LTO)
+
+---
+
+- **<https://github.com/david-cattermole/cxx-demo-example>**
+
+  - Includes a cbindgen component
+  - Tested on Windows 10 with MSVC, and on Linux
+
+---
diff --git a/book/src/build/other.md b/book/src/build/other.md
new file mode 100644
index 000000000..8933c41bb
--- /dev/null
+++ b/book/src/build/other.md
@@ -0,0 +1,75 @@
+{{#title Other build systems — Rust ♡ C++}}
+# Some other build system
+
+You will need to achieve at least these three things:
+
+- Produce the CXX-generated C++ bindings code.
+- Compile the generated C++ code.
+- Link the resulting objects together with your other C++ and Rust objects.
+
+### Producing the generated code
+
+CXX's Rust code generation automatically happens when the `#[cxx::bridge]`
+procedural macro is expanded during the normal Rust compilation process, so no
+special build steps are required there.
+
+But the C++ side of the bindings needs to be generated. Your options are:
+
+- Use the `cxxbridge` command, which is a standalone command line interface to
+  the CXX C++ code generator. Wire up your build system to compile and invoke
+  this tool.
+
+  ```console
+  $  cxxbridge src/bridge.rs --header > path/to/bridge.rs.h
+  $  cxxbridge src/bridge.rs > path/to/bridge.rs.cc
+  ```
+
+  It's packaged as the `cxxbridge-cmd` crate on crates.io or can be built from
+  the *gen/cmd/* directory of the CXX GitHub repo.
+
+- Or, build your own code generator frontend on top of the [cxx-gen] crate. This
+  is currently unofficial and unsupported.
+
+[cxx-gen]: https://docs.rs/cxx-gen
+
+### Compiling C++
+
+However you like. We can provide no guidance.
+
+### Linking the C++ and Rust together
+
+When linking a binary which contains mixed Rust and C++ code, you will have to
+choose between using the Rust toolchain (`rustc`) or the C++ toolchain which you
+may already have extensively tuned.
+
+Rust does not generate simple standalone `.o` files, so you can't just throw the
+Rust-generated code into your existing C++ toolchain linker. Instead you need to
+choose one of these options:
+
+* Use `rustc` as the final linker. Pass any non-Rust libraries using `-L
+  <directory>` and `-l<library>` rustc arguments, and/or `#[link]` directives in
+  your Rust code. If you need to link against C/C++ `.o` files you can use
+  `-Clink-arg=file.o`.
+
+* Use your C++ linker. In this case, you first need to use `rustc` and/or
+  `cargo` to generate a _single_ Rust `staticlib` target and pass that into your
+  foreign linker invocation.
+
+  * If you need to link multiple Rust subsystems, you will need to generate a
+    _single_ `staticlib` perhaps using lots of `extern crate` statements to
+    include multiple Rust `rlib`s.  Multiple Rust `staticlib` files are likely
+    to conflict.
+
+Passing Rust `rlib`s directly into your non-Rust linker is not supported (but
+apparently sometimes works).
+
+See the [Rust reference's *Linkage*][linkage] page for some general information
+here.
+
+[linkage]: https://doc.rust-lang.org/reference/linkage.html
+
+The following open rust-lang issues might hold more recent guidance or
+inspiration: [rust-lang/rust#73632], [rust-lang/rust#73295].
+
+[rust-lang/rust#73632]: https://github.com/rust-lang/rust/issues/73632
+[rust-lang/rust#73295]: https://github.com/rust-lang/rust/issues/73295
diff --git a/book/src/building.md b/book/src/building.md
new file mode 100644
index 000000000..c75939e0d
--- /dev/null
+++ b/book/src/building.md
@@ -0,0 +1,20 @@
+{{#title Multi-language build system options — Rust ♡ C++}}
+# Multi-language build system options
+
+CXX is designed to be convenient to integrate into a variety of build systems.
+
+If you are working in a project that does not already have a preferred build
+system for its C++ code *or* which will be relying heavily on open source
+libraries from the Rust package registry, you're likely to have the easiest
+experience with Cargo which is the build system commonly used by open source
+Rust projects. Refer to the ***[Cargo](build/cargo.md)*** chapter about CXX's
+Cargo support.
+
+Among build systems designed for first class multi-language support, Bazel is a
+solid choice. Refer to the ***[Bazel](build/bazel.md)*** chapter.
+
+If your codebase is already invested in CMake, refer to the
+***[CMake](build/cmake.md)*** chapter.
+
+If you have some other build system that you'd like to try to make work with
+CXX, see [this page](build/other.md) for notes.
diff --git a/book/src/concepts.md b/book/src/concepts.md
new file mode 100644
index 000000000..75daedde1
--- /dev/null
+++ b/book/src/concepts.md
@@ -0,0 +1,85 @@
+{{#title Core concepts — Rust ♡ C++}}
+# Core concepts
+
+This page is a brief overview of the major concepts of CXX, enough so that you
+recognize the shape of things as you read the tutorial and following chapters.
+
+In CXX, the language of the FFI boundary involves 3 kinds of items:
+
+- **Shared structs** &mdash; data structures whose fields are made visible to
+  both languages. The definition written within cxx::bridge in Rust is usually
+  the single source of truth, though there are ways to do sharing based on a
+  bindgen-generated definition with C++ as source of truth.
+
+- **Opaque types** &mdash; their fields are secret from the other language.
+  These cannot be passed across the FFI by value but only behind an indirection,
+  such as a reference `&`, a Rust `Box`, or a C++ `unique_ptr`. Can be a type
+  alias for an arbitrarily complicated generic language-specific type depending
+  on your use case.
+
+- **Functions** &mdash; implemented in either language, callable from the other
+  language.
+
+```rust,noplayground,focuscomment
+# #[cxx::bridge]
+# mod ffi {
+    // Any shared structs, whose fields will be visible to both languages.
+#     struct BlobMetadata {
+#         size: usize,
+#         tags: Vec<String>,
+#     }
+#
+#     extern "Rust" {
+        // Zero or more opaque types which both languages can pass around
+        // but only Rust can see the fields.
+#         type MultiBuf;
+#
+        // Functions implemented in Rust.
+#         fn next_chunk(buf: &mut MultiBuf) -> &[u8];
+#     }
+#
+#     unsafe extern "C++" {
+        // One or more headers with the matching C++ declarations for the
+        // enclosing extern "C++" block. Our code generators don't read it
+        // but it gets #include'd and used in static assertions to ensure
+        // our picture of the FFI boundary is accurate.
+#         include!("demo/include/blobstore.h");
+#
+        // Zero or more opaque types which both languages can pass around
+        // but only C++ can see the fields.
+#         type BlobstoreClient;
+#
+        // Functions implemented in C++.
+#         fn new_blobstore_client() -> UniquePtr<BlobstoreClient>;
+#         fn put(&self, parts: &mut MultiBuf) -> u64;
+#         fn tag(&self, blobid: u64, tag: &str);
+#         fn metadata(&self, blobid: u64) -> BlobMetadata;
+#     }
+# }
+```
+
+Within the `extern "Rust"` part of the CXX bridge we list the types and
+functions for which Rust is the source of truth. These all implicitly refer to
+the `super` module, the parent module of the CXX bridge. You can think of the
+two items listed in the example above as being like `use super::MultiBuf` and
+`use super::next_chunk` except re-exported to C++. The parent module will either
+contain the definitions directly for simple things, or contain the relevant
+`use` statements to bring them into scope from elsewhere.
+
+Within the `extern "C++"` part, we list types and functions for which C++ is the
+source of truth, as well as the header(s) that declare those APIs. In the future
+it's possible that this section could be generated bindgen-style from the
+headers but for now we need the signatures written out; static assertions verify
+that they are accurate.
+
+<br><br>
+
+Be aware that the design of this library is intentionally restrictive and
+opinionated! It isn't a goal to be flexible enough to handle an arbitrary
+signature in either language. Instead this project is about carving out a highly
+expressive set of functionality about which we can make powerful safety
+guarantees today and extend over time. You may find that it takes some practice
+to use CXX bridge effectively as it won't work in all the ways that you may be
+used to.
+
+<br>
diff --git a/book/src/context.md b/book/src/context.md
new file mode 100644
index 000000000..516ee91f2
--- /dev/null
+++ b/book/src/context.md
@@ -0,0 +1,118 @@
+{{#title Other Rust–C++ interop tools — Rust ♡ C++}}
+# Context: other Rust&ndash;C++ interop tools
+
+When it comes to interacting with an idiomatic Rust API or idiomatic C++ API
+from the other language, the generally applicable approaches outside of the CXX
+crate are:
+
+- Build a C-compatible wrapper around the code (expressed using `extern "C"`
+  signatures, primitives, C-compatible structs, raw pointers). Translate that
+  manually to equivalent `extern "C"` declarations in the other language and
+  keep them in sync. Preferably, build a safe/idiomatic wrapper around the
+  translated `extern "C"` signatures for callers to use.
+
+- Build a C wrapper around the C++ code and use **[bindgen]** to translate that
+  programmatically to `extern "C"` Rust signatures. Preferably, build a
+  safe/idiomatic Rust wrapper on top.
+
+- Build a C-compatible Rust wrapper around the Rust code and use **[cbindgen]**
+  to translate that programmatically to an `extern "C"` C++ header. Preferably,
+  build an idiomatic C++ wrapper.
+
+**If the code you are binding is already *"effectively C"*, the above has you
+covered.** You should use bindgen or cbindgen, or manually translated C
+signatures if there aren't too many and they seldom change.
+
+[bindgen]: https://github.com/rust-lang/rust-bindgen
+[cbindgen]: https://github.com/eqrion/cbindgen
+
+## C++ vs C
+
+Bindgen has some basic support for C++. It can reason about classes, member
+functions, and the layout of templated types. However, everything it does
+related to C++ is best-effort only. Bindgen starts from a point of wanting to
+generate declarations for everything, so any C++ detail that it hasn't
+implemented will cause a crash if you are lucky ([bindgen#388]) or more likely
+silently emit an incompatible signature ([bindgen#380], [bindgen#607],
+[bindgen#652], [bindgen#778], [bindgen#1194]) which will do arbitrary
+memory-unsafe things at runtime whenever called.
+
+[bindgen#388]: https://github.com/rust-lang/rust-bindgen/issues/388
+[bindgen#380]: https://github.com/rust-lang/rust-bindgen/issues/380
+[bindgen#607]: https://github.com/rust-lang/rust-bindgen/issues/607
+[bindgen#652]: https://github.com/rust-lang/rust-bindgen/issues/652
+[bindgen#778]: https://github.com/rust-lang/rust-bindgen/issues/778
+[bindgen#1194]: https://github.com/rust-lang/rust-bindgen/issues/1194
+
+Thus using bindgen correctly requires not just juggling all your pointers
+correctly at the language boundary, but also understanding ABI details and their
+workarounds and reliably applying them. For example, the programmer will
+discover that their program sometimes segfaults if they call a function that
+returns std::unique\_ptr\<T\> through bindgen. Why? Because unique\_ptr, despite
+being "just a pointer", has a different ABI than a pointer or a C struct
+containing a pointer ([bindgen#778]) and is not directly expressible in Rust.
+Bindgen emitted something that *looks* reasonable and you will have a hell of a
+time in gdb working out what went wrong. Eventually people learn to avoid
+anything involving a non-trivial copy constructor, destructor, or inheritance,
+and instead stick to raw pointers and primitives and trivial structs only
+&mdash; in other words C.
+
+## Geometric intuition for why there is so much opportunity for improvement
+
+The CXX project attempts a different approach to C++ FFI.
+
+Imagine Rust and C and C++ as three vertices of a scalene triangle, with length
+of the edges being related to similarity of the languages when it comes to
+library design.
+
+The most similar pair (the shortest edge) is Rust&ndash;C++. These languages
+have largely compatible concepts of things like ownership, vectors, strings,
+fallibility, etc that translate clearly from signatures in either language to
+signatures in the other language.
+
+When we make a binding for an idiomatic C++ API using bindgen, and we fall down
+to raw pointers and primitives and trivial structs as described above, what we
+are really doing is coding the two longest edges of the triangle: getting from
+C++ down to C, and C back up to Rust. The Rust&ndash;C edge always involves a
+great deal of `unsafe` code, and the C++&ndash;C edge similarly requires care
+just for basic memory safety. Something as basic as "how do I pass ownership of
+a string to the other language?" becomes a strap-yourself-in moment,
+particularly for someone not already an expert in one or both sides.
+
+You should think of the `cxx` crate as being the midpoint of the Rust&ndash;C++
+edge. Rather than coding the two long edges, you will code half the short edge
+in Rust and half the short edge in C++, in both cases with the library playing
+to the strengths of the Rust type system *and* the C++ type system to help
+assure correctness.
+
+If you've already been through the tutorial in the previous chapter, take a
+moment to appreciate that the C++ side *really* looks like we are just writing
+C++ and the Rust side *really* looks like we are just writing Rust. Anything you
+could do wrong in Rust, and almost anything you could reasonably do wrong in
+C++, will be caught by the compiler. This highlights that we are on the "short
+edge of the triangle".
+
+But it all still boils down to the same things: it's still FFI from one piece of
+native code to another, nothing is getting serialized or allocated or
+runtime-checked in between.
+
+## Role of CXX
+
+The role of CXX is to capture the language boundary with more fidelity than what
+`extern "C"` is able to represent. You can think of CXX as being a replacement
+for `extern "C"` in a sense.
+
+From this perspective, CXX is a lower level tool than the bindgens. Just as
+bindgen and cbindgen are built on top of `extern "C"`, it makes sense to think
+about higher level tools built on top of CXX. Such a tool might consume a C++
+header and/or Rust module (and/or IDL like Thrift) and emit the corresponding
+safe cxx::bridge language boundary, leveraging CXX's static analysis and
+underlying implementation of that boundary. We are beginning to see this space
+explored by the [autocxx] tool, though nothing yet ready for broad use in the
+way that CXX on its own is.
+
+[autocxx]: https://github.com/google/autocxx
+
+But note in other ways CXX is higher level than the bindgens, with rich support
+for common standard library types. CXX's types serve as an intuitive vocabulary
+for designing a good boundary between components in different languages.
diff --git a/book/src/extern-c++.md b/book/src/extern-c++.md
new file mode 100644
index 000000000..c015b036a
--- /dev/null
+++ b/book/src/extern-c++.md
@@ -0,0 +1,315 @@
+{{#title extern "C++" — Rust ♡ C++}}
+# extern "C++"
+
+```rust,noplayground
+#[cxx::bridge]
+mod ffi {
+    extern "C++" {
+        include!("path/to/header.h");
+        include!("path/to/another.h");
+
+        ...
+    }
+}
+```
+
+The `extern "C++"` section of a CXX bridge declares C++ types and signatures to
+be made available to Rust, and gives the paths of the header(s) which contain
+the corresponding C++ declarations.
+
+A bridge module may contain zero or more extern "C++" blocks.
+
+## Opaque C++ types
+
+Type defined in C++ that are made available to Rust, but only behind an
+indirection.
+
+```rust,noplayground
+# #[cxx::bridge]
+# mod ffi {
+    extern "C++" {
+        # include!("path/to/header.h");
+        #
+        type MyType;
+        type MyOtherType;
+    }
+# }
+```
+
+For example in the ***[Tutorial](tutorial.md)*** we saw `BlobstoreClient`
+implemented as an opaque C++ type. The blobstore client was created in C++ and
+returned to Rust by way of a UniquePtr.
+
+**Mutability:** Unlike extern Rust types and shared types, an extern C++ type is
+not permitted to be passed by plain mutable reference `&mut MyType` across the
+FFI bridge. For mutation support, the bridge is required to use `Pin<&mut
+MyType>`. This is to safeguard against things like mem::swap-ing the contents of
+two mutable references, given that Rust doesn't have information about the size
+of the underlying object and couldn't invoke an appropriate C++ move constructor
+anyway.
+
+**Thread safety:** Be aware that CXX does not assume anything about the thread
+safety of your extern C++ types. In other words the `MyType` etc bindings which
+CXX produces for you in Rust *do not* come with `Send` and `Sync` impls. If you
+are sure that your C++ type satisfies the requirements of `Send` and/or `Sync`
+and need to leverage that fact from Rust, you must provide your own unsafe
+marker trait impls.
+
+```rust,noplayground
+# #[cxx::bridge]
+# mod ffi {
+#     extern "C++" {
+#         include!("path/to/header.h");
+#
+#         type MyType;
+#     }
+# }
+#
+/// The C++ implementation of MyType is thread safe.
+unsafe impl Send for ffi::MyType {}
+unsafe impl Sync for ffi::MyType {}
+```
+
+Take care in doing this because thread safety in C++ can be extremely tricky to
+assess if you are coming from a Rust background. For example the
+`BlobstoreClient` type in the tutorial is *not thread safe* despite doing only
+completely innocuous things in its implementation. Concurrent calls to the `tag`
+member function trigger a data race on the `blobs` map.
+
+## Functions and member functions
+
+This largely follows the same principles as ***[extern
+"Rust"](extern-rust.md)*** functions and methods. In particular, any signature
+with a `self` parameter is interpreted as a C++ non-static member function and
+exposed to Rust as a method.
+
+The programmer **does not** need to promise that the signatures they have typed
+in are accurate; that would be unreasonable. CXX performs static assertions that
+the signatures exactly correspond with what is declared in C++. Rather, the
+programmer is only on the hook for things that C++'s static information is not
+precise enough to capture, i.e. things that would only be represented at most by
+comments in the C++ code unintelligible to a static assertion: namely whether
+the C++ function is safe or unsafe to be called from Rust.
+
+**Safety:** the extern "C++" block is responsible for deciding whether to expose
+each signature inside as safe-to-call or unsafe-to-call. If an extern block
+contains at least one safe-to-call signature, it must be written as an `unsafe
+extern` block, which serves as an item level unsafe block to indicate that an
+unchecked safety claim is being made about the contents of the block.
+
+```rust,noplayground
+#[cxx::bridge]
+mod ffi {
+    unsafe extern "C++" {
+        # include!("path/to/header.h");
+        #
+        fn f();  // safe to call
+    }
+
+    extern "C++" {
+        unsafe fn g();  // unsafe to call
+    }
+}
+```
+
+
+## Reusing existing binding types
+
+Extern C++ types support a syntax for declaring that a Rust binding of the
+correct C++ type already exists outside of the current bridge module. This
+avoids generating a fresh new binding which Rust's type system would consider
+non-interchangeable with the first.
+
+```rust,noplayground
+#[cxx::bridge(namespace = "path::to")]
+mod ffi {
+    extern "C++" {
+        type MyType = crate::existing::MyType;
+    }
+
+    extern "Rust" {
+        fn f(x: &MyType) -> usize;
+    }
+}
+```
+
+In this case rather than producing a unique new Rust type `ffi::MyType` for the
+Rust binding of C++'s `::path::to::MyType`, CXX will reuse the already existing
+binding at `crate::existing::MyType` in expressing the signature of `f` and any
+other uses of `MyType` within the bridge module.
+
+CXX safely validates that `crate::existing::MyType` is in fact a binding for the
+right C++ type `::path::to::MyType` by generating a static assertion based on
+`crate::existing::MyType`'s implementation of [`ExternType`], which is a trait
+automatically implemented by CXX for bindings that it generates but can also be
+manually implemented as described below.
+
+[`ExternType`]: https://docs.rs/cxx/*/cxx/trait.ExternType.html
+
+`ExternType` serves the following two related use cases.
+
+#### Safely unifying occurrences of an extern type across bridges
+
+In the following snippet, two #\[cxx::bridge\] invocations in different files
+(possibly different crates) both contain function signatures involving the same
+C++ type `example::Demo`. If both were written just containing `type Demo;`,
+then both macro expansions would produce their own separate Rust type called
+`Demo` and thus the compiler wouldn't allow us to take the `Demo` returned by
+`file1::ffi::create_demo` and pass it as the `Demo` argument accepted by
+`file2::ffi::take_ref_demo`. Instead, one of the two `Demo`s has been defined as
+an extern type alias of the other, making them the same type in Rust.
+
+```rust,noplayground
+// file1.rs
+#[cxx::bridge(namespace = "example")]
+pub mod ffi {
+    unsafe extern "C++" {
+        type Demo;
+
+        fn create_demo() -> UniquePtr<Demo>;
+    }
+}
+```
+
+```rust,noplayground
+// file2.rs
+#[cxx::bridge(namespace = "example")]
+pub mod ffi {
+    unsafe extern "C++" {
+        type Demo = crate::file1::ffi::Demo;
+
+        fn take_ref_demo(demo: &Demo);
+    }
+}
+```
+
+#### Integrating with bindgen-generated or handwritten unsafe bindings
+
+Handwritten `ExternType` impls make it possible to plug in a data structure
+emitted by bindgen as the definition of a C++ type emitted by CXX.
+
+By writing the unsafe `ExternType` impl, the programmer asserts that the C++
+namespace and type name given in the type id refers to a C++ type that is
+equivalent to Rust type that is the `Self` type of the impl.
+
+```rust,noplayground
+mod folly_sys;  // the bindgen-generated bindings
+
+use cxx::{type_id, ExternType};
+
+unsafe impl ExternType for folly_sys::StringPiece {
+    type Id = type_id!("folly::StringPiece");
+    type Kind = cxx::kind::Opaque;
+}
+
+#[cxx::bridge(namespace = "folly")]
+pub mod ffi {
+    unsafe extern "C++" {
+        include!("rust_cxx_bindings.h");
+
+        type StringPiece = crate::folly_sys::StringPiece;
+
+        fn print_string_piece(s: &StringPiece);
+    }
+}
+
+// Now if we construct a StringPiece or obtain one through one
+// of the bindgen-generated signatures, we are able to pass it
+// along to ffi::print_string_piece.
+```
+
+The `ExternType::Id` associated type encodes a type-level representation of the
+type's C++ namespace and type name. It will always be defined using the
+`type_id!` macro exposed in the cxx crate.
+
+The `ExternType::Kind` associated type will always be either
+[`cxx::kind::Opaque`] or [`cxx::kind::Trivial`] identifying whether a C++ type
+is soundly relocatable by Rust's move semantics. A C++ type is only okay to hold
+and pass around by value in Rust if its [move constructor is trivial] and it has
+no destructor. In CXX, these are called Trivial extern C++ types, while types
+with nontrivial move behavior or a destructor must be considered Opaque and
+handled by Rust only behind an indirection, such as a reference or UniquePtr.
+
+[`cxx::kind::Opaque`]: https://docs.rs/cxx/*/cxx/kind/enum.Opaque.html
+[`cxx::kind::Trivial`]: https://docs.rs/cxx/*/cxx/kind/enum.Trivial.html
+[move constructor is trivial]: https://en.cppreference.com/w/cpp/types/is_move_constructible
+
+If you believe your C++ type reflected by the ExternType impl is indeed fine to
+hold by value and move in Rust, you can specify:
+
+```rust,noplayground
+# unsafe impl cxx::ExternType for TypeName {
+#     type Id = cxx::type_id!("name::space::of::TypeName");
+    type Kind = cxx::kind::Trivial;
+# }
+```
+
+which will enable you to pass it into C++ functions by value, return it by
+value, and include it in `struct`s that you have declared to `cxx::bridge`. Your
+claim about the triviality of the C++ type will be checked by a `static_assert`
+in the generated C++ side of the binding.
+
+## Explicit shim trait impls
+
+This is a somewhat niche feature, but important when you need it.
+
+CXX's support for C++'s std::unique\_ptr and std::vector is built on a set of
+internal trait impls connecting the Rust API of UniquePtr and CxxVector to
+underlying template instantiations performed by the C++ compiler.
+
+When reusing a binding type across multiple bridge modules as described in the
+previous section, you may find that your code needs some trait impls which CXX
+hasn't decided to generate.
+
+```rust,noplayground
+#[cxx::bridge]
+mod ffi1 {
+    extern "C++" {
+        include!("path/to/header.h");
+
+        type A;
+        type B;
+
+        // Okay: CXX sees UniquePtr<B> using a type B defined within the same
+        // bridge, and automatically emits the right template instantiations
+        // corresponding to std::unique_ptr<B>.
+        fn get_b() -> UniquePtr<B>;
+    }
+}
+
+#[cxx::bridge]
+mod ffi2 {
+    extern "C++" {
+        type A = crate::ffi1::A;
+
+        // Rust trait error: CXX processing this module has no visibility into
+        // whether template instantiations corresponding to std::unique_ptr<A>
+        // have already been emitted by the upstream library, so it does not
+        // emit them here. If the upstream library does not have any signatures
+        // involving UniquePtr<A>, an explicit instantiation of the template
+        // needs to be requested in one module or the other.
+        fn get_a() -> UniquePtr<A>;
+    }
+}
+```
+
+You can request a specific template instantiation at a particular location in
+the Rust crate hierarchy by writing `impl UniquePtr<A> {}` inside of the bridge
+module which defines `A` but does not otherwise contain any use of
+`UniquePtr<A>`.
+
+```rust,noplayground
+#[cxx::bridge]
+mod ffi1 {
+    extern "C++" {
+        include!("path/to/header.h");
+
+        type A;
+        type B;
+
+        fn get_b() -> UniquePtr<B>;
+    }
+
+    impl UniquePtr<A> {}  // explicit instantiation
+}
+```
diff --git a/book/src/extern-rust.md b/book/src/extern-rust.md
new file mode 100644
index 000000000..a9ad8b6d2
--- /dev/null
+++ b/book/src/extern-rust.md
@@ -0,0 +1,165 @@
+{{#title extern "Rust" — Rust ♡ C++}}
+# extern "Rust"
+
+```rust,noplayground
+#[cxx::bridge]
+mod ffi {
+    extern "Rust" {
+
+    }
+}
+```
+
+The `extern "Rust"` section of a CXX bridge declares Rust types and signatures
+to be made available to C++.
+
+The CXX code generator uses your extern "Rust" section(s) to produce a C++
+header file containing the corresponding C++ declarations. The generated header
+has the same path as the Rust source file containing the bridge, except with a
+`.rs.h` file extension.
+
+A bridge module may contain zero or more extern "Rust" blocks.
+
+## Opaque Rust types
+
+Types defined in Rust that are made available to C++, but only behind an
+indirection.
+
+```rust,noplayground
+# #[cxx::bridge]
+# mod ffi {
+    extern "Rust" {
+        type MyType;
+        type MyOtherType;
+        type OneMoreType;
+    }
+# }
+```
+
+For example in the ***[Tutorial](tutorial.md)*** we saw `MultiBuf` used in this
+way. Rust code created the `MultiBuf`, passed a `&mut MultiBuf` to C++, and C++
+later passed a `&mut MultiBuf` back across the bridge to Rust.
+
+Another example is the one on the ***[Box\<T\>](binding/box.md)*** page, which
+exposes the Rust standard library's `std::fs::File` to C++ as an opaque type in
+a similar way but with Box as the indirection rather than &mut.
+
+The types named as opaque types (`MyType` etc) refer to types in the `super`
+module, the parent module of the CXX bridge. You can think of an opaque type `T`
+as being like a re-export `use super::T` made available to C++ via the generated
+header.
+
+Opaque types are currently required to be [`Sized`] and [`Unpin`]. In
+particular, a trait object `dyn MyTrait` or slice `[T]` may not be used for an
+opaque Rust type. These restrictions may be lifted in the future.
+
+[`Sized`]: https://doc.rust-lang.org/std/marker/trait.Sized.html
+[`Unpin`]: https://doc.rust-lang.org/std/marker/trait.Unpin.html
+
+For now, types used as extern Rust types are required to be defined by the same
+crate that contains the bridge using them. This restriction may be lifted in the
+future.
+
+The bridge's parent module will contain the appropriate imports or definitions
+for these types.
+
+```rust,noplayground
+use path::to::MyType;
+
+pub struct MyOtherType {
+    ...
+}
+#
+# #[cxx::bridge]
+# mod ffi {
+#     extern "Rust" {
+#         type MyType;
+#         type MyOtherType;
+#     }
+# }
+```
+
+## Functions
+
+Rust functions made callable to C++.
+
+Just like for opaque types, these functions refer implicitly to something in
+scope in the `super` module, whether defined there or imported by some `use`
+statement.
+
+```rust,noplayground
+#[cxx::bridge]
+mod ffi {
+    extern "Rust" {
+        struct MyType;
+        fn f() -> Box<MyType>;
+    }
+}
+
+struct MyType(i32);
+
+fn f() -> Box<MyType> {
+    return Box::new(MyType(1));
+}
+```
+
+Extern Rust function signature may consist of types defined in the bridge,
+primitives, and [any of these additional bindings](bindings.md).
+
+## Methods
+
+Any signature with a `self` parameter is interpreted as a Rust method and
+exposed to C++ as a non-static member function.
+
+```rust,noplayground
+# #[cxx::bridge]
+# mod ffi {
+    extern "Rust" {
+        type MyType;
+        fn f(&self) -> usize;
+    }
+# }
+```
+
+The `self` parameter may be a shared reference `&self`, an exclusive reference
+`&mut self`, or a pinned reference `self: Pin<&mut Self>`. A by-value `self` is
+not currently supported.
+
+If the surrounding `extern "Rust"` block contains exactly one extern type, that
+type is implicitly the receiver for a `&self` or `&mut self` method. If the
+surrounding block contains *more than one* extern type, a receiver type must be
+provided explicitly for the self parameter, or you can consider splitting into
+multiple extern blocks.
+
+```rust,noplayground
+# #[cxx::bridge]
+# mod ffi {
+    extern "Rust" {
+        type First;
+        type Second;
+        fn bar(self: &First);
+        fn foo(self: &mut Second);
+    }
+# }
+```
+
+## Functions with explicit lifetimes
+
+An extern Rust function signature is allowed to contain explicit lifetimes but
+in this case the function must be declared unsafe-to-call. This is pretty
+meaningless given we're talking about calls from C++, but at least it draws some
+extra attention from the caller that they may be responsible for upholding some
+atypical lifetime relationship.
+
+```rust,noplayground
+#[cxx::bridge]
+mod ffi {
+    extern "Rust" {
+        type MyType;
+        unsafe fn f<'a>(&'a self, s: &str) -> &'a str;
+    }
+}
+```
+
+Bounds on a lifetime (like `<'a, 'b: 'a>`) are not currently supported. Nor are
+type parameters or where-clauses.
diff --git a/book/src/index.md b/book/src/index.md
new file mode 100644
index 000000000..7b03e7e15
--- /dev/null
+++ b/book/src/index.md
@@ -0,0 +1,83 @@
+<div class="badges">
+<a href="https://github.com/dtolnay/cxx"><img src="https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github" alt="github" height="28" class="badge"></a><a href="https://crates.io/crates/cxx"><img src="https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust" alt="crates-io" height="28" class="badge"></a><a href="https://docs.rs/cxx"><img src="https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logoColor=white&logo=data:image/svg+xml;base64,PHN2ZyByb2xlPSJpbWciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDUxMiA1MTIiPjxwYXRoIGZpbGw9IiNmNWY1ZjUiIGQ9Ik00ODguNiAyNTAuMkwzOTIgMjE0VjEwNS41YzAtMTUtOS4zLTI4LjQtMjMuNC0zMy43bC0xMDAtMzcuNWMtOC4xLTMuMS0xNy4xLTMuMS0yNS4zIDBsLTEwMCAzNy41Yy0xNC4xIDUuMy0yMy40IDE4LjctMjMuNCAzMy43VjIxNGwtOTYuNiAzNi4yQzkuMyAyNTUuNSAwIDI2OC45IDAgMjgzLjlWMzk0YzAgMTMuNiA3LjcgMjYuMSAxOS45IDMyLjJsMTAwIDUwYzEwLjEgNS4xIDIyLjEgNS4xIDMyLjIgMGwxMDMuOS01MiAxMDMuOSA1MmMxMC4xIDUuMSAyMi4xIDUuMSAzMi4yIDBsMTAwLTUwYzEyLjItNi4xIDE5LjktMTguNiAxOS45LTMyLjJWMjgzLjljMC0xNS05LjMtMjguNC0yMy40LTMzLjd6TTM1OCAyMTQuOGwtODUgMzEuOXYtNjguMmw4NS0zN3Y3My4zek0xNTQgMTA0LjFsMTAyLTM4LjIgMTAyIDM4LjJ2LjZsLTEwMiA0MS40LTEwMi00MS40di0uNnptODQgMjkxLjFsLTg1IDQyLjV2LTc5LjFsODUtMzguOHY3NS40em0wLTExMmwtMTAyIDQxLjQtMTAyLTQxLjR2LS42bDEwMi0zOC4yIDEwMiAzOC4ydi42em0yNDAgMTEybC04NSA0Mi41di03OS4xbDg1LTM4Ljh2NzUuNHptMC0xMTJsLTEwMiA0MS40LTEwMi00MS40di0uNmwxMDItMzguMiAxMDIgMzguMnYuNnoiPjwvcGF0aD48L3N2Zz4K" alt="docs-rs" height="28" class="badge"></a>
+</div>
+
+# CXX — safe interop between Rust and C++
+
+This library provides a safe mechanism for calling C++ code from Rust and Rust
+code from C++. It carves out a regime of commonality where Rust and C++ are
+semantically very similar and guides the programmer to express their language
+boundary effectively within this regime. CXX fills in the low level stuff so
+that you get a safe binding, preventing the pitfalls of doing a foreign function
+interface over unsafe C-style signatures.
+
+<div style="height:226px;padding:34px 0 24px">
+<object type="image/svg+xml" data="overview.svg"></object>
+</div>
+
+From a high level description of the language boundary, CXX uses static analysis
+of the types and function signatures to protect both Rust's and C++'s
+invariants. Then it uses a pair of code generators to implement the boundary
+efficiently on both sides together with any necessary static assertions for
+later in the build process to verify correctness.
+
+The resulting FFI bridge operates at zero or negligible overhead, i.e. no
+copying, no serialization, no memory allocation, no runtime checks needed.
+
+The FFI signatures are able to use native data structures from whichever side
+they please. In addition, CXX provides builtin bindings for key standard library
+types like strings, vectors, Box, unique\_ptr, etc to expose an idiomatic API on
+those types to the other language.
+
+## Example
+
+In this example we are writing a Rust application that calls a C++ client of a
+large-file blobstore service. The blobstore supports a `put` operation for a
+discontiguous buffer upload. For example we might be uploading snapshots of a
+circular buffer which would tend to consist of 2 pieces, or fragments of a file
+spread across memory for some other reason (like a rope data structure).
+
+```rust,noplayground
+#[cxx::bridge]
+mod ffi {
+    extern "Rust" {
+        type MultiBuf;
+
+        fn next_chunk(buf: &mut MultiBuf) -> &[u8];
+    }
+
+    unsafe extern "C++" {
+        include!("example/include/blobstore.h");
+
+        type BlobstoreClient;
+
+        fn new_blobstore_client() -> UniquePtr<BlobstoreClient>;
+        fn put(self: &BlobstoreClient, buf: &mut MultiBuf) -> Result<u64>;
+    }
+}
+```
+
+Now we simply provide Rust definitions of all the things in the `extern "Rust"`
+block and C++ definitions of all the things in the `extern "C++"` block, and get
+to call back and forth safely.
+
+The [***Tutorial***](tutorial.md) chapter walks through a fleshed out version of
+this blobstore example in full detail, including all of the Rust code and all of
+the C++ code. The code is also provided in runnable form in the *demo* directory
+of <https://github.com/dtolnay/cxx>. To try it out, run `cargo run` from that
+directory.
+
+- [demo/src/main.rs](https://github.com/dtolnay/cxx/blob/master/demo/src/main.rs)
+- [demo/include/blobstore.h](https://github.com/dtolnay/cxx/blob/master/demo/include/blobstore.h)
+- [demo/src/blobstore.cc](https://github.com/dtolnay/cxx/blob/master/demo/src/blobstore.cc)
+
+The key takeaway, which is enabled by the CXX library, is that the Rust code in
+main.rs is 100% ordinary safe Rust code working idiomatically with Rust types
+while the C++ code in blobstore.cc is 100% ordinary C++ code working
+idiomatically with C++ types. The Rust code feels like Rust and the C++ code
+feels like C++, not like C-style "FFI glue".
+
+<br>
+
+***Chapter outline:** See the hamburger menu in the top left if you are on a
+small screen and it didn't open with a sidebar by default.*
diff --git a/book/src/overview.svg b/book/src/overview.svg
new file mode 100644
index 000000000..850e0343a
--- /dev/null
+++ b/book/src/overview.svg
@@ -0,0 +1,131 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="696" height="224">
+    <style>line, path, circle,rect,polygon {
+                          stroke: black;
+                          stroke-width: 2;
+                          stroke-opacity: 1;
+                          fill-opacity: 1;
+                          stroke-linecap: round;
+                          stroke-linejoin: miter;
+                        }
+
+                    text {
+                        fill: black;
+                        }
+                        rect.backdrop{
+                            stroke: none;
+                            fill: white;
+                            fill-opacity: 0;
+                        }
+                        .broken{
+                            stroke-dasharray: 8;
+                        }
+                        .filled{
+                            fill: black;
+                        }
+                        .bg_filled{
+                            fill: white;
+                        }
+                        .nofill{
+                            fill: white;
+                            fill-opacity: 0;
+                        }
+
+                        text {
+                         font-family: monospace;
+                         font-size: 14px;
+                        }
+
+                        .end_marked_arrow{
+                            marker-end: url(#arrow);
+                         }
+                        .start_marked_arrow{
+                            marker-start: url(#arrow);
+                         }
+
+                        .end_marked_diamond{
+                            marker-end: url(#diamond);
+                         }
+                        .start_marked_diamond{
+                            marker-start: url(#diamond);
+                         }
+
+                        .end_marked_circle{
+                            marker-end: url(#circle);
+                         }
+                        .start_marked_circle{
+                            marker-start: url(#circle);
+                         }
+
+                        .end_marked_open_circle{
+                            marker-end: url(#open_circle);
+                         }
+                        .start_marked_open_circle{
+                            marker-start: url(#open_circle);
+                         }
+
+                        .end_marked_big_open_circle{
+                            marker-end: url(#big_open_circle);
+                         }
+                        .start_marked_big_open_circle{
+                            marker-start: url(#big_open_circle);
+                         }
+
+                         
+                        </style>
+    <defs>
+        <marker id="arrow" viewBox="-2 -2 8 8" refX="4" refY="2" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
+            <polygon points="0,0 0,4 4,2 0,0"></polygon>
+        </marker>
+        <marker id="diamond" viewBox="-2 -2 8 8" refX="4" refY="2" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
+            <polygon points="0,2 2,0 4,2 2,4 0,2"></polygon>
+        </marker>
+        <marker id="circle" viewBox="0 0 8 8" refX="4" refY="4" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
+            <circle cx="4" cy="4" r="2" class="filled"></circle>
+        </marker>
+        <marker id="open_circle" viewBox="0 0 8 8" refX="4" refY="4" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
+            <circle cx="4" cy="4" r="2" class="bg_filled"></circle>
+        </marker>
+        <marker id="big_open_circle" viewBox="0 0 8 8" refX="4" refY="4" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
+            <circle cx="4" cy="4" r="3" class="bg_filled"></circle>
+        </marker>
+    </defs>
+    <rect class="backdrop" x="0" y="0" width="696" height="224"></rect>
+    <rect x="148" y="168" width="136" height="32" class="solid nofill" rx="4"></rect>
+    <text x="162" y="188" >Rust bindings</text>
+    <rect x="412" y="168" width="128" height="32" class="solid nofill" rx="4"></rect>
+    <text x="426" y="188" >C++ bindings</text>
+    <text x="272" y="28" >#[cxx::bridge] mod</text>
+    <text x="250" y="44" >description of boundary</text>
+    <line x1="220" y1="120" x2="220" y2="160" class="solid end_marked_arrow"></line>
+    <line x1="476" y1="120" x2="476" y2="160" class="solid end_marked_arrow"></line>
+    <text x="74" y="140" >Safe</text>
+    <text x="34" y="156" >straightforward</text>
+    <text x="530" y="156" >Straightforward</text>
+    <polygon points="48,180 40,184 48,188" class="filled"></polygon>
+    <line x1="48" y1="184" x2="144" y2="184" class="solid end_marked_arrow"></line>
+    <polygon points="296,180 288,184 296,188" class="filled"></polygon>
+    <line x1="296" y1="184" x2="408" y2="184" class="broken end_marked_arrow"></line>
+    <polygon points="552,180 544,184 552,188" class="filled"></polygon>
+    <line x1="552" y1="184" x2="648" y2="184" class="solid end_marked_arrow"></line>
+    <text x="2" y="188" >Rust</text>
+    <text x="2" y="204" >code</text>
+    <text x="658" y="204" >code</text>
+    <text x="202" y="108" >Macro expansion</text>
+    <text x="370" y="108" >Code generation</text>
+    <text x="58" y="172" >Rust APIs</text>
+    <text x="298" y="172" >Hidden C ABI</text>
+    <text x="562" y="172" >C++ APIs</text>
+    <text x="658" y="188" >C++</text>
+    <g>
+        <path d="M 228,8 A 8,8 0,0,0 220,16" class="nofill"></path>
+        <line x1="228" y1="8" x2="468" y2="8" class="solid"></line>
+        <path d="M 468,8 A 8,8 0,0,1 476,16" class="nofill"></path>
+        <line x1="220" y1="16" x2="220" y2="48" class="solid"></line>
+        <line x1="476" y1="16" x2="476" y2="48" class="solid"></line>
+        <path d="M 220,48 A 8,8 0,0,0 228,56" class="nofill"></path>
+        <line x1="228" y1="56" x2="468" y2="56" class="solid"></line>
+        <line x1="348" y1="56" x2="348" y2="120" class="solid"></line>
+        <path d="M 476,48 A 8,8 0,0,1 468,56" class="nofill"></path>
+        <line x1="220" y1="120" x2="476" y2="120" class="solid"></line>
+    </g>
+</svg>
diff --git a/book/src/reference.md b/book/src/reference.md
new file mode 100644
index 000000000..62ca35c51
--- /dev/null
+++ b/book/src/reference.md
@@ -0,0 +1,29 @@
+{{#title The bridge module — Rust ♡ C++}}
+# The bridge module reference
+
+The ***[Core concepts](concepts.md)*** in chapter 2 covered the high level model
+that CXX uses to represent a language boundary. This chapter builds on that one
+to document an exhaustive reference on the syntax and functionality of
+\#\[cxx::bridge\].
+
+- ***[extern "Rust"](extern-rust.md)*** &mdash; exposing opaque Rust types, Rust
+  functions, Rust methods to C++; functions with lifetimes.
+
+- ***[extern "C++"](extern-c++.md)*** &mdash; binding opaque C++ types, C++
+  functions, C++ member functions; sharing an opaque type definition across
+  multiple bridge modules or different crates; using bindgen-generated data
+  structures across a CXX bridge; Rust orphan-rule-compatible way to request
+  that particular glue code be emitted in a specific bridge module.
+
+- ***[Shared types](shared.md)*** &mdash; shared structs; shared enums; using
+  Rust as source of truth vs C++ as source of truth.
+
+- ***[Attributes](attributes.md)*** &mdash; working with namespaces; giving
+  functions a different name in their non-native language.
+
+- ***[Async functions](async.md)*** &mdash; integrating async C++ with async
+  Rust.
+
+- ***[Error handling](binding/result.md)*** &mdash; representing fallibility on
+  the language boundary; accessing a Rust error message from C++; customizing
+  the set of caught exceptions and their conversion to a Rust error message.
diff --git a/book/src/shared.md b/book/src/shared.md
new file mode 100644
index 000000000..09465fe86
--- /dev/null
+++ b/book/src/shared.md
@@ -0,0 +1,181 @@
+{{#title Shared types — Rust ♡ C++}}
+# Shared types
+
+Shared types enable *both* languages to have visibility into the internals of a
+type. This is in contrast to opaque Rust types and opaque C++ types, for which
+only one side gets to manipulate the internals.
+
+Unlike opaque types, the FFI bridge is allowed to pass and return shared types
+by value.
+
+The order in which shared types are written is not important. C++ is order
+sensitive but CXX will topologically sort and forward-declare your types as
+necessary.
+
+## Shared structs and enums
+
+For enums, only C-like a.k.a. unit variants are currently supported.
+
+```rust,noplayground
+#[cxx::bridge]
+mod ffi {
+    struct PlayingCard {
+        suit: Suit,
+        value: u8,  // A=1, J=11, Q=12, K=13
+    }
+
+    enum Suit {
+        Clubs,
+        Diamonds,
+        Hearts,
+        Spades,
+    }
+
+    unsafe extern "C++" {
+        fn deck() -> Vec<PlayingCard>;
+        fn sort(cards: &mut Vec<PlayingCard>);
+    }
+}
+```
+
+## The generated data structures
+
+Shared structs compile to an aggregate-initialization compatible C++ struct.
+
+Shared enums compile to a C++ `enum class` with a sufficiently sized integral
+base type decided by CXX.
+
+```cpp
+// generated header
+
+struct PlayingCard final {
+  Suit suit;
+  uint8_t value;
+};
+
+enum class Suit : uint8_t {
+  Clubs = 0,
+  Diamonds = 1,
+  Hearts = 2,
+  Spades = 3,
+};
+```
+
+Because it is not UB in C++ for an `enum class` to hold a value different from
+all of the listed variants, we use a Rust representation for shared enums that
+is compatible with this. The API you'll get is something like:
+
+```rust,noplayground
+#[derive(Copy, Clone, PartialEq, Eq)]
+#[repr(transparent)]
+pub struct Suit {
+    pub repr: u8,
+}
+#[allow(non_upper_case_globals)]
+impl Suit {
+    pub const Clubs: Self = Suit { repr: 0 };
+    pub const Diamonds: Self = Suit { repr: 1 };
+    pub const Hearts: Self = Suit { repr: 2 };
+    pub const Spades: Self = Suit { repr: 3 };
+}
+```
+
+Notice you're free to treat the enum as an integer in Rust code via the public
+`repr` field.
+
+Pattern matching with `match` still works but will require you to write wildcard
+arms to handle the situation of an enum value that is not one of the listed
+variants.
+
+```rust,noplayground
+fn main() {
+    let suit: Suit = /*...*/;
+    match suit {
+        Suit::Clubs => ...,
+        Suit::Diamonds => ...,
+        Suit::Hearts => ...,
+        Suit::Spades => ...,
+        _ => ...,  // fallback arm
+    }
+}
+```
+
+## Enum discriminants
+
+You may provide explicit discriminants for some or all of the enum variants, in
+which case those numbers will be propagated into the generated C++ `enum class`.
+
+```rust,noplayground
+#[cxx::bridge]
+mod ffi {
+    enum SmallPrime {
+        Two = 2,
+        Three = 3,
+        Five = 5,
+        Seven = 7,
+    }
+}
+```
+
+Variants without an explicit discriminant are assigned the previous discriminant
+plus 1. If the first variant has not been given an explicit discriminant, it is
+assigned discriminant 0.
+
+By default CXX represents your enum using the smallest integer type capable of
+fitting all the discriminants (whether explicit or implicit). If you need a
+different representation for reasons, provide a `repr` attribute.
+
+```rust,noplayground
+#[cxx::bridge]
+mod ffi {
+    #[repr(i32)]
+    enum Enum {
+        Zero,
+        One,
+        Five = 5,
+        Six,
+    }
+}
+```
+
+```cpp
+// generated header
+
+enum class Enum : int32_t {
+  Zero = 0,
+  One = 1,
+  Five = 5,
+  Six = 6,
+};
+```
+
+## Extern enums
+
+If you need to interoperate with an already existing enum for which an existing
+C++ definition is the source of truth, make sure that definition is provided by
+some header in the bridge and then declare your enum *additionally* as an extern
+C++ type.
+
+```rust,noplayground
+#[cxx::bridge]
+mod ffi {
+    enum Enum {
+        Yes,
+        No,
+    }
+
+    extern "C++" {
+        include!("path/to/the/header.h");
+        type Enum;
+    }
+}
+```
+
+CXX will recognize this pattern and, instead of generating a C++ definition of
+the enum, will instead generate C++ static assertions asserting that the
+variants and discriminant values and integer representation written in Rust all
+correctly match the existing C++ enum definition.
+
+Extern enums support all the same features as ordinary shared enums (explicit
+discriminants, repr). Again, CXX will static assert that all of those things you
+wrote are correct.
diff --git a/book/src/tutorial.md b/book/src/tutorial.md
new file mode 100644
index 000000000..a375ea0ac
--- /dev/null
+++ b/book/src/tutorial.md
@@ -0,0 +1,687 @@
+{{#title Tutorial — Rust ♡ C++}}
+# Tutorial: CXX blobstore client
+
+This example walks through a Rust application that calls into a C++ client of a
+blobstore service. In fact we'll see calls going in both directions: Rust to C++
+as well as C++ to Rust. For your own use case it may be that you need just one
+of these directions.
+
+All of the code involved in the example is shown on this page, but it's also
+provided in runnable form in the *demo* directory of
+<https://github.com/dtolnay/cxx>. To try it out directly, run `cargo run` from
+that directory.
+
+This tutorial assumes you've read briefly about **shared structs**, **opaque
+types**, and **functions** in the [*Core concepts*](concepts.md) page.
+
+## Creating the project
+
+We'll use Cargo, which is the build system commonly used by open source Rust
+projects. (CXX works with other build systems too; refer to chapter 5.)
+
+Create a blank Cargo project: `mkdir cxx-demo`; `cd cxx-demo`; `cargo init`.
+
+Edit the Cargo.toml to add a dependency on the `cxx` crate:
+
+```toml,hidelines
+## Cargo.toml
+# [package]
+# name = "cxx-demo"
+# version = "0.1.0"
+# edition = "2018"
+
+[dependencies]
+cxx = "1.0"
+```
+
+We'll revisit this Cargo.toml later when we get to compiling some C++ code.
+
+## Defining the language boundary
+
+CXX relies on a description of the function signatures that will be exposed from
+each language to the other. You provide this description using `extern` blocks
+in a Rust module annotated with the `#[cxx::bridge]` attribute macro.
+
+We'll open with just the following at the top of src/main.rs and walk through
+each item in detail.
+
+```rust,noplayground
+// src/main.rs
+
+#[cxx::bridge]
+mod ffi {
+
+}
+#
+# fn main() {}
+```
+
+The contents of this module will be everything that needs to be agreed upon by
+both sides of the FFI boundary.
+
+## Calling a C++ function from Rust
+
+Let's obtain an instance of the C++ blobstore client, a class `BlobstoreClient`
+defined in C++.
+
+We'll treat `BlobstoreClient` as an *opaque type* in CXX's classification so
+that Rust does not need to assume anything about its implementation, not even
+its size or alignment. In general, a C++ type might have a move-constructor
+which is incompatible with Rust's move semantics, or may hold internal
+references which cannot be modeled by Rust's borrowing system. Though there are
+alternatives, the easiest way to not care about any such thing on an FFI
+boundary is to require no knowledge about a type by treating it as opaque.
+
+Opaque types may only be manipulated behind an indirection such as a reference
+`&`, a Rust `Box`, or a `UniquePtr` (Rust binding of `std::unique_ptr`). We'll
+add a function through which C++ can return a `std::unique_ptr<BlobstoreClient>`
+to Rust.
+
+```rust,noplayground
+// src/main.rs
+
+#[cxx::bridge]
+mod ffi {
+    unsafe extern "C++" {
+        include!("cxx-demo/include/blobstore.h");
+
+        type BlobstoreClient;
+
+        fn new_blobstore_client() -> UniquePtr<BlobstoreClient>;
+    }
+}
+
+fn main() {
+    let client = ffi::new_blobstore_client();
+}
+```
+
+The nature of `unsafe` extern blocks is clarified in more detail in the
+[*extern "C++"*](extern-c++.md) chapter. In brief: the programmer is **not**
+promising that the signatures they have typed in are accurate; that would be
+unreasonable. CXX performs static assertions that the signatures exactly match
+what is declared in C++. Rather, the programmer is only on the hook for things
+that C++'s semantics are not precise enough to capture, i.e. things that would
+only be represented at most by comments in the C++ code. In this case, it's
+whether `new_blobstore_client` is safe or unsafe to call. If that function said
+something like "must be called at most once or we'll stomp yer memery", Rust
+would instead want to expose it as `unsafe fn new_blobstore_client`, this time
+inside a safe `extern "C++"` block because the programmer is no longer on the
+hook for any safety claim about the signature.
+
+If you build this file right now with `cargo build`, it won't build because we
+haven't written a C++ implementation of `new_blobstore_client` nor instructed
+Cargo about how to link it into the resulting binary. You'll see an error from
+the linker like this:
+
+```console
+error: linking with `cc` failed: exit code: 1
+ |
+ = /bin/ld: target/debug/deps/cxx-demo-7cb7fddf3d67d880.rcgu.o: in function `cxx_demo::ffi::new_blobstore_client':
+   src/main.rs:1: undefined reference to `cxxbridge1$new_blobstore_client'
+   collect2: error: ld returned 1 exit status
+```
+
+## Adding in the C++ code
+
+In CXX's integration with Cargo, all #include paths begin with a crate name by
+default (when not explicitly selected otherwise by a crate; see
+`CFG.include_prefix` in chapter 5). That's why we see
+`include!("cxx-demo/include/blobstore.h")` above &mdash; we'll be putting the
+C++ header at relative path `include/blobstore.h` within the Rust crate. If your
+crate is named something other than `cxx-demo` according to the `name` field in
+Cargo.toml, you will need to use that name everywhere in place of `cxx-demo`
+throughout this tutorial.
+
+```cpp
+// include/blobstore.h
+
+#pragma once
+#include <memory>
+
+class BlobstoreClient {
+public:
+  BlobstoreClient();
+};
+
+std::unique_ptr<BlobstoreClient> new_blobstore_client();
+```
+
+```cpp
+// src/blobstore.cc
+
+#include "cxx-demo/include/blobstore.h"
+
+BlobstoreClient::BlobstoreClient() {}
+
+std::unique_ptr<BlobstoreClient> new_blobstore_client() {
+  return std::unique_ptr<BlobstoreClient>(new BlobstoreClient());
+}
+```
+
+Using `std::make_unique` would work too, as long as you pass `-std=c++14` to the
+C++ compiler as described later on.
+
+The placement in *include/* and *src/* is not significant; you can place C++
+code anywhere else in the crate as long as you use the right paths throughout
+the tutorial.
+
+Be aware that *CXX does not look at any of these files.* You're free to put
+arbitrary C++ code in here, #include your own libraries, etc. All we do is emit
+static assertions against what you provide in the headers.
+
+## Compiling the C++ code with Cargo
+
+Cargo has a [build scripts] feature suitable for compiling non-Rust code.
+
+We need to introduce a new build-time dependency on CXX's C++ code generator in
+Cargo.toml:
+
+```toml,hidelines
+## Cargo.toml
+# [package]
+# name = "cxx-demo"
+# version = "0.1.0"
+# edition = "2018"
+
+[dependencies]
+cxx = "1.0"
+
+[build-dependencies]
+cxx-build = "1.0"
+```
+
+Then add a build.rs build script adjacent to Cargo.toml to run the cxx-build
+code generator and C++ compiler. The relevant arguments are the path to the Rust
+source file containing the cxx::bridge language boundary definition, and the
+paths to any additional C++ source files to be compiled during the Rust crate's
+build.
+
+```rust,noplayground
+// build.rs
+
+fn main() {
+    cxx_build::bridge("src/main.rs")
+        .file("src/blobstore.cc")
+        .compile("cxx-demo");
+}
+```
+
+This build.rs would also be where you set up C++ compiler flags, for example if
+you'd like to have access to `std::make_unique` from C++14. See the page on
+***[Cargo-based builds](build/cargo.md)*** for more details about CXX's Cargo
+integration.
+
+```rust,noplayground
+# // build.rs
+#
+# fn main() {
+    cxx_build::bridge("src/main.rs")
+        .file("src/blobstore.cc")
+        .flag_if_supported("-std=c++14")
+        .compile("cxx-demo");
+# }
+```
+
+[build scripts]: https://doc.rust-lang.org/cargo/reference/build-scripts.html
+
+The project should now build and run successfully, though not do anything useful
+yet.
+
+```console
+cxx-demo$  cargo run
+  Compiling cxx-demo v0.1.0
+  Finished dev [unoptimized + debuginfo] target(s) in 0.34s
+  Running `target/debug/cxx-demo`
+
+cxx-demo$
+```
+
+## Calling a Rust function from C++
+
+Our C++ blobstore supports a `put` operation for a discontiguous buffer upload.
+For example we might be uploading snapshots of a circular buffer which would
+tend to consist of 2 pieces, or fragments of a file spread across memory for
+some other reason (like a rope data structure).
+
+We'll express this by handing off an iterator over contiguous borrowed chunks.
+This loosely resembles the API of the widely used `bytes` crate's `Buf` trait.
+During a `put`, we'll make C++ call back into Rust to obtain contiguous chunks
+of the upload (all with no copying or allocation on the language boundary). In
+reality the C++ client might contain some sophisticated batching of chunks
+and/or parallel uploading that all of this ties into.
+
+```rust,noplayground
+// src/main.rs
+
+#[cxx::bridge]
+mod ffi {
+    extern "Rust" {
+        type MultiBuf;
+
+        fn next_chunk(buf: &mut MultiBuf) -> &[u8];
+    }
+
+    unsafe extern "C++" {
+        include!("cxx-demo/include/blobstore.h");
+
+        type BlobstoreClient;
+
+        fn new_blobstore_client() -> UniquePtr<BlobstoreClient>;
+        fn put(&self, parts: &mut MultiBuf) -> u64;
+    }
+}
+#
+# fn main() {
+#     let client = ffi::new_blobstore_client();
+# }
+```
+
+Any signature having a `self` parameter (the Rust name for C++'s `this`) is
+considered a method / non-static member function. If there is only one `type` in
+the surrounding extern block, it'll be a method of that type. If there is more
+than one `type`, you can disambiguate which one a method belongs to by writing
+`self: &BlobstoreClient` in the argument list.
+
+As usual, now we need to provide Rust definitions of everything declared by the
+`extern "Rust"` block and a C++ definition of the new signature declared by the
+`extern "C++"` block.
+
+```rust,noplayground
+// src/main.rs
+#
+# #[cxx::bridge]
+# mod ffi {
+#     extern "Rust" {
+#         type MultiBuf;
+#
+#         fn next_chunk(buf: &mut MultiBuf) -> &[u8];
+#     }
+#
+#     unsafe extern "C++" {
+#         include!("cxx-demo/include/blobstore.h");
+#
+#         type BlobstoreClient;
+#
+#         fn new_blobstore_client() -> UniquePtr<BlobstoreClient>;
+#         fn put(&self, parts: &mut MultiBuf) -> u64;
+#     }
+# }
+
+// An iterator over contiguous chunks of a discontiguous file object. Toy
+// implementation uses a Vec<Vec<u8>> but in reality this might be iterating
+// over some more complex Rust data structure like a rope, or maybe loading
+// chunks lazily from somewhere.
+pub struct MultiBuf {
+    chunks: Vec<Vec<u8>>,
+    pos: usize,
+}
+
+pub fn next_chunk(buf: &mut MultiBuf) -> &[u8] {
+    let next = buf.chunks.get(buf.pos);
+    buf.pos += 1;
+    next.map(Vec::as_slice).unwrap_or(&[])
+}
+#
+# fn main() {
+#     let client = ffi::new_blobstore_client();
+# }
+```
+
+```cpp,hidelines
+// include/blobstore.h
+
+# #pragma once
+# #include <memory>
+#
+struct MultiBuf;
+
+class BlobstoreClient {
+public:
+  BlobstoreClient();
+  uint64_t put(MultiBuf &buf) const;
+};
+#
+#std::unique_ptr<BlobstoreClient> new_blobstore_client();
+```
+
+In blobstore.cc we're able to call the Rust `next_chunk` function, exposed to
+C++ by a header `main.rs.h` generated by the CXX code generator. In CXX's Cargo
+integration this generated header has a path containing the crate name, the
+relative path of the Rust source file within the crate, and a `.rs.h` extension.
+
+```cpp,hidelines
+// src/blobstore.cc
+
+##include "cxx-demo/include/blobstore.h"
+##include "cxx-demo/src/main.rs.h"
+##include <functional>
+#
+# BlobstoreClient::BlobstoreClient() {}
+#
+# std::unique_ptr<BlobstoreClient> new_blobstore_client() {
+#   return std::make_unique<BlobstoreClient>();
+# }
+
+// Upload a new blob and return a blobid that serves as a handle to the blob.
+uint64_t BlobstoreClient::put(MultiBuf &buf) const {
+  // Traverse the caller's chunk iterator.
+  std::string contents;
+  while (true) {
+    auto chunk = next_chunk(buf);
+    if (chunk.size() == 0) {
+      break;
+    }
+    contents.append(reinterpret_cast<const char *>(chunk.data()), chunk.size());
+  }
+
+  // Pretend we did something useful to persist the data.
+  auto blobid = std::hash<std::string>{}(contents);
+  return blobid;
+}
+```
+
+This is now ready to use. :)
+
+```rust,noplayground
+// src/main.rs
+#
+# #[cxx::bridge]
+# mod ffi {
+#     extern "Rust" {
+#         type MultiBuf;
+#
+#         fn next_chunk(buf: &mut MultiBuf) -> &[u8];
+#     }
+#
+#     unsafe extern "C++" {
+#         include!("cxx-demo/include/blobstore.h");
+#
+#         type BlobstoreClient;
+#
+#         fn new_blobstore_client() -> UniquePtr<BlobstoreClient>;
+#         fn put(&self, parts: &mut MultiBuf) -> u64;
+#     }
+# }
+#
+# pub struct MultiBuf {
+#     chunks: Vec<Vec<u8>>,
+#     pos: usize,
+# }
+# pub fn next_chunk(buf: &mut MultiBuf) -> &[u8] {
+#     let next = buf.chunks.get(buf.pos);
+#     buf.pos += 1;
+#     next.map(Vec::as_slice).unwrap_or(&[])
+# }
+
+fn main() {
+    let client = ffi::new_blobstore_client();
+
+    // Upload a blob.
+    let chunks = vec![b"fearless".to_vec(), b"concurrency".to_vec()];
+    let mut buf = MultiBuf { chunks, pos: 0 };
+    let blobid = client.put(&mut buf);
+    println!("blobid = {}", blobid);
+}
+```
+
+```console
+cxx-demo$  cargo run
+  Compiling cxx-demo v0.1.0
+  Finished dev [unoptimized + debuginfo] target(s) in 0.41s
+  Running `target/debug/cxx-demo`
+
+blobid = 9851996977040795552
+```
+
+## Interlude: What gets generated?
+
+For the curious, it's easy to look behind the scenes at what CXX has done to
+make these function calls work. You shouldn't need to do this during normal
+usage of CXX, but for the purpose of this tutorial it can be educative.
+
+CXX comprises *two* code generators: a Rust one (which is the cxx::bridge
+attribute procedural macro) and a C++ one.
+
+### Rust generated code
+
+It's easiest to view the output of the procedural macro by installing
+[cargo-expand]. Then run `cargo expand ::ffi` to macro-expand the `mod ffi`
+module.
+
+[cargo-expand]: https://github.com/dtolnay/cargo-expand
+
+```console
+cxx-demo$  cargo install cargo-expand
+cxx-demo$  cargo expand ::ffi
+```
+
+You'll see some deeply unpleasant code involving `#[repr(C)]`, `#[link_name]`,
+and `#[export_name]`.
+
+### C++ generated code
+
+For debugging convenience, `cxx_build` links all generated C++ code into Cargo's
+target directory under *target/cxxbridge/*.
+
+```console
+cxx-demo$  exa -T target/cxxbridge/
+target/cxxbridge
+├── cxx-demo
+│  └── src
+│     ├── main.rs.cc -> ../../../debug/build/cxx-demo-11c6f678ce5c3437/out/cxxbridge/sources/cxx-demo/src/main.rs.cc
+│     └── main.rs.h -> ../../../debug/build/cxx-demo-11c6f678ce5c3437/out/cxxbridge/include/cxx-demo/src/main.rs.h
+└── rust
+   └── cxx.h -> ~/.cargo/registry/src/github.com-1ecc6299db9ec823/cxx-1.0.0/include/cxx.h
+```
+
+In those files you'll see declarations or templates of any CXX Rust types
+present in your language boundary (like `rust::Slice<T>` for `&[T]`) and `extern
+"C"` signatures corresponding to your extern functions.
+
+If it fits your workflow better, the CXX C++ code generator is also available as
+a standalone executable which outputs generated code to stdout.
+
+```console
+cxx-demo$  cargo install cxxbridge-cmd
+cxx-demo$  cxxbridge src/main.rs
+```
+
+## Shared data structures
+
+So far the calls in both directions above only used **opaque types**, not
+**shared structs**.
+
+Shared structs are data structures whose complete definition is visible to both
+languages, making it possible to pass them by value across the language
+boundary. Shared structs translate to a C++ aggregate-initialization compatible
+struct exactly matching the layout of the Rust one.
+
+As the last step of this demo, we'll use a shared struct `BlobMetadata` to pass
+metadata about blobs between our Rust application and C++ blobstore client.
+
+```rust,noplayground
+// src/main.rs
+
+#[cxx::bridge]
+mod ffi {
+    struct BlobMetadata {
+        size: usize,
+        tags: Vec<String>,
+    }
+
+    extern "Rust" {
+        // ...
+#         type MultiBuf;
+#
+#         fn next_chunk(buf: &mut MultiBuf) -> &[u8];
+    }
+
+    unsafe extern "C++" {
+        // ...
+#         include!("cxx-demo/include/blobstore.h");
+#
+#         type BlobstoreClient;
+#
+#         fn new_blobstore_client() -> UniquePtr<BlobstoreClient>;
+#         fn put(&self, parts: &mut MultiBuf) -> u64;
+        fn tag(&self, blobid: u64, tag: &str);
+        fn metadata(&self, blobid: u64) -> BlobMetadata;
+    }
+}
+#
+# pub struct MultiBuf {
+#     chunks: Vec<Vec<u8>>,
+#     pos: usize,
+# }
+# pub fn next_chunk(buf: &mut MultiBuf) -> &[u8] {
+#     let next = buf.chunks.get(buf.pos);
+#     buf.pos += 1;
+#     next.map(Vec::as_slice).unwrap_or(&[])
+# }
+
+fn main() {
+    let client = ffi::new_blobstore_client();
+
+    // Upload a blob.
+    let chunks = vec![b"fearless".to_vec(), b"concurrency".to_vec()];
+    let mut buf = MultiBuf { chunks, pos: 0 };
+    let blobid = client.put(&mut buf);
+    println!("blobid = {}", blobid);
+
+    // Add a tag.
+    client.tag(blobid, "rust");
+
+    // Read back the tags.
+    let metadata = client.metadata(blobid);
+    println!("tags = {:?}", metadata.tags);
+}
+```
+
+```cpp,hidelines
+// include/blobstore.h
+#
+# #pragma once
+# #include "rust/cxx.h"
+# #include <memory>
+
+struct MultiBuf;
+struct BlobMetadata;
+
+class BlobstoreClient {
+public:
+  BlobstoreClient();
+  uint64_t put(MultiBuf &buf) const;
+  void tag(uint64_t blobid, rust::Str tag) const;
+  BlobMetadata metadata(uint64_t blobid) const;
+
+private:
+  class impl;
+  std::shared_ptr<impl> impl;
+};
+#
+# std::unique_ptr<BlobstoreClient> new_blobstore_client();
+```
+
+```cpp,hidelines
+// src/blobstore.cc
+
+##include "cxx-demo/include/blobstore.h"
+##include "cxx-demo/src/main.rs.h"
+##include <algorithm>
+##include <functional>
+##include <set>
+##include <string>
+##include <unordered_map>
+
+// Toy implementation of an in-memory blobstore.
+//
+// In reality the implementation of BlobstoreClient could be a large
+// complex C++ library.
+class BlobstoreClient::impl {
+  friend BlobstoreClient;
+  using Blob = struct {
+    std::string data;
+    std::set<std::string> tags;
+  };
+  std::unordered_map<uint64_t, Blob> blobs;
+};
+
+BlobstoreClient::BlobstoreClient() : impl(new class BlobstoreClient::impl) {}
+#
+# // Upload a new blob and return a blobid that serves as a handle to the blob.
+# uint64_t BlobstoreClient::put(MultiBuf &buf) const {
+#   // Traverse the caller's chunk iterator.
+#   std::string contents;
+#   while (true) {
+#     auto chunk = next_chunk(buf);
+#     if (chunk.size() == 0) {
+#       break;
+#     }
+#     contents.append(reinterpret_cast<const char *>(chunk.data()), chunk.size());
+#   }
+#
+#   // Insert into map and provide caller the handle.
+#   auto blobid = std::hash<std::string>{}(contents);
+#   impl->blobs[blobid] = {std::move(contents), {}};
+#   return blobid;
+# }
+
+// Add tag to an existing blob.
+void BlobstoreClient::tag(uint64_t blobid, rust::Str tag) const {
+  impl->blobs[blobid].tags.emplace(tag);
+}
+
+// Retrieve metadata about a blob.
+BlobMetadata BlobstoreClient::metadata(uint64_t blobid) const {
+  BlobMetadata metadata{};
+  auto blob = impl->blobs.find(blobid);
+  if (blob != impl->blobs.end()) {
+    metadata.size = blob->second.data.size();
+    std::for_each(blob->second.tags.cbegin(), blob->second.tags.cend(),
+                  [&](auto &t) { metadata.tags.emplace_back(t); });
+  }
+  return metadata;
+}
+#
+# std::unique_ptr<BlobstoreClient> new_blobstore_client() {
+#   return std::make_unique<BlobstoreClient>();
+# }
+```
+
+```console
+cxx-demo$  cargo run
+  Running `target/debug/cxx-demo`
+
+blobid = 9851996977040795552
+tags = ["rust"]
+```
+
+*You've now seen all the code involved in the tutorial. It's available all
+together in runnable form in the* demo *directory of
+<https://github.com/dtolnay/cxx>. You can run it directly without stepping
+through the steps above by running `cargo run` from that directory.*
+
+<br>
+
+# Takeaways
+
+The key contribution of CXX is it gives you Rust&ndash;C++ interop in which
+*all* of the Rust side of the code you write *really* looks like you are just
+writing normal Rust, and the C++ side *really* looks like you are just writing
+normal C++.
+
+You've seen in this tutorial that none of the code involved feels like C or like
+the usual perilous "FFI glue" prone to leaks or memory safety flaws.
+
+An expressive system of opaque types, shared types, and key standard library
+type bindings enables API design on the language boundary that captures the
+proper ownership and borrowing contracts of the interface.
+
+CXX plays to the strengths of the Rust type system *and* C++ type system *and*
+the programmer's intuitions. An individual working on the C++ side without a
+Rust background, or the Rust side without a C++ background, will be able to
+apply all their usual intuitions and best practices about development in their
+language to maintain a correct FFI.
+
+<br><br>


Test patch: