Skip to content

Commit 3135373

Browse files
committed
Add support for async/streams/futures
This adds support for loading, compiling, linking, and running components which use the [Async ABI](https://github.com/WebAssembly/component-model/blob/main/design/mvp/Async.md) along with the [`stream`, `future`, and `error-context`](WebAssembly/component-model#405) types. It also adds support for generating host bindings such that multiple host functions can be run concurrently with guest tasks -- without monopolizing the `Store`. See the [implementation RFC](bytecodealliance/rfcs#38) for details, as well as [this repo](https://github.com/dicej/component-async-demo) containing end-to-end smoke tests. Signed-off-by: Joel Dice <[email protected]> fix clippy warnings and bench/fuzzing errors Signed-off-by: Joel Dice <[email protected]> revert atomic.wit whitespace change Signed-off-by: Joel Dice <[email protected]> fix build when component-model disabled Signed-off-by: Joel Dice <[email protected]> bless component-macro expected output Signed-off-by: Joel Dice <[email protected]> fix no-std build error Signed-off-by: Joel Dice <[email protected]> fix build with --no-default-features --features runtime,component-model Signed-off-by: Joel Dice <[email protected]> partly fix no-std build It's still broken due to the use of `std::collections::HashMap` in crates/wasmtime/src/runtime/vm/component.rs. I'll address that as part of the work to avoid exposing global task/future/stream/error-context handles to guests. Signed-off-by: Joel Dice <[email protected]> maintain per-instance tables for futures, streams, and error-contexts Signed-off-by: Joel Dice <[email protected]> refactor task/stream/future handle lifting/lowering This addresses a couple of issues: - Previously, we were passing task/stream/future/error-context reps directly to instances while keeping track of which instance had access to which rep. That worked fine in that there was no way to forge access to inaccessible reps, but it leaked information about what other instances were doing. Now we maintain per-instance waitable and error-context tables which map the reps to and from the handles which the instance sees. - The `no_std` build was broken due to use of `HashMap` in `runtime::vm::component`, which is now fixed. Note that we use one single table per instance for all tasks, streams, and futures. This is partly necessary because, when async events are delivered to the guest, it wouldn't have enough context to know which stream or future we're talking about if each unique stream and future type had its own table. So at minimum, we need to use the same table for all streams (regardless of payload type), and likewise for futures. Also, per WebAssembly/component-model#395 (comment), the plan is to move towards a shared table for all resource types as well, so this moves us in that direction. Signed-off-by: Joel Dice <[email protected]> fix wave breakage due to new stream/future/error-context types Signed-off-by: Joel Dice <[email protected]> switch wasm-tools to v1.220.0-based branch Signed-off-by: Joel Dice <[email protected]> check `task.return` type at runtime We can't statically verify a given call to `task.return` corresponds to the expected core signature appropriate for the currently running task, so we must do so at runtime. In order to make that check efficient, we intern the types. My initial plan was to use `ModuleInternedTypeIndex` and/or `VMSharedTypeIndex` for interning, but that got hairy with WasmGC considerations, so instead I added new fields to `ComponentTypes` and `ComponentTypesBuilder`. Signed-off-by: Joel Dice <[email protected]> add `TypedFunc::call_concurrent` and refine stream/future APIs This implements what I proposed in https://github.com/dicej/rfcs/blob/component-async/accepted/component-model-async.md#wasmtime. Specifically, it adds: - A new `Promise` type, useful for working with concurrent operations that require access to a `Store` to make progress. - A new `PromisesUnordered` type for `await`ing multiple promises concurrently -`TypedFunc::call_concurrent` (which returns a `Promise`), allowing multiple host->guest calls to run concurrently on the same instance. - Updated `{Stream|Future}{Writer|Reader}` APIs which use `Promise` The upshot is that the embedder can now ergonomically manage arbitrary numbers of concurrent operations. Previously, this was a lot more difficult to do without accidentally starving some of the operations due to another one monopolizing the `Store`. Finally, this includes various refactorings and fixes for bugs exposed by the newer, more versatile APIs. Signed-off-by: Joel Dice <[email protected]> clean up verbosity in component/func.rs Signed-off-by: Joel Dice <[email protected]> snapshot Signed-off-by: Joel Dice <[email protected]> implement stream/future read/write cancellation This required a somewhat viral addition of `Send` and `Sync` bounds for async host function closure types, unfortunately. Signed-off-by: Joel Dice <[email protected]> add `Func::call_concurrent` and `LinkerInstance::func_new_concurrent` Signed-off-by: Joel Dice <[email protected]> dynamic API support for streams/futures/error-contexts Signed-off-by: Joel Dice <[email protected]> support callback-less (AKA stackful) async lifts Signed-off-by: Joel Dice <[email protected]> fix `call_host` regression Signed-off-by: Joel Dice <[email protected]> add component model async end-to-end tests I've ported these over from https://github.com/dicej/component-async-demo Signed-off-by: Joel Dice <[email protected]> fix test regressions and clippy warnings Signed-off-by: Joel Dice <[email protected]> satisfy clippy Signed-off-by: Joel Dice <[email protected]> fix async tests when `component-model-async` enabled Enabling this feature for all tests revealed various missing pieces in the new `concurrent.rs` fiber mechanism, which I've addressed. This adds a bunch of ugly `#[cfg(feature = "component-model-async")]` guards, but those will all go away once I unify the two async fiber implementations. Signed-off-by: Joel Dice <[email protected]> add and modify tests to cover concurrent APIs Primarily, this tests and implements cases where parameters and/or results must be passed via linear memory instead of the stack. Signed-off-by: Joel Dice <[email protected]> `concurrent_{imports|exports}` component macro codegen tests This enables codegen testing of the `concurrent_imports` and `concurrent_exports` options to `wasmtime::component::bindgen` and also fixes code generation for world-level function and resource exports that use the concurrent call style. Signed-off-by: Joel Dice <[email protected]> `concurrent_{imports|exports}` component macro expanded tests This enables testing of the `concurrent_imports` and `concurrent_exports` options in `crates/component-macro/tests/expanded.rs`. Signed-off-by: Joel Dice <[email protected]> add tests/misc_testsuite/component-model-async/*.wast These only test instantiation of components which use various async options and built-ins so far. Next, I'll happy and sad path tests which actually execute code. Signed-off-by: Joel Dice <[email protected]> appease clippy Signed-off-by: Joel Dice <[email protected]> add tests/misc_testsuite/component-model-async/fused.wast Signed-off-by: Joel Dice <[email protected]> add non-panicking bounds checks where appropriate Signed-off-by: Joel Dice <[email protected]> remove post-return bits from async result lift code ...at least until we've determined whether post-return options even make sense for async-lifted exports. Signed-off-by: Joel Dice <[email protected]> fix component-model-async/fused.wast test failure Signed-off-by: Joel Dice <[email protected]> use `enum` types to represent status and event codes Signed-off-by: Joel Dice <[email protected]> fix component-model-async/fused.wast test failure (2nd try) Signed-off-by: Joel Dice <[email protected]> use `gc_types = true` in component-model-async/fused.wast We use `Instruction::RefFunc` when generating adapters for async lifts and/or lowers, which Winch doesn't understand, and apparently `gc_types = true` is what tells the test infra not to use Winch. Signed-off-by: Joel Dice <[email protected]> trap if async function finishes without calling `task.return` Signed-off-by: Joel Dice <[email protected]> update wit-bindgen and fix rebase damage Signed-off-by: Joel Dice <[email protected]> call post-return function if any for async->sync fused calls Signed-off-by: Joel Dice <[email protected]>
1 parent 4aeffe9 commit 3135373

File tree

249 files changed

+46915
-2388
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

249 files changed

+46915
-2388
lines changed

Cargo.toml

+6-2
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ rustix = { workspace = true, features = ["mm", "param", "process"] }
8686

8787
[dev-dependencies]
8888
# depend again on wasmtime to activate its default features for tests
89-
wasmtime = { workspace = true, features = ['default', 'winch', 'pulley', 'all-arch', 'call-hook', 'memory-protection-keys', 'signals-based-traps'] }
89+
wasmtime = { workspace = true, features = ['default', 'winch', 'pulley', 'all-arch', 'call-hook', 'memory-protection-keys', 'signals-based-traps', 'component-model-async'] }
9090
env_logger = { workspace = true }
9191
log = { workspace = true }
9292
filecheck = { workspace = true }
@@ -100,7 +100,7 @@ async-trait = { workspace = true }
100100
trait-variant = { workspace = true }
101101
wat = { workspace = true }
102102
rayon = "1.5.0"
103-
wasmtime-wast = { workspace = true, features = ['component-model'] }
103+
wasmtime-wast = { workspace = true, features = ['component-model', 'component-model-async'] }
104104
wasmtime-component-util = { workspace = true }
105105
component-macro-test = { path = "crates/misc/component-macro-test" }
106106
component-test-util = { workspace = true }
@@ -146,6 +146,7 @@ members = [
146146
"crates/bench-api",
147147
"crates/c-api/artifact",
148148
"crates/environ/fuzz",
149+
"crates/misc/component-async-tests",
149150
"crates/test-programs",
150151
"crates/wasi-preview1-component-adapter",
151152
"crates/wasi-preview1-component-adapter/verify",
@@ -241,6 +242,7 @@ wasmtime-versioned-export-macros = { path = "crates/versioned-export-macros", ve
241242
wasmtime-slab = { path = "crates/slab", version = "=30.0.0" }
242243
component-test-util = { path = "crates/misc/component-test-util" }
243244
component-fuzz-util = { path = "crates/misc/component-fuzz-util" }
245+
component-async-tests = { path = "crates/misc/component-async-tests" }
244246
wiggle = { path = "crates/wiggle", version = "=30.0.0", default-features = false }
245247
wiggle-macro = { path = "crates/wiggle/macro", version = "=30.0.0" }
246248
wiggle-generate = { path = "crates/wiggle/generate", version = "=30.0.0" }
@@ -294,6 +296,7 @@ io-extras = "0.18.1"
294296
rustix = "0.38.43"
295297
# wit-bindgen:
296298
wit-bindgen = { version = "0.37.0", default-features = false }
299+
wit-bindgen-rt = { version = "0.37.0", default-features = false }
297300
wit-bindgen-rust-macro = { version = "0.37.0", default-features = false }
298301

299302
# wasm-tools family:
@@ -307,6 +310,7 @@ wasm-mutate = "0.223.0"
307310
wit-parser = "0.223.0"
308311
wit-component = "0.223.0"
309312
wasm-wave = "0.223.0"
313+
wasm-compose = "0.223.0"
310314

311315
# Non-Bytecode Alliance maintained dependencies:
312316
# --------------------------

benches/call.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ fn bench_host_to_wasm<Params, Results>(
135135
typed_results: Results,
136136
) where
137137
Params: WasmParams + ToVals + Copy,
138-
Results: WasmResults + ToVals + Copy + PartialEq + Debug,
138+
Results: WasmResults + ToVals + Copy + PartialEq + Debug + Sync + 'static,
139139
{
140140
// Benchmark the "typed" version, which should be faster than the versions
141141
// below.
@@ -628,7 +628,8 @@ mod component {
628628
+ PartialEq
629629
+ Debug
630630
+ Send
631-
+ Sync,
631+
+ Sync
632+
+ 'static,
632633
{
633634
// Benchmark the "typed" version.
634635
c.bench_function(&format!("component - host-to-wasm - typed - {name}"), |b| {

crates/component-macro/Cargo.toml

+3-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ wasmtime-wit-bindgen = { workspace = true }
2929
wit-parser = { workspace = true }
3030

3131
[dev-dependencies]
32-
wasmtime = { path = '../wasmtime', features = ['component-model'] }
32+
wasmtime = { path = '../wasmtime', features = ['component-model', 'component-model-async'] }
33+
wasmtime-wit-bindgen = { workspace = true, features = ['component-model-async'] }
3334
component-macro-test-helpers = { path = 'test-helpers' }
3435
tracing = { workspace = true }
3536
# For use with the custom attributes test
@@ -41,3 +42,4 @@ similar = { workspace = true }
4142
[features]
4243
async = []
4344
std = ['wasmtime-wit-bindgen/std']
45+
component-model-async = ['std', 'async', 'wasmtime-wit-bindgen/component-model-async']

crates/component-macro/src/bindgen.rs

+41-7
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
use proc_macro2::{Span, TokenStream};
22
use quote::ToTokens;
3-
use std::collections::HashMap;
4-
use std::collections::HashSet;
3+
use std::collections::{HashMap, HashSet};
54
use std::env;
65
use std::path::{Path, PathBuf};
76
use std::sync::atomic::{AtomicUsize, Ordering::Relaxed};
87
use syn::parse::{Error, Parse, ParseStream, Result};
98
use syn::punctuated::Punctuated;
109
use syn::{braced, token, Token};
11-
use wasmtime_wit_bindgen::{AsyncConfig, Opts, Ownership, TrappableError, TrappableImports};
10+
use wasmtime_wit_bindgen::{
11+
AsyncConfig, CallStyle, Opts, Ownership, TrappableError, TrappableImports,
12+
};
1213
use wit_parser::{PackageId, Resolve, UnresolvedPackageGroup, WorldId};
1314

1415
pub struct Config {
@@ -20,13 +21,22 @@ pub struct Config {
2021
}
2122

2223
pub fn expand(input: &Config) -> Result<TokenStream> {
23-
if !cfg!(feature = "async") && input.opts.async_.maybe_async() {
24+
if let (CallStyle::Async | CallStyle::Concurrent, false) =
25+
(input.opts.call_style(), cfg!(feature = "async"))
26+
{
2427
return Err(Error::new(
2528
Span::call_site(),
2629
"cannot enable async bindings unless `async` crate feature is active",
2730
));
2831
}
2932

33+
if input.opts.concurrent_imports && !cfg!(feature = "component-model-async") {
34+
return Err(Error::new(
35+
Span::call_site(),
36+
"cannot enable `concurrent_imports` option unless `component-model-async` crate feature is active",
37+
));
38+
}
39+
3040
let mut src = match input.opts.generate(&input.resolve, input.world) {
3141
Ok(s) => s,
3242
Err(e) => return Err(Error::new(Span::call_site(), e.to_string())),
@@ -40,7 +50,10 @@ pub fn expand(input: &Config) -> Result<TokenStream> {
4050
// place a formatted version of the expanded code into a file. This file
4151
// will then show up in rustc error messages for any codegen issues and can
4252
// be inspected manually.
43-
if input.include_generated_code_from_file || std::env::var("WASMTIME_DEBUG_BINDGEN").is_ok() {
53+
if input.include_generated_code_from_file
54+
|| input.opts.debug
55+
|| std::env::var("WASMTIME_DEBUG_BINDGEN").is_ok()
56+
{
4457
static INVOCATION: AtomicUsize = AtomicUsize::new(0);
4558
let root = Path::new(env!("DEBUG_OUTPUT_DIR"));
4659
let world_name = &input.resolve.worlds[input.world].name;
@@ -107,13 +120,16 @@ impl Parse for Config {
107120
}
108121
Opt::Tracing(val) => opts.tracing = val,
109122
Opt::VerboseTracing(val) => opts.verbose_tracing = val,
123+
Opt::Debug(val) => opts.debug = val,
110124
Opt::Async(val, span) => {
111125
if async_configured {
112126
return Err(Error::new(span, "cannot specify second async config"));
113127
}
114128
async_configured = true;
115129
opts.async_ = val;
116130
}
131+
Opt::ConcurrentImports(val) => opts.concurrent_imports = val,
132+
Opt::ConcurrentExports(val) => opts.concurrent_exports = val,
117133
Opt::TrappableErrorType(val) => opts.trappable_error_type = val,
118134
Opt::TrappableImports(val) => opts.trappable_imports = val,
119135
Opt::Ownership(val) => opts.ownership = val,
@@ -138,7 +154,7 @@ impl Parse for Config {
138154
"cannot specify a world with `interfaces`",
139155
));
140156
}
141-
world = Some("interfaces".to_string());
157+
world = Some("wasmtime:component-macro-synthesized/interfaces".to_string());
142158

143159
opts.only_interfaces = true;
144160
}
@@ -281,6 +297,9 @@ mod kw {
281297
syn::custom_keyword!(require_store_data_send);
282298
syn::custom_keyword!(wasmtime_crate);
283299
syn::custom_keyword!(include_generated_code_from_file);
300+
syn::custom_keyword!(concurrent_imports);
301+
syn::custom_keyword!(concurrent_exports);
302+
syn::custom_keyword!(debug);
284303
}
285304

286305
enum Opt {
@@ -301,12 +320,19 @@ enum Opt {
301320
RequireStoreDataSend(bool),
302321
WasmtimeCrate(syn::Path),
303322
IncludeGeneratedCodeFromFile(bool),
323+
ConcurrentImports(bool),
324+
ConcurrentExports(bool),
325+
Debug(bool),
304326
}
305327

306328
impl Parse for Opt {
307329
fn parse(input: ParseStream<'_>) -> Result<Self> {
308330
let l = input.lookahead1();
309-
if l.peek(kw::path) {
331+
if l.peek(kw::debug) {
332+
input.parse::<kw::debug>()?;
333+
input.parse::<Token![:]>()?;
334+
Ok(Opt::Debug(input.parse::<syn::LitBool>()?.value))
335+
} else if l.peek(kw::path) {
310336
input.parse::<kw::path>()?;
311337
input.parse::<Token![:]>()?;
312338

@@ -380,6 +406,14 @@ impl Parse for Opt {
380406
span,
381407
))
382408
}
409+
} else if l.peek(kw::concurrent_imports) {
410+
input.parse::<kw::concurrent_imports>()?;
411+
input.parse::<Token![:]>()?;
412+
Ok(Opt::ConcurrentImports(input.parse::<syn::LitBool>()?.value))
413+
} else if l.peek(kw::concurrent_exports) {
414+
input.parse::<kw::concurrent_exports>()?;
415+
input.parse::<Token![:]>()?;
416+
Ok(Opt::ConcurrentExports(input.parse::<syn::LitBool>()?.value))
383417
} else if l.peek(kw::ownership) {
384418
input.parse::<kw::ownership>()?;
385419
input.parse::<Token![:]>()?;

crates/component-macro/tests/codegen.rs

+8
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,14 @@ macro_rules! gentest {
1212
async: true,
1313
});
1414
}
15+
mod concurrent {
16+
wasmtime::component::bindgen!({
17+
path: $path,
18+
async: true,
19+
concurrent_imports: true,
20+
concurrent_exports: true,
21+
});
22+
}
1523
mod tracing {
1624
wasmtime::component::bindgen!({
1725
path: $path,

crates/component-macro/tests/expanded.rs

+8
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,14 @@ macro_rules! genexpand {
1515
stringify: true,
1616
}))?;
1717

18+
process_expanded($path, "_concurrent", wasmtime::component::bindgen!({
19+
path: $path,
20+
async: true,
21+
concurrent_imports: true,
22+
concurrent_exports: true,
23+
stringify: true,
24+
}))?;
25+
1826
process_expanded($path, "_tracing_async", wasmtime::component::bindgen!({
1927
path: $path,
2028
async: true,

crates/component-macro/tests/expanded/char.rs

+21-8
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ impl<T> Clone for TheWorldPre<T> {
1818
}
1919
}
2020
}
21-
impl<_T> TheWorldPre<_T> {
21+
impl<_T: 'static> TheWorldPre<_T> {
2222
/// Creates a new copy of `TheWorldPre` bindings which can then
2323
/// be used to instantiate into a particular store.
2424
///
@@ -152,7 +152,10 @@ const _: () = {
152152
mut store: impl wasmtime::AsContextMut<Data = _T>,
153153
component: &wasmtime::component::Component,
154154
linker: &wasmtime::component::Linker<_T>,
155-
) -> wasmtime::Result<TheWorld> {
155+
) -> wasmtime::Result<TheWorld>
156+
where
157+
_T: 'static,
158+
{
156159
let pre = linker.instantiate_pre(component)?;
157160
TheWorldPre::new(pre)?.instantiate(store)
158161
}
@@ -194,19 +197,23 @@ pub mod foo {
194197
}
195198
pub trait GetHost<
196199
T,
197-
>: Fn(T) -> <Self as GetHost<T>>::Host + Send + Sync + Copy + 'static {
200+
D,
201+
>: Fn(T) -> <Self as GetHost<T, D>>::Host + Send + Sync + Copy + 'static {
198202
type Host: Host;
199203
}
200-
impl<F, T, O> GetHost<T> for F
204+
impl<F, T, D, O> GetHost<T, D> for F
201205
where
202206
F: Fn(T) -> O + Send + Sync + Copy + 'static,
203207
O: Host,
204208
{
205209
type Host = O;
206210
}
207-
pub fn add_to_linker_get_host<T>(
211+
pub fn add_to_linker_get_host<
212+
T,
213+
G: for<'a> GetHost<&'a mut T, T, Host: Host>,
214+
>(
208215
linker: &mut wasmtime::component::Linker<T>,
209-
host_getter: impl for<'a> GetHost<&'a mut T>,
216+
host_getter: G,
210217
) -> wasmtime::Result<()> {
211218
let mut inst = linker.instance("foo:foo/chars")?;
212219
inst.func_wrap(
@@ -354,7 +361,10 @@ pub mod exports {
354361
&self,
355362
mut store: S,
356363
arg0: char,
357-
) -> wasmtime::Result<()> {
364+
) -> wasmtime::Result<()>
365+
where
366+
<S as wasmtime::AsContext>::Data: Send + 'static,
367+
{
358368
let callee = unsafe {
359369
wasmtime::component::TypedFunc::<
360370
(char,),
@@ -369,7 +379,10 @@ pub mod exports {
369379
pub fn call_return_char<S: wasmtime::AsContextMut>(
370380
&self,
371381
mut store: S,
372-
) -> wasmtime::Result<char> {
382+
) -> wasmtime::Result<char>
383+
where
384+
<S as wasmtime::AsContext>::Data: Send + 'static,
385+
{
373386
let callee = unsafe {
374387
wasmtime::component::TypedFunc::<
375388
(),

crates/component-macro/tests/expanded/char_async.rs

+13-12
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ impl<T> Clone for TheWorldPre<T> {
1818
}
1919
}
2020
}
21-
impl<_T> TheWorldPre<_T> {
21+
impl<_T: Send + 'static> TheWorldPre<_T> {
2222
/// Creates a new copy of `TheWorldPre` bindings which can then
2323
/// be used to instantiate into a particular store.
2424
///
@@ -46,10 +46,7 @@ impl<_T> TheWorldPre<_T> {
4646
pub async fn instantiate_async(
4747
&self,
4848
mut store: impl wasmtime::AsContextMut<Data = _T>,
49-
) -> wasmtime::Result<TheWorld>
50-
where
51-
_T: Send,
52-
{
49+
) -> wasmtime::Result<TheWorld> {
5350
let mut store = store.as_context_mut();
5451
let instance = self.instance_pre.instantiate_async(&mut store).await?;
5552
self.indices.load(&mut store, &instance)
@@ -157,7 +154,7 @@ const _: () = {
157154
linker: &wasmtime::component::Linker<_T>,
158155
) -> wasmtime::Result<TheWorld>
159156
where
160-
_T: Send,
157+
_T: Send + 'static,
161158
{
162159
let pre = linker.instantiate_pre(component)?;
163160
TheWorldPre::new(pre)?.instantiate_async(store).await
@@ -202,19 +199,23 @@ pub mod foo {
202199
}
203200
pub trait GetHost<
204201
T,
205-
>: Fn(T) -> <Self as GetHost<T>>::Host + Send + Sync + Copy + 'static {
202+
D,
203+
>: Fn(T) -> <Self as GetHost<T, D>>::Host + Send + Sync + Copy + 'static {
206204
type Host: Host + Send;
207205
}
208-
impl<F, T, O> GetHost<T> for F
206+
impl<F, T, D, O> GetHost<T, D> for F
209207
where
210208
F: Fn(T) -> O + Send + Sync + Copy + 'static,
211209
O: Host + Send,
212210
{
213211
type Host = O;
214212
}
215-
pub fn add_to_linker_get_host<T>(
213+
pub fn add_to_linker_get_host<
214+
T,
215+
G: for<'a> GetHost<&'a mut T, T, Host: Host + Send>,
216+
>(
216217
linker: &mut wasmtime::component::Linker<T>,
217-
host_getter: impl for<'a> GetHost<&'a mut T>,
218+
host_getter: G,
218219
) -> wasmtime::Result<()>
219220
where
220221
T: Send,
@@ -372,7 +373,7 @@ pub mod exports {
372373
arg0: char,
373374
) -> wasmtime::Result<()>
374375
where
375-
<S as wasmtime::AsContext>::Data: Send,
376+
<S as wasmtime::AsContext>::Data: Send + 'static,
376377
{
377378
let callee = unsafe {
378379
wasmtime::component::TypedFunc::<
@@ -392,7 +393,7 @@ pub mod exports {
392393
mut store: S,
393394
) -> wasmtime::Result<char>
394395
where
395-
<S as wasmtime::AsContext>::Data: Send,
396+
<S as wasmtime::AsContext>::Data: Send + 'static,
396397
{
397398
let callee = unsafe {
398399
wasmtime::component::TypedFunc::<

0 commit comments

Comments
 (0)