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