mirror of
https://github.com/fluencelabs/wasm-bindgen
synced 2025-06-01 15:11:22 +00:00
Merge pull request #661 from fitzgen/guide-closures-and-attributes
Guide: closures and attributes
This commit is contained in:
commit
6d4d9150cb
@ -9,12 +9,29 @@
|
||||
- [What Just Happened?](./whirlwind-tour/what-just-happened.md)
|
||||
- [What Else Can We Do?](./whirlwind-tour/what-else-can-we-do.md)
|
||||
- [Reference](./reference/index.md)
|
||||
- [Closures](./reference/closures.md)
|
||||
- [Passing Rust Closures to JS](./reference/passing-rust-closures-to-js.md)
|
||||
- [Receiving JS Closures in Rust](./reference/receiving-js-closures-in-rust.md)
|
||||
- [No ES Modules](./reference/no-esm.md)
|
||||
- [Passing Arbitrary data](./reference/passing-data.md)
|
||||
- [Feature Reference](./reference/feature-reference.md)
|
||||
- [Command Line Interface](./reference/cli.md)
|
||||
- [Supported Types](./reference/types.md)
|
||||
- [`#[wasm_bindgen]` Attributes](./reference/attributes/index.md)
|
||||
- [On JavaScript Imports](./reference/attributes/on-js-imports/index.md)
|
||||
- [`catch`](./reference/attributes/on-js-imports/catch.md)
|
||||
- [`constructor`](./reference/attributes/on-js-imports/constructor.md)
|
||||
- [`getter` and `setter`](./reference/attributes/on-js-imports/getter-and-setter.md)
|
||||
- [`js_class = "Blah"`](./reference/attributes/on-js-imports/js_class.md)
|
||||
- [`js_name`](./reference/attributes/on-js-imports/js_name.md)
|
||||
- [`js_namespace`](./reference/attributes/on-js-imports/js_namespace.md)
|
||||
- [`method`](./reference/attributes/on-js-imports/method.md)
|
||||
- [`module = "blah"`](./reference/attributes/on-js-imports/module.md)
|
||||
- [`static_method_of = Blah`](./reference/attributes/on-js-imports/static_method_of.md)
|
||||
- [`structural`](./reference/attributes/on-js-imports/structural.md)
|
||||
- [On Rust Exports](./reference/attributes/on-rust-exports/index.md)
|
||||
- [`constructor`](./reference/attributes/on-rust-exports/constructor.md)
|
||||
- [`js_name = Blah`](./reference/attributes/on-rust-exports/js_name.md)
|
||||
- [`readonly`](./reference/attributes/on-rust-exports/readonly.md)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
@ -23,10 +40,8 @@
|
||||
- [JS Objects in Rust](./design/js-objects-in-rust.md)
|
||||
- [Exporting a function to JS](./design/exporting-rust.md)
|
||||
- [Exporting a struct to JS](./design/exporting-rust-struct.md)
|
||||
- [Customizing exports](./design/export-customization.md)
|
||||
- [Importing a function from JS](./design/importing-js.md)
|
||||
- [Importing a class from JS](./design/importing-js-struct.md)
|
||||
- [Customizing imports](./design/import-customization.md)
|
||||
- [Rust Type conversions](./design/rust-type-conversions.md)
|
||||
- [Types in `wasm-bindgen`](./design/describe.md)
|
||||
- [`js-sys`](./js-sys.md)
|
||||
|
@ -1,85 +0,0 @@
|
||||
# Customizing import behavior
|
||||
|
||||
The `#[wasm_bindgen]` macro supports a good amount of configuration for
|
||||
controlling precisely how exports are exported and what they generate in JS.
|
||||
This section is intended to hopefully be an exhaustive reference of the
|
||||
possibilities!
|
||||
|
||||
* `readonly` - when attached to a `pub` struct field this indicates that it's
|
||||
readonly from JS and a setter will not be generated.
|
||||
|
||||
```rust
|
||||
#[wasm_bindgen]
|
||||
pub struct Foo {
|
||||
pub first: u32,
|
||||
#[wasm_bindgen(readonly)]
|
||||
pub second: u32,
|
||||
}
|
||||
```
|
||||
|
||||
Here the `first` field will be both readable and writable from JS, but the
|
||||
`second` field will be a `readonly` field in JS where the setter isn't
|
||||
implemented and attempting to set it will throw an exception.
|
||||
|
||||
* `constructor` - when attached to a Rust "constructor" it will make the
|
||||
generated JS bindings callable as `new Foo()`, for example:
|
||||
|
||||
```rust
|
||||
#[wasm_bindgen]
|
||||
pub struct Foo {
|
||||
contents: u32,
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl Foo {
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new() -> Foo {
|
||||
Foo { contents: 0 }
|
||||
}
|
||||
|
||||
pub fn get_contents(&self) -> u32 {
|
||||
self.contents
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Here this can be used in JS as:
|
||||
|
||||
```js
|
||||
import { Foo } from './my_module';
|
||||
|
||||
const f = new Foo();
|
||||
console.log(f.get_contents());
|
||||
```
|
||||
|
||||
* `js_name` - this can be used to export a different name in JS than what
|
||||
something is named in Rust, for example:
|
||||
|
||||
```rust
|
||||
#[wasm_bindgen]
|
||||
pub struct Foo {
|
||||
contents: u32,
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = makeFoo)]
|
||||
pub fn make_foo() -> Foo {
|
||||
Foo { contents: 6 }
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl Foo {
|
||||
#[wasm_bindgen(js_name = getContents)]
|
||||
pub fn get_contents(&self) -> u32 {
|
||||
self.contents
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Here this can be used in JS as:
|
||||
|
||||
```js
|
||||
import { makeFoo } from './my_module';
|
||||
|
||||
const foo = makeFoo();
|
||||
console.log(foo.getContents());
|
||||
```
|
@ -1,193 +0,0 @@
|
||||
# Customizing import behavior
|
||||
|
||||
The `#[wasm_bindgen]` macro supports a good amount of configuration for
|
||||
controlling precisely how imports are imported and what they map to in JS. This
|
||||
section is intended to hopefully be an exhaustive reference of the
|
||||
possibilities!
|
||||
|
||||
* `catch` - this attribute allows catching a JS exception. This can be attached
|
||||
to any imported function and the function must return a `Result` where the
|
||||
`Err` payload is a `JsValue`, like so:
|
||||
|
||||
```rust
|
||||
#[wasm_bindgen]
|
||||
extern {
|
||||
#[wasm_bindgen(catch)]
|
||||
fn foo() -> Result<(), JsValue>;
|
||||
}
|
||||
```
|
||||
|
||||
If the imported function throws an exception then `Err` will be returned with
|
||||
the exception that was raised, and otherwise `Ok` is returned with the result
|
||||
of the function.
|
||||
|
||||
By default `wasm-bindgen` will take no action when wasm calls a JS function
|
||||
which ends up throwing an exception. The wasm spec right now doesn't support
|
||||
stack unwinding and as a result Rust code **will not execute destructors**.
|
||||
This can unfortunately cause memory leaks in Rust right now, but as soon as
|
||||
wasm implements catching exceptions we'll be sure to add support as well!
|
||||
|
||||
* `constructor` - this is used to indicate that the function being bound should
|
||||
actually translate to a `new` constructor in JS. The final argument must be a
|
||||
type that's imported from JS, and it's what'll get used in JS:
|
||||
|
||||
```rust
|
||||
#[wasm_bindgen]
|
||||
extern {
|
||||
type Foo;
|
||||
#[wasm_bindgen(constructor)]
|
||||
fn new() -> Foo;
|
||||
}
|
||||
```
|
||||
|
||||
This will attach the `new` function to the `Foo` type (implied by
|
||||
`constructor`) and in JS when this function is called it will be equivalent to
|
||||
`new Foo()`.
|
||||
|
||||
* `method` - this is the gateway to adding methods to imported objects or
|
||||
otherwise accessing properties on objects via methods and such. This should be
|
||||
done for doing the equivalent of expressions like `foo.bar()` in JS.
|
||||
|
||||
```rust
|
||||
#[wasm_bindgen]
|
||||
extern {
|
||||
type Foo;
|
||||
#[wasm_bindgen(method)]
|
||||
fn work(this: &Foo);
|
||||
}
|
||||
```
|
||||
|
||||
The first argument of a `method` annotation must be a borrowed reference (not
|
||||
mutable, shared) to the type that the method is attached to. In this case
|
||||
we'll be able to call this method like `foo.work()` in JS (where `foo` has
|
||||
type `Foo`).
|
||||
|
||||
In JS this invocation will correspond to accessing `Foo.prototype.work` and
|
||||
then calling that when the import is called. Note that `method` by default
|
||||
implies going through `prototype` to get a function pointer.
|
||||
|
||||
* `js_namespace` - this attribute indicates that the JS type is accessed through
|
||||
a particular namespace. For example the `WebAssembly.Module` APIs are all
|
||||
accessed through the `WebAssembly` namespace. The `js_namespace` can be
|
||||
applied to any import and whenever the generated JS attempts to reference a
|
||||
name (like a class or function name) it'll be accessed through this namespace.
|
||||
|
||||
```rust
|
||||
#[wasm_bindgen]
|
||||
extern {
|
||||
#[wasm_bindgen(js_namespace = console)]
|
||||
fn log(s: &str);
|
||||
}
|
||||
```
|
||||
|
||||
This is an example of how to bind `console.log(x)` in Rust. The `log` function
|
||||
will be available in the Rust module and will be invoked as `console.log` in
|
||||
JS.
|
||||
|
||||
* `getter` and `setter` - these two attributes can be combined with `method` to
|
||||
indicate that this is a getter or setter method. A `getter`-tagged function by
|
||||
default accesses the JS property with the same name as the getter function. A
|
||||
`setter`'s function name is currently required to start with "set\_" and the
|
||||
property it accesses is the suffix after "set\_".
|
||||
|
||||
```rust
|
||||
#[wasm_bindgen]
|
||||
extern {
|
||||
type Foo;
|
||||
#[wasm_bindgen(method, getter)]
|
||||
fn property(this: &Foo) -> u32;
|
||||
#[wasm_bindgen(method, setter)]
|
||||
fn set_property(this: &Foo, val: u32);
|
||||
}
|
||||
```
|
||||
|
||||
Here we're importing the `Foo` type and defining the ability to access each
|
||||
object's `property` property. The first function here is a getter and will be
|
||||
available in Rust as `foo.property()`, and the latter is the setter which is
|
||||
accessible as `foo.set_property(2)`. Note that both functions have a `this`
|
||||
argument as they're tagged with `method`.
|
||||
|
||||
Finally, you can also pass an argument to the `getter` and `setter`
|
||||
properties to configure what property is accessed. When the property is
|
||||
explicitly specified then there is no restriction on the method name. For
|
||||
example the below is equivalent to the above:
|
||||
|
||||
```rust
|
||||
#[wasm_bindgen]
|
||||
extern {
|
||||
type Foo;
|
||||
#[wasm_bindgen(method, getter = property)]
|
||||
fn assorted_method_name(this: &Foo) -> u32;
|
||||
#[wasm_bindgen(method, setter = "property")]
|
||||
fn some_other_method_name(this: &Foo, val: u32);
|
||||
}
|
||||
```
|
||||
|
||||
Properties in JS are accessed through `Object.getOwnPropertyDescriptor`. Note
|
||||
that this typically only works for class-like-defined properties which aren't
|
||||
just attached properties on any old object. For accessing any old property on
|
||||
an object we can use the `structural` flag.
|
||||
|
||||
* `indexing_getter`, `indexing_setter` and `indexing_deleter` - these three
|
||||
attributes can be combined with `method` to indicate that this is a indexing
|
||||
getter, indexing setter or indexing deleter method. They are different from
|
||||
`getter` and `setter` in a way that `getter` and `setter` can only access
|
||||
properties that have a name corresponding to the function name or their
|
||||
argument, but `indexing_getter`, `indexing_setter` and `indexing_deleter`
|
||||
work in a dynamic manner, similarly to the indexing syntax in JS
|
||||
(`object[propertyName]`), hence the name. Should always be used together with
|
||||
the `structural` flag. For example:
|
||||
|
||||
```rust
|
||||
#[wasm_bindgen]
|
||||
extern {
|
||||
type Foo;
|
||||
#[wasm_bindgen(method, structural, indexing_getter)]
|
||||
fn get(this: &Foo, prop: &str) -> u32;
|
||||
#[wasm_bindgen(method, structural, indexing_setter)]
|
||||
fn set(this: &Foo, prop: &str, val: u32);
|
||||
#[wasm_bindgen(method, structural, indexing_deleter)]
|
||||
fn delete(this: &Foo, prop: &str);
|
||||
}
|
||||
```
|
||||
|
||||
* `structural` - this is a flag to `method` annotations which indicates that the
|
||||
method being accessed (or property with getters/setters) should be accessed in
|
||||
a structural fashion. For example methods are *not* accessed through
|
||||
`prototype` and properties are accessed on the object directly rather than
|
||||
through `Object.getOwnPropertyDescriptor`.
|
||||
|
||||
```rust
|
||||
#[wasm_bindgen]
|
||||
extern {
|
||||
type Foo;
|
||||
#[wasm_bindgen(method, structural)]
|
||||
fn bar(this: &Foo);
|
||||
#[wasm_bindgen(method, getter, structural)]
|
||||
fn baz(this: &Foo) -> u32;
|
||||
}
|
||||
```
|
||||
|
||||
The type here, `Foo`, is not required to exist in JS (it's not referenced).
|
||||
Instead wasm-bindgen will generate shims that will access the passed in JS
|
||||
value's `bar` property to or the `baz` property (depending on the function).
|
||||
|
||||
* `js_name = foo` - this can be used to bind to a different function in JS than
|
||||
the identifier that's defined in Rust. For example you can also define
|
||||
multiple signatures for a polymorphic function in JS as well:
|
||||
|
||||
```rust
|
||||
#[wasm_bindgen]
|
||||
extern {
|
||||
type Foo;
|
||||
#[wasm_bindgen(js_namespace = console, js_name = log)]
|
||||
fn log_string(s: &str);
|
||||
#[wasm_bindgen(js_namespace = console, js_name = log)]
|
||||
fn log_u32(n: u32);
|
||||
#[wasm_bindgen(js_namespace = console, js_name = log)]
|
||||
fn log_many(a: u32, b: JsValue);
|
||||
}
|
||||
```
|
||||
|
||||
All of these functions will call `console.log` in JS, but each identifier
|
||||
will have only one signature in Rust.
|
6
guide/src/reference/attributes/index.md
Normal file
6
guide/src/reference/attributes/index.md
Normal file
@ -0,0 +1,6 @@
|
||||
# `#[wasm_bindgen]` Attributes
|
||||
|
||||
The `#[wasm_bindgen]` macro supports a good amount of configuration for
|
||||
controlling precisely how exports are exported, how imports are imported, and
|
||||
what the generated JavaScript glue ends up looking like. This section is an
|
||||
exhaustive reference of the possibilities!
|
29
guide/src/reference/attributes/on-js-imports/catch.md
Normal file
29
guide/src/reference/attributes/on-js-imports/catch.md
Normal file
@ -0,0 +1,29 @@
|
||||
# `catch`
|
||||
|
||||
The `catch` attribute allows catching a JavaScript exception. This can be
|
||||
attached to any imported function or method, and the function must return a
|
||||
`Result` where the `Err` payload is a `JsValue`:
|
||||
|
||||
```rust
|
||||
#[wasm_bindgen]
|
||||
extern {
|
||||
// `catch` on a standalone function.
|
||||
#[wasm_bindgen(catch)]
|
||||
fn foo() -> Result<(), JsValue>;
|
||||
|
||||
// `catch` on a method.
|
||||
type Zoidberg;
|
||||
#[wasm_bindgen(catch, method)]
|
||||
fn woop_woop_woop(this: &Zoidberg) -> Result<u32, JsValue>;
|
||||
}
|
||||
```
|
||||
|
||||
If calling the imported function throws an exception, then `Err` will be
|
||||
returned with the exception that was raised. Otherwise, `Ok` is returned with
|
||||
the result of the function.
|
||||
|
||||
> By default `wasm-bindgen` will take no action when wasm calls a JS function
|
||||
> which ends up throwing an exception. The wasm spec right now doesn't support
|
||||
> stack unwinding and as a result Rust code **will not execute destructors**.
|
||||
> This can unfortunately cause memory leaks in Rust right now, but as soon as
|
||||
> wasm implements catching exceptions we'll be sure to add support as well!
|
24
guide/src/reference/attributes/on-js-imports/constructor.md
Normal file
24
guide/src/reference/attributes/on-js-imports/constructor.md
Normal file
@ -0,0 +1,24 @@
|
||||
# `constructor`
|
||||
|
||||
The `constructor` attribute is used to indicate that the function being bound
|
||||
should actually translate to calling the `new` operator in JavaScript. The final
|
||||
argument must be a type that's imported from JavaScript, and it's what will get
|
||||
used in the generated glue:
|
||||
|
||||
```rust
|
||||
#[wasm_bindgen]
|
||||
extern {
|
||||
type Shoes;
|
||||
|
||||
#[wasm_bindgen(constructor)]
|
||||
fn new() -> Shoes;
|
||||
}
|
||||
```
|
||||
|
||||
This will attach a `new` static method to the `Shoes` type, and in JavaScript
|
||||
when this method is called, it will be equivalent to `new Shoes()`.
|
||||
|
||||
```rust
|
||||
// Become a cobbler; construct `new Shoes()`
|
||||
let shoes = Shoes::new();
|
||||
```
|
@ -0,0 +1,78 @@
|
||||
# `getter` and `setter`
|
||||
|
||||
These two attributes can be combined with `method` to indicate that this is a
|
||||
getter or setter method. A `getter`-tagged function by default accesses the
|
||||
JavaScript property with the same name as the getter function. A `setter`'s
|
||||
function name is currently required to start with `set_` and the property it
|
||||
accesses is the suffix after `set\_`.
|
||||
|
||||
Consider the following JavaScript class that has a getter and setter for the
|
||||
`white_russians` property:
|
||||
|
||||
```js
|
||||
class TheDude {
|
||||
get white_russians() {
|
||||
...
|
||||
}
|
||||
set white_russians(val) {
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
We would import this with the following `#[wasm_bindgen]` attributes:
|
||||
|
||||
```rust
|
||||
#[wasm_bindgen]
|
||||
extern {
|
||||
type TheDude;
|
||||
|
||||
#[wasm_bindgen(method, getter)]
|
||||
fn white_russians(this: &TheDude) -> u32;
|
||||
|
||||
#[wasm_bindgen(method, setter)]
|
||||
fn set_white_russians(this: &TheDude, val: u32);
|
||||
}
|
||||
```
|
||||
|
||||
Here we're importing the `TheDude` type and defining the ability to access each
|
||||
object's `white_russians` property. The first function here is a getter and will
|
||||
be available in Rust as `the_dude.white_russians()`, and the latter is the
|
||||
setter which is accessible as `the_dude.set_white_russians(2)`. Note that both
|
||||
functions have a `this` argument as they're tagged with `method`.
|
||||
|
||||
Finally, you can also pass an argument to the `getter` and `setter`
|
||||
properties to configure what property is accessed. When the property is
|
||||
explicitly specified then there is no restriction on the method name. For
|
||||
example the below is equivalent to the above:
|
||||
|
||||
```rust
|
||||
#[wasm_bindgen]
|
||||
extern {
|
||||
type TheDude;
|
||||
|
||||
#[wasm_bindgen(method, getter = white_russians)]
|
||||
fn my_custom_getter_name(this: &TheDude) -> u32;
|
||||
|
||||
#[wasm_bindgen(method, setter = white_russians)]
|
||||
fn my_custom_setter_name(this: &TheDude, val: u32);
|
||||
}
|
||||
```
|
||||
|
||||
Heads up! `getter` and `setter` functions are found on the constructor's
|
||||
prototype chain once at load time, cached, and then the cached accessor is
|
||||
invoked on each access. If you need to dynamically walk the prototype chain on
|
||||
every access, add the `structural` attribute!
|
||||
|
||||
```js
|
||||
// This is the default function Rust will invoke on `the_dude.white_russians()`:
|
||||
const white_russians = Object.getOwnPropertyDescriptor(
|
||||
TheDude.prototype,
|
||||
"white_russians"
|
||||
).get;
|
||||
|
||||
// This is what you get by adding `structural`:
|
||||
const white_russians = function(the_dude) {
|
||||
return the_dude.white_russians;
|
||||
};
|
||||
```
|
5
guide/src/reference/attributes/on-js-imports/index.md
Normal file
5
guide/src/reference/attributes/on-js-imports/index.md
Normal file
@ -0,0 +1,5 @@
|
||||
# `#[wasm_bindgen]` on JavaScript Imports
|
||||
|
||||
This section enumerates the attributes available for customizing bindings for
|
||||
JavaScript functions and classes imported into Rust within an `extern { ... }`
|
||||
block.
|
20
guide/src/reference/attributes/on-js-imports/js_class.md
Normal file
20
guide/src/reference/attributes/on-js-imports/js_class.md
Normal file
@ -0,0 +1,20 @@
|
||||
# `js_class = "Blah"`
|
||||
|
||||
The `js_class` attribute can be used in conjunction with the `method` attribute
|
||||
to bind methods of imported JavaScript classes that have been renamed on the
|
||||
Rust side.
|
||||
|
||||
```rust
|
||||
#[wasm_bindgen]
|
||||
extern {
|
||||
// We don't want to import JS strings as `String`, since Rust already has a
|
||||
// `String` type in its prelude, so rename it as `JsString`.
|
||||
#[wasm_bindgen(js_name = String)]
|
||||
type JsString;
|
||||
|
||||
// This is a method on the JavaScript "String" class, so specify that with
|
||||
// the `js_class` attribute.
|
||||
#[wasm_bindgen(method, js_class = "String", js_name = charAt)]
|
||||
fn char_at(this: &JsString, index: u32) -> JsString;
|
||||
}
|
||||
```
|
46
guide/src/reference/attributes/on-js-imports/js_name.md
Normal file
46
guide/src/reference/attributes/on-js-imports/js_name.md
Normal file
@ -0,0 +1,46 @@
|
||||
# `js_name = blah`
|
||||
|
||||
The `js_name` attribute can be used to bind to a different function in
|
||||
JavaScript than the identifier that's defined in Rust.
|
||||
|
||||
Most often, this is used to convert a camel-cased JavaScript identifier into a
|
||||
snake-cased Rust identifier:
|
||||
|
||||
```rust
|
||||
#[wasm_bindgen]
|
||||
extern {
|
||||
#[wasm_bindgen(js_name = jsOftenUsesCamelCase)]
|
||||
fn js_often_uses_camel_case() -> u32;
|
||||
}
|
||||
```
|
||||
|
||||
Sometimes, it is used to bind to JavaScript identifiers that are not valid Rust
|
||||
identifiers, in which case `js_name = "some string"` is used instead of `js_name
|
||||
= ident`:
|
||||
|
||||
```rust
|
||||
#[wasm_bindgen]
|
||||
extern {
|
||||
#[wasm_bindgen(js_name = "$$$")]
|
||||
fn cash_money() -> u32;
|
||||
}
|
||||
```
|
||||
However, you can also use `js_name` to define multiple signatures for
|
||||
polymorphic JavaScript functions:
|
||||
|
||||
```rust
|
||||
#[wasm_bindgen]
|
||||
extern {
|
||||
#[wasm_bindgen(js_namespace = console, js_name = log)]
|
||||
fn console_log_str(s: &str);
|
||||
|
||||
#[wasm_bindgen(js_namespace = console, js_name = log)]
|
||||
fn console_log_u32(n: u32);
|
||||
|
||||
#[wasm_bindgen(js_namespace = console, js_name = log)]
|
||||
fn console_log_many(a: u32, b: &JsValue);
|
||||
}
|
||||
```
|
||||
|
||||
All of these functions will call `console.log` in JavaScript, but each
|
||||
identifier will have only one signature in Rust.
|
21
guide/src/reference/attributes/on-js-imports/js_namespace.md
Normal file
21
guide/src/reference/attributes/on-js-imports/js_namespace.md
Normal file
@ -0,0 +1,21 @@
|
||||
# `js_namespace = blah`
|
||||
|
||||
This attribute indicates that the JavaScript type is accessed through the given
|
||||
namespace. For example, the `WebAssembly.Module` APIs are all accessed through
|
||||
the `WebAssembly` namespace. `js_namespace` can be applied to any import
|
||||
(function or type) and whenever the generated JavaScript attempts to reference a
|
||||
name (like a class or function name) it'll be accessed through this namespace.
|
||||
|
||||
```rust
|
||||
#[wasm_bindgen]
|
||||
extern {
|
||||
#[wasm_bindgen(js_namespace = console)]
|
||||
fn log(s: &str);
|
||||
}
|
||||
|
||||
log("hello, console!");
|
||||
```
|
||||
|
||||
This is an example of how to bind `console.log` in Rust. The `log` function will
|
||||
be available in the Rust module and will be invoked as `console.log` in
|
||||
JavaScript.
|
26
guide/src/reference/attributes/on-js-imports/method.md
Normal file
26
guide/src/reference/attributes/on-js-imports/method.md
Normal file
@ -0,0 +1,26 @@
|
||||
# `method`
|
||||
|
||||
The `method` attribute allows you to describe methods of imported JavaScript
|
||||
objects. It is applied on a function that has `this` as its first parameter,
|
||||
which is a shared reference to an imported JavaScript type.
|
||||
|
||||
```rust
|
||||
#[wasm_bindgen]
|
||||
extern {
|
||||
type Set;
|
||||
|
||||
#[wasm_bindgen(method)]
|
||||
fn has(this: &Set, element: &JsValue) -> bool;
|
||||
}
|
||||
```
|
||||
|
||||
This generates a `has` method on `Set` in Rust, which invokes the
|
||||
`Set.prototype.has` method in JavaScript.
|
||||
|
||||
```rust
|
||||
let set: Set = ...;
|
||||
let elem: JsValue = ...;
|
||||
if set.has(&elem) {
|
||||
...
|
||||
}
|
||||
```
|
33
guide/src/reference/attributes/on-js-imports/module.md
Normal file
33
guide/src/reference/attributes/on-js-imports/module.md
Normal file
@ -0,0 +1,33 @@
|
||||
# `module = "blah"`
|
||||
|
||||
The `module` attributes configures the module from which items are imported. For
|
||||
example,
|
||||
|
||||
```rust
|
||||
#[wasm_bindgen(module = "wu/tang/clan")]
|
||||
extern {
|
||||
type ThirtySixChambers;
|
||||
}
|
||||
```
|
||||
|
||||
generates JavaScript import glue like:
|
||||
|
||||
```js
|
||||
import { ThirtySixChambers } from "wu/tang/clan";
|
||||
```
|
||||
|
||||
If a `module` attribute is not present, then the global scope is used
|
||||
instead. For example,
|
||||
|
||||
```rust
|
||||
#[wasm_bindgen]
|
||||
extern {
|
||||
fn illmatic() -> u32;
|
||||
}
|
||||
```
|
||||
|
||||
generates JavaScript import glue like:
|
||||
|
||||
```js
|
||||
let illmatic = this.illmatic;
|
||||
```
|
@ -0,0 +1,25 @@
|
||||
# `static_method_of = Blah`
|
||||
|
||||
The `static_method_of` attribute allows one to specify that an imported function
|
||||
is a static method of the given imported JavaScript class. For example, to bind
|
||||
to JavaScript's `Date.now()` static method, one would use this attribute:
|
||||
|
||||
```rust
|
||||
#[wasm_bindgen]
|
||||
extern {
|
||||
type Date;
|
||||
|
||||
#[wasm_bindgen(static_method_of = Date)]
|
||||
pub fn now() -> f64;
|
||||
}
|
||||
```
|
||||
|
||||
The `now` function becomes a static method of the imported type in the Rust
|
||||
bindings as well:
|
||||
|
||||
```rust
|
||||
let instant = Date::now();
|
||||
```
|
||||
|
||||
This is similar to the `js_namespace` attribute, but the usage from within Rust
|
||||
is different since the method also becomes a static method of the imported type.
|
50
guide/src/reference/attributes/on-js-imports/structural.md
Normal file
50
guide/src/reference/attributes/on-js-imports/structural.md
Normal file
@ -0,0 +1,50 @@
|
||||
# `structural`
|
||||
|
||||
The `structural` flag can be added to `method` annotations, indicating that the
|
||||
method being accessed (or property with getters/setters) should be accessed in a
|
||||
structural, duck-type-y fashion. Rather than walking the constructor's prototype
|
||||
chain once at load time and caching the property result, the prototype chain is
|
||||
dynamically walked on every access.
|
||||
|
||||
```rust
|
||||
#[wasm_bindgen]
|
||||
extern {
|
||||
type Duck;
|
||||
|
||||
#[wasm_bindgen(method, structural)]
|
||||
fn quack(this: &Duck);
|
||||
|
||||
#[wasm_bindgen(method, getter, structural)]
|
||||
fn is_swimming(this: &Duck) -> bool;
|
||||
}
|
||||
```
|
||||
|
||||
The constructor for the type here, `Duck`, is not required to exist in
|
||||
JavaScript (it's not referenced). Instead `wasm-bindgen` will generate shims
|
||||
that will access the passed in JavaScript value's `quack` method or its
|
||||
`is_swimming` property.
|
||||
|
||||
```js
|
||||
// Without `structural`, get the method directly off the prototype at load time:
|
||||
const Duck_prototype_quack = Duck.prototype.quack;
|
||||
function quack(duck) {
|
||||
Duck_prototype_quack.call(duck);
|
||||
}
|
||||
|
||||
// With `structural`, walk the prototype chain on every access:
|
||||
function quack(duck) {
|
||||
duck.quack();
|
||||
}
|
||||
```
|
||||
|
||||
## Why don't we always use the `structural` behavior?
|
||||
|
||||
In theory, it is faster since the prototype chain doesn't need to be traversed
|
||||
every time the method or property is accessed, but today's optimizing JIT
|
||||
compilers are really good about eliminating that cost. The real reason is to be
|
||||
future compatible with the ["host bindings" proposal][host-bindings], which
|
||||
requires that there be no JavaScript shim between the caller and the native host
|
||||
function. In this scenario, the properties and methods *must* be resolved before
|
||||
the wasm is instantiated.
|
||||
|
||||
[host-bindings]: https://github.com/WebAssembly/host-bindings/blob/master/proposals/host-bindings/Overview.md
|
@ -0,0 +1,34 @@
|
||||
# `constructor`
|
||||
|
||||
When attached to a Rust "constructor" it will make the generated JavaScript
|
||||
bindings callable as `new Foo()`.
|
||||
|
||||
For example, consider this exported Rust type and `constructor` annotation:
|
||||
|
||||
```rust
|
||||
#[wasm_bindgen]
|
||||
pub struct Foo {
|
||||
contents: u32,
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl Foo {
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new() -> Foo {
|
||||
Foo { contents: 0 }
|
||||
}
|
||||
|
||||
pub fn get_contents(&self) -> u32 {
|
||||
self.contents
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This can be used in JavaScript as:
|
||||
|
||||
```js
|
||||
import { Foo } from './my_module';
|
||||
|
||||
const f = new Foo();
|
||||
console.log(f.get_contents());
|
||||
```
|
4
guide/src/reference/attributes/on-rust-exports/index.md
Normal file
4
guide/src/reference/attributes/on-rust-exports/index.md
Normal file
@ -0,0 +1,4 @@
|
||||
# `#[wasm_bindgen]` on Rust Exports
|
||||
|
||||
This section enumerates the attributes available for customizing bindings for
|
||||
Rust functions and `struct`s exported to JavaScript.
|
24
guide/src/reference/attributes/on-rust-exports/js_name.md
Normal file
24
guide/src/reference/attributes/on-rust-exports/js_name.md
Normal file
@ -0,0 +1,24 @@
|
||||
# `js_name = Blah`
|
||||
|
||||
The `js_name` attribute can be used to export a different name in JS than what
|
||||
something is named in Rust. It can be applied to both exported Rust functions
|
||||
and types.
|
||||
|
||||
For example, this is often used to convert between Rust's snake-cased
|
||||
identifiers into JavaScript's camel-cased identifiers:
|
||||
|
||||
```rust
|
||||
#[wasm_bindgen(js_name = doTheThing)]
|
||||
pub fn do_the_thing() -> u32 {
|
||||
42
|
||||
}
|
||||
```
|
||||
|
||||
This can be used in JavaScript as:
|
||||
|
||||
```js
|
||||
import { doTheThing } from './my_module';
|
||||
|
||||
const x = doTheThing();
|
||||
console.log(x);
|
||||
```
|
39
guide/src/reference/attributes/on-rust-exports/readonly.md
Normal file
39
guide/src/reference/attributes/on-rust-exports/readonly.md
Normal file
@ -0,0 +1,39 @@
|
||||
# `readonly`
|
||||
|
||||
When attached to a `pub` struct field this indicates that it's read-only from
|
||||
JavaScript, and a setter will not be generated and exported to JavaScript.
|
||||
|
||||
```rust
|
||||
#[wasm_bindgen]
|
||||
pub fn make_foo() -> Foo {
|
||||
Foo {
|
||||
first: 10,
|
||||
second: 20,
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub struct Foo {
|
||||
pub first: u32,
|
||||
|
||||
#[wasm_bindgen(readonly)]
|
||||
pub second: u32,
|
||||
}
|
||||
```
|
||||
|
||||
Here the `first` field will be both readable and writable from JS, but the
|
||||
`second` field will be a `readonly` field in JS where the setter isn't
|
||||
implemented and attempting to set it will throw an exception.
|
||||
|
||||
```js
|
||||
import { make_foo } from "./my_module";
|
||||
|
||||
const foo = make_foo();
|
||||
|
||||
// Can both get and set `first`.
|
||||
foo.first = 99;
|
||||
console.log(foo.first);
|
||||
|
||||
// Can only get `second`.
|
||||
console.log(foo.second);
|
||||
```
|
@ -1,65 +0,0 @@
|
||||
# Closures
|
||||
|
||||
The `#[wasm_bindgen]` attribute supports some Rust closures being passed to JS.
|
||||
Examples of what you can do are:
|
||||
|
||||
```rust
|
||||
#[wasm_bindgen]
|
||||
extern {
|
||||
fn foo(a: &Fn()); // could also be `&mut FnMut()`
|
||||
}
|
||||
```
|
||||
|
||||
Here a function `foo` is imported from JS where the first argument is a *stack
|
||||
closure*. You can call this function with a `&Fn()` argument and JS will receive
|
||||
a JS function. When the `foo` function returns, however, the JS function will be
|
||||
invalidated and any future usage of it will raise an exception.
|
||||
|
||||
Closures also support arguments and return values like exports do, for example:
|
||||
|
||||
```rust
|
||||
#[wasm_bindgen]
|
||||
extern {
|
||||
type Foo;
|
||||
|
||||
fn bar(a: &Fn(u32, String) -> Foo);
|
||||
}
|
||||
```
|
||||
|
||||
Sometimes the stack behavior of these closures is not desired. For example you'd
|
||||
like to schedule a closure to be run on the next turn of the event loop in JS
|
||||
through `setTimeout`. For this you want the imported function to return but the
|
||||
JS closure still needs to be valid!
|
||||
|
||||
To support this use case you can do:
|
||||
|
||||
```rust
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[wasm_bindgen]
|
||||
extern {
|
||||
fn baz(a: &Closure<Fn()>);
|
||||
}
|
||||
```
|
||||
|
||||
The `Closure` type is defined in the `wasm_bindgen` crate and represents a "long
|
||||
lived" closure. The JS closure passed to `baz` is still valid after `baz`
|
||||
returns, and the validity of the JS closure is tied to the lifetime of the
|
||||
`Closure` in Rust. Once `Closure` is dropped it will deallocate its internal
|
||||
memory and invalidate the corresponding JS function.
|
||||
|
||||
Like stack closures a `Closure` also supports `FnMut`:
|
||||
|
||||
```rust
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[wasm_bindgen]
|
||||
extern {
|
||||
fn another(a: &Closure<FnMut() -> u32>);
|
||||
}
|
||||
```
|
||||
|
||||
At this time you cannot [pass a JS closure to Rust][cbjs], you can only pass a
|
||||
Rust closure to JS in limited circumstances.
|
||||
|
||||
[cbjs]: https://github.com/rustwasm/wasm-bindgen/issues/103
|
118
guide/src/reference/passing-rust-closures-to-js.md
Normal file
118
guide/src/reference/passing-rust-closures-to-js.md
Normal file
@ -0,0 +1,118 @@
|
||||
# Passing Rust Closures to Imported JavaScript Functions
|
||||
|
||||
The `#[wasm_bindgen]` attribute supports Rust closures being passed to
|
||||
JavaScript in two variants:
|
||||
|
||||
1. Stack-lifetime closures that should not be invoked by JavaScript again after
|
||||
the imported JavaScript function that the closure was passed to returns.
|
||||
|
||||
2. Heap-allocated closures that can be invoked any number of times, but must be
|
||||
explicitly deallocated when finished.
|
||||
|
||||
## Stack-Lifetime Closures
|
||||
|
||||
Closures with a stack lifetime are passed to JavaScript as either `&Fn` or `&mut
|
||||
FnMut` trait objects:
|
||||
|
||||
```rust
|
||||
// Import JS functions that take closures
|
||||
|
||||
#[wasm_bindgen]
|
||||
extern {
|
||||
fn takes_immutable_closure(f: &Fn());
|
||||
|
||||
fn takes_mutable_closure(f: &mut FnMut());
|
||||
}
|
||||
|
||||
// Usage
|
||||
|
||||
takes_immutable_closure(&|| {
|
||||
// ...
|
||||
});
|
||||
|
||||
let mut times_called = 0;
|
||||
takes_mutable_closure(&mut || {
|
||||
times_called += 1;
|
||||
});
|
||||
```
|
||||
|
||||
**Once these imported functions return, the closures that were given to them
|
||||
will become invalidated, and any future attempts to call those closures from
|
||||
JavaScript will raise an exception.**
|
||||
|
||||
Closures also support arguments and return values like exports do, for example:
|
||||
|
||||
```rust
|
||||
#[wasm_bindgen]
|
||||
extern {
|
||||
fn takes_closure_that_takes_int_and_returns_string(x: &Fn(u32) -> String);
|
||||
}
|
||||
|
||||
takes_closure_that_takes_int_and_returns_string(&|x: u32| -> String {
|
||||
format!("x is {}", x)
|
||||
});
|
||||
```
|
||||
|
||||
## Heap-Allocated Closures
|
||||
|
||||
Sometimes the discipline of stack-lifetime closures is not desired. For example,
|
||||
you'd like to schedule a closure to be run on the next turn of the event loop in
|
||||
JavaScript through `setTimeout`. For this, you want the imported function to
|
||||
return but the JavaScript closure still needs to be valid!
|
||||
|
||||
For this scenario, you need the `Closure` type, which is defined in the
|
||||
`wasm_bindgen` crate, exported in `wasm_bindgen::prelude`, and represents a
|
||||
"long lived" closure.
|
||||
|
||||
The validity of the JavaScript closure is tied to the lifetime of the `Closure`
|
||||
in Rust. **Once a `Closure` is dropped, it will deallocate its internal memory
|
||||
and invalidate the corresponding JavaScript function so that any further
|
||||
attempts to invoke it raise an exception.**
|
||||
|
||||
Like stack closures a `Closure` supports both `Fn` and `FnMut` closures, as well
|
||||
as arguments and returns.
|
||||
|
||||
```rust
|
||||
#[wasm_bindgen]
|
||||
extern {
|
||||
fn setInterval(closure: &Closure<FnMut()>, millis: u32) -> f64;
|
||||
fn cancelInterval(token: f64);
|
||||
|
||||
#[wasm_bindgen(js_namespace = console)]
|
||||
fn log(s: &str);
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub struct Interval {
|
||||
closure: Closure<FnMut()>,
|
||||
token: f64,
|
||||
}
|
||||
|
||||
impl Interval {
|
||||
pub fn new<F>(millis: u32, f: F) -> Interval
|
||||
where
|
||||
F: FnMut()
|
||||
{
|
||||
// Construct a new closure.
|
||||
let closure = Closure::new(f);
|
||||
|
||||
// Pass the closuer to JS, to run every n milliseconds.
|
||||
let token = setInterval(&closure, millis);
|
||||
|
||||
Interval { closure, token }
|
||||
}
|
||||
}
|
||||
|
||||
// When the Interval is destroyed, cancel its `setInterval` timer.
|
||||
impl Drop for Interval {
|
||||
fn drop(&mut self) {
|
||||
cancelInterval(self.token);
|
||||
}
|
||||
}
|
||||
|
||||
// Keep logging "hello" every second until the resulting `Interval` is dropped.
|
||||
#[wasm_bindgen]
|
||||
pub fn hello() -> Interval {
|
||||
Interval::new(1_000, || log("hello"));
|
||||
}
|
||||
```
|
31
guide/src/reference/receiving-js-closures-in-rust.md
Normal file
31
guide/src/reference/receiving-js-closures-in-rust.md
Normal file
@ -0,0 +1,31 @@
|
||||
# Receiving JavaScript Closures in Exported Rust Functions
|
||||
|
||||
You can use the `js-sys` crate to access JavaScript's `Function` type, and
|
||||
invoke that function via `Function.prototype.apply` and
|
||||
`Function.prototype.call`.
|
||||
|
||||
For example, we can wrap a `Vec<u32>` in a new type, export it to JavaScript,
|
||||
and invoke a JavaScript closure on each member of the `Vec`:
|
||||
|
||||
```rust
|
||||
extern crate js_sys;
|
||||
extern crate wasm_bindgen;
|
||||
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub struct VecU32 {
|
||||
xs: Vec<u32>,
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl VecU32 {
|
||||
pub fn each(&self, f: &js_sys::Function) {
|
||||
let this = JsValue::NULL;
|
||||
for x in &self.xs {
|
||||
let x = JsValue::from(x);
|
||||
let _ = f.call1(&this, &x);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
Loading…
x
Reference in New Issue
Block a user