Rebase fallout and review comments

This commit is contained in:
Alex Crichton 2018-08-06 14:29:23 -07:00
parent 37db88ebfa
commit bd15db40a0
3 changed files with 9 additions and 179 deletions

View File

@ -1,170 +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...
* `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.

View File

@ -18,7 +18,7 @@ where
{
/// Test whether this JS value is an instance of the type `T`.
///
/// This commit performs a dynamic check (at runtime) using the JS
/// This method performs a dynamic check (at runtime) using the JS
/// `instanceof` operator. This method returns `self instanceof T`.
fn is_instance_of<T>(&self) -> bool
where
@ -32,7 +32,7 @@ where
///
/// This method will return `Err(self)` is `self.is_instance_of::<T>()`
/// returns `false`, and otherwise it will return `Ok(T)` manufactured with
/// an unchecked cast (verified safe via the `instanceof` operation).
/// an unchecked cast (verified correct via the `instanceof` operation).
fn dyn_into<T>(self) -> Result<T, Self>
where
T: JsCast,
@ -49,7 +49,7 @@ where
///
/// This method will return `None` is `self.is_instance_of::<T>()`
/// returns `false`, and otherwise it will return `Some(&T)` manufactured
/// with an unchecked cast (verified safe via the `instanceof` operation).
/// with an unchecked cast (verified correct via the `instanceof` operation).
fn dyn_ref<T>(&self) -> Option<&T>
where
T: JsCast,
@ -66,8 +66,8 @@ where
///
/// This method will return `None` is `self.is_instance_of::<T>()`
/// returns `false`, and otherwise it will return `Some(&mut T)`
/// manufactured with an unchecked cast (verified safe via the `instanceof`
/// operation).
/// manufactured with an unchecked cast (verified correct via the
/// `instanceof` operation).
fn dyn_mut<T>(&mut self) -> Option<&mut T>
where
T: JsCast,
@ -85,7 +85,7 @@ where
/// `self` and `T` are simple wrappers around `JsValue`. This method **does
/// not check whether `self` is an instance of `T`**. If used incorrectly
/// then this method may cause runtime exceptions in both Rust and JS, this
/// shoudl be used with caution.
/// should be used with caution.
fn unchecked_into<T>(self) -> T
where
T: JsCast,
@ -100,7 +100,7 @@ where
/// `self` and `T` are simple wrappers around `JsValue`. This method **does
/// not check whether `self` is an instance of `T`**. If used incorrectly
/// then this method may cause runtime exceptions in both Rust and JS, this
/// shoudl be used with caution.
/// should be used with caution.
///
/// This method, unlike `unchecked_into`, does not consume ownership of
/// `self` and instead works over a shared reference.
@ -118,7 +118,7 @@ where
/// `self` and `T` are simple wrappers around `JsValue`. This method **does
/// not check whether `self` is an instance of `T`**. If used incorrectly
/// then this method may cause runtime exceptions in both Rust and JS, this
/// shoudl be used with caution.
/// should be used with caution.
///
/// This method, unlike `unchecked_into`, does not consume ownership of
/// `self` and instead works over a utable reference.

View File

@ -2,7 +2,7 @@ use wasm_bindgen::JsCast;
use wasm_bindgen::prelude::*;
use wasm_bindgen_test::*;
#[wasm_bindgen(module = "tests/wasm/jscast.js", version = "*")]
#[wasm_bindgen(module = "tests/wasm/jscast.js")]
extern {
type JsCast1;
#[wasm_bindgen(constructor)]