diff options
Diffstat (limited to 'core')
-rw-r--r-- | core/bindings.rs | 112 | ||||
-rw-r--r-- | core/runtime.rs | 16 | ||||
-rw-r--r-- | core/serialize_deserialize_test.js | 69 |
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(); |