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