Skip to content

Commit 1795020

Browse files
authored
Create wasm-in-wasm-imports example (#2229)
1 parent e372596 commit 1795020

File tree

9 files changed

+168
-0
lines changed

9 files changed

+168
-0
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ members = [
7979
"examples/request-animation-frame",
8080
"examples/todomvc",
8181
"examples/wasm-in-wasm",
82+
"examples/wasm-in-wasm-imports",
8283
"examples/wasm2js",
8384
"examples/webaudio",
8485
"examples/webgl",
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
[package]
2+
name = "wasm-in-wasm-imports"
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.64"
12+
js-sys = "0.3.41"
13+
wasm-bindgen-futures = "0.4.14"
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# js-sys: WebAssembly in WebAssembly
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/wasm-in-wasm/
7+
[dox]: https://rustwasm.github.io/docs/wasm-bindgen/examples/wasm-in-wasm.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!
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<html>
2+
<head>
3+
<meta content="text/html;charset=utf-8" http-equiv="Content-Type"/>
4+
</head>
5+
<body>
6+
<p>The developer console should have messages in it</p>
7+
</body>
8+
</html>
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// For more comments about what's going on here, check out the `hello_world`
2+
// example
3+
import('./pkg')
4+
.catch(console.error);
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+
"text-encoding": "^0.7.0",
9+
"html-webpack-plugin": "^3.2.0",
10+
"webpack": "^4.29.4",
11+
"webpack-cli": "^3.1.1",
12+
"webpack-dev-server": "^3.1.0"
13+
}
14+
}
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
use js_sys::{Function, Map, Object, Reflect, WebAssembly};
2+
use wasm_bindgen::prelude::*;
3+
use wasm_bindgen::JsCast;
4+
use wasm_bindgen_futures::{spawn_local, JsFuture};
5+
6+
#[wasm_bindgen]
7+
extern "C" {
8+
#[wasm_bindgen(js_namespace = console)]
9+
pub(crate) fn log(a: &str);
10+
11+
#[wasm_bindgen(js_namespace = console)]
12+
pub(crate) fn error(a: &str);
13+
14+
}
15+
16+
#[macro_use]
17+
macro_rules! console_log {
18+
($($t:tt)*) => (log(&format_args!($($t)*).to_string()))
19+
}
20+
21+
#[macro_use]
22+
macro_rules! console_error {
23+
($($t:tt)*) => (log(&format_args!($($t)*).to_string()))
24+
}
25+
26+
const WASM: &[u8] = include_bytes!("native_add.wasm");
27+
28+
async fn run_async() -> Result<(), JsValue> {
29+
console_log!("instantiating a new wasm module directly");
30+
31+
let imports = make_imports()?;
32+
let a = JsFuture::from(WebAssembly::instantiate_buffer(WASM, &imports)).await?;
33+
34+
let instance: WebAssembly::Instance = Reflect::get(&a, &"instance".into())?.dyn_into()?;
35+
36+
let exports = instance.exports();
37+
38+
let add = Reflect::get(&exports, &"add".into())?
39+
.dyn_into::<Function>()
40+
.expect("add export wasn't a function");
41+
42+
let three = add.call2(&JsValue::undefined(), &1.into(), &2.into())?;
43+
console_log!("1 + 2 = {:?}", three);
44+
45+
Ok(())
46+
}
47+
48+
fn bind(this: &JsValue, func_name: &str) -> Result<(), JsValue> {
49+
let property_key = JsValue::from(func_name);
50+
let orig_func = Reflect::get(this, &property_key)?.dyn_into::<Function>()?;
51+
let func = orig_func.bind(this);
52+
if !Reflect::set(this, &property_key, &func)? {
53+
return Err(JsValue::from("failed to set property"));
54+
}
55+
Ok(())
56+
}
57+
58+
pub fn make_imports() -> Result<Object, JsValue> {
59+
let map = Map::new();
60+
let imports: JsValue = Imports.into();
61+
62+
bind(&imports, "native_add")?;
63+
64+
map.set(&JsValue::from("env"), &imports);
65+
Object::from_entries(&map.into())
66+
}
67+
68+
#[wasm_bindgen]
69+
pub struct Imports;
70+
71+
#[wasm_bindgen]
72+
impl Imports {
73+
pub fn native_add(&self, a: i32, b: i32) -> i32 {
74+
a + b
75+
}
76+
}
77+
78+
#[wasm_bindgen(start)]
79+
pub fn run() {
80+
spawn_local(async {
81+
match run_async().await {
82+
Ok(_) => console_log!("Finished"),
83+
Err(e) => console_error!("{:?}", e),
84+
}
85+
});
86+
}
76 Bytes
Binary file not shown.
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
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+
template: 'index.html'
15+
}),
16+
new WasmPackPlugin({
17+
crateDirectory: path.resolve(__dirname, ".")
18+
}),
19+
// Have this example work in Edge which doesn't ship `TextEncoder` or
20+
// `TextDecoder` at this time.
21+
new webpack.ProvidePlugin({
22+
TextDecoder: ['text-encoding', 'TextDecoder'],
23+
TextEncoder: ['text-encoding', 'TextEncoder']
24+
})
25+
],
26+
mode: 'development'
27+
};

0 commit comments

Comments
 (0)