diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 4b0fa85aba8a..8de9ac36eef9 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -222,6 +222,7 @@ jobs: cargo doc --no-deps --workspace \ --exclude wasmtime-cli \ --exclude test-programs \ + --exclude wasi-http-tests \ --exclude cranelift-codegen-meta \ --features component-model - run: cargo doc --package cranelift-codegen-meta --document-private-items diff --git a/Cargo.lock b/Cargo.lock index 4ebf1c4322a9..1121cd24ed89 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -686,7 +686,7 @@ dependencies = [ "target-lexicon", "thiserror", "toml", - "wasmparser 0.105.0", + "wasmparser 0.107.0", "wat", ] @@ -862,7 +862,7 @@ dependencies = [ "serde", "smallvec", "target-lexicon", - "wasmparser 0.105.0", + "wasmparser 0.107.0", "wasmtime-types", "wat", ] @@ -3150,7 +3150,7 @@ dependencies = [ "wasmtime", "wasmtime-wasi", "wasmtime-wasi-http", - "wit-component 0.9.0", + "wit-component", ] [[package]] @@ -3675,74 +3675,52 @@ dependencies = [ [[package]] name = "wasm-encoder" -version = "0.26.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d05d0b6fcd0aeb98adf16e7975331b3c17222aa815148f5b976370ce589d80ef" +checksum = "18c41dbd92eaebf3612a39be316540b8377c871cb9bde6b064af962984912881" dependencies = [ "leb128", ] -[[package]] -name = "wasm-encoder" -version = "0.27.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e77053dc709db790691d3732cfc458adc5acc881dec524965c608effdcd9c581" -dependencies = [ - "leb128", -] - -[[package]] -name = "wasm-metadata" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbdef99fafff010c57fabb7bc703f0903ec16fcee49207a22dcc4f78ea44562f" -dependencies = [ - "anyhow", - "indexmap", - "serde", - "wasm-encoder 0.26.0", - "wasmparser 0.104.0", -] - [[package]] name = "wasm-metadata" -version = "0.6.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27e6532071b112df81d756fabafab8cc882b84ae3d6ce9b90f3d90c80e4abe05" +checksum = "36e5156581ff4a302405c44ca7c85347563ca431d15f1a773f12c9c7b9a6cdc9" dependencies = [ "anyhow", "indexmap", "serde", - "wasm-encoder 0.27.0", - "wasmparser 0.105.0", + "wasm-encoder 0.29.0", + "wasmparser 0.107.0", ] [[package]] name = "wasm-mutate" -version = "0.2.25" +version = "0.2.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b8c74fd20d97b9ba8b1a6e3ccc6ec715e6c6d4605668926e582e88580180d96" +checksum = "f354beb7e2ccaf66dd263328486240899755ae0df3ac4b76305dace67fbd2169" dependencies = [ "egg", "log", "rand 0.8.5", "thiserror", - "wasm-encoder 0.27.0", - "wasmparser 0.105.0", + "wasm-encoder 0.29.0", + "wasmparser 0.107.0", ] [[package]] name = "wasm-smith" -version = "0.12.8" +version = "0.12.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c11c745f6f4ff2f953d8a94ef056b04b468fc021285cfaf614e77791c05499" +checksum = "027ec1c470cd5d56c43b8e02040250b136ddb5975dd76a1c16915137f5f17e76" dependencies = [ "arbitrary", "flagset", "indexmap", "leb128", - "wasm-encoder 0.27.0", - "wasmparser 0.105.0", + "wasm-encoder 0.29.0", + "wasmparser 0.107.0", ] [[package]] @@ -3794,22 +3772,12 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.104.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a396af81a7c56ad976131d6a35e4b693b78a1ea0357843bd436b4577e254a7d" -dependencies = [ - "indexmap", - "url", -] - -[[package]] -name = "wasmparser" -version = "0.105.0" +version = "0.107.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83be9e0b3f9570dc1979a33ae7b89d032c73211564232b99976553e5c155ec32" +checksum = "29e3ac9b780c7dda0cac7a52a5d6d2d6707cc6e3451c9db209b6c758f40d7acb" dependencies = [ "indexmap", - "url", + "semver", ] [[package]] @@ -3823,12 +3791,12 @@ dependencies = [ [[package]] name = "wasmprinter" -version = "0.2.57" +version = "0.2.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50b0e5ed7a74a065637f0d7798ce5f29cadb064980d24b0c82af5200122fa0d8" +checksum = "cc960b30b84abca377768f3c62cff3a1c74db8c0f6759ed581827da0bd3a3fed" dependencies = [ "anyhow", - "wasmparser 0.105.0", + "wasmparser 0.107.0", ] [[package]] @@ -3855,7 +3823,7 @@ dependencies = [ "target-lexicon", "tempfile", "wasi-cap-std-sync", - "wasmparser 0.105.0", + "wasmparser 0.107.0", "wasmtime-cache", "wasmtime-component-macro", "wasmtime-component-util", @@ -3970,8 +3938,8 @@ dependencies = [ "test-programs", "tokio", "walkdir", - "wasm-encoder 0.27.0", - "wasmparser 0.105.0", + "wasm-encoder 0.29.0", + "wasmparser 0.107.0", "wasmtime", "wasmtime-cache", "wasmtime-cli-flags", @@ -3986,7 +3954,7 @@ dependencies = [ "wasmtime-wasi-nn", "wasmtime-wasi-threads", "wasmtime-wast", - "wast 58.0.0", + "wast 60.0.0", "wat", "windows-sys 0.48.0", ] @@ -4039,7 +4007,7 @@ dependencies = [ "object", "target-lexicon", "thiserror", - "wasmparser 0.105.0", + "wasmparser 0.107.0", "wasmtime-cranelift-shared", "wasmtime-environ", ] @@ -4074,8 +4042,8 @@ dependencies = [ "serde", "target-lexicon", "thiserror", - "wasm-encoder 0.27.0", - "wasmparser 0.105.0", + "wasm-encoder 0.29.0", + "wasmparser 0.107.0", "wasmprinter", "wasmtime-component-util", "wasmtime-types", @@ -4090,7 +4058,7 @@ dependencies = [ "component-fuzz-util", "env_logger 0.10.0", "libfuzzer-sys", - "wasmparser 0.105.0", + "wasmparser 0.107.0", "wasmprinter", "wasmtime-environ", "wat", @@ -4144,7 +4112,7 @@ dependencies = [ "rand 0.8.5", "smallvec", "target-lexicon", - "wasmparser 0.105.0", + "wasmparser 0.107.0", "wasmtime", "wasmtime-fuzzing", ] @@ -4164,12 +4132,12 @@ dependencies = [ "target-lexicon", "tempfile", "v8", - "wasm-encoder 0.27.0", + "wasm-encoder 0.29.0", "wasm-mutate", "wasm-smith", "wasm-spec-interpreter", "wasmi", - "wasmparser 0.105.0", + "wasmparser 0.107.0", "wasmprinter", "wasmtime", "wasmtime-wast", @@ -4251,7 +4219,7 @@ dependencies = [ "cranelift-entity", "serde", "thiserror", - "wasmparser 0.105.0", + "wasmparser 0.107.0", ] [[package]] @@ -4338,7 +4306,7 @@ dependencies = [ "anyhow", "log", "wasmtime", - "wast 58.0.0", + "wast 60.0.0", ] [[package]] @@ -4350,7 +4318,7 @@ dependencies = [ "gimli", "object", "target-lexicon", - "wasmparser 0.105.0", + "wasmparser 0.107.0", "wasmtime-cranelift-shared", "wasmtime-environ", "winch-codegen", @@ -4376,23 +4344,23 @@ dependencies = [ [[package]] name = "wast" -version = "58.0.0" +version = "60.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "372eecae2d10a5091c2005b32377d7ecd6feecdf2c05838056d02d8b4f07c429" +checksum = "bd06cc744b536e30387e72a48fdd492105b9c938bb4f415c39c616a7a0a697ad" dependencies = [ "leb128", "memchr", "unicode-width", - "wasm-encoder 0.27.0", + "wasm-encoder 0.29.0", ] [[package]] name = "wat" -version = "1.0.64" +version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d47446190e112ab1579ab40b3ad7e319d859d74e5134683f04e9f0747bf4173" +checksum = "5abe520f0ab205366e9ac7d3e6b2fc71de44e32a2b58f2ec871b6b575bdcea3b" dependencies = [ - "wast 58.0.0", + "wast 60.0.0", ] [[package]] @@ -4520,7 +4488,7 @@ dependencies = [ "regalloc2", "smallvec", "target-lexicon", - "wasmparser 0.105.0", + "wasmparser 0.107.0", "wasmtime-environ", ] @@ -4564,7 +4532,7 @@ dependencies = [ "similar", "target-lexicon", "toml", - "wasmparser 0.105.0", + "wasmparser 0.107.0", "wasmtime-environ", "wat", "winch-codegen", @@ -4717,9 +4685,8 @@ dependencies = [ [[package]] name = "wit-bindgen" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad22d93d3f55847ac4b3df31607a26f35231754ef472382319de032770d8b5bf" +version = "0.7.0" +source = "git+https://github.com/bytecodealliance/wit-bindgen?branch=wasmtime-2023-05-26-wit-changes#7df2c15f54d7c20593ff2d38db48014889c9a46d" dependencies = [ "bitflags 2.2.1", "wit-bindgen-rust-macro", @@ -4727,33 +4694,30 @@ dependencies = [ [[package]] name = "wit-bindgen-core" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bc1b5a6e87f16491f2297f75312dc0fb354f8c88c8bece53ea0d3167fc98867" +version = "0.7.0" +source = "git+https://github.com/bytecodealliance/wit-bindgen?branch=wasmtime-2023-05-26-wit-changes#7df2c15f54d7c20593ff2d38db48014889c9a46d" dependencies = [ "anyhow", - "wit-component 0.8.2", + "wit-component", "wit-parser", ] [[package]] name = "wit-bindgen-rust" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7946a66f1132d3322c29de9d28097bd263f67e1e0909054f91253aa103cdf8be" +version = "0.7.0" +source = "git+https://github.com/bytecodealliance/wit-bindgen?branch=wasmtime-2023-05-26-wit-changes#7df2c15f54d7c20593ff2d38db48014889c9a46d" dependencies = [ "heck", - "wasm-metadata 0.5.0", + "wasm-metadata", "wit-bindgen-core", "wit-bindgen-rust-lib", - "wit-component 0.8.2", + "wit-component", ] [[package]] name = "wit-bindgen-rust-lib" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0baf7325748c5d363ab6ed3ddbd155c241cfe385410c61f2505ec978a61a2d2c" +version = "0.7.0" +source = "git+https://github.com/bytecodealliance/wit-bindgen?branch=wasmtime-2023-05-26-wit-changes#7df2c15f54d7c20593ff2d38db48014889c9a46d" dependencies = [ "heck", "wit-bindgen-core", @@ -4761,63 +4725,45 @@ dependencies = [ [[package]] name = "wit-bindgen-rust-macro" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42c131da5d2ba7746908e1401d474640371c31ad05281528c2a9e945a87d19be" +version = "0.7.0" +source = "git+https://github.com/bytecodealliance/wit-bindgen?branch=wasmtime-2023-05-26-wit-changes#7df2c15f54d7c20593ff2d38db48014889c9a46d" dependencies = [ "anyhow", "proc-macro2", "syn 2.0.16", "wit-bindgen-core", "wit-bindgen-rust", - "wit-component 0.8.2", -] - -[[package]] -name = "wit-component" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e291ff83cb9c8e59963cc6922bdda77ed8f5517d6835f0c98070c4e7f1ae4996" -dependencies = [ - "anyhow", - "bitflags 1.3.2", - "indexmap", - "log", - "url", - "wasm-encoder 0.26.0", - "wasm-metadata 0.5.0", - "wasmparser 0.104.0", - "wit-parser", + "wit-component", ] [[package]] name = "wit-component" -version = "0.9.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3cc435c15009f80d5e114d0dd3792959171f1fc28be2418e0f570d83b925a33" +checksum = "7cbd4c7f8f400327c482c88571f373844b7889e61460650d650fc5881bb3575c" dependencies = [ "anyhow", "bitflags 1.3.2", "indexmap", "log", - "url", - "wasm-encoder 0.27.0", - "wasm-metadata 0.6.0", - "wasmparser 0.105.0", + "wasm-encoder 0.29.0", + "wasm-metadata", + "wasmparser 0.107.0", "wit-parser", ] [[package]] name = "wit-parser" -version = "0.7.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ca2581061573ef6d1754983d7a9b3ed5871ef859d52708ea9a0f5af32919172" +checksum = "6daec9f093dbaea0e94043eeb92ece327bbbe70c86b1f41aca9bbfefd7f050f0" dependencies = [ "anyhow", "id-arena", "indexmap", "log", "pulldown-cmark", + "semver", "unicode-xid", "url", ] diff --git a/Cargo.toml b/Cargo.toml index 201494b6981f..6c33b266fe7e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -197,18 +197,18 @@ io-lifetimes = { version = "1.0.0", default-features = false } rustix = "0.37.13" # wit-bindgen: -wit-bindgen = "0.6.0" +wit-bindgen = { version = "0.7.0", default-features = false } # wasm-tools family: -wasmparser = "0.105.0" -wat = "1.0.64" -wast = "58.0.0" -wasmprinter = "0.2.57" -wasm-encoder = "0.27.0" -wasm-smith = "0.12.8" -wasm-mutate = "0.2.25" -wit-parser = "0.7.1" -wit-component = "0.9.0" +wasmparser = "0.107.0" +wat = "1.0.66" +wast = "60.0.0" +wasmprinter = "0.2.59" +wasm-encoder = "0.29.0" +wasm-smith = "0.12.10" +wasm-mutate = "0.2.27" +wit-parser = "0.8.0" +wit-component = "0.11.0" # Non-Bytecode Alliance maintained dependencies: # -------------------------- @@ -248,7 +248,8 @@ default = [ "vtune", "wasi-nn", "wasi-threads", - "wasi-http", + # TODO: the WIT needs to be updated + #"wasi-http", "pooling-allocator", ] jitdump = ["wasmtime/jitdump"] @@ -311,3 +312,5 @@ debug-assertions = false # string initializers. overflow-checks = false +[patch.crates-io] +wit-bindgen = { git = 'https://github.com/bytecodealliance/wit-bindgen', branch = 'wasmtime-2023-05-26-wit-changes' } diff --git a/cranelift/wasm/src/sections_translator.rs b/cranelift/wasm/src/sections_translator.rs index 68705ad4a775..e7b0486ea6ce 100644 --- a/cranelift/wasm/src/sections_translator.rs +++ b/cranelift/wasm/src/sections_translator.rs @@ -56,6 +56,9 @@ pub fn parse_type_section<'a>( let ty = environ.convert_func_type(&wasm_func_ty); environ.declare_type_func(ty)?; } + Type::Array(_) => { + unimplemented!("gc proposal"); + } } } Ok(()) diff --git a/crates/component-macro/src/bindgen.rs b/crates/component-macro/src/bindgen.rs index 02865920458e..e41e0fa2abcf 100644 --- a/crates/component-macro/src/bindgen.rs +++ b/crates/component-macro/src/bindgen.rs @@ -78,7 +78,16 @@ impl Parse for Config { if inline.is_some() { return Err(Error::new(s.span(), "cannot specify a second source")); } - inline = Some(format!("default world interfaces {{ {} }}", s.value())); + inline = Some(format!( + " + package wasmtime:component-macro-synthesized + + world interfaces {{ + {} + }} + ", + s.value() + )); if world.is_some() { return Err(Error::new( @@ -86,7 +95,7 @@ impl Parse for Config { "cannot specify a world with `interfaces`", )); } - world = Some("macro-input.interfaces".to_string()); + world = Some("interfaces".to_string()); opts.only_interfaces = true; } @@ -130,7 +139,7 @@ fn parse_source( } else { let pkg = UnresolvedPackage::parse_file(path)?; files.extend(pkg.source_files().map(|s| s.to_owned())); - resolve.push(pkg, &Default::default()) + resolve.push(pkg) } }; @@ -141,16 +150,7 @@ fn parse_source( }; let inline_pkg = if let Some(inline) = inline { - let deps = resolve - .packages - .iter() - .map(|(id, p)| (p.name.clone(), id)) - .collect(); - - Some(resolve.push( - UnresolvedPackage::parse("macro-input".as_ref(), &inline)?, - &deps, - )?) + Some(resolve.push(UnresolvedPackage::parse("macro-input".as_ref(), &inline)?)?) } else { None }; diff --git a/crates/component-macro/tests/codegen.rs b/crates/component-macro/tests/codegen.rs index ac39534022c0..616f3253c614 100644 --- a/crates/component-macro/tests/codegen.rs +++ b/crates/component-macro/tests/codegen.rs @@ -4,9 +4,6 @@ macro_rules! gentest { mod sugar { wasmtime::component::bindgen!(in $path); } - mod normal { - wasmtime::component::bindgen!($name in $path); - } mod async_ { wasmtime::component::bindgen!({ path: $path, @@ -16,15 +13,12 @@ macro_rules! gentest { mod tracing { wasmtime::component::bindgen!({ path: $path, - world: $name, tracing: true, duplicate_if_necessary: true, }); } } - // ... }; - } component_macro_test_helpers::foreach!(gentest); diff --git a/crates/component-macro/tests/codegen/char.wit b/crates/component-macro/tests/codegen/char.wit index 01b20f70077f..b49947b38abb 100644 --- a/crates/component-macro/tests/codegen/char.wit +++ b/crates/component-macro/tests/codegen/char.wit @@ -1,3 +1,5 @@ +package foo:foo + interface chars { /// A function that accepts a character take-char: func(x: char) @@ -5,7 +7,7 @@ interface chars { return-char: func() -> char } -default world the-world { - import imports: self.chars - export exports: self.chars +world the-world { + import chars + export chars } diff --git a/crates/component-macro/tests/codegen/conventions.wit b/crates/component-macro/tests/codegen/conventions.wit index 2c5645c66313..a96b5afd3444 100644 --- a/crates/component-macro/tests/codegen/conventions.wit +++ b/crates/component-macro/tests/codegen/conventions.wit @@ -1,4 +1,5 @@ // hello 🐱 world +package foo:foo interface conventions { kebab-case: func() @@ -32,7 +33,7 @@ interface conventions { %bool: func() } -default world the-world { - import imports: self.conventions - export exports: self.conventions +world the-world { + import conventions + export conventions } diff --git a/crates/component-macro/tests/codegen/direct-import.wit b/crates/component-macro/tests/codegen/direct-import.wit index d2b612d6de71..67d252a4a898 100644 --- a/crates/component-macro/tests/codegen/direct-import.wit +++ b/crates/component-macro/tests/codegen/direct-import.wit @@ -1,3 +1,5 @@ -default world foo { +package foo:foo + +world foo { import foo: func() } diff --git a/crates/component-macro/tests/codegen/empty.wit b/crates/component-macro/tests/codegen/empty.wit index 1f99081f58cb..b720c27d628e 100644 --- a/crates/component-macro/tests/codegen/empty.wit +++ b/crates/component-macro/tests/codegen/empty.wit @@ -1 +1,2 @@ -default world empty {} +package foo:foo +world empty {} diff --git a/crates/component-macro/tests/codegen/flags.wit b/crates/component-macro/tests/codegen/flags.wit index b5a2fa2d1c83..8c9c1437169d 100644 --- a/crates/component-macro/tests/codegen/flags.wit +++ b/crates/component-macro/tests/codegen/flags.wit @@ -1,3 +1,5 @@ +package foo:foo + interface flegs { flags flag1 { b0, @@ -47,7 +49,7 @@ interface flegs { roundtrip-flag64: func(x: flag64) -> flag64 } -default world the-flags { - import import-flags: self.flegs - export export-flags: self.flegs +world the-flags { + import flegs + export flegs } diff --git a/crates/component-macro/tests/codegen/floats.wit b/crates/component-macro/tests/codegen/floats.wit index 4a0c67ce2c29..6cd720a8dc39 100644 --- a/crates/component-macro/tests/codegen/floats.wit +++ b/crates/component-macro/tests/codegen/floats.wit @@ -1,3 +1,5 @@ +package foo:foo + interface floats { float32-param: func(x: float32) float64-param: func(x: float64) @@ -5,7 +7,7 @@ interface floats { float64-result: func() -> float64 } -default world the-world { - import imports: self.floats - export exports: self.floats +world the-world { + import floats + export floats } diff --git a/crates/component-macro/tests/codegen/function-new.wit b/crates/component-macro/tests/codegen/function-new.wit index fed79c6633c6..2f4e407566cd 100644 --- a/crates/component-macro/tests/codegen/function-new.wit +++ b/crates/component-macro/tests/codegen/function-new.wit @@ -1,3 +1,4 @@ -default world foo { +package foo:foo +world foo { export new: func() } diff --git a/crates/component-macro/tests/codegen/integers.wit b/crates/component-macro/tests/codegen/integers.wit index bfad272882d0..2f5866bb2ae6 100644 --- a/crates/component-macro/tests/codegen/integers.wit +++ b/crates/component-macro/tests/codegen/integers.wit @@ -1,3 +1,5 @@ +package foo:foo + interface integers { a1: func(x: u8) a2: func(x: s8) @@ -32,7 +34,7 @@ interface integers { pair-ret: func() -> tuple } -default world the-world { - import imports: self.integers - export exports: self.integers +world the-world { + import integers + export integers } diff --git a/crates/component-macro/tests/codegen/lists.wit b/crates/component-macro/tests/codegen/lists.wit index 19b946068706..256a1cdf8fcf 100644 --- a/crates/component-macro/tests/codegen/lists.wit +++ b/crates/component-macro/tests/codegen/lists.wit @@ -1,3 +1,5 @@ +package foo:foo + interface lists { list-u8-param: func(x: list) list-u16-param: func(x: list) @@ -77,7 +79,7 @@ interface lists { load-store-everything: func(a: load-store-all-sizes) -> load-store-all-sizes } -default world the-lists { - import import-lists: self.lists - export export-lists: self.lists +world the-lists { + import lists + export lists } diff --git a/crates/component-macro/tests/codegen/many-arguments.wit b/crates/component-macro/tests/codegen/many-arguments.wit index a5b67b2184b1..cbfc123144fa 100644 --- a/crates/component-macro/tests/codegen/many-arguments.wit +++ b/crates/component-macro/tests/codegen/many-arguments.wit @@ -1,3 +1,5 @@ +package foo:foo + interface manyarg { many-args: func( a1: u64, @@ -44,7 +46,7 @@ interface manyarg { big-argument: func(x: big-struct) } -default world the-world { - import imports: self.manyarg - export exports: self.manyarg +world the-world { + import manyarg + export manyarg } diff --git a/crates/component-macro/tests/codegen/multi-return.wit b/crates/component-macro/tests/codegen/multi-return.wit index 716e77a6c850..69951b2c3393 100644 --- a/crates/component-macro/tests/codegen/multi-return.wit +++ b/crates/component-macro/tests/codegen/multi-return.wit @@ -1,3 +1,5 @@ +package foo:foo + interface multi-return { mra: func() mrb: func() -> () @@ -6,7 +8,7 @@ interface multi-return { mre: func() -> (a: u32, b: float32) } -default world the-world { - import imports: self.multi-return - export exports: self.multi-return +world the-world { + import multi-return + export multi-return } diff --git a/crates/component-macro/tests/codegen/records.wit b/crates/component-macro/tests/codegen/records.wit index 39d5e81694e8..f51bb8f28f75 100644 --- a/crates/component-macro/tests/codegen/records.wit +++ b/crates/component-macro/tests/codegen/records.wit @@ -1,3 +1,5 @@ +package foo:foo + interface records { tuple-arg: func(x: tuple) tuple-result: func() -> tuple @@ -53,7 +55,7 @@ interface records { typedef-inout: func(e: tuple-typedef2) -> s32 } -default world the-world { - import imports: self.records - export exports: self.records +world the-world { + import records + export records } diff --git a/crates/component-macro/tests/codegen/rename.wit b/crates/component-macro/tests/codegen/rename.wit index d60d4f6f9f43..8bfc7f36862b 100644 --- a/crates/component-macro/tests/codegen/rename.wit +++ b/crates/component-macro/tests/codegen/rename.wit @@ -1,5 +1,7 @@ +package foo:foo + interface red { - use self.green.{thing} + use green.{thing} foo: func() -> thing } @@ -8,7 +10,7 @@ interface green { type thing = s32 } -default world neptune { - import blue: self.red - import orange: self.green +world neptune { + import red + import green } diff --git a/crates/component-macro/tests/codegen/share-types.wit b/crates/component-macro/tests/codegen/share-types.wit index 106ee70936d9..8d36d1b0aa88 100644 --- a/crates/component-macro/tests/codegen/share-types.wit +++ b/crates/component-macro/tests/codegen/share-types.wit @@ -1,3 +1,5 @@ +package foo:foo + interface http-types{ record request { method: string @@ -7,13 +9,13 @@ interface http-types{ } } -default world http-interface { +world http-interface { export http-handler: interface { - use self.http-types.{request,response} + use http-types.{request,response} handle-request: func(request: request) -> response } import http-fetch: interface { - use self.http-types.{request,response} + use http-types.{request,response} fetch-request: func(request: request) -> response } } diff --git a/crates/component-macro/tests/codegen/simple-functions.wit b/crates/component-macro/tests/codegen/simple-functions.wit index cdb1183790fa..2593d199e565 100644 --- a/crates/component-macro/tests/codegen/simple-functions.wit +++ b/crates/component-macro/tests/codegen/simple-functions.wit @@ -1,3 +1,5 @@ +package foo:foo + interface simple { f1: func() f2: func(a: u32) @@ -9,7 +11,7 @@ interface simple { f6: func(a: u32, b: u32, c: u32) -> tuple } -default world the-world { - import imports: self.simple - export exports: self.simple +world the-world { + import simple + export simple } diff --git a/crates/component-macro/tests/codegen/simple-lists.wit b/crates/component-macro/tests/codegen/simple-lists.wit index 885cdeb74305..8e082b6e34e7 100644 --- a/crates/component-macro/tests/codegen/simple-lists.wit +++ b/crates/component-macro/tests/codegen/simple-lists.wit @@ -1,3 +1,5 @@ +package foo:foo + interface simple-lists { simple-list1: func(l: list) simple-list2: func() -> list @@ -5,7 +7,7 @@ interface simple-lists { simple-list4: func(l: list>) -> list> } -default world my-world { - import imports: self.simple-lists - export exports: self.simple-lists +world my-world { + import simple-lists + export simple-lists } diff --git a/crates/component-macro/tests/codegen/simple-wasi.wit b/crates/component-macro/tests/codegen/simple-wasi.wit index 02c47dc9b8f4..60192473d99e 100644 --- a/crates/component-macro/tests/codegen/simple-wasi.wit +++ b/crates/component-macro/tests/codegen/simple-wasi.wit @@ -1,3 +1,5 @@ +package foo:foo + interface wasi-filesystem { record descriptor-stat { } @@ -15,7 +17,7 @@ interface wall-clock { } } -default world wasi { - import wasi-filesystem: self.wasi-filesystem - import wall-clock: self.wall-clock +world wasi { + import wasi-filesystem + import wall-clock } diff --git a/crates/component-macro/tests/codegen/small-anonymous.wit b/crates/component-macro/tests/codegen/small-anonymous.wit index 96436091344d..ad9c67287d4e 100644 --- a/crates/component-macro/tests/codegen/small-anonymous.wit +++ b/crates/component-macro/tests/codegen/small-anonymous.wit @@ -1,3 +1,5 @@ +package foo:foo + interface anon { enum error { success, @@ -7,7 +9,7 @@ interface anon { option-test: func() -> result, error> } -default world the-world { - import imports: self.anon - export exports: self.anon +world the-world { + import anon + export anon } diff --git a/crates/component-macro/tests/codegen/smoke-default.wit b/crates/component-macro/tests/codegen/smoke-default.wit index 0d269359063f..90be0b1e3cdc 100644 --- a/crates/component-macro/tests/codegen/smoke-default.wit +++ b/crates/component-macro/tests/codegen/smoke-default.wit @@ -1,3 +1,5 @@ -default world the-world { +package foo:foo + +world the-world { export y: func() } diff --git a/crates/component-macro/tests/codegen/smoke-export.wit b/crates/component-macro/tests/codegen/smoke-export.wit index cefdc19823a0..983f1c35066e 100644 --- a/crates/component-macro/tests/codegen/smoke-export.wit +++ b/crates/component-macro/tests/codegen/smoke-export.wit @@ -1,4 +1,6 @@ -default world the-world { +package foo:foo + +world the-world { export the-name: interface { y: func() } diff --git a/crates/component-macro/tests/codegen/smoke.wit b/crates/component-macro/tests/codegen/smoke.wit index 6d8e80ccea86..0476bd988ec1 100644 --- a/crates/component-macro/tests/codegen/smoke.wit +++ b/crates/component-macro/tests/codegen/smoke.wit @@ -1,4 +1,6 @@ -default world the-world { +package foo:foo + +world the-world { import imports: interface { y: func() } diff --git a/crates/component-macro/tests/codegen/strings.wit b/crates/component-macro/tests/codegen/strings.wit index 7fc1885529bc..650300acfb9d 100644 --- a/crates/component-macro/tests/codegen/strings.wit +++ b/crates/component-macro/tests/codegen/strings.wit @@ -1,10 +1,12 @@ +package foo:foo + interface strings { a: func(x: string) b: func() -> string c: func(a: string, b: string) -> string } -default world the-world { - import imports: self.strings - export exports: self.strings +world the-world { + import strings + export strings } diff --git a/crates/component-macro/tests/codegen/unions.wit b/crates/component-macro/tests/codegen/unions.wit index 07e0f380a0d0..252f513f2de8 100644 --- a/crates/component-macro/tests/codegen/unions.wit +++ b/crates/component-macro/tests/codegen/unions.wit @@ -1,3 +1,5 @@ +package foo:foo + interface unions { /// A union of all of the integral types union all-integers { @@ -58,7 +60,7 @@ interface unions { identify-distinguishable-num: func(num: distinguishable-num) -> u8 } -default world the-unions { - import import-unions: self.unions - export export-unions: self.unions +world the-unions { + import unions + export unions } diff --git a/crates/component-macro/tests/codegen/use-paths.wit b/crates/component-macro/tests/codegen/use-paths.wit index 1e877379caf4..dab6646afac8 100644 --- a/crates/component-macro/tests/codegen/use-paths.wit +++ b/crates/component-macro/tests/codegen/use-paths.wit @@ -1,3 +1,5 @@ +package foo:foo + interface a { record foo {} @@ -5,22 +7,22 @@ interface a { } interface b { - use self.a.{foo} + use a.{foo} a: func() -> foo } interface c { - use self.b.{foo} + use b.{foo} a: func() -> foo } -default world d { - import a: self.a - import b: self.b +world d { + import a + import b import d: interface { - use self.c.{foo} + use c.{foo} b: func() -> foo } diff --git a/crates/component-macro/tests/codegen/variants.wit b/crates/component-macro/tests/codegen/variants.wit index 590675dcf6c0..b6c47d89650e 100644 --- a/crates/component-macro/tests/codegen/variants.wit +++ b/crates/component-macro/tests/codegen/variants.wit @@ -1,3 +1,5 @@ +package foo:foo + interface variants { enum e1 { a, @@ -139,7 +141,7 @@ interface variants { return-named-result: func() -> (a: result) } -default world my-world { - import imports: self.variants - export exports: self.variants +world my-world { + import variants + export variants } diff --git a/crates/component-macro/tests/codegen/worlds-with-types.wit b/crates/component-macro/tests/codegen/worlds-with-types.wit index 25db9036da12..dc4cbddcbabe 100644 --- a/crates/component-macro/tests/codegen/worlds-with-types.wit +++ b/crates/component-macro/tests/codegen/worlds-with-types.wit @@ -1,9 +1,11 @@ +package foo:foo + interface i { type t = u16 } -default world foo { - use self.i.{t as u} +world foo { + use i.{t as u} type t = u32 diff --git a/crates/environ/src/component/translate.rs b/crates/environ/src/component/translate.rs index 5abd9e77755f..cb2306e25f2c 100644 --- a/crates/environ/src/component/translate.rs +++ b/crates/environ/src/component/translate.rs @@ -8,7 +8,7 @@ use anyhow::{bail, Result}; use indexmap::IndexMap; use std::collections::HashMap; use std::mem; -use wasmparser::{Chunk, Encoding, Parser, Payload, Validator}; +use wasmparser::{Chunk, ComponentExternName, Encoding, Parser, Payload, Validator}; mod adapt; pub use self::adapt::*; @@ -164,7 +164,7 @@ struct Translation<'data> { #[allow(missing_docs)] enum LocalInitializer<'data> { // imports - Import(&'data str, TypeDef), + Import(ComponentExternName<'data>, TypeDef), // canonical function sections Lower(ComponentFuncIndex, LocalCanonicalOptions), @@ -622,7 +622,7 @@ impl<'a, 'data> Translator<'a, 'data> { for export in s { let export = export?; let item = self.kind_to_item(export.kind, export.index); - let prev = self.result.exports.insert(export.name, item); + let prev = self.result.exports.insert(export.name.as_str(), item); assert!(prev.is_none()); self.result .initializers @@ -831,9 +831,9 @@ impl<'a, 'data> Translator<'a, 'data> { ComponentItem::Type(ty) => Some(ComponentItemType::Type(ty)), ComponentItem::Module(_) => None, }; - map.insert(export.name, idx); + map.insert(export.name.as_str(), idx); if let Some(ty) = ty { - types.insert(export.name, ty); + types.insert(export.name.as_str(), ty); } } @@ -900,15 +900,15 @@ impl<'a, 'data> Translator<'a, 'data> { // An imported component instance is being aliased, so the type of // the aliased item is directly available from the instance type. ComponentInstanceType::Index(ty) => { - let (_url, ty) = &self.types[ty].exports[name]; - self.push_typedef(*ty); + let ty = self.types[ty].exports[name]; + self.push_typedef(ty); } // An imported component was instantiated so the type of the aliased // export is available through the type of the export on the // original component. ComponentInstanceType::InstantiatedIndex(ty) => { - let (_, ty) = self.types[ty].exports[name]; + let ty = self.types[ty].exports[name]; self.push_typedef(ty); } diff --git a/crates/environ/src/component/translate/inline.rs b/crates/environ/src/component/translate/inline.rs index 95aa449c1e9b..62a7d007a318 100644 --- a/crates/environ/src/component/translate/inline.rs +++ b/crates/environ/src/component/translate/inline.rs @@ -82,9 +82,12 @@ pub(super) fn run( LocalInitializer::Import(name, ty) => (name, ty), _ => continue, }; - let index = inliner.result.import_types.push((name.to_string(), ty)); + let index = inliner + .result + .import_types + .push((name.as_str().to_string(), ty)); let path = ImportPath::root(index); - args.insert(name, ComponentItemDef::from_import(path, ty)?); + args.insert(name.as_str(), ComponentItemDef::from_import(path, ty)?); } // This will run the inliner to completion after being seeded with the @@ -376,7 +379,7 @@ impl<'a> Inliner<'a> { // but for sub-components this will do resolution to connect what // was provided as an import at the instantiation-site to what was // needed during the component's instantiation. - Import(name, _ty) => match &frame.args[name] { + Import(name, _ty) => match &frame.args[name.as_str()] { ComponentItemDef::Module(i) => { frame.modules.push(i.clone()); } @@ -674,7 +677,7 @@ impl<'a> Inliner<'a> { ComponentInstanceDef::Import(path, ty) => { let mut path = path.clone(); path.path.push(name); - match self.types[*ty].exports[*name].1 { + match self.types[*ty].exports[*name] { TypeDef::ComponentFunc(_) => { frame.component_funcs.push(ComponentFuncDef::Import(path)); } @@ -939,7 +942,7 @@ impl<'a> Inliner<'a> { // Note that for now this would only work with // module-exporting instances. ComponentInstanceDef::Import(path, ty) => { - for (name, (_url, ty)) in self.types[ty].exports.iter() { + for (name, ty) in self.types[ty].exports.iter() { let mut path = path.clone(); path.path.push(name); let def = ComponentItemDef::from_import(path, *ty)?; diff --git a/crates/environ/src/component/types.rs b/crates/environ/src/component/types.rs index d3424256ee53..e98271b4c85d 100644 --- a/crates/environ/src/component/types.rs +++ b/crates/environ/src/component/types.rs @@ -499,6 +499,9 @@ impl ComponentTypesBuilder { let ty = TypeDef::CoreFunc(self.module_types.wasm_func_type(f)); self.push_core_typedef(ty); } + wasmparser::ModuleTypeDeclaration::Type(wasmparser::Type::Array(_)) => { + unimplemented!("gc types"); + } wasmparser::ModuleTypeDeclaration::Export { name, ty } => { let prev = result .exports @@ -556,17 +559,13 @@ impl ComponentTypesBuilder { ComponentTypeDeclaration::Type(ty) => self.type_declaration_type(ty)?, ComponentTypeDeclaration::CoreType(ty) => self.type_declaration_core_type(ty)?, ComponentTypeDeclaration::Alias(alias) => self.type_declaration_alias(alias)?, - ComponentTypeDeclaration::Export { name, url, ty } => { + ComponentTypeDeclaration::Export { name, ty } => { let ty = self.type_declaration_define(ty); - result - .exports - .insert(name.to_string(), (url.to_string(), ty)); + result.exports.insert(name.as_str().to_string(), ty); } ComponentTypeDeclaration::Import(import) => { let ty = self.type_declaration_define(&import.ty); - result - .imports - .insert(import.name.to_string(), (import.url.to_string(), ty)); + result.imports.insert(import.name.as_str().to_string(), ty); } } } @@ -588,11 +587,9 @@ impl ComponentTypesBuilder { InstanceTypeDeclaration::Type(ty) => self.type_declaration_type(ty)?, InstanceTypeDeclaration::CoreType(ty) => self.type_declaration_core_type(ty)?, InstanceTypeDeclaration::Alias(alias) => self.type_declaration_alias(alias)?, - InstanceTypeDeclaration::Export { name, url, ty } => { + InstanceTypeDeclaration::Export { name, ty } => { let ty = self.type_declaration_define(ty); - result - .exports - .insert(name.to_string(), (url.to_string(), ty)); + result.exports.insert(name.as_str().to_string(), ty); } } } @@ -639,7 +636,7 @@ impl ComponentTypesBuilder { } => { let ty = self.type_scopes.last().unwrap().instances [ComponentInstanceIndex::from_u32(*instance_index)]; - let (_, ty) = self.component_types[ty].exports[*name]; + let ty = self.component_types[ty].exports[*name]; self.push_component_typedef(ty); } a => unreachable!("invalid alias {a:?}"), @@ -1031,9 +1028,9 @@ pub struct TypeModule { #[derive(Serialize, Deserialize, Default)] pub struct TypeComponent { /// The named values that this component imports. - pub imports: IndexMap, + pub imports: IndexMap, /// The named values that this component exports. - pub exports: IndexMap, + pub exports: IndexMap, } /// The type of a component instance in the component model, or an instantiated @@ -1043,7 +1040,7 @@ pub struct TypeComponent { #[derive(Serialize, Deserialize, Default)] pub struct TypeComponentInstance { /// The list of exports that this component has along with their types. - pub exports: IndexMap, + pub exports: IndexMap, } /// A component function type in the component model. diff --git a/crates/environ/src/module_environ.rs b/crates/environ/src/module_environ.rs index 06f8f158fd2d..bfa81fd8b2ed 100644 --- a/crates/environ/src/module_environ.rs +++ b/crates/environ/src/module_environ.rs @@ -243,6 +243,9 @@ impl<'a, 'data> ModuleEnvironment<'a, 'data> { let ty = self.convert_func_type(&wasm_func_ty); self.declare_type_func(ty)?; } + Type::Array(_) => { + unimplemented!("gc proposal") + } } } } diff --git a/crates/test-programs/Cargo.toml b/crates/test-programs/Cargo.toml index 6e07ab9ea993..37a97b40b384 100644 --- a/crates/test-programs/Cargo.toml +++ b/crates/test-programs/Cargo.toml @@ -13,6 +13,7 @@ cargo_metadata = "0.15.3" wit-component = { workspace = true } heck = { workspace = true } + [dev-dependencies] anyhow = { workspace = true } tempfile = { workspace = true } diff --git a/crates/test-programs/build.rs b/crates/test-programs/build.rs index e36db9162e00..e96ed83e32af 100644 --- a/crates/test-programs/build.rs +++ b/crates/test-programs/build.rs @@ -7,6 +7,11 @@ use std::path::PathBuf; use std::process::Command; use wit_component::ComponentEncoder; +// NB: this is set to `false` when a breaking change to WIT is made since the +// wasi-http WIT is currently a submodule and can't be updated atomically with +// the rest of Wasmtime. +const BUILD_WASI_HTTP_TESTS: bool = false; + fn main() { #[cfg(feature = "test_programs")] build_and_generate_tests(); @@ -23,9 +28,13 @@ fn build_and_generate_tests() { ); println!("cargo:rerun-if-changed=./wasi-tests"); - println!("cargo:rerun-if-changed=./wasi-http-tests"); println!("cargo:rerun-if-changed=./command-tests"); println!("cargo:rerun-if-changed=./reactor-tests"); + if BUILD_WASI_HTTP_TESTS { + println!("cargo:rerun-if-changed=./wasi-http-tests"); + } else { + println!("cargo:rustc-cfg=skip_wasi_http_tests"); + } // Build the test programs: let mut cmd = Command::new("rustup"); @@ -35,12 +44,14 @@ fn build_and_generate_tests() { .arg("build") .arg("--target=wasm32-wasi") .arg("--package=wasi-tests") - .arg("--package=wasi-http-tests") .arg("--package=command-tests") .arg("--package=reactor-tests") .env("CARGO_TARGET_DIR", &out_dir) .env("CARGO_PROFILE_DEV_DEBUG", "1") .env_remove("CARGO_ENCODED_RUSTFLAGS"); + if BUILD_WASI_HTTP_TESTS { + cmd.arg("--package=wasi-http-tests"); + } let status = cmd.status().unwrap(); assert!(status.success()); @@ -49,11 +60,13 @@ fn build_and_generate_tests() { modules_rs(&meta, "wasi-tests", "bin", &out_dir); components_rs(&meta, "wasi-tests", "bin", &command_adapter, &out_dir); - modules_rs(&meta, "wasi-http-tests", "bin", &out_dir); - // FIXME this is broken at the moment because guest bindgen is embedding the proxy world type, - // so wit-component expects the module to contain the proxy's exports. we need a different - // world to pass guest bindgen that is just "a command that also can do outbound http" - //components_rs(&meta, "wasi-http-tests", "bin", &command_adapter, &out_dir); + if BUILD_WASI_HTTP_TESTS { + modules_rs(&meta, "wasi-http-tests", "bin", &out_dir); + // FIXME this is broken at the moment because guest bindgen is embedding the proxy world type, + // so wit-component expects the module to contain the proxy's exports. we need a different + // world to pass guest bindgen that is just "a command that also can do outbound http" + //components_rs(&meta, "wasi-http-tests", "bin", &command_adapter, &out_dir); + } components_rs(&meta, "command-tests", "bin", &command_adapter, &out_dir); components_rs(&meta, "reactor-tests", "cdylib", &reactor_adapter, &out_dir); diff --git a/crates/test-programs/reactor-tests/src/lib.rs b/crates/test-programs/reactor-tests/src/lib.rs index c38640ac07c3..ff1c0cab78ff 100644 --- a/crates/test-programs/reactor-tests/src/lib.rs +++ b/crates/test-programs/reactor-tests/src/lib.rs @@ -1,4 +1,4 @@ -wit_bindgen::generate!("test-reactor"); +wit_bindgen::generate!("test-reactor" in "../../wasi/wit"); export_test_reactor!(T); @@ -26,12 +26,12 @@ impl TestReactor for T { fn write_strings_to(o: OutputStream) -> Result<(), ()> { unsafe { for s in STATE.iter() { - streams::write(o, s.as_bytes()).map_err(|_| ())?; + wasi::io::streams::write(o, s.as_bytes()).map_err(|_| ())?; } Ok(()) } } - fn pass_an_imported_record(stat: filesystem::DescriptorStat) -> String { + fn pass_an_imported_record(stat: wasi::filesystem::filesystem::DescriptorStat) -> String { format!("{stat:?}") } } diff --git a/crates/test-programs/reactor-tests/wit/deps.lock b/crates/test-programs/reactor-tests/wit/deps.lock deleted file mode 100644 index bfa0b9d4f662..000000000000 --- a/crates/test-programs/reactor-tests/wit/deps.lock +++ /dev/null @@ -1,41 +0,0 @@ -[clocks] -sha256 = "16155da02fdba4a51515b44dbd1c65e0909bb8c4d383bd32875c777044ce5389" -sha512 = "30efd2697885954f3846322adf94f28a28f958595708407696ef66e8fe5bb62c79525e6f13ec469476cba8f2a12d3d9aef8250b1fe04c90a28542d3245db11f2" - -[filesystem] -sha256 = "a3f57790dfd6af70758df33df82aa064f915eb795b71a190f272f10da9cfc9df" -sha512 = "2b0059ffae0a4b1ce3bd8d489a40d08c1faa229bf1bb4cc8df0a98e0fd13d4694742117b2bc609d7fb75db1ed4aa148d3af7beca6a84866d87d65a1769b1d988" - -[http] -sha256 = "b6a245b8f37f3be93650c1a8ae41c01923f3b7303bbf2d016d8d03a1c92b3c10" -sha512 = "e2e0612213bb1272153b3858b13110a7fee0d89dc97d0021ab5ccccc8822ccc1f1629c8fa8dc582862411b2517ef3f79e7e51986c946654bf6ddd3f390cf36f2" - -[io] -sha256 = "87d8bf336f37184edc9290af9a14f7cac38c8fe087a786e66d08d1a94e48d186" -sha512 = "cdb5b35860c46c637ad37d784dd17f6023cf1c7c689d37973ec7c4094718baee4a16864e64622173b5578eed3950ad73211d9fe48a5b61b951809fdd9242b607" - -[logging] -sha256 = "8c32c7f893c938e0b76cd42e3de97e268dfe8fd0e7525d1f42b7ad10a88b00bb" -sha512 = "e9ce2adf02bb518c179a40b7d7af84bf44b99b2098609a897a114fb5af24946992dd7bd08da02c60d2768963f94414a16165f11343ec053a44b9e586058c812a" - -[poll] -sha256 = "9f2e6b5ea1a017575f96a3c415c737fe31513b043d9b47aefeb21f6c27ab8425" -sha512 = "f65965395742a0290fd9e4e55408c2b5ce3a4eae0ee22be1ff012e3db75910110da21c5f0a61083e043b4c510967a0a73ff4491ae9719e9158543f512dbeea5f" - -[preview] -path = "../../../wit" -sha256 = "007d4902193faef77b2df60714a8dfe8ec243e030c1ce61fb11c52788e3a5fe0" -sha512 = "bd06e8338e7fad0fc2e56ae01c5b184282c66ca79d2040eaec5a11efb14a4002b2a6234baaf354aff3cd57dc99835e4979eb71cdbd5d12800ea289d9a13252f2" -deps = ["clocks", "filesystem", "http", "io", "logging", "poll", "random", "sockets", "wasi-cli-base"] - -[random] -sha256 = "19d57f2262530016ec2b32991db3d8b6705b3a0bc5a7b6ae8fff3bcef0cf1088" -sha512 = "f9eba7dfd858d1edcaa868ce636f69545323bf010c3b0d4a2a1b23584d8027240c592d13e91882617e70a4dbf290754a8697724b5633147d11fa3db7869a2afe" - -[sockets] -sha256 = "d5a51604d53eec88d2735356ce7089a0eeb06886262e7ad2fc74be6b4dd943b2" -sha512 = "99bd86c0c59174bc9dafc559ca7dbab1aa9ed04a9b54ae3f7bb2d974b3a97bae8846acf1d77232edecda0aef5b23b9e4010d53ebf4a1d04292581078763530b7" - -[wasi-cli-base] -sha256 = "a0beee69392d2b55baff0b5f2285f50f717473b1369bdb3fbbfbefbaa3bd6c86" -sha512 = "d80eada98646bfeec1066437f1a4f69d67d117f38407f35c48d8b31667c171656059c5abf638c5b31169119ef5fa73bbf199933ac198f815f58281f124cb4f8d" diff --git a/crates/test-programs/reactor-tests/wit/deps.toml b/crates/test-programs/reactor-tests/wit/deps.toml deleted file mode 100644 index c90a145d08ce..000000000000 --- a/crates/test-programs/reactor-tests/wit/deps.toml +++ /dev/null @@ -1 +0,0 @@ -preview = "../../../wit" diff --git a/crates/test-programs/reactor-tests/wit/deps/clocks/monotonic-clock.wit b/crates/test-programs/reactor-tests/wit/deps/clocks/monotonic-clock.wit deleted file mode 100644 index 42e2981f579a..000000000000 --- a/crates/test-programs/reactor-tests/wit/deps/clocks/monotonic-clock.wit +++ /dev/null @@ -1,32 +0,0 @@ -/// WASI Monotonic Clock is a clock API intended to let users measure elapsed -/// time. -/// -/// It is intended to be portable at least between Unix-family platforms and -/// Windows. -/// -/// A monotonic clock is a clock which has an unspecified initial value, and -/// successive reads of the clock will produce non-decreasing values. -/// -/// It is intended for measuring elapsed time. -default interface monotonic-clock { - use poll.poll.{pollable} - - /// A timestamp in nanoseconds. - type instant = u64 - - /// Read the current value of the clock. - /// - /// The clock is monotonic, therefore calling this function repeatedly will - /// produce a sequence of non-decreasing values. - now: func() -> instant - - /// Query the resolution of the clock. - resolution: func() -> instant - - /// Create a `pollable` which will resolve once the specified time has been - /// reached. - subscribe: func( - when: instant, - absolute: bool - ) -> pollable -} diff --git a/crates/test-programs/reactor-tests/wit/deps/clocks/timezone.wit b/crates/test-programs/reactor-tests/wit/deps/clocks/timezone.wit deleted file mode 100644 index 63f99cc401b1..000000000000 --- a/crates/test-programs/reactor-tests/wit/deps/clocks/timezone.wit +++ /dev/null @@ -1,61 +0,0 @@ -default interface timezone { - use pkg.wall-clock.{datetime} - - /// A timezone. - /// - /// In timezones that recognize daylight saving time, also known as daylight - /// time and summer time, the information returned from the functions varies - /// over time to reflect these adjustments. - /// - /// This [represents a resource](https://github.com/WebAssembly/WASI/blob/main/docs/WitInWasi.md#Resources). - type timezone = u32 - - /// Return information needed to display the given `datetime`. This includes - /// the UTC offset, the time zone name, and a flag indicating whether - /// daylight saving time is active. - /// - /// If the timezone cannot be determined for the given `datetime`, return a - /// `timezone-display` for `UTC` with a `utc-offset` of 0 and no daylight - /// saving time. - display: func(this: timezone, when: datetime) -> timezone-display - - /// The same as `display`, but only return the UTC offset. - utc-offset: func(this: timezone, when: datetime) -> s32 - - /// Dispose of the specified input-stream, after which it may no longer - /// be used. - drop-timezone: func(this: timezone) - - /// Information useful for displaying the timezone of a specific `datetime`. - /// - /// This information may vary within a single `timezone` to reflect daylight - /// saving time adjustments. - record timezone-display { - /// The number of seconds difference between UTC time and the local - /// time of the timezone. - /// - /// The returned value will always be less than 86400 which is the - /// number of seconds in a day (24*60*60). - /// - /// In implementations that do not expose an actual time zone, this - /// should return 0. - utc-offset: s32, - - /// The abbreviated name of the timezone to display to a user. The name - /// `UTC` indicates Coordinated Universal Time. Otherwise, this should - /// reference local standards for the name of the time zone. - /// - /// In implementations that do not expose an actual time zone, this - /// should be the string `UTC`. - /// - /// In time zones that do not have an applicable name, a formatted - /// representation of the UTC offset may be returned, such as `-04:00`. - name: string, - - /// Whether daylight saving time is active. - /// - /// In implementations that do not expose an actual time zone, this - /// should return false. - in-daylight-saving-time: bool, - } -} diff --git a/crates/test-programs/reactor-tests/wit/deps/clocks/wall-clock.wit b/crates/test-programs/reactor-tests/wit/deps/clocks/wall-clock.wit deleted file mode 100644 index 89c5a75da68b..000000000000 --- a/crates/test-programs/reactor-tests/wit/deps/clocks/wall-clock.wit +++ /dev/null @@ -1,41 +0,0 @@ -/// WASI Wall Clock is a clock API intended to let users query the current -/// time. The name "wall" makes an analogy to a "clock on the wall", which -/// is not necessarily monotonic as it may be reset. -/// -/// It is intended to be portable at least between Unix-family platforms and -/// Windows. -/// -/// A wall clock is a clock which measures the date and time according to -/// some external reference. -/// -/// External references may be reset, so this clock is not necessarily -/// monotonic, making it unsuitable for measuring elapsed time. -/// -/// It is intended for reporting the current date and time for humans. -default interface wall-clock { - /// A time and date in seconds plus nanoseconds. - record datetime { - seconds: u64, - nanoseconds: u32, - } - - /// Read the current value of the clock. - /// - /// This clock is not monotonic, therefore calling this function repeatedly - /// will not necessarily produce a sequence of non-decreasing values. - /// - /// The returned timestamps represent the number of seconds since - /// 1970-01-01T00:00:00Z, also known as [POSIX's Seconds Since the Epoch], - /// also known as [Unix Time]. - /// - /// The nanoseconds field of the output is always less than 1000000000. - /// - /// [POSIX's Seconds Since the Epoch]: https://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xbd_chap04.html#tag_21_04_16 - /// [Unix Time]: https://en.wikipedia.org/wiki/Unix_time - now: func() -> datetime - - /// Query the resolution of the clock. - /// - /// The nanoseconds field of the output is always less than 1000000000. - resolution: func() -> datetime -} diff --git a/crates/test-programs/reactor-tests/wit/deps/io/streams.wit b/crates/test-programs/reactor-tests/wit/deps/io/streams.wit deleted file mode 100644 index c1567fd4c1c8..000000000000 --- a/crates/test-programs/reactor-tests/wit/deps/io/streams.wit +++ /dev/null @@ -1,213 +0,0 @@ -/// WASI I/O is an I/O abstraction API which is currently focused on providing -/// stream types. -/// -/// In the future, the component model is expected to add built-in stream types; -/// when it does, they are expected to subsume this API. -default interface streams { - use poll.poll.{pollable} - - /// An error type returned from a stream operation. Currently this - /// doesn't provide any additional information. - record stream-error {} - - /// An input bytestream. In the future, this will be replaced by handle - /// types. - /// - /// This conceptually represents a `stream`. It's temporary - /// scaffolding until component-model's async features are ready. - /// - /// `input-stream`s are *non-blocking* to the extent practical on underlying - /// platforms. I/O operations always return promptly; if fewer bytes are - /// promptly available than requested, they return the number of bytes promptly - /// available, which could even be zero. To wait for data to be available, - /// use the `subscribe-to-input-stream` function to obtain a `pollable` which - /// can be polled for using `wasi_poll`. - /// - /// And at present, it is a `u32` instead of being an actual handle, until - /// the wit-bindgen implementation of handles and resources is ready. - /// - /// This [represents a resource](https://github.com/WebAssembly/WASI/blob/main/docs/WitInWasi.md#Resources). - type input-stream = u32 - - /// Read bytes from a stream. - /// - /// This function returns a list of bytes containing the data that was - /// read, along with a bool which, when true, indicates that the end of the - /// stream was reached. The returned list will contain up to `len` bytes; it - /// may return fewer than requested, but not more. - /// - /// Once a stream has reached the end, subsequent calls to read or - /// `skip` will always report end-of-stream rather than producing more - /// data. - /// - /// If `len` is 0, it represents a request to read 0 bytes, which should - /// always succeed, assuming the stream hasn't reached its end yet, and - /// return an empty list. - /// - /// The len here is a `u64`, but some callees may not be able to allocate - /// a buffer as large as that would imply. - /// FIXME: describe what happens if allocation fails. - read: func( - this: input-stream, - /// The maximum number of bytes to read - len: u64 - ) -> result, bool>, stream-error> - - /// Read bytes from a stream, with blocking. - /// - /// This is similar to `read`, except that it blocks until at least one - /// byte can be read. - blocking-read: func( - this: input-stream, - /// The maximum number of bytes to read - len: u64 - ) -> result, bool>, stream-error> - - /// Skip bytes from a stream. - /// - /// This is similar to the `read` function, but avoids copying the - /// bytes into the instance. - /// - /// Once a stream has reached the end, subsequent calls to read or - /// `skip` will always report end-of-stream rather than producing more - /// data. - /// - /// This function returns the number of bytes skipped, along with a bool - /// indicating whether the end of the stream was reached. The returned - /// value will be at most `len`; it may be less. - skip: func( - this: input-stream, - /// The maximum number of bytes to skip. - len: u64, - ) -> result, stream-error> - - /// Skip bytes from a stream, with blocking. - /// - /// This is similar to `skip`, except that it blocks until at least one - /// byte can be consumed. - blocking-skip: func( - this: input-stream, - /// The maximum number of bytes to skip. - len: u64, - ) -> result, stream-error> - - /// Create a `pollable` which will resolve once either the specified stream - /// has bytes available to read or the other end of the stream has been - /// closed. - subscribe-to-input-stream: func(this: input-stream) -> pollable - - /// Dispose of the specified `input-stream`, after which it may no longer - /// be used. - drop-input-stream: func(this: input-stream) - - /// An output bytestream. In the future, this will be replaced by handle - /// types. - /// - /// This conceptually represents a `stream`. It's temporary - /// scaffolding until component-model's async features are ready. - /// - /// `output-stream`s are *non-blocking* to the extent practical on - /// underlying platforms. Except where specified otherwise, I/O operations also - /// always return promptly, after the number of bytes that can be written - /// promptly, which could even be zero. To wait for the stream to be ready to - /// accept data, the `subscribe-to-output-stream` function to obtain a - /// `pollable` which can be polled for using `wasi_poll`. - /// - /// And at present, it is a `u32` instead of being an actual handle, until - /// the wit-bindgen implementation of handles and resources is ready. - /// - /// This [represents a resource](https://github.com/WebAssembly/WASI/blob/main/docs/WitInWasi.md#Resources). - type output-stream = u32 - - /// Write bytes to a stream. - /// - /// This function returns a `u64` indicating the number of bytes from - /// `buf` that were written; it may be less than the full list. - write: func( - this: output-stream, - /// Data to write - buf: list - ) -> result - - /// Write bytes to a stream, with blocking. - /// - /// This is similar to `write`, except that it blocks until at least one - /// byte can be written. - blocking-write: func( - this: output-stream, - /// Data to write - buf: list - ) -> result - - /// Write multiple zero bytes to a stream. - /// - /// This function returns a `u64` indicating the number of zero bytes - /// that were written; it may be less than `len`. - write-zeroes: func( - this: output-stream, - /// The number of zero bytes to write - len: u64 - ) -> result - - /// Write multiple zero bytes to a stream, with blocking. - /// - /// This is similar to `write-zeroes`, except that it blocks until at least - /// one byte can be written. - blocking-write-zeroes: func( - this: output-stream, - /// The number of zero bytes to write - len: u64 - ) -> result - - /// Read from one stream and write to another. - /// - /// This function returns the number of bytes transferred; it may be less - /// than `len`. - /// - /// Unlike other I/O functions, this function blocks until all the data - /// read from the input stream has been written to the output stream. - splice: func( - this: output-stream, - /// The stream to read from - src: input-stream, - /// The number of bytes to splice - len: u64, - ) -> result, stream-error> - - /// Read from one stream and write to another, with blocking. - /// - /// This is similar to `splice`, except that it blocks until at least - /// one byte can be read. - blocking-splice: func( - this: output-stream, - /// The stream to read from - src: input-stream, - /// The number of bytes to splice - len: u64, - ) -> result, stream-error> - - /// Forward the entire contents of an input stream to an output stream. - /// - /// This function repeatedly reads from the input stream and writes - /// the data to the output stream, until the end of the input stream - /// is reached, or an error is encountered. - /// - /// Unlike other I/O functions, this function blocks until the end - /// of the input stream is seen and all the data has been written to - /// the output stream. - /// - /// This function returns the number of bytes transferred. - forward: func( - this: output-stream, - /// The stream to read from - src: input-stream - ) -> result - - /// Create a `pollable` which will resolve once either the specified stream - /// is ready to accept bytes or the other end of the stream has been closed. - subscribe-to-output-stream: func(this: output-stream) -> pollable - - /// Dispose of the specified `output-stream`, after which it may no longer - /// be used. - drop-output-stream: func(this: output-stream) -} diff --git a/crates/test-programs/reactor-tests/wit/deps/poll/poll.wit b/crates/test-programs/reactor-tests/wit/deps/poll/poll.wit deleted file mode 100644 index 28f08e17d755..000000000000 --- a/crates/test-programs/reactor-tests/wit/deps/poll/poll.wit +++ /dev/null @@ -1,39 +0,0 @@ -/// A poll API intended to let users wait for I/O events on multiple handles -/// at once. -default interface poll { - /// A "pollable" handle. - /// - /// This is conceptually represents a `stream<_, _>`, or in other words, - /// a stream that one can wait on, repeatedly, but which does not itself - /// produce any data. It's temporary scaffolding until component-model's - /// async features are ready. - /// - /// And at present, it is a `u32` instead of being an actual handle, until - /// the wit-bindgen implementation of handles and resources is ready. - /// - /// `pollable` lifetimes are not automatically managed. Users must ensure - /// that they do not outlive the resource they reference. - /// - /// This [represents a resource](https://github.com/WebAssembly/WASI/blob/main/docs/WitInWasi.md#Resources). - type pollable = u32 - - /// Dispose of the specified `pollable`, after which it may no longer - /// be used. - drop-pollable: func(this: pollable) - - /// Poll for completion on a set of pollables. - /// - /// The "oneoff" in the name refers to the fact that this function must do a - /// linear scan through the entire list of subscriptions, which may be - /// inefficient if the number is large and the same subscriptions are used - /// many times. In the future, this is expected to be obsoleted by the - /// component model async proposal, which will include a scalable waiting - /// facility. - /// - /// Note that the return type would ideally be `list`, but that would - /// be more difficult to polyfill given the current state of `wit-bindgen`. - /// See - /// for details. For now, we use zero to mean "not ready" and non-zero to - /// mean "ready". - poll-oneoff: func(in: list) -> list -} diff --git a/crates/test-programs/reactor-tests/wit/deps/wasi-cli-base/environment.wit b/crates/test-programs/reactor-tests/wit/deps/wasi-cli-base/environment.wit deleted file mode 100644 index 876ea3a0c921..000000000000 --- a/crates/test-programs/reactor-tests/wit/deps/wasi-cli-base/environment.wit +++ /dev/null @@ -1,14 +0,0 @@ -default interface environment { - /// Get the POSIX-style environment variables. - /// - /// Each environment variable is provided as a pair of string variable names - /// and string value. - /// - /// Morally, these are a value import, but until value imports are available - /// in the component model, this import function should return the same - /// values each time it is called. - get-environment: func() -> list> - - /// Get the POSIX-style arguments to the program. - get-arguments: func() -> list -} diff --git a/crates/test-programs/reactor-tests/wit/deps/wasi-cli-base/exit.wit b/crates/test-programs/reactor-tests/wit/deps/wasi-cli-base/exit.wit deleted file mode 100644 index 2759e9dd989c..000000000000 --- a/crates/test-programs/reactor-tests/wit/deps/wasi-cli-base/exit.wit +++ /dev/null @@ -1,4 +0,0 @@ -default interface wasi-exit { - /// Exit the curerent instance and any linked instances. - exit: func(status: result) -} diff --git a/crates/test-programs/reactor-tests/wit/test-reactor.wit b/crates/test-programs/reactor-tests/wit/test-reactor.wit deleted file mode 100644 index 12abad593df0..000000000000 --- a/crates/test-programs/reactor-tests/wit/test-reactor.wit +++ /dev/null @@ -1,18 +0,0 @@ -default world test-reactor { - - import environment: wasi-cli-base.environment - import streams: io.streams - import preopens: wasi-cli-base.preopens - import filesystem: filesystem.filesystem - import exit: wasi-cli-base.exit - - export add-strings: func(s: list) -> u32 - export get-strings: func() -> list - - use io.streams.{output-stream} - - export write-strings-to: func(o: output-stream) -> result - - use filesystem.filesystem.{descriptor-stat} - export pass-an-imported-record: func(d: descriptor-stat) -> string -} diff --git a/crates/test-programs/tests/reactor.rs b/crates/test-programs/tests/reactor.rs index 16b61c7f376c..9cd6ececb55e 100644 --- a/crates/test-programs/tests/reactor.rs +++ b/crates/test-programs/tests/reactor.rs @@ -4,7 +4,9 @@ use wasmtime::{ component::{Component, Linker}, Config, Engine, Store, }; -use wasmtime_wasi::preview2::{wasi, Table, WasiCtx, WasiCtxBuilder, WasiView}; +use wasmtime_wasi::preview2::wasi::clocks::wall_clock; +use wasmtime_wasi::preview2::wasi::filesystem::filesystem; +use wasmtime_wasi::preview2::{self, Table, WasiCtx, WasiCtxBuilder, WasiView}; lazy_static::lazy_static! { static ref ENGINE: Engine = { @@ -22,18 +24,18 @@ lazy_static::lazy_static! { include!(concat!(env!("OUT_DIR"), "/reactor_tests_components.rs")); wasmtime::component::bindgen!({ - path: "../test-programs/reactor-tests/wit", + path: "../wasi/wit", world: "test-reactor", async: true, with: { - "environment": wasi::environment, - "streams": wasi::streams, - "preopens": wasi::preopens, - "stdin": wasi::stdin, - "stdout": wasi::stdout, - "stderr": wasi::stderr, - "filesystem": wasi::filesystem, - "exit": wasi::exit, + "wasi:io/streams": preview2::wasi::io::streams, + "wasi:filesystem/filesystem": preview2::wasi::filesystem::filesystem, + "wasi:cli-base/environment": preview2::wasi::cli_base::environment, + "wasi:cli-base/preopens": preview2::wasi::cli_base::preopens, + "wasi:cli-base/exit": preview2::wasi::cli_base::exit, + "wasi:cli-base/stdin": preview2::wasi::cli_base::stdin, + "wasi:cli-base/stdout": preview2::wasi::cli_base::stdout, + "wasi:cli-base/stderr": preview2::wasi::cli_base::stderr, }, }); @@ -64,14 +66,14 @@ async fn instantiate( let mut linker = Linker::new(&ENGINE); // All of the imports available to the world are provided by the wasi-common crate: - wasi::filesystem::add_to_linker(&mut linker, |x| x)?; - wasi::streams::add_to_linker(&mut linker, |x| x)?; - wasi::environment::add_to_linker(&mut linker, |x| x)?; - wasi::preopens::add_to_linker(&mut linker, |x| x)?; - wasi::stdin::add_to_linker(&mut linker, |x| x)?; - wasi::stdout::add_to_linker(&mut linker, |x| x)?; - wasi::stderr::add_to_linker(&mut linker, |x| x)?; - wasi::exit::add_to_linker(&mut linker, |x| x)?; + preview2::wasi::filesystem::filesystem::add_to_linker(&mut linker, |x| x)?; + preview2::wasi::io::streams::add_to_linker(&mut linker, |x| x)?; + preview2::wasi::cli_base::environment::add_to_linker(&mut linker, |x| x)?; + preview2::wasi::cli_base::preopens::add_to_linker(&mut linker, |x| x)?; + preview2::wasi::cli_base::exit::add_to_linker(&mut linker, |x| x)?; + preview2::wasi::cli_base::stdin::add_to_linker(&mut linker, |x| x)?; + preview2::wasi::cli_base::stdout::add_to_linker(&mut linker, |x| x)?; + preview2::wasi::cli_base::stderr::add_to_linker(&mut linker, |x| x)?; let mut store = Store::new(&ENGINE, wasi_ctx); @@ -131,12 +133,12 @@ async fn reactor_tests() -> Result<()> { // Show that the `with` invocation in the macro means we get to re-use the // type definitions from inside the `host` crate for these structures: - let ds = wasi::filesystem::DescriptorStat { - data_access_timestamp: wasi::wall_clock::Datetime { + let ds = filesystem::DescriptorStat { + data_access_timestamp: wall_clock::Datetime { nanoseconds: 123, seconds: 45, }, - data_modification_timestamp: wasi::wall_clock::Datetime { + data_modification_timestamp: wall_clock::Datetime { nanoseconds: 789, seconds: 10, }, @@ -144,11 +146,11 @@ async fn reactor_tests() -> Result<()> { inode: 0, link_count: 0, size: 0, - status_change_timestamp: wasi::wall_clock::Datetime { + status_change_timestamp: wall_clock::Datetime { nanoseconds: 0, seconds: 1, }, - type_: wasi::filesystem::DescriptorType::Unknown, + type_: filesystem::DescriptorType::Unknown, }; let expected = format!("{ds:?}"); let got = reactor.call_pass_an_imported_record(&mut store, ds).await?; diff --git a/crates/test-programs/tests/wasi-http.rs b/crates/test-programs/tests/wasi-http.rs index 78c99dc939af..0b1a4fd70567 100644 --- a/crates/test-programs/tests/wasi-http.rs +++ b/crates/test-programs/tests/wasi-http.rs @@ -1,4 +1,4 @@ -#![cfg(feature = "test_programs")] +#![cfg(all(feature = "test_programs", not(skip_wasi_http_tests)))] use wasmtime::{Config, Engine, Linker, Store}; use wasmtime_wasi::{sync::WasiCtxBuilder, WasiCtx}; use wasmtime_wasi_http::WasiHttp; diff --git a/crates/types/src/lib.rs b/crates/types/src/lib.rs index 68150ba639a3..0fbd349400de 100644 --- a/crates/types/src/lib.rs +++ b/crates/types/src/lib.rs @@ -441,7 +441,7 @@ pub trait TypeConvert { match ty { wasmparser::HeapType::Func => WasmHeapType::Func, wasmparser::HeapType::Extern => WasmHeapType::Extern, - wasmparser::HeapType::TypedFunc(i) => self.lookup_heap_type(TypeIndex::from_u32(i)), + wasmparser::HeapType::Indexed(i) => self.lookup_heap_type(TypeIndex::from_u32(i)), wasmparser::HeapType::Any | wasmparser::HeapType::None diff --git a/crates/wasi-http/src/lib.rs b/crates/wasi-http/src/lib.rs index 4f90015cc5ce..8f1ef030c67f 100644 --- a/crates/wasi-http/src/lib.rs +++ b/crates/wasi-http/src/lib.rs @@ -1,3 +1,7 @@ +// NB: this crate is temporarily disabled for a breaking change to WIT. This can +// be re-enabled when the WIT in the wasi-http submodule is updated. +#![cfg(FALSE)] + use crate::component_impl::add_component_to_linker; pub use crate::r#struct::WasiHttp; diff --git a/crates/wasi-preview1-component-adapter/Cargo.toml b/crates/wasi-preview1-component-adapter/Cargo.toml index c2ca4c9c61e6..16af98f56bc9 100644 --- a/crates/wasi-preview1-component-adapter/Cargo.toml +++ b/crates/wasi-preview1-component-adapter/Cargo.toml @@ -7,7 +7,7 @@ publish = false [dependencies] wasi = { version = "0.11.0", default-features = false } -wit-bindgen = { version = "0.6.0", default-features = false, features = ["macros"] } +wit-bindgen = { workspace = true, default-features = false, features = ["macros"] } byte-array-literals = { workspace = true } [build-dependencies] diff --git a/crates/wasi-preview1-component-adapter/src/descriptors.rs b/crates/wasi-preview1-component-adapter/src/descriptors.rs index 8b17ac7e6bbc..cdeff86082b5 100644 --- a/crates/wasi-preview1-component-adapter/src/descriptors.rs +++ b/crates/wasi-preview1-component-adapter/src/descriptors.rs @@ -1,5 +1,7 @@ -use crate::bindings::streams::{self, InputStream, OutputStream}; -use crate::bindings::{filesystem, tcp}; +use crate::bindings::wasi::cli_base::{stderr, stdin, stdout}; +use crate::bindings::wasi::filesystem::filesystem; +use crate::bindings::wasi::io::streams::{self, InputStream, OutputStream}; +use crate::bindings::wasi::sockets::tcp; use crate::{set_stderr_stream, BumpArena, File, ImportAlloc, TrappingUnwrap, WasmStr}; use core::cell::{Cell, UnsafeCell}; use core::mem::MaybeUninit; @@ -140,9 +142,9 @@ impl Descriptors { preopens: Cell::new(None), }; - let stdin = crate::bindings::stdin::get_stdin(); - let stdout = crate::bindings::stdout::get_stdout(); - let stderr = crate::bindings::stderr::get_stderr(); + let stdin = stdin::get_stdin(); + let stdout = stdout::get_stdout(); + let stderr = stderr::get_stderr(); unsafe { set_stderr_stream(stderr) }; d.push(Descriptor::Streams(Streams { @@ -164,7 +166,7 @@ impl Descriptors { })) .trapping_unwrap(); - #[link(wasm_import_module = "preopens")] + #[link(wasm_import_module = "wasi:cli-base/preopens")] extern "C" { #[link_name = "get-directories"] fn get_preopens_import(rval: *mut PreopenList); @@ -189,8 +191,7 @@ impl Descriptors { output: Cell::new(None), type_: StreamType::File(File { fd: preopen.descriptor, - descriptor_type: crate::bindings::filesystem::get_type(preopen.descriptor) - .trapping_unwrap(), + descriptor_type: filesystem::get_type(preopen.descriptor).trapping_unwrap(), position: Cell::new(0), append: false, blocking: false, @@ -346,7 +347,7 @@ impl Descriptors { } #[allow(dead_code)] // until Socket is implemented - pub fn get_socket(&self, fd: Fd) -> Result { + pub fn get_socket(&self, fd: Fd) -> Result { match self.get(fd)? { Descriptor::Streams(Streams { type_: StreamType::Socket(socket), diff --git a/crates/wasi-preview1-component-adapter/src/lib.rs b/crates/wasi-preview1-component-adapter/src/lib.rs index c368a57b2355..d10fc48cd87d 100644 --- a/crates/wasi-preview1-component-adapter/src/lib.rs +++ b/crates/wasi-preview1-component-adapter/src/lib.rs @@ -1,8 +1,12 @@ #![allow(unused_variables)] // TODO: remove this when more things are implemented -use crate::bindings::{ - exit, filesystem, monotonic_clock, network, poll, random, streams, wall_clock, -}; +use crate::bindings::wasi::cli_base::exit; +use crate::bindings::wasi::clocks::{monotonic_clock, wall_clock}; +use crate::bindings::wasi::filesystem::filesystem; +use crate::bindings::wasi::io::streams; +use crate::bindings::wasi::poll::poll; +use crate::bindings::wasi::random::random; +use crate::bindings::wasi::sockets::network; use core::cell::{Cell, RefCell, RefMut, UnsafeCell}; use core::cmp::min; use core::ffi::c_void; @@ -26,7 +30,8 @@ use crate::descriptors::{Descriptor, Descriptors, StreamType, Streams}; pub mod bindings { #[cfg(feature = "command")] wit_bindgen::generate!({ - world: "command", + path: "../wasi/wit", + world: "wasi:preview/command", std_feature, raw_strings, // The generated definition of command will pull in std, so we are defining it @@ -36,7 +41,8 @@ pub mod bindings { #[cfg(feature = "reactor")] wit_bindgen::generate!({ - world: "reactor", + path: "../wasi/wit", + world: "wasi:preview/reactor", std_feature, raw_strings, skip: ["get-directories", "get-environment"], @@ -2335,7 +2341,7 @@ impl State { fn get_environment(&self) -> &[StrTuple] { if self.env_vars.get().is_none() { - #[link(wasm_import_module = "environment")] + #[link(wasm_import_module = "wasi:cli-base/environment")] extern "C" { #[link_name = "get-environment"] fn get_environment_import(rval: *mut StrTupleList); @@ -2359,7 +2365,7 @@ impl State { fn get_args(&self) -> &[WasmStr] { if self.args.get().is_none() { - #[link(wasm_import_module = "environment")] + #[link(wasm_import_module = "wasi:cli-base/environment")] extern "C" { #[link_name = "get-arguments"] fn get_args_import(rval: *mut WasmStrList); diff --git a/crates/wasi-preview1-component-adapter/src/macros.rs b/crates/wasi-preview1-component-adapter/src/macros.rs index 13faf6bc62fc..ca46aacacf1c 100644 --- a/crates/wasi-preview1-component-adapter/src/macros.rs +++ b/crates/wasi-preview1-component-adapter/src/macros.rs @@ -2,10 +2,13 @@ //! //! We're avoiding static initializers, so we can't have things like string //! literals. Replace the standard assert macros with simpler implementations. + +use crate::bindings::wasi::io::streams; + #[allow(dead_code)] #[doc(hidden)] pub fn print(message: &[u8]) { - let _ = unsafe { crate::bindings::streams::write(crate::get_stderr_stream(), message) }; + let _ = unsafe { streams::write(crate::get_stderr_stream(), message) }; } /// A minimal `eprint` for debugging. diff --git a/crates/wasi-preview1-component-adapter/verify/src/main.rs b/crates/wasi-preview1-component-adapter/verify/src/main.rs index 8fb23617f33f..2a8b391d7c97 100644 --- a/crates/wasi-preview1-component-adapter/verify/src/main.rs +++ b/crates/wasi-preview1-component-adapter/verify/src/main.rs @@ -2,31 +2,6 @@ use anyhow::{bail, Result}; use std::env; use wasmparser::*; -const ALLOWED_IMPORT_MODULES: &[&str] = &[ - "wall-clock", - "monotonic-clock", - "timezone", - "filesystem", - "instance-network", - "ip-name-lookup", - "network", - "tcp-create-socket", - "tcp", - "udp-create-socket", - "udp", - "random", - "poll", - "streams", - "environment", - "preopens", - "exit", - "canonical_abi", - "stdin", - "stdout", - "stderr", - "__main_module__", -]; - fn main() -> Result<()> { let file = env::args() .nth(1) @@ -50,9 +25,13 @@ fn main() -> Result<()> { let i = i?; match i.ty { TypeRef::Func(_) => { - if !ALLOWED_IMPORT_MODULES.contains(&i.module) { - bail!("import from unknown module `{}`", i.module); + if i.module.starts_with("wasi:") { + continue; + } + if i.module == "__main_module__" { + continue; } + bail!("import from unknown module `{}`", i.module); } TypeRef::Table(_) => bail!("should not import table"), TypeRef::Global(_) => bail!("should not import globals"), diff --git a/crates/wasi-preview1-component-adapter/wit/deps/clocks/monotonic-clock.wit b/crates/wasi-preview1-component-adapter/wit/deps/clocks/monotonic-clock.wit deleted file mode 100644 index 42e2981f579a..000000000000 --- a/crates/wasi-preview1-component-adapter/wit/deps/clocks/monotonic-clock.wit +++ /dev/null @@ -1,32 +0,0 @@ -/// WASI Monotonic Clock is a clock API intended to let users measure elapsed -/// time. -/// -/// It is intended to be portable at least between Unix-family platforms and -/// Windows. -/// -/// A monotonic clock is a clock which has an unspecified initial value, and -/// successive reads of the clock will produce non-decreasing values. -/// -/// It is intended for measuring elapsed time. -default interface monotonic-clock { - use poll.poll.{pollable} - - /// A timestamp in nanoseconds. - type instant = u64 - - /// Read the current value of the clock. - /// - /// The clock is monotonic, therefore calling this function repeatedly will - /// produce a sequence of non-decreasing values. - now: func() -> instant - - /// Query the resolution of the clock. - resolution: func() -> instant - - /// Create a `pollable` which will resolve once the specified time has been - /// reached. - subscribe: func( - when: instant, - absolute: bool - ) -> pollable -} diff --git a/crates/wasi-preview1-component-adapter/wit/deps/clocks/timezone.wit b/crates/wasi-preview1-component-adapter/wit/deps/clocks/timezone.wit deleted file mode 100644 index 63f99cc401b1..000000000000 --- a/crates/wasi-preview1-component-adapter/wit/deps/clocks/timezone.wit +++ /dev/null @@ -1,61 +0,0 @@ -default interface timezone { - use pkg.wall-clock.{datetime} - - /// A timezone. - /// - /// In timezones that recognize daylight saving time, also known as daylight - /// time and summer time, the information returned from the functions varies - /// over time to reflect these adjustments. - /// - /// This [represents a resource](https://github.com/WebAssembly/WASI/blob/main/docs/WitInWasi.md#Resources). - type timezone = u32 - - /// Return information needed to display the given `datetime`. This includes - /// the UTC offset, the time zone name, and a flag indicating whether - /// daylight saving time is active. - /// - /// If the timezone cannot be determined for the given `datetime`, return a - /// `timezone-display` for `UTC` with a `utc-offset` of 0 and no daylight - /// saving time. - display: func(this: timezone, when: datetime) -> timezone-display - - /// The same as `display`, but only return the UTC offset. - utc-offset: func(this: timezone, when: datetime) -> s32 - - /// Dispose of the specified input-stream, after which it may no longer - /// be used. - drop-timezone: func(this: timezone) - - /// Information useful for displaying the timezone of a specific `datetime`. - /// - /// This information may vary within a single `timezone` to reflect daylight - /// saving time adjustments. - record timezone-display { - /// The number of seconds difference between UTC time and the local - /// time of the timezone. - /// - /// The returned value will always be less than 86400 which is the - /// number of seconds in a day (24*60*60). - /// - /// In implementations that do not expose an actual time zone, this - /// should return 0. - utc-offset: s32, - - /// The abbreviated name of the timezone to display to a user. The name - /// `UTC` indicates Coordinated Universal Time. Otherwise, this should - /// reference local standards for the name of the time zone. - /// - /// In implementations that do not expose an actual time zone, this - /// should be the string `UTC`. - /// - /// In time zones that do not have an applicable name, a formatted - /// representation of the UTC offset may be returned, such as `-04:00`. - name: string, - - /// Whether daylight saving time is active. - /// - /// In implementations that do not expose an actual time zone, this - /// should return false. - in-daylight-saving-time: bool, - } -} diff --git a/crates/wasi-preview1-component-adapter/wit/deps/clocks/wall-clock.wit b/crates/wasi-preview1-component-adapter/wit/deps/clocks/wall-clock.wit deleted file mode 100644 index 89c5a75da68b..000000000000 --- a/crates/wasi-preview1-component-adapter/wit/deps/clocks/wall-clock.wit +++ /dev/null @@ -1,41 +0,0 @@ -/// WASI Wall Clock is a clock API intended to let users query the current -/// time. The name "wall" makes an analogy to a "clock on the wall", which -/// is not necessarily monotonic as it may be reset. -/// -/// It is intended to be portable at least between Unix-family platforms and -/// Windows. -/// -/// A wall clock is a clock which measures the date and time according to -/// some external reference. -/// -/// External references may be reset, so this clock is not necessarily -/// monotonic, making it unsuitable for measuring elapsed time. -/// -/// It is intended for reporting the current date and time for humans. -default interface wall-clock { - /// A time and date in seconds plus nanoseconds. - record datetime { - seconds: u64, - nanoseconds: u32, - } - - /// Read the current value of the clock. - /// - /// This clock is not monotonic, therefore calling this function repeatedly - /// will not necessarily produce a sequence of non-decreasing values. - /// - /// The returned timestamps represent the number of seconds since - /// 1970-01-01T00:00:00Z, also known as [POSIX's Seconds Since the Epoch], - /// also known as [Unix Time]. - /// - /// The nanoseconds field of the output is always less than 1000000000. - /// - /// [POSIX's Seconds Since the Epoch]: https://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xbd_chap04.html#tag_21_04_16 - /// [Unix Time]: https://en.wikipedia.org/wiki/Unix_time - now: func() -> datetime - - /// Query the resolution of the clock. - /// - /// The nanoseconds field of the output is always less than 1000000000. - resolution: func() -> datetime -} diff --git a/crates/wasi-preview1-component-adapter/wit/deps/http/incoming-handler.wit b/crates/wasi-preview1-component-adapter/wit/deps/http/incoming-handler.wit deleted file mode 100644 index 1ecff0aa5f5b..000000000000 --- a/crates/wasi-preview1-component-adapter/wit/deps/http/incoming-handler.wit +++ /dev/null @@ -1,24 +0,0 @@ -// The `wasi:http/incoming-handler` interface is meant to be exported by -// components and called by the host in response to a new incoming HTTP -// response. -// -// NOTE: in Preview3, this interface will be merged with -// `wasi:http/outgoing-handler` into a single `wasi:http/handler` interface -// that takes a `request` parameter and returns a `response` result. -// -default interface incoming-handler { - use pkg.types.{incoming-request, response-outparam} - - // The `handle` function takes an outparam instead of returning its response - // so that the component may stream its response while streaming any other - // request or response bodies. The callee MUST write a response to the - // `response-out` and then finish the response before returning. The `handle` - // function is allowed to continue execution after finishing the response's - // output stream. While this post-response execution is taken off the - // critical path, since there is no return value, there is no way to report - // its success or failure. - handle: func( - request: incoming-request, - response-out: response-outparam - ) -} diff --git a/crates/wasi-preview1-component-adapter/wit/deps/http/outgoing-handler.wit b/crates/wasi-preview1-component-adapter/wit/deps/http/outgoing-handler.wit deleted file mode 100644 index abe812ffaba7..000000000000 --- a/crates/wasi-preview1-component-adapter/wit/deps/http/outgoing-handler.wit +++ /dev/null @@ -1,18 +0,0 @@ -// The `wasi:http/outgoing-handler` interface is meant to be imported by -// components and implemented by the host. -// -// NOTE: in Preview3, this interface will be merged with -// `wasi:http/outgoing-handler` into a single `wasi:http/handler` interface -// that takes a `request` parameter and returns a `response` result. -// -default interface outgoing-handler { - use pkg.types.{outgoing-request, request-options, future-incoming-response} - - // The parameter and result types of the `handle` function allow the caller - // to concurrently stream the bodies of the outgoing request and the incoming - // response. - handle: func( - request: outgoing-request, - options: option - ) -> future-incoming-response -} diff --git a/crates/wasi-preview1-component-adapter/wit/deps/http/types.wit b/crates/wasi-preview1-component-adapter/wit/deps/http/types.wit deleted file mode 100644 index bdcf79737273..000000000000 --- a/crates/wasi-preview1-component-adapter/wit/deps/http/types.wit +++ /dev/null @@ -1,157 +0,0 @@ -// The `wasi:http/types` interface is meant to be imported by components to -// define the HTTP resource types and operations used by the component's -// imported and exported interfaces. -default interface types { - use io.streams.{input-stream, output-stream} - use poll.poll.{pollable} - - // This type corresponds to HTTP standard Methods. - variant method { - get, - head, - post, - put, - delete, - connect, - options, - trace, - patch, - other(string) - } - - // This type corresponds to HTTP standard Related Schemes. - variant scheme { - HTTP, - HTTPS, - other(string) - } - - // TODO: perhaps better align with HTTP semantics? - // This type enumerates the different kinds of errors that may occur when - // initially returning a response. - variant error { - invalid-url(string), - timeout-error(string), - protocol-error(string), - unexpected-error(string) - } - - // This following block defines the `fields` resource which corresponds to - // HTTP standard Fields. Soon, when resource types are added, the `type - // fields = u32` type alias can be replaced by a proper `resource fields` - // definition containing all the functions using the method syntactic sugar. - type fields = u32 - drop-fields: func(fields: fields) - new-fields: func(entries: list>) -> fields - fields-get: func(fields: fields, name: string) -> list - fields-set: func(fields: fields, name: string, value: list) - fields-delete: func(fields: fields, name: string) - fields-append: func(fields: fields, name: string, value: string) - fields-entries: func(fields: fields) -> list> - fields-clone: func(fields: fields) -> fields - - type headers = fields - type trailers = fields - - // The following block defines stream types which corresponds to the HTTP - // standard Contents and Trailers. With Preview3, all of these fields can be - // replaced by a stream>. In the interim, we need to - // build on separate resource types defined by `wasi:io/streams`. The - // `finish-` functions emulate the stream's result value and MUST be called - // exactly once after the final read/write from/to the stream before dropping - // the stream. - type incoming-stream = input-stream - type outgoing-stream = output-stream - finish-incoming-stream: func(s: incoming-stream) -> option - finish-outgoing-stream: func(s: outgoing-stream, trailers: option) - - // The following block defines the `incoming-request` and `outgoing-request` - // resource types that correspond to HTTP standard Requests. Soon, when - // resource types are added, the `u32` type aliases can be replaced by - // proper `resource` type definitions containing all the functions as - // methods. Later, Preview2 will allow both types to be merged together into - // a single `request` type (that uses the single `stream` type mentioned - // above). The `consume` and `write` methods may only be called once (and - // return failure thereafter). - type incoming-request = u32 - type outgoing-request = u32 - drop-incoming-request: func(request: incoming-request) - drop-outgoing-request: func(request: outgoing-request) - incoming-request-method: func(request: incoming-request) -> method - incoming-request-path: func(request: incoming-request) -> string - incoming-request-query: func(request: incoming-request) -> string - incoming-request-scheme: func(request: incoming-request) -> option - incoming-request-authority: func(request: incoming-request) -> string - incoming-request-headers: func(request: incoming-request) -> headers - incoming-request-consume: func(request: incoming-request) -> result - new-outgoing-request: func( - method: method, - path: string, - query: string, - scheme: option, - authority: string, - headers: headers - ) -> outgoing-request - outgoing-request-write: func(request: outgoing-request) -> result - - // Additional optional parameters that can be set when making a request. - record request-options { - // The following timeouts are specific to the HTTP protocol and work - // independently of the overall timeouts passed to `io.poll.poll-oneoff`. - - // The timeout for the initial connect. - connect-timeout-ms: option, - - // The timeout for receiving the first byte of the response body. - first-byte-timeout-ms: option, - - // The timeout for receiving the next chunk of bytes in the response body - // stream. - between-bytes-timeout-ms: option - } - - // The following block defines a special resource type used by the - // `wasi:http/incoming-handler` interface. When resource types are added, this - // block can be replaced by a proper `resource response-outparam { ... }` - // definition. Later, with Preview3, the need for an outparam goes away entirely - // (the `wasi:http/handler` interface used for both incoming and outgoing can - // simply return a `stream`). - type response-outparam = u32 - drop-response-outparam: func(response: response-outparam) - set-response-outparam: func(response: result) -> result - - // This type corresponds to the HTTP standard Status Code. - type status-code = u16 - - // The following block defines the `incoming-response` and `outgoing-response` - // resource types that correspond to HTTP standard Responses. Soon, when - // resource types are added, the `u32` type aliases can be replaced by proper - // `resource` type definitions containing all the functions as methods. Later, - // Preview2 will allow both types to be merged together into a single `response` - // type (that uses the single `stream` type mentioned above). The `consume` and - // `write` methods may only be called once (and return failure thereafter). - type incoming-response = u32 - type outgoing-response = u32 - drop-incoming-response: func(response: incoming-response) - drop-outgoing-response: func(response: outgoing-response) - incoming-response-status: func(response: incoming-response) -> status-code - incoming-response-headers: func(response: incoming-response) -> headers - incoming-response-consume: func(response: incoming-response) -> result - new-outgoing-response: func( - status-code: status-code, - headers: headers - ) -> outgoing-response - outgoing-response-write: func(response: outgoing-response) -> result - - // The following block defines a special resource type used by the - // `wasi:http/outgoing-handler` interface to emulate - // `future>` in advance of Preview3. Given a - // `future-incoming-response`, the client can call the non-blocking `get` - // method to get the result if it is available. If the result is not available, - // the client can call `listen` to get a `pollable` that can be passed to - // `io.poll.poll-oneoff`. - type future-incoming-response = u32 - drop-future-incoming-response: func(f: future-incoming-response) - future-incoming-response-get: func(f: future-incoming-response) -> option> - listen-to-future-incoming-response: func(f: future-incoming-response) -> pollable -} diff --git a/crates/wasi-preview1-component-adapter/wit/deps/io/streams.wit b/crates/wasi-preview1-component-adapter/wit/deps/io/streams.wit deleted file mode 100644 index c1567fd4c1c8..000000000000 --- a/crates/wasi-preview1-component-adapter/wit/deps/io/streams.wit +++ /dev/null @@ -1,213 +0,0 @@ -/// WASI I/O is an I/O abstraction API which is currently focused on providing -/// stream types. -/// -/// In the future, the component model is expected to add built-in stream types; -/// when it does, they are expected to subsume this API. -default interface streams { - use poll.poll.{pollable} - - /// An error type returned from a stream operation. Currently this - /// doesn't provide any additional information. - record stream-error {} - - /// An input bytestream. In the future, this will be replaced by handle - /// types. - /// - /// This conceptually represents a `stream`. It's temporary - /// scaffolding until component-model's async features are ready. - /// - /// `input-stream`s are *non-blocking* to the extent practical on underlying - /// platforms. I/O operations always return promptly; if fewer bytes are - /// promptly available than requested, they return the number of bytes promptly - /// available, which could even be zero. To wait for data to be available, - /// use the `subscribe-to-input-stream` function to obtain a `pollable` which - /// can be polled for using `wasi_poll`. - /// - /// And at present, it is a `u32` instead of being an actual handle, until - /// the wit-bindgen implementation of handles and resources is ready. - /// - /// This [represents a resource](https://github.com/WebAssembly/WASI/blob/main/docs/WitInWasi.md#Resources). - type input-stream = u32 - - /// Read bytes from a stream. - /// - /// This function returns a list of bytes containing the data that was - /// read, along with a bool which, when true, indicates that the end of the - /// stream was reached. The returned list will contain up to `len` bytes; it - /// may return fewer than requested, but not more. - /// - /// Once a stream has reached the end, subsequent calls to read or - /// `skip` will always report end-of-stream rather than producing more - /// data. - /// - /// If `len` is 0, it represents a request to read 0 bytes, which should - /// always succeed, assuming the stream hasn't reached its end yet, and - /// return an empty list. - /// - /// The len here is a `u64`, but some callees may not be able to allocate - /// a buffer as large as that would imply. - /// FIXME: describe what happens if allocation fails. - read: func( - this: input-stream, - /// The maximum number of bytes to read - len: u64 - ) -> result, bool>, stream-error> - - /// Read bytes from a stream, with blocking. - /// - /// This is similar to `read`, except that it blocks until at least one - /// byte can be read. - blocking-read: func( - this: input-stream, - /// The maximum number of bytes to read - len: u64 - ) -> result, bool>, stream-error> - - /// Skip bytes from a stream. - /// - /// This is similar to the `read` function, but avoids copying the - /// bytes into the instance. - /// - /// Once a stream has reached the end, subsequent calls to read or - /// `skip` will always report end-of-stream rather than producing more - /// data. - /// - /// This function returns the number of bytes skipped, along with a bool - /// indicating whether the end of the stream was reached. The returned - /// value will be at most `len`; it may be less. - skip: func( - this: input-stream, - /// The maximum number of bytes to skip. - len: u64, - ) -> result, stream-error> - - /// Skip bytes from a stream, with blocking. - /// - /// This is similar to `skip`, except that it blocks until at least one - /// byte can be consumed. - blocking-skip: func( - this: input-stream, - /// The maximum number of bytes to skip. - len: u64, - ) -> result, stream-error> - - /// Create a `pollable` which will resolve once either the specified stream - /// has bytes available to read or the other end of the stream has been - /// closed. - subscribe-to-input-stream: func(this: input-stream) -> pollable - - /// Dispose of the specified `input-stream`, after which it may no longer - /// be used. - drop-input-stream: func(this: input-stream) - - /// An output bytestream. In the future, this will be replaced by handle - /// types. - /// - /// This conceptually represents a `stream`. It's temporary - /// scaffolding until component-model's async features are ready. - /// - /// `output-stream`s are *non-blocking* to the extent practical on - /// underlying platforms. Except where specified otherwise, I/O operations also - /// always return promptly, after the number of bytes that can be written - /// promptly, which could even be zero. To wait for the stream to be ready to - /// accept data, the `subscribe-to-output-stream` function to obtain a - /// `pollable` which can be polled for using `wasi_poll`. - /// - /// And at present, it is a `u32` instead of being an actual handle, until - /// the wit-bindgen implementation of handles and resources is ready. - /// - /// This [represents a resource](https://github.com/WebAssembly/WASI/blob/main/docs/WitInWasi.md#Resources). - type output-stream = u32 - - /// Write bytes to a stream. - /// - /// This function returns a `u64` indicating the number of bytes from - /// `buf` that were written; it may be less than the full list. - write: func( - this: output-stream, - /// Data to write - buf: list - ) -> result - - /// Write bytes to a stream, with blocking. - /// - /// This is similar to `write`, except that it blocks until at least one - /// byte can be written. - blocking-write: func( - this: output-stream, - /// Data to write - buf: list - ) -> result - - /// Write multiple zero bytes to a stream. - /// - /// This function returns a `u64` indicating the number of zero bytes - /// that were written; it may be less than `len`. - write-zeroes: func( - this: output-stream, - /// The number of zero bytes to write - len: u64 - ) -> result - - /// Write multiple zero bytes to a stream, with blocking. - /// - /// This is similar to `write-zeroes`, except that it blocks until at least - /// one byte can be written. - blocking-write-zeroes: func( - this: output-stream, - /// The number of zero bytes to write - len: u64 - ) -> result - - /// Read from one stream and write to another. - /// - /// This function returns the number of bytes transferred; it may be less - /// than `len`. - /// - /// Unlike other I/O functions, this function blocks until all the data - /// read from the input stream has been written to the output stream. - splice: func( - this: output-stream, - /// The stream to read from - src: input-stream, - /// The number of bytes to splice - len: u64, - ) -> result, stream-error> - - /// Read from one stream and write to another, with blocking. - /// - /// This is similar to `splice`, except that it blocks until at least - /// one byte can be read. - blocking-splice: func( - this: output-stream, - /// The stream to read from - src: input-stream, - /// The number of bytes to splice - len: u64, - ) -> result, stream-error> - - /// Forward the entire contents of an input stream to an output stream. - /// - /// This function repeatedly reads from the input stream and writes - /// the data to the output stream, until the end of the input stream - /// is reached, or an error is encountered. - /// - /// Unlike other I/O functions, this function blocks until the end - /// of the input stream is seen and all the data has been written to - /// the output stream. - /// - /// This function returns the number of bytes transferred. - forward: func( - this: output-stream, - /// The stream to read from - src: input-stream - ) -> result - - /// Create a `pollable` which will resolve once either the specified stream - /// is ready to accept bytes or the other end of the stream has been closed. - subscribe-to-output-stream: func(this: output-stream) -> pollable - - /// Dispose of the specified `output-stream`, after which it may no longer - /// be used. - drop-output-stream: func(this: output-stream) -} diff --git a/crates/wasi-preview1-component-adapter/wit/deps/logging/handler.wit b/crates/wasi-preview1-component-adapter/wit/deps/logging/handler.wit deleted file mode 100644 index c9632b9cc4f8..000000000000 --- a/crates/wasi-preview1-component-adapter/wit/deps/logging/handler.wit +++ /dev/null @@ -1,32 +0,0 @@ -/// WASI Logging is a logging API intended to let users emit log messages with -/// simple priority levels and context values. -default interface handler { - /// A log level, describing a kind of message. - enum level { - /// Describes messages about the values of variables and the flow of - /// control within a program. - trace, - - /// Describes messages likely to be of interest to someone debugging a - /// program. - debug, - - /// Describes messages likely to be of interest to someone monitoring a - /// program. - info, - - /// Describes messages indicating hazardous situations. - warn, - - /// Describes messages indicating serious errors. - error, - } - - /// Emit a log message. - /// - /// A log message has a `level` describing what kind of message is being - /// sent, a context, which is an uninterpreted string meant to help - /// consumers group similar messages, and a string containing the message - /// text. - log: func(level: level, context: string, message: string) -} diff --git a/crates/wasi-preview1-component-adapter/wit/deps/poll/poll.wit b/crates/wasi-preview1-component-adapter/wit/deps/poll/poll.wit deleted file mode 100644 index 28f08e17d755..000000000000 --- a/crates/wasi-preview1-component-adapter/wit/deps/poll/poll.wit +++ /dev/null @@ -1,39 +0,0 @@ -/// A poll API intended to let users wait for I/O events on multiple handles -/// at once. -default interface poll { - /// A "pollable" handle. - /// - /// This is conceptually represents a `stream<_, _>`, or in other words, - /// a stream that one can wait on, repeatedly, but which does not itself - /// produce any data. It's temporary scaffolding until component-model's - /// async features are ready. - /// - /// And at present, it is a `u32` instead of being an actual handle, until - /// the wit-bindgen implementation of handles and resources is ready. - /// - /// `pollable` lifetimes are not automatically managed. Users must ensure - /// that they do not outlive the resource they reference. - /// - /// This [represents a resource](https://github.com/WebAssembly/WASI/blob/main/docs/WitInWasi.md#Resources). - type pollable = u32 - - /// Dispose of the specified `pollable`, after which it may no longer - /// be used. - drop-pollable: func(this: pollable) - - /// Poll for completion on a set of pollables. - /// - /// The "oneoff" in the name refers to the fact that this function must do a - /// linear scan through the entire list of subscriptions, which may be - /// inefficient if the number is large and the same subscriptions are used - /// many times. In the future, this is expected to be obsoleted by the - /// component model async proposal, which will include a scalable waiting - /// facility. - /// - /// Note that the return type would ideally be `list`, but that would - /// be more difficult to polyfill given the current state of `wit-bindgen`. - /// See - /// for details. For now, we use zero to mean "not ready" and non-zero to - /// mean "ready". - poll-oneoff: func(in: list) -> list -} diff --git a/crates/wasi-preview1-component-adapter/wit/deps/preview/reactor.wit b/crates/wasi-preview1-component-adapter/wit/deps/preview/reactor.wit deleted file mode 100644 index 2abfa466ba3b..000000000000 --- a/crates/wasi-preview1-component-adapter/wit/deps/preview/reactor.wit +++ /dev/null @@ -1,21 +0,0 @@ -default world reactor { - import wall-clock: clocks.wall-clock - import monotonic-clock: clocks.monotonic-clock - import timezone: clocks.timezone - import filesystem: filesystem.filesystem - import instance-network: sockets.instance-network - import ip-name-lookup: sockets.ip-name-lookup - import network: sockets.network - import tcp-create-socket: sockets.tcp-create-socket - import tcp: sockets.tcp - import udp-create-socket: sockets.udp-create-socket - import udp: sockets.udp - import random: random.random - import poll: poll.poll - import streams: io.streams - import console: logging.handler - import default-outgoing-HTTP: http.outgoing-handler - import environment: wasi-cli-base.environment - import preopens: wasi-cli-base.preopens - import exit: wasi-cli-base.exit -} diff --git a/crates/wasi-preview1-component-adapter/wit/deps/sockets/instance-network.wit b/crates/wasi-preview1-component-adapter/wit/deps/sockets/instance-network.wit deleted file mode 100644 index b1f5c982d976..000000000000 --- a/crates/wasi-preview1-component-adapter/wit/deps/sockets/instance-network.wit +++ /dev/null @@ -1,9 +0,0 @@ - -/// This interface provides a value-export of the default network handle.. -default interface instance-network { - use pkg.network.{network} - - /// Get a handle to the default network. - instance-network: func() -> network - -} diff --git a/crates/wasi-preview1-component-adapter/wit/deps/wasi-cli-base/environment.wit b/crates/wasi-preview1-component-adapter/wit/deps/wasi-cli-base/environment.wit deleted file mode 100644 index 876ea3a0c921..000000000000 --- a/crates/wasi-preview1-component-adapter/wit/deps/wasi-cli-base/environment.wit +++ /dev/null @@ -1,14 +0,0 @@ -default interface environment { - /// Get the POSIX-style environment variables. - /// - /// Each environment variable is provided as a pair of string variable names - /// and string value. - /// - /// Morally, these are a value import, but until value imports are available - /// in the component model, this import function should return the same - /// values each time it is called. - get-environment: func() -> list> - - /// Get the POSIX-style arguments to the program. - get-arguments: func() -> list -} diff --git a/crates/wasi-preview1-component-adapter/wit/deps/wasi-cli-base/exit.wit b/crates/wasi-preview1-component-adapter/wit/deps/wasi-cli-base/exit.wit deleted file mode 100644 index 2759e9dd989c..000000000000 --- a/crates/wasi-preview1-component-adapter/wit/deps/wasi-cli-base/exit.wit +++ /dev/null @@ -1,4 +0,0 @@ -default interface wasi-exit { - /// Exit the curerent instance and any linked instances. - exit: func(status: result) -} diff --git a/crates/wasi/src/preview2/preview1/mod.rs b/crates/wasi/src/preview2/preview1/mod.rs index 3fb1a5806b2b..9040425acf33 100644 --- a/crates/wasi/src/preview2/preview1/mod.rs +++ b/crates/wasi/src/preview2/preview1/mod.rs @@ -1,25 +1,27 @@ use crate::preview2::filesystem::TableFsExt; use crate::preview2::preview2::filesystem::TableReaddirExt; +use crate::preview2::wasi::cli_base::{preopens, stderr, stdin, stdout}; +use crate::preview2::wasi::clocks::monotonic_clock; +use crate::preview2::wasi::clocks::wall_clock; +use crate::preview2::wasi::filesystem::filesystem; +use crate::preview2::wasi::io::streams; use crate::preview2::{wasi, TableError, WasiView}; - -use core::borrow::Borrow; -use core::cell::Cell; -use core::mem::{size_of, size_of_val}; -use core::ops::{Deref, DerefMut}; -use core::slice; -use core::sync::atomic::{AtomicU64, Ordering}; - +use anyhow::{anyhow, bail, Context}; +use std::borrow::Borrow; +use std::cell::Cell; use std::collections::BTreeMap; +use std::mem::{size_of, size_of_val}; +use std::ops::{Deref, DerefMut}; +use std::slice; +use std::sync::atomic::{AtomicU64, Ordering}; use std::sync::Arc; - -use anyhow::{anyhow, bail, Context}; use wiggle::tracing::instrument; use wiggle::{GuestPtr, GuestSliceMut, GuestStrCow, GuestType}; #[derive(Clone, Debug)] struct File { /// The handle to the preview2 descriptor that this file is referencing. - fd: wasi::filesystem::Descriptor, + fd: filesystem::Descriptor, /// The current-position pointer. position: Arc, @@ -35,10 +37,10 @@ struct File { #[derive(Clone, Debug)] enum Descriptor { - Stdin(wasi::preopens::InputStream), - Stdout(wasi::preopens::OutputStream), - Stderr(wasi::preopens::OutputStream), - PreopenDirectory((wasi::filesystem::Descriptor, String)), + Stdin(preopens::InputStream), + Stdout(preopens::OutputStream), + Stderr(preopens::OutputStream), + PreopenDirectory((filesystem::Descriptor, String)), File(File), } @@ -70,11 +72,7 @@ impl DerefMut for Descriptors { impl Descriptors { /// Initializes [Self] using `preopens` async fn new( - preopens: &mut (impl wasi::preopens::Host - + wasi::stdin::Host - + wasi::stdout::Host - + wasi::stderr::Host - + ?Sized), + preopens: &mut (impl preopens::Host + stdin::Host + stdout::Host + stderr::Host + ?Sized), ) -> Result { let stdin = preopens .get_stdin() @@ -245,8 +243,8 @@ impl Transaction<'_, T> { } } - /// Returns [`wasi::filesystem::Descriptor`] corresponding to `fd` - fn get_fd(&mut self, fd: types::Fd) -> ErrnoResult { + /// Returns [`filesystem::Descriptor`] corresponding to `fd` + fn get_fd(&mut self, fd: types::Fd) -> ErrnoResult { match self.get_descriptor(fd)? { Descriptor::File(File { fd, .. }) => Ok(*fd), Descriptor::PreopenDirectory((fd, _)) => Ok(*fd), @@ -255,16 +253,16 @@ impl Transaction<'_, T> { } } - /// Returns [`wasi::filesystem::Descriptor`] corresponding to `fd` + /// Returns [`filesystem::Descriptor`] corresponding to `fd` /// if it describes a [`Descriptor::File`] of [`crate::preview2::filesystem::File`] type - fn get_file_fd(&mut self, fd: types::Fd) -> ErrnoResult { + fn get_file_fd(&mut self, fd: types::Fd) -> ErrnoResult { self.get_file(fd).map(|File { fd, .. }| *fd) } - /// Returns [`wasi::filesystem::Descriptor`] corresponding to `fd` + /// Returns [`filesystem::Descriptor`] corresponding to `fd` /// if it describes a [`Descriptor::File`] or [`Descriptor::PreopenDirectory`] /// of [`crate::preview2::filesystem::Dir`] type - fn get_dir_fd(&mut self, fd: types::Fd) -> ErrnoResult { + fn get_dir_fd(&mut self, fd: types::Fd) -> ErrnoResult { let fd = fd.into(); match self.descriptors.get_mut().get(&fd) { Some(Descriptor::File(File { fd, .. })) if self.view.table().is_dir(*fd) => Ok(*fd), @@ -276,11 +274,7 @@ impl Transaction<'_, T> { #[wiggle::async_trait] trait WasiPreview1ViewExt: - WasiPreview1View - + wasi::preopens::Host - + wasi::stdin::Host - + wasi::stdout::Host - + wasi::stderr::Host + WasiPreview1View + preopens::Host + stdin::Host + stdout::Host + stderr::Host { /// Lazily initializes [`WasiPreview1Adapter`] returned by [`WasiPreview1View::adapter_mut`] /// and returns [`Transaction`] on success @@ -298,55 +292,46 @@ trait WasiPreview1ViewExt: } /// Lazily initializes [`WasiPreview1Adapter`] returned by [`WasiPreview1View::adapter_mut`] - /// and returns [`wasi::filesystem::Descriptor`] corresponding to `fd` - async fn get_fd( - &mut self, - fd: types::Fd, - ) -> Result { + /// and returns [`filesystem::Descriptor`] corresponding to `fd` + async fn get_fd(&mut self, fd: types::Fd) -> Result { let mut st = self.transact().await?; let fd = st.get_fd(fd)?; Ok(fd) } /// Lazily initializes [`WasiPreview1Adapter`] returned by [`WasiPreview1View::adapter_mut`] - /// and returns [`wasi::filesystem::Descriptor`] corresponding to `fd` + /// and returns [`filesystem::Descriptor`] corresponding to `fd` /// if it describes a [`Descriptor::File`] of [`crate::preview2::filesystem::File`] type - async fn get_file_fd( - &mut self, - fd: types::Fd, - ) -> Result { + async fn get_file_fd(&mut self, fd: types::Fd) -> Result { let mut st = self.transact().await?; let fd = st.get_file_fd(fd)?; Ok(fd) } /// Lazily initializes [`WasiPreview1Adapter`] returned by [`WasiPreview1View::adapter_mut`] - /// and returns [`wasi::filesystem::Descriptor`] corresponding to `fd` + /// and returns [`filesystem::Descriptor`] corresponding to `fd` /// if it describes a [`Descriptor::File`] or [`Descriptor::PreopenDirectory`] /// of [`crate::preview2::filesystem::Dir`] type - async fn get_dir_fd( - &mut self, - fd: types::Fd, - ) -> Result { + async fn get_dir_fd(&mut self, fd: types::Fd) -> Result { let mut st = self.transact().await?; let fd = st.get_dir_fd(fd)?; Ok(fd) } } -impl WasiPreview1ViewExt for T {} +impl WasiPreview1ViewExt for T {} pub fn add_to_linker< T: WasiPreview1View - + wasi::environment::Host - + wasi::exit::Host - + wasi::filesystem::Host - + wasi::monotonic_clock::Host - + wasi::poll::Host - + wasi::preopens::Host - + wasi::random::Host - + wasi::streams::Host - + wasi::wall_clock::Host, + + wasi::cli_base::environment::Host + + wasi::cli_base::exit::Host + + wasi::cli_base::preopens::Host + + wasi::filesystem::filesystem::Host + + wasi::poll::poll::Host + + wasi::random::random::Host + + wasi::io::streams::Host + + wasi::clocks::monotonic_clock::Host + + wasi::clocks::wall_clock::Host, >( linker: &mut wasmtime::Linker, ) -> anyhow::Result<()> { @@ -373,31 +358,29 @@ fn systimespec( set: bool, ts: types::Timestamp, now: bool, -) -> ErrnoResult { +) -> ErrnoResult { if set && now { Err(types::Errno::Inval) } else if set { - Ok(wasi::filesystem::NewTimestamp::Timestamp( - wasi::filesystem::Datetime { - seconds: ts / 1_000_000_000, - nanoseconds: (ts % 1_000_000_000) as _, - }, - )) + Ok(filesystem::NewTimestamp::Timestamp(filesystem::Datetime { + seconds: ts / 1_000_000_000, + nanoseconds: (ts % 1_000_000_000) as _, + })) } else if now { - Ok(wasi::filesystem::NewTimestamp::Now) + Ok(filesystem::NewTimestamp::Now) } else { - Ok(wasi::filesystem::NewTimestamp::NoChange) + Ok(filesystem::NewTimestamp::NoChange) } } -impl TryFrom for types::Timestamp { +impl TryFrom for types::Timestamp { type Error = types::Errno; fn try_from( - wasi::wall_clock::Datetime { + wall_clock::Datetime { seconds, nanoseconds, - }: wasi::wall_clock::Datetime, + }: wall_clock::Datetime, ) -> Result { types::Timestamp::from(seconds) .checked_mul(1_000_000_000) @@ -406,126 +389,124 @@ impl TryFrom for types::Timestamp { } } -impl From for wasi::filesystem::PathFlags { +impl From for filesystem::PathFlags { fn from(flags: types::Lookupflags) -> Self { if flags.contains(types::Lookupflags::SYMLINK_FOLLOW) { - wasi::filesystem::PathFlags::SYMLINK_FOLLOW + filesystem::PathFlags::SYMLINK_FOLLOW } else { - wasi::filesystem::PathFlags::empty() + filesystem::PathFlags::empty() } } } -impl From for wasi::filesystem::OpenFlags { +impl From for filesystem::OpenFlags { fn from(flags: types::Oflags) -> Self { - let mut out = wasi::filesystem::OpenFlags::empty(); + let mut out = filesystem::OpenFlags::empty(); if flags.contains(types::Oflags::CREAT) { - out |= wasi::filesystem::OpenFlags::CREATE; + out |= filesystem::OpenFlags::CREATE; } if flags.contains(types::Oflags::DIRECTORY) { - out |= wasi::filesystem::OpenFlags::DIRECTORY; + out |= filesystem::OpenFlags::DIRECTORY; } if flags.contains(types::Oflags::EXCL) { - out |= wasi::filesystem::OpenFlags::EXCLUSIVE; + out |= filesystem::OpenFlags::EXCLUSIVE; } if flags.contains(types::Oflags::TRUNC) { - out |= wasi::filesystem::OpenFlags::TRUNCATE; + out |= filesystem::OpenFlags::TRUNCATE; } out } } -impl From for wasi::filesystem::Advice { +impl From for filesystem::Advice { fn from(advice: types::Advice) -> Self { match advice { - types::Advice::Normal => wasi::filesystem::Advice::Normal, - types::Advice::Sequential => wasi::filesystem::Advice::Sequential, - types::Advice::Random => wasi::filesystem::Advice::Random, - types::Advice::Willneed => wasi::filesystem::Advice::WillNeed, - types::Advice::Dontneed => wasi::filesystem::Advice::DontNeed, - types::Advice::Noreuse => wasi::filesystem::Advice::NoReuse, + types::Advice::Normal => filesystem::Advice::Normal, + types::Advice::Sequential => filesystem::Advice::Sequential, + types::Advice::Random => filesystem::Advice::Random, + types::Advice::Willneed => filesystem::Advice::WillNeed, + types::Advice::Dontneed => filesystem::Advice::DontNeed, + types::Advice::Noreuse => filesystem::Advice::NoReuse, } } } -impl TryFrom for types::Filetype { +impl TryFrom for types::Filetype { type Error = anyhow::Error; - fn try_from(ty: wasi::filesystem::DescriptorType) -> Result { + fn try_from(ty: filesystem::DescriptorType) -> Result { match ty { - wasi::filesystem::DescriptorType::RegularFile => Ok(types::Filetype::RegularFile), - wasi::filesystem::DescriptorType::Directory => Ok(types::Filetype::Directory), - wasi::filesystem::DescriptorType::BlockDevice => Ok(types::Filetype::BlockDevice), - wasi::filesystem::DescriptorType::CharacterDevice => { - Ok(types::Filetype::CharacterDevice) - } + filesystem::DescriptorType::RegularFile => Ok(types::Filetype::RegularFile), + filesystem::DescriptorType::Directory => Ok(types::Filetype::Directory), + filesystem::DescriptorType::BlockDevice => Ok(types::Filetype::BlockDevice), + filesystem::DescriptorType::CharacterDevice => Ok(types::Filetype::CharacterDevice), // preview1 never had a FIFO code. - wasi::filesystem::DescriptorType::Fifo => Ok(types::Filetype::Unknown), + filesystem::DescriptorType::Fifo => Ok(types::Filetype::Unknown), // TODO: Add a way to disginguish between FILETYPE_SOCKET_STREAM and // FILETYPE_SOCKET_DGRAM. - wasi::filesystem::DescriptorType::Socket => { + filesystem::DescriptorType::Socket => { bail!("sockets are not currently supported") } - wasi::filesystem::DescriptorType::SymbolicLink => Ok(types::Filetype::SymbolicLink), - wasi::filesystem::DescriptorType::Unknown => Ok(types::Filetype::Unknown), + filesystem::DescriptorType::SymbolicLink => Ok(types::Filetype::SymbolicLink), + filesystem::DescriptorType::Unknown => Ok(types::Filetype::Unknown), } } } -impl From for types::Errno { - fn from(code: wasi::filesystem::ErrorCode) -> Self { +impl From for types::Errno { + fn from(code: filesystem::ErrorCode) -> Self { match code { - wasi::filesystem::ErrorCode::Access => types::Errno::Acces, - wasi::filesystem::ErrorCode::WouldBlock => types::Errno::Again, - wasi::filesystem::ErrorCode::Already => types::Errno::Already, - wasi::filesystem::ErrorCode::BadDescriptor => types::Errno::Badf, - wasi::filesystem::ErrorCode::Busy => types::Errno::Busy, - wasi::filesystem::ErrorCode::Deadlock => types::Errno::Deadlk, - wasi::filesystem::ErrorCode::Quota => types::Errno::Dquot, - wasi::filesystem::ErrorCode::Exist => types::Errno::Exist, - wasi::filesystem::ErrorCode::FileTooLarge => types::Errno::Fbig, - wasi::filesystem::ErrorCode::IllegalByteSequence => types::Errno::Ilseq, - wasi::filesystem::ErrorCode::InProgress => types::Errno::Inprogress, - wasi::filesystem::ErrorCode::Interrupted => types::Errno::Intr, - wasi::filesystem::ErrorCode::Invalid => types::Errno::Inval, - wasi::filesystem::ErrorCode::Io => types::Errno::Io, - wasi::filesystem::ErrorCode::IsDirectory => types::Errno::Isdir, - wasi::filesystem::ErrorCode::Loop => types::Errno::Loop, - wasi::filesystem::ErrorCode::TooManyLinks => types::Errno::Mlink, - wasi::filesystem::ErrorCode::MessageSize => types::Errno::Msgsize, - wasi::filesystem::ErrorCode::NameTooLong => types::Errno::Nametoolong, - wasi::filesystem::ErrorCode::NoDevice => types::Errno::Nodev, - wasi::filesystem::ErrorCode::NoEntry => types::Errno::Noent, - wasi::filesystem::ErrorCode::NoLock => types::Errno::Nolck, - wasi::filesystem::ErrorCode::InsufficientMemory => types::Errno::Nomem, - wasi::filesystem::ErrorCode::InsufficientSpace => types::Errno::Nospc, - wasi::filesystem::ErrorCode::Unsupported => types::Errno::Notsup, - wasi::filesystem::ErrorCode::NotDirectory => types::Errno::Notdir, - wasi::filesystem::ErrorCode::NotEmpty => types::Errno::Notempty, - wasi::filesystem::ErrorCode::NotRecoverable => types::Errno::Notrecoverable, - wasi::filesystem::ErrorCode::NoTty => types::Errno::Notty, - wasi::filesystem::ErrorCode::NoSuchDevice => types::Errno::Nxio, - wasi::filesystem::ErrorCode::Overflow => types::Errno::Overflow, - wasi::filesystem::ErrorCode::NotPermitted => types::Errno::Perm, - wasi::filesystem::ErrorCode::Pipe => types::Errno::Pipe, - wasi::filesystem::ErrorCode::ReadOnly => types::Errno::Rofs, - wasi::filesystem::ErrorCode::InvalidSeek => types::Errno::Spipe, - wasi::filesystem::ErrorCode::TextFileBusy => types::Errno::Txtbsy, - wasi::filesystem::ErrorCode::CrossDevice => types::Errno::Xdev, + filesystem::ErrorCode::Access => types::Errno::Acces, + filesystem::ErrorCode::WouldBlock => types::Errno::Again, + filesystem::ErrorCode::Already => types::Errno::Already, + filesystem::ErrorCode::BadDescriptor => types::Errno::Badf, + filesystem::ErrorCode::Busy => types::Errno::Busy, + filesystem::ErrorCode::Deadlock => types::Errno::Deadlk, + filesystem::ErrorCode::Quota => types::Errno::Dquot, + filesystem::ErrorCode::Exist => types::Errno::Exist, + filesystem::ErrorCode::FileTooLarge => types::Errno::Fbig, + filesystem::ErrorCode::IllegalByteSequence => types::Errno::Ilseq, + filesystem::ErrorCode::InProgress => types::Errno::Inprogress, + filesystem::ErrorCode::Interrupted => types::Errno::Intr, + filesystem::ErrorCode::Invalid => types::Errno::Inval, + filesystem::ErrorCode::Io => types::Errno::Io, + filesystem::ErrorCode::IsDirectory => types::Errno::Isdir, + filesystem::ErrorCode::Loop => types::Errno::Loop, + filesystem::ErrorCode::TooManyLinks => types::Errno::Mlink, + filesystem::ErrorCode::MessageSize => types::Errno::Msgsize, + filesystem::ErrorCode::NameTooLong => types::Errno::Nametoolong, + filesystem::ErrorCode::NoDevice => types::Errno::Nodev, + filesystem::ErrorCode::NoEntry => types::Errno::Noent, + filesystem::ErrorCode::NoLock => types::Errno::Nolck, + filesystem::ErrorCode::InsufficientMemory => types::Errno::Nomem, + filesystem::ErrorCode::InsufficientSpace => types::Errno::Nospc, + filesystem::ErrorCode::Unsupported => types::Errno::Notsup, + filesystem::ErrorCode::NotDirectory => types::Errno::Notdir, + filesystem::ErrorCode::NotEmpty => types::Errno::Notempty, + filesystem::ErrorCode::NotRecoverable => types::Errno::Notrecoverable, + filesystem::ErrorCode::NoTty => types::Errno::Notty, + filesystem::ErrorCode::NoSuchDevice => types::Errno::Nxio, + filesystem::ErrorCode::Overflow => types::Errno::Overflow, + filesystem::ErrorCode::NotPermitted => types::Errno::Perm, + filesystem::ErrorCode::Pipe => types::Errno::Pipe, + filesystem::ErrorCode::ReadOnly => types::Errno::Rofs, + filesystem::ErrorCode::InvalidSeek => types::Errno::Spipe, + filesystem::ErrorCode::TextFileBusy => types::Errno::Txtbsy, + filesystem::ErrorCode::CrossDevice => types::Errno::Xdev, } } } -impl From for types::Error { - fn from(code: wasi::filesystem::ErrorCode) -> Self { +impl From for types::Error { + fn from(code: filesystem::ErrorCode) -> Self { types::Errno::from(code).into() } } -impl TryFrom for types::Errno { +impl TryFrom for types::Errno { type Error = anyhow::Error; - fn try_from(err: wasi::filesystem::Error) -> Result { + fn try_from(err: filesystem::Error) -> Result { match err.downcast() { Ok(code) => Ok(code.into()), Err(e) => Err(e), @@ -533,10 +514,10 @@ impl TryFrom for types::Errno { } } -impl TryFrom for types::Error { +impl TryFrom for types::Error { type Error = anyhow::Error; - fn try_from(err: wasi::filesystem::Error) -> Result { + fn try_from(err: filesystem::Error) -> Result { match err.downcast() { Ok(code) => Ok(code.into()), Err(e) => Err(e), @@ -642,15 +623,15 @@ fn first_non_empty_iovec<'a>( #[wiggle::async_trait] impl< T: WasiPreview1View - + wasi::environment::Host - + wasi::exit::Host - + wasi::filesystem::Host - + wasi::monotonic_clock::Host - + wasi::poll::Host - + wasi::preopens::Host - + wasi::random::Host - + wasi::streams::Host - + wasi::wall_clock::Host, + + wasi::cli_base::environment::Host + + wasi::cli_base::exit::Host + + wasi::cli_base::preopens::Host + + wasi::filesystem::filesystem::Host + + wasi::poll::poll::Host + + wasi::random::random::Host + + wasi::io::streams::Host + + wasi::clocks::monotonic_clock::Host + + wasi::clocks::wall_clock::Host, > wasi_snapshot_preview1::WasiSnapshotPreview1 for T { #[instrument(skip(self))] @@ -756,12 +737,12 @@ impl< id: types::Clockid, ) -> Result { let res = match id { - types::Clockid::Realtime => wasi::wall_clock::Host::resolution(self) + types::Clockid::Realtime => wall_clock::Host::resolution(self) .await .context("failed to call `wall_clock::resolution`") .map_err(types::Error::trap)? .try_into()?, - types::Clockid::Monotonic => wasi::monotonic_clock::Host::resolution(self) + types::Clockid::Monotonic => monotonic_clock::Host::resolution(self) .await .context("failed to call `monotonic_clock::resolution`") .map_err(types::Error::trap)?, @@ -779,12 +760,12 @@ impl< _precision: types::Timestamp, ) -> Result { let now = match id { - types::Clockid::Realtime => wasi::wall_clock::Host::now(self) + types::Clockid::Realtime => wall_clock::Host::now(self) .await .context("failed to call `wall_clock::now`") .map_err(types::Error::trap)? .try_into()?, - types::Clockid::Monotonic => wasi::monotonic_clock::Host::now(self) + types::Clockid::Monotonic => monotonic_clock::Host::now(self) .await .context("failed to call `monotonic_clock::now`") .map_err(types::Error::trap)?, @@ -918,19 +899,19 @@ impl< .map_err(types::Error::trap)?; let mut fs_flags = types::Fdflags::empty(); let mut fs_rights_base = types::Rights::all(); - if !flags.contains(wasi::filesystem::DescriptorFlags::READ) { + if !flags.contains(filesystem::DescriptorFlags::READ) { fs_rights_base &= !types::Rights::FD_READ; } - if !flags.contains(wasi::filesystem::DescriptorFlags::WRITE) { + if !flags.contains(filesystem::DescriptorFlags::WRITE) { fs_rights_base &= !types::Rights::FD_WRITE; } - if flags.contains(wasi::filesystem::DescriptorFlags::DATA_INTEGRITY_SYNC) { + if flags.contains(filesystem::DescriptorFlags::DATA_INTEGRITY_SYNC) { fs_flags |= types::Fdflags::DSYNC; } - if flags.contains(wasi::filesystem::DescriptorFlags::REQUESTED_WRITE_SYNC) { + if flags.contains(filesystem::DescriptorFlags::REQUESTED_WRITE_SYNC) { fs_flags |= types::Fdflags::RSYNC; } - if flags.contains(wasi::filesystem::DescriptorFlags::FILE_INTEGRITY_SYNC) { + if flags.contains(filesystem::DescriptorFlags::FILE_INTEGRITY_SYNC) { fs_flags |= types::Fdflags::SYNC; } if append { @@ -1002,7 +983,7 @@ impl< }) } Descriptor::PreopenDirectory((fd, _)) | Descriptor::File(File { fd, .. }) => { - let wasi::filesystem::DescriptorStat { + let filesystem::DescriptorStat { device: dev, inode: ino, type_, @@ -1109,7 +1090,7 @@ impl< let (read, end) = if blocking { self.blocking_read(stream, max) } else { - wasi::streams::Host::read(self, stream, max) + streams::Host::read(self, stream, max) } .await .map_err(|_| types::Errno::Io)?; @@ -1124,13 +1105,10 @@ impl< let Some(buf) = first_non_empty_iovec(iovs)? else { return Ok(0) }; - let (read, end) = wasi::streams::Host::read( - self, - stream, - buf.len().try_into().unwrap_or(u64::MAX), - ) - .await - .map_err(|_| types::Errno::Io)?; + let (read, end) = + streams::Host::read(self, stream, buf.len().try_into().unwrap_or(u64::MAX)) + .await + .map_err(|_| types::Errno::Io)?; (buf, read, end) } _ => return Err(types::Errno::Badf.into()), @@ -1172,7 +1150,7 @@ impl< let (read, end) = if blocking { self.blocking_read(stream, max) } else { - wasi::streams::Host::read(self, stream, max) + streams::Host::read(self, stream, max) } .await .map_err(|_| types::Errno::Io)?; @@ -1235,7 +1213,7 @@ impl< let n = if blocking { self.blocking_write(stream, buf) } else { - wasi::streams::Host::write(self, stream, buf) + streams::Host::write(self, stream, buf) } .await .map_err(|_| types::Errno::Io)?; @@ -1249,7 +1227,7 @@ impl< let Some(buf) = first_non_empty_ciovec(ciovs)? else { return Ok(0) }; - wasi::streams::Host::write(self, stream, buf) + streams::Host::write(self, stream, buf) .await .map_err(|_| types::Errno::Io)? } @@ -1283,7 +1261,7 @@ impl< if blocking { self.blocking_write(stream, buf) } else { - wasi::streams::Host::write(self, stream, buf) + streams::Host::write(self, stream, buf) } .await .map_err(|_| types::Errno::Io)? @@ -1359,12 +1337,11 @@ impl< .checked_add_signed(offset) .ok_or(types::Errno::Inval)?, types::Whence::End => { - let wasi::filesystem::DescriptorStat { size, .. } = - self.stat(fd).await.map_err(|e| { - e.try_into() - .context("failed to call `stat`") - .unwrap_or_else(types::Error::trap) - })?; + let filesystem::DescriptorStat { size, .. } = self.stat(fd).await.map_err(|e| { + e.try_into() + .context("failed to call `stat`") + .unwrap_or_else(types::Error::trap) + })?; size.checked_add_signed(offset).ok_or(types::Errno::Inval)? } _ => return Err(types::Errno::Inval.into()), @@ -1411,7 +1388,7 @@ impl< .context("failed to call `read-directory`") .unwrap_or_else(types::Error::trap) })?; - let wasi::filesystem::DescriptorStat { + let filesystem::DescriptorStat { inode: fd_inode, .. } = self.stat(fd).await.map_err(|e| { e.try_into() @@ -1450,12 +1427,11 @@ impl< .into_iter() .zip(3u64..) .map(|(entry, d_next)| { - let wasi::filesystem::DirectoryEntry { inode, type_, name } = - entry.map_err(|e| { - e.try_into() - .context("failed to inspect `read-directory` entry") - .unwrap_or_else(types::Error::trap) - })?; + let filesystem::DirectoryEntry { inode, type_, name } = entry.map_err(|e| { + e.try_into() + .context("failed to inspect `read-directory` entry") + .unwrap_or_else(types::Error::trap) + })?; let d_type = type_.try_into().map_err(types::Error::trap)?; let d_namlen: u32 = name.len().try_into().map_err(|_| types::Errno::Overflow)?; Ok(( @@ -1534,7 +1510,7 @@ impl< ) -> Result { let dirfd = self.get_dir_fd(dirfd).await?; let path = read_string(path)?; - let wasi::filesystem::DescriptorStat { + let filesystem::DescriptorStat { device: dev, inode: ino, type_, @@ -1637,21 +1613,21 @@ impl< ) -> Result { let path = read_string(path)?; - let mut flags = wasi::filesystem::DescriptorFlags::empty(); + let mut flags = filesystem::DescriptorFlags::empty(); if fs_rights_base.contains(types::Rights::FD_READ) { - flags |= wasi::filesystem::DescriptorFlags::READ; + flags |= filesystem::DescriptorFlags::READ; } if fs_rights_base.contains(types::Rights::FD_WRITE) { - flags |= wasi::filesystem::DescriptorFlags::WRITE; + flags |= filesystem::DescriptorFlags::WRITE; } if fdflags.contains(types::Fdflags::SYNC) { - flags |= wasi::filesystem::DescriptorFlags::FILE_INTEGRITY_SYNC; + flags |= filesystem::DescriptorFlags::FILE_INTEGRITY_SYNC; } if fdflags.contains(types::Fdflags::DSYNC) { - flags |= wasi::filesystem::DescriptorFlags::DATA_INTEGRITY_SYNC; + flags |= filesystem::DescriptorFlags::DATA_INTEGRITY_SYNC; } if fdflags.contains(types::Fdflags::RSYNC) { - flags |= wasi::filesystem::DescriptorFlags::REQUESTED_WRITE_SYNC; + flags |= filesystem::DescriptorFlags::REQUESTED_WRITE_SYNC; } let desc = self.transact().await?.get_descriptor(dirfd)?.clone(); @@ -1671,7 +1647,7 @@ impl< path, oflags.into(), flags, - wasi::filesystem::Modes::READABLE | wasi::filesystem::Modes::WRITABLE, + filesystem::Modes::READABLE | filesystem::Modes::WRITABLE, ) .await .map_err(|e| { diff --git a/crates/wasi/src/preview2/preview2/clocks.rs b/crates/wasi/src/preview2/preview2/clocks.rs index d704c646d497..75d2927515eb 100644 --- a/crates/wasi/src/preview2/preview2/clocks.rs +++ b/crates/wasi/src/preview2/preview2/clocks.rs @@ -2,10 +2,10 @@ use crate::preview2::preview2::poll::PollableEntry; use crate::preview2::wasi::{ - monotonic_clock::{self, Instant}, - poll::Pollable, - timezone::{self, Timezone, TimezoneDisplay}, - wall_clock::{self, Datetime}, + clocks::monotonic_clock::{self, Instant}, + clocks::timezone::{self, Timezone, TimezoneDisplay}, + clocks::wall_clock::{self, Datetime}, + poll::poll::Pollable, }; use crate::preview2::WasiView; use cap_std::time::SystemTime; diff --git a/crates/wasi/src/preview2/preview2/env.rs b/crates/wasi/src/preview2/preview2/env.rs index 580a126e2632..b4288fc37f76 100644 --- a/crates/wasi/src/preview2/preview2/env.rs +++ b/crates/wasi/src/preview2/preview2/env.rs @@ -1,7 +1,14 @@ -use crate::preview2::{wasi, WasiView}; +use crate::preview2::wasi::cli_base::environment; +use crate::preview2::wasi::cli_base::preopens; +use crate::preview2::wasi::cli_base::stderr; +use crate::preview2::wasi::cli_base::stdin; +use crate::preview2::wasi::cli_base::stdout; +use crate::preview2::wasi::filesystem::filesystem; +use crate::preview2::wasi::io::streams; +use crate::preview2::WasiView; #[async_trait::async_trait] -impl wasi::environment::Host for T { +impl environment::Host for T { async fn get_environment(&mut self) -> anyhow::Result> { Ok(self.ctx().env.clone()) } @@ -11,31 +18,31 @@ impl wasi::environment::Host for T { } #[async_trait::async_trait] -impl wasi::preopens::Host for T { +impl preopens::Host for T { async fn get_directories( &mut self, - ) -> Result, anyhow::Error> { + ) -> Result, anyhow::Error> { Ok(self.ctx().preopens.clone()) } } #[async_trait::async_trait] -impl wasi::stdin::Host for T { - async fn get_stdin(&mut self) -> Result { +impl stdin::Host for T { + async fn get_stdin(&mut self) -> Result { Ok(self.ctx().stdin) } } #[async_trait::async_trait] -impl wasi::stdout::Host for T { - async fn get_stdout(&mut self) -> Result { +impl stdout::Host for T { + async fn get_stdout(&mut self) -> Result { Ok(self.ctx().stdout) } } #[async_trait::async_trait] -impl wasi::stderr::Host for T { - async fn get_stderr(&mut self) -> Result { +impl stderr::Host for T { + async fn get_stderr(&mut self) -> Result { Ok(self.ctx().stderr) } } diff --git a/crates/wasi/src/preview2/preview2/exit.rs b/crates/wasi/src/preview2/preview2/exit.rs index 164e142eae42..45754d594b13 100644 --- a/crates/wasi/src/preview2/preview2/exit.rs +++ b/crates/wasi/src/preview2/preview2/exit.rs @@ -1,4 +1,4 @@ -use crate::preview2::{wasi::exit, I32Exit, WasiView}; +use crate::preview2::{wasi::cli_base::exit, I32Exit, WasiView}; #[async_trait::async_trait] impl exit::Host for T { diff --git a/crates/wasi/src/preview2/preview2/filesystem.rs b/crates/wasi/src/preview2/preview2/filesystem.rs index bd542ca4c984..73c572314b7c 100644 --- a/crates/wasi/src/preview2/preview2/filesystem.rs +++ b/crates/wasi/src/preview2/preview2/filesystem.rs @@ -1,29 +1,32 @@ use crate::preview2::filesystem::{Dir, File, TableFsExt}; use crate::preview2::stream::TableStreamExt; -use crate::preview2::{wasi, DirPerms, FilePerms, Table, TableError, WasiView}; +use crate::preview2::wasi::clocks::wall_clock; +use crate::preview2::wasi::filesystem::filesystem; +use crate::preview2::wasi::io::streams; +use crate::preview2::{DirPerms, FilePerms, Table, TableError, WasiView}; -use wasi::filesystem::ErrorCode; +use filesystem::ErrorCode; -impl From for wasi::filesystem::Error { - fn from(error: TableError) -> wasi::filesystem::Error { +impl From for filesystem::Error { + fn from(error: TableError) -> filesystem::Error { match error { - TableError::Full => wasi::filesystem::Error::trap(anyhow::anyhow!(error)), + TableError::Full => filesystem::Error::trap(anyhow::anyhow!(error)), TableError::NotPresent | TableError::WrongType => ErrorCode::BadDescriptor.into(), } } } #[async_trait::async_trait] -impl wasi::filesystem::Host for T { +impl filesystem::Host for T { async fn advise( &mut self, - fd: wasi::filesystem::Descriptor, - offset: wasi::filesystem::Filesize, - len: wasi::filesystem::Filesize, - advice: wasi::filesystem::Advice, - ) -> Result<(), wasi::filesystem::Error> { + fd: filesystem::Descriptor, + offset: filesystem::Filesize, + len: filesystem::Filesize, + advice: filesystem::Advice, + ) -> Result<(), filesystem::Error> { + use filesystem::Advice; use system_interface::fs::{Advice as A, FileIoExt}; - use wasi::filesystem::Advice; let advice = match advice { Advice::Normal => A::Normal, @@ -39,10 +42,7 @@ impl wasi::filesystem::Host for T { Ok(()) } - async fn sync_data( - &mut self, - fd: wasi::filesystem::Descriptor, - ) -> Result<(), wasi::filesystem::Error> { + async fn sync_data(&mut self, fd: filesystem::Descriptor) -> Result<(), filesystem::Error> { let table = self.table(); if table.is_file(fd) { match table.get_file(fd)?.file.sync_data() { @@ -72,11 +72,11 @@ impl wasi::filesystem::Host for T { async fn get_flags( &mut self, - fd: wasi::filesystem::Descriptor, - ) -> Result { + fd: filesystem::Descriptor, + ) -> Result { use cap_std::io_lifetimes::AsFilelike; + use filesystem::DescriptorFlags; use system_interface::fs::{FdFlags, GetSetFdFlags}; - use wasi::filesystem::DescriptorFlags; fn get_from_fdflags(f: impl AsFilelike) -> std::io::Result { let flags = f.as_filelike().get_fd_flags()?; @@ -121,15 +121,15 @@ impl wasi::filesystem::Host for T { async fn get_type( &mut self, - fd: wasi::filesystem::Descriptor, - ) -> Result { + fd: filesystem::Descriptor, + ) -> Result { let table = self.table(); if table.is_file(fd) { let meta = table.get_file(fd)?.file.metadata()?; Ok(descriptortype_from(meta.file_type())) } else if table.is_dir(fd) { - Ok(wasi::filesystem::DescriptorType::Directory) + Ok(filesystem::DescriptorType::Directory) } else { Err(ErrorCode::BadDescriptor.into()) } @@ -137,9 +137,9 @@ impl wasi::filesystem::Host for T { async fn set_size( &mut self, - fd: wasi::filesystem::Descriptor, - size: wasi::filesystem::Filesize, - ) -> Result<(), wasi::filesystem::Error> { + fd: filesystem::Descriptor, + size: filesystem::Filesize, + ) -> Result<(), filesystem::Error> { let f = self.table().get_file(fd)?; if !f.perms.contains(FilePerms::WRITE) { Err(ErrorCode::NotPermitted)?; @@ -150,10 +150,10 @@ impl wasi::filesystem::Host for T { async fn set_times( &mut self, - fd: wasi::filesystem::Descriptor, - atim: wasi::filesystem::NewTimestamp, - mtim: wasi::filesystem::NewTimestamp, - ) -> Result<(), wasi::filesystem::Error> { + fd: filesystem::Descriptor, + atim: filesystem::NewTimestamp, + mtim: filesystem::NewTimestamp, + ) -> Result<(), filesystem::Error> { use fs_set_times::SetTimes; let table = self.table(); @@ -182,10 +182,10 @@ impl wasi::filesystem::Host for T { async fn read( &mut self, - fd: wasi::filesystem::Descriptor, - len: wasi::filesystem::Filesize, - offset: wasi::filesystem::Filesize, - ) -> Result<(Vec, bool), wasi::filesystem::Error> { + fd: filesystem::Descriptor, + len: filesystem::Filesize, + offset: filesystem::Filesize, + ) -> Result<(Vec, bool), filesystem::Error> { use std::io::IoSliceMut; use system_interface::fs::FileIoExt; @@ -213,10 +213,10 @@ impl wasi::filesystem::Host for T { async fn write( &mut self, - fd: wasi::filesystem::Descriptor, + fd: filesystem::Descriptor, buf: Vec, - offset: wasi::filesystem::Filesize, - ) -> Result { + offset: filesystem::Filesize, + ) -> Result { use std::io::IoSlice; use system_interface::fs::FileIoExt; @@ -228,13 +228,13 @@ impl wasi::filesystem::Host for T { let bytes_written = f.file.write_vectored_at(&[IoSlice::new(&buf)], offset)?; - Ok(wasi::filesystem::Filesize::try_from(bytes_written).expect("usize fits in Filesize")) + Ok(filesystem::Filesize::try_from(bytes_written).expect("usize fits in Filesize")) } async fn read_directory( &mut self, - fd: wasi::filesystem::Descriptor, - ) -> Result { + fd: filesystem::Descriptor, + ) -> Result { use cap_fs_ext::{DirEntryExt, MetadataExt}; let table = self.table_mut(); @@ -262,7 +262,7 @@ impl wasi::filesystem::Host for T { .file_name() .into_string() .map_err(|_| ReaddirError::IllegalSequence)?; - Ok(wasi::filesystem::DirectoryEntry { inode, type_, name }) + Ok(filesystem::DirectoryEntry { inode, type_, name }) }); // On windows, filter out files like `C:\DumpStack.log.tmp` which we // can't get full metadata for. @@ -280,7 +280,7 @@ impl wasi::filesystem::Host for T { }); let entries = entries.map(|r| match r { Ok(r) => Ok(r), - Err(ReaddirError::Io(e)) => Err(wasi::filesystem::Error::from(e)), + Err(ReaddirError::Io(e)) => Err(filesystem::Error::from(e)), Err(ReaddirError::IllegalSequence) => Err(ErrorCode::IllegalByteSequence.into()), }); Ok(table.push_readdir(ReaddirIterator::new(entries))?) @@ -288,8 +288,8 @@ impl wasi::filesystem::Host for T { async fn read_directory_entry( &mut self, - stream: wasi::filesystem::DirectoryEntryStream, - ) -> Result, wasi::filesystem::Error> { + stream: filesystem::DirectoryEntryStream, + ) -> Result, filesystem::Error> { let table = self.table(); let readdir = table.get_readdir(stream)?; readdir.next() @@ -297,16 +297,13 @@ impl wasi::filesystem::Host for T { async fn drop_directory_entry_stream( &mut self, - stream: wasi::filesystem::DirectoryEntryStream, + stream: filesystem::DirectoryEntryStream, ) -> anyhow::Result<()> { self.table_mut().delete_readdir(stream)?; Ok(()) } - async fn sync( - &mut self, - fd: wasi::filesystem::Descriptor, - ) -> Result<(), wasi::filesystem::Error> { + async fn sync(&mut self, fd: filesystem::Descriptor) -> Result<(), filesystem::Error> { let table = self.table(); if table.is_file(fd) { match table.get_file(fd)?.file.sync_all() { @@ -336,9 +333,9 @@ impl wasi::filesystem::Host for T { async fn create_directory_at( &mut self, - fd: wasi::filesystem::Descriptor, + fd: filesystem::Descriptor, path: String, - ) -> Result<(), wasi::filesystem::Error> { + ) -> Result<(), filesystem::Error> { let table = self.table(); let d = table.get_dir(fd)?; if !d.perms.contains(DirPerms::MUTATE) { @@ -350,8 +347,8 @@ impl wasi::filesystem::Host for T { async fn stat( &mut self, - fd: wasi::filesystem::Descriptor, - ) -> Result { + fd: filesystem::Descriptor, + ) -> Result { let table = self.table(); if table.is_file(fd) { let f = table.get_file(fd)?; @@ -374,10 +371,10 @@ impl wasi::filesystem::Host for T { async fn stat_at( &mut self, - fd: wasi::filesystem::Descriptor, - path_flags: wasi::filesystem::PathFlags, + fd: filesystem::Descriptor, + path_flags: filesystem::PathFlags, path: String, - ) -> Result { + ) -> Result { let table = self.table(); let d = table.get_dir(fd)?; if !d.perms.contains(DirPerms::READ) { @@ -394,12 +391,12 @@ impl wasi::filesystem::Host for T { async fn set_times_at( &mut self, - fd: wasi::filesystem::Descriptor, - path_flags: wasi::filesystem::PathFlags, + fd: filesystem::Descriptor, + path_flags: filesystem::PathFlags, path: String, - atim: wasi::filesystem::NewTimestamp, - mtim: wasi::filesystem::NewTimestamp, - ) -> Result<(), wasi::filesystem::Error> { + atim: filesystem::NewTimestamp, + mtim: filesystem::NewTimestamp, + ) -> Result<(), filesystem::Error> { use cap_fs_ext::DirExt; let table = self.table(); @@ -427,13 +424,13 @@ impl wasi::filesystem::Host for T { async fn link_at( &mut self, - fd: wasi::filesystem::Descriptor, + fd: filesystem::Descriptor, // TODO delete the path flags from this function - old_path_flags: wasi::filesystem::PathFlags, + old_path_flags: filesystem::PathFlags, old_path: String, - new_descriptor: wasi::filesystem::Descriptor, + new_descriptor: filesystem::Descriptor, new_path: String, - ) -> Result<(), wasi::filesystem::Error> { + ) -> Result<(), filesystem::Error> { let table = self.table(); let old_dir = table.get_dir(fd)?; if !old_dir.perms.contains(DirPerms::MUTATE) { @@ -452,18 +449,18 @@ impl wasi::filesystem::Host for T { async fn open_at( &mut self, - fd: wasi::filesystem::Descriptor, - path_flags: wasi::filesystem::PathFlags, + fd: filesystem::Descriptor, + path_flags: filesystem::PathFlags, path: String, - oflags: wasi::filesystem::OpenFlags, - flags: wasi::filesystem::DescriptorFlags, + oflags: filesystem::OpenFlags, + flags: filesystem::DescriptorFlags, // TODO: These are the permissions to use when creating a new file. // Not implemented yet. - _mode: wasi::filesystem::Modes, - ) -> Result { + _mode: filesystem::Modes, + ) -> Result { use cap_fs_ext::{FollowSymlinks, OpenOptionsFollowExt, OpenOptionsMaybeDirExt}; + use filesystem::{DescriptorFlags, OpenFlags}; use system_interface::fs::{FdFlags, GetSetFdFlags}; - use wasi::filesystem::{DescriptorFlags, OpenFlags}; let table = self.table_mut(); if table.is_file(fd) { @@ -548,7 +545,7 @@ impl wasi::filesystem::Host for T { } } - async fn drop_descriptor(&mut self, fd: wasi::filesystem::Descriptor) -> anyhow::Result<()> { + async fn drop_descriptor(&mut self, fd: filesystem::Descriptor) -> anyhow::Result<()> { let table = self.table_mut(); if table.delete_file(fd).is_err() { table.delete_dir(fd)?; @@ -558,9 +555,9 @@ impl wasi::filesystem::Host for T { async fn readlink_at( &mut self, - fd: wasi::filesystem::Descriptor, + fd: filesystem::Descriptor, path: String, - ) -> Result { + ) -> Result { let table = self.table(); let d = table.get_dir(fd)?; if !d.perms.contains(DirPerms::READ) { @@ -575,9 +572,9 @@ impl wasi::filesystem::Host for T { async fn remove_directory_at( &mut self, - fd: wasi::filesystem::Descriptor, + fd: filesystem::Descriptor, path: String, - ) -> Result<(), wasi::filesystem::Error> { + ) -> Result<(), filesystem::Error> { let table = self.table(); let d = table.get_dir(fd)?; if !d.perms.contains(DirPerms::MUTATE) { @@ -588,11 +585,11 @@ impl wasi::filesystem::Host for T { async fn rename_at( &mut self, - fd: wasi::filesystem::Descriptor, + fd: filesystem::Descriptor, old_path: String, - new_fd: wasi::filesystem::Descriptor, + new_fd: filesystem::Descriptor, new_path: String, - ) -> Result<(), wasi::filesystem::Error> { + ) -> Result<(), filesystem::Error> { let table = self.table(); let old_dir = table.get_dir(fd)?; if !old_dir.perms.contains(DirPerms::MUTATE) { @@ -608,10 +605,10 @@ impl wasi::filesystem::Host for T { async fn symlink_at( &mut self, - fd: wasi::filesystem::Descriptor, + fd: filesystem::Descriptor, src_path: String, dest_path: String, - ) -> Result<(), wasi::filesystem::Error> { + ) -> Result<(), filesystem::Error> { // On windows, Dir.symlink is provided by DirExt #[cfg(windows)] use cap_fs_ext::DirExt; @@ -627,9 +624,9 @@ impl wasi::filesystem::Host for T { async fn unlink_file_at( &mut self, - fd: wasi::filesystem::Descriptor, + fd: filesystem::Descriptor, path: String, - ) -> Result<(), wasi::filesystem::Error> { + ) -> Result<(), filesystem::Error> { use cap_fs_ext::DirExt; let table = self.table(); @@ -643,74 +640,68 @@ impl wasi::filesystem::Host for T { async fn access_at( &mut self, - _fd: wasi::filesystem::Descriptor, - _path_flags: wasi::filesystem::PathFlags, + _fd: filesystem::Descriptor, + _path_flags: filesystem::PathFlags, _path: String, - _access: wasi::filesystem::AccessType, - ) -> Result<(), wasi::filesystem::Error> { + _access: filesystem::AccessType, + ) -> Result<(), filesystem::Error> { todo!() } async fn change_file_permissions_at( &mut self, - _fd: wasi::filesystem::Descriptor, - _path_flags: wasi::filesystem::PathFlags, + _fd: filesystem::Descriptor, + _path_flags: filesystem::PathFlags, _path: String, - _mode: wasi::filesystem::Modes, - ) -> Result<(), wasi::filesystem::Error> { + _mode: filesystem::Modes, + ) -> Result<(), filesystem::Error> { todo!() } async fn change_directory_permissions_at( &mut self, - _fd: wasi::filesystem::Descriptor, - _path_flags: wasi::filesystem::PathFlags, + _fd: filesystem::Descriptor, + _path_flags: filesystem::PathFlags, _path: String, - _mode: wasi::filesystem::Modes, - ) -> Result<(), wasi::filesystem::Error> { + _mode: filesystem::Modes, + ) -> Result<(), filesystem::Error> { todo!() } - async fn lock_shared( - &mut self, - _fd: wasi::filesystem::Descriptor, - ) -> Result<(), wasi::filesystem::Error> { + async fn lock_shared(&mut self, _fd: filesystem::Descriptor) -> Result<(), filesystem::Error> { todo!() } async fn lock_exclusive( &mut self, - _fd: wasi::filesystem::Descriptor, - ) -> Result<(), wasi::filesystem::Error> { + _fd: filesystem::Descriptor, + ) -> Result<(), filesystem::Error> { todo!() } async fn try_lock_shared( &mut self, - _fd: wasi::filesystem::Descriptor, - ) -> Result<(), wasi::filesystem::Error> { + _fd: filesystem::Descriptor, + ) -> Result<(), filesystem::Error> { todo!() } async fn try_lock_exclusive( &mut self, - _fd: wasi::filesystem::Descriptor, - ) -> Result<(), wasi::filesystem::Error> { + _fd: filesystem::Descriptor, + ) -> Result<(), filesystem::Error> { todo!() } - async fn unlock( - &mut self, - _fd: wasi::filesystem::Descriptor, - ) -> Result<(), wasi::filesystem::Error> { + async fn unlock(&mut self, _fd: filesystem::Descriptor) -> Result<(), filesystem::Error> { todo!() } async fn read_via_stream( &mut self, - fd: wasi::filesystem::Descriptor, - offset: wasi::filesystem::Filesize, - ) -> anyhow::Result { + fd: filesystem::Descriptor, + offset: filesystem::Filesize, + ) -> anyhow::Result { // FIXME: this skips the perm check. We can't return a NotPermitted // error code here. Do we need to change the interface? @@ -731,9 +722,9 @@ impl wasi::filesystem::Host for T { async fn write_via_stream( &mut self, - fd: wasi::filesystem::Descriptor, - offset: wasi::filesystem::Filesize, - ) -> anyhow::Result { + fd: filesystem::Descriptor, + offset: filesystem::Filesize, + ) -> anyhow::Result { // Trap if fd lookup fails: let f = self.table().get_file(fd)?; @@ -751,8 +742,8 @@ impl wasi::filesystem::Host for T { async fn append_via_stream( &mut self, - fd: wasi::filesystem::Descriptor, - ) -> anyhow::Result { + fd: filesystem::Descriptor, + ) -> anyhow::Result { // Trap if fd lookup fails: let f = self.table().get_file(fd)?; @@ -770,7 +761,7 @@ impl wasi::filesystem::Host for T { } #[cfg(unix)] -fn from_raw_os_error(err: Option) -> Option { +fn from_raw_os_error(err: Option) -> Option { use rustix::io::Errno as RustixErrno; if err.is_none() { return None; @@ -810,7 +801,7 @@ fn from_raw_os_error(err: Option) -> Option { }) } #[cfg(windows)] -fn from_raw_os_error(raw_os_error: Option) -> Option { +fn from_raw_os_error(raw_os_error: Option) -> Option { use windows_sys::Win32::Foundation; Some(match raw_os_error.map(|code| code as u32) { Some(Foundation::ERROR_FILE_NOT_FOUND) => ErrorCode::NoEntry.into(), @@ -839,8 +830,8 @@ fn from_raw_os_error(raw_os_error: Option) -> Option for wasi::filesystem::Error { - fn from(err: std::io::Error) -> wasi::filesystem::Error { +impl From for filesystem::Error { + fn from(err: std::io::Error) -> filesystem::Error { match from_raw_os_error(err.raw_os_error()) { Some(errno) => errno, None => match err.kind() { @@ -848,31 +839,29 @@ impl From for wasi::filesystem::Error { std::io::ErrorKind::PermissionDenied => ErrorCode::NotPermitted.into(), std::io::ErrorKind::AlreadyExists => ErrorCode::Exist.into(), std::io::ErrorKind::InvalidInput => ErrorCode::Invalid.into(), - _ => { - wasi::filesystem::Error::trap(anyhow::anyhow!(err).context("Unknown OS error")) - } + _ => filesystem::Error::trap(anyhow::anyhow!(err).context("Unknown OS error")), }, } } } -impl From for wasi::filesystem::Error { - fn from(err: cap_rand::Error) -> wasi::filesystem::Error { +impl From for filesystem::Error { + fn from(err: cap_rand::Error) -> filesystem::Error { // I picked Error::Io as a 'reasonable default', FIXME dan is this ok? from_raw_os_error(err.raw_os_error()) - .unwrap_or_else(|| wasi::filesystem::Error::from(ErrorCode::Io)) + .unwrap_or_else(|| filesystem::Error::from(ErrorCode::Io)) } } -impl From for wasi::filesystem::Error { - fn from(_err: std::num::TryFromIntError) -> wasi::filesystem::Error { +impl From for filesystem::Error { + fn from(_err: std::num::TryFromIntError) -> filesystem::Error { ErrorCode::Overflow.into() } } -fn descriptortype_from(ft: cap_std::fs::FileType) -> wasi::filesystem::DescriptorType { +fn descriptortype_from(ft: cap_std::fs::FileType) -> filesystem::DescriptorType { use cap_fs_ext::FileTypeExt; - use wasi::filesystem::DescriptorType; + use filesystem::DescriptorType; if ft.is_dir() { DescriptorType::Directory } else if ft.is_symlink() { @@ -889,10 +878,10 @@ fn descriptortype_from(ft: cap_std::fs::FileType) -> wasi::filesystem::Descripto } fn systemtimespec_from( - t: wasi::filesystem::NewTimestamp, -) -> Result, wasi::filesystem::Error> { + t: filesystem::NewTimestamp, +) -> Result, filesystem::Error> { + use filesystem::NewTimestamp; use fs_set_times::SystemTimeSpec; - use wasi::filesystem::NewTimestamp; match t { NewTimestamp::NoChange => Ok(None), NewTimestamp::Now => Ok(Some(SystemTimeSpec::SymbolicNow)), @@ -900,23 +889,21 @@ fn systemtimespec_from( } } -fn systemtime_from( - t: wasi::wall_clock::Datetime, -) -> Result { +fn systemtime_from(t: wall_clock::Datetime) -> Result { use std::time::{Duration, SystemTime}; SystemTime::UNIX_EPOCH .checked_add(Duration::new(t.seconds, t.nanoseconds)) .ok_or_else(|| ErrorCode::Overflow.into()) } -fn datetime_from(t: std::time::SystemTime) -> wasi::wall_clock::Datetime { +fn datetime_from(t: std::time::SystemTime) -> wall_clock::Datetime { // FIXME make this infallible or handle errors properly - wasi::wall_clock::Datetime::try_from(cap_std::time::SystemTime::from_std(t)).unwrap() + wall_clock::Datetime::try_from(cap_std::time::SystemTime::from_std(t)).unwrap() } -fn descriptorstat_from(meta: cap_std::fs::Metadata) -> wasi::filesystem::DescriptorStat { +fn descriptorstat_from(meta: cap_std::fs::Metadata) -> filesystem::DescriptorStat { use cap_fs_ext::MetadataExt; - wasi::filesystem::DescriptorStat { + filesystem::DescriptorStat { // FIXME didn't we agree that the wit could be changed to make the device and ino fields // optional? device: meta.dev(), @@ -928,35 +915,35 @@ fn descriptorstat_from(meta: cap_std::fs::Metadata) -> wasi::filesystem::Descrip data_access_timestamp: meta .accessed() .map(|t| datetime_from(t.into_std())) - .unwrap_or(wasi::wall_clock::Datetime { + .unwrap_or(wall_clock::Datetime { seconds: 0, nanoseconds: 0, }), data_modification_timestamp: meta .modified() .map(|t| datetime_from(t.into_std())) - .unwrap_or(wasi::wall_clock::Datetime { + .unwrap_or(wall_clock::Datetime { seconds: 0, nanoseconds: 0, }), status_change_timestamp: meta .created() .map(|t| datetime_from(t.into_std())) - .unwrap_or(wasi::wall_clock::Datetime { + .unwrap_or(wall_clock::Datetime { seconds: 0, nanoseconds: 0, }), } } -fn symlink_follow(path_flags: wasi::filesystem::PathFlags) -> bool { - path_flags.contains(wasi::filesystem::PathFlags::SYMLINK_FOLLOW) +fn symlink_follow(path_flags: filesystem::PathFlags) -> bool { + path_flags.contains(filesystem::PathFlags::SYMLINK_FOLLOW) } pub(crate) struct ReaddirIterator( std::sync::Mutex< Box< - dyn Iterator> + dyn Iterator> + Send + 'static, >, @@ -965,19 +952,17 @@ pub(crate) struct ReaddirIterator( impl ReaddirIterator { fn new( - i: impl Iterator> - + Send - + 'static, + i: impl Iterator> + Send + 'static, ) -> Self { ReaddirIterator(std::sync::Mutex::new(Box::new(i))) } - fn next(&self) -> Result, wasi::filesystem::Error> { + fn next(&self) -> Result, filesystem::Error> { self.0.lock().unwrap().next().transpose() } } impl IntoIterator for ReaddirIterator { - type Item = Result; + type Item = Result; type IntoIter = Box>; fn into_iter(self) -> Self::IntoIter { diff --git a/crates/wasi/src/preview2/preview2/io.rs b/crates/wasi/src/preview2/preview2/io.rs index 407ae2c54d1d..4e9971f2dc05 100644 --- a/crates/wasi/src/preview2/preview2/io.rs +++ b/crates/wasi/src/preview2/preview2/io.rs @@ -1,8 +1,8 @@ use crate::preview2::{ preview2::poll::PollableEntry, stream::TableStreamExt, - wasi::poll::Pollable, - wasi::streams::{self, InputStream, OutputStream, StreamError}, + wasi::io::streams::{self, InputStream, OutputStream, StreamError}, + wasi::poll::poll::Pollable, TableError, WasiView, }; use anyhow::anyhow; diff --git a/crates/wasi/src/preview2/preview2/poll.rs b/crates/wasi/src/preview2/preview2/poll.rs index 311c36ab1406..d3b9380c71bc 100644 --- a/crates/wasi/src/preview2/preview2/poll.rs +++ b/crates/wasi/src/preview2/preview2/poll.rs @@ -1,9 +1,8 @@ use crate::preview2::{ stream::TableStreamExt, - wasi, - wasi::monotonic_clock::Instant, - wasi::poll::Pollable, - wasi::streams::{InputStream, OutputStream}, + wasi::clocks::monotonic_clock::Instant, + wasi::io::streams::{InputStream, OutputStream}, + wasi::poll::poll::{self, Pollable}, WasiView, }; @@ -29,7 +28,7 @@ pub(crate) enum PollableEntry { // this PR. #[async_trait::async_trait] -impl wasi::poll::Host for T { +impl poll::Host for T { async fn drop_pollable(&mut self, pollable: Pollable) -> anyhow::Result<()> { self.table_mut().delete::(pollable)?; Ok(()) diff --git a/crates/wasi/src/preview2/preview2/random.rs b/crates/wasi/src/preview2/preview2/random.rs index f94afed84a28..2cabe352b260 100644 --- a/crates/wasi/src/preview2/preview2/random.rs +++ b/crates/wasi/src/preview2/preview2/random.rs @@ -1,9 +1,11 @@ +use crate::preview2::wasi::random::insecure; +use crate::preview2::wasi::random::insecure_seed; +use crate::preview2::wasi::random::random; +use crate::preview2::WasiView; use cap_rand::{distributions::Standard, Rng}; -use crate::preview2::{wasi, WasiView}; - #[async_trait::async_trait] -impl wasi::random::Host for T { +impl random::Host for T { async fn get_random_bytes(&mut self, len: u64) -> anyhow::Result> { Ok((&mut self.ctx_mut().random) .sample_iter(Standard) @@ -17,7 +19,7 @@ impl wasi::random::Host for T { } #[async_trait::async_trait] -impl wasi::insecure_random::Host for T { +impl insecure::Host for T { async fn get_insecure_random_bytes(&mut self, len: u64) -> anyhow::Result> { Ok((&mut self.ctx_mut().insecure_random) .sample_iter(Standard) @@ -31,7 +33,7 @@ impl wasi::insecure_random::Host for T { } #[async_trait::async_trait] -impl wasi::insecure_random_seed::Host for T { +impl insecure_seed::Host for T { async fn insecure_seed(&mut self) -> anyhow::Result<(u64, u64)> { let seed: u128 = self.ctx_mut().insecure_random_seed; Ok((seed as u64, (seed >> 64) as u64)) diff --git a/crates/wasi/src/preview2/wasi/command.rs b/crates/wasi/src/preview2/wasi/command.rs index 6bc26f20bfb8..9dc472536ca3 100644 --- a/crates/wasi/src/preview2/wasi/command.rs +++ b/crates/wasi/src/preview2/wasi/command.rs @@ -1,8 +1,7 @@ use crate::preview2::WasiView; wasmtime::component::bindgen!({ - path: "wit", - world: "command", + world: "wasi:preview/command", tracing: true, async: true, trappable_error_type: { @@ -10,35 +9,35 @@ wasmtime::component::bindgen!({ "streams"::"stream-error": Error, }, with: { - "filesystem": crate::preview2::wasi::filesystem, - "monotonic_clock": crate::preview2::wasi::monotonic_clock, - "poll": crate::preview2::wasi::poll, - "streams": crate::preview2::wasi::streams, - "timezone": crate::preview2::wasi::timezone, - "wall_clock": crate::preview2::wasi::wall_clock, - "random": crate::preview2::wasi::random, - "environment": crate::preview2::wasi::environment, - "exit": crate::preview2::wasi::exit, - "preopens": crate::preview2::wasi::preopens, - "stdin": crate::preview2::wasi::stdin, - "stdout": crate::preview2::wasi::stdout, - "stderr": crate::preview2::wasi::stderr, + "wasi:filesystem/filesystem": crate::preview2::wasi::filesystem::filesystem, + "wasi:clocks/monotonic_clock": crate::preview2::wasi::clocks::monotonic_clock, + "wasi:poll/poll": crate::preview2::wasi::poll::poll, + "wasi:io/streams": crate::preview2::wasi::io::streams, + "wasi:clocks/timezone": crate::preview2::wasi::clocks::timezone, + "wasi:clocks/wall_clock": crate::preview2::wasi::clocks::wall_clock, + "wasi:random/random": crate::preview2::wasi::random::random, + "wasi:cli_base/environment": crate::preview2::wasi::cli_base::environment, + "wasi:cli_base/exit": crate::preview2::wasi::cli_base::exit, + "wasi:cli_base/preopens": crate::preview2::wasi::cli_base::preopens, + "wasi:cli_base/stdin": crate::preview2::wasi::cli_base::stdin, + "wasi:cli_base/stdout": crate::preview2::wasi::cli_base::stdout, + "wasi:cli_base/stderr": crate::preview2::wasi::cli_base::stderr, }, }); pub fn add_to_linker(l: &mut wasmtime::component::Linker) -> anyhow::Result<()> { - crate::preview2::wasi::wall_clock::add_to_linker(l, |t| t)?; - crate::preview2::wasi::monotonic_clock::add_to_linker(l, |t| t)?; - crate::preview2::wasi::timezone::add_to_linker(l, |t| t)?; - crate::preview2::wasi::filesystem::add_to_linker(l, |t| t)?; - crate::preview2::wasi::poll::add_to_linker(l, |t| t)?; - crate::preview2::wasi::streams::add_to_linker(l, |t| t)?; - crate::preview2::wasi::random::add_to_linker(l, |t| t)?; - crate::preview2::wasi::exit::add_to_linker(l, |t| t)?; - crate::preview2::wasi::environment::add_to_linker(l, |t| t)?; - crate::preview2::wasi::preopens::add_to_linker(l, |t| t)?; - crate::preview2::wasi::stdin::add_to_linker(l, |t| t)?; - crate::preview2::wasi::stdout::add_to_linker(l, |t| t)?; - crate::preview2::wasi::stderr::add_to_linker(l, |t| t)?; + crate::preview2::wasi::clocks::wall_clock::add_to_linker(l, |t| t)?; + crate::preview2::wasi::clocks::monotonic_clock::add_to_linker(l, |t| t)?; + crate::preview2::wasi::clocks::timezone::add_to_linker(l, |t| t)?; + crate::preview2::wasi::filesystem::filesystem::add_to_linker(l, |t| t)?; + crate::preview2::wasi::poll::poll::add_to_linker(l, |t| t)?; + crate::preview2::wasi::io::streams::add_to_linker(l, |t| t)?; + crate::preview2::wasi::random::random::add_to_linker(l, |t| t)?; + crate::preview2::wasi::cli_base::exit::add_to_linker(l, |t| t)?; + crate::preview2::wasi::cli_base::environment::add_to_linker(l, |t| t)?; + crate::preview2::wasi::cli_base::preopens::add_to_linker(l, |t| t)?; + crate::preview2::wasi::cli_base::stdin::add_to_linker(l, |t| t)?; + crate::preview2::wasi::cli_base::stdout::add_to_linker(l, |t| t)?; + crate::preview2::wasi::cli_base::stderr::add_to_linker(l, |t| t)?; Ok(()) } diff --git a/crates/wasi/src/preview2/wasi/mod.rs b/crates/wasi/src/preview2/wasi/mod.rs index 40aa9af2d476..aa1a1708a5c1 100644 --- a/crates/wasi/src/preview2/wasi/mod.rs +++ b/crates/wasi/src/preview2/wasi/mod.rs @@ -3,21 +3,21 @@ pub mod command; wasmtime::component::bindgen!({ path: "wit", interfaces: " - import wall-clock: clocks.wall-clock - import monotonic-clock: clocks.monotonic-clock - import timezone: clocks.timezone - import filesystem: filesystem.filesystem - import random: random.random - import insecure-random: random.insecure - import insecure-random-seed: random.insecure-seed - import poll: poll.poll - import streams: io.streams - import environment: wasi-cli-base.environment - import preopens: wasi-cli-base.preopens - import stdin: wasi-cli-base.stdio.stdin - import stdout: wasi-cli-base.stdio.stdout - import stderr: wasi-cli-base.stdio.stderr - import exit: wasi-cli-base.exit + import wasi:clocks/wall-clock + import wasi:clocks/monotonic-clock + import wasi:clocks/timezone + import wasi:filesystem/filesystem + import wasi:random/random + import wasi:random/insecure + import wasi:random/insecure-seed + import wasi:poll/poll + import wasi:io/streams + import wasi:cli-base/environment + import wasi:cli-base/preopens + import wasi:cli-base/exit + import wasi:cli-base/stdin + import wasi:cli-base/stdout + import wasi:cli-base/stderr ", tracing: true, async: true, @@ -26,3 +26,5 @@ wasmtime::component::bindgen!({ "streams"::"stream-error": Error, } }); + +pub use wasi::*; diff --git a/crates/wasi/wit/command.wit b/crates/wasi/wit/command.wit deleted file mode 100644 index 29845b60e887..000000000000 --- a/crates/wasi/wit/command.wit +++ /dev/null @@ -1,26 +0,0 @@ -default world command { - import wall-clock: clocks.wall-clock - import monotonic-clock: clocks.monotonic-clock - import timezone: clocks.timezone - import filesystem: filesystem.filesystem - import instance-network: sockets.instance-network - import ip-name-lookup: sockets.ip-name-lookup - import network: sockets.network - import tcp-create-socket: sockets.tcp-create-socket - import tcp: sockets.tcp - import udp-create-socket: sockets.udp-create-socket - import udp: sockets.udp - import random: random.random - import insecure-random: random.insecure - import insecure-random-seed: random.insecure-seed - import poll: poll.poll - import streams: io.streams - import environment: wasi-cli-base.environment - import preopens: wasi-cli-base.preopens - import stdin: wasi-cli-base.stdio.stdin - import stdout: wasi-cli-base.stdio.stdout - import stderr: wasi-cli-base.stdio.stderr - import exit: wasi-cli-base.exit - - export run: func() -> result -} diff --git a/crates/wasi/wit/deps/clocks/monotonic-clock.wit b/crates/wasi/wit/deps/clocks/monotonic-clock.wit index 42e2981f579a..50eb4de111af 100644 --- a/crates/wasi/wit/deps/clocks/monotonic-clock.wit +++ b/crates/wasi/wit/deps/clocks/monotonic-clock.wit @@ -1,3 +1,5 @@ +package wasi:clocks + /// WASI Monotonic Clock is a clock API intended to let users measure elapsed /// time. /// @@ -8,8 +10,8 @@ /// successive reads of the clock will produce non-decreasing values. /// /// It is intended for measuring elapsed time. -default interface monotonic-clock { - use poll.poll.{pollable} +interface monotonic-clock { + use wasi:poll/poll.{pollable} /// A timestamp in nanoseconds. type instant = u64 diff --git a/crates/wasi/wit/deps/clocks/timezone.wit b/crates/wasi/wit/deps/clocks/timezone.wit index 63f99cc401b1..2b6855668e1d 100644 --- a/crates/wasi/wit/deps/clocks/timezone.wit +++ b/crates/wasi/wit/deps/clocks/timezone.wit @@ -1,5 +1,7 @@ -default interface timezone { - use pkg.wall-clock.{datetime} +package wasi:clocks + +interface timezone { + use wall-clock.{datetime} /// A timezone. /// diff --git a/crates/wasi/wit/deps/clocks/wall-clock.wit b/crates/wasi/wit/deps/clocks/wall-clock.wit index 89c5a75da68b..6137724f60b1 100644 --- a/crates/wasi/wit/deps/clocks/wall-clock.wit +++ b/crates/wasi/wit/deps/clocks/wall-clock.wit @@ -1,3 +1,5 @@ +package wasi:clocks + /// WASI Wall Clock is a clock API intended to let users query the current /// time. The name "wall" makes an analogy to a "clock on the wall", which /// is not necessarily monotonic as it may be reset. @@ -12,7 +14,7 @@ /// monotonic, making it unsuitable for measuring elapsed time. /// /// It is intended for reporting the current date and time for humans. -default interface wall-clock { +interface wall-clock { /// A time and date in seconds plus nanoseconds. record datetime { seconds: u64, diff --git a/crates/wasi/wit/deps/filesystem/filesystem.wit b/crates/wasi/wit/deps/filesystem/filesystem.wit index a5716427829a..2477264a7367 100644 --- a/crates/wasi/wit/deps/filesystem/filesystem.wit +++ b/crates/wasi/wit/deps/filesystem/filesystem.wit @@ -1,3 +1,5 @@ +package wasi:filesystem + /// WASI filesystem is a filesystem API primarily intended to let users run WASI /// programs that access their files on their existing filesystems, without /// significant overhead. @@ -17,9 +19,9 @@ /// `..` and symbolic link steps, reaches a directory outside of the base /// directory, or reaches a symlink to an absolute or rooted path in the /// underlying filesystem, the function fails with `error-code::not-permitted`. -default interface filesystem { - use io.streams.{input-stream, output-stream} - use clocks.wall-clock.{datetime} +interface filesystem { + use wasi:io/streams.{input-stream, output-stream} + use wasi:clocks/wall-clock.{datetime} /// File size or length of a region within a file. type filesize = u64 diff --git a/crates/wasi/wit/deps/http/incoming-handler.wit b/crates/wasi/wit/deps/http/incoming-handler.wit index 1ecff0aa5f5b..d0e270465593 100644 --- a/crates/wasi/wit/deps/http/incoming-handler.wit +++ b/crates/wasi/wit/deps/http/incoming-handler.wit @@ -6,8 +6,8 @@ // `wasi:http/outgoing-handler` into a single `wasi:http/handler` interface // that takes a `request` parameter and returns a `response` result. // -default interface incoming-handler { - use pkg.types.{incoming-request, response-outparam} +interface incoming-handler { + use types.{incoming-request, response-outparam} // The `handle` function takes an outparam instead of returning its response // so that the component may stream its response while streaming any other diff --git a/crates/wasi/wit/deps/http/outgoing-handler.wit b/crates/wasi/wit/deps/http/outgoing-handler.wit index abe812ffaba7..06c8e469f95b 100644 --- a/crates/wasi/wit/deps/http/outgoing-handler.wit +++ b/crates/wasi/wit/deps/http/outgoing-handler.wit @@ -5,8 +5,8 @@ // `wasi:http/outgoing-handler` into a single `wasi:http/handler` interface // that takes a `request` parameter and returns a `response` result. // -default interface outgoing-handler { - use pkg.types.{outgoing-request, request-options, future-incoming-response} +interface outgoing-handler { + use types.{outgoing-request, request-options, future-incoming-response} // The parameter and result types of the `handle` function allow the caller // to concurrently stream the bodies of the outgoing request and the incoming diff --git a/crates/wasi/wit/deps/http/types.wit b/crates/wasi/wit/deps/http/types.wit index bdcf79737273..ee4227f423a8 100644 --- a/crates/wasi/wit/deps/http/types.wit +++ b/crates/wasi/wit/deps/http/types.wit @@ -1,10 +1,12 @@ +package wasi:http + // The `wasi:http/types` interface is meant to be imported by components to // define the HTTP resource types and operations used by the component's // imported and exported interfaces. -default interface types { - use io.streams.{input-stream, output-stream} - use poll.poll.{pollable} - +interface types { + use wasi:io/streams.{input-stream, output-stream} + use wasi:poll/poll.{pollable} + // This type corresponds to HTTP standard Methods. variant method { get, diff --git a/crates/wasi/wit/deps/io/streams.wit b/crates/wasi/wit/deps/io/streams.wit index c1567fd4c1c8..008e36cf59c8 100644 --- a/crates/wasi/wit/deps/io/streams.wit +++ b/crates/wasi/wit/deps/io/streams.wit @@ -1,10 +1,12 @@ +package wasi:io + /// WASI I/O is an I/O abstraction API which is currently focused on providing /// stream types. /// /// In the future, the component model is expected to add built-in stream types; /// when it does, they are expected to subsume this API. -default interface streams { - use poll.poll.{pollable} +interface streams { + use wasi:poll/poll.{pollable} /// An error type returned from a stream operation. Currently this /// doesn't provide any additional information. diff --git a/crates/wasi/wit/deps/logging/handler.wit b/crates/wasi/wit/deps/logging/handler.wit index c9632b9cc4f8..e6b077be8a60 100644 --- a/crates/wasi/wit/deps/logging/handler.wit +++ b/crates/wasi/wit/deps/logging/handler.wit @@ -1,6 +1,8 @@ +package wasi:logging + /// WASI Logging is a logging API intended to let users emit log messages with /// simple priority levels and context values. -default interface handler { +interface handler { /// A log level, describing a kind of message. enum level { /// Describes messages about the values of variables and the flow of diff --git a/crates/wasi/wit/deps/poll/poll.wit b/crates/wasi/wit/deps/poll/poll.wit index 28f08e17d755..cf5d8779c17e 100644 --- a/crates/wasi/wit/deps/poll/poll.wit +++ b/crates/wasi/wit/deps/poll/poll.wit @@ -1,6 +1,8 @@ +package wasi:poll + /// A poll API intended to let users wait for I/O events on multiple handles /// at once. -default interface poll { +interface poll { /// A "pollable" handle. /// /// This is conceptually represents a `stream<_, _>`, or in other words, diff --git a/crates/wasi/wit/deps/preview/command-extended.wit b/crates/wasi/wit/deps/preview/command-extended.wit index 92e3d7d81022..2beb119da319 100644 --- a/crates/wasi/wit/deps/preview/command-extended.wit +++ b/crates/wasi/wit/deps/preview/command-extended.wit @@ -1,29 +1,34 @@ -default world command-extended { - import wall-clock: clocks.wall-clock - import monotonic-clock: clocks.monotonic-clock - import timezone: clocks.timezone - import filesystem: filesystem.filesystem - import instance-network: sockets.instance-network - import ip-name-lookup: sockets.ip-name-lookup - import network: sockets.network - import tcp-create-socket: sockets.tcp-create-socket - import tcp: sockets.tcp - import udp-create-socket: sockets.udp-create-socket - import udp: sockets.udp - import random: random.random - import insecure-random: random.insecure - import insecure-random-seed: random.insecure-seed - import poll: poll.poll - import streams: io.streams - import environment: wasi-cli-base.environment - import preopens: wasi-cli-base.preopens - import exit: wasi-cli-base.exit +package wasi:preview + +world command-extended { + import wasi:clocks/wall-clock + import wasi:clocks/monotonic-clock + import wasi:clocks/timezone + import wasi:filesystem/filesystem + import wasi:sockets/instance-network + import wasi:sockets/ip-name-lookup + import wasi:sockets/network + import wasi:sockets/tcp-create-socket + import wasi:sockets/tcp + import wasi:sockets/udp-create-socket + import wasi:sockets/udp + import wasi:random/random + import wasi:random/insecure + import wasi:random/insecure-seed + import wasi:poll/poll + import wasi:io/streams + import wasi:cli-base/environment + import wasi:cli-base/preopens + import wasi:cli-base/exit + import wasi:cli-base/stdin + import wasi:cli-base/stdout + import wasi:cli-base/stderr // We should replace all others with `include self.command` // as soon as the unioning of worlds is available: // https://github.com/WebAssembly/component-model/issues/169 - import console: logging.handler - import default-outgoing-HTTP: http.outgoing-handler + import wasi:logging/handler + import wasi:http/outgoing-handler export run: func( args: list, diff --git a/crates/wasi/wit/deps/preview/command.wit b/crates/wasi/wit/deps/preview/command.wit index 780e2c4667ff..62608a05ccf9 100644 --- a/crates/wasi/wit/deps/preview/command.wit +++ b/crates/wasi/wit/deps/preview/command.wit @@ -1,23 +1,26 @@ -default world command { - import wall-clock: clocks.wall-clock - import monotonic-clock: clocks.monotonic-clock - import timezone: clocks.timezone - import filesystem: filesystem.filesystem - import instance-network: sockets.instance-network - import ip-name-lookup: sockets.ip-name-lookup - import network: sockets.network - import tcp-create-socket: sockets.tcp-create-socket - import tcp: sockets.tcp - import udp-create-socket: sockets.udp-create-socket - import udp: sockets.udp - import random: random.random - import insecure-random: random.insecure - import insecure-random-seed: random.insecure-seed - import poll: poll.poll - import streams: io.streams - import environment: wasi-cli-base.environment - import preopens: wasi-cli-base.preopens - import exit: wasi-cli-base.exit +world command { + import wasi:clocks/wall-clock + import wasi:clocks/monotonic-clock + import wasi:clocks/timezone + import wasi:filesystem/filesystem + import wasi:sockets/instance-network + import wasi:sockets/ip-name-lookup + import wasi:sockets/network + import wasi:sockets/tcp-create-socket + import wasi:sockets/tcp + import wasi:sockets/udp-create-socket + import wasi:sockets/udp + import wasi:random/random + import wasi:random/insecure + import wasi:random/insecure-seed + import wasi:poll/poll + import wasi:io/streams + import wasi:cli-base/environment + import wasi:cli-base/preopens + import wasi:cli-base/exit + import wasi:cli-base/stdin + import wasi:cli-base/stdout + import wasi:cli-base/stderr export run: func() -> result } diff --git a/crates/wasi/wit/deps/preview/proxy.wit b/crates/wasi/wit/deps/preview/proxy.wit index 03877e958e92..a616daa1c243 100644 --- a/crates/wasi/wit/deps/preview/proxy.wit +++ b/crates/wasi/wit/deps/preview/proxy.wit @@ -1,8 +1,9 @@ -default world proxy { - import random: random.random - import insecure-random: random.insecure - import insecure-random-seed: random.insecure-seed - import console: logging.handler - import default-outgoing-HTTP: http.outgoing-handler - export HTTP: http.incoming-handler +world proxy { + import wasi:random/random + import wasi:random/insecure + import wasi:random/insecure-seed + import wasi:logging/handler + import wasi:http/outgoing-handler + + export wasi:http/incoming-handler } diff --git a/crates/wasi/wit/deps/preview/reactor.wit b/crates/wasi/wit/deps/preview/reactor.wit index 2abfa466ba3b..4a262c551d3f 100644 --- a/crates/wasi/wit/deps/preview/reactor.wit +++ b/crates/wasi/wit/deps/preview/reactor.wit @@ -1,21 +1,24 @@ -default world reactor { - import wall-clock: clocks.wall-clock - import monotonic-clock: clocks.monotonic-clock - import timezone: clocks.timezone - import filesystem: filesystem.filesystem - import instance-network: sockets.instance-network - import ip-name-lookup: sockets.ip-name-lookup - import network: sockets.network - import tcp-create-socket: sockets.tcp-create-socket - import tcp: sockets.tcp - import udp-create-socket: sockets.udp-create-socket - import udp: sockets.udp - import random: random.random - import poll: poll.poll - import streams: io.streams - import console: logging.handler - import default-outgoing-HTTP: http.outgoing-handler - import environment: wasi-cli-base.environment - import preopens: wasi-cli-base.preopens - import exit: wasi-cli-base.exit +world reactor { + import wasi:clocks/wall-clock + import wasi:clocks/monotonic-clock + import wasi:clocks/timezone + import wasi:filesystem/filesystem + import wasi:sockets/instance-network + import wasi:sockets/ip-name-lookup + import wasi:sockets/network + import wasi:sockets/tcp-create-socket + import wasi:sockets/tcp + import wasi:sockets/udp-create-socket + import wasi:sockets/udp + import wasi:random/random + import wasi:poll/poll + import wasi:io/streams + import wasi:logging/handler + import wasi:http/outgoing-handler + import wasi:cli-base/environment + import wasi:cli-base/preopens + import wasi:cli-base/exit + import wasi:cli-base/stdin + import wasi:cli-base/stdout + import wasi:cli-base/stderr } diff --git a/crates/wasi/wit/deps/random/insecure-seed.wit b/crates/wasi/wit/deps/random/insecure-seed.wit index 93a2f17d4090..ff2ff65d0754 100644 --- a/crates/wasi/wit/deps/random/insecure-seed.wit +++ b/crates/wasi/wit/deps/random/insecure-seed.wit @@ -2,7 +2,7 @@ /// /// It is intended to be portable at least between Unix-family platforms and /// Windows. -default interface insecure-seed { +interface insecure-seed { /// Return a 128-bit value that may contain a pseudo-random value. /// /// The returned value is not required to be computed from a CSPRNG, and may diff --git a/crates/wasi/wit/deps/random/insecure.wit b/crates/wasi/wit/deps/random/insecure.wit index 1ef020a0998c..ff0826822d5f 100644 --- a/crates/wasi/wit/deps/random/insecure.wit +++ b/crates/wasi/wit/deps/random/insecure.wit @@ -2,7 +2,7 @@ /// /// It is intended to be portable at least between Unix-family platforms and /// Windows. -default interface insecure { +interface insecure { /// Return `len` insecure pseudo-random bytes. /// /// This function is not cryptographically secure. Do not use it for diff --git a/crates/wasi/wit/deps/random/random.wit b/crates/wasi/wit/deps/random/random.wit index 8f758578842f..f2bd6358c139 100644 --- a/crates/wasi/wit/deps/random/random.wit +++ b/crates/wasi/wit/deps/random/random.wit @@ -1,8 +1,10 @@ +package wasi:random + /// WASI Random is a random data API. /// /// It is intended to be portable at least between Unix-family platforms and /// Windows. -default interface random { +interface random { /// Return `len` cryptographically-secure pseudo-random bytes. /// /// This function must produce data from an adequately seeded diff --git a/crates/wasi/wit/deps/sockets/instance-network.wit b/crates/wasi/wit/deps/sockets/instance-network.wit index b1f5c982d976..d911a29cc8dd 100644 --- a/crates/wasi/wit/deps/sockets/instance-network.wit +++ b/crates/wasi/wit/deps/sockets/instance-network.wit @@ -1,7 +1,7 @@ /// This interface provides a value-export of the default network handle.. -default interface instance-network { - use pkg.network.{network} +interface instance-network { + use network.{network} /// Get a handle to the default network. instance-network: func() -> network diff --git a/crates/wasi/wit/deps/sockets/ip-name-lookup.wit b/crates/wasi/wit/deps/sockets/ip-name-lookup.wit index c4cc7268464c..6c64b4617b98 100644 --- a/crates/wasi/wit/deps/sockets/ip-name-lookup.wit +++ b/crates/wasi/wit/deps/sockets/ip-name-lookup.wit @@ -1,13 +1,13 @@ -default interface ip-name-lookup { - use poll.poll.{pollable} - use pkg.network.{network, error-code, ip-address, ip-address-family} +interface ip-name-lookup { + use wasi:poll/poll.{pollable} + use network.{network, error-code, ip-address, ip-address-family} /// Resolve an internet host name to a list of IP addresses. - /// + /// /// See the wasi-socket proposal README.md for a comparison with getaddrinfo. - /// + /// /// # Parameters /// - `name`: The name to look up. IP addresses are not allowed. Unicode domain names are automatically converted /// to ASCII using IDNA encoding. @@ -17,18 +17,18 @@ default interface ip-name-lookup { /// systems without an active IPv6 interface. Notes: /// - Even when no public IPv6 interfaces are present or active, names like "localhost" can still resolve to an IPv6 address. /// - Whatever is "available" or "unavailable" is volatile and can change everytime a network cable is unplugged. - /// + /// /// This function never blocks. It either immediately fails or immediately returns successfully with a `resolve-address-stream` /// that can be used to (asynchronously) fetch the results. - /// + /// /// At the moment, the stream never completes successfully with 0 items. Ie. the first call /// to `resolve-next-address` never returns `ok(none)`. This may change in the future. - /// + /// /// # Typical errors /// - `invalid-name`: `name` is a syntactically invalid domain name. /// - `invalid-name`: `name` is an IP address. /// - `address-family-not-supported`: The specified `address-family` is not supported. (EAI_FAMILY) - /// + /// /// # References: /// - /// - @@ -41,14 +41,14 @@ default interface ip-name-lookup { type resolve-address-stream = u32 /// Returns the next address from the resolver. - /// + /// /// This function should be called multiple times. On each call, it will /// return the next address in connection order preference. If all /// addresses have been exhausted, this function returns `none`. /// After which, you should release the stream with `drop-resolve-address-stream`. - /// + /// /// This function never returns IPv4-mapped IPv6 addresses. - /// + /// /// # Typical errors /// - `name-unresolvable`: Name does not exist or has no suitable associated IP addresses. (EAI_NONAME, EAI_NODATA, EAI_ADDRFAMILY) /// - `temporary-resolver-failure`: A temporary failure in name resolution occurred. (EAI_AGAIN) @@ -57,12 +57,12 @@ default interface ip-name-lookup { resolve-next-address: func(this: resolve-address-stream) -> result, error-code> /// Dispose of the specified `resolve-address-stream`, after which it may no longer be used. - /// + /// /// Note: this function is scheduled to be removed when Resources are natively supported in Wit. drop-resolve-address-stream: func(this: resolve-address-stream) /// Create a `pollable` which will resolve once the stream is ready for I/O. - /// + /// /// Note: this function is here for WASI Preview2 only. /// It's planned to be removed when `future` is natively supported in Preview3. subscribe: func(this: resolve-address-stream) -> pollable diff --git a/crates/wasi/wit/deps/sockets/network.wit b/crates/wasi/wit/deps/sockets/network.wit index 9176e6ba6594..c370214ce1f9 100644 --- a/crates/wasi/wit/deps/sockets/network.wit +++ b/crates/wasi/wit/deps/sockets/network.wit @@ -1,14 +1,15 @@ +package wasi:sockets -default interface network { +interface network { /// An opaque resource that represents access to (a subset of) the network. /// This enables context-based security for networking. /// There is no need for this to map 1:1 to a physical network interface. - /// + /// /// FYI, In the future this will be replaced by handle types. type network = u32 /// Dispose of the specified `network`, after which it may no longer be used. - /// + /// /// Note: this function is scheduled to be removed when Resources are natively supported in Wit. drop-network: func(this: network) @@ -152,7 +153,7 @@ default interface network { enum ip-address-family { /// Similar to `AF_INET` in POSIX. - ipv4, + ipv4, /// Similar to `AF_INET6` in POSIX. ipv6, @@ -183,4 +184,4 @@ default interface network { ipv6(ipv6-socket-address), } -} \ No newline at end of file +} diff --git a/crates/wasi/wit/deps/sockets/tcp-create-socket.wit b/crates/wasi/wit/deps/sockets/tcp-create-socket.wit index 6e948fae0a6c..f467d2856906 100644 --- a/crates/wasi/wit/deps/sockets/tcp-create-socket.wit +++ b/crates/wasi/wit/deps/sockets/tcp-create-socket.wit @@ -1,23 +1,23 @@ -default interface tcp-create-socket { - use pkg.network.{network, error-code, ip-address-family} - use pkg.tcp.{tcp-socket} +interface tcp-create-socket { + use network.{network, error-code, ip-address-family} + use tcp.{tcp-socket} /// Create a new TCP socket. - /// + /// /// Similar to `socket(AF_INET or AF_INET6, SOCK_STREAM, IPPROTO_TCP)` in POSIX. - /// + /// /// This function does not require a network capability handle. This is considered to be safe because /// at time of creation, the socket is not bound to any `network` yet. Up to the moment `bind`/`listen`/`connect` /// is called, the socket is effectively an in-memory configuration object, unable to communicate with the outside world. - /// + /// /// All sockets are non-blocking. Use the wasi-poll interface to block on asynchronous operations. - /// + /// /// # Typical errors /// - `not-supported`: The host does not support TCP sockets. (EOPNOTSUPP) /// - `address-family-not-supported`: The specified `address-family` is not supported. (EAFNOSUPPORT) /// - `new-socket-limit`: The new socket resource could not be created because of a system limit. (EMFILE, ENFILE) - /// + /// /// # References /// - /// - diff --git a/crates/wasi/wit/deps/sockets/tcp.wit b/crates/wasi/wit/deps/sockets/tcp.wit index b87153243c20..7ed46a690491 100644 --- a/crates/wasi/wit/deps/sockets/tcp.wit +++ b/crates/wasi/wit/deps/sockets/tcp.wit @@ -1,12 +1,12 @@ -default interface tcp { - use io.streams.{input-stream, output-stream} - use poll.poll.{pollable} - use pkg.network.{network, error-code, ip-socket-address, ip-address-family} +interface tcp { + use wasi:io/streams.{input-stream, output-stream} + use wasi:poll/poll.{pollable} + use network.{network, error-code, ip-socket-address, ip-address-family} /// A TCP socket handle. type tcp-socket = u32 - + enum shutdown-type { /// Similar to `SHUT_RD` in POSIX. @@ -25,24 +25,24 @@ default interface tcp { /// If the IP address is zero (`0.0.0.0` in IPv4, `::` in IPv6), it is left to the implementation to decide which /// network interface(s) to bind to. /// If the TCP/UDP port is zero, the socket will be bound to a random free port. - /// + /// /// When a socket is not explicitly bound, the first invocation to a listen or connect operation will /// implicitly bind the socket. - /// + /// /// Unlike in POSIX, this function is async. This enables interactive WASI hosts to inject permission prompts. - /// + /// /// # Typical `start` errors /// - `address-family-mismatch`: The `local-address` has the wrong address family. (EINVAL) /// - `already-bound`: The socket is already bound. (EINVAL) /// - `concurrency-conflict`: Another `bind`, `connect` or `listen` operation is already in progress. (EALREADY) - /// + /// /// # Typical `finish` errors /// - `ephemeral-ports-exhausted`: No ephemeral ports available. (EADDRINUSE, ENOBUFS on Windows) /// - `address-in-use`: Address is already in use. (EADDRINUSE) /// - `address-not-bindable`: `local-address` is not an address that the `network` can bind to. (EADDRNOTAVAIL) /// - `not-in-progress`: A `bind` operation is not in progress. /// - `would-block`: Can't finish the operation, it is still in progress. (EWOULDBLOCK, EAGAIN) - /// + /// /// # References /// - /// - @@ -52,11 +52,11 @@ default interface tcp { finish-bind: func(this: tcp-socket) -> result<_, error-code> /// Connect to a remote endpoint. - /// + /// /// On success: /// - the socket is transitioned into the Connection state /// - a pair of streams is returned that can be used to read & write to the connection - /// + /// /// # Typical `start` errors /// - `address-family-mismatch`: The `remote-address` has the wrong address family. (EAFNOSUPPORT) /// - `invalid-remote-address`: The IP address in `remote-address` is set to INADDR_ANY (`0.0.0.0` / `::`). (EADDRNOTAVAIL on Windows) @@ -65,7 +65,7 @@ default interface tcp { /// - `already-connected`: The socket is already in the Connection state. (EISCONN) /// - `already-listening`: The socket is already in the Listener state. (EOPNOTSUPP, EINVAL on Windows) /// - `concurrency-conflict`: Another `bind`, `connect` or `listen` operation is already in progress. (EALREADY) - /// + /// /// # Typical `finish` errors /// - `timeout`: Connection timed out. (ETIMEDOUT) /// - `connection-refused`: The connection was forcefully rejected. (ECONNREFUSED) @@ -74,7 +74,7 @@ default interface tcp { /// - `ephemeral-ports-exhausted`: Tried to perform an implicit bind, but there were no ephemeral ports available. (EADDRINUSE, EADDRNOTAVAIL on Linux, EAGAIN on BSD) /// - `not-in-progress`: A `connect` operation is not in progress. /// - `would-block`: Can't finish the operation, it is still in progress. (EWOULDBLOCK, EAGAIN) - /// + /// /// # References /// - /// - @@ -84,11 +84,11 @@ default interface tcp { finish-connect: func(this: tcp-socket) -> result, error-code> /// Start listening for new connections. - /// + /// /// Transitions the socket into the Listener state. - /// + /// /// Unlike in POSIX, this function is async. This enables interactive WASI hosts to inject permission prompts. - /// + /// /// # Typical `start` errors /// - `already-attached`: The socket is already attached to a different network. The `network` passed to `listen` must be identical to the one passed to `bind`. /// - `already-connected`: The socket is already in the Connection state. (EISCONN, EINVAL on BSD) @@ -109,18 +109,18 @@ default interface tcp { finish-listen: func(this: tcp-socket) -> result<_, error-code> /// Accept a new client socket. - /// + /// /// The returned socket is bound and in the Connection state. - /// + /// /// On success, this function returns the newly accepted client socket along with /// a pair of streams that can be used to read & write to the connection. - /// + /// /// # Typical errors /// - `not-listening`: Socket is not in the Listener state. (EINVAL) /// - `would-block`: No pending connections at the moment. (EWOULDBLOCK, EAGAIN) - /// + /// /// Host implementations must skip over transient errors returned by the native accept syscall. - /// + /// /// # References /// - /// - @@ -129,10 +129,10 @@ default interface tcp { accept: func(this: tcp-socket) -> result, error-code> /// Get the bound local address. - /// + /// /// # Typical errors /// - `not-bound`: The socket is not bound to any local address. - /// + /// /// # References /// - /// - @@ -141,10 +141,10 @@ default interface tcp { local-address: func(this: tcp-socket) -> result /// Get the bound remote address. - /// + /// /// # Typical errors /// - `not-connected`: The socket is not connected to a remote address. (ENOTCONN) - /// + /// /// # References /// - /// - @@ -153,14 +153,14 @@ default interface tcp { remote-address: func(this: tcp-socket) -> result /// Whether this is a IPv4 or IPv6 socket. - /// + /// /// Equivalent to the SO_DOMAIN socket option. address-family: func(this: tcp-socket) -> ip-address-family - + /// Whether IPv4 compatibility (dual-stack) mode is disabled or not. - /// + /// /// Equivalent to the IPV6_V6ONLY socket option. - /// + /// /// # Typical errors /// - `ipv6-only-operation`: (get/set) `this` socket is an IPv4 socket. /// - `already-bound`: (set) The socket is already bound. @@ -170,28 +170,28 @@ default interface tcp { set-ipv6-only: func(this: tcp-socket, value: bool) -> result<_, error-code> /// Hints the desired listen queue size. Implementations are free to ignore this. - /// + /// /// # Typical errors /// - `already-connected`: (set) The socket is already in the Connection state. /// - `concurrency-conflict`: (set) A `bind`, `connect` or `listen` operation is already in progress. (EALREADY) set-listen-backlog-size: func(this: tcp-socket, value: u64) -> result<_, error-code> /// Equivalent to the SO_KEEPALIVE socket option. - /// + /// /// # Typical errors /// - `concurrency-conflict`: (set) A `bind`, `connect` or `listen` operation is already in progress. (EALREADY) keep-alive: func(this: tcp-socket) -> result set-keep-alive: func(this: tcp-socket, value: bool) -> result<_, error-code> /// Equivalent to the TCP_NODELAY socket option. - /// + /// /// # Typical errors /// - `concurrency-conflict`: (set) A `bind`, `connect` or `listen` operation is already in progress. (EALREADY) no-delay: func(this: tcp-socket) -> result set-no-delay: func(this: tcp-socket, value: bool) -> result<_, error-code> - + /// Equivalent to the IP_TTL & IPV6_UNICAST_HOPS socket options. - /// + /// /// # Typical errors /// - `already-connected`: (set) The socket is already in the Connection state. /// - `already-listening`: (set) The socket is already in the Listener state. @@ -200,16 +200,16 @@ default interface tcp { set-unicast-hop-limit: func(this: tcp-socket, value: u8) -> result<_, error-code> /// The kernel buffer space reserved for sends/receives on this socket. - /// + /// /// Note #1: an implementation may choose to cap or round the buffer size when setting the value. /// In other words, after setting a value, reading the same setting back may return a different value. - /// + /// /// Note #2: there is not necessarily a direct relationship between the kernel buffer size and the bytes of /// actual data to be sent/received by the application, because the kernel might also use the buffer space /// for internal metadata structures. - /// + /// /// Equivalent to the SO_RCVBUF and SO_SNDBUF socket options. - /// + /// /// # Typical errors /// - `already-connected`: (set) The socket is already in the Connection state. /// - `already-listening`: (set) The socket is already in the Listener state. @@ -220,25 +220,25 @@ default interface tcp { set-send-buffer-size: func(this: tcp-socket, value: u64) -> result<_, error-code> /// Create a `pollable` which will resolve once the socket is ready for I/O. - /// + /// /// Note: this function is here for WASI Preview2 only. /// It's planned to be removed when `future` is natively supported in Preview3. subscribe: func(this: tcp-socket) -> pollable /// Initiate a graceful shutdown. - /// + /// /// - receive: the socket is not expecting to receive any more data from the peer. All subsequent read /// operations on the `input-stream` associated with this socket will return an End Of Stream indication. /// Any data still in the receive queue at time of calling `shutdown` will be discarded. /// - send: the socket is not expecting to send any more data to the peer. All subsequent write /// operations on the `output-stream` associated with this socket will return an error. /// - both: same effect as receive & send combined. - /// + /// /// The shutdown function does not close (drop) the socket. - /// + /// /// # Typical errors /// - `not-connected`: The socket is not in the Connection state. (ENOTCONN) - /// + /// /// # References /// - /// - @@ -247,9 +247,9 @@ default interface tcp { shutdown: func(this: tcp-socket, shutdown-type: shutdown-type) -> result<_, error-code> /// Dispose of the specified `tcp-socket`, after which it may no longer be used. - /// + /// /// Similar to the POSIX `close` function. - /// + /// /// Note: this function is scheduled to be removed when Resources are natively supported in Wit. drop-tcp-socket: func(this: tcp-socket) } diff --git a/crates/wasi/wit/deps/sockets/udp-create-socket.wit b/crates/wasi/wit/deps/sockets/udp-create-socket.wit index 2c987be08df5..1cfbd7f0bdd8 100644 --- a/crates/wasi/wit/deps/sockets/udp-create-socket.wit +++ b/crates/wasi/wit/deps/sockets/udp-create-socket.wit @@ -1,23 +1,23 @@ -default interface udp-create-socket { - use pkg.network.{network, error-code, ip-address-family} - use pkg.udp.{udp-socket} +interface udp-create-socket { + use network.{network, error-code, ip-address-family} + use udp.{udp-socket} /// Create a new UDP socket. - /// + /// /// Similar to `socket(AF_INET or AF_INET6, SOCK_DGRAM, IPPROTO_UDP)` in POSIX. - /// + /// /// This function does not require a network capability handle. This is considered to be safe because /// at time of creation, the socket is not bound to any `network` yet. Up to the moment `bind`/`connect` is called, /// the socket is effectively an in-memory configuration object, unable to communicate with the outside world. - /// + /// /// All sockets are non-blocking. Use the wasi-poll interface to block on asynchronous operations. - /// + /// /// # Typical errors /// - `not-supported`: The host does not support UDP sockets. (EOPNOTSUPP) /// - `address-family-not-supported`: The specified `address-family` is not supported. (EAFNOSUPPORT) /// - `new-socket-limit`: The new socket resource could not be created because of a system limit. (EMFILE, ENFILE) - /// + /// /// # References: /// - /// - diff --git a/crates/wasi/wit/deps/sockets/udp.wit b/crates/wasi/wit/deps/sockets/udp.wit index 271a2cb9f00f..9dd4573bd17c 100644 --- a/crates/wasi/wit/deps/sockets/udp.wit +++ b/crates/wasi/wit/deps/sockets/udp.wit @@ -1,7 +1,7 @@ -default interface udp { - use poll.poll.{pollable} - use pkg.network.{network, error-code, ip-socket-address, ip-address-family} +interface udp { + use wasi:poll/poll.{pollable} + use network.{network, error-code, ip-socket-address, ip-address-family} /// A UDP socket handle. @@ -27,23 +27,23 @@ default interface udp { /// If the IP address is zero (`0.0.0.0` in IPv4, `::` in IPv6), it is left to the implementation to decide which /// network interface(s) to bind to. /// If the TCP/UDP port is zero, the socket will be bound to a random free port. - /// + /// /// When a socket is not explicitly bound, the first invocation to connect will implicitly bind the socket. - /// + /// /// Unlike in POSIX, this function is async. This enables interactive WASI hosts to inject permission prompts. - /// + /// /// # Typical `start` errors /// - `address-family-mismatch`: The `local-address` has the wrong address family. (EINVAL) /// - `already-bound`: The socket is already bound. (EINVAL) /// - `concurrency-conflict`: Another `bind` or `connect` operation is already in progress. (EALREADY) - /// + /// /// # Typical `finish` errors /// - `ephemeral-ports-exhausted`: No ephemeral ports available. (EADDRINUSE, ENOBUFS on Windows) /// - `address-in-use`: Address is already in use. (EADDRINUSE) /// - `address-not-bindable`: `local-address` is not an address that the `network` can bind to. (EADDRNOTAVAIL) /// - `not-in-progress`: A `bind` operation is not in progress. /// - `would-block`: Can't finish the operation, it is still in progress. (EWOULDBLOCK, EAGAIN) - /// + /// /// # References /// - /// - @@ -53,29 +53,29 @@ default interface udp { finish-bind: func(this: udp-socket) -> result<_, error-code> /// Set the destination address. - /// + /// /// The local-address is updated based on the best network path to `remote-address`. - /// + /// /// When a destination address is set: /// - all receive operations will only return datagrams sent from the provided `remote-address`. /// - the `send` function can only be used to send to this destination. - /// + /// /// Note that this function does not generate any network traffic and the peer is not aware of this "connection". - /// + /// /// Unlike in POSIX, this function is async. This enables interactive WASI hosts to inject permission prompts. - /// + /// /// # Typical `start` errors /// - `address-family-mismatch`: The `remote-address` has the wrong address family. (EAFNOSUPPORT) /// - `invalid-remote-address`: The IP address in `remote-address` is set to INADDR_ANY (`0.0.0.0` / `::`). (EDESTADDRREQ, EADDRNOTAVAIL) /// - `invalid-remote-address`: The port in `remote-address` is set to 0. (EDESTADDRREQ, EADDRNOTAVAIL) /// - `already-attached`: The socket is already bound to a different network. The `network` passed to `connect` must be identical to the one passed to `bind`. /// - `concurrency-conflict`: Another `bind` or `connect` operation is already in progress. (EALREADY) - /// + /// /// # Typical `finish` errors /// - `ephemeral-ports-exhausted`: Tried to perform an implicit bind, but there were no ephemeral ports available. (EADDRINUSE, EADDRNOTAVAIL on Linux, EAGAIN on BSD) /// - `not-in-progress`: A `connect` operation is not in progress. /// - `would-block`: Can't finish the operation, it is still in progress. (EWOULDBLOCK, EAGAIN) - /// + /// /// # References /// - /// - @@ -85,16 +85,16 @@ default interface udp { finish-connect: func(this: udp-socket) -> result<_, error-code> /// Receive a message. - /// + /// /// Returns: /// - The sender address of the datagram /// - The number of bytes read. - /// + /// /// # Typical errors /// - `not-bound`: The socket is not bound to any local address. (EINVAL) /// - `remote-unreachable`: The remote address is not reachable. (ECONNREFUSED, ECONNRESET, ENETRESET on Windows, EHOSTUNREACH, EHOSTDOWN, ENETUNREACH, ENETDOWN) /// - `would-block`: There is no pending data available to be read at the moment. (EWOULDBLOCK, EAGAIN) - /// + /// /// # References /// - /// - @@ -106,10 +106,10 @@ default interface udp { receive: func(this: udp-socket) -> result /// Send a message to a specific destination address. - /// + /// /// The remote address option is required. To send a message to the "connected" peer, /// call `remote-address` to get their address. - /// + /// /// # Typical errors /// - `address-family-mismatch`: The `remote-address` has the wrong address family. (EAFNOSUPPORT) /// - `invalid-remote-address`: The IP address in `remote-address` is set to INADDR_ANY (`0.0.0.0` / `::`). (EDESTADDRREQ, EADDRNOTAVAIL) @@ -119,7 +119,7 @@ default interface udp { /// - `remote-unreachable`: The remote address is not reachable. (ECONNREFUSED, ECONNRESET, ENETRESET on Windows, EHOSTUNREACH, EHOSTDOWN, ENETUNREACH, ENETDOWN) /// - `datagram-too-large`: The datagram is too large. (EMSGSIZE) /// - `would-block`: The send buffer is currently full. (EWOULDBLOCK, EAGAIN) - /// + /// /// # References /// - /// - @@ -131,10 +131,10 @@ default interface udp { send: func(this: udp-socket, datagram: datagram) -> result<_, error-code> /// Get the current bound address. - /// + /// /// # Typical errors /// - `not-bound`: The socket is not bound to any local address. - /// + /// /// # References /// - /// - @@ -143,10 +143,10 @@ default interface udp { local-address: func(this: udp-socket) -> result /// Get the address set with `connect`. - /// + /// /// # Typical errors /// - `not-connected`: The socket is not connected to a remote address. (ENOTCONN) - /// + /// /// # References /// - /// - @@ -155,14 +155,14 @@ default interface udp { remote-address: func(this: udp-socket) -> result /// Whether this is a IPv4 or IPv6 socket. - /// + /// /// Equivalent to the SO_DOMAIN socket option. address-family: func(this: udp-socket) -> ip-address-family /// Whether IPv4 compatibility (dual-stack) mode is disabled or not. - /// + /// /// Equivalent to the IPV6_V6ONLY socket option. - /// + /// /// # Typical errors /// - `ipv6-only-operation`: (get/set) `this` socket is an IPv4 socket. /// - `already-bound`: (set) The socket is already bound. @@ -172,25 +172,25 @@ default interface udp { set-ipv6-only: func(this: udp-socket, value: bool) -> result<_, error-code> /// Equivalent to the IP_TTL & IPV6_UNICAST_HOPS socket options. - /// + /// /// # Typical errors /// - `concurrency-conflict`: (set) Another `bind` or `connect` operation is already in progress. (EALREADY) unicast-hop-limit: func(this: udp-socket) -> result set-unicast-hop-limit: func(this: udp-socket, value: u8) -> result<_, error-code> /// The kernel buffer space reserved for sends/receives on this socket. - /// + /// /// Note #1: an implementation may choose to cap or round the buffer size when setting the value. /// In other words, after setting a value, reading the same setting back may return a different value. - /// + /// /// Note #2: there is not necessarily a direct relationship between the kernel buffer size and the bytes of /// actual data to be sent/received by the application, because the kernel might also use the buffer space /// for internal metadata structures. - /// + /// /// Fails when this socket is in the Listening state. - /// + /// /// Equivalent to the SO_RCVBUF and SO_SNDBUF socket options. - /// + /// /// # Typical errors /// - `concurrency-conflict`: (set) Another `bind` or `connect` operation is already in progress. (EALREADY) receive-buffer-size: func(this: udp-socket) -> result @@ -199,13 +199,13 @@ default interface udp { set-send-buffer-size: func(this: udp-socket, value: u64) -> result<_, error-code> /// Create a `pollable` which will resolve once the socket is ready for I/O. - /// + /// /// Note: this function is here for WASI Preview2 only. /// It's planned to be removed when `future` is natively supported in Preview3. subscribe: func(this: udp-socket) -> pollable /// Dispose of the specified `udp-socket`, after which it may no longer be used. - /// + /// /// Note: this function is scheduled to be removed when Resources are natively supported in Wit. drop-udp-socket: func(this: udp-socket) } diff --git a/crates/wasi/wit/deps/wasi-cli-base/environment.wit b/crates/wasi/wit/deps/wasi-cli-base/environment.wit index 876ea3a0c921..4c97c85d1ab5 100644 --- a/crates/wasi/wit/deps/wasi-cli-base/environment.wit +++ b/crates/wasi/wit/deps/wasi-cli-base/environment.wit @@ -1,4 +1,6 @@ -default interface environment { +package wasi:cli-base + +interface environment { /// Get the POSIX-style environment variables. /// /// Each environment variable is provided as a pair of string variable names diff --git a/crates/wasi/wit/deps/wasi-cli-base/exit.wit b/crates/wasi/wit/deps/wasi-cli-base/exit.wit index 2759e9dd989c..66835aa7022d 100644 --- a/crates/wasi/wit/deps/wasi-cli-base/exit.wit +++ b/crates/wasi/wit/deps/wasi-cli-base/exit.wit @@ -1,4 +1,4 @@ -default interface wasi-exit { +interface exit { /// Exit the curerent instance and any linked instances. exit: func(status: result) } diff --git a/crates/wasi/wit/deps/wasi-cli-base/preopens.wit b/crates/wasi/wit/deps/wasi-cli-base/preopens.wit index 5595f8d392a2..f268f6b0b2e6 100644 --- a/crates/wasi/wit/deps/wasi-cli-base/preopens.wit +++ b/crates/wasi/wit/deps/wasi-cli-base/preopens.wit @@ -1,6 +1,6 @@ -default interface preopens { - use filesystem.filesystem.{descriptor} - use io.streams.{input-stream, output-stream} +interface preopens { + use wasi:filesystem/filesystem.{descriptor} + use wasi:io/streams.{input-stream, output-stream} /// Return the set of of preopened directories, and their path. get-directories: func() -> list> diff --git a/crates/wasi/wit/deps/wasi-cli-base/stdio.wit b/crates/wasi/wit/deps/wasi-cli-base/stdio.wit index 1f87e5485abb..6c9d4a41a6f9 100644 --- a/crates/wasi/wit/deps/wasi-cli-base/stdio.wit +++ b/crates/wasi/wit/deps/wasi-cli-base/stdio.wit @@ -1,17 +1,17 @@ interface stdin { - use io.streams.{input-stream} + use wasi:io/streams.{input-stream} get-stdin: func() -> input-stream } interface stdout { - use io.streams.{output-stream} + use wasi:io/streams.{output-stream} get-stdout: func() -> output-stream } interface stderr { - use io.streams.{output-stream} + use wasi:io/streams.{output-stream} get-stderr: func() -> output-stream } diff --git a/crates/wasi/wit/main.wit b/crates/wasi/wit/main.wit new file mode 100644 index 000000000000..264dfee8264d --- /dev/null +++ b/crates/wasi/wit/main.wit @@ -0,0 +1 @@ +package unused:main diff --git a/crates/wasi/wit/reactor.wit b/crates/wasi/wit/reactor.wit deleted file mode 100644 index fb6b1ac9647c..000000000000 --- a/crates/wasi/wit/reactor.wit +++ /dev/null @@ -1,26 +0,0 @@ -default world reactor { - import wall-clock: clocks.wall-clock - import monotonic-clock: clocks.monotonic-clock - import timezone: clocks.timezone - import filesystem: filesystem.filesystem - import instance-network: sockets.instance-network - import ip-name-lookup: sockets.ip-name-lookup - import network: sockets.network - import tcp-create-socket: sockets.tcp-create-socket - import tcp: sockets.tcp - import udp-create-socket: sockets.udp-create-socket - import udp: sockets.udp - import random: random.random - import insecure-random: random.insecure - import insecure-random-seed: random.insecure-seed - import poll: poll.poll - import streams: io.streams - import console: logging.handler - import default-outgoing-HTTP: http.outgoing-handler - import environment: wasi-cli-base.environment - import preopens: wasi-cli-base.preopens - import stdin: wasi-cli-base.stdio.stdin - import stdout: wasi-cli-base.stdio.stdout - import stderr: wasi-cli-base.stdio.stderr - import exit: wasi-cli-base.exit -} diff --git a/crates/wasi/wit/test.wit b/crates/wasi/wit/test.wit new file mode 100644 index 000000000000..a362fd4d906e --- /dev/null +++ b/crates/wasi/wit/test.wit @@ -0,0 +1,19 @@ +// only used as part of `test-programs` +world test-reactor { + + import wasi:cli-base/environment + import wasi:io/streams + import wasi:cli-base/preopens + import wasi:filesystem/filesystem + import wasi:cli-base/exit + + export add-strings: func(s: list) -> u32 + export get-strings: func() -> list + + use wasi:io/streams.{output-stream} + + export write-strings-to: func(o: output-stream) -> result + + use wasi:filesystem/filesystem.{descriptor-stat} + export pass-an-imported-record: func(d: descriptor-stat) -> string +} diff --git a/crates/wasmtime/src/component/matching.rs b/crates/wasmtime/src/component/matching.rs index 6f2cb5549baa..0f843032b97c 100644 --- a/crates/wasmtime/src/component/matching.rs +++ b/crates/wasmtime/src/component/matching.rs @@ -72,7 +72,7 @@ impl TypeChecker<'_> { // Like modules, every export in the expected type must be present in // the actual type. It's ok, though, to have extra exports in the actual // type. - for (name, (_url, expected)) in expected.exports.iter() { + for (name, expected) in expected.exports.iter() { // Interface types may be exported from a component in order to give them a name, but // they don't have a definition in the sense that this search is interested in, so // ignore them. diff --git a/crates/wasmtime/src/component/mod.rs b/crates/wasmtime/src/component/mod.rs index 671cce9d0bd8..f2066843e44a 100644 --- a/crates/wasmtime/src/component/mod.rs +++ b/crates/wasmtime/src/component/mod.rs @@ -73,7 +73,9 @@ pub(crate) use self::store::ComponentStoreData; /// ```text,ignore /// // wit/my-component.wit /// -/// default world hello-world { +/// package my:project +/// +/// world hello-world { /// import name: func() -> string /// export greet: func() /// } @@ -150,13 +152,15 @@ pub(crate) use self::store::ComponentStoreData; /// ```text,ignore /// // wit/my-component.wit /// +/// package my:project +/// /// interface host { /// gen-random-integer: func() -> u32 /// sha256: func(bytes: list) -> string /// } /// /// default world hello-world { -/// import host: self.host +/// import host /// /// export demo: interface { /// run: func() @@ -169,6 +173,7 @@ pub(crate) use self::store::ComponentStoreData; /// ```rust,ignore /// use wasmtime::component::*; /// use wasmtime::{Config, Engine, Store}; +/// use my::project::host::Host; /// /// bindgen!(); /// @@ -177,7 +182,7 @@ pub(crate) use self::store::ComponentStoreData; /// } /// /// // Note that the trait here is per-interface and within a submodule now. -/// impl host::Host for MyState { +/// impl Host for MyState { /// fn gen_random_integer(&mut self) -> wasmtime::Result { /// Ok(rand::thread_rng().gen()) /// } @@ -228,18 +233,12 @@ pub(crate) use self::store::ComponentStoreData; /// bindgen!(); /// /// // Parse the `wit/` folder adjacent to this crate's `Cargo.toml` and look -/// // for the document `foo`, which must have a `default world` contained -/// // within it. +/// // for the world `foo` contained in it. /// bindgen!("foo"); /// -/// // Parse the `wit/` folder adjacent to `Cargo.toml` and look up the document -/// // `foo` and the world named `bar`. -/// bindgen!("foo.bar"); -/// /// // Parse the folder `other/wit/folder` adjacent to `Cargo.toml`. /// bindgen!(in "other/wit/folder"); /// bindgen!("foo" in "other/wit/folder"); -/// bindgen!("foo.bar" in "other/wit/folder"); /// /// // Parse the file `foo.wit` as a single-file WIT package with no /// // dependencies. @@ -250,8 +249,7 @@ pub(crate) use self::store::ComponentStoreData; /// /// ```rust,ignore /// bindgen!({ -/// world: "foo", // or "foo.bar", same as in `bindgen!("foo")` -/// // not needed if `path` has one `default world` +/// world: "foo", // not needed if `path` has one `world` /// /// // same as in `bindgen!(in "other/wit/folder") /// path: "other/wit/folder", @@ -259,7 +257,9 @@ pub(crate) use self::store::ComponentStoreData; /// // Instead of `path` the WIT document can be provided inline if /// // desired. /// inline: " -/// default world foo { +/// package my:inline +/// +/// world foo { /// // ... /// } /// ", @@ -295,7 +295,7 @@ pub(crate) use self::store::ComponentStoreData; /// // Restrict the code generated to what's needed for the interface /// // imports in the inlined WIT document fragment. /// interfaces: " -/// import foo: package.foo; +/// import package.foo /// ", /// /// // Remap interface names to module names, imported from elsewhere. diff --git a/crates/wit-bindgen/src/lib.rs b/crates/wit-bindgen/src/lib.rs index a935912aab86..26ce89f8639f 100644 --- a/crates/wit-bindgen/src/lib.rs +++ b/crates/wit-bindgen/src/lib.rs @@ -31,28 +31,35 @@ struct InterfaceName { remapped: bool, /// The string name for this interface. - name: String, + path: String, } #[derive(Default)] struct Wasmtime { src: Source, opts: Opts, - imports: Vec, + import_interfaces: BTreeMap, Vec>, + import_functions: Vec, exports: Exports, types: Types, sizes: SizeAlign, interface_names: HashMap, + with_name_counter: usize, } -enum Import { - Interface { snake: String }, - Function { add_to_linker: String, sig: String }, +struct ImportInterface { + snake: String, + module: String, +} +struct ImportFunction { + add_to_linker: String, + sig: String, } #[derive(Default)] struct Exports { fields: BTreeMap, + modules: BTreeMap, Vec>, funcs: Vec, } @@ -111,16 +118,33 @@ impl Opts { } impl Wasmtime { - fn name_interface(&mut self, id: InterfaceId, name: String) -> bool { - let entry = if let Some(remapped_name) = self.opts.with.get(&name) { + fn name_interface(&mut self, resolve: &Resolve, id: InterfaceId, name: &WorldKey) -> bool { + let with_name = resolve.name_world_key(name); + let entry = if let Some(remapped_path) = self.opts.with.get(&with_name) { + let name = format!("__with_name{}", self.with_name_counter); + self.with_name_counter += 1; + uwriteln!(self.src, "use {remapped_path} as {name};"); InterfaceName { remapped: true, - name: remapped_name.clone(), + path: name, } } else { + let path = match name { + WorldKey::Name(name) => name.to_snake_case(), + WorldKey::Interface(_) => { + let iface = &resolve.interfaces[id]; + let pkgname = &resolve.packages[iface.package.unwrap()].name; + format!( + "{}::{}::{}", + pkgname.namespace.to_snake_case(), + pkgname.name.to_snake_case(), + iface.name.as_ref().unwrap().to_snake_case() + ) + } + }; InterfaceName { remapped: false, - name, + path, } }; @@ -146,30 +170,38 @@ impl Wasmtime { self.finish(resolve, id) } - fn import(&mut self, resolve: &Resolve, name: &str, item: &WorldItem) { - let snake = name.to_snake_case(); + fn import(&mut self, resolve: &Resolve, name: &WorldKey, item: &WorldItem) { let mut gen = InterfaceGenerator::new(self, resolve); - let import = match item { + match item { WorldItem::Function(func) => { gen.generate_function_trait_sig(TypeOwner::None, func); let sig = mem::take(&mut gen.src).into(); gen.generate_add_function_to_linker(TypeOwner::None, func, "linker"); let add_to_linker = gen.src.into(); - Import::Function { sig, add_to_linker } + self.import_functions + .push(ImportFunction { sig, add_to_linker }); } WorldItem::Interface(id) => { - if gen.gen.name_interface(*id, snake.clone()) { + if gen.gen.name_interface(resolve, *id, name) { return; } - gen.current_interface = Some(*id); + gen.current_interface = Some((*id, name, false)); gen.types(*id); gen.generate_trappable_error_types(TypeOwner::Interface(*id)); - gen.generate_add_to_linker(*id, name); + let key_name = resolve.name_world_key(name); + gen.generate_add_to_linker(*id, &key_name); let module = &gen.src[..]; - uwriteln!( - self.src, + let snake = match name { + WorldKey::Name(s) => s.to_snake_case(), + WorldKey::Interface(id) => resolve.interfaces[*id] + .name + .as_ref() + .unwrap() + .to_snake_case(), + }; + let module = format!( " #[allow(clippy::all)] pub mod {snake} {{ @@ -180,40 +212,55 @@ impl Wasmtime { }} " ); - Import::Interface { snake } + let pkg = resolve.interfaces[*id].package.unwrap(); + let pkgname = match name { + WorldKey::Name(_) => None, + WorldKey::Interface(_) => Some(resolve.packages[pkg].name.clone()), + }; + self.import_interfaces + .entry(pkgname) + .or_insert(Vec::new()) + .push(ImportInterface { snake, module }); } WorldItem::Type(ty) => { + let name = match name { + WorldKey::Name(name) => name, + WorldKey::Interface(_) => unreachable!(), + }; gen.define_type(name, *ty); let body = mem::take(&mut gen.src); self.src.push_str(&body); - return; } }; - - self.imports.push(import); } - fn export(&mut self, resolve: &Resolve, name: &str, item: &WorldItem) { - let snake = name.to_snake_case(); + fn export(&mut self, resolve: &Resolve, name: &WorldKey, item: &WorldItem) { let mut gen = InterfaceGenerator::new(self, resolve); - let (ty, getter) = match item { + let (field, ty, getter) = match item { WorldItem::Function(func) => { - gen.define_rust_guest_export(None, func); + gen.define_rust_guest_export(resolve, None, func); let body = mem::take(&mut gen.src).into(); let (_name, getter) = gen.extract_typed_function(func); assert!(gen.src.is_empty()); self.exports.funcs.push(body); - ("wasmtime::component::Func".to_string(), getter) + ( + func.name.to_snake_case(), + "wasmtime::component::Func".to_string(), + getter, + ) } WorldItem::Type(_) => unreachable!(), WorldItem::Interface(id) => { - gen.gen.name_interface(*id, snake.clone()); - gen.current_interface = Some(*id); + gen.gen.name_interface(resolve, *id, name); + gen.current_interface = Some((*id, name, true)); gen.types(*id); gen.generate_trappable_error_types(TypeOwner::Interface(*id)); let iface = &resolve.interfaces[*id]; - - let camel = to_rust_upper_camel_case(name); + let iface_name = match name { + WorldKey::Name(name) => name, + WorldKey::Interface(_) => iface.name.as_ref().unwrap(), + }; + let camel = to_rust_upper_camel_case(iface_name); uwriteln!(gen.src, "pub struct {camel} {{"); for (_, func) in iface.functions.iter() { uwriteln!( @@ -246,14 +293,14 @@ impl Wasmtime { uwriteln!(gen.src, "}})"); uwriteln!(gen.src, "}}"); for (_, func) in iface.functions.iter() { - gen.define_rust_guest_export(Some(name), func); + gen.define_rust_guest_export(resolve, Some(name), func); } uwriteln!(gen.src, "}}"); let module = &gen.src[..]; + let snake = iface_name.to_snake_case(); - uwriteln!( - self.src, + let module = format!( " #[allow(clippy::all)] pub mod {snake} {{ @@ -264,26 +311,54 @@ impl Wasmtime { }} " ); - + let pkgname = match name { + WorldKey::Name(_) => None, + WorldKey::Interface(_) => { + Some(resolve.packages[iface.package.unwrap()].name.clone()) + } + }; + self.exports + .modules + .entry(pkgname.clone()) + .or_insert(Vec::new()) + .push(module); + + let name = resolve.name_world_key(name); + let (path, method_name) = match pkgname { + Some(pkgname) => ( + format!( + "exports::{}::{}::{snake}::{camel}", + pkgname.namespace.to_snake_case(), + pkgname.name.to_snake_case(), + ), + format!( + "{}_{}_{snake}", + pkgname.namespace.to_snake_case(), + pkgname.name.to_snake_case() + ), + ), + None => (format!("exports::{snake}::{camel}"), snake.clone()), + }; let getter = format!( "\ - {snake}::{camel}::new( + {path}::new( &mut __exports.instance(\"{name}\") .ok_or_else(|| anyhow::anyhow!(\"exported instance `{name}` not present\"))? )?\ " ); + let field = format!("interface{}", self.exports.fields.len()); self.exports.funcs.push(format!( " - pub fn {snake}(&self) -> &{snake}::{camel} {{ - &self.{snake} + pub fn {method_name}(&self) -> &{path} {{ + &self.{field} }} - " + ", )); - (format!("{snake}::{camel}"), getter) + (field, path, getter) } }; - let prev = self.exports.fields.insert(snake.clone(), (ty, getter)); + let prev = self.exports.fields.insert(field, (ty, getter)); assert!(prev.is_none()); } @@ -375,6 +450,20 @@ impl Wasmtime { self.build_struct(resolve, world) } + let imports = mem::take(&mut self.import_interfaces); + self.emit_modules( + &imports + .into_iter() + .map(|(k, v)| (k, v.into_iter().map(|m| m.module).collect())) + .collect(), + ); + if !self.exports.modules.is_empty() { + uwriteln!(self.src, "pub mod exports {{"); + let exports = mem::take(&mut self.exports.modules); + self.emit_modules(&exports); + uwriteln!(self.src, "}}"); + } + let mut src = mem::take(&mut self.src); if self.opts.rustfmt { let mut child = Command::new("rustfmt") @@ -402,21 +491,42 @@ impl Wasmtime { src.into() } + + fn emit_modules(&mut self, modules: &BTreeMap, Vec>) { + let mut map = BTreeMap::new(); + for (pkg, modules) in modules { + match pkg { + Some(pkg) => { + let prev = map + .entry(&pkg.namespace) + .or_insert(BTreeMap::new()) + .insert(&pkg.name, modules); + assert!(prev.is_none()); + } + None => { + for module in modules { + uwriteln!(self.src, "{module}"); + } + } + } + } + for (ns, pkgs) in map { + uwriteln!(self.src, "pub mod {} {{", ns.to_snake_case()); + for (pkg, modules) in pkgs { + uwriteln!(self.src, "pub mod {} {{", pkg.to_snake_case()); + for module in modules { + uwriteln!(self.src, "{module}"); + } + uwriteln!(self.src, "}}"); + } + uwriteln!(self.src, "}}"); + } + } } impl Wasmtime { fn toplevel_import_trait(&mut self, resolve: &Resolve, world: WorldId) { - let mut functions = Vec::new(); - for import in self.imports.iter() { - match import { - Import::Interface { .. } => continue, - Import::Function { - sig, - add_to_linker: _, - } => functions.push(sig), - } - } - if functions.is_empty() { + if self.import_functions.is_empty() { return; } @@ -425,26 +535,29 @@ impl Wasmtime { uwriteln!(self.src, "#[wasmtime::component::__internal::async_trait]") } uwriteln!(self.src, "pub trait {world_camel}Imports {{"); - for sig in functions { - self.src.push_str(sig); + for f in self.import_functions.iter() { + self.src.push_str(&f.sig); self.src.push_str("\n"); } uwriteln!(self.src, "}}"); } fn toplevel_add_to_linker(&mut self, resolve: &Resolve, world: WorldId) { - if self.imports.is_empty() { + if self.import_interfaces.is_empty() && self.import_functions.is_empty() { return; } - let mut functions = Vec::new(); let mut interfaces = Vec::new(); - for import in self.imports.iter() { - match import { - Import::Interface { snake } => interfaces.push(snake), - Import::Function { - add_to_linker, - sig: _, - } => functions.push(add_to_linker), + for (pkg, imports) in self.import_interfaces.iter() { + for import in imports { + let mut path = String::new(); + if let Some(pkg) = pkg { + path.push_str(&pkg.namespace.to_snake_case()); + path.push_str("::"); + path.push_str(&pkg.name.to_snake_case()); + path.push_str("::"); + } + path.push_str(&import.snake); + interfaces.push(path) } } @@ -463,7 +576,7 @@ impl Wasmtime { for (i, name) in interfaces .iter() .map(|n| format!("{n}::Host")) - .chain(if functions.is_empty() { + .chain(if self.import_functions.is_empty() { None } else { Some(world_trait.clone()) @@ -485,11 +598,11 @@ impl Wasmtime { for name in interfaces.iter() { uwriteln!(self.src, "{name}::add_to_linker(linker, get)?;"); } - if !functions.is_empty() { + if !self.import_functions.is_empty() { uwriteln!(self.src, "Self::add_root_to_linker(linker, get)?;"); } uwriteln!(self.src, "Ok(())\n}}"); - if functions.is_empty() { + if self.import_functions.is_empty() { return; } @@ -505,8 +618,8 @@ impl Wasmtime { let mut linker = linker.root(); ", ); - for add_to_linker in functions { - self.src.push_str(add_to_linker); + for f in self.import_functions.iter() { + self.src.push_str(&f.add_to_linker); self.src.push_str("\n"); } uwriteln!(self.src, "Ok(())\n}}"); @@ -517,7 +630,7 @@ struct InterfaceGenerator<'a> { src: Source, gen: &'a mut Wasmtime, resolve: &'a Resolve, - current_interface: Option, + current_interface: Option<(InterfaceId, &'a WorldKey, bool)>, } impl<'a> InterfaceGenerator<'a> { @@ -1263,7 +1376,12 @@ impl<'a> InterfaceGenerator<'a> { ret } - fn define_rust_guest_export(&mut self, ns: Option<&str>, func: &Function) { + fn define_rust_guest_export( + &mut self, + resolve: &Resolve, + ns: Option<&WorldKey>, + func: &Function, + ) { let (async_, async__, await_) = if self.gen.opts.async_ { ("async", "_async", ".await") } else { @@ -1292,17 +1410,20 @@ impl<'a> InterfaceGenerator<'a> { } if self.gen.opts.tracing { + let ns = match ns { + Some(key) => resolve.name_world_key(key), + None => "default".to_string(), + }; self.src.push_str(&format!( " let span = tracing::span!( tracing::Level::TRACE, \"wit-bindgen export\", - module = \"{}\", + module = \"{ns}\", function = \"{}\", ); let _enter = span.enter(); ", - ns.unwrap_or("default"), func.name, )); } @@ -1466,17 +1587,26 @@ impl<'a> RustGenerator<'a> for InterfaceGenerator<'a> { } fn path_to_interface(&self, interface: InterfaceId) -> Option { - match self.current_interface { - Some(id) if id == interface => None, - _ => { - let InterfaceName { remapped, name } = &self.gen.interface_names[&interface]; - Some(if self.current_interface.is_some() && !remapped { - format!("super::{name}") - } else { - name.clone() - }) + let mut path_to_root = String::new(); + if let Some((cur, key, is_export)) = self.current_interface { + if cur == interface { + return None; + } + match key { + WorldKey::Name(_) => { + path_to_root.push_str("super::"); + } + WorldKey::Interface(_) => { + path_to_root.push_str("super::super::super::"); + } + } + if is_export { + path_to_root.push_str("super::"); } } + let InterfaceName { path, .. } = &self.gen.interface_names[&interface]; + path_to_root.push_str(path); + Some(path_to_root) } fn push_str(&mut self, s: &str) { diff --git a/supply-chain/imports.lock b/supply-chain/imports.lock index ea3707aac91a..f017f8768d14 100644 --- a/supply-chain/imports.lock +++ b/supply-chain/imports.lock @@ -64,6 +64,13 @@ user-id = 1 user-login = "alexcrichton" user-name = "Alex Crichton" +[[publisher.wasm-encoder]] +version = "0.29.0" +when = "2023-05-26" +user-id = 1 +user-login = "alexcrichton" +user-name = "Alex Crichton" + [[publisher.wasm-metadata]] version = "0.5.0" when = "2023-04-27" @@ -78,6 +85,13 @@ user-id = 1 user-login = "alexcrichton" user-name = "Alex Crichton" +[[publisher.wasm-metadata]] +version = "0.8.0" +when = "2023-05-26" +user-id = 1 +user-login = "alexcrichton" +user-name = "Alex Crichton" + [[publisher.wasm-mutate]] version = "0.2.25" when = "2023-05-15" @@ -85,6 +99,13 @@ user-id = 1 user-login = "alexcrichton" user-name = "Alex Crichton" +[[publisher.wasm-mutate]] +version = "0.2.27" +when = "2023-05-26" +user-id = 1 +user-login = "alexcrichton" +user-name = "Alex Crichton" + [[publisher.wasm-smith]] version = "0.12.8" when = "2023-05-15" @@ -92,6 +113,13 @@ user-id = 1 user-login = "alexcrichton" user-name = "Alex Crichton" +[[publisher.wasm-smith]] +version = "0.12.10" +when = "2023-05-26" +user-id = 1 +user-login = "alexcrichton" +user-name = "Alex Crichton" + [[publisher.wasmparser]] version = "0.104.0" when = "2023-04-27" @@ -106,72 +134,72 @@ user-id = 1 user-login = "alexcrichton" user-name = "Alex Crichton" -[[publisher.wasmprinter]] -version = "0.2.57" -when = "2023-05-15" +[[publisher.wasmparser]] +version = "0.107.0" +when = "2023-05-26" user-id = 1 user-login = "alexcrichton" user-name = "Alex Crichton" -[[publisher.wast]] -version = "58.0.0" +[[publisher.wasmprinter]] +version = "0.2.57" when = "2023-05-15" user-id = 1 user-login = "alexcrichton" user-name = "Alex Crichton" -[[publisher.wat]] -version = "1.0.64" -when = "2023-05-15" +[[publisher.wasmprinter]] +version = "0.2.59" +when = "2023-05-26" user-id = 1 user-login = "alexcrichton" user-name = "Alex Crichton" -[[publisher.wit-bindgen]] -version = "0.6.0" -when = "2023-04-27" +[[publisher.wast]] +version = "58.0.0" +when = "2023-05-15" user-id = 1 user-login = "alexcrichton" user-name = "Alex Crichton" -[[publisher.wit-bindgen-core]] -version = "0.6.0" -when = "2023-04-27" +[[publisher.wast]] +version = "60.0.0" +when = "2023-05-26" user-id = 1 user-login = "alexcrichton" user-name = "Alex Crichton" -[[publisher.wit-bindgen-rust]] -version = "0.6.0" -when = "2023-04-27" +[[publisher.wat]] +version = "1.0.64" +when = "2023-05-15" user-id = 1 user-login = "alexcrichton" user-name = "Alex Crichton" -[[publisher.wit-bindgen-rust-lib]] -version = "0.6.0" -when = "2023-04-27" +[[publisher.wat]] +version = "1.0.66" +when = "2023-05-26" user-id = 1 user-login = "alexcrichton" user-name = "Alex Crichton" -[[publisher.wit-bindgen-rust-macro]] -version = "0.6.0" +[[publisher.wit-component]] +version = "0.8.2" when = "2023-04-27" user-id = 1 user-login = "alexcrichton" user-name = "Alex Crichton" [[publisher.wit-component]] -version = "0.8.2" -when = "2023-04-27" +version = "0.9.0" +when = "2023-05-16" user-id = 1 user-login = "alexcrichton" user-name = "Alex Crichton" [[publisher.wit-component]] -version = "0.9.0" -when = "2023-05-16" +version = "0.11.0" +when = "2023-05-26" user-id = 1 user-login = "alexcrichton" user-name = "Alex Crichton" @@ -183,6 +211,13 @@ user-id = 1 user-login = "alexcrichton" user-name = "Alex Crichton" +[[publisher.wit-parser]] +version = "0.8.0" +when = "2023-05-26" +user-id = 1 +user-login = "alexcrichton" +user-name = "Alex Crichton" + [[audits.embark-studios.audits.anyhow]] who = "Johan Andersson " criteria = "safe-to-deploy" diff --git a/tests/all/component_model/bindgen.rs b/tests/all/component_model/bindgen.rs index d8c8f3023cd4..c377f08a6579 100644 --- a/tests/all/component_model/bindgen.rs +++ b/tests/all/component_model/bindgen.rs @@ -14,7 +14,9 @@ mod no_imports { wasmtime::component::bindgen!({ inline: " - default world no-imports { + package foo:foo + + world no-imports { export foo: interface { foo: func() } @@ -59,7 +61,9 @@ mod one_import { wasmtime::component::bindgen!({ inline: " - default world one-import { + package foo:foo + + world one-import { import foo: interface { foo: func() } diff --git a/tests/all/component_model/bindgen/results.rs b/tests/all/component_model/bindgen/results.rs index eaec5cc3ac4c..d0c49e40245e 100644 --- a/tests/all/component_model/bindgen/results.rs +++ b/tests/all/component_model/bindgen/results.rs @@ -9,7 +9,8 @@ mod empty_error { use super::*; wasmtime::component::bindgen!({ inline: " - default world result-playground { + package inline:inline + world result-playground { import imports: interface { empty-error: func(a: float64) -> result } @@ -109,7 +110,8 @@ mod string_error { use super::*; wasmtime::component::bindgen!({ inline: " - default world result-playground { + package inline:inline + world result-playground { import imports: interface { string-error: func(a: float64) -> result } @@ -219,14 +221,18 @@ mod string_error { mod enum_error { use super::*; + use exports::foo; + use inline::inline::imports; + wasmtime::component::bindgen!({ inline: " + package inline:inline interface imports { enum e1 { a, b, c } enum-error: func(a: float64) -> result } - default world result-playground { - import imports: self.imports + world result-playground { + import imports export foo: interface { enum e1 { a, b, c } enum-error: func(a: float64) -> result @@ -244,7 +250,7 @@ mod enum_error { r#" (component (type $err' (enum "a" "b" "c")) - (import "imports" (instance $i + (import (interface "inline:inline/imports") (instance $i (export $err "err" (type (eq $err'))) (export "enum-error" (func (param "a" float64) (result (result float64 (error $err))))) )) @@ -357,7 +363,7 @@ mod enum_error { .expect("no trap") .err() .expect("error returned"); - assert_eq!(e, enum_error::foo::E1::A); + assert_eq!(e, foo::E1::A); let e = results .foo() @@ -377,14 +383,18 @@ mod enum_error { mod record_error { use super::*; + use exports::foo; + use inline::inline::imports; + wasmtime::component::bindgen!({ inline: " + package inline:inline interface imports { record e2 { line: u32, col: u32 } record-error: func(a: float64) -> result } - default world result-playground { - import imports: self.imports + world result-playground { + import imports export foo: interface { record e2 { line: u32, col: u32 } record-error: func(a: float64) -> result @@ -407,7 +417,7 @@ mod record_error { (field "line" u32) (field "col" u32) )) - (import "imports" (instance $i + (import (interface "inline:inline/imports") (instance $i (export $e2 "e2" (type (eq $e2'))) (type $result (result float64 (error $e2))) (export "record-error" (func (param "a" float64) (result $result))) @@ -525,16 +535,20 @@ mod record_error { mod variant_error { use super::*; + use exports::foo; + use inline::inline::imports; + wasmtime::component::bindgen!({ inline: " + package inline:inline interface imports { enum e1 { a, b, c } record e2 { line: u32, col: u32 } variant e3 { E1(e1), E2(e2) } variant-error: func(a: float64) -> result } - default world result-playground { - import imports: self.imports + world result-playground { + import imports export foo: interface { enum e1 { a, b, c } record e2 { line: u32, col: u32 } @@ -559,7 +573,7 @@ mod variant_error { (case "E1" $e1') (case "E2" $e2') )) - (import "imports" (instance $i + (import (interface "inline:inline/imports") (instance $i (export $e1 "e1" (type (eq $e1'))) (export $e2 "e2" (type (eq $e2'))) (type $e3' (variant @@ -710,7 +724,8 @@ mod with_remapping { wasmtime::component::bindgen!({ inline: " - default world result-playground { + package inline:inline + world result-playground { import imports: interface { empty-error: func(a: float64) -> result }