summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/bindings.rs112
-rw-r--r--core/runtime.rs16
-rw-r--r--core/serialize_deserialize_test.js69
3 files changed, 182 insertions, 15 deletions
diff --git a/core/bindings.rs b/core/bindings.rs
index 0703117c7..08f244166 100644
--- a/core/bindings.rs
+++ b/core/bindings.rs
@@ -47,6 +47,12 @@ lazy_static! {
function: decode.map_fn_to()
},
v8::ExternalReference {
+ function: serialize.map_fn_to()
+ },
+ v8::ExternalReference {
+ function: deserialize.map_fn_to()
+ },
+ v8::ExternalReference {
function: get_promise_details.map_fn_to()
},
v8::ExternalReference {
@@ -124,6 +130,8 @@ pub fn initialize_context<'s>(
set_func(scope, core_val, "evalContext", eval_context);
set_func(scope, core_val, "encode", encode);
set_func(scope, core_val, "decode", decode);
+ set_func(scope, core_val, "serialize", serialize);
+ set_func(scope, core_val, "deserialize", deserialize);
set_func(scope, core_val, "getPromiseDetails", get_promise_details);
set_func(scope, core_val, "getProxyDetails", get_proxy_details);
@@ -427,9 +435,7 @@ fn eval_context(
let source = match v8::Local::<v8::String>::try_from(args.get(0)) {
Ok(s) => s,
Err(_) => {
- let msg = v8::String::new(scope, "Invalid argument").unwrap();
- let exception = v8::Exception::type_error(scope, msg);
- scope.throw_exception(exception);
+ throw_type_error(scope, "Invalid argument");
return;
}
};
@@ -550,9 +556,7 @@ fn encode(
let text = match v8::Local::<v8::String>::try_from(args.get(0)) {
Ok(s) => s,
Err(_) => {
- let msg = v8::String::new(scope, "Invalid argument").unwrap();
- let exception = v8::Exception::type_error(scope, msg);
- scope.throw_exception(exception);
+ throw_type_error(scope, "Invalid argument");
return;
}
};
@@ -583,9 +587,7 @@ fn decode(
let view = match v8::Local::<v8::ArrayBufferView>::try_from(args.get(0)) {
Ok(view) => view,
Err(_) => {
- let msg = v8::String::new(scope, "Invalid argument").unwrap();
- let exception = v8::Exception::type_error(scope, msg);
- scope.throw_exception(exception);
+ throw_type_error(scope, "Invalid argument");
return;
}
};
@@ -625,6 +627,90 @@ fn decode(
};
}
+struct SerializeDeserialize {}
+
+impl v8::ValueSerializerImpl for SerializeDeserialize {
+ #[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);
+ }
+}
+
+impl v8::ValueDeserializerImpl for SerializeDeserialize {}
+
+fn serialize(
+ scope: &mut v8::HandleScope,
+ args: v8::FunctionCallbackArguments,
+ mut rv: v8::ReturnValue,
+) {
+ let serialize_deserialize = Box::new(SerializeDeserialize {});
+ let mut value_serializer =
+ v8::ValueSerializer::new(scope, serialize_deserialize);
+ match value_serializer.write_value(scope.get_current_context(), args.get(0)) {
+ Some(true) => {
+ let vector = value_serializer.release();
+ let buf = {
+ let buf_len = vector.len();
+ let backing_store = v8::ArrayBuffer::new_backing_store_from_boxed_slice(
+ vector.into_boxed_slice(),
+ );
+ let backing_store_shared = backing_store.make_shared();
+ let ab =
+ v8::ArrayBuffer::with_backing_store(scope, &backing_store_shared);
+ v8::Uint8Array::new(scope, ab, 0, buf_len)
+ .expect("Failed to create UintArray8")
+ };
+
+ rv.set(buf.into());
+ }
+ _ => {
+ throw_type_error(scope, "Invalid argument");
+ }
+ }
+}
+
+fn deserialize(
+ scope: &mut v8::HandleScope,
+ args: v8::FunctionCallbackArguments,
+ mut rv: v8::ReturnValue,
+) {
+ let view = match v8::Local::<v8::ArrayBufferView>::try_from(args.get(0)) {
+ Ok(view) => view,
+ Err(_) => {
+ throw_type_error(scope, "Invalid argument");
+ return;
+ }
+ };
+
+ let backing_store = view.buffer(scope).unwrap().get_backing_store();
+ let buf = unsafe {
+ get_backing_store_slice(
+ &backing_store,
+ view.byte_offset(),
+ view.byte_length(),
+ )
+ };
+
+ let serialize_deserialize = Box::new(SerializeDeserialize {});
+ let mut value_deserializer =
+ v8::ValueDeserializer::new(scope, serialize_deserialize, buf);
+ let value = value_deserializer.read_value(scope.get_current_context());
+
+ match value {
+ Some(deserialized) => rv.set(deserialized),
+ None => {
+ let msg = v8::String::new(scope, "string too long").unwrap();
+ let exception = v8::Exception::range_error(scope, msg);
+ scope.throw_exception(exception);
+ }
+ };
+}
+
fn queue_microtask(
scope: &mut v8::HandleScope,
args: v8::FunctionCallbackArguments,
@@ -633,9 +719,7 @@ fn queue_microtask(
match v8::Local::<v8::Function>::try_from(args.get(0)) {
Ok(f) => scope.enqueue_microtask(f),
Err(_) => {
- let msg = v8::String::new(scope, "Invalid argument").unwrap();
- let exception = v8::Exception::type_error(scope, msg);
- scope.throw_exception(exception);
+ throw_type_error(scope, "Invalid argument");
}
};
}
@@ -725,9 +809,7 @@ fn get_promise_details(
let promise = match v8::Local::<v8::Promise>::try_from(args.get(0)) {
Ok(val) => val,
Err(_) => {
- let msg = v8::String::new(scope, "Invalid argument").unwrap();
- let exception = v8::Exception::type_error(scope, msg);
- scope.throw_exception(exception);
+ throw_type_error(scope, "Invalid argument");
return;
}
};
diff --git a/core/runtime.rs b/core/runtime.rs
index 05d76b4d5..9db1669cd 100644
--- a/core/runtime.rs
+++ b/core/runtime.rs
@@ -2039,6 +2039,22 @@ pub mod tests {
}
#[test]
+ fn test_serialize_deserialize() {
+ run_in_task(|mut cx| {
+ let (mut runtime, _dispatch_count) = setup(Mode::Async);
+ runtime
+ .execute(
+ "serialize_deserialize_test.js",
+ include_str!("serialize_deserialize_test.js"),
+ )
+ .unwrap();
+ if let Poll::Ready(Err(_)) = runtime.poll_event_loop(&mut cx) {
+ unreachable!();
+ }
+ });
+ }
+
+ #[test]
fn will_snapshot() {
let snapshot = {
let mut runtime = JsRuntime::new(RuntimeOptions {
diff --git a/core/serialize_deserialize_test.js b/core/serialize_deserialize_test.js
new file mode 100644
index 000000000..6368d56db
--- /dev/null
+++ b/core/serialize_deserialize_test.js
@@ -0,0 +1,69 @@
+// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
+"use strict";
+
+function assert(cond) {
+ if (!cond) {
+ throw Error("assert");
+ }
+}
+
+function assertArrayEquals(a1, a2) {
+ if (a1.length !== a2.length) throw Error("assert");
+
+ for (const index in a1) {
+ if (a1[index] !== a2[index]) {
+ throw Error("assert");
+ }
+ }
+}
+
+function main() {
+ const emptyString = "";
+ const emptyStringSerialized = [34, 0];
+ assertArrayEquals(Deno.core.serialize(emptyString), emptyStringSerialized);
+ assert(
+ Deno.core.deserialize(new Uint8Array(emptyStringSerialized)) ===
+ emptyString,
+ );
+
+ const primitiveValueArray = ["test", "a", null, undefined];
+ // deno-fmt-ignore
+ const primitiveValueArraySerialized = [
+ 65, 4, 34, 4, 116, 101, 115, 116,
+ 34, 1, 97, 48, 95, 36, 0, 4,
+ ];
+ assertArrayEquals(
+ Deno.core.serialize(primitiveValueArray),
+ primitiveValueArraySerialized,
+ );
+
+ assertArrayEquals(
+ Deno.core.deserialize(
+ new Uint8Array(primitiveValueArraySerialized),
+ ),
+ primitiveValueArray,
+ );
+
+ const circularObject = { test: null, test2: "dd", test3: "aa" };
+ circularObject.test = circularObject;
+ // deno-fmt-ignore
+ const circularObjectSerialized = [
+ 111, 34, 4, 116, 101, 115, 116, 94,
+ 0, 34, 5, 116, 101, 115, 116, 50,
+ 34, 2, 100, 100, 34, 5, 116, 101,
+ 115, 116, 51, 34, 2, 97, 97, 123,
+ 3,
+ ];
+
+ assertArrayEquals(
+ Deno.core.serialize(circularObject),
+ circularObjectSerialized,
+ );
+
+ const deserializedCircularObject = Deno.core.deserialize(
+ new Uint8Array(circularObjectSerialized),
+ );
+ assert(deserializedCircularObject.test == deserializedCircularObject);
+}
+
+main();