From 5c127f0f896a43d93b514bef26d760516dba05cb Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 4 Oct 2022 09:13:35 -0700 Subject: [PATCH 01/12] Remove support for handles and resources This commit removes all support for the `resource` and `Handle` types from the AST of `wit-parser` and all related support in all code generators. The motivation for this commit is that `wit-bindgen` is on the cusp of actually being able to work with components: producing a component from guest output and consuming components in host generators. More detail about this is in #314. With components as an intermediate format, however, there is no way to encode resources since they are not part of the component model proposal yet. All is not lost for handles and resources, though. The official design for handles and resources is being worked on upstream in the component model repository itself at this time and once added all of this support will be re-added to `wit-bindgen`. In the meantime though I personally think that the best way forward is to remove the interim support for a few reasons: * Primarily it unblocks progress at this time towards fully integrating components and the `wit-bindgen` generators. The requirement to run existing tests that use handles would mean that no host generator could actually switch to components and/or modes for today's core-wasm-lookalike would need to be preserved. * Otherwise though the semantics of the current handles are basically invented out of thin air by myself and were never really formally specified, debated, or designed deliberately. I grafted `witx`-style handles into `wit-component` and added features as necessary over time, but it seems highly unlikely that the handles designed as part of the component model will be the ones that `wit-bindgen` currently supports. This inevitably means that a new system would need new code anyway and would likely result in removal regardless. As usual git always has the history of handles and this all may come back in one shape or another if only slightly tweaked. I'm confident in our history spelunking abilities, though, so I don't feel that keeping support in the repository is necessary for this purpose. --- crates/bindgen-core/src/lib.rs | 10 - crates/gen-guest-c/src/lib.rs | 109 ------ crates/gen-guest-rust/src/lib.rs | 263 +------------ crates/gen-guest-teavm-java/src/lib.rs | 15 +- crates/gen-host-js/src/lib.rs | 345 +----------------- crates/gen-host-wasmtime-py/src/lib.rs | 244 +------------ crates/gen-host-wasmtime-py/src/source.rs | 77 +--- crates/gen-host-wasmtime-rust/src/lib.rs | 251 +------------ crates/gen-markdown/src/lib.rs | 9 - crates/gen-rust-lib/src/lib.rs | 99 +---- crates/test-helpers/src/lib.rs | 37 +- crates/test-rust-wasm/Cargo.toml | 4 - crates/test-rust-wasm/src/bin/handles.rs | 3 - crates/wit-component/src/encoding.rs | 15 - crates/wit-component/src/printing.rs | 4 - crates/wit-parser/src/abi.rs | 173 +-------- crates/wit-parser/src/ast.rs | 40 +- crates/wit-parser/src/ast/lex.rs | 3 - crates/wit-parser/src/ast/resolve.rs | 145 +------- crates/wit-parser/src/lib.rs | 20 +- crates/wit-parser/src/sizealign.rs | 6 +- crates/wit-parser/tests/all.rs | 14 - crates/wit-parser/tests/ui/comments.wit | 2 +- .../wit-parser/tests/ui/comments.wit.result | 16 +- .../wit-parser/tests/ui/import-me-too.wit.md | 11 - .../tests/ui/import-me-too.wit.md.result | 14 - crates/wit-parser/tests/ui/import-me.wit | 5 - .../wit-parser/tests/ui/import-me.wit.result | 14 - .../tests/ui/imports-from-wit-md.wit | 6 - .../tests/ui/imports-from-wit-md.wit.result | 38 +- crates/wit-parser/tests/ui/imports.wit | 5 - crates/wit-parser/tests/ui/imports.wit.result | 38 +- crates/wit-parser/tests/ui/imports2.wit | 2 +- .../wit-parser/tests/ui/imports2.wit.result | 21 +- .../tests/ui/parse-fail/bad-resource.wit | 5 - .../ui/parse-fail/bad-resource.wit.result | 5 - .../tests/ui/parse-fail/bad-resource2.wit | 6 - .../ui/parse-fail/bad-resource2.wit.result | 5 - .../ui/parse-fail/duplicate-resource.wit | 4 - .../parse-fail/duplicate-resource.wit.result | 5 - .../tests/ui/parse-fail/import-bad3.wit | 4 +- .../ui/parse-fail/import-bad3.wit.result | 4 +- .../tests/ui/parse-fail/import-bad4.wit | 2 +- .../ui/parse-fail/import-bad4.wit.result | 4 +- .../tests/ui/parse-fail/import-me.wit | 1 - .../tests/ui/parse-fail/import-me.wit.result | 9 - crates/wit-parser/tests/ui/resource.wit | 16 - .../wit-parser/tests/ui/resource.wit.result | 102 ------ crates/wit-parser/tests/ui/types.wit | 5 +- crates/wit-parser/tests/ui/types.wit.result | 146 ++++---- crates/wit-parser/tests/ui/wasi-http.wit | 158 -------- .../wit-parser/tests/ui/wasi-http.wit.result | 194 ---------- tests/codegen/resource.wit | 11 - tests/runtime/handles/exports.wit | 53 --- tests/runtime/handles/host.py | 189 ---------- tests/runtime/handles/host.rs | 156 -------- tests/runtime/handles/host.ts | 127 ------- tests/runtime/handles/imports.wit | 55 --- tests/runtime/handles/wasm.c | 223 ----------- tests/runtime/handles/wasm.rs | 131 ------- tests/runtime/invalid/exports.wit | 2 - tests/runtime/invalid/host.py | 5 - tests/runtime/invalid/host.rs | 19 +- tests/runtime/invalid/host.ts | 3 - tests/runtime/invalid/imports.wit | 3 - tests/runtime/invalid/wasm.rs | 22 -- tests/runtime/js_instantiate/host.ts | 1 - 67 files changed, 155 insertions(+), 3578 deletions(-) delete mode 100644 crates/test-rust-wasm/src/bin/handles.rs delete mode 100644 crates/wit-parser/tests/ui/parse-fail/bad-resource.wit delete mode 100644 crates/wit-parser/tests/ui/parse-fail/bad-resource.wit.result delete mode 100644 crates/wit-parser/tests/ui/parse-fail/bad-resource2.wit delete mode 100644 crates/wit-parser/tests/ui/parse-fail/bad-resource2.wit.result delete mode 100644 crates/wit-parser/tests/ui/parse-fail/duplicate-resource.wit delete mode 100644 crates/wit-parser/tests/ui/parse-fail/duplicate-resource.wit.result delete mode 100644 crates/wit-parser/tests/ui/resource.wit delete mode 100644 crates/wit-parser/tests/ui/resource.wit.result delete mode 100644 crates/wit-parser/tests/ui/wasi-http.wit delete mode 100644 crates/wit-parser/tests/ui/wasi-http.wit.result delete mode 100644 tests/codegen/resource.wit delete mode 100644 tests/runtime/handles/exports.wit delete mode 100644 tests/runtime/handles/host.py delete mode 100644 tests/runtime/handles/host.rs delete mode 100644 tests/runtime/handles/host.ts delete mode 100644 tests/runtime/handles/imports.wit delete mode 100644 tests/runtime/handles/wasm.c delete mode 100644 tests/runtime/handles/wasm.rs diff --git a/crates/bindgen-core/src/lib.rs b/crates/bindgen-core/src/lib.rs index ef15ccca4..a6869d45c 100644 --- a/crates/bindgen-core/src/lib.rs +++ b/crates/bindgen-core/src/lib.rs @@ -84,7 +84,6 @@ pub trait Generator { ); fn type_union(&mut self, iface: &Interface, id: TypeId, name: &str, union: &Union, docs: &Docs); fn type_enum(&mut self, iface: &Interface, id: TypeId, name: &str, enum_: &Enum, docs: &Docs); - fn type_resource(&mut self, iface: &Interface, ty: ResourceId); fn type_alias(&mut self, iface: &Interface, id: TypeId, name: &str, ty: &Type, docs: &Docs); fn type_list(&mut self, iface: &Interface, id: TypeId, name: &str, ty: &Type, docs: &Docs); fn type_builtin(&mut self, iface: &Interface, id: TypeId, name: &str, ty: &Type, docs: &Docs); @@ -131,10 +130,6 @@ pub trait Generator { } } - for (id, _resource) in iface.resources.iter() { - self.type_resource(iface, id); - } - self.preprocess_functions(iface, dir); for f in iface.functions.iter() { @@ -181,9 +176,6 @@ pub struct TypeInfo { /// Whether or not this type (transitively) has a list. pub has_list: bool, - - /// Whether or not this type (transitively) has a handle. - pub has_handle: bool, } impl std::ops::BitOrAssign for TypeInfo { @@ -191,7 +183,6 @@ impl std::ops::BitOrAssign for TypeInfo { self.param |= rhs.param; self.result |= rhs.result; self.has_list |= rhs.has_list; - self.has_handle |= rhs.has_handle; } } @@ -271,7 +262,6 @@ impl Types { pub fn type_info(&mut self, iface: &Interface, ty: &Type) -> TypeInfo { let mut info = TypeInfo::default(); match ty { - Type::Handle(_) => info.has_handle = true, Type::String => info.has_list = true, Type::Id(id) => return self.type_id_info(iface, *id), _ => {} diff --git a/crates/gen-guest-c/src/lib.rs b/crates/gen-guest-c/src/lib.rs index 53c167505..f0be76805 100644 --- a/crates/gen-guest-c/src/lib.rs +++ b/crates/gen-guest-c/src/lib.rs @@ -238,11 +238,6 @@ impl C { Type::S64 => self.src.h("int64_t"), Type::Float32 => self.src.h("float"), Type::Float64 => self.src.h("double"), - Type::Handle(id) => { - self.print_namespace(iface); - self.src.h(&iface.resources[*id].name.to_snake_case()); - self.src.h("_t"); - } Type::String => { self.print_namespace(iface); self.src.h("string_t"); @@ -285,7 +280,6 @@ impl C { Type::S64 => self.src.h("s64"), Type::Float32 => self.src.h("float32"), Type::Float64 => self.src.h("float64"), - Type::Handle(id) => self.src.h(&iface.resources[*id].name.to_snake_case()), Type::String => self.src.h("string"), Type::Id(id) => { let ty = &iface.types[*id]; @@ -579,7 +573,6 @@ impl C { let id = match ty { Type::Id(id) => *id, Type::String => return true, - Type::Handle(_) => return true, _ => return false, }; match &iface.types[id].kind { @@ -945,10 +938,6 @@ impl Generator for C { self.types.insert(id, mem::replace(&mut self.src.h, prev)); } - fn type_resource(&mut self, iface: &Interface, ty: ResourceId) { - drop((iface, ty)); - } - fn type_alias(&mut self, iface: &Interface, id: TypeId, name: &str, ty: &Type, docs: &Docs) { let prev = mem::take(&mut self.src.h); self.docs(docs); @@ -1178,90 +1167,6 @@ impl Generator for C { self.print_intrinsics(); - for (_, resource) in iface.resources.iter() { - let ns = iface.name.to_snake_case(); - let name = resource.name.to_snake_case(); - uwrite!( - self.src.h, - " - typedef struct {{ - uint32_t idx; - }} {ns}_{name}_t; - void {ns}_{name}_free({ns}_{name}_t *ptr); - {ns}_{name}_t {ns}_{name}_clone({ns}_{name}_t *ptr); - ", - ns = ns, - name = name, - ); - uwrite!( - self.src.c, - " - __attribute__((import_module(\"canonical_abi\"), import_name(\"resource_drop_{name_orig}\"))) - void __resource_{name}_drop(uint32_t idx); - - void {ns}_{name}_free({ns}_{name}_t *ptr) {{ - __resource_{name}_drop(ptr->idx); - }} - - __attribute__((import_module(\"canonical_abi\"), import_name(\"resource_clone_{name_orig}\"))) - uint32_t __resource_{name}_clone(uint32_t idx); - - {ns}_{name}_t {ns}_{name}_clone({ns}_{name}_t *ptr) {{ - return ({ns}_{name}_t){{__resource_{name}_clone(ptr->idx)}}; - }} - ", - ns = ns, - name = name, - name_orig = resource.name, - ); - - // Exported resources have more capabilities, they can create new - // resources and get the private value that it was created with. - // Furthermore we also define the destructor which delegates to the - // actual user-defined destructor, if any. - if !self.in_import { - uwrite!( - self.src.h, - "\ - {ns}_{name}_t {ns}_{name}_new(void *data); - void* {ns}_{name}_get({ns}_{name}_t *ptr); - - __attribute__((weak)) - void {ns}_{name}_dtor(void *data); - ", - ns = ns, - name = name, - ); - uwrite!( - self.src.c, - " - __attribute__((import_module(\"canonical_abi\"), import_name(\"resource_new_{name_orig}\"))) - uint32_t __resource_{name}_new(uint32_t val); - - {ns}_{name}_t {ns}_{name}_new(void *data) {{ - return ({ns}_{name}_t){{__resource_{name}_new((uint32_t) data)}}; - }} - - __attribute__((import_module(\"canonical_abi\"), import_name(\"resource_get_{name_orig}\"))) - uint32_t __resource_{name}_get(uint32_t idx); - - void* {ns}_{name}_get({ns}_{name}_t *ptr) {{ - return (void*) __resource_{name}_get(ptr->idx); - }} - - __attribute__((export_name(\"canonical_abi_drop_{name_orig}\"))) - void __resource_{name}_dtor(uint32_t val) {{ - if ({ns}_{name}_dtor) - {ns}_{name}_dtor((void*) val); - }} - ", - ns = ns, - name = name, - name_orig = resource.name, - ); - } - } - // Continuously generate anonymous types while we continue to find more // // First we take care of the public set of anonymous types. This will @@ -1595,20 +1500,6 @@ impl Bindgen for FunctionBindgen<'_> { results.push(operands[0].clone()); } - Instruction::I32FromOwnedHandle { .. } | Instruction::I32FromBorrowedHandle { .. } => { - results.push(format!("({}).idx", operands[0])); - } - - Instruction::HandleBorrowedFromI32 { ty, .. } - | Instruction::HandleOwnedFromI32 { ty, .. } => { - results.push(format!( - "({}_{}_t){{ {} }}", - iface.name.to_snake_case(), - iface.resources[*ty].name.to_snake_case(), - operands[0], - )); - } - Instruction::RecordLower { record, .. } => { let op = &operands[0]; for f in record.fields.iter() { diff --git a/crates/gen-guest-rust/src/lib.rs b/crates/gen-guest-rust/src/lib.rs index f882ae286..99c948d31 100644 --- a/crates/gen-guest-rust/src/lib.rs +++ b/crates/gen-guest-rust/src/lib.rs @@ -58,7 +58,6 @@ pub struct Opts { #[derive(Default)] struct Trait { methods: Vec, - resource_methods: BTreeMap>, } impl Opts { @@ -105,22 +104,6 @@ impl RustGenerator for RustWasm { } } - fn handle_projection(&self) -> Option<(&'static str, String)> { - None - } - - fn handle_in_super(&self) -> bool { - !self.in_import - } - - fn handle_wrapper(&self) -> Option<&'static str> { - if self.in_import { - None - } else { - Some("wit_bindgen_guest_rust::Handle") - } - } - fn push_str(&mut self, s: &str) { self.src.push_str(s); } @@ -282,172 +265,6 @@ impl Generator for RustWasm { self.print_typedef_enum(id, name, enum_, docs); } - fn type_resource(&mut self, iface: &Interface, ty: ResourceId) { - // For exported handles we synthesize some trait implementations - // automatically for runtime-required traits. - if !self.in_import { - let panic = " - #[cfg(not(target_arch = \"wasm32\"))] - { - panic!(\"handles can only be used on wasm32\"); - } - #[cfg(target_arch = \"wasm32\")] - "; - self.src.push_str(&format!( - " - unsafe impl wit_bindgen_guest_rust::HandleType for super::{ty} {{ - #[inline] - fn clone(_val: i32) -> i32 {{ - {panic_not_wasm} - {{ - #[link(wasm_import_module = \"canonical_abi\")] - extern \"C\" {{ - #[link_name = \"resource_clone_{name}\"] - fn clone(val: i32) -> i32; - }} - unsafe {{ clone(_val) }} - }} - }} - - #[inline] - fn drop(_val: i32) {{ - {panic_not_wasm} - {{ - #[link(wasm_import_module = \"canonical_abi\")] - extern \"C\" {{ - #[link_name = \"resource_drop_{name}\"] - fn drop(val: i32); - }} - unsafe {{ drop(_val) }} - }} - }} - }} - - unsafe impl wit_bindgen_guest_rust::LocalHandle for super::{ty} {{ - #[inline] - fn new(_val: i32) -> i32 {{ - {panic_not_wasm} - {{ - #[link(wasm_import_module = \"canonical_abi\")] - extern \"C\" {{ - #[link_name = \"resource_new_{name}\"] - fn new(val: i32) -> i32; - }} - unsafe {{ new(_val) }} - }} - }} - - #[inline] - fn get(_val: i32) -> i32 {{ - {panic_not_wasm} - {{ - #[link(wasm_import_module = \"canonical_abi\")] - extern \"C\" {{ - #[link_name = \"resource_get_{name}\"] - fn get(val: i32) -> i32; - }} - unsafe {{ get(_val) }} - }} - }} - }} - - const _: () = {{ - #[export_name = \"{ns}canonical_abi_drop_{name}\"] - extern \"C\" fn drop(ty: Box) {{ - ::drop_{name_snake}(*ty) - }} - }}; - ", - ty = iface.resources[ty].name.to_camel_case(), - name = iface.resources[ty].name, - name_snake = iface.resources[ty].name.to_snake_case(), - iface = iface.name.to_camel_case(), - ns = self.opts.symbol_namespace, - panic_not_wasm = panic, - )); - let trait_ = self - .traits - .entry(iface.name.to_camel_case()) - .or_insert(Trait::default()); - trait_.methods.push(format!( - " - /// An optional callback invoked when a handle is finalized - /// and destroyed. - fn drop_{}(val: super::{}) {{ - drop(val); - }} - ", - iface.resources[ty].name.to_snake_case(), - iface.resources[ty].name.to_camel_case(), - )); - return; - } - - let resource = &iface.resources[ty]; - let name = &resource.name; - - self.rustdoc(&resource.docs); - self.src.push_str("#[derive(Debug)]\n"); - self.src.push_str("#[repr(transparent)]\n"); - self.src - .push_str(&format!("pub struct {}(i32);\n", name.to_camel_case())); - self.src.push_str("impl "); - self.src.push_str(&name.to_camel_case()); - self.src.push_str( - " { - pub unsafe fn from_raw(raw: i32) -> Self { - Self(raw) - } - - pub fn into_raw(self) -> i32 { - let ret = self.0; - core::mem::forget(self); - return ret; - } - - pub fn as_raw(&self) -> i32 { - self.0 - } - }\n", - ); - - self.src.push_str("impl Drop for "); - self.src.push_str(&name.to_camel_case()); - self.src.push_str(&format!( - "{{ - fn drop(&mut self) {{ - #[link(wasm_import_module = \"canonical_abi\")] - extern \"C\" {{ - #[link_name = \"resource_drop_{}\"] - fn close(fd: i32); - }} - unsafe {{ - close(self.0); - }} - }} - }}\n", - name, - )); - - self.src.push_str("impl Clone for "); - self.src.push_str(&name.to_camel_case()); - self.src.push_str(&format!( - "{{ - fn clone(&self) -> Self {{ - #[link(wasm_import_module = \"canonical_abi\")] - extern \"C\" {{ - #[link_name = \"resource_clone_{}\"] - fn clone(val: i32) -> i32; - }} - unsafe {{ - Self(clone(self.0)) - }} - }} - }}\n", - name, - )); - } - fn type_alias(&mut self, iface: &Interface, id: TypeId, _name: &str, ty: &Type, docs: &Docs) { self.print_typedef_alias(iface, id, ty, docs); } @@ -476,21 +293,10 @@ impl Generator for RustWasm { } fn import(&mut self, iface: &Interface, func: &Function) { - let mut sig = FnSig::default(); + let sig = FnSig::default(); let param_mode = TypeMode::AllBorrowed("'_"); match &func.kind { FunctionKind::Freestanding => {} - FunctionKind::Static { resource, .. } | FunctionKind::Method { resource, .. } => { - sig.use_item_name = true; - self.src.push_str(&format!( - "impl {} {{\n", - iface.resources[*resource].name.to_camel_case() - )); - } - } - if let FunctionKind::Method { .. } = func.kind { - sig.self_arg = Some("&self".to_string()); - sig.self_is_first_param = true; } let params = self.print_signature(iface, func, param_mode, &sig); self.src.push_str("{\n"); @@ -519,9 +325,6 @@ impl Generator for RustWasm { match &func.kind { FunctionKind::Freestanding => {} - FunctionKind::Static { .. } | FunctionKind::Method { .. } => { - self.src.push_str("}\n"); - } } } @@ -625,15 +428,6 @@ impl Generator for RustWasm { self.in_trait = true; let mut sig = FnSig::default(); sig.private = true; - match &func.kind { - FunctionKind::Freestanding => {} - FunctionKind::Static { .. } => sig.use_item_name = true, - FunctionKind::Method { .. } => { - sig.use_item_name = true; - sig.self_is_first_param = true; - sig.self_arg = Some("&self".to_string()); - } - } self.print_signature(iface, func, TypeMode::Owned, &sig); self.src.push_str(";"); self.in_trait = false; @@ -643,10 +437,6 @@ impl Generator for RustWasm { .or_insert(Trait::default()); let dst = match &func.kind { FunctionKind::Freestanding => &mut trait_.methods, - FunctionKind::Static { resource, .. } | FunctionKind::Method { resource, .. } => trait_ - .resource_methods - .entry(*resource) - .or_insert(Vec::new()), }; dst.push(mem::replace(&mut self.src, prev).into()); } @@ -672,7 +462,7 @@ impl Generator for RustWasm { } } - fn finish_one(&mut self, iface: &Interface, files: &mut Files) { + fn finish_one(&mut self, _iface: &Interface, files: &mut Files) { let mut src = mem::take(&mut self.src); for (name, trait_) in self.traits.iter() { @@ -684,18 +474,6 @@ impl Generator for RustWasm { src.push_str("\n"); } src.push_str("}\n"); - - for (id, methods) in trait_.resource_methods.iter() { - src.push_str(&format!( - "pub trait {} {{\n", - iface.resources[*id].name.to_camel_case() - )); - for f in methods { - src.push_str(&f); - src.push_str("\n"); - } - src.push_str("}\n"); - } } // Close the opening `mod`. @@ -1020,32 +798,6 @@ impl Bindgen for FunctionBindgen<'_> { } } - // handles in exports - Instruction::I32FromOwnedHandle { .. } => { - results.push(format!( - "wit_bindgen_guest_rust::Handle::into_raw({})", - operands[0] - )); - } - Instruction::HandleBorrowedFromI32 { .. } => { - results.push(format!( - "wit_bindgen_guest_rust::Handle::from_raw({})", - operands[0], - )); - } - - // handles in imports - Instruction::I32FromBorrowedHandle { .. } => { - results.push(format!("{}.0", operands[0])); - } - Instruction::HandleOwnedFromI32 { ty } => { - results.push(format!( - "{}({})", - iface.resources[*ty].name.to_camel_case(), - operands[0] - )); - } - Instruction::FlagsLower { flags, .. } => { let tmp = self.tmp(); self.push_str(&format!("let flags{} = {};\n", tmp, operands[0])); @@ -1502,19 +1254,8 @@ impl Bindgen for FunctionBindgen<'_> { )); } } - FunctionKind::Static { resource, name } - | FunctionKind::Method { resource, name } => { - self.push_str(&format!( - "::{}", - name.to_snake_case(), - r = iface.resources[*resource].name.to_camel_case(), - )); - } } self.push_str("("); - if let FunctionKind::Method { .. } = func.kind { - self.push_str("&"); - } self.push_str(&operands.join(", ")); self.push_str(")"); self.push_str(";\n"); diff --git a/crates/gen-guest-teavm-java/src/lib.rs b/crates/gen-guest-teavm-java/src/lib.rs index 25097be31..ae09b4568 100644 --- a/crates/gen-guest-teavm-java/src/lib.rs +++ b/crates/gen-guest-teavm-java/src/lib.rs @@ -5,7 +5,7 @@ use wit_bindgen_core::{ wit_parser::{ abi::{AbiVariant, Bindgen, Bitcast, Instruction, LiftLower, WasmType}, Case, Docs, Enum, Flags, FlagsRepr, Function, FunctionKind, Int, Interface, Record, - ResourceId, Result_, SizeAlign, Tuple, Type, TypeDefKind, TypeId, Union, Variant, + Result_, SizeAlign, Tuple, Type, TypeDefKind, TypeId, Union, Variant, }, Direction, Files, Generator, Ns, }; @@ -59,7 +59,6 @@ impl TeaVmJava { Type::U64 | Type::S64 => "long".into(), Type::Float32 => "float".into(), Type::Float64 => "double".into(), - Type::Handle(_) => todo!("resources"), Type::String => "String".into(), Type::Id(id) => { let ty = &iface.types[*id]; @@ -558,10 +557,6 @@ impl Generator for TeaVmJava { ); } - fn type_resource(&mut self, _iface: &Interface, _ty: ResourceId) { - todo!("resources") - } - fn type_alias(&mut self, iface: &Interface, id: TypeId, _name: &str, _ty: &Type, _docs: &Docs) { self.type_name(iface, &Type::Id(id)); } @@ -1153,14 +1148,6 @@ impl Bindgen for FunctionBindgen<'_> { } Instruction::BoolFromI32 => results.push(format!("({} != 0)", operands[0])), - // handles in exports - Instruction::I32FromOwnedHandle { .. } => todo!("resources"), - Instruction::HandleBorrowedFromI32 { .. } => todo!("resources"), - - // handles in imports - Instruction::I32FromBorrowedHandle { .. } => todo!("resources"), - Instruction::HandleOwnedFromI32 { .. } => todo!("resources"), - // TODO: checked Instruction::FlagsLower { flags, .. } => match flags_repr(flags) { Int::U8 | Int::U16 | Int::U32 => { diff --git a/crates/gen-host-js/src/lib.rs b/crates/gen-host-js/src/lib.rs index f60524f9d..2765921b9 100644 --- a/crates/gen-host-js/src/lib.rs +++ b/crates/gen-host-js/src/lib.rs @@ -18,8 +18,6 @@ pub struct Js { intrinsics: BTreeMap, all_intrinsics: BTreeSet, needs_get_export: bool, - imported_resources: BTreeSet, - exported_resources: BTreeSet, needs_ty_option: bool, needs_ty_result: bool, } @@ -27,13 +25,11 @@ pub struct Js { #[derive(Default)] struct Imports { freestanding_funcs: Vec<(String, Source)>, - resource_funcs: BTreeMap>, } #[derive(Default)] struct Exports { freestanding_funcs: Vec, - resource_funcs: BTreeMap>, } #[derive(Default, Debug, Clone)] @@ -151,7 +147,6 @@ impl Js { Type::Float32 => Some("Float32Array"), Type::Float64 => Some("Float64Array"), Type::Char => None, - Type::Handle(_) => None, Type::String => None, Type::Id(id) => match &iface.types[*id].kind { TypeDefKind::Type(t) => self.array_ty(iface, t), @@ -173,7 +168,6 @@ impl Js { | Type::Float64 => self.src.ts("number"), Type::U64 | Type::S64 => self.src.ts("bigint"), Type::Char => self.src.ts("string"), - Type::Handle(id) => self.src.ts(&iface.resources[*id].name.to_camel_case()), Type::String => self.src.ts("string"), Type::Id(id) => { let ty = &iface.types[*id]; @@ -261,39 +255,11 @@ impl Js { fn ts_func(&mut self, iface: &Interface, func: &Function) { self.docs(&func.docs); - let mut name_printed = false; - if let FunctionKind::Static { .. } = &func.kind { - // static methods in imports are still wired up to an imported host - // object, but static methods on exports are actually static - // methods on the resource object. - if self.in_import { - name_printed = true; - self.src.ts(&func.name.to_mixed_case()); - } else { - self.src.ts("static "); - } - } - if !name_printed { - self.src.ts(&func.item_name().to_mixed_case()); - } + self.src.ts(&func.item_name().to_mixed_case()); self.src.ts("("); let param_start = match &func.kind { FunctionKind::Freestanding => 0, - FunctionKind::Static { .. } if self.in_import => 0, - FunctionKind::Static { .. } => { - // the 0th argument for exported static methods will be the - // instantiated interface - self.src.ts(&iface.name.to_mixed_case()); - self.src.ts(": "); - self.src.ts(&iface.name.to_camel_case()); - if func.params.len() > 0 { - self.src.ts(", "); - } - 0 - } - // skip the first parameter on methods which is `this` - FunctionKind::Method { .. } => 1, }; for (i, (name, ty)) in func.params[param_start..].iter().enumerate() { @@ -589,12 +555,6 @@ impl Generator for Js { self.src.ts(";\n"); } - fn type_resource(&mut self, _iface: &Interface, ty: ResourceId) { - if !self.in_import { - self.exported_resources.insert(ty); - } - } - fn type_alias(&mut self, iface: &Interface, _id: TypeId, name: &str, ty: &Type, docs: &Docs) { self.docs(docs); self.src @@ -666,13 +626,7 @@ impl Generator for Js { .entry(iface.name.to_string()) .or_insert(Imports::default()); let dst = match &func.kind { - FunctionKind::Freestanding | FunctionKind::Static { .. } => { - &mut imports.freestanding_funcs - } - FunctionKind::Method { resource, .. } => imports - .resource_funcs - .entry(*resource) - .or_insert(Vec::new()), + FunctionKind::Freestanding => &mut imports.freestanding_funcs, }; dst.push((func.name.to_string(), src)); } @@ -683,38 +637,22 @@ impl Generator for Js { fn import(&mut self, iface: &Interface, func: &Function) { let prev = mem::take(&mut self.src); - let mut params = func + let params = func .params .iter() .enumerate() .map(|(i, _)| format!("arg{}", i)) .collect::>(); - let mut sig_start = 0; - let mut first_is_operand = true; let src_object = match &func.kind { FunctionKind::Freestanding => "this".to_string(), - FunctionKind::Static { .. } => { - self.src.js("static "); - params.insert(0, iface.name.to_mixed_case()); - first_is_operand = false; - iface.name.to_mixed_case() - } - FunctionKind::Method { .. } => { - params[0] = "this".to_string(); - sig_start = 1; - "this._obj".to_string() - } }; self.src.js(&format!( "{}({}) {{\n", func.item_name().to_mixed_case(), - params[sig_start..].join(", ") + params.join(", ") )); self.ts_func(iface, func); - if !first_is_operand { - params.remove(0); - } let mut f = FunctionBindgen::new(self, params); f.src_object = src_object; iface.call( @@ -757,13 +695,6 @@ impl Generator for Js { FunctionKind::Freestanding => { exports.freestanding_funcs.push(func_body); } - FunctionKind::Static { resource, .. } | FunctionKind::Method { resource, .. } => { - exports - .resource_funcs - .entry(*resource) - .or_insert(Vec::new()) - .push(func_body); - } } } @@ -796,64 +727,18 @@ impl Generator for Js { self.src .ts(&format!("export interface {} {{\n", module.to_camel_case())); - for (name, src) in funcs - .freestanding_funcs - .iter() - .chain(funcs.resource_funcs.values().flat_map(|v| v)) - { + for (name, src) in funcs.freestanding_funcs.iter() { self.src.js(&format!( - "imports[\"{}\"][\"{}\"] = {};\n", - module, - name, - src.js.trim(), + "imports[\"{module}\"][\"{name}\"] = {};\n", + src.js.trim() )); - } - - for (_, src) in funcs.freestanding_funcs.iter() { self.src.ts(&src.ts); } - if self.imported_resources.len() > 0 { - self.src - .js("if (!(\"canonical_abi\" in imports)) imports[\"canonical_abi\"] = {};\n"); - } - for resource in self.imported_resources.clone() { - let slab = self.intrinsic(Intrinsic::Slab); - self.src.js(&format!( - " - const resources{idx} = new {slab}(); - imports.canonical_abi[\"resource_drop_{name}\"] = (i) => {{ - const val = resources{idx}.remove(i); - if (obj.drop{camel}) - obj.drop{camel}(val); - }}; - ", - name = iface.resources[resource].name, - camel = iface.resources[resource].name.to_camel_case(), - idx = resource.index(), - slab = slab, - )); - self.src.ts(&format!( - "drop{}?: (val: {0}) => void;\n", - iface.resources[resource].name.to_camel_case() - )); - } self.src.js("}"); self.src.ts("}\n"); - - for (resource, _) in iface.resources.iter() { - self.src.ts(&format!( - "export interface {} {{\n", - iface.resources[resource].name.to_camel_case() - )); - if let Some(funcs) = funcs.resource_funcs.get(&resource) { - for (_, src) in funcs { - self.src.ts(&src.ts); - } - } - self.src.ts("}\n"); - } } + let imports = mem::take(&mut self.src); for (module, exports) in mem::take(&mut self.guest_exports) { @@ -870,75 +755,6 @@ impl Generator for Js { instance: WebAssembly.Instance; "); - self.src.ts(" - /** - * Constructs a new instance with internal state necessary to - * manage a wasm instance. - * - * Note that this does not actually instantiate the WebAssembly - * instance or module, you'll need to call the `instantiate` - * method below to \"activate\" this class. - */ - constructor(); - "); - if self.exported_resources.len() > 0 { - self.src.js("constructor() {\n"); - let slab = self.intrinsic(Intrinsic::Slab); - for r in self.exported_resources.iter() { - self.src.js(&format!( - "this._resource{}_slab = new {}();\n", - r.index(), - slab - )); - } - self.src.js("}\n"); - } - - self.src.ts(" - /** - * This is a low-level method which can be used to add any - * intrinsics necessary for this instance to operate to an - * import object. - * - * The `import` object given here is expected to be used later - * to actually instantiate the module this class corresponds to. - * If the `instantiate` method below actually does the - * instantiation then there's no need to call this method, but - * if you're instantiating manually elsewhere then this can be - * used to prepare the import object for external instantiation. - */ - addToImports(imports: any): void; - "); - self.src.js("addToImports(imports) {\n"); - if self.exported_resources.len() > 0 { - self.src - .js("if (!(\"canonical_abi\" in imports)) imports[\"canonical_abi\"] = {};\n"); - } - for r in self.exported_resources.iter() { - self.src.js(&format!( - " - imports.canonical_abi['resource_drop_{name}'] = i => {{ - this._resource{idx}_slab.remove(i).drop(); - }}; - imports.canonical_abi['resource_clone_{name}'] = i => {{ - const obj = this._resource{idx}_slab.get(i); - return this._resource{idx}_slab.insert(obj.clone()) - }}; - imports.canonical_abi['resource_get_{name}'] = i => {{ - return this._resource{idx}_slab.get(i)._wasm_val; - }}; - imports.canonical_abi['resource_new_{name}'] = i => {{ - const registry = this._registry{idx}; - return this._resource{idx}_slab.insert(new {class}(i, this)); - }}; - ", - name = iface.resources[*r].name, - idx = r.index(), - class = iface.resources[*r].name.to_camel_case(), - )); - } - self.src.js("}\n"); - self.src.ts(&format!( " /** @@ -980,7 +796,6 @@ impl Generator for Js { self.src.js(" async instantiate(module, imports) { imports = imports || {}; - this.addToImports(imports); "); // With intrinsics prep'd we can now instantiate the module. JS has @@ -1000,17 +815,6 @@ impl Generator for Js { } this._exports = this.instance.exports; "); - - // Exported resources all get a finalization registry, and we - // created them after instantiation so we can pass the raw wasm - // export as the destructor callback. - for r in self.exported_resources.iter() { - self.src.js(&format!( - "this._registry{} = new FinalizationRegistry(this._exports['canonical_abi_drop_{}']);\n", - r.index(), - iface.resources[*r].name, - )); - } self.src.js("}\n"); for func in exports.freestanding_funcs.iter() { @@ -1019,81 +823,6 @@ impl Generator for Js { } self.src.ts("}\n"); self.src.js("}\n"); - - for &ty in self.exported_resources.iter() { - self.src.js(&format!( - " - export class {} {{ - constructor(wasm_val, obj) {{ - this._wasm_val = wasm_val; - this._obj = obj; - this._refcnt = 1; - obj._registry{idx}.register(this, wasm_val, this); - }} - - clone() {{ - this._refcnt += 1; - return this; - }} - - drop() {{ - this._refcnt -= 1; - if (this._refcnt !== 0) - return; - this._obj._registry{idx}.unregister(this); - const dtor = this._obj._exports['canonical_abi_drop_{}']; - const wasm_val = this._wasm_val; - delete this._obj; - delete this._refcnt; - delete this._wasm_val; - dtor(wasm_val); - }} - ", - iface.resources[ty].name.to_camel_case(), - iface.resources[ty].name, - idx = ty.index(), - )); - self.src.ts(&format!( - " - export class {} {{ - // Creates a new strong reference count as a new - // object. This is only required if you're also - // calling `drop` below and want to manually manage - // the reference count from JS. - // - // If you don't call `drop`, you don't need to call - // this and can simply use the object from JS. - clone(): {0}; - - // Explicitly indicate that this JS object will no - // longer be used. If the internal reference count - // reaches zero then this will deterministically - // destroy the underlying wasm object. - // - // This is not required to be called from JS. Wasm - // destructors will be automatically called for you - // if this is not called using the JS - // `FinalizationRegistry`. - // - // Calling this method does not guarantee that the - // underlying wasm object is deallocated. Something - // else (including wasm) may be holding onto a - // strong reference count. - drop(): void; - ", - iface.resources[ty].name.to_camel_case(), - )); - - if let Some(funcs) = exports.resource_funcs.get(&ty) { - for func in funcs { - self.src.js(&func.js); - self.src.ts(&func.ts); - } - } - - self.src.ts("}\n"); - self.src.js("}\n"); - } } let exports = mem::take(&mut self.src); @@ -1404,54 +1133,6 @@ impl Bindgen for FunctionBindgen<'_> { results.push(format!("{} ? 1 : 0", operands[0])); } - // These instructions are used with handles when we're implementing - // imports. This means we interact with the `resources` slabs to - // translate the wasm-provided index into a JS value. - Instruction::I32FromOwnedHandle { ty } => { - self.gen.imported_resources.insert(*ty); - results.push(format!("resources{}.insert({})", ty.index(), operands[0])); - } - Instruction::HandleBorrowedFromI32 { ty } => { - self.gen.imported_resources.insert(*ty); - results.push(format!("resources{}.get({})", ty.index(), operands[0])); - } - - // These instructions are used for handles to objects owned in wasm. - // This means that they're interacting with a wrapper class defined - // in JS. - Instruction::I32FromBorrowedHandle { ty } => { - let tmp = self.tmp(); - self.src - .js(&format!("const obj{} = {};\n", tmp, operands[0])); - - // If this is the `this` argument then it's implicitly already valid - if operands[0] != "this" { - self.src.js(&format!( - "if (!(obj{} instanceof {})) ", - tmp, - iface.resources[*ty].name.to_camel_case() - )); - self.src.js(&format!( - "throw new TypeError('expected instance of {}');\n", - iface.resources[*ty].name.to_camel_case() - )); - } - results.push(format!( - "{}._resource{}_slab.insert(obj{}.clone())", - self.src_object, - ty.index(), - tmp, - )); - } - Instruction::HandleOwnedFromI32 { ty } => { - results.push(format!( - "{}._resource{}_slab.remove({})", - self.src_object, - ty.index(), - operands[0], - )); - } - Instruction::RecordLower { record, .. } => { // use destructuring field access to get each // field individually. @@ -2150,21 +1831,13 @@ impl Bindgen for FunctionBindgen<'_> { Instruction::CallInterface { module: _, func } => { let call = |me: &mut FunctionBindgen<'_>| match &func.kind { - FunctionKind::Freestanding | FunctionKind::Static { .. } => { + FunctionKind::Freestanding => { me.src.js(&format!( "obj.{}({})", func.name.to_mixed_case(), operands.join(", "), )); } - FunctionKind::Method { name, .. } => { - me.src.js(&format!( - "{}.{}({})", - operands[0], - name.to_mixed_case(), - operands[1..].join(", "), - )); - } }; let mut bind_results = |me: &mut FunctionBindgen<'_>| { let amt = func.results.len(); diff --git a/crates/gen-host-wasmtime-py/src/lib.rs b/crates/gen-host-wasmtime-py/src/lib.rs index 64ea9efd1..08720b986 100644 --- a/crates/gen-host-wasmtime-py/src/lib.rs +++ b/crates/gen-host-wasmtime-py/src/lib.rs @@ -37,7 +37,6 @@ enum PyUnionRepresentation { #[derive(Default)] struct Imports { freestanding_funcs: Vec, - resource_funcs: BTreeMap>, } struct Import { @@ -50,7 +49,6 @@ struct Import { #[derive(Default)] struct Exports { freestanding_funcs: Vec, - resource_funcs: BTreeMap>, fields: BTreeMap, } @@ -95,11 +93,7 @@ impl WasmtimePy { } /// Creates a `Source` with all of the required intrinsics - fn intrinsics(&mut self, iface: &Interface) -> Source { - if iface.resources.len() > 0 { - self.deps.needs_resources = true; - self.deps.pyimport("typing", "runtime_checkable"); - } + fn intrinsics(&mut self, _iface: &Interface) -> Source { self.deps.intrinsics() } } @@ -118,7 +112,6 @@ fn array_ty(iface: &Interface, ty: &Type) -> Option<&'static str> { Type::Float32 => Some("c_float"), Type::Float64 => Some("c_double"), Type::Char => None, - Type::Handle(_) => None, Type::String => None, Type::Id(id) => match &iface.types[*id].kind { TypeDefKind::Type(t) => array_ty(iface, t), @@ -332,12 +325,6 @@ impl Generator for WasmtimePy { builder.push_str("\n"); } - fn type_resource(&mut self, _iface: &Interface, _ty: ResourceId) { - // if !self.in_import { - // self.exported_resources.insert(ty); - // } - } - fn type_alias(&mut self, iface: &Interface, _id: TypeId, name: &str, ty: &Type, docs: &Docs) { let mut builder = self.src.builder(&mut self.deps, iface); builder.comment(docs); @@ -457,13 +444,7 @@ impl Generator for WasmtimePy { .entry(iface.name.to_string()) .or_insert(Imports::default()); let dst = match &func.kind { - FunctionKind::Freestanding | FunctionKind::Static { .. } => { - &mut imports.freestanding_funcs - } - FunctionKind::Method { resource, .. } => imports - .resource_funcs - .entry(*resource) - .or_insert(Vec::new()), + FunctionKind::Freestanding => &mut imports.freestanding_funcs, }; dst.push(import); } @@ -484,8 +465,6 @@ impl Generator for WasmtimePy { // Use FunctionBindgen call let src_object = match &func.kind { FunctionKind::Freestanding => "self".to_string(), - FunctionKind::Static { .. } => "obj".to_string(), - FunctionKind::Method { .. } => "self._obj".to_string(), }; let mut f = FunctionBindgen::new(self, params); f.src_object = src_object; @@ -551,12 +530,6 @@ impl Generator for WasmtimePy { let dst = match &func.kind { FunctionKind::Freestanding => &mut exports.freestanding_funcs, - FunctionKind::Static { resource, .. } | FunctionKind::Method { resource, .. } => { - exports - .resource_funcs - .entry(*resource) - .or_insert(Vec::new()) - } }; dst.push(func_body); } @@ -596,78 +569,6 @@ impl Generator for WasmtimePy { } self.src.push_str(&intrinsics); - for (id, r) in iface.resources.iter() { - let name = r.name.to_camel_case(); - if self.in_import { - self.src.push_str("@runtime_checkable\n"); - self.src.push_str(&format!("class {}(Protocol):\n", name)); - self.src.indent(); - self.src.push_str("def drop(self) -> None:\n"); - self.src.indent(); - self.src.push_str("pass\n"); - self.src.dedent(); - - for (_, funcs) in self.guest_imports.iter() { - if let Some(funcs) = funcs.resource_funcs.get(&id) { - for func in funcs { - self.src.push_str("@abstractmethod\n"); - self.src.push_str(&func.pysig); - self.src.push_str(":\n"); - self.src.indent(); - self.src.push_str("raise NotImplementedError\n"); - self.src.dedent(); - } - } - } - self.src.dedent(); - } else { - self.src.push_str(&format!("class {}:\n", name)); - self.src.indent(); - self.src.push_str(&format!( - " - _wasm_val: int - _refcnt: int - _obj: '{iface}' - _destroyed: bool - - def __init__(self, val: int, obj: '{iface}') -> None: - self._wasm_val = val - self._refcnt = 1 - self._obj = obj - self._destroyed = False - - def clone(self) -> '{name}': - self._refcnt += 1 - return self - - def drop(self, store: wasmtime.Storelike) -> None: - self._refcnt -= 1; - if self._refcnt != 0: - return - assert(not self._destroyed) - self._destroyed = True - self._obj._canonical_abi_drop_{drop}(store, self._wasm_val) - - def __del__(self) -> None: - if not self._destroyed: - raise RuntimeError('wasm object not dropped') - ", - name = name, - iface = iface.name.to_camel_case(), - drop = name.to_snake_case(), - )); - - for (_, exports) in self.guest_exports.iter() { - if let Some(funcs) = exports.resource_funcs.get(&id) { - for func in funcs { - self.src.push_str(func); - } - } - } - - self.src.dedent(); - } - } self.src.push_str(&types); for (module, funcs) in mem::take(&mut self.guest_imports) { @@ -692,19 +593,7 @@ impl Generator for WasmtimePy { )); self.src.indent(); - for (id, r) in iface.resources.iter() { - self.src.push_str(&format!( - "_resources{}: Slab[{}] = Slab()\n", - id.index(), - r.name.to_camel_case() - )); - } - - for func in funcs - .freestanding_funcs - .iter() - .chain(funcs.resource_funcs.values().flat_map(|v| v)) - { + for func in funcs.freestanding_funcs.iter() { self.src.push_str(&format!("ty = {}\n", func.wasm_ty)); self.src.push_str(&func.src); self.src.push_str(&format!( @@ -715,25 +604,6 @@ impl Generator for WasmtimePy { )); } - for (id, resource) in iface.resources.iter() { - let snake = resource.name.to_snake_case(); - - self.src.push_str(&format!( - "def resource_drop_{}(i: int) -> None:\n _resources{}.remove(i).drop()\n", - snake, - id.index(), - )); - self.src - .push_str("ty = wasmtime.FuncType([wasmtime.ValType.i32()], [])\n"); - self.src.push_str(&format!( - "linker.define(\ - 'canonical_abi', \ - 'resource_drop_{}', \ - wasmtime.Func(store, ty, resource_drop_{})\ - )\n", - resource.name, snake, - )); - } self.src.dedent(); } @@ -743,16 +613,7 @@ impl Generator for WasmtimePy { self.src .push_str(&format!("class {}:\n", iface.name.to_camel_case())); self.src.indent(); - if iface.resources.len() == 0 { - self.src.push_str("pass\n"); - } else { - for (_, r) in iface.resources.iter() { - self.src.push_str(&format!( - "_canonical_abi_drop_{}: wasmtime.Func\n", - r.name.to_snake_case(), - )); - } - } + self.src.push_str("pass\n"); self.src.dedent(); } @@ -769,49 +630,9 @@ impl Generator for WasmtimePy { export.python_type )); } - for (id, r) in iface.resources.iter() { - self.src.push_str(&format!( - "_resource{}_slab: Slab[{}]\n", - id.index(), - r.name.to_camel_case(), - )); - self.src.push_str(&format!( - "_canonical_abi_drop_{}: wasmtime.Func\n", - r.name.to_snake_case(), - )); - } self.src.push_str("def __init__(self, store: wasmtime.Store, linker: wasmtime.Linker, module: wasmtime.Module):\n"); self.src.indent(); - for (id, r) in iface.resources.iter() { - self.src.push_str(&format!( - " - ty1 = wasmtime.FuncType([wasmtime.ValType.i32()], []) - ty2 = wasmtime.FuncType([wasmtime.ValType.i32()], [wasmtime.ValType.i32()]) - def drop_{snake}(caller: wasmtime.Caller, idx: int) -> None: - self._resource{idx}_slab.remove(idx).drop(caller); - linker.define('canonical_abi', 'resource_drop_{name}', wasmtime.Func(store, ty1, drop_{snake}, access_caller = True)) - - def clone_{snake}(idx: int) -> int: - obj = self._resource{idx}_slab.get(idx) - return self._resource{idx}_slab.insert(obj.clone()) - linker.define('canonical_abi', 'resource_clone_{name}', wasmtime.Func(store, ty2, clone_{snake})) - - def get_{snake}(idx: int) -> int: - obj = self._resource{idx}_slab.get(idx) - return obj._wasm_val - linker.define('canonical_abi', 'resource_get_{name}', wasmtime.Func(store, ty2, get_{snake})) - - def new_{snake}(val: int) -> int: - return self._resource{idx}_slab.insert({camel}(val, self)) - linker.define('canonical_abi', 'resource_new_{name}', wasmtime.Func(store, ty2, new_{snake})) - ", - name = r.name, - camel = r.name.to_camel_case(), - snake = r.name.to_snake_case(), - idx = id.index(), - )); - } self.src .push_str("self.instance = linker.instantiate(store, module)\n"); self.src @@ -828,19 +649,6 @@ impl Generator for WasmtimePy { ty = export.python_type, )); } - for (id, r) in iface.resources.iter() { - self.src.push_str(&format!( - " - self._resource{idx}_slab = Slab() - canon_drop_{snake} = exports['canonical_abi_drop_{name}'] - assert(isinstance(canon_drop_{snake}, wasmtime.Func)) - self._canonical_abi_drop_{snake} = canon_drop_{snake} - ", - idx = id.index(), - name = r.name, - snake = r.name.to_snake_case(), - )); - } self.src.dedent(); for func in exports.freestanding_funcs.iter() { @@ -1076,38 +884,6 @@ impl Bindgen for FunctionBindgen<'_> { results.push(format!("int({})", operands[0])); } - // These instructions are used with handles when we're implementing - // imports. This means we interact with the `resources` slabs to - // translate the wasm-provided index into a Python value. - Instruction::I32FromOwnedHandle { ty } => { - results.push(format!("_resources{}.insert({})", ty.index(), operands[0])); - } - Instruction::HandleBorrowedFromI32 { ty } => { - results.push(format!("_resources{}.get({})", ty.index(), operands[0])); - } - - // These instructions are used for handles to objects owned in wasm. - // This means that they're interacting with a wrapper class defined - // in Python. - Instruction::I32FromBorrowedHandle { ty } => { - let obj = self.locals.tmp("obj"); - builder.push_str(&format!("{} = {}\n", obj, operands[0])); - - results.push(format!( - "{}._resource{}_slab.insert({}.clone())", - self.src_object, - ty.index(), - obj, - )); - } - Instruction::HandleOwnedFromI32 { ty } => { - results.push(format!( - "{}._resource{}_slab.remove({})", - self.src_object, - ty.index(), - operands[0], - )); - } Instruction::RecordLower { record, .. } => { if record.fields.is_empty() { return; @@ -1737,21 +1513,13 @@ impl Bindgen for FunctionBindgen<'_> { builder.push_str(" = "); } match &func.kind { - FunctionKind::Freestanding | FunctionKind::Static { .. } => { + FunctionKind::Freestanding => { builder.push_str(&format!( "host.{}({})", func.name.to_snake_case(), operands.join(", "), )); } - FunctionKind::Method { name, .. } => { - builder.push_str(&format!( - "{}.{}({})", - operands[0], - name.to_snake_case(), - operands[1..].join(", "), - )); - } } builder.push_str("\n"); } @@ -1833,7 +1601,7 @@ fn py_type_class_of(ty: &Type) -> PyTypeClass { | Type::S64 => PyTypeClass::Int, Type::Float32 | Type::Float64 => PyTypeClass::Float, Type::Char | Type::String => PyTypeClass::Str, - Type::Handle(_) | Type::Id(_) => PyTypeClass::Custom, + Type::Id(_) => PyTypeClass::Custom, } } diff --git a/crates/gen-host-wasmtime-py/src/source.rs b/crates/gen-host-wasmtime-py/src/source.rs index 007ea423c..f412e874e 100644 --- a/crates/gen-host-wasmtime-py/src/source.rs +++ b/crates/gen-host-wasmtime-py/src/source.rs @@ -185,16 +185,6 @@ impl<'s, 'd, 'i> SourceBuilder<'s, 'd, 'i> { Type::Float32 | Type::Float64 => self.push_str("float"), Type::Char => self.push_str("str"), Type::String => self.push_str("str"), - Type::Handle(id) => { - if forward_ref { - self.push_str("'"); - } - let handle_name = &self.iface.resources[*id].name.to_camel_case(); - self.source.push_str(handle_name); - if forward_ref { - self.push_str("'"); - } - } Type::Id(id) => { let ty = &self.iface.types[*id]; if let Some(name) = &ty.name { @@ -325,36 +315,15 @@ impl<'s, 'd, 'i> SourceBuilder<'s, 'd, 'i> { } pub fn print_sig(&mut self, func: &Function, in_import: bool) -> Vec { - if !in_import { - if let FunctionKind::Static { .. } = func.kind { - self.push_str("@classmethod\n"); - } - } self.source.push_str("def "); - match &func.kind { - FunctionKind::Method { .. } => self.source.push_str(&func.item_name().to_snake_case()), - FunctionKind::Static { .. } if !in_import => { - self.source.push_str(&func.item_name().to_snake_case()) - } - _ => self.source.push_str(&func.name.to_snake_case()), - } + self.source.push_str(&func.name.to_snake_case()); if in_import { self.source.push_str("(self"); - } else if let FunctionKind::Static { .. } = func.kind { - self.source.push_str("(cls, caller: wasmtime.Store, obj: '"); - self.source.push_str(&self.iface.name.to_camel_case()); - self.source.push_str("'"); } else { self.source.push_str("(self, caller: wasmtime.Store"); } let mut params = Vec::new(); - for (i, (param, ty)) in func.params.iter().enumerate() { - if i == 0 { - if let FunctionKind::Method { .. } = func.kind { - params.push("self".to_string()); - continue; - } - } + for (param, ty) in func.params.iter() { self.source.push_str(", "); self.source.push_str(¶m.to_snake_case()); params.push(param.to_snake_case()); @@ -479,48 +448,6 @@ mod tests { assert_eq!(s.s, "def foo():\n return 1\n"); } - #[test] - fn print_ty_forward_ref() { - let mut deps = Dependencies::default(); - let mut iface = Interface::default(); - // Set up a Resource type to refer to - let resource_id = iface.resources.alloc(Resource { - docs: Docs::default(), - name: "foo".into(), - supertype: None, - foreign_module: None, - }); - iface.resource_lookup.insert("foo".into(), resource_id); - let handle_ty = Type::Handle(resource_id); - // ForwardRef usage can be controlled by an argument to print_ty - let mut s1 = Source::default(); - let mut builder = s1.builder(&mut deps, &iface); - builder.print_ty(&handle_ty, true); - drop(builder); - assert_eq!(s1.s, "'Foo'"); - - let mut s2 = Source::default(); - let mut builder = s2.builder(&mut deps, &iface); - builder.print_ty(&handle_ty, false); - drop(builder); - assert_eq!(s2.s, "Foo"); - - // ForwardRef is used for any types within other types - // Even if the outer type is itself not allowed to be one - let option_id = iface.types.alloc(TypeDef { - docs: Docs::default(), - kind: TypeDefKind::Option(handle_ty), - name: None, - foreign_module: None, - }); - let option_ty = Type::Id(option_id); - let mut s3 = Source::default(); - let mut builder = s3.builder(&mut deps, &iface); - builder.print_ty(&option_ty, false); - drop(builder); - assert_eq!(s3.s, "Optional['Foo']"); - } - #[test] fn print_list_bytes() { // If the element type is u8, it is interpreted as `bytes` diff --git a/crates/gen-host-wasmtime-rust/src/lib.rs b/crates/gen-host-wasmtime-rust/src/lib.rs index 2b336a116..80e274c77 100644 --- a/crates/gen-host-wasmtime-rust/src/lib.rs +++ b/crates/gen-host-wasmtime-rust/src/lib.rs @@ -26,7 +26,6 @@ pub struct Wasmtime { needs_custom_error_to_trap: bool, needs_custom_error_to_types: BTreeSet, all_needed_handles: BTreeSet, - exported_resources: BTreeSet, types: Types, guest_imports: HashMap>, guest_exports: HashMap, @@ -197,22 +196,6 @@ impl RustGenerator for Wasmtime { } } - fn handle_projection(&self) -> Option<(&'static str, String)> { - if self.in_import { - if self.in_trait { - Some(("Self", self.trait_name.clone())) - } else { - Some(("T", self.trait_name.clone())) - } - } else { - None - } - } - - fn handle_wrapper(&self) -> Option<&'static str> { - None - } - fn push_str(&mut self, s: &str) { self.src.push_str(s); } @@ -445,29 +428,6 @@ impl Generator for Wasmtime { self.print_typedef_enum(id, name, enum_, docs); } - fn type_resource(&mut self, iface: &Interface, ty: ResourceId) { - let name = &iface.resources[ty].name; - self.all_needed_handles.insert(name.to_string()); - - // If we're binding imports then all handles are associated types so - // there's nothing that we need to do about that. - if self.in_import { - return; - } - - self.exported_resources.insert(ty); - - // ... otherwise for exports we generate a newtype wrapper around an - // `i32` to manage the resultt. - let tyname = name.to_camel_case(); - self.rustdoc(&iface.resources[ty].docs); - self.src.push_str("#[derive(Debug)]\n"); - self.src.push_str(&format!( - "pub struct {}(wit_bindgen_host_wasmtime_rust::rt::ResourceIndex);\n", - tyname - )); - } - fn type_alias(&mut self, iface: &Interface, id: TypeId, _name: &str, ty: &Type, docs: &Docs) { self.print_typedef_alias(iface, id, ty, docs); } @@ -764,7 +724,7 @@ impl Generator for Wasmtime { ); } - fn finish_one(&mut self, iface: &Interface, files: &mut Files) { + fn finish_one(&mut self, _iface: &Interface, files: &mut Files) { for (module, funcs) in sorted_iter(&self.guest_imports) { let module_camel = module.to_camel_case(); self.src.push_str("pub trait "); @@ -842,11 +802,7 @@ impl Generator for Wasmtime { let module_camel = module.to_camel_case(); self.push_str("\npub fn add_to_linker(linker: &mut wasmtime::Linker"); self.push_str(", get: impl Fn(&mut T) -> "); - if self.all_needed_handles.is_empty() { - self.push_str("&mut U"); - } else { - self.push_str(&format!("(&mut U, &mut {}Tables)", module_camel)); - } + self.push_str("&mut U"); self.push_str("+ Send + Sync + Copy + 'static) -> anyhow::Result<()> \n"); self.push_str("where U: "); self.push_str(&module_camel); @@ -864,27 +820,6 @@ impl Generator for Wasmtime { method, module, f.name, f.closure, )); } - for handle in self.all_needed_handles.iter() { - self.src.push_str(&format!( - "linker.func_wrap( - \"canonical_abi\", - \"resource_drop_{name}\", - move |mut caller: wasmtime::Caller<'_, T>, handle: u32| {{ - let (host, tables) = get(caller.data_mut()); - let handle = tables - .{snake}_table - .remove(handle) - .map_err(|e| {{ - wasmtime::Trap::new(format!(\"failed to remove handle: {{}}\", e)) - }})?; - host.drop_{snake}(handle); - Ok(()) - }} - )?;\n", - name = handle, - snake = handle.to_snake_case(), - )); - } self.push_str("Ok(())\n}\n"); } @@ -907,16 +842,6 @@ impl Generator for Wasmtime { self.push_str("pub struct "); self.push_str(&name); self.push_str("Data {\n"); - for r in self.exported_resources.iter() { - self.src.push_str(&format!( - " - index_slab{}: wit_bindgen_host_wasmtime_rust::rt::IndexSlab, - resource_slab{0}: wit_bindgen_host_wasmtime_rust::rt::ResourceSlab, - dtor{0}: Option>, - ", - r.index() - )); - } self.push_str("}\n"); self.push_str("pub struct "); @@ -936,84 +861,6 @@ impl Generator for Wasmtime { let bound = ""; self.push_str(&format!("impl {} {{\n", bound, name)); - if self.exported_resources.len() == 0 { - self.push_str("#[allow(unused_variables)]\n"); - } - self.push_str(&format!( - " - /// Adds any intrinsics, if necessary for this exported wasm - /// functionality to the `linker` provided. - /// - /// The `get_state` closure is required to access the - /// auxiliary data necessary for these wasm exports from - /// the general store's state. - pub fn add_to_linker( - linker: &mut wasmtime::Linker, - get_state: impl Fn(&mut T) -> &mut {}Data + Send + Sync + Copy + 'static, - ) -> anyhow::Result<()> {{ - ", - name, - )); - for r in self.exported_resources.iter() { - let (func_wrap, call, wait, prefix, suffix) = ("func_wrap", "call", "", "", ""); - self.src.push_str(&format!( - " - linker.{func_wrap}( - \"canonical_abi\", - \"resource_drop_{name}\", - move |mut caller: wasmtime::Caller<'_, T>, idx: u32| {prefix}{{ - let state = get_state(caller.data_mut()); - let resource_idx = state.index_slab{idx}.remove(idx)?; - let wasm = match state.resource_slab{idx}.drop(resource_idx) {{ - Some(wasm) => wasm, - None => return Ok(()), - }}; - let dtor = state.dtor{idx}.expect(\"destructor not set yet\"); - dtor.{call}(&mut caller, wasm){wait}?; - Ok(()) - }}{suffix}, - )?; - linker.func_wrap( - \"canonical_abi\", - \"resource_clone_{name}\", - move |mut caller: wasmtime::Caller<'_, T>, idx: u32| {{ - let state = get_state(caller.data_mut()); - let resource_idx = state.index_slab{idx}.get(idx)?; - state.resource_slab{idx}.clone(resource_idx)?; - Ok(state.index_slab{idx}.insert(resource_idx)) - }}, - )?; - linker.func_wrap( - \"canonical_abi\", - \"resource_get_{name}\", - move |mut caller: wasmtime::Caller<'_, T>, idx: u32| {{ - let state = get_state(caller.data_mut()); - let resource_idx = state.index_slab{idx}.get(idx)?; - Ok(state.resource_slab{idx}.get(resource_idx)) - }}, - )?; - linker.func_wrap( - \"canonical_abi\", - \"resource_new_{name}\", - move |mut caller: wasmtime::Caller<'_, T>, val: i32| {{ - let state = get_state(caller.data_mut()); - let resource_idx = state.resource_slab{idx}.insert(val); - Ok(state.index_slab{idx}.insert(resource_idx)) - }}, - )?; - ", - name = iface.resources[*r].name, - idx = r.index(), - func_wrap = func_wrap, - call = call, - wait = wait, - prefix = prefix, - suffix = suffix, - )); - } - self.push_str("Ok(())\n"); - self.push_str("}\n"); - let (instantiate, wait) = ("", ""); self.push_str(&format!( " @@ -1037,7 +884,6 @@ impl Generator for Wasmtime { linker: &mut wasmtime::Linker, get_state: impl Fn(&mut T) -> &mut {}Data + Send + Sync + Copy + 'static, ) -> anyhow::Result<(Self, wasmtime::Instance)> {{ - Self::add_to_linker(linker, get_state)?; let instance = linker.instantiate{}(&mut store, module){}?; Ok((Self::new(store, &instance,get_state)?, instance)) }} @@ -1072,19 +918,6 @@ impl Generator for Wasmtime { self.push_str(&get); self.push_str(";\n"); } - for r in self.exported_resources.iter() { - self.src.push_str(&format!( - " - get_state(store.data_mut()).dtor{} = \ - Some(instance.get_typed_func::(\ - &mut store, \ - \"canonical_abi_drop_{}\", \ - )?);\n - ", - r.index(), - iface.resources[*r].name, - )); - } self.push_str("Ok("); self.push_str(&name); self.push_str("{\n"); @@ -1100,40 +933,6 @@ impl Generator for Wasmtime { self.push_str(func); } - for r in self.exported_resources.iter() { - let (call, wait) = ("call", ""); - self.src.push_str(&format!( - " - /// Drops the host-owned handle to the resource - /// specified. - /// - /// Note that this may execute the WebAssembly-defined - /// destructor for this type. This also may not run - /// the destructor if there are still other references - /// to this type. - pub fn drop_{name_snake}( - &self, - mut store: impl wasmtime::AsContextMut, - val: {name_camel}, - ) -> Result<(), wasmtime::Trap> {{ - let mut store = store.as_context_mut(); - let data = (self.get_state)(store.data_mut()); - let wasm = match data.resource_slab{idx}.drop(val.0) {{ - Some(val) => val, - None => return Ok(()), - }}; - data.dtor{idx}.unwrap().{call}(&mut store, wasm){wait}?; - Ok(()) - }} - ", - name_snake = iface.resources[*r].name.to_snake_case(), - name_camel = iface.resources[*r].name.to_camel_case(), - idx = r.index(), - call = call, - wait = wait, - )); - } - self.push_str("}\n"); } self.print_intrinsics(); @@ -1447,52 +1246,6 @@ impl Bindgen for FunctionBindgen<'_> { )); } - Instruction::I32FromOwnedHandle { ty } => { - let name = &iface.resources[*ty].name; - results.push(format!( - "_tables.{}_table.insert({}) as i32", - name.to_snake_case(), - operands[0] - )); - } - Instruction::HandleBorrowedFromI32 { ty } => { - let name = &iface.resources[*ty].name; - results.push(format!( - "_tables.{}_table.get(({}) as u32).ok_or_else(|| {{ - wasmtime::Trap::new(\"invalid handle index\") - }})?", - name.to_snake_case(), - operands[0] - )); - } - Instruction::I32FromBorrowedHandle { ty } => { - let tmp = self.tmp(); - self.push_str(&format!( - " - let obj{tmp} = {op}; - (self.get_state)(caller.as_context_mut().data_mut()).resource_slab{idx}.clone(obj{tmp}.0)?; - let handle{tmp} = (self.get_state)(caller.as_context_mut().data_mut()).index_slab{idx}.insert(obj{tmp}.0); - ", - tmp = tmp, - idx = ty.index(), - op = operands[0], - )); - - results.push(format!("handle{} as i32", tmp,)); - } - Instruction::HandleOwnedFromI32 { ty } => { - let tmp = self.tmp(); - self.push_str(&format!( - "let handle{} = (self.get_state)(caller.as_context_mut().data_mut()).index_slab{}.remove({} as u32)?;\n", - tmp, - ty.index(), - operands[0], - )); - - let name = iface.resources[*ty].name.to_camel_case(); - results.push(format!("{}(handle{})", name, tmp)); - } - Instruction::RecordLower { ty, record, .. } => { self.record_lower(iface, *ty, record, &operands[0], results); } diff --git a/crates/gen-markdown/src/lib.rs b/crates/gen-markdown/src/lib.rs index 8c59fa44a..a2492c318 100644 --- a/crates/gen-markdown/src/lib.rs +++ b/crates/gen-markdown/src/lib.rs @@ -48,11 +48,6 @@ impl Markdown { Type::Float64 => self.src.push_str("`float64`"), Type::Char => self.src.push_str("`char`"), Type::String => self.src.push_str("`string`"), - Type::Handle(id) => { - self.src.push_str("handle<"); - self.src.push_str(&iface.resources[*id].name); - self.src.push_str(">"); - } Type::Id(id) => { let ty = &iface.types[*id]; if !skip_name { @@ -422,10 +417,6 @@ impl Generator for Markdown { self.print_type_info(id, docs); } - fn type_resource(&mut self, iface: &Interface, ty: ResourceId) { - drop((iface, ty)); - } - fn type_alias(&mut self, iface: &Interface, id: TypeId, name: &str, ty: &Type, docs: &Docs) { self.print_type_header(name); self.print_ty(iface, ty, true); diff --git a/crates/gen-rust-lib/src/lib.rs b/crates/gen-rust-lib/src/lib.rs index ff568b383..8e0a6eb29 100644 --- a/crates/gen-rust-lib/src/lib.rs +++ b/crates/gen-rust-lib/src/lib.rs @@ -10,7 +10,6 @@ pub enum TypeMode { Owned, AllBorrowed(&'static str), LeafBorrowed(&'static str), - HandlesBorrowed(&'static str), } pub trait RustGenerator { @@ -26,11 +25,6 @@ pub trait RustGenerator { ); fn print_borrowed_str(&mut self, lifetime: &'static str); fn default_param_mode(&self) -> TypeMode; - fn handle_projection(&self) -> Option<(&'static str, String)>; - fn handle_wrapper(&self) -> Option<&'static str>; - fn handle_in_super(&self) -> bool { - false - } fn rustdoc(&mut self, docs: &Docs) { let docs = match &docs.contents { @@ -164,39 +158,6 @@ pub trait RustGenerator { fn print_ty(&mut self, iface: &Interface, ty: &Type, mode: TypeMode) { match ty { Type::Id(t) => self.print_tyid(iface, *t, mode), - Type::Handle(r) => { - let mut info = TypeInfo::default(); - info.has_handle = true; - let lt = self.lifetime_for(&info, mode); - // Borrowed handles are always behind a reference since - // in that case we never take ownership of the handle. - if let Some(lt) = lt { - self.push_str("&"); - if lt != "'_" { - self.push_str(lt); - } - self.push_str(" "); - } - - let suffix = match self.handle_wrapper() { - Some(wrapper) => { - self.push_str(wrapper); - self.push_str("<"); - ">" - } - None => "", - }; - if self.handle_in_super() { - self.push_str("super::"); - } - if let Some((proj, _)) = self.handle_projection() { - self.push_str(proj); - self.push_str("::"); - } - self.push_str(&iface.resources[*r].name.to_camel_case()); - self.push_str(suffix); - } - Type::Bool => self.push_str("bool"), Type::U8 => self.push_str("u8"), Type::U16 => self.push_str("u16"), @@ -213,7 +174,7 @@ pub trait RustGenerator { TypeMode::AllBorrowed(lt) | TypeMode::LeafBorrowed(lt) => { self.print_borrowed_str(lt) } - TypeMode::Owned | TypeMode::HandlesBorrowed(_) => self.push_str("String"), + TypeMode::Owned => self.push_str("String"), }, } } @@ -241,7 +202,7 @@ pub trait RustGenerator { // variant/record/list, then we need to place the // lifetime parameter on the type as well. if info.owns_data() && needs_generics(iface, &ty.kind) { - self.print_generics(&info, lt, false); + self.print_generics(lt); } return; @@ -261,7 +222,6 @@ pub trait RustGenerator { | TypeDefKind::Union(_) => true, TypeDefKind::Type(Type::Id(t)) => needs_generics(iface, &iface.types[*t].kind), TypeDefKind::Type(Type::String) => true, - TypeDefKind::Type(Type::Handle(_)) => true, TypeDefKind::Type(_) => false, } } @@ -340,7 +300,7 @@ pub trait RustGenerator { self.push_str(">"); } } - TypeMode::HandlesBorrowed(_) | TypeMode::Owned => { + TypeMode::Owned => { self.push_str("Vec<"); self.print_ty(iface, ty, mode); self.push_str(">"); @@ -368,13 +328,8 @@ pub trait RustGenerator { self.push_str("]"); } - fn print_generics(&mut self, info: &TypeInfo, lifetime: Option<&str>, bound: bool) { - let proj = if info.has_handle { - self.handle_projection() - } else { - None - }; - if lifetime.is_none() && proj.is_none() { + fn print_generics(&mut self, lifetime: Option<&str>) { + if lifetime.is_none() { return; } self.push_str("<"); @@ -382,13 +337,6 @@ pub trait RustGenerator { self.push_str(lt); self.push_str(","); } - if let Some((proj, trait_bound)) = proj { - self.push_str(proj); - if bound { - self.push_str(": "); - self.push_str(&trait_bound); - } - } self.push_str(">"); } @@ -428,7 +376,6 @@ pub trait RustGenerator { Type::Float64 => out.push_str("F64"), Type::Char => out.push_str("Char"), Type::String => out.push_str("String"), - Type::Handle(id) => out.push_str(&iface.resources[*id].name.to_camel_case()), Type::Id(id) => { let ty = &iface.types[*id]; match &ty.name { @@ -537,11 +484,11 @@ pub trait RustGenerator { if !info.owns_data() { self.push_str("#[repr(C)]\n"); self.push_str("#[derive(Copy, Clone)]\n"); - } else if !info.has_handle { + } else { self.push_str("#[derive(Clone)]\n"); } self.push_str(&format!("pub struct {}", name)); - self.print_generics(&info, lt, true); + self.print_generics(lt); self.push_str(" {\n"); for field in record.fields.iter() { self.rustdoc(&field.docs); @@ -554,10 +501,10 @@ pub trait RustGenerator { self.push_str("}\n"); self.push_str("impl"); - self.print_generics(&info, lt, true); + self.print_generics(lt); self.push_str(" core::fmt::Debug for "); self.push_str(&name); - self.print_generics(&info, lt, false); + self.print_generics(lt); self.push_str(" {\n"); self.push_str( "fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n", @@ -582,7 +529,7 @@ pub trait RustGenerator { let lt = self.lifetime_for(&info, mode); self.rustdoc(docs); self.push_str(&format!("pub type {}", name)); - self.print_generics(&info, lt, true); + self.print_generics(lt); self.push_str(" = ("); for ty in tuple.types.iter() { self.print_ty(iface, ty, mode); @@ -642,11 +589,11 @@ pub trait RustGenerator { let lt = self.lifetime_for(&info, mode); if !info.owns_data() { self.push_str("#[derive(Clone, Copy)]\n"); - } else if !info.has_handle { + } else { self.push_str("#[derive(Clone)]\n"); } self.push_str(&format!("pub enum {name}")); - self.print_generics(&info, lt, true); + self.print_generics(lt); self.push_str("{\n"); for (case_name, docs, payload) in cases.clone() { self.rustdoc(docs); @@ -684,10 +631,10 @@ pub trait RustGenerator { let info = self.info(id); let lt = self.lifetime_for(&info, mode); self.push_str("impl"); - self.print_generics(&info, lt, true); + self.print_generics(lt); self.push_str(" core::fmt::Debug for "); self.push_str(name); - self.print_generics(&info, lt, false); + self.print_generics(lt); self.push_str(" {\n"); self.push_str("fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n"); self.push_str("match self {\n"); @@ -718,7 +665,7 @@ pub trait RustGenerator { self.rustdoc(docs); let lt = self.lifetime_for(&info, mode); self.push_str(&format!("pub type {}", name)); - self.print_generics(&info, lt, true); + self.print_generics(lt); self.push_str("= Option<"); self.print_ty(iface, payload, mode); self.push_str(">;\n"); @@ -738,7 +685,7 @@ pub trait RustGenerator { self.rustdoc(docs); let lt = self.lifetime_for(&info, mode); self.push_str(&format!("pub type {}", name)); - self.print_generics(&info, lt, true); + self.print_generics(lt); self.push_str("= Result<"); self.print_optional_ty(iface, result.ok.as_ref(), mode); self.push_str(","); @@ -847,7 +794,7 @@ pub trait RustGenerator { self.rustdoc(docs); self.push_str(&format!("pub type {}", name)); let lt = self.lifetime_for(&info, mode); - self.print_generics(&info, lt, true); + self.print_generics(lt); self.push_str(" = "); self.print_ty(iface, ty, mode); self.push_str(";\n"); @@ -860,7 +807,7 @@ pub trait RustGenerator { let lt = self.lifetime_for(&info, mode); self.rustdoc(docs); self.push_str(&format!("pub type {}", name)); - self.print_generics(&info, lt, true); + self.print_generics(lt); self.push_str(" = "); self.print_list(iface, ty, mode); self.push_str(";\n"); @@ -893,19 +840,13 @@ pub trait RustGenerator { && info.result && match self.default_param_mode() { TypeMode::AllBorrowed(_) | TypeMode::LeafBorrowed(_) => true, - TypeMode::HandlesBorrowed(_) => info.has_handle, TypeMode::Owned => false, } } fn lifetime_for(&self, info: &TypeInfo, mode: TypeMode) -> Option<&'static str> { match mode { - TypeMode::AllBorrowed(s) | TypeMode::LeafBorrowed(s) - if info.has_list || info.has_handle => - { - Some(s) - } - TypeMode::HandlesBorrowed(s) if info.has_handle => Some(s), + TypeMode::AllBorrowed(s) | TypeMode::LeafBorrowed(s) if info.has_list => Some(s), _ => None, } } @@ -1119,7 +1060,7 @@ trait TypeInfoExt { impl TypeInfoExt for TypeInfo { fn owns_data(&self) -> bool { - self.has_list || self.has_handle + self.has_list } } diff --git a/crates/test-helpers/src/lib.rs b/crates/test-helpers/src/lib.rs index 073b17e36..b1216ac00 100644 --- a/crates/test-helpers/src/lib.rs +++ b/crates/test-helpers/src/lib.rs @@ -35,7 +35,6 @@ pub fn codegen_rust_wasm_import(input: TokenStream) -> TokenStream { #[cfg(feature = "guest-rust")] pub fn codegen_rust_wasm_export(input: TokenStream) -> TokenStream { use heck::*; - use std::collections::BTreeMap; use wit_parser::{FunctionKind, Type, TypeDefKind}; return gen_rust( @@ -62,24 +61,18 @@ pub fn codegen_rust_wasm_export(input: TokenStream) -> TokenStream { fn gen_extra(iface: &wit_parser::Interface) -> proc_macro2::TokenStream { let mut ret = quote::quote!(); - if iface.resources.len() == 0 && iface.functions.len() == 0 { + if iface.functions.len() == 0 { return ret; } let snake = quote::format_ident!("{}", iface.name.to_snake_case()); let camel = quote::format_ident!("{}", iface.name.to_camel_case()); - for (_, r) in iface.resources.iter() { - let name = quote::format_ident!("{}", r.name.to_camel_case()); - ret.extend(quote::quote!(pub struct #name;)); - } - let mut methods = Vec::new(); - let mut resources = BTreeMap::new(); for f in iface.functions.iter() { let name = quote::format_ident!("{}", f.item_name().to_snake_case()); - let mut params = f + let params = f .params .iter() .map(|(_, t)| quote_ty(true, iface, t)) @@ -89,29 +82,18 @@ pub fn codegen_rust_wasm_export(input: TokenStream) -> TokenStream { .iter_types() .map(|t| quote_ty(false, iface, t)) .collect::>(); - let mut self_ = quote::quote!(); - if let FunctionKind::Method { .. } = &f.kind { - params.remove(0); - self_ = quote::quote!(&self,); - } let ret = match rets.len() { 0 => quote::quote!(()), 1 => rets[0].clone(), _ => quote::quote!((#(#rets,)*)), }; let method = quote::quote! { - fn #name(#self_ #(_: #params),*) -> #ret { + fn #name(#(_: #params),*) -> #ret { loop {} } }; match &f.kind { FunctionKind::Freestanding => methods.push(method), - FunctionKind::Static { resource, .. } | FunctionKind::Method { resource, .. } => { - resources - .entry(*resource) - .or_insert(Vec::new()) - .push(method); - } } } ret.extend(quote::quote! { @@ -121,14 +103,6 @@ pub fn codegen_rust_wasm_export(input: TokenStream) -> TokenStream { #(#methods)* } }); - for (id, methods) in resources { - let name = quote::format_ident!("{}", iface.resources[id].name.to_camel_case()); - ret.extend(quote::quote! { - impl #snake::#name for #name { - #(#methods)* - } - }); - } ret } @@ -152,11 +126,6 @@ pub fn codegen_rust_wasm_export(input: TokenStream) -> TokenStream { Type::Float64 => quote::quote! { f64 }, Type::Char => quote::quote! { char }, Type::String => quote::quote! { String }, - Type::Handle(resource) => { - let name = - quote::format_ident!("{}", iface.resources[resource].name.to_camel_case()); - quote::quote! { wit_bindgen_guest_rust::Handle<#name> } - } Type::Id(id) => quote_id(param, iface, id), } } diff --git a/crates/test-rust-wasm/Cargo.toml b/crates/test-rust-wasm/Cargo.toml index 8afc68511..d58925b56 100644 --- a/crates/test-rust-wasm/Cargo.toml +++ b/crates/test-rust-wasm/Cargo.toml @@ -36,10 +36,6 @@ test = false name = "lists" test = false -[[bin]] -name = "handles" -test = false - [[bin]] name = "flavorful" test = false diff --git a/crates/test-rust-wasm/src/bin/handles.rs b/crates/test-rust-wasm/src/bin/handles.rs deleted file mode 100644 index 4d5732813..000000000 --- a/crates/test-rust-wasm/src/bin/handles.rs +++ /dev/null @@ -1,3 +0,0 @@ -include!("../../../../tests/runtime/handles/wasm.rs"); - -fn main() {} diff --git a/crates/wit-component/src/encoding.rs b/crates/wit-component/src/encoding.rs index dc6dbd613..b236915b6 100644 --- a/crates/wit-component/src/encoding.rs +++ b/crates/wit-component/src/encoding.rs @@ -548,8 +548,6 @@ impl<'a> TypeEncoder<'a> { required_funcs: &IndexSet<&'a str>, imports: &mut ImportEncoder<'a>, ) -> Result<()> { - Self::validate_interface(import)?; - let mut instance = InstanceTypeEncoder::default(); for func in &import.functions { @@ -574,8 +572,6 @@ impl<'a> TypeEncoder<'a> { export_func_types: bool, ) -> Result<()> { for (export, is_default) in interfaces { - Self::validate_interface(export)?; - // TODO: stick interface documentation in a custom section? for func in &export.functions { @@ -744,9 +740,6 @@ impl<'a> TypeEncoder<'a> { encoded } - Type::Handle(_) => { - bail!("the use of handle types in interfaces is not currently supported") - } }) } @@ -915,14 +908,6 @@ impl<'a> TypeEncoder<'a> { Ok(()) } - fn validate_interface(interface: &Interface) -> Result<()> { - if interface.resources.len() != 0 { - bail!("the use of resources in interfaces is not currently not supported"); - } - - Ok(()) - } - fn validate_function(function: &Function) -> Result<()> { if function.name.is_empty() { bail!("interface has an unnamed function"); diff --git a/crates/wit-component/src/printing.rs b/crates/wit-component/src/printing.rs index 0bc89dbcf..3886d01d0 100644 --- a/crates/wit-component/src/printing.rs +++ b/crates/wit-component/src/printing.rs @@ -122,8 +122,6 @@ impl InterfacePrinter { } } } - - Type::Handle(_) => bail!("interface has unsupported type"), } Ok(()) @@ -245,8 +243,6 @@ impl InterfacePrinter { TypeDefKind::Stream(_) => todo!("declare stream"), } } - - Type::Handle(_) => bail!("interface has unsupported type"), } Ok(()) } diff --git a/crates/wit-parser/src/abi.rs b/crates/wit-parser/src/abi.rs index 66bbb12ff..02be702a7 100644 --- a/crates/wit-parser/src/abi.rs +++ b/crates/wit-parser/src/abi.rs @@ -1,7 +1,7 @@ use crate::sizealign::align_to; use crate::{ - Enum, Flags, FlagsRepr, Function, Int, Interface, Record, ResourceId, Result_, Results, Tuple, - Type, TypeDefKind, TypeId, Union, Variant, + Enum, Flags, FlagsRepr, Function, Int, Interface, Record, Result_, Results, Tuple, Type, + TypeDefKind, TypeId, Union, Variant, }; /// A raw WebAssembly signature with params and results. @@ -267,113 +267,6 @@ def_instruction! { /// Creates an `i32` from a `bool` input, must return 0 or 1. I32FromBool : [1] => [1], - // Handles - - /// Converts a "borrowed" handle into a wasm `i32` value. - /// - /// > **Note**: this documentation is outdated and does not reflect the - /// > current implementation of the canonical ABI. This needs to be - /// > updated. - /// - /// A "borrowed" handle in this case means one where ownership is not - /// being relinquished. This is only used for lowering interface types - /// parameters. - /// - /// Situations that this is used are: - /// - /// * A wasm exported function receives, as a parameter, handles defined - /// by the wasm module itself. This is effectively proof of ownership - /// by an external caller (be it host or wasm module) and the - /// ownership of the handle still lies with the caller. The wasm - /// module is only receiving a reference to the resource. - /// - /// * A wasm module is calling an import with a handle defined by the - /// import's module. Sort of the converse of the previous case this - /// means that the wasm module is handing out a reference to a - /// resource that it owns. The type in the wasm module, for example, - /// needs to reflect this. - /// - /// This instruction is not used for return values in either - /// export/import positions. - I32FromBorrowedHandle { ty: ResourceId } : [1] => [1], - - /// Converts an "owned" handle into a wasm `i32` value. - /// - /// > **Note**: this documentation is outdated and does not reflect the - /// > current implementation of the canonical ABI. This needs to be - /// > updated. - /// - /// This conversion is used for handle values which are crossing a - /// module boundary for perhaps the first time. Some example cases of - /// when this conversion is used are: - /// - /// * When a host defines a function to be imported, returned handles - /// use this instruction. Handles being returned to wasm a granting a - /// capability, which means that this new capability is typically - /// wrapped up in a new integer descriptor. - /// - /// * When a wasm module calls an imported function with a type defined - /// by itself, then it's granting a capability to the callee. This - /// means that the wasm module's type is being granted for the first - /// time, possibly, so it needs to be an owned value that's consumed. - /// Note that this doesn't actually happen with `*.witx` today due to - /// the lack of handle type imports. - /// - /// * When a wasm module export returns a handle defined within the - /// module, then it's similar to calling an imported function with - /// that handle. The capability is being granted to the caller of the - /// export, so the owned value is wrapped up in an `i32`. - /// - /// * When a host is calling a wasm module with a capability defined by - /// the host, its' similar to the host import returning a capability. - /// This would be granting the wasm module with the capability so an - /// owned version with a fresh handle is passed to the wasm module. - /// Note that this doesn't happen today with `*.witx` due to the lack - /// of handle type imports. - /// - /// Basically this instruction is used for handle->wasm conversions - /// depending on the calling context and where the handle type in - /// question was defined. - I32FromOwnedHandle { ty: ResourceId } : [1] => [1], - - /// Converts a native wasm `i32` into an owned handle value. - /// - /// > **Note**: this documentation is outdated and does not reflect the - /// > current implementation of the canonical ABI. This needs to be - /// > updated. - /// - /// This is the converse of `I32FromOwnedHandle` and is used in similar - /// situations: - /// - /// * A host definition of an import receives a handle defined in the - /// module itself. - /// * A wasm module calling an import receives a handle defined by the - /// import. - /// * A wasm module's export receives a handle defined by an external - /// module. - /// * A host calling a wasm export receives a handle defined in the - /// module. - /// - /// Note that like `I32FromOwnedHandle` the first and third bullets - /// above don't happen today because witx can't express type imports - /// just yet. - HandleOwnedFromI32 { ty: ResourceId } : [1] => [1], - - /// Converts a native wasm `i32` into a borrowedhandle value. - /// - /// > **Note**: this documentation is outdated and does not reflect the - /// > current implementation of the canonical ABI. This needs to be - /// > updated. - /// - /// This is the converse of `I32FromBorrowedHandle` and is used in similar - /// situations: - /// - /// * An exported wasm function receives, as a parameter, a handle that - /// is defined by the wasm module. - /// * An host-defined imported function is receiving a handle, as a - /// parameter, that is defined by the host itself. - HandleBorrowedFromI32 { ty: ResourceId } : [1] => [1], - // lists /// Lowers a list where the element's layout in the native language is @@ -868,8 +761,7 @@ impl Interface { | Type::U16 | Type::S32 | Type::U32 - | Type::Char - | Type::Handle(_) => result.push(WasmType::I32), + | Type::Char => result.push(WasmType::I32), Type::U64 | Type::S64 => result.push(WasmType::I64), Type::Float32 => result.push(WasmType::F32), @@ -1024,10 +916,6 @@ impl Interface { TypeDefKind::Future(_) | TypeDefKind::Stream(_) => unimplemented!(), }, - // TODO: this is probably not correct, unsure though as handles are - // in flux at the moment - Type::Handle(_) => false, - Type::Bool | Type::U8 | Type::S8 @@ -1382,40 +1270,6 @@ impl<'a, B: Bindgen> Generator<'a, B> { Type::Char => self.emit(&I32FromChar), Type::Float32 => self.emit(&F32FromFloat32), Type::Float64 => self.emit(&F64FromFloat64), - Type::Handle(ty) => { - let borrowed = match self.lift_lower { - // This means that a return value is being lowered, which is - // never borrowed. - LiftLower::LiftArgsLowerResults => false, - // There's one of three possible situations we're in: - // - // * The handle is defined by the wasm module itself. This - // is the only actual possible scenario today due to how - // witx is defined. In this situation the handle is owned - // by the host and "proof of ownership" is being offered - // and there's no need to relinquish ownership. - // - // * The handle is defined by the host, and it's passing it - // to a wasm module. This should use an owned conversion. - // This isn't expressible in today's `*.witx` format. - // - // * The handle is defined by neither the host or the wasm - // mdoule. This means that the host is passing a - // capability from another wasm module into this one, - // meaning it's doing so by reference since the host is - // retaining access to its own - // - // Note, again, only the first bullet here is possible - // today, hence the hardcoded `true` value. We'll need to - // refactor `witx` to expose the other possibilities. - LiftLower::LowerArgsLiftResults => true, - }; - if borrowed { - self.emit(&I32FromBorrowedHandle { ty }); - } else { - self.emit(&I32FromOwnedHandle { ty }); - } - } Type::String => { let realloc = self.list_realloc(); self.emit(&StringLower { realloc }); @@ -1603,19 +1457,6 @@ impl<'a, B: Bindgen> Generator<'a, B> { Type::Char => self.emit(&CharFromI32), Type::Float32 => self.emit(&Float32FromF32), Type::Float64 => self.emit(&Float64FromF64), - Type::Handle(ty) => { - // For more information on these values see the comments in - // `lower` above. - let borrowed = match self.lift_lower { - LiftLower::LiftArgsLowerResults => true, - LiftLower::LowerArgsLiftResults => false, - }; - if borrowed { - self.emit(&HandleBorrowedFromI32 { ty }); - } else { - self.emit(&HandleOwnedFromI32 { ty }); - } - } Type::String => self.emit(&StringLift), Type::Id(id) => match &self.iface.types[id].kind { TypeDefKind::Type(t) => self.lift(t), @@ -1766,7 +1607,7 @@ impl<'a, B: Bindgen> Generator<'a, B> { self.lower_and_emit(ty, addr, &I32Store8 { offset }) } Type::U16 | Type::S16 => self.lower_and_emit(ty, addr, &I32Store16 { offset }), - Type::U32 | Type::S32 | Type::Handle(_) | Type::Char => { + Type::U32 | Type::S32 | Type::Char => { self.lower_and_emit(ty, addr, &I32Store { offset }) } Type::U64 | Type::S64 => self.lower_and_emit(ty, addr, &I64Store { offset }), @@ -1965,9 +1806,7 @@ impl<'a, B: Bindgen> Generator<'a, B> { Type::S8 => self.emit_and_lift(ty, addr, &I32Load8S { offset }), Type::U16 => self.emit_and_lift(ty, addr, &I32Load16U { offset }), Type::S16 => self.emit_and_lift(ty, addr, &I32Load16S { offset }), - Type::U32 | Type::S32 | Type::Char | Type::Handle(_) => { - self.emit_and_lift(ty, addr, &I32Load { offset }) - } + Type::U32 | Type::S32 | Type::Char => self.emit_and_lift(ty, addr, &I32Load { offset }), Type::U64 | Type::S64 => self.emit_and_lift(ty, addr, &I64Load { offset }), Type::Float32 => self.emit_and_lift(ty, addr, &F32Load { offset }), Type::Float64 => self.emit_and_lift(ty, addr, &F64Load { offset }), @@ -2165,8 +2004,6 @@ impl<'a, B: Bindgen> Generator<'a, B> { } match *ty { - Type::Handle(_) => unimplemented!(), - Type::String => { self.stack.push(addr.clone()); self.emit(&Instruction::I32Load { offset }); diff --git a/crates/wit-parser/src/ast.rs b/crates/wit-parser/src/ast.rs index 269cc8d0a..f8201dfa2 100644 --- a/crates/wit-parser/src/ast.rs +++ b/crates/wit-parser/src/ast.rs @@ -16,7 +16,6 @@ pub struct Ast<'a> { pub enum Item<'a> { Use(Use<'a>), - Resource(Resource<'a>), TypeDef(TypeDef<'a>), Value(Value<'a>), Interface(Interface<'a>), @@ -55,13 +54,6 @@ struct UseName<'a> { as_: Option>, } -pub struct Resource<'a> { - docs: Docs<'a>, - name: Id<'a>, - supertype: Option>, - values: Vec<(bool, Value<'a>)>, -} - #[derive(Default)] struct Docs<'a> { docs: Vec>, @@ -223,12 +215,11 @@ impl<'a> Item<'a> { } Some((_span, Token::Record)) => TypeDef::parse_record(tokens, docs).map(Item::TypeDef), Some((_span, Token::Union)) => TypeDef::parse_union(tokens, docs).map(Item::TypeDef), - Some((_span, Token::Resource)) => Resource::parse(tokens, docs).map(Item::Resource), Some((_span, Token::Interface)) => Interface::parse(tokens, docs).map(Item::Interface), Some((_span, Token::Id)) | Some((_span, Token::ExplicitId)) => { Value::parse(tokens, docs).map(Item::Value) } - other => Err(err_expected(tokens, "`type`, `resource`, or `func`", other).into()), + other => Err(err_expected(tokens, "`type` or `func`", other).into()), } } } @@ -378,35 +369,6 @@ impl<'a> TypeDef<'a> { } } -impl<'a> Resource<'a> { - fn parse(tokens: &mut Tokenizer<'a>, docs: Docs<'a>) -> Result { - tokens.expect(Token::Resource)?; - let name = parse_id(tokens)?; - let supertype = if tokens.eat(Token::Implements)? { - Some(parse_id(tokens)?) - } else { - None - }; - let mut values = Vec::new(); - if tokens.eat(Token::LeftBrace)? { - loop { - let docs = parse_docs(tokens)?; - if tokens.eat(Token::RightBrace)? { - break; - } - let statik = tokens.eat(Token::Static)?; - values.push((statik, Value::parse(tokens, docs)?)); - } - } - Ok(Resource { - docs, - name, - supertype, - values, - }) - } -} - impl<'a> Value<'a> { fn parse(tokens: &mut Tokenizer<'a>, docs: Docs<'a>) -> Result { let name = parse_id(tokens)?; diff --git a/crates/wit-parser/src/ast/lex.rs b/crates/wit-parser/src/ast/lex.rs index 9ab7cc4eb..84ea3dfb3 100644 --- a/crates/wit-parser/src/ast/lex.rs +++ b/crates/wit-parser/src/ast/lex.rs @@ -48,7 +48,6 @@ pub enum Token { Use, Type, - Resource, Func, U8, U16, @@ -236,7 +235,6 @@ impl<'a> Tokenizer<'a> { match &self.input[start..end] { "use" => Use, "type" => Type, - "resource" => Resource, "func" => Func, "u8" => U8, "u16" => U16, @@ -498,7 +496,6 @@ impl Token { GreaterThan => "'>'", Use => "keyword `use`", Type => "keyword `type`", - Resource => "keyword `resource`", Func => "keyword `func`", U8 => "keyword `u8`", U16 => "keyword `u16`", diff --git a/crates/wit-parser/src/ast/resolve.rs b/crates/wit-parser/src/ast/resolve.rs index 6bf88b63e..dc946e7d3 100644 --- a/crates/wit-parser/src/ast/resolve.rs +++ b/crates/wit-parser/src/ast/resolve.rs @@ -8,10 +8,7 @@ use std::mem; pub struct Resolver { type_lookup: HashMap, types: Arena, - resource_lookup: HashMap, - resources_copied: HashMap<(String, ResourceId), ResourceId>, types_copied: HashMap<(String, TypeId), TypeId>, - resources: Arena, anon_types: HashMap, functions: Vec, globals: Vec, @@ -63,7 +60,6 @@ impl Resolver { for field in fields { match field { Item::Value(v) => self.resolve_value(v)?, - Item::Resource(r) => self.resolve_resource(r)?, Item::TypeDef(t) => { self.validate_type_not_recursive( t.name.span, @@ -81,8 +77,6 @@ impl Resolver { module: None, types: mem::take(&mut self.types), type_lookup: mem::take(&mut self.type_lookup), - resources: mem::take(&mut self.resources), - resource_lookup: mem::take(&mut self.resource_lookup), interface_lookup: Default::default(), interfaces: Default::default(), functions: mem::take(&mut self.functions), @@ -127,12 +121,6 @@ impl Resolver { }; let mut found = false; - if let Some(id) = dep.resource_lookup.get(&*name.name.name) { - let resource = self.copy_resource(&mod_name.name, dep, *id); - self.define_resource(my_name, span, resource)?; - found = true; - } - if let Some(id) = dep.type_lookup.get(&*name.name.name) { let ty = self.copy_type_def(&mod_name.name, dep, *id); self.define_type(my_name, span, ty)?; @@ -149,10 +137,6 @@ impl Resolver { } } None => { - for (id, resource) in dep.resources.iter() { - let id = self.copy_resource(&mod_name.name, dep, id); - self.define_resource(&resource.name, mod_name.span, id)?; - } let mut names = dep.type_lookup.iter().collect::>(); names.sort(); // produce a stable order by which to add names for (name, id) in names { @@ -165,27 +149,6 @@ impl Resolver { Ok(()) } - fn copy_resource(&mut self, dep_name: &str, dep: &Interface, r: ResourceId) -> ResourceId { - let resources = &mut self.resources; - *self - .resources_copied - .entry((dep_name.to_string(), r)) - .or_insert_with(|| { - let r = &dep.resources[r]; - let resource = Resource { - docs: r.docs.clone(), - name: r.name.clone(), - supertype: r.supertype.clone(), - foreign_module: Some( - r.foreign_module - .clone() - .unwrap_or_else(|| dep_name.to_string()), - ), - }; - resources.alloc(resource) - }) - } - fn copy_type_def(&mut self, dep_name: &str, dep: &Interface, dep_id: TypeId) -> TypeId { if let Some(id) = self.types_copied.get(&(dep_name.to_string(), dep_id)) { return *id; @@ -268,7 +231,6 @@ impl Resolver { fn copy_type(&mut self, dep_name: &str, dep: &Interface, ty: Type) -> Type { match ty { Type::Id(id) => Type::Id(self.copy_type_def(dep_name, dep, id)), - Type::Handle(id) => Type::Handle(self.copy_resource(dep_name, dep, id)), other => other, } } @@ -281,7 +243,6 @@ impl Resolver { ) -> Option { match ty { Some(Type::Id(id)) => Some(Type::Id(self.copy_type_def(dep_name, dep, id))), - Some(Type::Handle(id)) => Some(Type::Handle(self.copy_resource(dep_name, dep, id))), other => other, } } @@ -290,26 +251,6 @@ impl Resolver { let mut values = HashSet::new(); for field in fields { match field { - Item::Resource(r) => { - let docs = self.docs(&r.docs); - let id = self.resources.alloc(Resource { - docs, - name: r.name.name.to_string(), - supertype: r - .supertype - .as_ref() - .map(|supertype| supertype.name.to_string()), - foreign_module: None, - }); - self.define_resource(&r.name.name, r.name.span, id)?; - let type_id = self.types.alloc(TypeDef { - docs: Docs::default(), - kind: TypeDefKind::Type(Type::Handle(id)), - name: None, - foreign_module: None, - }); - self.define_type(&r.name.name, r.name.span, type_id)?; - } Item::TypeDef(t) => { let docs = self.docs(&t.docs); let id = self.types.alloc(TypeDef { @@ -340,18 +281,6 @@ impl Resolver { Ok(()) } - fn define_resource(&mut self, name: &str, span: Span, id: ResourceId) -> Result<()> { - if self.resource_lookup.insert(name.to_string(), id).is_some() { - Err(Error { - span, - msg: format!("resource {:?} defined twice", name), - } - .into()) - } else { - Ok(()) - } - } - fn define_type(&mut self, name: &str, span: Span, id: TypeId) -> Result<()> { if self.type_lookup.insert(name.to_string(), id).is_some() { Err(Error { @@ -380,24 +309,17 @@ impl Resolver { super::Type::Char => TypeDefKind::Type(Type::Char), super::Type::String => TypeDefKind::Type(Type::String), super::Type::Name(name) => { - // Because resources are referred to directly by name, - // first check to see if we can look up this name as a - // resource. - if let Some(id) = self.resource_lookup.get(&*name.name) { - TypeDefKind::Type(Type::Handle(*id)) - } else { - let id = match self.type_lookup.get(&*name.name) { - Some(id) => *id, - None => { - return Err(Error { - span: name.span, - msg: format!("no type named `{}`", name.name), - } - .into()) + let id = match self.type_lookup.get(&*name.name) { + Some(id) => *id, + None => { + return Err(Error { + span: name.span, + msg: format!("no type named `{}`", name.name), } - }; - TypeDefKind::Type(Type::Id(id)) - } + .into()) + } + }; + TypeDefKind::Type(Type::Id(id)) } super::Type::List(list) => { let ty = self.resolve_type(list)?; @@ -638,53 +560,6 @@ impl Resolver { } } - fn resolve_resource(&mut self, resource: &super::Resource<'_>) -> Result<()> { - let mut names = HashSet::new(); - let id = self.resource_lookup[&*resource.name.name]; - for (statik, value) in resource.values.iter() { - let (params, results) = match &value.kind { - ValueKind::Function { params, results } => (params, results), - ValueKind::Global(_) => { - return Err(Error { - span: value.name.span, - msg: "globals not allowed in resources".to_string(), - } - .into()); - } - }; - if !names.insert(&value.name.name) { - return Err(Error { - span: value.name.span, - msg: format!("{:?} defined twice in this resource", value.name.name), - } - .into()); - } - let docs = self.docs(&value.docs); - let mut params = self.resolve_params(params)?; - let results = self.resolve_results(results)?; - let kind = if *statik { - FunctionKind::Static { - resource: id, - name: value.name.name.to_string(), - } - } else { - params.insert(0, ("self".to_string(), Type::Handle(id))); - FunctionKind::Method { - resource: id, - name: value.name.name.to_string(), - } - }; - self.functions.push(Function { - docs, - name: format!("{}::{}", resource.name.name, value.name.name), - kind, - params, - results, - }); - } - Ok(()) - } - fn validate_type_not_recursive( &self, span: Span, diff --git a/crates/wit-parser/src/lib.rs b/crates/wit-parser/src/lib.rs index 75b877d16..0394a6009 100644 --- a/crates/wit-parser/src/lib.rs +++ b/crates/wit-parser/src/lib.rs @@ -29,8 +29,6 @@ pub struct Interface { pub module: Option, pub types: Arena, pub type_lookup: HashMap, - pub resources: Arena, - pub resource_lookup: HashMap, pub interfaces: Arena, pub interface_lookup: HashMap, pub functions: Vec, @@ -38,7 +36,6 @@ pub struct Interface { } pub type TypeId = Id; -pub type ResourceId = Id; pub type InterfaceId = Id; #[derive(Debug, Clone, PartialEq)] @@ -82,7 +79,6 @@ pub enum Type { Float64, Char, String, - Handle(ResourceId), Id(TypeId), } @@ -233,16 +229,6 @@ pub struct Docs { pub contents: Option, } -#[derive(Debug, Clone, PartialEq)] -pub struct Resource { - pub docs: Docs, - pub name: String, - pub supertype: Option, - /// `None` if this resource is defined within the containing instance, - /// otherwise `Some` if it's defined in an instance named here. - pub foreign_module: Option, -} - #[derive(Debug, Clone, PartialEq)] pub struct Global { pub docs: Docs, @@ -316,16 +302,12 @@ pub struct Function { #[derive(Debug, Clone, PartialEq)] pub enum FunctionKind { Freestanding, - Static { resource: ResourceId, name: String }, - Method { resource: ResourceId, name: String }, } impl Function { pub fn item_name(&self) -> &str { match &self.kind { FunctionKind::Freestanding => &self.name, - FunctionKind::Static { name, .. } => name, - FunctionKind::Method { name, .. } => name, } } } @@ -536,7 +518,7 @@ impl Interface { | Type::Float32 | Type::Float64 => true, - Type::Bool | Type::Char | Type::Handle(_) | Type::String => false, + Type::Bool | Type::Char | Type::String => false, Type::Id(id) => match &self.types[*id].kind { TypeDefKind::List(_) diff --git a/crates/wit-parser/src/sizealign.rs b/crates/wit-parser/src/sizealign.rs index aa6cc03b1..20c45fee6 100644 --- a/crates/wit-parser/src/sizealign.rs +++ b/crates/wit-parser/src/sizealign.rs @@ -41,7 +41,7 @@ impl SizeAlign { match ty { Type::Bool | Type::U8 | Type::S8 => 1, Type::U16 | Type::S16 => 2, - Type::U32 | Type::S32 | Type::Float32 | Type::Char | Type::Handle(_) => 4, + Type::U32 | Type::S32 | Type::Float32 | Type::Char => 4, Type::U64 | Type::S64 | Type::Float64 | Type::String => 8, Type::Id(id) => self.map[id.index()].0, } @@ -51,9 +51,7 @@ impl SizeAlign { match ty { Type::Bool | Type::U8 | Type::S8 => 1, Type::U16 | Type::S16 => 2, - Type::U32 | Type::S32 | Type::Float32 | Type::Char | Type::Handle(_) | Type::String => { - 4 - } + Type::U32 | Type::S32 | Type::Float32 | Type::Char | Type::String => 4, Type::U64 | Type::S64 | Type::Float64 => 8, Type::Id(id) => self.map[id.index()].1, } diff --git a/crates/wit-parser/tests/all.rs b/crates/wit-parser/tests/all.rs index c46e91d6f..f3778e665 100644 --- a/crates/wit-parser/tests/all.rs +++ b/crates/wit-parser/tests/all.rs @@ -168,8 +168,6 @@ impl Runner<'_> { fn to_json(i: &Interface) -> String { #[derive(Serialize)] struct Interface { - #[serde(skip_serializing_if = "Vec::is_empty")] - resources: Vec, #[serde(skip_serializing_if = "Vec::is_empty")] types: Vec, #[serde(skip_serializing_if = "Vec::is_empty")] @@ -246,16 +244,6 @@ fn to_json(i: &Interface) -> String { ty: String, } - let resources = i - .resources - .iter() - .map(|(_, r)| Resource { - name: r.name.clone(), - supertype: r.supertype.as_ref().map(|supertype| supertype.clone()), - foreign_module: r.foreign_module.clone(), - }) - .collect::>(); - let types = i .types .iter() @@ -289,7 +277,6 @@ fn to_json(i: &Interface) -> String { .collect::>(); let iface = Interface { - resources, types, functions, globals, @@ -355,7 +342,6 @@ fn to_json(i: &Interface) -> String { Type::Float64 => format!("float64"), Type::Char => format!("char"), Type::String => format!("string"), - Type::Handle(resource) => format!("handle-{}", resource.index()), Type::Id(id) => format!("type-{}", id.index()), } } diff --git a/crates/wit-parser/tests/ui/comments.wit b/crates/wit-parser/tests/ui/comments.wit index 621acc164..590ae0d32 100644 --- a/crates/wit-parser/tests/ui/comments.wit +++ b/crates/wit-parser/tests/ui/comments.wit @@ -5,6 +5,7 @@ /* this too */ /* is a comment */ /* this /* is /* a */ nested */ comment */ +type x = u32 type /* foo */ bar /* baz */ = // stream < // @@ -18,4 +19,3 @@ x > -resource /* x */ x // ... diff --git a/crates/wit-parser/tests/ui/comments.wit.result b/crates/wit-parser/tests/ui/comments.wit.result index 069a9e732..fd64607c3 100644 --- a/crates/wit-parser/tests/ui/comments.wit.result +++ b/crates/wit-parser/tests/ui/comments.wit.result @@ -1,21 +1,17 @@ { - "resources": [ - { - "name": "x" - } - ], "types": [ { "idx": 0, + "name": "x", + "primitive": "u32" + }, + { + "idx": 1, "name": "bar", "stream": { - "element": "handle-0", + "element": "type-0", "end": null } - }, - { - "idx": 1, - "primitive": "handle-0" } ] } \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/import-me-too.wit.md b/crates/wit-parser/tests/ui/import-me-too.wit.md index 189116a79..aebde3c02 100644 --- a/crates/wit-parser/tests/ui/import-me-too.wit.md +++ b/crates/wit-parser/tests/ui/import-me-too.wit.md @@ -9,17 +9,6 @@ code blocks. type foo = u32 ``` -## `x` -```wit -/// This is x. -resource x -``` - -## `handle` -```wit -/// This is handle. -type handle = x -``` ## `some-record` ```wit diff --git a/crates/wit-parser/tests/ui/import-me-too.wit.md.result b/crates/wit-parser/tests/ui/import-me-too.wit.md.result index 94a04f5eb..154da7deb 100644 --- a/crates/wit-parser/tests/ui/import-me-too.wit.md.result +++ b/crates/wit-parser/tests/ui/import-me-too.wit.md.result @@ -1,9 +1,4 @@ { - "resources": [ - { - "name": "x" - } - ], "types": [ { "idx": 0, @@ -12,15 +7,6 @@ }, { "idx": 1, - "primitive": "handle-0" - }, - { - "idx": 2, - "name": "handle", - "primitive": "handle-0" - }, - { - "idx": 3, "name": "some-record", "tuple": { "types": [ diff --git a/crates/wit-parser/tests/ui/import-me.wit b/crates/wit-parser/tests/ui/import-me.wit index 816a8f6e1..85c784265 100644 --- a/crates/wit-parser/tests/ui/import-me.wit +++ b/crates/wit-parser/tests/ui/import-me.wit @@ -1,7 +1,2 @@ type foo = u32 - -resource x - -type handle = x - type some-record = tuple diff --git a/crates/wit-parser/tests/ui/import-me.wit.result b/crates/wit-parser/tests/ui/import-me.wit.result index 94a04f5eb..154da7deb 100644 --- a/crates/wit-parser/tests/ui/import-me.wit.result +++ b/crates/wit-parser/tests/ui/import-me.wit.result @@ -1,9 +1,4 @@ { - "resources": [ - { - "name": "x" - } - ], "types": [ { "idx": 0, @@ -12,15 +7,6 @@ }, { "idx": 1, - "primitive": "handle-0" - }, - { - "idx": 2, - "name": "handle", - "primitive": "handle-0" - }, - { - "idx": 3, "name": "some-record", "tuple": { "types": [ diff --git a/crates/wit-parser/tests/ui/imports-from-wit-md.wit b/crates/wit-parser/tests/ui/imports-from-wit-md.wit index b7263bebe..a89aaf3bc 100644 --- a/crates/wit-parser/tests/ui/imports-from-wit-md.wit +++ b/crates/wit-parser/tests/ui/imports-from-wit-md.wit @@ -3,14 +3,8 @@ use { foo } from import-me-too use { foo as bar } from import-me-too -use { x as import-me-x } from import-me-too type x = foo type y = bar -type z = import-me-x - -use { handle } from import-me-too -resource xyz -type my-handle = xyz use { some-record } from import-me-too diff --git a/crates/wit-parser/tests/ui/imports-from-wit-md.wit.result b/crates/wit-parser/tests/ui/imports-from-wit-md.wit.result index d39682f46..6cdd63e74 100644 --- a/crates/wit-parser/tests/ui/imports-from-wit-md.wit.result +++ b/crates/wit-parser/tests/ui/imports-from-wit-md.wit.result @@ -1,13 +1,4 @@ { - "resources": [ - { - "name": "x", - "foreign_module": "import-me-too" - }, - { - "name": "xyz" - } - ], "types": [ { "idx": 0, @@ -17,17 +8,6 @@ }, { "idx": 1, - "primitive": "handle-0", - "foreign_module": "import-me-too" - }, - { - "idx": 2, - "name": "handle", - "primitive": "handle-0", - "foreign_module": "import-me-too" - }, - { - "idx": 3, "name": "some-record", "tuple": { "types": [ @@ -39,28 +19,14 @@ "foreign_module": "import-me-too" }, { - "idx": 4, + "idx": 2, "name": "x", "primitive": "type-0" }, { - "idx": 5, + "idx": 3, "name": "y", "primitive": "type-0" - }, - { - "idx": 6, - "name": "z", - "primitive": "handle-0" - }, - { - "idx": 7, - "primitive": "handle-1" - }, - { - "idx": 8, - "name": "my-handle", - "primitive": "handle-1" } ] } \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/imports.wit b/crates/wit-parser/tests/ui/imports.wit index 6d864d413..7b9ef0d6c 100644 --- a/crates/wit-parser/tests/ui/imports.wit +++ b/crates/wit-parser/tests/ui/imports.wit @@ -1,13 +1,8 @@ use { foo } from import-me use { foo as bar } from import-me -use { x as import-me-x } from import-me type x = foo type y = bar -type z1 = import-me-x -use { handle } from import-me -resource xyz -type my-handle = xyz use { some-record } from import-me diff --git a/crates/wit-parser/tests/ui/imports.wit.result b/crates/wit-parser/tests/ui/imports.wit.result index 5ff1344d9..316124898 100644 --- a/crates/wit-parser/tests/ui/imports.wit.result +++ b/crates/wit-parser/tests/ui/imports.wit.result @@ -1,13 +1,4 @@ { - "resources": [ - { - "name": "x", - "foreign_module": "import-me" - }, - { - "name": "xyz" - } - ], "types": [ { "idx": 0, @@ -17,17 +8,6 @@ }, { "idx": 1, - "primitive": "handle-0", - "foreign_module": "import-me" - }, - { - "idx": 2, - "name": "handle", - "primitive": "handle-0", - "foreign_module": "import-me" - }, - { - "idx": 3, "name": "some-record", "tuple": { "types": [ @@ -39,28 +19,14 @@ "foreign_module": "import-me" }, { - "idx": 4, + "idx": 2, "name": "x", "primitive": "type-0" }, { - "idx": 5, + "idx": 3, "name": "y", "primitive": "type-0" - }, - { - "idx": 6, - "name": "z1", - "primitive": "handle-0" - }, - { - "idx": 7, - "primitive": "handle-1" - }, - { - "idx": 8, - "name": "my-handle", - "primitive": "handle-1" } ] } \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/imports2.wit b/crates/wit-parser/tests/ui/imports2.wit index 709ed2f24..c7ba24134 100644 --- a/crates/wit-parser/tests/ui/imports2.wit +++ b/crates/wit-parser/tests/ui/imports2.wit @@ -1,3 +1,3 @@ use * from import-me -type my-handle = x +type my-handle = some-record diff --git a/crates/wit-parser/tests/ui/imports2.wit.result b/crates/wit-parser/tests/ui/imports2.wit.result index 6db867b07..5e02058fc 100644 --- a/crates/wit-parser/tests/ui/imports2.wit.result +++ b/crates/wit-parser/tests/ui/imports2.wit.result @@ -1,10 +1,4 @@ { - "resources": [ - { - "name": "x", - "foreign_module": "import-me" - } - ], "types": [ { "idx": 0, @@ -14,12 +8,6 @@ }, { "idx": 1, - "name": "handle", - "primitive": "handle-0", - "foreign_module": "import-me" - }, - { - "idx": 2, "name": "some-record", "tuple": { "types": [ @@ -31,14 +19,9 @@ "foreign_module": "import-me" }, { - "idx": 3, - "primitive": "handle-0", - "foreign_module": "import-me" - }, - { - "idx": 4, + "idx": 2, "name": "my-handle", - "primitive": "handle-0" + "primitive": "type-1" } ] } \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-resource.wit b/crates/wit-parser/tests/ui/parse-fail/bad-resource.wit deleted file mode 100644 index f2a8e1346..000000000 --- a/crates/wit-parser/tests/ui/parse-fail/bad-resource.wit +++ /dev/null @@ -1,5 +0,0 @@ -// parse-fail - -resource x { - x: s32 -} diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-resource.wit.result b/crates/wit-parser/tests/ui/parse-fail/bad-resource.wit.result deleted file mode 100644 index 2c6572b6a..000000000 --- a/crates/wit-parser/tests/ui/parse-fail/bad-resource.wit.result +++ /dev/null @@ -1,5 +0,0 @@ -globals not allowed in resources - --> tests/ui/parse-fail/bad-resource.wit:4:3 - | - 4 | x: s32 - | ^ \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-resource2.wit b/crates/wit-parser/tests/ui/parse-fail/bad-resource2.wit deleted file mode 100644 index 585045a38..000000000 --- a/crates/wit-parser/tests/ui/parse-fail/bad-resource2.wit +++ /dev/null @@ -1,6 +0,0 @@ -// parse-fail - -resource x { - x: func() - x: func() -} diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-resource2.wit.result b/crates/wit-parser/tests/ui/parse-fail/bad-resource2.wit.result deleted file mode 100644 index 661e879fe..000000000 --- a/crates/wit-parser/tests/ui/parse-fail/bad-resource2.wit.result +++ /dev/null @@ -1,5 +0,0 @@ -"x" defined twice in this resource - --> tests/ui/parse-fail/bad-resource2.wit:5:3 - | - 5 | x: func() - | ^ \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/duplicate-resource.wit b/crates/wit-parser/tests/ui/parse-fail/duplicate-resource.wit deleted file mode 100644 index 336ea11cb..000000000 --- a/crates/wit-parser/tests/ui/parse-fail/duplicate-resource.wit +++ /dev/null @@ -1,4 +0,0 @@ -// parse-fail - -resource a -resource a diff --git a/crates/wit-parser/tests/ui/parse-fail/duplicate-resource.wit.result b/crates/wit-parser/tests/ui/parse-fail/duplicate-resource.wit.result deleted file mode 100644 index 287fbade5..000000000 --- a/crates/wit-parser/tests/ui/parse-fail/duplicate-resource.wit.result +++ /dev/null @@ -1,5 +0,0 @@ -resource "a" defined twice - --> tests/ui/parse-fail/duplicate-resource.wit:4:10 - | - 4 | resource a - | ^ \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/import-bad3.wit b/crates/wit-parser/tests/ui/parse-fail/import-bad3.wit index e9ad08f68..aa749d894 100644 --- a/crates/wit-parser/tests/ui/parse-fail/import-bad3.wit +++ b/crates/wit-parser/tests/ui/parse-fail/import-bad3.wit @@ -1,3 +1,3 @@ // parse-fail -use { bar } from import-me -use { bar } from import-me +use { foo } from import-me +use { foo } from import-me diff --git a/crates/wit-parser/tests/ui/parse-fail/import-bad3.wit.result b/crates/wit-parser/tests/ui/parse-fail/import-bad3.wit.result index 1d5035c93..41d5ebdc8 100644 --- a/crates/wit-parser/tests/ui/parse-fail/import-bad3.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/import-bad3.wit.result @@ -1,5 +1,5 @@ -resource "bar" defined twice +type "foo" defined twice --> tests/ui/parse-fail/import-bad3.wit:3:7 | - 3 | use { bar } from import-me + 3 | use { foo } from import-me | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/import-bad4.wit b/crates/wit-parser/tests/ui/parse-fail/import-bad4.wit index 0a5b19e20..7685afd99 100644 --- a/crates/wit-parser/tests/ui/parse-fail/import-bad4.wit +++ b/crates/wit-parser/tests/ui/parse-fail/import-bad4.wit @@ -1,2 +1,2 @@ // parse-fail -use { bar, bar } from import-me +use { foo, foo } from import-me diff --git a/crates/wit-parser/tests/ui/parse-fail/import-bad4.wit.result b/crates/wit-parser/tests/ui/parse-fail/import-bad4.wit.result index 2c136e049..83e3150dc 100644 --- a/crates/wit-parser/tests/ui/parse-fail/import-bad4.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/import-bad4.wit.result @@ -1,5 +1,5 @@ -resource "bar" defined twice +type "foo" defined twice --> tests/ui/parse-fail/import-bad4.wit:2:12 | - 2 | use { bar, bar } from import-me + 2 | use { foo, foo } from import-me | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/import-me.wit b/crates/wit-parser/tests/ui/parse-fail/import-me.wit index fe776fa4c..e4e4f1a97 100644 --- a/crates/wit-parser/tests/ui/parse-fail/import-me.wit +++ b/crates/wit-parser/tests/ui/parse-fail/import-me.wit @@ -1,2 +1 @@ type foo = u32 -resource bar diff --git a/crates/wit-parser/tests/ui/parse-fail/import-me.wit.result b/crates/wit-parser/tests/ui/parse-fail/import-me.wit.result index 915fe49b0..ce5b16ea4 100644 --- a/crates/wit-parser/tests/ui/parse-fail/import-me.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/import-me.wit.result @@ -1,18 +1,9 @@ { - "resources": [ - { - "name": "bar" - } - ], "types": [ { "idx": 0, "name": "foo", "primitive": "u32" - }, - { - "idx": 1, - "primitive": "handle-0" } ] } \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/resource.wit b/crates/wit-parser/tests/ui/resource.wit deleted file mode 100644 index ceb5a1eb4..000000000 --- a/crates/wit-parser/tests/ui/resource.wit +++ /dev/null @@ -1,16 +0,0 @@ -resource a -resource b -resource c -resource d {} -resource e { - x: func() -} -resource f { - x: func() - y: func() -} -resource g implements a -resource h implements b {} -resource i implements e { - z: func() -} diff --git a/crates/wit-parser/tests/ui/resource.wit.result b/crates/wit-parser/tests/ui/resource.wit.result deleted file mode 100644 index 77ca4b912..000000000 --- a/crates/wit-parser/tests/ui/resource.wit.result +++ /dev/null @@ -1,102 +0,0 @@ -{ - "resources": [ - { - "name": "a" - }, - { - "name": "b" - }, - { - "name": "c" - }, - { - "name": "d" - }, - { - "name": "e" - }, - { - "name": "f" - }, - { - "name": "g", - "supertype": "a" - }, - { - "name": "h", - "supertype": "b" - }, - { - "name": "i", - "supertype": "e" - } - ], - "types": [ - { - "idx": 0, - "primitive": "handle-0" - }, - { - "idx": 1, - "primitive": "handle-1" - }, - { - "idx": 2, - "primitive": "handle-2" - }, - { - "idx": 3, - "primitive": "handle-3" - }, - { - "idx": 4, - "primitive": "handle-4" - }, - { - "idx": 5, - "primitive": "handle-5" - }, - { - "idx": 6, - "primitive": "handle-6" - }, - { - "idx": 7, - "primitive": "handle-7" - }, - { - "idx": 8, - "primitive": "handle-8" - } - ], - "functions": [ - { - "name": "e::x", - "params": [ - "handle-4" - ], - "results": [] - }, - { - "name": "f::x", - "params": [ - "handle-5" - ], - "results": [] - }, - { - "name": "f::y", - "params": [ - "handle-5" - ], - "results": [] - }, - { - "name": "i::z", - "params": [ - "handle-8" - ], - "results": [] - } - ] -} \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/types.wit b/crates/wit-parser/tests/ui/types.wit index 18ad670a6..594be5cf1 100644 --- a/crates/wit-parser/tests/ui/types.wit +++ b/crates/wit-parser/tests/ui/types.wit @@ -1,5 +1,3 @@ -resource x - type t1 = u8 type t2 = u16 type t3 = u32 @@ -18,13 +16,12 @@ type t15 = result type t16 = result<_, u32> type t17 = result type t18 = result -type t19 = x record t20 {} record t21 { a: u32 } record t22 { a: u32, } record t23 { a: u32, b: u64 } record t24 { a: u32, b: u64, } -record t25 { %x: u32 } +record t25 { x: u32 } record %record {} type t26 = tuple<> type t27 = tuple diff --git a/crates/wit-parser/tests/ui/types.wit.result b/crates/wit-parser/tests/ui/types.wit.result index e9ae53339..a66b37ee4 100644 --- a/crates/wit-parser/tests/ui/types.wit.result +++ b/crates/wit-parser/tests/ui/types.wit.result @@ -1,86 +1,77 @@ { - "resources": [ - { - "name": "x" - } - ], "types": [ { "idx": 0, - "primitive": "handle-0" - }, - { - "idx": 1, "name": "t1", "primitive": "u8" }, { - "idx": 2, + "idx": 1, "name": "t2", "primitive": "u16" }, { - "idx": 3, + "idx": 2, "name": "t3", "primitive": "u32" }, { - "idx": 4, + "idx": 3, "name": "t4", "primitive": "u64" }, { - "idx": 5, + "idx": 4, "name": "t5", "primitive": "s8" }, { - "idx": 6, + "idx": 5, "name": "t6", "primitive": "s16" }, { - "idx": 7, + "idx": 6, "name": "t7", "primitive": "s32" }, { - "idx": 8, + "idx": 7, "name": "t8", "primitive": "s64" }, { - "idx": 9, + "idx": 8, "name": "t9", "primitive": "float32" }, { - "idx": 10, + "idx": 9, "name": "t10", "primitive": "float64" }, { - "idx": 11, + "idx": 10, "name": "t11", "primitive": "char" }, { - "idx": 12, + "idx": 11, "name": "t12", "list": "char" }, { - "idx": 13, + "idx": 12, "name": "t13", "primitive": "string" }, { - "idx": 14, + "idx": 13, "name": "t14", "option": "u32" }, { - "idx": 15, + "idx": 14, "name": "t15", "result": { "ok": "u32", @@ -88,7 +79,7 @@ } }, { - "idx": 16, + "idx": 15, "name": "t16", "result": { "ok": null, @@ -96,7 +87,7 @@ } }, { - "idx": 17, + "idx": 16, "name": "t17", "result": { "ok": "u32", @@ -104,7 +95,7 @@ } }, { - "idx": 18, + "idx": 17, "name": "t18", "result": { "ok": null, @@ -112,19 +103,14 @@ } }, { - "idx": 19, - "name": "t19", - "primitive": "handle-0" - }, - { - "idx": 20, + "idx": 18, "name": "t20", "record": { "fields": [] } }, { - "idx": 21, + "idx": 19, "name": "t21", "record": { "fields": [ @@ -136,7 +122,7 @@ } }, { - "idx": 22, + "idx": 20, "name": "t22", "record": { "fields": [ @@ -148,7 +134,7 @@ } }, { - "idx": 23, + "idx": 21, "name": "t23", "record": { "fields": [ @@ -164,7 +150,7 @@ } }, { - "idx": 24, + "idx": 22, "name": "t24", "record": { "fields": [ @@ -180,7 +166,7 @@ } }, { - "idx": 25, + "idx": 23, "name": "t25", "record": { "fields": [ @@ -192,21 +178,21 @@ } }, { - "idx": 26, + "idx": 24, "name": "record", "record": { "fields": [] } }, { - "idx": 27, + "idx": 25, "name": "t26", "tuple": { "types": [] } }, { - "idx": 28, + "idx": 26, "name": "t27", "tuple": { "types": [ @@ -215,7 +201,7 @@ } }, { - "idx": 29, + "idx": 27, "name": "t28", "tuple": { "types": [ @@ -224,7 +210,7 @@ } }, { - "idx": 30, + "idx": 28, "name": "t29", "tuple": { "types": [ @@ -234,14 +220,14 @@ } }, { - "idx": 31, + "idx": 29, "name": "t30", "flags": { "flags": [] } }, { - "idx": 32, + "idx": 30, "name": "t31", "flags": { "flags": [ @@ -252,7 +238,7 @@ } }, { - "idx": 33, + "idx": 31, "name": "t32", "flags": { "flags": [ @@ -263,7 +249,7 @@ } }, { - "idx": 34, + "idx": 32, "name": "t33", "variant": { "cases": [ @@ -275,7 +261,7 @@ } }, { - "idx": 35, + "idx": 33, "name": "t34", "variant": { "cases": [ @@ -291,7 +277,7 @@ } }, { - "idx": 36, + "idx": 34, "name": "t35", "variant": { "cases": [ @@ -307,7 +293,7 @@ } }, { - "idx": 37, + "idx": 35, "name": "t36", "variant": { "cases": [ @@ -323,7 +309,7 @@ } }, { - "idx": 38, + "idx": 36, "name": "t37", "variant": { "cases": [ @@ -333,13 +319,13 @@ ], [ "b", - "type-57" + "type-55" ] ] } }, { - "idx": 39, + "idx": 37, "name": "t38", "union": { "cases": [ @@ -349,27 +335,27 @@ } }, { - "idx": 40, + "idx": 38, "name": "t39", "union": { "cases": [ "u32", - "type-57" + "type-55" ] } }, { - "idx": 41, + "idx": 39, "name": "t40", "union": { "cases": [ "u32", - "type-57" + "type-55" ] } }, { - "idx": 42, + "idx": 40, "name": "t41", "enum": { "cases": [ @@ -380,7 +366,7 @@ } }, { - "idx": 43, + "idx": 41, "name": "t42", "enum": { "cases": [ @@ -391,32 +377,32 @@ } }, { - "idx": 44, + "idx": 42, "name": "t43", "primitive": "bool" }, { - "idx": 45, + "idx": 43, "name": "t44", "primitive": "string" }, { - "idx": 46, + "idx": 44, "name": "t45", - "list": "type-59" + "list": "type-57" }, { - "idx": 47, + "idx": 45, "name": "t46", - "primitive": "type-45" + "primitive": "type-43" }, { - "idx": 48, + "idx": 46, "name": "t47", - "primitive": "type-45" + "primitive": "type-43" }, { - "idx": 49, + "idx": 47, "name": "t48", "stream": { "element": "u32", @@ -424,7 +410,7 @@ } }, { - "idx": 50, + "idx": 48, "name": "t49", "stream": { "element": null, @@ -432,7 +418,7 @@ } }, { - "idx": 51, + "idx": 49, "name": "t50", "stream": { "element": "u32", @@ -440,7 +426,7 @@ } }, { - "idx": 52, + "idx": 50, "name": "t51", "stream": { "element": null, @@ -448,36 +434,36 @@ } }, { - "idx": 53, + "idx": 51, "name": "t52", "future": "u32" }, { - "idx": 54, + "idx": 52, "name": "t53", "future": null }, { - "idx": 55, + "idx": 53, "name": "foo", - "primitive": "type-56" + "primitive": "type-54" }, { - "idx": 56, + "idx": 54, "name": "bar", "primitive": "u32" }, { - "idx": 57, + "idx": 55, "option": "u32" }, { - "idx": 58, - "list": "type-33" + "idx": 56, + "list": "type-31" }, { - "idx": 59, - "list": "type-58" + "idx": 57, + "list": "type-56" } ] } \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/wasi-http.wit b/crates/wit-parser/tests/ui/wasi-http.wit deleted file mode 100644 index a0c50d789..000000000 --- a/crates/wit-parser/tests/ui/wasi-http.wit +++ /dev/null @@ -1,158 +0,0 @@ -// Note: this note isn't a doc comment. - -// Note: the following comment block is a doc comment, because it start with `///`. -// It's also a comment about the interface defined in this file, because it starts with `@interface` - -/// @interface WASI HTTP Core functionality. -/// -/// Defines requests & responses and associated types, and `fetch`. - -// `use` imports things from namespaces. The first identifier of an `ident1::ident2::[..]::identN` -// namespace chain needs to be resolved out of band. The remaining part of the chain is resolved -// as nested interfaces inside the definition of `ident1`. -// Note: I'm not sure if Result should just be an Interface Types thing instead of a WASI thing. -//use { Result, Option } from wasi::core - -/// A blocking function for turning requests into responses. -/// @param req - a `request` object to process -/// @return resp - the `Result` object produced once the blocking operation has finished. -// -// Note: the syntax for function definitions is chosen with three goals in mind: -// -// 1. maximizing human parseability and intuitive understanding, by not presupposing -// familiarity with any specific notations. Having the `function` keyword isn't otherwise -// strictly required for disambiguation. This becomes even more important given that part of -// the "weirdness budget" needs to be used for having support for multiple return values. -// -// 2. uniformity in the face of multiple return values. Basically, it's always a mapping -// of N arguments to M return values, with the same syntax for both. -// -// 3. provide an obvious place for adding attributes, like `blocking` and `reentrant`. -// -// Note: the `blocking` attribute means that different lowering can be generated for this -// function, either based on synchronous, blocking calls, or on a callback-style interface. -fetch: /*blocking*/ func(req: request) -> response - -/// A request resource, with lots of things missing for now. -// Note: `resource` blocks serve two purposes: -// 1. namespacing the definition of a Handle type with functions for operating on that handle -// 2. providing a way to define said functions such that they implicitly take the handle itself as -// the first argument. E.g., `method` in `request` is roughly equivalent to -// `request::method: func(self: request) -> (string)` -// ("Roughly" because the `resource` semantics allow us to generate better bindings for languages -// that have a concept of implicit receivers, such as `this` in JS.) -resource request { - - /// A static function acting as a constructor - /// @return req - returns a new `request` - // Note: `static` here simply means that no implicit receiver argument will be passed. - // I.e., this is ~roughly~ analogous to a top-level definition of - // `request::request: func() -> (req: request)` - // whereas without `static`, it'd be analogous to - // `request::request: func(self: request) -> (req: request)` - static request: func() -> request - - method: func() -> string - - // Note: We could consider allowing the parens to be omitted for single return values, like so: - headers: func() -> headers - - // Note: Or we could even allow leaving off the return value identifier, making it use the - // function name, like so: - body: func() -> body // This return type would be shorthand for `(body: body)` -} - -/// A response resource, with lots of things missing for now. -resource response { - status: func() -> u16 - headers: func() -> headers - body: func() -> body -} - -/// A headers resource, with lots of things missing for now. -resource headers { - /// Return values for the given header name. - /// @param name - the header's name. - /// @return values - the values for this header, seperated by ", " - // Note: in reality, it might make sense for the values to be a sequence of some kind. - get: func(name: string) -> option -} - -/// A body resource. -/// Bodies are interesting in that they can be both sources and sinks, on both requests and responses. -resource body { - /// Read from a body. - /// @param dest - destination buffer to write into - /// @return result - a result containing the number of bytes written on success - // TODO: check if `out-buffer` is the right way to express this - read: func(dest: list) -> result - - /// Write to a body. - /// @param source - source buffer to read from - /// @return result - a result containing the number of bytes read on success - // TODO: check if `in-buffer` is the right way to express this - write: func(source: list) -> result -} -/* - -/// A nested interface, doing something neat and elaborate. -interface nested-interface1 { - /// An even better request resource than the one everybody's using. - resource better-request { - // TODO: do we need to have a ctor with special semantics? E.g. to generate actual - // constructors for languages that have them, such as JS? - new: func(request: request) -> better-request - // Note: sadly, the sauce better-request uses must remain secret, so it doesn't actually - // expose any of its functionality, and hence doesn't need any other methods. - } - /// Maps a request to an even better request. - // Note: the containing scope's members are in scope in a nested interface - fun: func(request: request) -> response -} - -/// Another nested interface, doing something even more neat and elaborate. -/// It does this by adding shiny stuff to what nested-interface1 is doing. -interface nested-interface2 { - // Note: as mentioned in the comment on this file's first `use` statement, the first - // ident in a namespace chain needs to be resolved out of band. `self` is an exception to - // this rule, and allows referring to the outermost containing scope. - use self::nested-interface1::better-request - - /// The secret sauce. It's so secret and magic that you're not allowed to touch it, quite sadly. - resource the-shiny { - } - - /// Maps a better request to a plain old response. - /// @param request - the already pretty good request to add the shiny to - /// @return response - a boring, normal response - /// @return added-shiny - the shiny! - // Note: this just exists to demonstrate multiple return values, including their documentation - fun: func(request: better-request) -> tuple -} -*/ - -/// An enum with some values -// Note: should we have a way to declare the underlying representation, along the lines of -// `enum error: u8 {..}`? -// Note: what about non-numeric types? -// Note: what about heterogeneous enums? -enum error { - overflow, - unavailable, -} - -/// A function returning a Result, with the enum above as one of the options -/// @return result - a `Result` containing either the desired number, or an `error` -maybe-number: func() -> result - -/// A simple struct -record timestamp { - seconds: u64, - nanoseconds: u64, -} - -/// A simple value -my-int: u32 - -/// A handle to a request -my-request: request diff --git a/crates/wit-parser/tests/ui/wasi-http.wit.result b/crates/wit-parser/tests/ui/wasi-http.wit.result deleted file mode 100644 index 52cf7a8cc..000000000 --- a/crates/wit-parser/tests/ui/wasi-http.wit.result +++ /dev/null @@ -1,194 +0,0 @@ -{ - "resources": [ - { - "name": "request" - }, - { - "name": "response" - }, - { - "name": "headers" - }, - { - "name": "body" - } - ], - "types": [ - { - "idx": 0, - "primitive": "handle-0" - }, - { - "idx": 1, - "primitive": "handle-1" - }, - { - "idx": 2, - "primitive": "handle-2" - }, - { - "idx": 3, - "primitive": "handle-3" - }, - { - "idx": 4, - "name": "error", - "enum": { - "cases": [ - "overflow", - "unavailable" - ] - } - }, - { - "idx": 5, - "name": "timestamp", - "record": { - "fields": [ - [ - "seconds", - "u64" - ], - [ - "nanoseconds", - "u64" - ] - ] - } - }, - { - "idx": 6, - "option": "string" - }, - { - "idx": 7, - "list": "u8" - }, - { - "idx": 8, - "result": { - "ok": "u64", - "err": "type-4" - } - } - ], - "functions": [ - { - "name": "fetch", - "params": [ - "handle-0" - ], - "results": [ - "handle-1" - ] - }, - { - "name": "request::request", - "params": [], - "results": [ - "handle-0" - ] - }, - { - "name": "request::method", - "params": [ - "handle-0" - ], - "results": [ - "string" - ] - }, - { - "name": "request::headers", - "params": [ - "handle-0" - ], - "results": [ - "handle-2" - ] - }, - { - "name": "request::body", - "params": [ - "handle-0" - ], - "results": [ - "handle-3" - ] - }, - { - "name": "response::status", - "params": [ - "handle-1" - ], - "results": [ - "u16" - ] - }, - { - "name": "response::headers", - "params": [ - "handle-1" - ], - "results": [ - "handle-2" - ] - }, - { - "name": "response::body", - "params": [ - "handle-1" - ], - "results": [ - "handle-3" - ] - }, - { - "name": "headers::get", - "params": [ - "handle-2", - "string" - ], - "results": [ - "type-6" - ] - }, - { - "name": "body::read", - "params": [ - "handle-3", - "type-7" - ], - "results": [ - "type-8" - ] - }, - { - "name": "body::write", - "params": [ - "handle-3", - "type-7" - ], - "results": [ - "type-8" - ] - }, - { - "name": "maybe-number", - "params": [], - "results": [ - "type-8" - ] - } - ], - "globals": [ - { - "name": "my-int", - "ty": "u32" - }, - { - "name": "my-request", - "ty": "handle-0" - } - ] -} \ No newline at end of file diff --git a/tests/codegen/resource.wit b/tests/codegen/resource.wit deleted file mode 100644 index 3c87154f5..000000000 --- a/tests/codegen/resource.wit +++ /dev/null @@ -1,11 +0,0 @@ -resource x - -acquire-an-x: func() -> x -receive-an-x: func(val: x) - -resource y { - static some-constructor: func() -> y - method-on-y: func() - method-with-param: func(x: u32) - method-with-result: func() -> string -} diff --git a/tests/runtime/handles/exports.wit b/tests/runtime/handles/exports.wit deleted file mode 100644 index cc6aab0f7..000000000 --- a/tests/runtime/handles/exports.wit +++ /dev/null @@ -1,53 +0,0 @@ -test-imports: func() - -resource wasm-state -resource wasm-state2 - -wasm-state-create: func() -> wasm-state -wasm-state-get-val: func(a: wasm-state) -> u32 - -wasm-state2-create: func() -> wasm-state2 -wasm-state2-saw-close: func() -> bool -two-wasm-states: func(a: wasm-state, b: wasm-state2) -> (a: wasm-state, b: wasm-state2) - -record wasm-state-param-record { a: wasm-state2 } -wasm-state2-param-record: func(a: wasm-state-param-record) - -type wasm-state-param-tuple = tuple -wasm-state2-param-tuple: func(a: wasm-state-param-tuple) - -type wasm-state-param-option = option -wasm-state2-param-option: func(a: wasm-state-param-option) - -type wasm-state-param-result = result -wasm-state2-param-result: func(a: wasm-state-param-result) - -union wasm-state-param-variant { wasm-state2, u32 } -wasm-state2-param-variant: func(a: wasm-state-param-variant) - -wasm-state2-param-list: func(a: list) - - -record wasm-state-result-record { a: wasm-state2 } -wasm-state2-result-record: func() -> wasm-state-result-record - -type wasm-state-result-tuple = tuple -wasm-state2-result-tuple: func() -> wasm-state-result-tuple - -type wasm-state-result-option = option -wasm-state2-result-option: func() -> wasm-state-result-option - -type wasm-state-result-result = result -wasm-state2-result-result: func() -> wasm-state-result-result - -union wasm-state-result-variant { wasm-state2, u32 } -wasm-state2-result-variant: func() -> wasm-state-result-variant - -wasm-state2-result-list: func() -> list - -resource markdown { - static create: func() -> option - append: func(buf: string) - render: func() -> string -} - diff --git a/tests/runtime/handles/host.py b/tests/runtime/handles/host.py deleted file mode 100644 index e2ff01965..000000000 --- a/tests/runtime/handles/host.py +++ /dev/null @@ -1,189 +0,0 @@ -from dataclasses import dataclass -from exports.bindings import Exports -from imports.bindings import add_imports_to_linker, Imports -from typing import Tuple, List -import exports.bindings as e -import imports.bindings as i -import sys -import wasmtime - -@dataclass -class HostState(i.HostState): - val: int - - def __init__(self, val: int) -> None: - self.val = val - - def drop(self) -> None: - pass - - -HOST_STATE2_CLOSED = False - - -@dataclass -class HostState2(i.HostState2): - val: int - - def __init__(self, val: int) -> None: - self.val = val - - def drop(self) -> None: - global HOST_STATE2_CLOSED - HOST_STATE2_CLOSED = True - - -@dataclass -class Markdown(i.Markdown2): - buf: str = '' - - def append(self, data: str) -> None: - self.buf += data - - def render(self) -> str: - return self.buf.replace('red', 'green') - - def drop(self) -> None: - pass - - -class OddName(i.OddName): - def frob_the_odd(self) -> None: - pass - - def drop(self) -> None: - pass - - -class MyImports: - def host_state_create(self) -> i.HostState: - return HostState(100) - - def host_state_get(self, a: i.HostState) -> int: - assert(isinstance(a, HostState)) - return a.val - - def host_state2_create(self) -> i.HostState2: - return HostState2(101) - - def host_state2_saw_close(self) -> bool: - return HOST_STATE2_CLOSED - - def two_host_states(self, a: i.HostState, b: i.HostState2) -> Tuple[i.HostState, i.HostState2]: - return (b, a) - - def host_state2_param_record(self, a: i.HostStateParamRecord) -> None: - pass - - def host_state2_param_tuple(self, a: i.HostStateParamTuple) -> None: - pass - - def host_state2_param_option(self, a: i.HostStateParamOption) -> None: - pass - - def host_state2_param_result(self, a: i.HostStateParamResult) -> None: - pass - - def host_state2_param_variant(self, a: i.HostStateParamVariant) -> None: - pass - - def host_state2_param_list(self, a: List[i.HostState2]) -> None: - pass - - def host_state2_result_record(self) -> i.HostStateResultRecord: - return i.HostStateResultRecord(HostState(2)) - - def host_state2_result_tuple(self) -> i.HostStateResultTuple: - return (HostState(2),) - - def host_state2_result_option(self) -> i.HostStateResultOption: - return HostState(2) - - def host_state2_result_result(self) -> i.HostStateResultResult: - return i.Ok(HostState2(2)) - - def host_state2_result_variant(self) -> i.HostStateResultVariant: - return HostState2(2) - - def host_state2_result_list(self) -> List[i.HostState2]: - return [HostState2(2), HostState2(5)] - - def markdown2_create(self) -> i.Markdown2: - return Markdown() - - def odd_name_create(self) -> i.OddName: - return OddName() - -def run(wasm_file: str) -> None: - store = wasmtime.Store() - module = wasmtime.Module.from_file(store.engine, wasm_file) - linker = wasmtime.Linker(store.engine) - linker.define_wasi() - wasi = wasmtime.WasiConfig() - wasi.inherit_stdout() - wasi.inherit_stderr() - store.set_wasi(wasi) - - imports = MyImports() - add_imports_to_linker(linker, store, imports) - wasm = Exports(store, linker, module) - - wasm.test_imports(store) - - # Param/result of a handle works in a simple fashion - s: e.WasmState = wasm.wasm_state_create(store) - assert(wasm.wasm_state_get_val(store, s) == 100) - - # Deterministic destruction is possible - assert(wasm.wasm_state2_saw_close(store) == False) - s2: e.WasmState2 = wasm.wasm_state2_create(store) - assert(wasm.wasm_state2_saw_close(store) == False) - s2.drop(store) - assert(wasm.wasm_state2_saw_close(store) == True) - - arg1 = wasm.wasm_state_create(store) - arg2 = wasm.wasm_state2_create(store) - c, d = wasm.two_wasm_states(store, arg1, arg2) - arg1.drop(store) - arg2.drop(store) - - wasm.wasm_state2_param_record(store, e.WasmStateParamRecord(d)) - wasm.wasm_state2_param_tuple(store, (d,)) - wasm.wasm_state2_param_option(store, d) - wasm.wasm_state2_param_option(store, None) - wasm.wasm_state2_param_result(store, e.Ok(d)) - wasm.wasm_state2_param_result(store, e.Err(2)) - wasm.wasm_state2_param_variant(store, d) - wasm.wasm_state2_param_variant(store, 2) - wasm.wasm_state2_param_list(store, []) - wasm.wasm_state2_param_list(store, [d]) - wasm.wasm_state2_param_list(store, [d, d]) - - c.drop(store) - d.drop(store) - - wasm.wasm_state2_result_record(store).a.drop(store) - wasm.wasm_state2_result_tuple(store)[0].drop(store) - opt = wasm.wasm_state2_result_option(store) - assert(opt is not None) - opt.drop(store) - result = wasm.wasm_state2_result_result(store) - assert(isinstance(result, e.Ok)) - result.value.drop(store) - variant = wasm.wasm_state2_result_variant(store) - print(variant) - assert(isinstance(variant, e.WasmState2)) - variant.drop(store) - for val in wasm.wasm_state2_result_list(store): - val.drop(store) - - s.drop(store) - - md = e.Markdown.create(store, wasm) - if md: - md.append(store, "red is the best color") - assert(md.render(store) == "green is the best color") - md.drop(store) - -if __name__ == '__main__': - run(sys.argv[1]) diff --git a/tests/runtime/handles/host.rs b/tests/runtime/handles/host.rs deleted file mode 100644 index 84f555a90..000000000 --- a/tests/runtime/handles/host.rs +++ /dev/null @@ -1,156 +0,0 @@ -wit_bindgen_host_wasmtime_rust::export!("../../tests/runtime/handles/imports.wit"); - -use anyhow::Result; -use imports::*; -use std::cell::RefCell; - -#[derive(Default)] -pub struct MyImports { - host_state2_closed: bool, -} - -#[derive(Debug)] -pub struct SuchState(u32); - -#[derive(Default, Debug)] -pub struct Markdown { - buf: RefCell, -} - -impl Imports for MyImports { - type HostState = SuchState; - type HostState2 = (); - type Markdown2 = Markdown; - type OddName = (); - - fn host_state_create(&mut self) -> SuchState { - SuchState(100) - } - - fn host_state_get(&mut self, state: &SuchState) -> u32 { - state.0 - } - - fn host_state2_create(&mut self) {} - - fn host_state2_saw_close(&mut self) -> bool { - self.host_state2_closed - } - - fn drop_host_state2(&mut self, _state: ()) { - self.host_state2_closed = true; - } - - fn two_host_states(&mut self, _a: &SuchState, _b: &()) -> (SuchState, ()) { - (SuchState(2), ()) - } - - fn host_state2_param_record(&mut self, _a: HostStateParamRecord<'_, Self>) {} - fn host_state2_param_tuple(&mut self, _a: (&'_ (),)) {} - fn host_state2_param_option(&mut self, _a: Option<&'_ ()>) {} - fn host_state2_param_result(&mut self, _a: Result<&'_ (), u32>) {} - fn host_state2_param_variant(&mut self, _a: HostStateParamVariant<'_, Self>) {} - fn host_state2_param_list(&mut self, _a: Vec<&()>) {} - - fn host_state2_result_record(&mut self) -> HostStateResultRecord { - HostStateResultRecord { a: () } - } - fn host_state2_result_tuple(&mut self) -> ((),) { - ((),) - } - fn host_state2_result_option(&mut self) -> Option<()> { - Some(()) - } - fn host_state2_result_result(&mut self) -> Result<(), u32> { - Ok(()) - } - fn host_state2_result_variant(&mut self) -> HostStateResultVariant { - HostStateResultVariant::HostState2(()) - } - fn host_state2_result_list(&mut self) -> Vec<()> { - vec![(), ()] - } - - fn markdown2_create(&mut self) -> Markdown { - Markdown::default() - } - - fn markdown2_append(&mut self, md: &Markdown, buf: &str) { - md.buf.borrow_mut().push_str(buf); - } - - fn markdown2_render(&mut self, md: &Markdown) -> String { - md.buf.borrow().replace("red", "green") - } - - fn odd_name_create(&mut self) {} - fn odd_name_frob_the_odd(&mut self, _: &()) {} -} - -wit_bindgen_host_wasmtime_rust::import!("../../tests/runtime/handles/exports.wit"); - -fn run(wasm: &str) -> Result<()> { - use exports::*; - - let (exports, mut store) = crate::instantiate( - wasm, - |linker| { - imports::add_to_linker( - linker, - |cx: &mut crate::Context<(MyImports, imports::ImportsTables), _>| { - (&mut cx.imports.0, &mut cx.imports.1) - }, - ) - }, - |store, module, linker| Exports::instantiate(store, module, linker, |cx| &mut cx.exports), - )?; - - exports.test_imports(&mut store)?; - - let s: WasmState = exports.wasm_state_create(&mut store)?; - assert_eq!(exports.wasm_state_get_val(&mut store, &s)?, 100); - exports.drop_wasm_state(&mut store, s)?; - - assert_eq!(exports.wasm_state2_saw_close(&mut store)?, false); - let s: WasmState2 = exports.wasm_state2_create(&mut store)?; - assert_eq!(exports.wasm_state2_saw_close(&mut store)?, false); - exports.drop_wasm_state2(&mut store, s)?; - assert_eq!(exports.wasm_state2_saw_close(&mut store)?, true); - - let a = exports.wasm_state_create(&mut store)?; - let b = exports.wasm_state2_create(&mut store)?; - let (s1, s2) = exports.two_wasm_states(&mut store, &a, &b)?; - exports.drop_wasm_state(&mut store, a)?; - exports.drop_wasm_state(&mut store, s1)?; - exports.drop_wasm_state2(&mut store, b)?; - - exports.wasm_state2_param_record(&mut store, WasmStateParamRecord { a: &s2 })?; - exports.wasm_state2_param_tuple(&mut store, (&s2,))?; - exports.wasm_state2_param_option(&mut store, Some(&s2))?; - exports.wasm_state2_param_option(&mut store, None)?; - exports.wasm_state2_param_result(&mut store, Ok(&s2))?; - exports.wasm_state2_param_result(&mut store, Err(2))?; - exports.wasm_state2_param_variant(&mut store, WasmStateParamVariant::WasmState2(&s2))?; - exports.wasm_state2_param_variant(&mut store, WasmStateParamVariant::U32(2))?; - exports.wasm_state2_param_list(&mut store, &[])?; - exports.wasm_state2_param_list(&mut store, &[&s2])?; - exports.wasm_state2_param_list(&mut store, &[&s2, &s2])?; - exports.drop_wasm_state2(&mut store, s2)?; - - let s = exports.wasm_state2_result_record(&mut store)?.a; - exports.drop_wasm_state2(&mut store, s)?; - let s = exports.wasm_state2_result_tuple(&mut store)?.0; - exports.drop_wasm_state2(&mut store, s)?; - let s = exports.wasm_state2_result_option(&mut store)?.unwrap(); - exports.drop_wasm_state2(&mut store, s)?; - let s = exports.wasm_state2_result_result(&mut store)?.unwrap(); - match exports.wasm_state2_result_variant(&mut store)? { - WasmStateResultVariant::WasmState2(s) => exports.drop_wasm_state2(&mut store, s)?, - WasmStateResultVariant::U32(_) => panic!(), - } - exports.drop_wasm_state2(&mut store, s)?; - for s in exports.wasm_state2_result_list(&mut store)? { - exports.drop_wasm_state2(&mut store, s)?; - } - Ok(()) -} diff --git a/tests/runtime/handles/host.ts b/tests/runtime/handles/host.ts deleted file mode 100644 index e611fc997..000000000 --- a/tests/runtime/handles/host.ts +++ /dev/null @@ -1,127 +0,0 @@ -import { addImportsToImports, Imports } from "./imports.js"; -import { Exports } from "./exports.js"; -import * as exports from "./exports.js"; -import { getWasm, addWasiToImports } from "./helpers.js"; -// @ts-ignore -import * as assert from 'assert'; - -async function run() { - const importObj = {}; - let sawClose = false; - const imports: Imports = { - hostStateCreate() { return 100; }, - hostStateGet(x) { return x as number; }, - hostState2Create() { return 101; }, - hostState2SawClose() { return sawClose; }, - dropHostState2(state) { sawClose = true; }, - twoHostStates(a, b) { return [b, a]; }, - hostState2ParamRecord(x) {}, - hostState2ParamTuple(x) {}, - hostState2ParamOption(x) {}, - hostState2ParamResult(x) {}, - hostState2ParamVariant(x) {}, - hostState2ParamList(x) {}, - - hostState2ResultRecord() { return { a: {} }; }, - hostState2ResultTuple() { return [{}]; }, - hostState2ResultOption() { return 102; }, - hostState2ResultResult() { return { tag: 'ok', val: {} }; }, - hostState2ResultVariant() { return { tag: 0, val: {} }; }, - hostState2ResultList() { return [{}, 3]; }, - - markdown2Create() { - class Markdown { - buf: string; - - constructor() { - this.buf = ''; - } - append(extra: string) { - this.buf += extra; - } - render() { - return this.buf.replace('red', 'green'); - } - } - - return new Markdown(); - }, - - oddNameCreate() { - class OddName { - frobTheOdd() {} - } - return new OddName(); - } - }; - let instance: WebAssembly.Instance; - addImportsToImports(importObj, imports, name => instance.exports[name]); - const wasi = addWasiToImports(importObj); - - const wasm = new Exports(); - await wasm.instantiate(getWasm(), importObj); - wasi.start(wasm.instance); - instance = wasm.instance; - - wasm.testImports(); - - // Param/result of a handle works in a simple fashion - const s: exports.WasmState = wasm.wasmStateCreate(); - assert.strictEqual(wasm.wasmStateGetVal(s), 100); - - // Deterministic destruction is possible - assert.strictEqual(wasm.wasmState2SawClose(), false); - const s2: exports.WasmState2 = wasm.wasmState2Create(); - assert.strictEqual(wasm.wasmState2SawClose(), false); - s2.drop(); - assert.strictEqual(wasm.wasmState2SawClose(), true); - - const arg1 = wasm.wasmStateCreate(); - const arg2 = wasm.wasmState2Create(); - const [c, d] = wasm.twoWasmStates(arg1, arg2); - arg1.drop(); - arg2.drop(); - - wasm.wasmState2ParamRecord({ a: d }); - wasm.wasmState2ParamTuple([d]); - wasm.wasmState2ParamOption(d); - wasm.wasmState2ParamOption(null); - wasm.wasmState2ParamResult({ tag: 'ok', val: d }); - wasm.wasmState2ParamResult({ tag: 'err', val: 2 }); - wasm.wasmState2ParamVariant({ tag: 0, val: d }); - wasm.wasmState2ParamVariant({ tag: 1, val: 2 }); - wasm.wasmState2ParamList([]); - wasm.wasmState2ParamList([d]); - wasm.wasmState2ParamList([d, d]); - - c.drop(); - d.drop(); - - wasm.wasmState2ResultRecord().a?.drop(); - wasm.wasmState2ResultTuple()[0].drop(); - const opt = wasm.wasmState2ResultOption(); - if (opt === null) - throw new Error('should be some'); - opt.drop(); - const result = wasm.wasmState2ResultResult(); - if (result.tag === 'err') - throw new Error('should be ok'); - result.val.drop(); - const variant = wasm.wasmState2ResultVariant(); - if (variant.tag === 1) - throw new Error('should be 0'); - variant.val.drop(); - for (let val of wasm.wasmState2ResultList()) - val.drop(); - - s.drop(); - - const md = exports.Markdown.create(wasm); - if (md) { - md.append("red is the best color"); - assert.strictEqual(md.render(), "green is the best color"); - md.drop(); - } -} - -await run() diff --git a/tests/runtime/handles/imports.wit b/tests/runtime/handles/imports.wit deleted file mode 100644 index f83f46372..000000000 --- a/tests/runtime/handles/imports.wit +++ /dev/null @@ -1,55 +0,0 @@ -resource host-state -resource host-state2 - -host-state-create: func() -> host-state -host-state-get: func(a: host-state) -> u32 - -host-state2-create: func() -> host-state2 -host-state2-saw-close: func() -> bool -two-host-states: func(a: host-state, b: host-state2) -> (a: host-state, b: host-state2) - -record host-state-param-record { a: host-state2 } -host-state2-param-record: func(a: host-state-param-record) - -type host-state-param-tuple = tuple -host-state2-param-tuple: func(a: host-state-param-tuple) - -type host-state-param-option = option -host-state2-param-option: func(a: host-state-param-option) - -type host-state-param-result = result -host-state2-param-result: func(a: host-state-param-result) - -union host-state-param-variant { host-state2, u32 } -host-state2-param-variant: func(a: host-state-param-variant) - -host-state2-param-list: func(a: list) - - -record host-state-result-record { a: host-state2 } -host-state2-result-record: func() -> host-state-result-record - -type host-state-result-tuple = tuple -host-state2-result-tuple: func() -> host-state-result-tuple - -type host-state-result-option = option -host-state2-result-option: func() -> host-state-result-option - -type host-state-result-result = result -host-state2-result-result: func() -> host-state-result-result - -union host-state-result-variant { host-state2, u32 } -host-state2-result-variant: func() -> host-state-result-variant - -host-state2-result-list: func() -> list - -resource markdown2 { - static create: func() -> markdown2 - append: func(buf: string) - render: func() -> string -} - -resource %odd-name { - static create: func() -> %odd-name - %frob-the-odd: func() -} diff --git a/tests/runtime/handles/wasm.c b/tests/runtime/handles/wasm.c deleted file mode 100644 index ef95592f8..000000000 --- a/tests/runtime/handles/wasm.c +++ /dev/null @@ -1,223 +0,0 @@ -#include -#include -#include -#include -#include - -void exports_test_imports() { - imports_host_state_t s = imports_host_state_create(); - assert(imports_host_state_get(s) == 100); - imports_host_state_free(&s); - - assert(imports_host_state2_saw_close() == false); - imports_host_state2_t s2 = imports_host_state2_create(); - assert(imports_host_state2_saw_close() == false); - imports_host_state2_free(&s2); - assert(imports_host_state2_saw_close() == true); - - { - imports_host_state_t a, b; - imports_host_state2_t c, d; - - a = imports_host_state_create(); - c = imports_host_state2_create(); - imports_two_host_states(a, c, &b, &d); - imports_host_state_free(&a); - imports_host_state_free(&b); - imports_host_state2_free(&c); - - { - imports_host_state_param_record_t a; - a.a = d; - imports_host_state2_param_record(&a); - } - { - imports_host_state_param_tuple_t a; - a.f0 = d; - imports_host_state2_param_tuple(&a); - } - { - imports_host_state_param_option_t a; - a.is_some = true; - a.val = d; - imports_host_state2_param_option(&a); - } - { - imports_host_state_param_result_t a; - a.is_err = false; - a.val.ok = d; - imports_host_state2_param_result(&a); - a.is_err = true; - a.val.err = 2; - imports_host_state2_param_result(&a); - } - { - imports_host_state_param_variant_t a; - a.tag = 0; - a.val.f0 = d; - imports_host_state2_param_variant(&a); - a.tag = 1; - a.val.f1 = 2; - imports_host_state2_param_variant(&a); - } - { - imports_host_state2_t arr[2]; - arr[0] = d; - arr[1] = d; - imports_list_host_state2_t list; - list.len = 0; - list.ptr = arr; - imports_host_state2_param_list(&list); - list.len = 1; - imports_host_state2_param_list(&list); - list.len = 2; - imports_host_state2_param_list(&list); - } - - imports_host_state2_free(&d); - } - - { - imports_host_state_result_record_t a; - imports_host_state2_result_record(&a); - imports_host_state2_free(&a.a); - } - { - imports_host_state_result_tuple_t a; - imports_host_state2_result_tuple(&a); - imports_host_state2_free(&a.f0); - } - { - imports_host_state2_t a; - assert(imports_host_state2_result_option(&a)); - imports_host_state2_free(&a); - } - { - imports_host_state_result_result_t a; - imports_host_state2_result_result(&a); - assert(!a.is_err); - imports_host_state2_free(&a.val.ok); - } - { - imports_host_state_result_variant_t a; - imports_host_state2_result_variant(&a); - assert(a.tag == 0); - imports_host_state2_free(&a.val.f0); - } - { - imports_list_host_state2_t a; - imports_host_state2_result_list(&a); - imports_list_host_state2_free(&a); - } - { - imports_markdown2_t a = imports_markdown2_create(); - imports_string_t s; - imports_string_set(&s, "red is the best color"); - imports_markdown2_append(a, &s); - imports_markdown2_render(a, &s); - - const char *expected = "green is the best color"; - assert(s.len == strlen(expected)); - assert(memcmp(s.ptr, expected, s.len) == 0); - imports_string_free(&s); - imports_markdown2_free(&a); - } -} - -exports_wasm_state_t exports_wasm_state_create(void) { - return exports_wasm_state_new((void*) 100); -} - -uint32_t exports_wasm_state_get_val(exports_wasm_state_t a) { - uint32_t ret = (uint32_t) exports_wasm_state_get(&a); - exports_wasm_state_free(&a); - return ret; -} - -exports_wasm_state2_t exports_wasm_state2_create(void) { - return exports_wasm_state2_new((void*) 33); -} - -static bool WASM_STATE2_CLOSED = false; - -bool exports_wasm_state2_saw_close(void) { - return WASM_STATE2_CLOSED; -} - -void exports_wasm_state2_dtor(void *data) { - WASM_STATE2_CLOSED = true; -} - -void exports_two_wasm_states(exports_wasm_state_t a, exports_wasm_state2_t b, exports_wasm_state_t *ret0, exports_wasm_state2_t *ret1) { - exports_wasm_state_free(&a); - exports_wasm_state2_free(&b); - - *ret0 = exports_wasm_state_new((void*) 101); - *ret1 = exports_wasm_state2_new((void*) 102); -} - -void exports_wasm_state2_param_record(exports_wasm_state_param_record_t *a) { - exports_wasm_state_param_record_free(a); -} - -void exports_wasm_state2_param_tuple(exports_wasm_state_param_tuple_t *a) { - exports_wasm_state_param_tuple_free(a); -} - -void exports_wasm_state2_param_option(exports_wasm_state_param_option_t *a) { - exports_wasm_state_param_option_free(a); -} - -void exports_wasm_state2_param_result(exports_wasm_state_param_result_t *a) { - exports_wasm_state_param_result_free(a); -} - -void exports_wasm_state2_param_variant(exports_wasm_state_param_variant_t *a) { - exports_wasm_state_param_variant_free(a); -} - -void exports_wasm_state2_param_list(exports_list_wasm_state2_t *a) { - exports_list_wasm_state2_free(a); -} - -void exports_wasm_state2_result_record(exports_wasm_state_result_record_t *ret0) { - ret0->a = exports_wasm_state2_new((void*) 222); -} - -void exports_wasm_state2_result_tuple(exports_wasm_state_result_tuple_t *ret0) { - ret0->f0 = exports_wasm_state2_new((void*) 333); -} - -bool exports_wasm_state2_result_option(exports_wasm_state2_t *ret0) { - *ret0 = exports_wasm_state2_new((void*) 444); - return true; -} - -void exports_wasm_state2_result_result(exports_wasm_state_result_result_t *ret0) { - ret0->is_err = false; - ret0->val.ok = exports_wasm_state2_new((void*) 555); -} - -void exports_wasm_state2_result_variant(exports_wasm_state_result_variant_t *ret0) { - ret0->tag = 0; - ret0->val.f0 = exports_wasm_state2_new((void*) 666); -} - -void exports_wasm_state2_result_list(exports_list_wasm_state2_t *ret0) { - ret0->len = 2; - ret0->ptr = malloc(2 * sizeof(exports_wasm_state2_t)); - ret0->ptr[0] = exports_wasm_state2_new((void*) 777); - ret0->ptr[1] = exports_wasm_state2_new((void*) 888); -} - -bool exports_markdown_create(exports_markdown_t *md) { - return false; -} - -void exports_markdown_append(exports_markdown_t md, exports_string_t *s) { - abort(); -} - -void exports_markdown_render(exports_markdown_t md, exports_string_t *ret) { - abort(); -} diff --git a/tests/runtime/handles/wasm.rs b/tests/runtime/handles/wasm.rs deleted file mode 100644 index 18b44371e..000000000 --- a/tests/runtime/handles/wasm.rs +++ /dev/null @@ -1,131 +0,0 @@ -wit_bindgen_guest_rust::import!("../../tests/runtime/handles/imports.wit"); -wit_bindgen_guest_rust::export!("../../tests/runtime/handles/exports.wit"); - -use exports::*; -use std::cell::RefCell; -use std::sync::atomic::{AtomicU32, Ordering::SeqCst}; -use wit_bindgen_guest_rust::Handle; - -struct Exports; - -static CLOSED: AtomicU32 = AtomicU32::new(0); - -pub struct WasmState(u32); - -pub struct WasmState2(u32); - -impl exports::Exports for Exports { - fn test_imports() { - use imports::*; - - let s: HostState = host_state_create(); - assert_eq!(host_state_get(&s), 100); - assert_eq!(host_state2_saw_close(), false); - let s: HostState2 = host_state2_create(); - assert_eq!(host_state2_saw_close(), false); - drop(s); - assert_eq!(host_state2_saw_close(), true); - - let (_a, s2) = two_host_states(&host_state_create(), &host_state2_create()); - - host_state2_param_record(HostStateParamRecord { a: &s2 }); - host_state2_param_tuple((&s2,)); - host_state2_param_option(Some(&s2)); - host_state2_param_option(None); - host_state2_param_result(Ok(&s2)); - host_state2_param_result(Err(2)); - host_state2_param_variant(HostStateParamVariant::HostState2(&s2)); - host_state2_param_variant(HostStateParamVariant::U32(2)); - host_state2_param_list(&[]); - host_state2_param_list(&[&s2]); - host_state2_param_list(&[&s2, &s2]); - - drop(host_state2_result_record().a); - drop(host_state2_result_tuple().0); - drop(host_state2_result_option().unwrap()); - drop(host_state2_result_result().unwrap()); - drop(host_state2_result_variant()); - drop(host_state2_result_list()); - - let md = Markdown2::create(); - md.append("red is the best color"); - assert_eq!(md.render(), "green is the best color"); - - let odd = OddName::create(); - odd.frob_the_odd(); - } - - fn wasm_state_create() -> Handle { - WasmState(100).into() - } - - fn wasm_state_get_val(state: Handle) -> u32 { - state.0 - } - - fn wasm_state2_create() -> Handle { - WasmState2(33).into() - } - - fn wasm_state2_saw_close() -> bool { - CLOSED.load(SeqCst) != 0 - } - - fn drop_wasm_state2(_state: WasmState2) { - CLOSED.store(1, SeqCst); - } - - fn two_wasm_states( - _a: Handle, - _b: Handle, - ) -> (Handle, Handle) { - (WasmState(101).into(), WasmState2(102).into()) - } - - fn wasm_state2_param_record(_a: WasmStateParamRecord) {} - fn wasm_state2_param_tuple(_a: (Handle,)) {} - fn wasm_state2_param_option(_a: Option>) {} - fn wasm_state2_param_result(_a: Result, u32>) {} - fn wasm_state2_param_variant(_a: WasmStateParamVariant) {} - fn wasm_state2_param_list(_a: Vec>) {} - - fn wasm_state2_result_record() -> WasmStateResultRecord { - WasmStateResultRecord { - a: WasmState2(222).into(), - } - } - fn wasm_state2_result_tuple() -> (Handle,) { - (WasmState2(333).into(),) - } - fn wasm_state2_result_option() -> Option> { - Some(WasmState2(444).into()) - } - fn wasm_state2_result_result() -> Result, u32> { - Ok(WasmState2(555).into()) - } - fn wasm_state2_result_variant() -> WasmStateResultVariant { - WasmStateResultVariant::WasmState2(Handle::new(WasmState2(666))) - } - fn wasm_state2_result_list() -> Vec> { - vec![WasmState2(777).into(), WasmState2(888).into()] - } -} - -#[derive(Default)] -pub struct Markdown { - buf: RefCell, -} - -impl exports::Markdown for Markdown { - fn create() -> Option> { - Some(Markdown::default().into()) - } - - fn append(&self, input: String) { - self.buf.borrow_mut().push_str(&input); - } - - fn render(&self) -> String { - self.buf.borrow().replace("red", "green") - } -} diff --git a/tests/runtime/invalid/exports.wit b/tests/runtime/invalid/exports.wit index 7272c498a..7619764fe 100644 --- a/tests/runtime/invalid/exports.wit +++ b/tests/runtime/invalid/exports.wit @@ -5,5 +5,3 @@ invalid-s16: func() invalid-char: func() invalid-bool: func() invalid-enum: func() -invalid-handle: func() -invalid-handle-close: func() diff --git a/tests/runtime/invalid/host.py b/tests/runtime/invalid/host.py index 3895cb9c1..d9a0a90b8 100644 --- a/tests/runtime/invalid/host.py +++ b/tests/runtime/invalid/host.py @@ -27,9 +27,6 @@ def roundtrip_char(self, x: str) -> str: def roundtrip_enum(self, x: i.E) -> i.E: raise Exception('unreachable') - def get_internal(self, x: i.HostState) -> int: - raise Exception('unreachable') - def run(wasm_file: str) -> None: store = wasmtime.Store() module = wasmtime.Module.from_file(store.engine, wasm_file) @@ -67,8 +64,6 @@ def assert_throws(f: Callable, msg: str) -> None: assert_throws(lambda: wasm.invalid_s16(store), 'must be between') assert_throws(lambda: wasm.invalid_char(store), 'not a valid char') assert_throws(lambda: wasm.invalid_enum(store), 'not a valid E') - assert_throws(lambda: wasm.invalid_handle(store), 'handle index not valid') - assert_throws(lambda: wasm.invalid_handle_close(store), 'handle index not valid') if __name__ == '__main__': run(sys.argv[1]) diff --git a/tests/runtime/invalid/host.rs b/tests/runtime/invalid/host.rs index 8a43c3bfd..fea0701ce 100644 --- a/tests/runtime/invalid/host.rs +++ b/tests/runtime/invalid/host.rs @@ -8,8 +8,6 @@ use wasmtime::Trap; pub struct MyImports; impl Imports for MyImports { - type HostState = (); - fn roundtrip_u8(&mut self, _: u8) -> u8 { unreachable!() } @@ -31,9 +29,6 @@ impl Imports for MyImports { fn roundtrip_enum(&mut self, _: imports::E) -> imports::E { unreachable!() } - fn get_internal(&mut self, _: &()) -> u32 { - unreachable!() - } } wit_bindgen_host_wasmtime_rust::import!("../../tests/runtime/invalid/exports.wit"); @@ -44,12 +39,9 @@ fn run(wasm: &str) -> Result<()> { let (exports, mut store) = crate::instantiate( wasm, |linker| { - imports::add_to_linker( - linker, - |cx: &mut crate::Context<(MyImports, imports::ImportsTables), _>| { - (&mut cx.imports.0, &mut cx.imports.1) - }, - ) + imports::add_to_linker(linker, |cx: &mut crate::Context| { + &mut cx.imports + }) }, |store, module, linker| Exports::instantiate(store, module, linker, |cx| &mut cx.exports), )?; @@ -82,11 +74,6 @@ fn run(wasm: &str) -> Result<()> { exports.invalid_enum(&mut store), "invalid discriminant for `E`", )?; - assert_err(exports.invalid_handle(&mut store), "invalid handle index")?; - assert_err( - exports.invalid_handle_close(&mut store), - "invalid handle index", - )?; return Ok(()); fn assert_err(result: Result<(), Trap>, err: &str) -> Result<()> { diff --git a/tests/runtime/invalid/host.ts b/tests/runtime/invalid/host.ts index 5e6cb31df..d38457227 100644 --- a/tests/runtime/invalid/host.ts +++ b/tests/runtime/invalid/host.ts @@ -14,7 +14,6 @@ async function run() { roundtripBool(x) { throw new Error('unreachable'); }, roundtripChar(x) { throw new Error('unreachable'); }, roundtripEnum(x) { throw new Error('unreachable'); }, - getInternal(x) { throw new Error('unreachable'); }, }; let instance: WebAssembly.Instance; addImportsToImports(importObj, imports); @@ -32,8 +31,6 @@ async function run() { assert.throws(() => wasm.invalidS16(), /must be between/); assert.throws(() => wasm.invalidChar(), /not a valid char/); assert.throws(() => wasm.invalidEnum(), /invalid discriminant specified for E/); - assert.throws(() => wasm.invalidHandle(), /handle index not valid/); - assert.throws(() => wasm.invalidHandleClose(), /handle index not valid/); } await run() diff --git a/tests/runtime/invalid/imports.wit b/tests/runtime/invalid/imports.wit index 420e8adef..9f236993b 100644 --- a/tests/runtime/invalid/imports.wit +++ b/tests/runtime/invalid/imports.wit @@ -8,6 +8,3 @@ enum e { a, b, c } roundtrip-enum: func(a: e) -> e roundtrip-bool: func(a: bool) -> bool - -resource host-state -get-internal: func(a: host-state) -> u32 diff --git a/tests/runtime/invalid/wasm.rs b/tests/runtime/invalid/wasm.rs index 00c95cb80..22c262a00 100644 --- a/tests/runtime/invalid/wasm.rs +++ b/tests/runtime/invalid/wasm.rs @@ -16,14 +16,6 @@ extern "C" { fn roundtrip_char(a: i32) -> i32; #[link_name = "roundtrip-enum"] fn roundtrip_enum(a: i32) -> i32; - #[link_name = "get-internal"] - fn get_internal(a: i32) -> i32; -} - -#[link(wasm_import_module = "canonical_abi")] -extern "C" { - #[link_name = "resource_drop_host-state"] - fn resource_drop_host_state(a: i32); } struct Exports; @@ -71,18 +63,4 @@ impl exports::Exports for Exports { } unreachable!(); } - - fn invalid_handle() { - unsafe { - get_internal(100); - } - unreachable!(); - } - - fn invalid_handle_close() { - unsafe { - resource_drop_host_state(100); - } - unreachable!(); - } } diff --git a/tests/runtime/js_instantiate/host.ts b/tests/runtime/js_instantiate/host.ts index 895d2fc31..e3cca6341 100644 --- a/tests/runtime/js_instantiate/host.ts +++ b/tests/runtime/js_instantiate/host.ts @@ -12,7 +12,6 @@ async function run() { (new Exports()).instantiate(new WebAssembly.Module(getWasm()), importObj); { const obj = new Exports(); - obj.addToImports(importObj); obj.instantiate(new WebAssembly.Instance(new WebAssembly.Module(getWasm()), importObj)); } } From d74b23fa1955a08d695b557b8c7831129b612596 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 4 Oct 2022 10:11:21 -0700 Subject: [PATCH 02/12] Remove resources from the demo --- crates/guest-rust/src/lib.rs | 116 ----------------------------- crates/wit-bindgen-demo/demo.wit | 15 ++-- crates/wit-bindgen-demo/main.ts | 21 ++++-- crates/wit-bindgen-demo/src/lib.rs | 71 +++++++----------- 4 files changed, 45 insertions(+), 178 deletions(-) diff --git a/crates/guest-rust/src/lib.rs b/crates/guest-rust/src/lib.rs index dcc002653..1a8bdac37 100644 --- a/crates/guest-rust/src/lib.rs +++ b/crates/guest-rust/src/lib.rs @@ -1,8 +1,3 @@ -use std::fmt; -use std::marker; -use std::mem; -use std::ops::Deref; - #[cfg(feature = "macros")] pub use wit_bindgen_guest_rust_macro::{export, import}; @@ -10,117 +5,6 @@ pub use wit_bindgen_guest_rust_macro::{export, import}; #[doc(hidden)] pub use bitflags; -/// A type for handles to resources that appear in exported functions. -/// -/// This type is used as `Handle` for argument types and return values of -/// exported functions when exposing a Rust-defined resource. A `Handle` -/// represents an owned reference count on the interface-types-managed resource. -/// It's similar to an `Rc` in Rust. Internally a `Handle` can provide -/// access to `&T` when `T` is defined in the current module. -pub struct Handle { - val: i32, - _marker: marker::PhantomData, -} - -impl Handle { - /// Creates a new handle around the specified value. - /// - /// Note that the lifetime of `T` will afterwards be managed by the - /// interface types runtime. The host may hold references to `T` that wasm - /// isn't necessarily aware of, preventing its destruction. Nevertheless - /// though the `Drop for T` implementation will still be run when there are - /// no more references to `T`. - pub fn new(val: T) -> Handle - where - T: LocalHandle, - { - unsafe { Handle::from_raw(T::new(Box::into_raw(Box::new(val)) as i32)) } - } - - /// Consumes a handle and returns the underlying raw wasm i32 descriptor. - /// - /// Note that this, if used improperly, will leak the resource `T`. This - /// generally should be avoided unless you're calling raw ABI bindings and - /// managing the lifetime manually. - pub fn into_raw(handle: Handle) -> i32 { - let ret = handle.val; - mem::forget(handle); - ret - } - - /// Returns the raw underlying handle value for this handle. - /// - /// This typically isn't necessary to interact with, but can be useful when - /// interacting with raw ABI bindings. - pub fn as_raw(handle: &Handle) -> i32 { - handle.val - } - - /// Unsafely assumes that the given integer descriptor is a handle for `T`. - /// - /// This is unsafe because no validation is performed to ensure that `val` - /// is actually a valid descriptor for `T`. - pub unsafe fn from_raw(val: i32) -> Handle { - Handle { - val, - _marker: marker::PhantomData, - } - } -} - -impl Deref for Handle { - type Target = T; - - fn deref(&self) -> &T { - unsafe { &*(T::get(self.val) as *const T) } - } -} - -impl From for Handle { - fn from(val: T) -> Handle { - Handle::new(val) - } -} - -impl Clone for Handle { - fn clone(&self) -> Self { - unsafe { Handle::from_raw(T::clone(self.val)) } - } -} - -impl fmt::Debug for Handle { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Handle").field("val", &self.val).finish() - } -} - -impl Drop for Handle { - fn drop(&mut self) { - T::drop(self.val); - } -} - -/// A trait for types that can show up as the `T` in `Handle`. -/// -/// This trait is automatically synthesized for exported handles and typically -/// shouldn't be implemented manually. -pub unsafe trait HandleType { - #[doc(hidden)] - fn clone(val: i32) -> i32; - #[doc(hidden)] - fn drop(val: i32); -} - -/// An extension of the [`HandleType`] trait for locally-defined types. -/// -/// This trait may not stick around forever... -pub unsafe trait LocalHandle: HandleType { - #[doc(hidden)] - fn new(val: i32) -> i32; - #[doc(hidden)] - fn get(val: i32) -> i32; -} - #[doc(hidden)] pub mod rt { use std::alloc::{self, Layout}; diff --git a/crates/wit-bindgen-demo/demo.wit b/crates/wit-bindgen-demo/demo.wit index 22235ccf7..00b06c663 100644 --- a/crates/wit-bindgen-demo/demo.wit +++ b/crates/wit-bindgen-demo/demo.wit @@ -11,12 +11,11 @@ enum lang { } -resource config { - static new: func() -> config - - render: func(lang: lang, wit: string, import: bool) -> result - - set-rust-unchecked: func(unchecked: bool) - set-wasmtime-tracing: func(unchecked: bool) - set-wasmtime-custom-error: func(custom: bool) +record options { + rust-unchecked: bool, + wasmtime-tracing: bool, + wasmtime-custom-error: bool, + import: bool, } + +render: func(lang: lang, wit: string, options: options) -> result diff --git a/crates/wit-bindgen-demo/main.ts b/crates/wit-bindgen-demo/main.ts index 9ca11b653..089f40810 100644 --- a/crates/wit-bindgen-demo/main.ts +++ b/crates/wit-bindgen-demo/main.ts @@ -1,4 +1,4 @@ -import { Demo, Config } from './demo.js'; +import { Demo, Options } from './demo.js'; import * as browser from './browser.js'; class Editor { @@ -11,7 +11,7 @@ class Editor { wasmtimeCustomError: HTMLInputElement; generatedFiles: Record; demo: Demo; - config: Config | null; + options: Options; rerender: number | null; inputEditor: AceAjax.Editor; outputEditor: AceAjax.Editor; @@ -37,7 +37,12 @@ class Editor { this.generatedFiles = {}; this.demo = new Demo(); - this.config = null; + this.options = { + rustUnchecked: false, + wasmtimeTracing: false, + wasmtimeCustomError: false, + import: false, + }; this.rerender = null; } @@ -49,7 +54,6 @@ class Editor { }; browser.addBrowserToImports(imports, obj, name => this.demo.instance.exports[name]); await this.demo.instantiate(fetch('./demo.wasm'), imports); - this.config = Config.new(this.demo); this.installListeners(); this.render(); } @@ -66,16 +70,16 @@ class Editor { this.mode.addEventListener('change', () => this.render()); this.rustUnchecked.addEventListener('change', () => { - this.config.setRustUnchecked(this.rustUnchecked.checked); + this.options.rustUnchecked = this.rustUnchecked.checked; this.render(); }); this.wasmtimeTracing.addEventListener('change', () => { - this.config.setWasmtimeTracing(this.wasmtimeTracing.checked); + this.options.wasmtimeTracing = this.wasmtimeTracing.checked; this.render(); }); this.wasmtimeCustomError.addEventListener('change', () => { - this.config.setWasmtimeCustomError(this.wasmtimeCustomError.checked); + this.options.wasmtimeCustomError = this.wasmtimeCustomError.checked; this.render(); }); this.files.addEventListener('change', () => this.updateSelectedFile()); @@ -105,7 +109,8 @@ class Editor { break; default: return; } - const result = this.config.render(lang, wit, is_import); + this.options.import = is_import; + const result = this.demo.render(lang, wit, this.options); if (result.tag === 'err') { this.outputEditor.setValue(result.val); this.outputEditor.clearSelection(); diff --git a/crates/wit-bindgen-demo/src/lib.rs b/crates/wit-bindgen-demo/src/lib.rs index a4361bc25..f925e2437 100644 --- a/crates/wit-bindgen-demo/src/lib.rs +++ b/crates/wit-bindgen-demo/src/lib.rs @@ -1,29 +1,18 @@ -use std::cell::RefCell; use std::sync::Once; use wit_bindgen_core::wit_parser::Interface; use wit_bindgen_core::Generator; -use wit_bindgen_guest_rust::Handle; wit_bindgen_guest_rust::export!("demo.wit"); wit_bindgen_guest_rust::import!("browser.wit"); struct Demo; -impl demo::Demo for Demo {} - -#[derive(Default)] -pub struct Config { - js: RefCell, - c: RefCell, - rust: RefCell, - java: RefCell, - wasmtime: RefCell, - wasmtime_py: RefCell, - markdown: RefCell, -} - -impl demo::Config for Config { - fn new() -> Handle { +impl demo::Demo for Demo { + fn render( + lang: demo::Lang, + wit: String, + options: demo::Options, + ) -> Result, String> { static INIT: Once = Once::new(); INIT.call_once(|| { let prev_hook = std::panic::take_hook(); @@ -33,27 +22,29 @@ impl demo::Config for Config { })); }); - Config::default().into() - } - - fn render( - &self, - lang: demo::Lang, - wit: String, - import: bool, - ) -> Result, String> { let mut gen: Box = match lang { - demo::Lang::Rust => Box::new(self.rust.borrow().clone().build()), - demo::Lang::Java => Box::new(self.java.borrow().clone().build()), - demo::Lang::Wasmtime => Box::new(self.wasmtime.borrow().clone().build()), - demo::Lang::WasmtimePy => Box::new(self.wasmtime_py.borrow().clone().build()), - demo::Lang::Js => Box::new(self.js.borrow().clone().build()), - demo::Lang::C => Box::new(self.c.borrow().clone().build()), - demo::Lang::Markdown => Box::new(self.markdown.borrow().clone().build()), + demo::Lang::Rust => Box::new({ + let mut opts = wit_bindgen_gen_guest_rust::Opts::default(); + opts.unchecked = options.rust_unchecked; + opts.build() + }), + demo::Lang::Java => Box::new(wit_bindgen_gen_guest_teavm_java::Opts::default().build()), + demo::Lang::Wasmtime => Box::new({ + let mut opts = wit_bindgen_gen_host_wasmtime_rust::Opts::default(); + opts.tracing = options.wasmtime_tracing; + opts.custom_error = options.wasmtime_custom_error; + opts.build() + }), + demo::Lang::WasmtimePy => { + Box::new(wit_bindgen_gen_host_wasmtime_py::Opts::default().build()) + } + demo::Lang::Js => Box::new(wit_bindgen_gen_host_js::Opts::default().build()), + demo::Lang::C => Box::new(wit_bindgen_gen_guest_c::Opts::default().build()), + demo::Lang::Markdown => Box::new(wit_bindgen_gen_markdown::Opts::default().build()), }; let iface = Interface::parse("input", &wit).map_err(|e| format!("{:?}", e))?; let mut files = Default::default(); - let (imports, exports) = if import { + let (imports, exports) = if options.import { (vec![iface], vec![]) } else { (vec![], vec![iface]) @@ -71,16 +62,4 @@ impl demo::Config for Config { }) .collect()) } - - fn set_rust_unchecked(&self, unchecked: bool) { - self.rust.borrow_mut().unchecked = unchecked; - } - - fn set_wasmtime_tracing(&self, tracing: bool) { - self.wasmtime.borrow_mut().tracing = tracing; - } - fn set_wasmtime_custom_error(&self, custom_error: bool) { - browser::log("custom error"); - self.wasmtime.borrow_mut().custom_error = custom_error; - } } From 465551506859012bfe79a90401345031cdf12aad Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Thu, 29 Sep 2022 12:18:50 -0700 Subject: [PATCH 03/12] smuggle wit information in custom sections --- crates/wit-component/tests/components.rs | 158 ++++++++++++++++++++++- 1 file changed, 156 insertions(+), 2 deletions(-) diff --git a/crates/wit-component/tests/components.rs b/crates/wit-component/tests/components.rs index ded443b0b..f2628320f 100644 --- a/crates/wit-component/tests/components.rs +++ b/crates/wit-component/tests/components.rs @@ -1,7 +1,7 @@ use anyhow::{bail, Context, Result}; use pretty_assertions::assert_eq; use std::{fs, path::Path}; -use wit_component::ComponentEncoder; +use wit_component::{decode_interface_component, ComponentEncoder, InterfaceEncoder}; use wit_parser::Interface; fn read_interface(path: &Path) -> Result { @@ -78,7 +78,7 @@ fn read_adapters(dir: &Path) -> Result, Interface)>> { /// Run the test with the environment variable `BLESS` set to update /// either `component.wat` or `error.txt` depending on the outcome of the encoding. #[test] -fn component_encoding() -> Result<()> { +fn component_encoding_via_flags() -> Result<()> { drop(env_logger::try_init()); for entry in fs::read_dir("tests/components")? { @@ -154,3 +154,157 @@ fn component_encoding() -> Result<()> { Ok(()) } + +/// Tests the encoding of components. +/// +/// This test looks in the `components/` directory for test cases. +/// +/// The expected input files for a test case are: +/// +/// * [required] `module.wat` - contains the core module definition to be encoded +/// as a component. +/// * [optional] `default.wit` - represents the component's default interface. +/// * [optional] `export-.wit` - represents an interface exported by the component. +/// * [optional] `import-.wit` - represents an interface imported by the component. +/// +/// And the output files are one of the following: +/// +/// * `component.wat` - the expected encoded component in text format if the encoding +/// is expected to succeed. +/// * `error.txt` - the expected error message if the encoding is expected to fail. +/// +/// The test encodes a component based on the input files. If the encoding succeeds, +/// it expects the output to match `component.wat`. If the encoding fails, it expects +/// the output to match `error.txt`. +/// +/// Run the test with the environment variable `BLESS` set to update +/// either `component.wat` or `error.txt` depending on the outcome of the encoding. +#[test] +fn component_encoding_via_custom_section() -> Result<()> { + use wasm_encoder::{Encode, Section}; + + for entry in fs::read_dir("tests/components")? { + let path = entry?.path(); + if !path.is_dir() { + continue; + } + + let test_case = path.file_stem().unwrap().to_str().unwrap(); + + let module_path = path.join("module.wat"); + let interface_path = path.join("default.wit"); + let component_path = path.join("component.wat"); + let error_path = path.join("error.txt"); + + let mut module = wat::parse_file(&module_path) + .with_context(|| format!("expected file `{}`", module_path.display()))?; + + let base_module = module.clone(); + + fn encode_interface(i: &Interface, module: &mut Vec, kind: &str) -> Result<()> { + let name = &format!("component-type:{}:{}", kind, i.name); + let contents = InterfaceEncoder::new(&i).validate(true).encode()?; + let section = wasm_encoder::CustomSection { + name, + data: &contents, + }; + module.push(section.id()); + section.encode(module); + Ok(()) + } + + if interface_path.is_file() { + let i = read_interface(&interface_path)?; + encode_interface(&i, &mut module, "export")?; + } + for i in read_interfaces(&path, "import-*.wit")? { + encode_interface(&i, &mut module, "import")?; + } + for i in read_interfaces(&path, "export-*.wit")? { + encode_interface(&i, &mut module, "export-instance")?; + } + + // Everything is now encoded into `module`: now lets deconstruct it + + let mut encoder = ComponentEncoder::default() + .module(&base_module) + .validate(true); + + let mut interface = None; + let mut imports = Vec::new(); + let mut exports = Vec::new(); + for payload in wasmparser::Parser::new(0).parse_all(&module) { + match payload.context("decoding item in module")? { + wasmparser::Payload::CustomSection(cs) => { + if let Some(export) = cs.name().strip_prefix("component-type:export:") { + let mut i = decode_interface_component(cs.data()).with_context(|| { + format!("decoding component-type in export section {}", export) + })?; + i.name = export.to_owned(); + interface = Some(i); + } else if let Some(import) = cs.name().strip_prefix("component-type:import:") { + let mut interface = + decode_interface_component(cs.data()).with_context(|| { + format!("decoding component-type in import section {}", import) + })?; + interface.name = import.to_owned(); + imports.push(interface); + } else if let Some(export_instance) = + cs.name().strip_prefix("component-type:export-instance:") + { + let mut interface = + decode_interface_component(cs.data()).with_context(|| { + format!( + "decoding component-type in export-instance section {}", + export_instance + ) + })?; + interface.name = export_instance.to_owned(); + exports.push(interface); + } + } + _ => {} + } + } + + encoder = encoder.imports(&imports).exports(&exports); + if let Some(interface) = &interface { + encoder = encoder.interface(&interface); + } + + let r = encoder.encode(); + let (output, baseline_path) = if error_path.is_file() { + match r { + Ok(_) => bail!("encoding should fail for test case `{}`", test_case), + Err(e) => (e.to_string(), &error_path), + } + } else { + ( + wasmprinter::print_bytes( + &r.with_context(|| format!("failed to encode for test case `{}`", test_case))?, + ) + .with_context(|| { + format!( + "failed to print component bytes for test case `{}`", + test_case + ) + })?, + &component_path, + ) + }; + + if std::env::var_os("BLESS").is_some() { + fs::write(&baseline_path, output)?; + } else { + assert_eq!( + fs::read_to_string(&baseline_path)?.replace("\r\n", "\n"), + output, + "failed baseline comparison for test case `{}` ({})", + test_case, + baseline_path.display(), + ); + } + } + + Ok(()) +} From 1edee0f6957951ae955615f4be1d65f3ea027473 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Thu, 29 Sep 2022 15:50:00 -0700 Subject: [PATCH 04/12] move transcoder to the crate, and make it available in the cli --- crates/wit-component/src/cli.rs | 59 ++++++++++++++---------- crates/wit-component/src/lib.rs | 2 + crates/wit-component/src/transcode.rs | 52 +++++++++++++++++++++ crates/wit-component/tests/components.rs | 51 +------------------- 4 files changed, 90 insertions(+), 74 deletions(-) create mode 100644 crates/wit-component/src/transcode.rs diff --git a/crates/wit-component/src/cli.rs b/crates/wit-component/src/cli.rs index cef566ca7..83ea31dd6 100644 --- a/crates/wit-component/src/cli.rs +++ b/crates/wit-component/src/cli.rs @@ -3,7 +3,7 @@ #![deny(missing_docs)] use crate::{ - decode_interface_component, ComponentEncoder, InterfaceEncoder, InterfacePrinter, + decode_interface_component, transcode, ComponentEncoder, InterfaceEncoder, InterfacePrinter, StringEncoding, }; use anyhow::{bail, Context, Result}; @@ -109,6 +109,11 @@ pub struct WitComponentApp { #[clap(long)] pub skip_validation: bool, + /// Transcode the WebAssembly module into a Component using only the interface definitions + /// found in custom sections. + #[clap(long)] + pub transcode: bool, + /// The expected string encoding format for the component. /// Supported values are: `utf8` (default), `utf16`, and `compact-utf16`. #[clap(long, value_name = "ENCODING")] @@ -138,30 +143,34 @@ impl WitComponentApp { let module = wat::parse_file(&self.module) .with_context(|| format!("failed to parse module `{}`", self.module.display()))?; - let mut encoder = ComponentEncoder::default() - .module(&module) - .imports(&self.imports) - .exports(&self.exports) - .validate(!self.skip_validation); - - for (name, wasm, interface) in self.adapters.iter() { - encoder = encoder.adapter(name, wasm, interface); - } - - if let Some(interface) = &self.interface { - encoder = encoder.interface(interface); - } - - if let Some(encoding) = &self.encoding { - encoder = encoder.encoding(*encoding); - } - - let bytes = encoder.encode().with_context(|| { - format!( - "failed to encode a component from module `{}`", - self.module.display() - ) - })?; + let bytes = if self.transcode { + transcode(&module)? + } else { + let mut encoder = ComponentEncoder::default() + .module(&module) + .imports(&self.imports) + .exports(&self.exports) + .validate(!self.skip_validation); + + for (name, wasm, interface) in self.adapters.iter() { + encoder = encoder.adapter(name, wasm, interface); + } + + if let Some(interface) = &self.interface { + encoder = encoder.interface(interface); + } + + if let Some(encoding) = &self.encoding { + encoder = encoder.encoding(*encoding); + } + + encoder.encode().with_context(|| { + format!( + "failed to encode a component from module `{}`", + self.module.display() + ) + })? + }; std::fs::write(&output, bytes) .with_context(|| format!("failed to write output file `{}`", output.display()))?; diff --git a/crates/wit-component/src/lib.rs b/crates/wit-component/src/lib.rs index a1f51744e..f65b17996 100644 --- a/crates/wit-component/src/lib.rs +++ b/crates/wit-component/src/lib.rs @@ -13,10 +13,12 @@ mod decoding; mod encoding; mod gc; mod printing; +mod transcode; mod validation; pub use encoding::*; pub use printing::*; +pub use transcode::*; /// Supported string encoding formats. #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] diff --git a/crates/wit-component/src/transcode.rs b/crates/wit-component/src/transcode.rs new file mode 100644 index 000000000..368ddfa39 --- /dev/null +++ b/crates/wit-component/src/transcode.rs @@ -0,0 +1,52 @@ +use crate::{decode_interface_component, ComponentEncoder}; +use anyhow::{Context, Result}; +use wasmparser::{Parser, Payload}; + +/// Transcode a core Module containing Component types in custom sections into a Component. +pub fn transcode(module: &[u8]) -> Result> { + let mut encoder = ComponentEncoder::default().module(&module).validate(true); + + let mut interface = None; + let mut imports = Vec::new(); + let mut exports = Vec::new(); + for payload in Parser::new(0).parse_all(&module) { + match payload.context("decoding item in module")? { + Payload::CustomSection(cs) => { + if let Some(export) = cs.name().strip_prefix("component-type:export:") { + let mut i = decode_interface_component(cs.data()).with_context(|| { + format!("decoding component-type in export section {}", export) + })?; + i.name = export.to_owned(); + interface = Some(i); + } else if let Some(import) = cs.name().strip_prefix("component-type:import:") { + let mut interface = + decode_interface_component(cs.data()).with_context(|| { + format!("decoding component-type in import section {}", import) + })?; + interface.name = import.to_owned(); + imports.push(interface); + } else if let Some(export_instance) = + cs.name().strip_prefix("component-type:export-instance:") + { + let mut interface = + decode_interface_component(cs.data()).with_context(|| { + format!( + "decoding component-type in export-instance section {}", + export_instance + ) + })?; + interface.name = export_instance.to_owned(); + exports.push(interface); + } + } + _ => {} + } + } + + encoder = encoder.imports(&imports).exports(&exports); + if let Some(interface) = &interface { + encoder = encoder.interface(&interface); + } + + encoder.encode() +} diff --git a/crates/wit-component/tests/components.rs b/crates/wit-component/tests/components.rs index f2628320f..7500f1f6a 100644 --- a/crates/wit-component/tests/components.rs +++ b/crates/wit-component/tests/components.rs @@ -1,7 +1,7 @@ use anyhow::{bail, Context, Result}; use pretty_assertions::assert_eq; use std::{fs, path::Path}; -use wit_component::{decode_interface_component, ComponentEncoder, InterfaceEncoder}; +use wit_component::{transcode, ComponentEncoder, InterfaceEncoder}; use wit_parser::Interface; fn read_interface(path: &Path) -> Result { @@ -199,8 +199,6 @@ fn component_encoding_via_custom_section() -> Result<()> { let mut module = wat::parse_file(&module_path) .with_context(|| format!("expected file `{}`", module_path.display()))?; - let base_module = module.clone(); - fn encode_interface(i: &Interface, module: &mut Vec, kind: &str) -> Result<()> { let name = &format!("component-type:{}:{}", kind, i.name); let contents = InterfaceEncoder::new(&i).validate(true).encode()?; @@ -226,53 +224,8 @@ fn component_encoding_via_custom_section() -> Result<()> { // Everything is now encoded into `module`: now lets deconstruct it - let mut encoder = ComponentEncoder::default() - .module(&base_module) - .validate(true); - - let mut interface = None; - let mut imports = Vec::new(); - let mut exports = Vec::new(); - for payload in wasmparser::Parser::new(0).parse_all(&module) { - match payload.context("decoding item in module")? { - wasmparser::Payload::CustomSection(cs) => { - if let Some(export) = cs.name().strip_prefix("component-type:export:") { - let mut i = decode_interface_component(cs.data()).with_context(|| { - format!("decoding component-type in export section {}", export) - })?; - i.name = export.to_owned(); - interface = Some(i); - } else if let Some(import) = cs.name().strip_prefix("component-type:import:") { - let mut interface = - decode_interface_component(cs.data()).with_context(|| { - format!("decoding component-type in import section {}", import) - })?; - interface.name = import.to_owned(); - imports.push(interface); - } else if let Some(export_instance) = - cs.name().strip_prefix("component-type:export-instance:") - { - let mut interface = - decode_interface_component(cs.data()).with_context(|| { - format!( - "decoding component-type in export-instance section {}", - export_instance - ) - })?; - interface.name = export_instance.to_owned(); - exports.push(interface); - } - } - _ => {} - } - } - - encoder = encoder.imports(&imports).exports(&exports); - if let Some(interface) = &interface { - encoder = encoder.interface(&interface); - } + let r = transcode(&module); - let r = encoder.encode(); let (output, baseline_path) = if error_path.is_file() { match r { Ok(_) => bail!("encoding should fail for test case `{}`", test_case), From 672f4eba94a956251fe769c03e0e079c4ce1de0c Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Thu, 29 Sep 2022 16:32:57 -0700 Subject: [PATCH 05/12] gen-guest-rust can emit custom component-type section --- Cargo.lock | 1 + crates/gen-guest-rust/Cargo.toml | 1 + crates/gen-guest-rust/src/lib.rs | 18 ++++++++++++++++++ 3 files changed, 20 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index ecbbf57c0..428d6b7bf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2046,6 +2046,7 @@ dependencies = [ "wit-bindgen-core", "wit-bindgen-gen-rust-lib", "wit-bindgen-guest-rust", + "wit-component", ] [[package]] diff --git a/crates/gen-guest-rust/Cargo.toml b/crates/gen-guest-rust/Cargo.toml index 905eed65c..e79a16add 100644 --- a/crates/gen-guest-rust/Cargo.toml +++ b/crates/gen-guest-rust/Cargo.toml @@ -11,6 +11,7 @@ doctest = false [dependencies] wit-bindgen-core = { workspace = true } wit-bindgen-gen-rust-lib = { workspace = true } +wit-component = { workspace = true } heck = { workspace = true } clap = { workspace = true, optional = true } diff --git a/crates/gen-guest-rust/src/lib.rs b/crates/gen-guest-rust/src/lib.rs index 99c948d31..61b4e3822 100644 --- a/crates/gen-guest-rust/src/lib.rs +++ b/crates/gen-guest-rust/src/lib.rs @@ -456,6 +456,24 @@ impl Generator for RustWasm { )); } + if let Ok(component_type) = wit_component::InterfaceEncoder::new(iface).encode() { + let direction = match dir { + Direction::Import => "import", + Direction::Export => "export", + }; + let iface_name = &iface.name; + + self.src.push_str("#[cfg(target_arch = \"wasm32\")]\n"); + self.src.push_str(&format!( + "#[link_section = \"component-type:{direction}:{iface_name}\"]\n" + )); + self.src.push_str(&format!( + "const __WIT_BINDGEN_COMPONENT_TYPE: [u8; {}] = ", + component_type.len() + )); + self.src.push_str(&format!("{:?};\n", component_type)); + } + // For standalone generation, close the export! macro if self.opts.standalone && dir == Direction::Export { self.src.push_str("});\n"); From f8264fbb4e9afe99be41827f8a48c9dacc38218e Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Thu, 29 Sep 2022 17:03:54 -0700 Subject: [PATCH 06/12] custom section takes a pub static, not a const --- crates/gen-guest-rust/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/gen-guest-rust/src/lib.rs b/crates/gen-guest-rust/src/lib.rs index 61b4e3822..1e7ab099a 100644 --- a/crates/gen-guest-rust/src/lib.rs +++ b/crates/gen-guest-rust/src/lib.rs @@ -468,7 +468,7 @@ impl Generator for RustWasm { "#[link_section = \"component-type:{direction}:{iface_name}\"]\n" )); self.src.push_str(&format!( - "const __WIT_BINDGEN_COMPONENT_TYPE: [u8; {}] = ", + "pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; {}] = ", component_type.len() )); self.src.push_str(&format!("{:?};\n", component_type)); From 4711e5850b98dba55629efaa5a7d3d40926170a6 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Mon, 3 Oct 2022 17:09:07 -0700 Subject: [PATCH 07/12] ComponentEncoder needs to own its Interfaces so that I can use the Interfaces decoded from the module's custom section --- crates/wit-component/src/encoding.rs | 23 +++++++++++++---------- crates/wit-component/src/validation.rs | 2 +- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/crates/wit-component/src/encoding.rs b/crates/wit-component/src/encoding.rs index b236915b6..1b4f42fbd 100644 --- a/crates/wit-component/src/encoding.rs +++ b/crates/wit-component/src/encoding.rs @@ -2097,9 +2097,9 @@ impl<'a> ImportEncoder<'a> { pub struct ComponentEncoder<'a> { module: &'a [u8], encoding: StringEncoding, - interface: Option<&'a Interface>, - imports: &'a [Interface], - exports: &'a [Interface], + interface: Option, + imports: Vec, + exports: Vec, validate: bool, types_only: bool, adapters: IndexMap<&'a str, (&'a [u8], &'a Interface)>, @@ -2126,19 +2126,23 @@ impl<'a> ComponentEncoder<'a> { /// Set the default interface exported by the component. pub fn interface(mut self, interface: &'a Interface) -> Self { - self.interface = Some(interface); + self.interface = Some(interface.clone()); self } /// Set the interfaces the component imports. pub fn imports(mut self, imports: &'a [Interface]) -> Self { - self.imports = imports; + for i in imports { + self.imports.push(i.clone()) + } self } /// Set the interfaces the component exports. pub fn exports(mut self, exports: &'a [Interface]) -> Self { - self.exports = exports; + for e in exports { + self.exports.push(e.clone()) + } self } @@ -2171,8 +2175,8 @@ impl<'a> ComponentEncoder<'a> { validate_module( self.module, &self.interface, - self.imports, - self.exports, + &self.imports, + &self.exports, &adapters, )? } else { @@ -2182,7 +2186,6 @@ impl<'a> ComponentEncoder<'a> { let exports = self .interface .iter() - .copied() .map(|i| (i, true)) .chain(self.exports.iter().map(|i| (i, false))); @@ -2190,7 +2193,7 @@ impl<'a> ComponentEncoder<'a> { let mut types = TypeEncoder::default(); let mut imports = ImportEncoder::default(); types.encode_func_types(exports.clone(), false)?; - types.encode_instance_imports(self.imports, &info, &mut imports)?; + types.encode_instance_imports(&self.imports, &info, &mut imports)?; if self.types_only { if !self.module.is_empty() { diff --git a/crates/wit-component/src/validation.rs b/crates/wit-component/src/validation.rs index d42fc16ce..d309f1803 100644 --- a/crates/wit-component/src/validation.rs +++ b/crates/wit-component/src/validation.rs @@ -86,7 +86,7 @@ pub struct ValidatedModule<'a> { /// for this module. pub fn validate_module<'a>( bytes: &'a [u8], - interface: &Option<&Interface>, + interface: &Option, imports: &[Interface], exports: &[Interface], adapters: &IndexSet<&str>, From 63e4b4c96c772fb261b1d92ec7c6a89ae4bc1c4b Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Mon, 3 Oct 2022 18:24:13 -0700 Subject: [PATCH 08/12] make ComponentEncoder always transcode component-type info from custom sections --- crates/wit-component/src/cli.rs | 59 ++++++++++-------------- crates/wit-component/src/encoding.rs | 39 +++++++++++++++- crates/wit-component/src/lib.rs | 2 - crates/wit-component/src/transcode.rs | 52 --------------------- crates/wit-component/tests/components.rs | 49 ++++++++++---------- 5 files changed, 86 insertions(+), 115 deletions(-) delete mode 100644 crates/wit-component/src/transcode.rs diff --git a/crates/wit-component/src/cli.rs b/crates/wit-component/src/cli.rs index 83ea31dd6..e0d375b1e 100644 --- a/crates/wit-component/src/cli.rs +++ b/crates/wit-component/src/cli.rs @@ -3,7 +3,7 @@ #![deny(missing_docs)] use crate::{ - decode_interface_component, transcode, ComponentEncoder, InterfaceEncoder, InterfacePrinter, + decode_interface_component, ComponentEncoder, InterfaceEncoder, InterfacePrinter, StringEncoding, }; use anyhow::{bail, Context, Result}; @@ -109,11 +109,6 @@ pub struct WitComponentApp { #[clap(long)] pub skip_validation: bool, - /// Transcode the WebAssembly module into a Component using only the interface definitions - /// found in custom sections. - #[clap(long)] - pub transcode: bool, - /// The expected string encoding format for the component. /// Supported values are: `utf8` (default), `utf16`, and `compact-utf16`. #[clap(long, value_name = "ENCODING")] @@ -143,34 +138,30 @@ impl WitComponentApp { let module = wat::parse_file(&self.module) .with_context(|| format!("failed to parse module `{}`", self.module.display()))?; - let bytes = if self.transcode { - transcode(&module)? - } else { - let mut encoder = ComponentEncoder::default() - .module(&module) - .imports(&self.imports) - .exports(&self.exports) - .validate(!self.skip_validation); - - for (name, wasm, interface) in self.adapters.iter() { - encoder = encoder.adapter(name, wasm, interface); - } - - if let Some(interface) = &self.interface { - encoder = encoder.interface(interface); - } - - if let Some(encoding) = &self.encoding { - encoder = encoder.encoding(*encoding); - } - - encoder.encode().with_context(|| { - format!( - "failed to encode a component from module `{}`", - self.module.display() - ) - })? - }; + let mut encoder = ComponentEncoder::default() + .module(&module)? + .imports(&self.imports) + .exports(&self.exports) + .validate(!self.skip_validation); + + for (name, wasm, interface) in self.adapters.iter() { + encoder = encoder.adapter(name, wasm, interface); + } + + if let Some(interface) = &self.interface { + encoder = encoder.interface(interface); + } + + if let Some(encoding) = &self.encoding { + encoder = encoder.encoding(*encoding); + } + + let bytes = encoder.encode().with_context(|| { + format!( + "failed to encode a component from module `{}`", + self.module.display() + ) + })?; std::fs::write(&output, bytes) .with_context(|| format!("failed to write output file `{}`", output.display()))?; diff --git a/crates/wit-component/src/encoding.rs b/crates/wit-component/src/encoding.rs index 1b4f42fbd..afa080c0c 100644 --- a/crates/wit-component/src/encoding.rs +++ b/crates/wit-component/src/encoding.rs @@ -53,6 +53,7 @@ //! component model. use crate::{ + decode_interface_component, validation::{ expected_export_name, validate_adapter_module, validate_module, ValidatedAdapter, ValidatedModule, @@ -2107,9 +2108,43 @@ pub struct ComponentEncoder<'a> { impl<'a> ComponentEncoder<'a> { /// Set the core module to encode as a component. - pub fn module(mut self, module: &'a [u8]) -> Self { + /// This method will also parse any component type information stored in custom sections + /// inside the module, and add them as the interface, imports, and exports. + pub fn module(mut self, module: &'a [u8]) -> Result { + for payload in wasmparser::Parser::new(0).parse_all(&module) { + match payload.context("decoding item in module")? { + wasmparser::Payload::CustomSection(cs) => { + if let Some(export) = cs.name().strip_prefix("component-type:export:") { + let mut i = decode_interface_component(cs.data()).with_context(|| { + format!("decoding component-type in export section {}", export) + })?; + i.name = export.to_owned(); + self.interface = Some(i); + } else if let Some(import) = cs.name().strip_prefix("component-type:import:") { + let mut i = decode_interface_component(cs.data()).with_context(|| { + format!("decoding component-type in import section {}", import) + })?; + i.name = import.to_owned(); + self.imports.push(i); + } else if let Some(export_instance) = + cs.name().strip_prefix("component-type:export-instance:") + { + let mut i = decode_interface_component(cs.data()).with_context(|| { + format!( + "decoding component-type in export-instance section {}", + export_instance + ) + })?; + i.name = export_instance.to_owned(); + self.exports.push(i); + } + } + _ => {} + } + } + self.module = module; - self + Ok(self) } /// Set the string encoding expected by the core module. diff --git a/crates/wit-component/src/lib.rs b/crates/wit-component/src/lib.rs index f65b17996..a1f51744e 100644 --- a/crates/wit-component/src/lib.rs +++ b/crates/wit-component/src/lib.rs @@ -13,12 +13,10 @@ mod decoding; mod encoding; mod gc; mod printing; -mod transcode; mod validation; pub use encoding::*; pub use printing::*; -pub use transcode::*; /// Supported string encoding formats. #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] diff --git a/crates/wit-component/src/transcode.rs b/crates/wit-component/src/transcode.rs deleted file mode 100644 index 368ddfa39..000000000 --- a/crates/wit-component/src/transcode.rs +++ /dev/null @@ -1,52 +0,0 @@ -use crate::{decode_interface_component, ComponentEncoder}; -use anyhow::{Context, Result}; -use wasmparser::{Parser, Payload}; - -/// Transcode a core Module containing Component types in custom sections into a Component. -pub fn transcode(module: &[u8]) -> Result> { - let mut encoder = ComponentEncoder::default().module(&module).validate(true); - - let mut interface = None; - let mut imports = Vec::new(); - let mut exports = Vec::new(); - for payload in Parser::new(0).parse_all(&module) { - match payload.context("decoding item in module")? { - Payload::CustomSection(cs) => { - if let Some(export) = cs.name().strip_prefix("component-type:export:") { - let mut i = decode_interface_component(cs.data()).with_context(|| { - format!("decoding component-type in export section {}", export) - })?; - i.name = export.to_owned(); - interface = Some(i); - } else if let Some(import) = cs.name().strip_prefix("component-type:import:") { - let mut interface = - decode_interface_component(cs.data()).with_context(|| { - format!("decoding component-type in import section {}", import) - })?; - interface.name = import.to_owned(); - imports.push(interface); - } else if let Some(export_instance) = - cs.name().strip_prefix("component-type:export-instance:") - { - let mut interface = - decode_interface_component(cs.data()).with_context(|| { - format!( - "decoding component-type in export-instance section {}", - export_instance - ) - })?; - interface.name = export_instance.to_owned(); - exports.push(interface); - } - } - _ => {} - } - } - - encoder = encoder.imports(&imports).exports(&exports); - if let Some(interface) = &interface { - encoder = encoder.interface(&interface); - } - - encoder.encode() -} diff --git a/crates/wit-component/tests/components.rs b/crates/wit-component/tests/components.rs index 7500f1f6a..31040c8e8 100644 --- a/crates/wit-component/tests/components.rs +++ b/crates/wit-component/tests/components.rs @@ -1,7 +1,7 @@ use anyhow::{bail, Context, Result}; use pretty_assertions::assert_eq; use std::{fs, path::Path}; -use wit_component::{transcode, ComponentEncoder, InterfaceEncoder}; +use wit_component::{ComponentEncoder, InterfaceEncoder}; use wit_parser::Interface; fn read_interface(path: &Path) -> Result { @@ -105,7 +105,7 @@ fn component_encoding_via_flags() -> Result<()> { let adapters = read_adapters(&path)?; let mut encoder = ComponentEncoder::default() - .module(&module) + .module(&module)? .imports(&imports) .exports(&exports) .validate(true); @@ -119,6 +119,7 @@ fn component_encoding_via_flags() -> Result<()> { } let r = encoder.encode(); + let (output, baseline_path) = if error_path.is_file() { match r { Ok(_) => bail!("encoding should fail for test case `{}`", test_case), @@ -157,30 +158,20 @@ fn component_encoding_via_flags() -> Result<()> { /// Tests the encoding of components. /// -/// This test looks in the `components/` directory for test cases. -/// -/// The expected input files for a test case are: -/// -/// * [required] `module.wat` - contains the core module definition to be encoded -/// as a component. -/// * [optional] `default.wit` - represents the component's default interface. -/// * [optional] `export-.wit` - represents an interface exported by the component. -/// * [optional] `import-.wit` - represents an interface imported by the component. +/// This test looks in the `components/` directory for test cases. It parses +/// the inputs to the test out of that directly exactly like +/// `component_encoding_via_flags` does in this same file. /// -/// And the output files are one of the following: +/// Rather than pass the default interface, imports, and exports directly to +/// the `ComponentEncoder`, this test encodes those Interfaces as component +/// types in custom sections of the wasm Module. /// -/// * `component.wat` - the expected encoded component in text format if the encoding -/// is expected to succeed. -/// * `error.txt` - the expected error message if the encoding is expected to fail. -/// -/// The test encodes a component based on the input files. If the encoding succeeds, -/// it expects the output to match `component.wat`. If the encoding fails, it expects -/// the output to match `error.txt`. -/// -/// Run the test with the environment variable `BLESS` set to update -/// either `component.wat` or `error.txt` depending on the outcome of the encoding. +/// This simulates the flow that toolchains which don't yet know how to +/// emit a Component will emit a canonical ABI Module containing these custom sections, +/// and those will then be translated by wit-component to a Component without +/// needing the wit files passed in as well. #[test] -fn component_encoding_via_custom_section() -> Result<()> { +fn component_encoding_via_custom_sections() -> Result<()> { use wasm_encoder::{Encode, Section}; for entry in fs::read_dir("tests/components")? { @@ -211,6 +202,8 @@ fn component_encoding_via_custom_section() -> Result<()> { Ok(()) } + // Encode the interface, exports, and imports into the module, instead of + // passing them to the ComponentEncoder explicitly. if interface_path.is_file() { let i = read_interface(&interface_path)?; encode_interface(&i, &mut module, "export")?; @@ -221,10 +214,16 @@ fn component_encoding_via_custom_section() -> Result<()> { for i in read_interfaces(&path, "export-*.wit")? { encode_interface(&i, &mut module, "export-instance")?; } + // + let adapters = read_adapters(&path)?; + + let mut encoder = ComponentEncoder::default().module(&module)?.validate(true); - // Everything is now encoded into `module`: now lets deconstruct it + for (name, wasm, interface) in adapters.iter() { + encoder = encoder.adapter(name, wasm, interface); + } - let r = transcode(&module); + let r = encoder.encode(); let (output, baseline_path) = if error_path.is_file() { match r { From 939afb61f03c8f731a590e12885a33153253cb86 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Mon, 3 Oct 2022 22:41:15 -0700 Subject: [PATCH 09/12] flavorful tests: types and functions are actually the same namespace theyre not in wit, but thats a bug we need to fix, because they are in component types --- tests/runtime/flavorful/exports.wit | 14 +++++++------- tests/runtime/flavorful/host.py | 28 ++++++++++++++-------------- tests/runtime/flavorful/host.rs | 28 ++++++++++++++-------------- tests/runtime/flavorful/host.ts | 28 ++++++++++++++-------------- tests/runtime/flavorful/imports.wit | 14 +++++++------- tests/runtime/flavorful/wasm.c | 28 ++++++++++++++-------------- tests/runtime/flavorful/wasm.rs | 28 ++++++++++++++-------------- 7 files changed, 84 insertions(+), 84 deletions(-) diff --git a/tests/runtime/flavorful/exports.wit b/tests/runtime/flavorful/exports.wit index be79aace7..558acb826 100644 --- a/tests/runtime/flavorful/exports.wit +++ b/tests/runtime/flavorful/exports.wit @@ -6,21 +6,21 @@ record list-in-record3 { a: string } record list-in-record4 { a: string } type list-in-alias = list-in-record4 -list-in-record1: func(a: list-in-record1) -list-in-record2: func() -> list-in-record2 -list-in-record3: func(a: list-in-record3) -> list-in-record3 -list-in-record4: func(a: list-in-alias) -> list-in-alias +f-list-in-record1: func(a: list-in-record1) +f-list-in-record2: func() -> list-in-record2 +f-list-in-record3: func(a: list-in-record3) -> list-in-record3 +f-list-in-record4: func(a: list-in-alias) -> list-in-alias type list-in-variant1-v1 = option type list-in-variant1-v2 = result<_, string> union list-in-variant1-v3 { string, float32 } -list-in-variant1: func(a: list-in-variant1-v1, b: list-in-variant1-v2, c: list-in-variant1-v3) +f-list-in-variant1: func(a: list-in-variant1-v1, b: list-in-variant1-v2, c: list-in-variant1-v3) type list-in-variant2 = option -list-in-variant2: func() -> list-in-variant2 +f-list-in-variant2: func() -> list-in-variant2 type list-in-variant3 = option -list-in-variant3: func(a: list-in-variant3) -> list-in-variant3 +f-list-in-variant3: func(a: list-in-variant3) -> list-in-variant3 enum my-errno { success, a, b } errno-result: func() -> result<_, my-errno> diff --git a/tests/runtime/flavorful/host.py b/tests/runtime/flavorful/host.py index 010e03840..355404caf 100644 --- a/tests/runtime/flavorful/host.py +++ b/tests/runtime/flavorful/host.py @@ -7,29 +7,29 @@ import wasmtime class MyImports: - def list_in_record1(self, a: i.ListInRecord1) -> None: + def f_list_in_record1(self, a: i.ListInRecord1) -> None: pass - def list_in_record2(self) -> i.ListInRecord2: + def f_list_in_record2(self) -> i.ListInRecord2: return i.ListInRecord2('list_in_record2') - def list_in_record3(self, a: i.ListInRecord3) -> i.ListInRecord3: + def f_list_in_record3(self, a: i.ListInRecord3) -> i.ListInRecord3: assert(a.a == 'list_in_record3 input') return i.ListInRecord3('list_in_record3 output') - def list_in_record4(self, a: i.ListInAlias) -> i.ListInAlias: + def f_list_in_record4(self, a: i.ListInAlias) -> i.ListInAlias: assert(a.a == 'input4') return i.ListInRecord4('result4') - def list_in_variant1(self, a: i.ListInVariant1V1, b: i.ListInVariant1V2, c: i.ListInVariant1V3) -> None: + def f_list_in_variant1(self, a: i.ListInVariant1V1, b: i.ListInVariant1V2, c: i.ListInVariant1V3) -> None: assert(a == 'foo') assert(b == i.Err('bar')) assert(c == 'baz') - def list_in_variant2(self) -> i.ListInVariant2: + def f_list_in_variant2(self) -> i.ListInVariant2: return 'list_in_variant2' - def list_in_variant3(self, a: i.ListInVariant3) -> i.ListInVariant3: + def f_list_in_variant3(self, a: i.ListInVariant3) -> i.ListInVariant3: assert(a == 'input3') return 'output3' @@ -66,15 +66,15 @@ def run(wasm_file: str) -> None: wasm = Exports(store, linker, module) wasm.test_imports(store) - wasm.list_in_record1(store, e.ListInRecord1("list_in_record1")) - assert(wasm.list_in_record2(store) == e.ListInRecord2(a="list_in_record2")) + wasm.f_list_in_record1(store, e.ListInRecord1("list_in_record1")) + assert(wasm.f_list_in_record2(store) == e.ListInRecord2(a="list_in_record2")) - assert(wasm.list_in_record3(store, e.ListInRecord3("list_in_record3 input")).a == "list_in_record3 output") - assert(wasm.list_in_record4(store, e.ListInRecord4("input4")).a == "result4") + assert(wasm.f_list_in_record3(store, e.ListInRecord3("list_in_record3 input")).a == "list_in_record3 output") + assert(wasm.f_list_in_record4(store, e.ListInRecord4("input4")).a == "result4") - wasm.list_in_variant1(store, "foo", e.Err("bar"), 'baz') - assert(wasm.list_in_variant2(store) == "list_in_variant2") - assert(wasm.list_in_variant3(store, "input3") == "output3") + wasm.f_list_in_variant1(store, "foo", e.Err("bar"), 'baz') + assert(wasm.f_list_in_variant2(store) == "list_in_variant2") + assert(wasm.f_list_in_variant3(store, "input3") == "output3") assert(isinstance(wasm.errno_result(store), e.Err)) diff --git a/tests/runtime/flavorful/host.rs b/tests/runtime/flavorful/host.rs index a4b192041..9c72b5aba 100644 --- a/tests/runtime/flavorful/host.rs +++ b/tests/runtime/flavorful/host.rs @@ -8,31 +8,31 @@ use imports::*; pub struct MyImports; impl Imports for MyImports { - fn list_in_record1(&mut self, ty: ListInRecord1<'_>) { + fn f_list_in_record1(&mut self, ty: ListInRecord1<'_>) { assert_eq!(ty.a, "list_in_record1"); } - fn list_in_record2(&mut self) -> ListInRecord2 { + fn f_list_in_record2(&mut self) -> ListInRecord2 { ListInRecord2 { a: "list_in_record2".to_string(), } } - fn list_in_record3(&mut self, a: ListInRecord3Param<'_>) -> ListInRecord3Result { + fn f_list_in_record3(&mut self, a: ListInRecord3Param<'_>) -> ListInRecord3Result { assert_eq!(a.a, "list_in_record3 input"); ListInRecord3Result { a: "list_in_record3 output".to_string(), } } - fn list_in_record4(&mut self, a: ListInAliasParam<'_>) -> ListInAliasResult { + fn f_list_in_record4(&mut self, a: ListInAliasParam<'_>) -> ListInAliasResult { assert_eq!(a.a, "input4"); ListInRecord4Result { a: "result4".to_string(), } } - fn list_in_variant1( + fn f_list_in_variant1( &mut self, a: ListInVariant1V1<'_>, b: ListInVariant1V2<'_>, @@ -46,11 +46,11 @@ impl Imports for MyImports { } } - fn list_in_variant2(&mut self) -> Option { + fn f_list_in_variant2(&mut self) -> Option { Some("list_in_variant2".to_string()) } - fn list_in_variant3(&mut self, a: ListInVariant3Param<'_>) -> Option { + fn f_list_in_variant3(&mut self, a: ListInVariant3Param<'_>) -> Option { assert_eq!(a.unwrap(), "input3"); Some("output3".to_string()) } @@ -104,17 +104,17 @@ fn run(wasm: &str) -> Result<()> { exports.test_imports(&mut store)?; - exports.list_in_record1( + exports.f_list_in_record1( &mut store, ListInRecord1 { a: "list_in_record1", }, )?; - assert_eq!(exports.list_in_record2(&mut store)?.a, "list_in_record2"); + assert_eq!(exports.f_list_in_record2(&mut store)?.a, "list_in_record2"); assert_eq!( exports - .list_in_record3( + .f_list_in_record3( &mut store, ListInRecord3Param { a: "list_in_record3 input" @@ -126,23 +126,23 @@ fn run(wasm: &str) -> Result<()> { assert_eq!( exports - .list_in_record4(&mut store, ListInAliasParam { a: "input4" })? + .f_list_in_record4(&mut store, ListInAliasParam { a: "input4" })? .a, "result4" ); - exports.list_in_variant1( + exports.f_list_in_variant1( &mut store, Some("foo"), Err("bar"), ListInVariant1V3::String("baz"), )?; assert_eq!( - exports.list_in_variant2(&mut store)?, + exports.f_list_in_variant2(&mut store)?, Some("list_in_variant2".to_string()) ); assert_eq!( - exports.list_in_variant3(&mut store, Some("input3"))?, + exports.f_list_in_variant3(&mut store, Some("input3"))?, Some("output3".to_string()) ); diff --git a/tests/runtime/flavorful/host.ts b/tests/runtime/flavorful/host.ts index 1548505e8..277b288cb 100644 --- a/tests/runtime/flavorful/host.ts +++ b/tests/runtime/flavorful/host.ts @@ -8,23 +8,23 @@ import * as assert from 'assert'; async function run() { const importObj = {}; const imports: Imports = { - listInRecord1(x) {}, - listInRecord2() { return { a: 'list_in_record2' }; }, - listInRecord3(x) { + fListInRecord1(x) {}, + fListInRecord2() { return { a: 'list_in_record2' }; }, + fListInRecord3(x) { assert.strictEqual(x.a, 'list_in_record3 input'); return { a: 'list_in_record3 output' }; }, - listInRecord4(x) { + fListInRecord4(x) { assert.strictEqual(x.a, 'input4'); return { a: 'result4' }; }, - listInVariant1(a, b, c) { + fListInVariant1(a, b, c) { assert.strictEqual(a, 'foo'); assert.deepStrictEqual(b, { tag: 'err', val: 'bar' }); assert.deepStrictEqual(c, { tag: 0, val: 'baz' }); }, - listInVariant2() { return 'list_in_variant2'; }, - listInVariant3(x) { + fListInVariant2() { return 'list_in_variant2'; }, + fListInVariant3(x) { assert.strictEqual(x, 'input3'); return 'output3'; }, @@ -57,23 +57,23 @@ async function run() { instance = wasm.instance; wasm.testImports(); - wasm.listInRecord1({ a: "list_in_record1" }); - assert.deepStrictEqual(wasm.listInRecord2(), { a: "list_in_record2" }); + wasm.fListInRecord1({ a: "list_in_record1" }); + assert.deepStrictEqual(wasm.fListInRecord2(), { a: "list_in_record2" }); assert.deepStrictEqual( - wasm.listInRecord3({ a: "list_in_record3 input" }), + wasm.fListInRecord3({ a: "list_in_record3 input" }), { a: "list_in_record3 output" }, ); assert.deepStrictEqual( - wasm.listInRecord4({ a: "input4" }), + wasm.fListInRecord4({ a: "input4" }), { a: "result4" }, ); - wasm.listInVariant1("foo", { tag: 'err', val: 'bar' }, { tag: 0, val: 'baz' }); + wasm.fListInVariant1("foo", { tag: 'err', val: 'bar' }, { tag: 0, val: 'baz' }); - assert.deepStrictEqual(wasm.listInVariant2(), "list_in_variant2"); - assert.deepStrictEqual(wasm.listInVariant3("input3"), "output3"); + assert.deepStrictEqual(wasm.fListInVariant2(), "list_in_variant2"); + assert.deepStrictEqual(wasm.fListInVariant3("input3"), "output3"); assert.deepStrictEqual(wasm.errnoResult().tag, 'err'); diff --git a/tests/runtime/flavorful/imports.wit b/tests/runtime/flavorful/imports.wit index 242d95433..d2b92dca0 100644 --- a/tests/runtime/flavorful/imports.wit +++ b/tests/runtime/flavorful/imports.wit @@ -4,21 +4,21 @@ record list-in-record3 { a: string } record list-in-record4 { a: string } type list-in-alias = list-in-record4 -list-in-record1: func(a: list-in-record1) -list-in-record2: func() -> list-in-record2 -list-in-record3: func(a: list-in-record3) -> list-in-record3 -list-in-record4: func(a: list-in-alias) -> list-in-alias +f-list-in-record1: func(a: list-in-record1) +f-list-in-record2: func() -> list-in-record2 +f-list-in-record3: func(a: list-in-record3) -> list-in-record3 +f-list-in-record4: func(a: list-in-alias) -> list-in-alias type list-in-variant1-v1 = option type list-in-variant1-v2 = result<_, string> union list-in-variant1-v3 { string, float32 } -list-in-variant1: func(a: list-in-variant1-v1, b: list-in-variant1-v2, c: list-in-variant1-v3) +f-list-in-variant1: func(a: list-in-variant1-v1, b: list-in-variant1-v2, c: list-in-variant1-v3) type list-in-variant2 = option -list-in-variant2: func() -> list-in-variant2 +f-list-in-variant2: func() -> list-in-variant2 type list-in-variant3 = option -list-in-variant3: func(a: list-in-variant3) -> list-in-variant3 +f-list-in-variant3: func(a: list-in-variant3) -> list-in-variant3 enum my-errno { success, a, b } errno-result: func() -> result<_, my-errno> diff --git a/tests/runtime/flavorful/wasm.c b/tests/runtime/flavorful/wasm.c index 360809bc3..0ea2c62e1 100644 --- a/tests/runtime/flavorful/wasm.c +++ b/tests/runtime/flavorful/wasm.c @@ -8,10 +8,10 @@ void exports_test_imports() { { imports_list_in_record1_t a; imports_string_set(&a.a, "list_in_record1"); - imports_list_in_record1(&a); + imports_f_list_in_record1(&a); imports_list_in_record2_t b; - imports_list_in_record2(&b); + imports_f_list_in_record2(&b); assert(memcmp(b.a.ptr, "list_in_record2", b.a.len) == 0); imports_list_in_record2_free(&b); } @@ -19,7 +19,7 @@ void exports_test_imports() { { imports_list_in_record3_t a, b; imports_string_set(&a.a, "list_in_record3 input"); - imports_list_in_record3(&a, &b); + imports_f_list_in_record3(&a, &b); assert(memcmp(b.a.ptr, "list_in_record3 output", b.a.len) == 0); imports_list_in_record3_free(&b); } @@ -27,7 +27,7 @@ void exports_test_imports() { { imports_list_in_record4_t a, b; imports_string_set(&a.a, "input4"); - imports_list_in_record4(&a, &b); + imports_f_list_in_record4(&a, &b); assert(memcmp(b.a.ptr, "result4", b.a.len) == 0); imports_list_in_record4_free(&b); } @@ -42,12 +42,12 @@ void exports_test_imports() { imports_string_set(&b.val.err, "bar"); c.tag = 0; imports_string_set(&c.val.f0, "baz"); - imports_list_in_variant1(&a, &b, &c); + imports_f_list_in_variant1(&a, &b, &c); } { imports_string_t a; - assert(imports_list_in_variant2(&a)); + assert(imports_f_list_in_variant2(&a)); assert(memcmp(a.ptr, "list_in_variant2", a.len) == 0); imports_string_free(&a); } @@ -57,7 +57,7 @@ void exports_test_imports() { a.is_some = true; imports_string_set(&a.val, "input3"); imports_string_t b; - assert(imports_list_in_variant3(&a, &b)); + assert(imports_f_list_in_variant3(&a, &b)); assert(memcmp(b.ptr, "output3", b.len) == 0); imports_string_free(&b); } @@ -127,28 +127,28 @@ void exports_test_imports() { } } -void exports_list_in_record1(exports_list_in_record1_t *a) { +void exports_f_list_in_record1(exports_list_in_record1_t *a) { assert(memcmp(a->a.ptr, "list_in_record1", a->a.len) == 0); exports_list_in_record1_free(a); } -void exports_list_in_record2(exports_list_in_record2_t *ret0) { +void exports_f_list_in_record2(exports_list_in_record2_t *ret0) { exports_string_dup(&ret0->a, "list_in_record2"); } -void exports_list_in_record3(exports_list_in_record3_t *a, exports_list_in_record3_t *ret0) { +void exports_f_list_in_record3(exports_list_in_record3_t *a, exports_list_in_record3_t *ret0) { assert(memcmp(a->a.ptr, "list_in_record3 input", a->a.len) == 0); exports_list_in_record3_free(a); exports_string_dup(&ret0->a, "list_in_record3 output"); } -void exports_list_in_record4(exports_list_in_alias_t *a, exports_list_in_alias_t *ret0) { +void exports_f_list_in_record4(exports_list_in_alias_t *a, exports_list_in_alias_t *ret0) { assert(memcmp(a->a.ptr, "input4", a->a.len) == 0); exports_list_in_alias_free(a); exports_string_dup(&ret0->a, "result4"); } -void exports_list_in_variant1(exports_list_in_variant1_v1_t *a, exports_list_in_variant1_v2_t *b, exports_list_in_variant1_v3_t *c) { +void exports_f_list_in_variant1(exports_list_in_variant1_v1_t *a, exports_list_in_variant1_v2_t *b, exports_list_in_variant1_v3_t *c) { assert(a->is_some); assert(memcmp(a->val.ptr, "foo", a->val.len) == 0); exports_list_in_variant1_v1_free(a); @@ -162,12 +162,12 @@ void exports_list_in_variant1(exports_list_in_variant1_v1_t *a, exports_list_in_ exports_list_in_variant1_v3_free(c); } -bool exports_list_in_variant2(exports_string_t *ret0) { +bool exports_f_list_in_variant2(exports_string_t *ret0) { exports_string_dup(ret0, "list_in_variant2"); return true; } -bool exports_list_in_variant3(exports_list_in_variant3_t *a, exports_string_t *ret0) { +bool exports_f_list_in_variant3(exports_list_in_variant3_t *a, exports_string_t *ret0) { assert(a->is_some); assert(memcmp(a->val.ptr, "input3", a->val.len) == 0); exports_list_in_variant3_free(a); diff --git a/tests/runtime/flavorful/wasm.rs b/tests/runtime/flavorful/wasm.rs index 719630901..4783923d3 100644 --- a/tests/runtime/flavorful/wasm.rs +++ b/tests/runtime/flavorful/wasm.rs @@ -11,13 +11,13 @@ impl exports::Exports for Exports { let _guard = test_rust_wasm::guard(); - list_in_record1(ListInRecord1 { + f_list_in_record1(ListInRecord1 { a: "list_in_record1", }); - assert_eq!(list_in_record2().a, "list_in_record2"); + assert_eq!(f_list_in_record2().a, "list_in_record2"); assert_eq!( - list_in_record3(ListInRecord3Param { + f_list_in_record3(ListInRecord3Param { a: "list_in_record3 input" }) .a, @@ -25,14 +25,14 @@ impl exports::Exports for Exports { ); assert_eq!( - list_in_record4(ListInAliasParam { a: "input4" }).a, + f_list_in_record4(ListInAliasParam { a: "input4" }).a, "result4" ); - list_in_variant1(Some("foo"), Err("bar"), ListInVariant1V3::String("baz")); - assert_eq!(list_in_variant2(), Some("list_in_variant2".to_string())); + f_list_in_variant1(Some("foo"), Err("bar"), ListInVariant1V3::String("baz")); + assert_eq!(f_list_in_variant2(), Some("list_in_variant2".to_string())); assert_eq!( - list_in_variant3(Some("input3")), + f_list_in_variant3(Some("input3")), Some("output3".to_string()) ); @@ -57,31 +57,31 @@ impl exports::Exports for Exports { assert_eq!(c, [MyErrno::A, MyErrno::B]); } - fn list_in_record1(ty: ListInRecord1) { + fn f_list_in_record1(ty: ListInRecord1) { assert_eq!(ty.a, "list_in_record1"); } - fn list_in_record2() -> ListInRecord2 { + fn f_list_in_record2() -> ListInRecord2 { ListInRecord2 { a: "list_in_record2".to_string(), } } - fn list_in_record3(a: ListInRecord3) -> ListInRecord3 { + fn f_list_in_record3(a: ListInRecord3) -> ListInRecord3 { assert_eq!(a.a, "list_in_record3 input"); ListInRecord3 { a: "list_in_record3 output".to_string(), } } - fn list_in_record4(a: ListInAlias) -> ListInAlias { + fn f_list_in_record4(a: ListInAlias) -> ListInAlias { assert_eq!(a.a, "input4"); ListInRecord4 { a: "result4".to_string(), } } - fn list_in_variant1(a: ListInVariant1V1, b: ListInVariant1V2, c: ListInVariant1V3) { + fn f_list_in_variant1(a: ListInVariant1V1, b: ListInVariant1V2, c: ListInVariant1V3) { assert_eq!(a.unwrap(), "foo"); assert_eq!(b.unwrap_err(), "bar"); match c { @@ -90,11 +90,11 @@ impl exports::Exports for Exports { } } - fn list_in_variant2() -> Option { + fn f_list_in_variant2() -> Option { Some("list_in_variant2".to_string()) } - fn list_in_variant3(a: ListInVariant3) -> Option { + fn f_list_in_variant3(a: ListInVariant3) -> Option { assert_eq!(a.unwrap(), "input3"); Some("output3".to_string()) } From 4c5bc810fe562f3ed068e659b981723a73888851 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Mon, 3 Oct 2022 22:41:55 -0700 Subject: [PATCH 10/12] test-helpers: build rust guests with wasm32-unknown-unknown and assert they encode as components except for "invalid" and "handles" which are not gonna work --- crates/gen-guest-rust/src/lib.rs | 1 + crates/test-helpers/build.rs | 29 +++++++++++++++++++++++++++-- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/crates/gen-guest-rust/src/lib.rs b/crates/gen-guest-rust/src/lib.rs index 1e7ab099a..c3e3c25e3 100644 --- a/crates/gen-guest-rust/src/lib.rs +++ b/crates/gen-guest-rust/src/lib.rs @@ -456,6 +456,7 @@ impl Generator for RustWasm { )); } + // TODO make this infallible once we get rid of handle tests from the tree if let Ok(component_type) = wit_component::InterfaceEncoder::new(iface).encode() { let direction = match dir { Direction::Import => "import", diff --git a/crates/test-helpers/build.rs b/crates/test-helpers/build.rs index 93da1f183..efc7fb5c1 100644 --- a/crates/test-helpers/build.rs +++ b/crates/test-helpers/build.rs @@ -3,6 +3,7 @@ use std::fs; use std::path::PathBuf; use std::process::Command; use wit_bindgen_core::{wit_parser::Interface, Direction, Generator}; +use wit_component::ComponentEncoder; fn main() { let out_dir = PathBuf::from(std::env::var_os("OUT_DIR").unwrap()); @@ -13,14 +14,18 @@ fn main() { let mut cmd = Command::new("cargo"); cmd.arg("build") .current_dir("../test-rust-wasm") - .arg("--target=wasm32-wasi") + .arg("--target=wasm32-unknown-unknown") .env("CARGO_TARGET_DIR", &out_dir) .env("CARGO_PROFILE_DEV_DEBUG", "1") .env("RUSTFLAGS", "-Clink-args=--export-table") .env_remove("CARGO_ENCODED_RUSTFLAGS"); let status = cmd.status().unwrap(); assert!(status.success()); - for file in out_dir.join("wasm32-wasi/debug").read_dir().unwrap() { + for file in out_dir + .join("wasm32-unknown-unknown/debug") + .read_dir() + .unwrap() + { let file = file.unwrap().path(); if file.extension().and_then(|s| s.to_str()) != Some("wasm") { continue; @@ -31,6 +36,26 @@ fn main() { file.to_str().unwrap().to_string(), )); + // TODO: add an adapter for snapshot 1, and go back to compiling this target for + // wasm32-wasi + let module = fs::read(&file).expect("failed to read wasm file"); + match ComponentEncoder::default() + .module(module.as_slice()) + .expect("pull custom sections from module") + .validate(true) + .encode() + { + Ok(_) => {} + Err(e) => { + if !["invalid", "handles"] + .iter() + .any(|s| *s == file.file_stem().unwrap().to_str().unwrap()) + { + panic!("component encoder for {:?} failed: {:?}", file, e); + } + } + } + let dep_file = file.with_extension("d"); let deps = fs::read_to_string(&dep_file).expect("failed to read dep file"); for dep in deps From 2233e8b32f7b35b54ed96a260971fe721f116053 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Tue, 4 Oct 2022 16:04:02 -0700 Subject: [PATCH 11/12] refactor --- crates/test-helpers/build.rs | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/crates/test-helpers/build.rs b/crates/test-helpers/build.rs index efc7fb5c1..c8e5df3ba 100644 --- a/crates/test-helpers/build.rs +++ b/crates/test-helpers/build.rs @@ -14,6 +14,8 @@ fn main() { let mut cmd = Command::new("cargo"); cmd.arg("build") .current_dir("../test-rust-wasm") + // TODO: this should go back to wasm32-wasi once we have an adapter + // for snapshot 1 to a component .arg("--target=wasm32-unknown-unknown") .env("CARGO_TARGET_DIR", &out_dir) .env("CARGO_PROFILE_DEV_DEBUG", "1") @@ -36,24 +38,20 @@ fn main() { file.to_str().unwrap().to_string(), )); - // TODO: add an adapter for snapshot 1, and go back to compiling this target for - // wasm32-wasi - let module = fs::read(&file).expect("failed to read wasm file"); - match ComponentEncoder::default() - .module(module.as_slice()) - .expect("pull custom sections from module") - .validate(true) - .encode() - { - Ok(_) => {} - Err(e) => { - if !["invalid", "handles"] - .iter() - .any(|s| *s == file.file_stem().unwrap().to_str().unwrap()) - { - panic!("component encoder for {:?} failed: {:?}", file, e); - } - } + // The "invalid" test doesn't actually use the rust-guest macro + // and doesn't put the custom sections in, so component translation + // will fail. + if file.file_stem().unwrap().to_str().unwrap() != "invalid" { + // Validate that the module can be translated to a component, using + // the component-type custom sections. We don't yet consume this component + // anywhere. + let module = fs::read(&file).expect("failed to read wasm file"); + ComponentEncoder::default() + .module(module.as_slice()) + .expect("pull custom sections from module") + .validate(true) + .encode() + .expect("module can be translated to a component"); } let dep_file = file.with_extension("d"); From f3516015869fc2fc9313fa818ce1982cd94ce075 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Tue, 4 Oct 2022 16:27:23 -0700 Subject: [PATCH 12/12] gen-guest-rust: now infallible --- crates/gen-guest-rust/src/lib.rs | 37 +++++++++++++++++--------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/crates/gen-guest-rust/src/lib.rs b/crates/gen-guest-rust/src/lib.rs index c3e3c25e3..899a44001 100644 --- a/crates/gen-guest-rust/src/lib.rs +++ b/crates/gen-guest-rust/src/lib.rs @@ -456,24 +456,27 @@ impl Generator for RustWasm { )); } - // TODO make this infallible once we get rid of handle tests from the tree - if let Ok(component_type) = wit_component::InterfaceEncoder::new(iface).encode() { - let direction = match dir { - Direction::Import => "import", - Direction::Export => "export", - }; - let iface_name = &iface.name; - - self.src.push_str("#[cfg(target_arch = \"wasm32\")]\n"); - self.src.push_str(&format!( - "#[link_section = \"component-type:{direction}:{iface_name}\"]\n" - )); - self.src.push_str(&format!( - "pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; {}] = ", - component_type.len() + let component_type = wit_component::InterfaceEncoder::new(iface) + .encode() + .expect(&format!( + "encoding interface {} as a component type", + iface.name )); - self.src.push_str(&format!("{:?};\n", component_type)); - } + let direction = match dir { + Direction::Import => "import", + Direction::Export => "export", + }; + let iface_name = &iface.name; + + self.src.push_str("#[cfg(target_arch = \"wasm32\")]\n"); + self.src.push_str(&format!( + "#[link_section = \"component-type:{direction}:{iface_name}\"]\n" + )); + self.src.push_str(&format!( + "pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; {}] = ", + component_type.len() + )); + self.src.push_str(&format!("{:?};\n", component_type)); // For standalone generation, close the export! macro if self.opts.standalone && dir == Direction::Export {