Crate quickjs_runtime

source ·
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 safe (Facades)Runtime Thread-local (Adapters)
QuickJsRuntimeFacade the ‘starting point’QuickJsRuntimeAdapter the wrapper for all things quickjs
-QuickJsRealmAdapter a realm or context
JsValueFacade copy of- or reference to a value in the JsRuntimeAdapterQuickJsValueAdapter reference counting pointer to a Value

§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();

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

// with the first Option you may specify which realm to use, None indicates the default or main realm
let res = rt.loop_realm(None, |rt: QuickJsRuntimeAdapter, realm: QuickJsRealmAdapter| {
   // this will run in the Worker thread, here we can use the Adapters
   // since we passed None as realm the realm adapter will be the "main" realm
   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.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.eval(Script::new("init_func.js", "globalThis.myObj = {someMember: {someFunction: function(input){return(input + " > hello rust!");}}};")).await;

// create an input variable by using one of the constructor methods of the JsValueFacade
let input_facade = JsValueFacade::new_str("hello js!");
// move it into a closure which will run in the worker thread
let res = rt.loop_realm(None, move |rt: JsRuntimeAdapter, realm: JsRealmAdapter| {
   // convert the input JsValueFacade to JsValueAdapter
   let input_adapter = realm.from_js_value_facade(input_facade)?;
   // call myObj.someMember.someFunction();
   let result_adapter = realm.invoke_function_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(&result_adapter);
}).await;
assert_eq!(res.get_str(), "hello_js! > hello rust!");

For more details and examples please explore the packages below

Re-exports§

Modules§

  • contains the QuickJsRuntimeBuilder which may be used to instantiate a new QuickjsRuntimeFacade
  • contains the QuickJsRuntimeFacade
  • contains engine features like console, setTimeout, setInterval and setImmediate
  • This contains abstract traits and structs for use with different javascript runtimes the Adapter traits are use in the worker thread (EventLoop) of the Runtime and thus are not Send, they should never leave the thread The facade classes are for use outside the worker thread, they are Send
  • low level contains utils for calling the quickjs api
  • JSValueRef is a wrapper for quickjs’s JSValue. it provides automatic reference counting making it safer to use
  • utils for implementing proxy classes which can be used to use rust structs from JS (define method/getters/setters/etc)