Giter VIP home page Giter VIP logo

spidermonkey_runtime's Introduction

This project is currently low on attention from me, i'm currently doing a lot of work for the quickjs based alternative which is a bit more practical for me because it's easier to compile on sbc's like the raspberry pi. I am however planning to get back to this when i feel quick_spidermonkey_runtime is where i want it to be..

spidermonkey_runtime

spidermonkey_runtime is a crate aimed at making it possible for rust developers to integrate the SpiderMonkey JavaScript engine in their rust projects without having specialized knowledge about the SpiderMonkey JavaScript engines.

Status

Nowhere near production ready, it is untested...

From 0.2.0 it works with the latest mozjs crate version 0.14.1 which uses SpiderMonkey version 88

0.1.0 and older worked with the mozjs 0.10.1 release. (mozjs does not publish new release any more because of a bug in cargo)

Please see the CHANGELOG for what's new.

Goals

Embedding a script engine in a rust project seems a very tedious job which involves learning a lot about the inner workings of that engine.

The main goal of this project is to make that job easy!

The manner in which this is achieved is primarily focused on abstracting the workings of the engine from the implementor, therefore some functionality may not be the fastest way of getting things done.

So a second goal is to make implementing a fast and efficient integration doable for the uninitiated, the most common tasks you do with the engine should be doable with the utils in this package and working examples should be provided in the test modules.

The reason I chose SpiderMonkey as the engine is that I've been dealing with less modern engines in my java projects and not being able to use the latest and greatest ECMA-script features becomes quite disappointing at times.

Examples

Cargo.toml

[dependencies]
# latest tag
spidermonkey_runtime = {git = "https://github.com/DRFos/spidermonkey_runtime", tag = "0.5.0"}
# or just get the latest
# spidermonkey_runtime = {git = "https://github.com/DRFos/spidermonkey_runtime"}

my_app.rs

#[test]
fn example() {
    // start a runtime

    let rt: EsRuntime = EsRuntimeWrapper::builder()
                // run the garbage collector every 5 secs
                .gc_interval(Duration::from_secs(5))
                .build();

    // create an example object

    rt.eval_sync("this.myObj = {a: 1, b: 2};", "test1.es")
        .ok()
        .unwrap();
    
    // add a rust function which will run async and thus return a promise in script
    // you can also run your function sync by using add_global_sync_function instead
    let func = |args: Vec<EsValueFacade>| {
        // do something here, and then return a value as a EsValueFacade
        Ok(EsValueFacade::new_i32(1268))
    };
    rt.add_global_async_function("myFunc", func);
    
    // we can then use the function in script
    rt.eval_sync("let prom = myFunc(1, 2, 3);\
                  prom.then((res) => {console.log('myFunc resolved to %s', res);});", 
                 "test1.es")
                 .ok()
                 .unwrap();

}

For a more detailed getting started you should see the examples in the DOCS

0.1 Goals

  • Get a grip on when to use rooted values (Handle) and when to use Values (JSVal)
  • Easy loading script files
  • Error handling (get ES errors in rust with filename/linenumber etc)
  • Adding rust function to the engine, so they are callable from ECMA-Script
    • Blocking
    • Non-blocking (returns a Promise in script)
  • Easy way to call ECMA-Script functions from rust
    • By name (run_global_function())
    • By object name and name (myObj.doSomething())
    • Passing params from rust
  • Getting data from the engine as primitives or Vecs and Maps
    • Primitives
    • Objects from and to Maps
    • Arrays as Vecs
  • A working console (logging)
  • Working Promises in Script
  • Waiting for Promises from rust
  • import/export statement support
    • cache modules
  • No more memory leaks

0.2 goals

  • Use newer mozjs
  • Re-enable possibility to create multiple runtimes
  • Init a EsValueFacade as a promise from rust, #19
  • More tests for e.g. error handling in module loading, error handling in promises

0.3 goals

  • Run rust-ops multithreaded, and return Promises from rust #8
  • Pass functions as consumer argument to rust-ops
  • Proxy class for rust objects

0.4 goals

  • EsProxy (easy to use proxy class using EsValueFacade instead of JSAPI)
  • Simpler method invocation (deprecate invoke_rust_op)
  • Fix inline docs

0.5 goals

  • Dynamic imports #4

0.6 goals

  • Import native features API
 import {http} from 'esses.com.http';
 http.doSomething();
 // and
 import('esses.com.http').then((http) => {
    http.doSomething();
 });
  • TypedArrays from and to Vecs
  • EsValueFacade rewrite for easier type support

0.7 goals

  • fetch API (interface only, resolution is up to impl)
  • WebAssembly

0.8 goals

  • Fix module caching, or check that the current impl actually works
  • WebWorker API (interface only, execution is up to impl)

0.9 goals

  • Code pre-processing
    • enable stuff like
      • macro's
      • transpilers (like typescript)
      • conditional statements (e.g. logging based on loglevel)

0.10 goals

  • use macro's to define proxies and functions

1.0 goals

  • No more segfaults in unit test with gc_zeal_options

goals for later

  • Interactive Debugging
  • Profiling
  • Use PersistentRooted instead of deprecated Add*Root and Remove*Root
  • Much more

Other plans

I'm also working on a more feature rich runtime with a commandline tool, and an application server based on this runtime.

These are in a very early testing stage and may become available later as a separate project.

A word on compiling

Currently, I have only compiled this on and for a 64 bit linux machine (I use openSUSE).

Besides rust, you'll need to install the following packages to compile the mozjs crate.

  • from 0.0.1
    • gcc-7
    • autoconf2.13
    • automake
    • clang
    • python
    • llvm (mozjs_sys needs llvm-objdump)
  • on openSUSE i also need
    • python-xml
    • gcc-c

for more detailed info please visit https://github.com/servo/mozjs#building

spidermonkey_runtime's People

Contributors

actions-user avatar andrieshiemstra avatar sagudev avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

spidermonkey_runtime's Issues

Extend Github Actions

Now, as the base work is done, you can additional functionality to GitHub actions, here is list of my favorite:

  • Automatic format
  • Docs generation and publishing it to GitHub pages
  • Annotations (clippy lints)
  • Add cache to speed up rebuilding process

I have implemented them here, so just say which functionality do you want and I will make PR.

IDEA: Is api really easy?

If I understand correctly you call rust function from JS like:
esses.invoke_rust_op_sync("print", "this will be printed")
is it possible to invoke it like:
print("this will be printed")

Writing rust functions for JS is still pretty hard (not hard as writing it directly for mozjs):

fn reg_op(rt: &EsRuntimeWrapper) {
    rt.register_op(
        "my_rusty_op",
        Arc::new(|_rt, args: Vec<EsValueFacade>| {
            let a = args.get(0).unwrap().get_i32();
            let b = args.get(1).unwrap().get_i32();
            Ok(EsValueFacade::new_i32(a * b))
        }),
    );
}

My idea is that adding rusty code to JS should be as close as writing normal rust code and than just telling es_runtime to use that function (preferably even without special types, using Rusts types).

moduleloading, add metadata / support relative paths

https://doc.servo.org/mozjs/jsapi/fn.SetModuleMetadataHook.html
setmoduleprivate , this adds a private obj to the module?
this is populated by populateImportMeta? set url

we want this so we can alter the moduleLoader to also have a url which imports the new module so we can support relative paths

url should allways be full path so loading /mod,mes from one module or the other can load a different module entirely, caching should be done by full path

Proxy update: Results

refactor methods, getter, setters to return a Result<JSVal, String> so we can throw errors from Proxy classes

Storing EsValueFacade from function call

Hi, first of all thanks for this nice simplification of the Spider Monkey interface.

Now I'm rather new to Rust and this library and I wanted to add a global function to "register" functions. These functions are saved in a map and called later. My code looks like this:

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

let mut map = HashMap::new();

rt.add_global_sync_function("test", |args| {
  map.insert(args[0].get_string(), &args[1]);
  Ok(EsValueFacade::undefined())
});

This won't compile (Error message: (dyn es_runtime::esvaluefacade::EsValueConvertible + std::marker::Send + 'static) cannot be shared between threads safely).

I don't expect it to work like this but this was my only approach. I'd guess doing it like this will conflict with the GC as it doesn't know whether the arguments are still used.

Now my question is: Is there a proper way of saving a EsValueFacade in a map and being able to use it later which won't conflict with the GC and the Rust compiler?

impl es_utils::report_error

currently there is a lot of error reporting done with the JSAPI method like so

unsafe {
    JS_ReportErrorASCII(cx, b"poof\0".as_ptr() as *const libc::c_char);
}

we need a pub fn report_error(err: &str); in es_utils.rs which does the above so the occurances in

  • the rest of the code may be replaced with this:
es_utils::report_error(cx, "poof");
  • the util should look something like this
// in es_utils.rs
pub fn report_error(cx: 8mut JSContext, err: &str) {
    let err_string = format!(b"{}\0", err);
    unsafe {
        JS_ReportErrorASCII(cx, err_string.as_str().as_ptr() as *const libc::c_char);
    }
}
  • There is also a JS_ReportErrorUTF8 we may want to figure out if and when we need that

  • the current report_es_ex() in es_utils.rs should be renamed to ```fetch_pending_exception()

import native features

implement an API to add features (objects) based on import events rather than just code

this is a modification to the current code loader which can return either code or an object (or null when a feature is installed by impl)

Question@sagu about clippy config

the clippy workflow started giving errors about a 404 @

##[error]An action could not be found at the URI 'https://api.github.com/repos/actions-rs/clippy-check/tarball/annotations-fallback'

i updated this to v1 in cc59e11

it works now but the actions takes only 7m instead of the usual 12-14 minutes

i can only find examples about the v1 variant so my question is what is the annotations-fallback variant and should this still work or is my modification to v1 ok?

Finish inline documentation

  • for at least
    • EsValueFacade
    • EsProxy
    • Proxy
    • EsRuntime(Builder)
    • SmRuntime
  • later
    • jsapi_utils.rs
    • arrays.rs
    • functions.rs
    • modules.rs
    • objects.rs
    • promises.rs
    • rooting.rs

TypedArrays and EsValueFacade revamp

  • typedArrays from and to Vecs

  • EsValueFacade should get a TYPE enum and store it's value in a Any instead of the current ever growing if else if statements

  • or something like a JSValCovertable for each type

  • rewrite prmise stuff so we don't need es files anymore
  • rewrite EsValueFacade
  • add typedarrays stuff for EsValueFacade

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.