js_ffi
toml
[dependencies]
js_ffi = "0.0.6"
A simple FFI library for calling javascript from web assembly with Rust
* #![nostd] + alloc for uber small wasm ( unfortunately async-await does't work with no std yet)
* low magic
* minimal
* no macros
* ready for web references
* compatible with async-await
* works with web assembly languages other than Rust
Simple Example
```rust
use js_ffi::*;
use executor::Executor;
const FUNCTIONLOG: i32 = 0;
const FUNCTION SETTIMEOUT: i32 = 1;
const FUNCTION ALERT: i32 = 2;
[no_mangle]
pub fn main() -> () {
register(FUNCTIONLOG,"console.log");
register(FUNCTION SETTIMEOUT,"window.setTimeout");
register(FUNCTION ALERT,"window.alert");
Executor::spawn(async {
consolelog("hey");
window settimeout(1000).await;
window alert("you");
});
}
pub fn consolelog(msg: &str) {
call 1(UNDEFINED, FUNCTIONLOG, TYPE STRING, to_string(msg));
}
pub fn windowalert(msg: &str) {
call 1(UNDEFINED, FUNCTIONALERT, TYPE STRING, to_string(msg));
}
pub fn windowset timeout(millis: i32) -> CallbackFuture {
let (future, id) = CallbackFuture::create();
jscall 2(
UNDEFINED,
FUNCTIONSET TIMEOUT,
TYPEFUNCTION,
id,
TYPE NUM,
millis as f32,
);
future
}
```
```html
```
## How it works
The basic premise is that you `register` the JavaScript functions you want to have access to from Rust to a constant number function handle. Then you can use `call_*` to send execute the function with arguments depending on the argument count you want to send (e.g. `call_1`, `call_7`). The idea is you can quickly create wrapper functions for exactly what you need. When calling the function you specify the object to call the function of (or undefined if you just want to call the function), the function id to call you registered with, and pairs of argument type and arguments afer.
`call_*(,,,,,,...)`
## Advanced
Wrap third party. Anything with its functions in global space should be able to be wrapped and invoked.
```rust
const FUNCTION_JQUERY: i32 = 0;
const FUNCTION_JQUERY_ON: i32 = 1;
const FUNCTION_SAY_LOUD: i32 = 2;
const FUNCTION_SAY_QUEIT: i32 = 3;
fn main() {
// register functions of things in global scope
register(FUNCTION_JQUERY,"$");
// someimes functions are hidden on prototypes of things in global scope
register(FUNCTION_JQUERY_ON,"jQuery.prototype.on");
// reference your own functions created in global scope
register(FUNCTION_SAY_LOUD,"say_loud");
// create evaluated functions on the fly
register(FUNCTION_SAY_QUEIT,"(x) => console.log(x)");
call_1(UNDEFINED,FUNCTION_SAY_QUEIT,TYPE_STRING,to_string("adding event handler"));
let obj = call_1(UNDEFINED,FUNCTION_JQUERY,TYPE_STRING,to_string("body"));
call_2(obj,
FUNCTION_JQUERY_ON,
TYPE_STRING,
to_string("click"),
FUNCTION,
create_callback(Box::new(||{
call_1(UNDEFINED,
FUNCTION_SAY_LOUD,
TYPE_STRING,
to_string("I was clicked!"));
}));
}
```
```html
```
Don't like Rust?
The script js_ffi.js
has nothing Rust specific. Everything is only done through methods
jsfficall0(f32,i32)
jsfficall1(f32,i32,i32,f32)
jsfficall2(f32,i32,i32,f32,i32,f32)
...
jsfficall10(f32,i32,i32,f32,i32,f32,i32,f32,i32,f32,i32,f32,i32,f32,i32,f32,i32,f32,i32,f32,i32,f32)
jsffiregister(i32,i32)
And one callback:
And an entry point function:
As long as your module adheres to this you can use js_ffi. Strings are simply cstrings that end in a 0
character.
License
This project is licensed under either of
Apache License, Version 2.0, (LICENSE-APACHE or
http://www.apache.org/licenses/LICENSE-2.0)
MIT license (LICENSE-MIT or
http://opensource.org/licenses/MIT)
at your option.
Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in woke by you, as defined in the Apache-2.0 license, shall be
dual licensed as above, without any additional terms or conditions.