From e75ffab0c8a21ecb0827bb906905cd0315c1b5a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Wed, 9 Jun 2021 20:37:43 +0200 Subject: [PATCH] chore: move serde_v8 to separate repo (#10909) Now available at https://github.com/denoland/serde_v8 --- Cargo.lock | 4 +- Cargo.toml | 1 - core/Cargo.toml | 3 +- serde_v8/Cargo.toml | 29 -- serde_v8/README.md | 57 --- serde_v8/benches/de.rs | 160 -------- serde_v8/benches/ser.rs | 108 ----- serde_v8/examples/basic.rs | 58 --- serde_v8/src/de.rs | 617 ---------------------------- serde_v8/src/error.rs | 46 --- serde_v8/src/keys.rs | 33 -- serde_v8/src/lib.rs | 17 - serde_v8/src/magic/buffer.rs | 139 ------- serde_v8/src/magic/field.rs | 144 ------- serde_v8/src/magic/mod.rs | 8 - serde_v8/src/magic/value.rs | 79 ---- serde_v8/src/magic/zero_copy_buf.rs | 102 ----- serde_v8/src/payload.rs | 34 -- serde_v8/src/ser.rs | 559 ------------------------- serde_v8/src/serializable.rs | 118 ------ serde_v8/src/utils.rs | 34 -- serde_v8/tests/de.rs | 223 ---------- serde_v8/tests/magic.rs | 124 ------ serde_v8/tests/ser.rs | 132 ------ tools/cut_a_release.md | 3 - 25 files changed, 3 insertions(+), 2829 deletions(-) delete mode 100644 serde_v8/Cargo.toml delete mode 100644 serde_v8/README.md delete mode 100644 serde_v8/benches/de.rs delete mode 100644 serde_v8/benches/ser.rs delete mode 100644 serde_v8/examples/basic.rs delete mode 100644 serde_v8/src/de.rs delete mode 100644 serde_v8/src/error.rs delete mode 100644 serde_v8/src/keys.rs delete mode 100644 serde_v8/src/lib.rs delete mode 100644 serde_v8/src/magic/buffer.rs delete mode 100644 serde_v8/src/magic/field.rs delete mode 100644 serde_v8/src/magic/mod.rs delete mode 100644 serde_v8/src/magic/value.rs delete mode 100644 serde_v8/src/magic/zero_copy_buf.rs delete mode 100644 serde_v8/src/payload.rs delete mode 100644 serde_v8/src/ser.rs delete mode 100644 serde_v8/src/serializable.rs delete mode 100644 serde_v8/src/utils.rs delete mode 100644 serde_v8/tests/de.rs delete mode 100644 serde_v8/tests/magic.rs delete mode 100644 serde_v8/tests/ser.rs diff --git a/Cargo.lock b/Cargo.lock index bb2144df23..098c2799b5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2906,11 +2906,11 @@ dependencies = [ [[package]] name = "serde_v8" version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d1c602ced78c18b33338c832d79595e75ac6fd204d20fd4cc462ce5af29a75e" dependencies = [ - "bencher", "rusty_v8", "serde", - "serde_json", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 98ea64293c..5f60ac6602 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,6 @@ members = [ "cli", "core", "runtime", - "serde_v8", "test_plugin", "test_util", "extensions/broadcast_channel", diff --git a/core/Cargo.toml b/core/Cargo.toml index 9bee37188b..a9abf68c82 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -13,8 +13,6 @@ repository = "https://github.com/denoland/deno" path = "lib.rs" [dependencies] -serde_v8 = { version = "0.4.1", path = "../serde_v8" } - anyhow = "1.0.40" futures = "0.3.15" indexmap = "1.6.2" @@ -25,6 +23,7 @@ pin-project = "1.0.6" rusty_v8 = "0.22.3" serde = { version = "1.0.125", features = ["derive"] } serde_json = { version = "1.0.64", features = ["preserve_order"] } +serde_v8 = { version = "0.4.1" } url = { version = "2.2.1", features = ["serde"] } [[example]] diff --git a/serde_v8/Cargo.toml b/serde_v8/Cargo.toml deleted file mode 100644 index 78a064626a..0000000000 --- a/serde_v8/Cargo.toml +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -[package] -name = "serde_v8" -version = "0.4.1" -authors = ["the Deno authors"] -edition = "2018" -description = "Rust to V8 serialization and deserialization" -license = "MIT" -readme = "README.md" -repository = "https://github.com/denoland/deno" - -[dependencies] -serde = { version = "1.0.125", features = ["derive"] } -rusty_v8 = "0.22.2" - -[dev-dependencies] -serde_json = "1.0.64" -bencher = "0.1" - -[[example]] -name = "basic" - -[[bench]] -name = "de" -harness = false - -[[bench]] -name = "ser" -harness = false diff --git a/serde_v8/README.md b/serde_v8/README.md deleted file mode 100644 index 207f8baf49..0000000000 --- a/serde_v8/README.md +++ /dev/null @@ -1,57 +0,0 @@ -# serde_v8 - -Author: Aaron O'Mullan - -Serde support for encoding/decoding (rusty_)v8 values. - -Broadly `serde_v8` aims to provide an expressive but ~maximally efficient -encoding layer to biject rust & v8/js values. It's a core component of deno's -op-layer and is used to encode/decode all non-buffer values. - -**Original issue:** -[denoland/deno#9540](https://github.com/denoland/deno/issues/9540) - -## Quickstart - -`serde_v8` fits naturally into the serde ecosystem, so if you've already used -`serde` or `serde_json`, `serde_v8`'s API should be very familiar. - -`serde_v8` exposes two key-functions: - -- `to_v8`: maps `rust->v8`, similar to `serde_json::to_string`, ... -- `from_v8`: maps `v8->rust`, similar to `serde_json::from_str`, ... - -## Best practices - -Whilst `serde_v8` is compatible with `serde_json::Value` it's important to keep -in mind that `serde_json::Value` is essentially a loosely-typed value (think -nested HashMaps), so when writing ops we recommend directly using rust -structs/tuples or primitives, since mapping to `serde_json::Value` will add -extra overhead and result in slower ops. - -I also recommend avoiding unecessary "wrappers", if your op takes a single-keyed -struct, consider unwrapping that as a plain value unless you plan to add fields -in the near-future. - -Instead of returning "nothing" via `Ok(json!({}))`, change your return type to -rust's unit type `()` and returning `Ok(())`, `serde_v8` will efficiently encode -that as a JS `null`. - -## Advanced features - -If you need to mix rust & v8 values in structs/tuples, you can use the special -`serde_v8::Value` type, which will passthrough the original v8 value untouched -when encoding/decoding. - -## TODO - -- [ ] Experiment with KeyCache to optimize struct keys -- [ ] Experiment with external v8 strings -- [ ] Explore using - [json-stringifier.cc](https://chromium.googlesource.com/v8/v8/+/refs/heads/master/src/json/json-stringifier.cc)'s - fast-paths for arrays -- [ ] Improve tests to test parity with `serde_json` (should be mostly - interchangeable) -- [ ] Consider a `Payload` type that's deserializable by itself (holds scope & - value) -- [ ] Ensure we return errors instead of panicking on `.unwrap()`s diff --git a/serde_v8/benches/de.rs b/serde_v8/benches/de.rs deleted file mode 100644 index 6bd4f0f9b0..0000000000 --- a/serde_v8/benches/de.rs +++ /dev/null @@ -1,160 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -use bencher::{benchmark_group, benchmark_main, Bencher}; - -use rusty_v8 as v8; -use std::convert::TryFrom; - -use serde::Deserialize; - -use serde_v8::utils::{js_exec, v8_do}; - -#[derive(Debug, Deserialize, PartialEq)] -struct MathOp { - arg1: u64, - arg2: u64, - operator: Option, -} - -fn dedo( - code: &str, - f: impl FnOnce(&mut v8::HandleScope, v8::Local), -) { - v8_do(|| { - let isolate = &mut v8::Isolate::new(v8::CreateParams::default()); - let handle_scope = &mut v8::HandleScope::new(isolate); - let context = v8::Context::new(handle_scope); - let scope = &mut v8::ContextScope::new(handle_scope, context); - let v = js_exec(scope, code); - - f(scope, v); - }) -} - -fn dedo_json(code: &str, f: impl FnOnce(String)) { - let code = format!("JSON.stringify({})", code); - dedo(&code[..], |scope, v| { - let s: String = serde_v8::from_v8(scope, v).unwrap(); - f(s); - }) -} - -fn de_struct_v8(b: &mut Bencher) { - dedo("({arg1: 10, arg2: 123 })", |scope, obj| { - let mut total = 0; - b.iter(move || { - let op: MathOp = serde_v8::from_v8(scope, obj).unwrap(); - total = total + op.arg1 + op.arg2; - }); - }); -} - -fn de_struct_v8_opt(b: &mut Bencher) { - dedo("({arg1: 10, arg2: 123 })", |scope, v| { - let k_arg1 = v8::String::new(scope, "arg1").unwrap().into(); - let k_arg2 = v8::String::new(scope, "arg2").unwrap().into(); - let obj = v8::Local::::try_from(v).unwrap(); - let mut total = 0; - b.iter(move || { - let v_arg1 = obj.get(scope, k_arg1).unwrap(); - let v_arg2 = obj.get(scope, k_arg2).unwrap(); - let op = MathOp { - arg1: serde_v8::from_v8(scope, v_arg1).unwrap(), - arg2: serde_v8::from_v8(scope, v_arg2).unwrap(), - operator: None, - }; - total = total + op.arg1 + op.arg2; - }); - }); -} - -fn de_struct_json(b: &mut Bencher) { - dedo_json("({arg1: 10, arg2: 123 })", |s| { - let mut total = 0; - b.iter(move || { - let op: MathOp = serde_json::from_str(&s).unwrap(); - total = total + op.arg1 + op.arg2; - }); - }); -} - -fn de_struct_json_deopt(b: &mut Bencher) { - // JSON.stringify() in loop (semi-simulating ABI loop) - dedo("({arg1: 10, arg2: 123 })", |scope, obj| { - let mut total = 0; - b.iter(move || { - let mut scope = v8::HandleScope::new(scope); - let s = v8::json::stringify(&mut scope, obj).unwrap(); - let rs = s.to_rust_string_lossy(&mut scope); - let op: MathOp = serde_json::from_str(&rs).unwrap(); - total = total + op.arg1 + op.arg2; - }); - }); -} - -macro_rules! dualbench { - ($v8_fn:ident, $json_fn:ident, $src:expr, $t:ty) => { - fn $v8_fn(b: &mut Bencher) { - dedo($src, |scope, v| { - b.iter(move || { - let _: $t = serde_v8::from_v8(scope, v).unwrap(); - }); - }); - } - - fn $json_fn(b: &mut Bencher) { - dedo_json($src, |s| { - b.iter(move || { - let _: $t = serde_json::from_str(&s).unwrap(); - }); - }); - } - }; -} - -dualbench!(de_bool_v8, de_bool_json, "true", bool); -dualbench!(de_int_v8, de_int_json, "12345", u32); -dualbench!( - de_array_v8, - de_array_json, - "[1,2,3,4,5,6,7,8,9,10]", - Vec -); -dualbench!(de_str_v8, de_str_json, "'hello world'", String); -dualbench!(de_tuple_v8, de_tuple_json, "[1,false]", (u8, bool)); - -fn de_tuple_v8_opt(b: &mut Bencher) { - dedo("[1,false]", |scope, obj| { - let arr = v8::Local::::try_from(obj).unwrap(); - let obj = v8::Local::::from(arr); - - b.iter(move || { - let v1 = obj.get_index(scope, 0).unwrap(); - let v2 = obj.get_index(scope, 1).unwrap(); - let _: (u8, bool) = ( - serde_v8::from_v8(scope, v1).unwrap(), - serde_v8::from_v8(scope, v2).unwrap(), - ); - }); - }); -} - -benchmark_group!( - benches, - de_struct_v8, - de_struct_v8_opt, - de_struct_json, - de_struct_json_deopt, - de_bool_v8, - de_bool_json, - de_int_v8, - de_int_json, - de_array_v8, - de_array_json, - de_str_v8, - de_str_json, - de_tuple_v8, - de_tuple_json, - de_tuple_v8_opt, -); - -benchmark_main!(benches); diff --git a/serde_v8/benches/ser.rs b/serde_v8/benches/ser.rs deleted file mode 100644 index d62e264cd1..0000000000 --- a/serde_v8/benches/ser.rs +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -use bencher::{benchmark_group, benchmark_main, Bencher}; - -use rusty_v8 as v8; - -use serde::Serialize; - -use serde_v8::utils::v8_do; - -#[derive(Serialize)] -struct MathOp { - arg1: u64, - arg2: u64, - operator: Option, -} - -fn serdo(f: impl FnOnce(&mut v8::HandleScope)) { - v8_do(|| { - let isolate = &mut v8::Isolate::new(v8::CreateParams::default()); - let handle_scope = &mut v8::HandleScope::new(isolate); - let context = v8::Context::new(handle_scope); - let scope = &mut v8::ContextScope::new(handle_scope, context); - - f(scope); - }) -} - -macro_rules! dualbench { - ($v8_fn:ident, $json_fn:ident, $src:expr) => { - fn $v8_fn(b: &mut Bencher) { - serdo(|scope| { - let v = $src; - b.iter(move || { - let _ = serde_v8::to_v8(scope, &v).unwrap(); - }); - }); - } - - fn $json_fn(b: &mut Bencher) { - let v = $src; - b.iter(move || { - let _ = serde_json::to_string(&v).unwrap(); - }); - } - }; -} - -dualbench!( - ser_struct_v8, - ser_struct_json, - MathOp { - arg1: 10, - arg2: 123, - operator: None - } -); -dualbench!(ser_bool_v8, ser_bool_json, true); -dualbench!(ser_int_v8, ser_int_json, 12345); -dualbench!( - ser_array_v8, - ser_array_json, - vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10] -); -dualbench!(ser_str_v8, ser_str_json, "hello world"); -dualbench!(ser_tuple_v8, ser_tuple_json, (1, false)); - -fn ser_struct_v8_manual(b: &mut Bencher) { - serdo(|scope| { - let v = MathOp { - arg1: 10, - arg2: 123, - operator: None, - }; - b.iter(|| { - let obj = v8::Object::new(scope); - let k1 = v8::String::new(scope, "arg1").unwrap(); - let k2 = v8::String::new(scope, "arg2").unwrap(); - let k3 = v8::String::new(scope, "operator").unwrap(); - // let k1 = v8::String::new_from_utf8(scope, "arg1".as_ref(), v8::NewStringType::Internalized).unwrap(); - // let k2 = v8::String::new_from_utf8(scope, "arg2".as_ref(), v8::NewStringType::Internalized).unwrap(); - // let k3 = v8::String::new_from_utf8(scope, "operator".as_ref(), v8::NewStringType::Internalized).unwrap(); - let v1 = v8::Number::new(scope, v.arg1 as f64); - let v2 = v8::Number::new(scope, v.arg2 as f64); - let v3 = v8::null(scope); - obj.set(scope, k1.into(), v1.into()).unwrap(); - obj.set(scope, k2.into(), v2.into()).unwrap(); - obj.set(scope, k3.into(), v3.into()).unwrap(); - }); - }); -} - -benchmark_group!( - benches, - ser_struct_v8, - ser_struct_json, - ser_bool_v8, - ser_bool_json, - ser_int_v8, - ser_int_json, - ser_array_v8, - ser_array_json, - ser_str_v8, - ser_str_json, - ser_tuple_v8, - ser_tuple_json, - ser_struct_v8_manual, -); -benchmark_main!(benches); diff --git a/serde_v8/examples/basic.rs b/serde_v8/examples/basic.rs deleted file mode 100644 index 6567a51d8e..0000000000 --- a/serde_v8/examples/basic.rs +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -use rusty_v8 as v8; - -use serde::Deserialize; - -#[derive(Debug, Deserialize)] -struct MathOp { - pub a: u64, - pub b: u64, - pub operator: Option, -} - -fn main() { - let platform = v8::new_default_platform().unwrap(); - v8::V8::initialize_platform(platform); - v8::V8::initialize(); - - { - let isolate = &mut v8::Isolate::new(v8::CreateParams::default()); - let handle_scope = &mut v8::HandleScope::new(isolate); - let context = v8::Context::new(handle_scope); - let scope = &mut v8::ContextScope::new(handle_scope, context); - - fn exec<'s>( - scope: &mut v8::HandleScope<'s>, - src: &str, - ) -> v8::Local<'s, v8::Value> { - let code = v8::String::new(scope, src).unwrap(); - let script = v8::Script::compile(scope, code, None).unwrap(); - script.run(scope).unwrap() - } - - let v = exec(scope, "32"); - let x32: u64 = serde_v8::from_v8(scope, v).unwrap(); - println!("x32 = {}", x32); - - let v = exec(scope, "({a: 1, b: 3, c: 'ignored'})"); - let mop: MathOp = serde_v8::from_v8(scope, v).unwrap(); - println!("mop = {:?}", mop); - - let v = exec(scope, "[1,2,3,4,5]"); - let arr: Vec = serde_v8::from_v8(scope, v).unwrap(); - println!("arr = {:?}", arr); - - let v = exec(scope, "['hello', 'world']"); - let hi: Vec = serde_v8::from_v8(scope, v).unwrap(); - println!("hi = {:?}", hi); - - let v: v8::Local = v8::Number::new(scope, 12345.0).into(); - let x: f64 = serde_v8::from_v8(scope, v).unwrap(); - println!("x = {}", x); - } - - unsafe { - v8::V8::dispose(); - } - v8::V8::shutdown_platform(); -} diff --git a/serde_v8/src/de.rs b/serde_v8/src/de.rs deleted file mode 100644 index b0237d514a..0000000000 --- a/serde_v8/src/de.rs +++ /dev/null @@ -1,617 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -use rusty_v8 as v8; -use serde::de::{self, Visitor}; -use serde::Deserialize; - -use std::convert::TryFrom; - -use crate::error::{Error, Result}; -use crate::keys::{v8_struct_key, KeyCache}; -use crate::payload::ValueType; - -use crate::magic; - -pub struct Deserializer<'a, 'b, 's> { - input: v8::Local<'a, v8::Value>, - scope: &'b mut v8::HandleScope<'s>, - _key_cache: Option<&'b mut KeyCache>, -} - -impl<'a, 'b, 's> Deserializer<'a, 'b, 's> { - pub fn new( - scope: &'b mut v8::HandleScope<'s>, - input: v8::Local<'a, v8::Value>, - key_cache: Option<&'b mut KeyCache>, - ) -> Self { - Deserializer { - input, - scope, - _key_cache: key_cache, - } - } -} - -// from_v8 deserializes a v8::Value into a Deserializable / rust struct -pub fn from_v8<'de, 'a, 'b, 's, T>( - scope: &'b mut v8::HandleScope<'s>, - input: v8::Local<'a, v8::Value>, -) -> Result -where - T: Deserialize<'de>, -{ - let mut deserializer = Deserializer::new(scope, input, None); - let t = T::deserialize(&mut deserializer)?; - Ok(t) -} - -// like from_v8 except accepts a KeyCache to optimize struct key decoding -pub fn from_v8_cached<'de, 'a, 'b, 's, T>( - scope: &'b mut v8::HandleScope<'s>, - input: v8::Local<'a, v8::Value>, - key_cache: &mut KeyCache, -) -> Result -where - T: Deserialize<'de>, -{ - let mut deserializer = Deserializer::new(scope, input, Some(key_cache)); - let t = T::deserialize(&mut deserializer)?; - Ok(t) -} - -macro_rules! wip { - ($method:ident) => { - fn $method(self, _v: V) -> Result - where - V: Visitor<'de>, - { - unimplemented!() - } - }; -} - -macro_rules! deserialize_signed { - ($dmethod:ident, $vmethod:ident, $t:tt) => { - fn $dmethod(self, visitor: V) -> Result - where - V: Visitor<'de>, - { - visitor.$vmethod(self.input.integer_value(&mut self.scope).unwrap() as $t) - } - }; -} - -impl<'de, 'a, 'b, 's, 'x> de::Deserializer<'de> - for &'x mut Deserializer<'a, 'b, 's> -{ - type Error = Error; - - fn deserialize_any(self, visitor: V) -> Result - where - V: Visitor<'de>, - { - match ValueType::from_v8(self.input) { - ValueType::Null => self.deserialize_unit(visitor), - ValueType::Bool => self.deserialize_bool(visitor), - // Handle floats & ints separately to work with loosely-typed serde_json - ValueType::Number => { - if self.input.is_uint32() { - self.deserialize_u32(visitor) - } else if self.input.is_int32() { - self.deserialize_i32(visitor) - } else { - self.deserialize_f64(visitor) - } - } - ValueType::String => self.deserialize_string(visitor), - ValueType::Array => self.deserialize_seq(visitor), - ValueType::Object => self.deserialize_map(visitor), - } - } - - fn deserialize_bool(self, visitor: V) -> Result - where - V: Visitor<'de>, - { - // Relaxed typechecking, will map all non-true vals to false - visitor.visit_bool(self.input.is_true()) - } - - deserialize_signed!(deserialize_i8, visit_i8, i8); - deserialize_signed!(deserialize_i16, visit_i16, i16); - deserialize_signed!(deserialize_i32, visit_i32, i32); - deserialize_signed!(deserialize_i64, visit_i64, i64); - // TODO: maybe handle unsigned by itself ? - deserialize_signed!(deserialize_u8, visit_u8, u8); - deserialize_signed!(deserialize_u16, visit_u16, u16); - deserialize_signed!(deserialize_u32, visit_u32, u32); - deserialize_signed!(deserialize_u64, visit_u64, u64); - - fn deserialize_f32(self, visitor: V) -> Result - where - V: Visitor<'de>, - { - visitor.visit_f32(self.input.number_value(&mut self.scope).unwrap() as f32) - } - - fn deserialize_f64(self, visitor: V) -> Result - where - V: Visitor<'de>, - { - visitor.visit_f64(self.input.number_value(&mut self.scope).unwrap()) - } - - wip!(deserialize_char); - - fn deserialize_str(self, visitor: V) -> Result - where - V: Visitor<'de>, - { - self.deserialize_string(visitor) - } - - fn deserialize_string(self, visitor: V) -> Result - where - V: Visitor<'de>, - { - if self.input.is_string() { - let v8_string = v8::Local::::try_from(self.input).unwrap(); - let string = v8_string.to_rust_string_lossy(self.scope); - visitor.visit_string(string) - } else { - Err(Error::ExpectedString) - } - } - - wip!(deserialize_bytes); - wip!(deserialize_byte_buf); - - fn deserialize_option(self, visitor: V) -> Result - where - V: Visitor<'de>, - { - if self.input.is_null_or_undefined() { - visitor.visit_none() - } else { - visitor.visit_some(self) - } - } - - fn deserialize_unit(self, visitor: V) -> Result - where - V: Visitor<'de>, - { - if self.input.is_null_or_undefined() { - visitor.visit_unit() - } else { - Err(Error::ExpectedNull) - } - } - - fn deserialize_unit_struct( - self, - _name: &'static str, - visitor: V, - ) -> Result - where - V: Visitor<'de>, - { - self.deserialize_unit(visitor) - } - - // As is done here, serializers are encouraged to treat newtype structs as - // insignificant wrappers around the data they contain. That means not - // parsing anything other than the contained value. - fn deserialize_newtype_struct( - self, - _name: &'static str, - visitor: V, - ) -> Result - where - V: Visitor<'de>, - { - visitor.visit_newtype_struct(self) - } - - fn deserialize_seq(self, visitor: V) -> Result - where - V: Visitor<'de>, - { - let arr = v8::Local::::try_from(self.input) - .map_err(|_| Error::ExpectedArray)?; - let len = arr.length(); - let obj = v8::Local::::from(arr); - let seq = SeqAccess { - pos: 0, - len, - obj, - scope: self.scope, - }; - visitor.visit_seq(seq) - } - - // Like deserialize_seq except it prefers tuple's length over input array's length - fn deserialize_tuple(self, len: usize, visitor: V) -> Result - where - V: Visitor<'de>, - { - // TODO: error on length mismatch - let obj = v8::Local::::try_from(self.input).unwrap(); - let seq = SeqAccess { - pos: 0, - len: len as u32, - obj, - scope: self.scope, - }; - visitor.visit_seq(seq) - } - - // Tuple structs look just like sequences in JSON. - fn deserialize_tuple_struct( - self, - _name: &'static str, - len: usize, - visitor: V, - ) -> Result - where - V: Visitor<'de>, - { - self.deserialize_tuple(len, visitor) - } - - fn deserialize_map(self, visitor: V) -> Result - where - V: de::Visitor<'de>, - { - // Assume object, then get_own_property_names - let obj = v8::Local::::try_from(self.input).unwrap(); - let prop_names = obj.get_own_property_names(self.scope); - let mut keys: Vec = match prop_names { - Some(names) => from_v8(self.scope, names.into()).unwrap(), - None => vec![], - }; - let keys: Vec> = keys - .drain(..) - .map(|x| x.into()) - // Filter keys to drop keys whose value is undefined - // TODO: optimize, since this doubles our get calls - .filter(|key| !obj.get(self.scope, *key).unwrap().is_undefined()) - .collect(); - - let map = MapAccess { - obj, - keys, - pos: 0, - scope: self.scope, - }; - visitor.visit_map(map) - } - - fn deserialize_struct( - self, - name: &'static str, - fields: &'static [&'static str], - visitor: V, - ) -> Result - where - V: Visitor<'de>, - { - // Magic for serde_v8::magic::Value, to passthrough v8::Value - // TODO: ensure this is cross-platform and there's no alternative - if name == magic::NAME { - let mv = magic::Value { - v8_value: self.input, - }; - let hack: u64 = unsafe { std::mem::transmute(mv) }; - return visitor.visit_u64(hack); - } - - // Magic Buffer - if name == magic::buffer::BUF_NAME { - let zero_copy_buf = - v8::Local::::try_from(self.input) - .map(|view| magic::zero_copy_buf::ZeroCopyBuf::new(self.scope, view)) - .map_err(|_| Error::ExpectedArray)?; - let data: [u8; 32] = unsafe { std::mem::transmute(zero_copy_buf) }; - return visitor.visit_bytes(&data); - } - - // Regular struct - let obj = v8::Local::::try_from(self.input).unwrap(); - let map = ObjectAccess { - fields, - obj, - pos: 0, - scope: self.scope, - _cache: None, - }; - - visitor.visit_map(map) - } - - /// To be compatible with `serde-json`, we expect enums to be: - /// - `"Variant"`: strings for unit variants, i.e: Enum::Variant - /// - `{ Variant: payload }`: single K/V pairs, converted to `Enum::Variant { payload }` - fn deserialize_enum( - self, - _name: &str, - _variants: &'static [&'static str], - visitor: V, - ) -> Result - where - V: Visitor<'de>, - { - // Unit variant - if self.input.is_string() { - let payload = v8::undefined(self.scope).into(); - visitor.visit_enum(EnumAccess { - scope: self.scope, - tag: self.input, - payload, - }) - } - // Struct or tuple variant - else if self.input.is_object() { - // Assume object - let obj = v8::Local::::try_from(self.input).unwrap(); - // Unpack single-key - let tag = { - let prop_names = obj.get_own_property_names(self.scope); - let prop_names = prop_names.ok_or(Error::ExpectedEnum)?; - if prop_names.length() != 1 { - return Err(Error::LengthMismatch); - } - prop_names.get_index(self.scope, 0).unwrap() - }; - - let payload = obj.get(self.scope, tag).unwrap(); - visitor.visit_enum(EnumAccess { - scope: self.scope, - tag, - payload, - }) - } else { - // TODO: improve error - Err(Error::ExpectedEnum) - } - } - - // An identifier in Serde is the type that identifies a field of a struct or - // the variant of an enum. In JSON, struct fields and enum variants are - // represented as strings. In other formats they may be represented as - // numeric indices. - fn deserialize_identifier(self, visitor: V) -> Result - where - V: Visitor<'de>, - { - self.deserialize_str(visitor) - } - - fn deserialize_ignored_any(self, visitor: V) -> Result - where - V: Visitor<'de>, - { - visitor.visit_none() - } -} - -struct MapAccess<'a, 'b, 's> { - obj: v8::Local<'a, v8::Object>, - scope: &'b mut v8::HandleScope<'s>, - keys: Vec>, - pos: usize, -} - -impl<'de> de::MapAccess<'de> for MapAccess<'_, '_, '_> { - type Error = Error; - - fn next_key_seed>( - &mut self, - seed: K, - ) -> Result> { - Ok(match self.keys.get(self.pos) { - Some(key) => { - let mut deserializer = Deserializer::new(self.scope, *key, None); - Some(seed.deserialize(&mut deserializer)?) - } - None => None, - }) - } - - fn next_value_seed>( - &mut self, - seed: V, - ) -> Result { - if self.pos >= self.keys.len() { - return Err(Error::LengthMismatch); - } - let key = self.keys[self.pos]; - self.pos += 1; - let v8_val = self.obj.get(self.scope, key).unwrap(); - let mut deserializer = Deserializer::new(self.scope, v8_val, None); - seed.deserialize(&mut deserializer) - } - - fn next_entry_seed< - K: de::DeserializeSeed<'de>, - V: de::DeserializeSeed<'de>, - >( - &mut self, - kseed: K, - vseed: V, - ) -> Result> { - if self.pos >= self.keys.len() { - return Ok(None); - } - let v8_key = self.keys[self.pos]; - self.pos += 1; - let mut kdeserializer = Deserializer::new(self.scope, v8_key, None); - Ok(Some((kseed.deserialize(&mut kdeserializer)?, { - let v8_val = self.obj.get(self.scope, v8_key).unwrap(); - let mut deserializer = Deserializer::new(self.scope, v8_val, None); - vseed.deserialize(&mut deserializer)? - }))) - } -} - -struct ObjectAccess<'a, 'b, 's> { - obj: v8::Local<'a, v8::Object>, - scope: &'b mut v8::HandleScope<'s>, - fields: &'static [&'static str], - pos: usize, - _cache: Option<&'b mut KeyCache>, -} - -fn str_deserializer(s: &str) -> de::value::StrDeserializer { - de::IntoDeserializer::into_deserializer(s) -} - -impl<'de, 'a, 'b, 's> de::MapAccess<'de> for ObjectAccess<'a, 'b, 's> { - type Error = Error; - - fn next_key_seed>( - &mut self, - seed: K, - ) -> Result> { - Ok(match self.fields.get(self.pos) { - Some(&field) => Some(seed.deserialize(str_deserializer(field))?), - None => None, - }) - } - - fn next_value_seed>( - &mut self, - seed: V, - ) -> Result { - if self.pos >= self.fields.len() { - return Err(Error::LengthMismatch); - } - let field = self.fields[self.pos]; - self.pos += 1; - let key = v8_struct_key(self.scope, field).into(); - let v8_val = self.obj.get(self.scope, key).unwrap(); - let mut deserializer = Deserializer::new(self.scope, v8_val, None); - seed.deserialize(&mut deserializer) - } - - fn next_entry_seed< - K: de::DeserializeSeed<'de>, - V: de::DeserializeSeed<'de>, - >( - &mut self, - kseed: K, - vseed: V, - ) -> Result> { - if self.pos >= self.fields.len() { - return Ok(None); - } - let field = self.fields[self.pos]; - self.pos += 1; - Ok(Some((kseed.deserialize(str_deserializer(field))?, { - let key = v8_struct_key(self.scope, field).into(); - let v8_val = self.obj.get(self.scope, key).unwrap(); - let mut deserializer = Deserializer::new(self.scope, v8_val, None); - vseed.deserialize(&mut deserializer)? - }))) - } -} - -struct SeqAccess<'a, 'b, 's> { - obj: v8::Local<'a, v8::Object>, - scope: &'b mut v8::HandleScope<'s>, - len: u32, - pos: u32, -} - -impl<'de> de::SeqAccess<'de> for SeqAccess<'_, '_, '_> { - type Error = Error; - - fn next_element_seed>( - &mut self, - seed: T, - ) -> Result> { - let pos = self.pos; - self.pos += 1; - - if pos < self.len { - let val = self.obj.get_index(self.scope, pos).unwrap(); - let mut deserializer = Deserializer::new(self.scope, val, None); - Ok(Some(seed.deserialize(&mut deserializer)?)) - } else { - Ok(None) - } - } - - fn size_hint(&self) -> Option { - Some((self.len - self.pos) as usize) - } -} - -struct EnumAccess<'a, 'b, 's> { - tag: v8::Local<'a, v8::Value>, - payload: v8::Local<'a, v8::Value>, - scope: &'b mut v8::HandleScope<'s>, - // p1: std::marker::PhantomData<&'x ()>, -} - -impl<'de, 'a, 'b, 's, 'x> de::EnumAccess<'de> for EnumAccess<'a, 'b, 's> { - type Error = Error; - type Variant = VariantDeserializer<'a, 'b, 's>; - - fn variant_seed>( - self, - seed: V, - ) -> Result<(V::Value, Self::Variant)> { - let seed = { - let mut dtag = Deserializer::new(self.scope, self.tag, None); - seed.deserialize(&mut dtag) - }; - let dpayload = VariantDeserializer::<'a, 'b, 's> { - scope: self.scope, - value: self.payload, - }; - - Ok((seed?, dpayload)) - } -} - -struct VariantDeserializer<'a, 'b, 's> { - value: v8::Local<'a, v8::Value>, - scope: &'b mut v8::HandleScope<'s>, -} - -impl<'de, 'a, 'b, 's> de::VariantAccess<'de> - for VariantDeserializer<'a, 'b, 's> -{ - type Error = Error; - - fn unit_variant(self) -> Result<()> { - let mut d = Deserializer::new(self.scope, self.value, None); - de::Deserialize::deserialize(&mut d) - } - - fn newtype_variant_seed>( - self, - seed: T, - ) -> Result { - let mut d = Deserializer::new(self.scope, self.value, None); - seed.deserialize(&mut d) - } - - fn tuple_variant>( - self, - len: usize, - visitor: V, - ) -> Result { - let mut d = Deserializer::new(self.scope, self.value, None); - de::Deserializer::deserialize_tuple(&mut d, len, visitor) - } - - fn struct_variant>( - self, - fields: &'static [&'static str], - visitor: V, - ) -> Result { - let mut d = Deserializer::new(self.scope, self.value, None); - de::Deserializer::deserialize_struct(&mut d, "", fields, visitor) - } -} diff --git a/serde_v8/src/error.rs b/serde_v8/src/error.rs deleted file mode 100644 index 7dc84e5e5c..0000000000 --- a/serde_v8/src/error.rs +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -use std::fmt::{self, Display}; - -use serde::{de, ser}; - -pub type Result = std::result::Result; - -#[derive(Clone, Debug, PartialEq)] -pub enum Error { - Message(String), - - ExpectedBoolean, - ExpectedInteger, - ExpectedString, - ExpectedNull, - ExpectedArray, - ExpectedMap, - ExpectedEnum, - - ExpectedUtf8, - - LengthMismatch, -} - -impl ser::Error for Error { - fn custom(msg: T) -> Self { - Error::Message(msg.to_string()) - } -} - -impl de::Error for Error { - fn custom(msg: T) -> Self { - Error::Message(msg.to_string()) - } -} - -impl Display for Error { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - match self { - Error::Message(msg) => formatter.write_str(msg), - err => formatter.write_str(format!("serde_v8 error: {:?}", err).as_ref()), - } - } -} - -impl std::error::Error for Error {} diff --git a/serde_v8/src/keys.rs b/serde_v8/src/keys.rs deleted file mode 100644 index ea989086c0..0000000000 --- a/serde_v8/src/keys.rs +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -use rusty_v8 as v8; - -use std::collections::HashMap; - -// KeyCache stores a pool struct keys mapped to v8, -// to minimize allocs and speed up decoding/encoding `v8::Object`s -// TODO: experiment with in from_v8/to_v8 -pub struct KeyCache(HashMap<&'static str, v8::Global>); - -// creates an optimized v8::String for a struct field -// TODO: experiment with external strings -// TODO: evaluate if own KeyCache is better than v8's dedupe -pub fn v8_struct_key<'s>( - scope: &mut v8::HandleScope<'s>, - field: &'static str, -) -> v8::Local<'s, v8::String> { - // Internalized v8 strings are significantly faster than "normal" v8 strings - // since v8 deduplicates re-used strings minimizing new allocations - // see: https://github.com/v8/v8/blob/14ac92e02cc3db38131a57e75e2392529f405f2f/include/v8.h#L3165-L3171 - v8::String::new_from_utf8( - scope, - field.as_ref(), - v8::NewStringType::Internalized, - ) - .unwrap() - - // TODO: consider external strings later - // right now non-deduped external strings (without KeyCache) - // are slower than the deduped internalized strings by ~2.5x - // since they're a new string in v8's eyes and needs to be hashed, etc... - // v8::String::new_external_onebyte_static(scope, field).unwrap() -} diff --git a/serde_v8/src/lib.rs b/serde_v8/src/lib.rs deleted file mode 100644 index 93ad4908fe..0000000000 --- a/serde_v8/src/lib.rs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -mod de; -mod error; -mod keys; -mod magic; -mod payload; -mod ser; -mod serializable; -pub mod utils; - -pub use de::{from_v8, from_v8_cached, Deserializer}; -pub use error::{Error, Result}; -pub use keys::KeyCache; -pub use magic::buffer::MagicBuffer as Buffer; -pub use magic::Value; -pub use ser::{to_v8, Serializer}; -pub use serializable::{Serializable, SerializablePkg}; diff --git a/serde_v8/src/magic/buffer.rs b/serde_v8/src/magic/buffer.rs deleted file mode 100644 index 1fcfffc723..0000000000 --- a/serde_v8/src/magic/buffer.rs +++ /dev/null @@ -1,139 +0,0 @@ -use rusty_v8 as v8; - -use std::fmt; -use std::ops::Deref; -use std::ops::DerefMut; -use std::sync::Mutex; - -use super::zero_copy_buf::ZeroCopyBuf; - -// An asymmetric wrapper around ZeroCopyBuf, -// allowing us to use a single type for familiarity -pub enum MagicBuffer { - FromV8(ZeroCopyBuf), - ToV8(Mutex>>), -} - -impl MagicBuffer { - pub fn new<'s>( - scope: &mut v8::HandleScope<'s>, - view: v8::Local, - ) -> Self { - Self::FromV8(ZeroCopyBuf::new(scope, view)) - } - - pub fn empty() -> Self { - MagicBuffer::ToV8(Mutex::new(Some(vec![0_u8; 0].into_boxed_slice()))) - } -} - -impl Clone for MagicBuffer { - fn clone(&self) -> Self { - match self { - Self::FromV8(zbuf) => Self::FromV8(zbuf.clone()), - Self::ToV8(_) => panic!("Don't Clone a MagicBuffer sent to v8"), - } - } -} - -impl AsRef<[u8]> for MagicBuffer { - fn as_ref(&self) -> &[u8] { - &*self - } -} - -impl AsMut<[u8]> for MagicBuffer { - fn as_mut(&mut self) -> &mut [u8] { - &mut *self - } -} - -impl Deref for MagicBuffer { - type Target = [u8]; - fn deref(&self) -> &[u8] { - match self { - Self::FromV8(buf) => &*buf, - Self::ToV8(_) => panic!("Don't Deref a MagicBuffer sent to v8"), - } - } -} - -impl DerefMut for MagicBuffer { - fn deref_mut(&mut self) -> &mut [u8] { - match self { - Self::FromV8(buf) => &mut *buf, - Self::ToV8(_) => panic!("Don't Deref a MagicBuffer sent to v8"), - } - } -} - -impl From> for MagicBuffer { - fn from(buf: Box<[u8]>) -> Self { - MagicBuffer::ToV8(Mutex::new(Some(buf))) - } -} - -impl From> for MagicBuffer { - fn from(vec: Vec) -> Self { - vec.into_boxed_slice().into() - } -} - -pub const BUF_NAME: &str = "$__v8_magic_Buffer"; -pub const BUF_FIELD_1: &str = "$__v8_magic_buffer_1"; -pub const BUF_FIELD_2: &str = "$__v8_magic_buffer_2"; - -impl serde::Serialize for MagicBuffer { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - use serde::ser::SerializeStruct; - - let mut s = serializer.serialize_struct(BUF_NAME, 1)?; - let boxed: Box<[u8]> = match self { - Self::FromV8(buf) => { - let value: &[u8] = &buf; - value.into() - } - Self::ToV8(x) => x.lock().unwrap().take().expect("MagicBuffer was empty"), - }; - let hack: [usize; 2] = unsafe { std::mem::transmute(boxed) }; - let f1: u64 = hack[0] as u64; - let f2: u64 = hack[1] as u64; - s.serialize_field(BUF_FIELD_1, &f1)?; - s.serialize_field(BUF_FIELD_2, &f2)?; - s.end() - } -} - -impl<'de, 's> serde::Deserialize<'de> for MagicBuffer { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - struct ValueVisitor {} - - impl<'de> serde::de::Visitor<'de> for ValueVisitor { - type Value = MagicBuffer; - - fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - formatter.write_str("a serde_v8::MagicBuffer") - } - - fn visit_bytes(self, v: &[u8]) -> Result - where - E: serde::de::Error, - { - let p1: &[usize] = unsafe { &*(v as *const [u8] as *const [usize]) }; - let p2: [usize; 4] = [p1[0], p1[1], p1[2], p1[3]]; - let zero_copy: ZeroCopyBuf = unsafe { std::mem::transmute(p2) }; - Ok(MagicBuffer::FromV8(zero_copy)) - } - } - - static FIELDS: [&str; 0] = []; - let visitor = ValueVisitor {}; - deserializer.deserialize_struct(BUF_NAME, &FIELDS, visitor) - } -} diff --git a/serde_v8/src/magic/field.rs b/serde_v8/src/magic/field.rs deleted file mode 100644 index e6bb9ee547..0000000000 --- a/serde_v8/src/magic/field.rs +++ /dev/null @@ -1,144 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -use crate::error::{Error, Result}; -use serde::ser::{Impossible, Serialize, Serializer}; - -/// All serde_v8 "magic" values are reduced to structs with 1 or 2 u64 fields -/// assuming usize==u64, most types are simply a pointer or pointer+len (e.g: Box) -pub type TransmutedField = u64; -pub type FieldResult = Result; - -macro_rules! not_reachable { - ($($name:ident($ty:ty);)*) => { - $(fn $name(self, _v: $ty) -> FieldResult { - unreachable!(); - })* - }; -} - -/// FieldSerializer is a simple serde::Serializer that only returns u64s -/// it allows the "magic" struct serializers to obtain the transmuted field values -pub struct FieldSerializer {} - -impl Serializer for FieldSerializer { - type Ok = TransmutedField; - type Error = Error; - - type SerializeSeq = Impossible; - type SerializeTuple = Impossible; - type SerializeTupleStruct = Impossible; - type SerializeTupleVariant = Impossible; - type SerializeMap = Impossible; - type SerializeStruct = Impossible; - type SerializeStructVariant = Impossible; - - fn serialize_u64(self, transmuted_field: u64) -> FieldResult { - Ok(transmuted_field) - } - - not_reachable! { - serialize_i8(i8); - serialize_i16(i16); - serialize_i32(i32); - serialize_i64(i64); - serialize_u8(u8); - serialize_u16(u16); - serialize_u32(u32); - // serialize_u64(TransmutedField); the chosen one - serialize_f32(f32); - serialize_f64(f64); - serialize_bool(bool); - serialize_char(char); - serialize_str(&str); - serialize_bytes(&[u8]); - } - - fn serialize_none(self) -> FieldResult { - unreachable!(); - } - - fn serialize_some(self, _value: &T) -> FieldResult { - unreachable!(); - } - - fn serialize_unit(self) -> FieldResult { - unreachable!(); - } - - fn serialize_unit_struct(self, _name: &'static str) -> FieldResult { - unreachable!(); - } - - fn serialize_unit_variant( - self, - _name: &'static str, - _variant_index: u32, - _variant: &'static str, - ) -> FieldResult { - unreachable!(); - } - - fn serialize_newtype_struct( - self, - _name: &'static str, - _value: &T, - ) -> FieldResult { - unreachable!(); - } - - fn serialize_newtype_variant( - self, - _name: &'static str, - _variant_index: u32, - _variant: &'static str, - _value: &T, - ) -> FieldResult { - unreachable!(); - } - fn serialize_seq(self, _len: Option) -> Result { - unreachable!(); - } - - fn serialize_tuple(self, _len: usize) -> Result { - unreachable!(); - } - - fn serialize_tuple_struct( - self, - _name: &'static str, - _len: usize, - ) -> Result { - unreachable!(); - } - - fn serialize_tuple_variant( - self, - _name: &'static str, - _variant_index: u32, - _variant: &'static str, - _len: usize, - ) -> Result { - unreachable!(); - } - - fn serialize_map(self, _len: Option) -> Result { - unreachable!(); - } - - fn serialize_struct( - self, - _name: &'static str, - _len: usize, - ) -> Result { - unreachable!(); - } - - fn serialize_struct_variant( - self, - _name: &'static str, - _variant_index: u32, - _variant: &'static str, - _len: usize, - ) -> Result { - unreachable!(); - } -} diff --git a/serde_v8/src/magic/mod.rs b/serde_v8/src/magic/mod.rs deleted file mode 100644 index 29c35a831d..0000000000 --- a/serde_v8/src/magic/mod.rs +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -pub mod buffer; -mod field; -mod value; -pub mod zero_copy_buf; - -pub use field::FieldSerializer; -pub use value::{Value, FIELD, NAME}; diff --git a/serde_v8/src/magic/value.rs b/serde_v8/src/magic/value.rs deleted file mode 100644 index 2cb6224668..0000000000 --- a/serde_v8/src/magic/value.rs +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -use rusty_v8 as v8; - -use std::fmt; -use std::marker::PhantomData; - -pub const FIELD: &str = "$__v8_magic_value"; -pub const NAME: &str = "$__v8_magic_Value"; - -/// serde_v8::Value allows passing through `v8::Value`s untouched -/// when encoding/decoding and allows mixing rust & v8 values in -/// structs, tuples... -/// The implementation mainly breaks down to: -/// 1. Transmuting between u64 <> serde_v8::Value -/// 2. Using special struct/field names to detect these values -/// 3. Then serde "boilerplate" -pub struct Value<'s> { - pub v8_value: v8::Local<'s, v8::Value>, -} - -impl<'s> From> for Value<'s> { - fn from(v8_value: v8::Local<'s, v8::Value>) -> Self { - Self { v8_value } - } -} - -impl<'s> From> for v8::Local<'s, v8::Value> { - fn from(v: Value<'s>) -> Self { - v.v8_value - } -} - -impl serde::Serialize for Value<'_> { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - use serde::ser::SerializeStruct; - - let mut s = serializer.serialize_struct(NAME, 1)?; - let mv = Value { - v8_value: self.v8_value, - }; - let hack: u64 = unsafe { std::mem::transmute(mv) }; - s.serialize_field(FIELD, &hack)?; - s.end() - } -} - -impl<'de, 's> serde::Deserialize<'de> for Value<'s> { - fn deserialize(deserializer: D) -> Result, D::Error> - where - D: serde::Deserializer<'de>, - { - struct ValueVisitor<'s> { - p1: PhantomData<&'s ()>, - } - - impl<'de, 's> serde::de::Visitor<'de> for ValueVisitor<'s> { - type Value = Value<'s>; - - fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - formatter.write_str("a v8::Value") - } - - fn visit_u64(self, v: u64) -> Result - where - E: serde::de::Error, - { - let mv: Value<'s> = unsafe { std::mem::transmute(v) }; - Ok(mv) - } - } - - static FIELDS: [&str; 1] = [FIELD]; - let visitor = ValueVisitor { p1: PhantomData }; - deserializer.deserialize_struct(NAME, &FIELDS, visitor) - } -} diff --git a/serde_v8/src/magic/zero_copy_buf.rs b/serde_v8/src/magic/zero_copy_buf.rs deleted file mode 100644 index 1f07292ba6..0000000000 --- a/serde_v8/src/magic/zero_copy_buf.rs +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. - -use rusty_v8 as v8; -use std::cell::Cell; -use std::ops::Deref; -use std::ops::DerefMut; - -/// A ZeroCopyBuf encapsulates a slice that's been borrowed from a JavaScript -/// ArrayBuffer object. JavaScript objects can normally be garbage collected, -/// but the existence of a ZeroCopyBuf inhibits this until it is dropped. It -/// behaves much like an Arc<[u8]>. -/// -/// # Cloning -/// Cloning a ZeroCopyBuf does not clone the contents of the buffer, -/// it creates a new reference to that buffer. -/// -/// To actually clone the contents of the buffer do -/// `let copy = Vec::from(&*zero_copy_buf);` -#[derive(Clone)] -pub struct ZeroCopyBuf { - backing_store: v8::SharedRef, - byte_offset: usize, - byte_length: usize, -} - -unsafe impl Send for ZeroCopyBuf {} - -impl ZeroCopyBuf { - pub fn new<'s>( - scope: &mut v8::HandleScope<'s>, - view: v8::Local, - ) -> Self { - let backing_store = view.buffer(scope).unwrap().get_backing_store(); - let byte_offset = view.byte_offset(); - let byte_length = view.byte_length(); - Self { - backing_store, - byte_offset, - byte_length, - } - } -} - -impl Deref for ZeroCopyBuf { - type Target = [u8]; - fn deref(&self) -> &[u8] { - unsafe { - get_backing_store_slice( - &self.backing_store, - self.byte_offset, - self.byte_length, - ) - } - } -} - -impl DerefMut for ZeroCopyBuf { - fn deref_mut(&mut self) -> &mut [u8] { - unsafe { - get_backing_store_slice_mut( - &self.backing_store, - self.byte_offset, - self.byte_length, - ) - } - } -} - -impl AsRef<[u8]> for ZeroCopyBuf { - fn as_ref(&self) -> &[u8] { - &*self - } -} - -impl AsMut<[u8]> for ZeroCopyBuf { - fn as_mut(&mut self) -> &mut [u8] { - &mut *self - } -} - -unsafe fn get_backing_store_slice( - backing_store: &v8::SharedRef, - byte_offset: usize, - byte_length: usize, -) -> &[u8] { - let cells: *const [Cell] = - &backing_store[byte_offset..byte_offset + byte_length]; - let bytes = cells as *const [u8]; - &*bytes -} - -#[allow(clippy::mut_from_ref)] -unsafe fn get_backing_store_slice_mut( - backing_store: &v8::SharedRef, - byte_offset: usize, - byte_length: usize, -) -> &mut [u8] { - let cells: *const [Cell] = - &backing_store[byte_offset..byte_offset + byte_length]; - let bytes = cells as *const _ as *mut [u8]; - &mut *bytes -} diff --git a/serde_v8/src/payload.rs b/serde_v8/src/payload.rs deleted file mode 100644 index 816158f93c..0000000000 --- a/serde_v8/src/payload.rs +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -use rusty_v8 as v8; - -// TODO: maybe add a Payload type that holds scope & v8::Value -// so it can implement Deserialize by itself - -// Classifies v8::Values into sub-types -pub enum ValueType { - Null, - Bool, - Number, - String, - Array, - Object, -} - -impl ValueType { - pub fn from_v8(v: v8::Local) -> ValueType { - if v.is_boolean() { - return Self::Bool; - } else if v.is_number() { - return Self::Number; - } else if v.is_string() { - return Self::String; - } else if v.is_array() { - return Self::Array; - } else if v.is_object() { - return Self::Object; - } else if v.is_null_or_undefined() { - return Self::Null; - } - panic!("serde_v8: unknown ValueType for v8::Value") - } -} diff --git a/serde_v8/src/ser.rs b/serde_v8/src/ser.rs deleted file mode 100644 index b0f1a5e7d2..0000000000 --- a/serde_v8/src/ser.rs +++ /dev/null @@ -1,559 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -use rusty_v8 as v8; -use serde::ser; -use serde::ser::Serialize; - -use std::cell::RefCell; - -use crate::error::{Error, Result}; -use crate::keys::v8_struct_key; -use crate::magic; - -type JsValue<'s> = v8::Local<'s, v8::Value>; -type JsResult<'s> = Result>; - -type ScopePtr<'a, 'b, 'c> = &'c RefCell<&'b mut v8::HandleScope<'a>>; - -pub fn to_v8<'a, T>(scope: &mut v8::HandleScope<'a>, input: T) -> JsResult<'a> -where - T: Serialize, -{ - let scopeptr = RefCell::new(scope); - let serializer = Serializer::new(&scopeptr); - - input.serialize(serializer) -} - -/// Wraps other serializers into an enum tagged variant form. -/// Uses {"Variant": ...payload...} for compatibility with serde-json. -pub struct VariantSerializer<'a, 'b, 'c, S> { - inner: S, - scope: ScopePtr<'a, 'b, 'c>, - variant: &'static str, -} - -impl<'a, 'b, 'c, S> VariantSerializer<'a, 'b, 'c, S> { - pub fn new( - scope: ScopePtr<'a, 'b, 'c>, - variant: &'static str, - inner: S, - ) -> Self { - Self { - inner, - scope, - variant, - } - } - - fn end(self, inner: impl FnOnce(S) -> JsResult<'a>) -> JsResult<'a> { - let value = inner(self.inner)?; - let scope = &mut *self.scope.borrow_mut(); - let obj = v8::Object::new(scope); - let key = v8_struct_key(scope, self.variant).into(); - obj.set(scope, key, value); - Ok(obj.into()) - } -} - -impl<'a, 'b, 'c, S> ser::SerializeTupleVariant - for VariantSerializer<'a, 'b, 'c, S> -where - S: ser::SerializeTupleStruct, Error = Error>, -{ - type Ok = JsValue<'a>; - type Error = Error; - - fn serialize_field( - &mut self, - value: &T, - ) -> Result<()> { - self.inner.serialize_field(value) - } - - fn end(self) -> JsResult<'a> { - self.end(S::end) - } -} - -impl<'a, 'b, 'c, S> ser::SerializeStructVariant - for VariantSerializer<'a, 'b, 'c, S> -where - S: ser::SerializeStruct, Error = Error>, -{ - type Ok = JsValue<'a>; - type Error = Error; - - fn serialize_field( - &mut self, - key: &'static str, - value: &T, - ) -> Result<()> { - self.inner.serialize_field(key, value) - } - - fn end(self) -> JsResult<'a> { - self.end(S::end) - } -} - -pub struct ArraySerializer<'a, 'b, 'c> { - pending: Vec>, - scope: ScopePtr<'a, 'b, 'c>, -} - -impl<'a, 'b, 'c> ArraySerializer<'a, 'b, 'c> { - pub fn new(scope: ScopePtr<'a, 'b, 'c>, len: Option) -> Self { - let pending = match len { - Some(len) => Vec::with_capacity(len), - None => vec![], - }; - Self { pending, scope } - } -} - -impl<'a, 'b, 'c> ser::SerializeSeq for ArraySerializer<'a, 'b, 'c> { - type Ok = JsValue<'a>; - type Error = Error; - - fn serialize_element( - &mut self, - value: &T, - ) -> Result<()> { - let x = value.serialize(Serializer::new(self.scope))?; - self.pending.push(x); - Ok(()) - } - - fn end(self) -> JsResult<'a> { - let elements = self.pending.iter().as_slice(); - let scope = &mut *self.scope.borrow_mut(); - let arr = v8::Array::new_with_elements(scope, elements); - Ok(arr.into()) - } -} - -impl<'a, 'b, 'c> ser::SerializeTuple for ArraySerializer<'a, 'b, 'c> { - type Ok = JsValue<'a>; - type Error = Error; - - fn serialize_element( - &mut self, - value: &T, - ) -> Result<()> { - ser::SerializeSeq::serialize_element(self, value) - } - - fn end(self) -> JsResult<'a> { - ser::SerializeSeq::end(self) - } -} - -impl<'a, 'b, 'c> ser::SerializeTupleStruct for ArraySerializer<'a, 'b, 'c> { - type Ok = JsValue<'a>; - type Error = Error; - - fn serialize_field( - &mut self, - value: &T, - ) -> Result<()> { - ser::SerializeTuple::serialize_element(self, value) - } - - fn end(self) -> JsResult<'a> { - ser::SerializeTuple::end(self) - } -} - -pub struct ObjectSerializer<'a, 'b, 'c> { - scope: ScopePtr<'a, 'b, 'c>, - obj: v8::Local<'a, v8::Object>, -} - -impl<'a, 'b, 'c> ObjectSerializer<'a, 'b, 'c> { - pub fn new(scope: ScopePtr<'a, 'b, 'c>) -> Self { - let obj = v8::Object::new(&mut *scope.borrow_mut()); - Self { scope, obj } - } -} - -impl<'a, 'b, 'c> ser::SerializeStruct for ObjectSerializer<'a, 'b, 'c> { - type Ok = JsValue<'a>; - type Error = Error; - - fn serialize_field( - &mut self, - key: &'static str, - value: &T, - ) -> Result<()> { - let value = value.serialize(Serializer::new(self.scope))?; - let scope = &mut *self.scope.borrow_mut(); - let key = v8_struct_key(scope, key).into(); - self.obj.set(scope, key, value); - Ok(()) - } - - fn end(self) -> JsResult<'a> { - Ok(self.obj.into()) - } -} - -pub struct MagicSerializer<'a> { - v8_value: Option>, -} - -impl<'a> ser::SerializeStruct for MagicSerializer<'a> { - type Ok = JsValue<'a>; - type Error = Error; - - fn serialize_field( - &mut self, - key: &'static str, - value: &T, - ) -> Result<()> { - if key != magic::FIELD { - unreachable!(); - } - let transmuted: u64 = value.serialize(magic::FieldSerializer {})?; - let mv: magic::Value<'a> = unsafe { std::mem::transmute(transmuted) }; - self.v8_value = Some(mv.v8_value); - Ok(()) - } - - fn end(self) -> JsResult<'a> { - Ok(self.v8_value.unwrap()) - } -} - -// TODO(@AaronO): refactor this and streamline how we transmute values -pub struct MagicBufferSerializer<'a, 'b, 'c> { - scope: ScopePtr<'a, 'b, 'c>, - f1: u64, - f2: u64, -} - -impl<'a, 'b, 'c> MagicBufferSerializer<'a, 'b, 'c> { - pub fn new(scope: ScopePtr<'a, 'b, 'c>) -> Self { - Self { - scope, - f1: 0, - f2: 0, - } - } -} - -impl<'a, 'b, 'c> ser::SerializeStruct for MagicBufferSerializer<'a, 'b, 'c> { - type Ok = JsValue<'a>; - type Error = Error; - - fn serialize_field( - &mut self, - key: &'static str, - value: &T, - ) -> Result<()> { - // Get u64 chunk - let transmuted: u64 = value.serialize(magic::FieldSerializer {})?; - match key { - magic::buffer::BUF_FIELD_1 => self.f1 = transmuted, - magic::buffer::BUF_FIELD_2 => self.f2 = transmuted, - _ => unreachable!(), - } - Ok(()) - } - - fn end(self) -> JsResult<'a> { - let x: [usize; 2] = [self.f1 as usize, self.f2 as usize]; - let buf: Box<[u8]> = unsafe { std::mem::transmute(x) }; - let scope = &mut *self.scope.borrow_mut(); - let v8_value = boxed_slice_to_uint8array(scope, buf); - Ok(v8_value.into()) - } -} - -// Dispatches between magic and regular struct serializers -pub enum StructSerializers<'a, 'b, 'c> { - Magic(MagicSerializer<'a>), - MagicBuffer(MagicBufferSerializer<'a, 'b, 'c>), - Regular(ObjectSerializer<'a, 'b, 'c>), -} - -impl<'a, 'b, 'c> ser::SerializeStruct for StructSerializers<'a, 'b, 'c> { - type Ok = JsValue<'a>; - type Error = Error; - - fn serialize_field( - &mut self, - key: &'static str, - value: &T, - ) -> Result<()> { - match self { - StructSerializers::Magic(s) => s.serialize_field(key, value), - StructSerializers::MagicBuffer(s) => s.serialize_field(key, value), - StructSerializers::Regular(s) => s.serialize_field(key, value), - } - } - - fn end(self) -> JsResult<'a> { - match self { - StructSerializers::Magic(s) => s.end(), - StructSerializers::MagicBuffer(s) => s.end(), - StructSerializers::Regular(s) => s.end(), - } - } -} - -// Serializes to JS Objects, NOT JS Maps ... -pub struct MapSerializer<'a, 'b, 'c> { - scope: ScopePtr<'a, 'b, 'c>, - obj: v8::Local<'a, v8::Object>, - next_key: Option>, -} - -impl<'a, 'b, 'c> MapSerializer<'a, 'b, 'c> { - pub fn new(scope: ScopePtr<'a, 'b, 'c>) -> Self { - let obj = v8::Object::new(&mut *scope.borrow_mut()); - Self { - scope, - obj, - next_key: None, - } - } -} - -impl<'a, 'b, 'c> ser::SerializeMap for MapSerializer<'a, 'b, 'c> { - type Ok = JsValue<'a>; - type Error = Error; - - fn serialize_key(&mut self, key: &T) -> Result<()> { - debug_assert!(self.next_key.is_none()); - self.next_key = Some(key.serialize(Serializer::new(self.scope))?); - Ok(()) - } - - fn serialize_value( - &mut self, - value: &T, - ) -> Result<()> { - let v8_value = value.serialize(Serializer::new(self.scope))?; - let scope = &mut *self.scope.borrow_mut(); - self.obj.set(scope, self.next_key.take().unwrap(), v8_value); - Ok(()) - } - - fn end(self) -> JsResult<'a> { - debug_assert!(self.next_key.is_none()); - Ok(self.obj.into()) - } -} - -pub struct Serializer<'a, 'b, 'c> { - scope: ScopePtr<'a, 'b, 'c>, -} - -impl<'a, 'b, 'c> Serializer<'a, 'b, 'c> { - pub fn new(scope: ScopePtr<'a, 'b, 'c>) -> Self { - Serializer { scope } - } -} - -macro_rules! forward_to { - ($($name:ident($ty:ty, $to:ident, $lt:lifetime);)*) => { - $(fn $name(self, v: $ty) -> JsResult<$lt> { - self.$to(v as _) - })* - }; -} - -impl<'a, 'b, 'c> ser::Serializer for Serializer<'a, 'b, 'c> { - type Ok = v8::Local<'a, v8::Value>; - type Error = Error; - - type SerializeSeq = ArraySerializer<'a, 'b, 'c>; - type SerializeTuple = ArraySerializer<'a, 'b, 'c>; - type SerializeTupleStruct = ArraySerializer<'a, 'b, 'c>; - type SerializeTupleVariant = - VariantSerializer<'a, 'b, 'c, ArraySerializer<'a, 'b, 'c>>; - type SerializeMap = MapSerializer<'a, 'b, 'c>; - type SerializeStruct = StructSerializers<'a, 'b, 'c>; - type SerializeStructVariant = - VariantSerializer<'a, 'b, 'c, StructSerializers<'a, 'b, 'c>>; - - forward_to! { - serialize_i8(i8, serialize_i32, 'a); - serialize_i16(i16, serialize_i32, 'a); - - serialize_u8(u8, serialize_u32, 'a); - serialize_u16(u16, serialize_u32, 'a); - - serialize_f32(f32, serialize_f64, 'a); - serialize_u64(u64, serialize_f64, 'a); - serialize_i64(i64, serialize_f64, 'a); - } - - fn serialize_i32(self, v: i32) -> JsResult<'a> { - Ok(v8::Integer::new(&mut self.scope.borrow_mut(), v).into()) - } - - fn serialize_u32(self, v: u32) -> JsResult<'a> { - Ok(v8::Integer::new_from_unsigned(&mut self.scope.borrow_mut(), v).into()) - } - - fn serialize_f64(self, v: f64) -> JsResult<'a> { - Ok(v8::Number::new(&mut self.scope.borrow_mut(), v).into()) - } - - fn serialize_bool(self, v: bool) -> JsResult<'a> { - Ok(v8::Boolean::new(&mut self.scope.borrow_mut(), v).into()) - } - - fn serialize_char(self, _v: char) -> JsResult<'a> { - unimplemented!(); - } - - fn serialize_str(self, v: &str) -> JsResult<'a> { - v8::String::new(&mut self.scope.borrow_mut(), v) - .map(|v| v.into()) - .ok_or(Error::ExpectedString) - } - - fn serialize_bytes(self, _v: &[u8]) -> JsResult<'a> { - // TODO: investigate using Uint8Arrays - unimplemented!() - } - - fn serialize_none(self) -> JsResult<'a> { - Ok(v8::null(&mut self.scope.borrow_mut()).into()) - } - - fn serialize_some(self, value: &T) -> JsResult<'a> { - value.serialize(self) - } - - fn serialize_unit(self) -> JsResult<'a> { - Ok(v8::null(&mut self.scope.borrow_mut()).into()) - } - - fn serialize_unit_struct(self, _name: &'static str) -> JsResult<'a> { - Ok(v8::null(&mut self.scope.borrow_mut()).into()) - } - - /// For compatibility with serde-json, serialises unit variants as "Variant" strings. - fn serialize_unit_variant( - self, - _name: &'static str, - _variant_index: u32, - variant: &'static str, - ) -> JsResult<'a> { - Ok(v8_struct_key(&mut self.scope.borrow_mut(), variant).into()) - } - - fn serialize_newtype_struct( - self, - _name: &'static str, - value: &T, - ) -> JsResult<'a> { - value.serialize(self) - } - - fn serialize_newtype_variant( - self, - _name: &'static str, - _variant_index: u32, - variant: &'static str, - value: &T, - ) -> JsResult<'a> { - let scope = self.scope; - let x = self.serialize_newtype_struct(variant, value)?; - VariantSerializer::new(scope, variant, x).end(Ok) - } - - /// Serialises any Rust iterable into a JS Array - fn serialize_seq(self, len: Option) -> Result { - Ok(ArraySerializer::new(self.scope, len)) - } - - fn serialize_tuple(self, len: usize) -> Result { - self.serialize_seq(Some(len)) - } - - fn serialize_tuple_struct( - self, - _name: &'static str, - len: usize, - ) -> Result { - self.serialize_tuple(len) - } - - fn serialize_tuple_variant( - self, - _name: &'static str, - _variant_index: u32, - variant: &'static str, - len: usize, - ) -> Result { - Ok(VariantSerializer::new( - self.scope, - variant, - self.serialize_tuple_struct(variant, len)?, - )) - } - - fn serialize_map(self, _len: Option) -> Result { - // Serializes a rust Map (e.g: BTreeMap, HashMap) to a v8 Object - // TODO: consider allowing serializing to v8 Maps (e.g: via a magic type) - // since they're lighter and better suited for K/V data - // and maybe restrict keys (e.g: strings and numbers) - Ok(MapSerializer::new(self.scope)) - } - - /// Serialises Rust typed structs into plain JS objects. - fn serialize_struct( - self, - name: &'static str, - _len: usize, - ) -> Result { - match name { - magic::NAME => { - let m: MagicSerializer<'a> = MagicSerializer { v8_value: None }; - Ok(StructSerializers::Magic(m)) - } - magic::buffer::BUF_NAME => { - let m = MagicBufferSerializer::new(self.scope); - Ok(StructSerializers::MagicBuffer(m)) - } - _ => { - let o = ObjectSerializer::new(self.scope); - Ok(StructSerializers::Regular(o)) - } - } - } - - fn serialize_struct_variant( - self, - _name: &'static str, - _variant_index: u32, - variant: &'static str, - len: usize, - ) -> Result { - let scope = self.scope; - let x = self.serialize_struct(variant, len)?; - Ok(VariantSerializer::new(scope, variant, x)) - } -} - -// Used to map MagicBuffers to v8 -pub fn boxed_slice_to_uint8array<'a>( - scope: &mut v8::HandleScope<'a>, - buf: Box<[u8]>, -) -> v8::Local<'a, v8::Uint8Array> { - if buf.is_empty() { - let ab = v8::ArrayBuffer::new(scope, 0); - return v8::Uint8Array::new(scope, ab, 0, 0) - .expect("Failed to create UintArray8"); - } - let buf_len = buf.len(); - let backing_store = v8::ArrayBuffer::new_backing_store_from_boxed_slice(buf); - 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") -} diff --git a/serde_v8/src/serializable.rs b/serde_v8/src/serializable.rs deleted file mode 100644 index c9182b636f..0000000000 --- a/serde_v8/src/serializable.rs +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -use rusty_v8 as v8; -use std::any::TypeId; -use std::mem::transmute_copy; - -/// Serializable exists to allow boxing values as "objects" to be serialized later, -/// this is particularly useful for async op-responses. This trait is a more efficient -/// replacement for erased-serde that makes less allocations, since it's specific to serde_v8 -/// (and thus doesn't have to have generic outputs, etc...) -pub trait Serializable { - fn to_v8<'a>( - &self, - scope: &mut v8::HandleScope<'a>, - ) -> Result, crate::Error>; -} - -/// Allows all implementors of `serde::Serialize` to implement Serializable -impl Serializable for T { - fn to_v8<'a>( - &self, - scope: &mut v8::HandleScope<'a>, - ) -> Result, crate::Error> { - crate::to_v8(scope, self) - } -} - -/// SerializablePkg exists to provide a fast path for op returns, -/// allowing them to avoid boxing primtives (ints/floats/bool/unit/...) -pub enum SerializablePkg { - Primitive(Primitive), - Serializable(Box), -} - -impl SerializablePkg { - pub fn to_v8<'a>( - &self, - scope: &mut v8::HandleScope<'a>, - ) -> Result, crate::Error> { - match &*self { - Self::Primitive(x) => crate::to_v8(scope, x), - Self::Serializable(x) => x.to_v8(scope), - } - } -} - -/// Primitive serves as a lightweight serializable wrapper around primitives -/// so that we can use them for async values -#[derive(Clone, Copy)] -pub enum Primitive { - Unit, - Bool(bool), - Int8(i8), - Int16(i16), - Int32(i32), - Int64(i64), - UInt8(u8), - UInt16(u16), - UInt32(u32), - UInt64(u64), - Float32(f32), - Float64(f64), -} - -impl serde::Serialize for Primitive { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - match *self { - Self::Unit => serializer.serialize_unit(), - Self::Bool(x) => serializer.serialize_bool(x), - Self::Int8(x) => serializer.serialize_i8(x), - Self::Int16(x) => serializer.serialize_i16(x), - Self::Int32(x) => serializer.serialize_i32(x), - Self::Int64(x) => serializer.serialize_i64(x), - Self::UInt8(x) => serializer.serialize_u8(x), - Self::UInt16(x) => serializer.serialize_u16(x), - Self::UInt32(x) => serializer.serialize_u32(x), - Self::UInt64(x) => serializer.serialize_u64(x), - Self::Float32(x) => serializer.serialize_f32(x), - Self::Float64(x) => serializer.serialize_f64(x), - } - } -} - -impl From for SerializablePkg { - fn from(x: T) -> Self { - let tid = TypeId::of::(); - - if tid == TypeId::of::<()>() { - Self::Primitive(Primitive::Unit) - } else if tid == TypeId::of::() { - Self::Primitive(Primitive::Bool(unsafe { transmute_copy(&x) })) - } else if tid == TypeId::of::() { - Self::Primitive(Primitive::Int8(unsafe { transmute_copy(&x) })) - } else if tid == TypeId::of::() { - Self::Primitive(Primitive::Int16(unsafe { transmute_copy(&x) })) - } else if tid == TypeId::of::() { - Self::Primitive(Primitive::Int32(unsafe { transmute_copy(&x) })) - } else if tid == TypeId::of::() { - Self::Primitive(Primitive::Int64(unsafe { transmute_copy(&x) })) - } else if tid == TypeId::of::() { - Self::Primitive(Primitive::UInt8(unsafe { transmute_copy(&x) })) - } else if tid == TypeId::of::() { - Self::Primitive(Primitive::UInt16(unsafe { transmute_copy(&x) })) - } else if tid == TypeId::of::() { - Self::Primitive(Primitive::UInt32(unsafe { transmute_copy(&x) })) - } else if tid == TypeId::of::() { - Self::Primitive(Primitive::UInt64(unsafe { transmute_copy(&x) })) - } else if tid == TypeId::of::() { - Self::Primitive(Primitive::Float32(unsafe { transmute_copy(&x) })) - } else if tid == TypeId::of::() { - Self::Primitive(Primitive::Float64(unsafe { transmute_copy(&x) })) - } else { - Self::Serializable(Box::new(x)) - } - } -} diff --git a/serde_v8/src/utils.rs b/serde_v8/src/utils.rs deleted file mode 100644 index 8f2a7a1eba..0000000000 --- a/serde_v8/src/utils.rs +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -use rusty_v8 as v8; -use std::sync::Once; - -pub fn js_exec<'s>( - scope: &mut v8::HandleScope<'s>, - src: &str, -) -> v8::Local<'s, v8::Value> { - let code = v8::String::new(scope, src).unwrap(); - let script = v8::Script::compile(scope, code, None).unwrap(); - script.run(scope).unwrap() -} - -pub fn v8_init() { - let platform = v8::new_default_platform().unwrap(); - v8::V8::initialize_platform(platform); - v8::V8::initialize(); -} - -pub fn v8_shutdown() { - unsafe { - v8::V8::dispose(); - } - v8::V8::shutdown_platform(); -} - -pub fn v8_do(f: impl FnOnce()) { - static V8_INIT: Once = Once::new(); - V8_INIT.call_once(|| { - v8_init(); - }); - f(); - // v8_shutdown(); -} diff --git a/serde_v8/tests/de.rs b/serde_v8/tests/de.rs deleted file mode 100644 index 785de63742..0000000000 --- a/serde_v8/tests/de.rs +++ /dev/null @@ -1,223 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -use rusty_v8 as v8; - -use serde::Deserialize; - -use serde_v8::utils::{js_exec, v8_do}; - -#[derive(Debug, Deserialize, PartialEq)] -struct MathOp { - pub a: u64, - pub b: u64, - pub operator: Option, -} - -#[derive(Debug, PartialEq, Deserialize)] -enum EnumUnit { - A, - B, - C, -} - -#[derive(Debug, PartialEq, Deserialize)] -enum EnumPayloads { - UInt(u64), - Int(i64), - Float(f64), - Point { x: i64, y: i64 }, - Tuple(bool, i64, ()), -} - -fn dedo( - code: &str, - f: impl FnOnce(&mut v8::HandleScope, v8::Local), -) { - v8_do(|| { - let isolate = &mut v8::Isolate::new(v8::CreateParams::default()); - let handle_scope = &mut v8::HandleScope::new(isolate); - let context = v8::Context::new(handle_scope); - let scope = &mut v8::ContextScope::new(handle_scope, context); - let v = js_exec(scope, code); - - f(scope, v); - }) -} - -macro_rules! detest { - ($fn_name:ident, $t:ty, $src:expr, $rust:expr) => { - #[test] - fn $fn_name() { - dedo($src, |scope, v| { - let rt = serde_v8::from_v8(scope, v); - assert!(rt.is_ok(), "from_v8(\"{}\"): {:?}", $src, rt.err()); - let t: $t = rt.unwrap(); - assert_eq!(t, $rust); - }); - } - }; -} - -detest!(de_option_some, Option, "true", Some(true)); -detest!(de_option_null, Option, "null", None); -detest!(de_option_undefined, Option, "undefined", None); -detest!(de_unit_null, (), "null", ()); -detest!(de_unit_undefined, (), "undefined", ()); -detest!(de_bool, bool, "true", true); -detest!(de_u64, u64, "32", 32); -detest!(de_string, String, "'Hello'", "Hello".to_owned()); -detest!(de_vec_u64, Vec, "[1,2,3,4,5]", vec![1, 2, 3, 4, 5]); -detest!( - de_vec_str, - Vec, - "['hello', 'world']", - vec!["hello".to_owned(), "world".to_owned()] -); -detest!( - de_tuple, - (u64, bool, ()), - "[123, true, null]", - (123, true, ()) -); -detest!( - de_mathop, - MathOp, - "({a: 1, b: 3, c: 'ignored'})", - MathOp { - a: 1, - b: 3, - operator: None - } -); - -// Unit enums -detest!(de_enum_unit_a, EnumUnit, "'A'", EnumUnit::A); -detest!(de_enum_unit_b, EnumUnit, "'B'", EnumUnit::B); -detest!(de_enum_unit_c, EnumUnit, "'C'", EnumUnit::C); - -// Enums with payloads (tuples & struct) -detest!( - de_enum_payload_int, - EnumPayloads, - "({ Int: -123 })", - EnumPayloads::Int(-123) -); -detest!( - de_enum_payload_uint, - EnumPayloads, - "({ UInt: 123 })", - EnumPayloads::UInt(123) -); -detest!( - de_enum_payload_float, - EnumPayloads, - "({ Float: 1.23 })", - EnumPayloads::Float(1.23) -); -detest!( - de_enum_payload_point, - EnumPayloads, - "({ Point: { x: 1, y: 2 } })", - EnumPayloads::Point { x: 1, y: 2 } -); -detest!( - de_enum_payload_tuple, - EnumPayloads, - "({ Tuple: [true, 123, null ] })", - EnumPayloads::Tuple(true, 123, ()) -); - -#[test] -fn de_f64() { - dedo("12345.0", |scope, v| { - let x: f64 = serde_v8::from_v8(scope, v).unwrap(); - assert!((x - 12345.0).abs() < f64::EPSILON); - }); -} - -#[test] -fn de_map() { - use std::collections::HashMap; - - dedo("({a: 1, b: 2, c: 3})", |scope, v| { - let map: HashMap = serde_v8::from_v8(scope, v).unwrap(); - assert_eq!(map.get("a").cloned(), Some(1)); - assert_eq!(map.get("b").cloned(), Some(2)); - assert_eq!(map.get("c").cloned(), Some(3)); - assert_eq!(map.get("nada"), None); - }) -} - -//// -// JSON tests: serde_json::Value compatibility -//// - -detest!( - de_json_null, - serde_json::Value, - "null", - serde_json::Value::Null -); -detest!( - de_json_bool, - serde_json::Value, - "true", - serde_json::Value::Bool(true) -); -detest!( - de_json_int, - serde_json::Value, - "123", - serde_json::Value::Number(serde_json::Number::from(123)) -); -detest!( - de_json_float, - serde_json::Value, - "123.45", - serde_json::Value::Number(serde_json::Number::from_f64(123.45).unwrap()) -); -detest!( - de_json_string, - serde_json::Value, - "'Hello'", - serde_json::Value::String("Hello".to_string()) -); -detest!( - de_json_vec_string, - serde_json::Value, - "['Hello', 'World']", - serde_json::Value::Array(vec![ - serde_json::Value::String("Hello".to_string()), - serde_json::Value::String("World".to_string()) - ]) -); -detest!( - de_json_tuple, - serde_json::Value, - "[true, 'World', 123.45, null]", - serde_json::Value::Array(vec![ - serde_json::Value::Bool(true), - serde_json::Value::String("World".to_string()), - serde_json::Value::Number(serde_json::Number::from_f64(123.45).unwrap()), - serde_json::Value::Null, - ]) -); -detest!( - de_json_object, - serde_json::Value, - "({a: 1, b: 'hello', c: true})", - serde_json::Value::Object( - vec![ - ( - "a".to_string(), - serde_json::Value::Number(serde_json::Number::from(1)), - ), - ( - "b".to_string(), - serde_json::Value::String("hello".to_string()), - ), - ("c".to_string(), serde_json::Value::Bool(true),), - ] - .drain(..) - .collect() - ) -); diff --git a/serde_v8/tests/magic.rs b/serde_v8/tests/magic.rs deleted file mode 100644 index 33ed394ede..0000000000 --- a/serde_v8/tests/magic.rs +++ /dev/null @@ -1,124 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -use rusty_v8 as v8; - -use serde::{Deserialize, Serialize}; - -use serde_v8::utils::{js_exec, v8_do}; -use std::convert::TryFrom; - -#[derive(Deserialize)] -struct MagicOp<'s> { - pub a: u64, - pub b: u64, - pub c: serde_v8::Value<'s>, - pub operator: Option, -} - -#[derive(Serialize)] -struct MagicContainer<'s> { - pub magic: bool, - pub contains: serde_v8::Value<'s>, -} - -#[test] -fn magic_basic() { - v8_do(|| { - let isolate = &mut v8::Isolate::new(v8::CreateParams::default()); - let handle_scope = &mut v8::HandleScope::new(isolate); - let context = v8::Context::new(handle_scope); - let scope = &mut v8::ContextScope::new(handle_scope, context); - - // Decode - let v = js_exec(scope, "({a: 1, b: 3, c: 'abracadabra'})"); - let mop: MagicOp = serde_v8::from_v8(scope, v).unwrap(); - // Check string - let v8_value: v8::Local = mop.c.into(); - let vs = v8::Local::::try_from(v8_value).unwrap(); - let s = vs.to_rust_string_lossy(scope); - assert_eq!(s, "abracadabra"); - - // Encode - let container = MagicContainer { - magic: true, - contains: v.into(), - }; - let vc = serde_v8::to_v8(scope, container).unwrap(); - // JSON stringify & check - let json = v8::json::stringify(scope, vc).unwrap(); - let s2 = json.to_rust_string_lossy(scope); - assert_eq!( - s2, - r#"{"magic":true,"contains":{"a":1,"b":3,"c":"abracadabra"}}"# - ); - }) -} - -#[test] -fn magic_buffer() { - v8_do(|| { - // Init isolate - let isolate = &mut v8::Isolate::new(v8::CreateParams::default()); - let handle_scope = &mut v8::HandleScope::new(isolate); - let context = v8::Context::new(handle_scope); - let scope = &mut v8::ContextScope::new(handle_scope, context); - let global = context.global(scope); - - // Simple buffer - let v8_array = js_exec(scope, "new Uint8Array([1,2,3,4,5])"); - let zbuf: serde_v8::Buffer = serde_v8::from_v8(scope, v8_array).unwrap(); - assert_eq!(&*zbuf, &[1, 2, 3, 4, 5]); - - // Multi buffers - let v8_arrays = - js_exec(scope, "[new Uint8Array([1,2]), new Uint8Array([3,4,5])]"); - let (z1, z2): (serde_v8::Buffer, serde_v8::Buffer) = - serde_v8::from_v8(scope, v8_arrays).unwrap(); - assert_eq!(&*z1, &[1, 2]); - assert_eq!(&*z2, &[3, 4, 5]); - - // Wrapped in option, like our current op-ABI - let v8_array = js_exec(scope, "new Uint8Array([1,2,3,4,5])"); - let zbuf: Option = - serde_v8::from_v8(scope, v8_array).unwrap(); - assert_eq!(&*zbuf.unwrap(), &[1, 2, 3, 4, 5]); - - // Observe mutation in JS - let v8_array = js_exec(scope, "new Uint8Array([1,2,3,4,5])"); - let mut zbuf: serde_v8::Buffer = - serde_v8::from_v8(scope, v8_array).unwrap(); - let key = serde_v8::to_v8(scope, "t1").unwrap(); - global.set(scope, key, v8_array); - (&mut *zbuf)[2] = 42; - let eq = js_exec(scope, "t1[2] === 42"); - assert!(eq.is_true()); - - // Serialization - let buf: Vec = vec![1, 2, 3, 99, 5]; - let zbuf: serde_v8::Buffer = buf.into(); - let v8_value = serde_v8::to_v8(scope, zbuf).unwrap(); - let key = serde_v8::to_v8(scope, "t2").unwrap(); - global.set(scope, key, v8_value); - let eq = js_exec(scope, "t2[3] === 99"); - assert!(eq.is_true()); - - // Composite Serialization - #[derive(serde::Serialize)] - struct Wrapper { - a: serde_v8::Buffer, - b: serde_v8::Buffer, - } - let buf1: Vec = vec![1, 2, 33, 4, 5]; - let buf2: Vec = vec![5, 4, 3, 2, 11]; - let wrapped = Wrapper { - a: buf1.into(), - b: buf2.into(), - }; - let v8_value = serde_v8::to_v8(scope, wrapped).unwrap(); - let key = serde_v8::to_v8(scope, "t3").unwrap(); - global.set(scope, key, v8_value); - let eq = js_exec(scope, "t3.a[2] === 33"); - assert!(eq.is_true()); - let eq = js_exec(scope, "t3.b[4] === 11"); - assert!(eq.is_true()); - }) -} diff --git a/serde_v8/tests/ser.rs b/serde_v8/tests/ser.rs deleted file mode 100644 index 2ae6065269..0000000000 --- a/serde_v8/tests/ser.rs +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -use rusty_v8 as v8; - -use serde::Serialize; -use serde_json::json; -use serde_v8::utils::{js_exec, v8_do}; - -#[derive(Debug, Serialize, PartialEq)] -struct MathOp { - pub a: u64, - pub b: u64, - pub operator: Option, -} - -// Utility JS code (obj equality, etc...) -const JS_UTILS: &str = r#" -// Shallow obj equality (don't use deep objs for now) -function objEqual(a, b) { - const ka = Object.keys(a); - const kb = Object.keys(b); - return ka.length === kb.length && ka.every(k => a[k] === b[k]); -} - -function arrEqual(a, b) { - return a.length === b.length && a.every((v, i) => v === b[i]); -} -"#; - -fn sercheck(val: T, code: &str) -> bool { - let mut equal = false; - - v8_do(|| { - // Setup isolate - let isolate = &mut v8::Isolate::new(v8::CreateParams::default()); - let handle_scope = &mut v8::HandleScope::new(isolate); - let context = v8::Context::new(handle_scope); - let scope = &mut v8::ContextScope::new(handle_scope, context); - - // Set value as "x" in global scope - let global = context.global(scope); - let v8_key = serde_v8::to_v8(scope, "x").unwrap(); - let v8_val = serde_v8::to_v8(scope, val).unwrap(); - global.set(scope, v8_key, v8_val); - - // Load util functions - js_exec(scope, JS_UTILS); - // Execute equality check in JS (e.g: x == ...) - let v = js_exec(scope, code); - // Cast to bool - equal = serde_v8::from_v8(scope, v).unwrap(); - }); - - equal -} - -macro_rules! sertest { - ($fn_name:ident, $rust:expr, $src:expr) => { - #[test] - fn $fn_name() { - assert!( - sercheck($rust, $src), - "Expected: {} where x={:?}", - $src, - $rust, - ); - } - }; -} - -sertest!(ser_option_some, Some(true), "x === true"); -sertest!(ser_option_null, None as Option, "x === null"); -sertest!(ser_unit_null, (), "x === null"); -sertest!(ser_bool, true, "x === true"); -sertest!(ser_u64, 32, "x === 32"); -sertest!(ser_f64, 12345.0, "x === 12345.0"); -sertest!(ser_string, "Hello".to_owned(), "x === 'Hello'"); -sertest!(ser_vec_u64, vec![1, 2, 3, 4, 5], "arrEqual(x, [1,2,3,4,5])"); -sertest!( - ser_vec_string, - vec!["hello".to_owned(), "world".to_owned(),], - "arrEqual(x, ['hello', 'world'])" -); -sertest!(ser_tuple, (123, true, ()), "arrEqual(x, [123, true, null])"); -sertest!( - ser_mathop, - MathOp { - a: 1, - b: 3, - operator: None - }, - "objEqual(x, {a: 1, b: 3, operator: null})" -); - -sertest!( - ser_map, - { - let map: std::collections::BTreeMap<&str, u32> = - vec![("a", 1), ("b", 2), ("c", 3)].drain(..).collect(); - map - }, - "objEqual(x, {a: 1, b: 2, c: 3})" -); - -//// -// JSON tests: json!() compatibility -//// -sertest!(ser_json_bool, json!(true), "x === true"); -sertest!(ser_json_null, json!(null), "x === null"); -sertest!(ser_json_int, json!(123), "x === 123"); -sertest!(ser_json_f64, json!(123.45), "x === 123.45"); -sertest!(ser_json_string, json!("Hello World"), "x === 'Hello World'"); -sertest!(ser_json_obj_empty, json!({}), "objEqual(x, {})"); -sertest!( - ser_json_obj, - json!({"a": 1, "b": 2, "c": true}), - "objEqual(x, {a: 1, b: 2, c: true})" -); -sertest!( - ser_json_vec_int, - json!([1, 2, 3, 4, 5]), - "arrEqual(x, [1,2,3,4,5])" -); -sertest!( - ser_json_vec_string, - json!(["Goodbye", "Dinosaurs 👋☄️"]), - "arrEqual(x, ['Goodbye', 'Dinosaurs 👋☄️'])" -); -sertest!( - ser_json_tuple, - json!([true, 42, "nabla"]), - "arrEqual(x, [true, 42, 'nabla'])" -); diff --git a/tools/cut_a_release.md b/tools/cut_a_release.md index 246dde28f8..2b823738bf 100644 --- a/tools/cut_a_release.md +++ b/tools/cut_a_release.md @@ -30,9 +30,6 @@ publish those crates.** This is done by running `cargo publish` in each crate, because of dependencies between the crates, it must be done in specific order: -- `serde_v8` - `deno_core` depends on it, but this crate shouldn't change that - often, so you might want to skip publishing a new version if there are no - changes - `deno_core` - all crates depend on `deno_core` so it must always be published first - `bench_util`