Coder Social home page Coder Social logo

rustwasm / wasm-bindgen Goto Github PK

View Code? Open in Web Editor NEW
7.3K 101.0 1.0K 21.37 MB

Facilitating high-level interactions between Wasm modules and JavaScript

Home Page: https://rustwasm.github.io/docs/wasm-bindgen/

License: Apache License 2.0

Rust 98.37% JavaScript 1.12% Shell 0.04% HTML 0.11% TypeScript 0.07% WebAssembly 0.29%
wasm javascript rust binding-generator rust-wasm

wasm-bindgen's People

Contributors

afdw avatar alexcrichton avatar belfz avatar brisad avatar c410-f3r avatar chinedufn avatar daxpedda avatar dependabot-support avatar derekdreery avatar eminence avatar fitzgen avatar grovesnl avatar hywan avatar ibaryshnikov avatar jannikkeye avatar jonathan-s avatar konstin avatar liamolucko avatar lukaslihotzki avatar ohanar avatar pauan avatar pepsighan avatar rreverser avatar rylev avatar sendilkumarn avatar striezel avatar t5uku5hi avatar toversus avatar twilco avatar wismer avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

wasm-bindgen's Issues

Support for u8 slices

wasm_bindgen! {
    pub fn parse_data(data: &[u8]) -> i32 {
        data.len() as i32
    }
}

Returns

unsupported reference type

I'm hoping that you'd be open to more borrowed types (specifically &[u8]) in addition to BorrowedStr. This could be part of a larger issue to support Vec and other slices, but I figure &[u8] might be easiest and would be implemented very closely to BorrowedStr.

Use case:

After I use a FileReader to read a binary file into an ArrayBuffer and create WebAssembly.Memory (I believe that flow is correct), I want to send the data to rust for parsing.

target_family condition not met

Hi @alexcrichton! It's quite exciting to be writing someone who is so prolific in the Rust community.
Thank you so much for wasm-bindgen and thank you for your time.

Laying out my issue:

Host: nightly-x86_64-pc-windows-gnu
Version: rustc 1.26.0-nightly

Attempting to compile this library with cargo build --release --target wasm32-unknown-unknown.
Receiving long error output all having to do with undeclared modules:

sys::try_lock_exclusive(self)
    |         ^^^ Use of undeclared type or module `sys`

error[E0433]: failed to resolve. Use of undeclared type or module `MmapInner`
   --> C:\Users\guilf\.cargo\registry\src\github.com-1ecc6299db9ec823\memmap-0.5.2\src\lib.rs:130:9
    |
130 |         MmapInner::open(&file, prot, 0, len as usize).map(|inner| Mmap { inner: inner })
    |         ^^^^^^^^^ Use of undeclared type or module `MmapInner`
error[E0433]

Looking at memmap v0.5.2, I see the MmapInner module declared here if Windows target family and also on line 12 if Linux target family condition is met.

Is this occurring because wasm32-unknown-unknown is neither Windows nor Linux target family?

Passing Rust struct ownership into JS

Currently you can't pass ownership of a rust struct from rust to JS through an import, like this:

#[wasm_bindgen]
struct Foo();

#[wasm_bindgen]
extern {
    fn take_struct(foo: Foo);
}

but you can return it from an exported function:

#[wasm_bindgen]
fn create_foo() -> Foo {
    Foo()
}

Is this a conscious style choice or is passing in structs by value just not implemented yet?

In both cases js takes ownership of the object and becomes responsible for freeing it if it's dropped. But I can see that being clearer when the object is a return from a rust export, than when receiving an object as an argument from rust.

wasm_bindgen panics

rustc 1.25.0-nightly (4d2d3fc5d 2018-02-13) and
rustc 1.25.0-nightly (3ec5a99aa 2018-02-14)

command:

$ wasm-bindgen target/wasm32-unknown-unknown/release/bullet_wasm.wasm --out-dir .

failure point: https://github.com/alexcrichton/wasm-bindgen/blob/9183236522723b198cdb993225b205f0225af543/crates/wasm-bindgen-cli-support/src/js.rs#L840

custom: '\u{b2796}'

traceback:

  11: <std::collections::hash::map::HashMap<K, V, S> as core::ops::index::Index<&'a Q>>::index
             at /checkout/src/libstd/collections/hash/map.rs:1394
  12: wasm_bindgen_cli_support::js::SubContext::generate_function
             at crates/wasm-bindgen-cli-support/src/js.rs:840
  13: wasm_bindgen_cli_support::js::SubContext::generate_export_for_class
             at crates/wasm-bindgen-cli-support/src/js.rs:669
  14: wasm_bindgen_cli_support::js::SubContext::generate_export
             at crates/wasm-bindgen-cli-support/src/js.rs:653
  15: wasm_bindgen_cli_support::js::SubContext::generate
             at crates/wasm-bindgen-cli-support/src/js.rs:644
  16: wasm_bindgen_cli_support::Bindgen::_generate
             at crates/wasm-bindgen-cli-support/src/lib.rs:90
  17: wasm_bindgen_cli_support::Bindgen::generate
             at /home/sebk/Rust/wasm-bindgen/crates/wasm-bindgen-cli-support/src/lib.rs:58
  18: wasm_bindgen::main
             at crates/wasm-bindgen-cli/src/bin/wasm-bindgen.rs:51

source code:

extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;

#[wasm_bindgen]
pub struct Context {}

#[wasm_bindgen]
impl Context {
    pub fn parse(&self, expr: &str) -> Expr {
        panic!()
    }
    pub fn eval(&self, expr: &Expr) -> f64 {
        panic!()
    }
    pub fn set(&mut self, var: &str, val: f64) {
        panic!()
    }
}

#[wasm_bindgen]
pub struct Expr {}

#[wasm_bindgen]
#[no_mangle]
pub extern fn context() -> Context {
    panic!()
}

Enable returning `&JsValue` from exported functions

Right now you can't write a function like:

#[wasm_bindgen]
#[no_mangle]
pub extern fn foo(a: &JsValue) -> &JsValue {
    a
}

This is because JsValue goes through all the same machinery as Foo, but I think we want to add a specific trait for "can be returned as a reference" or maybe even just AsRef<JsValue> as I think that's the only way this can work?

Enabling this would help avoid an unnecessary Clone otherwise to extract data from wasm back into JS.

Support for directly importing builtin Web APIs

It would be neat if the developer could put a bindgen annotation on function imports that said "import the JS function found at "x.y.z" (i.e., a sequence of JS property accesses, explicitly starting at the JS global object). This could allow a dev to import, e.g. console.log directly. Without this support, I think one would have to write a dummy ES Module that exports a function that calls console.log. With this support, one could write a whole DOM-accessing app entirely in Rust.

hello_world example gives "WebAssembly.Instance is disallowed" in Chrome

Heya! I just tried to run the hello_world example on my machine (rustc 1.26.0-nightly (9cb18a92a 2018-03-02), wasm-bindgen master today 98b9bee, Mac Chrome) and it throws the error:

RangeError: WebAssembly.Instance is disallowed on the main thread, if the buffer size is larger than 4KB. Use WebAssembly.instantiate.

which appears to directly result from the generated import * as wasm from './hello_world_wasm'; line. I found webpack/webpack#6475 implying this is a browser limitation of sync wasm instantiation and https://github.com/alexcrichton/wasm-bindgen/issues/39 where you briefly discuss this issue, but from your comments it sounds like async import causes this error, not the sync import which is what I'm seeing.

Any chance you can point me in the right direction? Not sure if it's user error. :)

Module not found: "env"

When using wasm2es6js or even looking at the generated raw wasm file, the generated module refers to a module called "env". This module I assume should resolve to the main .js file generated by wasm-bindgen since it expects it to contain __wbindgen_throw according to the import table of the .wasm file.

However it also expects the __web_on_grow function which is not defined.

I'm attempting to integrate this tool with webpack. How should I map this "env" module?

How can I get a reference to the `document` object?

On js side, document or rather window.document provides the reference to the document object contained in the current window. Is there any way I can access that document using wasm_bindgen? Or do I need to write a js file exposes the required functionality of the document API?

Support for C-Style Enums

Supporting the full power of Rust enums is probably a lot of work, but C-Style enums seem more doable. Is this something worth while tackling? If so, I would volunteer to help out (although I might need a bit of coaching).

Can I import multiple version of a js function based on its arity? If yes, how?

For example, I have this js module test.js.

export function test(a) {
    return a || 1
}

Now in js, I can call this function with or without an argument. Can I mimic the same thing on rust side with something like this?

#[wasm_bindgen(module = "./test")]
extern {
    fn test(i: i32) -> i32;
    #[wasm_bindgen(...some attr indicating its the same function on JS side)]
    fn test_without_arg() -> i32;
}

Cannot resolve dependency 'env'

ร—  try_gluon\src\client\gluon_wasm_wasm.js:2:38: Cannot resolve dependency 'env'
  1 | 
> 2 |             import * as import_b from 'env';import * as import_c from './gluon_wasm';

After going through the steps in the README I am currently stuck at the above error. Apparently the code generated from wasm2es6js expects an env module but I don't get where that is supposed to come from?

Support for returning Vec<JsValue>

Returning a JsValue works and returning Vec or String works, but returning a Vec<JsValue> does not, failing with: the trait wasm_bindgen::convert::WasmBoundary is not implemented for std::vec::Vec<wasm_bindgen::JsValue>. I don't see a reason why returning a Vec<JsValue> shouldn't work.

I would also be interested in implementing this, but I'm getting lost in the code generation.

Circular dependencies don't always work

I stepped on this while trying to add some webassembly to a Visual Studio Code extension.
Right now output.js and output_wasm.js both import each other and this doesn't work in VS Code because import_b is empty when WebAssembly.instantiate is called:
wasm-bindgen-missing-exports

While the same file imported in the main module has everything in place:
wasm-bindgen-exports-in-place

Everything started working like a charm after I manually moved stuff required by wasm into a separate file and imported it from both files.

You can see the example extension in https://github.com/gentoo90/vs-wasm
Uncomment line 24 in tasks.json and relaunch to see the error.

Add support for emitting RAII-style with functions

Emitting something like:

class Whatever {
    ...
    async with(whateverInstance, f) {
        try {
            return await f(whateverInstance);
        } finally {
            whateverInstance.free();
        }
    }
}

Would ideally control with some kind of #[wasm_bindgen(...)] attribute. Should be able to control whether async or not or both versions.

JS getters and setters

Right now there's no way to set a property on an imported JS object, and this should be added!

Current thinking of how to do this:

#[wasm_bindgen]
extern {
    type Foo;

    #[wasm_bindgen(getter)] // field inferred via method name, could also be explicit here
    fn foo(this: &Foo) -> u32; // required to have only one `this` argument

    #[wasm_bindgen(setter)]
    fn set_foo(this: &Foo, val: u32); // no return type allowed
}

generating JS that looks like:

const foo_get = Object.getOwnPropertyDescriptor(Foo.prototype, 'foo').get;
export function foo_get_shim(idx) {
    return foo_get.call(getObject(idx));
}

const foo_set = Object.getOwnPropertyDescriptor(Foo.prototype, 'foo').set;
export function foo_set_shim(idx, val) {
    return foo_set.call(getObject(idx), val);
}

Previous strawman

I'm not really sure how to model this in Rust's syntax well, but something like this is always an option

#[wasm_bindgen]
extern {
    #[wasm_bindgen(properties(foo: u32, bar: String))]
    type Foo;

    #[wasm_bindgen(properties(foo(getter): String))] // no setter? .. needs better syntax
    type Bar;
}

Passing mutable slice from JS to Rust

I am trying to reduce allocation overhead and avoid the use of Vec, which leads me to a C-style interface like this

#[wasm-bindgen]
pub fn expensive_work(input: &[u8], output: &mut [u8]) {
  // do expensive work
}

now currently this throws when trying to compile with a missmatched types error.
Would it be possible to support something like this?

Unable to build when including libraries that rely on c_int, socklen_t, etc.

This may be purely a case of naรฏvetรฉ on my part, I came across the Mozilla article that referenced your library and thought it would be a fun project to set up a rust-wasm bridge to this rust unrar package โ€“ that itself is a bridge to the C unrar โ€“ and compare it in performance to a similar project created with emscripten. It's been years since I've touched a system-level language and have equally little knowledge about wasm, but at the very least I can determine that the source of my headache is purely from including the unrar library when compiling to wasm32-unknown-unknown. The attached is the full output that I received when attempting to compile to that target with the following setup.

// src/lib.rs
#![feature(proc_macro)]

extern crate wasm_bindgen;

use wasm_bindgen::prelude::*;

#[wasm_bindgen]
extern {
    fn alert(s: &str);
}

#[wasm_bindgen]
pub fn greet(name: &str) {
    alert(&format!("Hello, {}!", name));
}
# Cargo.toml
[package]
name = "wasm_test"
version = "0.1.0"
authors = ["Ben Teichman <[email protected]>"]

[lib]
crate-type = ["cdylib"]

[dependencies]
wasm-bindgen = "0.1"
unrar = "0.4.3"

This was the output I received when running it:

output.log

How this crate positions itself against stdweb?

It seems that stdweb aims to do a lot of the same things wasm-bindgen does (and some more). How is this crate positioned against stdweb? Is it a strict competitor (i.e. more choice, the better) or does it aim to be something different?

unsafe `into_inner()`

@alexcrichton thanks for this tool, it looks amazing. I was trying to get it running from master and I am running into an unsafe call error. I tried wrapping the module in unsafe but that didn't seem to work.

code

#![feature(proc_macro)]

extern crate wasm_bindgen;

use wasm_bindgen::prelude::*;

wasm_bindgen! {
    pub fn greet(name: &str) -> String {
      format!("Hello, {}!", name)
    }
}
error[E0133]: call to unsafe function requires unsafe function or block
   --> /Users/charlesking/.cargo/git/checkouts/wasm-bindgen-aa905f4284ca7fbe/322f520/src/lib.rs:341:13
    |
341 |             self.value.into_inner()
    |             ^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function

error: aborting due to previous error

error: Could not compile `wasm-bindgen`.

Seems to be related to changes made here - alexcrichton@c51a342. If I specify an earlier revision, it compiles without error.

Should #[no_mangle] and extern be required?

Right now when you want to export a function to JS it looks like:

#[wasm_bindgen]
#[no_mangle]
pub extern fn foo() {
    // ...
}

but should the #[no_mangle] and extern be required? The original thinking was that one day the #[wasm_bindgen] attribute could be removed and this'd just reflect what rustc does under the hood already, but I'm getting less and less certain that'll be the case (aka custom types and &str probably "won't ever work" in terms of being the right ABI).

It'd certainly be a little easier on the eyes to remove those two components!

Add more JS initialization options

Currently, the CLI-generated TS bindings export a single entry point, instantiate. This internally calls WebAssembly.instantiate and then processes the returned WebAssembly.ResultObject like

function xform(obj: WebAssembly.ResultObject): Exports {
    let { module, instance } = obj;
    // etc.
}

This is a great general starting point, but it has a couple limitations:

  1. You can't pass a pre-compiled WebAssembly.Module to instantiate, since the overload of WebAssembly.instantiate that takes a WebAssembly.Module doesn't return a WebAssembly.ResultObject but instead just a WebAssembly.Instance. So the destructuring above will set both module and instance to undefined.
  2. You can't use the newer WebAssembly.instantiateStreaming API.

Would you support adding a lower-level JS API for these use cases? I'm imagining a pair of functions something like getImports(_imports : Imports) and initWithInstance(instance : WebAssembly.Instance). It'd be up to consuming code to call WebAssembly.instantiate(Streaming), like

import { MyStruct, getImports, initWithInstance } from './cli-generated-bindings.ts';

WebAssembly.instantiateStreaming(fetch('my-wasm.wasm'), getImports({}))
    .then(({ instance }) => initiWithInstance(instance))
    .then(wasm => {
        const myStruct = MyStruct.new();
        wasm.my_rust_fn(myStruct);
        // etc...
    });

This would also support things like fetching and compiling the WASM once via WebAssembly.compile or WebAssembly.compileStreaming and then passing the compiled WebAssembly.Module to multiple worker threads, each of which constructs its own WebAssembly.Instance using the cli-generated bindings.

[Question] Can I pass Promise between JS and Rust by wasm-bindgen?

Hi.
I have a question.

I want to call a wasm(Rust) function, that uses a JS async function, from JS.
The wasm function should return a Promise because the function uses an async function.
So there seems be two challenges.

  1. The wasm(Rust) function must return something that can be converted to JS promise.
  2. The JS async function must return something that can be converted to something like Futures.

Is it possible by wasm-bindgen?
And if possible, I can use a syntax like futures-await in that case?
(Since I have relatively large amount of synchrous codes, I will be happy if I can use the syntax.)

Thanks!

Confusing error when trying to use a moved value

When a struct is passed by value (i.e., moved) into a function that is being called by JS the generated JS code nulls out the pointer to that struct in the wrapping ES6 class. This makes total sense - the struct has been moved so the previous ref to it is now invalidated, but the error at run time is simply: Error: null pointer passed to rust.

Would it make debugging easier if the class kept track of if it has been invalidated due to a move and throws a more descriptive error?

Support for Option

#[no_mangle]
#[wasm_bindgen]
pub extern fn optional() -> Option<i32> {
    None
}

Ideally this would be returned as null on the JS side

the trait `wasm_bindgen::convert::WasmBoundary` is not implemented for `std::option::Option<i32>`

(this seems like lower hanging fruit than Result)


The good news is that I'm getting my head around WebAssembly so I may be able to help in the future ๐Ÿคž

Edit: Oof, maybe it's best to tackle the general generics problem before specializing for the Option use case.

WebIDL binding generator

The #[wasm_bindgen] attribute is pretty feature-ful right now and notably allows importing a class from JS and using it in Rust. Unfortunately though it's a pretty manual process to write this out for web apis, so it'd be great to do this automatically!

Thankfully there's this awesome thing called WebIDL which is a programmatic description of APIs available on the web. There's even two parsers on crates.io for WebIDL!

I think it'd be pretty neat if a WebIDL generator were added to this repo to automatically generate #[wasm_bindgen] decorated bindings. In that sense I'd imagine that we could auto-generate a bunch of *-sys crates which provide bindings for all the web-related functionality JS has to offer. At that point working with the DOM or other web APIs should be as simple as extern crate foo!

An issue like this certainly has a lot of design questions to explore as I'm sure WebIDL is far richer than what #[wasm_bindgen] supports today. We'll need to add features to #[wasm_bindgen] along the way as well as probably developing idioms to map JS to Rust, but I think it'd be great to at least start out with some simple APIs to see how it goes.

For example the README has an example:

#[wasm_bindgen]
extern {
    fn alert(s: &str);
}

but it'd be awesome if we could automatically generate this binding from a WebIDL file and place it in a crate to use. Once we have the "hello world" variants working we should hopefully have enough information to inform the next phase of design questions.

Support for native modules in generated JS

It could be nice to have an option where the generated JS does not depend on webpack. The primary issue is the import statement of the wasm file I think? Since this project implicitly targets browsers that support wasm, this mostly overlaps also with browsers that support native modules.

error[E0463]: can't find crate for `std`

This is my first experience using Rust so I may be missing an obvious setup step.
I'm following along with the README and I get an error when I run the cargo build command:

cargo build --release --target wasm32-unknown-unknown
    Updating registry `https://github.com/rust-lang/crates.io-index`
   Compiling itoa v0.3.4
   Compiling dtoa v0.4.2
   Compiling num-traits v0.2.1
   Compiling fnv v1.0.6
   Compiling wasm-bindgen-shared v0.1.1
   Compiling serde v1.0.29
   Compiling unicode-xid v0.1.0
   Compiling proc-macro2 v0.2.3
   Compiling quote v0.4.2
   Compiling syn v0.12.14
   Compiling serde_json v1.0.10
   Compiling serde_derive_internals v0.20.0
   Compiling serde_derive v1.0.29
   Compiling wasm-bindgen-macro v0.1.1
   Compiling wasm-bindgen v0.1.0
error[E0463]: can't find crate for `std`
  |
  = note: the `wasm32-unknown-unknown` target may not be installed

error: aborting due to previous error

If you want more information on this error, try using "rustc --explain E0463"
error: Could not compile `wasm-bindgen`.

To learn more, run the command again with --verbose.

This is the result of running rustup show:

 rustup show
Default host: x86_64-apple-darwin

installed toolchains
--------------------

stable-x86_64-apple-darwin
nightly-x86_64-apple-darwin (default)

installed targets for active toolchain
--------------------------------------

wasm32-unknown-emscripten
wasm32-unknown-unknown
x86_64-apple-darwin

active toolchain
----------------

nightly-x86_64-apple-darwin (default)
rustc 1.26.0-nightly (2789b067d 2018-03-06)

I'd be happy to provide additional debugging information if needed.

feature request: automatically target the lib

the final step for running wasm-bindgen is:

wasm-bindgen target/wasm32-unknown-unknown/release/<name of lib>.wasm \ --out-dir .

it would be easier to use this tool to automate if it automagically knew to look in that directory for a wasm file named with the same name as the crate.

i'm sure i don't know all the details but would that be possible?

Build error: No matching package `synom`

https://github.com/alexcrichton/wasm-bindgen/blob/bef908a9b110e7ac0828a1eb391f56b25f01ec18/crates/wasm-bindgen-macro/Cargo.toml#L11

I tried following the example, but I ran into this error:

cargo +nightly build --release --target wasm32-unknown-unknown
    Updating git repository `https://github.com/alexcrichton/wasm-bindgen`
    Updating registry `https://github.com/rust-lang/crates.io-index`            
    Updating git repository `https://github.com/dtolnay/quote`
    Updating git repository `https://github.com/dtolnay/syn`                    
error: no matching package named `synom` found (required by `wasm-bindgen-macro`)
location searched: https://github.com/dtolnay/syn
version required: *

Seems like it was renamed or moved?

Just get typings for exports

In order to just get .d.ts types for a rust file compiled to wasm, should I use this project or is there something more suitable?
Also, in my case, all <projectname>.js does is reexport functions already exported in <projectname>_wasm.js, and <projectname>.d.ts is provided for that, meaining it doesn't export for example the memory or even the booted promise (how can I know when I can start using the module, do I need to import both, one for the promise the other for booted actions?)

I am looking for something that, based on a rust file, produces the definition of a custom ResultObject where instance.exports is statically typed.
Maybe the return of WebAssembly.Module.exports(), but that's less significant.

Functions called by shims should not do property lookups

Currently something like:

#[wasm_bindgen]
extern {
    type Node;
    #[wasm_bindgen(method)] 
    fn contains(this: &Node, other: u32);
}

will generate a shim in js like:

export function shim(idx, other) {
    return Node.prototype.contains.call(getObject(idx), other);
}

Instead, though, we should generate a shim like:

const __shim_function = Node.prototype.contains;
export function shim(idx, other) {
    return __shim_function.call(getObject(idx), other);
}

and that way the JS engine will hopefully have fewer guards/property lookups to go through! (plus this more closely mirrors what wasm will eventually do natively)

Should emit bindings for trait implementations

This test should pass, but right now there aren't any default bindings emitted for Tricycle:

extern crate test_support;

#[test]
fn default() {
    test_support::project()
        .file("src/lib.rs", r#"
            #![feature(proc_macro)]

            extern crate wasm_bindgen;

            use wasm_bindgen::prelude::*;

            #[wasm_bindgen]
            #[derive(Default)]
            pub struct Tricycle {
                uno: f64,
                dos: f64,
                tres: f64,
            }

            #[wasm_bindgen]
            impl Tricycle {
                pub fn uno(&self) -> f64 { self.uno }
                pub fn dos(&self) -> f64 { self.dos }
                pub fn tres(&self) -> f64 { self.tres }
            }
        "#)
        .file("test.ts", r#"
            import * as assert from "assert";
            import * as wasm from "./out";

            export function test() {
                let tricycle = wasm.Tricycle.default();
                assert.strictEqual(tricycle.uno(), 0);
                assert.strictEqual(tricycle.dos(), 0);
                assert.strictEqual(tricycle.tres(), 0);
            }
      "#)
        .test();
}

Returning Custom Struct

I have a simple Rust program (compiled as wasm) that is attempting to interface with JS:

#![feature(proc_macro)]

extern crate wasm_bindgen;

use wasm_bindgen::prelude::*;

#[wasm_bindgen]
pub struct MyStruct {
    my_property: usize
}

#[wasm_bindgen]
#[no_mangle]
pub extern fn my_function() -> MyStruct {
    MyStruct { my_property: 1 }
}

I then run the following:

cargo build --release --target wasm32-unknown-unknown
wasm-bindgen target/wasm32-unknown-unknown/release/wasm_test.wasm --out-dir dist

And I get the following error:
thread 'main' panicked at 'no entry found for key', libcore/option.rs:917:5

This happens when the wasm-bindgen-cli tool is running.

I poked around and found that the panic comes from here after being called here. It seems that the custom_type_names hash table is not populated. I then found the JSON that is being stored in the .wasm file:
{"exports":[{"class":null,"method":false,"function":{"name":"my_function","arguments":[],"ret":"๒ทŸ’"}}],"imports":[],"custom_type_names":[]}.

Two things that don't make sense to me:

  • It's hard to see here but the value in "ret" is actually \u{b77d2}.
  • The custom_type_names array is empty, but I'm guessing that should somehow reference the MyStruct struct.

I attempted to dive into the code-gen aspect of bindgen but I got lost. Any ideas?

--help / options don't actually get shown

Not sure what's up with this, but the options don't get printed:

$ wasm-bindgen --help
Invalid arguments.

Usage:
    wasm-bindgen [options] <input>
$ wasm-bindgen
Invalid arguments.

Usage:
    wasm-bindgen [options] <input>

There should be a section like this:

Options:
    -h --help               Show this screen.
    --output-ts FILE        Output TypeScript file
    --output-wasm FILE      Output WASM file
    --nodejs                Generate output for node.js, not the browser
    --debug                 Include otherwise-extraneous debug checks in output

... but this section doesn't actually show up.

Format of the custom section

The general idea behind this tool is that source languages will encode data into a custom section of the wasm binary which the wasm-bindgen tool will decode and remove, using it to generate appropriate JS bindings.

Currently, however, this isn't what happens! Instead we shove data into a static as rustc doesn't expose a way to emit data into a custom section as-is. Additionally the static is just a totally random encoding that I got working, it's not principled at all. We should fix that!

I think it's relatively uncontroversial to use a custom section to communicate this information, and we'll continue to work around rustc's lack of ability to emit a custom section in the meantime and will otherwise take advantage of the ability to do this in rustc as soon as it becomes available! In the meantime, though, I think it may be useful to discuss the custom format as well.

Right now the wasm-bindgen-cli-shared crate shows off effectively what's encoded right now, the top-level entry being a Program and a wasm binary has multiple Program instances. That is, however, only what the bindgen tool currently uses and will likely change over time both in requirements and breadth. In that sense, does it makes sense to lock down a binary format just yet? Or maybe we can lock down an extensible format like JSON which you can easily add keys to over time?

One thing I definitely want to do in the near term is to version the wasm-bindgen information in the sense that if the CLI installed at a particular git rev finds information produced by a different git rev then it should immediately generate an error saying they're out of sync (as it's so unstable). Eventually this'll probably get removed and we'll want to have the producer and consumer versioned separately, but that may be awhile!

In any case, this is all just some off-the-cuff thinking, I'd love to hear others' thoughts on this too!

wasm2es6js looking for non-existent wasm file

ERROR in ./src/main.rs
Module build failed: Error: Command failed: wasm2es6js target\wasm32-unknown-unknown\release\garuda-wasm-mdns_wasm.wasm -o target\wasm32-unknown-unknown\release\garuda-wasm-mdns_wasm.js --base64
thread 'main' panicked at 'failed to open input: Os { code: 2, kind: NotFound, message: "The system cannot find the file specified." }', libcore\result.rs:945:5
note: Run with `RUST_BACKTRACE=1` for a backtrace.

The wasm2es6js command is looking for garuda-wasm-mdns_wasm.wasm which is non-existent. The file that does exist is garuda-wasm-mdns.wasm. Somewhere there must be a descrepency between naming the release file and what wasm2es6js is looking for.

rustc 1.26.0-nightly (2789b067d 2018-03-06)
wasm-bindgen 0.1.1

Webpack config

rules: [
      {
        test: /\.rs$/,
        use: [{
          loader: 'wasm-loader',
        }, {
          loader: 'rust-native-wasm-loader',
          options: {
            release: true,
            gc: true,
            wasmBindgen: true,
            wasm2es6js: true,
          },
        }],
      }
    ],

Rust struct reference in js

If we wanted to pass a temporary reference to a struct defined in Rust to a js function, this should work.
The user defines Foo like so:

#[wasm_bindgen]
pub struct Foo {
    internal: i32,
}

#[wasm_bindgen]
impl Foo {
    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;
    }
}

And a js function that takes a &Foo:

function bar(/*FooRef*/f)
{
    console.log("Foo.get(): ", f.get());
}

Generated/hidden Rust:

#[wasm_bindgen(module = "./index")]
extern {
    fn bar_js(ptr_to_foo: *const Foo);
}

fn bar(f: &Foo){
    bar_js(f as *const Foo)
}

#[wasm_bindgen]
#[no_mangle]
#[allow(non_snake_case)]
pub extern fn Foo_get(ptr_to_foo: *const Foo) -> i32 {
    let f = unsafe{ptr_to_foo.as_ref()}.unwrap();
    f.get()
}
#[wasm_bindgen]
#[no_mangle]
#[allow(non_snake_case)]
pub extern fn Foo_set(ptr_to_foo: *mut Foo, val: i32) {
    let f = unsafe{ptr_to_foo.as_mut()}.unwrap();
    f.set(val);
}

Generated js:

export function bar_js(ptr_to_foo)
{
    const f = new FooRef(ptr_to_foo);
    bar(f);
    f._ptr = 0;
}

class FooRef {
    constructor(ptr){
        this._ptr = ptr;
    }
    get(){
        // call `get` on `Foo` referenced by `this`
        return Foo_get(this._ptr);
    }
}
class FooMutRef extends  FooRef{
    constructor(ptr){
        super(ptr);
    }
    set(val){
        // call `set` on `Foo` referenced by `this`
        Foo_set(this._ptr, val);
    }
}

(Instead of invalidating the this._ptr immediately, we could wait for Foo to drop. I don't know where this would be useful though.)

Example usage in Rust:

let f = Foo::new(42);
bar(&f); // call to js

Would there be any theoretical problems with this?

Copy doc comments from Rust to JS

Would be good for JS programmers reading the generated JS to have documentation on

  • Classes
  • Methods
  • Functions
  • Anything else that gets emitted and has a doc comment in the Rust version

Allow i64 values to be passed

I mentioned here WebAssembly/design#1172 that we will be able to use the BigInt proposal to represent the i64 values from WebAssembly.

Currently there is not support for BigInt in browsers (nor in Babel). So I believe we can use this kind of tools to allow it.

We use a 64 bit two's-complement (https://github.com/dcodeIO/long.js).

Have you considered to implement it?

Edit:
I just remembered that WebAssembly doesn't allow multiple results for a func, I'm not sure what's the best solution, maybe the linear memory?

When I said "we use" I meant in https://github.com/xtuc/webassemblyjs which is not the same use-case.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.