diff --git a/Cargo.lock b/Cargo.lock index 4acc2e888..f64dad37a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3303,7 +3303,7 @@ version = "0.0.0" dependencies = [ "codegen-macro", "wit-bindgen-core", - "wit-parser 0.220.0", + "wit-parser 0.223.0", ] [[package]] @@ -4081,16 +4081,6 @@ dependencies = [ "wasmparser 0.219.1", ] -[[package]] -name = "wasm-encoder" -version = "0.220.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebf48234b389415b226a4daef6562933d38c7b28a8b8f64c5c4130dad1561ab7" -dependencies = [ - "leb128", - "wasmparser 0.220.0", -] - [[package]] name = "wasm-encoder" version = "0.221.2" @@ -4102,26 +4092,20 @@ dependencies = [ ] [[package]] -name = "wasm-metadata" -version = "0.220.0" +name = "wasm-encoder" +version = "0.223.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f3e5f5920c5abfc45573c89b07b38efdaae1515ef86f83dad12d60e50ecd62b" +checksum = "7e636076193fa68103e937ac951b5f2f587624097017d764b8984d9c0f149464" dependencies = [ - "anyhow", - "indexmap", - "serde", - "serde_derive", - "serde_json", - "spdx", - "wasm-encoder 0.220.0", - "wasmparser 0.220.0", + "leb128", + "wasmparser 0.223.0", ] [[package]] name = "wasm-metadata" -version = "0.221.2" +version = "0.223.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9a7018a96c4f55a8f339954c66e09728f2d6112689000e58f15f6a6d7436e8f" +checksum = "5c730c3379d3d20e5a0245b0724b924483e853588ca8fba547c1e21f19e7d735" dependencies = [ "anyhow", "indexmap", @@ -4129,8 +4113,9 @@ dependencies = [ "serde_derive", "serde_json", "spdx", - "wasm-encoder 0.221.2", - "wasmparser 0.221.2", + "url", + "wasm-encoder 0.223.0", + "wasmparser 0.223.0", ] [[package]] @@ -4162,22 +4147,20 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.220.0" +version = "0.221.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e246c2772ce3ebc83f89a2d4487ac5794cad6c309b2071818a88c7db7c36d87b" +checksum = "9845c470a2e10b61dd42c385839cdd6496363ed63b5c9e420b5488b77bd22083" dependencies = [ - "ahash", "bitflags 2.6.0", - "hashbrown 0.14.5", "indexmap", "semver", ] [[package]] name = "wasmparser" -version = "0.221.2" +version = "0.223.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9845c470a2e10b61dd42c385839cdd6496363ed63b5c9e420b5488b77bd22083" +checksum = "d5a99faceb1a5a84dd6084ec4bfa4b2ab153b5793b43fd8f58b89232634afc35" dependencies = [ "bitflags 2.6.0", "hashbrown 0.15.2", @@ -4800,23 +4783,23 @@ dependencies = [ [[package]] name = "wit-bindgen" -version = "0.36.0" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a2b3e15cd6068f233926e7d8c7c588b2ec4fb7cc7bf3824115e7c7e2a8485a3" +checksum = "9219694564701fa935754f1552ce299154fc74948d6d148134ce55f3504c8bf1" dependencies = [ - "wit-bindgen-rt 0.36.0", + "wit-bindgen-rt 0.37.0", "wit-bindgen-rust-macro", ] [[package]] name = "wit-bindgen-core" -version = "0.36.0" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b632a5a0fa2409489bd49c9e6d99fcc61bb3d4ce9d1907d44662e75a28c71172" +checksum = "8ba105733ba146c94e067793fb46505265ea8720eb14ceae65b10797c7728a65" dependencies = [ "anyhow", "heck", - "wit-parser 0.220.0", + "wit-parser 0.223.0", ] [[package]] @@ -4830,34 +4813,34 @@ dependencies = [ [[package]] name = "wit-bindgen-rt" -version = "0.36.0" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7947d0131c7c9da3f01dfde0ab8bd4c4cf3c5bd49b6dba0ae640f1fa752572ea" +checksum = "fc801b991c56492f87ab3086e786468f75c285a4d73017ab0ebc2fa1aed5d82c" dependencies = [ "bitflags 2.6.0", ] [[package]] name = "wit-bindgen-rust" -version = "0.36.0" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4329de4186ee30e2ef30a0533f9b3c123c019a237a7c82d692807bf1b3ee2697" +checksum = "257e0d217bc06635837d751447c39e77b9901752e052288ff6fe0fdb17850bc5" dependencies = [ "anyhow", "heck", "indexmap", "prettyplease", "syn", - "wasm-metadata 0.220.0", + "wasm-metadata", "wit-bindgen-core", - "wit-component 0.220.0", + "wit-component", ] [[package]] name = "wit-bindgen-rust-macro" -version = "0.36.0" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "177fb7ee1484d113b4792cc480b1ba57664bbc951b42a4beebe573502135b1fc" +checksum = "8ac98caa9302234687b8e67ce7dfcf31ae5238523f166b93c23988fd0d4e0594" dependencies = [ "anyhow", "prettyplease", @@ -4932,28 +4915,9 @@ dependencies = [ [[package]] name = "wit-component" -version = "0.220.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73ccedf54cc65f287da268d64d2bf4f7530d2cfb2296ffbe3ad5f65567e4cf53" -dependencies = [ - "anyhow", - "bitflags 2.6.0", - "indexmap", - "log", - "serde", - "serde_derive", - "serde_json", - "wasm-encoder 0.220.0", - "wasm-metadata 0.220.0", - "wasmparser 0.220.0", - "wit-parser 0.220.0", -] - -[[package]] -name = "wit-component" -version = "0.221.2" +version = "0.223.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c6b907a1af1f2cf2160d7fe2ff5967cef120dc5c034d22593a1f24e40272cb2" +checksum = "c10ed2aeee4c8ec5715875f62f4a3de3608d6987165c116810d8c2908aa9d93b" dependencies = [ "anyhow", "bitflags 2.6.0", @@ -4962,10 +4926,10 @@ dependencies = [ "serde", "serde_derive", "serde_json", - "wasm-encoder 0.221.2", - "wasm-metadata 0.221.2", - "wasmparser 0.221.2", - "wit-parser 0.221.2", + "wasm-encoder 0.223.0", + "wasm-metadata", + "wasmparser 0.223.0", + "wit-parser 0.223.0", ] [[package]] @@ -4988,9 +4952,9 @@ dependencies = [ [[package]] name = "wit-parser" -version = "0.220.0" +version = "0.223.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b7117ce3adc0b4354b46dc1cf3190b00b333e65243d244c613ffcc58bdec84d" +checksum = "92772f4dcacb804b275981eea1d920b12b377993b53307f1e33d87404e080281" dependencies = [ "anyhow", "id-arena", @@ -5001,25 +4965,7 @@ dependencies = [ "serde_derive", "serde_json", "unicode-xid", - "wasmparser 0.220.0", -] - -[[package]] -name = "wit-parser" -version = "0.221.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbe1538eea6ea5ddbe5defd0dc82539ad7ba751e1631e9185d24a931f0a5adc8" -dependencies = [ - "anyhow", - "id-arena", - "indexmap", - "log", - "semver", - "serde", - "serde_derive", - "serde_json", - "unicode-xid", - "wasmparser 0.221.2", + "wasmparser 0.223.0", ] [[package]] @@ -5079,7 +5025,7 @@ dependencies = [ name = "wrpc-introspect" version = "0.6.0" dependencies = [ - "wit-parser 0.220.0", + "wit-parser 0.223.0", ] [[package]] @@ -5107,7 +5053,7 @@ dependencies = [ "wasm-tokio", "wasmtime", "wasmtime-wasi", - "wit-parser 0.220.0", + "wit-parser 0.223.0", "wrpc-introspect", "wrpc-transport", ] @@ -5245,12 +5191,12 @@ dependencies = [ "tracing", "url", "wasi-preview1-component-adapter-provider", - "wasmparser 0.221.2", + "wasmparser 0.223.0", "wasmtime", "wasmtime-cli-flags", "wasmtime-wasi", "wasmtime-wasi-http", - "wit-component 0.221.2", + "wit-component", "wrpc-cli", "wrpc-runtime-wasmtime", "wrpc-transport", diff --git a/Cargo.toml b/Cargo.toml index c93027ba8..207bf8357 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -161,19 +161,19 @@ uuid = { version = "1", default-features = false } wasi = { version = "0.13", default-features = false } wasi-preview1-component-adapter-provider = { version = "27", default-features = false } wasm-tokio = { version = "0.6", default-features = false } -wasmparser = { version = "0.221", default-features = false } +wasmparser = { version = "0.223", default-features = false } wasmtime = { version = "27", default-features = false } wasmtime-cli-flags = { version = "27", default-features = false } wasmtime-wasi = { version = "27", default-features = false } wasmtime-wasi-http = { version = "27", default-features = false } -wit-bindgen = { version = "0.36", default-features = false } -wit-bindgen-core = { version = "0.36", default-features = false } +wit-bindgen = { version = "0.37", default-features = false } +wit-bindgen-core = { version = "0.37", default-features = false } wit-bindgen-wrpc = { version = "0.9", default-features = false, path = "./crates/wit-bindgen" } wit-bindgen-wrpc-go = { version = "0.11", default-features = false, path = "./crates/wit-bindgen-go" } wit-bindgen-wrpc-rust = { version = "0.9", default-features = false, path = "./crates/wit-bindgen-rust" } wit-bindgen-wrpc-rust-macro = { version = "0.9", default-features = false, path = "./crates/wit-bindgen-rust-macro" } -wit-component = { version = "0.221", default-features = false } -wit-parser = { version = "0.220", default-features = false } +wit-component = { version = "0.223", default-features = false } +wit-parser = { version = "0.223", default-features = false } wrpc-cli = { version = "0.5", path = "./crates/cli", default-features = false } wrpc-introspect = { version = "0.6", default-features = false, path = "./crates/introspect" } wrpc-runtime-wasmtime = { version = "0.26", path = "./crates/runtime-wasmtime", default-features = false } diff --git a/crates/introspect/src/lib.rs b/crates/introspect/src/lib.rs index 0a1cc8657..fda634fb8 100644 --- a/crates/introspect/src/lib.rs +++ b/crates/introspect/src/lib.rs @@ -1,8 +1,8 @@ use std::collections::{BTreeSet, VecDeque}; use wit_parser::{ - Case, Field, Flags, Function, FunctionKind, Handle, Int, Record, Resolve, Stream, Type, - TypeDefKind, TypeId, + Case, Field, Flags, Function, FunctionKind, Handle, Int, Record, Resolve, Type, TypeDefKind, + TypeId, }; #[must_use] @@ -188,22 +188,21 @@ pub fn async_paths_tyid(resolve: &Resolve, id: TypeId) -> (BTreeSet { + TypeDefKind::Stream(ty) => { let mut paths = BTreeSet::new(); - if let Some(ty) = element { - let (nested, fut) = async_paths_ty(resolve, ty); - for mut path in nested { - path.push_front(None); - paths.insert(path); - } - if fut { - paths.insert(vec![None].into()); - } + let (nested, fut) = async_paths_ty(resolve, ty); + for mut path in nested { + path.push_front(None); + paths.insert(path); + } + if fut { + paths.insert(vec![None].into()); } (paths.into_iter().collect(), true) } TypeDefKind::Type(ty) => async_paths_ty(resolve, ty), TypeDefKind::Resource + | TypeDefKind::ErrorContext | TypeDefKind::Flags(..) | TypeDefKind::Enum(..) | TypeDefKind::Handle(Handle::Own(..) | Handle::Borrow(..)) => (BTreeSet::default(), false), diff --git a/crates/test-helpers/src/lib.rs b/crates/test-helpers/src/lib.rs index d48f6cd0d..96c621deb 100644 --- a/crates/test-helpers/src/lib.rs +++ b/crates/test-helpers/src/lib.rs @@ -31,9 +31,10 @@ pub fn test_directory(suite_name: &str, gen_name: &str, wit_name: &str) -> PathB /// Helper function to execute a process during tests and print informative /// information if it fails. pub fn run_command(cmd: &mut Command) { + let command = format!("{cmd:?}"); let output = cmd .output() - .expect("failed to run executable; is it installed"); + .unwrap_or_else(|e| panic!("failed to run executable: {e}; command was `{command}`")); if output.status.success() { return; diff --git a/crates/transport/src/value.rs b/crates/transport/src/value.rs index 3215b11ee..02ede4fba 100644 --- a/crates/transport/src/value.rs +++ b/crates/transport/src/value.rs @@ -1286,8 +1286,12 @@ pub trait TupleDecode: Decode {} impl Encode for () { type Encoder = UnitCodec; } +impl Encode for &() { + type Encoder = UnitCodec; +} impl TupleEncode for () {} +impl TupleEncode for &() {} impl Decode for () { type Decoder = UnitCodec; diff --git a/crates/wit-bindgen-go/src/interface.rs b/crates/wit-bindgen-go/src/interface.rs index a86491826..d100ee8de 100644 --- a/crates/wit-bindgen-go/src/interface.rs +++ b/crates/wit-bindgen-go/src/interface.rs @@ -6,8 +6,8 @@ use std::mem; use heck::ToUpperCamelCase; use wit_bindgen_core::wit_parser::{ Case, Docs, Enum, EnumCase, Field, Flag, Flags, Function, FunctionKind, Handle, Int, - InterfaceId, Record, Resolve, Result_, Stream, Tuple, Type, TypeDefKind, TypeId, TypeOwner, - Variant, World, WorldKey, + InterfaceId, Record, Resolve, Result_, Tuple, Type, TypeDefKind, TypeId, TypeOwner, Variant, + World, WorldKey, }; use wit_bindgen_core::{uwrite, uwriteln, Source, TypeInfo}; use wrpc_introspect::{async_paths_ty, is_list_of, is_tuple, is_ty, rpc_func_name}; @@ -1069,18 +1069,17 @@ impl InterfaceGenerator<'_> { } } - fn print_read_stream(&mut self, Stream { element, .. }: &Stream, reader: &str, path: &str) { - match element { - Some(ty) if is_ty(self.resolve, Type::U8, ty) => { - let bytes = self.deps.bytes(); - let io = self.deps.io(); - let fmt = self.deps.fmt(); - let slog = self.deps.slog(); - let wrpc = self.deps.wrpc(); + fn print_read_stream(&mut self, ty: &Type, reader: &str, path: &str) { + if is_ty(self.resolve, Type::U8, ty) { + let bytes = self.deps.bytes(); + let io = self.deps.io(); + let fmt = self.deps.fmt(); + let slog = self.deps.slog(); + let wrpc = self.deps.wrpc(); - uwriteln!( - self.src, - r#"func(r {wrpc}.IndexReadCloser, path ...uint32) ({io}.ReadCloser, error) {{ + uwriteln!( + self.src, + r#"func(r {wrpc}.IndexReadCloser, path ...uint32) ({io}.ReadCloser, error) {{ {slog}.Debug("reading byte stream status byte") status, err := r.ReadByte() if err != nil {{ @@ -1099,11 +1098,11 @@ impl InterfaceGenerator<'_> { case 1: {slog}.Debug("reading ready byte stream contents") buf, err := "# - ); - self.print_read_byte_list("r"); - uwrite!( - self.src, - r#" + ); + self.print_read_byte_list("r"); + uwrite!( + self.src, + r#" if err != nil {{ return nil, {fmt}.Errorf("failed to read ready byte stream contents: %w", err) }} @@ -1113,30 +1112,29 @@ impl InterfaceGenerator<'_> { return nil, {fmt}.Errorf("invalid stream status byte %d", status) }} }}({reader}"# - ); - if !path.is_empty() { - self.src.push_str(", "); - self.src.push_str(path); - self.src.push_str("..."); - } - self.src.push_str(")"); + ); + if !path.is_empty() { + self.src.push_str(", "); + self.src.push_str(path); + self.src.push_str("..."); } - Some(ty) => { - let errors = self.deps.errors(); - let fmt = self.deps.fmt(); - let io = self.deps.io(); - let math = self.deps.math(); - let slog = self.deps.slog(); - let wrpc = self.deps.wrpc(); + self.src.push_str(")"); + } else { + let errors = self.deps.errors(); + let fmt = self.deps.fmt(); + let io = self.deps.io(); + let math = self.deps.math(); + let slog = self.deps.slog(); + let wrpc = self.deps.wrpc(); - uwrite!( - self.src, - r#"func(r {wrpc}.IndexReadCloser, path ...uint32) ({wrpc}.Receiver["# - ); - self.print_list(ty); - uwrite!( - self.src, - r#"], error) {{ + uwrite!( + self.src, + r#"func(r {wrpc}.IndexReadCloser, path ...uint32) ({wrpc}.Receiver["# + ); + self.print_list(ty); + uwrite!( + self.src, + r#"], error) {{ {slog}.Debug("reading stream status byte") status, err := r.ReadByte() if err != nil {{ @@ -1153,18 +1151,18 @@ impl InterfaceGenerator<'_> { }} var total uint32 return {wrpc}.NewDecodeReceiver(r, func(r {wrpc}.IndexReadCloser) ("# - ); - self.print_list(ty); - uwrite!( - self.src, - r#", error) {{ + ); + self.print_list(ty); + uwrite!( + self.src, + r#", error) {{ {slog}.Debug("reading pending stream chunk length") n, err := "# - ); - self.print_read_u32("r"); - uwrite!( - self.src, - r#" + ); + self.print_read_u32("r"); + uwrite!( + self.src, + r#" if err != nil {{ return nil, {fmt}.Errorf("failed to read pending stream chunk length: %w", err) }} @@ -1175,19 +1173,19 @@ impl InterfaceGenerator<'_> { return nil, {errors}.New("total incoming pending stream element count would overflow a 32-bit unsigned integer") }} vs := make("# - ); - self.print_list(ty); - uwrite!( - self.src, - r#", n) + ); + self.print_list(ty); + uwrite!( + self.src, + r#", n) for i := range vs {{ {slog}.Debug("reading pending stream element", "i", total) v, err := "# - ); - self.print_read_ty(ty, "r", "[]uint32{total}"); - uwriteln!( - self.src, - r#" + ); + self.print_read_ty(ty, "r", "[]uint32{total}"); + uwriteln!( + self.src, + r#" if err != nil {{ return nil, {fmt}.Errorf("failed to read pending stream chunk element %d: %w", i, err) }} @@ -1199,11 +1197,11 @@ impl InterfaceGenerator<'_> { case 1: {slog}.Debug("reading ready stream contents") vs, err := "# - ); - self.print_read_list(ty, "r", "path"); - uwrite!( - self.src, - r#" + ); + self.print_read_list(ty, "r", "path"); + uwrite!( + self.src, + r#" if err != nil {{ return nil, {fmt}.Errorf("failed to read ready stream contents: %w", err) }} @@ -1213,18 +1211,27 @@ impl InterfaceGenerator<'_> { return nil, {fmt}.Errorf("invalid stream status byte %d", status) }} }}({reader}"# - ); - if !path.is_empty() { - self.src.push_str(", "); - self.src.push_str(path); - self.src.push_str("..."); - } - self.src.push_str(")"); + ); + if !path.is_empty() { + self.src.push_str(", "); + self.src.push_str(path); + self.src.push_str("..."); } - None => panic!("streams with no element types are not supported"), + self.src.push_str(")"); } } + fn print_read_error_context(&mut self, reader: &str) { + // TODO: Define error context encoding and read it + let io = self.deps.io(); + uwrite!( + self.src, + r#"func(r {io}.ByteReader) (struct{{}}, error) {{ + return struct{{}}{{}}, nil +}}({reader})"#, + ); + } + fn print_read_own(&mut self, reader: &str, id: TypeId) { let errors = self.deps.errors(); let fmt = self.deps.fmt(); @@ -1372,6 +1379,7 @@ impl InterfaceGenerator<'_> { TypeDefKind::List(ty) => self.print_read_list(ty, reader, path), TypeDefKind::Future(ty) => self.print_read_future(ty, reader, path), TypeDefKind::Stream(ty) => self.print_read_stream(ty, reader, path), + TypeDefKind::ErrorContext => self.print_read_error_context(reader), TypeDefKind::Type(ty) => { if let Some(name) = name { self.push_str("func() ("); @@ -2063,17 +2071,16 @@ impl InterfaceGenerator<'_> { } } - fn print_write_stream(&mut self, Stream { element, .. }: &Stream, name: &str, writer: &str) { - match element { - Some(ty) if is_ty(self.resolve, Type::U8, ty) => { - let fmt = self.deps.fmt(); - let io = self.deps.io(); - let math = self.deps.math(); - let slog = self.deps.slog(); - let wrpc = self.deps.wrpc(); - uwrite!( - self.src, - r#"func(v {io}.ReadCloser, w interface {{ {io}.ByteWriter; {io}.Writer }}) (write func({wrpc}.IndexWriter) error, err error) {{ + fn print_write_stream(&mut self, ty: &Type, name: &str, writer: &str) { + if is_ty(self.resolve, Type::U8, ty) { + let fmt = self.deps.fmt(); + let io = self.deps.io(); + let math = self.deps.math(); + let slog = self.deps.slog(); + let wrpc = self.deps.wrpc(); + uwrite!( + self.src, + r#"func(v {io}.ReadCloser, w interface {{ {io}.ByteWriter; {io}.Writer }}) (write func({wrpc}.IndexWriter) error, err error) {{ {slog}.Debug("writing byte stream `stream::pending` status byte") if err = w.WriteByte(0); err != nil {{ return nil, fmt.Errorf("failed to write `stream::pending` byte: %w", err) @@ -2122,22 +2129,21 @@ impl InterfaceGenerator<'_> { }} }}, nil }}({name}, {writer})"#, - ); - } - Some(ty) => { - let atomic = self.deps.atomic(); - let errors = self.deps.errors(); - let fmt = self.deps.fmt(); - let io = self.deps.io(); - let math = self.deps.math(); - let slog = self.deps.slog(); - let sync = self.deps.sync(); - let wrpc = self.deps.wrpc(); - uwrite!(self.src, "func(v {wrpc}.Receiver[",); - self.print_list(ty); - uwrite!( - self.src, - r#"], w interface {{ {io}.ByteWriter; {io}.Writer }}) (write func({wrpc}.IndexWriter) error, err error) {{ + ); + } else { + let atomic = self.deps.atomic(); + let errors = self.deps.errors(); + let fmt = self.deps.fmt(); + let io = self.deps.io(); + let math = self.deps.math(); + let slog = self.deps.slog(); + let sync = self.deps.sync(); + let wrpc = self.deps.wrpc(); + uwrite!(self.src, "func(v {wrpc}.Receiver[",); + self.print_list(ty); + uwrite!( + self.src, + r#"], w interface {{ {io}.ByteWriter; {io}.Writer }}) (write func({wrpc}.IndexWriter) error, err error) {{ {slog}.Debug("writing stream `stream::pending` status byte") if err := w.WriteByte(0); err != nil {{ return nil, fmt.Errorf("failed to write `stream::pending` byte: %w", err) @@ -2180,11 +2186,11 @@ impl InterfaceGenerator<'_> { for _, v := range chunk {{ {slog}.Debug("writing pending stream element", "i", total) write, err :="#, - ); - self.print_write_ty(ty, "v", "w"); - uwrite!( - self.src, - r#" + ); + self.print_write_ty(ty, "v", "w"); + uwrite!( + self.src, + r#" if err != nil {{ return {fmt}.Errorf("failed to write pending stream chunk element %d: %w", total, err) }} @@ -2217,12 +2223,23 @@ impl InterfaceGenerator<'_> { }} }}, nil }}({name}, {writer})"#, - ); - } - None => panic!("streams with no element types are not supported"), + ); } } + fn print_write_error_context(&mut self, name: &str, writer: &str) { + // TODO: Define encoding and write error context + let io = self.deps.io(); + let slog = self.deps.slog(); + uwrite!( + self.src, + r#"func(struct{{}}, {io}.ByteWriter) error {{ + {slog}.Debug("writing error context") + return nil + }}({name}, {writer})"#, + ); + } + fn print_write_ty(&mut self, ty: &Type, name: &str, writer: &str) { match ty { Type::Id(t) => self.print_write_tyid(*t, name, writer), @@ -2313,6 +2330,7 @@ impl InterfaceGenerator<'_> { TypeDefKind::List(ty) => self.print_write_list(ty, name, writer), TypeDefKind::Future(ty) => self.print_write_future(ty, name, writer), TypeDefKind::Stream(ty) => self.print_write_stream(ty, name, writer), + TypeDefKind::ErrorContext => self.print_write_error_context(name, writer), TypeDefKind::Type(ty) => self.print_write_ty(ty, name, writer), _ => { if ty.name.is_some() { @@ -3252,26 +3270,24 @@ func ServeInterface(s {wrpc}.Server, h Handler) (stop func() error, err error) { } } - fn print_stream(&mut self, Stream { element, .. }: &Stream) { - match element { - Some(ty) if is_ty(self.resolve, Type::U8, ty) => { - let io = self.deps.io(); - self.push_str(io); - self.push_str(".ReadCloser"); - } - Some(ty) => { - let wrpc = self.deps.wrpc(); - self.push_str(wrpc); - self.push_str(".Receiver["); - self.print_list(ty); - self.push_str("]"); - } - None => { - panic!("streams with no element types are not supported") - } + fn print_stream(&mut self, ty: &Type) { + if is_ty(self.resolve, Type::U8, ty) { + let io = self.deps.io(); + self.push_str(io); + self.push_str(".ReadCloser"); + } else { + let wrpc = self.deps.wrpc(); + self.push_str(wrpc); + self.push_str(".Receiver["); + self.print_list(ty); + self.push_str("]"); } } + fn print_error_context(&mut self) { + self.push_str("struct{}"); + } + fn print_own(&mut self, id: TypeId) { let wrpc = self.deps.wrpc(); self.push_str(wrpc); @@ -3307,6 +3323,7 @@ func ServeInterface(s {wrpc}.Server, h Handler) (stop func() error, err error) { TypeDefKind::Enum(_) => panic!("unsupported anonymous type reference: enum"), TypeDefKind::Future(ty) => self.print_future(ty), TypeDefKind::Stream(ty) => self.print_stream(ty), + TypeDefKind::ErrorContext => self.print_error_context(), TypeDefKind::Handle(Handle::Own(id)) => self.print_own(*id), TypeDefKind::Handle(Handle::Borrow(id)) => self.print_borrow(*id), TypeDefKind::Type(t) => self.print_ty(t, decl), @@ -3860,6 +3877,33 @@ func (v *{name}) WriteToIndex(w {wrpc}.ByteWriter) (func({wrpc}.IndexWriter) err } } + fn type_future(&mut self, id: TypeId, _name: &str, ty: &Option, docs: &Docs) { + if let Some(name) = self.name_of(id) { + self.godoc(docs); + uwrite!(self.src, "type {name} = "); + self.print_future(ty); + self.push_str("\n"); + } + } + + fn type_stream(&mut self, id: TypeId, _name: &str, ty: &Type, docs: &Docs) { + if let Some(name) = self.name_of(id) { + self.godoc(docs); + uwrite!(self.src, "type {name} = "); + self.print_stream(ty); + self.push_str("\n"); + } + } + + fn type_error_context(&mut self, id: TypeId, _name: &str, docs: &Docs) { + if let Some(name) = self.name_of(id) { + self.godoc(docs); + uwrite!(self.src, "type {name} = "); + self.print_error_context(); + self.push_str("\n"); + } + } + fn type_builtin(&mut self, _id: TypeId, name: &str, ty: &Type, docs: &Docs) { self.godoc(docs); uwrite!(self.src, "type {} = ", name.to_upper_camel_case()); diff --git a/crates/wit-bindgen-rust-macro/src/lib.rs b/crates/wit-bindgen-rust-macro/src/lib.rs index 3ec27a66c..9385f3484 100644 --- a/crates/wit-bindgen-rust-macro/src/lib.rs +++ b/crates/wit-bindgen-rust-macro/src/lib.rs @@ -46,6 +46,7 @@ struct Config { resolve: Resolve, world: WorldId, files: Vec, + debug: bool, } /// The source of the wit package definition @@ -63,6 +64,7 @@ impl Parse for Config { let mut world = None; let mut source = None; let mut features = Vec::new(); + let mut debug = false; if input.peek(token::Brace) { let content; @@ -138,6 +140,9 @@ impl Parse for Config { Opt::WrpcTransportPath(path) => { opts.wrpc_transport_path = Some(path.value()); } + Opt::Debug(enable) => { + debug = enable.value(); + } } } } else { @@ -157,6 +162,7 @@ impl Parse for Config { resolve, world, files, + debug, }) } } @@ -249,7 +255,7 @@ impl Config { // place a formatted version of the expanded code into a file. This file // will then show up in rustc error messages for any codegen issues and can // be inspected manually. - if std::env::var("WIT_BINDGEN_DEBUG").is_ok() { + if std::env::var("WIT_BINDGEN_DEBUG").is_ok() || self.debug { static INVOCATION: AtomicUsize = AtomicUsize::new(0); let root = Path::new(env!("DEBUG_OUTPUT_DIR")); let world_name = &self.resolve.worlds[self.world].name; @@ -304,6 +310,7 @@ mod kw { syn::custom_keyword!(tracing_path); syn::custom_keyword!(wasm_tokio_path); syn::custom_keyword!(wrpc_transport_path); + syn::custom_keyword!(debug); } enum Opt { @@ -326,6 +333,7 @@ enum Opt { TracingPath(syn::LitStr), WasmTokioPath(syn::LitStr), WrpcTransportPath(syn::LitStr), + Debug(syn::LitBool), } impl Parse for Opt { @@ -426,6 +434,10 @@ impl Parse for Opt { input.parse::()?; input.parse::()?; Ok(Opt::WrpcTransportPath(input.parse()?)) + } else if l.peek(kw::debug) { + input.parse::()?; + input.parse::()?; + Ok(Opt::Debug(input.parse()?)) } else { Err(l.error()) } diff --git a/crates/wit-bindgen-rust/src/interface.rs b/crates/wit-bindgen-rust/src/interface.rs index 616ed4625..d5bd736b3 100644 --- a/crates/wit-bindgen-rust/src/interface.rs +++ b/crates/wit-bindgen-rust/src/interface.rs @@ -8,8 +8,7 @@ use std::fmt::Write as _; use std::mem; use wit_bindgen_core::wit_parser::{ Case, Docs, Enum, Field, Flags, Function, FunctionKind, Handle, Int, InterfaceId, Record, - Resolve, Result_, Stream, Tuple, Type, TypeDefKind, TypeId, TypeOwner, Variant, World, - WorldKey, + Resolve, Result_, Tuple, Type, TypeDefKind, TypeId, TypeOwner, Variant, World, WorldKey, }; use wit_bindgen_core::{uwrite, uwriteln, Source, TypeInfo}; use wrpc_introspect::{async_paths_ty, async_paths_tyid, is_ty, rpc_func_name}; @@ -978,20 +977,21 @@ pub fn serve_interface<'a, T: {wrpc_transport}::Serve>( self.push_str("> + ::core::marker::Send>>"); } - fn print_stream(&mut self, Stream { element, .. }: &Stream, submodule: bool) { + fn print_stream(&mut self, ty: &Type, submodule: bool) { uwrite!( self.src, "::core::pin::Pin<::std::boxed::Box"); - } + self.print_list(ty, true, submodule); self.push_str("> + ::core::marker::Send>>"); } + fn print_error_context(&mut self) { + // TODO: Define encoding and print + self.push_str("()") + } + fn print_own(&mut self, id: TypeId, submodule: bool) { self.src.push_str(self.gen.wrpc_transport_path()); self.push_str("::ResourceOwn<"); @@ -1025,6 +1025,7 @@ pub fn serve_interface<'a, T: {wrpc_transport}::Serve>( TypeDefKind::Enum(_) => panic!("unsupported anonymous type reference: enum"), TypeDefKind::Future(ty) => self.print_future(ty, submodule), TypeDefKind::Stream(ty) => self.print_stream(ty, submodule), + TypeDefKind::ErrorContext => self.print_error_context(), TypeDefKind::Handle(Handle::Own(id)) => self.print_own(*id, submodule), TypeDefKind::Handle(Handle::Borrow(id)) => self.print_borrow(*id, submodule), TypeDefKind::Type(t) => self.print_ty(t, owned, submodule), @@ -1893,8 +1894,8 @@ mod {mod_name} {{ } else { let tokio = self.gen.tokio_path().to_string(); - let (paths, _) = async_paths_tyid(self.resolve, id); - if paths.is_empty() { + let (paths, fut) = async_paths_tyid(self.resolve, id); + if !fut && paths.is_empty() { uwrite!( self.src, r#" @@ -1952,7 +1953,7 @@ mod {mod_name} {{ ); let mut names = vec![format!("super::{name}")]; - if paths.is_empty() { + if !fut && paths.is_empty() { names.extend_from_slice(&[ format!("&super::{name}"), format!("&&super::{name}"), @@ -2429,6 +2430,33 @@ mod {mod_name} {{ } } + fn type_future(&mut self, id: TypeId, _name: &str, ty: &Option, docs: &Docs) { + if let Some(name) = self.name_of(id) { + self.rustdoc(docs); + uwrite!(self.src, "type {name} = "); + self.print_future(ty, false); + self.push_str(";\n"); + } + } + + fn type_stream(&mut self, id: TypeId, _name: &str, ty: &Type, docs: &Docs) { + if let Some(name) = self.name_of(id) { + self.rustdoc(docs); + uwrite!(self.src, "type {name} = "); + self.print_stream(ty, false); + self.push_str(";\n"); + } + } + + fn type_error_context(&mut self, id: TypeId, _name: &str, docs: &Docs) { + if let Some(name) = self.name_of(id) { + self.rustdoc(docs); + uwrite!(self.src, "type {name} = "); + self.print_error_context(); + self.push_str(";\n"); + } + } + fn type_builtin(&mut self, _id: TypeId, name: &str, ty: &Type, docs: &Docs) { self.rustdoc(docs); uwrite!(self.src, "pub type {} = ", name.to_upper_camel_case()); diff --git a/crates/wit-bindgen-rust/tests/codegen.rs b/crates/wit-bindgen-rust/tests/codegen.rs index 11dd27ba4..70645e427 100644 --- a/crates/wit-bindgen-rust/tests/codegen.rs +++ b/crates/wit-bindgen-rust/tests/codegen.rs @@ -75,6 +75,66 @@ mod strings { } } +/// Like `strings` but with a type alias. +mod aliased_strings { + wit_bindgen_wrpc::generate!({ + inline: " + package my:strings; + world not-used-name { + import cat: interface { + type my-string = string; + foo: func(x: my-string); + bar: func() -> my-string; + } + } + ", + }); + + #[allow(dead_code)] + async fn test( + wrpc: &impl wit_bindgen_wrpc::wrpc_transport::Invoke, + ) -> anyhow::Result<()> { + // Test the argument is `&str`. + cat::foo(wrpc, (), "hello").await?; + + // Test the return type is `String`. + let _t: String = cat::bar(wrpc, ()).await?; + + Ok(()) + } +} + +/// Like `aliased_string` but with lists instead of strings. +mod aliased_lists { + use wit_bindgen_wrpc::bytes::Bytes; + + wit_bindgen_wrpc::generate!({ + inline: " + package my:strings; + world not-used-name { + import cat: interface { + type my-list = list; + foo: func(x: my-list); + bar: func() -> my-list; + } + } + ", + }); + + #[allow(dead_code)] + async fn test( + wrpc: &impl wit_bindgen_wrpc::wrpc_transport::Invoke, + ) -> anyhow::Result<()> { + // Test the argument is `Bytes`. + cat::foo(wrpc, (), &Bytes::from("hello")).await?; + + // Test the return type is `Bytes`. + let _t: Bytes = cat::bar(wrpc, ()).await?; + + Ok(()) + } +} + mod skip { wit_bindgen_wrpc::generate!({ inline: " diff --git a/crates/wit-bindgen/src/lib.rs b/crates/wit-bindgen/src/lib.rs index 663638ac8..92e08505d 100644 --- a/crates/wit-bindgen/src/lib.rs +++ b/crates/wit-bindgen/src/lib.rs @@ -320,10 +320,7 @@ /// `hello`. A custom type, here called `MyComponent`, is created and the trait /// is implemented for that type. /// -/// Additionally a macro is generated by `generate!` (macros generating macros) -/// called `serve`. The `serve` function is given a component that implements -/// the export `trait`s and then it will itself generate all necessary -/// `#[no_mangle]` functions to implement the ABI required. +/// Additionally a funcion is generated by `generate!` called `serve`. /// /// ## Exports: Multiple Interfaces /// @@ -568,9 +565,7 @@ /// Components are created by having exported WebAssembly functions with /// specific names, and these functions are not created when `generate!` is /// invoked. Instead these functions are created afterwards once you've defined -/// your own type an implemented the various `trait`s for it. The `#[no_mangle]` -/// functions that will become the component are created with the generated -/// `serve` function. +/// your own type an implemented the various `trait`s for it. /// /// Each call to `generate!` will itself generate a macro called `serve`. /// The macro's first argument is the name of a type that implements the traits diff --git a/tests/codegen/error-context.wit b/tests/codegen/error-context.wit new file mode 100644 index 000000000..d76f89685 --- /dev/null +++ b/tests/codegen/error-context.wit @@ -0,0 +1,12 @@ +package foo:foo; + +interface error-contexts { + type foo = error-context; + + bar: func(x: foo, y: error-context, z: future) -> result, error-context>; +} + +world foo { + import error-contexts; + export error-contexts; +} diff --git a/tests/codegen/futures.wit b/tests/codegen/futures.wit new file mode 100644 index 000000000..2d634a400 --- /dev/null +++ b/tests/codegen/futures.wit @@ -0,0 +1,87 @@ +package foo:foo; + +interface futures { + future-param: func(x: future); + future-u8-param: func(x: future); + future-u16-param: func(x: future); + future-u32-param: func(x: future); + future-u64-param: func(x: future); + future-s8-param: func(x: future); + future-s16-param: func(x: future); + future-s32-param: func(x: future); + future-s64-param: func(x: future); + future-f32-param: func(x: future); + future-f64-param: func(x: future); + + future-ret: func(x: future); + future-u8-ret: func() -> future; + future-u16-ret: func() -> future; + future-u32-ret: func() -> future; + future-u64-ret: func() -> future; + future-s8-ret: func() -> future; + future-s16-ret: func() -> future; + future-s32-ret: func() -> future; + future-s64-ret: func() -> future; + future-f32-ret: func() -> future; + future-f64-ret: func() -> future; + + tuple-future: func(x: future>) -> future>; + string-future-arg: func(a: future); + string-future-ret: func() -> future; + tuple-string-future: func(x: future>) -> future>; + string-future: func(x: future) -> future; + + record some-record { + x: string, + y: other-record, + z: future, + c1: u32, + c2: u64, + c3: s32, + c4: s64, + } + record other-record { + a1: u32, + a2: u64, + a3: s32, + a4: s64, + b: string, + c: future, + } + record-future: func(x: future) -> future; + record-future-reverse: func(x: future) -> future; + + variant some-variant { + a(string), + b, + c(u32), + d(future), + } + variant other-variant { + a, + b(u32), + c(string), + } + variant-future: func(x: future) -> future; + + type load-store-all-sizes = future>; + load-store-everything: func(a: load-store-all-sizes) -> load-store-all-sizes; +} + +world the-futures { + import futures; + export futures; +} diff --git a/tests/codegen/import-export-same-func.wit b/tests/codegen/import-export-same-func.wit new file mode 100644 index 000000000..93f45e1cf --- /dev/null +++ b/tests/codegen/import-export-same-func.wit @@ -0,0 +1,6 @@ +package green:blue; + +world my-world { + import purple: func(); + export purple: func(); +} diff --git a/tests/codegen/import_export_func.wit b/tests/codegen/import_export_func.wit new file mode 100644 index 000000000..6ef165d63 --- /dev/null +++ b/tests/codegen/import_export_func.wit @@ -0,0 +1,6 @@ +package foo:foo; + +world foo { + import foo: func(); + export foo1: func(); +} diff --git a/tests/codegen/resources-with-futures.wit b/tests/codegen/resources-with-futures.wit new file mode 100644 index 000000000..33a2b2aeb --- /dev/null +++ b/tests/codegen/resources-with-futures.wit @@ -0,0 +1,17 @@ +package my:resources; + +interface with-futures { + resource x { + constructor(l: future); + get: func() -> future; + set: func(l: future); + etc: static func(l: future) -> future; + } + + foo: func(x: future) -> future; +} + +world resources { + import with-futures; + export with-futures; +} diff --git a/tests/codegen/resources-with-streams.wit b/tests/codegen/resources-with-streams.wit new file mode 100644 index 000000000..d9e3620fc --- /dev/null +++ b/tests/codegen/resources-with-streams.wit @@ -0,0 +1,17 @@ +package my:resources; + +interface with-streams { + resource x { + constructor(l: stream); + get: func() -> stream; + set: func(l: stream); + etc: static func(l: stream) -> stream; + } + + foo: func(x: stream) -> stream; +} + +world resources { + import with-streams; + export with-streams; +} diff --git a/tests/codegen/streams.wit b/tests/codegen/streams.wit new file mode 100644 index 000000000..7ed696ed8 --- /dev/null +++ b/tests/codegen/streams.wit @@ -0,0 +1,100 @@ +package foo:foo; + +interface transmit { + variant control { + read-stream(string), + read-future(string), + write-stream(string), + write-future(string), + } + + exchange: func(control: stream, + caller-stream: stream, + caller-future1: future, + caller-future2: future) -> tuple, future, future>; +} + +interface streams { + stream-u8-param: func(x: stream); + stream-u16-param: func(x: stream); + stream-u32-param: func(x: stream); + stream-u64-param: func(x: stream); + stream-s8-param: func(x: stream); + stream-s16-param: func(x: stream); + stream-s32-param: func(x: stream); + stream-s64-param: func(x: stream); + stream-f32-param: func(x: stream); + stream-f64-param: func(x: stream); + + stream-u8-ret: func() -> stream; + stream-u16-ret: func() -> stream; + stream-u32-ret: func() -> stream; + stream-u64-ret: func() -> stream; + stream-s8-ret: func() -> stream; + stream-s16-ret: func() -> stream; + stream-s32-ret: func() -> stream; + stream-s64-ret: func() -> stream; + stream-f32-ret: func() -> stream; + stream-f64-ret: func() -> stream; + + tuple-stream: func(x: stream>) -> stream>; + string-stream-arg: func(a: stream); + string-stream-ret: func() -> stream; + tuple-string-stream: func(x: stream>) -> stream>; + string-stream: func(x: stream) -> stream; + + record some-record { + x: string, + y: other-record, + z: stream, + c1: u32, + c2: u64, + c3: s32, + c4: s64, + } + record other-record { + a1: u32, + a2: u64, + a3: s32, + a4: s64, + b: string, + c: stream, + } + record-stream: func(x: stream) -> stream; + record-stream-reverse: func(x: stream) -> stream; + + variant some-variant { + a(string), + b, + c(u32), + d(stream), + } + variant other-variant { + a, + b(u32), + c(string), + } + variant-stream: func(x: stream) -> stream; + + type load-store-all-sizes = stream>; + load-store-everything: func(a: load-store-all-sizes) -> load-store-all-sizes; +} + +world the-streams { + import streams; + export streams; + export transmit; +}