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 smi
s, which are immediates
and don’t require allocation or garbage collection.