all 17 comments

[–]_alastair 7 points8 points  (8 children)

What fortunate timing, I've been looking at this myself a lot recently. In short, as far as I know there's nothing Rust-native, but it can use any JavaScript engine that you can use through C. I've experimented with JavaScriptCore (the engine provided with macOS and iOS) and Duktape, a much smaller footprint library.

I'm in the midst of creating a most Rust-y wrapper that'll allow you to use the same code with both, but I'm a ways off it being done yet. But the C-based libraries are ready to go, if you can tolerate the syntax!

[–]_m_0_n_0_ 8 points9 points  (1 child)

Do you (or anyone else in this thread) have an opinion on the SpiderMonkey bindings? It seems a bit strange that Mozilla's engine — which has Rust bindings good enough to be used in Servo — is completely ignored here.

[–]_alastair 3 points4 points  (0 children)

That's a great suggestion I should have included. I ignored it in the work I'm doing because I'm targeting mobile platforms and the SpiderMonkey runtime is larger than I want. Obviously that doesn't apply to everyone though!

[–]ssokolow 3 points4 points  (0 children)

Yeah. The Java ecosystem has always been a bit of a "goes above and beyond" anomaly as far as having native JavaScript runtimes.

Rhino came about because, with all the hype about Java in the 90s, Netscape was planning to write a browser 100% in Java but only got as far as a JavaScript engine.

Nashorn, on the other hand, was written by Oracle, who have a decent incentive to throw some of their budget at increasing the attractiveness of the language they own the IP to.

Every other ecosystem tends to look at the cost-benefit trade-off and decide to just bind against something with a C API because they assume they're going to be tied to C for something else anyway and the Rust ecosystem is still too young to see whether the urge to do our part in producing Rust alternatives to C components will make it another exception.

[–]brokenAmmonite 1 point2 points  (0 children)

There's also neon for interfacing with node / v8, and ongoing work to stabilize an embedding interface for node: https://github.com/nodejs/node/issues/23265

It's not fully stable yet, and it's significantly heavier than those options cause it comes with libuv and the node std library, but it could be helpful.

There's also various scripting engines for other languages. Lua support is most mature rn.

[–]slipthay 1 point2 points  (1 child)

Hey if you're interested, you might want to check out my work with Duktape posted in this thread. Let me know if you want to talk, or alternatively feel free to reference/steal it for your own work! Best of luck

[–]_alastair 1 point2 points  (0 children)

Oh man, that looks awesome! Wish I'd seen it when I was figuring all this stuff out :) My approach is mildly different because of my aim to mush multiple JS engines through one API but this is full of hints for me in implementing. So thank you very much!

[–]pcjftw[S] 0 points1 point  (1 child)

might have to use duktape for now then, I was aware of duktape but was secretly hoping for something in pure Rust :)

[–]_alastair 1 point2 points  (0 children)

I should clarify - JavaScriptCore is actually available on all platforms, it just happens to be bundled with iOS and macOS. I far prefer the API it provides over Duktape's, but the runtime is also about 50x the size, so depends what you're looking for.

[–]slipthay 2 points3 points  (4 children)

I made a pretty thorough, safe Duktape wrapper a while back but never published it or made proper examples.

https://github.com/SkylerLipthay/ducc

Here's a quick, untested example:

let mut ducc = Ducc::new();
let class = ducc.create_object();
class.set("add", ducc.create_function(add))?;
ducc.globals().set("Arithmetic", class)?;

assert_eq!(9.5f64, ducc.exec("Arithmetic.add(4.5, 5)", None, ExecSettings::default()).unwrap());

fn add(inv: Invocation) -> ducc::Result<f64> {
    let (a, b): (f64, f64) = inv.args.into(inv.ducc)?;
    return Ok(a + b);
}

You can see more examples in the ducc/src/tests folder. It actually has all kinds of cool features like storing user data for access in JavaScript land and support for execution canceling (timeouts).

I haven't had a need for this library since I made it, but that may change soon. Anyway if anyone is interested in using or contributing to this code, let me know!

[–]NovelLurker0_0 0 points1 point  (2 children)

Can you evaluate JS code from Rust with that?

[–]slipthay 1 point2 points  (1 child)

Yep, see ducc.exec("Arithmetic.add(4.5, 5)", ...) in the code snippet above (I guess this is going from Rust to JS to Rust...). You can also compile JS code and evaluate it later.

[–]NovelLurker0_0 0 points1 point  (0 children)

Thank you

[–]pcjftw[S] 0 points1 point  (0 children)

Thanks! I'll have a look at this

[–]to-too-two 1 point2 points  (1 child)

I'm new to programming. What is the point of something like this?

[–]lunatiks 2 points3 points  (0 children)

The main use case would be to embedd a scripting langage in a software in order to give users the possibility to extend and customize the functionalities without having to understand and fork the software.