1 /**
2  * \file wasmtime/error.hh
3  */
4 
5 #ifndef WASMTIME_ERROR_HH
6 #define WASMTIME_ERROR_HH
7 
8 #include <memory>
9 #include <optional>
10 #include <string>
11 #include <variant>
12 #include <wasmtime/error.h>
13 
14 namespace wasmtime {
15 
16 class Trace;
17 
18 /**
19  * \brief Errors coming from Wasmtime
20  *
21  * This class represents an error that came from Wasmtime and contains a textual
22  * description of the error that occurred.
23  */
24 class Error {
25   struct deleter {
26     void operator()(wasmtime_error_t *p) const { wasmtime_error_delete(p); }
27   };
28 
29   std::unique_ptr<wasmtime_error_t, deleter> ptr;
30 
31 public:
32   /// \brief Creates an error from the raw C API representation
33   ///
34   /// Takes ownership of the provided `error`.
35   Error(wasmtime_error_t *error) : ptr(error) {}
36 
37   /// \brief Creates an error with the provided message.
38   Error(const std::string &s) : ptr(wasmtime_error_new(s.c_str())) {}
39 
40   /// \brief Returns the error message associated with this error.
41   std::string message() const {
42     wasm_byte_vec_t msg_bytes;
43     wasmtime_error_message(ptr.get(), &msg_bytes);
44     auto ret = std::string(msg_bytes.data, msg_bytes.size);
45     wasm_byte_vec_delete(&msg_bytes);
46     return ret;
47   }
48 
49   /// If this trap represents a call to `exit` for WASI, this will return the
50   /// optional error code associated with the exit trap.
51   std::optional<int32_t> i32_exit() const {
52     int32_t status = 0;
53     if (wasmtime_error_exit_status(ptr.get(), &status)) {
54       return status;
55     }
56     return std::nullopt;
57   }
58 
59   /// Returns the trace of WebAssembly frames associated with this error.
60   ///
61   /// Note that the `trace` cannot outlive this error object.
62   Trace trace() const;
63 
64   /// Release ownership of this error, acquiring the underlying C raw pointer.
65   wasmtime_error_t *release() { return ptr.release(); }
66 };
67 
68 /// \brief Used to print an error.
69 inline std::ostream &operator<<(std::ostream &os, const Error &e) {
70   os << e.message();
71   return os;
72 }
73 
74 /**
75  * \brief Fallible result type used for Wasmtime.
76  *
77  * This type is used as the return value of many methods in the Wasmtime API.
78  * This behaves similarly to Rust's `Result<T, E>` and will be replaced with a
79  * C++ standard when it exists.
80  */
81 template <typename T, typename E = Error> class [[nodiscard]] Result {
82   std::variant<T, E> data;
83 
84 public:
85   /// \brief Creates a `Result` from its successful value.
86   Result(T t) : data(std::move(t)) {}
87   /// \brief Creates a `Result` from an error value.
88   Result(E e) : data(std::move(e)) {}
89 
90   /// \brief Returns `true` if this result is a success, `false` if it's an
91   /// error
92   explicit operator bool() const { return data.index() == 0; }
93 
94   /// \brief Returns the error, if present, aborts if this is not an error.
95   E &&err() { return std::get<E>(std::move(data)); }
96   /// \brief Returns the error, if present, aborts if this is not an error.
97   const E &&err() const { return std::get<E>(std::move(data)); }
98 
99   /// \brief Returns the success, if present, aborts if this is an error.
100   T &&ok() { return std::get<T>(std::move(data)); }
101   /// \brief Returns the success, if present, aborts if this is an error.
102   const T &&ok() const { return std::get<T>(std::move(data)); }
103 
104   /// \brief Returns the success, if present, aborts if this is an error.
105   T unwrap() {
106     if (*this) {
107       return this->ok();
108     }
109     unwrap_failed();
110   }
111 
112 private:
113   [[noreturn]] void unwrap_failed() {
114     fprintf(stderr, "error: %s\n", this->err().message().c_str()); // NOLINT
115     std::abort();
116   }
117 };
118 
119 } // namespace wasmtime
120 
121 #endif // WASMTIME_ERROR_HH
122