10467d6f9SAlex Crichton /**
20467d6f9SAlex Crichton * \file wasmtime/error.hh
30467d6f9SAlex Crichton */
40467d6f9SAlex Crichton
50467d6f9SAlex Crichton #ifndef WASMTIME_ERROR_HH
60467d6f9SAlex Crichton #define WASMTIME_ERROR_HH
70467d6f9SAlex Crichton
80467d6f9SAlex Crichton #include <memory>
90467d6f9SAlex Crichton #include <optional>
10313f23d8SAlex Crichton #include <ostream>
110467d6f9SAlex Crichton #include <string>
120467d6f9SAlex Crichton #include <variant>
130467d6f9SAlex Crichton #include <wasmtime/error.h>
14*311d023aSAlex Crichton #include <wasmtime/helpers.hh>
150467d6f9SAlex Crichton
160467d6f9SAlex Crichton namespace wasmtime {
170467d6f9SAlex Crichton
180467d6f9SAlex Crichton class Trace;
190467d6f9SAlex Crichton
200467d6f9SAlex Crichton /**
210467d6f9SAlex Crichton * \brief Errors coming from Wasmtime
220467d6f9SAlex Crichton *
230467d6f9SAlex Crichton * This class represents an error that came from Wasmtime and contains a textual
240467d6f9SAlex Crichton * description of the error that occurred.
250467d6f9SAlex Crichton */
260467d6f9SAlex Crichton class Error {
27*311d023aSAlex Crichton WASMTIME_OWN_WRAPPER(Error, wasmtime_error);
280467d6f9SAlex Crichton
290467d6f9SAlex Crichton /// \brief Creates an error with the provided message.
Error(const std::string & s)300467d6f9SAlex Crichton Error(const std::string &s) : ptr(wasmtime_error_new(s.c_str())) {}
310467d6f9SAlex Crichton
320467d6f9SAlex Crichton /// \brief Returns the error message associated with this error.
message() const330467d6f9SAlex Crichton std::string message() const {
340467d6f9SAlex Crichton wasm_byte_vec_t msg_bytes;
350467d6f9SAlex Crichton wasmtime_error_message(ptr.get(), &msg_bytes);
360467d6f9SAlex Crichton auto ret = std::string(msg_bytes.data, msg_bytes.size);
370467d6f9SAlex Crichton wasm_byte_vec_delete(&msg_bytes);
380467d6f9SAlex Crichton return ret;
390467d6f9SAlex Crichton }
400467d6f9SAlex Crichton
410467d6f9SAlex Crichton /// If this trap represents a call to `exit` for WASI, this will return the
420467d6f9SAlex Crichton /// optional error code associated with the exit trap.
i32_exit() const430467d6f9SAlex Crichton std::optional<int32_t> i32_exit() const {
440467d6f9SAlex Crichton int32_t status = 0;
450467d6f9SAlex Crichton if (wasmtime_error_exit_status(ptr.get(), &status)) {
460467d6f9SAlex Crichton return status;
470467d6f9SAlex Crichton }
480467d6f9SAlex Crichton return std::nullopt;
490467d6f9SAlex Crichton }
500467d6f9SAlex Crichton
510467d6f9SAlex Crichton /// Returns the trace of WebAssembly frames associated with this error.
520467d6f9SAlex Crichton ///
530467d6f9SAlex Crichton /// Note that the `trace` cannot outlive this error object.
540467d6f9SAlex Crichton Trace trace() const;
550467d6f9SAlex Crichton };
560467d6f9SAlex Crichton
570467d6f9SAlex Crichton /// \brief Used to print an error.
operator <<(std::ostream & os,const Error & e)580467d6f9SAlex Crichton inline std::ostream &operator<<(std::ostream &os, const Error &e) {
590467d6f9SAlex Crichton os << e.message();
600467d6f9SAlex Crichton return os;
610467d6f9SAlex Crichton }
620467d6f9SAlex Crichton
630467d6f9SAlex Crichton /**
640467d6f9SAlex Crichton * \brief Fallible result type used for Wasmtime.
650467d6f9SAlex Crichton *
660467d6f9SAlex Crichton * This type is used as the return value of many methods in the Wasmtime API.
670467d6f9SAlex Crichton * This behaves similarly to Rust's `Result<T, E>` and will be replaced with a
680467d6f9SAlex Crichton * C++ standard when it exists.
690467d6f9SAlex Crichton */
700467d6f9SAlex Crichton template <typename T, typename E = Error> class [[nodiscard]] Result {
710467d6f9SAlex Crichton std::variant<T, E> data;
720467d6f9SAlex Crichton
730467d6f9SAlex Crichton public:
740467d6f9SAlex Crichton /// \brief Creates a `Result` from its successful value.
Result(T t)750467d6f9SAlex Crichton Result(T t) : data(std::move(t)) {}
760467d6f9SAlex Crichton /// \brief Creates a `Result` from an error value.
Result(E e)770467d6f9SAlex Crichton Result(E e) : data(std::move(e)) {}
780467d6f9SAlex Crichton
790467d6f9SAlex Crichton /// \brief Returns `true` if this result is a success, `false` if it's an
800467d6f9SAlex Crichton /// error
operator bool() const810467d6f9SAlex Crichton explicit operator bool() const { return data.index() == 0; }
820467d6f9SAlex Crichton
830467d6f9SAlex Crichton /// \brief Returns the error, if present, aborts if this is not an error.
err()840467d6f9SAlex Crichton E &&err() { return std::get<E>(std::move(data)); }
850467d6f9SAlex Crichton /// \brief Returns the error, if present, aborts if this is not an error.
err() const860467d6f9SAlex Crichton const E &&err() const { return std::get<E>(std::move(data)); }
870467d6f9SAlex Crichton
880467d6f9SAlex Crichton /// \brief Returns the success, if present, aborts if this is an error.
ok()890467d6f9SAlex Crichton T &&ok() { return std::get<T>(std::move(data)); }
900467d6f9SAlex Crichton /// \brief Returns the success, if present, aborts if this is an error.
ok() const910467d6f9SAlex Crichton const T &&ok() const { return std::get<T>(std::move(data)); }
920467d6f9SAlex Crichton
930467d6f9SAlex Crichton /// \brief Returns the success, if present, aborts if this is an error.
ok_ref()94adff9d9dSAlex Crichton T &ok_ref() { return std::get<T>(data); }
95adff9d9dSAlex Crichton /// \brief Returns the success, if present, aborts if this is an error.
ok_ref() const96adff9d9dSAlex Crichton const T &ok_ref() const { return std::get<T>(data); }
97adff9d9dSAlex Crichton
98adff9d9dSAlex Crichton /// \brief Returns the error, if present, aborts if this is not an error.
err_ref()99adff9d9dSAlex Crichton E &err_ref() { return std::get<T>(data); }
100adff9d9dSAlex Crichton /// \brief Returns the error, if present, aborts if this is not an error.
err_ref() const101adff9d9dSAlex Crichton const E &err_ref() const { return std::get<T>(data); }
102adff9d9dSAlex Crichton
103adff9d9dSAlex Crichton /// \brief Returns the success, if present, aborts if this is an error.
unwrap()1040467d6f9SAlex Crichton T unwrap() {
1050467d6f9SAlex Crichton if (*this) {
1060467d6f9SAlex Crichton return this->ok();
1070467d6f9SAlex Crichton }
1080467d6f9SAlex Crichton unwrap_failed();
1090467d6f9SAlex Crichton }
1100467d6f9SAlex Crichton
1110467d6f9SAlex Crichton private:
unwrap_failed()1120467d6f9SAlex Crichton [[noreturn]] void unwrap_failed() {
1130467d6f9SAlex Crichton fprintf(stderr, "error: %s\n", this->err().message().c_str()); // NOLINT
1140467d6f9SAlex Crichton std::abort();
1150467d6f9SAlex Crichton }
1160467d6f9SAlex Crichton };
1170467d6f9SAlex Crichton
1180467d6f9SAlex Crichton } // namespace wasmtime
1190467d6f9SAlex Crichton
1200467d6f9SAlex Crichton #endif // WASMTIME_ERROR_HH
121