summaryrefslogtreecommitdiff
path: root/serde_v8
diff options
context:
space:
mode:
authorMatt Mastracci <matthew@mastracci.com>2023-07-01 18:00:14 -0600
committerGitHub <noreply@github.com>2023-07-02 00:00:14 +0000
commite746b6d80654ba4e4e26370fe6e4f784ce841d92 (patch)
tree153ffad92a96126b9ab8e906dcdabf7648755931 /serde_v8
parentb9c0e7cd550ab14fa7da7e33ed87cbeeeb9785a0 (diff)
refactor(core): Extract deno_core (#19658)
`deno_core` is moving out! You'll find it at https://github.com/denoland/deno_core/ once this PR lands.
Diffstat (limited to 'serde_v8')
-rw-r--r--serde_v8/Cargo.toml39
-rw-r--r--serde_v8/README.md57
-rw-r--r--serde_v8/benches/de.rs236
-rw-r--r--serde_v8/benches/ser.rs131
-rw-r--r--serde_v8/de.rs787
-rw-r--r--serde_v8/error.rs159
-rw-r--r--serde_v8/examples/basic.rs61
-rw-r--r--serde_v8/keys.rs31
-rw-r--r--serde_v8/lib.rs32
-rw-r--r--serde_v8/magic/any_value.rs68
-rw-r--r--serde_v8/magic/bigint.rs77
-rw-r--r--serde_v8/magic/buffer.rs119
-rw-r--r--serde_v8/magic/bytestring.rs109
-rw-r--r--serde_v8/magic/detached_buffer.rs70
-rw-r--r--serde_v8/magic/external_pointer.rs58
-rw-r--r--serde_v8/magic/global.rs41
-rw-r--r--serde_v8/magic/mod.rs17
-rw-r--r--serde_v8/magic/rawbytes.rs122
-rw-r--r--serde_v8/magic/string_or_buffer.rs58
-rw-r--r--serde_v8/magic/transl8.rs165
-rw-r--r--serde_v8/magic/u16string.rs59
-rw-r--r--serde_v8/magic/v8slice.rs181
-rw-r--r--serde_v8/magic/value.rs48
-rw-r--r--serde_v8/payload.rs43
-rw-r--r--serde_v8/ser.rs647
-rw-r--r--serde_v8/serializable.rs149
-rw-r--r--serde_v8/tests/de.rs613
-rw-r--r--serde_v8/tests/magic.rs192
-rw-r--r--serde_v8/tests/ser.rs270
-rw-r--r--serde_v8/utils.rs34
30 files changed, 0 insertions, 4673 deletions
diff --git a/serde_v8/Cargo.toml b/serde_v8/Cargo.toml
deleted file mode 100644
index 527bc27a0..000000000
--- a/serde_v8/Cargo.toml
+++ /dev/null
@@ -1,39 +0,0 @@
-# Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-
-[package]
-name = "serde_v8"
-version = "0.102.0"
-authors.workspace = true
-edition.workspace = true
-license.workspace = true
-readme = "README.md"
-repository.workspace = true
-description = "Rust to V8 serialization and deserialization"
-
-[lib]
-path = "lib.rs"
-
-[dependencies]
-bytes.workspace = true
-derive_more = "0.99.17"
-num-bigint.workspace = true
-serde.workspace = true
-serde_bytes.workspace = true
-smallvec = { workspace = true, features = ["union"] }
-thiserror.workspace = true
-v8.workspace = true
-
-[dev-dependencies]
-bencher.workspace = true
-serde_json.workspace = true
-
-[[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 d36f69375..000000000
--- a/serde_v8/README.md
+++ /dev/null
@@ -1,57 +0,0 @@
-# serde_v8
-
-Author: Aaron O'Mullan <aaron.omullan@gmail.com>
-
-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 unnecessary "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 b7cd0bf32..000000000
--- a/serde_v8/benches/de.rs
+++ /dev/null
@@ -1,236 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-use bencher::benchmark_group;
-use bencher::benchmark_main;
-use bencher::Bencher;
-
-use serde::Deserialize;
-
-use serde_v8::utils::js_exec;
-use serde_v8::utils::v8_do;
-use serde_v8::ByteString;
-
-#[derive(Debug, Deserialize, PartialEq)]
-struct MathOp {
- arg1: u64,
- arg2: u64,
- operator: Option<String>,
-}
-
-fn dedo(
- code: &str,
- f: impl FnOnce(&mut v8::HandleScope, v8::Local<v8::Value>),
-) {
- 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::<v8::Object>::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<u32>
-);
-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::<v8::Array>::try_from(obj).unwrap();
- let obj = v8::Local::<v8::Object>::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(),
- );
- });
- });
-}
-
-fn de_bstr_v8_12_b(b: &mut Bencher) {
- dedo(r#""hello world\n""#, |scope, v| {
- b.iter(move || {
- let _: ByteString = serde_v8::from_v8(scope, v).unwrap();
- });
- });
-}
-
-fn de_bstr_v8_1024_b(b: &mut Bencher) {
- dedo(
- r#""hello world\n".repeat(1e2).slice(0, 1024)"#,
- |scope, v| {
- b.iter(move || {
- let _: ByteString = serde_v8::from_v8(scope, v).unwrap();
- });
- },
- );
-}
-
-fn de_sob_str_6b(b: &mut Bencher) {
- dedo("'byebye'", |scope, v| {
- b.iter(move || {
- let _: serde_v8::StringOrBuffer = serde_v8::from_v8(scope, v).unwrap();
- })
- })
-}
-
-fn de_sob_str_1kb(b: &mut Bencher) {
- dedo("'deno'.repeat(256)", |scope, v| {
- b.iter(move || {
- let _: serde_v8::StringOrBuffer = serde_v8::from_v8(scope, v).unwrap();
- })
- })
-}
-
-fn de_sob_buf_1b(b: &mut Bencher) {
- dedo("new Uint8Array([97])", |scope, v| {
- b.iter(move || {
- let _: serde_v8::StringOrBuffer = serde_v8::from_v8(scope, v).unwrap();
- })
- })
-}
-
-fn de_sob_buf_1kb(b: &mut Bencher) {
- dedo("(new Uint8Array(1*1024)).fill(42)", |scope, v| {
- b.iter(move || {
- let _: serde_v8::StringOrBuffer = serde_v8::from_v8(scope, v).unwrap();
- })
- })
-}
-
-fn de_sob_buf_16kb(b: &mut Bencher) {
- dedo("(new Uint8Array(16*1024)).fill(42)", |scope, v| {
- b.iter(move || {
- let _: serde_v8::StringOrBuffer = serde_v8::from_v8(scope, v).unwrap();
- })
- })
-}
-
-fn de_sob_buf_512kb(b: &mut Bencher) {
- dedo("(new Uint8Array(512*1024)).fill(42)", |scope, v| {
- b.iter(move || {
- let _: serde_v8::StringOrBuffer = serde_v8::from_v8(scope, v).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,
- de_bstr_v8_12_b,
- de_bstr_v8_1024_b,
- de_sob_str_6b,
- de_sob_str_1kb,
- de_sob_buf_1b,
- de_sob_buf_1kb,
- de_sob_buf_16kb,
- de_sob_buf_512kb,
-);
-
-benchmark_main!(benches);
diff --git a/serde_v8/benches/ser.rs b/serde_v8/benches/ser.rs
deleted file mode 100644
index 83274fae3..000000000
--- a/serde_v8/benches/ser.rs
+++ /dev/null
@@ -1,131 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-use bencher::benchmark_group;
-use bencher::benchmark_main;
-use bencher::Bencher;
-
-use serde::Serialize;
-
-use serde_v8::utils::v8_do;
-use serde_v8::ByteString;
-
-#[derive(Serialize)]
-struct MathOp {
- arg1: u64,
- arg2: u64,
- operator: Option<String>,
-}
-
-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();
- });
- });
-}
-
-fn ser_bstr_12_b(b: &mut Bencher) {
- serdo(|scope| {
- let bstr = ByteString::from("hello world\n");
- b.iter(|| {
- let _ = serde_v8::to_v8(scope, &bstr).unwrap();
- });
- });
-}
-
-fn ser_bstr_1024_b(b: &mut Bencher) {
- serdo(|scope| {
- let mut s = "hello world\n".repeat(100);
- s.truncate(1024);
- let bstr = ByteString::from(s);
- b.iter(|| {
- let _ = serde_v8::to_v8(scope, &bstr).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,
- ser_bstr_12_b,
- ser_bstr_1024_b,
-);
-benchmark_main!(benches);
diff --git a/serde_v8/de.rs b/serde_v8/de.rs
deleted file mode 100644
index eb07271b4..000000000
--- a/serde_v8/de.rs
+++ /dev/null
@@ -1,787 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-use serde::de::SeqAccess as _;
-use serde::de::Visitor;
-use serde::de::{self};
-use serde::Deserialize;
-
-use crate::error::value_to_type_str;
-use crate::error::Error;
-use crate::error::Result;
-use crate::keys::v8_struct_key;
-use crate::keys::KeyCache;
-use crate::magic;
-use crate::magic::transl8::visit_magic;
-use crate::magic::transl8::FromV8;
-use crate::magic::transl8::MagicType;
-use crate::payload::ValueType;
-use crate::AnyValue;
-use crate::BigInt;
-use crate::ByteString;
-use crate::DetachedBuffer;
-use crate::JsBuffer;
-use crate::StringOrBuffer;
-use crate::U16String;
-
-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<T>
-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<T>
-where
- T: Deserialize<'de>,
-{
- let mut deserializer = Deserializer::new(scope, input, Some(key_cache));
- let t = T::deserialize(&mut deserializer)?;
- Ok(t)
-}
-
-macro_rules! deserialize_signed {
- ($dmethod:ident, $vmethod:ident, $t:tt) => {
- fn $dmethod<V>(self, visitor: V) -> Result<V::Value>
- where
- V: Visitor<'de>,
- {
- visitor.$vmethod(
- if let Ok(x) = v8::Local::<v8::Number>::try_from(self.input) {
- x.value() as $t
- } else if let Ok(x) = v8::Local::<v8::BigInt>::try_from(self.input) {
- x.i64_value().0 as $t
- } else {
- return Err(Error::ExpectedInteger(value_to_type_str(self.input)));
- },
- )
- }
- };
-}
-
-macro_rules! deserialize_unsigned {
- ($dmethod:ident, $vmethod:ident, $t:tt) => {
- fn $dmethod<V>(self, visitor: V) -> Result<V::Value>
- where
- V: Visitor<'de>,
- {
- visitor.$vmethod(
- if let Ok(x) = v8::Local::<v8::Number>::try_from(self.input) {
- x.value() as $t
- } else if let Ok(x) = v8::Local::<v8::BigInt>::try_from(self.input) {
- x.u64_value().0 as $t
- } else {
- return Err(Error::ExpectedInteger(value_to_type_str(self.input)));
- },
- )
- }
- };
-}
-
-impl<'de, 'a, 'b, 's, 'x> de::Deserializer<'de>
- for &'x mut Deserializer<'a, 'b, 's>
-{
- type Error = Error;
-
- fn deserialize_any<V>(self, visitor: V) -> Result<V::Value>
- 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::BigInt => Err(Error::UnsupportedType),
- ValueType::String => self.deserialize_string(visitor),
- ValueType::Array => self.deserialize_seq(visitor),
- ValueType::Object => self.deserialize_map(visitor),
- // Map to Vec<u8> when deserialized via deserialize_any
- // e.g: for untagged enums or StringOrBuffer
- ValueType::ArrayBufferView | ValueType::ArrayBuffer => {
- magic::v8slice::V8Slice::from_v8(&mut *self.scope, self.input)
- .and_then(|zb| visitor.visit_byte_buf(Vec::from(&*zb)))
- }
- }
- }
-
- fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value>
- where
- V: Visitor<'de>,
- {
- // Relaxed typechecking, will map all non-true vals to false
- visitor.visit_bool(self.input.is_true())
- }
-
- // signed
- 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);
- // unsigned
- deserialize_unsigned!(deserialize_u8, visit_u8, u8);
- deserialize_unsigned!(deserialize_u16, visit_u16, u16);
- deserialize_unsigned!(deserialize_u32, visit_u32, u32);
- deserialize_unsigned!(deserialize_u64, visit_u64, u64);
-
- fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value>
- where
- V: Visitor<'de>,
- {
- self.deserialize_f64(visitor)
- }
- fn deserialize_f64<V>(self, visitor: V) -> Result<V::Value>
- where
- V: Visitor<'de>,
- {
- visitor.visit_f64(
- if let Ok(x) = v8::Local::<v8::Number>::try_from(self.input) {
- x.value()
- } else if let Ok(x) = v8::Local::<v8::BigInt>::try_from(self.input) {
- bigint_to_f64(x)
- } else {
- return Err(Error::ExpectedNumber(value_to_type_str(self.input)));
- },
- )
- }
-
- fn deserialize_char<V>(self, visitor: V) -> Result<V::Value>
- where
- V: Visitor<'de>,
- {
- self.deserialize_str(visitor)
- }
-
- fn deserialize_str<V>(self, visitor: V) -> Result<V::Value>
- where
- V: Visitor<'de>,
- {
- self.deserialize_string(visitor)
- }
-
- fn deserialize_string<V>(self, visitor: V) -> Result<V::Value>
- where
- V: Visitor<'de>,
- {
- if self.input.is_string() || self.input.is_string_object() {
- let v8_string = self.input.to_string(self.scope).unwrap();
- let string = to_utf8(v8_string, self.scope);
- visitor.visit_string(string)
- } else {
- Err(Error::ExpectedString(value_to_type_str(self.input)))
- }
- }
-
- fn deserialize_option<V>(self, visitor: V) -> Result<V::Value>
- where
- V: Visitor<'de>,
- {
- if self.input.is_null_or_undefined() {
- visitor.visit_none()
- } else {
- visitor.visit_some(self)
- }
- }
-
- fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value>
- where
- V: Visitor<'de>,
- {
- visitor.visit_unit()
- }
-
- fn deserialize_unit_struct<V>(
- self,
- _name: &'static str,
- visitor: V,
- ) -> Result<V::Value>
- 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<V>(
- self,
- _name: &'static str,
- visitor: V,
- ) -> Result<V::Value>
- where
- V: Visitor<'de>,
- {
- visitor.visit_newtype_struct(self)
- }
-
- fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value>
- where
- V: Visitor<'de>,
- {
- let arr = v8::Local::<v8::Array>::try_from(self.input)
- .map_err(|_| Error::ExpectedArray(value_to_type_str(self.input)))?;
- visitor.visit_seq(SeqAccess::new(arr.into(), self.scope, 0..arr.length()))
- }
-
- // Like deserialize_seq except it prefers tuple's length over input array's length
- fn deserialize_tuple<V>(self, len: usize, visitor: V) -> Result<V::Value>
- where
- V: Visitor<'de>,
- {
- let obj = v8::Local::<v8::Object>::try_from(self.input).unwrap();
- if obj.is_array() {
- // If the obj is an array fail if it's length differs from the tuple length
- let array = v8::Local::<v8::Array>::try_from(self.input).unwrap();
- let array_len = array.length() as usize;
- if array_len != len {
- return Err(Error::LengthMismatch(array_len, len));
- }
- }
- visitor.visit_seq(SeqAccess::new(obj, self.scope, 0..len as u32))
- }
-
- // Tuple structs look just like sequences in JSON.
- fn deserialize_tuple_struct<V>(
- self,
- _name: &'static str,
- len: usize,
- visitor: V,
- ) -> Result<V::Value>
- where
- V: Visitor<'de>,
- {
- self.deserialize_tuple(len, visitor)
- }
-
- fn deserialize_map<V>(self, visitor: V) -> Result<V::Value>
- where
- V: de::Visitor<'de>,
- {
- // Assume object, then get_own_property_names
- let obj = v8::Local::<v8::Object>::try_from(self.input)
- .map_err(|_| Error::ExpectedObject(value_to_type_str(self.input)))?;
-
- if v8::Local::<v8::Map>::try_from(self.input).is_ok() {
- let pairs_array = v8::Local::<v8::Map>::try_from(self.input)
- .unwrap()
- .as_array(self.scope);
- let map = MapPairsAccess {
- pos: 0,
- len: pairs_array.length(),
- obj: pairs_array,
- scope: self.scope,
- };
- visitor.visit_map(map)
- } else {
- visitor.visit_map(MapObjectAccess::new(obj, self.scope))
- }
- }
-
- fn deserialize_struct<V>(
- self,
- name: &'static str,
- fields: &'static [&'static str],
- visitor: V,
- ) -> Result<V::Value>
- where
- V: Visitor<'de>,
- {
- match name {
- JsBuffer::MAGIC_NAME => {
- visit_magic(visitor, JsBuffer::from_v8(self.scope, self.input)?)
- }
- DetachedBuffer::MAGIC_NAME => {
- visit_magic(visitor, DetachedBuffer::from_v8(self.scope, self.input)?)
- }
- ByteString::MAGIC_NAME => {
- visit_magic(visitor, ByteString::from_v8(self.scope, self.input)?)
- }
- U16String::MAGIC_NAME => {
- visit_magic(visitor, U16String::from_v8(self.scope, self.input)?)
- }
- StringOrBuffer::MAGIC_NAME => {
- visit_magic(visitor, StringOrBuffer::from_v8(self.scope, self.input)?)
- }
- BigInt::MAGIC_NAME => {
- visit_magic(visitor, BigInt::from_v8(self.scope, self.input)?)
- }
- magic::Value::MAGIC_NAME => {
- visit_magic(visitor, magic::Value::from_v8(self.scope, self.input)?)
- }
- AnyValue::MAGIC_NAME => {
- visit_magic(visitor, AnyValue::from_v8(self.scope, self.input)?)
- }
- _ => {
- // Regular struct
- let obj = v8::Local::<v8::Object>::try_from(self.input)
- .map_err(|_| Error::ExpectedObject(value_to_type_str(self.input)))?;
-
- // Fields names are a hint and must be inferred when not provided
- if fields.is_empty() {
- visitor.visit_map(MapObjectAccess::new(obj, self.scope))
- } else {
- visitor.visit_map(StructAccess {
- obj,
- scope: self.scope,
- keys: fields.iter(),
- next_value: None,
- })
- }
- }
- }
- }
-
- /// 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<V>(
- self,
- _name: &str,
- _variants: &'static [&'static str],
- visitor: V,
- ) -> Result<V::Value>
- where
- V: Visitor<'de>,
- {
- // Unit variant
- if self.input.is_string() || self.input.is_string_object() {
- 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::<v8::Object>::try_from(self.input).unwrap();
- // Unpack single-key
- let tag = {
- let prop_names =
- obj.get_own_property_names(self.scope, Default::default());
- let prop_names = prop_names
- .ok_or_else(|| Error::ExpectedEnum(value_to_type_str(self.input)))?;
- let prop_names_len = prop_names.length();
- if prop_names_len != 1 {
- return Err(Error::LengthMismatch(prop_names_len as usize, 1));
- }
- 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 {
- Err(Error::ExpectedEnum(value_to_type_str(self.input)))
- }
- }
-
- // 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<V>(self, visitor: V) -> Result<V::Value>
- where
- V: Visitor<'de>,
- {
- self.deserialize_str(visitor)
- }
-
- fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value>
- where
- V: Visitor<'de>,
- {
- visitor.visit_none()
- }
-
- fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value>
- where
- V: Visitor<'de>,
- {
- magic::buffer::JsBuffer::from_v8(self.scope, self.input)
- .and_then(|zb| visitor.visit_bytes(&zb))
- }
-
- fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value>
- where
- V: Visitor<'de>,
- {
- magic::buffer::JsBuffer::from_v8(self.scope, self.input)
- .and_then(|zb| visitor.visit_byte_buf(Vec::from(&*zb)))
- }
-}
-
-struct MapObjectAccess<'a, 's> {
- obj: v8::Local<'a, v8::Object>,
- keys: SeqAccess<'a, 's>,
- next_value: Option<v8::Local<'s, v8::Value>>,
-}
-
-impl<'a, 's> MapObjectAccess<'a, 's> {
- pub fn new(
- obj: v8::Local<'a, v8::Object>,
- scope: &'a mut v8::HandleScope<'s>,
- ) -> Self {
- let keys = match obj.get_own_property_names(
- scope,
- v8::GetPropertyNamesArgsBuilder::new()
- .key_conversion(v8::KeyConversionMode::ConvertToString)
- .build(),
- ) {
- Some(keys) => SeqAccess::new(keys.into(), scope, 0..keys.length()),
- None => SeqAccess::new(obj, scope, 0..0),
- };
-
- Self {
- obj,
- keys,
- next_value: None,
- }
- }
-}
-
-impl<'de> de::MapAccess<'de> for MapObjectAccess<'_, '_> {
- type Error = Error;
-
- fn next_key_seed<K: de::DeserializeSeed<'de>>(
- &mut self,
- seed: K,
- ) -> Result<Option<K::Value>> {
- while let Some(key) = self.keys.next_element::<magic::Value>()? {
- let v8_val = self.obj.get(self.keys.scope, key.v8_value).unwrap();
- if v8_val.is_undefined() {
- // Historically keys/value pairs with undefined values are not added to the output
- continue;
- }
- self.next_value = Some(v8_val);
- let mut deserializer =
- Deserializer::new(self.keys.scope, key.v8_value, None);
- return seed.deserialize(&mut deserializer).map(Some);
- }
- Ok(None)
- }
-
- fn next_value_seed<V: de::DeserializeSeed<'de>>(
- &mut self,
- seed: V,
- ) -> Result<V::Value> {
- let v8_val = self
- .next_value
- .take()
- .expect("Call next_key_seed before next_value_seed");
- let mut deserializer = Deserializer::new(self.keys.scope, v8_val, None);
- seed.deserialize(&mut deserializer)
- }
-
- fn size_hint(&self) -> Option<usize> {
- self.keys.size_hint()
- }
-}
-
-struct MapPairsAccess<'a, 's> {
- obj: v8::Local<'a, v8::Array>,
- pos: u32,
- len: u32,
- scope: &'a mut v8::HandleScope<'s>,
-}
-
-impl<'de> de::MapAccess<'de> for MapPairsAccess<'_, '_> {
- type Error = Error;
-
- fn next_key_seed<K: de::DeserializeSeed<'de>>(
- &mut self,
- seed: K,
- ) -> Result<Option<K::Value>> {
- if self.pos < self.len {
- let v8_key = self.obj.get_index(self.scope, self.pos).unwrap();
- self.pos += 1;
- let mut deserializer = Deserializer::new(self.scope, v8_key, None);
- let k = seed.deserialize(&mut deserializer)?;
- Ok(Some(k))
- } else {
- Ok(None)
- }
- }
-
- fn next_value_seed<V: de::DeserializeSeed<'de>>(
- &mut self,
- seed: V,
- ) -> Result<V::Value> {
- debug_assert!(self.pos < self.len);
- let v8_val = self.obj.get_index(self.scope, self.pos).unwrap();
- self.pos += 1;
- let mut deserializer = Deserializer::new(self.scope, v8_val, None);
- seed.deserialize(&mut deserializer)
- }
-
- fn size_hint(&self) -> Option<usize> {
- Some((self.len - self.pos) as usize / 2)
- }
-}
-
-struct StructAccess<'a, 's> {
- obj: v8::Local<'a, v8::Object>,
- scope: &'a mut v8::HandleScope<'s>,
- keys: std::slice::Iter<'static, &'static str>,
- next_value: Option<v8::Local<'s, v8::Value>>,
-}
-
-impl<'de> de::MapAccess<'de> for StructAccess<'_, '_> {
- type Error = Error;
-
- fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>>
- where
- K: de::DeserializeSeed<'de>,
- {
- for field in self.keys.by_ref() {
- let key = v8_struct_key(self.scope, field).into();
- let val = self.obj.get(self.scope, key).unwrap();
- if val.is_undefined() {
- // Historically keys/value pairs with undefined values are not added to the output
- continue;
- }
- self.next_value = Some(val);
- let mut deserializer = Deserializer::new(self.scope, key, None);
- return seed.deserialize(&mut deserializer).map(Some);
- }
- Ok(None)
- }
-
- fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value>
- where
- V: de::DeserializeSeed<'de>,
- {
- let val = self
- .next_value
- .take()
- .expect("Call next_key_seed before next_value_seed");
- let mut deserializer = Deserializer::new(self.scope, val, None);
- seed.deserialize(&mut deserializer)
- }
-}
-
-struct SeqAccess<'a, 's> {
- obj: v8::Local<'a, v8::Object>,
- scope: &'a mut v8::HandleScope<'s>,
- range: std::ops::Range<u32>,
-}
-
-impl<'a, 's> SeqAccess<'a, 's> {
- pub fn new(
- obj: v8::Local<'a, v8::Object>,
- scope: &'a mut v8::HandleScope<'s>,
- range: std::ops::Range<u32>,
- ) -> Self {
- Self { obj, scope, range }
- }
-}
-
-impl<'de> de::SeqAccess<'de> for SeqAccess<'_, '_> {
- type Error = Error;
-
- fn next_element_seed<T: de::DeserializeSeed<'de>>(
- &mut self,
- seed: T,
- ) -> Result<Option<T::Value>> {
- if let Some(pos) = self.range.next() {
- let val = self.obj.get_index(self.scope, pos).unwrap();
- let mut deserializer = Deserializer::new(self.scope, val, None);
- seed.deserialize(&mut deserializer).map(Some)
- } else {
- Ok(None)
- }
- }
-
- fn size_hint(&self) -> Option<usize> {
- self.range.size_hint().1
- }
-}
-
-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> de::EnumAccess<'de> for EnumAccess<'a, 'b, 's> {
- type Error = Error;
- type Variant = VariantDeserializer<'a, 'b, 's>;
-
- fn variant_seed<V: de::DeserializeSeed<'de>>(
- 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<T: de::DeserializeSeed<'de>>(
- self,
- seed: T,
- ) -> Result<T::Value> {
- let mut d = Deserializer::new(self.scope, self.value, None);
- seed.deserialize(&mut d)
- }
-
- fn tuple_variant<V: de::Visitor<'de>>(
- self,
- len: usize,
- visitor: V,
- ) -> Result<V::Value> {
- let mut d = Deserializer::new(self.scope, self.value, None);
- de::Deserializer::deserialize_tuple(&mut d, len, visitor)
- }
-
- fn struct_variant<V: de::Visitor<'de>>(
- self,
- fields: &'static [&'static str],
- visitor: V,
- ) -> Result<V::Value> {
- let mut d = Deserializer::new(self.scope, self.value, None);
- de::Deserializer::deserialize_struct(&mut d, "", fields, visitor)
- }
-}
-
-fn bigint_to_f64(b: v8::Local<v8::BigInt>) -> f64 {
- // log2(f64::MAX) == log2(1.7976931348623157e+308) == 1024
- let mut words: [u64; 16] = [0; 16]; // 1024/64 => 16 64bit words
- let (neg, words) = b.to_words_array(&mut words);
- if b.word_count() > 16 {
- return match neg {
- true => f64::NEG_INFINITY,
- false => f64::INFINITY,
- };
- }
- let sign = if neg { -1.0 } else { 1.0 };
- let x: f64 = words
- .iter()
- .enumerate()
- .map(|(i, w)| (*w as f64) * 2.0f64.powi(64 * i as i32))
- .sum();
- sign * x
-}
-
-pub fn to_utf8(
- s: v8::Local<v8::String>,
- scope: &mut v8::HandleScope,
-) -> String {
- to_utf8_fast(s, scope).unwrap_or_else(|| to_utf8_slow(s, scope))
-}
-
-fn to_utf8_fast(
- s: v8::Local<v8::String>,
- scope: &mut v8::HandleScope,
-) -> Option<String> {
- // Over-allocate by 20% to avoid checking string twice
- let str_chars = s.length();
- let capacity = (str_chars as f64 * 1.2) as usize;
- let mut buf = Vec::with_capacity(capacity);
-
- let mut nchars = 0;
- let bytes_len = s.write_utf8_uninit(
- scope,
- buf.spare_capacity_mut(),
- Some(&mut nchars),
- v8::WriteOptions::NO_NULL_TERMINATION
- | v8::WriteOptions::REPLACE_INVALID_UTF8,
- );
-
- if nchars < str_chars {
- return None;
- }
-
- // SAFETY: write_utf8_uninit guarantees `bytes_len` bytes are initialized & valid utf8
- unsafe {
- buf.set_len(bytes_len);
- Some(String::from_utf8_unchecked(buf))
- }
-}
-
-fn to_utf8_slow(
- s: v8::Local<v8::String>,
- scope: &mut v8::HandleScope,
-) -> String {
- let capacity = s.utf8_length(scope);
- let mut buf = Vec::with_capacity(capacity);
-
- let bytes_len = s.write_utf8_uninit(
- scope,
- buf.spare_capacity_mut(),
- None,
- v8::WriteOptions::NO_NULL_TERMINATION
- | v8::WriteOptions::REPLACE_INVALID_UTF8,
- );
-
- // SAFETY: write_utf8_uninit guarantees `bytes_len` bytes are initialized & valid utf8
- unsafe {
- buf.set_len(bytes_len);
- String::from_utf8_unchecked(buf)
- }
-}
diff --git a/serde_v8/error.rs b/serde_v8/error.rs
deleted file mode 100644
index 16d7882b7..000000000
--- a/serde_v8/error.rs
+++ /dev/null
@@ -1,159 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-use std::fmt::Display;
-
-pub type Result<T> = std::result::Result<T, Error>;
-
-#[derive(Clone, Debug, Eq, PartialEq, thiserror::Error)]
-#[non_exhaustive]
-pub enum Error {
- #[error("{0}")]
- Message(String),
-
- #[error("serde_v8 error: invalid type; expected: boolean, got: {0}")]
- ExpectedBoolean(&'static str),
-
- #[error("serde_v8 error: invalid type; expected: integer, got: {0}")]
- ExpectedInteger(&'static str),
-
- #[error("serde_v8 error: invalid type; expected: number, got: {0}")]
- ExpectedNumber(&'static str),
-
- #[error("serde_v8 error: invalid type; expected: string, got: {0}")]
- ExpectedString(&'static str),
-
- #[error("serde_v8 error: invalid type; expected: array, got: {0}")]
- ExpectedArray(&'static str),
-
- #[error("serde_v8 error: invalid type; expected: map, got: {0}")]
- ExpectedMap(&'static str),
-
- #[error("serde_v8 error: invalid type; expected: enum, got: {0}")]
- ExpectedEnum(&'static str),
-
- #[error("serde_v8 error: invalid type; expected: object, got: {0}")]
- ExpectedObject(&'static str),
-
- #[error("serde_v8 error: invalid type; expected: buffer, got: {0}")]
- ExpectedBuffer(&'static str),
-
- #[error("serde_v8 error: invalid type; expected: detachable, got: {0}")]
- ExpectedDetachable(&'static str),
-
- #[error("serde_v8 error: invalid type; expected: external, got: {0}")]
- ExpectedExternal(&'static str),
-
- #[error("serde_v8 error: invalid type; expected: bigint, got: {0}")]
- ExpectedBigInt(&'static str),
-
- #[error("serde_v8 error: invalid type, expected: utf8")]
- ExpectedUtf8,
- #[error("serde_v8 error: invalid type, expected: latin1")]
- ExpectedLatin1,
-
- #[error("serde_v8 error: unsupported type")]
- UnsupportedType,
-
- #[error("serde_v8 error: length mismatch, got: {0}, expected: {1}")]
- LengthMismatch(usize, usize),
-
- #[error("serde_v8 error: can't create slice from resizable ArrayBuffer")]
- ResizableBackingStoreNotSupported,
-}
-
-impl serde::ser::Error for Error {
- fn custom<T: Display>(msg: T) -> Self {
- Error::Message(msg.to_string())
- }
-}
-
-impl serde::de::Error for Error {
- fn custom<T: Display>(msg: T) -> Self {
- Error::Message(msg.to_string())
- }
-}
-
-pub(crate) fn value_to_type_str(value: v8::Local<v8::Value>) -> &'static str {
- if value.is_module_namespace_object() {
- "Module"
- } else if value.is_wasm_module_object() {
- "WASM module"
- } else if value.is_wasm_memory_object() {
- "WASM memory object"
- } else if value.is_proxy() {
- "Proxy"
- } else if value.is_shared_array_buffer() {
- "SharedArrayBuffer"
- } else if value.is_data_view() {
- "DataView"
- } else if value.is_big_uint64_array() {
- "BigUint64Array"
- } else if value.is_big_int64_array() {
- "BigInt64Array"
- } else if value.is_float64_array() {
- "Float64Array"
- } else if value.is_float32_array() {
- "Float32Array"
- } else if value.is_int32_array() {
- "Int32Array"
- } else if value.is_uint32_array() {
- "Uint32Array"
- } else if value.is_int16_array() {
- "Int16Array"
- } else if value.is_uint16_array() {
- "Uint16Array"
- } else if value.is_int8_array() {
- "Int8Array"
- } else if value.is_uint8_clamped_array() {
- "Uint8ClampedArray"
- } else if value.is_uint8_array() {
- "Uint8Array"
- } else if value.is_typed_array() {
- "TypedArray"
- } else if value.is_array_buffer_view() {
- "ArrayBufferView"
- } else if value.is_array_buffer() {
- "ArrayBuffer"
- } else if value.is_weak_set() {
- "WeakSet"
- } else if value.is_weak_map() {
- "WeakMap"
- } else if value.is_set_iterator() {
- "Set Iterator"
- } else if value.is_map_iterator() {
- "Map Iterator"
- } else if value.is_set() {
- "Set"
- } else if value.is_map() {
- "Map"
- } else if value.is_promise() {
- "Promise"
- } else if value.is_generator_function() {
- "Generator function"
- } else if value.is_async_function() {
- "Async function"
- } else if value.is_reg_exp() {
- "RegExp"
- } else if value.is_date() {
- "Date"
- } else if value.is_number() {
- "Number"
- } else if value.is_boolean() {
- "Boolean"
- } else if value.is_big_int() {
- "bigint"
- } else if value.is_array() {
- "array"
- } else if value.is_function() {
- "function"
- } else if value.is_symbol() {
- "symbol"
- } else if value.is_string() {
- "string"
- } else if value.is_null() {
- "null"
- } else if value.is_undefined() {
- "undefined"
- } else {
- "unknown"
- }
-}
diff --git a/serde_v8/examples/basic.rs b/serde_v8/examples/basic.rs
deleted file mode 100644
index 29fb98085..000000000
--- a/serde_v8/examples/basic.rs
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-use serde::Deserialize;
-
-#[derive(Debug, Deserialize)]
-struct MathOp {
- pub a: u64,
- pub b: u64,
- pub operator: Option<String>,
-}
-
-fn main() {
- let platform = v8::new_default_platform(0, false).make_shared();
- 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 = {{ a: {}, b: {}, operator: {:?} }}",
- mop.a, mop.b, mop.operator
- );
-
- let v = exec(scope, "[1,2,3,4,5]");
- let arr: Vec<u64> = serde_v8::from_v8(scope, v).unwrap();
- println!("arr = {arr:?}");
-
- let v = exec(scope, "['hello', 'world']");
- let hi: Vec<String> = serde_v8::from_v8(scope, v).unwrap();
- println!("hi = {hi:?}");
-
- let v: v8::Local<v8::Value> = v8::Number::new(scope, 12345.0).into();
- let x: f64 = serde_v8::from_v8(scope, v).unwrap();
- println!("x = {x}");
- }
-
- // SAFETY: all isolates have been destroyed, so we can now safely let V8 clean
- // up its resources.
- unsafe {
- v8::V8::dispose();
- }
- v8::V8::dispose_platform();
-}
diff --git a/serde_v8/keys.rs b/serde_v8/keys.rs
deleted file mode 100644
index d44306fd6..000000000
--- a/serde_v8/keys.rs
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-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<v8::String>>);
-
-// 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/lib.rs b/serde_v8/lib.rs
deleted file mode 100644
index 59c8fd41f..000000000
--- a/serde_v8/lib.rs
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2018-2023 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;
-pub use de::from_v8_cached;
-pub use de::to_utf8;
-pub use de::Deserializer;
-pub use error::Error;
-pub use error::Result;
-pub use keys::KeyCache;
-pub use magic::any_value::AnyValue;
-pub use magic::bigint::BigInt;
-pub use magic::buffer::JsBuffer;
-pub use magic::buffer::ToJsBuffer;
-pub use magic::bytestring::ByteString;
-pub use magic::detached_buffer::DetachedBuffer;
-pub use magic::string_or_buffer::StringOrBuffer;
-pub use magic::u16string::U16String;
-pub use magic::ExternalPointer;
-pub use magic::Global;
-pub use magic::Value;
-pub use ser::to_v8;
-pub use ser::Serializer;
-pub use serializable::Serializable;
-pub use serializable::SerializablePkg;
diff --git a/serde_v8/magic/any_value.rs b/serde_v8/magic/any_value.rs
deleted file mode 100644
index df85f90d8..000000000
--- a/serde_v8/magic/any_value.rs
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-use super::buffer::JsBuffer;
-use super::transl8::FromV8;
-use super::transl8::ToV8;
-use crate::magic::transl8::impl_magic;
-use crate::Error;
-use crate::ToJsBuffer;
-use num_bigint::BigInt;
-
-/// An untagged enum type that can be any of number, string, bool, bigint, or
-/// buffer.
-#[derive(Debug)]
-pub enum AnyValue {
- RustBuffer(ToJsBuffer),
- V8Buffer(JsBuffer),
- String(String),
- Number(f64),
- BigInt(BigInt),
- Bool(bool),
-}
-
-impl_magic!(AnyValue);
-
-impl ToV8 for AnyValue {
- fn to_v8<'a>(
- &mut self,
- scope: &mut v8::HandleScope<'a>,
- ) -> Result<v8::Local<'a, v8::Value>, crate::Error> {
- match self {
- Self::RustBuffer(buf) => crate::to_v8(scope, buf),
- Self::V8Buffer(_) => unreachable!(),
- Self::String(s) => crate::to_v8(scope, s),
- Self::Number(num) => crate::to_v8(scope, num),
- Self::BigInt(bigint) => {
- crate::to_v8(scope, crate::BigInt::from(bigint.clone()))
- }
- Self::Bool(b) => crate::to_v8(scope, b),
- }
- }
-}
-
-impl FromV8 for AnyValue {
- fn from_v8(
- scope: &mut v8::HandleScope,
- value: v8::Local<v8::Value>,
- ) -> Result<Self, crate::Error> {
- if value.is_string() {
- let string = crate::from_v8(scope, value)?;
- Ok(AnyValue::String(string))
- } else if value.is_number() {
- let string = crate::from_v8(scope, value)?;
- Ok(AnyValue::Number(string))
- } else if value.is_big_int() {
- let bigint = crate::BigInt::from_v8(scope, value)?;
- Ok(AnyValue::BigInt(bigint.into()))
- } else if value.is_array_buffer_view() {
- let buf = JsBuffer::from_v8(scope, value)?;
- Ok(AnyValue::V8Buffer(buf))
- } else if value.is_boolean() {
- let string = crate::from_v8(scope, value)?;
- Ok(AnyValue::Bool(string))
- } else {
- Err(Error::Message(
- "expected string, number, bigint, ArrayBufferView, boolean".into(),
- ))
- }
- }
-}
diff --git a/serde_v8/magic/bigint.rs b/serde_v8/magic/bigint.rs
deleted file mode 100644
index 330803daf..000000000
--- a/serde_v8/magic/bigint.rs
+++ /dev/null
@@ -1,77 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-
-use smallvec::smallvec;
-use smallvec::SmallVec;
-
-use super::transl8::FromV8;
-use super::transl8::ToV8;
-use crate::error::value_to_type_str;
-use crate::magic::transl8::impl_magic;
-use crate::Error;
-
-#[derive(
- PartialEq,
- Eq,
- Clone,
- Debug,
- Default,
- derive_more::Deref,
- derive_more::DerefMut,
- derive_more::AsRef,
- derive_more::AsMut,
-)]
-#[as_mut(forward)]
-#[as_ref(forward)]
-pub struct BigInt(num_bigint::BigInt);
-impl_magic!(BigInt);
-
-impl ToV8 for BigInt {
- fn to_v8<'a>(
- &mut self,
- scope: &mut v8::HandleScope<'a>,
- ) -> Result<v8::Local<'a, v8::Value>, crate::Error> {
- let (sign, words) = self.0.to_u64_digits();
- let sign_bit = sign == num_bigint::Sign::Minus;
- let v = v8::BigInt::new_from_words(scope, sign_bit, &words).unwrap();
- Ok(v.into())
- }
-}
-
-impl FromV8 for BigInt {
- fn from_v8(
- _scope: &mut v8::HandleScope,
- value: v8::Local<v8::Value>,
- ) -> Result<Self, crate::Error> {
- let v8bigint = v8::Local::<v8::BigInt>::try_from(value)
- .map_err(|_| Error::ExpectedBigInt(value_to_type_str(value)))?;
- let word_count = v8bigint.word_count();
- let mut words: SmallVec<[u64; 1]> = smallvec![0u64; word_count];
- let (sign_bit, _words) = v8bigint.to_words_array(&mut words);
- let sign = match sign_bit {
- true => num_bigint::Sign::Minus,
- false => num_bigint::Sign::Plus,
- };
- // SAFETY: Because the alignment of u64 is 8, the alignment of u32 is 4, and
- // the size of u64 is 8, the size of u32 is 4, the alignment of u32 is a
- // factor of the alignment of u64, and the size of u32 is a factor of the
- // size of u64, we can safely transmute the slice of u64 to a slice of u32.
- let (prefix, slice, suffix) = unsafe { words.align_to::<u32>() };
- assert!(prefix.is_empty());
- assert!(suffix.is_empty());
- assert_eq!(slice.len(), words.len() * 2);
- let big_int = num_bigint::BigInt::from_slice(sign, slice);
- Ok(Self(big_int))
- }
-}
-
-impl From<num_bigint::BigInt> for BigInt {
- fn from(big_int: num_bigint::BigInt) -> Self {
- Self(big_int)
- }
-}
-
-impl From<BigInt> for num_bigint::BigInt {
- fn from(big_int: BigInt) -> Self {
- big_int.0
- }
-}
diff --git a/serde_v8/magic/buffer.rs b/serde_v8/magic/buffer.rs
deleted file mode 100644
index 032a3be33..000000000
--- a/serde_v8/magic/buffer.rs
+++ /dev/null
@@ -1,119 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-
-use std::fmt::Debug;
-use std::ops::Deref;
-use std::ops::DerefMut;
-
-use super::transl8::FromV8;
-use super::transl8::ToV8;
-use super::v8slice::V8Slice;
-use crate::magic::transl8::impl_magic;
-
-pub struct JsBuffer(V8Slice);
-
-impl_magic!(JsBuffer);
-
-impl Debug for JsBuffer {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- f.debug_list().entries(self.0.as_ref().iter()).finish()
- }
-}
-
-impl Clone for JsBuffer {
- fn clone(&self) -> Self {
- Self(self.0.clone())
- }
-}
-
-impl AsRef<[u8]> for JsBuffer {
- fn as_ref(&self) -> &[u8] {
- &self.0
- }
-}
-
-impl AsMut<[u8]> for JsBuffer {
- fn as_mut(&mut self) -> &mut [u8] {
- &mut self.0
- }
-}
-
-impl Deref for JsBuffer {
- type Target = [u8];
- fn deref(&self) -> &[u8] {
- &self.0
- }
-}
-
-impl DerefMut for JsBuffer {
- fn deref_mut(&mut self) -> &mut [u8] {
- &mut self.0
- }
-}
-
-impl FromV8 for JsBuffer {
- fn from_v8(
- scope: &mut v8::HandleScope,
- value: v8::Local<v8::Value>,
- ) -> Result<Self, crate::Error> {
- Ok(Self(V8Slice::from_v8(scope, value)?))
- }
-}
-
-impl From<JsBuffer> for bytes::Bytes {
- fn from(zbuf: JsBuffer) -> bytes::Bytes {
- zbuf.0.into()
- }
-}
-
-// NOTE(bartlomieju): we use Option here, because `to_v8()` uses `&mut self`
-// instead of `self` which is dictated by the `serde` API.
-#[derive(Debug)]
-pub struct ToJsBuffer(Option<Box<[u8]>>);
-
-impl_magic!(ToJsBuffer);
-
-impl ToJsBuffer {
- pub fn empty() -> Self {
- ToJsBuffer(Some(vec![0_u8; 0].into_boxed_slice()))
- }
-}
-
-impl From<Box<[u8]>> for ToJsBuffer {
- fn from(buf: Box<[u8]>) -> Self {
- ToJsBuffer(Some(buf))
- }
-}
-
-impl From<Vec<u8>> for ToJsBuffer {
- fn from(vec: Vec<u8>) -> Self {
- vec.into_boxed_slice().into()
- }
-}
-
-impl ToV8 for ToJsBuffer {
- fn to_v8<'a>(
- &mut self,
- scope: &mut v8::HandleScope<'a>,
- ) -> Result<v8::Local<'a, v8::Value>, crate::Error> {
- let buf: Box<[u8]> = self.0.take().expect("RustToV8Buf was empty");
-
- if buf.is_empty() {
- let ab = v8::ArrayBuffer::new(scope, 0);
- return Ok(
- v8::Uint8Array::new(scope, ab, 0, 0)
- .expect("Failed to create Uint8Array")
- .into(),
- );
- }
- let buf_len: usize = 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);
- Ok(
- v8::Uint8Array::new(scope, ab, 0, buf_len)
- .expect("Failed to create Uint8Array")
- .into(),
- )
- }
-}
diff --git a/serde_v8/magic/bytestring.rs b/serde_v8/magic/bytestring.rs
deleted file mode 100644
index 3baa704e5..000000000
--- a/serde_v8/magic/bytestring.rs
+++ /dev/null
@@ -1,109 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-use super::transl8::FromV8;
-use super::transl8::ToV8;
-use crate::error::value_to_type_str;
-use crate::magic::transl8::impl_magic;
-use crate::Error;
-use smallvec::SmallVec;
-use std::mem::size_of;
-
-const USIZE2X: usize = size_of::<usize>() * 2;
-
-#[derive(
- PartialEq,
- Eq,
- Clone,
- Debug,
- Default,
- derive_more::Deref,
- derive_more::DerefMut,
- derive_more::AsRef,
- derive_more::AsMut,
-)]
-#[as_mut(forward)]
-#[as_ref(forward)]
-pub struct ByteString(SmallVec<[u8; USIZE2X]>);
-impl_magic!(ByteString);
-
-// const-assert that Vec<u8> and SmallVec<[u8; size_of::<usize>() * 2]> have a same size.
-// Note from https://docs.rs/smallvec/latest/smallvec/#union -
-// smallvec can still be larger than Vec if the inline buffer is
-// larger than two machine words.
-const _: () =
- assert!(size_of::<Vec<u8>>() == size_of::<SmallVec<[u8; USIZE2X]>>());
-
-impl ToV8 for ByteString {
- fn to_v8<'a>(
- &mut self,
- scope: &mut v8::HandleScope<'a>,
- ) -> Result<v8::Local<'a, v8::Value>, crate::Error> {
- let v =
- v8::String::new_from_one_byte(scope, self, v8::NewStringType::Normal)
- .unwrap();
- Ok(v.into())
- }
-}
-
-impl FromV8 for ByteString {
- fn from_v8(
- scope: &mut v8::HandleScope,
- value: v8::Local<v8::Value>,
- ) -> Result<Self, crate::Error> {
- let v8str = v8::Local::<v8::String>::try_from(value)
- .map_err(|_| Error::ExpectedString(value_to_type_str(value)))?;
- if !v8str.contains_only_onebyte() {
- return Err(Error::ExpectedLatin1);
- }
- let len = v8str.length();
- let mut buffer = SmallVec::with_capacity(len);
- #[allow(clippy::uninit_vec)]
- // SAFETY: we set length == capacity (see previous line),
- // before immediately writing into that buffer and sanity check with an assert
- unsafe {
- buffer.set_len(len);
- let written = v8str.write_one_byte(
- scope,
- &mut buffer,
- 0,
- v8::WriteOptions::NO_NULL_TERMINATION,
- );
- assert!(written == len);
- }
- Ok(Self(buffer))
- }
-}
-
-// smallvec does not impl From/Into traits
-// like Vec<u8> does. So here we are.
-
-impl From<Vec<u8>> for ByteString {
- fn from(vec: Vec<u8>) -> Self {
- ByteString(SmallVec::from_vec(vec))
- }
-}
-
-#[allow(clippy::from_over_into)]
-impl Into<Vec<u8>> for ByteString {
- fn into(self) -> Vec<u8> {
- self.0.into_vec()
- }
-}
-
-impl From<&[u8]> for ByteString {
- fn from(s: &[u8]) -> Self {
- ByteString(SmallVec::from_slice(s))
- }
-}
-
-impl From<&str> for ByteString {
- fn from(s: &str) -> Self {
- let v: Vec<u8> = s.into();
- ByteString::from(v)
- }
-}
-
-impl From<String> for ByteString {
- fn from(s: String) -> Self {
- ByteString::from(s.into_bytes())
- }
-}
diff --git a/serde_v8/magic/detached_buffer.rs b/serde_v8/magic/detached_buffer.rs
deleted file mode 100644
index bc4b3de67..000000000
--- a/serde_v8/magic/detached_buffer.rs
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-
-use core::ops::Range;
-use std::ops::Deref;
-use std::ops::DerefMut;
-
-use super::transl8::FromV8;
-use super::transl8::ToV8;
-use super::v8slice::to_ranged_buffer;
-use super::v8slice::V8Slice;
-use crate::error::value_to_type_str;
-use crate::magic::transl8::impl_magic;
-
-// A buffer that detaches when deserialized from JS
-pub struct DetachedBuffer(V8Slice);
-impl_magic!(DetachedBuffer);
-
-impl AsRef<[u8]> for DetachedBuffer {
- fn as_ref(&self) -> &[u8] {
- self.0.as_ref()
- }
-}
-
-impl AsMut<[u8]> for DetachedBuffer {
- fn as_mut(&mut self) -> &mut [u8] {
- self.0.as_mut()
- }
-}
-
-impl Deref for DetachedBuffer {
- type Target = [u8];
- fn deref(&self) -> &[u8] {
- self.0.deref()
- }
-}
-
-impl DerefMut for DetachedBuffer {
- fn deref_mut(&mut self) -> &mut [u8] {
- self.0.deref_mut()
- }
-}
-
-impl ToV8 for DetachedBuffer {
- fn to_v8<'a>(
- &mut self,
- scope: &mut v8::HandleScope<'a>,
- ) -> Result<v8::Local<'a, v8::Value>, crate::Error> {
- let buffer = v8::ArrayBuffer::with_backing_store(scope, &self.0.store);
- let Range { start, end } = self.0.range;
- let (off, len) = (start, end - start);
- let v = v8::Uint8Array::new(scope, buffer, off, len).unwrap();
- Ok(v.into())
- }
-}
-
-impl FromV8 for DetachedBuffer {
- fn from_v8(
- scope: &mut v8::HandleScope,
- value: v8::Local<v8::Value>,
- ) -> Result<Self, crate::Error> {
- let (b, range) = to_ranged_buffer(scope, value)
- .map_err(|_| crate::Error::ExpectedBuffer(value_to_type_str(value)))?;
- if !b.is_detachable() {
- return Err(crate::Error::ExpectedDetachable(value_to_type_str(value)));
- }
- let store = b.get_backing_store();
- b.detach(None); // Detach
- Ok(Self(V8Slice { store, range }))
- }
-}
diff --git a/serde_v8/magic/external_pointer.rs b/serde_v8/magic/external_pointer.rs
deleted file mode 100644
index e22e41a01..000000000
--- a/serde_v8/magic/external_pointer.rs
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-
-use std::ffi::c_void;
-
-use crate::error::value_to_type_str;
-
-use super::transl8::impl_magic;
-use super::transl8::FromV8;
-use super::transl8::ToV8;
-
-pub struct ExternalPointer(*mut c_void);
-
-// SAFETY: Nonblocking FFI is user controller and we must trust user to have it right.
-unsafe impl Send for ExternalPointer {}
-// SAFETY: Nonblocking FFI is user controller and we must trust user to have it right.
-unsafe impl Sync for ExternalPointer {}
-
-impl_magic!(ExternalPointer);
-
-impl ToV8 for ExternalPointer {
- fn to_v8<'a>(
- &mut self,
- scope: &mut v8::HandleScope<'a>,
- ) -> Result<v8::Local<'a, v8::Value>, crate::Error> {
- if self.0.is_null() {
- Ok(v8::null(scope).into())
- } else {
- Ok(v8::External::new(scope, self.0).into())
- }
- }
-}
-
-impl FromV8 for ExternalPointer {
- fn from_v8(
- _scope: &mut v8::HandleScope,
- value: v8::Local<v8::Value>,
- ) -> Result<Self, crate::Error> {
- if value.is_null() {
- Ok(ExternalPointer(std::ptr::null_mut()))
- } else if let Ok(external) = v8::Local::<v8::External>::try_from(value) {
- Ok(ExternalPointer(external.value()))
- } else {
- Err(crate::Error::ExpectedExternal(value_to_type_str(value)))
- }
- }
-}
-
-impl From<*mut c_void> for ExternalPointer {
- fn from(value: *mut c_void) -> Self {
- ExternalPointer(value)
- }
-}
-
-impl From<*const c_void> for ExternalPointer {
- fn from(value: *const c_void) -> Self {
- ExternalPointer(value as *mut c_void)
- }
-}
diff --git a/serde_v8/magic/global.rs b/serde_v8/magic/global.rs
deleted file mode 100644
index 52b316fa5..000000000
--- a/serde_v8/magic/global.rs
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-
-use crate::magic::transl8::impl_magic;
-use crate::magic::transl8::FromV8;
-use crate::magic::transl8::ToV8;
-
-pub struct Global {
- pub v8_value: v8::Global<v8::Value>,
-}
-impl_magic!(Global);
-
-impl From<v8::Global<v8::Value>> for Global {
- fn from(v8_value: v8::Global<v8::Value>) -> Self {
- Self { v8_value }
- }
-}
-
-impl From<Global> for v8::Global<v8::Value> {
- fn from(v: Global) -> Self {
- v.v8_value
- }
-}
-
-impl ToV8 for Global {
- fn to_v8<'a>(
- &mut self,
- scope: &mut v8::HandleScope<'a>,
- ) -> Result<v8::Local<'a, v8::Value>, crate::Error> {
- Ok(v8::Local::new(scope, self.v8_value.clone()))
- }
-}
-
-impl FromV8 for Global {
- fn from_v8(
- scope: &mut v8::HandleScope,
- value: v8::Local<v8::Value>,
- ) -> Result<Self, crate::Error> {
- let global = v8::Global::new(scope, value);
- Ok(global.into())
- }
-}
diff --git a/serde_v8/magic/mod.rs b/serde_v8/magic/mod.rs
deleted file mode 100644
index 3e984527d..000000000
--- a/serde_v8/magic/mod.rs
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-pub mod any_value;
-pub mod bigint;
-pub mod buffer;
-pub mod bytestring;
-pub mod detached_buffer;
-mod external_pointer;
-mod global;
-pub(super) mod rawbytes;
-pub mod string_or_buffer;
-pub mod transl8;
-pub mod u16string;
-pub mod v8slice;
-mod value;
-pub use external_pointer::ExternalPointer;
-pub use global::Global;
-pub use value::Value;
diff --git a/serde_v8/magic/rawbytes.rs b/serde_v8/magic/rawbytes.rs
deleted file mode 100644
index 2703c7756..000000000
--- a/serde_v8/magic/rawbytes.rs
+++ /dev/null
@@ -1,122 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-pub(crate) type AtomicPtr<T> = *mut T;
-#[allow(unused)]
-pub(crate) struct RawBytes {
- ptr: *const u8,
- len: usize,
- // inlined "trait object"
- data: AtomicPtr<()>,
- vtable: &'static Vtable,
-}
-
-impl RawBytes {
- pub fn new_raw(
- ptr: *const u8,
- len: usize,
- data: AtomicPtr<()>,
- vtable: &'static Vtable,
- ) -> bytes::Bytes {
- RawBytes {
- ptr,
- len,
- data,
- vtable,
- }
- .into()
- }
-}
-
-// Validate some bytes::Bytes layout assumptions at compile time.
-const _: () = {
- assert!(
- core::mem::size_of::<RawBytes>() == core::mem::size_of::<bytes::Bytes>(),
- );
- assert!(
- core::mem::align_of::<RawBytes>() == core::mem::align_of::<bytes::Bytes>(),
- );
-};
-
-#[allow(unused)]
-pub(crate) struct Vtable {
- /// fn(data, ptr, len)
- pub clone: unsafe fn(&AtomicPtr<()>, *const u8, usize) -> bytes::Bytes,
- /// fn(data, ptr, len)
- ///
- /// takes `Bytes` to value
- pub to_vec: unsafe fn(&AtomicPtr<()>, *const u8, usize) -> Vec<u8>,
- /// fn(data, ptr, len)
- pub drop: unsafe fn(&mut AtomicPtr<()>, *const u8, usize),
-}
-
-impl From<RawBytes> for bytes::Bytes {
- fn from(b: RawBytes) -> Self {
- // SAFETY: RawBytes has the same layout as bytes::Bytes
- // this is tested below, both are composed of usize-d ptrs/values
- // thus aren't currently subject to rust's field re-ordering to minimize padding
- unsafe { std::mem::transmute(b) }
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
- use std::mem;
-
- const HELLO: &str = "hello";
-
- // ===== impl StaticVtable =====
-
- const STATIC_VTABLE: Vtable = Vtable {
- clone: static_clone,
- drop: static_drop,
- to_vec: static_to_vec,
- };
-
- unsafe fn static_clone(
- _: &AtomicPtr<()>,
- ptr: *const u8,
- len: usize,
- ) -> bytes::Bytes {
- from_static(std::slice::from_raw_parts(ptr, len)).into()
- }
-
- unsafe fn static_to_vec(
- _: &AtomicPtr<()>,
- ptr: *const u8,
- len: usize,
- ) -> Vec<u8> {
- let slice = std::slice::from_raw_parts(ptr, len);
- slice.to_vec()
- }
-
- unsafe fn static_drop(_: &mut AtomicPtr<()>, _: *const u8, _: usize) {
- // nothing to drop for &'static [u8]
- }
-
- fn from_static(bytes: &'static [u8]) -> RawBytes {
- RawBytes {
- ptr: bytes.as_ptr(),
- len: bytes.len(),
- data: std::ptr::null_mut(),
- vtable: &STATIC_VTABLE,
- }
- }
-
- #[test]
- fn bytes_identity() {
- let b1: bytes::Bytes = from_static(HELLO.as_bytes()).into();
- let b2 = bytes::Bytes::from_static(HELLO.as_bytes());
- assert_eq!(b1, b2); // Values are equal
- }
-
- #[test]
- fn bytes_layout() {
- let u1: [usize; 4] =
- // SAFETY: ensuring layout is the same
- unsafe { mem::transmute(from_static(HELLO.as_bytes())) };
- let u2: [usize; 4] =
- // SAFETY: ensuring layout is the same
- unsafe { mem::transmute(bytes::Bytes::from_static(HELLO.as_bytes())) };
- assert_eq!(u1[..3], u2[..3]); // Struct bytes are equal besides Vtables
- }
-}
diff --git a/serde_v8/magic/string_or_buffer.rs b/serde_v8/magic/string_or_buffer.rs
deleted file mode 100644
index 986f7d32a..000000000
--- a/serde_v8/magic/string_or_buffer.rs
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-use super::buffer::JsBuffer;
-use super::transl8::FromV8;
-use crate::error::value_to_type_str;
-use crate::magic::transl8::impl_magic;
-use crate::Error;
-use std::ops::Deref;
-
-#[derive(Debug)]
-pub enum StringOrBuffer {
- Buffer(JsBuffer),
- String(String),
-}
-
-impl_magic!(StringOrBuffer);
-
-impl Deref for StringOrBuffer {
- type Target = [u8];
- fn deref(&self) -> &Self::Target {
- match self {
- Self::Buffer(b) => b.as_ref(),
- Self::String(s) => s.as_bytes(),
- }
- }
-}
-
-impl<'a> TryFrom<&'a StringOrBuffer> for &'a str {
- type Error = std::str::Utf8Error;
- fn try_from(value: &'a StringOrBuffer) -> Result<Self, Self::Error> {
- match value {
- StringOrBuffer::String(s) => Ok(s.as_str()),
- StringOrBuffer::Buffer(b) => std::str::from_utf8(b.as_ref()),
- }
- }
-}
-
-impl FromV8 for StringOrBuffer {
- fn from_v8(
- scope: &mut v8::HandleScope,
- value: v8::Local<v8::Value>,
- ) -> Result<Self, crate::Error> {
- if let Ok(buf) = JsBuffer::from_v8(scope, value) {
- return Ok(Self::Buffer(buf));
- } else if let Ok(s) = crate::from_v8(scope, value) {
- return Ok(Self::String(s));
- }
- Err(Error::ExpectedBuffer(value_to_type_str(value)))
- }
-}
-
-impl From<StringOrBuffer> for bytes::Bytes {
- fn from(sob: StringOrBuffer) -> Self {
- match sob {
- StringOrBuffer::Buffer(b) => b.into(),
- StringOrBuffer::String(s) => s.into_bytes().into(),
- }
- }
-}
diff --git a/serde_v8/magic/transl8.rs b/serde_v8/magic/transl8.rs
deleted file mode 100644
index 3a8d0c358..000000000
--- a/serde_v8/magic/transl8.rs
+++ /dev/null
@@ -1,165 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-
-//! Transerialization extends the set of serde-compatible types (for given de/serializers).
-//! By "hackishly" transmuting references across serde boundaries as u64s.
-//! Type-safety is enforced using special struct names for each "magic type".
-//! Memory-safety relies on transerialized values being "pinned" during de/serialization.
-
-pub(crate) const MAGIC_FIELD: &str = "$__v8_magic_field";
-
-pub(crate) trait MagicType {
- const NAME: &'static str;
- const MAGIC_NAME: &'static str;
-}
-
-pub(crate) trait ToV8 {
- fn to_v8<'a>(
- &mut self,
- scope: &mut v8::HandleScope<'a>,
- ) -> Result<v8::Local<'a, v8::Value>, crate::Error>;
-}
-
-pub(crate) trait FromV8: Sized {
- fn from_v8(
- scope: &mut v8::HandleScope,
- value: v8::Local<v8::Value>,
- ) -> Result<Self, crate::Error>;
-}
-
-pub(crate) fn magic_serialize<T, S>(
- serializer: S,
- x: &T,
-) -> Result<S::Ok, S::Error>
-where
- S: serde::Serializer,
- T: MagicType,
-{
- use serde::ser::SerializeStruct;
-
- let mut s = serializer.serialize_struct(T::MAGIC_NAME, 1)?;
- let ptr = opaque_send(x);
- s.serialize_field(MAGIC_FIELD, &ptr)?;
- s.end()
-}
-
-pub(crate) fn magic_deserialize<'de, T, D>(
- deserializer: D,
-) -> Result<T, D::Error>
-where
- D: serde::Deserializer<'de>,
- T: MagicType,
-{
- struct ValueVisitor<T> {
- p1: std::marker::PhantomData<T>,
- }
-
- impl<'de, T: MagicType> serde::de::Visitor<'de> for ValueVisitor<T> {
- type Value = T;
-
- fn expecting(
- &self,
- formatter: &mut std::fmt::Formatter,
- ) -> std::fmt::Result {
- formatter.write_str("a ")?;
- formatter.write_str(T::NAME)
- }
-
- fn visit_u64<E>(self, ptr: u64) -> Result<Self::Value, E>
- where
- E: serde::de::Error,
- {
- // SAFETY: opaque ptr originates from visit_magic, which forgets ownership so we can take it
- Ok(unsafe { opaque_take(ptr) })
- }
- }
-
- deserializer.deserialize_struct(
- T::MAGIC_NAME,
- &[MAGIC_FIELD],
- ValueVisitor::<T> {
- p1: std::marker::PhantomData,
- },
- )
-}
-
-pub(crate) fn visit_magic<'de, T, V, E>(visitor: V, x: T) -> Result<V::Value, E>
-where
- V: serde::de::Visitor<'de>,
- E: serde::de::Error,
-{
- let y = visitor.visit_u64::<E>(opaque_send(&x));
- std::mem::forget(x);
- y
-}
-
-/// Constructs an "opaque" ptr from a reference to transerialize
-pub(crate) fn opaque_send<T: Sized>(x: &T) -> u64 {
- (x as *const T) as u64
-}
-
-/// Copies an "opaque" ptr from a reference to an opaque ptr (transerialized)
-/// NOTE: ptr-to-ptr, extra indirection
-pub(crate) unsafe fn opaque_recv<T: ?Sized>(ptr: &T) -> u64 {
- *(ptr as *const T as *const u64)
-}
-
-/// Transmutes an "opaque" ptr back into a reference
-pub(crate) unsafe fn opaque_deref_mut<'a, T>(ptr: u64) -> &'a mut T {
- std::mem::transmute(ptr as usize)
-}
-
-/// Transmutes & copies the value from the "opaque" ptr
-/// NOTE: takes ownership & requires other end to forget its ownership
-pub(crate) unsafe fn opaque_take<T>(ptr: u64) -> T {
- std::mem::transmute_copy::<T, T>(std::mem::transmute(ptr as usize))
-}
-
-macro_rules! impl_magic {
- ($t:ty) => {
- impl crate::magic::transl8::MagicType for $t {
- const NAME: &'static str = stringify!($t);
- const MAGIC_NAME: &'static str = concat!("$__v8_magic_", stringify!($t));
- }
-
- impl serde::Serialize for $t {
- fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
- where
- S: serde::Serializer,
- {
- crate::magic::transl8::magic_serialize(serializer, self)
- }
- }
-
- impl<'de> serde::Deserialize<'de> for $t {
- fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
- where
- D: serde::Deserializer<'de>,
- {
- crate::magic::transl8::magic_deserialize(deserializer)
- }
- }
- };
-}
-pub(crate) use impl_magic;
-
-macro_rules! impl_wrapper {
- ($i:item) => {
- #[derive(
- PartialEq,
- Eq,
- Clone,
- Debug,
- Default,
- derive_more::Deref,
- derive_more::DerefMut,
- derive_more::AsRef,
- derive_more::AsMut,
- derive_more::From,
- )]
- #[as_mut(forward)]
- #[as_ref(forward)]
- #[from(forward)]
- $i
- };
-}
-pub(crate) use impl_wrapper;
diff --git a/serde_v8/magic/u16string.rs b/serde_v8/magic/u16string.rs
deleted file mode 100644
index 04d742da9..000000000
--- a/serde_v8/magic/u16string.rs
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-
-use crate::error::value_to_type_str;
-use crate::Error;
-
-use super::transl8::impl_magic;
-use super::transl8::impl_wrapper;
-use super::transl8::FromV8;
-use super::transl8::ToV8;
-
-impl_wrapper!(
- pub struct U16String(Vec<u16>);
-);
-impl_magic!(U16String);
-
-impl ToV8 for U16String {
- fn to_v8<'a>(
- &mut self,
- scope: &mut v8::HandleScope<'a>,
- ) -> Result<v8::Local<'a, v8::Value>, crate::Error> {
- let maybe_v =
- v8::String::new_from_two_byte(scope, self, v8::NewStringType::Normal);
-
- // 'new_from_two_byte' can return 'None' if buffer length > kMaxLength.
- if let Some(v) = maybe_v {
- Ok(v.into())
- } else {
- Err(Error::Message(String::from(
- "Cannot allocate String from UTF-16: buffer exceeds maximum length.",
- )))
- }
- }
-}
-
-impl FromV8 for U16String {
- fn from_v8(
- scope: &mut v8::HandleScope,
- value: v8::Local<v8::Value>,
- ) -> Result<Self, crate::Error> {
- let v8str = v8::Local::<v8::String>::try_from(value)
- .map_err(|_| Error::ExpectedString(value_to_type_str(value)))?;
- let len = v8str.length();
- let mut buffer = Vec::with_capacity(len);
- #[allow(clippy::uninit_vec)]
- // SAFETY: we set length == capacity (see previous line),
- // before immediately writing into that buffer and sanity check with an assert
- unsafe {
- buffer.set_len(len);
- let written = v8str.write(
- scope,
- &mut buffer,
- 0,
- v8::WriteOptions::NO_NULL_TERMINATION,
- );
- assert!(written == len);
- }
- Ok(buffer.into())
- }
-}
diff --git a/serde_v8/magic/v8slice.rs b/serde_v8/magic/v8slice.rs
deleted file mode 100644
index 2b103f1c9..000000000
--- a/serde_v8/magic/v8slice.rs
+++ /dev/null
@@ -1,181 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-
-use std::ops::Deref;
-use std::ops::DerefMut;
-use std::ops::Range;
-use std::rc::Rc;
-
-use crate::error::value_to_type_str;
-
-use super::rawbytes;
-use super::transl8::FromV8;
-
-/// A V8Slice encapsulates a slice that's been borrowed from a JavaScript
-/// ArrayBuffer object. JavaScript objects can normally be garbage collected,
-/// but the existence of a V8Slice inhibits this until it is dropped. It
-/// behaves much like an Arc<[u8]>.
-///
-/// # Cloning
-/// Cloning a V8Slice 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 V8Slice {
- pub(crate) store: v8::SharedRef<v8::BackingStore>,
- pub(crate) range: Range<usize>,
-}
-
-// SAFETY: unsafe trait must have unsafe implementation
-unsafe impl Send for V8Slice {}
-
-impl V8Slice {
- fn as_slice(&self) -> &[u8] {
- // SAFETY: v8::SharedRef<v8::BackingStore> is similar to Arc<[u8]>,
- // it points to a fixed continuous slice of bytes on the heap.
- // We assume it's initialized and thus safe to read (though may not contain meaningful data)
- unsafe { &*(&self.store[self.range.clone()] as *const _ as *const [u8]) }
- }
-
- fn as_slice_mut(&mut self) -> &mut [u8] {
- #[allow(clippy::cast_ref_to_mut)]
- // SAFETY: v8::SharedRef<v8::BackingStore> is similar to Arc<[u8]>,
- // it points to a fixed continuous slice of bytes on the heap.
- // It's safe-ish to mutate concurrently because it can not be
- // shrunk/grown/moved/reallocated, thus avoiding dangling refs (unlike a Vec).
- // Concurrent writes can't lead to meaningful structural invalidation
- // since we treat them as opaque buffers / "bags of bytes",
- // concurrent mutation is simply an accepted fact of life.
- // And in practice V8Slices also do not have overallping read/write phases.
- // TLDR: permissive interior mutability on slices of bytes is "fine"
- unsafe {
- &mut *(&self.store[self.range.clone()] as *const _ as *mut [u8])
- }
- }
-}
-
-pub(crate) fn to_ranged_buffer<'s>(
- scope: &mut v8::HandleScope<'s>,
- value: v8::Local<v8::Value>,
-) -> Result<(v8::Local<'s, v8::ArrayBuffer>, Range<usize>), v8::DataError> {
- if let Ok(view) = v8::Local::<v8::ArrayBufferView>::try_from(value) {
- let (offset, len) = (view.byte_offset(), view.byte_length());
- let buffer = view.buffer(scope).ok_or(v8::DataError::NoData {
- expected: "view to have a buffer",
- })?;
- let buffer = v8::Local::new(scope, buffer); // recreate handle to avoid lifetime issues
- return Ok((buffer, offset..offset + len));
- }
- let b: v8::Local<v8::ArrayBuffer> = value.try_into()?;
- let b = v8::Local::new(scope, b); // recreate handle to avoid lifetime issues
- Ok((b, 0..b.byte_length()))
-}
-
-impl FromV8 for V8Slice {
- fn from_v8(
- scope: &mut v8::HandleScope,
- value: v8::Local<v8::Value>,
- ) -> Result<Self, crate::Error> {
- match to_ranged_buffer(scope, value) {
- Ok((b, range)) => {
- let store = b.get_backing_store();
- if store.is_resizable_by_user_javascript() {
- Err(crate::Error::ResizableBackingStoreNotSupported)
- } else if store.is_shared() {
- Err(crate::Error::ExpectedBuffer(value_to_type_str(value)))
- } else {
- Ok(V8Slice { store, range })
- }
- }
- Err(_) => Err(crate::Error::ExpectedBuffer(value_to_type_str(value))),
- }
- }
-}
-
-impl Deref for V8Slice {
- type Target = [u8];
- fn deref(&self) -> &[u8] {
- self.as_slice()
- }
-}
-
-impl DerefMut for V8Slice {
- fn deref_mut(&mut self) -> &mut [u8] {
- self.as_slice_mut()
- }
-}
-
-impl AsRef<[u8]> for V8Slice {
- fn as_ref(&self) -> &[u8] {
- self.as_slice()
- }
-}
-
-impl AsMut<[u8]> for V8Slice {
- fn as_mut(&mut self) -> &mut [u8] {
- self.as_slice_mut()
- }
-}
-
-// Implement V8Slice -> bytes::Bytes
-impl V8Slice {
- fn rc_into_byte_parts(self: Rc<Self>) -> (*const u8, usize, *mut V8Slice) {
- let (ptr, len) = {
- let slice = self.as_ref();
- (slice.as_ptr(), slice.len())
- };
- let rc_raw = Rc::into_raw(self);
- let data = rc_raw as *mut V8Slice;
- (ptr, len, data)
- }
-}
-
-impl From<V8Slice> for bytes::Bytes {
- fn from(v8slice: V8Slice) -> Self {
- let (ptr, len, data) = Rc::new(v8slice).rc_into_byte_parts();
- rawbytes::RawBytes::new_raw(ptr, len, data.cast(), &V8SLICE_VTABLE)
- }
-}
-
-// NOTE: in the limit we could avoid extra-indirection and use the C++ shared_ptr
-// but we can't store both the underlying data ptr & ctrl ptr ... so instead we
-// use a shared rust ptr (Rc/Arc) that itself controls the C++ shared_ptr
-const V8SLICE_VTABLE: rawbytes::Vtable = rawbytes::Vtable {
- clone: v8slice_clone,
- drop: v8slice_drop,
- to_vec: v8slice_to_vec,
-};
-
-unsafe fn v8slice_clone(
- data: &rawbytes::AtomicPtr<()>,
- ptr: *const u8,
- len: usize,
-) -> bytes::Bytes {
- let rc = Rc::from_raw(*data as *const V8Slice);
- let (_, _, data) = rc.clone().rc_into_byte_parts();
- std::mem::forget(rc);
- // NOTE: `bytes::Bytes` does bounds checking so we trust its ptr, len inputs
- // and must use them to allow cloning Bytes it has sliced
- rawbytes::RawBytes::new_raw(ptr, len, data.cast(), &V8SLICE_VTABLE)
-}
-
-unsafe fn v8slice_to_vec(
- data: &rawbytes::AtomicPtr<()>,
- ptr: *const u8,
- len: usize,
-) -> Vec<u8> {
- let rc = Rc::from_raw(*data as *const V8Slice);
- std::mem::forget(rc);
- // NOTE: `bytes::Bytes` does bounds checking so we trust its ptr, len inputs
- // and must use them to allow cloning Bytes it has sliced
- Vec::from_raw_parts(ptr as _, len, len)
-}
-
-unsafe fn v8slice_drop(
- data: &mut rawbytes::AtomicPtr<()>,
- _: *const u8,
- _: usize,
-) {
- drop(Rc::from_raw(*data as *const V8Slice))
-}
diff --git a/serde_v8/magic/value.rs b/serde_v8/magic/value.rs
deleted file mode 100644
index 0333d75bc..000000000
--- a/serde_v8/magic/value.rs
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-
-use crate::magic::transl8::impl_magic;
-use crate::magic::transl8::FromV8;
-use crate::magic::transl8::ToV8;
-use std::mem::transmute;
-
-/// serde_v8::Value allows passing through `v8::Value`s untouched
-/// when de/serializing & allows mixing rust & v8 values in structs, tuples...
-//
-// SAFETY: caveat emptor, the rust-compiler can no longer link lifetimes to their
-// original scope, you must take special care in ensuring your handles don't outlive their scope
-pub struct Value<'s> {
- pub v8_value: v8::Local<'s, v8::Value>,
-}
-impl_magic!(Value<'_>);
-
-impl<'s> From<v8::Local<'s, v8::Value>> for Value<'s> {
- fn from(v8_value: v8::Local<'s, v8::Value>) -> Self {
- Self { v8_value }
- }
-}
-
-impl<'s> From<Value<'s>> for v8::Local<'s, v8::Value> {
- fn from(v: Value<'s>) -> Self {
- v.v8_value
- }
-}
-
-impl ToV8 for Value<'_> {
- fn to_v8<'a>(
- &mut self,
- _scope: &mut v8::HandleScope<'a>,
- ) -> Result<v8::Local<'a, v8::Value>, crate::Error> {
- // SAFETY: not fully safe, since lifetimes are detached from original scope
- Ok(unsafe { transmute(self.v8_value) })
- }
-}
-
-impl FromV8 for Value<'_> {
- fn from_v8(
- _scope: &mut v8::HandleScope,
- value: v8::Local<v8::Value>,
- ) -> Result<Self, crate::Error> {
- // SAFETY: not fully safe, since lifetimes are detached from original scope
- Ok(unsafe { transmute::<Value, Value>(value.into()) })
- }
-}
diff --git a/serde_v8/payload.rs b/serde_v8/payload.rs
deleted file mode 100644
index b396ad01d..000000000
--- a/serde_v8/payload.rs
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-
-// TODO: maybe add a Payload type that holds scope & v8::Value
-// so it can implement Deserialize by itself
-
-// Classifies v8::Values into sub-types
-#[derive(Debug)]
-pub enum ValueType {
- Null,
- Bool,
- Number,
- BigInt,
- String,
- Array,
- ArrayBuffer,
- ArrayBufferView,
- Object,
-}
-
-impl ValueType {
- pub fn from_v8(v: v8::Local<v8::Value>) -> 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_big_int() {
- return Self::BigInt;
- } else if v.is_array_buffer() {
- return Self::ArrayBuffer;
- } else if v.is_array_buffer_view() {
- return Self::ArrayBufferView;
- } 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/ser.rs b/serde_v8/ser.rs
deleted file mode 100644
index 51625f230..000000000
--- a/serde_v8/ser.rs
+++ /dev/null
@@ -1,647 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-use serde::ser;
-use serde::ser::Serialize;
-
-use std::cell::RefCell;
-use std::ops::DerefMut;
-
-use crate::error::Error;
-use crate::error::Result;
-use crate::keys::v8_struct_key;
-use crate::magic;
-use crate::magic::transl8::opaque_deref_mut;
-use crate::magic::transl8::opaque_recv;
-use crate::magic::transl8::MagicType;
-use crate::magic::transl8::ToV8;
-use crate::magic::transl8::MAGIC_FIELD;
-use crate::AnyValue;
-use crate::BigInt;
-use crate::ByteString;
-use crate::DetachedBuffer;
-use crate::ExternalPointer;
-use crate::ToJsBuffer;
-use crate::U16String;
-
-type JsValue<'s> = v8::Local<'s, v8::Value>;
-type JsResult<'s> = Result<JsValue<'s>>;
-
-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 null = v8::null(scope).into();
- let key = v8_struct_key(scope, self.variant).into();
- let obj =
- v8::Object::with_prototype_and_properties(scope, null, &[key], &[value]);
- Ok(obj.into())
- }
-}
-
-impl<'a, 'b, 'c, S> ser::SerializeTupleVariant
- for VariantSerializer<'a, 'b, 'c, S>
-where
- S: ser::SerializeTupleStruct<Ok = JsValue<'a>, Error = Error>,
-{
- type Ok = JsValue<'a>;
- type Error = Error;
-
- fn serialize_field<T: ?Sized + Serialize>(
- &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<Ok = JsValue<'a>, Error = Error>,
-{
- type Ok = JsValue<'a>;
- type Error = Error;
-
- fn serialize_field<T: ?Sized + Serialize>(
- &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<JsValue<'a>>,
- scope: ScopePtr<'a, 'b, 'c>,
-}
-
-impl<'a, 'b, 'c> ArraySerializer<'a, 'b, 'c> {
- pub fn new(scope: ScopePtr<'a, 'b, 'c>, len: Option<usize>) -> 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<T: ?Sized + Serialize>(
- &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<T: ?Sized + Serialize>(
- &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<T: ?Sized + Serialize>(
- &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>,
- keys: Vec<v8::Local<'a, v8::Name>>,
- values: Vec<JsValue<'a>>,
-}
-
-impl<'a, 'b, 'c> ObjectSerializer<'a, 'b, 'c> {
- pub fn new(scope: ScopePtr<'a, 'b, 'c>, len: usize) -> Self {
- let keys = Vec::with_capacity(len);
- let values = Vec::with_capacity(len);
- Self {
- scope,
- keys,
- values,
- }
- }
-}
-
-impl<'a, 'b, 'c> ser::SerializeStruct for ObjectSerializer<'a, 'b, 'c> {
- type Ok = JsValue<'a>;
- type Error = Error;
-
- fn serialize_field<T: ?Sized + Serialize>(
- &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.keys.push(key);
- self.values.push(value);
- Ok(())
- }
-
- fn end(self) -> JsResult<'a> {
- let scope = &mut *self.scope.borrow_mut();
- let null = v8::null(scope);
- let obj = v8::Object::with_prototype_and_properties(
- scope,
- null.into(),
- &self.keys[..],
- &self.values[..],
- );
- Ok(obj.into())
- }
-}
-
-pub struct MagicalSerializer<'a, 'b, 'c, T> {
- scope: ScopePtr<'a, 'b, 'c>,
- opaque: u64,
- p1: std::marker::PhantomData<T>,
-}
-
-impl<'a, 'b, 'c, T> MagicalSerializer<'a, 'b, 'c, T> {
- pub fn new(scope: ScopePtr<'a, 'b, 'c>) -> MagicalSerializer<'a, 'b, 'c, T> {
- Self {
- scope,
- opaque: 0,
- p1: std::marker::PhantomData::<T> {},
- }
- }
-}
-
-impl<'a, 'b, 'c, T: MagicType + ToV8> ser::SerializeStruct
- for MagicalSerializer<'a, 'b, 'c, T>
-{
- type Ok = JsValue<'a>;
- type Error = Error;
-
- fn serialize_field<U: ?Sized + Serialize>(
- &mut self,
- key: &'static str,
- value: &U,
- ) -> Result<()> {
- assert_eq!(key, MAGIC_FIELD);
- let ptr: &U = value;
- // SAFETY: MagicalSerializer only ever receives single field u64s,
- // type-safety is ensured by MAGIC_NAME checks in `serialize_struct()`
- self.opaque = unsafe { opaque_recv(ptr) };
- Ok(())
- }
-
- fn end(self) -> JsResult<'a> {
- // SAFETY: transerialization assumptions imply `T` is still alive.
- let x: &mut T = unsafe { opaque_deref_mut(self.opaque) };
- let scope = &mut *self.scope.borrow_mut();
- x.to_v8(scope)
- }
-}
-
-// Dispatches between magic and regular struct serializers
-pub enum StructSerializers<'a, 'b, 'c> {
- ExternalPointer(MagicalSerializer<'a, 'b, 'c, magic::ExternalPointer>),
- Magic(MagicalSerializer<'a, 'b, 'c, magic::Value<'a>>),
- RustToV8Buf(MagicalSerializer<'a, 'b, 'c, ToJsBuffer>),
- MagicAnyValue(MagicalSerializer<'a, 'b, 'c, AnyValue>),
- MagicDetached(MagicalSerializer<'a, 'b, 'c, DetachedBuffer>),
- MagicByteString(MagicalSerializer<'a, 'b, 'c, ByteString>),
- MagicU16String(MagicalSerializer<'a, 'b, 'c, U16String>),
- MagicBigInt(MagicalSerializer<'a, 'b, 'c, BigInt>),
- 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<T: ?Sized + Serialize>(
- &mut self,
- key: &'static str,
- value: &T,
- ) -> Result<()> {
- match self {
- StructSerializers::ExternalPointer(s) => s.serialize_field(key, value),
- StructSerializers::Magic(s) => s.serialize_field(key, value),
- StructSerializers::RustToV8Buf(s) => s.serialize_field(key, value),
- StructSerializers::MagicAnyValue(s) => s.serialize_field(key, value),
- StructSerializers::MagicDetached(s) => s.serialize_field(key, value),
- StructSerializers::MagicByteString(s) => s.serialize_field(key, value),
- StructSerializers::MagicU16String(s) => s.serialize_field(key, value),
- StructSerializers::MagicBigInt(s) => s.serialize_field(key, value),
- StructSerializers::Regular(s) => s.serialize_field(key, value),
- }
- }
-
- fn end(self) -> JsResult<'a> {
- match self {
- StructSerializers::ExternalPointer(s) => s.end(),
- StructSerializers::Magic(s) => s.end(),
- StructSerializers::RustToV8Buf(s) => s.end(),
- StructSerializers::MagicAnyValue(s) => s.end(),
- StructSerializers::MagicDetached(s) => s.end(),
- StructSerializers::MagicByteString(s) => s.end(),
- StructSerializers::MagicU16String(s) => s.end(),
- StructSerializers::MagicBigInt(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>,
- keys: Vec<v8::Local<'a, v8::Name>>,
- values: Vec<JsValue<'a>>,
-}
-
-impl<'a, 'b, 'c> MapSerializer<'a, 'b, 'c> {
- pub fn new(scope: ScopePtr<'a, 'b, 'c>, len: Option<usize>) -> Self {
- let keys = Vec::with_capacity(len.unwrap_or_default());
- let values = Vec::with_capacity(len.unwrap_or_default());
- Self {
- scope,
- keys,
- values,
- }
- }
-}
-
-impl<'a, 'b, 'c> ser::SerializeMap for MapSerializer<'a, 'b, 'c> {
- type Ok = JsValue<'a>;
- type Error = Error;
-
- fn serialize_key<T: ?Sized + Serialize>(&mut self, key: &T) -> Result<()> {
- let key = key.serialize(Serializer::new(self.scope))?;
- self.keys.push(key.try_into().map_err(|_| {
- Error::Message("Serialized Maps expect String keys".into())
- })?);
- Ok(())
- }
-
- fn serialize_value<T: ?Sized + Serialize>(
- &mut self,
- value: &T,
- ) -> Result<()> {
- let v8_value = value.serialize(Serializer::new(self.scope))?;
- self.values.push(v8_value);
- Ok(())
- }
-
- fn end(self) -> JsResult<'a> {
- debug_assert!(self.keys.len() == self.values.len());
- let scope = &mut *self.scope.borrow_mut();
- let null = v8::null(scope).into();
- let obj = v8::Object::with_prototype_and_properties(
- scope,
- null,
- &self.keys[..],
- &self.values[..],
- );
- Ok(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 _)
- })*
- };
-}
-
-pub(crate) const MAX_SAFE_INTEGER: i64 = (1 << 53) - 1;
-pub(crate) const MIN_SAFE_INTEGER: i64 = -MAX_SAFE_INTEGER;
-
-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);
- }
-
- 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_i64(self, v: i64) -> JsResult<'a> {
- let s = &mut self.scope.borrow_mut();
- // If i64 can fit in max safe integer bounds then serialize as v8::Number
- // otherwise serialize as v8::BigInt
- if (MIN_SAFE_INTEGER..=MAX_SAFE_INTEGER).contains(&v) {
- Ok(v8::Number::new(s, v as _).into())
- } else {
- Ok(v8::BigInt::new_from_i64(s, v).into())
- }
- }
-
- fn serialize_u64(self, v: u64) -> JsResult<'a> {
- let s = &mut self.scope.borrow_mut();
- // If u64 can fit in max safe integer bounds then serialize as v8::Number
- // otherwise serialize as v8::BigInt
- if v <= (MAX_SAFE_INTEGER as u64) {
- Ok(v8::Number::new(s, v as _).into())
- } else {
- Ok(v8::BigInt::new_from_u64(s, v).into())
- }
- }
-
- fn serialize_f64(self, v: f64) -> JsResult<'a> {
- let scope = &mut self.scope.borrow_mut();
- Ok(v8::Number::new(scope.deref_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> {
- self.serialize_str(&v.to_string())
- }
-
- fn serialize_str(self, v: &str) -> JsResult<'a> {
- let maybe_str = v8::String::new(&mut self.scope.borrow_mut(), v);
-
- // v8 string can return 'None' if buffer length > kMaxLength.
- if let Some(str) = maybe_str {
- Ok(str.into())
- } else {
- Err(Error::Message(String::from(
- "Cannot allocate String: buffer exceeds maximum length.",
- )))
- }
- }
-
- fn serialize_bytes(self, v: &[u8]) -> JsResult<'a> {
- Ok(slice_to_uint8array(&mut self.scope.borrow_mut(), v).into())
- }
-
- fn serialize_none(self) -> JsResult<'a> {
- Ok(v8::null(&mut *self.scope.borrow_mut()).into())
- }
-
- fn serialize_some<T: ?Sized + Serialize>(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<T: ?Sized + Serialize>(
- self,
- _name: &'static str,
- value: &T,
- ) -> JsResult<'a> {
- value.serialize(self)
- }
-
- fn serialize_newtype_variant<T: ?Sized + Serialize>(
- 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<usize>) -> Result<Self::SerializeSeq> {
- Ok(ArraySerializer::new(self.scope, len))
- }
-
- fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple> {
- self.serialize_seq(Some(len))
- }
-
- fn serialize_tuple_struct(
- self,
- _name: &'static str,
- len: usize,
- ) -> Result<Self::SerializeTupleStruct> {
- self.serialize_tuple(len)
- }
-
- fn serialize_tuple_variant(
- self,
- _name: &'static str,
- _variant_index: u32,
- variant: &'static str,
- len: usize,
- ) -> Result<Self::SerializeTupleVariant> {
- Ok(VariantSerializer::new(
- self.scope,
- variant,
- self.serialize_tuple_struct(variant, len)?,
- ))
- }
-
- fn serialize_map(self, len: Option<usize>) -> Result<Self::SerializeMap> {
- // 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, len))
- }
-
- /// Serialises Rust typed structs into plain JS objects.
- fn serialize_struct(
- self,
- name: &'static str,
- len: usize,
- ) -> Result<Self::SerializeStruct> {
- match name {
- magic::ExternalPointer::MAGIC_NAME => {
- let m = MagicalSerializer::<ExternalPointer>::new(self.scope);
- Ok(StructSerializers::ExternalPointer(m))
- }
- ByteString::MAGIC_NAME => {
- let m = MagicalSerializer::<ByteString>::new(self.scope);
- Ok(StructSerializers::MagicByteString(m))
- }
- U16String::MAGIC_NAME => {
- let m = MagicalSerializer::<U16String>::new(self.scope);
- Ok(StructSerializers::MagicU16String(m))
- }
- ToJsBuffer::MAGIC_NAME => {
- let m = MagicalSerializer::<ToJsBuffer>::new(self.scope);
- Ok(StructSerializers::RustToV8Buf(m))
- }
- AnyValue::MAGIC_NAME => {
- let m = MagicalSerializer::<AnyValue>::new(self.scope);
- Ok(StructSerializers::MagicAnyValue(m))
- }
- DetachedBuffer::MAGIC_NAME => {
- let m = MagicalSerializer::<DetachedBuffer>::new(self.scope);
- Ok(StructSerializers::MagicDetached(m))
- }
- BigInt::MAGIC_NAME => {
- let m = MagicalSerializer::<BigInt>::new(self.scope);
- Ok(StructSerializers::MagicBigInt(m))
- }
- magic::Value::MAGIC_NAME => {
- let m = MagicalSerializer::<magic::Value<'a>>::new(self.scope);
- Ok(StructSerializers::Magic(m))
- }
- _ => {
- // Regular structs
- let o = ObjectSerializer::new(self.scope, len);
- Ok(StructSerializers::Regular(o))
- }
- }
- }
-
- fn serialize_struct_variant(
- self,
- _name: &'static str,
- _variant_index: u32,
- variant: &'static str,
- len: usize,
- ) -> Result<Self::SerializeStructVariant> {
- let scope = self.scope;
- let x = self.serialize_struct(variant, len)?;
- Ok(VariantSerializer::new(scope, variant, x))
- }
-}
-
-pub fn slice_to_uint8array<'a>(
- scope: &mut v8::HandleScope<'a>,
- buf: &[u8],
-) -> v8::Local<'a, v8::Uint8Array> {
- let buffer = if buf.is_empty() {
- v8::ArrayBuffer::new(scope, 0)
- } else {
- let store: v8::UniqueRef<_> =
- v8::ArrayBuffer::new_backing_store(scope, buf.len());
- // SAFETY: raw memory copy into the v8 ArrayBuffer allocated above
- unsafe {
- std::ptr::copy_nonoverlapping(
- buf.as_ptr(),
- store.data().unwrap().as_ptr() as *mut u8,
- buf.len(),
- )
- }
- v8::ArrayBuffer::with_backing_store(scope, &store.make_shared())
- };
- v8::Uint8Array::new(scope, buffer, 0, buf.len())
- .expect("Failed to create UintArray8")
-}
diff --git a/serde_v8/serializable.rs b/serde_v8/serializable.rs
deleted file mode 100644
index 7380ab5a7..000000000
--- a/serde_v8/serializable.rs
+++ /dev/null
@@ -1,149 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-use std::any::TypeId;
-use std::mem::transmute_copy;
-
-use crate::BigInt;
-use crate::ByteString;
-use crate::ToJsBuffer;
-use crate::U16String;
-
-/// 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>(
- &mut self,
- scope: &mut v8::HandleScope<'a>,
- ) -> Result<v8::Local<'a, v8::Value>, crate::Error>;
-}
-
-/// Allows all implementors of `serde::Serialize` to implement Serializable
-impl<T: serde::Serialize> Serializable for T {
- fn to_v8<'a>(
- &mut self,
- scope: &mut v8::HandleScope<'a>,
- ) -> Result<v8::Local<'a, v8::Value>, crate::Error> {
- crate::to_v8(scope, self)
- }
-}
-
-/// SerializablePkg exists to provide a fast path for op returns,
-/// allowing them to avoid boxing primitives (ints/floats/bool/unit/...)
-pub enum SerializablePkg {
- Primitive(Primitive),
- Serializable(Box<dyn Serializable>),
-}
-
-impl SerializablePkg {
- pub fn to_v8<'a>(
- &mut self,
- scope: &mut v8::HandleScope<'a>,
- ) -> Result<v8::Local<'a, v8::Value>, 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
-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),
- String(String),
- RustToV8Buf(ToJsBuffer),
- ByteString(ByteString),
- U16String(U16String),
- BigInt(BigInt),
-}
-
-impl serde::Serialize for Primitive {
- fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
- where
- S: serde::Serializer,
- {
- match self {
- Self::Unit => ().serialize(s),
- Self::Bool(x) => x.serialize(s),
- Self::Int8(x) => x.serialize(s),
- Self::Int16(x) => x.serialize(s),
- Self::Int32(x) => x.serialize(s),
- Self::Int64(x) => x.serialize(s),
- Self::UInt8(x) => x.serialize(s),
- Self::UInt16(x) => x.serialize(s),
- Self::UInt32(x) => x.serialize(s),
- Self::UInt64(x) => x.serialize(s),
- Self::Float32(x) => x.serialize(s),
- Self::Float64(x) => x.serialize(s),
- Self::String(x) => x.serialize(s),
- Self::RustToV8Buf(x) => x.serialize(s),
- Self::ByteString(x) => x.serialize(s),
- Self::U16String(x) => x.serialize(s),
- Self::BigInt(x) => x.serialize(s),
- }
- }
-}
-
-impl<T: serde::Serialize + 'static> From<T> for SerializablePkg {
- fn from(x: T) -> Self {
- #[inline(always)]
- fn tc<T, U>(src: T) -> U {
- // SAFETY: the caller has ensured via the TypeId that the T and U types
- // are the same.
- let x = unsafe { transmute_copy(&src) };
- std::mem::forget(src);
- x
- }
-
- let tid = TypeId::of::<T>();
- if tid == TypeId::of::<()>() {
- Self::Primitive(Primitive::Unit)
- } else if tid == TypeId::of::<bool>() {
- Self::Primitive(Primitive::Bool(tc(x)))
- } else if tid == TypeId::of::<i8>() {
- Self::Primitive(Primitive::Int8(tc(x)))
- } else if tid == TypeId::of::<i16>() {
- Self::Primitive(Primitive::Int16(tc(x)))
- } else if tid == TypeId::of::<i32>() {
- Self::Primitive(Primitive::Int32(tc(x)))
- } else if tid == TypeId::of::<i64>() {
- Self::Primitive(Primitive::Int64(tc(x)))
- } else if tid == TypeId::of::<u8>() {
- Self::Primitive(Primitive::UInt8(tc(x)))
- } else if tid == TypeId::of::<u16>() {
- Self::Primitive(Primitive::UInt16(tc(x)))
- } else if tid == TypeId::of::<u32>() {
- Self::Primitive(Primitive::UInt32(tc(x)))
- } else if tid == TypeId::of::<u64>() {
- Self::Primitive(Primitive::UInt64(tc(x)))
- } else if tid == TypeId::of::<f32>() {
- Self::Primitive(Primitive::Float32(tc(x)))
- } else if tid == TypeId::of::<f64>() {
- Self::Primitive(Primitive::Float64(tc(x)))
- } else if tid == TypeId::of::<String>() {
- Self::Primitive(Primitive::String(tc(x)))
- } else if tid == TypeId::of::<ToJsBuffer>() {
- Self::Primitive(Primitive::RustToV8Buf(tc(x)))
- } else if tid == TypeId::of::<ByteString>() {
- Self::Primitive(Primitive::ByteString(tc(x)))
- } else if tid == TypeId::of::<U16String>() {
- Self::Primitive(Primitive::U16String(tc(x)))
- } else if tid == TypeId::of::<BigInt>() {
- Self::Primitive(Primitive::BigInt(tc(x)))
- } else {
- Self::Serializable(Box::new(x))
- }
- }
-}
diff --git a/serde_v8/tests/de.rs b/serde_v8/tests/de.rs
deleted file mode 100644
index 2edfe1bc6..000000000
--- a/serde_v8/tests/de.rs
+++ /dev/null
@@ -1,613 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-use serde::Deserialize;
-use serde::Deserializer;
-
-use serde_v8::utils::js_exec;
-use serde_v8::utils::v8_do;
-use serde_v8::BigInt;
-use serde_v8::ByteString;
-use serde_v8::Error;
-use serde_v8::JsBuffer;
-use serde_v8::U16String;
-
-#[derive(Debug, Deserialize, PartialEq)]
-struct MathOp {
- pub a: u64,
- pub b: u64,
- pub operator: Option<String>,
-}
-
-#[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::Value>),
-) {
- 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! decheck {
- ($fn_name:ident, $t:ty, $src:expr, $x:ident, $check:expr) => {
- #[test]
- fn $fn_name() {
- #[allow(clippy::bool_assert_comparison)]
- dedo($src, |scope, v| {
- let rt = serde_v8::from_v8(scope, v);
- assert!(rt.is_ok(), "from_v8(\"{}\"): {:?}", $src, rt.err());
- let $x: $t = rt.unwrap();
- $check
- });
- }
- };
-}
-
-macro_rules! detest {
- ($fn_name:ident, $t:ty, $src:expr, $rust:expr) => {
- decheck!($fn_name, $t, $src, t, assert_eq!(t, $rust));
- };
-}
-
-macro_rules! defail {
- ($fn_name:ident, $t:ty, $src:expr, $failcase:expr) => {
- #[test]
- fn $fn_name() {
- #[allow(clippy::bool_assert_comparison)]
- dedo($src, |scope, v| {
- let rt: serde_v8::Result<$t> = serde_v8::from_v8(scope, v);
- let rtstr = format!("{:?}", rt);
- let failed_as_expected = $failcase(rt);
- assert!(
- failed_as_expected,
- "expected failure on deserialize(\"{}\"), got: {}",
- $src, rtstr
- );
- });
- }
- };
-}
-
-detest!(de_option_some, Option<bool>, "true", Some(true));
-detest!(de_option_null, Option<bool>, "null", None);
-detest!(de_option_undefined, Option<bool>, "undefined", None);
-detest!(de_unit_null, (), "null", ());
-detest!(de_unit_undefined, (), "undefined", ());
-detest!(de_bool, bool, "true", true);
-detest!(de_char, char, "'é'", 'é');
-detest!(de_u64, u64, "32", 32);
-detest!(de_string, String, "'Hello'", "Hello".to_owned());
-detest!(de_vec_empty, Vec<u64>, "[]", vec![0; 0]);
-detest!(de_vec_u64, Vec<u64>, "[1,2,3,4,5]", vec![1, 2, 3, 4, 5]);
-detest!(
- de_vec_str,
- Vec<String>,
- "['hello', 'world']",
- vec!["hello".to_owned(), "world".to_owned()]
-);
-detest!(
- de_tuple,
- (u64, bool, ()),
- "[123, true, null]",
- (123, true, ())
-);
-defail!(
- de_tuple_wrong_len_short,
- (u64, bool, ()),
- "[123, true]",
- |e| e == Err(Error::LengthMismatch(2, 3))
-);
-defail!(
- de_tuple_wrong_len_long,
- (u64, bool, ()),
- "[123, true, null, 'extra']",
- |e| e == Err(Error::LengthMismatch(4, 3))
-);
-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_so_a, EnumUnit, "new String('A')", EnumUnit::A);
-detest!(de_enum_unit_b, EnumUnit, "'B'", EnumUnit::B);
-detest!(de_enum_unit_so_b, EnumUnit, "new String('B')", EnumUnit::B);
-detest!(de_enum_unit_c, EnumUnit, "'C'", EnumUnit::C);
-detest!(de_enum_unit_so_c, EnumUnit, "new String('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<String, u64> = 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);
- })
-}
-
-#[test]
-fn de_obj_with_numeric_keys() {
- dedo(
- r#"({
- lines: {
- 100: {
- unit: "m"
- },
- 200: {
- unit: "cm"
- }
- }
-})"#,
- |scope, v| {
- let json: serde_json::Value = serde_v8::from_v8(scope, v).unwrap();
- assert_eq!(
- json.to_string(),
- r#"{"lines":{"100":{"unit":"m"},"200":{"unit":"cm"}}}"#
- );
- },
- )
-}
-
-#[test]
-fn de_string_or_buffer() {
- dedo("'hello'", |scope, v| {
- let sob: serde_v8::StringOrBuffer = serde_v8::from_v8(scope, v).unwrap();
- assert_eq!(sob.as_ref(), &[0x68, 0x65, 0x6C, 0x6C, 0x6F]);
- });
-
- dedo("new Uint8Array([97])", |scope, v| {
- let sob: serde_v8::StringOrBuffer = serde_v8::from_v8(scope, v).unwrap();
- assert_eq!(sob.as_ref(), &[97]);
- });
-
- dedo("new Uint8Array([128])", |scope, v| {
- let sob: serde_v8::StringOrBuffer = serde_v8::from_v8(scope, v).unwrap();
- assert_eq!(sob.as_ref(), &[128]);
- });
-
- dedo(
- "(Uint8Array.from([0x68, 0x65, 0x6C, 0x6C, 0x6F]))",
- |scope, v| {
- let sob: serde_v8::StringOrBuffer = serde_v8::from_v8(scope, v).unwrap();
- assert_eq!(sob.as_ref(), &[0x68, 0x65, 0x6C, 0x6C, 0x6F]);
- },
- );
-}
-
-#[test]
-fn de_buffers() {
- // ArrayBufferView
- dedo("new Uint8Array([97])", |scope, v| {
- let buf: JsBuffer = serde_v8::from_v8(scope, v).unwrap();
- assert_eq!(&*buf, &[97]);
- });
-
- // ArrayBuffer
- dedo("(new Uint8Array([97])).buffer", |scope, v| {
- let buf: JsBuffer = serde_v8::from_v8(scope, v).unwrap();
- assert_eq!(&*buf, &[97]);
- });
-
- dedo(
- "(Uint8Array.from([0x68, 0x65, 0x6C, 0x6C, 0x6F]))",
- |scope, v| {
- let buf: JsBuffer = serde_v8::from_v8(scope, v).unwrap();
- assert_eq!(&*buf, &[0x68, 0x65, 0x6C, 0x6C, 0x6F]);
- },
- );
-
- dedo("(new ArrayBuffer(4))", |scope, v| {
- let buf: JsBuffer = serde_v8::from_v8(scope, v).unwrap();
- assert_eq!(&*buf, &[0x0, 0x0, 0x0, 0x0]);
- });
-
- dedo("(new ArrayBuffer(8, { maxByteLength: 16}))", |scope, v| {
- let result: Result<JsBuffer, Error> = serde_v8::from_v8(scope, v);
- matches!(result, Err(Error::ResizableBackingStoreNotSupported));
- });
-}
-
-// Structs
-#[derive(Debug, PartialEq, Deserialize)]
-struct StructUnit;
-
-#[derive(Debug, PartialEq)]
-struct StructPayload {
- a: u64,
- b: u64,
-}
-
-struct StructVisitor;
-
-impl<'de> serde::de::Visitor<'de> for StructVisitor {
- type Value = StructPayload;
- fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
- formatter.write_str("struct StructPayload")
- }
- fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
- where
- A: serde::de::MapAccess<'de>,
- {
- let mut payload = StructPayload { a: 0, b: 0 };
- while let Some(key) = map.next_key::<String>()? {
- match key.as_ref() {
- "a" => payload.a = map.next_value()?,
- "b" => payload.b = map.next_value()?,
- f => panic!("Unknown field {f}"),
- }
- }
- Ok(payload)
- }
-}
-
-detest!(de_unit_struct, StructUnit, "'StructUnit'", StructUnit);
-
-#[test]
-fn de_struct() {
- dedo("({ a: 1, b: 2 })", |scope, v| {
- let mut de = serde_v8::Deserializer::new(scope, v, None);
- let payload = de
- .deserialize_struct("StructPayload", &[], StructVisitor)
- .unwrap();
- assert_eq!(payload, StructPayload { a: 1, b: 2 })
- })
-}
-
-#[test]
-fn de_struct_hint() {
- dedo("({ a: 1, b: 2 })", |scope, v| {
- let mut de = serde_v8::Deserializer::new(scope, v, None);
- let payload = de
- .deserialize_struct("StructPayload", &["a", "b"], StructVisitor)
- .unwrap();
- assert_eq!(payload, StructPayload { a: 1, b: 2 })
- })
-}
-
-////
-// 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::json!({
- "a": 1,
- "b": "hello",
- "c": true,
- })
-);
-detest!(
- de_json_object_from_map,
- serde_json::Value,
- "(new Map([['a', 1], ['b', 'hello'], ['c', true]]))",
- serde_json::json!({
- "a": 1,
- "b": "hello",
- "c": true,
- })
-);
-// TODO: this is not optimal, ideally we'd get an array of [1,2,3] instead.
-// Fixing that will require exposing Set::AsArray in the v8 bindings.
-detest!(
- de_json_object_from_set,
- serde_json::Value,
- "(new Set([1, 2, 3]))",
- serde_json::json!({})
-);
-
-defail!(defail_struct, MathOp, "123", |e| e
- == Err(Error::ExpectedObject("Number")));
-
-#[derive(Eq, PartialEq, Debug, Deserialize)]
-pub struct SomeThing {
- pub a: String,
- #[serde(default)]
- pub b: String,
-}
-detest!(
- de_struct_defaults,
- SomeThing,
- "({ a: 'hello' })",
- SomeThing {
- a: "hello".into(),
- b: "".into()
- }
-);
-
-detest!(de_bstr, ByteString, "'hello'", "hello".into());
-defail!(defail_bstr, ByteString, "'👋bye'", |e| e
- == Err(Error::ExpectedLatin1));
-
-#[derive(Eq, PartialEq, Debug, Deserialize)]
-pub struct StructWithBytes {
- #[serde(with = "serde_bytes")]
- a: Vec<u8>,
- #[serde(with = "serde_bytes")]
- b: Vec<u8>,
- #[serde(with = "serde_bytes")]
- c: Vec<u8>,
-}
-detest!(
- de_struct_with_bytes,
- StructWithBytes,
- "({ a: new Uint8Array([1, 2]), b: (new Uint8Array([3 , 4])).buffer, c: (new Uint32Array([0])).buffer})",
- StructWithBytes {
- a: vec![1, 2],
- b: vec![3, 4],
- c: vec![0, 0, 0, 0],
- }
-);
-detest!(
- de_u16str,
- U16String,
- "'hello'",
- "hello".encode_utf16().collect::<Vec<_>>().into()
-);
-detest!(
- de_u16str_non_latin1,
- U16String,
- "'👋bye'",
- "👋bye".encode_utf16().collect::<Vec<_>>().into()
-);
-
-// NaN
-detest!(de_nan_u8, u8, "NaN", 0);
-detest!(de_nan_u16, u16, "NaN", 0);
-detest!(de_nan_u32, u32, "NaN", 0);
-detest!(de_nan_u64, u64, "NaN", 0);
-detest!(de_nan_i8, i8, "NaN", 0);
-detest!(de_nan_i16, i16, "NaN", 0);
-detest!(de_nan_i32, i32, "NaN", 0);
-detest!(de_nan_i64, i64, "NaN", 0);
-decheck!(de_nan_f32, f32, "NaN", t, assert!(t.is_nan()));
-decheck!(de_nan_f64, f64, "NaN", t, assert!(t.is_nan()));
-
-// Infinity
-detest!(de_inf_u8, u8, "Infinity", u8::MAX);
-detest!(de_inf_u16, u16, "Infinity", u16::MAX);
-detest!(de_inf_u32, u32, "Infinity", u32::MAX);
-detest!(de_inf_u64, u64, "Infinity", u64::MAX);
-detest!(de_inf_i8, i8, "Infinity", i8::MAX);
-detest!(de_inf_i16, i16, "Infinity", i16::MAX);
-detest!(de_inf_i32, i32, "Infinity", i32::MAX);
-detest!(de_inf_i64, i64, "Infinity", i64::MAX);
-detest!(de_inf_f32, f32, "Infinity", f32::INFINITY);
-detest!(de_inf_f64, f64, "Infinity", f64::INFINITY);
-
-// -Infinity
-detest!(de_neg_inf_u8, u8, "-Infinity", u8::MIN);
-detest!(de_neg_inf_u16, u16, "-Infinity", u16::MIN);
-detest!(de_neg_inf_u32, u32, "-Infinity", u32::MIN);
-detest!(de_neg_inf_u64, u64, "-Infinity", u64::MIN);
-detest!(de_neg_inf_i8, i8, "-Infinity", i8::MIN);
-detest!(de_neg_inf_i16, i16, "-Infinity", i16::MIN);
-detest!(de_neg_inf_i32, i32, "-Infinity", i32::MIN);
-detest!(de_neg_inf_i64, i64, "-Infinity", i64::MIN);
-detest!(de_neg_inf_f32, f32, "-Infinity", f32::NEG_INFINITY);
-detest!(de_neg_inf_f64, f64, "-Infinity", f64::NEG_INFINITY);
-
-// BigInt to f32/f64 max/min
-detest!(
- de_bigint_f64_max,
- f64,
- "BigInt(1.7976931348623157e+308)",
- f64::MAX
-);
-detest!(
- de_bigint_f64_min,
- f64,
- "BigInt(-1.7976931348623157e+308)",
- f64::MIN
-);
-detest!(de_bigint_f32_max, f32, "BigInt(3.40282347e38)", f32::MAX);
-detest!(de_bigint_f32_min, f32, "BigInt(-3.40282347e38)", f32::MIN);
-// BigInt to f32/f64 saturating to inf
-detest!(
- de_bigint_f64_inf,
- f64,
- "(BigInt(1.7976931348623157e+308)*BigInt(100))",
- f64::INFINITY
-);
-detest!(
- de_bigint_f64_neg_inf,
- f64,
- "(BigInt(-1.7976931348623157e+308)*BigInt(100))",
- f64::NEG_INFINITY
-);
-
-detest!(
- de_bigint_f32_inf,
- f32,
- "BigInt(1.7976931348623157e+308)",
- f32::INFINITY
-);
-detest!(
- de_bigint_f32_neg_inf,
- f32,
- "BigInt(-1.7976931348623157e+308)",
- f32::NEG_INFINITY
-);
-
-// BigInt to BigInt
-detest!(
- de_bigint_var_u8,
- BigInt,
- "255n",
- num_bigint::BigInt::from(255u8).into()
-);
-detest!(
- de_bigint_var_i8,
- BigInt,
- "-128n",
- num_bigint::BigInt::from(-128i8).into()
-);
-detest!(
- de_bigint_var_u16,
- BigInt,
- "65535n",
- num_bigint::BigInt::from(65535u16).into()
-);
-detest!(
- de_bigint_var_i16,
- BigInt,
- "-32768n",
- num_bigint::BigInt::from(-32768i16).into()
-);
-detest!(
- de_bigint_var_u32,
- BigInt,
- "4294967295n",
- num_bigint::BigInt::from(4294967295u32).into()
-);
-detest!(
- de_bigint_var_i32,
- BigInt,
- "-2147483648n",
- num_bigint::BigInt::from(-2147483648i32).into()
-);
-detest!(
- de_bigint_var_u64,
- BigInt,
- "18446744073709551615n",
- num_bigint::BigInt::from(18446744073709551615u64).into()
-);
-detest!(
- de_bigint_var_i64,
- BigInt,
- "-9223372036854775808n",
- num_bigint::BigInt::from(-9223372036854775808i64).into()
-);
-detest!(
- de_bigint_var_u128,
- BigInt,
- "340282366920938463463374607431768211455n",
- num_bigint::BigInt::from(340282366920938463463374607431768211455u128).into()
-);
-detest!(
- de_bigint_var_i128,
- BigInt,
- "-170141183460469231731687303715884105728n",
- num_bigint::BigInt::from(-170141183460469231731687303715884105728i128).into()
-);
diff --git a/serde_v8/tests/magic.rs b/serde_v8/tests/magic.rs
deleted file mode 100644
index e3ed1d330..000000000
--- a/serde_v8/tests/magic.rs
+++ /dev/null
@@ -1,192 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-use serde::Deserialize;
-use serde::Serialize;
-
-use serde_v8::utils::js_exec;
-use serde_v8::utils::v8_do;
-use serde_v8::Result;
-
-#[derive(Deserialize)]
-struct MagicOp<'s> {
- #[allow(unused)]
- pub a: u64,
- #[allow(unused)]
- pub b: u64,
- pub c: serde_v8::Value<'s>,
- #[allow(unused)]
- pub operator: Option<String>,
-}
-
-#[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<v8::Value> = mop.c.into();
- let vs = v8::Local::<v8::String>::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::JsBuffer = 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::JsBuffer, serde_v8::JsBuffer) =
- 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::JsBuffer> =
- 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::JsBuffer =
- 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());
-
- // Shared buffers
- let v8_array =
- js_exec(scope, "new Uint8Array(new SharedArrayBuffer([1,2,3,4,5]))");
- let zbuf: Result<serde_v8::JsBuffer> = serde_v8::from_v8(scope, v8_array);
- assert!(zbuf.is_err());
-
- // Serialization
- let buf: Vec<u8> = vec![1, 2, 3, 99, 5];
- let zbuf: serde_v8::ToJsBuffer = 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::ToJsBuffer,
- b: serde_v8::ToJsBuffer,
- }
- let buf1: Vec<u8> = vec![1, 2, 33, 4, 5];
- let buf2: Vec<u8> = 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());
-
- // JsBuffer as bytes::Bytes
- let v8_array = js_exec(scope, "new Uint8Array([1,2,3,4,5])");
- let zbuf: serde_v8::JsBuffer = serde_v8::from_v8(scope, v8_array).unwrap();
- let buf: bytes::Bytes = zbuf.into();
- assert_eq!(buf, bytes::Bytes::from_static(&[1, 2, 3, 4, 5]));
- assert_eq!(buf, bytes::Bytes::from_static(&[1, 2, 3, 4, 5]));
- assert_eq!(buf.slice(0..2), bytes::Bytes::from_static(&[1, 2]));
- assert_eq!(buf.slice(2..), bytes::Bytes::from_static(&[3, 4, 5]));
- // We're specifically testing that slices are preserved post-clone
- #[allow(clippy::redundant_clone)]
- let buf2 = buf.slice(2..).clone();
- assert_eq!(buf2, bytes::Bytes::from_static(&[3, 4, 5]));
- })
-}
-
-#[test]
-fn magic_byte_string() {
- 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);
-
- // JS string to ByteString
- let v8_string = js_exec(scope, "'test \\0\\t\\n\\r\\x7F\\x80áþÆñ'");
- let rust_reflex: serde_v8::ByteString =
- serde_v8::from_v8(scope, v8_string).unwrap();
- assert_eq!(
- rust_reflex.as_slice(),
- b"test \0\t\n\r\x7F\x80\xE1\xFE\xC6\xF1"
- );
-
- // Non-Latin-1 characters
- let v8_string = js_exec(scope, "'日本語'");
- let rust_reflex: Result<serde_v8::ByteString> =
- serde_v8::from_v8(scope, v8_string);
- assert!(rust_reflex.is_err());
-
- // Windows-1252 characters that aren't Latin-1
- let v8_string = js_exec(scope, "'œ'");
- let rust_reflex: Result<serde_v8::ByteString> =
- serde_v8::from_v8(scope, v8_string);
- assert!(rust_reflex.is_err());
-
- // ByteString to JS string
- let expected = "a\x00sf:~\x7Fá\u{009C}þ\u{008A}";
- let buf: Vec<u8> = b"a\x00sf:~\x7F\xE1\x9C\xFE\x8A".as_ref().into();
- let zbuf = serde_v8::ByteString::from(buf);
- let v8_value = serde_v8::to_v8(scope, zbuf).unwrap();
- let key = serde_v8::to_v8(scope, "actual").unwrap();
- global.set(scope, key, v8_value);
- let v8_value_expected = serde_v8::to_v8(scope, expected).unwrap();
- let key_expected = serde_v8::to_v8(scope, "expected").unwrap();
- global.set(scope, key_expected, v8_value_expected);
- let eq = js_exec(scope, "actual === expected");
- assert!(eq.is_true());
- })
-}
diff --git a/serde_v8/tests/ser.rs b/serde_v8/tests/ser.rs
deleted file mode 100644
index b61a758f9..000000000
--- a/serde_v8/tests/ser.rs
+++ /dev/null
@@ -1,270 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-use serde::Serialize;
-use serde_json::json;
-use serde_v8::utils::js_exec;
-use serde_v8::utils::v8_do;
-use serde_v8::BigInt;
-
-#[derive(Debug, Serialize, PartialEq)]
-struct MathOp {
- pub a: u64,
- pub b: u64,
- pub operator: Option<String>,
-}
-
-// 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]);
-}
-"#;
-const JS_POLLUTE: &str = r#"
-Object.defineProperty(Array.prototype, "0", {
- set: function (v) {
- throw new Error("Polluted Array 0 set");
- },
-});
-
-Object.defineProperty(Object.prototype, "a", {
- set: (v) => {
- throw new Error("Polluted Object 'a' set");
- }
-});
-"#;
-
-fn sercheck<T: Serialize>(val: T, code: &str, pollute: bool) -> 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);
-
- // Load util functions
- js_exec(scope, JS_UTILS);
- if pollute {
- js_exec(scope, JS_POLLUTE);
- }
- // TryCatch scope (to catch pollution exceptions)
- let scope = &mut v8::TryCatch::new(scope);
-
- // 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);
-
- // Pollution check
- if let Some(message) = scope.message() {
- let msg = message.get(scope).to_rust_string_lossy(scope);
- panic!("JS Exception: {msg}");
- }
-
- // 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, false),
- "Expected: {} where x={:?}",
- $src,
- $rust,
- );
- }
- };
-}
-
-macro_rules! sertest_polluted {
- ($fn_name:ident, $rust:expr, $src:expr) => {
- #[test]
- fn $fn_name() {
- assert!(
- sercheck($rust, $src, true),
- "Expected: {} where x={:?}",
- $src,
- $rust,
- );
- }
- };
-}
-
-sertest!(ser_char, 'é', "x === 'é'");
-sertest!(ser_option_some, Some(true), "x === true");
-sertest!(ser_option_null, None as Option<bool>, "x === null");
-sertest!(ser_unit_null, (), "x === null");
-sertest!(ser_bool, true, "x === true");
-sertest!(ser_u64, 9007199254740991_u64, "x === 9007199254740991");
-sertest!(ser_big_int, 9007199254740992_i64, "x === 9007199254740992n");
-sertest!(
- ser_neg_big_int,
- -9007199254740992_i64,
- "x === -9007199254740992n"
-);
-sertest!(ser_f64, 12345.0, "x === 12345.0");
-sertest!(ser_string, "Hello", "x === 'Hello'");
-sertest!(ser_bytes, b"\x01\x02\x03", "arrEqual(x, [1, 2, 3])");
-sertest!(ser_vec_u64, vec![1, 2, 3, 4, 5], "arrEqual(x, [1,2,3,4,5])");
-sertest!(
- ser_vec_string,
- vec!["hello", "world"],
- "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_bigint_u8,
- BigInt::from(num_bigint::BigInt::from(255_u8)),
- "x === 255n"
-);
-sertest!(
- ser_bigint_i8,
- BigInt::from(num_bigint::BigInt::from(-128_i8)),
- "x === -128n"
-);
-sertest!(
- ser_bigint_u16,
- BigInt::from(num_bigint::BigInt::from(65535_u16)),
- "x === 65535n"
-);
-sertest!(
- ser_bigint_i16,
- BigInt::from(num_bigint::BigInt::from(-32768_i16)),
- "x === -32768n"
-);
-sertest!(
- ser_bigint_u32,
- BigInt::from(num_bigint::BigInt::from(4294967295_u32)),
- "x === 4294967295n"
-);
-sertest!(
- ser_bigint_i32,
- BigInt::from(num_bigint::BigInt::from(-2147483648_i32)),
- "x === -2147483648n"
-);
-sertest!(
- ser_bigint_u64,
- BigInt::from(num_bigint::BigInt::from(9007199254740991_u64)),
- "x === 9007199254740991n"
-);
-sertest!(
- ser_bigint_i64,
- BigInt::from(num_bigint::BigInt::from(-9007199254740991_i64)),
- "x === -9007199254740991n"
-);
-sertest!(
- ser_bigint_u128,
- BigInt::from(num_bigint::BigInt::from(
- 340282366920938463463374607431768211455_u128
- )),
- "x === 340282366920938463463374607431768211455n"
-);
-sertest!(
- ser_bigint_i128,
- BigInt::from(num_bigint::BigInt::from(
- -170141183460469231731687303715884105728_i128
- )),
- "x === -170141183460469231731687303715884105728n"
-);
-
-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!(9007199254740991_u64),
- "x === 9007199254740991"
-);
-sertest!(
- ser_json_big_int,
- json!(9007199254740992_i64),
- "x === 9007199254740992n"
-);
-sertest!(
- ser_json_neg_big_int,
- json!(-9007199254740992_i64),
- "x === -9007199254740992n"
-);
-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'])"
-);
-
-////
-// Pollution tests
-////
-
-sertest_polluted!(
- ser_polluted_obj,
- MathOp {
- a: 1,
- b: 2,
- operator: None
- },
- "objEqual(x, { a: 1, b: 2, operator: null })"
-);
-
-sertest_polluted!(
- ser_polluted_tuple,
- (true, 123, false),
- "arrEqual(x, [true, 123, false])"
-);
-
-sertest_polluted!(ser_polluted_vec, vec![1, 2, 3], "arrEqual(x, [1, 2, 3])");
diff --git a/serde_v8/utils.rs b/serde_v8/utils.rs
deleted file mode 100644
index 6a9732400..000000000
--- a/serde_v8/utils.rs
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-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(0, false).make_shared();
- v8::V8::initialize_platform(platform);
- v8::V8::initialize();
-}
-
-pub fn v8_shutdown() {
- // SAFETY: this is safe, because all isolates have been shut down already.
- unsafe {
- v8::V8::dispose();
- }
- v8::V8::dispose_platform();
-}
-
-pub fn v8_do(f: impl FnOnce()) {
- static V8_INIT: Once = Once::new();
- V8_INIT.call_once(|| {
- v8_init();
- });
- f();
- // v8_shutdown();
-}