1 /**
2  * \file wasmtime/component/component.hh
3  */
4 
5 #ifndef WASMTIME_COMPONENT_HH
6 #define WASMTIME_COMPONENT_HH
7 
8 #include <wasmtime/conf.h>
9 
10 #ifdef WASMTIME_FEATURE_COMPONENT_MODEL
11 
12 #include <memory>
13 #include <optional>
14 #include <string_view>
15 #include <vector>
16 #include <wasmtime/component/component.h>
17 #include <wasmtime/engine.hh>
18 #include <wasmtime/error.hh>
19 #include <wasmtime/span.hh>
20 #include <wasmtime/wat.hh>
21 
22 namespace wasmtime {
23 namespace component {
24 
25 /**
26  * \brief An index to an exported item within a particular component.
27  *
28  * This structure is acquired from a `Component` and used to lookup exports on
29  * instances.
30  */
31 class ExportIndex {
32   friend class Component;
33 
34   struct deleter {
35     void operator()(wasmtime_component_export_index_t *p) const {
36       wasmtime_component_export_index_delete(p);
37     }
38   };
39 
40   std::unique_ptr<wasmtime_component_export_index_t, deleter> ptr;
41 
42   ExportIndex(wasmtime_component_export_index_t *raw) : ptr(raw) {}
43 
44 public:
45   /// Copies another index into this one.
46   ExportIndex(const ExportIndex &other)
47       : ptr(wasmtime_component_export_index_clone(other.ptr.get())) {}
48   /// Copies another index into this one.
49   ExportIndex &operator=(const ExportIndex &other) {
50     ptr.reset(wasmtime_component_export_index_clone(other.ptr.get()));
51     return *this;
52   }
53 
54   ~ExportIndex() = default;
55   /// Moves resources from another component into this one.
56   ExportIndex(ExportIndex &&other) = default;
57   /// Moves resources from another component into this one.
58   ExportIndex &operator=(ExportIndex &&other) = default;
59 
60   /// \brief Returns the underlying C API pointer.
61   const wasmtime_component_export_index_t *capi() const { return ptr.get(); }
62 
63   /// \brief Returns the underlying C API pointer.
64   wasmtime_component_export_index_t *capi() { return ptr.get(); }
65 };
66 
67 /**
68  * \brief Representation of a compiled WebAssembly component.
69  */
70 class Component {
71   struct deleter {
72     void operator()(wasmtime_component_t *p) const {
73       wasmtime_component_delete(p);
74     }
75   };
76 
77   std::unique_ptr<wasmtime_component_t, deleter> ptr;
78 
79   Component(wasmtime_component_t *raw) : ptr(raw) {}
80 
81 public:
82   /// Copies another component into this one.
83   Component(const Component &other)
84       : ptr(wasmtime_component_clone(other.ptr.get())) {}
85   /// Copies another component into this one.
86   Component &operator=(const Component &other) {
87     ptr.reset(wasmtime_component_clone(other.ptr.get()));
88     return *this;
89   }
90   ~Component() = default;
91   /// Moves resources from another component into this one.
92   Component(Component &&other) = default;
93   /// Moves resources from another component into this one.
94   Component &operator=(Component &&other) = default;
95 
96   /// \brief Returns the underlying C API pointer.
97   const wasmtime_component_t *capi() const { return ptr.get(); }
98 
99   /// \brief Returns the underlying C API pointer.
100   wasmtime_component_t *capi() { return ptr.get(); }
101 
102 #ifdef WASMTIME_FEATURE_COMPILER
103   /**
104    * \brief Compiles a component from the WebAssembly text format.
105    *
106    * This function will automatically use `wat2wasm` on the input and then
107    * delegate to the #compile function.
108    */
109   static Result<Component> compile(Engine &engine, std::string_view wat) {
110     auto wasm = wat2wasm(wat);
111     if (!wasm) {
112       return wasm.err();
113     }
114     auto bytes = wasm.ok();
115     return compile(engine, bytes);
116   }
117 
118   /**
119    * \brief Compiles a component from the WebAssembly binary format.
120    *
121    * This function compiles the provided WebAssembly binary specified by `wasm`
122    * within the compilation settings configured by `engine`. This method is
123    * synchronous and will not return until the component has finished compiling.
124    *
125    * This function can fail if the WebAssembly binary is invalid or doesn't
126    * validate (or similar). Note that this API does not compile WebAssembly
127    * modules, which is done with `Module` instead of `Component`.
128    */
129   static Result<Component> compile(Engine &engine, Span<uint8_t> wasm) {
130     wasmtime_component_t *ret = nullptr;
131     auto *error =
132         wasmtime_component_new(engine.capi(), wasm.data(), wasm.size(), &ret);
133     if (error != nullptr) {
134       return Error(error);
135     }
136     return Component(ret);
137   }
138 #endif // WASMTIME_FEATURE_COMPILER
139 
140   /**
141    * \brief Deserializes a previous list of bytes created with `serialize`.
142    *
143    * This function is intended to be much faster than `compile` where it uses
144    * the artifacts of a previous compilation to quickly create an in-memory
145    * component ready for instantiation.
146    *
147    * It is not safe to pass arbitrary input to this function, it is only safe to
148    * pass in output from previous calls to `serialize`. For more information see
149    * the Rust documentation -
150    * https://docs.wasmtime.dev/api/wasmtime/struct.Module.html#method.deserialize
151    */
152   static Result<Component> deserialize(Engine &engine, Span<uint8_t> wasm) {
153     wasmtime_component_t *ret = nullptr;
154     auto *error = wasmtime_component_deserialize(engine.capi(), wasm.data(),
155                                                  wasm.size(), &ret);
156     if (error != nullptr) {
157       return Error(error);
158     }
159     return Component(ret);
160   }
161 
162   /**
163    * \brief Deserializes a component from an on-disk file.
164    *
165    * This function is the same as `deserialize` except that it reads the data
166    * for the serialized component from the path on disk. This can be faster than
167    * the alternative which may require copying the data around.
168    *
169    * It is not safe to pass arbitrary input to this function, it is only safe to
170    * pass in output from previous calls to `serialize`. For more information see
171    * the Rust documentation -
172    * https://docs.wasmtime.dev/api/wasmtime/struct.Module.html#method.deserialize
173    */
174   static Result<Component> deserialize_file(Engine &engine,
175                                             const std::string &path) {
176     wasmtime_component_t *ret = nullptr;
177     auto *error =
178         wasmtime_component_deserialize_file(engine.capi(), path.c_str(), &ret);
179     if (error != nullptr) {
180       return Error(error);
181     }
182     return Component(ret);
183   }
184 
185 #ifdef WASMTIME_FEATURE_COMPILER
186   /**
187    * \brief Serializes this component to a list of bytes.
188    *
189    * The returned bytes can then be used to later pass to `deserialize` to
190    * quickly recreate this component in a different process perhaps.
191    */
192   Result<std::vector<uint8_t>> serialize() const {
193     wasm_byte_vec_t bytes;
194     auto *error = wasmtime_component_serialize(ptr.get(), &bytes);
195     if (error != nullptr) {
196       return Error(error);
197     }
198     std::vector<uint8_t> ret;
199     Span<uint8_t> raw(reinterpret_cast<uint8_t *>(bytes.data), bytes.size);
200     ret.assign(raw.begin(), raw.end());
201     wasm_byte_vec_delete(&bytes);
202     return ret;
203   }
204 #endif // WASMTIME_FEATURE_COMPILER
205 
206   /**
207    * \brief Returns the export index for the export named `name` in this
208    * component.
209    *
210    * The `instance` argument is an optionally provided index which is the
211    * instance under which the `name` should be looked up.
212    */
213   std::optional<ExportIndex> export_index(ExportIndex *instance,
214                                           std::string_view name) {
215     auto ret = wasmtime_component_get_export_index(
216         capi(), instance ? instance->capi() : nullptr, name.data(),
217         name.size());
218     if (ret) {
219       return ExportIndex(ret);
220     }
221     return std::nullopt;
222   };
223 };
224 
225 } // namespace component
226 } // namespace wasmtime
227 
228 #endif // WASMTIME_FEATURE_COMPONENT_MODEL
229 
230 #endif // WASMTIME_COMPONENT_HH
231