Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/crates/wasi/src/p2/mod.rs
1692 views
1
//! # Wasmtime's WASIp2 Implementation
2
//!
3
//!
4
//! This module provides a Wasmtime host implementation of WASI 0.2 (aka WASIp2
5
//! aka Preview 2) and WASI 0.1 (aka WASIp1 aka Preview 1). WASI is implemented
6
//! with the Rust crates [`tokio`] and [`cap-std`] primarily, meaning that
7
//! operations are implemented in terms of their native platform equivalents by
8
//! default.
9
//!
10
//! # WASIp2 interfaces
11
//!
12
//! This module contains implementations of the following interfaces:
13
//!
14
//! * [`wasi:cli/environment`]
15
//! * [`wasi:cli/exit`]
16
//! * [`wasi:cli/stderr`]
17
//! * [`wasi:cli/stdin`]
18
//! * [`wasi:cli/stdout`]
19
//! * [`wasi:cli/terminal-input`]
20
//! * [`wasi:cli/terminal-output`]
21
//! * [`wasi:cli/terminal-stderr`]
22
//! * [`wasi:cli/terminal-stdin`]
23
//! * [`wasi:cli/terminal-stdout`]
24
//! * [`wasi:clocks/monotonic-clock`]
25
//! * [`wasi:clocks/wall-clock`]
26
//! * [`wasi:filesystem/preopens`]
27
//! * [`wasi:filesystem/types`]
28
//! * [`wasi:random/insecure-seed`]
29
//! * [`wasi:random/insecure`]
30
//! * [`wasi:random/random`]
31
//! * [`wasi:sockets/instance-network`]
32
//! * [`wasi:sockets/ip-name-lookup`]
33
//! * [`wasi:sockets/network`]
34
//! * [`wasi:sockets/tcp-create-socket`]
35
//! * [`wasi:sockets/tcp`]
36
//! * [`wasi:sockets/udp-create-socket`]
37
//! * [`wasi:sockets/udp`]
38
//!
39
//! Most traits are implemented for [`WasiCtxView`] trait which provides
40
//! access to [`WasiCtx`] and [`ResourceTable`], which defines the configuration
41
//! for WASI and handle state. The [`WasiView`] trait is used to acquire and
42
//! construct a [`WasiCtxView`].
43
//!
44
//! The [`wasmtime-wasi-io`] crate contains implementations of the
45
//! following interfaces, and this module reuses those implementations:
46
//!
47
//! * [`wasi:io/error`]
48
//! * [`wasi:io/poll`]
49
//! * [`wasi:io/streams`]
50
//!
51
//! These traits are implemented directly for [`ResourceTable`]. All aspects of
52
//! `wasmtime-wasi-io` that are used by this module are re-exported. Unless you
53
//! are implementing other host functionality that needs to interact with the
54
//! WASI scheduler and don't want to use other functionality provided by
55
//! `wasmtime-wasi`, you don't need to take a direct dependency on
56
//! `wasmtime-wasi-io`.
57
//!
58
//! # Generated Bindings
59
//!
60
//! This module uses [`wasmtime::component::bindgen!`] to generate bindings for
61
//! all WASI interfaces. Raw bindings are available in the [`bindings`] submodule
62
//! of this module. Downstream users can either implement these traits themselves
63
//! or you can use the built-in implementations in this module for
64
//! `WasiImpl<T: WasiView>`.
65
//!
66
//! # The `WasiView` trait
67
//!
68
//! This module's implementation of WASI is done in terms of an implementation of
69
//! [`WasiView`]. This trait provides a "view" into WASI-related state that is
70
//! contained within a [`Store<T>`](wasmtime::Store).
71
//!
72
//! For all of the generated bindings in this module (Host traits),
73
//! implementations are provided looking like:
74
//!
75
//! ```
76
//! # use wasmtime_wasi::WasiCtxView;
77
//! # trait WasiView {}
78
//! # mod bindings { pub mod wasi { pub trait Host {} } }
79
//! impl bindings::wasi::Host for WasiCtxView<'_> {
80
//! // ...
81
//! }
82
//! ```
83
//!
84
//! where the [`WasiCtxView`] type comes from [`WasiView::ctx`] for the type
85
//! contained within the `Store<T>`. The [`add_to_linker_sync`] and
86
//! [`add_to_linker_async`] function then require that `T: WasiView` with
87
//! [`Linker<T>`](wasmtime::component::Linker).
88
//!
89
//! To implement the [`WasiView`] trait you will first select a
90
//! `T` to put in `Store<T>` (typically, by defining your own struct).
91
//! Somewhere within `T` you'll store:
92
//!
93
//! * [`ResourceTable`] - created through default constructors.
94
//! * [`WasiCtx`] - created through [`WasiCtxBuilder`].
95
//!
96
//! You'll then write an implementation of the [`WasiView`]
97
//! trait to access those items in your `T`. For example:
98
//! ```
99
//! use wasmtime::component::ResourceTable;
100
//! use wasmtime_wasi::{WasiCtx, WasiCtxView, WasiView};
101
//!
102
//! struct MyCtx {
103
//! table: ResourceTable,
104
//! wasi: WasiCtx,
105
//! }
106
//!
107
//! impl WasiView for MyCtx {
108
//! fn ctx(&mut self) -> WasiCtxView<'_> {
109
//! WasiCtxView { ctx: &mut self.wasi, table: &mut self.table }
110
//! }
111
//! }
112
//! ```
113
//!
114
//! # Async and Sync
115
//!
116
//! As of WASI0.2, WASI functions are not blocking from WebAssembly's point of
117
//! view: a WebAssembly call into these functions returns when they are
118
//! complete.
119
//!
120
//! This module provides an implementation of those functions in the host,
121
//! where for some functions, it is appropriate to implement them using
122
//! async Rust and the Tokio executor, so that the host implementation can be
123
//! nonblocking when Wasmtime's [`Config::async_support`][async] is set.
124
//! Synchronous wrappers are provided for all async implementations, which
125
//! creates a private Tokio executor.
126
//!
127
//! Users can choose between these modes of implementation using variants
128
//! of the add_to_linker functions:
129
//!
130
//! * For non-async users (the default of `Config`), use [`add_to_linker_sync`].
131
//! * For async users, use [`add_to_linker_async`].
132
//!
133
//! Note that bindings are generated once for async and once for sync. Most
134
//! interfaces do not change, however, so only interfaces with blocking
135
//! functions have bindings generated twice. Bindings are organized as:
136
//!
137
//! * [`bindings`] - default location of all bindings, blocking functions are
138
//! `async`
139
//! * [`bindings::sync`] - blocking interfaces have synchronous versions here.
140
//!
141
//! # Module-specific traits
142
//!
143
//! This module's default implementation of WASI bindings to native primitives
144
//! for the platform that it is compiled for. For example opening a TCP socket
145
//! uses the native platform to open a TCP socket (so long as [`WasiCtxBuilder`]
146
//! allows it). There are a few important traits, however, that are specific to
147
//! this module.
148
//!
149
//! * [`InputStream`] and [`OutputStream`] - these are the host traits
150
//! behind the WASI `input-stream` and `output-stream` types in the
151
//! `wasi:io/streams` interface. These enable embedders to build their own
152
//! custom stream and insert them into a [`ResourceTable`] (as a boxed trait
153
//! object, see [`DynInputStream`] and [`DynOutputStream`]) to be used from
154
//! wasm.
155
//!
156
//! * [`Pollable`] - this trait enables building arbitrary logic to get hooked
157
//! into a `pollable` resource from `wasi:io/poll`. A pollable resource is
158
//! created through the [`subscribe`] function.
159
//!
160
//! * [`HostWallClock`](crate::HostWallClock) and [`HostMonotonicClock`](crate::HostMonotonicClock) are used in conjunction with
161
//! [`WasiCtxBuilder::wall_clock`] and [`WasiCtxBuilder::monotonic_clock`] if
162
//! the defaults host's clock should not be used.
163
//!
164
//! * [`StdinStream`] and [`StdoutStream`] are used to provide custom
165
//! stdin/stdout streams if they're not inherited (or null, which is the
166
//! default).
167
//!
168
//! These traits enable embedders to customize small portions of WASI interfaces
169
//! provided while still providing all other interfaces.
170
//!
171
//! # Examples
172
//!
173
//! Usage of this module is done through a few steps to get everything hooked up:
174
//!
175
//! 1. First implement [`WasiView`] for your type which is the
176
//! `T` in `Store<T>`.
177
//! 2. Add WASI interfaces to a `wasmtime::component::Linker<T>`. This is either
178
//! done through top-level functions like [`add_to_linker_sync`] or through
179
//! individual `add_to_linker` functions in generated bindings throughout
180
//! this module.
181
//! 3. Create a [`WasiCtx`] for each `Store<T>` through [`WasiCtxBuilder`]. Each
182
//! WASI context is "null" or "empty" by default, so items must be explicitly
183
//! added to get accessed by wasm (such as env vars or program arguments).
184
//! 4. Use the previous `Linker<T>` to instantiate a `Component` within a
185
//! `Store<T>`.
186
//!
187
//! For examples see each of [`WasiView`], [`WasiCtx`], [`WasiCtxBuilder`],
188
//! [`add_to_linker_sync`], and [`bindings::Command`].
189
//!
190
//! [`wasmtime::component::bindgen!`]: https://docs.rs/wasmtime/latest/wasmtime/component/macro.bindgen.html
191
//! [`tokio`]: https://crates.io/crates/tokio
192
//! [`cap-std`]: https://crates.io/crates/cap-std
193
//! [`wasmtime-wasi-io`]: https://crates.io/crates/wasmtime-wasi-io
194
//! [`wasi:cli/environment`]: bindings::cli::environment::Host
195
//! [`wasi:cli/exit`]: bindings::cli::exit::Host
196
//! [`wasi:cli/stderr`]: bindings::cli::stderr::Host
197
//! [`wasi:cli/stdin`]: bindings::cli::stdin::Host
198
//! [`wasi:cli/stdout`]: bindings::cli::stdout::Host
199
//! [`wasi:cli/terminal-input`]: bindings::cli::terminal_input::Host
200
//! [`wasi:cli/terminal-output`]: bindings::cli::terminal_output::Host
201
//! [`wasi:cli/terminal-stdin`]: bindings::cli::terminal_stdin::Host
202
//! [`wasi:cli/terminal-stdout`]: bindings::cli::terminal_stdout::Host
203
//! [`wasi:cli/terminal-stderr`]: bindings::cli::terminal_stderr::Host
204
//! [`wasi:clocks/monotonic-clock`]: bindings::clocks::monotonic_clock::Host
205
//! [`wasi:clocks/wall-clock`]: bindings::clocks::wall_clock::Host
206
//! [`wasi:filesystem/preopens`]: bindings::filesystem::preopens::Host
207
//! [`wasi:filesystem/types`]: bindings::filesystem::types::Host
208
//! [`wasi:io/error`]: wasmtime_wasi_io::bindings::wasi::io::error::Host
209
//! [`wasi:io/poll`]: wasmtime_wasi_io::bindings::wasi::io::poll::Host
210
//! [`wasi:io/streams`]: wasmtime_wasi_io::bindings::wasi::io::streams::Host
211
//! [`wasi:random/insecure-seed`]: bindings::random::insecure_seed::Host
212
//! [`wasi:random/insecure`]: bindings::random::insecure::Host
213
//! [`wasi:random/random`]: bindings::random::random::Host
214
//! [`wasi:sockets/instance-network`]: bindings::sockets::instance_network::Host
215
//! [`wasi:sockets/ip-name-lookup`]: bindings::sockets::ip_name_lookup::Host
216
//! [`wasi:sockets/network`]: bindings::sockets::network::Host
217
//! [`wasi:sockets/tcp-create-socket`]: bindings::sockets::tcp_create_socket::Host
218
//! [`wasi:sockets/tcp`]: bindings::sockets::tcp::Host
219
//! [`wasi:sockets/udp-create-socket`]: bindings::sockets::udp_create_socket::Host
220
//! [`wasi:sockets/udp`]: bindings::sockets::udp::Host
221
//! [async]: https://docs.rs/wasmtime/latest/wasmtime/struct.Config.html#method.async_support
222
//! [`ResourceTable`]: wasmtime::component::ResourceTable
223
224
use crate::WasiView;
225
use crate::cli::{WasiCli, WasiCliView as _};
226
use crate::clocks::{WasiClocks, WasiClocksView as _};
227
use crate::filesystem::{WasiFilesystem, WasiFilesystemView as _};
228
use crate::random::WasiRandom;
229
use crate::sockets::{WasiSockets, WasiSocketsView as _};
230
use wasmtime::component::{HasData, Linker, ResourceTable};
231
232
pub mod bindings;
233
pub(crate) mod filesystem;
234
mod host;
235
mod ip_name_lookup;
236
mod network;
237
pub mod pipe;
238
mod poll;
239
mod stdio;
240
mod tcp;
241
mod udp;
242
mod write_stream;
243
244
pub use self::filesystem::{FsError, FsResult, ReaddirIterator};
245
pub use self::network::{Network, SocketError, SocketResult};
246
pub use self::stdio::IsATTY;
247
pub(crate) use tcp::P2TcpStreamingState;
248
// These contents of wasmtime-wasi-io are re-exported by this module for compatibility:
249
// they were originally defined in this module before being factored out, and many
250
// users of this module depend on them at these names.
251
pub use wasmtime_wasi_io::poll::{DynFuture, DynPollable, MakeFuture, Pollable, subscribe};
252
pub use wasmtime_wasi_io::streams::{
253
DynInputStream, DynOutputStream, Error as IoError, InputStream, OutputStream, StreamError,
254
StreamResult,
255
};
256
257
/// Add all WASI interfaces from this crate into the `linker` provided.
258
///
259
/// This function will add the `async` variant of all interfaces into the
260
/// [`Linker`] provided. By `async` this means that this function is only
261
/// compatible with [`Config::async_support(true)`][async]. For embeddings with
262
/// async support disabled see [`add_to_linker_sync`] instead.
263
///
264
/// This function will add all interfaces implemented by this crate to the
265
/// [`Linker`], which corresponds to the `wasi:cli/imports` world supported by
266
/// this crate.
267
///
268
/// [async]: wasmtime::Config::async_support
269
///
270
/// # Example
271
///
272
/// ```
273
/// use wasmtime::{Engine, Result, Store, Config};
274
/// use wasmtime::component::{ResourceTable, Linker};
275
/// use wasmtime_wasi::{WasiCtx, WasiCtxView, WasiView};
276
///
277
/// fn main() -> Result<()> {
278
/// let mut config = Config::new();
279
/// config.async_support(true);
280
/// let engine = Engine::new(&config)?;
281
///
282
/// let mut linker = Linker::<MyState>::new(&engine);
283
/// wasmtime_wasi::p2::add_to_linker_async(&mut linker)?;
284
/// // ... add any further functionality to `linker` if desired ...
285
///
286
/// let mut builder = WasiCtx::builder();
287
///
288
/// // ... configure `builder` more to add env vars, args, etc ...
289
///
290
/// let mut store = Store::new(
291
/// &engine,
292
/// MyState {
293
/// ctx: builder.build(),
294
/// table: ResourceTable::new(),
295
/// },
296
/// );
297
///
298
/// // ... use `linker` to instantiate within `store` ...
299
///
300
/// Ok(())
301
/// }
302
///
303
/// struct MyState {
304
/// ctx: WasiCtx,
305
/// table: ResourceTable,
306
/// }
307
///
308
/// impl WasiView for MyState {
309
/// fn ctx(&mut self) -> WasiCtxView<'_> {
310
/// WasiCtxView { ctx: &mut self.ctx, table: &mut self.table }
311
/// }
312
/// }
313
/// ```
314
pub fn add_to_linker_async<T: WasiView>(linker: &mut Linker<T>) -> anyhow::Result<()> {
315
let options = bindings::LinkOptions::default();
316
add_to_linker_with_options_async(linker, &options)
317
}
318
319
/// Similar to [`add_to_linker_async`], but with the ability to enable unstable features.
320
pub fn add_to_linker_with_options_async<T: WasiView>(
321
linker: &mut Linker<T>,
322
options: &bindings::LinkOptions,
323
) -> anyhow::Result<()> {
324
add_async_io_to_linker(linker)?;
325
add_nonblocking_to_linker(linker, options)?;
326
327
let l = linker;
328
bindings::filesystem::types::add_to_linker::<T, WasiFilesystem>(l, T::filesystem)?;
329
bindings::sockets::tcp::add_to_linker::<T, WasiSockets>(l, T::sockets)?;
330
bindings::sockets::udp::add_to_linker::<T, WasiSockets>(l, T::sockets)?;
331
Ok(())
332
}
333
334
/// Shared functionality for [`add_to_linker_async`] and [`add_to_linker_sync`].
335
fn add_nonblocking_to_linker<'a, T: WasiView, O>(
336
linker: &mut Linker<T>,
337
options: &'a O,
338
) -> anyhow::Result<()>
339
where
340
bindings::sockets::network::LinkOptions: From<&'a O>,
341
bindings::cli::exit::LinkOptions: From<&'a O>,
342
{
343
use crate::p2::bindings::{cli, clocks, filesystem, random, sockets};
344
345
let l = linker;
346
clocks::wall_clock::add_to_linker::<T, WasiClocks>(l, T::clocks)?;
347
clocks::monotonic_clock::add_to_linker::<T, WasiClocks>(l, T::clocks)?;
348
filesystem::preopens::add_to_linker::<T, WasiFilesystem>(l, T::filesystem)?;
349
random::random::add_to_linker::<T, WasiRandom>(l, |t| &mut t.ctx().ctx.random)?;
350
random::insecure::add_to_linker::<T, WasiRandom>(l, |t| &mut t.ctx().ctx.random)?;
351
random::insecure_seed::add_to_linker::<T, WasiRandom>(l, |t| &mut t.ctx().ctx.random)?;
352
cli::exit::add_to_linker::<T, WasiCli>(l, &options.into(), T::cli)?;
353
cli::environment::add_to_linker::<T, WasiCli>(l, T::cli)?;
354
cli::stdin::add_to_linker::<T, WasiCli>(l, T::cli)?;
355
cli::stdout::add_to_linker::<T, WasiCli>(l, T::cli)?;
356
cli::stderr::add_to_linker::<T, WasiCli>(l, T::cli)?;
357
cli::terminal_input::add_to_linker::<T, WasiCli>(l, T::cli)?;
358
cli::terminal_output::add_to_linker::<T, WasiCli>(l, T::cli)?;
359
cli::terminal_stdin::add_to_linker::<T, WasiCli>(l, T::cli)?;
360
cli::terminal_stdout::add_to_linker::<T, WasiCli>(l, T::cli)?;
361
cli::terminal_stderr::add_to_linker::<T, WasiCli>(l, T::cli)?;
362
sockets::tcp_create_socket::add_to_linker::<T, WasiSockets>(l, T::sockets)?;
363
sockets::udp_create_socket::add_to_linker::<T, WasiSockets>(l, T::sockets)?;
364
sockets::instance_network::add_to_linker::<T, WasiSockets>(l, T::sockets)?;
365
sockets::network::add_to_linker::<T, WasiSockets>(l, &options.into(), T::sockets)?;
366
sockets::ip_name_lookup::add_to_linker::<T, WasiSockets>(l, T::sockets)?;
367
Ok(())
368
}
369
370
/// Same as [`add_to_linker_async`] except that this only adds interfaces
371
/// present in the `wasi:http/proxy` world.
372
pub fn add_to_linker_proxy_interfaces_async<T: WasiView>(
373
linker: &mut Linker<T>,
374
) -> anyhow::Result<()> {
375
add_async_io_to_linker(linker)?;
376
add_proxy_interfaces_nonblocking(linker)
377
}
378
379
/// Same as [`add_to_linker_sync`] except that this only adds interfaces
380
/// present in the `wasi:http/proxy` world.
381
#[doc(hidden)]
382
pub fn add_to_linker_proxy_interfaces_sync<T: WasiView>(
383
linker: &mut Linker<T>,
384
) -> anyhow::Result<()> {
385
add_sync_wasi_io(linker)?;
386
add_proxy_interfaces_nonblocking(linker)
387
}
388
389
fn add_proxy_interfaces_nonblocking<T: WasiView>(linker: &mut Linker<T>) -> anyhow::Result<()> {
390
use crate::p2::bindings::{cli, clocks, random};
391
392
let l = linker;
393
clocks::wall_clock::add_to_linker::<T, WasiClocks>(l, T::clocks)?;
394
clocks::monotonic_clock::add_to_linker::<T, WasiClocks>(l, T::clocks)?;
395
random::random::add_to_linker::<T, WasiRandom>(l, |t| &mut t.ctx().ctx.random)?;
396
cli::stdin::add_to_linker::<T, WasiCli>(l, T::cli)?;
397
cli::stdout::add_to_linker::<T, WasiCli>(l, T::cli)?;
398
cli::stderr::add_to_linker::<T, WasiCli>(l, T::cli)?;
399
Ok(())
400
}
401
402
/// Add all WASI interfaces from this crate into the `linker` provided.
403
///
404
/// This function will add the synchronous variant of all interfaces into the
405
/// [`Linker`] provided. By synchronous this means that this function is only
406
/// compatible with [`Config::async_support(false)`][async]. For embeddings
407
/// with async support enabled see [`add_to_linker_async`] instead.
408
///
409
/// This function will add all interfaces implemented by this crate to the
410
/// [`Linker`], which corresponds to the `wasi:cli/imports` world supported by
411
/// this crate.
412
///
413
/// [async]: wasmtime::Config::async_support
414
///
415
/// # Example
416
///
417
/// ```
418
/// use wasmtime::{Engine, Result, Store, Config};
419
/// use wasmtime::component::{ResourceTable, Linker};
420
/// use wasmtime_wasi::{WasiCtx, WasiCtxView, WasiView};
421
///
422
/// fn main() -> Result<()> {
423
/// let engine = Engine::default();
424
///
425
/// let mut linker = Linker::<MyState>::new(&engine);
426
/// wasmtime_wasi::p2::add_to_linker_sync(&mut linker)?;
427
/// // ... add any further functionality to `linker` if desired ...
428
///
429
/// let mut builder = WasiCtx::builder();
430
///
431
/// // ... configure `builder` more to add env vars, args, etc ...
432
///
433
/// let mut store = Store::new(
434
/// &engine,
435
/// MyState {
436
/// ctx: builder.build(),
437
/// table: ResourceTable::new(),
438
/// },
439
/// );
440
///
441
/// // ... use `linker` to instantiate within `store` ...
442
///
443
/// Ok(())
444
/// }
445
///
446
/// struct MyState {
447
/// ctx: WasiCtx,
448
/// table: ResourceTable,
449
/// }
450
/// impl WasiView for MyState {
451
/// fn ctx(&mut self) -> WasiCtxView<'_> {
452
/// WasiCtxView { ctx: &mut self.ctx, table: &mut self.table }
453
/// }
454
/// }
455
/// ```
456
pub fn add_to_linker_sync<T: WasiView>(
457
linker: &mut wasmtime::component::Linker<T>,
458
) -> anyhow::Result<()> {
459
let options = bindings::sync::LinkOptions::default();
460
add_to_linker_with_options_sync(linker, &options)
461
}
462
463
/// Similar to [`add_to_linker_sync`], but with the ability to enable unstable features.
464
pub fn add_to_linker_with_options_sync<T: WasiView>(
465
linker: &mut wasmtime::component::Linker<T>,
466
options: &bindings::sync::LinkOptions,
467
) -> anyhow::Result<()> {
468
add_nonblocking_to_linker(linker, options)?;
469
add_sync_wasi_io(linker)?;
470
471
let l = linker;
472
bindings::sync::filesystem::types::add_to_linker::<T, WasiFilesystem>(l, T::filesystem)?;
473
bindings::sync::sockets::tcp::add_to_linker::<T, WasiSockets>(l, T::sockets)?;
474
bindings::sync::sockets::udp::add_to_linker::<T, WasiSockets>(l, T::sockets)?;
475
Ok(())
476
}
477
478
/// Shared functionality of [`add_to_linker_sync`]` and
479
/// [`add_to_linker_proxy_interfaces_sync`].
480
fn add_sync_wasi_io<T: WasiView>(
481
linker: &mut wasmtime::component::Linker<T>,
482
) -> anyhow::Result<()> {
483
let l = linker;
484
wasmtime_wasi_io::bindings::wasi::io::error::add_to_linker::<T, HasIo>(l, |t| t.ctx().table)?;
485
bindings::sync::io::poll::add_to_linker::<T, HasIo>(l, |t| t.ctx().table)?;
486
bindings::sync::io::streams::add_to_linker::<T, HasIo>(l, |t| t.ctx().table)?;
487
Ok(())
488
}
489
490
struct HasIo;
491
492
impl HasData for HasIo {
493
type Data<'a> = &'a mut ResourceTable;
494
}
495
496
// FIXME: it's a bit unfortunate that this can't use
497
// `wasmtime_wasi_io::add_to_linker` and that's because `T: WasiView`, here,
498
// not `T: IoView`. Ideally we'd have `impl<T: WasiView> IoView for T` but
499
// that's not possible with these two traits in separate crates. For now this
500
// is some small duplication but if this gets worse over time then we'll want
501
// to massage this.
502
fn add_async_io_to_linker<T: WasiView>(l: &mut Linker<T>) -> anyhow::Result<()> {
503
wasmtime_wasi_io::bindings::wasi::io::error::add_to_linker::<T, HasIo>(l, |t| t.ctx().table)?;
504
wasmtime_wasi_io::bindings::wasi::io::poll::add_to_linker::<T, HasIo>(l, |t| t.ctx().table)?;
505
wasmtime_wasi_io::bindings::wasi::io::streams::add_to_linker::<T, HasIo>(l, |t| t.ctx().table)?;
506
Ok(())
507
}
508
509