summaryrefslogtreecommitdiffstats
path: root/vendor/cxx/book/src/binding/result.md
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/cxx/book/src/binding/result.md')
-rw-r--r--vendor/cxx/book/src/binding/result.md148
1 files changed, 148 insertions, 0 deletions
diff --git a/vendor/cxx/book/src/binding/result.md b/vendor/cxx/book/src/binding/result.md
new file mode 100644
index 000000000..e49dcf4de
--- /dev/null
+++ b/vendor/cxx/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
+```