Skip to content

Commit

Permalink
Add NonNull<T> as parameter (#3857)
Browse files Browse the repository at this point in the history
  • Loading branch information
daxpedda authored Mar 2, 2024
1 parent 0095fa7 commit 983ec57
Show file tree
Hide file tree
Showing 9 changed files with 50 additions and 4 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

* Add support for `Option<*const T>`, `Option<*mut T>` and `NonNull<T>`.
[#3852](https://github.com/rustwasm/wasm-bindgen/pull/3852)
[#3857](https://github.com/rustwasm/wasm-bindgen/pull/3857)

* Allow overriding the URL used for headless tests by setting `WASM_BINDGEN_TEST_ADDRESS`.
[#3861](https://github.com/rustwasm/wasm-bindgen/pull/3861)
Expand Down
11 changes: 11 additions & 0 deletions crates/cli-support/src/js/binding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -497,6 +497,11 @@ impl<'a, 'b> JsBuilder<'a, 'b> {
self.prelude("}");
}

fn assert_non_null(&mut self, arg: &str) {
self.cx.expose_assert_non_null();
self.prelude(&format!("_assertNonNull({});", arg));
}

fn assert_optional_bigint(&mut self, arg: &str) {
if !self.cx.config.debug {
return;
Expand Down Expand Up @@ -1218,6 +1223,12 @@ fn instruction(
js.push(format!("{0} === {1} ? undefined : {0}", val, hole));
}

Instruction::I32FromNonNull => {
let val = js.pop();
js.assert_non_null(&val);
js.push(val);
}

Instruction::I32FromOptionNonNull => {
let val = js.pop();
js.cx.expose_is_like_none();
Expand Down
13 changes: 13 additions & 0 deletions crates/cli-support/src/js/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2103,6 +2103,19 @@ impl<'a> Context<'a> {
);
}

fn expose_assert_non_null(&mut self) {
if !self.should_write_global("assert_non_null") {
return;
}
self.global(
"
function _assertNonNull(n) {
if (typeof(n) !== 'number' || n === 0) throw new Error(`expected a number argument that is not 0, found ${n}`);
}
",
);
}

fn expose_make_mut_closure(&mut self) -> Result<(), Error> {
if !self.should_write_global("make_mut_closure") {
return Ok(());
Expand Down
6 changes: 5 additions & 1 deletion crates/cli-support/src/wit/incoming.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,11 @@ impl InstructionBuilder<'_, '_> {
// Largely synthetic and can't show up
Descriptor::ClampedU8 => unreachable!(),

Descriptor::NonNull => unimplemented!("converting `NonNull<T>` from Wasm to Rust is not implemented"),
Descriptor::NonNull => self.instruction(
&[AdapterType::NonNull],
Instruction::I32FromNonNull,
&[AdapterType::I32],
),
}
Ok(())
}
Expand Down
1 change: 1 addition & 0 deletions crates/cli-support/src/wit/standard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,7 @@ pub enum Instruction {
},
I32FromOptionNonNull,
OptionNonNullFromI32,
I32FromNonNull,
}

impl AdapterType {
Expand Down
2 changes: 1 addition & 1 deletion guide/src/reference/types/non-null.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

| `T` parameter | `&T` parameter | `&mut T` parameter | `T` return value | `Option<T>` parameter | `Option<T>` return value | JavaScript representation |
|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
| No | No | No | Yes | Yes | Yes | A JavaScript number value |
| Yes | No | No | Yes | Yes | Yes | A JavaScript number value |

## Example Rust Usage

Expand Down
12 changes: 10 additions & 2 deletions src/convert/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -294,12 +294,20 @@ impl<T> OptionIntoWasmAbi for NonNull<T> {
}
}

impl<T> FromWasmAbi for Option<NonNull<T>> {
impl<T> FromWasmAbi for NonNull<T> {
type Abi = u32;

#[inline]
unsafe fn from_abi(js: Self::Abi) -> Self {
NonNull::new(js as *mut T)
// SAFETY: Checked in bindings.
NonNull::new_unchecked(js as *mut T)
}
}

impl<T> OptionFromWasmAbi for NonNull<T> {
#[inline]
fn is_none(js: &u32) -> bool {
*js == 0
}
}

Expand Down
3 changes: 3 additions & 0 deletions tests/wasm/simple.js
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,9 @@ exports.test_raw_pointers = function() {
};

exports.test_non_null = function() {
assert.strictEqual(wasm.simple_nonnull_work(wasm.simple_return_non_null()), 42);
assert.throws(() => wasm.simple_nonnull_work(0), /expected a number argument that is not 0/);

assert.strictEqual(wasm.simple_option_nonnull_work(0), undefined);
assert.strictEqual(wasm.simple_option_nonnull_work(null), undefined);
assert.strictEqual(wasm.simple_option_nonnull_work(undefined), undefined);
Expand Down
5 changes: 5 additions & 0 deletions tests/wasm/simple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,11 @@ pub fn simple_return_option_non_null(value: u32) -> Option<NonNull<u32>> {
Some(NonNull::from(Box::leak(Box::new(value))))
}

#[wasm_bindgen]
pub unsafe fn simple_nonnull_work(a: NonNull<u32>) -> u32 {
*Box::from_raw(a.as_ptr())
}

#[wasm_bindgen]
pub unsafe fn simple_option_nonnull_work(a: Option<NonNull<u32>>) -> Option<u32> {
a.map(|ptr| *Box::from_raw(ptr.as_ptr()))
Expand Down

0 comments on commit 983ec57

Please sign in to comment.