Expand description

quickjs_runtime

This crate consists of two main parts:

  • thread-safe utils and wrappers you can call these from any thread, all logic is directed to a single worker-thread(EventLoop) which invokes the quickjs API
  • quickjs bindings and utils these talk to the quickjs API directly and need to run in the same thread as the Runtime

Noteworthy structs

These are the structs you’ll use the most

Thread safeAbstracted in hirofa_utils asRuntime Thread-localAbstracted in hirofa_utils as
QuickjsRuntimeFacade the ‘starting point’JsRuntimeFacadeQuickJsRuntimeAdapter the wrapper for all things quickjsJsRuntimeAdapter
--QuickJsRealmAdapter a realm or contextJsRealmAdapter
-JsValueFacade copy of- or reference to a value in the JsRuntimeAdapterJSValueRef reference counting pointer to a ValueJsValueAdapter

Doing something in the runtime worker thread

You always start with building a new QuickjsRuntimeFacade

use quickjs_runtime::builder::QuickJsRuntimeBuilder;
let rt: JsRuntimeFacade = QuickJsRuntimeBuilder::new().js_build();

JsRuntimeFacade has plenty public methods you can check out but one of the things you’ll need to understand is how to communicate with the JsRuntimeAdapter and the JsRealmAdapter This is done by adding a job to the EventLoop of the JsRuntimeFacade

// with the first Option you may specify which realm to use, None indicates the default or main realm
let res = rt.js_loop_realm(None, |rt: JsRuntimeAdapter, realm: JsRealmAdapter| {
   // this will run in the Worker thread, here we can use the Adapters
    
   return true;
}).await;

All the non-sync functions return a Future so you can .await them from async functions.

In order to do something and get the result synchronously you can use the sync variant

use quickjs_runtime::quickjsruntime::QuickJsRuntime;
let res = rt.js_loop_realm_sync(None, |rt, realm| {
   // this will run in the Worker thread, here we can use the quickjs API
   return 1;
});

One last thing you need to know is how to pass values from the js engine out of the worker thread

This is where the JsValueFacade comes in


// init a simple function
rt.js_eval(Script::new("init_func.js", "globalThis.myObj = {someMember: {someFunction: function(input){return(input + " > hello rust!");}}};")).await;

let input_facade = JsValueFacade::new_str("hello js!");
let res = rt.js_loop_realm(None, move |rt: JsRuntimeAdapter, realm: JsRealmAdapter| {
   // convert JsValueFacade to JsValueAdapter
   let input_adapter = realm.from_js_value_facade(input_facade);
   // call myObj.someMember.someFunction();
   let result_adapter = realm.js_function_invoke_by_name(&["myObj", "someMember"], "someFunction", &[input_adapter])?;
   // convert adapter to facade again so it may move out of the worker thread
   return realm.to_js_value_facade();
}).await;
assert_eq!(res.get_str(), "hello_js! > hello rust!");

For more details and examples please explore the packages below

Modules

contains the QuickJsRuntimeBuilder which may be used to instantiate a new QuickjsRuntimeFacade

contains the legacy EsValueFacade which will be deprecated in favour of utils::JsValueFacade in the near future

contains the QuickJsRuntimeFacade

contains engine features like console, setTimeout, setInterval and setImmediate

low level contains utils for calling the quickjs api

utils for implementing proxy classes which can be used to use rust structs from JS (define method/getters/setters/etc)

JSValueRef is a wrapper for quickjs’s JSValue. it provides automatic reference counting making it safer to use

Macros