From 5a3cfa4321e17af009e21fc6f0a18d18582d775f Mon Sep 17 00:00:00 2001 From: Christian Ivicevic Date: Sat, 7 Oct 2023 05:17:36 +0200 Subject: [PATCH 1/2] Add enum types for function parameters and return types --- crates/backend/src/codegen.rs | 5 +++++ crates/cli-support/src/descriptor.rs | 8 ++++++-- crates/cli-support/src/js/binding.rs | 1 + crates/cli-support/src/wit/incoming.rs | 15 ++++++++++++--- crates/cli-support/src/wit/outgoing.rs | 6 +++--- crates/cli-support/src/wit/standard.rs | 2 ++ crates/typescript-tests/src/enums.rs | 16 ++++++++++++++++ crates/typescript-tests/src/enums.ts | 5 +++++ 8 files changed, 50 insertions(+), 8 deletions(-) diff --git a/crates/backend/src/codegen.rs b/crates/backend/src/codegen.rs index 86a584becc8..97d0d7330f8 100644 --- a/crates/backend/src/codegen.rs +++ b/crates/backend/src/codegen.rs @@ -1382,6 +1382,9 @@ impl<'a> ToTokens for DescribeImport<'a> { impl ToTokens for ast::Enum { fn to_tokens(&self, into: &mut TokenStream) { let enum_name = &self.rust_name; + let name_str = self.js_name.to_string(); + let name_len = name_str.len() as u32; + let name_chars = name_str.chars().map(|c| c as u32).collect::>(); let hole = &self.hole; let cast_clauses = self.variants.iter().map(|variant| { let variant_name = &variant.name; @@ -1433,6 +1436,8 @@ impl ToTokens for ast::Enum { fn describe() { use #wasm_bindgen::describe::*; inform(ENUM); + inform(#name_len); + #(inform(#name_chars);)* inform(#hole); } } diff --git a/crates/cli-support/src/descriptor.rs b/crates/cli-support/src/descriptor.rs index 6f7a6ceef42..e21dae1ed29 100644 --- a/crates/cli-support/src/descriptor.rs +++ b/crates/cli-support/src/descriptor.rs @@ -66,7 +66,7 @@ pub enum Descriptor { String, Externref, NamedExternref(String), - Enum { hole: u32 }, + Enum { name: String, hole: u32 }, RustStruct(String), Char, Option(Box), @@ -149,7 +149,11 @@ impl Descriptor { CACHED_STRING => Descriptor::CachedString, STRING => Descriptor::String, EXTERNREF => Descriptor::Externref, - ENUM => Descriptor::Enum { hole: get(data) }, + ENUM => { + let name = get_string(data); + let hole = get(data); + Descriptor::Enum { name, hole } + } RUST_STRUCT => { let name = get_string(data); Descriptor::RustStruct(name) diff --git a/crates/cli-support/src/js/binding.rs b/crates/cli-support/src/js/binding.rs index c86927c6e8b..76b61b42f86 100644 --- a/crates/cli-support/src/js/binding.rs +++ b/crates/cli-support/src/js/binding.rs @@ -1336,6 +1336,7 @@ fn adapter2ts(ty: &AdapterType, dst: &mut String) { } AdapterType::NamedExternref(name) => dst.push_str(name), AdapterType::Struct(name) => dst.push_str(name), + AdapterType::Enum(name) => dst.push_str(name), AdapterType::Function => dst.push_str("any"), } } diff --git a/crates/cli-support/src/wit/incoming.rs b/crates/cli-support/src/wit/incoming.rs index 483185ce627..b42541791eb 100644 --- a/crates/cli-support/src/wit/incoming.rs +++ b/crates/cli-support/src/wit/incoming.rs @@ -98,7 +98,16 @@ impl InstructionBuilder<'_, '_> { self.get(AdapterType::F64); self.output.push(AdapterType::F64); } - Descriptor::Enum { .. } => self.number(AdapterType::U32, WasmVT::I32), + Descriptor::Enum { name, .. } => { + self.instruction( + &[AdapterType::Enum(name.clone())], + Instruction::IntToWasm { + input: AdapterType::U32, + output: ValType::I32, + }, + &[AdapterType::I32], + ); + }, Descriptor::Ref(d) => self.incoming_ref(false, d)?, Descriptor::RefMut(d) => self.incoming_ref(true, d)?, Descriptor::Option(d) => self.incoming_option(d)?, @@ -274,9 +283,9 @@ impl InstructionBuilder<'_, '_> { &[AdapterType::I32], ); } - Descriptor::Enum { hole } => { + Descriptor::Enum { name, hole } => { self.instruction( - &[AdapterType::U32.option()], + &[AdapterType::Enum(name.clone()).option()], Instruction::I32FromOptionEnum { hole: *hole }, &[AdapterType::I32], ); diff --git a/crates/cli-support/src/wit/outgoing.rs b/crates/cli-support/src/wit/outgoing.rs index d90dcd3f5ee..41763bdbe00 100644 --- a/crates/cli-support/src/wit/outgoing.rs +++ b/crates/cli-support/src/wit/outgoing.rs @@ -73,7 +73,7 @@ impl InstructionBuilder<'_, '_> { self.get(AdapterType::F64); self.output.push(AdapterType::F64); } - Descriptor::Enum { .. } => self.outgoing_i32(AdapterType::U32), + Descriptor::Enum { name, .. } => self.outgoing_i32(AdapterType::Enum(name.clone())), Descriptor::Char => { self.instruction( @@ -278,11 +278,11 @@ impl InstructionBuilder<'_, '_> { &[AdapterType::String.option()], ); } - Descriptor::Enum { hole } => { + Descriptor::Enum { name, hole } => { self.instruction( &[AdapterType::I32], Instruction::OptionEnumFromI32 { hole: *hole }, - &[AdapterType::U32.option()], + &[AdapterType::Enum(name.clone()).option()], ); } Descriptor::RustStruct(name) => { diff --git a/crates/cli-support/src/wit/standard.rs b/crates/cli-support/src/wit/standard.rs index 5a771d59675..95781a6131e 100644 --- a/crates/cli-support/src/wit/standard.rs +++ b/crates/cli-support/src/wit/standard.rs @@ -85,6 +85,7 @@ pub enum AdapterType { Vector(VectorKind), Option(Box), Struct(String), + Enum(String), NamedExternref(String), Function, } @@ -327,6 +328,7 @@ impl AdapterType { AdapterType::I64 => walrus::ValType::I64, AdapterType::F32 => walrus::ValType::F32, AdapterType::F64 => walrus::ValType::F64, + AdapterType::Enum(_) => walrus::ValType::I32, AdapterType::Externref | AdapterType::NamedExternref(_) => walrus::ValType::Externref, _ => return None, }) diff --git a/crates/typescript-tests/src/enums.rs b/crates/typescript-tests/src/enums.rs index 3d711ad01b0..7a4ebe5122e 100644 --- a/crates/typescript-tests/src/enums.rs +++ b/crates/typescript-tests/src/enums.rs @@ -5,3 +5,19 @@ pub enum Foo { A = 1, B = 3, } + +#[wasm_bindgen] +pub fn fn_expects_enum(_: Foo) {} + +#[wasm_bindgen] +pub fn fn_returns_enum() -> Foo { + Foo::A +} + +#[wasm_bindgen] +pub fn fn_expects_option_enum(_: Option) {} + +#[wasm_bindgen] +pub fn fn_returns_option_enum() -> Option { + Some(Foo::A) +} diff --git a/crates/typescript-tests/src/enums.ts b/crates/typescript-tests/src/enums.ts index 3cda5bc78ff..20520e73700 100644 --- a/crates/typescript-tests/src/enums.ts +++ b/crates/typescript-tests/src/enums.ts @@ -6,3 +6,8 @@ const a3: wbg.Foo.A = 1; const b1: wbg.Foo = wbg.Foo.B; const b2: wbg.Foo.B = wbg.Foo.B; const b3: wbg.Foo.B = 3; + +const fn_expects_enum: (_: wbg.Foo) => void = wbg.fn_expects_enum; +const fn_returns_enum: () => wbg.Foo = wbg.fn_returns_enum; +const fn_expects_option_enum: (_?: wbg.Foo | undefined) => void = wbg.fn_expects_option_enum; +const fn_returns_option_enum: () => wbg.Foo | undefined = wbg.fn_returns_option_enum; From 048d36ad164dcbc9819addbee6bed51ade722690 Mon Sep 17 00:00:00 2001 From: Christian Ivicevic Date: Sat, 7 Oct 2023 17:28:37 +0200 Subject: [PATCH 2/2] Apply requested review changes. --- CHANGELOG.md | 4 ++++ crates/backend/src/codegen.rs | 2 +- crates/typescript-tests/src/enums.ts | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a92caea4abf..44543f5cc83 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -104,6 +104,10 @@ as normal exceptions rather than as rejected promises. [#3611](https://github.com/rustwasm/wasm-bindgen/pull/3611) +* Improved TypeScript bindings to accurately reference Rust enum types in function signatures, + enhancing type safety and compatibility. + [#3647](https://github.com/rustwasm/wasm-bindgen/pull/3647) + ### Fixed * Fixed `wasm_bindgen` macro to handle raw identifiers in field names. diff --git a/crates/backend/src/codegen.rs b/crates/backend/src/codegen.rs index 97d0d7330f8..656fae58dc3 100644 --- a/crates/backend/src/codegen.rs +++ b/crates/backend/src/codegen.rs @@ -1384,7 +1384,7 @@ impl ToTokens for ast::Enum { let enum_name = &self.rust_name; let name_str = self.js_name.to_string(); let name_len = name_str.len() as u32; - let name_chars = name_str.chars().map(|c| c as u32).collect::>(); + let name_chars = name_str.chars().map(|c| c as u32); let hole = &self.hole; let cast_clauses = self.variants.iter().map(|variant| { let variant_name = &variant.name; diff --git a/crates/typescript-tests/src/enums.ts b/crates/typescript-tests/src/enums.ts index 20520e73700..ea246fc847a 100644 --- a/crates/typescript-tests/src/enums.ts +++ b/crates/typescript-tests/src/enums.ts @@ -9,5 +9,5 @@ const b3: wbg.Foo.B = 3; const fn_expects_enum: (_: wbg.Foo) => void = wbg.fn_expects_enum; const fn_returns_enum: () => wbg.Foo = wbg.fn_returns_enum; -const fn_expects_option_enum: (_?: wbg.Foo | undefined) => void = wbg.fn_expects_option_enum; +const fn_expects_option_enum: (_?: wbg.Foo) => void = wbg.fn_expects_option_enum; const fn_returns_option_enum: () => wbg.Foo | undefined = wbg.fn_returns_option_enum;