quickjs_runtime

quickjs_runtime is a library for quickly getting started with embedding a javascript engine in your rust project.

DISCLAIMER: This project is not yet what I would call "Battle Tested", use at your own risk.

quickjsruntime focuses purely on making quickjs easy to use and does not add any additional features, that's where these projects come in: * TypeScript support can be added by using typescriptutils * A more feature-rich (e.g. fetch api support, http based module loader and much more) runtime: GreenCopperRuntime. * The commandline client: GreenCopperCmd.

This project is inspired by the quickjs wrapper at theduke/quickjs-rs and still uses its low level bindings libquickjs-sys.

The big difference to quickjs-rs is that quickjs_runtime executes all quickjs related code in a dedicated single-threaded EventLoop.

Please see the DOCS for all inner workings

This lib serves two main goals:

1. Provide simple utils for working with quickjs (these are located in the quickjs_utils mod)

2. Wrap quickjs for use as a ready to go JavaScript Runtime

What works?

Script and Modules

Rust-Script interoperability

Future / Todo

goals

Same goals as https://github.com/HiRoFa/es_runtime but with using quickjs

so * slower js

but

For some of my projects those are a big plus!

examples

Here are some quickstarts:

Cargo.toml

toml [dependencies] hirofa_utils = "0.4" quickjs_runtime = "0.7" log = "0.4" simple-logging = "2.0"

```rust use crate::builder::QuickJsRuntimeBuilder; use crate::facades::QuickJsRuntimeFacade; use crate::quickjsrealmadapter::QuickJsRealmAdapter; use futures::executor::blockon; use hirofautils::jsutils::adapters::proxies::JsProxy; use hirofautils::jsutils::adapters::JsRealmAdapter; use hirofautils::jsutils::facades::values::{JsValueConvertable, JsValueFacade}; use hirofautils::jsutils::facades::{JsRuntimeBuilder, JsRuntimeFacade}; use hirofautils::js_utils::{JsError, Script}; use log::LevelFilter; use std::time::Duration;

#[test]
fn test_examples() {
    let rt = QuickJsRuntimeBuilder::new().js_build();
    let outcome = block_on(run_examples(&rt));
    if outcome.is_err() {
        log::error!("an error occured: {}", outcome.err().unwrap());
    }
    log::info!("done");
}

async fn take_long() -> i32 {
    std::thread::sleep(Duration::from_millis(500));
    537
}

async fn run_examples(rt: &QuickJsRuntimeFacade) -> Result<(), JsError> {
    // ensure console.log calls get outputted
    simple_logging::log_to_stderr(LevelFilter::Info);

    // do a simple eval on the main realm
    let eval_res = rt
        .js_eval(None, Script::new("simple_eval.js", "2*7;"))
        .await?;
    log::info!("simple eval:{}", eval_res.get_i32());

    // invoke a JS method from rust

    let meth_res = rt
        .js_function_invoke(None, &["Math"], "round", vec![12.321.to_js_value_facade()])
        .await?;
    log::info!("Math.round(12.321) = {}", meth_res.get_i32());

    // add a rust function to js as a callback

    let cb = JsValueFacade::new_callback(|args| {
        let a = args[0].get_i32();
        let b = args[1].get_i32();
        log::info!("rust cb was called with a:{} and b:{}", a, b);
        Ok(JsValueFacade::Null)
    });
    rt.js_function_invoke(
        None,
        &[],
        "setTimeout",
        vec![
            cb,
            10.to_js_value_facade(),
            12.to_js_value_facade(),
            13.to_js_value_facade(),
        ],
    )
    .await?;
    std::thread::sleep(Duration::from_millis(20));
    log::info!("rust cb should have been called by now");

    // create simple proxy class with an async function
    rt.js_loop_realm_sync(None, |_rt_adapter, realm_adapter| {
        let proxy = JsProxy::new(&["com", "mystuff"], "MyProxy").add_static_method(
            "doSomething",
            |_rt_adapter, realm_adapter: &QuickJsRealmAdapter, _args| {
                realm_adapter.js_promise_create_resolving_async(
                    async { Ok(take_long().await) },
                    |realm_adapter, producer_result| {
                        realm_adapter.js_i32_create(producer_result)
                    },
                )
            },
        );
        realm_adapter
            .js_proxy_install(proxy, true)
            .ok()
            .expect("could not install proxy");
    });

    rt.js_eval(
        None,
        Script::new(
            "testMyProxy.js",
            "async function a() {\
                        console.log('a called at %s ms', new Date().getTime());\
                        let res = await com.mystuff.MyProxy.doSomething();\
                        console.log('a got result %s at %s ms', res, new Date().getTime());\
                       }; a();",
        ),
    )
    .await?;
    std::thread::sleep(Duration::from_millis(600));
    log::info!("a should have been called by now");

    Ok(())
}

```