diff --git a/Cargo.toml b/Cargo.toml index ed227a61..ed4dbb22 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,4 +17,5 @@ test-support = { path = "crates/test-support" } members = [ "crates/wasm-bindgen-cli", "examples/hello_world", + "examples/smorgasboard", ] diff --git a/README.md b/README.md index f33bdbb5..3d6177da 100644 --- a/README.md +++ b/README.md @@ -223,6 +223,12 @@ $ npm run serve If you open https://localhost:8080 in a browser you should see a `Hello, world!` dialog pop up! +If that was all a bit much, no worries! You can [follow along +online][hello-tree] to see all the files necessary as well as a script to set it +all up. + +[hello-tree]: https://github.com/alexcrichton/wasm-bindgen/tree/master/examples/hello_world + ## What just happened? Phew! That was a lot of words and a lot ended up happening along the way. There @@ -329,7 +335,7 @@ extern { #[wasm_bindgen] impl Bar { pub fn from_str(s: &str, opaque: JsValue) -> Bar { - let contents = s.parse().unwrap_or_else(|| { + let contents = s.parse().unwrap_or_else(|_| { Awesome::new().get_internal() }); Bar { contents, opaque } diff --git a/examples/README.md b/examples/README.md index 828d8a17..36162a4a 100644 --- a/examples/README.md +++ b/examples/README.md @@ -9,3 +9,6 @@ The examples here are: * `hello_world` - the "hello world" of `#[wasm_bindgen]`, aka throwing up a dialog greeting you +* `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 diff --git a/examples/smorgasboard/.gitignore b/examples/smorgasboard/.gitignore new file mode 100644 index 00000000..8ac1e848 --- /dev/null +++ b/examples/smorgasboard/.gitignore @@ -0,0 +1,3 @@ +package-lock.json +smorgasboard.js +smorgasboard_wasm.wasm diff --git a/examples/smorgasboard/Cargo.toml b/examples/smorgasboard/Cargo.toml new file mode 100644 index 00000000..3f2b558a --- /dev/null +++ b/examples/smorgasboard/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "smorgasboard" +version = "0.1.0" +authors = ["Alex Crichton "] + +[lib] +crate-type = ["cdylib"] + +[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 = { git = "https://github.com/alexcrichton/wasm-bindgen" } diff --git a/examples/smorgasboard/README.md b/examples/smorgasboard/README.md new file mode 100644 index 00000000..f80f4983 --- /dev/null +++ b/examples/smorgasboard/README.md @@ -0,0 +1,16 @@ +# Smorgasboard of examples + +This directory is an 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. diff --git a/examples/smorgasboard/app.js b/examples/smorgasboard/app.js new file mode 100644 index 00000000..008027bf --- /dev/null +++ b/examples/smorgasboard/app.js @@ -0,0 +1,32 @@ +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 the `new Foo()` syntax cannot be used, static function +// constructors must be used instead. 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 = Foo.new(); +assertEq(foo.add(10), 10); +foo.free(); + +// Pass objects to one another +let foo1 = Foo.new(); +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!') diff --git a/examples/smorgasboard/awesome.js b/examples/smorgasboard/awesome.js new file mode 100644 index 00000000..896cc001 --- /dev/null +++ b/examples/smorgasboard/awesome.js @@ -0,0 +1,14 @@ +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; + } +} diff --git a/examples/smorgasboard/build.sh b/examples/smorgasboard/build.sh new file mode 100755 index 00000000..a28ec2e1 --- /dev/null +++ b/examples/smorgasboard/build.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +set -ex + +cargo +nightly build --target wasm32-unknown-unknown --release + +# 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/wasm-bindgen-cli/Cargo.toml \ + --bin wasm-bindgen -- \ + ../../target/wasm32-unknown-unknown/release/smorgasboard.wasm --out-dir . +# wasm-bindgen ../../target/wasm32-unknown-unknown/hello_world.wasm --out-dir . + +npm install +npm run serve diff --git a/examples/smorgasboard/index.html b/examples/smorgasboard/index.html new file mode 100644 index 00000000..bad47a7c --- /dev/null +++ b/examples/smorgasboard/index.html @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/examples/smorgasboard/index.js b/examples/smorgasboard/index.js new file mode 100644 index 00000000..17ff8acf --- /dev/null +++ b/examples/smorgasboard/index.js @@ -0,0 +1 @@ +import("./app"); diff --git a/examples/smorgasboard/package.json b/examples/smorgasboard/package.json new file mode 100644 index 00000000..408b462e --- /dev/null +++ b/examples/smorgasboard/package.json @@ -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" + } +} diff --git a/examples/smorgasboard/src/lib.rs b/examples/smorgasboard/src/lib.rs new file mode 100644 index 00000000..f68232c5 --- /dev/null +++ b/examples/smorgasboard/src/lib.rs @@ -0,0 +1,79 @@ +#![feature(proc_macro)] + +extern crate wasm_bindgen; + +use wasm_bindgen::prelude::*; + +// Strings can both be passed in and received +#[wasm_bindgen] +#[no_mangle] +pub extern 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 { + 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 { + 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; + } + } +} diff --git a/examples/smorgasboard/webpack.config.js b/examples/smorgasboard/webpack.config.js new file mode 100644 index 00000000..5910e2ae --- /dev/null +++ b/examples/smorgasboard/webpack.config.js @@ -0,0 +1,10 @@ +const path = require('path'); + +module.exports = { + entry: "./index.js", + output: { + path: path.resolve(__dirname, "dist"), + filename: "index.js", + }, + mode: "development" +};