Trait deno_core::convert::ToV8

source ·
pub trait ToV8<'a> {
    type Error: Error + Send + Sync + 'static;

    // Required method
    fn to_v8(
        self,
        scope: &mut HandleScope<'a>
    ) -> Result<Local<'a, Value>, Self::Error>;
}
Expand description

A conversion from a rust value to a v8 value.

When passing data from Rust into JS, either via an op or by calling a JS function directly, you need to serialize the data into a native V8 value. When using the op2 macro, the return value is converted to a v8::Local<Value> automatically, and the strategy for conversion is controlled by attributes like #[smi], #[number], #[string]. For types with support built-in to the op2 macro, like primitives, strings, and buffers, these attributes are sufficient and you don’t need to worry about this trait.

If, however, you want to return a custom type from an op, or simply want more control over the conversion process, you can implement the ToV8 trait. This allows you the choose the best serialization strategy for your specific use case. You can then use the #[to_v8] attribute to indicate that the #[op2] macro should call your implementation for the conversion.

§Example

use deno_core::ToV8;
use deno_core::convert::Smi;
use deno_core::op2;

struct Foo(i32);

impl<'a> ToV8<'a> for Foo {
  // This conversion can never fail, so we use `Infallible` as the error type.
  // Any error type that implements `std::error::Error` can be used here.
  type Error = std::convert::Infallible;

  fn to_v8(self, scope: &mut v8::HandleScope<'a>) -> Result<v8::Local<'a, v8::Value>, Self::Error> {
    // For performance, pass this value as a `v8::Integer` (i.e. a `smi`).
    // The `Smi` wrapper type implements this conversion for you.
    Smi(self.0).to_v8(scope)
  }
}

// using the `#[to_v8]` attribute tells the `op2` macro to call this implementation.
#[op2]
#[to_v8]
fn op_foo() -> Foo {
  Foo(42)
}

§Performance Notes

§Structs

The natural representation of a struct in JS is an object with fields corresponding the struct. This, however, is a performance footgun and you should avoid creating and passing objects to V8 whenever possible. In general, if you need to pass a compound type to JS, it is more performant to serialize to a tuple (a v8::Array) rather than an object. Object keys are V8 strings, and strings are expensive to pass to V8 and they have to be managed by the V8 garbage collector. Tuples, on the other hand, are keyed by smis, which are immediates and don’t require allocation or garbage collection.

Required Associated Types§

source

type Error: Error + Send + Sync + 'static

Required Methods§

source

fn to_v8( self, scope: &mut HandleScope<'a> ) -> Result<Local<'a, Value>, Self::Error>

Converts the value to a V8 value.

Implementations on Foreign Types§

source§

impl<'a> ToV8<'a> for bool

§

type Error = Infallible

source§

fn to_v8( self, scope: &mut HandleScope<'a> ) -> Result<Local<'a, Value>, Self::Error>

Implementors§

source§

impl<'a, T: Numeric> ToV8<'a> for Number<T>

source§

impl<'a, T: SmallInt> ToV8<'a> for Smi<T>