quickjs_runtime

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

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

quickjs_runtime focuses purely on making quickjs easy to use and does not add anny additional features, that where these projects come in: * A more feature-rich runtime can be found in ESsesLib-q. * There is also a commandline client: ESsesCmd-q. * And last but not least there is GreenCopper which aspires to be a full fledged application platform: Green-Copper-q.

This project is heavily inspired by the awesome 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 EventQueue.

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

see the DOCS for all inner working but here are some quickstarts:

Cargo.toml

toml [dependencies] quickjs_runtime = "0.1.0" log = "0.4.11" simple-logging = "2.0.2"

main.rs

```rust

use quickjsruntime::esruntimebuilder::EsRuntimeBuilder; use quickjsruntime::esscript::EsScript; use quickjs_runtime::esvalue::EsValueFacade;

fn loadmodule(base: &str, name: &str) -> Option { // you should load your modules from files here // please note that you need to return the name as absolutepath in the returned script struct // return None if module is not found Some(EsScript::new(name, "export const foo = 12;")) }

fn main() { simplelogging::logto_stderr(LevelFilter::Info);

let rt = EsRuntimeBuilder::new()
    .module_script_loader(load_module)
    .build();

// eval some basic stuff

rt.eval_sync(EsScript::new(
    "basics.es",
    "this.my_app_utils = {f: function(a, b){return a * b;}, f2: function(rf){rf(12);}};",
))
.ok()
.expect("basics.es failed");

} ```

invoke a js method from rust

rust let a = 8.to_es_value_facade(); let b = 7.to_es_value_facade(); let res = rt.call_function_sync(vec!["my_app_utils"], "f", vec![a, b]); match res { Ok(val) => log::info!("8*7 in JavaScript = {}", val.get_i32()), Err(e) => println!("script failed: {}", e), }

add a function from rust and invoke it

```rust rt.setfunction(vec!["nl", "my", "utils"], "methodA", |args| { if args.len() != 2 || !args.get(0).unwrap().isi32() || !args.get(1).unwrap().isi32() { Err(EsError::newstr( "i'd really like 2 args of the int32 kind please", )) } else { let a = args.get(0).unwrap().geti32(); let b = args.get(1).unwrap().geti32(); log::info!("rust is multiplying {} and {}", a, b); Ok((a * b).toesvaluefacade()) } }) .ok() .expect("setfunction failed");

let method_a_res = rt.eval_sync(EsScript::new(
    "test_func.es",
    "(nl.my.utils.methodA(13, 56));",
));

match method_a_res {
    Ok(val) => {
        assert_eq!(val.get_i32(), 13 * 56);
    }
    Err(e) => {
        panic!("test_func.es failed: {}", e);
    }
}

```

eval a module

rust rt.eval_module_sync(EsScript::new( "my_app.mes", "\ import {foo} from 'example.mes';\ console.log('static foo is ' + foo);\ ", )) .ok() .expect("module failed");

eval a module with a dynamic import

```rust

rt.eval_module_sync(EsScript::new(
    "my_app2.es",
    "\
import('example.mes')\
.then((example_module) => {\
    console.log('dynamic foo is ' + example_module.foo);\
});\
",
))
.ok()
.expect("script failed");

```

get a function from js and invoke it in rust

```rust rt.setfunction(vec!["nl", "my", "utils"], "methodB", |mut args| { if args.len() != 1 || !args.get(0).unwrap().isfunction() { Err(EsError::newstr( "i'd really like 1 arg of the function kind please", )) } else { let consumerfunc = args.remove(0);

        // invoke the func async, just because we can
        std::thread::spawn(move || {
            let a = 19.to_es_value_facade();
            let b = 17.to_es_value_facade();
            consumer_func
                .invoke_function(vec![a, b])
                .ok()
                .expect("func failed");
        });

        Ok(quickjs_es_runtime::esvalue::EsNullValue {}.to_es_value_facade())
    }
})
.ok()
.expect("set_function failed");

rt.eval_sync(EsScript::new(
    "test_func2.es",
    "(nl.my.utils.methodB(function(a, b){console.log('consumer was called with ' +a + ', ' + b);}));",
)).ok().expect("test_func2.es failed");

// wait a sec for the async onvoker to run
std::thread::sleep(Duration::from_secs(1));

```