1 /// \file wasmtime/component/linker.hh
2 
3 #ifndef WASMTIME_COMPONENT_LINKER_HH
4 #define WASMTIME_COMPONENT_LINKER_HH
5 
6 #include <wasmtime/conf.h>
7 
8 #ifdef WASMTIME_FEATURE_COMPONENT_MODEL
9 
10 #include <memory>
11 #include <string_view>
12 #include <wasmtime/component/instance.hh>
13 #include <wasmtime/component/linker.h>
14 #include <wasmtime/component/val.hh>
15 #include <wasmtime/engine.hh>
16 #include <wasmtime/module.hh>
17 
18 namespace wasmtime {
19 namespace component {
20 
21 /**
22  * \brief Helper class for linking modules together with name-based resolution.
23  *
24  * This class is used for easily instantiating `Module`s by defining names into
25  * the linker and performing name-based resolution during instantiation. A
26  * `Linker` can also be used to link in WASI functions to instantiate a module.
27  */
28 class LinkerInstance {
29   WASMTIME_OWN_WRAPPER(LinkerInstance, wasmtime_component_linker_instance);
30 
31   /**
32    * \brief Adds a module to this linker instance under the specified name.
33    */
add_module(std::string_view name,Module & module)34   Result<std::monostate> add_module(std::string_view name, Module &module) {
35     wasmtime_error_t *error = wasmtime_component_linker_instance_add_module(
36         ptr.get(), name.data(), name.size(), module.capi());
37     if (error != nullptr) {
38       return Error(error);
39     }
40     return std::monostate();
41   }
42 
43   /**
44    * \brief Adds an new instance to this linker instance under the specified
45    * name.
46    *
47    * Note that this `LinkerInstance` can no longer be used until the returned
48    * `LinkerInstance` is dropped.
49    */
add_instance(std::string_view name)50   Result<LinkerInstance> add_instance(std::string_view name) {
51     wasmtime_component_linker_instance_t *ret = nullptr;
52     wasmtime_error_t *error = wasmtime_component_linker_instance_add_instance(
53         ptr.get(), name.data(), name.size(), &ret);
54     if (error != nullptr) {
55       return Error(error);
56     }
57     return LinkerInstance(ret);
58   }
59 
60 private:
61   template <typename F>
62   static wasmtime_error_t *
raw_callback(void * env,wasmtime_context_t * store,const wasmtime_component_func_type_t * ty_const,wasmtime_component_val_t * args,size_t nargs,wasmtime_component_val_t * results,size_t nresults)63   raw_callback(void *env, wasmtime_context_t *store,
64                const wasmtime_component_func_type_t *ty_const,
65                wasmtime_component_val_t *args, size_t nargs,
66                wasmtime_component_val_t *results, size_t nresults) {
67     static_assert(alignof(Val) == alignof(wasmtime_component_val_t));
68     static_assert(sizeof(Val) == sizeof(wasmtime_component_val_t));
69     wasmtime_component_func_type_t *ty =
70         const_cast<wasmtime_component_func_type_t *>(ty_const);
71     F *func = reinterpret_cast<F *>(env);
72     Span<Val> args_span(Val::from_capi(args), nargs);
73     Span<Val> results_span(Val::from_capi(results), nresults);
74     Result<std::monostate> result =
75         (*func)(Store::Context(store), *FuncType::from_capi(&ty), args_span,
76                 results_span);
77 
78     if (!result) {
79       return result.err().capi_release();
80     }
81     return nullptr;
82   }
83 
raw_finalize(void * env)84   template <typename F> static void raw_finalize(void *env) {
85     std::unique_ptr<F> ptr(reinterpret_cast<F *>(env));
86   }
87 
88 public:
89   /// \brief Defines a function within this linker instance.
90   template <typename F,
91             std::enable_if_t<
92                 std::is_invocable_r_v<Result<std::monostate>, F, Store::Context,
93                                       const FuncType &, Span<Val>, Span<Val>>,
94                 bool> = true>
add_func(std::string_view name,F && f)95   Result<std::monostate> add_func(std::string_view name, F &&f) {
96     auto *error = wasmtime_component_linker_instance_add_func(
97         ptr.get(), name.data(), name.length(),
98         raw_callback<std::remove_reference_t<F>>,
99         std::make_unique<std::remove_reference_t<F>>(std::forward<F>(f))
100             .release(),
101         raw_finalize<std::remove_reference_t<F>>);
102 
103     if (error != nullptr) {
104       return Error(error);
105     }
106 
107     return std::monostate();
108   }
109 
110 private:
111   template <typename F>
112   static wasmtime_error_t *
raw_resource_destructor_callback(void * env,wasmtime_context_t * store,uint32_t rep)113   raw_resource_destructor_callback(void *env, wasmtime_context_t *store,
114                                    uint32_t rep) {
115     F *func = reinterpret_cast<F *>(env);
116     Result<std::monostate> result = (*func)(Store::Context(store), rep);
117     if (!result) {
118       return result.err().capi_release();
119     }
120     return nullptr;
121   }
122 
123 public:
124   /// \brief Defines a new resource in this linker with the provided
125   /// destructor.
126   template <typename F,
127             std::enable_if_t<std::is_invocable_r_v<Result<std::monostate>, F,
128                                                    Store::Context, uint32_t>,
129                              bool> = true>
add_resource(std::string_view name,const ResourceType & ty,F && f)130   Result<std::monostate> add_resource(std::string_view name,
131                                       const ResourceType &ty, F &&f) {
132     auto *error = wasmtime_component_linker_instance_add_resource(
133         ptr.get(), name.data(), name.length(), ty.capi(),
134         raw_resource_destructor_callback<std::remove_reference_t<F>>,
135         std::make_unique<std::remove_reference_t<F>>(std::forward<F>(f))
136             .release(),
137         raw_finalize<std::remove_reference_t<F>>);
138 
139     if (error != nullptr) {
140       return Error(error);
141     }
142 
143     return std::monostate();
144   }
145 };
146 
147 /**
148  * \brief Class used to instantiate a `Component` into an instance.
149  */
150 class Linker {
151   WASMTIME_OWN_WRAPPER(Linker, wasmtime_component_linker);
152 
153   /// Creates a new linker which will instantiate in the given engine.
Linker(Engine & engine)154   explicit Linker(Engine &engine)
155       : ptr(wasmtime_component_linker_new(engine.capi())) {}
156 
157   /**
158    * \brief Gets the "root" instance of this linker which can be used to define
159    * items into the linker under the top-level namespace.
160    *
161    * This `Linker` cannot be used while the returned `LinkerInstance` is in
162    * scope. To use more methods on this `Linker` it's required that the instance
163    * returned here is dropped first.
164    */
root()165   LinkerInstance root() {
166     wasmtime_component_linker_instance_t *instance_capi =
167         wasmtime_component_linker_root(ptr.get());
168     return LinkerInstance(instance_capi);
169   }
170 
171   /**
172    * \brief Defines all unknown imports of `component` as trapping functions.
173    */
174   Result<std::monostate>
define_unknown_imports_as_traps(const Component & component)175   define_unknown_imports_as_traps(const Component &component) {
176     auto err = wasmtime_component_linker_define_unknown_imports_as_traps(
177         ptr.get(), component.capi());
178     if (err)
179       return Error(err);
180     return std::monostate();
181   }
182 
183   /// Configures whether shadowing previous names is allowed or not.
184   ///
185   /// By default shadowing is not allowed.
allow_shadowing(bool allow)186   void allow_shadowing(bool allow) {
187     wasmtime_component_linker_allow_shadowing(ptr.get(), allow);
188   }
189 
190   /// \brief Instantiates the given component within this linker.
instantiate(Store::Context cx,Component & component)191   Result<Instance> instantiate(Store::Context cx, Component &component) {
192     wasmtime_component_instance_t ret;
193     wasmtime_error_t *error = wasmtime_component_linker_instantiate(
194         ptr.get(), cx.capi(), component.capi(), &ret);
195     if (error != nullptr) {
196       return Error(error);
197     }
198     return Instance(ret);
199   }
200 
201 #ifdef WASMTIME_FEATURE_WASI
202   /**
203    * \brief Adds WASIp2 API definitions to this linker.
204    *
205    * This will use the WASIp2 API definitions in Wasmtime to this linker. Note
206    * that this adds *synchronous* versions of WASIp2 definitions which will
207    * block the caller when invoked. Internally this will use Wasmtime's
208    * default async runtime implemented with Tokio to handle async I/O.
209    */
add_wasip2()210   Result<std::monostate> add_wasip2() {
211     wasmtime_error_t *error = wasmtime_component_linker_add_wasip2(ptr.get());
212     if (error != nullptr) {
213       return Error(error);
214     }
215     return std::monostate();
216   }
217 #endif // WASMTIME_FEATURE_WASI
218 
219 #ifdef WASMTIME_FEATURE_WASI_HTTP
220   /**
221    * \brief Adds WASI HTTP definitions to this linker.
222    *
223    * This adds `wasi:http/types` and `wasi:http/outgoing-handler` to the linker.
224    * Requires WASIp2 to be added first via \ref add_wasip2.
225    */
add_wasi_http()226   Result<std::monostate> add_wasi_http() {
227     wasmtime_error_t *error =
228         wasmtime_component_linker_add_wasi_http(ptr.get());
229     if (error != nullptr) {
230       return Error(error);
231     }
232     return std::monostate();
233   }
234 #endif // WASMTIME_FEATURE_WASI_HTTP
235 };
236 
237 } // namespace component
238 } // namespace wasmtime
239 
240 #endif // WASMTIME_FEATURE_COMPONENT_MODEL
241 
242 #endif // WASMTIME_COMPONENT_LINKER_H
243