guide: add exhuastive reference docs for #[wasm_bindgen] attributes

This commit is contained in:
Nick Fitzgerald
2018-08-06 16:35:28 -07:00
parent b6a6dee7f1
commit 33520d4828
19 changed files with 477 additions and 280 deletions

View File

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

View File

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