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