RPM build fix (reverted CI changes which will need to be un-reverted or made conditional) and vendor Rust dependencies to make builds much faster in any CI system.
This commit is contained in:
57
zeroidc/vendor/wasm-bindgen/guide/src/contributing/design/describe.md
vendored
Normal file
57
zeroidc/vendor/wasm-bindgen/guide/src/contributing/design/describe.md
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
# Communicating types to `wasm-bindgen`
|
||||
|
||||
The last aspect to talk about when converting Rust/JS types amongst one another
|
||||
is how this information is actually communicated. The `#[wasm_bindgen]` macro is
|
||||
running over the syntactical (unresolved) structure of the Rust code and is then
|
||||
responsible for generating information that `wasm-bindgen` the CLI tool later
|
||||
reads.
|
||||
|
||||
To accomplish this a slightly unconventional approach is taken. Static
|
||||
information about the structure of the Rust code is serialized via JSON
|
||||
(currently) to a custom section of the wasm executable. Other information, like
|
||||
what the types actually are, unfortunately isn't known until later in the
|
||||
compiler due to things like associated type projections and typedefs. It also
|
||||
turns out that we want to convey "rich" types like `FnMut(String, Foo,
|
||||
&JsValue)` to the `wasm-bindgen` CLI, and handling all this is pretty tricky!
|
||||
|
||||
To solve this issue the `#[wasm_bindgen]` macro generates **executable
|
||||
functions** which "describe the type signature of an import or export". These
|
||||
executable functions are what the `WasmDescribe` trait is all about:
|
||||
|
||||
```rust
|
||||
pub trait WasmDescribe {
|
||||
fn describe();
|
||||
}
|
||||
```
|
||||
|
||||
While deceptively simple this trait is actually quite important. When you write,
|
||||
an export like this:
|
||||
|
||||
```rust
|
||||
#[wasm_bindgen]
|
||||
fn greet(a: &str) {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
In addition to the shims we talked about above which JS generates the macro
|
||||
*also* generates something like:
|
||||
|
||||
```
|
||||
#[no_mangle]
|
||||
pub extern "C" fn __wbindgen_describe_greet() {
|
||||
<dyn Fn(&str)>::describe();
|
||||
}
|
||||
```
|
||||
|
||||
Or in other words it generates invocations of `describe` functions. In doing so
|
||||
the `__wbindgen_describe_greet` shim is a programmatic description of the type
|
||||
layouts of an import/export. These are then executed when `wasm-bindgen` runs!
|
||||
These executions rely on an import called `__wbindgen_describe` which passes one
|
||||
`u32` to the host, and when called multiple times gives a `Vec<u32>`
|
||||
effectively. This `Vec<u32>` can then be reparsed into an `enum Descriptor`
|
||||
which fully describes a type.
|
||||
|
||||
All in all this is a bit roundabout but shouldn't have any impact on the
|
||||
generated code or runtime at all. All these descriptor functions are pruned from
|
||||
the emitted wasm file.
|
||||
149
zeroidc/vendor/wasm-bindgen/guide/src/contributing/design/exporting-rust-struct.md
vendored
Normal file
149
zeroidc/vendor/wasm-bindgen/guide/src/contributing/design/exporting-rust-struct.md
vendored
Normal file
@@ -0,0 +1,149 @@
|
||||
# Exporting a struct to JS
|
||||
|
||||
So far we've covered JS objects, importing functions, and exporting functions.
|
||||
This has given us quite a rich base to build on so far, and that's great! We
|
||||
sometimes, though, want to go even further and define a JS `class` in Rust. Or
|
||||
in other words, we want to expose an object with methods from Rust to JS rather
|
||||
than just importing/exporting free functions.
|
||||
|
||||
The `#[wasm_bindgen]` attribute can annotate both a `struct` and `impl` blocks
|
||||
to allow:
|
||||
|
||||
```rust
|
||||
#[wasm_bindgen]
|
||||
pub struct Foo {
|
||||
internal: i32,
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl Foo {
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new(val: i32) -> Foo {
|
||||
Foo { internal: val }
|
||||
}
|
||||
|
||||
pub fn get(&self) -> i32 {
|
||||
self.internal
|
||||
}
|
||||
|
||||
pub fn set(&mut self, val: i32) {
|
||||
self.internal = val;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This is a typical Rust `struct` definition for a type with a constructor and a
|
||||
few methods. Annotating the struct with `#[wasm_bindgen]` means that we'll
|
||||
generate necessary trait impls to convert this type to/from the JS boundary. The
|
||||
annotated `impl` block here means that the functions inside will also be made
|
||||
available to JS through generated shims. If we take a look at the generated JS
|
||||
code for this we'll see:
|
||||
|
||||
```js
|
||||
import * as wasm from './js_hello_world_bg';
|
||||
|
||||
export class Foo {
|
||||
static __construct(ptr) {
|
||||
return new Foo(ptr);
|
||||
}
|
||||
|
||||
constructor(ptr) {
|
||||
this.ptr = ptr;
|
||||
}
|
||||
|
||||
free() {
|
||||
const ptr = this.ptr;
|
||||
this.ptr = 0;
|
||||
wasm.__wbg_foo_free(ptr);
|
||||
}
|
||||
|
||||
static new(arg0) {
|
||||
const ret = wasm.foo_new(arg0);
|
||||
return Foo.__construct(ret)
|
||||
}
|
||||
|
||||
get() {
|
||||
const ret = wasm.foo_get(this.ptr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
set(arg0) {
|
||||
const ret = wasm.foo_set(this.ptr, arg0);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
That's actually not much! We can see here though how we've translated from Rust
|
||||
to JS:
|
||||
|
||||
* Associated functions in Rust (those without `self`) turn into `static`
|
||||
functions in JS.
|
||||
* Methods in Rust turn into methods in wasm.
|
||||
* Manual memory management is exposed in JS as well. The `free` function is
|
||||
required to be invoked to deallocate resources on the Rust side of things.
|
||||
|
||||
To be able to use `new Foo()`, you'd need to annotate `new` as `#[wasm_bindgen(constructor)]`.
|
||||
|
||||
One important aspect to note here, though, is that once `free` is called the JS
|
||||
object is "neutered" in that its internal pointer is nulled out. This means that
|
||||
future usage of this object should trigger a panic in Rust.
|
||||
|
||||
The real trickery with these bindings ends up happening in Rust, however, so
|
||||
let's take a look at that.
|
||||
|
||||
```rust
|
||||
// original input to `#[wasm_bindgen]` omitted ...
|
||||
|
||||
#[export_name = "foo_new"]
|
||||
pub extern "C" fn __wasm_bindgen_generated_Foo_new(arg0: i32) -> u32
|
||||
let ret = Foo::new(arg0);
|
||||
Box::into_raw(Box::new(WasmRefCell::new(ret))) as u32
|
||||
}
|
||||
|
||||
#[export_name = "foo_get"]
|
||||
pub extern "C" fn __wasm_bindgen_generated_Foo_get(me: u32) -> i32 {
|
||||
let me = me as *mut WasmRefCell<Foo>;
|
||||
wasm_bindgen::__rt::assert_not_null(me);
|
||||
let me = unsafe { &*me };
|
||||
return me.borrow().get();
|
||||
}
|
||||
|
||||
#[export_name = "foo_set"]
|
||||
pub extern "C" fn __wasm_bindgen_generated_Foo_set(me: u32, arg1: i32) {
|
||||
let me = me as *mut WasmRefCell<Foo>;
|
||||
wasm_bindgen::__rt::assert_not_null(me);
|
||||
let me = unsafe { &*me };
|
||||
me.borrow_mut().set(arg1);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn __wbindgen_foo_free(me: u32) {
|
||||
let me = me as *mut WasmRefCell<Foo>;
|
||||
wasm_bindgen::__rt::assert_not_null(me);
|
||||
(*me).borrow_mut(); // ensure no active borrows
|
||||
drop(Box::from_raw(me));
|
||||
}
|
||||
```
|
||||
|
||||
As with before this is cleaned up from the actual output but it's the same idea
|
||||
as to what's going on! Here we can see a shim for each function as well as a
|
||||
shim for deallocating an instance of `Foo`. Recall that the only valid wasm
|
||||
types today are numbers, so we're required to shoehorn all of `Foo` into a
|
||||
`u32`, which is currently done via `Box` (like `std::unique_ptr` in C++).
|
||||
Note, though, that there's an extra layer here, `WasmRefCell`. This type is the
|
||||
same as [`RefCell`] and can be mostly glossed over.
|
||||
|
||||
The purpose for this type, if you're interested though, is to uphold Rust's
|
||||
guarantees about aliasing in a world where aliasing is rampant (JS).
|
||||
Specifically the `&Foo` type means that there can be as much aliasing as you'd
|
||||
like, but crucially `&mut Foo` means that it is the sole pointer to the data
|
||||
(no other `&Foo` to the same instance exists). The [`RefCell`] type in libstd
|
||||
is a way of dynamically enforcing this at runtime (as opposed to compile time
|
||||
where it usually happens). Baking in `WasmRefCell` is the same idea here,
|
||||
adding runtime checks for aliasing which are typically happening at compile
|
||||
time. This is currently a Rust-specific feature which isn't actually in the
|
||||
`wasm-bindgen` tool itself, it's just in the Rust-generated code (aka the
|
||||
`#[wasm_bindgen]` attribute).
|
||||
|
||||
[`RefCell`]: https://doc.rust-lang.org/std/cell/struct.RefCell.html
|
||||
120
zeroidc/vendor/wasm-bindgen/guide/src/contributing/design/exporting-rust.md
vendored
Normal file
120
zeroidc/vendor/wasm-bindgen/guide/src/contributing/design/exporting-rust.md
vendored
Normal file
@@ -0,0 +1,120 @@
|
||||
# Exporting a function to JS
|
||||
|
||||
Alright now that we've got a good grasp on JS objects and how they're working,
|
||||
let's take a look at another feature of `wasm-bindgen`: exporting functionality
|
||||
with types that are richer than just numbers.
|
||||
|
||||
The basic idea around exporting functionality with more flavorful types is that
|
||||
the wasm exports won't actually be called directly. Instead the generated
|
||||
`foo.js` module will have shims for all exported functions in the wasm module.
|
||||
|
||||
The most interesting conversion here happens with strings so let's take a look
|
||||
at that.
|
||||
|
||||
```rust
|
||||
#[wasm_bindgen]
|
||||
pub fn greet(a: &str) -> String {
|
||||
format!("Hello, {}!", a)
|
||||
}
|
||||
```
|
||||
|
||||
Here we'd like to define an ES module that looks like
|
||||
|
||||
```ts
|
||||
// foo.d.ts
|
||||
export function greet(a: string): string;
|
||||
```
|
||||
|
||||
To see what's going on, let's take a look at the generated shim
|
||||
|
||||
```js
|
||||
import * as wasm from './foo_bg';
|
||||
|
||||
function passStringToWasm(arg) {
|
||||
const buf = new TextEncoder('utf-8').encode(arg);
|
||||
const len = buf.length;
|
||||
const ptr = wasm.__wbindgen_malloc(len);
|
||||
let array = new Uint8Array(wasm.memory.buffer);
|
||||
array.set(buf, ptr);
|
||||
return [ptr, len];
|
||||
}
|
||||
|
||||
function getStringFromWasm(ptr, len) {
|
||||
const mem = new Uint8Array(wasm.memory.buffer);
|
||||
const slice = mem.slice(ptr, ptr + len);
|
||||
const ret = new TextDecoder('utf-8').decode(slice);
|
||||
return ret;
|
||||
}
|
||||
|
||||
export function greet(arg0) {
|
||||
const [ptr0, len0] = passStringToWasm(arg0);
|
||||
try {
|
||||
const ret = wasm.greet(ptr0, len0);
|
||||
const ptr = wasm.__wbindgen_boxed_str_ptr(ret);
|
||||
const len = wasm.__wbindgen_boxed_str_len(ret);
|
||||
const realRet = getStringFromWasm(ptr, len);
|
||||
wasm.__wbindgen_boxed_str_free(ret);
|
||||
return realRet;
|
||||
} finally {
|
||||
wasm.__wbindgen_free(ptr0, len0);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Phew, that's quite a lot! We can sort of see though if we look closely what's
|
||||
happening:
|
||||
|
||||
* Strings are passed to wasm via two arguments, a pointer and a length. Right
|
||||
now we have to copy the string onto the wasm heap which means we'll be using
|
||||
`TextEncoder` to actually do the encoding. Once this is done we use an
|
||||
internal function in `wasm-bindgen` to allocate space for the string to go,
|
||||
and then we'll pass that ptr/length to wasm later on.
|
||||
|
||||
* Returning strings from wasm is a little tricky as we need to return a ptr/len
|
||||
pair, but wasm currently only supports one return value (multiple return values
|
||||
[is being standardized](https://github.com/WebAssembly/design/issues/1146)).
|
||||
To work around this in the meantime, we're actually returning a pointer to a
|
||||
ptr/len pair, and then using functions to access the various fields.
|
||||
|
||||
* Some cleanup ends up happening in wasm. The `__wbindgen_boxed_str_free`
|
||||
function is used to free the return value of `greet` after it's been decoded
|
||||
onto the JS heap (using `TextDecoder`). The `__wbindgen_free` is then used to
|
||||
free the space we allocated to pass the string argument once the function call
|
||||
is done.
|
||||
|
||||
Next let's take a look at the Rust side of things as well. Here we'll be looking
|
||||
at a mostly abbreviated and/or "simplified" in the sense of this is what it
|
||||
compiles down to:
|
||||
|
||||
```rust
|
||||
pub extern "C" fn greet(a: &str) -> String {
|
||||
format!("Hello, {}!", a)
|
||||
}
|
||||
|
||||
#[export_name = "greet"]
|
||||
pub extern "C" fn __wasm_bindgen_generated_greet(
|
||||
arg0_ptr: *const u8,
|
||||
arg0_len: usize,
|
||||
) -> *mut String {
|
||||
let arg0 = unsafe {
|
||||
let slice = ::std::slice::from_raw_parts(arg0_ptr, arg0_len);
|
||||
::std::str::from_utf8_unchecked(slice)
|
||||
};
|
||||
let _ret = greet(arg0);
|
||||
Box::into_raw(Box::new(_ret))
|
||||
}
|
||||
```
|
||||
|
||||
Here we can see again that our `greet` function is unmodified and has a wrapper
|
||||
to call it. This wrapper will take the ptr/len argument and convert it to a
|
||||
string slice, while the return value is boxed up into just a pointer and is
|
||||
then returned up to was for reading via the `__wbindgen_boxed_str_*` functions.
|
||||
|
||||
So in general exporting a function involves a shim both in JS and in Rust with
|
||||
each side translating to or from wasm arguments to the native types of each
|
||||
language. The `wasm-bindgen` tool manages hooking up all these shims while the
|
||||
`#[wasm_bindgen]` macro takes care of the Rust shim as well.
|
||||
|
||||
Most arguments have a relatively clear way to convert them, bit if you've got
|
||||
any questions just let me know!
|
||||
|
||||
206
zeroidc/vendor/wasm-bindgen/guide/src/contributing/design/importing-js-struct.md
vendored
Normal file
206
zeroidc/vendor/wasm-bindgen/guide/src/contributing/design/importing-js-struct.md
vendored
Normal file
@@ -0,0 +1,206 @@
|
||||
# Importing a class from JS
|
||||
|
||||
Just like with functions after we've started exporting we'll also want to
|
||||
import! Now that we've exported a `class` to JS we'll want to also be able to
|
||||
import classes in Rust as well to invoke methods and such. Since JS classes are
|
||||
in general just JS objects the bindings here will look pretty similar to the JS
|
||||
object bindings describe above.
|
||||
|
||||
As usual though, let's dive into an example!
|
||||
|
||||
```rust
|
||||
#[wasm_bindgen(module = "./bar")]
|
||||
extern "C" {
|
||||
type Bar;
|
||||
|
||||
#[wasm_bindgen(constructor)]
|
||||
fn new(arg: i32) -> Bar;
|
||||
|
||||
#[wasm_bindgen(js_namespace = Bar)]
|
||||
fn another_function() -> i32;
|
||||
|
||||
#[wasm_bindgen(method)]
|
||||
fn get(this: &Bar) -> i32;
|
||||
|
||||
#[wasm_bindgen(method)]
|
||||
fn set(this: &Bar, val: i32);
|
||||
|
||||
#[wasm_bindgen(method, getter)]
|
||||
fn property(this: &Bar) -> i32;
|
||||
|
||||
#[wasm_bindgen(method, setter)]
|
||||
fn set_property(this: &Bar, val: i32);
|
||||
}
|
||||
|
||||
fn run() {
|
||||
let bar = Bar::new(Bar::another_function());
|
||||
let x = bar.get();
|
||||
bar.set(x + 3);
|
||||
|
||||
bar.set_property(bar.property() + 6);
|
||||
}
|
||||
```
|
||||
|
||||
Unlike our previous imports, this one's a bit more chatty! Remember that one of
|
||||
the goals of `wasm-bindgen` is to use native Rust syntax wherever possible, so
|
||||
this is mostly intended to use the `#[wasm_bindgen]` attribute to interpret
|
||||
what's written down in Rust. Now there's a few attribute annotations here, so
|
||||
let's go through one-by-one:
|
||||
|
||||
* `#[wasm_bindgen(module = "./bar")]` - seen before with imports this is declare
|
||||
where all the subsequent functionality is imported from. For example the `Bar`
|
||||
type is going to be imported from the `./bar` module.
|
||||
* `type Bar` - this is a declaration of JS class as a new type in Rust. This
|
||||
means that a new type `Bar` is generated which is "opaque" but is represented
|
||||
as internally containing a `JsValue`. We'll see more on this later.
|
||||
* `#[wasm_bindgen(constructor)]` - this indicates that the binding's name isn't
|
||||
actually used in JS but rather translates to `new Bar()`. The return value of
|
||||
this function must be a bare type, like `Bar`.
|
||||
* `#[wasm_bindgen(js_namespace = Bar)]` - this attribute indicates that the
|
||||
function declaration is namespaced through the `Bar` class in JS.
|
||||
* `#[wasm_bindgen(static_method_of = SomeJsClass)]` - this attribute is similar
|
||||
to `js_namespace`, but instead of producing a free function, produces a static
|
||||
method of `SomeJsClass`.
|
||||
* `#[wasm_bindgen(method)]` - and finally, this attribute indicates that a
|
||||
method call is going to happen. The first argument must be a JS struct, like
|
||||
`Bar`, and the call in JS looks like `Bar.prototype.set.call(...)`.
|
||||
|
||||
With all that in mind, let's take a look at the JS generated.
|
||||
|
||||
```js
|
||||
import * as wasm from './foo_bg';
|
||||
|
||||
import { Bar } from './bar';
|
||||
|
||||
// other support functions omitted...
|
||||
|
||||
export function __wbg_s_Bar_new() {
|
||||
return addHeapObject(new Bar());
|
||||
}
|
||||
|
||||
const another_function_shim = Bar.another_function;
|
||||
export function __wbg_s_Bar_another_function() {
|
||||
return another_function_shim();
|
||||
}
|
||||
|
||||
const get_shim = Bar.prototype.get;
|
||||
export function __wbg_s_Bar_get(ptr) {
|
||||
return shim.call(getObject(ptr));
|
||||
}
|
||||
|
||||
const set_shim = Bar.prototype.set;
|
||||
export function __wbg_s_Bar_set(ptr, arg0) {
|
||||
set_shim.call(getObject(ptr), arg0)
|
||||
}
|
||||
|
||||
const property_shim = Object.getOwnPropertyDescriptor(Bar.prototype, 'property').get;
|
||||
export function __wbg_s_Bar_property(ptr) {
|
||||
return property_shim.call(getObject(ptr));
|
||||
}
|
||||
|
||||
const set_property_shim = Object.getOwnPropertyDescriptor(Bar.prototype, 'property').set;
|
||||
export function __wbg_s_Bar_set_property(ptr, arg0) {
|
||||
set_property_shim.call(getObject(ptr), arg0)
|
||||
}
|
||||
```
|
||||
|
||||
Like when importing functions from JS we can see a bunch of shims are generated
|
||||
for all the relevant functions. The `new` static function has the
|
||||
`#[wasm_bindgen(constructor)]` attribute which means that instead of any
|
||||
particular method it should actually invoke the `new` constructor instead (as
|
||||
we see here). The static function `another_function`, however, is dispatched as
|
||||
`Bar.another_function`.
|
||||
|
||||
The `get` and `set` functions are methods so they go through `Bar.prototype`,
|
||||
and otherwise their first argument is implicitly the JS object itself which is
|
||||
loaded through `getObject` like we saw earlier.
|
||||
|
||||
Some real meat starts to show up though on the Rust side of things, so let's
|
||||
take a look:
|
||||
|
||||
```rust
|
||||
pub struct Bar {
|
||||
obj: JsValue,
|
||||
}
|
||||
|
||||
impl Bar {
|
||||
fn new() -> Bar {
|
||||
extern "C" {
|
||||
fn __wbg_s_Bar_new() -> u32;
|
||||
}
|
||||
unsafe {
|
||||
let ret = __wbg_s_Bar_new();
|
||||
Bar { obj: JsValue::__from_idx(ret) }
|
||||
}
|
||||
}
|
||||
|
||||
fn another_function() -> i32 {
|
||||
extern "C" {
|
||||
fn __wbg_s_Bar_another_function() -> i32;
|
||||
}
|
||||
unsafe {
|
||||
__wbg_s_Bar_another_function()
|
||||
}
|
||||
}
|
||||
|
||||
fn get(&self) -> i32 {
|
||||
extern "C" {
|
||||
fn __wbg_s_Bar_get(ptr: u32) -> i32;
|
||||
}
|
||||
unsafe {
|
||||
let ptr = self.obj.__get_idx();
|
||||
let ret = __wbg_s_Bar_get(ptr);
|
||||
return ret
|
||||
}
|
||||
}
|
||||
|
||||
fn set(&self, val: i32) {
|
||||
extern "C" {
|
||||
fn __wbg_s_Bar_set(ptr: u32, val: i32);
|
||||
}
|
||||
unsafe {
|
||||
let ptr = self.obj.__get_idx();
|
||||
__wbg_s_Bar_set(ptr, val);
|
||||
}
|
||||
}
|
||||
|
||||
fn property(&self) -> i32 {
|
||||
extern "C" {
|
||||
fn __wbg_s_Bar_property(ptr: u32) -> i32;
|
||||
}
|
||||
unsafe {
|
||||
let ptr = self.obj.__get_idx();
|
||||
let ret = __wbg_s_Bar_property(ptr);
|
||||
return ret
|
||||
}
|
||||
}
|
||||
|
||||
fn set_property(&self, val: i32) {
|
||||
extern "C" {
|
||||
fn __wbg_s_Bar_set_property(ptr: u32, val: i32);
|
||||
}
|
||||
unsafe {
|
||||
let ptr = self.obj.__get_idx();
|
||||
__wbg_s_Bar_set_property(ptr, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl WasmBoundary for Bar {
|
||||
// ...
|
||||
}
|
||||
|
||||
impl ToRefWasmBoundary for Bar {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
In Rust we're seeing that a new type, `Bar`, is generated for this import of a
|
||||
class. The type `Bar` internally contains a `JsValue` as an instance of `Bar`
|
||||
is meant to represent a JS object stored in our module's stack/slab. This then
|
||||
works mostly the same way that we saw JS objects work in the beginning.
|
||||
|
||||
When calling `Bar::new` we'll get an index back which is wrapped up in `Bar`
|
||||
(which is itself just a `u32` in memory when stripped down). Each function then
|
||||
passes the index as the first argument and otherwise forwards everything along
|
||||
in Rust.
|
||||
75
zeroidc/vendor/wasm-bindgen/guide/src/contributing/design/importing-js.md
vendored
Normal file
75
zeroidc/vendor/wasm-bindgen/guide/src/contributing/design/importing-js.md
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
# Importing a function from JS
|
||||
|
||||
Now that we've exported some rich functionality to JS it's also time to import
|
||||
some! The goal here is to basically implement JS `import` statements in Rust,
|
||||
with fancy types and all.
|
||||
|
||||
First up, let's say we invert the function above and instead want to generate
|
||||
greetings in JS but call it from Rust. We might have, for example:
|
||||
|
||||
```rust
|
||||
#[wasm_bindgen(module = "./greet")]
|
||||
extern "C" {
|
||||
fn greet(a: &str) -> String;
|
||||
}
|
||||
|
||||
fn other_code() {
|
||||
let greeting = greet("foo");
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
The basic idea of imports is the same as exports in that we'll have shims in
|
||||
both JS and Rust doing the necessary translation. Let's first see the JS shim in
|
||||
action:
|
||||
|
||||
```js
|
||||
import * as wasm from './foo_bg';
|
||||
|
||||
import { greet } from './greet';
|
||||
|
||||
// ...
|
||||
|
||||
export function __wbg_f_greet(ptr0, len0, wasmretptr) {
|
||||
const [retptr, retlen] = passStringToWasm(greet(getStringFromWasm(ptr0, len0)));
|
||||
(new Uint32Array(wasm.memory.buffer))[wasmretptr / 4] = retlen;
|
||||
return retptr;
|
||||
}
|
||||
```
|
||||
|
||||
The `getStringFromWasm` and `passStringToWasm` are the same as we saw before,
|
||||
and like with `__wbindgen_object_drop_ref` far above we've got this weird export
|
||||
from our module now! The `__wbg_f_greet` function is what's generated by
|
||||
`wasm-bindgen` to actually get imported in the `foo.wasm` module.
|
||||
|
||||
The generated `foo.js` we see imports from the `./greet` module with the `greet`
|
||||
name (was the function import in Rust said) and then the `__wbg_f_greet`
|
||||
function is shimming that import.
|
||||
|
||||
There's some tricky ABI business going on here so let's take a look at the
|
||||
generated Rust as well. Like before this is simplified from what's actually
|
||||
generated.
|
||||
|
||||
```rust
|
||||
extern "C" fn greet(a: &str) -> String {
|
||||
extern "C" {
|
||||
fn __wbg_f_greet(a_ptr: *const u8, a_len: usize, ret_len: *mut usize) -> *mut u8;
|
||||
}
|
||||
unsafe {
|
||||
let a_ptr = a.as_ptr();
|
||||
let a_len = a.len();
|
||||
let mut __ret_strlen = 0;
|
||||
let mut __ret_strlen_ptr = &mut __ret_strlen as *mut usize;
|
||||
let _ret = __wbg_f_greet(a_ptr, a_len, __ret_strlen_ptr);
|
||||
String::from_utf8_unchecked(
|
||||
Vec::from_raw_parts(_ret, __ret_strlen, __ret_strlen)
|
||||
)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Here we can see that the `greet` function was generated but it's largely just a
|
||||
shim around the `__wbg_f_greet` function that we're calling. The ptr/len pair
|
||||
for the argument is passed as two arguments and for the return value we're
|
||||
receiving one value (the length) indirectly while directly receiving the
|
||||
returned pointer.
|
||||
67
zeroidc/vendor/wasm-bindgen/guide/src/contributing/design/index.md
vendored
Normal file
67
zeroidc/vendor/wasm-bindgen/guide/src/contributing/design/index.md
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
# Design of `wasm-bindgen`
|
||||
|
||||
This section is intended to be a deep-dive into how `wasm-bindgen` internally
|
||||
works today, specifically for Rust. If you're reading this far in the future it
|
||||
may no longer be up to date, but feel free to open an issue and we can try to
|
||||
answer questions and/or update this!
|
||||
|
||||
## Foundation: ES Modules
|
||||
|
||||
The first thing to know about `wasm-bindgen` is that it's fundamentally built on
|
||||
the idea of ES Modules. In other words this tool takes an opinionated stance
|
||||
that wasm files *should be viewed as ES modules*. This means that you can
|
||||
`import` from a wasm file, use its `export`-ed functionality, etc, from normal
|
||||
JS files.
|
||||
|
||||
Now unfortunately at the time of this writing the interface of wasm interop
|
||||
isn't very rich. Wasm modules can only call functions or export functions that
|
||||
deal exclusively with `i32`, `i64`, `f32`, and `f64`. Bummer!
|
||||
|
||||
That's where this project comes in. The goal of `wasm-bindgen` is to enhance the
|
||||
"ABI" of wasm modules with richer types like classes, JS objects, Rust structs,
|
||||
strings, etc. Keep in mind, though, that everything is based on ES Modules! This
|
||||
means that the compiler is actually producing a "broken" wasm file of sorts. The
|
||||
wasm file emitted by rustc, for example, does not have the interface we would
|
||||
like to have. Instead it requires the `wasm-bindgen` tool to postprocess the
|
||||
file, generating a `foo.js` and `foo_bg.wasm` file. The `foo.js` file is the
|
||||
desired interface expressed in JS (classes, types, strings, etc) and the
|
||||
`foo_bg.wasm` module is simply used as an implementation detail (it was
|
||||
lightly modified from the original `foo.wasm` file).
|
||||
|
||||
As more features are stabilized in WebAssembly over time (like host bindings)
|
||||
the JS file is expected to get smaller and smaller. It's unlikely to ever
|
||||
disappear, but `wasm-bindgen` is designed to follow the WebAssembly spec and
|
||||
proposals closely to optimize JS/Rust as much as possible.
|
||||
|
||||
## Foundation #2: Unintrusive in Rust
|
||||
|
||||
On the more Rust-y side of things the `wasm-bindgen` crate is designed to
|
||||
ideally have as minimal impact on a Rust crate as possible. Ideally a few
|
||||
`#[wasm_bindgen]` attributes are annotated in key locations and otherwise you're
|
||||
off to the races. The attribute strives to both not invent new syntax and work
|
||||
with existing idioms today.
|
||||
|
||||
For example a library might exposed a function in normal Rust that looks like:
|
||||
|
||||
```rust
|
||||
pub fn greet(name: &str) -> String {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
And with `#[wasm_bindgen]` all you need to do in exporting it to JS is:
|
||||
|
||||
```rust
|
||||
#[wasm_bindgen]
|
||||
pub fn greet(name: &str) -> String {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
Additionally the design here with minimal intervention in Rust should allow us
|
||||
to easily take advantage of the upcoming [host bindings][host] proposal. Ideally
|
||||
you'd simply upgrade `wasm-bindgen`-the-crate as well as your toolchain and
|
||||
you're immediately getting raw access to host bindings! (this is still a bit of
|
||||
a ways off though...)
|
||||
|
||||
[host]: https://github.com/WebAssembly/host-bindings
|
||||
237
zeroidc/vendor/wasm-bindgen/guide/src/contributing/design/js-objects-in-rust.md
vendored
Normal file
237
zeroidc/vendor/wasm-bindgen/guide/src/contributing/design/js-objects-in-rust.md
vendored
Normal file
@@ -0,0 +1,237 @@
|
||||
# Polyfill for "JS objects in wasm"
|
||||
|
||||
One of the main goals of `wasm-bindgen` is to allow working with and passing
|
||||
around JS objects in wasm, but that's not allowed today! While indeed true,
|
||||
that's where the polyfill comes in.
|
||||
|
||||
The question here is how we shoehorn JS objects into a `u32` for wasm to use.
|
||||
The current strategy for this approach is to maintain a module-local variable
|
||||
in the generated `foo.js` file: a `heap`.
|
||||
|
||||
### Temporary JS objects on the "stack"
|
||||
|
||||
The first slots in the `heap` in `foo.js` are considered a stack. This stack,
|
||||
like typical program execution stacks, grows down. JS objects are pushed on the
|
||||
bottom of the stack, and their index in the stack is the identifier that's passed
|
||||
to wasm. A stack pointer is maintained to figure out where the next item is
|
||||
pushed.
|
||||
|
||||
JS objects are then only removed from the bottom of the stack as well. Removal
|
||||
is simply storing null then incrementing a counter. Because of the "stack-y"
|
||||
nature of this scheme it only works for when wasm doesn't hold onto a JS object
|
||||
(aka it only gets a "reference" in Rust parlance).
|
||||
|
||||
Let's take a look at an example.
|
||||
|
||||
```rust
|
||||
// foo.rs
|
||||
#[wasm_bindgen]
|
||||
pub fn foo(a: &JsValue) {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
Here we're using the special `JsValue` type from the `wasm-bindgen` library
|
||||
itself. Our exported function, `foo`, takes a *reference* to an object. This
|
||||
notably means that it can't persist the object past the lifetime of this
|
||||
function call.
|
||||
|
||||
Now what we actually want to generate is a JS module that looks like (in
|
||||
TypeScript parlance)
|
||||
|
||||
```ts
|
||||
// foo.d.ts
|
||||
export function foo(a: any);
|
||||
```
|
||||
|
||||
and what we actually generate looks something like:
|
||||
|
||||
```js
|
||||
// foo.js
|
||||
import * as wasm from './foo_bg';
|
||||
|
||||
const heap = new Array(32);
|
||||
heap.push(undefined, null, true, false);
|
||||
let stack_pointer = 32;
|
||||
|
||||
function addBorrowedObject(obj) {
|
||||
stack_pointer -= 1;
|
||||
heap[stack_pointer] = obj;
|
||||
return stack_pointer;
|
||||
}
|
||||
|
||||
export function foo(arg0) {
|
||||
const idx0 = addBorrowedObject(arg0);
|
||||
try {
|
||||
wasm.foo(idx0);
|
||||
} finally {
|
||||
heap[stack_pointer++] = undefined;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Here we can see a few notable points of action:
|
||||
|
||||
* The wasm file was renamed to `foo_bg.wasm`, and we can see how the JS module
|
||||
generated here is importing from the wasm file.
|
||||
* Next we can see our `heap` module variable which is to store all JS values
|
||||
reference-able from wasm.
|
||||
* Our exported function `foo`, takes an arbitrary argument, `arg0`, which is
|
||||
converted to an index with the `addBorrowedObject` object function. The index
|
||||
is then passed to wasm so wasm can operate with it.
|
||||
* Finally, we have a `finally` which frees the stack slot as it's no longer
|
||||
used, popping the value that was pushed at the start of the function.
|
||||
|
||||
It's also helpful to dig into the Rust side of things to see what's going on
|
||||
there! Let's take a look at the code that `#[wasm_bindgen]` generates in Rust:
|
||||
|
||||
```rust
|
||||
// what the user wrote
|
||||
pub fn foo(a: &JsValue) {
|
||||
// ...
|
||||
}
|
||||
|
||||
#[export_name = "foo"]
|
||||
pub extern "C" fn __wasm_bindgen_generated_foo(arg0: u32) {
|
||||
let arg0 = unsafe {
|
||||
ManuallyDrop::new(JsValue::__from_idx(arg0))
|
||||
};
|
||||
let arg0 = &*arg0;
|
||||
foo(arg0);
|
||||
}
|
||||
```
|
||||
|
||||
And as with the JS, the notable points here are:
|
||||
|
||||
* The original function, `foo`, is unmodified in the output
|
||||
* A generated function here (with a unique name) is the one that's actually
|
||||
exported from the wasm module
|
||||
* Our generated function takes an integer argument (our index) and then wraps it
|
||||
in a `JsValue`. There's some trickery here that's not worth going into just
|
||||
yet, but we'll see in a bit what's happening under the hood.
|
||||
|
||||
### Long-lived JS objects
|
||||
|
||||
The above strategy is useful when JS objects are only temporarily used in Rust,
|
||||
for example only during one function call. Sometimes, though, objects may have a
|
||||
dynamic lifetime or otherwise need to be stored on Rust's heap. To cope with
|
||||
this there's a second half of management of JS objects, naturally corresponding
|
||||
to the other side of the JS `heap` array.
|
||||
|
||||
JS Objects passed to wasm that are not references are assumed to have a dynamic
|
||||
lifetime inside of the wasm module. As a result the strict push/pop of the stack
|
||||
won't work and we need more permanent storage for the JS objects. To cope with
|
||||
this we build our own "slab allocator" of sorts.
|
||||
|
||||
A picture (or code) is worth a thousand words so let's show what happens with an
|
||||
example.
|
||||
|
||||
```rust
|
||||
// foo.rs
|
||||
#[wasm_bindgen]
|
||||
pub fn foo(a: JsValue) {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
Note that the `&` is missing in front of the `JsValue` we had before, and in
|
||||
Rust parlance this means it's taking ownership of the JS value. The exported ES
|
||||
module interface is the same as before, but the ownership mechanics are slightly
|
||||
different. Let's see the generated JS's slab in action:
|
||||
|
||||
```js
|
||||
import * as wasm from './foo_bg'; // imports from wasm file
|
||||
|
||||
const heap = new Array(32);
|
||||
heap.push(undefined, null, true, false);
|
||||
let heap_next = 36;
|
||||
|
||||
function addHeapObject(obj) {
|
||||
if (heap_next === heap.length)
|
||||
heap.push(heap.length + 1);
|
||||
const idx = heap_next;
|
||||
heap_next = heap[idx];
|
||||
heap[idx] = obj;
|
||||
return idx;
|
||||
}
|
||||
|
||||
export function foo(arg0) {
|
||||
const idx0 = addHeapObject(arg0);
|
||||
wasm.foo(idx0);
|
||||
}
|
||||
|
||||
export function __wbindgen_object_drop_ref(idx) {
|
||||
heap[idx ] = heap_next;
|
||||
heap_next = idx;
|
||||
}
|
||||
```
|
||||
|
||||
Unlike before we're now calling `addHeapObject` on the argument to `foo` rather
|
||||
than `addBorrowedObject`. This function will use `heap` and `heap_next` as a
|
||||
slab allocator to acquire a slot to store the object, placing a structure there
|
||||
once it's found. Note that this is going on the right-half of the array, unlike
|
||||
the stack which resides on the left half. This discipline mirrors the stack/heap
|
||||
in normal programs, roughly.
|
||||
|
||||
Another curious aspect of this generated module is the
|
||||
`__wbindgen_object_drop_ref` function. This is one that's actually imported to
|
||||
wasm rather than used in this module! This function is used to signal the end of
|
||||
the lifetime of a `JsValue` in Rust, or in other words when it goes out of
|
||||
scope. Otherwise though this function is largely just a general "slab free"
|
||||
implementation.
|
||||
|
||||
And finally, let's take a look at the Rust generated again too:
|
||||
|
||||
```rust
|
||||
// what the user wrote
|
||||
pub fn foo(a: JsValue) {
|
||||
// ...
|
||||
}
|
||||
|
||||
#[export_name = "foo"]
|
||||
pub extern "C" fn __wasm_bindgen_generated_foo(arg0: u32) {
|
||||
let arg0 = unsafe {
|
||||
JsValue::__from_idx(arg0)
|
||||
};
|
||||
foo(arg0);
|
||||
}
|
||||
```
|
||||
|
||||
Ah that looks much more familiar! Not much interesting is happening here, so
|
||||
let's move on to...
|
||||
|
||||
### Anatomy of `JsValue`
|
||||
|
||||
Currently the `JsValue` struct is actually quite simple in Rust, it's:
|
||||
|
||||
```rust
|
||||
pub struct JsValue {
|
||||
idx: u32,
|
||||
}
|
||||
|
||||
// "private" constructors
|
||||
|
||||
impl Drop for JsValue {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
__wbindgen_object_drop_ref(self.idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Or in other words it's a newtype wrapper around a `u32`, the index that we're
|
||||
passed from wasm. The destructor here is where the `__wbindgen_object_drop_ref`
|
||||
function is called to relinquish our reference count of the JS object, freeing
|
||||
up our slot in the `slab` that we saw above.
|
||||
|
||||
If you'll recall as well, when we took `&JsValue` above we generated a wrapper
|
||||
of `ManuallyDrop` around the local binding, and that's because we wanted to
|
||||
avoid invoking this destructor when the object comes from the stack.
|
||||
|
||||
### Working with `heap` in reality
|
||||
|
||||
The above explanations are pretty close to what happens today, but in reality
|
||||
there's a few differences especially around handling constant values like
|
||||
`undefined`, `null`, etc. Be sure to check out the actual generated JS and the
|
||||
generation code for the full details!
|
||||
117
zeroidc/vendor/wasm-bindgen/guide/src/contributing/design/rust-type-conversions.md
vendored
Normal file
117
zeroidc/vendor/wasm-bindgen/guide/src/contributing/design/rust-type-conversions.md
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
# Rust Type conversions
|
||||
|
||||
Previously we've been seeing mostly abridged versions of type conversions when
|
||||
values enter Rust. Here we'll go into some more depth about how this is
|
||||
implemented. There are two categories of traits for converting values, traits
|
||||
for converting values from Rust to JS and traits for the other way around.
|
||||
|
||||
## From Rust to JS
|
||||
|
||||
First up let's take a look at going from Rust to JS:
|
||||
|
||||
```rust
|
||||
pub trait IntoWasmAbi: WasmDescribe {
|
||||
type Abi: WasmAbi;
|
||||
fn into_abi(self, extra: &mut Stack) -> Self::Abi;
|
||||
}
|
||||
```
|
||||
|
||||
And that's it! This is actually the only trait needed currently for translating
|
||||
a Rust value to a JS one. There's a few points here:
|
||||
|
||||
* We'll get to `WasmDescribe` later in this section
|
||||
* The associated type `Abi` is what will actually be generated as an argument to
|
||||
the wasm export. The bound `WasmAbi` is only implemented for types like `u32`
|
||||
and `f64`, those which can be placed on the boundary and transmitted
|
||||
losslessly.
|
||||
* And finally we have the `into_abi` function, returning the `Abi` associated
|
||||
type which will be actually passed to JS. There's also this `Stack` parameter,
|
||||
however. Not all Rust values can be communicated in 32 bits to the `Stack`
|
||||
parameter allows transmitting more data, explained in a moment.
|
||||
|
||||
This trait is implemented for all types that can be converted to JS and is
|
||||
unconditionally used during codegen. For example you'll often see `IntoWasmAbi
|
||||
for Foo` but also `IntoWasmAbi for &'a Foo`.
|
||||
|
||||
The `IntoWasmAbi` trait is used in two locations. First it's used to convert
|
||||
return values of Rust exported functions to JS. Second it's used to convert the
|
||||
Rust arguments of JS functions imported to Rust.
|
||||
|
||||
## From JS to Rust
|
||||
|
||||
Unfortunately the opposite direction from above, going from JS to Rust, is a bit
|
||||
more complicated. Here we've got three traits:
|
||||
|
||||
```rust
|
||||
pub trait FromWasmAbi: WasmDescribe {
|
||||
type Abi: WasmAbi;
|
||||
unsafe fn from_abi(js: Self::Abi, extra: &mut Stack) -> Self;
|
||||
}
|
||||
|
||||
pub trait RefFromWasmAbi: WasmDescribe {
|
||||
type Abi: WasmAbi;
|
||||
type Anchor: Deref<Target=Self>;
|
||||
unsafe fn ref_from_abi(js: Self::Abi, extra: &mut Stack) -> Self::Anchor;
|
||||
}
|
||||
|
||||
pub trait RefMutFromWasmAbi: WasmDescribe {
|
||||
type Abi: WasmAbi;
|
||||
type Anchor: DerefMut<Target=Self>;
|
||||
unsafe fn ref_mut_from_abi(js: Self::Abi, extra: &mut Stack) -> Self::Anchor;
|
||||
}
|
||||
```
|
||||
|
||||
The `FromWasmAbi` is relatively straightforward, basically the opposite of
|
||||
`IntoWasmAbi`. It takes the ABI argument (typically the same as
|
||||
`IntoWasmAbi::Abi`) and then the auxiliary stack to produce an instance of
|
||||
`Self`. This trait is implemented primarily for types that *don't* have internal
|
||||
lifetimes or are references.
|
||||
|
||||
The latter two traits here are mostly the same, and are intended for generating
|
||||
references (both shared and mutable references). They look almost the same as
|
||||
`FromWasmAbi` except that they return an `Anchor` type which implements a
|
||||
`Deref` trait rather than `Self`.
|
||||
|
||||
The `Ref*` traits allow having arguments in functions that are references rather
|
||||
than bare types, for example `&str`, `&JsValue`, or `&[u8]`. The `Anchor` here
|
||||
is required to ensure that the lifetimes don't persist beyond one function call
|
||||
and remain anonymous.
|
||||
|
||||
The `From*` family of traits are used for converting the Rust arguments in Rust
|
||||
exported functions to JS. They are also used for the return value in JS
|
||||
functions imported into Rust.
|
||||
|
||||
## Global stack
|
||||
|
||||
Mentioned above not all Rust types will fit within 32 bits. While we can
|
||||
communicate an `f64` we don't necessarily have the ability to use all the bits.
|
||||
Types like `&str` need to communicate two items, a pointer and a length (64
|
||||
bits). Other types like `&Closure<dyn Fn()>` have even more information to
|
||||
transmit.
|
||||
|
||||
As a result we need a method of communicating more data through the signatures
|
||||
of functions. While we could add more arguments this is somewhat difficult to do
|
||||
in the world of closures where code generation isn't quite as dynamic as a
|
||||
procedural macro. Consequently a "global stack" is used to transmit extra
|
||||
data for a function call.
|
||||
|
||||
The global stack is a fixed-sized static allocation in the wasm module. This
|
||||
stack is temporary scratch space for any one function call from either JS to
|
||||
Rust or Rust to JS. Both Rust and the JS shim generated have pointers to this
|
||||
global stack and will read/write information from it.
|
||||
|
||||
Using this scheme whenever we want to pass `&str` from JS to Rust we can pass
|
||||
the pointer as the actual ABI argument and the length is then placed in the next
|
||||
spot on the global stack.
|
||||
|
||||
The `Stack` argument to the conversion traits above looks like:
|
||||
|
||||
```rust
|
||||
pub trait Stack {
|
||||
fn push(&mut self, bits: u32);
|
||||
fn pop(&mut self) -> u32;
|
||||
}
|
||||
```
|
||||
|
||||
A trait is used here to facilitate testing but typically the calls don't end up
|
||||
being virtually dispatched at runtime.
|
||||
26
zeroidc/vendor/wasm-bindgen/guide/src/contributing/index.md
vendored
Normal file
26
zeroidc/vendor/wasm-bindgen/guide/src/contributing/index.md
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
# Contributing to `wasm-bindgen`
|
||||
|
||||
This section contains instructions on how to get this project up and running for
|
||||
development. You may want to browse the [unpublished guide documentation] for
|
||||
`wasm-bindgen` as well as it may have more up-to-date information.
|
||||
|
||||
[unpublished documentation]: https://rustwasm.github.io/wasm-bindgen/
|
||||
|
||||
## Prerequisites
|
||||
|
||||
1. Rust. [Install Rust]. Once Rust is installed, run
|
||||
|
||||
```shell
|
||||
rustup target add wasm32-unknown-unknown
|
||||
```
|
||||
|
||||
[install Rust]: https://www.rust-lang.org/en-US/install.html
|
||||
|
||||
2. The tests for this project use Node. Make sure you have node >= 10 installed,
|
||||
as that is when WebAssembly support was introduced. [Install Node].
|
||||
|
||||
[Install Node]: https://nodejs.org/en/
|
||||
|
||||
## Code Formatting
|
||||
|
||||
Although formatting rules are not mandatory, it is encouraged to run `cargo run` (`rustfmt`) with its default rules within a PR to maintain a more organized code base. If necessary, a PR with a single commit that formats the entire project is also welcome.
|
||||
35
zeroidc/vendor/wasm-bindgen/guide/src/contributing/js-sys/adding-more-apis.md
vendored
Normal file
35
zeroidc/vendor/wasm-bindgen/guide/src/contributing/js-sys/adding-more-apis.md
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
# Adding Support for More JavaScript Global APIs
|
||||
|
||||
As of 2018-09-24 we've [added all APIs][issue] in the current ECMAScript
|
||||
standard (yay!). To that end you'll hopefully not find a missing API, but if you
|
||||
do please feel free to file an issue!
|
||||
|
||||
We currently add new APIs added to ECMAScript that are in [TC39 stage 4][tc39]
|
||||
to this crate. If there's a new API in stage 4, feel free to file an issue as
|
||||
well!
|
||||
|
||||
### Instructions for adding an API
|
||||
|
||||
* [ ] Find the `wasm-bindgen` issue for the API you'd like to add. If this
|
||||
doesn't exist, feel free to open one! Afterwards be sure to comment on the
|
||||
issue to avoid duplication of work.
|
||||
|
||||
* [ ] Open the [MDN
|
||||
page](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects)
|
||||
for the relevant JS API.
|
||||
|
||||
* [ ] Open `crates/js-sys/src/lib.rs` in your editor; this is the file where we
|
||||
are implementing the bindings.
|
||||
|
||||
* [ ] Follow the instructions in the top of `crates/js-sys/src/lib.rs` about how
|
||||
to add new bindings.
|
||||
|
||||
* [ ] Add a test for the new binding to `crates/js-sys/tests/wasm/MyType.rs`
|
||||
|
||||
* [ ] Run the [JS global API bindings tests][test]
|
||||
|
||||
* [ ] Send a pull request!
|
||||
|
||||
[issue]: https://github.com/rustwasm/wasm-bindgen/issues/275
|
||||
[tc39]: https://tc39.github.io/process-document/
|
||||
[test]: testing.html
|
||||
45
zeroidc/vendor/wasm-bindgen/guide/src/contributing/js-sys/index.md
vendored
Normal file
45
zeroidc/vendor/wasm-bindgen/guide/src/contributing/js-sys/index.md
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
# `js-sys`
|
||||
|
||||
The [`js-sys` crate][js-sys] provides raw bindings to all the global APIs
|
||||
guaranteed to exist in every JavaScript environment by the ECMAScript standard,
|
||||
and its source lives at [`wasm-bindgen/crates/js-sys`][src]. With the `js-sys`
|
||||
crate, we can work with `Object`s, `Array`s, `Function`s, `Map`s, `Set`s,
|
||||
etc... without writing the `#[wasm_bindgen]` imports by hand.
|
||||
|
||||
Documentation for the published version of this crate is available on
|
||||
[docs.rs][docsrs] but you can also check out the [master branch
|
||||
documentation][masterdoc] for the crate.
|
||||
|
||||
[docsrs]: https://docs.rs/js-sys
|
||||
[masterdoc]: https://rustwasm.github.io/wasm-bindgen/api/js_sys/
|
||||
[src]: https://github.com/rustwasm/wasm-bindgen/tree/master/crates/js-sys
|
||||
|
||||
For example, we can invoke JavaScript [`Function`][mdn-function] callbacks and
|
||||
time how long they take to execute with [`Date.now()`][mdn-date-now], and we
|
||||
don't need to write any JS imports ourselves:
|
||||
|
||||
```rust
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn timed(callback: &js_sys::Function) -> f64 {
|
||||
let then = js_sys::Date::now();
|
||||
callback.apply(JsValue::null(), &js_sys::Array::new()).unwrap();
|
||||
let now = js_sys::Date::now();
|
||||
now - then
|
||||
}
|
||||
```
|
||||
|
||||
The `js-sys` crate doesn't contain bindings to any Web APIs like
|
||||
[`document.querySelectorAll`][mdn-qsa]. These will be part of the
|
||||
[`web-sys`][web-sys] crate.
|
||||
|
||||
[MDN]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects
|
||||
[js-sys]: https://crates.io/crates/js-sys
|
||||
[issue]: https://github.com/rustwasm/wasm-bindgen/issues/275
|
||||
[mdn-function]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function
|
||||
[mdn-qsa]: https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelectorAll
|
||||
[web-sys]: https://crates.io/crates/web-sys
|
||||
[web-sys-contributing]: https://rustwasm.github.io/wasm-bindgen/web-sys.html
|
||||
[web-sys-issues]: https://github.com/rustwasm/wasm-bindgen/issues?q=is%3Aissue+is%3Aopen+label%3Aweb-sys
|
||||
[mdn-date-now]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/now
|
||||
13
zeroidc/vendor/wasm-bindgen/guide/src/contributing/js-sys/testing.md
vendored
Normal file
13
zeroidc/vendor/wasm-bindgen/guide/src/contributing/js-sys/testing.md
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
# Testing
|
||||
|
||||
You can test the `js-sys` crate by running `cargo test --target
|
||||
wasm32-unknown-unknown` within the `crates/js-sys` directory in the
|
||||
`wasm-bindgen` repository:
|
||||
|
||||
```sh
|
||||
cd wasm-bindgen/crates/js-sys
|
||||
cargo test --target wasm32-unknown-unknown
|
||||
```
|
||||
|
||||
These tests are largely executed in Node.js right now via the
|
||||
[`wasm-bindgen-test` framework](../../wasm-bindgen-test/index.html)
|
||||
24
zeroidc/vendor/wasm-bindgen/guide/src/contributing/publishing.md
vendored
Normal file
24
zeroidc/vendor/wasm-bindgen/guide/src/contributing/publishing.md
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
# Publishing New `wasm-bindgen` Releases
|
||||
|
||||
1. <input type="checkbox"/> Compile the `publish.rs` script:
|
||||
|
||||
```
|
||||
rustc publish.rs
|
||||
```
|
||||
|
||||
2. <input type="checkbox"/> Bump every crate's minor version:
|
||||
|
||||
```
|
||||
# Make sure you are in the root of the wasm-bindgen repo!
|
||||
./publish bump
|
||||
```
|
||||
|
||||
3. <input type="checkbox"/> Send a pull request for the version bump.
|
||||
|
||||
4. <input type="checkbox"/> After the pull request's CI is green and it has been
|
||||
merged, publish to cargo:
|
||||
|
||||
```
|
||||
# Make sure you are in the root of the wasm-bindgen repo!
|
||||
./publish publish
|
||||
```
|
||||
36
zeroidc/vendor/wasm-bindgen/guide/src/contributing/team.md
vendored
Normal file
36
zeroidc/vendor/wasm-bindgen/guide/src/contributing/team.md
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
# Team
|
||||
|
||||
`wasm-bindgen` follows the [`rustwasm` organization's governance described
|
||||
here][governance]:
|
||||
|
||||
* All pull requests (including those made by a team member) must be approved by
|
||||
at least one other team member.
|
||||
|
||||
* Larger, more nuanced decisions about design, architecture, breaking changes,
|
||||
trade offs, etc are made by team consensus.
|
||||
|
||||
[governance]: https://github.com/rustwasm/team/blob/master/GOVERNANCE.md#repositories
|
||||
|
||||
## Members
|
||||
|
||||
<style>
|
||||
img {
|
||||
max-width: 117px;
|
||||
max-height: 117px;
|
||||
}
|
||||
</style>
|
||||
|
||||
| [][alexcrichton] | [][fitzgen] | [][spastorino] | [][ohanar] | [][jonathan-s] |
|
||||
|:---:|:---:|:---:|:---:|
|
||||
| [`alexcrichton`][alexcrichton] | [`fitzgen`][fitzgen] | [`spastorino`][spastorino] | [`ohanar`][ohanar] | [`jonathan-s`][jonathan-s] |
|
||||
| [][sendilkumarn] | [][belfz] | [][afdw] | | |
|
||||
| [`sendilkumarn`][sendilkumarn] | [`belfz`][belfz] | [`afdw`][afdw] | | |
|
||||
|
||||
[alexcrichton]: https://github.com/alexcrichton
|
||||
[fitzgen]: https://github.com/fitzgen
|
||||
[spastorino]: https://github.com/spastorino
|
||||
[ohanar]: https://github.com/ohanar
|
||||
[jonathan-s]: https://github.com/jonathan-s
|
||||
[sendilkumarn]: https://github.com/sendilkumarn
|
||||
[belfz]: https://github.com/belfz
|
||||
[afdw]: https://github.com/afdw
|
||||
47
zeroidc/vendor/wasm-bindgen/guide/src/contributing/testing.md
vendored
Normal file
47
zeroidc/vendor/wasm-bindgen/guide/src/contributing/testing.md
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
# Running `wasm-bindgen`'s Tests
|
||||
|
||||
## Wasm Tests on Node and Headless Browsers
|
||||
|
||||
These are the largest test suites, and most common to run in day to day
|
||||
`wasm-bindgen` development. These tests are compiled to Wasm and then run in
|
||||
Node.js or a headless browser via the WebDriver protocol.
|
||||
|
||||
```bash
|
||||
cargo test --target wasm32-unknown-unknown
|
||||
```
|
||||
|
||||
See [the `wasm-bindgen-test` crate's
|
||||
`README.md`](https://github.com/rustwasm/wasm-bindgen/blob/master/crates/test/README.md)
|
||||
for details and configuring which headless browser is used.
|
||||
|
||||
## Sanity Tests for `wasm-bindgen` on the Native Host Target
|
||||
|
||||
This small test suite just verifies that exported `wasm-bindgen` methods can
|
||||
still be used on the native host's target.
|
||||
|
||||
```
|
||||
cargo test
|
||||
```
|
||||
|
||||
## The Web IDL Frontend's Tests
|
||||
|
||||
```
|
||||
cargo test -p webidl-tests --target wasm32-unknown-unknown
|
||||
```
|
||||
|
||||
## The Macro UI Tests
|
||||
|
||||
These tests assert that we have reasonable error messages that point to the
|
||||
right source spans when the `#[wasm_bindgen]` proc-macro is misused.
|
||||
|
||||
```
|
||||
cargo test -p ui-tests
|
||||
```
|
||||
|
||||
## The `js-sys` Tests
|
||||
|
||||
See [the `js-sys` testing page](js-sys/testing.html).
|
||||
|
||||
## The `web-sys` Tests
|
||||
|
||||
See [the `web-sys` testing page](web-sys/testing.html).
|
||||
17
zeroidc/vendor/wasm-bindgen/guide/src/contributing/web-sys/index.md
vendored
Normal file
17
zeroidc/vendor/wasm-bindgen/guide/src/contributing/web-sys/index.md
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
# `web-sys`
|
||||
|
||||
The `web-sys` crate provides raw bindings to all of the Web's APIs, and its
|
||||
source lives at `wasm-bindgen/crates/web-sys`.
|
||||
|
||||
The `web-sys` crate is **entirely** mechanically generated inside `build.rs`
|
||||
using `wasm-bindgen`'s WebIDL frontend and the WebIDL interface definitions for
|
||||
Web APIs. This means that `web-sys` isn't always the most ergonomic crate to
|
||||
use, but it's intended to provide verified and correct bindings to the web
|
||||
platform, and then better interfaces can be iterated on crates.io!
|
||||
|
||||
Documentation for the published version of this crate is available on
|
||||
[docs.rs][docsrs] but you can also check out the [master branch
|
||||
documentation][masterdoc] for the crate.
|
||||
|
||||
[docsrs]: https://docs.rs/web-sys
|
||||
[masterdoc]: https://rustwasm.github.io/wasm-bindgen/api/web_sys/
|
||||
23
zeroidc/vendor/wasm-bindgen/guide/src/contributing/web-sys/logging.md
vendored
Normal file
23
zeroidc/vendor/wasm-bindgen/guide/src/contributing/web-sys/logging.md
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
# Logging
|
||||
|
||||
The `wasm_bindgen_webidl` crate (used by `web-sys`'s `build.rs`) uses
|
||||
[`env_logger`][env_logger] for logging, which can be enabled by setting the
|
||||
`RUST_LOG=wasm_bindgen_webidl` environment variable while building the `web-sys`
|
||||
crate.
|
||||
|
||||
Make sure to enable "very verbose" output during `cargo build` to see these logs
|
||||
within `web-sys`'s build script output.
|
||||
|
||||
```sh
|
||||
cd crates/web-sys
|
||||
RUST_LOG=wasm_bindgen_webidl cargo build -vv
|
||||
```
|
||||
|
||||
If `wasm_bindgen_webidl` encounters WebIDL constructs that it doesn't know how
|
||||
to translate into `wasm-bindgen` AST items, it will emit warn-level logs.
|
||||
|
||||
```
|
||||
WARN 2018-07-06T18:21:49Z: wasm_bindgen_webidl: Unsupported WebIDL interface: ...
|
||||
```
|
||||
|
||||
[env_logger]: https://crates.io/crates/env_logger
|
||||
44
zeroidc/vendor/wasm-bindgen/guide/src/contributing/web-sys/overview.md
vendored
Normal file
44
zeroidc/vendor/wasm-bindgen/guide/src/contributing/web-sys/overview.md
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
# `web-sys` Overview
|
||||
|
||||
The `web-sys` crate has this file and directory layout:
|
||||
|
||||
```text
|
||||
.
|
||||
├── build.rs
|
||||
├── Cargo.toml
|
||||
├── README.md
|
||||
├── src
|
||||
│ └── lib.rs
|
||||
└── webidls
|
||||
└── enabled
|
||||
└── ...
|
||||
```
|
||||
|
||||
### `webidls/enabled/*.webidl`
|
||||
|
||||
These are the WebIDL interfaces that we will actually generate bindings for (or
|
||||
at least bindings for *some* of the things defined in these files).
|
||||
|
||||
### `build.rs`
|
||||
|
||||
The `build.rs` invokes `wasm-bindgen`'s WebIDL frontend on all the WebIDL files
|
||||
in `webidls/enabled`. It writes the resulting bindings into the cargo build's
|
||||
out directory.
|
||||
|
||||
### `src/lib.rs`
|
||||
|
||||
The only thing `src/lib.rs` does is include the bindings generated at compile
|
||||
time in `build.rs`. Here is the whole `src/lib.rs` file:
|
||||
|
||||
```rust
|
||||
{{#include ../../../../crates/web-sys/src/lib.rs}}
|
||||
```
|
||||
|
||||
### Cargo features
|
||||
|
||||
When compiled the crate is almost empty by default, which probably isn't what
|
||||
you want! Due to the very large number of APIs, this crate uses features to
|
||||
enable portions of its API to reduce compile times. The list of features in
|
||||
`Cargo.toml` all correspond to types in the generated functions. Enabling a
|
||||
feature enables that type. All methods should indicate what features need to be
|
||||
activated to use the method.
|
||||
39
zeroidc/vendor/wasm-bindgen/guide/src/contributing/web-sys/supporting-more-web-apis.md
vendored
Normal file
39
zeroidc/vendor/wasm-bindgen/guide/src/contributing/web-sys/supporting-more-web-apis.md
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
# Supporting More Web APIs in `web-sys`
|
||||
|
||||
1. Ensure that the `.webidl` file describing the
|
||||
interface exists somewhere within the `crates/web-sys/webidls/enabled`
|
||||
directory.
|
||||
|
||||
First, check to see whether we have the WebIDL definition file for
|
||||
your API:
|
||||
|
||||
```sh
|
||||
grep -rn MyWebApi crates/web-sys/webidls
|
||||
```
|
||||
|
||||
* If your interface is defined in a `.webidl` file that is inside the
|
||||
`crates/web-sys/webidls/enabled` directory, skip to step (3).
|
||||
|
||||
* If your interface isn't defined in any file yet, find the WebIDL definition
|
||||
in the relevant standard and add it as a new `.webidl` file in
|
||||
`crates/web-sys/webidls/enabled`. Make sure that it is a standard Web API!
|
||||
We don't want to add non-standard APIs to this crate.
|
||||
|
||||
* If your interface is defined in a `.webidl` file within any of the
|
||||
`crates/web-sys/webidls/unavailable_*` directories, you need to move it into
|
||||
`crates/web-sys/webidls/enabled`, e.g.:
|
||||
|
||||
```sh
|
||||
cd crates/web-sys
|
||||
git mv webidls/unavailable_enum_ident/MyWebApi.webidl webidls/enabled/MyWebApi.webidl
|
||||
```
|
||||
|
||||
2. Regenerate the `web-sys` crate auto-generated bindings, which you can do with
|
||||
the following commands:
|
||||
|
||||
```sh
|
||||
cd crates/web-sys
|
||||
cargo run --release --package wasm-bindgen-webidl -- webidls src/features
|
||||
```
|
||||
|
||||
You can then use `git diff` to ensure the bindings look correct.
|
||||
14
zeroidc/vendor/wasm-bindgen/guide/src/contributing/web-sys/testing.md
vendored
Normal file
14
zeroidc/vendor/wasm-bindgen/guide/src/contributing/web-sys/testing.md
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
# Testing
|
||||
|
||||
You can test the `web-sys` crate by running `cargo test` within the
|
||||
`crates/web-sys` directory in the `wasm-bindgen` repository:
|
||||
|
||||
```sh
|
||||
cd wasm-bindgen/crates/web-sys
|
||||
cargo test --target wasm32-unknown-unknown --all-features
|
||||
```
|
||||
|
||||
The Wasm tests all run within a headless browser. See [the `wasm-bindgen-test`
|
||||
crate's
|
||||
`README.md`](https://github.com/rustwasm/wasm-bindgen/blob/master/crates/test/README.md)
|
||||
for details and configuring which headless browser is used.
|
||||
Reference in New Issue
Block a user