Skip to content

Commit 44253ba

Browse files
committed
Implement *WasmAbi for arrays
1 parent 93cb6cb commit 44253ba

File tree

13 files changed

+271
-9
lines changed

13 files changed

+271
-9
lines changed

crates/cli-support/src/descriptor.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ pub enum Descriptor {
5353
U64,
5454
F32,
5555
F64,
56+
Array,
5657
Boolean,
5758
Function(Box<Function>),
5859
Closure(Box<Closure>),

crates/cli-support/src/wit/incoming.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,17 @@ impl InstructionBuilder<'_, '_> {
4545
fn _incoming(&mut self, arg: &Descriptor) -> Result<(), Error> {
4646
use walrus::ValType as WasmVT;
4747
use wit_walrus::ValType as WitVT;
48+
let vector_kind = |arg: &Descriptor| arg.vector_kind().ok_or_else(|| {
49+
format_err!("unsupported argument type for calling Rust function from JS {:?}", arg)
50+
});
4851
match arg {
52+
Descriptor::Array => {
53+
self.instruction(
54+
&[AdapterType::Vector(vector_kind(arg)?)],
55+
Instruction::I32FromAnyrefOwned,
56+
&[AdapterType::I32],
57+
);
58+
}
4959
Descriptor::Boolean => {
5060
self.instruction(
5161
&[AdapterType::Bool],
@@ -117,9 +127,7 @@ impl InstructionBuilder<'_, '_> {
117127
}
118128

119129
Descriptor::Vector(_) => {
120-
let kind = arg.vector_kind().ok_or_else(|| {
121-
format_err!("unsupported argument type for calling Rust function from JS {:?}", arg)
122-
})?;
130+
let kind = vector_kind(arg)?;
123131
self.instruction(
124132
&[AdapterType::Vector(kind)],
125133
Instruction::VectorToMemory {

crates/cli-support/src/wit/outgoing.rs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,17 @@ impl InstructionBuilder<'_, '_> {
2424
}
2525

2626
fn _outgoing(&mut self, arg: &Descriptor) -> Result<(), Error> {
27+
let vector_kind = |arg: &Descriptor| arg.vector_kind().ok_or_else(|| {
28+
format_err!("unsupported argument type for calling JS function from Rust {:?}", arg)
29+
});
2730
match arg {
31+
Descriptor::Array => {
32+
self.instruction(
33+
&[AdapterType::I32],
34+
Instruction::I32FromAnyrefOwned,
35+
&[AdapterType::Vector(vector_kind(arg)?)],
36+
);
37+
}
2838
Descriptor::Boolean => {
2939
self.instruction(
3040
&[AdapterType::I32],
@@ -129,12 +139,7 @@ impl InstructionBuilder<'_, '_> {
129139
}
130140

131141
Descriptor::Vector(_) => {
132-
let kind = arg.vector_kind().ok_or_else(|| {
133-
format_err!(
134-
"unsupported argument type for calling JS function from Rust {:?}",
135-
arg
136-
)
137-
})?;
142+
let kind = vector_kind(arg)?;
138143
let mem = self.cx.memory()?;
139144
let free = self.cx.free()?;
140145
self.instruction(

examples/arrays/Cargo.toml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
[package]
2+
name = "arrays"
3+
version = "0.1.0"
4+
authors = ["The wasm-bindgen Developers"]
5+
edition = "2018"
6+
7+
[lib]
8+
crate-type = ["cdylib"]
9+
10+
[dependencies]
11+
wasm-bindgen = "0.2.58"

examples/arrays/README.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Working with arrays (up to 32)
2+
3+
[View documentation for this example online][dox] or [View compiled example
4+
online][compiled]
5+
6+
[compiled]: https://rustwasm.github.io/wasm-bindgen/exbuild/arrays/
7+
[dox]: https://rustwasm.github.io/docs/wasm-bindgen/examples/arrays.html
8+
9+
You can build the example locally with:
10+
11+
```
12+
$ npm run serve
13+
```
14+
15+
and then visiting http://localhost:8080 in a browser should run the example!

examples/arrays/index.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
const rust = import('./pkg');
2+
rust
3+
.then(m => {
4+
console.log(m.asceding_array(10));
5+
console.log(m.product([1, 2, 3, 4]));
6+
})
7+
.catch(console.error);

examples/arrays/package.json

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"scripts": {
3+
"build": "webpack",
4+
"serve": "webpack-dev-server"
5+
},
6+
"devDependencies": {
7+
"@wasm-tool/wasm-pack-plugin": "1.0.1",
8+
"html-webpack-plugin": "^3.2.0",
9+
"text-encoding": "^0.7.0",
10+
"webpack-cli": "^3.1.1",
11+
"webpack-dev-server": "^3.1.0",
12+
"webpack": "^4.29.4"
13+
}
14+
}

examples/arrays/src/lib.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
use wasm_bindgen::prelude::*;
2+
3+
#[wasm_bindgen]
4+
pub fn asceding_array(start: i32) -> [i32; 8] {
5+
let mut array = [0; 4];
6+
array.iter_mut().enumerate().for_each(|(idx, value)| *value = start + idx);
7+
array
8+
}
9+
10+
#[wasm_bindgen]
11+
pub fn product(from_js: [i32; 4]) -> i32 {
12+
from_js.iter().product()
13+
}

examples/arrays/webpack.config.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
const path = require('path');
2+
const HtmlWebpackPlugin = require('html-webpack-plugin');
3+
const webpack = require('webpack');
4+
const WasmPackPlugin = require("@wasm-tool/wasm-pack-plugin");
5+
6+
module.exports = {
7+
entry: './index.js',
8+
output: {
9+
path: path.resolve(__dirname, 'dist'),
10+
filename: 'index.js',
11+
},
12+
plugins: [
13+
new HtmlWebpackPlugin(),
14+
new WasmPackPlugin({
15+
crateDirectory: path.resolve(__dirname, ".")
16+
}),
17+
// Have this example work in Edge which doesn't ship `TextEncoder` or
18+
// `TextDecoder` at this time.
19+
new webpack.ProvidePlugin({
20+
TextDecoder: ['text-encoding', 'TextDecoder'],
21+
TextEncoder: ['text-encoding', 'TextEncoder']
22+
})
23+
],
24+
mode: 'development'
25+
};

src/convert/slices.rs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,3 +271,53 @@ if_std! {
271271
fn is_none(slice: &WasmSlice) -> bool { slice.ptr == 0 }
272272
}
273273
}
274+
275+
276+
macro_rules! array_impls {
277+
($($N:expr),+) => {
278+
$(
279+
unsafe impl<T> WasmAbi for [T; $N] {}
280+
281+
impl<T> FromWasmAbi for [T; $N]
282+
where
283+
T: Copy + FromWasmAbi<Abi = [T; $N]>
284+
{
285+
type Abi = [T; $N];
286+
287+
#[inline]
288+
unsafe fn from_abi(js: Self::Abi) -> Self {
289+
use core::convert::TryInto;
290+
let slice = slice::from_raw_parts(
291+
<*const T>::from_abi(js.as_ptr() as u32),
292+
js.len(),
293+
);
294+
slice.try_into().unwrap()
295+
}
296+
}
297+
298+
impl<T> IntoWasmAbi for [T; $N]
299+
where
300+
T: Copy + IntoWasmAbi<Abi = [T; $N]>
301+
{
302+
type Abi = [T; $N];
303+
304+
#[inline]
305+
fn into_abi(self) -> Self::Abi {
306+
unsafe {
307+
use core::convert::TryInto;
308+
let slice = slice::from_raw_parts(
309+
self.as_ptr(),
310+
self.len()
311+
);
312+
slice.try_into().unwrap()
313+
}
314+
}
315+
}
316+
)+
317+
}
318+
}
319+
320+
array_impls!(
321+
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
322+
26, 27, 28, 29, 30, 31, 32
323+
);

0 commit comments

Comments
 (0)