mirror of
https://github.com/denoland/rusty_v8.git
synced 2025-01-11 08:34:01 -05:00
add basic serializer bindings (#442)
This commit is contained in:
parent
18a3eab7c6
commit
dbc0509f2a
7 changed files with 1496 additions and 2 deletions
242
src/binding.cc
242
src/binding.cc
|
@ -2025,5 +2025,245 @@ V(number_of_detached_contexts)
|
|||
V(does_zap_garbage) // Returns size_t, not bool like you'd expect.
|
||||
|
||||
#undef V
|
||||
|
||||
} // extern "C"
|
||||
|
||||
// v8::ValueSerializer::Delegate
|
||||
|
||||
extern "C" {
|
||||
void v8__ValueSerializer__Delegate__ThrowDataCloneError(
|
||||
v8::ValueSerializer::Delegate* self,
|
||||
v8::Local<v8::String> message);
|
||||
|
||||
MaybeBool v8__ValueSerializer__Delegate__WriteHostObject(
|
||||
v8::ValueSerializer::Delegate* self, v8::Isolate* isolate,
|
||||
v8::Local<v8::Object> object);
|
||||
|
||||
bool v8__ValueSerializer__Delegate__GetSharedArrayBufferId(
|
||||
v8::ValueSerializer::Delegate* self, v8::Isolate* isolate,
|
||||
v8::Local<v8::SharedArrayBuffer> shared_array_buffer, uint32_t* result);
|
||||
|
||||
bool v8__ValueSerializer__Delegate__GetWasmModuleTransferId(
|
||||
v8::ValueSerializer::Delegate* self, v8::Isolate* isolate,
|
||||
v8::Local<v8::WasmModuleObject> module, uint32_t* result);
|
||||
|
||||
void* v8__ValueSerializer__Delegate__ReallocateBufferMemory(
|
||||
v8::ValueSerializer::Delegate* self, void* old_buffer, size_t size,
|
||||
size_t* actual_size);
|
||||
|
||||
void v8__ValueSerializer__Delegate__FreeBufferMemory(
|
||||
v8::ValueSerializer::Delegate* self, void* buffer);
|
||||
}
|
||||
|
||||
struct v8__ValueSerializer__Delegate : public v8::ValueSerializer::Delegate {
|
||||
void ThrowDataCloneError(v8::Local<v8::String> message) override {
|
||||
v8__ValueSerializer__Delegate__ThrowDataCloneError(this, message);
|
||||
}
|
||||
|
||||
v8::Maybe<bool> WriteHostObject(v8::Isolate* isolate,
|
||||
v8::Local<v8::Object> object) override {
|
||||
return maybe_bool_to_maybe(
|
||||
v8__ValueSerializer__Delegate__WriteHostObject(this, isolate,
|
||||
object));
|
||||
}
|
||||
|
||||
v8::Maybe<uint32_t> GetSharedArrayBufferId(
|
||||
v8::Isolate* isolate,
|
||||
v8::Local<v8::SharedArrayBuffer> shared_array_buffer) override {
|
||||
uint32_t result = 0;
|
||||
if (!v8__ValueSerializer__Delegate__GetSharedArrayBufferId(
|
||||
this, isolate, shared_array_buffer, &result))
|
||||
return v8::Nothing<uint32_t>();
|
||||
return v8::Just(result);
|
||||
}
|
||||
|
||||
v8::Maybe<uint32_t> GetWasmModuleTransferId(
|
||||
v8::Isolate* isolate, v8::Local<v8::WasmModuleObject> module) override {
|
||||
uint32_t result = 0;
|
||||
if (!v8__ValueSerializer__Delegate__GetWasmModuleTransferId(
|
||||
this, isolate, module, &result))
|
||||
return v8::Nothing<uint32_t>();
|
||||
return v8::Just(result);
|
||||
}
|
||||
|
||||
void* ReallocateBufferMemory(void* old_buffer, size_t size,
|
||||
size_t* actual_size) override {
|
||||
return v8__ValueSerializer__Delegate__ReallocateBufferMemory(
|
||||
this, old_buffer, size, actual_size);
|
||||
}
|
||||
|
||||
void FreeBufferMemory(void* buffer) override {
|
||||
v8__ValueSerializer__Delegate__FreeBufferMemory(this, buffer);
|
||||
}
|
||||
};
|
||||
|
||||
extern "C" {
|
||||
void v8__ValueSerializer__Delegate__CONSTRUCT(
|
||||
uninit_t<v8__ValueSerializer__Delegate>* buf) {
|
||||
static_assert(sizeof(v8__ValueSerializer__Delegate) == sizeof(size_t),
|
||||
"v8__ValueSerializer__Delegate size mismatch");
|
||||
construct_in_place<v8__ValueSerializer__Delegate>(buf);
|
||||
}
|
||||
}
|
||||
|
||||
// v8::ValueSerializer
|
||||
|
||||
extern "C" {
|
||||
void v8__ValueSerializer__CONSTRUCT(uninit_t<v8::ValueSerializer>* buf,
|
||||
v8::Isolate* isolate,
|
||||
v8::ValueSerializer::Delegate* delegate) {
|
||||
static_assert(sizeof(v8::ValueSerializer) == sizeof(size_t),
|
||||
"v8::ValueSerializer size mismatch");
|
||||
construct_in_place<v8::ValueSerializer>(buf, isolate, delegate);
|
||||
}
|
||||
|
||||
void v8__ValueSerializer__DESTRUCT(v8::ValueSerializer* self) {
|
||||
self->~ValueSerializer();
|
||||
}
|
||||
|
||||
void v8__ValueSerializer__Release(v8::ValueSerializer* self,
|
||||
uint8_t** ptr, size_t* size) {
|
||||
auto result = self->Release();
|
||||
*ptr = result.first;
|
||||
*size = result.second;
|
||||
}
|
||||
|
||||
void v8__ValueSerializer__WriteHeader(v8::ValueSerializer* self) {
|
||||
self->WriteHeader();
|
||||
}
|
||||
|
||||
MaybeBool v8__ValueSerializer__WriteValue(v8::ValueSerializer* self,
|
||||
v8::Local<v8::Context> context,
|
||||
v8::Local<v8::Value> value) {
|
||||
return maybe_to_maybe_bool(self->WriteValue(context, value));
|
||||
}
|
||||
|
||||
void v8__ValueSerializer__TransferArrayBuffer(
|
||||
v8::ValueSerializer* self, uint32_t transfer_id,
|
||||
v8::Local<v8::ArrayBuffer> array_buffer) {
|
||||
self->TransferArrayBuffer(transfer_id, array_buffer);
|
||||
}
|
||||
|
||||
void v8__ValueSerializer__WriteUint32(v8::ValueSerializer* self,
|
||||
uint32_t value) {
|
||||
self->WriteUint32(value);
|
||||
}
|
||||
|
||||
void v8__ValueSerializer__WriteUint64(v8::ValueSerializer* self,
|
||||
uint64_t value) {
|
||||
self->WriteUint64(value);
|
||||
}
|
||||
|
||||
void v8__ValueSerializer__WriteDouble(v8::ValueSerializer* self, double value) {
|
||||
self->WriteDouble(value);
|
||||
}
|
||||
|
||||
void v8__ValueSerializer__WriteRawBytes(v8::ValueSerializer* self,
|
||||
const void* source, size_t length) {
|
||||
self->WriteRawBytes(source, length);
|
||||
}
|
||||
}
|
||||
|
||||
// v8::ValueDeserializer::Delegate
|
||||
|
||||
extern "C" {
|
||||
v8::Object* v8__ValueDeserializer__Delegate__ReadHostObject(
|
||||
v8::ValueDeserializer::Delegate* self, v8::Isolate* isolate);
|
||||
|
||||
v8::SharedArrayBuffer*
|
||||
v8__ValueDeserializer__Delegate__GetSharedArrayBufferFromId(
|
||||
v8::ValueDeserializer::Delegate* self, v8::Isolate* isolate,
|
||||
uint32_t transfer_id);
|
||||
|
||||
v8::WasmModuleObject*
|
||||
v8__ValueDeserializer__Delegate__GetWasmModuleFromId(
|
||||
v8::ValueDeserializer::Delegate* self, v8::Isolate* isolate,
|
||||
uint32_t clone_id);
|
||||
}
|
||||
|
||||
struct v8__ValueDeserializer__Delegate : public v8::ValueDeserializer::Delegate {
|
||||
v8::MaybeLocal<v8::Object> ReadHostObject(v8::Isolate* isolate) override {
|
||||
return ptr_to_maybe_local(
|
||||
v8__ValueDeserializer__Delegate__ReadHostObject(this, isolate));
|
||||
}
|
||||
|
||||
v8::MaybeLocal<v8::SharedArrayBuffer> GetSharedArrayBufferFromId(
|
||||
v8::Isolate* isolate, uint32_t transfer_id) override {
|
||||
return ptr_to_maybe_local(
|
||||
v8__ValueDeserializer__Delegate__GetSharedArrayBufferFromId(
|
||||
this, isolate, transfer_id));
|
||||
}
|
||||
|
||||
v8::MaybeLocal<v8::WasmModuleObject> GetWasmModuleFromId(
|
||||
v8::Isolate* isolate, uint32_t clone_id) override {
|
||||
return ptr_to_maybe_local(
|
||||
v8__ValueDeserializer__Delegate__GetWasmModuleFromId(
|
||||
this, isolate, clone_id));
|
||||
}
|
||||
};
|
||||
|
||||
extern "C" {
|
||||
void v8__ValueDeserializer__Delegate__CONSTRUCT(
|
||||
uninit_t<v8__ValueDeserializer__Delegate>* buf) {
|
||||
static_assert(sizeof(v8__ValueDeserializer__Delegate) == sizeof(size_t),
|
||||
"v8__ValueDeserializer__Delegate size mismatch");
|
||||
construct_in_place<v8__ValueDeserializer__Delegate>(buf);
|
||||
}
|
||||
}
|
||||
|
||||
// v8::ValueDeserializer
|
||||
|
||||
extern "C" {
|
||||
void v8__ValueDeserializer__CONSTRUCT(
|
||||
uninit_t<v8::ValueDeserializer>* buf, v8::Isolate* isolate,
|
||||
const uint8_t* data, size_t size,
|
||||
v8::ValueDeserializer::Delegate* delegate) {
|
||||
static_assert(sizeof(v8::ValueDeserializer) == sizeof(size_t),
|
||||
"v8::ValueDeserializer size mismatch");
|
||||
construct_in_place<v8::ValueDeserializer>(buf, isolate, data, size, delegate);
|
||||
}
|
||||
|
||||
void v8__ValueDeserializer__DESTRUCT(v8::ValueDeserializer* self) {
|
||||
self->~ValueDeserializer();
|
||||
}
|
||||
|
||||
MaybeBool v8__ValueDeserializer__ReadHeader(v8::ValueDeserializer* self,
|
||||
v8::Local<v8::Context> context) {
|
||||
return maybe_to_maybe_bool(self->ReadHeader(context));
|
||||
}
|
||||
|
||||
v8::Value* v8__ValueDeserializer__ReadValue(v8::ValueDeserializer* self,
|
||||
v8::Local<v8::Context> context) {
|
||||
return maybe_local_to_ptr(self->ReadValue(context));
|
||||
}
|
||||
|
||||
void v8__ValueDeserializer__TransferArrayBuffer(
|
||||
v8::ValueDeserializer* self, uint32_t transfer_id,
|
||||
v8::Local<v8::ArrayBuffer> array_buffer) {
|
||||
self->TransferArrayBuffer(transfer_id, array_buffer);
|
||||
}
|
||||
|
||||
void v8__ValueDeserializer__SetSupportsLegacyWireFormat(
|
||||
v8::ValueDeserializer* self, bool supports_legacy_wire_format) {
|
||||
self->SetSupportsLegacyWireFormat(supports_legacy_wire_format);
|
||||
}
|
||||
|
||||
bool v8__ValueDeserializer__ReadUint32(v8::ValueDeserializer* self,
|
||||
uint32_t* value) {
|
||||
return self->ReadUint32(value);
|
||||
}
|
||||
|
||||
bool v8__ValueDeserializer__ReadUint64(v8::ValueDeserializer* self,
|
||||
uint64_t* value) {
|
||||
return self->ReadUint64(value);
|
||||
}
|
||||
|
||||
bool v8__ValueDeserializer__ReadDouble(v8::ValueDeserializer* self,
|
||||
double* value) {
|
||||
return self->ReadDouble(value);
|
||||
}
|
||||
|
||||
bool v8__ValueDeserializer__ReadRawBytes(v8::ValueDeserializer* self,
|
||||
size_t length, const void** data) {
|
||||
return self->ReadRawBytes(length, data);
|
||||
}
|
||||
} // extern "C"
|
||||
|
|
|
@ -68,6 +68,8 @@ mod symbol;
|
|||
mod template;
|
||||
mod uint8_array;
|
||||
mod value;
|
||||
mod value_deserializer;
|
||||
mod value_serializer;
|
||||
|
||||
pub mod inspector;
|
||||
pub mod json;
|
||||
|
@ -127,6 +129,12 @@ pub use support::UniquePtr;
|
|||
pub use support::UniqueRef;
|
||||
pub use symbol::*;
|
||||
pub use template::*;
|
||||
pub use value_deserializer::ValueDeserializer;
|
||||
pub use value_deserializer::ValueDeserializerHelper;
|
||||
pub use value_deserializer::ValueDeserializerImpl;
|
||||
pub use value_serializer::ValueSerializer;
|
||||
pub use value_serializer::ValueSerializerHelper;
|
||||
pub use value_serializer::ValueSerializerImpl;
|
||||
|
||||
// TODO(piscisaureus): Ideally this trait would not be exported.
|
||||
pub use support::MapFnTo;
|
||||
|
|
|
@ -111,6 +111,16 @@ inline static MaybeBool maybe_to_maybe_bool(v8::Maybe<bool> maybe) {
|
|||
}
|
||||
}
|
||||
|
||||
inline static v8::Maybe<bool> maybe_bool_to_maybe(MaybeBool maybe) {
|
||||
switch(maybe) {
|
||||
case MaybeBool::JustTrue:
|
||||
case MaybeBool::JustFalse:
|
||||
return v8::Just<bool>(maybe == MaybeBool::JustTrue);
|
||||
default:
|
||||
return v8::Nothing<bool>();
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline static T* local_to_ptr(v8::Local<T> local) {
|
||||
return *local;
|
||||
|
|
|
@ -451,7 +451,7 @@ impl<T: ?Sized> Borrow<T> for Allocation<T> {
|
|||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub(crate) enum MaybeBool {
|
||||
pub enum MaybeBool {
|
||||
JustFalse = 0,
|
||||
JustTrue = 1,
|
||||
Nothing = 2,
|
||||
|
@ -467,6 +467,16 @@ impl Into<Option<bool>> for MaybeBool {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<Option<bool>> for MaybeBool {
|
||||
fn from(option: Option<bool>) -> Self {
|
||||
match option {
|
||||
Some(false) => MaybeBool::JustFalse,
|
||||
Some(true) => MaybeBool::JustTrue,
|
||||
None => MaybeBool::Nothing,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(transparent)]
|
||||
pub struct CxxVTable(pub *const Opaque);
|
||||
|
|
422
src/value_deserializer.rs
Normal file
422
src/value_deserializer.rs
Normal file
|
@ -0,0 +1,422 @@
|
|||
use crate::ArrayBuffer;
|
||||
use crate::Context;
|
||||
use crate::Exception;
|
||||
use crate::HandleScope;
|
||||
use crate::Isolate;
|
||||
use crate::Local;
|
||||
use crate::Object;
|
||||
use crate::SharedArrayBuffer;
|
||||
use crate::String;
|
||||
use crate::Value;
|
||||
use crate::WasmModuleObject;
|
||||
|
||||
use crate::support::CxxVTable;
|
||||
use crate::support::FieldOffset;
|
||||
use crate::support::MaybeBool;
|
||||
|
||||
use std::ffi::c_void;
|
||||
use std::mem::MaybeUninit;
|
||||
use std::pin::Pin;
|
||||
|
||||
// Must be == sizeof(v8::ValueDeserializer::Delegate),
|
||||
// see v8__ValueDeserializer__Delegate__CONSTRUCT().
|
||||
#[repr(C)]
|
||||
pub struct CxxValueDeserializerDelegate {
|
||||
_cxx_vtable: CxxVTable,
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn v8__ValueDeserializer__Delegate__ReadHostObject(
|
||||
this: &mut CxxValueDeserializerDelegate,
|
||||
_isolate: *mut Isolate,
|
||||
) -> *const Object {
|
||||
let value_deserializer_heap = ValueDeserializerHeap::dispatch_mut(this);
|
||||
let scope =
|
||||
&mut crate::scope::CallbackScope::new(value_deserializer_heap.context);
|
||||
let value_deserializer_impl =
|
||||
value_deserializer_heap.value_deserializer_impl.as_mut();
|
||||
match value_deserializer_impl
|
||||
.read_host_object(scope, &value_deserializer_heap.cxx_value_deserializer)
|
||||
{
|
||||
None => std::ptr::null(),
|
||||
Some(x) => x.as_non_null().as_ptr(),
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn v8__ValueDeserializer__Delegate__GetSharedArrayBufferFromId(
|
||||
this: &mut CxxValueDeserializerDelegate,
|
||||
_isolate: *mut Isolate,
|
||||
transfer_id: u32,
|
||||
) -> *const SharedArrayBuffer {
|
||||
let value_deserializer_heap = ValueDeserializerHeap::dispatch_mut(this);
|
||||
let scope =
|
||||
&mut crate::scope::CallbackScope::new(value_deserializer_heap.context);
|
||||
let value_deserializer_impl =
|
||||
value_deserializer_heap.value_deserializer_impl.as_mut();
|
||||
match value_deserializer_impl
|
||||
.get_shared_array_buffer_from_id(scope, transfer_id)
|
||||
{
|
||||
None => std::ptr::null(),
|
||||
Some(x) => x.as_non_null().as_ptr(),
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn v8__ValueDeserializer__Delegate__GetWasmModuleFromId(
|
||||
this: &mut CxxValueDeserializerDelegate,
|
||||
_isolate: *mut Isolate,
|
||||
clone_id: u32,
|
||||
) -> *const WasmModuleObject {
|
||||
let value_deserializer_heap = ValueDeserializerHeap::dispatch_mut(this);
|
||||
let scope =
|
||||
&mut crate::scope::CallbackScope::new(value_deserializer_heap.context);
|
||||
let value_deserializer_impl =
|
||||
value_deserializer_heap.value_deserializer_impl.as_mut();
|
||||
match value_deserializer_impl.get_wasm_module_from_id(scope, clone_id) {
|
||||
None => std::ptr::null(),
|
||||
Some(x) => x.as_non_null().as_ptr(),
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
fn v8__ValueDeserializer__Delegate__CONSTRUCT(
|
||||
buf: *mut MaybeUninit<CxxValueDeserializerDelegate>,
|
||||
);
|
||||
}
|
||||
|
||||
// Must be == sizeof(v8::ValueDeserializer),
|
||||
// see v8__ValueDeserializer__CONSTRUCT().
|
||||
#[repr(C)]
|
||||
pub struct CxxValueDeserializer {
|
||||
_cxx_vtable: CxxVTable,
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
fn v8__ValueDeserializer__CONSTRUCT(
|
||||
buf: *mut MaybeUninit<CxxValueDeserializer>,
|
||||
isolate: *mut Isolate,
|
||||
data: *const u8,
|
||||
size: usize,
|
||||
delegate: *mut CxxValueDeserializerDelegate,
|
||||
);
|
||||
|
||||
fn v8__ValueDeserializer__DESTRUCT(this: *mut CxxValueDeserializer);
|
||||
|
||||
fn v8__ValueDeserializer__TransferArrayBuffer(
|
||||
this: *mut CxxValueDeserializer,
|
||||
transfer_id: u32,
|
||||
array_buffer: Local<ArrayBuffer>,
|
||||
);
|
||||
|
||||
fn v8__ValueDeserializer__SetSupportsLegacyWireFormat(
|
||||
this: *mut CxxValueDeserializer,
|
||||
supports_legacy_wire_format: bool,
|
||||
);
|
||||
|
||||
fn v8__ValueDeserializer__ReadHeader(
|
||||
this: *mut CxxValueDeserializer,
|
||||
context: Local<Context>,
|
||||
) -> MaybeBool;
|
||||
|
||||
fn v8__ValueDeserializer__ReadValue(
|
||||
this: *mut CxxValueDeserializer,
|
||||
context: Local<Context>,
|
||||
) -> *const Value;
|
||||
|
||||
fn v8__ValueDeserializer__ReadUint32(
|
||||
this: *mut CxxValueDeserializer,
|
||||
value: *mut u32,
|
||||
) -> bool;
|
||||
|
||||
fn v8__ValueDeserializer__ReadUint64(
|
||||
this: *mut CxxValueDeserializer,
|
||||
value: *mut u64,
|
||||
) -> bool;
|
||||
|
||||
fn v8__ValueDeserializer__ReadDouble(
|
||||
this: *mut CxxValueDeserializer,
|
||||
value: *mut f64,
|
||||
) -> bool;
|
||||
|
||||
fn v8__ValueDeserializer__ReadRawBytes(
|
||||
this: *mut CxxValueDeserializer,
|
||||
length: usize,
|
||||
data: *mut *const c_void,
|
||||
) -> bool;
|
||||
}
|
||||
|
||||
/// The ValueDeserializerImpl trait allows for
|
||||
/// custom callback functions used by v8.
|
||||
pub trait ValueDeserializerImpl {
|
||||
#[allow(unused_variables)]
|
||||
fn read_host_object<'s>(
|
||||
&mut self,
|
||||
scope: &mut HandleScope<'s>,
|
||||
value_deserializer: &dyn ValueDeserializerHelper,
|
||||
) -> Option<Local<'s, Object>> {
|
||||
let msg =
|
||||
String::new(scope, "Deno deserializer: read_host_object not implemented")
|
||||
.unwrap();
|
||||
let exc = Exception::error(scope, msg);
|
||||
scope.throw_exception(exc);
|
||||
None
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn get_shared_array_buffer_from_id<'s>(
|
||||
&mut self,
|
||||
scope: &mut HandleScope<'s>,
|
||||
transfer_id: u32,
|
||||
) -> Option<Local<'s, SharedArrayBuffer>> {
|
||||
let msg = String::new(
|
||||
scope,
|
||||
"Deno deserializer: get_shared_array_buffer_from_id not implemented",
|
||||
)
|
||||
.unwrap();
|
||||
let exc = Exception::error(scope, msg);
|
||||
scope.throw_exception(exc);
|
||||
None
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn get_wasm_module_from_id<'s>(
|
||||
&mut self,
|
||||
scope: &mut HandleScope<'s>,
|
||||
clone_id: u32,
|
||||
) -> Option<Local<'s, WasmModuleObject>> {
|
||||
let msg = String::new(
|
||||
scope,
|
||||
"Deno deserializer: get_wasm_module_from_id not implemented",
|
||||
)
|
||||
.unwrap();
|
||||
let exc = Exception::error(scope, msg);
|
||||
scope.throw_exception(exc);
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// The ValueDeserializerHeap object contains all objects related to a
|
||||
/// deserializer. This object has to be pinned to the heap because of the Cpp
|
||||
/// pointers that have to remain valid. Moving this object would result in the
|
||||
/// Cpp pointer to the delegate to become invalid and thus causing the delegate
|
||||
/// callback to fail. Additionally the deserializer and implementation are also
|
||||
/// pinned in memory because these have to be accessable from within the
|
||||
/// delegate callback methods.
|
||||
pub struct ValueDeserializerHeap<'a, 's> {
|
||||
value_deserializer_impl: Box<dyn ValueDeserializerImpl + 'a>,
|
||||
cxx_value_deserializer: CxxValueDeserializer,
|
||||
cxx_value_deserializer_delegate: CxxValueDeserializerDelegate,
|
||||
context: Local<'s, Context>,
|
||||
}
|
||||
|
||||
impl<'a, 's> ValueDeserializerHeap<'a, 's> {
|
||||
fn get_cxx_value_deserializer_delegate_offset(
|
||||
) -> FieldOffset<CxxValueDeserializerDelegate> {
|
||||
let buf = std::mem::MaybeUninit::<Self>::uninit();
|
||||
FieldOffset::from_ptrs(buf.as_ptr(), unsafe {
|
||||
&(*buf.as_ptr()).cxx_value_deserializer_delegate
|
||||
})
|
||||
}
|
||||
|
||||
/// Starting from 'this' pointer a ValueDeserializerHeap ref can be created
|
||||
pub unsafe fn dispatch(
|
||||
value_serializer_delegate: &'s CxxValueDeserializerDelegate,
|
||||
) -> &Self {
|
||||
Self::get_cxx_value_deserializer_delegate_offset()
|
||||
.to_embedder::<Self>(value_serializer_delegate)
|
||||
}
|
||||
|
||||
/// Starting from 'this' pointer the ValueDeserializerHeap mut ref can be
|
||||
/// created
|
||||
pub unsafe fn dispatch_mut(
|
||||
value_serializer_delegate: &'s mut CxxValueDeserializerDelegate,
|
||||
) -> &mut Self {
|
||||
Self::get_cxx_value_deserializer_delegate_offset()
|
||||
.to_embedder_mut::<Self>(value_serializer_delegate)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 's> Drop for ValueDeserializerHeap<'a, 's> {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
v8__ValueDeserializer__DESTRUCT(&mut self.cxx_value_deserializer)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// Trait used for direct read from the deserialization buffer.
|
||||
/// Mostly used by the read_host_object callback function in the
|
||||
/// ValueDeserializerImpl trait to create custom deserialization logic.
|
||||
pub trait ValueDeserializerHelper {
|
||||
fn get_cxx_value_deserializer(&mut self) -> &mut CxxValueDeserializer;
|
||||
|
||||
fn read_header(&mut self, context: Local<Context>) -> Option<bool> {
|
||||
unsafe {
|
||||
v8__ValueDeserializer__ReadHeader(
|
||||
self.get_cxx_value_deserializer(),
|
||||
context,
|
||||
)
|
||||
}
|
||||
.into()
|
||||
}
|
||||
|
||||
fn read_value(&mut self, context: Local<Context>) -> Option<Local<Value>> {
|
||||
unsafe {
|
||||
Local::from_raw(v8__ValueDeserializer__ReadValue(
|
||||
self.get_cxx_value_deserializer(),
|
||||
context,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
fn read_uint32(&mut self, value: &mut u32) -> bool {
|
||||
unsafe {
|
||||
v8__ValueDeserializer__ReadUint32(
|
||||
self.get_cxx_value_deserializer(),
|
||||
value,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn read_uint64(&mut self, value: &mut u64) -> bool {
|
||||
unsafe {
|
||||
v8__ValueDeserializer__ReadUint64(
|
||||
self.get_cxx_value_deserializer(),
|
||||
value,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn read_double(&mut self, value: &mut f64) -> bool {
|
||||
unsafe {
|
||||
v8__ValueDeserializer__ReadDouble(
|
||||
self.get_cxx_value_deserializer(),
|
||||
value,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn read_raw_bytes(&mut self, length: usize) -> Option<&[u8]> {
|
||||
let mut data: *const c_void = std::ptr::null_mut();
|
||||
let ok = unsafe {
|
||||
v8__ValueDeserializer__ReadRawBytes(
|
||||
self.get_cxx_value_deserializer(),
|
||||
length,
|
||||
&mut data,
|
||||
)
|
||||
};
|
||||
if ok {
|
||||
assert!(!data.is_null());
|
||||
unsafe { Some(std::slice::from_raw_parts(data as *const u8, length)) }
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn transfer_array_buffer(
|
||||
&mut self,
|
||||
transfer_id: u32,
|
||||
array_buffer: Local<ArrayBuffer>,
|
||||
) {
|
||||
unsafe {
|
||||
v8__ValueDeserializer__TransferArrayBuffer(
|
||||
self.get_cxx_value_deserializer(),
|
||||
transfer_id,
|
||||
array_buffer,
|
||||
)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
impl ValueDeserializerHelper for CxxValueDeserializer {
|
||||
fn get_cxx_value_deserializer(&mut self) -> &mut CxxValueDeserializer {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 's> ValueDeserializerHelper for ValueDeserializerHeap<'a, 's> {
|
||||
fn get_cxx_value_deserializer(&mut self) -> &mut CxxValueDeserializer {
|
||||
&mut self.cxx_value_deserializer
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 's> ValueDeserializerHelper for ValueDeserializer<'a, 's> {
|
||||
fn get_cxx_value_deserializer(&mut self) -> &mut CxxValueDeserializer {
|
||||
&mut (*self.value_deserializer_heap).cxx_value_deserializer
|
||||
}
|
||||
}
|
||||
|
||||
/// ValueDeserializer is a stack object used as entry-point for an owned and
|
||||
/// pinned heap object ValueDeserializerHeap.
|
||||
/// The 'a lifetime is the lifetime of the ValueDeserializerImpl implementation.
|
||||
/// The 's lifetime is the lifetime of the HandleScope which is used to retrieve
|
||||
/// a Local<'s, Context> for the CallbackScopes
|
||||
pub struct ValueDeserializer<'a, 's> {
|
||||
value_deserializer_heap: Pin<Box<ValueDeserializerHeap<'a, 's>>>,
|
||||
}
|
||||
|
||||
impl<'a, 's> ValueDeserializer<'a, 's> {
|
||||
pub fn new<D: ValueDeserializerImpl + 'a>(
|
||||
scope: &mut HandleScope<'s>,
|
||||
value_deserializer_impl: Box<D>,
|
||||
data: &[u8],
|
||||
) -> Self {
|
||||
// create dummy ValueDeserializerHeap and move to heap + pin to address
|
||||
let mut value_deserializer_heap = Box::pin(ValueDeserializerHeap {
|
||||
value_deserializer_impl,
|
||||
cxx_value_deserializer: CxxValueDeserializer {
|
||||
_cxx_vtable: CxxVTable {
|
||||
0: std::ptr::null(),
|
||||
},
|
||||
},
|
||||
cxx_value_deserializer_delegate: CxxValueDeserializerDelegate {
|
||||
_cxx_vtable: CxxVTable {
|
||||
0: std::ptr::null(),
|
||||
},
|
||||
},
|
||||
context: scope.get_current_context(),
|
||||
});
|
||||
|
||||
unsafe {
|
||||
v8__ValueDeserializer__Delegate__CONSTRUCT(core::mem::transmute(
|
||||
&mut (*value_deserializer_heap).cxx_value_deserializer_delegate,
|
||||
));
|
||||
|
||||
v8__ValueDeserializer__CONSTRUCT(
|
||||
core::mem::transmute(
|
||||
&mut (*value_deserializer_heap).cxx_value_deserializer,
|
||||
),
|
||||
scope.get_isolate_ptr(),
|
||||
data.as_ptr(),
|
||||
data.len(),
|
||||
&mut (*value_deserializer_heap).cxx_value_deserializer_delegate,
|
||||
);
|
||||
};
|
||||
|
||||
ValueDeserializer {
|
||||
value_deserializer_heap,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 's> ValueDeserializer<'a, 's> {
|
||||
pub fn set_supports_legacy_wire_format(
|
||||
&mut self,
|
||||
supports_legacy_wire_format: bool,
|
||||
) {
|
||||
unsafe {
|
||||
v8__ValueDeserializer__SetSupportsLegacyWireFormat(
|
||||
&mut (*self.value_deserializer_heap).cxx_value_deserializer,
|
||||
supports_legacy_wire_format,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_value(
|
||||
&mut self,
|
||||
context: Local<Context>,
|
||||
) -> Option<Local<Value>> {
|
||||
(*self.value_deserializer_heap).read_value(context)
|
||||
}
|
||||
}
|
473
src/value_serializer.rs
Normal file
473
src/value_serializer.rs
Normal file
|
@ -0,0 +1,473 @@
|
|||
use crate::ArrayBuffer;
|
||||
use crate::Context;
|
||||
use crate::Exception;
|
||||
use crate::HandleScope;
|
||||
use crate::Isolate;
|
||||
use crate::Local;
|
||||
use crate::Object;
|
||||
use crate::SharedArrayBuffer;
|
||||
use crate::String;
|
||||
use crate::Value;
|
||||
use crate::WasmModuleObject;
|
||||
|
||||
use std::alloc::alloc;
|
||||
use std::alloc::dealloc;
|
||||
use std::alloc::realloc;
|
||||
use std::alloc::Layout;
|
||||
use std::mem::MaybeUninit;
|
||||
|
||||
use crate::support::CxxVTable;
|
||||
use crate::support::FieldOffset;
|
||||
use crate::support::MaybeBool;
|
||||
|
||||
use std::ffi::c_void;
|
||||
use std::pin::Pin;
|
||||
|
||||
// Must be == sizeof(v8::ValueSerializer::Delegate),
|
||||
// see v8__ValueSerializer__Delegate__CONSTRUCT().
|
||||
#[repr(C)]
|
||||
pub struct CxxValueSerializerDelegate {
|
||||
_cxx_vtable: CxxVTable,
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn v8__ValueSerializer__Delegate__ThrowDataCloneError(
|
||||
this: &mut CxxValueSerializerDelegate,
|
||||
message: Local<String>,
|
||||
) {
|
||||
let value_serializer_heap = ValueSerializerHeap::dispatch_mut(this);
|
||||
let scope =
|
||||
&mut crate::scope::CallbackScope::new(value_serializer_heap.context);
|
||||
value_serializer_heap
|
||||
.value_serializer_impl
|
||||
.as_mut()
|
||||
.throw_data_clone_error(scope, message)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn v8__ValueSerializer__Delegate__WriteHostObject(
|
||||
this: &mut CxxValueSerializerDelegate,
|
||||
_isolate: *mut Isolate,
|
||||
object: Local<Object>,
|
||||
) -> MaybeBool {
|
||||
let value_serializer_heap = ValueSerializerHeap::dispatch_mut(this);
|
||||
let scope =
|
||||
&mut crate::scope::CallbackScope::new(value_serializer_heap.context);
|
||||
let value_serializer_impl =
|
||||
value_serializer_heap.value_serializer_impl.as_mut();
|
||||
MaybeBool::from(value_serializer_impl.write_host_object(
|
||||
scope,
|
||||
object,
|
||||
&value_serializer_heap.cxx_value_serializer,
|
||||
))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn v8__ValueSerializer__Delegate__GetSharedArrayBufferId(
|
||||
this: &mut CxxValueSerializerDelegate,
|
||||
_isolate: *mut Isolate,
|
||||
shared_array_buffer: Local<SharedArrayBuffer>,
|
||||
clone_id: *mut u32,
|
||||
) -> bool {
|
||||
let value_serializer_heap = ValueSerializerHeap::dispatch_mut(this);
|
||||
let scope =
|
||||
&mut crate::scope::CallbackScope::new(value_serializer_heap.context);
|
||||
match value_serializer_heap
|
||||
.value_serializer_impl
|
||||
.as_mut()
|
||||
.get_shared_array_buffer_id(scope, shared_array_buffer)
|
||||
{
|
||||
Some(x) => {
|
||||
*clone_id = x;
|
||||
true
|
||||
}
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn v8__ValueSerializer__Delegate__GetWasmModuleTransferId(
|
||||
this: &mut CxxValueSerializerDelegate,
|
||||
_isolate: *mut Isolate,
|
||||
module: Local<WasmModuleObject>,
|
||||
transfer_id: *mut u32,
|
||||
) -> bool {
|
||||
let value_serializer_heap = ValueSerializerHeap::dispatch_mut(this);
|
||||
let scope =
|
||||
&mut crate::scope::CallbackScope::new(value_serializer_heap.context);
|
||||
match value_serializer_heap
|
||||
.value_serializer_impl
|
||||
.as_mut()
|
||||
.get_wasm_module_transfer_id(scope, module)
|
||||
{
|
||||
Some(x) => {
|
||||
*transfer_id = x;
|
||||
true
|
||||
}
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn v8__ValueSerializer__Delegate__ReallocateBufferMemory(
|
||||
this: &mut CxxValueSerializerDelegate,
|
||||
old_buffer: *mut c_void,
|
||||
size: usize,
|
||||
actual_size: *mut usize,
|
||||
) -> *mut c_void {
|
||||
let base = ValueSerializerHeap::dispatch_mut(this);
|
||||
|
||||
let new_buffer = if old_buffer.is_null() {
|
||||
let layout = Layout::from_size_align(size, 1).unwrap();
|
||||
alloc(layout)
|
||||
} else {
|
||||
let old_layout = Layout::from_size_align(base.buffer_size, 1).unwrap();
|
||||
realloc(old_buffer as *mut _, old_layout, size)
|
||||
};
|
||||
|
||||
base.buffer_size = size;
|
||||
|
||||
*actual_size = size;
|
||||
new_buffer as *mut c_void
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn v8__ValueSerializer__Delegate__FreeBufferMemory(
|
||||
this: &mut CxxValueSerializerDelegate,
|
||||
buffer: *mut c_void,
|
||||
) {
|
||||
let base = ValueSerializerHeap::dispatch_mut(this);
|
||||
if !buffer.is_null() {
|
||||
let layout = Layout::from_size_align(base.buffer_size, 1).unwrap();
|
||||
dealloc(buffer as *mut _, layout)
|
||||
};
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
fn v8__ValueSerializer__Delegate__CONSTRUCT(
|
||||
buf: *mut MaybeUninit<CxxValueSerializerDelegate>,
|
||||
);
|
||||
}
|
||||
|
||||
// Must be == sizeof(v8::ValueSerializer), see v8__ValueSerializer__CONSTRUCT().
|
||||
#[repr(C)]
|
||||
pub struct CxxValueSerializer {
|
||||
_cxx_vtable: CxxVTable,
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
fn v8__ValueSerializer__CONSTRUCT(
|
||||
buf: *mut MaybeUninit<CxxValueSerializer>,
|
||||
isolate: *mut Isolate,
|
||||
delegate: *mut CxxValueSerializerDelegate,
|
||||
);
|
||||
|
||||
fn v8__ValueSerializer__DESTRUCT(this: *mut CxxValueSerializer);
|
||||
|
||||
fn v8__ValueSerializer__Release(
|
||||
this: *mut CxxValueSerializer,
|
||||
ptr: *mut *mut u8,
|
||||
size: *mut usize,
|
||||
);
|
||||
|
||||
fn v8__ValueSerializer__TransferArrayBuffer(
|
||||
this: *mut CxxValueSerializer,
|
||||
transfer_id: u32,
|
||||
array_buffer: Local<ArrayBuffer>,
|
||||
);
|
||||
|
||||
fn v8__ValueSerializer__WriteHeader(this: *mut CxxValueSerializer);
|
||||
fn v8__ValueSerializer__WriteValue(
|
||||
this: *mut CxxValueSerializer,
|
||||
context: Local<Context>,
|
||||
value: Local<Value>,
|
||||
) -> MaybeBool;
|
||||
fn v8__ValueSerializer__WriteUint32(
|
||||
this: *mut CxxValueSerializer,
|
||||
value: u32,
|
||||
);
|
||||
fn v8__ValueSerializer__WriteUint64(
|
||||
this: *mut CxxValueSerializer,
|
||||
value: u64,
|
||||
);
|
||||
fn v8__ValueSerializer__WriteDouble(
|
||||
this: *mut CxxValueSerializer,
|
||||
value: f64,
|
||||
);
|
||||
fn v8__ValueSerializer__WriteRawBytes(
|
||||
this: *mut CxxValueSerializer,
|
||||
source: *const c_void,
|
||||
length: usize,
|
||||
);
|
||||
}
|
||||
|
||||
/// The ValueSerializerImpl trait allows for
|
||||
/// custom callback functions used by v8.
|
||||
pub trait ValueSerializerImpl {
|
||||
fn throw_data_clone_error<'s>(
|
||||
&mut self,
|
||||
scope: &mut HandleScope<'s>,
|
||||
message: Local<'s, String>,
|
||||
);
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn write_host_object<'s>(
|
||||
&mut self,
|
||||
scope: &mut HandleScope<'s>,
|
||||
object: Local<'s, Object>,
|
||||
value_serializer: &dyn ValueSerializerHelper,
|
||||
) -> Option<bool> {
|
||||
let msg =
|
||||
String::new(scope, "Deno serializer: write_host_object not implemented")
|
||||
.unwrap();
|
||||
let exc = Exception::error(scope, msg);
|
||||
scope.throw_exception(exc);
|
||||
None
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn get_shared_array_buffer_id<'s>(
|
||||
&mut self,
|
||||
scope: &mut HandleScope<'s>,
|
||||
shared_array_buffer: Local<'s, SharedArrayBuffer>,
|
||||
) -> Option<u32> {
|
||||
let msg = String::new(
|
||||
scope,
|
||||
"Deno serializer: get_shared_array_buffer_id not implemented",
|
||||
)
|
||||
.unwrap();
|
||||
let exc = Exception::error(scope, msg);
|
||||
scope.throw_exception(exc);
|
||||
None
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn get_wasm_module_transfer_id(
|
||||
&mut self,
|
||||
scope: &mut HandleScope<'_>,
|
||||
module: Local<WasmModuleObject>,
|
||||
) -> Option<u32> {
|
||||
let msg = String::new(
|
||||
scope,
|
||||
"Deno serializer: get_wasm_module_transfer_id not implemented",
|
||||
)
|
||||
.unwrap();
|
||||
let exc = Exception::error(scope, msg);
|
||||
scope.throw_exception(exc);
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// The ValueSerializerHeap object contains all objects related to serializer.
|
||||
/// This object has to be pinned to the heap because of the Cpp pointers that
|
||||
/// have to remain valid. Moving this object would result in the Cpp pointer
|
||||
/// to the delegate to become invalid and thus causing the delegate callback
|
||||
/// to fail. Additionally the serializer and implementation are also pinned
|
||||
/// in memory because these have to be accessable from within the delegate
|
||||
/// callback methods.
|
||||
pub struct ValueSerializerHeap<'a, 's> {
|
||||
value_serializer_impl: Box<dyn ValueSerializerImpl + 'a>,
|
||||
cxx_value_serializer_delegate: CxxValueSerializerDelegate,
|
||||
cxx_value_serializer: CxxValueSerializer,
|
||||
buffer_size: usize,
|
||||
context: Local<'s, Context>,
|
||||
}
|
||||
|
||||
impl<'a, 's> ValueSerializerHeap<'a, 's> {
|
||||
fn get_cxx_value_serializer_delegate_offset(
|
||||
) -> FieldOffset<CxxValueSerializerDelegate> {
|
||||
let buf = std::mem::MaybeUninit::<Self>::uninit();
|
||||
FieldOffset::from_ptrs(buf.as_ptr(), unsafe {
|
||||
&(*buf.as_ptr()).cxx_value_serializer_delegate
|
||||
})
|
||||
}
|
||||
|
||||
/// Starting from 'this' pointer a ValueSerializerHeap ref can be created
|
||||
pub unsafe fn dispatch(
|
||||
value_serializer_delegate: &'s CxxValueSerializerDelegate,
|
||||
) -> &Self {
|
||||
Self::get_cxx_value_serializer_delegate_offset()
|
||||
.to_embedder::<Self>(value_serializer_delegate)
|
||||
}
|
||||
|
||||
/// Starting from 'this' pointer the ValueSerializerHeap mut ref can be
|
||||
/// created
|
||||
pub unsafe fn dispatch_mut(
|
||||
value_serializer_delegate: &'s mut CxxValueSerializerDelegate,
|
||||
) -> &mut Self {
|
||||
Self::get_cxx_value_serializer_delegate_offset()
|
||||
.to_embedder_mut::<Self>(value_serializer_delegate)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 's> Drop for ValueSerializerHeap<'a, 's> {
|
||||
fn drop(&mut self) {
|
||||
unsafe { v8__ValueSerializer__DESTRUCT(&mut self.cxx_value_serializer) };
|
||||
}
|
||||
}
|
||||
|
||||
/// Trait used for direct write to the serialization buffer.
|
||||
/// Mostly used by the write_host_object callback function in the
|
||||
/// ValueSerializerImpl trait to create custom serialization logic.
|
||||
pub trait ValueSerializerHelper {
|
||||
fn get_cxx_value_serializer(&mut self) -> &mut CxxValueSerializer;
|
||||
|
||||
fn write_header(&mut self) {
|
||||
unsafe {
|
||||
v8__ValueSerializer__WriteHeader(self.get_cxx_value_serializer())
|
||||
};
|
||||
}
|
||||
|
||||
fn write_value(
|
||||
&mut self,
|
||||
context: Local<Context>,
|
||||
value: Local<Value>,
|
||||
) -> Option<bool> {
|
||||
unsafe {
|
||||
v8__ValueSerializer__WriteValue(
|
||||
self.get_cxx_value_serializer(),
|
||||
context,
|
||||
value,
|
||||
)
|
||||
}
|
||||
.into()
|
||||
}
|
||||
|
||||
fn write_uint32(&mut self, value: u32) {
|
||||
unsafe {
|
||||
v8__ValueSerializer__WriteUint32(self.get_cxx_value_serializer(), value)
|
||||
};
|
||||
}
|
||||
|
||||
fn write_uint64(&mut self, value: u64) {
|
||||
unsafe {
|
||||
v8__ValueSerializer__WriteUint64(self.get_cxx_value_serializer(), value)
|
||||
};
|
||||
}
|
||||
|
||||
fn write_double(&mut self, value: f64) {
|
||||
unsafe {
|
||||
v8__ValueSerializer__WriteDouble(self.get_cxx_value_serializer(), value)
|
||||
};
|
||||
}
|
||||
|
||||
fn write_raw_bytes(&mut self, source: &[u8]) {
|
||||
unsafe {
|
||||
v8__ValueSerializer__WriteRawBytes(
|
||||
self.get_cxx_value_serializer(),
|
||||
source.as_ptr() as *const _,
|
||||
source.len(),
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
fn transfer_array_buffer(
|
||||
&mut self,
|
||||
transfer_id: u32,
|
||||
array_buffer: Local<ArrayBuffer>,
|
||||
) {
|
||||
unsafe {
|
||||
v8__ValueSerializer__TransferArrayBuffer(
|
||||
self.get_cxx_value_serializer(),
|
||||
transfer_id,
|
||||
array_buffer,
|
||||
)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
impl ValueSerializerHelper for CxxValueSerializer {
|
||||
fn get_cxx_value_serializer(&mut self) -> &mut CxxValueSerializer {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 's> ValueSerializerHelper for ValueSerializerHeap<'a, 's> {
|
||||
fn get_cxx_value_serializer(&mut self) -> &mut CxxValueSerializer {
|
||||
&mut self.cxx_value_serializer
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 's> ValueSerializerHelper for ValueSerializer<'a, 's> {
|
||||
fn get_cxx_value_serializer(&mut self) -> &mut CxxValueSerializer {
|
||||
&mut (*self.value_serializer_heap).cxx_value_serializer
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ValueSerializer<'a, 's> {
|
||||
value_serializer_heap: Pin<Box<ValueSerializerHeap<'a, 's>>>,
|
||||
}
|
||||
|
||||
/// ValueSerializer is a stack object used as entry-point for an owned and
|
||||
/// pinned heap object ValueSerializerHeap.
|
||||
/// The 'a lifetime is the lifetime of the ValueSerializerImpl implementation.
|
||||
/// The 's lifetime is the lifetime of the HandleScope which is used to retrieve
|
||||
/// a Local<'s, Context> for the CallbackScopes
|
||||
impl<'a, 's> ValueSerializer<'a, 's> {
|
||||
pub fn new<D: ValueSerializerImpl + 'a>(
|
||||
scope: &mut HandleScope<'s>,
|
||||
value_serializer_impl: Box<D>,
|
||||
) -> Self {
|
||||
// create dummy ValueSerializerHeap 'a, and move to heap + pin to address
|
||||
let mut value_serializer_heap = Box::pin(ValueSerializerHeap {
|
||||
value_serializer_impl,
|
||||
cxx_value_serializer: CxxValueSerializer {
|
||||
_cxx_vtable: CxxVTable {
|
||||
0: std::ptr::null(),
|
||||
},
|
||||
},
|
||||
cxx_value_serializer_delegate: CxxValueSerializerDelegate {
|
||||
_cxx_vtable: CxxVTable {
|
||||
0: std::ptr::null(),
|
||||
},
|
||||
},
|
||||
buffer_size: 0,
|
||||
context: scope.get_current_context(),
|
||||
});
|
||||
|
||||
unsafe {
|
||||
v8__ValueSerializer__Delegate__CONSTRUCT(core::mem::transmute(
|
||||
&mut (*value_serializer_heap).cxx_value_serializer_delegate,
|
||||
));
|
||||
|
||||
v8__ValueSerializer__CONSTRUCT(
|
||||
core::mem::transmute(
|
||||
&mut (*value_serializer_heap).cxx_value_serializer,
|
||||
),
|
||||
scope.get_isolate_ptr(),
|
||||
&mut (*value_serializer_heap).cxx_value_serializer_delegate,
|
||||
);
|
||||
};
|
||||
|
||||
Self {
|
||||
value_serializer_heap,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 's> ValueSerializer<'a, 's> {
|
||||
pub fn release(mut self) -> Vec<u8> {
|
||||
unsafe {
|
||||
let mut size: usize = 0;
|
||||
let mut ptr: *mut u8 = &mut 0;
|
||||
v8__ValueSerializer__Release(
|
||||
&mut (*self.value_serializer_heap).cxx_value_serializer,
|
||||
&mut ptr,
|
||||
&mut size,
|
||||
);
|
||||
Vec::from_raw_parts(
|
||||
ptr as *mut u8,
|
||||
size,
|
||||
(*self.value_serializer_heap).buffer_size,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_value(
|
||||
&mut self,
|
||||
context: Local<Context>,
|
||||
value: Local<Value>,
|
||||
) -> Option<bool> {
|
||||
(*self.value_serializer_heap).write_value(context, value)
|
||||
}
|
||||
}
|
|
@ -3744,3 +3744,334 @@ fn bigint() {
|
|||
vec.resize(20, 1337);
|
||||
assert_eq!(raw_b.to_words_array(&mut vec), (true, &mut [10, 10][..]));
|
||||
}
|
||||
|
||||
// SerDes testing
|
||||
type ArrayBuffers = Vec<v8::SharedRef<v8::BackingStore>>;
|
||||
|
||||
struct Custom1Value<'a> {
|
||||
array_buffers: &'a mut ArrayBuffers,
|
||||
}
|
||||
|
||||
impl<'a> Custom1Value<'a> {
|
||||
fn serializer<'s>(
|
||||
scope: &mut v8::HandleScope<'s>,
|
||||
array_buffers: &'a mut ArrayBuffers,
|
||||
) -> v8::ValueSerializer<'a, 's> {
|
||||
v8::ValueSerializer::new(scope, Box::new(Self { array_buffers }))
|
||||
}
|
||||
|
||||
fn deserializer<'s>(
|
||||
scope: &mut v8::HandleScope<'s>,
|
||||
data: &[u8],
|
||||
array_buffers: &'a mut ArrayBuffers,
|
||||
) -> v8::ValueDeserializer<'a, 's> {
|
||||
v8::ValueDeserializer::new(scope, Box::new(Self { array_buffers }), data)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> v8::ValueSerializerImpl for Custom1Value<'a> {
|
||||
#[allow(unused_variables)]
|
||||
fn throw_data_clone_error<'s>(
|
||||
&mut self,
|
||||
scope: &mut v8::HandleScope<'s>,
|
||||
message: v8::Local<'s, v8::String>,
|
||||
) {
|
||||
let error = v8::Exception::error(scope, message);
|
||||
scope.throw_exception(error);
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn get_shared_array_buffer_id<'s>(
|
||||
&mut self,
|
||||
scope: &mut v8::HandleScope<'s>,
|
||||
shared_array_buffer: v8::Local<'s, v8::SharedArrayBuffer>,
|
||||
) -> Option<u32> {
|
||||
self
|
||||
.array_buffers
|
||||
.push(v8::SharedArrayBuffer::get_backing_store(
|
||||
&shared_array_buffer,
|
||||
));
|
||||
Some((self.array_buffers.len() as u32) - 1)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> v8::ValueDeserializerImpl for Custom1Value<'a> {
|
||||
#[allow(unused_variables)]
|
||||
fn get_shared_array_buffer_from_id<'s>(
|
||||
&mut self,
|
||||
scope: &mut v8::HandleScope<'s>,
|
||||
transfer_id: u32,
|
||||
) -> Option<v8::Local<'s, v8::SharedArrayBuffer>> {
|
||||
let backing_store = self.array_buffers.get(transfer_id as usize).unwrap();
|
||||
Some(v8::SharedArrayBuffer::with_backing_store(
|
||||
scope,
|
||||
backing_store,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn value_serializer_and_deserializer() {
|
||||
use v8::ValueDeserializerHelper;
|
||||
use v8::ValueSerializerHelper;
|
||||
|
||||
let _setup_guard = setup();
|
||||
let mut array_buffers = ArrayBuffers::new();
|
||||
let isolate = &mut v8::Isolate::new(Default::default());
|
||||
|
||||
let scope = &mut v8::HandleScope::new(isolate);
|
||||
|
||||
let context = v8::Context::new(scope);
|
||||
let scope = &mut v8::ContextScope::new(scope, context);
|
||||
let buffer;
|
||||
{
|
||||
let mut value_serializer =
|
||||
Custom1Value::serializer(scope, &mut array_buffers);
|
||||
value_serializer.write_header();
|
||||
value_serializer.write_double(55.44);
|
||||
value_serializer.write_uint32(22);
|
||||
buffer = value_serializer.release();
|
||||
}
|
||||
|
||||
let mut double: f64 = 0.0;
|
||||
let mut int32: u32 = 0;
|
||||
{
|
||||
let mut value_deserializer =
|
||||
Custom1Value::deserializer(scope, &buffer, &mut array_buffers);
|
||||
assert_eq!(value_deserializer.read_header(context), Some(true));
|
||||
assert_eq!(value_deserializer.read_double(&mut double), true);
|
||||
assert_eq!(value_deserializer.read_uint32(&mut int32), true);
|
||||
|
||||
assert_eq!(value_deserializer.read_uint32(&mut int32), false);
|
||||
}
|
||||
|
||||
assert_eq!((double - 55.44).abs() < f64::EPSILON, true);
|
||||
assert_eq!(int32, 22);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn value_serializer_and_deserializer_js_objects() {
|
||||
let buffer;
|
||||
let mut array_buffers = ArrayBuffers::new();
|
||||
{
|
||||
let _setup_guard = setup();
|
||||
let isolate = &mut v8::Isolate::new(Default::default());
|
||||
|
||||
let scope = &mut v8::HandleScope::new(isolate);
|
||||
|
||||
let context = v8::Context::new(scope);
|
||||
let scope = &mut v8::ContextScope::new(scope, context);
|
||||
|
||||
let objects: v8::Local<v8::Value> = eval(
|
||||
scope,
|
||||
r#"[
|
||||
undefined,
|
||||
true,
|
||||
false,
|
||||
null,
|
||||
33,
|
||||
44.444,
|
||||
99999.55434344,
|
||||
"test",
|
||||
[1, 2, 3],
|
||||
{a: "tt", add: "tsqqqss"}
|
||||
]"#,
|
||||
)
|
||||
.unwrap();
|
||||
let mut value_serializer =
|
||||
Custom1Value::serializer(scope, &mut array_buffers);
|
||||
assert_eq!(value_serializer.write_value(context, objects), Some(true));
|
||||
|
||||
buffer = value_serializer.release();
|
||||
}
|
||||
|
||||
{
|
||||
let _setup_guard = setup();
|
||||
let isolate = &mut v8::Isolate::new(Default::default());
|
||||
|
||||
let scope = &mut v8::HandleScope::new(isolate);
|
||||
|
||||
let context = v8::Context::new(scope);
|
||||
let scope = &mut v8::ContextScope::new(scope, context);
|
||||
|
||||
let mut value_deserializer =
|
||||
Custom1Value::deserializer(scope, &buffer, &mut array_buffers);
|
||||
let name = v8::String::new(scope, "objects").unwrap();
|
||||
let objects: v8::Local<v8::Value> =
|
||||
value_deserializer.read_value(context).unwrap();
|
||||
|
||||
context.global(scope).set(scope, name.into(), objects);
|
||||
|
||||
let result: v8::Local<v8::Value> = eval(
|
||||
scope,
|
||||
r#"
|
||||
{
|
||||
const compare = [
|
||||
undefined,
|
||||
true,
|
||||
false,
|
||||
null,
|
||||
33,
|
||||
44.444,
|
||||
99999.55434344,
|
||||
"test",
|
||||
[1, 2, 3],
|
||||
{a: "tt", add: "tsqqqss"}
|
||||
];
|
||||
let equal = true;
|
||||
function obj_isEquivalent(a, b) {
|
||||
if (a == null) return b == null;
|
||||
let aProps = Object.getOwnPropertyNames(a);
|
||||
let bProps = Object.getOwnPropertyNames(b);
|
||||
if (aProps.length != bProps.length) return false;
|
||||
for (let i = 0; i < aProps.length; i++) {
|
||||
let propName = aProps[i];
|
||||
if (a[propName] !== b[propName]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
function arr_isEquivalent(a, b) {
|
||||
if (a.length != b.length) return false;
|
||||
for (let i = 0; i < Math.max(a.length, b.length); i++) {
|
||||
if (a[i] !== b[i]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
objects.forEach(function (item, index) {
|
||||
let other = compare[index];
|
||||
if (Array.isArray(item)) {
|
||||
equal = equal && arr_isEquivalent(item, other);
|
||||
} else if (typeof item == 'object') {
|
||||
equal = equal && obj_isEquivalent(item, other);
|
||||
} else {
|
||||
equal = equal && (item == objects[index]);
|
||||
}
|
||||
});
|
||||
equal.toString()
|
||||
}
|
||||
"#,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let expected = v8::String::new(scope, "true").unwrap();
|
||||
assert!(expected.strict_equals(result));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn value_serializer_and_deserializer_array_buffers() {
|
||||
let buffer;
|
||||
let mut array_buffers = ArrayBuffers::new();
|
||||
{
|
||||
let _setup_guard = setup();
|
||||
let isolate = &mut v8::Isolate::new(Default::default());
|
||||
|
||||
let scope = &mut v8::HandleScope::new(isolate);
|
||||
|
||||
let context = v8::Context::new(scope);
|
||||
let scope = &mut v8::ContextScope::new(scope, context);
|
||||
|
||||
let objects: v8::Local<v8::Value> = eval(
|
||||
scope,
|
||||
r#"{
|
||||
var sab = new SharedArrayBuffer(10);
|
||||
var arr = new Int8Array(sab);
|
||||
arr[3] = 4;
|
||||
sab
|
||||
}"#,
|
||||
)
|
||||
.unwrap();
|
||||
let mut value_serializer =
|
||||
Custom1Value::serializer(scope, &mut array_buffers);
|
||||
assert_eq!(value_serializer.write_value(context, objects), Some(true));
|
||||
|
||||
buffer = value_serializer.release();
|
||||
}
|
||||
|
||||
{
|
||||
let _setup_guard = setup();
|
||||
let isolate = &mut v8::Isolate::new(Default::default());
|
||||
|
||||
let scope = &mut v8::HandleScope::new(isolate);
|
||||
|
||||
let context = v8::Context::new(scope);
|
||||
let scope = &mut v8::ContextScope::new(scope, context);
|
||||
|
||||
let mut value_deserializer =
|
||||
Custom1Value::deserializer(scope, &buffer, &mut array_buffers);
|
||||
let name = v8::String::new(scope, "objects").unwrap();
|
||||
let objects: v8::Local<v8::Value> =
|
||||
value_deserializer.read_value(context).unwrap();
|
||||
|
||||
context.global(scope).set(scope, name.into(), objects);
|
||||
|
||||
let result: v8::Local<v8::Value> = eval(
|
||||
scope,
|
||||
r#"
|
||||
{
|
||||
var arr = new Int8Array(objects);
|
||||
arr.toString()
|
||||
}
|
||||
"#,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let expected = v8::String::new(scope, "0,0,0,4,0,0,0,0,0,0").unwrap();
|
||||
assert!(expected.strict_equals(result));
|
||||
}
|
||||
}
|
||||
|
||||
struct Custom2Value {}
|
||||
|
||||
impl<'a> Custom2Value {
|
||||
fn serializer<'s>(
|
||||
scope: &mut v8::HandleScope<'s>,
|
||||
) -> v8::ValueSerializer<'a, 's> {
|
||||
v8::ValueSerializer::new(scope, Box::new(Self {}))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> v8::ValueSerializerImpl for Custom2Value {
|
||||
#[allow(unused_variables)]
|
||||
fn throw_data_clone_error<'s>(
|
||||
&mut self,
|
||||
scope: &mut v8::HandleScope<'s>,
|
||||
message: v8::Local<'s, v8::String>,
|
||||
) {
|
||||
let error = v8::Exception::error(scope, message);
|
||||
scope.throw_exception(error);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn value_serializer_not_implemented() {
|
||||
let _setup_guard = setup();
|
||||
let isolate = &mut v8::Isolate::new(Default::default());
|
||||
|
||||
let scope = &mut v8::HandleScope::new(isolate);
|
||||
|
||||
let context = v8::Context::new(scope);
|
||||
let scope = &mut v8::ContextScope::new(scope, context);
|
||||
let scope = &mut v8::TryCatch::new(scope);
|
||||
|
||||
let objects: v8::Local<v8::Value> = eval(
|
||||
scope,
|
||||
r#"{
|
||||
var sab = new SharedArrayBuffer(10);
|
||||
var arr = new Int8Array(sab);
|
||||
arr[3] = 4;
|
||||
sab
|
||||
}"#,
|
||||
)
|
||||
.unwrap();
|
||||
let mut value_serializer = Custom2Value::serializer(scope);
|
||||
assert_eq!(value_serializer.write_value(context, objects), None);
|
||||
|
||||
assert!(scope.exception().is_some());
|
||||
assert!(scope.stack_trace().is_some());
|
||||
assert!(scope.message().is_some());
|
||||
assert_eq!(
|
||||
scope.message().unwrap().get(scope).to_rust_string_lossy(scope),
|
||||
"Uncaught Error: Deno serializer: get_shared_array_buffer_id not implemented"
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue