mirror of
https://github.com/rustwasm/wasm-bindgen.git
synced 2024-12-28 12:32:37 +03:00
Merge pull request #860 from alexcrichton/juggle-examples
Reorganize and rewrite examples
This commit is contained in:
commit
70c821b442
@ -58,11 +58,9 @@ members = [
|
||||
"crates/webidl",
|
||||
"crates/webidl-tests",
|
||||
"examples/add",
|
||||
"examples/asm.js",
|
||||
"examples/canvas",
|
||||
"examples/char",
|
||||
"examples/closures",
|
||||
"examples/comments",
|
||||
"examples/console_log",
|
||||
"examples/duck-typed-interfaces",
|
||||
"examples/dom",
|
||||
@ -71,12 +69,11 @@ members = [
|
||||
"examples/hello_world",
|
||||
"examples/import_js",
|
||||
"examples/julia_set",
|
||||
"examples/math",
|
||||
"examples/no_modules",
|
||||
"examples/paint",
|
||||
"examples/performance",
|
||||
"examples/smorgasboard",
|
||||
"examples/wasm-in-wasm",
|
||||
"examples/wasm2js",
|
||||
"examples/webaudio",
|
||||
"examples/webgl",
|
||||
"tests/no-std",
|
||||
|
@ -1753,6 +1753,13 @@ extern "C" {
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new(init: &JsValue) -> Date;
|
||||
|
||||
/// Creates a JavaScript Date instance that represents the current moment in
|
||||
/// time.
|
||||
///
|
||||
/// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date)
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new_0() -> Date;
|
||||
|
||||
/// The `Date.now()` method returns the number of milliseconds
|
||||
/// elapsed since January 1, 1970 00:00:00 UTC.
|
||||
///
|
||||
|
@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "ui-tests"
|
||||
version = "0.1.0"
|
||||
authors = ["The wasm-bindgen Authors"]
|
||||
authors = ["The wasm-bindgen Developers"]
|
||||
|
||||
[lib]
|
||||
path = "test.rs"
|
||||
|
@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "sample"
|
||||
version = "0.1.0"
|
||||
authors = ["The wasm-bindgen Authors"]
|
||||
authors = ["The wasm-bindgen Developers"]
|
||||
|
||||
[lib]
|
||||
test = false
|
||||
|
@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "webidl-tests"
|
||||
version = "0.1.0"
|
||||
authors = ["The wasm-bindgen authors"]
|
||||
authors = ["The wasm-bindgen Developers"]
|
||||
|
||||
[lib]
|
||||
test = false
|
||||
|
@ -1,42 +1,7 @@
|
||||
# Examples
|
||||
|
||||
This directory contains a number of examples of the `#[wasm_bindgen]` macro and
|
||||
how to display them in the browser. Each directory contains a README with a link
|
||||
to https://webassembly.studio so you can also explore the example online
|
||||
(apologies if they're out of sync!), and each directory also contains a
|
||||
`build.sh` which assembles all the relevant files locally. If you open up
|
||||
`index.html` in a web browser you should be able to see everything in action
|
||||
when using `build.sh`!
|
||||
This directory contains a number of Cargo projects that are all examples of how
|
||||
to use `wasm-bindgen` in various contexts. More documentation can be [found
|
||||
online][dox]
|
||||
|
||||
The examples here are:
|
||||
|
||||
* `add` - an example of generating a tiny wasm binary, one that only adds two
|
||||
numbers.
|
||||
* `asm.js` - an example of using the `wasm2js` tool from [binaryen] to convert
|
||||
the generated WebAssembly to normal JS
|
||||
* `char` - an example of passing the rust `char` type to and from the js `string` type
|
||||
* `closures` - an example of how to invoke functions like `setInterval` or use
|
||||
the `onclick` property in conjunction with closures.
|
||||
* `comments` - an example of how Rust comments are copied into js bindings
|
||||
* `console_log` - a showcase of `#[wasm_bindgen]` importing classes and how to
|
||||
bind `console.log`
|
||||
* `dom` - an example of accessing the global `document` object and appending
|
||||
HTML to it
|
||||
* `fetch` -- how to use the Fetch API to make async http requests
|
||||
* `hello_world` - the "hello world" of `#[wasm_bindgen]`, aka throwing up a
|
||||
dialog greeting you
|
||||
* `import_js` - an example of importing local JS functionality into a crate
|
||||
* `math` - like `console_log` except showing how to import Math-related
|
||||
functions instead
|
||||
* `no_modules` - an example of how to use the `--no-modules` flag to
|
||||
the `wasm-bindgen` CLI tool
|
||||
* `performance` - how to import APIs like `performance.now()` and time various
|
||||
operations in Rust
|
||||
* `smorgasboard` - a bunch of features all thrown into one, showing off the
|
||||
various capabilities of the `#[wasm_bindgen]` macro and what you can do with
|
||||
it from JS
|
||||
* `wasm-in-wasm` - how to interact with namespaced APIs like
|
||||
`WebAssembly.Module` and shows off creation of a WebAssembly module from Rust
|
||||
* `webaudio` - how to use the Web Audio APIs to generate sounds
|
||||
|
||||
[binaryen]: https://github.com/WebAssembly/binaryen
|
||||
[dox]: https://rustwasm.github.io/wasm-bindgen/examples/index.html
|
||||
|
@ -1,12 +1,10 @@
|
||||
# Adding Numbers
|
||||
# Adding numbers (small wasm files)
|
||||
|
||||
[View this example online](https://webassembly.studio/?f=612vwsrmwft)
|
||||
[View documentation for this example online][dox]
|
||||
|
||||
This directory is an example of using the `#[wasm_bindgen]` macro to simply add
|
||||
two numbers. The neat part about this is that it's an example of how to generate
|
||||
the smallest wasm-bindgen binary.
|
||||
[dox]: https://rustwasm.github.io/wasm-bindgen/examples/add.html
|
||||
|
||||
You can build the example with:
|
||||
You can build the example locally with:
|
||||
|
||||
```
|
||||
$ ./build.sh
|
||||
@ -14,48 +12,4 @@ $ ./build.sh
|
||||
|
||||
(or running the commands on Windows manually)
|
||||
|
||||
Currently this generates a 651 byte wasm binary:
|
||||
|
||||
```
|
||||
$ ls -alh add_bg.wasm
|
||||
-rw-rw-r-- 1 alex alex 651 Apr 20 22:16 add_bg.wasm
|
||||
```
|
||||
|
||||
If you run [wasm-opt], a C++ tool for optimize WebAssembly, you can make it even
|
||||
smaller too!
|
||||
|
||||
```
|
||||
$ wasm-opt -Os add_bg.wasm -o add.wasm
|
||||
$ ls -alh add.wasm
|
||||
-rw-rw-r-- 1 alex alex 100 Apr 20 22:19 add.wasm
|
||||
```
|
||||
|
||||
And sure enough, using the [wasm2wat] tool it's quite small!
|
||||
|
||||
```
|
||||
$ wasm2wat add.wasm
|
||||
(module
|
||||
(type (;0;) (func (param i32 i32) (result i32)))
|
||||
(func (;0;) (type 0) (param i32 i32) (result i32)
|
||||
get_local 1
|
||||
get_local 0
|
||||
i32.add)
|
||||
(memory (;0;) 2)
|
||||
(export "memory" (memory 0))
|
||||
(export "add" (func 0))
|
||||
(data (i32.const 1545) "invalid malloc request"))
|
||||
```
|
||||
|
||||
Note that it's important to point out that the size reductions here are because
|
||||
the wasm is compiled in release mode by the build script and this crate's
|
||||
workspace has the following configuration
|
||||
|
||||
```toml
|
||||
[profile.release]
|
||||
lto = true
|
||||
opt-level = 's'
|
||||
panic = 'abort'
|
||||
```
|
||||
|
||||
[wasm2wat]: https://github.com/webassembly/wabt
|
||||
[wasm-opt]: https://github.com/webassembly/binaryen
|
||||
and then visiting http://localhost:8080 in a browser should run the example!
|
||||
|
@ -1,19 +0,0 @@
|
||||
# WebAssembly to asm.js
|
||||
|
||||
This directory is an example of using [binaryen]'s `wasm2js` tool to convert
|
||||
the wasm output of `wasm-bindgen` to a normal JS file that can be executed like
|
||||
asm.js.
|
||||
|
||||
You can build the example locally with:
|
||||
|
||||
```
|
||||
$ ./build.sh
|
||||
```
|
||||
|
||||
When opened in a web browser this should print "Hello, World!" to the console.
|
||||
|
||||
Note that the `wasm2js` tool is still pretty early days so there's likely to be
|
||||
a number of bugs to run into or work around. If any are encountered though
|
||||
please feel free to report them upstream!
|
||||
|
||||
[binaryen]: https://github.com/WebAssembly/binaryen
|
@ -1,3 +0,0 @@
|
||||
import { run } from './asmjs';
|
||||
|
||||
run();
|
6
examples/canvas/.gitignore
vendored
6
examples/canvas/.gitignore
vendored
@ -1,4 +1,4 @@
|
||||
package-lock.json
|
||||
wasm_bindgen_canvas_demo.js
|
||||
wasm_bindgen_canvas_demo_bg.js
|
||||
wasm_bindgen_canvas_demo_bg.wasm
|
||||
canvas.js
|
||||
canvas_bg.js
|
||||
canvas_bg.wasm
|
||||
|
@ -1,5 +1,5 @@
|
||||
[package]
|
||||
name = "wasm-bindgen-canvas-demo"
|
||||
name = "canvas"
|
||||
version = "0.1.0"
|
||||
authors = ["The wasm-bindgen Developers"]
|
||||
|
||||
|
@ -1,9 +1,10 @@
|
||||
# Canvas 2D Example
|
||||
# 2D Canvas
|
||||
|
||||
This directory is an example of using the `web-sys` crate to draw on a 2D
|
||||
canvas.
|
||||
[View documentation for this example online][dox]
|
||||
|
||||
You can build and run the example with:
|
||||
[dox]: https://rustwasm.github.io/wasm-bindgen/examples/2d-canvas.html
|
||||
|
||||
You can build the example locally with:
|
||||
|
||||
```
|
||||
$ ./build.sh
|
||||
@ -11,5 +12,4 @@ $ ./build.sh
|
||||
|
||||
(or running the commands on Windows manually)
|
||||
|
||||
and then opening up `http://localhost:8080/` in a web browser should show a
|
||||
smiley face drawn on canvas by Rust and WebAssembly.
|
||||
and then visiting http://localhost:8080 in a browser should run the example!
|
||||
|
@ -9,7 +9,7 @@ cargo +nightly build --target wasm32-unknown-unknown
|
||||
|
||||
cargo +nightly run --manifest-path ../../crates/cli/Cargo.toml \
|
||||
--bin wasm-bindgen -- \
|
||||
../../target/wasm32-unknown-unknown/debug/wasm_bindgen_canvas_demo.wasm --out-dir .
|
||||
../../target/wasm32-unknown-unknown/debug/canvas.wasm --out-dir .
|
||||
|
||||
npm install
|
||||
npm run serve
|
||||
|
@ -4,6 +4,5 @@
|
||||
</head>
|
||||
<body>
|
||||
<canvas id="canvas" height="150" width="150" />
|
||||
<script src='./index.js'></script>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -1,5 +1,5 @@
|
||||
// For more comments about what's going on here, check out the `hello_world`
|
||||
// example.
|
||||
import('./wasm_bindgen_canvas_demo').then(canvas => {
|
||||
import('./canvas').then(canvas => {
|
||||
canvas.draw();
|
||||
});
|
||||
|
@ -1,6 +1,8 @@
|
||||
# Char
|
||||
# Working with the `char` type
|
||||
|
||||
This directory is an example of how the `#[wasm_bindgen]` macro will convert the rust `char` type to a single code-point js `string`.
|
||||
[View documentation for this example online][dox]
|
||||
|
||||
[dox]: https://rustwasm.github.io/wasm-bindgen/examples/char.html
|
||||
|
||||
You can build the example locally with:
|
||||
|
||||
@ -8,6 +10,6 @@ You can build the example locally with:
|
||||
$ ./build.sh
|
||||
```
|
||||
|
||||
Opening your web browser should display a single counter with a random character for it's `key` and 0 for its `count`. You can click the `+` button to increase a counter's count. By clicking on the "add counter" button you should see a new counter added to the list with a different random character for it's `key`.
|
||||
(or running the commands on Windows manually)
|
||||
|
||||
Under the hood javascript is choosing a random character from an Array of characters and passing that to the rust Counter struct's constructor so the character you are seeing on the page has made the full round trip from js to rust and back to js.
|
||||
and then visiting http://localhost:8080 in a browser should run the example!
|
||||
|
@ -32,7 +32,7 @@
|
||||
align-content: flex-start;
|
||||
}
|
||||
.counter {
|
||||
margin-bottom: 10px;
|
||||
margin-bottom: 10px;
|
||||
background: steelblue;
|
||||
color: white;
|
||||
align-items: center;
|
||||
@ -49,8 +49,7 @@
|
||||
<body>
|
||||
<button id="add-counter" type="button">add counter</button>
|
||||
<div id="container">
|
||||
|
||||
|
||||
</div>
|
||||
<script type="text/javascript" src="index.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* eslint-disable no-unused-vars */
|
||||
import {chars} from './chars.js';
|
||||
import { chars } from './chars-list.js';
|
||||
let imp = import('./char.js');
|
||||
let mod;
|
||||
|
||||
@ -71,4 +71,4 @@ function newField(key, value) {
|
||||
val.appendChild(document.createTextNode(value));
|
||||
ret.appendChild(val);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ extern crate wasm_bindgen;
|
||||
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
// lifted from the `console_log` example
|
||||
#[wasm_bindgen]
|
||||
extern "C" {
|
||||
#[wasm_bindgen(js_namespace = console)]
|
||||
|
@ -9,3 +9,13 @@ crate-type = ["cdylib"]
|
||||
[dependencies]
|
||||
wasm-bindgen = { path = "../..", features = ['nightly'] }
|
||||
js-sys = { path = "../../crates/js-sys" }
|
||||
|
||||
[dependencies.web-sys]
|
||||
path = "../../crates/web-sys"
|
||||
features = [
|
||||
'CssStyleDeclaration',
|
||||
'Document',
|
||||
'Element',
|
||||
'HtmlElement',
|
||||
'Window',
|
||||
]
|
||||
|
@ -1,11 +1,10 @@
|
||||
# Closure examples
|
||||
# web-sys: Closures
|
||||
|
||||
[View this example online](https://webassembly.studio/?f=g3hc1qs6tka)
|
||||
[View documentation for this example online][dox]
|
||||
|
||||
This directory is an example of using the `#[wasm_bindgen]` macro with closures
|
||||
to interact with the DOM.
|
||||
[dox]: https://rustwasm.github.io/wasm-bindgen/examples/closures.html
|
||||
|
||||
You can build the example with:
|
||||
You can build the example locally with:
|
||||
|
||||
```
|
||||
$ ./build.sh
|
||||
@ -13,10 +12,4 @@ $ ./build.sh
|
||||
|
||||
(or running the commands on Windows manually)
|
||||
|
||||
and then opening up `index.html` in a web browser should show a hello message on
|
||||
the web page generated by the wasm.
|
||||
|
||||
For more information about this example be sure to check out
|
||||
[`hello_world`][hello] which also has more comments about caveats and such.
|
||||
|
||||
[hello]: https://github.com/alexcrichton/wasm-bindgen/tree/master/examples/hello_world
|
||||
and then visiting http://localhost:8080 in a browser should run the example!
|
||||
|
@ -35,6 +35,5 @@
|
||||
times
|
||||
</p>
|
||||
</div>
|
||||
<script src='./index.js'></script>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -1,74 +1,88 @@
|
||||
extern crate wasm_bindgen;
|
||||
extern crate js_sys;
|
||||
extern crate web_sys;
|
||||
|
||||
use js_sys::Date;
|
||||
use js_sys::{Date, Array};
|
||||
use wasm_bindgen::JsCast;
|
||||
use wasm_bindgen::prelude::*;
|
||||
use web_sys::{Document, Element, HtmlElement, Window};
|
||||
|
||||
#[wasm_bindgen]
|
||||
extern "C" {
|
||||
// Binding for the `setInverval` method in JS. This function takes a "long
|
||||
// lived" closure as the first argument so we use `Closure` instead of
|
||||
// a bare `&Fn()` which only surives for that one stack frame.
|
||||
//
|
||||
// The second argument is then the interval and the return value is how we
|
||||
// clear this interval. We're not going to clear our interval in this
|
||||
// example though so the return value is ignored.
|
||||
#[wasm_bindgen(js_name = setInterval)]
|
||||
fn set_interval(cb: &Closure<FnMut()>, delay: u32) -> f64;
|
||||
pub fn run() -> Result<(), JsValue> {
|
||||
let window = web_sys::window().expect("should have a window in this context");
|
||||
let document = window.document().expect("window should have a document");
|
||||
|
||||
// Bindings for `document` and various methods of updating HTML elements.
|
||||
// Like with the `dom` example these'll ideally be upstream in a generated
|
||||
// crate one day but for now we manually define them.
|
||||
type HTMLDocument;
|
||||
static document: HTMLDocument;
|
||||
#[wasm_bindgen(method, js_name = getElementById)]
|
||||
fn get_element_by_id(this: &HTMLDocument, id: &str) -> Element;
|
||||
#[wasm_bindgen(method, js_name = getElementById)]
|
||||
fn get_html_element_by_id(this: &HTMLDocument, id: &str) -> HTMLElement;
|
||||
// One of the first interesting things we can do with closures is simply
|
||||
// access stack data in Rust!
|
||||
let array = Array::new();
|
||||
array.push(&"Hello".into());
|
||||
array.push(&1.into());
|
||||
let mut first_item = None;
|
||||
array.for_each(&mut |obj, idx, _arr| {
|
||||
match idx {
|
||||
0 => {
|
||||
assert_eq!(obj, "Hello");
|
||||
first_item = obj.as_string();
|
||||
}
|
||||
1 => assert_eq!(obj, 1),
|
||||
_ => panic!("unknown index: {}", idx)
|
||||
}
|
||||
});
|
||||
assert_eq!(first_item, Some("Hello".to_string()));
|
||||
|
||||
type Element;
|
||||
#[wasm_bindgen(method, setter = innerHTML)]
|
||||
fn set_inner_html(this: &Element, html: &str);
|
||||
// Below are some more advanced usages of the `Closure` type for closures
|
||||
// that need to live beyond our function call.
|
||||
|
||||
type HTMLElement;
|
||||
#[wasm_bindgen(method, setter)]
|
||||
fn set_onclick(this: &HTMLElement, cb: &Closure<FnMut()>);
|
||||
#[wasm_bindgen(method, getter)]
|
||||
fn style(this: &HTMLElement) -> CSS2Properties;
|
||||
setup_clock(&window, &document)?;
|
||||
setup_clicker(&document);
|
||||
|
||||
type CSS2Properties;
|
||||
#[wasm_bindgen(method, setter)]
|
||||
fn set_display(this: &CSS2Properties, display: &str);
|
||||
// And now that our demo is ready to go let's switch things up so
|
||||
// everything is displayed and our loading prompt is hidden.
|
||||
document
|
||||
.get_element_by_id("loading")
|
||||
.expect("should have #loading on the page")
|
||||
.dyn_ref::<HtmlElement>()
|
||||
.expect("#loading should be an `HtmlElement`")
|
||||
.style()
|
||||
.set_property("display", "none")?;
|
||||
document
|
||||
.get_element_by_id("script")
|
||||
.expect("should have #script on the page")
|
||||
.dyn_ref::<HtmlElement>()
|
||||
.expect("#script should be an `HtmlElement`")
|
||||
.style()
|
||||
.set_property("display", "block")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn run() {
|
||||
// Set up a clock on our page and update it each second to ensure it's got
|
||||
// an accurate date.
|
||||
let a = Closure::new(update_time);
|
||||
set_interval(&a, 1000);
|
||||
update_time();
|
||||
fn update_time() {
|
||||
document
|
||||
.get_element_by_id("current-time")
|
||||
// Set up a clock on our page and update it each second to ensure it's got
|
||||
// an accurate date.
|
||||
//
|
||||
// Note the usage of `Closure` here because the closure is "long lived",
|
||||
// basically meaning it has to persist beyond the call to this one function.
|
||||
// Also of note here is the `.as_ref().unchecked_ref()` chain, which is who
|
||||
// you can extract `&Function`, what `web-sys` expects, from a `Closure`
|
||||
// which only hands you `&JsValue` via `AsRef`.
|
||||
fn setup_clock(window: &Window, document: &Document) -> Result<(), JsValue> {
|
||||
let current_time = document
|
||||
.get_element_by_id("current-time")
|
||||
.expect("should have #current-time on the page");
|
||||
update_time(¤t_time);
|
||||
let a = Closure::wrap(Box::new(move || {
|
||||
update_time(¤t_time)
|
||||
}) as Box<Fn()>);
|
||||
window.set_interval_with_callback_and_timeout_and_arguments_0(
|
||||
a.as_ref().unchecked_ref(),
|
||||
1000,
|
||||
)?;
|
||||
fn update_time(current_time: &Element) {
|
||||
current_time
|
||||
.set_inner_html(&String::from(
|
||||
Date::new(&JsValue::undefined())
|
||||
.to_locale_string("en-GB", &JsValue::undefined()),
|
||||
Date::new_0().to_locale_string("en-GB", &JsValue::undefined()),
|
||||
));
|
||||
}
|
||||
|
||||
// We also want to count the number of times that our green square has been
|
||||
// clicked. Our callback will update the `#num-clicks` div
|
||||
let square = document.get_html_element_by_id("green-square");
|
||||
let mut clicks = 0;
|
||||
let b = Closure::new(move || {
|
||||
clicks += 1;
|
||||
document
|
||||
.get_element_by_id("num-clicks")
|
||||
.set_inner_html(&clicks.to_string());
|
||||
});
|
||||
square.set_onclick(&b);
|
||||
|
||||
// The instances of `Closure` that we created will invalidate their
|
||||
// corresponding JS callback whenever they're dropped, so if we were to
|
||||
// normally return from `run` then both of our registered closures will
|
||||
@ -79,16 +93,29 @@ pub fn run() {
|
||||
// `forget` method to drop them without invalidating the closure. Note that
|
||||
// this is leaking memory in Rust, so this should be done judiciously!
|
||||
a.forget();
|
||||
b.forget();
|
||||
|
||||
// And finally now that our demo is ready to go let's switch things up so
|
||||
// everything is displayed and our loading prompt is hidden.
|
||||
document
|
||||
.get_html_element_by_id("loading")
|
||||
.style()
|
||||
.set_display("none");
|
||||
document
|
||||
.get_html_element_by_id("script")
|
||||
.style()
|
||||
.set_display("block");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// We also want to count the number of times that our green square has been
|
||||
// clicked. Our callback will update the `#num-clicks` div.
|
||||
//
|
||||
// This is pretty similar above, but showing how closures can also implement
|
||||
// `FnMut()`.
|
||||
fn setup_clicker(document: &Document) {
|
||||
let num_clicks = document
|
||||
.get_element_by_id("num-clicks")
|
||||
.expect("should have #num-clicks on the page");
|
||||
let mut clicks = 0;
|
||||
let a = Closure::wrap(Box::new(move || {
|
||||
clicks += 1;
|
||||
num_clicks.set_inner_html(&clicks.to_string());
|
||||
}) as Box<FnMut()>);
|
||||
document
|
||||
.get_element_by_id("green-square")
|
||||
.expect("should have #green-square on the page")
|
||||
.dyn_ref::<HtmlElement>()
|
||||
.expect("#green-square be an `HtmlElement`")
|
||||
.set_onclick(Some(a.as_ref().unchecked_ref()));
|
||||
a.forget();
|
||||
}
|
||||
|
@ -1,14 +0,0 @@
|
||||
[package]
|
||||
name = "comments"
|
||||
version = "0.1.0"
|
||||
authors = ["robert masen <r@robertmasen.pizza>"]
|
||||
|
||||
[dependencies]
|
||||
# Here we're using a path dependency to use what's already in this repository,
|
||||
# but you'd use the commented out version below if you're copying this into your
|
||||
# project.
|
||||
wasm-bindgen = { path = "../.." }
|
||||
#wasm-bindgen = "0.2"
|
||||
|
||||
[lib]
|
||||
crate-type = ['cdylib']
|
@ -1,16 +0,0 @@
|
||||
# Comments
|
||||
|
||||
This directory is an example of how the `#[wasm_bindgen]` macro will
|
||||
move your Rust doc comments to [JSDoc](http://usejsdoc.org/) comments
|
||||
|
||||
You can build the example locally with:
|
||||
|
||||
```
|
||||
$ ./build.sh
|
||||
```
|
||||
|
||||
(or running the two commands on Windows manually)
|
||||
|
||||
You should see the doc comments have been copied into the `comments.js` file.
|
||||
|
||||
If you wanted to run the project itself, simply run `npm run serve`
|
@ -1,20 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -ex
|
||||
# Build the comments project
|
||||
cargo +nightly build --target wasm32-unknown-unknown
|
||||
|
||||
# Run the `wasm-bindgen` CLI tool to postprocess the wasm file emitted by the
|
||||
# Rust compiler to emit the JS support glue that's necessary
|
||||
#
|
||||
# Here we're using the version of the CLI in this repository, but for external
|
||||
# usage you'd use the commented out version below
|
||||
cargo +nightly run --manifest-path ../../crates/cli/Cargo.toml \
|
||||
--bin wasm-bindgen -- \
|
||||
../../target/wasm32-unknown-unknown/debug/comments.wasm --out-dir .
|
||||
# wasm-bindgen ../../target/wasm32-unknown-unknown/hello_world.wasm --out-dir .
|
||||
|
||||
# Finally, package everything up using Webpack and start a server so we can
|
||||
# browse the result
|
||||
npm install
|
||||
npm run serve
|
@ -1,90 +0,0 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta content="text/html;charset=utf-8" http-equiv="Content-Type"/>
|
||||
</head>
|
||||
<style>
|
||||
body > * {
|
||||
font-family: sans-serif;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
#comments {
|
||||
width: 500px;
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
margin: auto;
|
||||
background: darkgrey;
|
||||
padding: 5px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
#comments > .comment {
|
||||
width: calc(100% - 14px);
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
margin-bottom: 5px;
|
||||
padding: 5px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
#comments > .comment.blue {
|
||||
border: 2px solid lightcyan;
|
||||
}
|
||||
#comments > .comment.pink {
|
||||
border: 2px solid lightpink;
|
||||
}
|
||||
#comments > .comment > .comment-top {
|
||||
display: flex;
|
||||
flex-flow: row;
|
||||
}
|
||||
#comments > .comment > .comment-top > .count {
|
||||
margin: 0 5px;
|
||||
}
|
||||
#comments > .comment > .comment-bottom {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
justify-content: flex-start;
|
||||
align-items: flex-start;
|
||||
}
|
||||
#comments > .comment > .comment-bottom > .comment-title {
|
||||
font-weight: bold;
|
||||
text-decoration: underline;
|
||||
}
|
||||
#comments > .comment > .comment-bottom > .comment-text {
|
||||
background: white;
|
||||
margin-top: 5px;
|
||||
padding: 5px;
|
||||
border-radius: 5px;
|
||||
width: calc(100% - 10px);
|
||||
}
|
||||
#new-comment {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
align-items: flex-end;
|
||||
width: 500px;
|
||||
margin: auto;
|
||||
}
|
||||
#new-comment > .input-group {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
justify-content: flex-start;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<div id="comments"></div>
|
||||
<div id="input-container">
|
||||
<form id="new-comment">
|
||||
<div class="input-group">
|
||||
<label for="name">Name</label>
|
||||
<input type="text" id="name" required validation-message="name is required" />
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<label for="name">Comment</label>
|
||||
<textarea type="text" id="comment" required validation-message="comment is required" ></textarea>
|
||||
</div>
|
||||
<button type="button" id="add-comment-button">Add</button>
|
||||
</form>
|
||||
<span id="error"></span>
|
||||
</div>
|
||||
<script src='./index.js'></script>
|
||||
</body>
|
||||
</html>
|
@ -1,141 +0,0 @@
|
||||
/* eslint-disable no-unused-vars */
|
||||
const mod = import('./comments');
|
||||
let wasm;
|
||||
mod.then(m => {
|
||||
wasm = m;
|
||||
let button = document.getElementById('add-comment-button');
|
||||
if (!button) return console.error('Unable to find add button');
|
||||
button.addEventListener('click', newComment);
|
||||
displayComments();
|
||||
});
|
||||
|
||||
/**
|
||||
* Click event handler for add button
|
||||
* @param {MouseEvent} ev
|
||||
*/
|
||||
function newComment(ev) {
|
||||
clearError();
|
||||
let name = document.getElementById('name');
|
||||
if (!name) return console.error('Failed to find name input');
|
||||
if (name.value == '') return displayError('Name cannot be blank');
|
||||
let comment = document.getElementById('comment');
|
||||
if (!comment) return console.error('Failed to find comment input');
|
||||
if (comment.value == '') return displayError('comment cannot be blank');
|
||||
addComment(name.value, comment.value);
|
||||
name.form.reset();
|
||||
displayComments();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a comment to the list
|
||||
* @param {string} name The name of the person submitting
|
||||
* @param {string} content The actual text of the comment
|
||||
*/
|
||||
function addComment(name, content) {
|
||||
let existing = comments();
|
||||
let count = existing.length;
|
||||
existing.push(new wasm.Comment(name, content, count));
|
||||
storeComments();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the rust comments to JSON comments and store
|
||||
* in local storage
|
||||
*/
|
||||
function storeComments() {
|
||||
let json = comments().map(c => {
|
||||
console.log('mapping comments for storage', c);
|
||||
return {
|
||||
name: c.name(),
|
||||
comment: c.comment(),
|
||||
count: c.count,
|
||||
};
|
||||
});
|
||||
localStorage.setItem('comments', JSON.stringify(json));
|
||||
}
|
||||
/**
|
||||
* Get the comments from local storage and convert them to
|
||||
* rust comments
|
||||
*/
|
||||
function getComments() {
|
||||
let json = localStorage.getItem('comments');
|
||||
if (!json) return [];
|
||||
let raw = JSON.parse(json);
|
||||
return raw.map(c => new wasm.Comment(c.name, c.comment, c.count));
|
||||
}
|
||||
|
||||
/**A in memory cache of the localStorage comments for this site */
|
||||
let cachedComments = null;
|
||||
/**
|
||||
* Get a list of comments for this page
|
||||
* @param {boolean} refresh force a refresh from localStorage
|
||||
*/
|
||||
function comments(refresh = false) {
|
||||
if (refresh || !cachedComments) {
|
||||
cachedComments = getComments();
|
||||
}
|
||||
return cachedComments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the comments section and re-render with the
|
||||
* current comments list
|
||||
*/
|
||||
function displayComments() {
|
||||
let node = document.getElementById('comments');
|
||||
if (!node) return console.error('Failed to get comments container');
|
||||
while (node.hasChildNodes()) {
|
||||
node.removeChild(node.lastChild);
|
||||
}
|
||||
for (let comment of comments()) {
|
||||
node.appendChild(renderComment(comment));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the HTML needed to display a single comment
|
||||
* @param {Comment} comment the comment to display
|
||||
* @returns {HTMLDivElement} The div containing the comment html
|
||||
*/
|
||||
function renderComment(comment) {
|
||||
let cls = `comment ${comment.color() == wasm.Color.Blue ? 'blue' : 'pink'}`;
|
||||
let div = document.createElement('div');
|
||||
div.setAttribute('class', cls);
|
||||
let top = document.createElement('div');
|
||||
top.setAttribute('class', 'comment-top');
|
||||
let ct = document.createElement('span');
|
||||
ct.setAttribute('class', 'count');
|
||||
ct.appendChild(document.createTextNode(`${comment.count}:`));
|
||||
let name = document.createElement('span');
|
||||
name.setAttribute('class', 'user-name');
|
||||
name.appendChild(document.createTextNode(`${comment.name()}`));
|
||||
top.appendChild(ct);
|
||||
top.appendChild(name);
|
||||
let bottom = document.createElement('div');
|
||||
bottom.setAttribute('class', 'comment-bottom');
|
||||
let title = document.createElement('span');
|
||||
title.setAttribute('class', 'comment-title');
|
||||
title.appendChild(document.createTextNode('comment'));
|
||||
bottom.appendChild(title);
|
||||
let text = document.createElement('span');
|
||||
text.setAttribute('class', 'comment-text');
|
||||
text.appendChild(document.createTextNode(comment.comment()));
|
||||
bottom.appendChild(text);
|
||||
div.appendChild(top);
|
||||
div.appendChild(bottom);
|
||||
return div;
|
||||
}
|
||||
|
||||
function displayError(message) {
|
||||
let e = document.getElementById('error');
|
||||
if (!e) return console.error('Failed to find error container');
|
||||
if (e.innerHTML != '') return setTimeout(displayError, 1000, message);
|
||||
e.innerHTML = message;
|
||||
setTimeout(clearError, 3000);
|
||||
}
|
||||
|
||||
function clearError() {
|
||||
let e = document.getElementById('error');
|
||||
if (!e) return console.error('Failed to find error container');
|
||||
e.innerHTML = '';
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
{
|
||||
"scripts": {
|
||||
"serve": "webpack-dev-server"
|
||||
},
|
||||
"devDependencies": {
|
||||
"html-webpack-plugin": "^3.2.0",
|
||||
"webpack": "^4.8.1",
|
||||
"webpack-cli": "^2.0.10",
|
||||
"webpack-dev-server": "^3.1.0"
|
||||
}
|
||||
}
|
@ -1,57 +0,0 @@
|
||||
extern crate wasm_bindgen;
|
||||
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[wasm_bindgen]
|
||||
/// A user defined comment
|
||||
pub struct Comment {
|
||||
name: String,
|
||||
comment: String,
|
||||
/// The position this comment
|
||||
/// should exist at
|
||||
pub count: u32,
|
||||
color: Color,
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl Comment {
|
||||
#[wasm_bindgen(method)]
|
||||
/// The name of the user who
|
||||
/// posted this comment
|
||||
pub fn name(&self) -> String {
|
||||
self.name.clone()
|
||||
}
|
||||
#[wasm_bindgen(method)]
|
||||
/// The content of this comment
|
||||
pub fn comment(&self) -> String {
|
||||
self.comment.clone()
|
||||
}
|
||||
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new(name: String, comment: String, count: u32) -> Comment {
|
||||
let color = if count % 2 == 0 {
|
||||
Color::Blue
|
||||
} else {
|
||||
Color::Pink
|
||||
};
|
||||
Comment {
|
||||
name,
|
||||
comment,
|
||||
count,
|
||||
color,
|
||||
}
|
||||
}
|
||||
#[wasm_bindgen(method)]
|
||||
/// What color should this comment be
|
||||
pub fn color(&self) -> Color {
|
||||
self.color.clone()
|
||||
}
|
||||
}
|
||||
|
||||
/// The border of a comment
|
||||
#[wasm_bindgen]
|
||||
#[derive(Clone)]
|
||||
pub enum Color {
|
||||
Blue,
|
||||
Pink,
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
const path = require('path');
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||
|
||||
module.exports = {
|
||||
entry: './index.js',
|
||||
output: {
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
filename: 'index.js',
|
||||
},
|
||||
plugins: [
|
||||
new HtmlWebpackPlugin({
|
||||
template: "index.html"
|
||||
})
|
||||
],
|
||||
mode: 'development',
|
||||
devtool: 'source-map',
|
||||
};
|
@ -8,3 +8,4 @@ crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
wasm-bindgen = { path = "../.." }
|
||||
web-sys = { path = '../../crates/web-sys' }
|
||||
|
@ -1,13 +1,10 @@
|
||||
# `console.log`
|
||||
|
||||
[View this example online](https://webassembly.studio/?f=ppd7u8k9i9)
|
||||
[View documentation for this example online][dox]
|
||||
|
||||
[dox]: https://rustwasm.github.io/wasm-bindgen/examples/console-log.html
|
||||
|
||||
This directory is an example of two ways to get access to the `console.log` function.
|
||||
The first way uses the `#[wasm_bindgen]` macro to import the function and call it.
|
||||
The second way uses the binding from the `web-sys` crate.
|
||||
|
||||
You can build the example with:
|
||||
You can build the example locally with:
|
||||
|
||||
```
|
||||
$ ./build.sh
|
||||
@ -15,9 +12,4 @@ $ ./build.sh
|
||||
|
||||
(or running the commands on Windows manually)
|
||||
|
||||
and then opening up `index.html` in a web browser should show a dialog!
|
||||
|
||||
For more information about this example be sure to check out
|
||||
[`hello_world`][hello] which also has more comments about caveats and such.
|
||||
|
||||
[hello]: https://github.com/rustwasm/wasm-bindgen/tree/master/examples/hello_world
|
||||
and then visiting http://localhost:8080 in a browser should run the example!
|
||||
|
@ -3,7 +3,6 @@
|
||||
<meta content="text/html;charset=utf-8" http-equiv="Content-Type"/>
|
||||
</head>
|
||||
<body>
|
||||
<script src='./index.js'></script>
|
||||
<p>Open up the developer console and you should see "Hello from Rust!"</p>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -1,21 +1,69 @@
|
||||
extern crate wasm_bindgen;
|
||||
extern crate web_sys;
|
||||
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
// ... or you can manually write the bindings yourself
|
||||
#[wasm_bindgen]
|
||||
pub fn run() {
|
||||
bare_bones();
|
||||
using_a_macro();
|
||||
using_web_sys();
|
||||
}
|
||||
|
||||
// First up let's take a look of binding `console.log` manually, without the
|
||||
// help of `web_sys`. Here we're writing the `#[wasm_bindgen]` annotations
|
||||
// manually ourselves, and the correctness of our program relies on the
|
||||
// correctness of these annotations!
|
||||
|
||||
#[wasm_bindgen]
|
||||
extern "C" {
|
||||
// Use `js_namespace` here to bind `console.log(..)` instead of just
|
||||
// `log(..)`
|
||||
#[wasm_bindgen(js_namespace = console)]
|
||||
fn log(s: &str);
|
||||
|
||||
// The `console.log` is quite polymorphic, so we can bind it with multiple
|
||||
// signatures. Note that we need to use `js_name` to ensure we always call
|
||||
// `log` in JS.
|
||||
#[wasm_bindgen(js_namespace = console, js_name = log)]
|
||||
fn log_u32(a: u32);
|
||||
|
||||
// Multiple arguments too!
|
||||
#[wasm_bindgen(js_namespace = console, js_name = log)]
|
||||
fn log_many(a: &str, b: &str);
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn run() {
|
||||
fn bare_bones() {
|
||||
log("Hello from Rust!");
|
||||
log_u32(42);
|
||||
log_many("Logging", "many values!");
|
||||
}
|
||||
|
||||
// Next let's define a macro that's like `println!`, only it works for
|
||||
// `console.log`. Note that `println!` doesn't actually work on the wasm target
|
||||
// because the standard library currently just eats all output. To get
|
||||
// `println!`-like behavior in your app you'll likely want a macro like this.
|
||||
|
||||
macro_rules! console_log {
|
||||
// Note that this is using the `log` function imported above during
|
||||
// `bare_bones`
|
||||
($($t:tt)*) => (log(&format_args!($($t)*).to_string()))
|
||||
}
|
||||
|
||||
fn using_a_macro() {
|
||||
console_log!("Hello {}!", "world");
|
||||
console_log!("Let's print some numbers...");
|
||||
console_log!("1 + 3 = {}", 1 + 3);
|
||||
}
|
||||
|
||||
// And finally, we don't even have to define the `log` function ourselves! The
|
||||
// `web_sys` crate already has it defined for us.
|
||||
|
||||
fn using_web_sys() {
|
||||
use web_sys::console;
|
||||
|
||||
console::log_1(&"Hello using web-sys".into());
|
||||
|
||||
let js: JsValue = 4.into();
|
||||
console::log_2(&"Logging arbitrary values looks like".into(), &js);
|
||||
}
|
||||
|
@ -1,10 +1,20 @@
|
||||
[package]
|
||||
name = "dom"
|
||||
version = "0.1.0"
|
||||
authors = ["Alex Crichton <alex@alexcrichton.com>"]
|
||||
authors = ["The wasm-bindgen Developers"]
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
wasm-bindgen = { path = "../.." }
|
||||
|
||||
[dependencies.web-sys]
|
||||
path = '../../crates/web-sys'
|
||||
features = [
|
||||
'Document',
|
||||
'Element',
|
||||
'HtmlElement',
|
||||
'Node',
|
||||
'Window',
|
||||
]
|
||||
|
@ -1,13 +1,10 @@
|
||||
# DOM access
|
||||
# web-sys: DOM hello world
|
||||
|
||||
[View this example online](https://webassembly.studio/?f=54xnz04tcke)
|
||||
[View documentation for this example online][dox]
|
||||
|
||||
This directory is an example of using the `#[wasm_bindgen]` macro to interact
|
||||
with the DOM, specifically the `document` object. You'll see here a few examples
|
||||
of defining access to the global `document` variable as well as appending a new
|
||||
HTML node to it.
|
||||
[dox]: https://rustwasm.github.io/wasm-bindgen/examples/dom.html
|
||||
|
||||
You can build the example with:
|
||||
You can build the example locally with:
|
||||
|
||||
```
|
||||
$ ./build.sh
|
||||
@ -15,10 +12,4 @@ $ ./build.sh
|
||||
|
||||
(or running the commands on Windows manually)
|
||||
|
||||
and then opening up `index.html` in a web browser should show a hello message on
|
||||
the web page generated by the wasm.
|
||||
|
||||
For more information about this example be sure to check out
|
||||
[`hello_world`][hello] which also has more comments about caveats and such.
|
||||
|
||||
[hello]: https://github.com/alexcrichton/wasm-bindgen/tree/master/examples/hello_world
|
||||
and then visiting http://localhost:8080 in a browser should run the example!
|
||||
|
@ -3,7 +3,6 @@
|
||||
<meta content="text/html;charset=utf-8" http-equiv="Content-Type"/>
|
||||
</head>
|
||||
<body>
|
||||
<script src='./index.js'></script>
|
||||
<p>A greeting from rust looks like...</p>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -1,37 +1,25 @@
|
||||
extern crate wasm_bindgen;
|
||||
extern crate web_sys;
|
||||
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
// Definitions of the functionality available in JS, which wasm-bindgen will
|
||||
// generate shims for today (and eventually these should be near-0 cost!)
|
||||
//
|
||||
// These definitions need to be hand-written today but the current vision is
|
||||
// that we'll use WebIDL to generate this `extern` block into a crate which you
|
||||
// can link and import. There's a tracking issue for this at
|
||||
// https://github.com/rustwasm/wasm-bindgen/issues/42
|
||||
//
|
||||
// In the meantime these are written out by hand and correspond to the names and
|
||||
// signatures documented on MDN, for example
|
||||
#[wasm_bindgen]
|
||||
extern "C" {
|
||||
type HTMLDocument;
|
||||
static document: HTMLDocument;
|
||||
#[wasm_bindgen(method)]
|
||||
fn createElement(this: &HTMLDocument, tagName: &str) -> Element;
|
||||
#[wasm_bindgen(method, getter)]
|
||||
fn body(this: &HTMLDocument) -> Element;
|
||||
|
||||
type Element;
|
||||
#[wasm_bindgen(method, setter = innerHTML)]
|
||||
fn set_inner_html(this: &Element, html: &str);
|
||||
#[wasm_bindgen(method, js_name = appendChild)]
|
||||
fn append_child(this: &Element, other: Element);
|
||||
}
|
||||
|
||||
// Called by our JS entry point to run the example
|
||||
#[wasm_bindgen]
|
||||
pub fn run() {
|
||||
let val = document.createElement("p");
|
||||
pub fn run() -> Result<(), JsValue> {
|
||||
// Use `web_sys`'s global `window` function to get a handle on the global
|
||||
// window object.
|
||||
let window = web_sys::window().expect("no global `window` exists");
|
||||
let document = window.document().expect("should have a document on window");
|
||||
let body = document.body().expect("document should have a body");
|
||||
|
||||
// Manufacture the element we're gonna append
|
||||
let val = document.create_element("p")?;
|
||||
val.set_inner_html("Hello from Rust!");
|
||||
document.body().append_child(val);
|
||||
|
||||
// Right now the class inheritance hierarchy of the DOM isn't super
|
||||
// ergonomic, so we manually cast `val: Element` to `&Node` to call the
|
||||
// `append_child` method.
|
||||
AsRef::<web_sys::Node>::as_ref(&body).append_child(val.as_ref())?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
16
examples/fetch/README.md
Normal file
16
examples/fetch/README.md
Normal file
@ -0,0 +1,16 @@
|
||||
# The `fetch` API
|
||||
|
||||
[View documentation for this example online][dox]
|
||||
|
||||
[dox]: https://rustwasm.github.io/wasm-bindgen/examples/fetch.html
|
||||
|
||||
You can build the example locally with:
|
||||
|
||||
```
|
||||
$ ./build.sh
|
||||
```
|
||||
|
||||
(or running the commands on Windows manually)
|
||||
|
||||
and then visiting http://localhost:8080 in a browser should run the example!
|
||||
|
@ -1,2 +0,0 @@
|
||||
cargo +nightly build --target wasm32-unknown-unknown
|
||||
cargo +nightly run --manifest-path ../../crates/cli/Cargo.toml --bin wasm-bindgen -- ../../target/wasm32-unknown-unknown/debug/fetch.wasm --out-dir .
|
@ -1,61 +0,0 @@
|
||||
# Adding Numbers
|
||||
|
||||
[View this example online](https://webassembly.studio/?f=612vwsrmwft)
|
||||
|
||||
This directory is an example of using the `#[wasm_bindgen]` macro to simply add
|
||||
two numbers. The neat part about this is that it's an example of how to generate
|
||||
the smallest wasm-bindgen binary.
|
||||
|
||||
You can build the example with:
|
||||
|
||||
```
|
||||
$ ./build.sh
|
||||
```
|
||||
|
||||
(or running the commands on Windows manually)
|
||||
|
||||
Currently this generates a 651 byte wasm binary:
|
||||
|
||||
```
|
||||
$ ls -alh add_bg.wasm
|
||||
-rw-rw-r-- 1 alex alex 651 Apr 20 22:16 add_bg.wasm
|
||||
```
|
||||
|
||||
If you run [wasm-opt], a C++ tool for optimize WebAssembly, you can make it even
|
||||
smaller too!
|
||||
|
||||
```
|
||||
$ wasm-opt -Os add_bg.wasm -o add.wasm
|
||||
$ ls -alh add.wasm
|
||||
-rw-rw-r-- 1 alex alex 100 Apr 20 22:19 add.wasm
|
||||
```
|
||||
|
||||
And sure enough, using the [wasm2wat] tool it's quite small!
|
||||
|
||||
```
|
||||
$ wasm2wat add.wasm
|
||||
(module
|
||||
(type (;0;) (func (param i32 i32) (result i32)))
|
||||
(func (;0;) (type 0) (param i32 i32) (result i32)
|
||||
get_local 1
|
||||
get_local 0
|
||||
i32.add)
|
||||
(memory (;0;) 2)
|
||||
(export "memory" (memory 0))
|
||||
(export "add" (func 0))
|
||||
(data (i32.const 1545) "invalid malloc request"))
|
||||
```
|
||||
|
||||
Note that it's important to point out that the size reductions here are because
|
||||
the wasm is compiled in release mode by the build script and this crate's
|
||||
workspace has the following configuration
|
||||
|
||||
```toml
|
||||
[profile.release]
|
||||
lto = true
|
||||
opt-level = 's'
|
||||
panic = 'abort'
|
||||
```
|
||||
|
||||
[wasm2wat]: https://github.com/webassembly/wabt
|
||||
[wasm-opt]: https://github.com/webassembly/binaryen
|
@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "hello_world"
|
||||
version = "0.1.0"
|
||||
authors = ["Alex Crichton <alex@alexcrichton.com>"]
|
||||
authors = ["The wasm-bindgen Developers"]
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
@ -1,9 +1,8 @@
|
||||
# Hello, World!
|
||||
|
||||
[View this example online](https://webassembly.studio/?f=gzubao6tg3)
|
||||
[View documentation for this example online][dox]
|
||||
|
||||
This directory is an example of using the `#[wasm_bindgen]` macro to create an
|
||||
entry point that's called from the browser and then displays a dialog.
|
||||
[dox]: https://rustwasm.github.io/wasm-bindgen/examples/hello-world.html
|
||||
|
||||
You can build the example locally with:
|
||||
|
||||
@ -11,6 +10,6 @@ You can build the example locally with:
|
||||
$ ./build.sh
|
||||
```
|
||||
|
||||
(or running the two commands on Windows manually)
|
||||
(or running the commands on Windows manually)
|
||||
|
||||
and then opening up `index.html` in a web browser should show a dialog!
|
||||
and then visiting http://localhost:8080 in a browser should show a dialog!
|
||||
|
@ -1,9 +1,10 @@
|
||||
# Importing non-browser JS
|
||||
|
||||
This directory is an example of using the `#[wasm_bindgen]` macro to import the
|
||||
JS defined by you rather than the browser.
|
||||
[View documentation for this example online][dox]
|
||||
|
||||
You can build the example with:
|
||||
[dox]: https://rustwasm.github.io/wasm-bindgen/examples/import-js.html
|
||||
|
||||
You can build the example locally with:
|
||||
|
||||
```
|
||||
$ ./build.sh
|
||||
@ -11,10 +12,4 @@ $ ./build.sh
|
||||
|
||||
(or running the commands on Windows manually)
|
||||
|
||||
and then opening up `index.html` in a web browser and see some messages in the
|
||||
console.
|
||||
|
||||
For more information about this example be sure to check out
|
||||
[`hello_world`][hello] which also has more comments about caveats and such.
|
||||
|
||||
[hello]: https://github.com/alexcrichton/wasm-bindgen/tree/master/examples/hello_world
|
||||
and then visiting http://localhost:8080 in a browser should run the example!
|
||||
|
@ -3,7 +3,6 @@
|
||||
<meta content="text/html;charset=utf-8" http-equiv="Content-Type"/>
|
||||
</head>
|
||||
<body>
|
||||
<script src='./index.js'></script>
|
||||
<p>Open up the developer console and you should see "Hello from Rust!"</p>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -19,7 +19,7 @@ extern "C" {
|
||||
fn render(this: &MyClass) -> String;
|
||||
}
|
||||
|
||||
// Import `console.log` so we can log something to the console
|
||||
// lifted from the `console_log` example
|
||||
#[wasm_bindgen]
|
||||
extern "C" {
|
||||
#[wasm_bindgen(js_namespace = console)]
|
||||
|
@ -8,3 +8,11 @@ crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
wasm-bindgen = { path = "../.." }
|
||||
js-sys = { path = '../../crates/js-sys' }
|
||||
|
||||
[dependencies.web-sys]
|
||||
path = '../../crates/web-sys'
|
||||
features = [
|
||||
'ImageData',
|
||||
'CanvasRenderingContext2d',
|
||||
]
|
||||
|
@ -1,14 +1,15 @@
|
||||
# Julia Set
|
||||
|
||||
[View this example online](https://webassembly.studio/?f=qmg1c6dbjos)
|
||||
[View documentation for this example online][dox]
|
||||
|
||||
This is an example of more complex computations needed to generate a fractal (Julia Set).
|
||||
It's also an example of direct interaction with CanvasRenderingContext2D's API via `#[wasm_bindgen]` macro.
|
||||
[dox]: https://rustwasm.github.io/wasm-bindgen/examples/julia.html
|
||||
|
||||
You can build the example with:
|
||||
You can build the example locally with:
|
||||
|
||||
```
|
||||
$ ./build.sh
|
||||
```
|
||||
|
||||
(or running the commands on Windows manually)
|
||||
|
||||
and then visiting http://localhost:8080 in a browser should run the example!
|
||||
|
@ -21,6 +21,5 @@
|
||||
</div>
|
||||
<canvas id="drawing" width="600" height="600"></canvas>
|
||||
</main>
|
||||
<script src='./index.js'></script>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -1,27 +0,0 @@
|
||||
use std::ops::Add;
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Complex {
|
||||
pub real: f64,
|
||||
pub imaginary: f64,
|
||||
}
|
||||
|
||||
impl Complex {
|
||||
pub fn square(self) -> Complex {
|
||||
let real = (self.real * self.real) - (self.imaginary * self.imaginary);
|
||||
let imaginary = 2.0 * self.real * self.imaginary;
|
||||
Complex { real, imaginary }
|
||||
}
|
||||
|
||||
pub fn norm(&self) -> f64 {
|
||||
(self.real * self.real) + (self.imaginary * self.imaginary)
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<Complex> for Complex {
|
||||
type Output = Complex;
|
||||
|
||||
fn add(self, rhs: Complex) -> Complex {
|
||||
Complex { real: self.real + rhs.real, imaginary: self.imaginary + rhs.imaginary }
|
||||
}
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
pub mod complex;
|
||||
use self::complex::Complex;
|
||||
|
||||
fn get_iter_index(z: Complex, c: Complex) -> u32 {
|
||||
let mut iter_index: u32 = 0;
|
||||
let mut z = z;
|
||||
while iter_index < 900 {
|
||||
if z.norm() > 2.0 {
|
||||
break
|
||||
}
|
||||
z = z.square() + c;
|
||||
iter_index += 1;
|
||||
}
|
||||
iter_index
|
||||
}
|
||||
|
||||
pub fn get_julia_set(width: u32, height: u32, c: Complex) -> Vec<u8> {
|
||||
let mut data: Vec<u8> = vec![];
|
||||
|
||||
let param_i = 1.5;
|
||||
let param_r = 1.5;
|
||||
let scale = 0.005;
|
||||
|
||||
for x in 0..width {
|
||||
for y in 0..height {
|
||||
let z = Complex { real: y as f64 * scale - param_r, imaginary: x as f64 * scale - param_i };
|
||||
let iter_index = get_iter_index(z, c);
|
||||
data.push((iter_index / 4) as u8);
|
||||
data.push((iter_index / 2) as u8);
|
||||
data.push(iter_index as u8);
|
||||
data.push(255);
|
||||
}
|
||||
}
|
||||
|
||||
data
|
||||
}
|
@ -1,39 +1,115 @@
|
||||
extern crate js_sys;
|
||||
extern crate wasm_bindgen;
|
||||
extern crate web_sys;
|
||||
|
||||
use std::ops::Add;
|
||||
use wasm_bindgen::JsCast;
|
||||
use wasm_bindgen::prelude::*;
|
||||
use web_sys::CanvasRenderingContext2d;
|
||||
use js_sys::{WebAssembly, Uint8ClampedArray};
|
||||
|
||||
mod fractal;
|
||||
use fractal::get_julia_set;
|
||||
use fractal::complex::Complex;
|
||||
|
||||
// Unfortunately `web-sys` at this time doesn't bind APIs with
|
||||
// `Uint8ClampedArray`. For more information see rustwasm/wasm-bindgen#421.
|
||||
//
|
||||
// For now we just bind it ourselves and do some manual frobbing below.
|
||||
#[wasm_bindgen]
|
||||
extern "C" {
|
||||
pub type ImageData;
|
||||
type ImageData;
|
||||
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new(arr: &Uint8ClampedArray, width: u32, height: u32) -> ImageData;
|
||||
fn new(arr: &Uint8ClampedArray, width: u32, height: u32) -> ImageData;
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
extern "C" {
|
||||
pub type Uint8ClampedArray;
|
||||
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new(arr: &[u8]) -> Uint8ClampedArray;
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
extern "C" {
|
||||
pub type CanvasRenderingContext2D;
|
||||
|
||||
#[wasm_bindgen(method, js_name = putImageData)]
|
||||
pub fn put_image_data(this: &CanvasRenderingContext2D, image_data: &ImageData, p_1: i32, p_2: i32);
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn draw(ctx: &CanvasRenderingContext2D, width: u32, height: u32, real: f64, imaginary: f64) {
|
||||
let c = Complex { real, imaginary };
|
||||
pub fn draw(
|
||||
ctx: &CanvasRenderingContext2d,
|
||||
width: u32,
|
||||
height: u32,
|
||||
real: f64,
|
||||
imaginary: f64,
|
||||
) -> Result<(), JsValue> {
|
||||
// The real workhorse of this algorithm, generating pixel data
|
||||
let c = Complex { real, imaginary, };
|
||||
let data = get_julia_set(width, height, c);
|
||||
let uint8_array = Uint8ClampedArray::new(&data);
|
||||
|
||||
ctx.put_image_data(&ImageData::new(&uint8_array, width, height), 0, 0);
|
||||
// And now that we've got some pixels, let's create an `ImageData` with the
|
||||
// pixels and then ship it off to the canvas.
|
||||
//
|
||||
// See notes in the `wasm-in-wasm` example for why this is a bit dangerous
|
||||
let my_memory = wasm_bindgen::memory()
|
||||
.dyn_into::<WebAssembly::Memory>()
|
||||
.unwrap();
|
||||
let uint8_array = Uint8ClampedArray::new(&my_memory.buffer())
|
||||
.subarray(
|
||||
data.as_ptr() as u32,
|
||||
data.as_ptr() as u32 + data.len() as u32,
|
||||
);
|
||||
let data = ImageData::new(&uint8_array, width, height);
|
||||
ctx.put_image_data(data.unchecked_ref(), 0.0, 0.0)
|
||||
}
|
||||
|
||||
fn get_julia_set(width: u32, height: u32, c: Complex) -> Vec<u8> {
|
||||
let mut data = Vec::new();
|
||||
|
||||
let param_i = 1.5;
|
||||
let param_r = 1.5;
|
||||
let scale = 0.005;
|
||||
|
||||
for x in 0..width {
|
||||
for y in 0..height {
|
||||
let z = Complex {
|
||||
real: y as f64 * scale - param_r,
|
||||
imaginary: x as f64 * scale - param_i,
|
||||
};
|
||||
let iter_index = get_iter_index(z, c);
|
||||
data.push((iter_index / 4) as u8);
|
||||
data.push((iter_index / 2) as u8);
|
||||
data.push(iter_index as u8);
|
||||
data.push(255);
|
||||
}
|
||||
}
|
||||
|
||||
data
|
||||
}
|
||||
|
||||
fn get_iter_index(z: Complex, c: Complex) -> u32 {
|
||||
let mut iter_index: u32 = 0;
|
||||
let mut z = z;
|
||||
while iter_index < 900 {
|
||||
if z.norm() > 2.0 {
|
||||
break
|
||||
}
|
||||
z = z.square() + c;
|
||||
iter_index += 1;
|
||||
}
|
||||
iter_index
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
struct Complex {
|
||||
real: f64,
|
||||
imaginary: f64,
|
||||
}
|
||||
|
||||
impl Complex {
|
||||
fn square(self) -> Complex {
|
||||
let real = (self.real * self.real) - (self.imaginary * self.imaginary);
|
||||
let imaginary = 2.0 * self.real * self.imaginary;
|
||||
Complex { real, imaginary }
|
||||
}
|
||||
|
||||
fn norm(&self) -> f64 {
|
||||
(self.real * self.real) + (self.imaginary * self.imaginary)
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<Complex> for Complex {
|
||||
type Output = Complex;
|
||||
|
||||
fn add(self, rhs: Complex) -> Complex {
|
||||
Complex {
|
||||
real: self.real + rhs.real,
|
||||
imaginary: self.imaginary + rhs.imaginary,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
4
examples/math/.gitignore
vendored
4
examples/math/.gitignore
vendored
@ -1,4 +0,0 @@
|
||||
package-lock.json
|
||||
math.js
|
||||
math_bg.js
|
||||
math_bg.wasm
|
@ -1,10 +0,0 @@
|
||||
[package]
|
||||
name = "math"
|
||||
version = "0.1.0"
|
||||
authors = ["Alex Crichton <alex@alexcrichton.com>"]
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
wasm-bindgen = { path = "../.." }
|
@ -1,21 +0,0 @@
|
||||
# `Math`
|
||||
|
||||
[View this example online](https://webassembly.studio/?f=ffnm4kpzmib)
|
||||
|
||||
This directory is an example of using the `#[wasm_bindgen]` macro to import the
|
||||
`Math` object and invoke various functions on it.
|
||||
|
||||
You can build the example with:
|
||||
|
||||
```
|
||||
$ ./build.sh
|
||||
```
|
||||
|
||||
(or running the commands on Windows manually)
|
||||
|
||||
and then opening up `index.html` in a web browser should show a dialog!
|
||||
|
||||
For more information about this example be sure to check out
|
||||
[`hello_world`][hello] which also has more comments about caveats and such.
|
||||
|
||||
[hello]: https://github.com/alexcrichton/wasm-bindgen/tree/master/examples/hello_world
|
@ -1,12 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
# For more coments about what's going on here, see the `hello_world` example
|
||||
|
||||
set -ex
|
||||
|
||||
cargo +nightly build --target wasm32-unknown-unknown
|
||||
cargo +nightly run --manifest-path ../../crates/cli/Cargo.toml \
|
||||
--bin wasm-bindgen -- \
|
||||
../../target/wasm32-unknown-unknown/debug/math.wasm --out-dir .
|
||||
npm install
|
||||
npm run serve
|
@ -1,10 +0,0 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta content="text/html;charset=utf-8" http-equiv="Content-Type"/>
|
||||
</head>
|
||||
<body>
|
||||
<script src='./index.js'></script>
|
||||
<p>Open the developer console and you should see wasm invoking `Math`
|
||||
functions</p>
|
||||
</body>
|
||||
</html>
|
@ -1,10 +0,0 @@
|
||||
// For more comments about what's going on here, check out the `hello_world`
|
||||
// example
|
||||
const rust = import('./math');
|
||||
|
||||
rust.then(m => {
|
||||
m.run();
|
||||
console.log('and in JS the answers look like:');
|
||||
console.log(`Math.log2(10.0) = ${Math.log2(10.0)}`);
|
||||
console.log(`Math.sin(1.2) = ${Math.sin(1.2)}`);
|
||||
});
|
@ -1,11 +0,0 @@
|
||||
{
|
||||
"scripts": {
|
||||
"serve": "webpack-dev-server"
|
||||
},
|
||||
"devDependencies": {
|
||||
"html-webpack-plugin": "^3.2.0",
|
||||
"webpack": "^4.11.1",
|
||||
"webpack-cli": "^2.0.10",
|
||||
"webpack-dev-server": "^3.1.0"
|
||||
}
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
extern crate wasm_bindgen;
|
||||
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[wasm_bindgen]
|
||||
extern "C" {
|
||||
#[wasm_bindgen(js_namespace = Math)]
|
||||
fn log2(a: f64) -> f64;
|
||||
#[wasm_bindgen(js_namespace = Math)]
|
||||
fn sin(a: f64) -> f64;
|
||||
|
||||
#[wasm_bindgen(js_namespace = console)]
|
||||
fn log(a: &str);
|
||||
}
|
||||
|
||||
macro_rules! println {
|
||||
($($t:tt)*) => (log(&format_args!($($t)*).to_string()))
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn run() {
|
||||
println!("Math.log2(10.0) = {}", log2(10.0));
|
||||
println!("Math.sin(1.2) = {}", sin(1.2));
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
const path = require('path');
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||
|
||||
module.exports = {
|
||||
entry: './index.js',
|
||||
output: {
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
filename: 'index.js',
|
||||
},
|
||||
plugins: [
|
||||
new HtmlWebpackPlugin({
|
||||
template: "index.html"
|
||||
})
|
||||
],
|
||||
mode: 'development'
|
||||
};
|
@ -1,10 +1,15 @@
|
||||
# `--no-modules`
|
||||
# Using `--no-modules`
|
||||
|
||||
This directory is an example of using the `--no-modules` flag and how it
|
||||
integrates with the rest of the HTML/JS used.
|
||||
[View documentation for this example online][dox]
|
||||
|
||||
[dox]: https://rustwasm.github.io/wasm-bindgen/examples/no-modules.html
|
||||
|
||||
You can build the example locally with:
|
||||
|
||||
```
|
||||
$ ./build.sh
|
||||
```
|
||||
|
||||
(or running the commands on Windows manually)
|
||||
|
||||
and then opening `index.html` in a browser should run the example!
|
||||
|
@ -3,7 +3,22 @@
|
||||
<meta content="text/html;charset=utf-8" http-equiv="Content-Type"/>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
// The `--no-modules`-generated JS from `wasm-bindgen` attempts to use
|
||||
// `WebAssembly.instantiateStreaming` to instantiate the wasm module,
|
||||
// but this doesn't work with `file://` urls. This example is frequently
|
||||
// viewed by simply opening `index.html` in a browser (with a `file://`
|
||||
// url), so it would fail if we were to call this function!
|
||||
//
|
||||
// Work around this for now by deleting the function to ensure that the
|
||||
// `no_modules.js` script doesn't have access to it. You won't need this
|
||||
// hack when deploying over HTTP.
|
||||
delete WebAssembly.instantiateStreaming;
|
||||
</script>
|
||||
|
||||
<!-- this is the JS generated by the `wasm-bindgen` CLI tool -->
|
||||
<script src='./no_modules.js'></script>
|
||||
|
||||
<script>
|
||||
// the `wasm_bindgen` global is set to the exports of the Rust module
|
||||
const { greet } = wasm_bindgen;
|
||||
|
@ -1,9 +1,10 @@
|
||||
# Paint Example
|
||||
|
||||
This directory is an example of using the `web-sys` crate for making a simple
|
||||
painting program with all of the logic written in Rust.
|
||||
[View documentation for this example online][dox]
|
||||
|
||||
You can build and run the example with:
|
||||
[dox]: https://rustwasm.github.io/wasm-bindgen/examples/console-log.html
|
||||
|
||||
You can build the example locally with:
|
||||
|
||||
```
|
||||
$ ./build.sh
|
||||
@ -11,5 +12,4 @@ $ ./build.sh
|
||||
|
||||
(or running the commands on Windows manually)
|
||||
|
||||
and then opening up `http://localhost:8080/` in a web browser should show a
|
||||
blank canvas on which you can draw.
|
||||
and then visiting http://localhost:8080 in a browser should run the example!
|
||||
|
@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "performance"
|
||||
version = "0.1.0"
|
||||
authors = ["Alex Crichton <alex@alexcrichton.com>"]
|
||||
authors = ["The wasm-bindgen Developers"]
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
@ -9,3 +9,7 @@ crate-type = ["cdylib"]
|
||||
[dependencies]
|
||||
wasm-bindgen = { path = "../.." }
|
||||
humantime = "1"
|
||||
|
||||
[dependencies.web-sys]
|
||||
path = '../../crates/web-sys'
|
||||
features = ['Window', 'Performance', 'PerformanceTiming']
|
||||
|
@ -1,12 +1,10 @@
|
||||
# `performance`
|
||||
# web-sys: `performance.now`
|
||||
|
||||
[View this example online](https://webassembly.studio/?f=6gxcp4f4953)
|
||||
[View documentation for this example online][dox]
|
||||
|
||||
This directory is an example of using the `#[wasm_bindgen]` macro to interact
|
||||
with global APIs like `performance.now()` to learn about the current time in
|
||||
Rust.
|
||||
[dox]: https://rustwasm.github.io/wasm-bindgen/examples/performance.html
|
||||
|
||||
You can build the example with:
|
||||
You can build the example locally with:
|
||||
|
||||
```
|
||||
$ ./build.sh
|
||||
@ -14,10 +12,4 @@ $ ./build.sh
|
||||
|
||||
(or running the commands on Windows manually)
|
||||
|
||||
and then opening up `index.html` in a web browser should show a hello message on
|
||||
the web page generated by the wasm.
|
||||
|
||||
For more information about this example be sure to check out
|
||||
[`hello_world`][hello] which also has more comments about caveats and such.
|
||||
|
||||
[hello]: https://github.com/alexcrichton/wasm-bindgen/tree/master/examples/hello_world
|
||||
and then visiting http://localhost:8080 in a browser should run the example!
|
||||
|
@ -3,7 +3,6 @@
|
||||
<meta content="text/html;charset=utf-8" http-equiv="Content-Type"/>
|
||||
</head>
|
||||
<body>
|
||||
<script src='./index.js'></script>
|
||||
<p>The developer console should have timing log messages in it</p>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -1,45 +1,35 @@
|
||||
extern crate humantime;
|
||||
extern crate wasm_bindgen;
|
||||
extern crate web_sys;
|
||||
|
||||
use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
||||
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
// Like with the `dom` example this block will eventually be auto-generated, but
|
||||
// for now we can write it by hand to get by!
|
||||
// lifted from the `console_log` example
|
||||
#[wasm_bindgen]
|
||||
extern "C" {
|
||||
type Performance;
|
||||
static performance: Performance;
|
||||
#[wasm_bindgen(method)]
|
||||
fn now(this: &Performance) -> f64;
|
||||
#[wasm_bindgen(method, getter)]
|
||||
fn timing(this: &Performance) -> PerformanceTiming;
|
||||
|
||||
type PerformanceTiming;
|
||||
#[wasm_bindgen(method, getter)]
|
||||
fn requestStart(this: &PerformanceTiming) -> f64;
|
||||
#[wasm_bindgen(method, getter)]
|
||||
fn responseEnd(this: &PerformanceTiming) -> f64;
|
||||
|
||||
#[wasm_bindgen(js_namespace = console)]
|
||||
fn log(a: &str);
|
||||
}
|
||||
|
||||
macro_rules! println {
|
||||
macro_rules! console_log {
|
||||
($($t:tt)*) => (log(&format_args!($($t)*).to_string()))
|
||||
}
|
||||
|
||||
// Called by our JS entry point to run the example
|
||||
#[wasm_bindgen]
|
||||
pub fn run() {
|
||||
println!("the current time is {}", performance.now());
|
||||
let window = web_sys::window().expect("should have a window in this context");
|
||||
let performance = window.performance().expect("performance should be available");
|
||||
|
||||
let start = perf_to_system(performance.timing().requestStart());
|
||||
let end = perf_to_system(performance.timing().responseEnd());
|
||||
console_log!("the current time (in ms) is {}", performance.now());
|
||||
|
||||
println!("request started at {}", humantime::format_rfc3339(start));
|
||||
println!("request ended at {}", humantime::format_rfc3339(end));
|
||||
let start = perf_to_system(performance.timing().request_start());
|
||||
let end = perf_to_system(performance.timing().response_end());
|
||||
|
||||
console_log!("request started at {}", humantime::format_rfc3339(start));
|
||||
console_log!("request ended at {}", humantime::format_rfc3339(end));
|
||||
}
|
||||
|
||||
fn perf_to_system(amt: f64) -> SystemTime {
|
||||
|
3
examples/smorgasboard/.gitignore
vendored
3
examples/smorgasboard/.gitignore
vendored
@ -1,3 +0,0 @@
|
||||
package-lock.json
|
||||
smorgasboard.js
|
||||
smorgasboard_bg.wasm
|
@ -1,10 +0,0 @@
|
||||
[package]
|
||||
name = "smorgasboard"
|
||||
version = "0.1.0"
|
||||
authors = ["Alex Crichton <alex@alexcrichton.com>"]
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
wasm-bindgen = { path = "../.." }
|
@ -1,18 +0,0 @@
|
||||
# Smorgasboard of examples
|
||||
|
||||
[View this example online](https://webassembly.studio/?f=t61j18noqz)
|
||||
|
||||
This directory is a smattering of examples using the `#[wasm_bindgen]` macro.
|
||||
Here we see passing strings back and for, exporting classes from Rust to JS,
|
||||
importing classes from JS to Rust, etc.
|
||||
|
||||
You can build the example with:
|
||||
|
||||
```
|
||||
$ ./build.sh
|
||||
```
|
||||
|
||||
(or running the two commands on Windows manually)
|
||||
|
||||
and then opening up `index.html` in a web browser should show a dialog saying
|
||||
"all passed" as well as some console output.
|
@ -1,32 +0,0 @@
|
||||
import { Foo, Bar, concat } from './smorgasboard';
|
||||
|
||||
function assertEq(a, b) {
|
||||
if (a !== b)
|
||||
throw new Error(`${a} != ${b}`);
|
||||
console.log(`found ${a} === ${b}`);
|
||||
}
|
||||
|
||||
assertEq(concat('a', 'b'), 'ab');
|
||||
|
||||
// Note that to use `new Foo()` the constructor function must be annotated
|
||||
// with `#[wasm_bindgen(constructor)]`, otherwise only `Foo.new()` can be used.
|
||||
// Additionally objects allocated corresponding to Rust structs will need to
|
||||
// be deallocated on the Rust side of things with an explicit call to `free`.
|
||||
let foo = new Foo();
|
||||
assertEq(foo.add(10), 10);
|
||||
foo.free();
|
||||
|
||||
// Pass objects to one another
|
||||
let foo1 = new Foo();
|
||||
let bar = Bar.from_str('22', { opaque: 'object' });
|
||||
foo1.add_other(bar);
|
||||
|
||||
// We also don't have to `free` the `bar` variable as this function is
|
||||
// transferring ownership to `foo1`
|
||||
bar.reset('34');
|
||||
foo1.consume_other(bar);
|
||||
|
||||
assertEq(foo1.add(2), 22 + 34 + 2);
|
||||
foo1.free();
|
||||
|
||||
alert('all passed!');
|
@ -1,14 +0,0 @@
|
||||
export function bar_on_reset(s, token) {
|
||||
console.log(token);
|
||||
console.log(`this instance of bar was reset to ${s}`);
|
||||
}
|
||||
|
||||
export class Awesome {
|
||||
constructor() {
|
||||
this.internal = 32;
|
||||
}
|
||||
|
||||
get_internal() {
|
||||
return this.internal;
|
||||
}
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -ex
|
||||
|
||||
cargo +nightly build --target wasm32-unknown-unknown
|
||||
|
||||
# Here we're using the version of the CLI in this repository, but for external
|
||||
# usage you'd use the commented out version below
|
||||
cargo +nightly run --manifest-path ../../crates/cli/Cargo.toml \
|
||||
--bin wasm-bindgen -- \
|
||||
../../target/wasm32-unknown-unknown/debug/smorgasboard.wasm --out-dir .
|
||||
# wasm-bindgen ../../target/wasm32-unknown-unknown/hello_world.wasm --out-dir .
|
||||
|
||||
npm install
|
||||
npm run serve
|
@ -1 +0,0 @@
|
||||
import('./app');
|
@ -1,11 +0,0 @@
|
||||
{
|
||||
"scripts": {
|
||||
"serve": "webpack-dev-server"
|
||||
},
|
||||
"devDependencies": {
|
||||
"html-webpack-plugin": "^3.2.0",
|
||||
"webpack": "^4.11.1",
|
||||
"webpack-cli": "^2.0.10",
|
||||
"webpack-dev-server": "^3.1.0"
|
||||
}
|
||||
}
|
@ -1,76 +0,0 @@
|
||||
extern crate wasm_bindgen;
|
||||
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
// Strings can both be passed in and received
|
||||
#[wasm_bindgen]
|
||||
#[no_mangle]
|
||||
pub extern "C" fn concat(a: &str, b: &str) -> String {
|
||||
let mut a = a.to_string();
|
||||
a.push_str(b);
|
||||
return a;
|
||||
}
|
||||
|
||||
// A struct will show up as a class on the JS side of things
|
||||
#[wasm_bindgen]
|
||||
pub struct Foo {
|
||||
contents: u32,
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl Foo {
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new() -> Foo {
|
||||
Foo { contents: 0 }
|
||||
}
|
||||
|
||||
// Methods can be defined with `&mut self` or `&self`, and arguments you
|
||||
// can pass to a normal free function also all work in methods.
|
||||
pub fn add(&mut self, amt: u32) -> u32 {
|
||||
self.contents += amt;
|
||||
return self.contents;
|
||||
}
|
||||
|
||||
// You can also take a limited set of references to other types as well.
|
||||
pub fn add_other(&mut self, bar: &Bar) {
|
||||
self.contents += bar.contents;
|
||||
}
|
||||
|
||||
// Ownership can work too!
|
||||
pub fn consume_other(&mut self, bar: Bar) {
|
||||
self.contents += bar.contents;
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub struct Bar {
|
||||
contents: u32,
|
||||
opaque: JsValue, // defined in `wasm_bindgen`, imported via prelude
|
||||
}
|
||||
|
||||
#[wasm_bindgen(module = "./awesome")] // what ES6 module to import from
|
||||
extern "C" {
|
||||
fn bar_on_reset(to: &str, opaque: &JsValue);
|
||||
|
||||
// We can import classes and annotate functionality on those classes as well
|
||||
type Awesome;
|
||||
#[wasm_bindgen(constructor)]
|
||||
fn new() -> Awesome;
|
||||
#[wasm_bindgen(method)]
|
||||
fn get_internal(this: &Awesome) -> u32;
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl Bar {
|
||||
pub fn from_str(s: &str, opaque: JsValue) -> Bar {
|
||||
let contents = s.parse().unwrap_or_else(|_| Awesome::new().get_internal());
|
||||
Bar { contents, opaque }
|
||||
}
|
||||
|
||||
pub fn reset(&mut self, s: &str) {
|
||||
if let Ok(n) = s.parse() {
|
||||
bar_on_reset(s, &self.opaque);
|
||||
self.contents = n;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
const path = require('path');
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||
|
||||
module.exports = {
|
||||
entry: './index.js',
|
||||
output: {
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
filename: 'index.js',
|
||||
},
|
||||
plugins: [
|
||||
new HtmlWebpackPlugin()
|
||||
],
|
||||
mode: 'development'
|
||||
};
|
@ -8,3 +8,4 @@ crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
wasm-bindgen = { path = "../.." }
|
||||
js-sys = { path = "../../crates/js-sys" }
|
||||
|
@ -1,10 +1,10 @@
|
||||
# WASM in WASM!
|
||||
# js-sys: WebAssembly in WebAssembly
|
||||
|
||||
This directory is an example of using the `#[wasm_bindgen]` macro to interact
|
||||
with namespaced APIs like `WebAssembly.Module` and friends. This example
|
||||
instantiates a wasm module (from Rust!) and then interacts with it.
|
||||
[View documentation for this example online][dox]
|
||||
|
||||
You can build the example with:
|
||||
[dox]: https://rustwasm.github.io/wasm-bindgen/examples/wasm-in-wasm.html
|
||||
|
||||
You can build the example locally with:
|
||||
|
||||
```
|
||||
$ ./build.sh
|
||||
@ -12,10 +12,4 @@ $ ./build.sh
|
||||
|
||||
(or running the commands on Windows manually)
|
||||
|
||||
and then opening up `index.html` in a web browser should show a hello message on
|
||||
the web page generated by the wasm.
|
||||
|
||||
For more information about this example be sure to check out
|
||||
[`hello_world`][hello] which also has more comments about caveats and such.
|
||||
|
||||
[hello]: https://github.com/alexcrichton/wasm-bindgen/tree/master/examples/hello_world
|
||||
and then visiting http://localhost:8080 in a browser should run the example!
|
||||
|
@ -3,7 +3,6 @@
|
||||
<meta content="text/html;charset=utf-8" http-equiv="Content-Type"/>
|
||||
</head>
|
||||
<body>
|
||||
<script src='./index.js'></script>
|
||||
<p>The developer console should have messages in it</p>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -1,52 +1,57 @@
|
||||
extern crate wasm_bindgen;
|
||||
extern crate js_sys;
|
||||
|
||||
use wasm_bindgen::prelude::*;
|
||||
use wasm_bindgen::JsCast;
|
||||
use js_sys::{WebAssembly, Object, Reflect, Function, Uint8Array};
|
||||
|
||||
// Like with the `dom` example this block will eventually be auto-generated, but
|
||||
// for now we can write it by hand to get by!
|
||||
// lifted from the `console_log` example
|
||||
#[wasm_bindgen]
|
||||
extern "C" {
|
||||
type Module;
|
||||
#[wasm_bindgen(constructor, js_namespace = WebAssembly)]
|
||||
fn new(data: &[u8]) -> Module;
|
||||
|
||||
type Instance;
|
||||
#[wasm_bindgen(constructor, js_namespace = WebAssembly)]
|
||||
fn new(module: Module) -> Instance;
|
||||
#[wasm_bindgen(method, getter, js_namespace = WebAssembly)]
|
||||
fn exports(this: &Instance) -> Exports;
|
||||
|
||||
type Exports;
|
||||
#[wasm_bindgen(method, structural)]
|
||||
fn add(this: &Exports, a: u32, b: u32) -> u32;
|
||||
#[wasm_bindgen(method, getter, structural)]
|
||||
fn memory(this: &Exports) -> Memory;
|
||||
|
||||
type Memory;
|
||||
#[wasm_bindgen(method, js_namespace = WebAssembly)]
|
||||
fn grow(this: &Memory, amt: u32) -> u32;
|
||||
|
||||
#[wasm_bindgen(js_namespace = console)]
|
||||
fn log(a: &str);
|
||||
}
|
||||
|
||||
macro_rules! println {
|
||||
macro_rules! console_log {
|
||||
($($t:tt)*) => (log(&format_args!($($t)*).to_string()))
|
||||
}
|
||||
|
||||
const WASM: &[u8] = include_bytes!("add.wasm");
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn run() {
|
||||
println!("instantiating a new wasm module directly");
|
||||
let a = Module::new(WASM);
|
||||
let b = Instance::new(a);
|
||||
pub fn run() -> Result<(), JsValue> {
|
||||
console_log!("instantiating a new wasm module directly");
|
||||
let my_memory = wasm_bindgen::memory()
|
||||
.dyn_into::<WebAssembly::Memory>()
|
||||
.unwrap();
|
||||
|
||||
// Note that this is somewhat dangerous, once we look at our
|
||||
// `WebAssembly.Memory` buffer then if we allocate more pages for ourself
|
||||
// (aka do a memory allocation in Rust) it'll cause the buffer to change.
|
||||
// That means we can't actually do any memory allocations after we do this
|
||||
// until we pass it back to JS.
|
||||
let my_memory = Uint8Array::new(&my_memory.buffer())
|
||||
.subarray(
|
||||
WASM.as_ptr() as u32,
|
||||
WASM.as_ptr() as u32 + WASM.len() as u32,
|
||||
);
|
||||
let a = WebAssembly::Module::new(my_memory.as_ref())?;
|
||||
let b = WebAssembly::Instance::new(&a, &Object::new())?;
|
||||
let c = b.exports();
|
||||
|
||||
println!("1 + 2 = {}", c.add(1, 2));
|
||||
let mem = c.memory();
|
||||
println!("created module has {} pages of memory", mem.grow(0));
|
||||
println!("giving the module 4 more pages of memory");
|
||||
let add = Reflect::get(c.as_ref(), &"add".into())
|
||||
.dyn_into::<Function>()
|
||||
.expect("add export wasn't a function");
|
||||
|
||||
let three = add.call2(&JsValue::undefined(), &1.into(), &2.into())?;
|
||||
console_log!("1 + 2 = {:?}", three);
|
||||
let mem = Reflect::get(c.as_ref(), &"memory".into())
|
||||
.dyn_into::<WebAssembly::Memory>()
|
||||
.expect("memory export wasn't a `WebAssembly.Memory`");
|
||||
console_log!("created module has {} pages of memory", mem.grow(0));
|
||||
console_log!("giving the module 4 more pages of memory");
|
||||
mem.grow(4);
|
||||
println!("now the module has {} pages of memory", mem.grow(0));
|
||||
console_log!("now the module has {} pages of memory", mem.grow(0));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1,2 +1,2 @@
|
||||
package-lock.json
|
||||
asmjs*
|
||||
wasm2js*
|
@ -1,5 +1,5 @@
|
||||
[package]
|
||||
name = "asmjs"
|
||||
name = "wasm2js"
|
||||
version = "0.1.0"
|
||||
authors = ["Alex Crichton <alex@alexcrichton.com>"]
|
||||
|
15
examples/wasm2js/README.md
Normal file
15
examples/wasm2js/README.md
Normal file
@ -0,0 +1,15 @@
|
||||
# Converting WebAssembly to JS
|
||||
|
||||
[View documentation for this example online][dox]
|
||||
|
||||
[dox]: https://rustwasm.github.io/wasm-bindgen/examples/wasm2js.html
|
||||
|
||||
You can build the example locally with:
|
||||
|
||||
```
|
||||
$ ./build.sh
|
||||
```
|
||||
|
||||
(or running the commands on Windows manually)
|
||||
|
||||
and then visiting http://localhost:8080 in a browser should run the example!
|
@ -2,21 +2,17 @@
|
||||
|
||||
set -ex
|
||||
|
||||
# Compile our wasm module
|
||||
# Compile our wasm module and run `wasm-bindgen`
|
||||
cargo +nightly build --target wasm32-unknown-unknown --release
|
||||
|
||||
# Run wasm-bindgen, and note that the `--no-demangle` argument is here is
|
||||
# important for compatibility with wasm2js!
|
||||
cargo +nightly run --manifest-path ../../crates/cli/Cargo.toml \
|
||||
--bin wasm-bindgen -- \
|
||||
--no-demangle \
|
||||
../../target/wasm32-unknown-unknown/release/asmjs.wasm --out-dir .
|
||||
../../target/wasm32-unknown-unknown/release/wasm2js.wasm --out-dir .
|
||||
|
||||
# Run the `wasm2js` tool from `binaryen`
|
||||
wasm2js asmjs_bg.wasm -o asmjs_bg.js
|
||||
wasm2js wasm2js_bg.wasm -o wasm2js_bg.js
|
||||
|
||||
# Move our original wasm out of the way to avoid cofusing Webpack.
|
||||
mv asmjs_bg.wasm asmjs_bg.bak.wasm
|
||||
mv wasm2js_bg.wasm wasm2js_bg.bak.wasm
|
||||
|
||||
npm install
|
||||
npm run serve
|
@ -4,6 +4,5 @@
|
||||
</head>
|
||||
<body>
|
||||
<p>Open up the developer console to see "Hello, World!"</p>
|
||||
<script src='./index.js'></script>
|
||||
</body>
|
||||
</html>
|
4
examples/wasm2js/index.js
Normal file
4
examples/wasm2js/index.js
Normal file
@ -0,0 +1,4 @@
|
||||
// Note that since we're not using `WebAssembly` we can do a synchronous import
|
||||
// here!
|
||||
import { run } from './wasm2js';
|
||||
run();
|
@ -2,6 +2,7 @@ extern crate wasm_bindgen;
|
||||
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
// lifted from the `console_log` example
|
||||
#[wasm_bindgen]
|
||||
extern "C" {
|
||||
#[wasm_bindgen(js_namespace = console)]
|
@ -1,14 +1,15 @@
|
||||
# Web Audio example
|
||||
# WebAudio
|
||||
|
||||
This directory is an example of how to use the Web Audio APIs from Rust. It creates a very simple
|
||||
FM (frequency modulation) synth, and let's you control the primary frequency, the modulation amount,
|
||||
and the modulation frequency.
|
||||
[View documentation for this example online][dox]
|
||||
|
||||
To run, first install some utilities via npm:
|
||||
[dox]: https://rustwasm.github.io/wasm-bindgen/examples/web-audio.html
|
||||
|
||||
> npm install
|
||||
|
||||
Then build the project with either `build.bat` or `build.sh`.
|
||||
|
||||
Finally, run a development web server with `npm run serve` and then open
|
||||
[http://localhost:8080/](http://localhost:8080/) in a browser!
|
||||
You can build the example locally with:
|
||||
|
||||
```
|
||||
$ ./build.sh
|
||||
```
|
||||
|
||||
(or running the commands on Windows manually)
|
||||
|
||||
and then visiting http://localhost:8080 in a browser should run the example!
|
||||
|
@ -1,2 +0,0 @@
|
||||
cargo +nightly build --target wasm32-unknown-unknown
|
||||
cargo +nightly run --manifest-path ../../crates/cli/Cargo.toml --bin wasm-bindgen -- ../../target/wasm32-unknown-unknown/debug/webaudio.wasm --out-dir .
|
@ -3,8 +3,6 @@
|
||||
<meta content="text/html;charset=utf-8" http-equiv="Content-Type"/>
|
||||
</head>
|
||||
<body>
|
||||
<script src='./index.js'></script>
|
||||
|
||||
<input id="play" type="button" value="Click me first to turn on audio"/>
|
||||
(headphone users, please make sure your volume is not too loud!)
|
||||
|
||||
|
6
examples/webgl/.gitignore
vendored
6
examples/webgl/.gitignore
vendored
@ -1,4 +1,4 @@
|
||||
package-lock.json
|
||||
wasm_bindgen_webgl_demo.js
|
||||
wasm_bindgen_webgl_demo_bg.js
|
||||
wasm_bindgen_webgl_demo_bg.wasm
|
||||
webgl.js
|
||||
webgl_bg.js
|
||||
webgl_bg.wasm
|
||||
|
@ -1,5 +1,5 @@
|
||||
[package]
|
||||
name = "wasm-bindgen-webgl-demo"
|
||||
name = "webgl"
|
||||
version = "0.1.0"
|
||||
authors = ["The wasm-bindgen Developers"]
|
||||
|
||||
|
@ -1,9 +1,10 @@
|
||||
# WebGL Example
|
||||
|
||||
This directory is an example of using the `web-sys` crate to interact with
|
||||
a WebGL context.
|
||||
[View documentation for this example online][dox]
|
||||
|
||||
You can build and run the example with:
|
||||
[dox]: https://rustwasm.github.io/wasm-bindgen/examples/webgl.html
|
||||
|
||||
You can build the example locally with:
|
||||
|
||||
```
|
||||
$ ./build.sh
|
||||
@ -11,5 +12,4 @@ $ ./build.sh
|
||||
|
||||
(or running the commands on Windows manually)
|
||||
|
||||
and then opening up `http://localhost:8080/` in a web browser should show a
|
||||
nice triangle.
|
||||
and then visiting http://localhost:8080 in a browser should run the example!
|
||||
|
@ -9,7 +9,7 @@ cargo +nightly build --target wasm32-unknown-unknown
|
||||
|
||||
cargo +nightly run --manifest-path ../../crates/cli/Cargo.toml \
|
||||
--bin wasm-bindgen -- \
|
||||
../../target/wasm32-unknown-unknown/debug/wasm_bindgen_webgl_demo.wasm --out-dir .
|
||||
../../target/wasm32-unknown-unknown/debug/webgl.wasm --out-dir .
|
||||
|
||||
npm install
|
||||
npm run serve
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user