mirror of
https://github.com/fluencelabs/wasm-bindgen
synced 2025-05-19 00:51:19 +00:00
Rebase fallout and review comments
This commit is contained in:
parent
37db88ebfa
commit
bd15db40a0
@ -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.
|
|
16
src/cast.rs
16
src/cast.rs
@ -18,7 +18,7 @@ where
|
|||||||
{
|
{
|
||||||
/// Test whether this JS value is an instance of the type `T`.
|
/// 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`.
|
/// `instanceof` operator. This method returns `self instanceof T`.
|
||||||
fn is_instance_of<T>(&self) -> bool
|
fn is_instance_of<T>(&self) -> bool
|
||||||
where
|
where
|
||||||
@ -32,7 +32,7 @@ where
|
|||||||
///
|
///
|
||||||
/// This method will return `Err(self)` is `self.is_instance_of::<T>()`
|
/// This method will return `Err(self)` is `self.is_instance_of::<T>()`
|
||||||
/// returns `false`, and otherwise it will return `Ok(T)` manufactured with
|
/// 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>
|
fn dyn_into<T>(self) -> Result<T, Self>
|
||||||
where
|
where
|
||||||
T: JsCast,
|
T: JsCast,
|
||||||
@ -49,7 +49,7 @@ where
|
|||||||
///
|
///
|
||||||
/// This method will return `None` is `self.is_instance_of::<T>()`
|
/// This method will return `None` is `self.is_instance_of::<T>()`
|
||||||
/// returns `false`, and otherwise it will return `Some(&T)` manufactured
|
/// 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>
|
fn dyn_ref<T>(&self) -> Option<&T>
|
||||||
where
|
where
|
||||||
T: JsCast,
|
T: JsCast,
|
||||||
@ -66,8 +66,8 @@ where
|
|||||||
///
|
///
|
||||||
/// This method will return `None` is `self.is_instance_of::<T>()`
|
/// This method will return `None` is `self.is_instance_of::<T>()`
|
||||||
/// returns `false`, and otherwise it will return `Some(&mut T)`
|
/// returns `false`, and otherwise it will return `Some(&mut T)`
|
||||||
/// manufactured with an unchecked cast (verified safe via the `instanceof`
|
/// manufactured with an unchecked cast (verified correct via the
|
||||||
/// operation).
|
/// `instanceof` operation).
|
||||||
fn dyn_mut<T>(&mut self) -> Option<&mut T>
|
fn dyn_mut<T>(&mut self) -> Option<&mut T>
|
||||||
where
|
where
|
||||||
T: JsCast,
|
T: JsCast,
|
||||||
@ -85,7 +85,7 @@ where
|
|||||||
/// `self` and `T` are simple wrappers around `JsValue`. This method **does
|
/// `self` and `T` are simple wrappers around `JsValue`. This method **does
|
||||||
/// not check whether `self` is an instance of `T`**. If used incorrectly
|
/// 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
|
/// 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
|
fn unchecked_into<T>(self) -> T
|
||||||
where
|
where
|
||||||
T: JsCast,
|
T: JsCast,
|
||||||
@ -100,7 +100,7 @@ where
|
|||||||
/// `self` and `T` are simple wrappers around `JsValue`. This method **does
|
/// `self` and `T` are simple wrappers around `JsValue`. This method **does
|
||||||
/// not check whether `self` is an instance of `T`**. If used incorrectly
|
/// 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
|
/// 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
|
/// This method, unlike `unchecked_into`, does not consume ownership of
|
||||||
/// `self` and instead works over a shared reference.
|
/// `self` and instead works over a shared reference.
|
||||||
@ -118,7 +118,7 @@ where
|
|||||||
/// `self` and `T` are simple wrappers around `JsValue`. This method **does
|
/// `self` and `T` are simple wrappers around `JsValue`. This method **does
|
||||||
/// not check whether `self` is an instance of `T`**. If used incorrectly
|
/// 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
|
/// 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
|
/// This method, unlike `unchecked_into`, does not consume ownership of
|
||||||
/// `self` and instead works over a utable reference.
|
/// `self` and instead works over a utable reference.
|
||||||
|
@ -2,7 +2,7 @@ use wasm_bindgen::JsCast;
|
|||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
use wasm_bindgen_test::*;
|
use wasm_bindgen_test::*;
|
||||||
|
|
||||||
#[wasm_bindgen(module = "tests/wasm/jscast.js", version = "*")]
|
#[wasm_bindgen(module = "tests/wasm/jscast.js")]
|
||||||
extern {
|
extern {
|
||||||
type JsCast1;
|
type JsCast1;
|
||||||
#[wasm_bindgen(constructor)]
|
#[wasm_bindgen(constructor)]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user