Merge pull request #860 from alexcrichton/juggle-examples

Reorganize and rewrite examples
This commit is contained in:
Alex Crichton 2018-09-20 17:34:37 -07:00 committed by GitHub
commit 70c821b442
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
128 changed files with 939 additions and 1304 deletions

View File

@ -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",

View File

@ -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.
///

View File

@ -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"

View File

@ -1,7 +1,7 @@
[package]
name = "sample"
version = "0.1.0"
authors = ["The wasm-bindgen Authors"]
authors = ["The wasm-bindgen Developers"]
[lib]
test = false

View File

@ -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

View File

@ -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

View File

@ -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!

View File

@ -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

View File

@ -1,3 +0,0 @@
import { run } from './asmjs';
run();

View File

@ -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

View File

@ -1,5 +1,5 @@
[package]
name = "wasm-bindgen-canvas-demo"
name = "canvas"
version = "0.1.0"
authors = ["The wasm-bindgen Developers"]

View File

@ -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!

View File

@ -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

View File

@ -4,6 +4,5 @@
</head>
<body>
<canvas id="canvas" height="150" width="150" />
<script src='./index.js'></script>
</body>
</html>

View File

@ -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();
});

View File

@ -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!

View File

@ -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>

View File

@ -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;
}
}

View File

@ -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)]

View File

@ -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',
]

View File

@ -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!

View File

@ -35,6 +35,5 @@
times
</p>
</div>
<script src='./index.js'></script>
</body>
</html>

View File

@ -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(&current_time);
let a = Closure::wrap(Box::new(move || {
update_time(&current_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();
}

View File

@ -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']

View File

@ -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`

View File

@ -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

View File

@ -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>

View File

@ -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 = '';
}

View File

@ -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"
}
}

View File

@ -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,
}

View File

@ -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',
};

View File

@ -8,3 +8,4 @@ crate-type = ["cdylib"]
[dependencies]
wasm-bindgen = { path = "../.." }
web-sys = { path = '../../crates/web-sys' }

View File

@ -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!

View File

@ -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>

View File

@ -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);
}

View File

@ -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',
]

View File

@ -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!

View File

@ -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>

View File

@ -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
View 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!

View File

@ -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 .

View File

@ -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

View File

@ -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"]

View File

@ -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!

View File

@ -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!

View File

@ -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>

View File

@ -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)]

View File

@ -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',
]

View File

@ -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!

View File

@ -21,6 +21,5 @@
</div>
<canvas id="drawing" width="600" height="600"></canvas>
</main>
<script src='./index.js'></script>
</body>
</html>

View File

@ -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 }
}
}

View File

@ -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
}

View File

@ -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,
}
}
}

View File

@ -1,4 +0,0 @@
package-lock.json
math.js
math_bg.js
math_bg.wasm

View File

@ -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 = "../.." }

View File

@ -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

View File

@ -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

View File

@ -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>

View File

@ -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)}`);
});

View File

@ -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"
}
}

View File

@ -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));
}

View File

@ -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'
};

View File

@ -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!

View File

@ -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;

View File

@ -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!

View File

@ -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']

View File

@ -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!

View File

@ -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>

View File

@ -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 {

View File

@ -1,3 +0,0 @@
package-lock.json
smorgasboard.js
smorgasboard_bg.wasm

View File

@ -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 = "../.." }

View File

@ -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.

View File

@ -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!');

View File

@ -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;
}
}

View File

@ -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

View File

@ -1 +0,0 @@
import('./app');

View File

@ -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"
}
}

View File

@ -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;
}
}
}

View File

@ -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'
};

View File

@ -8,3 +8,4 @@ crate-type = ["cdylib"]
[dependencies]
wasm-bindgen = { path = "../.." }
js-sys = { path = "../../crates/js-sys" }

View File

@ -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!

View File

@ -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>

View File

@ -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(())
}

View File

@ -1,2 +1,2 @@
package-lock.json
asmjs*
wasm2js*

View File

@ -1,5 +1,5 @@
[package]
name = "asmjs"
name = "wasm2js"
version = "0.1.0"
authors = ["Alex Crichton <alex@alexcrichton.com>"]

View 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!

View File

@ -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

View File

@ -4,6 +4,5 @@
</head>
<body>
<p>Open up the developer console to see "Hello, World!"</p>
<script src='./index.js'></script>
</body>
</html>

View 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();

View File

@ -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)]

View File

@ -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!

View File

@ -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 .

View File

@ -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!)

View File

@ -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

View File

@ -1,5 +1,5 @@
[package]
name = "wasm-bindgen-webgl-demo"
name = "webgl"
version = "0.1.0"
authors = ["The wasm-bindgen Developers"]

View File

@ -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!

View File

@ -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