Convert Figma logo to code with AI

denoland logorusty_v8

Rust bindings for the V8 JavaScript engine

3,455
320
3,455
73

Top Related Projects

23,704

The official mirror of the V8 Git repository

28,719

Servo, the embeddable, independent, memory-safe, modular, parallel web rendering engine

42,295

The C based gRPC (C++, Python, Ruby, Objective-C, PHP, C#)

108,341

Node.js JavaScript runtime ✨🐢🚀✨

15,716

A lightweight WebAssembly runtime that is fast, secure, and standards-compliant

43,547

The zero configuration build tool for the web. 📦🚀

Quick Overview

The denoland/rusty_v8 repository is a Rust binding for the V8 JavaScript engine, which is the core of the Deno runtime. This project allows developers to embed the V8 engine into their Rust applications, enabling them to execute and interact with JavaScript code from within their Rust programs.

Pros

  • High Performance: The V8 engine is known for its high-performance JavaScript execution, which is inherited by the Rust binding.
  • Extensive Functionality: The V8 engine provides a wide range of features and functionality, which are accessible through the Rust binding.
  • Interoperability: The Rust binding allows for seamless integration between Rust and JavaScript, enabling developers to leverage the strengths of both languages.
  • Active Development: The denoland/rusty_v8 project is actively maintained and developed, with regular updates and improvements.

Cons

  • Complexity: Integrating the V8 engine into a Rust application can be a complex task, requiring a deep understanding of both Rust and the V8 engine.
  • Dependency Management: The denoland/rusty_v8 project has a significant number of dependencies, which can make it challenging to manage and update.
  • Compatibility: The Rust binding may not always be compatible with the latest version of the V8 engine, which can lead to compatibility issues.
  • Learning Curve: Developers new to Rust or the V8 engine may face a steeper learning curve when working with the denoland/rusty_v8 project.

Code Examples

Here are a few code examples demonstrating the usage of the denoland/rusty_v8 project:

  1. Executing JavaScript Code:
use rusty_v8::{Context, Isolate, JsString, JsValue};

fn main() {
    let mut isolate = Isolate::new(Default::default());
    let context = Context::new(&mut isolate);

    let result: JsValue = context.eval("2 + 2", "").unwrap();
    let value: i64 = result.into_smi().unwrap();
    println!("Result: {}", value); // Output: Result: 4
}
  1. Calling Rust Functions from JavaScript:
use rusty_v8::{Context, Isolate, JsFunction, JsString, JsValue};

fn add(mut ctx: rusty_v8::FunctionContext) -> rusty_v8::JsResult<rusty_v8::JsValue> {
    let a: i64 = ctx.get::<_, JsValue>(0)?.into_smi()?;
    let b: i64 = ctx.get::<_, JsValue>(1)?.into_smi()?;
    Ok(JsValue::from_smi(a + b))
}

fn main() {
    let mut isolate = Isolate::new(Default::default());
    let context = Context::new(&mut isolate);

    let add_function = JsFunction::new(&mut context, add).unwrap();
    let result: JsValue = add_function.call(&mut context, &[2.into(), 3.into()]).unwrap();
    let value: i64 = result.into_smi().unwrap();
    println!("Result: {}", value); // Output: Result: 5
}
  1. Accessing JavaScript Objects:
use rusty_v8::{Context, Isolate, JsObject, JsString, JsValue};

fn main() {
    let mut isolate = Isolate::new(Default::default());
    let context = Context::new(&mut isolate);

    let obj: JsObject = JsObject::new(&mut context);
    obj.set(&mut context, "name", JsString::new(&mut context, "John").unwrap()).unwrap();
    obj.set(&mut context, "age", JsValue::from_smi(30)).unwrap();

    let name: JsString = obj.get(&mut context, "name").unwrap().into();
    let age: i64 = obj

Competitor Comparisons

23,704

The official mirror of the V8 Git repository

Pros of v8/v8

  • Mature and widely-used JavaScript engine, with a large and active community
  • Extensive documentation and resources available for developers
  • Supports a wide range of platforms and architectures

Cons of v8/v8

  • Larger codebase and more complex to build and maintain
  • May have higher resource requirements compared to Rusty_V8
  • Potentially less flexible for specific use cases or integration with Rust-based projects

Code Comparison

v8/v8:

v8::Isolate::CreateParams create_params;
create_params.array_buffer_allocator =
    v8::ArrayBuffer::Allocator::NewDefaultAllocator();
v8::Isolate* isolate = v8::Isolate::New(create_params);

denoland/rusty_v8:

let isolate = Isolate::new(IsolateOptions::default());
28,719

Servo, the embeddable, independent, memory-safe, modular, parallel web rendering engine

Pros of Servo

  • Servo is a more mature and feature-rich browser engine, with support for a wide range of web technologies and standards.
  • Servo has a strong focus on parallelism and performance, which can lead to faster rendering and better responsiveness.
  • Servo has a larger and more active community, with contributions from a wide range of developers.

Cons of Servo

  • Servo is a larger and more complex project, which can make it more difficult to set up and contribute to.
  • Servo's development is primarily focused on the browser engine, rather than on a specific use case like Rusty V8.
  • Servo's performance and stability may not be as consistent as Rusty V8, especially for specific use cases.

Code Comparison

Here's a brief code comparison between Servo and Rusty V8:

Servo (Rust):

let mut context = ServoContext::new();
let mut document = Document::new(&mut context);
document.set_url(Url::parse("https://example.com").unwrap());
document.set_content(r#"<html><body>Hello, world!</body></html>"#);
document.reflow();

Rusty V8 (Rust):

let mut isolate = Isolate::new(Default::default());
let mut context = Context::new(&mut isolate);
let source = r#"console.log('Hello, world!');"#;
let script = Script::compile(&mut context, source, None).unwrap();
script.run(&mut context).unwrap();

Both examples demonstrate the basic usage of the respective libraries, but Servo's code is more focused on the browser engine, while Rusty V8's code is more focused on the JavaScript runtime.

42,295

The C based gRPC (C++, Python, Ruby, Objective-C, PHP, C#)

Pros of grpc/grpc

  • Supports a wide range of programming languages, including C++, Java, Python, and more, making it a versatile choice for cross-platform development.
  • Provides a robust and efficient RPC (Remote Procedure Call) framework for building distributed applications.
  • Offers advanced features like load balancing, tracing, and authentication, which can simplify the development of complex distributed systems.

Cons of grpc/grpc

  • Steeper learning curve compared to simpler RPC frameworks, as it requires understanding of protocol buffers and the gRPC protocol.
  • May have higher overhead and complexity compared to more lightweight communication mechanisms, depending on the specific use case.
  • Requires additional tooling and setup, such as the gRPC compiler, which can add complexity to the development process.

Code Comparison

Here's a brief code comparison between grpc/grpc and denoland/rusty_v8:

grpc/grpc (C++ example):

#include <grpcpp/grpcpp.h>
#include "helloworld.grpc.pb.h"

class GreeterServiceImpl final : public helloworld::Greeter::Service {
  Status SayHello(ServerContext* context, const HelloRequest* request,
                  HelloReply* reply) override {
    std::string prefix("Hello ");
    reply->set_message(prefix + request->name());
    return Status::OK;
  }
};

denoland/rusty_v8 (Rust example):

use rusty_v8::Context;

fn main() {
    let mut isolate = rusty_v8::Isolate::new(Default::default());
    let mut context = Context::new(&mut isolate);
    let source = r#"
        console.log('Hello, World!');
    "#;
    context.eval(source).unwrap();
}
108,341

Node.js JavaScript runtime ✨🐢🚀✨

Pros of Node.js

  • Vast ecosystem of libraries and tools available through npm, the Node.js package manager.
  • Extensive community support and a large number of active contributors.
  • Mature and well-documented, with a wealth of resources and tutorials available.

Cons of Node.js

  • Relies on the V8 JavaScript engine, which may not be as performant as a dedicated runtime like Rust's Rusty_V8.
  • Potential for memory leaks and other performance issues, especially in long-running server applications.

Code Comparison

Node.js:

const http = require('http');

http.createServer((req, res) => {
  res.writeHead(200, { 'Content-Type': 'text/plain' });
  res.end('Hello, World!\n');
}).listen(8000);

console.log('Server running at http://localhost:8000/');

Rusty_V8:

use rusty_v8::{Context, EscapableHandleScope, HandleScope, Local, Value};

fn main() {
    let mut isolate = rusty_v8::new_isolate();
    let mut scope = HandleScope::new(&mut isolate);
    let context = Context::new(&mut scope);
    let mut scope = EscapableHandleScope::new(&mut scope);
    let global = context.global(&mut scope);
    global.set(&mut scope, "message", &mut scope, Value::new_string(&mut scope, "Hello, World!")).unwrap();
}
15,716

A lightweight WebAssembly runtime that is fast, secure, and standards-compliant

Pros of Wasmtime

  • WebAssembly Support: Wasmtime is a WebAssembly runtime that supports the latest WebAssembly specification, allowing for the execution of a wide range of WebAssembly modules.
  • Performance: Wasmtime is designed for high-performance execution of WebAssembly, with a focus on optimizing the runtime for speed and efficiency.
  • Portability: Wasmtime is built to be cross-platform, with support for various operating systems and architectures, making it a versatile choice for developers.

Cons of Wasmtime

  • Limited Language Support: While Wasmtime supports WebAssembly, it does not provide the same level of language support as Rusty_V8, which is primarily focused on the V8 JavaScript engine.
  • Ecosystem: Rusty_V8 benefits from the large and active JavaScript/Node.js ecosystem, while Wasmtime's ecosystem may be smaller and less mature.

Code Comparison

Rusty_V8 (JavaScript execution):

let context = v8::Context::new(&isolate);
context.enter();

let source = v8::String::new(&isolate, "console.log('Hello, World!')").unwrap();
let script = v8::Script::compile(&context, source).unwrap();
script.run(&context).unwrap();

Wasmtime (WebAssembly execution):

let engine = Engine::default();
let module = Module::from_file(&engine, "example.wasm")?;
let instance = Instance::new(&module, &[])?;

let result = instance.get_export("add")?.get_func().unwrap().call(&[10.into(), 32.into()])?;
println!("Result: {}", result.unwrap().i32());
43,547

The zero configuration build tool for the web. 📦🚀

Pros of Parcel

  • Ease of Use: Parcel is known for its simplicity and ease of use, making it a popular choice for developers who want to quickly set up a development environment without the need for complex configuration.
  • Fast Bundling: Parcel utilizes a file watcher and a cache system to provide fast bundling and rebuilding, which can improve development workflow.
  • Automatic Optimization: Parcel automatically optimizes the output, including code splitting, minification, and tree shaking, without the need for manual configuration.

Cons of Parcel

  • Limited Customization: Parcel's focus on simplicity and ease of use can also be a limitation, as it may not provide the same level of customization and control as other bundlers like Webpack.
  • Dependency on Node.js: Parcel is built on Node.js, which means that developers who are not familiar with the Node.js ecosystem may face a steeper learning curve.
  • Potential Performance Issues: In some cases, Parcel's automatic optimization and bundling may not be as efficient as a more manual approach, leading to potential performance issues.

Code Comparison

Parcel:

const app = document.getElementById('app');
app.innerHTML = 'Hello, Parcel!';

Rusty V8:

fn main() {
    let mut isolate = v8::Isolate::new(Default::default());
    let mut scope = v8::HandleScope::new(&mut isolate);
    let context = v8::Context::new(&mut scope);
    let mut scope = v8::ContextScope::new(&mut scope, context);
    println!("Hello, Rusty V8!");
}

In this comparison, Parcel provides a more concise and straightforward approach to setting up a simple web application, while Rusty V8 demonstrates the more complex and lower-level nature of working with the V8 JavaScript engine directly in Rust.

Convert Figma logo designs to code with AI

Visual Copilot

Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.

Try Visual Copilot

README

Rusty V8 Binding

V8 Version: 13.0.245.12

ci crates docs

Goals

  1. Provide high quality Rust bindings to V8's C++ API. The API should match the original API as closely as possible.

  2. Do not introduce additional call overhead. (For example, previous attempts at Rust V8 bindings forced the use of Persistent handles.)

  3. Do not rely on a binary libv8.a built outside of cargo. V8 is a very large project (over 600,000 lines of C++) which often takes 30 minutes to compile. Furthermore, V8 relies on Chromium's bespoke build system (gn + ninja) which is not easy to use outside of Chromium. For this reason many attempts to bind to V8 rely on pre-built binaries that are built separately from the binding itself. While this is simple, it makes upgrading V8 difficult, it makes CI difficult, it makes producing builds with different configurations difficult, and it is a security concern since binary blobs can hide malicious code. For this reason we believe it is imperative to build V8 from source code during "cargo build".

  4. Publish the crate on crates.io and allow docs.rs to generate documentation. Due to the complexity and size of V8's build, this is nontrivial. For example the crate size must be kept under 10 MiB in order to publish.

Versioning

Rusty V8's major version aligns with Chrome's major version, which corresponds to a specific V8 release. For example, Rusty V8 129.0.0 maps to Chrome 129.x.y.z, which uses V8 12.9.a.b. While the minor and patch numbers between Chrome and V8 may differ, Rusty V8 will follow Chrome's release schedule, with a new major version every 4 weeks.

As a Rust crate, Rusty V8 follows semantic versioning (semver) and will not introduce breaking changes within a major version. However, major version bumps will occur regularly to stay in sync with Chrome's release cycle.

Binary Build

V8 is very large and takes a long time to compile. Many users will prefer to use a prebuilt version of V8. We publish static libs for every version of rusty v8 on Github.

Binaries builds are turned on by default: cargo build will initiate a download from github to get the static lib. To disable this build using the V8_FROM_SOURCE environmental variable.

When making changes to rusty_v8 itself, it should be tested by build from source. The CI always builds from source.

The V8_FORCE_DEBUG environment variable

By default rusty_v8 will link against release builds of v8, if you want to use a debug build of v8 set V8_FORCE_DEBUG=true.

We default to release builds of v8 due to performance & CI reasons in deno.

The RUSTY_V8_MIRROR environment variable

Tells the build script where to get binary builds from. Understands http:// and https:// URLs, and file paths. The default is https://github.com/denoland/rusty_v8/releases.

File-based mirrors are good for using cached downloads. First, point the environment variable to a suitable location:

# you might want to add this to your .bashrc
$ export RUSTY_V8_MIRROR=$HOME/.cache/rusty_v8

Then populate the cache:

#!/bin/bash

# see https://github.com/denoland/rusty_v8/releases

for REL in v0.13.0 v0.12.0; do
  mkdir -p $RUSTY_V8_MIRROR/$REL
  for FILE in \
    librusty_v8_debug_x86_64-unknown-linux-gnu.a \
    librusty_v8_release_x86_64-unknown-linux-gnu.a \
  ; do
    if [ ! -f $RUSTY_V8_MIRROR/$REL/$FILE ]; then
      wget -O $RUSTY_V8_MIRROR/$REL/$FILE \
        https://github.com/denoland/rusty_v8/releases/download/$REL/$FILE
    fi
  done
done

The RUSTY_V8_ARCHIVE environment variable

Tell the build script to use a specific v8 library. This can be an URL or a path. This is useful when you have a prebuilt archive somewhere:

export RUSTY_V8_ARCHIVE=/path/to/custom_archive.a
cargo build

Build V8 from Source

Use V8_FROM_SOURCE=1 cargo build -vv to build the crate completely from source.

The build scripts require Python 3 to be available as python3 in your PATH. If you want to specify the exact binary of Python to use, you should use the PYTHON environment variable.

The build also requires curl to be installed on your system.

For linux builds: glib-2.0 development files need to be installed such that pkg-config can find them. On Ubuntu, run sudo apt install libglib2.0-dev to install them.

For Windows builds: the 64-bit toolchain needs to be used. 32-bit targets are not supported.

For Mac builds: You'll need Xcode and Xcode CLT installed. Recent macOS versions will also require you to pass PYTHON=python3 because macOS no longer ships with python simlinked to Python 3.

For Android builds: You'll need to cross compile from a x86_64 host to the aarch64 or x64 android. You can use the following commands:

rustup target add aarch64-linux-android  # or x86_64-linux-android
V8_FROM_SOURCE=1 cargo build -vv --target aarch64-linux-android
# or with cross
docker build --build-arg CROSS_BASE_IMAGE=ghcr.io/cross-rs/aarch64-linux-android:0.2.5 -t cross-rusty_v8:aarch64-linux-android .
V8_FROM_SOURCE=1 cross build -vv --target aarch64-linux-android

The build depends on several binary tools: gn, ninja and clang. The tools will automatically be downloaded, if they are not detected in the environment.

Specifying the $GN and $NINJA environmental variables can be used to skip the download of gn and ninja. The clang download can be skipped by setting $CLANG_BASE_PATH to the directory containing a llvm/clang installation. V8 is known to rely on bleeding edge features, so LLVM v8.0+ or Apple clang 11.0+ is recommended.

Arguments can be passed to gn by setting the $GN_ARGS environmental variable.

Env vars used in when building from source: SCCACHE, CCACHE, GN, NINJA, CLANG_BASE_PATH, GN_ARGS

FAQ

Building V8 takes over 30 minutes, this is too slow for me to use this crate. What should I do?

Install sccache or ccache. Our build scripts will detect and use them. Set the $SCCACHE or $CCACHE environmental variable if it's not in your path.

What are all these random directories for like build and buildtools are these really necessary?

In order to build V8 from source code, we must provide a certain directory structure with some git submodules from Chromium. We welcome any simplifications to the code base, but this is a structure we have found after many failed attempts that carefully balances the requirements of cargo crates and GN/Ninja.

V8 has a very large API with hundreds of methods. Why don't you automate the generation of this binding code?

We have actually started down this route several times, however due to many eccentric features of the V8 API, this has not proven successful. Therefore we are proceeding in a brute-force fashion for now, focusing on solving our stated goals first. We hope to auto-generate bindings in the future.

Why are you building this?

This is to support the Deno project. We previously have gotten away with a simpler high-level Rust binding to V8 called libdeno. But as Deno has matured we've found ourselves continually needing access to an increasing amount of V8's API in Rust.

When building I get unknown argument: '-gno-inline-line-tables'

Use export GN_ARGS="no_inline_line_tables=false" during build.

My program crashes when initializing on non-main thread

Initializing V8 on a non-main thread with the CPUs PKU feature enabled might lead to crashes. You can work around this problem by using v8::new_unprotected_default_platform.

See https://github.com/denoland/rusty_v8/issues/1381

Download cache

The v8 archives used for linking in prebuilt mode can be cached to avoid re-downloading archives when switching between branches that otherwise change the current rusty_v8 version.

To populate the cache by hand, you'll need to place the files in the appropriate location in your .cargo folder. Running cargo build -v -v will print two lines that you can use to determine the correct file and cache location:

[v8 0.87.0] static lib URL: https://github.com/denoland/rusty_v8/releases/download/v0.87.0/librusty_v8_release_aarch64-apple-darwin.a.gz
[v8 0.87.0] Looking for download in '"/Users/<name>/.cargo/.rusty_v8/https___github_com_denoland_rusty_v8_releases_download_v0_87_0_librusty_v8_release_aarch64_apple_darwin_a_gz"'

Given the above log output, use curl to download the file like so:

curl -L https://github.com/denoland/rusty_v8/releases/download/v0.87.0/librusty_v8_release_aarch64-apple-darwin.a.gz >
  /Users/<name>/.cargo/.rusty_v8/https___github_com_denoland_rusty_v8_releases_download_v0_87_0_librusty_v8_release_aarch64_apple_darwin_a_gz

For maintainers

Cut a release

Create a PR to bump the release version (e.g. https://github.com/denoland/rusty_v8/pull/1415).

Create a new release/tag after the bump PR is landed. CI will publish the crate and upload release binaries. You will need to manually upload binary archives for M1 build.

$ V8_FROM_SOURCE=1 cargo build
$ V8_FROM_SOURCE=1 cargo build --release