3 unstable releases

0.1.0 Apr 28, 2023
0.0.3 Sep 24, 2022
0.0.2 Sep 2, 2022

#5 in #javascriptcore

Download history 1410/week @ 2023-12-18 280/week @ 2023-12-25 1009/week @ 2024-01-01 1405/week @ 2024-01-08 569/week @ 2024-01-15 1024/week @ 2024-01-22 1186/week @ 2024-01-29 685/week @ 2024-02-05 626/week @ 2024-02-12 1326/week @ 2024-02-19 1063/week @ 2024-02-26 800/week @ 2024-03-04 1094/week @ 2024-03-11 1246/week @ 2024-03-18 607/week @ 2024-03-25 1078/week @ 2024-04-01

4,075 downloads per month
Used in 4 crates (via rusty_jsc)

MIT license

5KB
76 lines

JavaScriptCore API for Rust

crates docs

This library provides a Rust API for the JavaScriptCore engine with the following goals:

  • High-level API like the JavaScriptCore API for Swift
  • Wrap the low-level C++ API instead of jsc to avoid the dependency to GTK.

Getting Started

Implementing a JavaScript runtime

Please check out PunJS for an example of how to implement a JavaScript runtime with rusty_jsc.

Evaluating a JavaScript script

use rusty_jsc::{JSContext};

fn main() {
    let mut context = JSContext::default();
    match context.evaluate_script("'Hello World!'", 1) {
        Ok(value) => {
            println!("{}", value.to_string(&context).unwrap());
        }
        Err(e) => {
            println!("Uncaught: {}", e.to_string(&context).unwrap())
        }
    }
}

Callbacks from JavaScript to Rust

use rusty_jsc::{JSContext, JSValue};
use rusty_jsc_macros::callback;

#[callback]
fn greet(
    ctx: JSContext,
    function: JSObject,
    this: JSObject,
    args: &[JSValue],
) -> Result<JSValue, JSValue> {
    Ok(JSValue::string(&ctx, format!("Hello, {}", args[0].to_string(&ctx).unwrap())))
}

fn main() {
    let mut context = JSContext::default();
    let callback = JSValue::callback(&context, Some(greet));
    let global = context.get_global_object();
    global.set_property(&context, "greet", callback).unwrap();

    match context.evaluate_script("greet('Tom')", 1) {
        Ok(value) => {
            println!("{}", value.to_string(&context).unwrap());
        }
        Err(e) => {
            println!("Uncaught: {}", e.to_string(&context).unwrap())
        }
    }
}

Passing functions to a callback

use rusty_jsc::{JSContext, JSObject, JSValue, JSString};
use rusty_jsc_macros::callback;

#[callback]
fn greet(
    ctx: JSContext,
    function: JSObject,
    this: JSObject,
    args: &[JSValue],
) -> Result<JSValue, JSValue> {
    // Parse the argument as a function and call it with an argument
    let callback_function = args[0].to_object(&ctx).unwrap().call(&ctx, None, &[JSValue::string(&ctx, "Tom")]).unwrap();
    Ok(callback_function)
}

fn main() {
    let mut context = JSContext::default();
    let callback = JSValue::callback(&context, Some(greet));
    let global = context.get_global_object();
    global.set_property(&context, "greet", callback).unwrap();

    match context.evaluate_script("greet((name) => 'Hello, ' + name)", 1) {
        Ok(value) => {
            println!("{}", value.to_string(&context).unwrap());
        }
        Err(e) => {
            println!("Uncaught: {}", e.to_string(&context).unwrap())
        }
    }
}

FAQ

What about the other JavaScriptCore bindings for Rust?

The wrappers in rusty_jsc are built against <JavaScriptCore/JavaScript.h> header rather than the jsc variant that requires GTK.

Why JavaScriptCore when there's already rusty_v8?

Bun has shown that JavaScriptCore is a worthy contender to V8 on the server-side, so let's bring it over to the Rust ecosystem as well.

How were the C++ low-level bindings generated?

I first used bindgen to do the rough conversion of JavaScript/JavaScript.h header and then cleaned it up by hand. The plan is to maintain the low-level bindings by hand.

Dependencies

~1.5MB
~33K SLoC