Skip to content

Commit b52eddd

Browse files
committed
async/stream/future support for wasmtime-wit-bindgen
I've split this out of bytecodealliance#9582 to make review easier. This patch adds async/stream/future/error-context support to the host binding generator, along with placeholder type and function definitions in the `wasmtime` crate which the generated bindings can refer to. See https://github.com/dicej/rfcs/blob/component-async/accepted/component-model-async.md#componentbindgen-updates for the design and rationale. Note that I've added temporary `[patch.crates-io]` overrides in Cargo.toml until bytecodealliance/wit-bindgen#1130 and bytecodealliance/wasm-tools#1978 have been released. Also note that we emit a `T: 'static` bound for `AsContextMut<Data = T>` when generating bindings with `concurrent_imports: true`. This is only because `rustc` insists that the closure we're passing to `LinkerInstance::func_wrap_concurrent` captures the lifetime of `T` despite my best efforts to convince it otherwise. Alex and I suspect this is a limitation in the compiler, and I asked about it on the rust-lang Zulip, but we haven't been able to determine a workaround so far. Signed-off-by: Joel Dice <[email protected]>
1 parent 6ac02e1 commit b52eddd

File tree

144 files changed

+30271
-950
lines changed

Some content is hidden

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

144 files changed

+30271
-950
lines changed

Cargo.lock

Lines changed: 17 additions & 32 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -564,3 +564,21 @@ opt-level = 's'
564564
inherits = "release"
565565
codegen-units = 1
566566
lto = true
567+
568+
# TODO: Remove these patches once wit-bindgen 0.38 and wasm-tools 1.224 are available:
569+
[patch.crates-io]
570+
wit-bindgen = { git = "https://github.com/dicej/wit-bindgen", branch = "feat/stream-unit" }
571+
wit-bindgen-rt = { git = "https://github.com/dicej/wit-bindgen", branch = "feat/stream-unit" }
572+
wit-bindgen-rust-macro = { git = "https://github.com/dicej/wit-bindgen", branch = "feat/stream-unit" }
573+
wasmparser = { git = "https://github.com/bytecodealliance/wasm-tools" }
574+
wasm-metadata = { git = "https://github.com/bytecodealliance/wasm-tools" }
575+
wat = { git = "https://github.com/bytecodealliance/wasm-tools" }
576+
wast = { git = "https://github.com/bytecodealliance/wasm-tools" }
577+
wasmprinter = { git = "https://github.com/bytecodealliance/wasm-tools" }
578+
wasm-encoder = { git = "https://github.com/bytecodealliance/wasm-tools" }
579+
wasm-smith = { git = "https://github.com/bytecodealliance/wasm-tools" }
580+
wasm-mutate = { git = "https://github.com/bytecodealliance/wasm-tools" }
581+
wit-parser = { git = "https://github.com/bytecodealliance/wasm-tools" }
582+
wit-component = { git = "https://github.com/bytecodealliance/wasm-tools" }
583+
wasm-wave = { git = "https://github.com/bytecodealliance/wasm-tools" }
584+

crates/component-macro/Cargo.toml

Lines changed: 3 additions & 1 deletion
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

Lines changed: 41 additions & 7 deletions
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

Lines changed: 8 additions & 0 deletions
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

Lines changed: 8 additions & 0 deletions
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,

0 commit comments

Comments
 (0)