# #2 Daily Rabbit Holes: Diving Deeper into Rust, V8, and the JavaScript™️ Saga

Unfortunately, today I had very little time to dive into interesting topics. I spent some time on a side project (which I’ll probably write about in the coming days), worked on my day job, and did some sports. Still, my focus remains on **Deno**, **Rust**, and the **V8 engine**, just like in my [previous article](https://pul.hashnode.dev/1-daily-rabbit-holes-rusty-v8-nodejs-and-deno).

I managed to review the [fantastic article](https://dzx.cz/2023-03-08/how_do_cloudflare_workers_work/) by [Matouš Dzivjak](https://dzx.cz/about/), where he explains how to build a runtime using **Rust V8**.

The code from the article is a bit outdated and doesn’t run with the current version of Rust. I managed to get it working somehow, even though I don’t actually know Rust yet (so it’s either an easy task or I just got really lucky).

Below is the updated code with minor tweaks and some comments to help with understanding. All credits, of course, go to Matouš.

### Quick Breakdown

This code demonstrates how to build a **minimal JavaScript runtime using Rust** and the **V8 engine**:

* **Platform and V8 Initialization:** The [main.rs](http://main.rs) file initializes the V8 engine and platform, preparing it to execute JavaScript code.
    
* **Runtime Setup:** A global object (*globalThis.workerHandler*) is exposed in the runtime using JavaScript, enabling a Rust function to be callable from JavaScript.
    
* **Script Compilation:** The build\_worker function compiles and evaluates the JavaScript code, combining the *runtime script* and a *worker\_script* that defines a handler function.
    
* **Global Context Binding:** Rust functions, such as *sayHello*, are exposed to the V8 runtime by binding them to global object properties.
    
* **Function Execution:** The run\_worker function calls the JavaScript handler function from Rust, passing parameters and printing the result (Hello World) to the console.
    

```javascript
// runtime.js
globalThis.workerHandler = (x) => { 
  return handler(x);
}
```

```rust
// main.rs
use v8;

fn main() {
    // Platform and V8 initialization
    let platform = v8::Platform::new(0, false).make_shared();
    v8::V8::initialize_platform(platform);
    v8::V8::initialize();
    // `include_str!` is a Rust macro that loads a file and converts it into a Rust string
    let runtime = include_str!("runtime.js");

    let worker_script = r#"
    export function handler(y) {
        return sayHello(y);
    };
    "#;
    // The runtime.js file exposes the `handler` function as a global object
    let script = format!(
        r#"
        {runtime}
        {worker_script}
        "#
    );

    {
        // Create a V8 isolate with default parameters
        let mut isolate = v8::Isolate::new(v8::CreateParams::default());
        let global = setup_runtime(&mut isolate);
        let worker_scope = &mut v8::HandleScope::with_context(isolate.as_mut(), global.clone());
        let handler = build_worker(script.as_str(), worker_scope, &global);
        run_worker(handler, worker_scope, &global);
    }

    unsafe {
        v8::V8::dispose();
    }
    v8::V8::dispose_platform();
}
// Set up the global runtime context
fn setup_runtime(isolate: &mut v8::OwnedIsolate) -> v8::Global<v8::Context> {
    // Create a handle scope for all isolate handles    
    let isolate_scope = &mut v8::HandleScope::new(isolate);
    // ObjectTemplate is used to create objects inside the isolate
    let globals = v8::ObjectTemplate::new(isolate_scope);
    // The function name to bind to the Rust implementation
    let resource_name = v8::String::new(isolate_scope, "sayHello").unwrap().into();
    // Expose the function to the global object
    globals.set(
        resource_name,
        v8::FunctionTemplate::new(isolate_scope, say_hello_binding).into()
    );
    // Create a context for isolate execution
    let context_options = v8::ContextOptions {
        global_template: Some(globals),
        ..Default::default()
    };
    let global_context = v8::Context::new(isolate_scope, context_options);
    // Create and return the global context
    v8::Global::new(isolate_scope, global_context)
}
// Define the Rust binding for the sayHello function
pub fn say_hello_binding(
    scope: &mut v8::HandleScope,
    args: v8::FunctionCallbackArguments,
    mut retval: v8::ReturnValue,
) {
    let to = args.get(0).to_rust_string_lossy(scope);
    let hello = v8::String::new(scope, format!("Hello {}", to).as_str())
    .unwrap().into();
    retval.set(hello);
}
// Build the worker by compiling and instantiating the script
fn build_worker(
    script: &str,
    worker_scope: &mut v8::HandleScope,
    global: &v8::Global<v8::Context>,
) -> v8::Global<v8::Function> {
    let code = v8::String::new(worker_scope, script).unwrap();
    let resource_name = v8::String::new(worker_scope, "script.js").unwrap().into();
    // The source map is optional and used for debugging purposes
    let source_map_url: Option<v8::Local<'_, v8::Value>> = Some(v8::String::new(worker_scope, "placeholder").unwrap().into());
    let mut source = v8::script_compiler::Source::new(
        code,
        Some(&v8::ScriptOrigin::new(
            worker_scope,
            resource_name,
            0,
            0,
            false,
            i32::from(0),
            source_map_url,
            false,
            false,
            true,
            None
        )),
    );
    // Compile and evaluate the module
    let module = v8::script_compiler::compile_module(worker_scope, &mut source).unwrap();
    let _ = module.instantiate_module(worker_scope, |_, _, _, _| None);
    let _ = module.evaluate(worker_scope);
    // open a global scope associated to the worker_scope
    let global = global.open(worker_scope);
    // create and assign the handler to the global context
    let global = global.global(worker_scope);
    let handler_key = v8::String::new(worker_scope, "workerHandler").unwrap();
    let js_handler = global.get(worker_scope, handler_key.into()).unwrap();    
    let local_handler = v8::Local::<v8::Function>::try_from(js_handler).unwrap();
    v8::Global::new(worker_scope, local_handler)
}

// Run the worker and execute the `handler` function
pub fn run_worker(
    worker: v8::Global<v8::Function>,
    scope: &mut v8::HandleScope,
    global: &v8::Global<v8::Context>,
) {
    let handler = worker.open(scope);
    let global = global.open(scope);
    let global = global.global(scope);

    let param = v8::String::new(scope, "World").unwrap().into();
    // call the handler and get the result
    match handler.call(scope, global.into(), &[param]) {
        Some(response) => {
            let result = v8::Local::<v8::String>::try_from(response)
                .expect("Handler did not return a string");
            let result = result.to_string(scope).unwrap();
            println!("{}", result.to_rust_string_lossy(scope));
        }
        None => todo!(),
    };
}
```

I strongly encourage you to read Matouš Dzivjak’s excellent article for a deeper dive into the code and its concepts. This was just a summary—his detailed explanations are essential for understanding the technical nuances!

## JavaScript Petition!

By the way, I had completely forgotten that Oracle owns the **JavaScript** trademark—something I already knew but slipped my mind. This week, Deno’s petition to cancel the trademark served as a reminder of this curious fact.

If you're interested in learning more, check out:

* [https://javascript.tm/](https://javascript.tm/)
    
* [https://deno.com/blog/deno-v-oracle](https://deno.com/blog/deno-v-oracle)
