koute / stdweb

A standard library for the client-side Web
Apache License 2.0
3.44k stars 177 forks source link

Leverage WebIDL to generate API wrappers #4

Open casey opened 7 years ago

casey commented 7 years ago

Not sure this is already on your radar, but as webassembly moves forward it might be worth looking at autogenerating rust interfaces based on WebIDL specs:

https://github.com/heycam/webidl

This document contains some interesting notes about IDL + WebAssembly

https://github.com/WebAssembly/design/blob/master/GC.md

Even if the generated rust code isn't particularly idiomatic, it could take care of a lot of tedious FFI work.

koute commented 7 years ago

This is definitely something I'd like to look into in the future!

Ideally I'd probably envision something like this:

Right now though I think it's still too early for this, especially since neither webasm is ready for this nor I (we?) haven't fully explored yet what are the tradeoffs when interacting with JavaScript from Rust and in general what's the best way to do it.

casey commented 7 years ago

I think you're correct about the not-yet-ready part. I've only seen a few tiny examples of Rust / webasm FFI so far, which are mostly hand rolled.

One thing which would help enormously in this effort would be a central repository of WebIDL APIs. It seems that most WebIDL only exists in specs.

casey commented 7 years ago

Ooooo, jackpot! Looks like there is a directory full of WebIDL files for the browser APIs in the firefox source tree:

https://dxr.mozilla.org/mozilla-central/source/dom/webidl

I'm not sure if these are used directly, or are perhaps simply a reference.

ghost commented 7 years ago

Web DOM IDL files and support files copied from Blink : https://github.com/dart-lang/webcore

koute commented 7 years ago

Thanks for the links; it'll certainly come in handy once I get to it, although it'll probably take quite a while until I do. (Unless someone else would like to take a stab at this; I guess writing a parser in Rust for the .idl files would be a good first step [so we can generate whatever we need to generate from these in a build.rs].)

LegNeato commented 7 years ago

Servo does some webidl parsing and rust code gen:

https://github.com/servo/servo/tree/master/components/script/dom/bindings/codegen

Herschel commented 7 years ago

I've been playing with this a tiny bit. The webidl crate can successfully parse thorugh all of these IDLs from servo. The Mozilla and Chromium IDLs both use non-standard extensions to the grammar that webidl-rs doesn't support. I've got it parsing in a build.rs, but not really doing much code generation yet.

My first instinct is that generating these in a stdweb-sys submodule/crate is the way to go, as I expect we'll want to re-implement most of the APIs on top of the sys versions. For example, a lot of the JS 'enum'-ish APIs aren't listed as enums in the IDL, and we'd have to manually map these to a Rust enum type, unless we can put this info in the IDL in some way.

(I can't believe that W3C or WHATWG don't just provide a repo of standard IDLs somewhere?!)

Diggsey commented 6 years ago

I implemented a fairly powerful WebIDL => stdweb binding generator: https://github.com/brendanzab/gl-rs/pull/447

It is specifically for WebGL at the moment, although I don't imagine it would require too many changes to use with other APIs.

It is able to fully understand WebIDL types and map them onto the best rust interface, taking into account that parameters are typically passed by reference vs return values by move, and it's capable of remapping types, performing custom conversions for specific types, and annotating methods with generic parameters and constraints to allow for more usable APIs.

As an example, it can take these IDL definitions:

typedef unsigned long  GLuint;
typedef ([AllowShared] Float32Array or sequence<GLfloat>) Float32List;
...
void vertexAttrib4fv(GLuint index, Float32List values);

And convert them to this:

pub type GLuint = u32;
pub type Float32List = TypedArray<f32>;
...
pub fn vertex_attrib4fv<'a0, T0>(&self, index: u32, values: T0) where T0: AsTypedArray<'a0, f32> {
    js!( @{self}.vertexAttrib4fv(@{index}, @{unsafe { values.as_typed_array() }}); );
}
LegNeato commented 6 years ago

There is also https://github.com/kryptan/webinden by @kryptan

Boscop commented 6 years ago

@Diggsey Does this also work for callback based APIs like Geolocation? https://w3c.github.io/geolocation-api/#idl-index (I really want Geolocation in stdweb/yew..)

Btw, here is how the FFI for the Geolocation API is defined in PureScript: https://github.com/chexxor/purescript-dom-geolocation/blob/use-aff/src/DOM/HTML/Navigator/Geolocation.purs https://github.com/chexxor/purescript-dom-geolocation/blob/use-aff/src/DOM/HTML/Navigator/Geolocation.js

Diggsey commented 6 years ago

@Boscop not sure until you try it.

Boscop commented 6 years ago

@Diggsey Is your Web IDL bindings generator available in its own crate somewhere?

Diggsey commented 6 years ago

No, it's just everything in this module right now: https://github.com/brendanzab/gl-rs/tree/master/webgl_generator/webgl_registry