mirror of
https://github.com/fluencelabs/wasm-bindgen
synced 2025-07-31 03:51:56 +00:00
Add examples/documentation for closures
This commit is contained in:
@@ -22,3 +22,5 @@ The examples here are:
|
||||
operations in Rust
|
||||
* `wasm-in-wasm` - how to interact with namespaced APIs like
|
||||
`WebAssembly.Module` and shows off creation of a WebAssembly module from Rust
|
||||
* `closures` - an example of how to invoke functions like `setInterval` or use
|
||||
the `onclick` property in conjunction with closures.
|
||||
|
4
examples/closures/.gitignore
vendored
Normal file
4
examples/closures/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
package-lock.json
|
||||
closures.js
|
||||
closures_bg.js
|
||||
closures_bg.wasm
|
10
examples/closures/Cargo.toml
Normal file
10
examples/closures/Cargo.toml
Normal file
@@ -0,0 +1,10 @@
|
||||
[package]
|
||||
name = "closures"
|
||||
version = "0.1.0"
|
||||
authors = ["Alex Crichton <alex@alexcrichton.com>"]
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
wasm-bindgen = { path = "../.." }
|
20
examples/closures/README.md
Normal file
20
examples/closures/README.md
Normal file
@@ -0,0 +1,20 @@
|
||||
# Closure examples
|
||||
|
||||
This directory is an example of using the `#[wasm_bindgen]` macro with closures
|
||||
to interact with the DOM.
|
||||
|
||||
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 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
|
12
examples/closures/build.sh
Executable file
12
examples/closures/build.sh
Executable file
@@ -0,0 +1,12 @@
|
||||
#!/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/closures.wasm --out-dir .
|
||||
#npm install
|
||||
npm run serve
|
40
examples/closures/index.html
Normal file
40
examples/closures/index.html
Normal file
@@ -0,0 +1,40 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta content="text/html;charset=utf-8" http-equiv="Content-Type"/>
|
||||
<style>
|
||||
#green-square {
|
||||
background: green;
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
text-align: center;
|
||||
line-height: 200px;
|
||||
color: white;
|
||||
}
|
||||
#green-square span {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id='loading'>
|
||||
Loading...
|
||||
</div>
|
||||
<div id='script' style='display:none'>
|
||||
<p>
|
||||
The current time is:
|
||||
<span id='current-time'>...</span>
|
||||
</p>
|
||||
|
||||
<div id='green-square'>
|
||||
<span>Click me!</span>
|
||||
</div>
|
||||
<p>
|
||||
You've clicked the green square
|
||||
<span id='num-clicks'>0</span>
|
||||
times
|
||||
</p>
|
||||
</div>
|
||||
<script src='./index.js'></script>
|
||||
</body>
|
||||
</html>
|
4
examples/closures/index.js
Normal file
4
examples/closures/index.js
Normal file
@@ -0,0 +1,4 @@
|
||||
// For more comments about what's going on here, check out the `hello_world`
|
||||
// example
|
||||
const rust = import("./closures");
|
||||
rust.then(m => m.run());
|
10
examples/closures/package.json
Normal file
10
examples/closures/package.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"scripts": {
|
||||
"serve": "webpack-dev-server"
|
||||
},
|
||||
"devDependencies": {
|
||||
"webpack": "^4.0.1",
|
||||
"webpack-cli": "^2.0.10",
|
||||
"webpack-dev-server": "^3.1.0"
|
||||
}
|
||||
}
|
94
examples/closures/src/lib.rs
Normal file
94
examples/closures/src/lib.rs
Normal file
@@ -0,0 +1,94 @@
|
||||
#![feature(proc_macro, wasm_custom_section, wasm_import_module)]
|
||||
|
||||
extern crate wasm_bindgen;
|
||||
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[wasm_bindgen]
|
||||
extern {
|
||||
// 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;
|
||||
|
||||
// Bindings for JS `Date` so we can update our local timer
|
||||
type Date;
|
||||
#[wasm_bindgen(constructor)]
|
||||
fn new() -> Date;
|
||||
#[wasm_bindgen(method, js_name = toLocaleString)]
|
||||
fn to_locale_string(this: &Date) -> String;
|
||||
|
||||
// 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;
|
||||
|
||||
type Element;
|
||||
#[wasm_bindgen(method, setter = innerHTML)]
|
||||
fn set_inner_html(this: &Element, html: &str);
|
||||
|
||||
type HTMLElement;
|
||||
#[wasm_bindgen(method, setter)]
|
||||
fn set_onclick(this: &HTMLElement, cb: &Closure<FnMut()>);
|
||||
#[wasm_bindgen(method, getter)]
|
||||
fn style(this: &HTMLElement) -> CSS2Properties;
|
||||
|
||||
type CSS2Properties;
|
||||
#[wasm_bindgen(method, setter)]
|
||||
fn set_display(this: &CSS2Properties, display: &str);
|
||||
}
|
||||
|
||||
#[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_inner_html(&Date::new().to_locale_string());
|
||||
}
|
||||
|
||||
// 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
|
||||
// raise exceptions when invoked.
|
||||
//
|
||||
// Normally we'd store these handles to later get dropped at an appropriate
|
||||
// time but for now we want these to be global handlers so we use the
|
||||
// `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");
|
||||
}
|
10
examples/closures/webpack.config.js
Normal file
10
examples/closures/webpack.config.js
Normal file
@@ -0,0 +1,10 @@
|
||||
const path = require('path');
|
||||
|
||||
module.exports = {
|
||||
entry: "./index.js",
|
||||
output: {
|
||||
path: path.resolve(__dirname, "dist"),
|
||||
filename: "index.js",
|
||||
},
|
||||
mode: "development"
|
||||
};
|
Reference in New Issue
Block a user