diff --git a/crates/core/src/async_.rs b/crates/core/src/async_.rs index e801e2ea3..eea645960 100644 --- a/crates/core/src/async_.rs +++ b/crates/core/src/async_.rs @@ -3,42 +3,40 @@ use std::collections::HashSet; use std::fmt; use wit_parser::{Function, FunctionKind, Resolve, WorldKey}; -/// Structure used to parse the command line argument `--async` consistently +/// Structure used to parse the command line argument `--sync` consistently /// across guest generators. #[cfg_attr(feature = "clap", derive(clap::Parser))] #[cfg_attr(feature = "serde", derive(serde::Deserialize))] #[derive(Clone, Default, Debug)] pub struct AsyncFilterSet { - /// Determines which functions to lift or lower `async`, if any. + /// Determines which `async` functions to lift or lower synchronously, if + /// any. /// /// This option can be passed multiple times and additionally accepts /// comma-separated values for each option passed. Each individual argument /// passed here can be one of: /// - /// - `all` - all imports and exports will be async - /// - `-all` - force all imports and exports to be sync - /// - `foo:bar/baz#method` - force this method to be async - /// - `import:foo:bar/baz#method` - force this method to be async, but only + /// - `all` - all imports and exports will be sync + /// - `foo:bar/baz#method` - force this method to be sync + /// - `import:foo:bar/baz#method` - force this method to be sync, but only /// as an import - /// - `-export:foo:bar/baz#method` - force this export to be sync + /// - `export:foo:bar/baz#method` - force this method to be sync, but only + /// as an export /// - /// If a method is not listed in this option then the WIT's default bindings - /// mode will be used. If the WIT function is defined as `async` then async - /// bindings will be generated, otherwise sync bindings will be generated. - /// - /// Options are processed in the order they are passed here, so if a method - /// matches two directives passed the least-specific one should be last. + /// Functions defined as `async` in WIT get async bindings unless they are + /// listed here. Functions not defined as `async` always get sync bindings, + /// as the component model does not allow lifting or lowering them async. #[cfg_attr( feature = "clap", arg( - long = "async", - value_parser = parse_async, + long = "sync", + value_parser = parse_sync, value_delimiter =',', value_name = "FILTER", ), )] - #[cfg_attr(feature = "serde", serde(rename = "async"))] - async_: Vec, + #[cfg_attr(feature = "serde", serde(rename = "sync"))] + sync: Vec, #[cfg_attr(feature = "clap", arg(skip))] #[cfg_attr(feature = "serde", serde(skip))] @@ -46,23 +44,11 @@ pub struct AsyncFilterSet { } #[cfg(feature = "clap")] -fn parse_async(s: &str) -> Result { - Ok(Async::parse(s)) +fn parse_sync(s: &str) -> Result { + Ok(SyncFilter::parse(s)) } impl AsyncFilterSet { - /// Returns a set where all functions should be async or not depending on - /// `async_` provided. - pub fn all(async_: bool) -> AsyncFilterSet { - AsyncFilterSet { - async_: vec![Async { - enabled: async_, - filter: AsyncFilter::All, - }], - used_options: HashSet::new(), - } - } - /// Returns whether the `func` provided is to be bound `async` or not. pub fn is_async( &mut self, @@ -75,31 +61,22 @@ impl AsyncFilterSet { Some(key) => format!("{}#{}", resolve.name_world_key(key), func.name), None => func.name.clone(), }; - for (i, opt) in self.async_.iter().enumerate() { - let name = match &opt.filter { - AsyncFilter::All => { - self.used_options.insert(i); - return opt.enabled; - } - AsyncFilter::Function(s) => s, - AsyncFilter::Import(s) => { - if !is_import { - continue; - } - s - } - AsyncFilter::Export(s) => { - if is_import { - continue; - } - s - } + let mut sync = false; + for (i, filter) in self.sync.iter().enumerate() { + let matches = match filter { + SyncFilter::All => true, + SyncFilter::Function(s) => *s == name_to_test, + SyncFilter::Import(s) => is_import && *s == name_to_test, + SyncFilter::Export(s) => !is_import && *s == name_to_test, }; - if *name == name_to_test { + if matches { self.used_options.insert(i); - return opt.enabled; + sync = true; } } + if sync { + return false; + } match &func.kind { FunctionKind::Freestanding @@ -115,86 +92,60 @@ impl AsyncFilterSet { /// Intended to be used in the header comment of generated code to help /// indicate what options were specified. pub fn debug_opts(&self) -> impl Iterator + '_ { - self.async_.iter().map(|opt| opt.to_string()) + self.sync.iter().map(|filter| filter.to_string()) } - /// Tests whether all `--async` options were used throughout bindings + /// Tests whether all `--sync` options were used throughout bindings /// generation, returning an error if any were unused. pub fn ensure_all_used(&self) -> Result<()> { - for (i, opt) in self.async_.iter().enumerate() { + for (i, filter) in self.sync.iter().enumerate() { if self.used_options.contains(&i) { continue; } - if !matches!(opt.filter, AsyncFilter::All) { - bail!("unused async option: {opt}"); + if !matches!(filter, SyncFilter::All) { + bail!("unused sync option: {filter}"); } } Ok(()) } - /// Returns whether any option explicitly requests that async is enabled. - pub fn any_enabled(&self) -> bool { - self.async_.iter().any(|o| o.enabled) - } - /// Pushes a new option into this set. pub fn push(&mut self, directive: &str) { - self.async_.push(Async::parse(directive)); + self.sync.push(SyncFilter::parse(directive)); } } #[derive(Debug, Clone)] #[cfg_attr(feature = "serde", derive(serde::Deserialize))] -struct Async { - enabled: bool, - filter: AsyncFilter, +enum SyncFilter { + All, + Function(String), + Import(String), + Export(String), } -impl Async { - fn parse(s: &str) -> Async { - let (s, enabled) = match s.strip_prefix('-') { - Some(s) => (s, false), - None => (s, true), - }; - let filter = match s { - "all" => AsyncFilter::All, +impl SyncFilter { + fn parse(s: &str) -> SyncFilter { + match s { + "all" => SyncFilter::All, other => match other.strip_prefix("import:") { - Some(s) => AsyncFilter::Import(s.to_string()), + Some(s) => SyncFilter::Import(s.to_string()), None => match other.strip_prefix("export:") { - Some(s) => AsyncFilter::Export(s.to_string()), - None => AsyncFilter::Function(s.to_string()), + Some(s) => SyncFilter::Export(s.to_string()), + None => SyncFilter::Function(s.to_string()), }, }, - }; - Async { enabled, filter } - } -} - -impl fmt::Display for Async { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if !self.enabled { - write!(f, "-")?; } - self.filter.fmt(f) } } -#[derive(Debug, Clone)] -#[cfg_attr(feature = "serde", derive(serde::Deserialize))] -enum AsyncFilter { - All, - Function(String), - Import(String), - Export(String), -} - -impl fmt::Display for AsyncFilter { +impl fmt::Display for SyncFilter { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - AsyncFilter::All => write!(f, "all"), - AsyncFilter::Function(s) => write!(f, "{s}"), - AsyncFilter::Import(s) => write!(f, "import:{s}"), - AsyncFilter::Export(s) => write!(f, "export:{s}"), + SyncFilter::All => write!(f, "all"), + SyncFilter::Function(s) => write!(f, "{s}"), + SyncFilter::Import(s) => write!(f, "import:{s}"), + SyncFilter::Export(s) => write!(f, "export:{s}"), } } } diff --git a/crates/guest-rust/macro/src/lib.rs b/crates/guest-rust/macro/src/lib.rs index 68b9b6871..df7db7188 100644 --- a/crates/guest-rust/macro/src/lib.rs +++ b/crates/guest-rust/macro/src/lib.rs @@ -86,7 +86,7 @@ impl Parse for Config { let mut world = None; let mut source = None; let mut features = Vec::new(); - let mut async_configured = false; + let mut sync_configured = false; let mut method_chaining_configured = false; let mut debug = false; @@ -184,11 +184,11 @@ impl Parse for Config { Opt::Debug(enable) => { debug = enable.value(); } - Opt::Async(val, span) => { - if async_configured { - return Err(Error::new(span, "cannot specify second async config")); + Opt::Sync(val, span) => { + if sync_configured { + return Err(Error::new(span, "cannot specify second sync config")); } - async_configured = true; + sync_configured = true; opts.async_ = val; } Opt::ChainableMethods(val, span) => { @@ -366,6 +366,7 @@ mod kw { syn::custom_keyword!(imports); syn::custom_keyword!(debug); syn::custom_keyword!(chainable_methods); + syn::custom_keyword!(sync); syn::custom_keyword!(merge_structurally_equal_types); } @@ -447,7 +448,7 @@ enum Opt { GenerateUnusedTypes(syn::LitBool), Features(Vec), DisableCustomSectionLinkHelpers(syn::LitBool), - Async(AsyncFilterSet, Span), + Sync(AsyncFilterSet, Span), Debug(syn::LitBool), ChainableMethods(ChainableMethodFilterSet, Span), MergeStructurallyEqualTypes(syn::LitBool), @@ -646,21 +647,29 @@ impl Parse for Opt { set.push(&val.value()); } Ok(Opt::ChainableMethods(set, span)) - } else if l.peek(Token![async]) { - let span = input.parse::()?.span; + } else if l.peek(kw::sync) { + let span = input.parse::()?.span; input.parse::()?; + let mut set = AsyncFilterSet::default(); if input.peek(syn::LitBool) { - let enabled = input.parse::()?.value; - Ok(Opt::Async(AsyncFilterSet::all(enabled), span)) + if input.parse::()?.value { + set.push("all"); + } } else { - let mut set = AsyncFilterSet::default(); let contents; syn::bracketed!(contents in input); for val in contents.parse_terminated(|p| p.parse::(), Token![,])? { set.push(&val.value()); } - Ok(Opt::Async(set, span)) } + Ok(Opt::Sync(set, span)) + } else if input.peek(Token![async]) { + let span = input.parse::()?.span; + Err(Error::new( + span, + "the `async` option has been removed: functions that are `async` \ + in WIT get async bindings by default, and `sync` opts them out", + )) } else if l.peek(kw::merge_structurally_equal_types) { input.parse::()?; input.parse::()?; diff --git a/crates/guest-rust/src/lib.rs b/crates/guest-rust/src/lib.rs index e88633847..62bbf101a 100644 --- a/crates/guest-rust/src/lib.rs +++ b/crates/guest-rust/src/lib.rs @@ -860,22 +860,18 @@ extern crate std; /// // the specific `generate!` call where it is used. /// debug: true, /// -/// // Generate async import and/or export bindings. +/// // Generate sync bindings for functions that are `async` in WIT. /// // -/// // The resulting bindings will use the component model -/// // [async ABI](https://github.com/WebAssembly/component-model/blob/main/design/mvp/Async.md). -/// // -/// // If this option is not provided then the WIT's source annotation will -/// // be used instead. -/// async: true, // all bindings are async -/// async: false, // all bindings are sync -/// // With an array per-function configuration can be specified. A leading -/// // '-' will disable async for that particular function. -/// async: [ +/// // Functions that are `async` in WIT get bindings using the component +/// // model [async ABI](https://github.com/WebAssembly/component-model/blob/main/design/mvp/Async.md) +/// // by default, and all other functions get sync bindings. This option +/// // switches `async` functions back to sync bindings. +/// sync: true, // all bindings are sync +/// // With an array per-function configuration can be specified. +/// sync: [ /// "wasi:http/types@0.3.0-draft#[static]body.finish", /// "import:wasi:http/handler@0.3.0-draft#handle", -/// "-export:wasi:http/handler@0.3.0-draft#handle", -/// "all", +/// "export:wasi:http/handler@0.3.0-draft#handle", /// ], /// /// // All resource methods with empty returns are instead generated as diff --git a/crates/moonbit/src/lib.rs b/crates/moonbit/src/lib.rs index f91eb4d2e..fc95b2713 100644 --- a/crates/moonbit/src/lib.rs +++ b/crates/moonbit/src/lib.rs @@ -3257,7 +3257,7 @@ mod tests { } #[test] - fn async_filters_respect_import_export_direction() { + fn sync_filters_respect_import_export_direction() { // The world both imports and exports `run` so that each directional // filter below matches something; an unmatched filter is now an error // (see `AsyncFilterSet::ensure_all_used`), which would mask what this @@ -3265,8 +3265,8 @@ mod tests { let wit = r#" package a:b; world runner { - import run: func(); - export run: func(); + import run: async func(); + export run: async func(); } "#; @@ -3278,8 +3278,9 @@ mod tests { let import_files = try_generate_with_opts(wit, "runner", import_opts).unwrap(); let import = file(&import_files, "world/runner/import.mbt"); let import_ffi = file(&import_files, "world/runner/ffi_import.mbt"); - assert!(import.contains("pub async fn run("), "{import}"); - assert!(import_ffi.contains("[async-lower]run"), "{import_ffi}"); + assert!(import.contains("pub fn run("), "{import}"); + assert!(!import.contains("pub async fn run("), "{import}"); + assert!(!import_ffi.contains("[async-lower]run"), "{import_ffi}"); let mut export_opts = Opts { gen_dir: "gen".into(), @@ -3289,9 +3290,8 @@ mod tests { let export_files = try_generate_with_opts(wit, "runner", export_opts).unwrap(); let import = file(&export_files, "world/runner/import.mbt"); let import_ffi = file(&export_files, "world/runner/ffi_import.mbt"); - assert!(import.contains("pub fn run("), "{import}"); - assert!(!import.contains("pub async fn run("), "{import}"); - assert!(!import_ffi.contains("[async-lower]run"), "{import_ffi}"); + assert!(import.contains("pub async fn run("), "{import}"); + assert!(import_ffi.contains("[async-lower]run"), "{import_ffi}"); } #[test] diff --git a/crates/rust/src/lib.rs b/crates/rust/src/lib.rs index 7a2058937..29270865b 100644 --- a/crates/rust/src/lib.rs +++ b/crates/rust/src/lib.rs @@ -1225,7 +1225,7 @@ impl WorldGenerator for RustWasm { ); } for opt in self.opts.async_.debug_opts() { - uwriteln!(self.src_preamble, "// * async: {opt}"); + uwriteln!(self.src_preamble, "// * sync: {opt}"); } for opt in self.opts.chainable_methods.debug_opts() { uwriteln!(self.src_preamble, "// * chainable-methods: {opt}"); diff --git a/crates/test/src/c.rs b/crates/test/src/c.rs index 944f833be..d78af7a37 100644 --- a/crates/test/src/c.rs +++ b/crates/test/src/c.rs @@ -64,7 +64,6 @@ impl LanguageMethods for C { &[ ("no-sig-flattening", &["--no-sig-flattening"]), ("autodrop", &["--autodrop-borrows=yes"]), - ("async", &["--async=all"]), ] } diff --git a/crates/test/src/moonbit.rs b/crates/test/src/moonbit.rs index 7ad5fbc9d..f55c19863 100644 --- a/crates/test/src/moonbit.rs +++ b/crates/test/src/moonbit.rs @@ -29,7 +29,7 @@ impl LanguageMethods for MoonBit { } fn codegen_test_variants(&self) -> &[(&str, &[&str])] { - &[("async", &["--async=all"])] + &[] } fn prepare(&self, runner: &mut Runner) -> anyhow::Result<()> { @@ -120,11 +120,11 @@ impl LanguageMethods for MoonBit { fn should_fail_verify( &self, _runner: &Runner, - name: &str, + _name: &str, config: &crate::config::WitConfig, _args: &[String], ) -> bool { - name == "named-fixed-length-list.wit-async" || config.error_context + config.error_context } fn verify(&self, runner: &Runner, verify: &crate::Verify) -> anyhow::Result<()> { diff --git a/crates/test/src/rust.rs b/crates/test/src/rust.rs index e2b3ddf74..3ac6f4924 100644 --- a/crates/test/src/rust.rs +++ b/crates/test/src/rust.rs @@ -98,11 +98,6 @@ impl LanguageMethods for Rust { return true; } - // Named fixed-length lists don't work with async yet. - if name == "named-fixed-length-list.wit-async" { - return true; - } - false } @@ -113,7 +108,6 @@ impl LanguageMethods for Rust { "borrowed-duplicate", &["--ownership=borrowing-duplicate-if-necessary"], ), - ("async", &["--async=all"]), ("no-std", &["--std-feature"]), ("merge-equal", &["--merge-structurally-equal-types"]), ("hashmap", &["--map-type=std::collections::HashMap"]), diff --git a/tests/runtime/cancel-import/runner.c b/tests/runtime/cancel-import/runner.c index bb3877f52..2a35f7385 100644 --- a/tests/runtime/cancel-import/runner.c +++ b/tests/runtime/cancel-import/runner.c @@ -1,4 +1,4 @@ -//@ args = '--rename my:test/i=test --async=-run' +//@ args = '--rename my:test/i=test --sync=run' //@ wasmtime-flags = '-Wcomponent-model-async' #include diff --git a/tests/runtime/future-cancel-read/runner.c b/tests/runtime/future-cancel-read/runner.c index be17144c2..0ab8d5446 100644 --- a/tests/runtime/future-cancel-read/runner.c +++ b/tests/runtime/future-cancel-read/runner.c @@ -1,4 +1,4 @@ -//@ args = '--rename my:test/i=test --async=-run' +//@ args = '--rename my:test/i=test --sync=run' //@ wasmtime-flags = '-Wcomponent-model-async' #include diff --git a/tests/runtime/future-cancel-write/runner.c b/tests/runtime/future-cancel-write/runner.c index 4533b0adf..2f441b9f1 100644 --- a/tests/runtime/future-cancel-write/runner.c +++ b/tests/runtime/future-cancel-write/runner.c @@ -1,4 +1,4 @@ -//@ args = '--rename my:test/i=test --async=-run' +//@ args = '--rename my:test/i=test --sync=run' //@ wasmtime-flags = '-Wcomponent-model-async' #include diff --git a/tests/runtime/future-write-then-read-remote/runner.rs b/tests/runtime/future-write-then-read-remote/runner.rs index bbaeeed20..4d32d52ec 100644 --- a/tests/runtime/future-write-then-read-remote/runner.rs +++ b/tests/runtime/future-write-then-read-remote/runner.rs @@ -1,4 +1,4 @@ -//@ args = '--async=-all' +//@ args = '--sync=all' //@ wasmtime-flags = '-Wcomponent-model-async' include!(env!("BINDINGS")); diff --git a/tests/runtime/future-write-then-read-remote/runner2.rs b/tests/runtime/future-write-then-read-remote/runner2.rs index 8f6e261f3..884fd4e67 100644 --- a/tests/runtime/future-write-then-read-remote/runner2.rs +++ b/tests/runtime/future-write-then-read-remote/runner2.rs @@ -1,4 +1,4 @@ -//@ args = '--async=-all' +//@ args = '--sync=all' //@ wasmtime-flags = '-Wcomponent-model-async' include!(env!("BINDINGS")); diff --git a/tests/runtime/pending-import/runner.c b/tests/runtime/pending-import/runner.c index 2d80f3920..58ec0d42e 100644 --- a/tests/runtime/pending-import/runner.c +++ b/tests/runtime/pending-import/runner.c @@ -1,4 +1,4 @@ -//@ args = '--rename my:test/i=test --async=-run' +//@ args = '--rename my:test/i=test --sync=run' //@ wasmtime-flags = '-Wcomponent-model-async' #include diff --git a/tests/runtime/ping-pong/runner.c b/tests/runtime/ping-pong/runner.c index 02a76e655..acc05d7a0 100644 --- a/tests/runtime/ping-pong/runner.c +++ b/tests/runtime/ping-pong/runner.c @@ -1,4 +1,4 @@ -//@ args = '--rename my:test/i=test --async=-run' +//@ args = '--rename my:test/i=test --sync=run' //@ wasmtime-flags = '-Wcomponent-model-async' #include diff --git a/tests/runtime/simple-call-import/runner.c b/tests/runtime/simple-call-import/runner.c index 71053d82c..fb7103882 100644 --- a/tests/runtime/simple-call-import/runner.c +++ b/tests/runtime/simple-call-import/runner.c @@ -1,4 +1,4 @@ -//@ args = '--rename a:b/i=test --async=-run' +//@ args = '--rename a:b/i=test --sync=run' //@ wasmtime-flags = '-Wcomponent-model-async' #include diff --git a/tests/runtime/simple-future/runner.c b/tests/runtime/simple-future/runner.c index b5d716f54..15e906b7f 100644 --- a/tests/runtime/simple-future/runner.c +++ b/tests/runtime/simple-future/runner.c @@ -1,4 +1,4 @@ -//@ args = '--rename my:test/i=test --async=-run' +//@ args = '--rename my:test/i=test --sync=run' //@ wasmtime-flags = '-Wcomponent-model-async' #include diff --git a/tests/runtime/simple-import-params-results/runner.c b/tests/runtime/simple-import-params-results/runner.c index 2dc4e4548..af471eead 100644 --- a/tests/runtime/simple-import-params-results/runner.c +++ b/tests/runtime/simple-import-params-results/runner.c @@ -1,4 +1,4 @@ -//@ args = '--rename a:b/i=test --async=-run' +//@ args = '--rename a:b/i=test --sync=run' //@ wasmtime-flags = '-Wcomponent-model-async' #include diff --git a/tests/runtime/simple-pending-import/runner.c b/tests/runtime/simple-pending-import/runner.c index 36fb6a86d..718c9caa8 100644 --- a/tests/runtime/simple-pending-import/runner.c +++ b/tests/runtime/simple-pending-import/runner.c @@ -1,4 +1,4 @@ -//@ args = '--rename a:b/i=test --async=-run' +//@ args = '--rename a:b/i=test --sync=run' //@ wasmtime-flags = '-Wcomponent-model-async' #include diff --git a/tests/runtime/simple-stream-payload/runner.c b/tests/runtime/simple-stream-payload/runner.c index 472cf5a3f..c52138e0b 100644 --- a/tests/runtime/simple-stream-payload/runner.c +++ b/tests/runtime/simple-stream-payload/runner.c @@ -1,4 +1,4 @@ -//@ args = '--rename my:test/i=test --async=-run' +//@ args = '--rename my:test/i=test --sync=run' //@ wasmtime-flags = '-Wcomponent-model-async' #include diff --git a/tests/runtime/simple-stream/runner.c b/tests/runtime/simple-stream/runner.c index 54c1fef4d..4966c0704 100644 --- a/tests/runtime/simple-stream/runner.c +++ b/tests/runtime/simple-stream/runner.c @@ -1,4 +1,4 @@ -//@ args = '--rename my:test/i=test --async=-run' +//@ args = '--rename my:test/i=test --sync=run' //@ wasmtime-flags = '-Wcomponent-model-async' #include diff --git a/tests/runtime/simple-yield/runner.c b/tests/runtime/simple-yield/runner.c index b74b9f8cc..462e9f44c 100644 --- a/tests/runtime/simple-yield/runner.c +++ b/tests/runtime/simple-yield/runner.c @@ -1,4 +1,4 @@ -//@ args = '--rename a:b/i=test --async=-run' +//@ args = '--rename a:b/i=test --sync=run' //@ wasmtime-flags = '-Wcomponent-model-async' #include