From 618a3ecef98f8b983c88895d938ad60ec7e34eec Mon Sep 17 00:00:00 2001 From: Christopher Schramm Date: Tue, 19 Sep 2023 15:00:45 +0200 Subject: [PATCH 1/2] Allow creating `Vec`s of exported enums Also implements `TryFrom` and `Into` for them. Enums were left behind in #3554. This adds the missing bits. --- crates/backend/src/codegen.rs | 59 +++++++++++++++++++++++++++++++++++ tests/wasm/enum_vecs.js | 23 ++++++++++++++ tests/wasm/enum_vecs.rs | 36 +++++++++++++++++++++ tests/wasm/main.rs | 1 + 4 files changed, 119 insertions(+) create mode 100644 tests/wasm/enum_vecs.js create mode 100644 tests/wasm/enum_vecs.rs diff --git a/crates/backend/src/codegen.rs b/crates/backend/src/codegen.rs index e45d4e50ba1..cda345eb183 100644 --- a/crates/backend/src/codegen.rs +++ b/crates/backend/src/codegen.rs @@ -1427,6 +1427,65 @@ impl ToTokens for ast::Enum { inform(#hole); } } + + #[automatically_derived] + impl #wasm_bindgen::__rt::core::convert::From<#enum_name> for + #wasm_bindgen::JsValue + { + fn from(value: #enum_name) -> Self { + #wasm_bindgen::JsValue::from_f64((value as u32).into()) + } + } + + #[allow(clippy::all)] + impl #wasm_bindgen::__rt::core::convert::TryFrom<#wasm_bindgen::JsValue> for #enum_name { + type Error = #wasm_bindgen::JsValue; + + fn try_from(value: #wasm_bindgen::JsValue) + -> #wasm_bindgen::__rt::std::result::Result { + let val = f64::try_from(value)? as u32; + + unsafe { + #wasm_bindgen::__rt::std::result::Result::Ok( + ::from_abi(val) + ) + } + } + } + + impl #wasm_bindgen::describe::WasmDescribeVector for #enum_name { + fn describe_vector() { + use #wasm_bindgen::describe::*; + inform(VECTOR); + <#wasm_bindgen::JsValue as #wasm_bindgen::describe::WasmDescribe>::describe(); + } + } + + impl #wasm_bindgen::convert::VectorIntoWasmAbi for #enum_name { + type Abi = < + #wasm_bindgen::__rt::std::boxed::Box<[#wasm_bindgen::JsValue]> + as #wasm_bindgen::convert::IntoWasmAbi + >::Abi; + + fn vector_into_abi( + vector: #wasm_bindgen::__rt::std::boxed::Box<[#enum_name]> + ) -> Self::Abi { + #wasm_bindgen::convert::js_value_vector_into_abi(vector) + } + } + + impl #wasm_bindgen::convert::VectorFromWasmAbi for #enum_name { + type Abi = < + #wasm_bindgen::__rt::std::boxed::Box<[#wasm_bindgen::JsValue]> + as #wasm_bindgen::convert::FromWasmAbi + >::Abi; + + unsafe fn vector_from_abi( + js: Self::Abi + ) -> #wasm_bindgen::__rt::std::boxed::Box<[#enum_name]> { + #wasm_bindgen::convert::js_value_vector_from_abi(js) + } + } }) .to_tokens(into); } diff --git a/tests/wasm/enum_vecs.js b/tests/wasm/enum_vecs.js new file mode 100644 index 00000000000..bef43b3e417 --- /dev/null +++ b/tests/wasm/enum_vecs.js @@ -0,0 +1,23 @@ +const wasm = require('wasm-bindgen-test.js'); +const assert = require('assert'); + +exports.pass_enum_vec = () => { + const el1 = wasm.EnumArrayElement.Unit; + const el2 = wasm.EnumArrayElement.Unit; + const ret = wasm.consume_enum_vec([el1, el2]); + assert.strictEqual(ret.length, 3); + + const ret2 = wasm.consume_optional_enum_vec(ret); + assert.strictEqual(ret2.length, 4); + + assert.strictEqual(wasm.consume_optional_enum_vec(undefined), undefined); +}; + +exports.pass_invalid_enum_vec = () => { + try { + wasm.consume_enum_vec(['not an enum value']); + } catch (e) { + assert.match(e.message, /invalid enum value passed/) + assert.match(e.stack, /consume_enum_vec/) + } +}; diff --git a/tests/wasm/enum_vecs.rs b/tests/wasm/enum_vecs.rs new file mode 100644 index 00000000000..7b6e6bcaf46 --- /dev/null +++ b/tests/wasm/enum_vecs.rs @@ -0,0 +1,36 @@ +use wasm_bindgen::prelude::*; +use wasm_bindgen_test::*; + +#[wasm_bindgen(module = "tests/wasm/enum_vecs.js")] +extern "C" { + fn pass_enum_vec(); + fn pass_invalid_enum_vec(); +} + +#[wasm_bindgen] +pub enum EnumArrayElement { + Unit, +} + +#[wasm_bindgen] +pub fn consume_enum_vec(mut vec: Vec) -> Vec { + vec.push(EnumArrayElement::Unit); + vec +} + +#[wasm_bindgen] +pub fn consume_optional_enum_vec( + vec: Option>, +) -> Option> { + vec.map(consume_enum_vec) +} + +#[wasm_bindgen_test] +fn test_valid() { + pass_enum_vec(); +} + +#[wasm_bindgen_test] +fn test_invalid() { + pass_invalid_enum_vec(); +} diff --git a/tests/wasm/main.rs b/tests/wasm/main.rs index eebde19677e..8059e721fee 100644 --- a/tests/wasm/main.rs +++ b/tests/wasm/main.rs @@ -23,6 +23,7 @@ pub mod closures; pub mod comments; pub mod duplicate_deps; pub mod duplicates; +pub mod enum_vecs; pub mod enums; #[path = "final.rs"] pub mod final_; From 4864ecc37ee9020cc87e1a5d4f22334832f5661f Mon Sep 17 00:00:00 2001 From: Christopher Schramm Date: Wed, 20 Sep 2023 15:52:33 +0200 Subject: [PATCH 2/2] Do not panic in TryFrom --- crates/backend/src/codegen.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/crates/backend/src/codegen.rs b/crates/backend/src/codegen.rs index cda345eb183..2c86370eaf4 100644 --- a/crates/backend/src/codegen.rs +++ b/crates/backend/src/codegen.rs @@ -1383,6 +1383,7 @@ impl ToTokens for ast::Enum { } } }); + let try_from_cast_clauses = cast_clauses.clone(); let wasm_bindgen = &self.wasm_bindgen; (quote! { #[automatically_derived] @@ -1443,13 +1444,13 @@ impl ToTokens for ast::Enum { fn try_from(value: #wasm_bindgen::JsValue) -> #wasm_bindgen::__rt::std::result::Result { - let val = f64::try_from(value)? as u32; + let js = f64::try_from(&value)? as u32; - unsafe { - #wasm_bindgen::__rt::std::result::Result::Ok( - ::from_abi(val) - ) - } + #wasm_bindgen::__rt::std::result::Result::Ok( + #(#try_from_cast_clauses else)* { + return #wasm_bindgen::__rt::std::result::Result::Err(value) + } + ) } }