diff --git a/crates/cli-support/src/js/js2rust.rs b/crates/cli-support/src/js/js2rust.rs index 5382a9af..67ce0694 100644 --- a/crates/cli-support/src/js/js2rust.rs +++ b/crates/cli-support/src/js/js2rust.rs @@ -259,7 +259,26 @@ impl<'a, 'b> Js2Rust<'a, 'b> { return Ok(self); } - bail!("unsupported optional argument type for calling Rust function from JS: {:?}", arg); + match *arg { + Descriptor::Boolean => { + self.cx.expose_is_like_none(); + self.js_arguments.push((name.clone(), "boolean".to_string())); + if self.cx.config.debug { + self.cx.expose_assert_bool(); + self.prelude(&format!( + " + if (!isLikeNone({0})) {{ + _assertBoolean({0}); + }} + ", + name, + )); + } + self.rust_arguments.push(format!("isLikeNone({0}) ? 0xFFFFFF : {0} ? 1 : 0", name)); + return Ok(self); + }, + _ => bail!("unsupported optional argument type for calling Rust function from JS: {:?}", arg), + }; } if let Some(s) = arg.rust_struct() { @@ -486,7 +505,17 @@ impl<'a, 'b> Js2Rust<'a, 'b> { return Ok(self); } - bail!("unsupported optional return type for calling Rust function from JS: {:?}", ty); + match *ty { + Descriptor::Boolean => { + self.ret_ty = "boolean".to_string(); + self.ret_expr = " + const ret = RET; + return ret === 0xFFFFFF ? undefined : ret !== 0; + ".to_string(); + return Ok(self); + }, + _ => bail!("unsupported optional return type for calling Rust function from JS: {:?}", ty), + }; } if ty.is_ref_anyref() { diff --git a/crates/cli-support/src/js/rust2js.rs b/crates/cli-support/src/js/rust2js.rs index eed1d13c..ceab835e 100644 --- a/crates/cli-support/src/js/rust2js.rs +++ b/crates/cli-support/src/js/rust2js.rs @@ -173,7 +173,13 @@ impl<'a, 'b> Rust2Js<'a, 'b> { return Ok(()); } - bail!("unsupported optional argument type for calling JS function from Rust: {:?}", arg); + match *arg { + Descriptor::Boolean => { + self.js_arguments.push(format!("{0} === 0xFFFFFF ? undefined : {0} !== 0", abi)); + return Ok(()) + }, + _ => bail!("unsupported optional argument type for calling JS function from Rust: {:?}", arg), + }; } if let Some(signed) = arg.get_64() { @@ -424,7 +430,17 @@ impl<'a, 'b> Rust2Js<'a, 'b> { return Ok(()); } - bail!("unsupported optional return type for calling JS function from Rust: {:?}", ty); + match *ty { + Descriptor::Boolean => { + self.cx.expose_is_like_none(); + self.ret_expr = " + const val = JS; + return isLikeNone(val) ? 0xFFFFFF : val ? 1 : 0; + ".to_string(); + return Ok(()); + }, + _ => bail!("unsupported optional return type for calling JS function from Rust: {:?}", ty), + }; } if ty.is_number() { self.ret_expr = "return JS;".to_string(); diff --git a/src/convert/impls.rs b/src/convert/impls.rs index 05468700..31e37467 100644 --- a/src/convert/impls.rs +++ b/src/convert/impls.rs @@ -220,6 +220,16 @@ impl FromWasmAbi for bool { } } +impl OptionIntoWasmAbi for bool { + #[inline] + fn none() -> u32 { 0xFFFFFFu32 } +} + +impl OptionFromWasmAbi for bool { + #[inline] + fn is_none(js: &u32) -> bool { *js == 0xFFFFFFu32 } +} + impl IntoWasmAbi for char { type Abi = u32; diff --git a/tests/wasm/optional_numbers.js b/tests/wasm/optional_numbers.js index 882c6510..5f29efa8 100644 --- a/tests/wasm/optional_numbers.js +++ b/tests/wasm/optional_numbers.js @@ -76,6 +76,10 @@ exports.test_works = function() { assert.strictEqual(wasm.u64_identity(wasm.u64_one()), BigInt('1')); assert.strictEqual(wasm.u64_identity(wasm.u64_max()), BigInt('18446744073709551615')); assert.strictEqual(wasm.u64_identity(wasm.u64_min()), BigInt('0')); + + assert.strictEqual(wasm.bool_identity(wasm.bool_none()), undefined); + assert.strictEqual(wasm.bool_identity(wasm.bool_false()), false); + assert.strictEqual(wasm.bool_identity(wasm.bool_true()), true); }; exports.i32_js_identity = function(a) { return a; }; @@ -90,3 +94,4 @@ exports.i16_js_identity = function(a) { return a; }; exports.u16_js_identity = function(a) { return a; }; exports.i64_js_identity = function(a) { return a; }; exports.u64_js_identity = function(a) { return a; }; +exports.bool_js_identity = function(a) { return a; }; diff --git a/tests/wasm/optional_numbers.rs b/tests/wasm/optional_numbers.rs index 34f187cd..3722c89b 100644 --- a/tests/wasm/optional_numbers.rs +++ b/tests/wasm/optional_numbers.rs @@ -15,6 +15,7 @@ extern { fn u16_js_identity(a: Option) -> Option; fn i64_js_identity(a: Option) -> Option; fn u64_js_identity(a: Option) -> Option; + fn bool_js_identity(a: Option) -> Option; fn test_works(); } @@ -181,6 +182,15 @@ pub fn u64_min() -> Option { Some(u64::min_value()) } #[wasm_bindgen] pub fn u64_identity(a: Option) -> Option { u64_js_identity(a) } +#[wasm_bindgen] +pub fn bool_none() -> Option { None } +#[wasm_bindgen] +pub fn bool_false() -> Option { Some(false) } +#[wasm_bindgen] +pub fn bool_true() -> Option { Some(true) } +#[wasm_bindgen] +pub fn bool_identity(a: Option) -> Option { bool_js_identity(a) } + #[wasm_bindgen_test] fn works() { test_works();