#emscripten #bindings #api-bindings

emscripten-functions

Rust-friendly bindings to various emscripten system functions

7 releases

0.2.5 Feb 1, 2025
0.2.4 Jan 25, 2025
0.2.3 Sep 26, 2024
0.2.2 Jul 15, 2024
0.1.0 Aug 26, 2023

#138 in WebAssembly

Download history 5/week @ 2024-10-30 9/week @ 2024-11-06 6/week @ 2024-11-13 32/week @ 2024-11-20 154/week @ 2024-11-27 18/week @ 2024-12-04 12/week @ 2024-12-11 21/week @ 2024-12-25 10/week @ 2025-01-08 110/week @ 2025-01-22 138/week @ 2025-01-29 33/week @ 2025-02-05

282 downloads per month
Used in emscripten-val

MIT license

2.5MB
9K SLoC

emscripten-functions

crates.io badge

This crate contains various emscripten system functions (made with rust-native parameter and return value types) that make programming in rust for emscripten targets easier. Functions based on ones from the following emscripten headers are available:

  • emscripten
  • console

Examples

For more examples and tips for emscripten in rust refer to my main project's README.

Run javascript from rust

Using the emscripten_functions::emscripten::run_script family of functions you can run the javascript you need in your web app.

Example

// The `.escape_unicode()` method makes it safe to pass untrusted user input.
run_script(
    format!(
        r##"
            document.querySelector("#this-is-secure").innerHTML = "{}"
        "##,
        "untrusted user input".escape_unicode()
    )
);

Calling JavaScript functions using the val API

Using the emscripten-val crate, you can make use of emscripten's val API to call JavaScript from the Rust side.

Example

Example taken from the emscripten-val README:

use emscripten_functions::emscripten::{run_script, run_script_int};
use emscripten_val::*;

fn main() {
    let a = Val::from_array(&[1, 2]);
    run_script(format!(
        r#"
        console.log(Emval.toValue({}));
    "#,
        a.as_handle() as i32
    ));

    a.call("push", argv![3]);
    run_script(format!(
        r#"
        console.log(Emval.toValue({}));
    "#,
        a.as_handle() as i32
    ));

    let handle = run_script_int("let n = new Number('123'); Emval.toHandle(n)");
    let number = Val::take_ownership(handle as EM_VAL);
    println!("{}", number.call("valueOf", &[]).as_i32());

    #[no_mangle]
    pub extern "C" fn event_handler(ev: EM_VAL) {
        let val = Val::take_ownership(ev);
        let target = val.get(&"target");
        target.set(&"textContent", &"Clicked");
    }

    let button = Val::take_ownership(run_script_int(
        r#"
        let button = document.createElement('BUTTON');
        button.addEventListener('click', (ev) => {
            _event_handler(Emval.toHandle(ev));
        });
        let body = document.getElementsByTagName('body')[0];
        body.appendChild(button);
        Emval.toHandle(button)
    "#,
    ) as EM_VAL);
    button.set(&"textContent", &"click");
}

Main loop control

If you need to run a loop function over and over, emscripten has its own main loop managing system. Using the emscripten_functions::emscripten::set_main_loop and emscripten_functions::emscripten::set_main_loop_with_arg functions you can run your rust functions as main loops, with full control over the main loop running parameters.

Example

struct GameData {
    level: u32,
    score: u32
}
let mut game_data = GameData {
    level: 1,
    score: 0
}

set_main_loop_with_arg(|data| {
    if data.score < data.level {
        data.score += 1;
    } else {
        data.score = 0;
        data.level += 1;
    }

    // Here you call your display to screen functions.
    // For demonstration purposes I chose `println!`.
    println!("Score {}, level {}", data.score, data.level);
}, game_data, 0, true);

An SDL game example

An SDL game example that has image handling can be found here.

Dependencies