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