mirror of
https://github.com/fluencelabs/wasm-bindgen
synced 2025-06-24 02:01:35 +00:00
guide: add exhuastive reference docs for #[wasm_bindgen] attributes
This commit is contained in:
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());
|
||||
```
|
1
guide/src/reference/attributes/on-rust-exports/index.md
Normal file
1
guide/src/reference/attributes/on-rust-exports/index.md
Normal file
@ -0,0 +1 @@
|
||||
# `#[wasm_bindgen]` on Rust Exports
|
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);
|
||||
```
|
Reference in New Issue
Block a user