summaryrefslogtreecommitdiff
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
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.
-rw-r--r--Cargo.lock77
-rw-r--r--Cargo.toml12
-rw-r--r--cli/tests/integration/check_tests.rs29
-rw-r--r--cli/tests/unit/stat_test.ts8
-rw-r--r--core/00_primordials.js615
-rw-r--r--core/01_core.js878
-rw-r--r--core/02_error.js157
-rw-r--r--core/Cargo.toml50
-rw-r--r--core/README.md31
-rw-r--r--core/async_cancel.rs793
-rw-r--r--core/async_cell.rs780
-rw-r--r--core/error.rs719
-rw-r--r--core/error_codes.rs216
-rw-r--r--core/examples/disable_ops.rs27
-rw-r--r--core/examples/eval_js_value.rs48
-rw-r--r--core/examples/fs_module_loader.rs40
-rw-r--r--core/examples/hello_world.rs68
-rw-r--r--core/examples/http_bench_json_ops/http_bench_json_ops.js46
-rw-r--r--core/examples/http_bench_json_ops/main.rs176
-rw-r--r--core/examples/panik.rs36
-rw-r--r--core/examples/schedule_task.rs69
-rw-r--r--core/examples/ts_module_loader.rs128
-rw-r--r--core/examples/wasm.js28
-rw-r--r--core/examples/wasm.rs67
-rw-r--r--core/examples/wasm.ts7
-rw-r--r--core/extensions.rs645
-rw-r--r--core/fast_string.rs243
-rw-r--r--core/flags.rs7
-rw-r--r--core/gotham_state.rs193
-rw-r--r--core/inspector.rs853
-rw-r--r--core/internal.d.ts1079
-rw-r--r--core/io.rs300
-rw-r--r--core/joinset.rs92
-rw-r--r--core/lib.deno_core.d.ts212
-rw-r--r--core/lib.rs204
-rw-r--r--core/module_specifier.rs500
-rw-r--r--core/modules/loaders.rs253
-rw-r--r--core/modules/map.rs1014
-rw-r--r--core/modules/mod.rs689
-rw-r--r--core/modules/tests.rs1252
-rw-r--r--core/normalize_path.rs39
-rw-r--r--core/ops.rs234
-rw-r--r--core/ops_builtin.rs369
-rw-r--r--core/ops_builtin_v8.rs939
-rw-r--r--core/ops_metrics.rs91
-rw-r--r--core/path.rs91
-rw-r--r--core/resources.rs429
-rw-r--r--core/runtime/bindings.js51
-rw-r--r--core/runtime/bindings.rs545
-rw-r--r--core/runtime/encode_decode_test.js69
-rw-r--r--core/runtime/error_builder_test.js32
-rw-r--r--core/runtime/icudtl.datbin10541264 -> 0 bytes
-rw-r--r--core/runtime/jsrealm.rs365
-rw-r--r--core/runtime/jsruntime.rs2316
-rw-r--r--core/runtime/mod.rs34
-rw-r--r--core/runtime/ops.rs634
-rw-r--r--core/runtime/serialize_deserialize_test.js74
-rw-r--r--core/runtime/snapshot_util.rs259
-rw-r--r--core/runtime/tests.rs2396
-rw-r--r--core/source_map.rs109
-rw-r--r--core/task.rs135
-rw-r--r--core/task_queue.rs143
-rw-r--r--ops/Cargo.toml37
-rw-r--r--ops/README.md62
-rw-r--r--ops/attrs.rs54
-rw-r--r--ops/deno.rs35
-rw-r--r--ops/fast_call.rs363
-rw-r--r--ops/lib.rs1025
-rw-r--r--ops/op2/dispatch_fast.rs327
-rw-r--r--ops/op2/dispatch_slow.rs401
-rw-r--r--ops/op2/generator_state.rs40
-rw-r--r--ops/op2/mod.rs326
-rw-r--r--ops/op2/signature.rs741
-rw-r--r--ops/op2/test_cases/sync/add.out78
-rw-r--r--ops/op2/test_cases/sync/add.rs6
-rw-r--r--ops/op2/test_cases/sync/add_options.out57
-rw-r--r--ops/op2/test_cases/sync/add_options.rs6
-rw-r--r--ops/op2/test_cases/sync/doc_comment.out59
-rw-r--r--ops/op2/test_cases/sync/doc_comment.rs5
-rw-r--r--ops/op2/test_cases/sync/generics.out59
-rw-r--r--ops/op2/test_cases/sync/generics.rs4
-rw-r--r--ops/op2/test_cases/sync/result_primitive.out122
-rw-r--r--ops/op2/test_cases/sync/result_primitive.rs4
-rw-r--r--ops/op2/test_cases/sync/result_void.out117
-rw-r--r--ops/op2/test_cases/sync/result_void.rs4
-rw-r--r--ops/op2/test_cases/sync/smi.out76
-rw-r--r--ops/op2/test_cases/sync/smi.rs4
-rw-r--r--ops/op2/test_cases/sync/string_cow.out75
-rw-r--r--ops/op2/test_cases/sync/string_cow.rs4
-rw-r--r--ops/op2/test_cases/sync/string_option_return.out53
-rw-r--r--ops/op2/test_cases/sync/string_option_return.rs5
-rw-r--r--ops/op2/test_cases/sync/string_owned.out73
-rw-r--r--ops/op2/test_cases/sync/string_owned.rs4
-rw-r--r--ops/op2/test_cases/sync/string_ref.out75
-rw-r--r--ops/op2/test_cases/sync/string_ref.rs4
-rw-r--r--ops/op2/test_cases/sync/string_return.out49
-rw-r--r--ops/op2/test_cases/sync/string_return.rs5
-rw-r--r--ops/optimizer.rs1004
-rw-r--r--ops/optimizer_tests/async_nop.expected11
-rw-r--r--ops/optimizer_tests/async_nop.out137
-rw-r--r--ops/optimizer_tests/async_nop.rs3
-rw-r--r--ops/optimizer_tests/async_result.expected11
-rw-r--r--ops/optimizer_tests/async_result.out150
-rw-r--r--ops/optimizer_tests/async_result.rs6
-rw-r--r--ops/optimizer_tests/callback_options.expected11
-rw-r--r--ops/optimizer_tests/callback_options.out106
-rw-r--r--ops/optimizer_tests/callback_options.rs5
-rw-r--r--ops/optimizer_tests/cow_str.expected11
-rw-r--r--ops/optimizer_tests/cow_str.out121
-rw-r--r--ops/optimizer_tests/cow_str.rs3
-rw-r--r--ops/optimizer_tests/f64_slice.expected11
-rw-r--r--ops/optimizer_tests/f64_slice.out137
-rw-r--r--ops/optimizer_tests/f64_slice.rs3
-rw-r--r--ops/optimizer_tests/incompatible_1.expected1
-rw-r--r--ops/optimizer_tests/incompatible_1.out93
-rw-r--r--ops/optimizer_tests/incompatible_1.rs9
-rw-r--r--ops/optimizer_tests/issue16934.expected11
-rw-r--r--ops/optimizer_tests/issue16934.out115
-rw-r--r--ops/optimizer_tests/issue16934.rs11
-rw-r--r--ops/optimizer_tests/issue16934_fast.expected1
-rw-r--r--ops/optimizer_tests/issue16934_fast.out110
-rw-r--r--ops/optimizer_tests/issue16934_fast.rs8
-rw-r--r--ops/optimizer_tests/op_blob_revoke_object_url.expected11
-rw-r--r--ops/optimizer_tests/op_blob_revoke_object_url.out93
-rw-r--r--ops/optimizer_tests/op_blob_revoke_object_url.rs10
-rw-r--r--ops/optimizer_tests/op_ffi_ptr_value.expected11
-rw-r--r--ops/optimizer_tests/op_ffi_ptr_value.out152
-rw-r--r--ops/optimizer_tests/op_ffi_ptr_value.rs3
-rw-r--r--ops/optimizer_tests/op_print.expected11
-rw-r--r--ops/optimizer_tests/op_print.out108
-rw-r--r--ops/optimizer_tests/op_print.rs7
-rw-r--r--ops/optimizer_tests/op_state.expected11
-rw-r--r--ops/optimizer_tests/op_state.out120
-rw-r--r--ops/optimizer_tests/op_state.rs3
-rw-r--r--ops/optimizer_tests/op_state_basic1.expected11
-rw-r--r--ops/optimizer_tests/op_state_basic1.out148
-rw-r--r--ops/optimizer_tests/op_state_basic1.rs3
-rw-r--r--ops/optimizer_tests/op_state_generics.expected11
-rw-r--r--ops/optimizer_tests/op_state_generics.out115
-rw-r--r--ops/optimizer_tests/op_state_generics.rs5
-rw-r--r--ops/optimizer_tests/op_state_result.expected11
-rw-r--r--ops/optimizer_tests/op_state_result.out168
-rw-r--r--ops/optimizer_tests/op_state_result.rs3
-rw-r--r--ops/optimizer_tests/op_state_warning.expected11
-rw-r--r--ops/optimizer_tests/op_state_warning.out157
-rw-r--r--ops/optimizer_tests/op_state_warning.rs9
-rw-r--r--ops/optimizer_tests/op_state_with_transforms.expected11
-rw-r--r--ops/optimizer_tests/op_state_with_transforms.out162
-rw-r--r--ops/optimizer_tests/op_state_with_transforms.rs5
-rw-r--r--ops/optimizer_tests/opstate_with_arity.expected11
-rw-r--r--ops/optimizer_tests/opstate_with_arity.out188
-rw-r--r--ops/optimizer_tests/opstate_with_arity.rs3
-rw-r--r--ops/optimizer_tests/option_arg.expected1
-rw-r--r--ops/optimizer_tests/option_arg.out91
-rw-r--r--ops/optimizer_tests/option_arg.rs6
-rw-r--r--ops/optimizer_tests/owned_string.expected11
-rw-r--r--ops/optimizer_tests/owned_string.out131
-rw-r--r--ops/optimizer_tests/owned_string.rs3
-rw-r--r--ops/optimizer_tests/param_mut_binding_warning.expected1
-rw-r--r--ops/optimizer_tests/param_mut_binding_warning.out111
-rw-r--r--ops/optimizer_tests/param_mut_binding_warning.rs11
-rw-r--r--ops/optimizer_tests/raw_ptr.expected11
-rw-r--r--ops/optimizer_tests/raw_ptr.out211
-rw-r--r--ops/optimizer_tests/raw_ptr.rs6
-rw-r--r--ops/optimizer_tests/serde_v8_value.expected11
-rw-r--r--ops/optimizer_tests/serde_v8_value.out124
-rw-r--r--ops/optimizer_tests/serde_v8_value.rs3
-rw-r--r--ops/optimizer_tests/strings.expected11
-rw-r--r--ops/optimizer_tests/strings.out132
-rw-r--r--ops/optimizer_tests/strings.rs3
-rw-r--r--ops/optimizer_tests/strings_result.expected11
-rw-r--r--ops/optimizer_tests/strings_result.out93
-rw-r--r--ops/optimizer_tests/strings_result.rs4
-rw-r--r--ops/optimizer_tests/u64_result.expected1
-rw-r--r--ops/optimizer_tests/u64_result.out94
-rw-r--r--ops/optimizer_tests/u64_result.rs5
-rw-r--r--ops/optimizer_tests/uint8array.expected11
-rw-r--r--ops/optimizer_tests/uint8array.out205
-rw-r--r--ops/optimizer_tests/uint8array.rs3
-rw-r--r--ops/optimizer_tests/unit_result.expected11
-rw-r--r--ops/optimizer_tests/unit_result.out137
-rw-r--r--ops/optimizer_tests/unit_result.rs3
-rw-r--r--ops/optimizer_tests/unit_result2.expected11
-rw-r--r--ops/optimizer_tests/unit_result2.out172
-rw-r--r--ops/optimizer_tests/unit_result2.rs9
-rw-r--r--ops/optimizer_tests/unit_ret.expected11
-rw-r--r--ops/optimizer_tests/unit_ret.out109
-rw-r--r--ops/optimizer_tests/unit_ret.rs3
-rw-r--r--ops/optimizer_tests/wasm_op.expected11
-rw-r--r--ops/optimizer_tests/wasm_op.out107
-rw-r--r--ops/optimizer_tests/wasm_op.rs3
-rw-r--r--ops/tests/compile_fail/mem_slices.rs24
-rw-r--r--ops/tests/compile_fail/mem_slices.stderr15
-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
223 files changed, 17 insertions, 36602 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 9e85d56a4..b7fea19ce 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -358,15 +358,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
[[package]]
-name = "basic-toml"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c0de75129aa8d0cceaf750b89013f0e08804d6ec61416da787b35ad0d7cddf1"
-dependencies = [
- "serde",
-]
-
-[[package]]
name = "bencher"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -608,12 +599,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e"
[[package]]
-name = "cooked-waker"
-version = "5.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "147be55d677052dabc6b22252d5dd0fd4c29c8c27aa4f2fbef0f94aa003b406f"
-
-[[package]]
name = "core-foundation"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -973,12 +958,12 @@ dependencies = [
[[package]]
name = "deno_core"
-version = "0.191.0"
+version = "0.193.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2d7eeb863655f377ffe22d5a90f01d1b57b4d4ad0acbfeec266d5d3faf4cd1cf"
dependencies = [
"anyhow",
"bytes",
- "cooked-waker",
- "deno_ast",
"deno_ops",
"futures",
"indexmap",
@@ -1346,14 +1331,14 @@ dependencies = [
[[package]]
name = "deno_ops"
-version = "0.69.0"
+version = "0.71.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2dd95626e113f292ce758f216bb12e50c9c58e886195bcd85231e715c73d6470"
dependencies = [
"deno-proc-macro-rules",
"lazy-regex",
"once_cell",
"pmutil",
- "pretty_assertions",
- "prettyplease",
"proc-macro-crate",
"proc-macro2 1.0.60",
"quote 1.0.28",
@@ -1362,9 +1347,7 @@ dependencies = [
"strum_macros",
"syn 1.0.109",
"syn 2.0.18",
- "testing_macros",
"thiserror",
- "trybuild",
"v8",
]
@@ -3680,16 +3663,6 @@ dependencies = [
]
[[package]]
-name = "prettyplease"
-version = "0.1.25"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86"
-dependencies = [
- "proc-macro2 1.0.60",
- "syn 1.0.109",
-]
-
-[[package]]
name = "primeorder"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4393,15 +4366,15 @@ dependencies = [
[[package]]
name = "serde_v8"
-version = "0.102.0"
+version = "0.104.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2481189a5019f43a6b68620193578623701323754409555c36588c81ee2487de"
dependencies = [
- "bencher",
"bytes",
"derive_more",
"num-bigint",
"serde",
"serde_bytes",
- "serde_json",
"smallvec",
"thiserror",
"v8",
@@ -5245,23 +5218,6 @@ dependencies = [
]
[[package]]
-name = "testing_macros"
-version = "0.2.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e6d536c776d47c59f8f47fbf4e7062b23095be9fce218d11d9c9fb988b579dfa"
-dependencies = [
- "anyhow",
- "glob",
- "once_cell",
- "pmutil",
- "proc-macro2 1.0.60",
- "quote 1.0.28",
- "regex",
- "relative-path",
- "syn 1.0.109",
-]
-
-[[package]]
name = "text-size"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -5651,21 +5607,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed"
[[package]]
-name = "trybuild"
-version = "1.0.79"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "db3115bddce1b5f52dd4b5e0ec8298a66ce733e4cc6759247dc2d1c11508ec38"
-dependencies = [
- "basic-toml",
- "glob",
- "once_cell",
- "serde",
- "serde_derive",
- "serde_json",
- "termcolor",
-]
-
-[[package]]
name = "twox-hash"
version = "1.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
index 0cd91de48..5cc401a95 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -6,10 +6,7 @@ members = [
"bench_util",
"cli",
"cli/napi/sym",
- "core",
- "ops",
"runtime",
- "serde_v8",
"test_ffi",
"test_napi",
"test_util",
@@ -44,9 +41,10 @@ repository = "https://github.com/denoland/deno"
v8 = { version = "0.74.1", default-features = false }
deno_ast = { version = "0.27.0", features = ["transpiling"] }
-deno_core = { version = "0.191.0", path = "./core" }
-deno_ops = { version = "0.69.0", path = "./ops" }
-serde_v8 = { version = "0.102.0", path = "./serde_v8" }
+deno_core = { version = "0.193.0" }
+deno_ops = { version = "0.70.0" }
+serde_v8 = { version = "0.103.0" }
+
deno_runtime = { version = "0.117.0", path = "./runtime" }
napi_sym = { version = "0.39.0", path = "./cli/napi/sym" }
deno_bench_util = { version = "0.103.0", path = "./bench_util" }
@@ -132,8 +130,6 @@ signature = "=1.6.4"
slab = "0.4"
smallvec = "1.8"
socket2 = "0.4.7"
-strum = { version = "0.24", features = ["derive"] }
-strum_macros = "0.24"
tar = "=0.4.38"
tempfile = "3.4.0"
thiserror = "1.0.40"
diff --git a/cli/tests/integration/check_tests.rs b/cli/tests/integration/check_tests.rs
index 41c568ad3..ab17713f2 100644
--- a/cli/tests/integration/check_tests.rs
+++ b/cli/tests/integration/check_tests.rs
@@ -195,35 +195,6 @@ fn typecheck_declarations_unstable() {
}
#[test]
-fn typecheck_core() {
- let context = TestContext::default();
- let deno_dir = context.deno_dir();
- let test_file = deno_dir.path().join("test_deno_core_types.ts");
- std::fs::write(
- &test_file,
- format!(
- "import \"{}\";",
- deno_core::resolve_path(
- &util::root_path()
- .join("core")
- .join("lib.deno_core.d.ts")
- .to_string(),
- &std::env::current_dir().unwrap()
- )
- .unwrap()
- ),
- )
- .unwrap();
-
- let args = vec!["run".to_string(), test_file.to_string()];
- let output = context.new_command().args_vec(args).split_output().run();
-
- println!("stdout: {}", output.stdout());
- println!("stderr: {}", output.stderr());
- output.assert_exit_code(0);
-}
-
-#[test]
fn ts_no_recheck_on_redirect() {
let test_context = TestContext::default();
let check_command = test_context.new_command().args_vec([
diff --git a/cli/tests/unit/stat_test.ts b/cli/tests/unit/stat_test.ts
index 69730d439..75693541d 100644
--- a/cli/tests/unit/stat_test.ts
+++ b/cli/tests/unit/stat_test.ts
@@ -135,11 +135,11 @@ Deno.test({ permissions: { read: true } }, function lstatSyncSuccess() {
assert(!modulesInfoByUrl.isDirectory);
assert(modulesInfoByUrl.isSymlink);
- const coreInfo = Deno.lstatSync("core");
+ const coreInfo = Deno.lstatSync("cli");
assert(coreInfo.isDirectory);
assert(!coreInfo.isSymlink);
- const coreInfoByUrl = Deno.lstatSync(pathToAbsoluteFileUrl("core"));
+ const coreInfoByUrl = Deno.lstatSync(pathToAbsoluteFileUrl("cli"));
assert(coreInfoByUrl.isDirectory);
assert(!coreInfoByUrl.isSymlink);
});
@@ -261,11 +261,11 @@ Deno.test({ permissions: { read: true } }, async function lstatSuccess() {
assert(!modulesInfoByUrl.isDirectory);
assert(modulesInfoByUrl.isSymlink);
- const coreInfo = await Deno.lstat("core");
+ const coreInfo = await Deno.lstat("cli");
assert(coreInfo.isDirectory);
assert(!coreInfo.isSymlink);
- const coreInfoByUrl = await Deno.lstat(pathToAbsoluteFileUrl("core"));
+ const coreInfoByUrl = await Deno.lstat(pathToAbsoluteFileUrl("cli"));
assert(coreInfoByUrl.isDirectory);
assert(!coreInfoByUrl.isSymlink);
});
diff --git a/core/00_primordials.js b/core/00_primordials.js
deleted file mode 100644
index 60474e649..000000000
--- a/core/00_primordials.js
+++ /dev/null
@@ -1,615 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-
-// Based on https://github.com/nodejs/node/blob/889ad35d3d41e376870f785b0c1b669cb732013d/lib/internal/per_context/primordials.js
-// Copyright Joyent, Inc. and other Node contributors.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a
-// copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to permit
-// persons to whom the Software is furnished to do so, subject to the
-// following conditions:
-//
-// The above copyright notice and this permission notice shall be included
-// in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
-// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
-// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
-// USE OR OTHER DEALINGS IN THE SOFTWARE.
-// This file subclasses and stores the JS builtins that come from the VM
-// so that Node.js's builtin modules do not need to later look these up from
-// the global proxy, which can be mutated by users.
-
-// Use of primordials have sometimes a dramatic impact on performance, please
-// benchmark all changes made in performance-sensitive areas of the codebase.
-// See: https://github.com/nodejs/node/pull/38248
-
-// deno-lint-ignore-file prefer-primordials
-
-"use strict";
-
-(() => {
- const primordials = {};
-
- const {
- defineProperty: ReflectDefineProperty,
- getOwnPropertyDescriptor: ReflectGetOwnPropertyDescriptor,
- ownKeys: ReflectOwnKeys,
- } = Reflect;
-
- // `uncurryThis` is equivalent to `func => Function.prototype.call.bind(func)`.
- // It is using `bind.bind(call)` to avoid using `Function.prototype.bind`
- // and `Function.prototype.call` after it may have been mutated by users.
- const { apply, bind, call } = Function.prototype;
- const uncurryThis = bind.bind(call);
- primordials.uncurryThis = uncurryThis;
-
- // `applyBind` is equivalent to `func => Function.prototype.apply.bind(func)`.
- // It is using `bind.bind(apply)` to avoid using `Function.prototype.bind`
- // and `Function.prototype.apply` after it may have been mutated by users.
- const applyBind = bind.bind(apply);
- primordials.applyBind = applyBind;
-
- // Methods that accept a variable number of arguments, and thus it's useful to
- // also create `${prefix}${key}Apply`, which uses `Function.prototype.apply`,
- // instead of `Function.prototype.call`, and thus doesn't require iterator
- // destructuring.
- const varargsMethods = [
- // 'ArrayPrototypeConcat' is omitted, because it performs the spread
- // on its own for arrays and array-likes with a truthy
- // @@isConcatSpreadable symbol property.
- "ArrayOf",
- "ArrayPrototypePush",
- "ArrayPrototypeUnshift",
- // 'FunctionPrototypeCall' is omitted, since there's 'ReflectApply'
- // and 'FunctionPrototypeApply'.
- "MathHypot",
- "MathMax",
- "MathMin",
- "StringPrototypeConcat",
- "TypedArrayOf",
- ];
-
- function getNewKey(key) {
- return typeof key === "symbol"
- ? `Symbol${key.description[7].toUpperCase()}${key.description.slice(8)}`
- : `${key[0].toUpperCase()}${key.slice(1)}`;
- }
-
- function copyAccessor(dest, prefix, key, { enumerable, get, set }) {
- ReflectDefineProperty(dest, `${prefix}Get${key}`, {
- value: uncurryThis(get),
- enumerable,
- });
- if (set !== undefined) {
- ReflectDefineProperty(dest, `${prefix}Set${key}`, {
- value: uncurryThis(set),
- enumerable,
- });
- }
- }
-
- function copyPropsRenamed(src, dest, prefix) {
- for (const key of ReflectOwnKeys(src)) {
- const newKey = getNewKey(key);
- const desc = ReflectGetOwnPropertyDescriptor(src, key);
- if ("get" in desc) {
- copyAccessor(dest, prefix, newKey, desc);
- } else {
- const name = `${prefix}${newKey}`;
- ReflectDefineProperty(dest, name, desc);
- if (varargsMethods.includes(name)) {
- ReflectDefineProperty(dest, `${name}Apply`, {
- // `src` is bound as the `this` so that the static `this` points
- // to the object it was defined on,
- // e.g.: `ArrayOfApply` gets a `this` of `Array`:
- value: applyBind(desc.value, src),
- });
- }
- }
- }
- }
-
- function copyPropsRenamedBound(src, dest, prefix) {
- for (const key of ReflectOwnKeys(src)) {
- const newKey = getNewKey(key);
- const desc = ReflectGetOwnPropertyDescriptor(src, key);
- if ("get" in desc) {
- copyAccessor(dest, prefix, newKey, desc);
- } else {
- const { value } = desc;
- if (typeof value === "function") {
- desc.value = value.bind(src);
- }
-
- const name = `${prefix}${newKey}`;
- ReflectDefineProperty(dest, name, desc);
- if (varargsMethods.includes(name)) {
- ReflectDefineProperty(dest, `${name}Apply`, {
- value: applyBind(value, src),
- });
- }
- }
- }
- }
-
- function copyPrototype(src, dest, prefix) {
- for (const key of ReflectOwnKeys(src)) {
- const newKey = getNewKey(key);
- const desc = ReflectGetOwnPropertyDescriptor(src, key);
- if ("get" in desc) {
- copyAccessor(dest, prefix, newKey, desc);
- } else {
- const { value } = desc;
- if (typeof value === "function") {
- desc.value = uncurryThis(value);
- }
-
- const name = `${prefix}${newKey}`;
- ReflectDefineProperty(dest, name, desc);
- if (varargsMethods.includes(name)) {
- ReflectDefineProperty(dest, `${name}Apply`, {
- value: applyBind(value),
- });
- }
- }
- }
- }
-
- // Create copies of configurable value properties of the global object
- [
- "Proxy",
- "globalThis",
- ].forEach((name) => {
- primordials[name] = globalThis[name];
- });
-
- // Create copy of isNaN
- primordials[isNaN.name] = isNaN;
-
- // Create copies of URI handling functions
- [
- decodeURI,
- decodeURIComponent,
- encodeURI,
- encodeURIComponent,
- ].forEach((fn) => {
- primordials[fn.name] = fn;
- });
-
- // Create copies of the namespace objects
- [
- "JSON",
- "Math",
- "Proxy",
- "Reflect",
- ].forEach((name) => {
- copyPropsRenamed(globalThis[name], primordials, name);
- });
-
- // Create copies of intrinsic objects
- [
- "AggregateError",
- "Array",
- "ArrayBuffer",
- "BigInt",
- "BigInt64Array",
- "BigUint64Array",
- "Boolean",
- "DataView",
- "Date",
- "Error",
- "EvalError",
- "FinalizationRegistry",
- "Float32Array",
- "Float64Array",
- "Function",
- "Int16Array",
- "Int32Array",
- "Int8Array",
- "Map",
- "Number",
- "Object",
- "RangeError",
- "ReferenceError",
- "RegExp",
- "Set",
- "String",
- "Symbol",
- "SyntaxError",
- "TypeError",
- "URIError",
- "Uint16Array",
- "Uint32Array",
- "Uint8Array",
- "Uint8ClampedArray",
- "WeakMap",
- "WeakRef",
- "WeakSet",
- ].forEach((name) => {
- const original = globalThis[name];
- primordials[name] = original;
- copyPropsRenamed(original, primordials, name);
- copyPrototype(original.prototype, primordials, `${name}Prototype`);
- });
-
- // Create copies of intrinsic objects that require a valid `this` to call
- // static methods.
- // Refs: https://www.ecma-international.org/ecma-262/#sec-promise.all
- [
- "Promise",
- ].forEach((name) => {
- const original = globalThis[name];
- primordials[name] = original;
- copyPropsRenamedBound(original, primordials, name);
- copyPrototype(original.prototype, primordials, `${name}Prototype`);
- });
-
- // Create copies of abstract intrinsic objects that are not directly exposed
- // on the global object.
- // Refs: https://tc39.es/ecma262/#sec-%typedarray%-intrinsic-object
- [
- { name: "TypedArray", original: Reflect.getPrototypeOf(Uint8Array) },
- {
- name: "ArrayIterator",
- original: {
- prototype: Reflect.getPrototypeOf(Array.prototype[Symbol.iterator]()),
- },
- },
- {
- name: "SetIterator",
- original: {
- prototype: Reflect.getPrototypeOf(new Set()[Symbol.iterator]()),
- },
- },
- {
- name: "MapIterator",
- original: {
- prototype: Reflect.getPrototypeOf(new Map()[Symbol.iterator]()),
- },
- },
- {
- name: "StringIterator",
- original: {
- prototype: Reflect.getPrototypeOf(String.prototype[Symbol.iterator]()),
- },
- },
- { name: "Generator", original: Reflect.getPrototypeOf(function* () {}) },
- {
- name: "AsyncGenerator",
- original: Reflect.getPrototypeOf(async function* () {}),
- },
- ].forEach(({ name, original }) => {
- primordials[name] = original;
- // The static %TypedArray% methods require a valid `this`, but can't be bound,
- // as they need a subclass constructor as the receiver:
- copyPrototype(original, primordials, name);
- copyPrototype(original.prototype, primordials, `${name}Prototype`);
- });
-
- const {
- ArrayPrototypeForEach,
- ArrayPrototypeJoin,
- ArrayPrototypeMap,
- FunctionPrototypeCall,
- ObjectDefineProperty,
- ObjectFreeze,
- ObjectPrototypeIsPrototypeOf,
- ObjectSetPrototypeOf,
- Promise,
- PromisePrototype,
- PromisePrototypeThen,
- SymbolIterator,
- TypedArrayPrototypeJoin,
- } = primordials;
-
- // Because these functions are used by `makeSafe`, which is exposed
- // on the `primordials` object, it's important to use const references
- // to the primordials that they use:
- const createSafeIterator = (factory, next) => {
- class SafeIterator {
- constructor(iterable) {
- this._iterator = factory(iterable);
- }
- next() {
- return next(this._iterator);
- }
- [SymbolIterator]() {
- return this;
- }
- }
- ObjectSetPrototypeOf(SafeIterator.prototype, null);
- ObjectFreeze(SafeIterator.prototype);
- ObjectFreeze(SafeIterator);
- return SafeIterator;
- };
-
- const SafeArrayIterator = createSafeIterator(
- primordials.ArrayPrototypeSymbolIterator,
- primordials.ArrayIteratorPrototypeNext,
- );
- primordials.SafeArrayIterator = SafeArrayIterator;
- primordials.SafeSetIterator = createSafeIterator(
- primordials.SetPrototypeSymbolIterator,
- primordials.SetIteratorPrototypeNext,
- );
- primordials.SafeMapIterator = createSafeIterator(
- primordials.MapPrototypeSymbolIterator,
- primordials.MapIteratorPrototypeNext,
- );
- primordials.SafeStringIterator = createSafeIterator(
- primordials.StringPrototypeSymbolIterator,
- primordials.StringIteratorPrototypeNext,
- );
-
- const copyProps = (src, dest) => {
- ArrayPrototypeForEach(ReflectOwnKeys(src), (key) => {
- if (!ReflectGetOwnPropertyDescriptor(dest, key)) {
- ReflectDefineProperty(
- dest,
- key,
- ReflectGetOwnPropertyDescriptor(src, key),
- );
- }
- });
- };
-
- /**
- * @type {typeof primordials.makeSafe}
- */
- const makeSafe = (unsafe, safe) => {
- if (SymbolIterator in unsafe.prototype) {
- const dummy = new unsafe();
- let next; // We can reuse the same `next` method.
-
- ArrayPrototypeForEach(ReflectOwnKeys(unsafe.prototype), (key) => {
- if (!ReflectGetOwnPropertyDescriptor(safe.prototype, key)) {
- const desc = ReflectGetOwnPropertyDescriptor(unsafe.prototype, key);
- if (
- typeof desc.value === "function" &&
- desc.value.length === 0 &&
- SymbolIterator in (FunctionPrototypeCall(desc.value, dummy) ?? {})
- ) {
- const createIterator = uncurryThis(desc.value);
- next ??= uncurryThis(createIterator(dummy).next);
- const SafeIterator = createSafeIterator(createIterator, next);
- desc.value = function () {
- return new SafeIterator(this);
- };
- }
- ReflectDefineProperty(safe.prototype, key, desc);
- }
- });
- } else {
- copyProps(unsafe.prototype, safe.prototype);
- }
- copyProps(unsafe, safe);
-
- ObjectSetPrototypeOf(safe.prototype, null);
- ObjectFreeze(safe.prototype);
- ObjectFreeze(safe);
- return safe;
- };
- primordials.makeSafe = makeSafe;
-
- // Subclass the constructors because we need to use their prototype
- // methods later.
- // Defining the `constructor` is necessary here to avoid the default
- // constructor which uses the user-mutable `%ArrayIteratorPrototype%.next`.
- primordials.SafeMap = makeSafe(
- Map,
- class SafeMap extends Map {
- constructor(i) {
- if (i == null) {
- super();
- return;
- }
- super(new SafeArrayIterator(i));
- }
- },
- );
- primordials.SafeWeakMap = makeSafe(
- WeakMap,
- class SafeWeakMap extends WeakMap {
- constructor(i) {
- if (i == null) {
- super();
- return;
- }
- super(new SafeArrayIterator(i));
- }
- },
- );
-
- primordials.SafeSet = makeSafe(
- Set,
- class SafeSet extends Set {
- constructor(i) {
- if (i == null) {
- super();
- return;
- }
- super(new SafeArrayIterator(i));
- }
- },
- );
- primordials.SafeWeakSet = makeSafe(
- WeakSet,
- class SafeWeakSet extends WeakSet {
- constructor(i) {
- if (i == null) {
- super();
- return;
- }
- super(new SafeArrayIterator(i));
- }
- },
- );
-
- primordials.SafeRegExp = makeSafe(
- RegExp,
- class SafeRegExp extends RegExp {
- constructor(pattern, flags) {
- super(pattern, flags);
- }
- },
- );
-
- primordials.SafeFinalizationRegistry = makeSafe(
- FinalizationRegistry,
- class SafeFinalizationRegistry extends FinalizationRegistry {
- constructor(cleanupCallback) {
- super(cleanupCallback);
- }
- },
- );
-
- primordials.SafeWeakRef = makeSafe(
- WeakRef,
- class SafeWeakRef extends WeakRef {
- constructor(target) {
- super(target);
- }
- },
- );
-
- const SafePromise = makeSafe(
- Promise,
- class SafePromise extends Promise {
- constructor(executor) {
- super(executor);
- }
- },
- );
-
- primordials.ArrayPrototypeToString = (thisArray) =>
- ArrayPrototypeJoin(thisArray);
-
- primordials.TypedArrayPrototypeToString = (thisArray) =>
- TypedArrayPrototypeJoin(thisArray);
-
- primordials.PromisePrototypeCatch = (thisPromise, onRejected) =>
- PromisePrototypeThen(thisPromise, undefined, onRejected);
-
- const arrayToSafePromiseIterable = (array) =>
- new SafeArrayIterator(
- ArrayPrototypeMap(
- array,
- (p) => {
- if (ObjectPrototypeIsPrototypeOf(PromisePrototype, p)) {
- return new SafePromise((c, d) => PromisePrototypeThen(p, c, d));
- }
- return p;
- },
- ),
- );
-
- /**
- * Creates a Promise that is resolved with an array of results when all of the
- * provided Promises resolve, or rejected when any Promise is rejected.
- * @template T
- * @param {Array<T | PromiseLike<T>>} values
- * @returns {Promise<Awaited<T>[]>}
- */
- primordials.SafePromiseAll = (values) =>
- // Wrapping on a new Promise is necessary to not expose the SafePromise
- // prototype to user-land.
- new Promise((a, b) =>
- SafePromise.all(arrayToSafePromiseIterable(values)).then(a, b)
- );
-
- // NOTE: Uncomment the following functions when you need to use them
-
- // /**
- // * Creates a Promise that is resolved with an array of results when all
- // * of the provided Promises resolve or reject.
- // * @template T
- // * @param {Array<T | PromiseLike<T>>} values
- // * @returns {Promise<PromiseSettledResult<T>[]>}
- // */
- // primordials.SafePromiseAllSettled = (values) =>
- // // Wrapping on a new Promise is necessary to not expose the SafePromise
- // // prototype to user-land.
- // new Promise((a, b) =>
- // SafePromise.allSettled(arrayToSafePromiseIterable(values)).then(a, b)
- // );
-
- // /**
- // * The any function returns a promise that is fulfilled by the first given
- // * promise to be fulfilled, or rejected with an AggregateError containing
- // * an array of rejection reasons if all of the given promises are rejected.
- // * It resolves all elements of the passed iterable to promises as it runs
- // * this algorithm.
- // * @template T
- // * @param {T} values
- // * @returns {Promise<Awaited<T[number]>>}
- // */
- // primordials.SafePromiseAny = (values) =>
- // // Wrapping on a new Promise is necessary to not expose the SafePromise
- // // prototype to user-land.
- // new Promise((a, b) =>
- // SafePromise.any(arrayToSafePromiseIterable(values)).then(a, b)
- // );
-
- // /**
- // * Creates a Promise that is resolved or rejected when any of the provided
- // * Promises are resolved or rejected.
- // * @template T
- // * @param {T} values
- // * @returns {Promise<Awaited<T[number]>>}
- // */
- // primordials.SafePromiseRace = (values) =>
- // // Wrapping on a new Promise is necessary to not expose the SafePromise
- // // prototype to user-land.
- // new Promise((a, b) =>
- // SafePromise.race(arrayToSafePromiseIterable(values)).then(a, b)
- // );
-
- /**
- * Attaches a callback that is invoked when the Promise is settled (fulfilled or
- * rejected). The resolved value cannot be modified from the callback.
- * Prefer using async functions when possible.
- * @param {Promise<any>} thisPromise
- * @param {() => void) | undefined | null} onFinally The callback to execute
- * when the Promise is settled (fulfilled or rejected).
- * @returns A Promise for the completion of the callback.
- */
- primordials.SafePromisePrototypeFinally = (thisPromise, onFinally) =>
- // Wrapping on a new Promise is necessary to not expose the SafePromise
- // prototype to user-land.
- new Promise((a, b) =>
- new SafePromise((a, b) => PromisePrototypeThen(thisPromise, a, b))
- .finally(onFinally)
- .then(a, b)
- );
-
- // Create getter and setter for `queueMicrotask`, it hasn't been bound yet.
- let queueMicrotask = undefined;
- ObjectDefineProperty(primordials, "queueMicrotask", {
- get() {
- return queueMicrotask;
- },
- });
- primordials.setQueueMicrotask = (value) => {
- if (queueMicrotask !== undefined) {
- throw new Error("queueMicrotask is already defined");
- }
- queueMicrotask = value;
- };
-
- // Renaming from `eval` is necessary because otherwise it would perform direct
- // evaluation, allowing user-land access to local variables.
- // This is because the identifier `eval` is somewhat treated as a keyword
- primordials.indirectEval = eval;
-
- ObjectSetPrototypeOf(primordials, null);
- ObjectFreeze(primordials);
-
- // Provide bootstrap namespace
- globalThis.__bootstrap = { primordials };
-})();
diff --git a/core/01_core.js b/core/01_core.js
deleted file mode 100644
index 674e772ae..000000000
--- a/core/01_core.js
+++ /dev/null
@@ -1,878 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-"use strict";
-
-((window) => {
- const {
- Array,
- ArrayPrototypeFill,
- ArrayPrototypeMap,
- ArrayPrototypePush,
- Error,
- ErrorCaptureStackTrace,
- MapPrototypeDelete,
- MapPrototypeGet,
- MapPrototypeHas,
- MapPrototypeSet,
- ObjectAssign,
- ObjectDefineProperty,
- ObjectFreeze,
- ObjectFromEntries,
- ObjectKeys,
- Promise,
- PromiseReject,
- PromiseResolve,
- PromisePrototypeThen,
- Proxy,
- RangeError,
- ReferenceError,
- ReflectHas,
- ReflectApply,
- SafeArrayIterator,
- SafeMap,
- SafePromisePrototypeFinally,
- StringPrototypeSlice,
- StringPrototypeSplit,
- SymbolFor,
- SyntaxError,
- TypeError,
- URIError,
- setQueueMicrotask,
- } = window.__bootstrap.primordials;
- const { ops, asyncOps } = window.Deno.core;
-
- const build = {
- target: "unknown",
- arch: "unknown",
- os: "unknown",
- vendor: "unknown",
- env: undefined,
- };
-
- function setBuildInfo(target) {
- const { 0: arch, 1: vendor, 2: os, 3: env } = StringPrototypeSplit(
- target,
- "-",
- 4,
- );
- build.target = target;
- build.arch = arch;
- build.vendor = vendor;
- build.os = os;
- build.env = env;
- ObjectFreeze(build);
- }
-
- const errorMap = {};
- // Builtin v8 / JS errors
- registerErrorClass("Error", Error);
- registerErrorClass("RangeError", RangeError);
- registerErrorClass("ReferenceError", ReferenceError);
- registerErrorClass("SyntaxError", SyntaxError);
- registerErrorClass("TypeError", TypeError);
- registerErrorClass("URIError", URIError);
-
- let nextPromiseId = 1;
- const promiseMap = new SafeMap();
- const RING_SIZE = 4 * 1024;
- const NO_PROMISE = null; // Alias to null is faster than plain nulls
- const promiseRing = ArrayPrototypeFill(new Array(RING_SIZE), NO_PROMISE);
- // TODO(bartlomieju): it future use `v8::Private` so it's not visible
- // to users. Currently missing bindings.
- const promiseIdSymbol = SymbolFor("Deno.core.internalPromiseId");
-
- let opCallTracingEnabled = false;
- const opCallTraces = new SafeMap();
-
- function enableOpCallTracing() {
- opCallTracingEnabled = true;
- }
-
- function isOpCallTracingEnabled() {
- return opCallTracingEnabled;
- }
-
- function movePromise(promiseId) {
- const idx = promiseId % RING_SIZE;
- // Move old promise from ring to map
- const oldPromise = promiseRing[idx];
- if (oldPromise !== NO_PROMISE) {
- const oldPromiseId = promiseId - RING_SIZE;
- MapPrototypeSet(promiseMap, oldPromiseId, oldPromise);
- }
- return promiseRing[idx] = NO_PROMISE;
- }
-
- function setPromise(promiseId) {
- const idx = promiseId % RING_SIZE;
- // Move old promise from ring to map
- const oldPromise = promiseRing[idx];
- if (oldPromise !== NO_PROMISE) {
- const oldPromiseId = promiseId - RING_SIZE;
- MapPrototypeSet(promiseMap, oldPromiseId, oldPromise);
- }
- // Set new promise
- return promiseRing[idx] = newPromise();
- }
-
- function getPromise(promiseId) {
- // Check if out of ring bounds, fallback to map
- const outOfBounds = promiseId < nextPromiseId - RING_SIZE;
- if (outOfBounds) {
- const promise = MapPrototypeGet(promiseMap, promiseId);
- MapPrototypeDelete(promiseMap, promiseId);
- return promise;
- }
- // Otherwise take from ring
- const idx = promiseId % RING_SIZE;
- const promise = promiseRing[idx];
- promiseRing[idx] = NO_PROMISE;
- return promise;
- }
-
- function newPromise() {
- let resolve, reject;
- const promise = new Promise((resolve_, reject_) => {
- resolve = resolve_;
- reject = reject_;
- });
- promise.resolve = resolve;
- promise.reject = reject;
- return promise;
- }
-
- function hasPromise(promiseId) {
- // Check if out of ring bounds, fallback to map
- const outOfBounds = promiseId < nextPromiseId - RING_SIZE;
- if (outOfBounds) {
- return MapPrototypeHas(promiseMap, promiseId);
- }
- // Otherwise check it in ring
- const idx = promiseId % RING_SIZE;
- return promiseRing[idx] != NO_PROMISE;
- }
-
- const macrotaskCallbacks = [];
- const nextTickCallbacks = [];
-
- function setMacrotaskCallback(cb) {
- ArrayPrototypePush(macrotaskCallbacks, cb);
- }
-
- function setNextTickCallback(cb) {
- ArrayPrototypePush(nextTickCallbacks, cb);
- }
-
- // This function has variable number of arguments. The last argument describes
- // if there's a "next tick" scheduled by the Node.js compat layer. Arguments
- // before last are alternating integers and any values that describe the
- // responses of async ops.
- function eventLoopTick() {
- // First respond to all pending ops.
- for (let i = 0; i < arguments.length - 1; i += 2) {
- const promiseId = arguments[i];
- const res = arguments[i + 1];
- const promise = getPromise(promiseId);
- promise.resolve(res);
- }
- // Drain nextTick queue if there's a tick scheduled.
- if (arguments[arguments.length - 1]) {
- for (let i = 0; i < nextTickCallbacks.length; i++) {
- nextTickCallbacks[i]();
- }
- } else {
- ops.op_run_microtasks();
- }
- // Finally drain macrotask queue.
- for (let i = 0; i < macrotaskCallbacks.length; i++) {
- const cb = macrotaskCallbacks[i];
- while (true) {
- const res = cb();
-
- // If callback returned `undefined` then it has no work to do, we don't
- // need to perform microtask checkpoint.
- if (res === undefined) {
- break;
- }
-
- ops.op_run_microtasks();
- // If callback returned `true` then it has no more work to do, stop
- // calling it then.
- if (res === true) {
- break;
- }
- }
- }
- }
-
- function registerErrorClass(className, errorClass) {
- registerErrorBuilder(className, (msg) => new errorClass(msg));
- }
-
- function registerErrorBuilder(className, errorBuilder) {
- if (typeof errorMap[className] !== "undefined") {
- throw new TypeError(`Error class for "${className}" already registered`);
- }
- errorMap[className] = errorBuilder;
- }
-
- function buildCustomError(className, message, code) {
- let error;
- try {
- error = errorMap[className]?.(message);
- } catch (e) {
- throw new Error(
- `Unable to build custom error for "${className}"\n ${e.message}`,
- );
- }
- // Strip buildCustomError() calls from stack trace
- if (typeof error == "object") {
- ErrorCaptureStackTrace(error, buildCustomError);
- if (code) {
- error.code = code;
- }
- }
- return error;
- }
-
- function unwrapOpError(hideFunction) {
- return (res) => {
- // .$err_class_name is a special key that should only exist on errors
- const className = res?.$err_class_name;
- if (!className) {
- return res;
- }
-
- const errorBuilder = errorMap[className];
- const err = errorBuilder ? errorBuilder(res.message) : new Error(
- `Unregistered error class: "${className}"\n ${res.message}\n Classes of errors returned from ops should be registered via Deno.core.registerErrorClass().`,
- );
- // Set .code if error was a known OS error, see error_codes.rs
- if (res.code) {
- err.code = res.code;
- }
- // Strip unwrapOpResult() and errorBuilder() calls from stack trace
- ErrorCaptureStackTrace(err, hideFunction);
- throw err;
- };
- }
-
- function unwrapOpResultNewPromise(id, res, hideFunction) {
- // .$err_class_name is a special key that should only exist on errors
- if (res?.$err_class_name) {
- const className = res.$err_class_name;
- const errorBuilder = errorMap[className];
- const err = errorBuilder ? errorBuilder(res.message) : new Error(
- `Unregistered error class: "${className}"\n ${res.message}\n Classes of errors returned from ops should be registered via Deno.core.registerErrorClass().`,
- );
- // Set .code if error was a known OS error, see error_codes.rs
- if (res.code) {
- err.code = res.code;
- }
- // Strip unwrapOpResult() and errorBuilder() calls from stack trace
- ErrorCaptureStackTrace(err, hideFunction);
- return PromiseReject(err);
- }
- const promise = PromiseResolve(res);
- promise[promiseIdSymbol] = id;
- return promise;
- }
-
- /*
-Basic codegen.
-
-TODO(mmastrac): automate this (handlebars?)
-
-let s = "";
-const vars = "abcdefghijklm";
-for (let i = 0; i < 10; i++) {
- let args = "";
- for (let j = 0; j < i; j++) {
- args += `${vars[j]},`;
- }
- s += `
- case ${i}:
- fn = function async_op_${i}(${args}) {
- const id = nextPromiseId++;
- try {
- const maybeResult = originalOp(id, ${args});
- if (maybeResult !== undefined) {
- movePromise(id);
- return unwrapOpResultNewPromise(id, maybeResult, async_op_${i});
- }
- } catch (err) {
- movePromise(id);
- ErrorCaptureStackTrace(err, async_op_${i});
- return PromiseReject(err);
- }
- let promise = PromisePrototypeThen(setPromise(id), unwrapOpError(eventLoopTick));
- promise = handleOpCallTracing(opName, id, promise);
- promise[promiseIdSymbol] = id;
- return promise;
- };
- break;
- `;
-}
- */
-
- // This function is called once per async stub
- function asyncStub(opName, args) {
- setUpAsyncStub(opName);
- return ReflectApply(ops[opName], undefined, args);
- }
-
- function setUpAsyncStub(opName) {
- const originalOp = asyncOps[opName];
- let fn;
- // The body of this switch statement can be generated using the script above.
- switch (originalOp.length - 1) {
- case 0:
- fn = function async_op_0() {
- const id = nextPromiseId++;
- try {
- const maybeResult = originalOp(id);
- if (maybeResult !== undefined) {
- movePromise(id);
- return unwrapOpResultNewPromise(id, maybeResult, async_op_0);
- }
- } catch (err) {
- movePromise(id);
- ErrorCaptureStackTrace(err, async_op_0);
- return PromiseReject(err);
- }
- let promise = PromisePrototypeThen(
- setPromise(id),
- unwrapOpError(eventLoopTick),
- );
- promise = handleOpCallTracing(opName, id, promise);
- promise[promiseIdSymbol] = id;
- return promise;
- };
- break;
-
- case 1:
- fn = function async_op_1(a) {
- const id = nextPromiseId++;
- try {
- const maybeResult = originalOp(id, a);
- if (maybeResult !== undefined) {
- movePromise(id);
- return unwrapOpResultNewPromise(id, maybeResult, async_op_1);
- }
- } catch (err) {
- movePromise(id);
- ErrorCaptureStackTrace(err, async_op_1);
- return PromiseReject(err);
- }
- let promise = PromisePrototypeThen(
- setPromise(id),
- unwrapOpError(eventLoopTick),
- );
- promise = handleOpCallTracing(opName, id, promise);
- promise[promiseIdSymbol] = id;
- return promise;
- };
- break;
-
- case 2:
- fn = function async_op_2(a, b) {
- const id = nextPromiseId++;
- try {
- const maybeResult = originalOp(id, a, b);
- if (maybeResult !== undefined) {
- movePromise(id);
- return unwrapOpResultNewPromise(id, maybeResult, async_op_2);
- }
- } catch (err) {
- movePromise(id);
- ErrorCaptureStackTrace(err, async_op_2);
- return PromiseReject(err);
- }
- let promise = PromisePrototypeThen(
- setPromise(id),
- unwrapOpError(eventLoopTick),
- );
- promise = handleOpCallTracing(opName, id, promise);
- promise[promiseIdSymbol] = id;
- return promise;
- };
- break;
-
- case 3:
- fn = function async_op_3(a, b, c) {
- const id = nextPromiseId++;
- try {
- const maybeResult = originalOp(id, a, b, c);
- if (maybeResult !== undefined) {
- movePromise(id);
- return unwrapOpResultNewPromise(id, maybeResult, async_op_3);
- }
- } catch (err) {
- movePromise(id);
- ErrorCaptureStackTrace(err, async_op_3);
- return PromiseReject(err);
- }
- let promise = PromisePrototypeThen(
- setPromise(id),
- unwrapOpError(eventLoopTick),
- );
- promise = handleOpCallTracing(opName, id, promise);
- promise[promiseIdSymbol] = id;
- return promise;
- };
- break;
-
- case 4:
- fn = function async_op_4(a, b, c, d) {
- const id = nextPromiseId++;
- try {
- const maybeResult = originalOp(id, a, b, c, d);
- if (maybeResult !== undefined) {
- movePromise(id);
- return unwrapOpResultNewPromise(id, maybeResult, async_op_4);
- }
- } catch (err) {
- movePromise(id);
- ErrorCaptureStackTrace(err, async_op_4);
- return PromiseReject(err);
- }
- let promise = PromisePrototypeThen(
- setPromise(id),
- unwrapOpError(eventLoopTick),
- );
- promise = handleOpCallTracing(opName, id, promise);
- promise[promiseIdSymbol] = id;
- return promise;
- };
- break;
-
- case 5:
- fn = function async_op_5(a, b, c, d, e) {
- const id = nextPromiseId++;
- try {
- const maybeResult = originalOp(id, a, b, c, d, e);
- if (maybeResult !== undefined) {
- movePromise(id);
- return unwrapOpResultNewPromise(id, maybeResult, async_op_5);
- }
- } catch (err) {
- movePromise(id);
- ErrorCaptureStackTrace(err, async_op_5);
- return PromiseReject(err);
- }
- let promise = PromisePrototypeThen(
- setPromise(id),
- unwrapOpError(eventLoopTick),
- );
- promise = handleOpCallTracing(opName, id, promise);
- promise[promiseIdSymbol] = id;
- return promise;
- };
- break;
-
- case 6:
- fn = function async_op_6(a, b, c, d, e, f) {
- const id = nextPromiseId++;
- try {
- const maybeResult = originalOp(id, a, b, c, d, e, f);
- if (maybeResult !== undefined) {
- movePromise(id);
- return unwrapOpResultNewPromise(id, maybeResult, async_op_6);
- }
- } catch (err) {
- movePromise(id);
- ErrorCaptureStackTrace(err, async_op_6);
- return PromiseReject(err);
- }
- let promise = PromisePrototypeThen(
- setPromise(id),
- unwrapOpError(eventLoopTick),
- );
- promise = handleOpCallTracing(opName, id, promise);
- promise[promiseIdSymbol] = id;
- return promise;
- };
- break;
-
- case 7:
- fn = function async_op_7(a, b, c, d, e, f, g) {
- const id = nextPromiseId++;
- try {
- const maybeResult = originalOp(id, a, b, c, d, e, f, g);
- if (maybeResult !== undefined) {
- movePromise(id);
- return unwrapOpResultNewPromise(id, maybeResult, async_op_7);
- }
- } catch (err) {
- movePromise(id);
- ErrorCaptureStackTrace(err, async_op_7);
- return PromiseReject(err);
- }
- let promise = PromisePrototypeThen(
- setPromise(id),
- unwrapOpError(eventLoopTick),
- );
- promise = handleOpCallTracing(opName, id, promise);
- promise[promiseIdSymbol] = id;
- return promise;
- };
- break;
-
- case 8:
- fn = function async_op_8(a, b, c, d, e, f, g, h) {
- const id = nextPromiseId++;
- try {
- const maybeResult = originalOp(id, a, b, c, d, e, f, g, h);
- if (maybeResult !== undefined) {
- movePromise(id);
- return unwrapOpResultNewPromise(id, maybeResult, async_op_8);
- }
- } catch (err) {
- movePromise(id);
- ErrorCaptureStackTrace(err, async_op_8);
- return PromiseReject(err);
- }
- let promise = PromisePrototypeThen(
- setPromise(id),
- unwrapOpError(eventLoopTick),
- );
- promise = handleOpCallTracing(opName, id, promise);
- promise[promiseIdSymbol] = id;
- return promise;
- };
- break;
-
- case 9:
- fn = function async_op_9(a, b, c, d, e, f, g, h, i) {
- const id = nextPromiseId++;
- try {
- const maybeResult = originalOp(id, a, b, c, d, e, f, g, h, i);
- if (maybeResult !== undefined) {
- movePromise(id);
- return unwrapOpResultNewPromise(id, maybeResult, async_op_9);
- }
- } catch (err) {
- movePromise(id);
- ErrorCaptureStackTrace(err, async_op_9);
- return PromiseReject(err);
- }
- let promise = PromisePrototypeThen(
- setPromise(id),
- unwrapOpError(eventLoopTick),
- );
- promise = handleOpCallTracing(opName, id, promise);
- promise[promiseIdSymbol] = id;
- return promise;
- };
- break;
-
- default:
- throw new Error(
- `Too many arguments for async op codegen (length of ${opName} was ${
- originalOp.length - 1
- })`,
- );
- }
- ObjectDefineProperty(fn, "name", {
- value: opName,
- configurable: false,
- writable: false,
- });
- return (ops[opName] = fn);
- }
-
- function opAsync(name, ...args) {
- const id = nextPromiseId++;
- try {
- const maybeResult = asyncOps[name](id, ...new SafeArrayIterator(args));
- if (maybeResult !== undefined) {
- movePromise(id);
- return unwrapOpResultNewPromise(id, maybeResult, opAsync);
- }
- } catch (err) {
- movePromise(id);
- if (!ReflectHas(asyncOps, name)) {
- return PromiseReject(new TypeError(`${name} is not a registered op`));
- }
- ErrorCaptureStackTrace(err, opAsync);
- return PromiseReject(err);
- }
- let promise = PromisePrototypeThen(
- setPromise(id),
- unwrapOpError(eventLoopTick),
- );
- promise = handleOpCallTracing(name, id, promise);
- promise[promiseIdSymbol] = id;
- return promise;
- }
-
- function handleOpCallTracing(opName, promiseId, p) {
- if (opCallTracingEnabled) {
- const stack = StringPrototypeSlice(new Error().stack, 6);
- MapPrototypeSet(opCallTraces, promiseId, { opName, stack });
- return SafePromisePrototypeFinally(
- p,
- () => MapPrototypeDelete(opCallTraces, promiseId),
- );
- } else {
- return p;
- }
- }
-
- function refOp(promiseId) {
- if (!hasPromise(promiseId)) {
- return;
- }
- ops.op_ref_op(promiseId);
- }
-
- function unrefOp(promiseId) {
- if (!hasPromise(promiseId)) {
- return;
- }
- ops.op_unref_op(promiseId);
- }
-
- function resources() {
- return ObjectFromEntries(ops.op_resources());
- }
-
- function metrics() {
- const { 0: aggregate, 1: perOps } = ops.op_metrics();
- aggregate.ops = ObjectFromEntries(ArrayPrototypeMap(
- ops.op_op_names(),
- (opName, opId) => [opName, perOps[opId]],
- ));
- return aggregate;
- }
-
- let reportExceptionCallback = undefined;
-
- // Used to report errors thrown from functions passed to `queueMicrotask()`.
- // The callback will be passed the thrown error. For example, you can use this
- // to dispatch an error event to the global scope.
- // In other words, set the implementation for
- // https://html.spec.whatwg.org/multipage/webappapis.html#report-the-exception
- function setReportExceptionCallback(cb) {
- if (typeof cb != "function") {
- throw new TypeError("expected a function");
- }
- reportExceptionCallback = cb;
- }
-
- function queueMicrotask(cb) {
- if (typeof cb != "function") {
- throw new TypeError("expected a function");
- }
- return ops.op_queue_microtask(() => {
- try {
- cb();
- } catch (error) {
- if (reportExceptionCallback) {
- reportExceptionCallback(error);
- } else {
- throw error;
- }
- }
- });
- }
-
- // Some "extensions" rely on "BadResource" and "Interrupted" errors in the
- // JS code (eg. "deno_net") so they are provided in "Deno.core" but later
- // reexported on "Deno.errors"
- class BadResource extends Error {
- constructor(msg) {
- super(msg);
- this.name = "BadResource";
- }
- }
- const BadResourcePrototype = BadResource.prototype;
-
- class Interrupted extends Error {
- constructor(msg) {
- super(msg);
- this.name = "Interrupted";
- }
- }
- const InterruptedPrototype = Interrupted.prototype;
-
- const promiseHooks = [
- [], // init
- [], // before
- [], // after
- [], // resolve
- ];
-
- function setPromiseHooks(init, before, after, resolve) {
- const hooks = [init, before, after, resolve];
- for (let i = 0; i < hooks.length; i++) {
- const hook = hooks[i];
- // Skip if no callback was provided for this hook type.
- if (hook == null) {
- continue;
- }
- // Verify that the type of `hook` is a function.
- if (typeof hook !== "function") {
- throw new TypeError(`Expected function at position ${i}`);
- }
- // Add the hook to the list.
- ArrayPrototypePush(promiseHooks[i], hook);
- }
-
- const wrappedHooks = ArrayPrototypeMap(promiseHooks, (hooks) => {
- switch (hooks.length) {
- case 0:
- return undefined;
- case 1:
- return hooks[0];
- case 2:
- return create2xHookWrapper(hooks[0], hooks[1]);
- case 3:
- return create3xHookWrapper(hooks[0], hooks[1], hooks[2]);
- default:
- return createHookListWrapper(hooks);
- }
-
- // The following functions are used to create wrapper functions that call
- // all the hooks in a list of a certain length. The reason to use a
- // function that creates a wrapper is to minimize the number of objects
- // captured in the closure.
- function create2xHookWrapper(hook1, hook2) {
- return function (promise, parent) {
- hook1(promise, parent);
- hook2(promise, parent);
- };
- }
- function create3xHookWrapper(hook1, hook2, hook3) {
- return function (promise, parent) {
- hook1(promise, parent);
- hook2(promise, parent);
- hook3(promise, parent);
- };
- }
- function createHookListWrapper(hooks) {
- return function (promise, parent) {
- for (let i = 0; i < hooks.length; i++) {
- const hook = hooks[i];
- hook(promise, parent);
- }
- };
- }
- });
-
- ops.op_set_promise_hooks(
- wrappedHooks[0],
- wrappedHooks[1],
- wrappedHooks[2],
- wrappedHooks[3],
- );
- }
-
- // Eagerly initialize ops for snapshot purposes
- for (const opName of new SafeArrayIterator(ObjectKeys(asyncOps))) {
- setUpAsyncStub(opName);
- }
-
- function ensureFastOps() {
- return new Proxy({}, {
- get(_target, opName) {
- if (ops[opName] === undefined) {
- throw new Error(`Unknown or disabled op '${opName}'`);
- }
- if (asyncOps[opName] !== undefined) {
- return setUpAsyncStub(opName);
- } else {
- return ops[opName];
- }
- },
- });
- }
-
- const {
- op_close: close,
- op_try_close: tryClose,
- op_read: read,
- op_read_all: readAll,
- op_write: write,
- op_write_all: writeAll,
- op_read_sync: readSync,
- op_write_sync: writeSync,
- op_shutdown: shutdown,
- } = ensureFastOps();
-
- // Extra Deno.core.* exports
- const core = ObjectAssign(globalThis.Deno.core, {
- asyncStub,
- ensureFastOps,
- opAsync,
- resources,
- metrics,
- registerErrorBuilder,
- registerErrorClass,
- buildCustomError,
- eventLoopTick,
- BadResource,
- BadResourcePrototype,
- Interrupted,
- InterruptedPrototype,
- enableOpCallTracing,
- isOpCallTracingEnabled,
- opCallTraces,
- refOp,
- unrefOp,
- setReportExceptionCallback,
- setPromiseHooks,
- close,
- tryClose,
- read,
- readAll,
- write,
- writeAll,
- readSync,
- writeSync,
- shutdown,
- print: (msg, isErr) => ops.op_print(msg, isErr),
- setMacrotaskCallback,
- setNextTickCallback,
- runMicrotasks: () => ops.op_run_microtasks(),
- hasTickScheduled: () => ops.op_has_tick_scheduled(),
- setHasTickScheduled: (bool) => ops.op_set_has_tick_scheduled(bool),
- evalContext: (
- source,
- specifier,
- ) => ops.op_eval_context(source, specifier),
- createHostObject: () => ops.op_create_host_object(),
- encode: (text) => ops.op_encode(text),
- decode: (buffer) => ops.op_decode(buffer),
- serialize: (
- value,
- options,
- errorCallback,
- ) => ops.op_serialize(value, options, errorCallback),
- deserialize: (buffer, options) => ops.op_deserialize(buffer, options),
- getPromiseDetails: (promise) => ops.op_get_promise_details(promise),
- getProxyDetails: (proxy) => ops.op_get_proxy_details(proxy),
- isProxy: (value) => ops.op_is_proxy(value),
- memoryUsage: () => ops.op_memory_usage(),
- setWasmStreamingCallback: (fn) => ops.op_set_wasm_streaming_callback(fn),
- abortWasmStreaming: (
- rid,
- error,
- ) => ops.op_abort_wasm_streaming(rid, error),
- destructureError: (error) => ops.op_destructure_error(error),
- opNames: () => ops.op_op_names(),
- eventLoopHasMoreWork: () => ops.op_event_loop_has_more_work(),
- setPromiseRejectCallback: (fn) => ops.op_set_promise_reject_callback(fn),
- byteLength: (str) => ops.op_str_byte_length(str),
- build,
- setBuildInfo,
- });
-
- ObjectAssign(globalThis.__bootstrap, { core });
- const internals = {};
- ObjectAssign(globalThis.__bootstrap, { internals });
- ObjectAssign(globalThis.Deno, { core });
-
- // Direct bindings on `globalThis`
- ObjectAssign(globalThis, { queueMicrotask });
- setQueueMicrotask(queueMicrotask);
-})(globalThis);
diff --git a/core/02_error.js b/core/02_error.js
deleted file mode 100644
index b29dc9b4e..000000000
--- a/core/02_error.js
+++ /dev/null
@@ -1,157 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-"use strict";
-
-((window) => {
- const core = Deno.core;
- const ops = core.ops;
- const {
- Error,
- ObjectFreeze,
- ObjectAssign,
- StringPrototypeStartsWith,
- StringPrototypeEndsWith,
- ObjectDefineProperties,
- ArrayPrototypePush,
- ArrayPrototypeMap,
- ArrayPrototypeJoin,
- } = window.__bootstrap.primordials;
-
- // Keep in sync with `cli/fmt_errors.rs`.
- function formatLocation(cse) {
- if (cse.isNative) {
- return "native";
- }
- let result = "";
- if (cse.fileName) {
- result += ops.op_format_file_name(cse.fileName);
- } else {
- if (cse.isEval) {
- if (cse.evalOrigin == null) {
- throw new Error("assert evalOrigin");
- }
- result += `${cse.evalOrigin}, `;
- }
- result += "<anonymous>";
- }
- if (cse.lineNumber != null) {
- result += `:${cse.lineNumber}`;
- if (cse.columnNumber != null) {
- result += `:${cse.columnNumber}`;
- }
- }
- return result;
- }
-
- // Keep in sync with `cli/fmt_errors.rs`.
- function formatCallSiteEval(cse) {
- let result = "";
- if (cse.isAsync) {
- result += "async ";
- }
- if (cse.isPromiseAll) {
- result += `Promise.all (index ${cse.promiseIndex})`;
- return result;
- }
- const isMethodCall = !(cse.isToplevel || cse.isConstructor);
- if (isMethodCall) {
- if (cse.functionName) {
- if (cse.typeName) {
- if (!StringPrototypeStartsWith(cse.functionName, cse.typeName)) {
- result += `${cse.typeName}.`;
- }
- }
- result += cse.functionName;
- if (cse.methodName) {
- if (!StringPrototypeEndsWith(cse.functionName, cse.methodName)) {
- result += ` [as ${cse.methodName}]`;
- }
- }
- } else {
- if (cse.typeName) {
- result += `${cse.typeName}.`;
- }
- if (cse.methodName) {
- result += cse.methodName;
- } else {
- result += "<anonymous>";
- }
- }
- } else if (cse.isConstructor) {
- result += "new ";
- if (cse.functionName) {
- result += cse.functionName;
- } else {
- result += "<anonymous>";
- }
- } else if (cse.functionName) {
- result += cse.functionName;
- } else {
- result += formatLocation(cse);
- return result;
- }
-
- result += ` (${formatLocation(cse)})`;
- return result;
- }
-
- function evaluateCallSite(callSite) {
- return {
- this: callSite.getThis(),
- typeName: callSite.getTypeName(),
- function: callSite.getFunction(),
- functionName: callSite.getFunctionName(),
- methodName: callSite.getMethodName(),
- fileName: callSite.getFileName(),
- lineNumber: callSite.getLineNumber(),
- columnNumber: callSite.getColumnNumber(),
- evalOrigin: callSite.getEvalOrigin(),
- isToplevel: callSite.isToplevel(),
- isEval: callSite.isEval(),
- isNative: callSite.isNative(),
- isConstructor: callSite.isConstructor(),
- isAsync: callSite.isAsync(),
- isPromiseAll: callSite.isPromiseAll(),
- promiseIndex: callSite.getPromiseIndex(),
- };
- }
-
- function sourceMapCallSiteEval(cse) {
- if (cse.fileName && cse.lineNumber != null && cse.columnNumber != null) {
- return { ...cse, ...ops.op_apply_source_map(cse) };
- }
- return cse;
- }
-
- /** A function that can be used as `Error.prepareStackTrace`. */
- function prepareStackTrace(error, callSites) {
- let callSiteEvals = ArrayPrototypeMap(callSites, evaluateCallSite);
- callSiteEvals = ArrayPrototypeMap(callSiteEvals, sourceMapCallSiteEval);
- ObjectDefineProperties(error, {
- __callSiteEvals: { __proto__: null, value: [], configurable: true },
- });
- const formattedCallSites = [];
- for (let i = 0; i < callSiteEvals.length; ++i) {
- const cse = callSiteEvals[i];
- ArrayPrototypePush(error.__callSiteEvals, cse);
- ArrayPrototypePush(formattedCallSites, formatCallSiteEval(cse));
- }
- const message = error.message !== undefined ? error.message : "";
- const name = error.name !== undefined ? error.name : "Error";
- let messageLine;
- if (name != "" && message != "") {
- messageLine = `${name}: ${message}`;
- } else if ((name || message) != "") {
- messageLine = name || message;
- } else {
- messageLine = "";
- }
- return messageLine +
- ArrayPrototypeJoin(
- ArrayPrototypeMap(formattedCallSites, (s) => `\n at ${s}`),
- "",
- );
- }
-
- ObjectAssign(globalThis.__bootstrap.core, { prepareStackTrace });
- ObjectFreeze(globalThis.__bootstrap.core);
-})(this);
diff --git a/core/Cargo.toml b/core/Cargo.toml
deleted file mode 100644
index e8e659726..000000000
--- a/core/Cargo.toml
+++ /dev/null
@@ -1,50 +0,0 @@
-# Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-
-[package]
-name = "deno_core"
-version = "0.191.0"
-authors.workspace = true
-edition.workspace = true
-license.workspace = true
-readme = "README.md"
-repository.workspace = true
-description = "A modern JavaScript/TypeScript runtime built with V8, Rust, and Tokio"
-
-[lib]
-path = "lib.rs"
-
-[features]
-default = ["v8_use_custom_libcxx"]
-v8_use_custom_libcxx = ["v8/use_custom_libcxx"]
-include_js_files_for_snapshotting = []
-
-[dependencies]
-anyhow.workspace = true
-bytes.workspace = true
-deno_ops.workspace = true
-futures.workspace = true
-# Stay on 1.6 to avoid a dependency cycle in ahash https://github.com/tkaitchuck/aHash/issues/95
-# Projects not depending on ahash are unaffected as cargo will pull any 1.X that is >= 1.6.
-indexmap = "1.6"
-libc.workspace = true
-log.workspace = true
-once_cell.workspace = true
-parking_lot.workspace = true
-pin-project.workspace = true
-serde.workspace = true
-serde_json = { workspace = true, features = ["preserve_order"] }
-serde_v8.workspace = true
-smallvec.workspace = true
-sourcemap = "6.1"
-tokio.workspace = true
-url.workspace = true
-v8.workspace = true
-
-[[example]]
-name = "http_bench_json_ops"
-path = "examples/http_bench_json_ops/main.rs"
-
-# These dependencies are only used for the 'http_bench_*_ops' examples.
-[dev-dependencies]
-cooked-waker = "5"
-deno_ast.workspace = true
diff --git a/core/README.md b/core/README.md
deleted file mode 100644
index 9b4f33fa0..000000000
--- a/core/README.md
+++ /dev/null
@@ -1,31 +0,0 @@
-# Deno Core Crate
-
-[![crates](https://img.shields.io/crates/v/deno_core.svg)](https://crates.io/crates/deno_core)
-[![docs](https://docs.rs/deno_core/badge.svg)](https://docs.rs/deno_core)
-
-The main dependency of this crate is
-[rusty_v8](https://github.com/denoland/rusty_v8), which provides the V8-Rust
-bindings.
-
-This Rust crate contains the essential V8 bindings for Deno's command-line
-interface (Deno CLI). The main abstraction here is the JsRuntime which provides
-a way to execute JavaScript.
-
-The JsRuntime implements an event loop abstraction for the executed code that
-keeps track of all pending tasks (async ops, dynamic module loads). It is user's
-responsibility to drive that loop by using `JsRuntime::run_event_loop` method -
-it must be executed in the context of Rust's future executor (eg. tokio, smol).
-
-Rust functions can be registered in JavaScript using `deno_core::Extension`. Use
-the `Deno.core.ops.op_name()` and `Deno.core.opAsync("op_name", ...)` functions
-to trigger the op function callback. A conventional way to write ops is using
-the [`deno_ops`](https://github.com/denoland/deno/blob/main/ops) crate.
-
-Documentation for this crate is thin at the moment. Please see
-[hello_world.rs](https://github.com/denoland/deno/blob/main/core/examples/hello_world.rs)
-and
-[http_bench_json_ops/main.rs](https://github.com/denoland/deno/blob/main/core/examples/http_bench_json_ops/main.rs)
-as examples of usage.
-
-TypeScript support and lots of other functionality are not available at this
-layer. See the [CLI](https://github.com/denoland/deno/tree/main/cli) for that.
diff --git a/core/async_cancel.rs b/core/async_cancel.rs
deleted file mode 100644
index 5573e543d..000000000
--- a/core/async_cancel.rs
+++ /dev/null
@@ -1,793 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-
-use std::any::type_name;
-use std::borrow::Cow;
-use std::error::Error;
-use std::fmt;
-use std::fmt::Display;
-use std::fmt::Formatter;
-use std::io;
-use std::pin::Pin;
-use std::rc::Rc;
-
-use futures::future::FusedFuture;
-use futures::future::Future;
-use futures::future::TryFuture;
-use futures::task::Context;
-use futures::task::Poll;
-use pin_project::pin_project;
-
-use crate::RcLike;
-use crate::Resource;
-
-use self::internal as i;
-
-#[derive(Debug, Default)]
-pub struct CancelHandle {
- node: i::Node,
-}
-
-impl CancelHandle {
- pub fn new() -> Self {
- Default::default()
- }
-
- pub fn new_rc() -> Rc<Self> {
- Rc::new(Self::new())
- }
-
- /// Cancel all cancelable futures that are bound to this handle. Note that
- /// this method does not require a mutable reference to the `CancelHandle`.
- pub fn cancel(&self) {
- self.node.cancel();
- }
-
- pub fn is_canceled(&self) -> bool {
- self.node.is_canceled()
- }
-}
-
-#[pin_project(project = CancelableProjection)]
-#[derive(Debug)]
-pub enum Cancelable<F> {
- Pending {
- #[pin]
- future: F,
- #[pin]
- registration: i::Registration,
- },
- Terminated,
-}
-
-impl<F: Future> Future for Cancelable<F> {
- type Output = Result<F::Output, Canceled>;
-
- fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
- let poll_result = match self.as_mut().project() {
- CancelableProjection::Pending {
- future,
- registration,
- } => Self::poll_pending(future, registration, cx),
- CancelableProjection::Terminated => {
- panic!("{}::poll() called after completion", type_name::<Self>())
- }
- };
- // Fuse: if this Future is completed or canceled, make sure the inner
- // `future` and `registration` fields are dropped in order to unlink it from
- // its cancel handle.
- if matches!(poll_result, Poll::Ready(_)) {
- self.set(Cancelable::Terminated)
- }
- poll_result
- }
-}
-
-impl<F: Future> FusedFuture for Cancelable<F> {
- fn is_terminated(&self) -> bool {
- matches!(self, Self::Terminated)
- }
-}
-
-impl Resource for CancelHandle {
- fn name(&self) -> Cow<str> {
- "cancellation".into()
- }
-
- fn close(self: Rc<Self>) {
- self.cancel();
- }
-}
-
-#[pin_project(project = TryCancelableProjection)]
-#[derive(Debug)]
-pub struct TryCancelable<F> {
- #[pin]
- inner: Cancelable<F>,
-}
-
-impl<F, T, E> Future for TryCancelable<F>
-where
- F: Future<Output = Result<T, E>>,
- Canceled: Into<E>,
-{
- type Output = F::Output;
-
- fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
- let TryCancelableProjection { inner } = self.project();
- match inner.poll(cx) {
- Poll::Pending => Poll::Pending,
- Poll::Ready(Ok(result)) => Poll::Ready(result),
- Poll::Ready(Err(err)) => Poll::Ready(Err(err.into())),
- }
- }
-}
-
-impl<F, T, E> FusedFuture for TryCancelable<F>
-where
- F: Future<Output = Result<T, E>>,
- Canceled: Into<E>,
-{
- fn is_terminated(&self) -> bool {
- self.inner.is_terminated()
- }
-}
-
-pub trait CancelFuture
-where
- Self: Future + Sized,
-{
- fn or_cancel<H: RcLike<CancelHandle>>(
- self,
- cancel_handle: H,
- ) -> Cancelable<Self> {
- Cancelable::new(self, cancel_handle.into())
- }
-}
-
-impl<F> CancelFuture for F where F: Future {}
-
-pub trait CancelTryFuture
-where
- Self: TryFuture + Sized,
- Canceled: Into<Self::Error>,
-{
- fn try_or_cancel<H: RcLike<CancelHandle>>(
- self,
- cancel_handle: H,
- ) -> TryCancelable<Self> {
- TryCancelable::new(self, cancel_handle.into())
- }
-}
-
-impl<F> CancelTryFuture for F
-where
- F: TryFuture,
- Canceled: Into<F::Error>,
-{
-}
-
-#[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialEq)]
-pub struct Canceled;
-
-impl Display for Canceled {
- fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
- write!(f, "operation canceled")
- }
-}
-
-impl Error for Canceled {}
-
-impl From<Canceled> for io::Error {
- fn from(_: Canceled) -> Self {
- io::Error::new(io::ErrorKind::Interrupted, Canceled)
- }
-}
-
-mod internal {
- use super::CancelHandle;
- use super::Cancelable;
- use super::Canceled;
- use super::TryCancelable;
- use crate::RcRef;
- use futures::future::Future;
- use futures::task::Context;
- use futures::task::Poll;
- use futures::task::Waker;
- use pin_project::pin_project;
- use std::any::Any;
- use std::cell::UnsafeCell;
- use std::marker::PhantomPinned;
- use std::mem::replace;
- use std::pin::Pin;
- use std::ptr::NonNull;
- use std::rc::Rc;
- use std::rc::Weak;
-
- impl<F: Future> Cancelable<F> {
- pub(super) fn new(future: F, cancel_handle: RcRef<CancelHandle>) -> Self {
- let head_node = RcRef::map(cancel_handle, |r| &r.node);
- let registration = Registration::WillRegister { head_node };
- Self::Pending {
- future,
- registration,
- }
- }
-
- pub(super) fn poll_pending(
- future: Pin<&mut F>,
- mut registration: Pin<&mut Registration>,
- cx: &mut Context,
- ) -> Poll<Result<F::Output, Canceled>> {
- // Do a cancellation check _before_ polling the inner future. If it has
- // already been canceled the inner future will not be polled.
- let node = match &*registration {
- Registration::WillRegister { head_node } => head_node,
- Registration::Registered { node } => node,
- };
- if node.is_canceled() {
- return Poll::Ready(Err(Canceled));
- }
-
- match future.poll(cx) {
- Poll::Ready(res) => return Poll::Ready(Ok(res)),
- Poll::Pending => {}
- }
-
- // Register this future with its `CancelHandle`, saving the `Waker` that
- // can be used to make the runtime poll this future when it is canceled.
- // When already registered, update the stored `Waker` if necessary.
- let head_node = match &*registration {
- Registration::WillRegister { .. } => {
- match registration.as_mut().project_replace(Default::default()) {
- RegistrationProjectionOwned::WillRegister { head_node } => {
- Some(head_node)
- }
- _ => unreachable!(),
- }
- }
- _ => None,
- };
- let node = match registration.project() {
- RegistrationProjection::Registered { node } => node,
- _ => unreachable!(),
- };
- node.register(cx.waker(), head_node)?;
-
- Poll::Pending
- }
- }
-
- impl<F: Future> TryCancelable<F> {
- pub(super) fn new(future: F, cancel_handle: RcRef<CancelHandle>) -> Self {
- Self {
- inner: Cancelable::new(future, cancel_handle),
- }
- }
- }
-
- #[pin_project(project = RegistrationProjection,
- project_replace = RegistrationProjectionOwned)]
- #[derive(Debug)]
- pub enum Registration {
- WillRegister {
- head_node: RcRef<Node>,
- },
- Registered {
- #[pin]
- node: Node,
- },
- }
-
- impl Default for Registration {
- fn default() -> Self {
- Self::Registered {
- node: Default::default(),
- }
- }
- }
-
- #[derive(Debug)]
- pub struct Node {
- inner: UnsafeCell<NodeInner>,
- _pin: PhantomPinned,
- }
-
- impl Node {
- /// If necessary, register a `Cancelable` node with a `CancelHandle`, and
- /// save or update the `Waker` that can wake with this cancelable future.
- pub fn register(
- &self,
- waker: &Waker,
- head_rc: Option<RcRef<Node>>,
- ) -> Result<(), Canceled> {
- match head_rc.as_ref().map(RcRef::split) {
- Some((head, rc)) => {
- // Register this `Cancelable` node with a `CancelHandle` head node.
- assert_ne!(self, head);
- // TODO(piscisaureus): safety comment
- #[allow(clippy::undocumented_unsafe_blocks)]
- let self_inner = unsafe { &mut *self.inner.get() };
- // TODO(piscisaureus): safety comment
- #[allow(clippy::undocumented_unsafe_blocks)]
- let head_inner = unsafe { &mut *head.inner.get() };
- self_inner.link(waker, head_inner, rc)
- }
- None => {
- // This `Cancelable` has already been linked to a `CancelHandle` head
- // node; just update our stored `Waker` if necessary.
- // TODO(piscisaureus): safety comment
- #[allow(clippy::undocumented_unsafe_blocks)]
- let inner = unsafe { &mut *self.inner.get() };
- inner.update_waker(waker)
- }
- }
- }
-
- pub fn cancel(&self) {
- // TODO(piscisaureus): safety comment
- #[allow(clippy::undocumented_unsafe_blocks)]
- let inner = unsafe { &mut *self.inner.get() };
- inner.cancel();
- }
-
- pub fn is_canceled(&self) -> bool {
- // TODO(piscisaureus): safety comment
- #[allow(clippy::undocumented_unsafe_blocks)]
- let inner = unsafe { &mut *self.inner.get() };
- inner.is_canceled()
- }
- }
-
- impl Default for Node {
- fn default() -> Self {
- Self {
- inner: UnsafeCell::new(NodeInner::Unlinked),
- _pin: PhantomPinned,
- }
- }
- }
-
- impl Drop for Node {
- fn drop(&mut self) {
- // TODO(piscisaureus): safety comment
- #[allow(clippy::undocumented_unsafe_blocks)]
- let inner = unsafe { &mut *self.inner.get() };
- inner.unlink();
- }
- }
-
- impl PartialEq for Node {
- fn eq(&self, other: &Self) -> bool {
- std::ptr::eq(self, other)
- }
- }
-
- #[derive(Debug)]
- enum NodeInner {
- Unlinked,
- Linked {
- kind: NodeKind,
- prev: NonNull<NodeInner>,
- next: NonNull<NodeInner>,
- },
- Canceled,
- }
-
- impl NodeInner {
- fn as_non_null(&mut self) -> NonNull<Self> {
- NonNull::from(self)
- }
-
- fn link(
- &mut self,
- waker: &Waker,
- head: &mut Self,
- rc_pin: &Rc<dyn Any>,
- ) -> Result<(), Canceled> {
- // The future should not have been linked to a cancel handle before.
- assert!(matches!(self, NodeInner::Unlinked));
-
- match head {
- NodeInner::Unlinked => {
- *head = NodeInner::Linked {
- kind: NodeKind::head(rc_pin),
- prev: self.as_non_null(),
- next: self.as_non_null(),
- };
- *self = NodeInner::Linked {
- kind: NodeKind::item(waker),
- prev: head.as_non_null(),
- next: head.as_non_null(),
- };
- Ok(())
- }
- NodeInner::Linked {
- kind: NodeKind::Head { .. },
- prev: next_prev_nn,
- ..
- } => {
- // TODO(piscisaureus): safety comment
- #[allow(clippy::undocumented_unsafe_blocks)]
- let prev = unsafe { &mut *next_prev_nn.as_ptr() };
- match prev {
- NodeInner::Linked {
- kind: NodeKind::Item { .. },
- next: prev_next_nn,
- ..
- } => {
- *self = NodeInner::Linked {
- kind: NodeKind::item(waker),
- prev: replace(next_prev_nn, self.as_non_null()),
- next: replace(prev_next_nn, self.as_non_null()),
- };
- Ok(())
- }
- _ => unreachable!(),
- }
- }
- NodeInner::Canceled => Err(Canceled),
- _ => unreachable!(),
- }
- }
-
- fn update_waker(&mut self, new_waker: &Waker) -> Result<(), Canceled> {
- match self {
- NodeInner::Unlinked => Ok(()),
- NodeInner::Linked {
- kind: NodeKind::Item { waker },
- ..
- } => {
- if !waker.will_wake(new_waker) {
- *waker = new_waker.clone();
- }
- Ok(())
- }
- NodeInner::Canceled => Err(Canceled),
- _ => unreachable!(),
- }
- }
-
- /// If this node is linked to other nodes, remove it from the chain. This
- /// method is called (only) by the drop handler for `Node`. It is suitable
- /// for both 'head' and 'item' nodes.
- fn unlink(&mut self) {
- if let NodeInner::Linked {
- prev: mut prev_nn,
- next: mut next_nn,
- ..
- } = replace(self, NodeInner::Unlinked)
- {
- if prev_nn == next_nn {
- // There were only two nodes in this chain; after unlinking ourselves
- // the other node is no longer linked.
- // TODO(piscisaureus): safety comment
- #[allow(clippy::undocumented_unsafe_blocks)]
- let other = unsafe { prev_nn.as_mut() };
- *other = NodeInner::Unlinked;
- } else {
- // The chain had more than two nodes.
- // TODO(piscisaureus): safety comment
- #[allow(clippy::undocumented_unsafe_blocks)]
- match unsafe { prev_nn.as_mut() } {
- NodeInner::Linked {
- next: prev_next_nn, ..
- } => {
- *prev_next_nn = next_nn;
- }
- _ => unreachable!(),
- }
- // TODO(piscisaureus): safety comment
- #[allow(clippy::undocumented_unsafe_blocks)]
- match unsafe { next_nn.as_mut() } {
- NodeInner::Linked {
- prev: next_prev_nn, ..
- } => {
- *next_prev_nn = prev_nn;
- }
- _ => unreachable!(),
- }
- }
- }
- }
-
- /// Mark this node and all linked nodes for cancellation. Note that `self`
- /// must refer to a head (`CancelHandle`) node.
- fn cancel(&mut self) {
- let mut head_nn = NonNull::from(self);
-
- // TODO(piscisaureus): safety comment
- #[allow(clippy::undocumented_unsafe_blocks)]
- // Mark the head node as canceled.
- let mut item_nn =
- match replace(unsafe { head_nn.as_mut() }, NodeInner::Canceled) {
- NodeInner::Linked {
- kind: NodeKind::Head { .. },
- next: next_nn,
- ..
- } => next_nn,
- NodeInner::Unlinked | NodeInner::Canceled => return,
- _ => unreachable!(),
- };
-
- // Cancel all item nodes in the chain, waking each stored `Waker`.
- while item_nn != head_nn {
- // TODO(piscisaureus): safety comment
- #[allow(clippy::undocumented_unsafe_blocks)]
- match replace(unsafe { item_nn.as_mut() }, NodeInner::Canceled) {
- NodeInner::Linked {
- kind: NodeKind::Item { waker },
- next: next_nn,
- ..
- } => {
- waker.wake();
- item_nn = next_nn;
- }
- _ => unreachable!(),
- }
- }
- }
-
- /// Returns true if this node has been marked for cancellation. This method
- /// may be used with both head (`CancelHandle`) and item (`Cancelable`)
- /// nodes.
- fn is_canceled(&self) -> bool {
- match self {
- NodeInner::Unlinked | NodeInner::Linked { .. } => false,
- NodeInner::Canceled => true,
- }
- }
- }
-
- #[derive(Debug)]
- enum NodeKind {
- /// In a chain of linked nodes, the "head" node is owned by the
- /// `CancelHandle`. A chain usually contains at most one head node; however
- /// when a `CancelHandle` is dropped before the futures associated with it
- /// are dropped, a chain may temporarily contain no head node at all.
- Head {
- /// The `weak_pin` field adds adds a weak reference to the `Rc` guarding
- /// the heap allocation that contains the `CancelHandle`. Without this
- /// extra weak reference, `Rc::get_mut()` might succeed and allow the
- /// `CancelHandle` to be moved when it isn't safe to do so.
- _weak_pin: Weak<dyn Any>,
- },
- /// All item nodes in a chain are associated with a `Cancelable` head node.
- Item {
- /// If this future indeed does get canceled, the waker is needed to make
- /// sure that the canceled future gets polled as soon as possible.
- waker: Waker,
- },
- }
-
- impl NodeKind {
- fn head(rc_pin: &Rc<dyn Any>) -> Self {
- let _weak_pin = Rc::downgrade(rc_pin);
- Self::Head { _weak_pin }
- }
-
- fn item(waker: &Waker) -> Self {
- let waker = waker.clone();
- Self::Item { waker }
- }
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
- use anyhow::Error;
- use futures::future::pending;
- use futures::future::poll_fn;
- use futures::future::ready;
- use futures::future::FutureExt;
- use futures::future::TryFutureExt;
- use futures::pending;
- use futures::select;
- use futures::task::noop_waker_ref;
- use futures::task::Context;
- use futures::task::Poll;
- use std::convert::Infallible as Never;
- use std::io;
- use tokio::net::TcpStream;
- use tokio::spawn;
- use tokio::task::yield_now;
-
- fn box_fused<'a, F: FusedFuture + 'a>(
- future: F,
- ) -> Pin<Box<dyn FusedFuture<Output = F::Output> + 'a>> {
- Box::pin(future)
- }
-
- async fn ready_in_n(name: &str, count: usize) -> &str {
- let mut remaining = count as isize;
- poll_fn(|_| {
- assert!(remaining >= 0);
- if remaining == 0 {
- Poll::Ready(name)
- } else {
- remaining -= 1;
- Poll::Pending
- }
- })
- .await
- }
-
- #[test]
- fn cancel_future() {
- let cancel_now = CancelHandle::new_rc();
- let cancel_at_0 = CancelHandle::new_rc();
- let cancel_at_1 = CancelHandle::new_rc();
- let cancel_at_4 = CancelHandle::new_rc();
- let cancel_never = CancelHandle::new_rc();
-
- cancel_now.cancel();
-
- let mut futures = vec![
- box_fused(ready("A").or_cancel(&cancel_now)),
- box_fused(ready("B").or_cancel(&cancel_at_0)),
- box_fused(ready("C").or_cancel(&cancel_at_1)),
- box_fused(
- ready_in_n("D", 0)
- .or_cancel(&cancel_never)
- .try_or_cancel(&cancel_now),
- ),
- box_fused(
- ready_in_n("E", 1)
- .or_cancel(&cancel_at_1)
- .try_or_cancel(&cancel_at_1),
- ),
- box_fused(ready_in_n("F", 2).or_cancel(&cancel_at_1)),
- box_fused(ready_in_n("G", 3).or_cancel(&cancel_at_4)),
- box_fused(ready_in_n("H", 4).or_cancel(&cancel_at_4)),
- box_fused(ready_in_n("I", 5).or_cancel(&cancel_at_4)),
- box_fused(ready_in_n("J", 5).map(Ok)),
- box_fused(ready_in_n("K", 5).or_cancel(cancel_never)),
- ];
-
- let mut cx = Context::from_waker(noop_waker_ref());
-
- for i in 0..=5 {
- match i {
- 0 => cancel_at_0.cancel(),
- 1 => cancel_at_1.cancel(),
- 4 => cancel_at_4.cancel(),
- 2 | 3 | 5 => {}
- _ => unreachable!(),
- }
-
- let results = futures
- .iter_mut()
- .filter(|fut| !fut.is_terminated())
- .filter_map(|fut| match fut.poll_unpin(&mut cx) {
- Poll::Pending => None,
- Poll::Ready(res) => Some(res),
- })
- .collect::<Vec<_>>();
-
- match i {
- 0 => assert_eq!(
- results,
- [Err(Canceled), Err(Canceled), Ok("C"), Err(Canceled)]
- ),
- 1 => assert_eq!(results, [Err(Canceled), Err(Canceled)]),
- 2 => assert_eq!(results, []),
- 3 => assert_eq!(results, [Ok("G")]),
- 4 => assert_eq!(results, [Err(Canceled), Err(Canceled)]),
- 5 => assert_eq!(results, [Ok("J"), Ok("K")]),
- _ => unreachable!(),
- }
- }
-
- assert!(!futures.into_iter().any(|fut| !fut.is_terminated()));
-
- let cancel_handles = [cancel_now, cancel_at_0, cancel_at_1, cancel_at_4];
- assert!(!cancel_handles.iter().any(|c| !c.is_canceled()));
- }
-
- #[tokio::test]
- async fn cancel_try_future() {
- {
- // Cancel a spawned task before it actually runs.
- let cancel_handle = Rc::new(CancelHandle::new());
- let future = spawn(async { panic!("the task should not be spawned") })
- .map_err(Error::from)
- .try_or_cancel(&cancel_handle);
- cancel_handle.cancel();
- let error = future.await.unwrap_err();
- assert!(error.downcast_ref::<Canceled>().is_some());
- assert_eq!(error.to_string().as_str(), "operation canceled");
- }
-
- {
- // Cancel a network I/O future right after polling it.
- let cancel_handle = Rc::new(CancelHandle::new());
- let result = loop {
- select! {
- r = TcpStream::connect("1.2.3.4:12345")
- .try_or_cancel(&cancel_handle) => break r,
- default => cancel_handle.cancel(),
- };
- };
- let error = result.unwrap_err();
- assert_eq!(error.kind(), io::ErrorKind::Interrupted);
- assert_eq!(error.to_string().as_str(), "operation canceled");
- }
- }
-
- #[tokio::test]
- async fn future_cancels_itself_before_completion() {
- // A future cancels itself before it reaches completion. This future should
- // indeed get canceled and should not be polled again.
- let cancel_handle = CancelHandle::new_rc();
- let result = async {
- cancel_handle.cancel();
- yield_now().await;
- unreachable!();
- }
- .or_cancel(&cancel_handle)
- .await;
- assert_eq!(result.unwrap_err(), Canceled);
- }
-
- #[tokio::test]
- async fn future_cancels_itself_and_hangs() {
- // A future cancels itself, after which it returns `Poll::Pending` without
- // setting up a waker that would allow it to make progress towards
- // completion. Nevertheless, the `Cancelable` wrapper future must finish.
- let cancel_handle = CancelHandle::new_rc();
- let result = async {
- yield_now().await;
- cancel_handle.cancel();
- pending!();
- unreachable!();
- }
- .or_cancel(&cancel_handle)
- .await;
- assert_eq!(result.unwrap_err(), Canceled);
- }
-
- #[tokio::test]
- async fn future_cancels_itself_and_completes() {
- // A TryFuture attempts to cancel itself while it is getting polled, and
- // yields a result from the very same `poll()` call. Because this future
- // actually reaches completion, the attempted cancellation has no effect.
- let cancel_handle = CancelHandle::new_rc();
- let result = async {
- yield_now().await;
- cancel_handle.cancel();
- Ok::<_, io::Error>("done")
- }
- .try_or_cancel(&cancel_handle)
- .await;
- assert_eq!(result.unwrap(), "done");
- }
-
- #[test]
- fn cancel_handle_pinning() {
- let mut cancel_handle = CancelHandle::new_rc();
-
- // There is only one reference to `cancel_handle`, so `Rc::get_mut()` should
- // succeed.
- assert!(Rc::get_mut(&mut cancel_handle).is_some());
-
- let mut future = pending::<Never>().or_cancel(&cancel_handle);
- // SAFETY: `Cancelable` pins the future
- let future = unsafe { Pin::new_unchecked(&mut future) };
-
- // There are two `Rc<CancelHandle>` references now, so this fails.
- assert!(Rc::get_mut(&mut cancel_handle).is_none());
-
- let mut cx = Context::from_waker(noop_waker_ref());
- assert!(future.poll(&mut cx).is_pending());
-
- // Polling `future` has established a link between the future and
- // `cancel_handle`, so both values should be pinned at this point.
- assert!(Rc::get_mut(&mut cancel_handle).is_none());
-
- cancel_handle.cancel();
-
- // Canceling or dropping the associated future(s) unlinks them from the
- // cancel handle, therefore `cancel_handle` can now safely be moved again.
- assert!(Rc::get_mut(&mut cancel_handle).is_some());
- }
-}
diff --git a/core/async_cell.rs b/core/async_cell.rs
deleted file mode 100644
index 97d70699d..000000000
--- a/core/async_cell.rs
+++ /dev/null
@@ -1,780 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-
-use std::any::type_name;
-use std::any::Any;
-use std::borrow::Borrow;
-use std::cell::Cell;
-use std::cell::UnsafeCell;
-use std::collections::VecDeque;
-use std::fmt;
-use std::fmt::Debug;
-use std::fmt::Formatter;
-use std::ops::Deref;
-use std::rc::Rc;
-
-use self::internal as i;
-
-pub type AsyncRef<T> = i::AsyncBorrowImpl<T, i::Shared>;
-pub type AsyncMut<T> = i::AsyncBorrowImpl<T, i::Exclusive>;
-
-pub type AsyncRefFuture<T> = i::AsyncBorrowFutureImpl<T, i::Shared>;
-pub type AsyncMutFuture<T> = i::AsyncBorrowFutureImpl<T, i::Exclusive>;
-
-pub struct AsyncRefCell<T> {
- value: UnsafeCell<T>,
- borrow_count: Cell<i::BorrowCount>,
- waiters: Cell<VecDeque<Option<i::Waiter>>>,
- turn: Cell<usize>,
-}
-
-impl<T: 'static> AsyncRefCell<T> {
- /// Create a new `AsyncRefCell` that encapsulates the specified value.
- /// Note that in order to borrow the inner value, the `AsyncRefCell`
- /// needs to be wrapped in an `Rc` or an `RcRef`. These can be created
- /// either manually, or by using the convenience method
- /// `AsyncRefCell::new_rc()`.
- pub fn new(value: T) -> Self {
- Self {
- value: UnsafeCell::new(value),
- borrow_count: Default::default(),
- waiters: Default::default(),
- turn: Default::default(),
- }
- }
-
- pub fn new_rc(value: T) -> Rc<Self> {
- Rc::new(Self::new(value))
- }
-
- pub fn as_ptr(&self) -> *mut T {
- self.value.get()
- }
-
- pub fn into_inner(self) -> T {
- assert!(self.borrow_count.get().is_empty());
- self.value.into_inner()
- }
-}
-
-impl<T> Debug for AsyncRefCell<T> {
- fn fmt(&self, f: &mut Formatter) -> fmt::Result {
- write!(f, "AsyncRefCell<{}>", type_name::<T>())
- }
-}
-
-impl<T: Default + 'static> Default for AsyncRefCell<T> {
- fn default() -> Self {
- Self::new(Default::default())
- }
-}
-
-impl<T: Default + 'static> AsyncRefCell<T> {
- pub fn default_rc() -> Rc<Self> {
- Rc::new(Default::default())
- }
-}
-
-impl<T: 'static> From<T> for AsyncRefCell<T> {
- fn from(value: T) -> Self {
- Self::new(value)
- }
-}
-
-impl<T> AsyncRefCell<T> {
- pub fn borrow(self: &Rc<Self>) -> AsyncRefFuture<T> {
- AsyncRefFuture::new(self)
- }
-
- pub fn borrow_mut(self: &Rc<Self>) -> AsyncMutFuture<T> {
- AsyncMutFuture::new(self)
- }
-
- pub fn try_borrow(self: &Rc<Self>) -> Option<AsyncRef<T>> {
- Self::borrow_sync(self)
- }
-
- pub fn try_borrow_mut(self: &Rc<Self>) -> Option<AsyncMut<T>> {
- Self::borrow_sync(self)
- }
-}
-
-impl<T> RcRef<AsyncRefCell<T>> {
- pub fn borrow(&self) -> AsyncRefFuture<T> {
- AsyncRefFuture::new(self)
- }
-
- pub fn borrow_mut(&self) -> AsyncMutFuture<T> {
- AsyncMutFuture::new(self)
- }
-
- pub fn try_borrow(&self) -> Option<AsyncRef<T>> {
- AsyncRefCell::<T>::borrow_sync(self)
- }
-
- pub fn try_borrow_mut(&self) -> Option<AsyncMut<T>> {
- AsyncRefCell::<T>::borrow_sync(self)
- }
-}
-
-/// An `RcRef` encapsulates a reference counted pointer, just like a regular
-/// `std::rc::Rc`. However, unlike a regular `Rc`, it can be remapped so that
-/// it dereferences to any value that's reachable through the reference-counted
-/// pointer. This is achieved through the associated method, `RcRef::map()`,
-/// similar to how `std::cell::Ref::map()` works. Example:
-///
-/// ```rust
-/// # use std::rc::Rc;
-/// # use deno_core::RcRef;
-///
-/// struct Stuff {
-/// foo: u32,
-/// bar: String,
-/// }
-///
-/// let stuff_rc = Rc::new(Stuff {
-/// foo: 42,
-/// bar: "hello".to_owned(),
-/// });
-///
-/// // `foo_rc` and `bar_rc` dereference to different types, however
-/// // they share a reference count.
-/// let foo_rc: RcRef<u32> = RcRef::map(stuff_rc.clone(), |v| &v.foo);
-/// let bar_rc: RcRef<String> = RcRef::map(stuff_rc, |v| &v.bar);
-/// ```
-#[derive(Debug)]
-pub struct RcRef<T> {
- rc: Rc<dyn Any>,
- value: *const T,
-}
-
-impl<T: 'static> RcRef<T> {
- pub fn new(value: T) -> Self {
- Self::from(Rc::new(value))
- }
-
- pub fn map<S: 'static, R: RcLike<S>, F: FnOnce(&S) -> &T>(
- source: R,
- map_fn: F,
- ) -> RcRef<T> {
- let RcRef::<S> { rc, value } = source.into();
- // TODO(piscisaureus): safety comment
- #[allow(clippy::undocumented_unsafe_blocks)]
- let value = map_fn(unsafe { &*value });
- RcRef { rc, value }
- }
-
- pub(crate) fn split(rc_ref: &Self) -> (&T, &Rc<dyn Any>) {
- let &Self { ref rc, value } = rc_ref;
- // TODO(piscisaureus): safety comment
- #[allow(clippy::undocumented_unsafe_blocks)]
- (unsafe { &*value }, rc)
- }
-}
-
-impl<T: Default + 'static> Default for RcRef<T> {
- fn default() -> Self {
- Self::new(Default::default())
- }
-}
-
-impl<T> Clone for RcRef<T> {
- fn clone(&self) -> Self {
- Self {
- rc: self.rc.clone(),
- value: self.value,
- }
- }
-}
-
-impl<T: 'static> From<&RcRef<T>> for RcRef<T> {
- fn from(rc_ref: &RcRef<T>) -> Self {
- rc_ref.clone()
- }
-}
-
-impl<T: 'static> From<Rc<T>> for RcRef<T> {
- fn from(rc: Rc<T>) -> Self {
- Self {
- value: &*rc,
- rc: rc as Rc<_>,
- }
- }
-}
-
-impl<T: 'static> From<&Rc<T>> for RcRef<T> {
- fn from(rc: &Rc<T>) -> Self {
- rc.clone().into()
- }
-}
-
-impl<T> Deref for RcRef<T> {
- type Target = T;
- fn deref(&self) -> &Self::Target {
- // TODO(piscisaureus): safety comment
- #[allow(clippy::undocumented_unsafe_blocks)]
- unsafe {
- &*self.value
- }
- }
-}
-
-impl<T> Borrow<T> for RcRef<T> {
- fn borrow(&self) -> &T {
- self
- }
-}
-
-impl<T> AsRef<T> for RcRef<T> {
- fn as_ref(&self) -> &T {
- self
- }
-}
-
-/// The `RcLike` trait provides an abstraction over `std::rc::Rc` and `RcRef`,
-/// so that applicable methods can operate on either type.
-pub trait RcLike<T>: AsRef<T> + Into<RcRef<T>> {}
-
-impl<T: 'static> RcLike<T> for Rc<T> {}
-impl<T: 'static> RcLike<T> for RcRef<T> {}
-impl<T: 'static> RcLike<T> for &Rc<T> {}
-impl<T: 'static> RcLike<T> for &RcRef<T> {}
-
-mod internal {
- use super::AsyncRefCell;
- use super::RcLike;
- use super::RcRef;
- use futures::future::Future;
- use futures::ready;
- use futures::task::Context;
- use futures::task::Poll;
- use futures::task::Waker;
- use std::borrow::Borrow;
- use std::borrow::BorrowMut;
- use std::fmt::Debug;
- use std::marker::PhantomData;
- use std::ops::Deref;
- use std::ops::DerefMut;
- use std::pin::Pin;
-
- impl<T> AsyncRefCell<T> {
- /// Borrow the cell's contents synchronously without creating an
- /// intermediate future. If the cell has already been borrowed and either
- /// the existing or the requested borrow is exclusive, this function returns
- /// `None`.
- pub fn borrow_sync<M: BorrowModeTrait, R: RcLike<AsyncRefCell<T>>>(
- cell: R,
- ) -> Option<AsyncBorrowImpl<T, M>> {
- let cell_ref = cell.as_ref();
- // Don't allow synchronous borrows to cut in line; if there are any
- // enqueued waiters, return `None`, even if the current borrow is a shared
- // one and the requested borrow is too.
- // TODO(piscisaureus): safety comment
- #[allow(clippy::undocumented_unsafe_blocks)]
- let waiters = unsafe { &mut *cell_ref.waiters.as_ptr() };
- if waiters.is_empty() {
- // There are no enqueued waiters, but it is still possible that the cell
- // is currently borrowed. If there are no current borrows, or both the
- // existing and requested ones are shared, `try_add()` returns the
- // adjusted borrow count.
- let new_borrow_count =
- cell_ref.borrow_count.get().try_add(M::borrow_mode())?;
- cell_ref.borrow_count.set(new_borrow_count);
- Some(AsyncBorrowImpl::<T, M>::new(cell.into()))
- } else {
- None
- }
- }
-
- fn drop_borrow<M: BorrowModeTrait>(&self) {
- let new_borrow_count = self.borrow_count.get().remove(M::borrow_mode());
- self.borrow_count.set(new_borrow_count);
-
- if new_borrow_count.is_empty() {
- self.wake_waiters()
- }
- }
-
- fn create_waiter<M: BorrowModeTrait>(&self) -> usize {
- let waiter = Waiter::new(M::borrow_mode());
- let turn = self.turn.get();
- let index = {
- // TODO(piscisaureus): safety comment
- #[allow(clippy::undocumented_unsafe_blocks)]
- let waiters = unsafe { &mut *self.waiters.as_ptr() };
- waiters.push_back(Some(waiter));
- waiters.len() - 1
- };
- if index == 0 {
- // SAFETY: the `waiters` reference used above *must* be dropped here.
- self.wake_waiters()
- }
- // Return the new waiter's id.
- turn + index
- }
-
- fn poll_waiter<M: BorrowModeTrait>(
- &self,
- id: usize,
- cx: &mut Context,
- ) -> Poll<()> {
- let borrow_count = self.borrow_count.get();
- let turn = self.turn.get();
- if id < turn {
- // This waiter made it to the front of the line; we reserved a borrow
- // for it, woke its Waker, and removed the waiter from the queue.
- // Assertion: BorrowCount::remove() will panic if `mode` is incorrect.
- let _ = borrow_count.remove(M::borrow_mode());
- Poll::Ready(())
- } else {
- // This waiter is still in line and has not yet been woken.
- // TODO(piscisaureus): safety comment
- #[allow(clippy::undocumented_unsafe_blocks)]
- let waiters = unsafe { &mut *self.waiters.as_ptr() };
- // Sanity check: id cannot be higher than the last queue element.
- assert!(id < turn + waiters.len());
- // Sanity check: since we always call wake_waiters() when the queue head
- // is updated, it should be impossible to add it to the current borrow.
- assert!(id > turn || borrow_count.try_add(M::borrow_mode()).is_none());
- // Save or update the waiter's Waker.
- let waiter_mut = waiters[id - turn].as_mut().unwrap();
- waiter_mut.set_waker(cx.waker());
- Poll::Pending
- }
- }
-
- fn wake_waiters(&self) {
- let mut borrow_count = self.borrow_count.get();
- // TODO(piscisaureus): safety comment
- #[allow(clippy::undocumented_unsafe_blocks)]
- let waiters = unsafe { &mut *self.waiters.as_ptr() };
- let mut turn = self.turn.get();
-
- loop {
- let waiter_entry = match waiters.front().map(Option::as_ref) {
- None => break, // Queue empty.
- Some(w) => w,
- };
- let borrow_mode = match waiter_entry {
- None => {
- // Queue contains a hole. This happens when a Waiter is dropped
- // before it makes it to the front of the queue.
- waiters.pop_front();
- turn += 1;
- continue;
- }
- Some(waiter) => waiter.borrow_mode(),
- };
- // See if the waiter at the front of the queue can borrow the cell's
- // value now. If it does, `try_add()` returns the new borrow count,
- // effectively "reserving" the borrow until the associated
- // AsyncBorrowFutureImpl future gets polled and produces the actual
- // borrow.
- borrow_count = match borrow_count.try_add(borrow_mode) {
- None => break, // Can't borrow yet.
- Some(b) => b,
- };
- // Drop from queue.
- let mut waiter = waiters.pop_front().unwrap().unwrap();
- turn += 1;
- // Wake this waiter, so the AsyncBorrowFutureImpl future gets polled.
- if let Some(waker) = waiter.take_waker() {
- waker.wake()
- }
- }
- // Save updated counters.
- self.borrow_count.set(borrow_count);
- self.turn.set(turn);
- }
-
- fn drop_waiter<M: BorrowModeTrait>(&self, id: usize) {
- let turn = self.turn.get();
- if id < turn {
- // We already made a borrow count reservation for this waiter but the
- // borrow will never be picked up and consequently, never dropped.
- // Therefore, call the borrow drop handler here.
- self.drop_borrow::<M>();
- } else {
- // This waiter is still in the queue, take it out and leave a "hole".
- // TODO(piscisaureus): safety comment
- #[allow(clippy::undocumented_unsafe_blocks)]
- let waiters = unsafe { &mut *self.waiters.as_ptr() };
- waiters[id - turn].take().unwrap();
- }
-
- if id == turn {
- // Since the first entry in the waiter queue was touched we have to
- // reprocess the waiter queue.
- self.wake_waiters()
- }
- }
- }
-
- pub struct AsyncBorrowFutureImpl<T: 'static, M: BorrowModeTrait> {
- cell: Option<RcRef<AsyncRefCell<T>>>,
- id: usize,
- _phantom: PhantomData<M>,
- }
-
- impl<T, M: BorrowModeTrait> AsyncBorrowFutureImpl<T, M> {
- pub fn new<R: RcLike<AsyncRefCell<T>>>(cell: R) -> Self {
- Self {
- id: cell.as_ref().create_waiter::<M>(),
- cell: Some(cell.into()),
- _phantom: PhantomData,
- }
- }
- }
-
- impl<T: 'static, M: BorrowModeTrait> Future for AsyncBorrowFutureImpl<T, M> {
- type Output = AsyncBorrowImpl<T, M>;
- fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
- ready!(self.cell.as_ref().unwrap().poll_waiter::<M>(self.id, cx));
- // TODO(piscisaureus): safety comment
- #[allow(clippy::undocumented_unsafe_blocks)]
- let self_mut = unsafe { Pin::get_unchecked_mut(self) };
- let cell = self_mut.cell.take().unwrap();
- Poll::Ready(AsyncBorrowImpl::<T, M>::new(cell))
- }
- }
-
- impl<T, M: BorrowModeTrait> Drop for AsyncBorrowFutureImpl<T, M> {
- fn drop(&mut self) {
- // The expected mode of operation is that this future gets polled until it
- // is ready and yields a value of type `AsyncBorrowImpl`, which has a drop
- // handler that adjusts the `AsyncRefCell` borrow counter. However if the
- // `cell` field still holds a value at this point, it means that the
- // future was never polled to completion and no `AsyncBorrowImpl` was ever
- // created, so we have to adjust the borrow count here.
- if let Some(cell) = self.cell.take() {
- cell.drop_waiter::<M>(self.id)
- }
- }
- }
-
- pub struct AsyncBorrowImpl<T: 'static, M: BorrowModeTrait> {
- cell: RcRef<AsyncRefCell<T>>,
- _phantom: PhantomData<M>,
- }
-
- impl<T, M: BorrowModeTrait> AsyncBorrowImpl<T, M> {
- fn new(cell: RcRef<AsyncRefCell<T>>) -> Self {
- Self {
- cell,
- _phantom: PhantomData,
- }
- }
- }
-
- impl<T, M: BorrowModeTrait> Deref for AsyncBorrowImpl<T, M> {
- type Target = T;
- fn deref(&self) -> &Self::Target {
- // TODO(piscisaureus): safety comment
- #[allow(clippy::undocumented_unsafe_blocks)]
- unsafe {
- &*self.cell.as_ptr()
- }
- }
- }
-
- impl<T, M: BorrowModeTrait> Borrow<T> for AsyncBorrowImpl<T, M> {
- fn borrow(&self) -> &T {
- self
- }
- }
-
- impl<T, M: BorrowModeTrait> AsRef<T> for AsyncBorrowImpl<T, M> {
- fn as_ref(&self) -> &T {
- self
- }
- }
-
- impl<T> DerefMut for AsyncBorrowImpl<T, Exclusive> {
- fn deref_mut(&mut self) -> &mut Self::Target {
- // TODO(piscisaureus): safety comment
- #[allow(clippy::undocumented_unsafe_blocks)]
- unsafe {
- &mut *self.cell.as_ptr()
- }
- }
- }
-
- impl<T> BorrowMut<T> for AsyncBorrowImpl<T, Exclusive> {
- fn borrow_mut(&mut self) -> &mut T {
- self
- }
- }
-
- impl<T> AsMut<T> for AsyncBorrowImpl<T, Exclusive> {
- fn as_mut(&mut self) -> &mut T {
- self
- }
- }
-
- impl<T, M: BorrowModeTrait> Drop for AsyncBorrowImpl<T, M> {
- fn drop(&mut self) {
- self.cell.drop_borrow::<M>()
- }
- }
-
- #[derive(Copy, Clone, Debug, Eq, PartialEq)]
- pub enum BorrowMode {
- Shared,
- Exclusive,
- }
-
- pub trait BorrowModeTrait: Copy {
- fn borrow_mode() -> BorrowMode;
- }
-
- #[derive(Copy, Clone, Debug)]
- pub struct Shared;
-
- impl BorrowModeTrait for Shared {
- fn borrow_mode() -> BorrowMode {
- BorrowMode::Shared
- }
- }
-
- #[derive(Copy, Clone, Debug)]
- pub struct Exclusive;
-
- impl BorrowModeTrait for Exclusive {
- fn borrow_mode() -> BorrowMode {
- BorrowMode::Exclusive
- }
- }
-
- #[derive(Copy, Clone, Debug, Eq, PartialEq)]
- pub enum BorrowCount {
- Shared(usize),
- Exclusive,
- }
-
- impl Default for BorrowCount {
- fn default() -> Self {
- Self::Shared(0)
- }
- }
-
- impl BorrowCount {
- pub fn is_empty(self) -> bool {
- matches!(self, BorrowCount::Shared(0))
- }
-
- pub fn try_add(self, mode: BorrowMode) -> Option<BorrowCount> {
- match (self, mode) {
- (BorrowCount::Shared(refs), BorrowMode::Shared) => {
- Some(BorrowCount::Shared(refs + 1))
- }
- (BorrowCount::Shared(0), BorrowMode::Exclusive) => {
- Some(BorrowCount::Exclusive)
- }
- _ => None,
- }
- }
-
- #[allow(dead_code)]
- pub fn add(self, mode: BorrowMode) -> BorrowCount {
- match self.try_add(mode) {
- Some(value) => value,
- None => panic!("Can't add {mode:?} to {self:?}"),
- }
- }
-
- pub fn try_remove(self, mode: BorrowMode) -> Option<BorrowCount> {
- match (self, mode) {
- (BorrowCount::Shared(refs), BorrowMode::Shared) if refs > 0 => {
- Some(BorrowCount::Shared(refs - 1))
- }
- (BorrowCount::Exclusive, BorrowMode::Exclusive) => {
- Some(BorrowCount::Shared(0))
- }
- _ => None,
- }
- }
-
- pub fn remove(self, mode: BorrowMode) -> BorrowCount {
- match self.try_remove(mode) {
- Some(value) => value,
- None => panic!("Can't remove {mode:?} from {self:?}"),
- }
- }
- }
-
- /// The `waiters` queue that is associated with an individual `AsyncRefCell`
- /// contains elements of the `Waiter` type.
- pub struct Waiter {
- borrow_mode: BorrowMode,
- waker: Option<Waker>,
- }
-
- impl Waiter {
- pub fn new(borrow_mode: BorrowMode) -> Self {
- Self {
- borrow_mode,
- waker: None,
- }
- }
-
- pub fn borrow_mode(&self) -> BorrowMode {
- self.borrow_mode
- }
-
- pub fn set_waker(&mut self, new_waker: &Waker) {
- if self
- .waker
- .as_ref()
- .filter(|waker| waker.will_wake(new_waker))
- .is_none()
- {
- self.waker.replace(new_waker.clone());
- }
- }
-
- pub fn take_waker(&mut self) -> Option<Waker> {
- self.waker.take()
- }
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- #[derive(Default)]
- struct Thing {
- touch_count: usize,
- _private: (),
- }
-
- impl Thing {
- pub fn look(&self) -> usize {
- self.touch_count
- }
-
- pub fn touch(&mut self) -> usize {
- self.touch_count += 1;
- self.touch_count
- }
- }
-
- #[tokio::test]
- async fn async_ref_cell_borrow() {
- let cell = AsyncRefCell::<Thing>::default_rc();
-
- let fut1 = cell.borrow();
- let fut2 = cell.borrow_mut();
- let fut3 = cell.borrow();
- let fut4 = cell.borrow();
- let fut5 = cell.borrow();
- let fut6 = cell.borrow();
- let fut7 = cell.borrow_mut();
- let fut8 = cell.borrow();
-
- // The `try_borrow` and `try_borrow_mut` methods should always return `None`
- // if there's a queue of async borrowers.
- assert!(cell.try_borrow().is_none());
- assert!(cell.try_borrow_mut().is_none());
-
- assert_eq!(fut1.await.look(), 0);
-
- assert_eq!(fut2.await.touch(), 1);
-
- {
- let ref5 = fut5.await;
- let ref4 = fut4.await;
- let ref3 = fut3.await;
- let ref6 = fut6.await;
- assert_eq!(ref3.look(), 1);
- assert_eq!(ref4.look(), 1);
- assert_eq!(ref5.look(), 1);
- assert_eq!(ref6.look(), 1);
- }
-
- {
- let mut ref7 = fut7.await;
- assert_eq!(ref7.look(), 1);
- assert_eq!(ref7.touch(), 2);
- }
-
- {
- let ref8 = fut8.await;
- assert_eq!(ref8.look(), 2);
- }
- }
-
- #[test]
- fn async_ref_cell_try_borrow() {
- let cell = AsyncRefCell::<Thing>::default_rc();
-
- {
- let ref1 = cell.try_borrow().unwrap();
- assert_eq!(ref1.look(), 0);
- assert!(cell.try_borrow_mut().is_none());
- }
-
- {
- let mut ref2 = cell.try_borrow_mut().unwrap();
- assert_eq!(ref2.touch(), 1);
- assert!(cell.try_borrow().is_none());
- assert!(cell.try_borrow_mut().is_none());
- }
-
- {
- let ref3 = cell.try_borrow().unwrap();
- let ref4 = cell.try_borrow().unwrap();
- let ref5 = cell.try_borrow().unwrap();
- let ref6 = cell.try_borrow().unwrap();
- assert_eq!(ref3.look(), 1);
- assert_eq!(ref4.look(), 1);
- assert_eq!(ref5.look(), 1);
- assert_eq!(ref6.look(), 1);
- assert!(cell.try_borrow_mut().is_none());
- }
-
- {
- let mut ref7 = cell.try_borrow_mut().unwrap();
- assert_eq!(ref7.look(), 1);
- assert_eq!(ref7.touch(), 2);
- assert!(cell.try_borrow().is_none());
- assert!(cell.try_borrow_mut().is_none());
- }
-
- {
- let ref8 = cell.try_borrow().unwrap();
- assert_eq!(ref8.look(), 2);
- assert!(cell.try_borrow_mut().is_none());
- assert!(cell.try_borrow().is_some());
- }
- }
-
- #[derive(Default)]
- struct ThreeThings {
- pub thing1: AsyncRefCell<Thing>,
- pub thing2: AsyncRefCell<Thing>,
- pub thing3: AsyncRefCell<Thing>,
- }
-
- #[tokio::test]
- async fn rc_ref_map() {
- let three_cells = Rc::new(ThreeThings::default());
-
- let rc1 = RcRef::map(three_cells.clone(), |things| &things.thing1);
- let rc2 = RcRef::map(three_cells.clone(), |things| &things.thing2);
- let rc3 = RcRef::map(three_cells, |things| &things.thing3);
-
- let mut ref1 = rc1.borrow_mut().await;
- let ref2 = rc2.borrow().await;
- let mut ref3 = rc3.borrow_mut().await;
-
- assert_eq!(ref1.look(), 0);
- assert_eq!(ref3.touch(), 1);
- assert_eq!(ref1.touch(), 1);
- assert_eq!(ref2.look(), 0);
- assert_eq!(ref3.touch(), 2);
- assert_eq!(ref1.look(), 1);
- assert_eq!(ref1.touch(), 2);
- assert_eq!(ref3.touch(), 3);
- assert_eq!(ref1.touch(), 3);
- }
-}
diff --git a/core/error.rs b/core/error.rs
deleted file mode 100644
index 55fdcaa7c..000000000
--- a/core/error.rs
+++ /dev/null
@@ -1,719 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-
-use std::borrow::Cow;
-use std::collections::HashSet;
-use std::fmt;
-use std::fmt::Debug;
-use std::fmt::Display;
-use std::fmt::Formatter;
-
-use anyhow::Error;
-
-use crate::runtime::JsRealm;
-use crate::runtime::JsRuntime;
-use crate::source_map::apply_source_map;
-use crate::source_map::get_source_line;
-use crate::url::Url;
-
-/// A generic wrapper that can encapsulate any concrete error type.
-// TODO(ry) Deprecate AnyError and encourage deno_core::anyhow::Error instead.
-pub type AnyError = anyhow::Error;
-
-pub type JsErrorCreateFn = dyn Fn(JsError) -> Error;
-pub type GetErrorClassFn = &'static dyn for<'e> Fn(&'e Error) -> &'static str;
-
-/// Creates a new error with a caller-specified error class name and message.
-pub fn custom_error(
- class: &'static str,
- message: impl Into<Cow<'static, str>>,
-) -> Error {
- CustomError {
- class,
- message: message.into(),
- }
- .into()
-}
-
-pub fn generic_error(message: impl Into<Cow<'static, str>>) -> Error {
- custom_error("Error", message)
-}
-
-pub fn type_error(message: impl Into<Cow<'static, str>>) -> Error {
- custom_error("TypeError", message)
-}
-
-pub fn range_error(message: impl Into<Cow<'static, str>>) -> Error {
- custom_error("RangeError", message)
-}
-
-pub fn invalid_hostname(hostname: &str) -> Error {
- type_error(format!("Invalid hostname: '{hostname}'"))
-}
-
-pub fn uri_error(message: impl Into<Cow<'static, str>>) -> Error {
- custom_error("URIError", message)
-}
-
-pub fn bad_resource(message: impl Into<Cow<'static, str>>) -> Error {
- custom_error("BadResource", message)
-}
-
-pub fn bad_resource_id() -> Error {
- custom_error("BadResource", "Bad resource ID")
-}
-
-pub fn not_supported() -> Error {
- custom_error("NotSupported", "The operation is not supported")
-}
-
-pub fn resource_unavailable() -> Error {
- custom_error(
- "Busy",
- "Resource is unavailable because it is in use by a promise",
- )
-}
-
-/// A simple error type that lets the creator specify both the error message and
-/// the error class name. This type is private; externally it only ever appears
-/// wrapped in an `anyhow::Error`. To retrieve the error class name from a wrapped
-/// `CustomError`, use the function `get_custom_error_class()`.
-#[derive(Debug)]
-struct CustomError {
- class: &'static str,
- message: Cow<'static, str>,
-}
-
-impl Display for CustomError {
- fn fmt(&self, f: &mut Formatter) -> fmt::Result {
- f.write_str(&self.message)
- }
-}
-
-impl std::error::Error for CustomError {}
-
-/// If this error was crated with `custom_error()`, return the specified error
-/// class name. In all other cases this function returns `None`.
-pub fn get_custom_error_class(error: &Error) -> Option<&'static str> {
- error.downcast_ref::<CustomError>().map(|e| e.class)
-}
-
-pub fn to_v8_error<'a>(
- scope: &mut v8::HandleScope<'a>,
- get_class: GetErrorClassFn,
- error: &Error,
-) -> v8::Local<'a, v8::Value> {
- let tc_scope = &mut v8::TryCatch::new(scope);
- let cb = JsRealm::state_from_scope(tc_scope)
- .borrow()
- .js_build_custom_error_cb
- .clone()
- .expect("Custom error builder must be set");
- let cb = cb.open(tc_scope);
- let this = v8::undefined(tc_scope).into();
- let class = v8::String::new(tc_scope, get_class(error)).unwrap();
- let message = v8::String::new(tc_scope, &format!("{error:#}")).unwrap();
- let mut args = vec![class.into(), message.into()];
- if let Some(code) = crate::error_codes::get_error_code(error) {
- args.push(v8::String::new(tc_scope, code).unwrap().into());
- }
- let maybe_exception = cb.call(tc_scope, this, &args);
-
- match maybe_exception {
- Some(exception) => exception,
- None => {
- let mut msg =
- "Custom error class must have a builder registered".to_string();
- if tc_scope.has_caught() {
- let e = tc_scope.exception().unwrap();
- let js_error = JsError::from_v8_exception(tc_scope, e);
- msg = format!("{}: {}", msg, js_error.exception_message);
- }
- panic!("{}", msg);
- }
- }
-}
-
-/// A `JsError` represents an exception coming from V8, with stack frames and
-/// line numbers. The deno_cli crate defines another `JsError` type, which wraps
-/// the one defined here, that adds source map support and colorful formatting.
-/// When updating this struct, also update errors_are_equal_without_cause() in
-/// fmt_error.rs.
-#[derive(Debug, PartialEq, Clone, serde::Deserialize, serde::Serialize)]
-#[serde(rename_all = "camelCase")]
-pub struct JsError {
- pub name: Option<String>,
- pub message: Option<String>,
- pub stack: Option<String>,
- pub cause: Option<Box<JsError>>,
- pub exception_message: String,
- pub frames: Vec<JsStackFrame>,
- pub source_line: Option<String>,
- pub source_line_frame_index: Option<usize>,
- pub aggregated: Option<Vec<JsError>>,
-}
-
-#[derive(Debug, Eq, PartialEq, Clone, serde::Deserialize, serde::Serialize)]
-#[serde(rename_all = "camelCase")]
-pub struct JsStackFrame {
- pub type_name: Option<String>,
- pub function_name: Option<String>,
- pub method_name: Option<String>,
- pub file_name: Option<String>,
- pub line_number: Option<i64>,
- pub column_number: Option<i64>,
- pub eval_origin: Option<String>,
- // Warning! isToplevel has inconsistent snake<>camel case, "typo" originates in v8:
- // https://source.chromium.org/search?q=isToplevel&sq=&ss=chromium%2Fchromium%2Fsrc:v8%2F
- #[serde(rename = "isToplevel")]
- pub is_top_level: Option<bool>,
- pub is_eval: bool,
- pub is_native: bool,
- pub is_constructor: bool,
- pub is_async: bool,
- pub is_promise_all: bool,
- pub promise_index: Option<i64>,
-}
-
-impl JsStackFrame {
- pub fn from_location(
- file_name: Option<String>,
- line_number: Option<i64>,
- column_number: Option<i64>,
- ) -> Self {
- Self {
- type_name: None,
- function_name: None,
- method_name: None,
- file_name,
- line_number,
- column_number,
- eval_origin: None,
- is_top_level: None,
- is_eval: false,
- is_native: false,
- is_constructor: false,
- is_async: false,
- is_promise_all: false,
- promise_index: None,
- }
- }
-
- /// Gets the source mapped stack frame corresponding to the
- /// (script_resource_name, line_number, column_number) from a v8 message.
- /// For non-syntax errors, it should also correspond to the first stack frame.
- pub fn from_v8_message<'a>(
- scope: &'a mut v8::HandleScope,
- message: v8::Local<'a, v8::Message>,
- ) -> Option<Self> {
- let f = message.get_script_resource_name(scope)?;
- let f: v8::Local<v8::String> = f.try_into().ok()?;
- let f = f.to_rust_string_lossy(scope);
- let l = message.get_line_number(scope)? as i64;
- // V8's column numbers are 0-based, we want 1-based.
- let c = message.get_start_column() as i64 + 1;
- let state_rc = JsRuntime::state_from(scope);
- let (getter, cache) = {
- let state = state_rc.borrow();
- (
- state.source_map_getter.clone(),
- state.source_map_cache.clone(),
- )
- };
-
- if let Some(source_map_getter) = getter {
- let mut cache = cache.borrow_mut();
- let (f, l, c) =
- apply_source_map(f, l, c, &mut cache, &**source_map_getter);
- Some(JsStackFrame::from_location(Some(f), Some(l), Some(c)))
- } else {
- Some(JsStackFrame::from_location(Some(f), Some(l), Some(c)))
- }
- }
-
- pub fn maybe_format_location(&self) -> Option<String> {
- Some(format!(
- "{}:{}:{}",
- self.file_name.as_ref()?,
- self.line_number?,
- self.column_number?
- ))
- }
-}
-
-fn get_property<'a>(
- scope: &mut v8::HandleScope<'a>,
- object: v8::Local<v8::Object>,
- key: &str,
-) -> Option<v8::Local<'a, v8::Value>> {
- let key = v8::String::new(scope, key).unwrap();
- object.get(scope, key.into())
-}
-
-#[derive(Default, serde::Deserialize)]
-pub(crate) struct NativeJsError {
- pub name: Option<String>,
- pub message: Option<String>,
- // Warning! .stack is special so handled by itself
- // stack: Option<String>,
-}
-
-impl JsError {
- pub fn from_v8_exception(
- scope: &mut v8::HandleScope,
- exception: v8::Local<v8::Value>,
- ) -> Self {
- Self::inner_from_v8_exception(scope, exception, Default::default())
- }
-
- pub fn from_v8_message<'a>(
- scope: &'a mut v8::HandleScope,
- msg: v8::Local<'a, v8::Message>,
- ) -> Self {
- // Create a new HandleScope because we're creating a lot of new local
- // handles below.
- let scope = &mut v8::HandleScope::new(scope);
-
- let exception_message = msg.get(scope).to_rust_string_lossy(scope);
-
- // Convert them into Vec<JsStackFrame>
- let mut frames: Vec<JsStackFrame> = vec![];
- let mut source_line = None;
- let mut source_line_frame_index = None;
-
- if let Some(stack_frame) = JsStackFrame::from_v8_message(scope, msg) {
- frames = vec![stack_frame];
- }
- {
- let state_rc = JsRuntime::state_from(scope);
- let (getter, cache) = {
- let state = state_rc.borrow();
- (
- state.source_map_getter.clone(),
- state.source_map_cache.clone(),
- )
- };
- if let Some(source_map_getter) = getter {
- let mut cache = cache.borrow_mut();
- for (i, frame) in frames.iter().enumerate() {
- if let (Some(file_name), Some(line_number)) =
- (&frame.file_name, frame.line_number)
- {
- if !file_name.trim_start_matches('[').starts_with("ext:") {
- source_line = get_source_line(
- file_name,
- line_number,
- &mut cache,
- &**source_map_getter,
- );
- source_line_frame_index = Some(i);
- break;
- }
- }
- }
- }
- }
-
- Self {
- name: None,
- message: None,
- exception_message,
- cause: None,
- source_line,
- source_line_frame_index,
- frames,
- stack: None,
- aggregated: None,
- }
- }
-
- fn inner_from_v8_exception<'a>(
- scope: &'a mut v8::HandleScope,
- exception: v8::Local<'a, v8::Value>,
- mut seen: HashSet<v8::Local<'a, v8::Object>>,
- ) -> Self {
- // Create a new HandleScope because we're creating a lot of new local
- // handles below.
- let scope = &mut v8::HandleScope::new(scope);
-
- let msg = v8::Exception::create_message(scope, exception);
-
- let mut exception_message = None;
- let context_state_rc = JsRealm::state_from_scope(scope);
-
- let js_format_exception_cb =
- context_state_rc.borrow().js_format_exception_cb.clone();
- if let Some(format_exception_cb) = js_format_exception_cb {
- let format_exception_cb = format_exception_cb.open(scope);
- let this = v8::undefined(scope).into();
- let formatted = format_exception_cb.call(scope, this, &[exception]);
- if let Some(formatted) = formatted {
- if formatted.is_string() {
- exception_message = Some(formatted.to_rust_string_lossy(scope));
- }
- }
- }
-
- if is_instance_of_error(scope, exception) {
- let v8_exception = exception;
- // The exception is a JS Error object.
- let exception: v8::Local<v8::Object> = exception.try_into().unwrap();
- let cause = get_property(scope, exception, "cause");
- let e: NativeJsError =
- serde_v8::from_v8(scope, exception.into()).unwrap_or_default();
- // Get the message by formatting error.name and error.message.
- let name = e.name.clone().unwrap_or_else(|| "Error".to_string());
- let message_prop = e.message.clone().unwrap_or_default();
- let exception_message = exception_message.unwrap_or_else(|| {
- if !name.is_empty() && !message_prop.is_empty() {
- format!("Uncaught {name}: {message_prop}")
- } else if !name.is_empty() {
- format!("Uncaught {name}")
- } else if !message_prop.is_empty() {
- format!("Uncaught {message_prop}")
- } else {
- "Uncaught".to_string()
- }
- });
- let cause = cause.and_then(|cause| {
- if cause.is_undefined() || seen.contains(&exception) {
- None
- } else {
- seen.insert(exception);
- Some(Box::new(JsError::inner_from_v8_exception(
- scope, cause, seen,
- )))
- }
- });
-
- // Access error.stack to ensure that prepareStackTrace() has been called.
- // This should populate error.__callSiteEvals.
- let stack = get_property(scope, exception, "stack");
- let stack: Option<v8::Local<v8::String>> =
- stack.and_then(|s| s.try_into().ok());
- let stack = stack.map(|s| s.to_rust_string_lossy(scope));
-
- // Read an array of structured frames from error.__callSiteEvals.
- let frames_v8 = get_property(scope, exception, "__callSiteEvals");
- // Ignore non-array values
- let frames_v8: Option<v8::Local<v8::Array>> =
- frames_v8.and_then(|a| a.try_into().ok());
-
- // Convert them into Vec<JsStackFrame>
- let mut frames: Vec<JsStackFrame> = match frames_v8 {
- Some(frames_v8) => serde_v8::from_v8(scope, frames_v8.into()).unwrap(),
- None => vec![],
- };
- let mut source_line = None;
- let mut source_line_frame_index = None;
-
- // When the stack frame array is empty, but the source location given by
- // (script_resource_name, line_number, start_column + 1) exists, this is
- // likely a syntax error. For the sake of formatting we treat it like it
- // was given as a single stack frame.
- if frames.is_empty() {
- if let Some(stack_frame) = JsStackFrame::from_v8_message(scope, msg) {
- frames = vec![stack_frame];
- }
- }
- {
- let state_rc = JsRuntime::state_from(scope);
- let (getter, cache) = {
- let state = state_rc.borrow();
- (
- state.source_map_getter.clone(),
- state.source_map_cache.clone(),
- )
- };
- if let Some(source_map_getter) = getter {
- let mut cache = cache.borrow_mut();
-
- for (i, frame) in frames.iter().enumerate() {
- if let (Some(file_name), Some(line_number)) =
- (&frame.file_name, frame.line_number)
- {
- if !file_name.trim_start_matches('[').starts_with("ext:") {
- source_line = get_source_line(
- file_name,
- line_number,
- &mut cache,
- &**source_map_getter,
- );
- source_line_frame_index = Some(i);
- break;
- }
- }
- }
- } else if let Some(frame) = frames.first() {
- if let Some(file_name) = &frame.file_name {
- if !file_name.trim_start_matches('[').starts_with("ext:") {
- source_line = msg
- .get_source_line(scope)
- .map(|v| v.to_rust_string_lossy(scope));
- source_line_frame_index = Some(0);
- }
- }
- }
- }
-
- let mut aggregated: Option<Vec<JsError>> = None;
- if is_aggregate_error(scope, v8_exception) {
- // Read an array of stored errors, this is only defined for `AggregateError`
- let aggregated_errors = get_property(scope, exception, "errors");
- let aggregated_errors: Option<v8::Local<v8::Array>> =
- aggregated_errors.and_then(|a| a.try_into().ok());
-
- if let Some(errors) = aggregated_errors {
- if errors.length() > 0 {
- let mut agg = vec![];
- for i in 0..errors.length() {
- let error = errors.get_index(scope, i).unwrap();
- let js_error = Self::from_v8_exception(scope, error);
- agg.push(js_error);
- }
- aggregated = Some(agg);
- }
- }
- };
-
- Self {
- name: e.name,
- message: e.message,
- exception_message,
- cause,
- source_line,
- source_line_frame_index,
- frames,
- stack,
- aggregated,
- }
- } else {
- let exception_message = exception_message
- .unwrap_or_else(|| msg.get(scope).to_rust_string_lossy(scope));
- // The exception is not a JS Error object.
- // Get the message given by V8::Exception::create_message(), and provide
- // empty frames.
- Self {
- name: None,
- message: None,
- exception_message,
- cause: None,
- source_line: None,
- source_line_frame_index: None,
- frames: vec![],
- stack: None,
- aggregated: None,
- }
- }
- }
-}
-
-impl std::error::Error for JsError {}
-
-impl Display for JsError {
- fn fmt(&self, f: &mut Formatter) -> fmt::Result {
- if let Some(stack) = &self.stack {
- let stack_lines = stack.lines();
- if stack_lines.count() > 1 {
- return write!(f, "{stack}");
- }
- }
- write!(f, "{}", self.exception_message)?;
- let location = self.frames.first().and_then(|f| f.maybe_format_location());
- if let Some(location) = location {
- write!(f, "\n at {location}")?;
- }
- Ok(())
- }
-}
-
-// TODO(piscisaureus): rusty_v8 should implement the Error trait on
-// values of type v8::Global<T>.
-pub(crate) fn to_v8_type_error(
- scope: &mut v8::HandleScope,
- err: Error,
-) -> v8::Global<v8::Value> {
- let err_string = err.to_string();
- let error_chain = err
- .chain()
- .skip(1)
- .filter(|e| e.to_string() != err_string)
- .map(|e| e.to_string())
- .collect::<Vec<_>>();
-
- let message = if !error_chain.is_empty() {
- format!(
- "{}\n Caused by:\n {}",
- err_string,
- error_chain.join("\n ")
- )
- } else {
- err_string
- };
-
- let message = v8::String::new(scope, &message).unwrap();
- let exception = v8::Exception::type_error(scope, message);
- v8::Global::new(scope, exception)
-}
-
-/// Implements `value instanceof primordials.Error` in JS. Similar to
-/// `Value::is_native_error()` but more closely matches the semantics
-/// of `instanceof`. `Value::is_native_error()` also checks for static class
-/// inheritance rather than just scanning the prototype chain, which doesn't
-/// work with our WebIDL implementation of `DOMException`.
-pub(crate) fn is_instance_of_error(
- scope: &mut v8::HandleScope,
- value: v8::Local<v8::Value>,
-) -> bool {
- if !value.is_object() {
- return false;
- }
- let message = v8::String::empty(scope);
- let error_prototype = v8::Exception::error(scope, message)
- .to_object(scope)
- .unwrap()
- .get_prototype(scope)
- .unwrap();
- let mut maybe_prototype =
- value.to_object(scope).unwrap().get_prototype(scope);
- while let Some(prototype) = maybe_prototype {
- if !prototype.is_object() {
- return false;
- }
- if prototype.strict_equals(error_prototype) {
- return true;
- }
- maybe_prototype = prototype
- .to_object(scope)
- .and_then(|o| o.get_prototype(scope));
- }
- false
-}
-
-/// Implements `value instanceof primordials.AggregateError` in JS,
-/// by walking the prototype chain, and comparing each links constructor `name` property.
-///
-/// NOTE: There is currently no way to detect `AggregateError` via `rusty_v8`,
-/// as v8 itself doesn't expose `v8__Exception__AggregateError`,
-/// and we cannot create bindings for it. This forces us to rely on `name` inference.
-pub(crate) fn is_aggregate_error(
- scope: &mut v8::HandleScope,
- value: v8::Local<v8::Value>,
-) -> bool {
- let mut maybe_prototype = Some(value);
- while let Some(prototype) = maybe_prototype {
- if !prototype.is_object() {
- return false;
- }
-
- let prototype = prototype.to_object(scope).unwrap();
- let prototype_name = match get_property(scope, prototype, "constructor") {
- Some(constructor) => {
- let ctor = constructor.to_object(scope).unwrap();
- get_property(scope, ctor, "name").map(|v| v.to_rust_string_lossy(scope))
- }
- None => return false,
- };
-
- if prototype_name == Some(String::from("AggregateError")) {
- return true;
- }
-
- maybe_prototype = prototype.get_prototype(scope);
- }
-
- false
-}
-
-const DATA_URL_ABBREV_THRESHOLD: usize = 150;
-
-pub fn format_file_name(file_name: &str) -> String {
- abbrev_file_name(file_name).unwrap_or_else(|| file_name.to_string())
-}
-
-fn abbrev_file_name(file_name: &str) -> Option<String> {
- if file_name.len() <= DATA_URL_ABBREV_THRESHOLD {
- return None;
- }
- let url = Url::parse(file_name).ok()?;
- if url.scheme() != "data" {
- return None;
- }
- let (head, tail) = url.path().split_once(',')?;
- let len = tail.len();
- let start = tail.get(0..20)?;
- let end = tail.get(len - 20..)?;
- Some(format!("{}:{},{}......{}", url.scheme(), head, start, end))
-}
-
-pub(crate) fn exception_to_err_result<T>(
- scope: &mut v8::HandleScope,
- exception: v8::Local<v8::Value>,
- in_promise: bool,
-) -> Result<T, Error> {
- let state_rc = JsRuntime::state_from(scope);
-
- let was_terminating_execution = scope.is_execution_terminating();
- // Disable running microtasks for a moment. When upgrading to V8 v11.4
- // we discovered that canceling termination here will cause the queued
- // microtasks to run which breaks some tests.
- scope.set_microtasks_policy(v8::MicrotasksPolicy::Explicit);
- // If TerminateExecution was called, cancel isolate termination so that the
- // exception can be created. Note that `scope.is_execution_terminating()` may
- // have returned false if TerminateExecution was indeed called but there was
- // no JS to execute after the call.
- scope.cancel_terminate_execution();
- let mut exception = exception;
- {
- // If termination is the result of a `op_dispatch_exception` call, we want
- // to use the exception that was passed to it rather than the exception that
- // was passed to this function.
- let state = state_rc.borrow();
- exception = if let Some(exception) = &state.dispatched_exception {
- v8::Local::new(scope, exception.clone())
- } else if was_terminating_execution && exception.is_null_or_undefined() {
- let message = v8::String::new(scope, "execution terminated").unwrap();
- v8::Exception::error(scope, message)
- } else {
- exception
- };
- }
-
- let mut js_error = JsError::from_v8_exception(scope, exception);
- if in_promise {
- js_error.exception_message = format!(
- "Uncaught (in promise) {}",
- js_error.exception_message.trim_start_matches("Uncaught ")
- );
- }
-
- if was_terminating_execution {
- // Resume exception termination.
- scope.terminate_execution();
- }
- scope.set_microtasks_policy(v8::MicrotasksPolicy::Auto);
-
- Err(js_error.into())
-}
-
-pub fn throw_type_error(scope: &mut v8::HandleScope, message: impl AsRef<str>) {
- let message = v8::String::new(scope, message.as_ref()).unwrap();
- let exception = v8::Exception::type_error(scope, message);
- scope.throw_exception(exception);
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- #[test]
- fn test_bad_resource() {
- let err = bad_resource("Resource has been closed");
- assert_eq!(err.to_string(), "Resource has been closed");
- }
-
- #[test]
- fn test_bad_resource_id() {
- let err = bad_resource_id();
- assert_eq!(err.to_string(), "Bad resource ID");
- }
-}
diff --git a/core/error_codes.rs b/core/error_codes.rs
deleted file mode 100644
index ebe036609..000000000
--- a/core/error_codes.rs
+++ /dev/null
@@ -1,216 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-
-use anyhow::Error;
-
-pub fn get_error_code(err: &Error) -> Option<&'static str> {
- err
- .downcast_ref::<std::io::Error>()
- .map(|e| match e.raw_os_error() {
- Some(code) => get_os_error_code(code),
- None => get_io_error_code(e),
- })
- .and_then(|code| match code.is_empty() {
- true => None,
- false => Some(code),
- })
-}
-
-fn get_io_error_code(err: &std::io::Error) -> &'static str {
- // not exhaustive but simple and possibly sufficient once `io_error_more` is stabilized (https://github.com/rust-lang/rust/issues/86442)
- // inversion of https://github.com/rust-lang/rust/blob/dca3f1b786efd27be3b325ed1e01e247aa589c3b/library/std/src/sys/unix/mod.rs#L138-L185
- // TODO(@AaronO): revisit as `io_error_more` lands in rust stable
- use std::io::ErrorKind;
- match err.kind() {
- // ErrorKind::ArgumentListTooLong => "E2BIG",
- ErrorKind::AddrInUse => "EADDRINUSE",
- ErrorKind::AddrNotAvailable => "EADDRNOTAVAIL",
- // ErrorKind::ResourceBusy => "EBUSY",
- ErrorKind::ConnectionAborted => "ECONNABORTED",
- ErrorKind::ConnectionRefused => "ECONNREFUSED",
- ErrorKind::ConnectionReset => "ECONNRESET",
- // ErrorKind::Deadlock => "EDEADLK",
- // ErrorKind::FilesystemQuotaExceeded => "EDQUOT",
- ErrorKind::AlreadyExists => "EEXIST",
- // ErrorKind::FileTooLarge => "EFBIG",
- // ErrorKind::HostUnreachable => "EHOSTUNREACH",
- ErrorKind::Interrupted => "EINTR",
- ErrorKind::InvalidInput => "EINVAL",
- // ErrorKind::IsADirectory => "EISDIR",
- // ErrorKind::FilesystemLoop => "ELOOP",
- ErrorKind::NotFound => "ENOENT",
- ErrorKind::OutOfMemory => "ENOMEM",
- // ErrorKind::StorageFull => "ENOSPC",
- ErrorKind::Unsupported => "ENOSYS",
- // ErrorKind::TooManyLinks => "EMLINK",
- // ErrorKind::FilenameTooLong => "ENAMETOOLONG",
- // ErrorKind::NetworkDown => "ENETDOWN",
- // ErrorKind::NetworkUnreachable => "ENETUNREACH",
- ErrorKind::NotConnected => "ENOTCONN",
- // ErrorKind::NotADirectory => "ENOTDIR",
- // ErrorKind::DirectoryNotEmpty => "ENOTEMPTY",
- ErrorKind::BrokenPipe => "EPIPE",
- // ErrorKind::ReadOnlyFilesystem => "EROFS",
- // ErrorKind::NotSeekable => "ESPIPE",
- // ErrorKind::StaleNetworkFileHandle => "ESTALE",
- ErrorKind::TimedOut => "ETIMEDOUT",
- // ErrorKind::ExecutableFileBusy => "ETXTBSY",
- // ErrorKind::CrossesDevices => "EXDEV",
- ErrorKind::PermissionDenied => "EACCES", // NOTE: Collides with EPERM ...
- ErrorKind::WouldBlock => "EWOULDBLOCK", // NOTE: Collides with EAGAIN ...
- _ => "",
- }
-}
-
-/// Maps OS errno codes to string names
-/// derived from libuv: https://github.com/libuv/libuv/blob/26b2e5dbb6301756644d6e4cf6ca9c49c00513d3/include/uv/errno.h
-/// generated with tools/codegen_error_codes.js
-#[cfg(unix)]
-fn get_os_error_code(errno: i32) -> &'static str {
- match errno {
- libc::E2BIG => "E2BIG",
- libc::EACCES => "EACCES",
- libc::EADDRINUSE => "EADDRINUSE",
- libc::EADDRNOTAVAIL => "EADDRNOTAVAIL",
- libc::EAFNOSUPPORT => "EAFNOSUPPORT",
- libc::EAGAIN => "EAGAIN",
- libc::EALREADY => "EALREADY",
- libc::EBADF => "EBADF",
- libc::EBUSY => "EBUSY",
- libc::ECANCELED => "ECANCELED",
- libc::ECONNABORTED => "ECONNABORTED",
- libc::ECONNREFUSED => "ECONNREFUSED",
- libc::ECONNRESET => "ECONNRESET",
- libc::EEXIST => "EEXIST",
- libc::EFAULT => "EFAULT",
- libc::EHOSTUNREACH => "EHOSTUNREACH",
- libc::EINVAL => "EINVAL",
- libc::EIO => "EIO",
- libc::EISCONN => "EISCONN",
- libc::EISDIR => "EISDIR",
- libc::ELOOP => "ELOOP",
- libc::EMFILE => "EMFILE",
- libc::EMSGSIZE => "EMSGSIZE",
- libc::ENAMETOOLONG => "ENAMETOOLONG",
- libc::ENETUNREACH => "ENETUNREACH",
- libc::ENOBUFS => "ENOBUFS",
- libc::ENOENT => "ENOENT",
- libc::ENOMEM => "ENOMEM",
- libc::ENOSPC => "ENOSPC",
- libc::ENOTCONN => "ENOTCONN",
- libc::ENOTDIR => "ENOTDIR",
- libc::ENOTEMPTY => "ENOTEMPTY",
- libc::ENOTSOCK => "ENOTSOCK",
- libc::ENOTSUP => "ENOTSUP",
- libc::EPERM => "EPERM",
- libc::EPIPE => "EPIPE",
- libc::EPROTONOSUPPORT => "EPROTONOSUPPORT",
- libc::EROFS => "EROFS",
- libc::ETIMEDOUT => "ETIMEDOUT",
- libc::EXDEV => "EXDEV",
- libc::ESOCKTNOSUPPORT => "ESOCKTNOSUPPORT",
- _ => "",
- }
-}
-
-#[cfg(windows)]
-fn get_os_error_code(errno: i32) -> &'static str {
- match errno {
- 998 => "EACCES", // ERROR_NOACCESS
- 10013 => "EACCES", // WSAEACCES
- 1920 => "EACCES", // ERROR_CANT_ACCESS_FILE
- 1227 => "EADDRINUSE", // ERROR_ADDRESS_ALREADY_ASSOCIATED
- 10048 => "EADDRINUSE", // WSAEADDRINUSE
- 10049 => "EADDRNOTAVAIL", // WSAEADDRNOTAVAIL
- 10047 => "EAFNOSUPPORT", // WSAEAFNOSUPPORT
- 10035 => "EAGAIN", // WSAEWOULDBLOCK
- 10037 => "EALREADY", // WSAEALREADY
- 1004 => "EBADF", // ERROR_INVALID_FLAGS
- 6 => "EBADF", // ERROR_INVALID_HANDLE
- 33 => "EBUSY", // ERROR_LOCK_VIOLATION
- 231 => "EBUSY", // ERROR_PIPE_BUSY
- 32 => "EBUSY", // ERROR_SHARING_VIOLATION
- 995 => "ECANCELED", // ERROR_OPERATION_ABORTED
- 10004 => "ECANCELED", // WSAEINTR
- 1236 => "ECONNABORTED", // ERROR_CONNECTION_ABORTED
- 10053 => "ECONNABORTED", // WSAECONNABORTED
- 1225 => "ECONNREFUSED", // ERROR_CONNECTION_REFUSED
- 10061 => "ECONNREFUSED", // WSAECONNREFUSED
- 64 => "ECONNRESET", // ERROR_NETNAME_DELETED
- 10054 => "ECONNRESET", // WSAECONNRESET
- 183 => "EEXIST", // ERROR_ALREADY_EXISTS
- 80 => "EEXIST", // ERROR_FILE_EXISTS
- 111 => "EFAULT", // ERROR_BUFFER_OVERFLOW
- 10014 => "EFAULT", // WSAEFAULT
- 1232 => "EHOSTUNREACH", // ERROR_HOST_UNREACHABLE
- 10065 => "EHOSTUNREACH", // WSAEHOSTUNREACH
- 122 => "EINVAL", // ERROR_INSUFFICIENT_BUFFER
- 13 => "EINVAL", // ERROR_INVALID_DATA
- 87 => "EINVAL", // ERROR_INVALID_PARAMETER
- 1464 => "EINVAL", // ERROR_SYMLINK_NOT_SUPPORTED
- 10022 => "EINVAL", // WSAEINVAL
- 10046 => "EINVAL", // WSAEPFNOSUPPORT
- 1102 => "EIO", // ERROR_BEGINNING_OF_MEDIA
- 1111 => "EIO", // ERROR_BUS_RESET
- 23 => "EIO", // ERROR_CRC
- 1166 => "EIO", // ERROR_DEVICE_DOOR_OPEN
- 1165 => "EIO", // ERROR_DEVICE_REQUIRES_CLEANING
- 1393 => "EIO", // ERROR_DISK_CORRUPT
- 1129 => "EIO", // ERROR_EOM_OVERFLOW
- 1101 => "EIO", // ERROR_FILEMARK_DETECTED
- 31 => "EIO", // ERROR_GEN_FAILURE
- 1106 => "EIO", // ERROR_INVALID_BLOCK_LENGTH
- 1117 => "EIO", // ERROR_IO_DEVICE
- 1104 => "EIO", // ERROR_NO_DATA_DETECTED
- 205 => "EIO", // ERROR_NO_SIGNAL_SENT
- 110 => "EIO", // ERROR_OPEN_FAILED
- 1103 => "EIO", // ERROR_SETMARK_DETECTED
- 156 => "EIO", // ERROR_SIGNAL_REFUSED
- 10056 => "EISCONN", // WSAEISCONN
- 1921 => "ELOOP", // ERROR_CANT_RESOLVE_FILENAME
- 4 => "EMFILE", // ERROR_TOO_MANY_OPEN_FILES
- 10024 => "EMFILE", // WSAEMFILE
- 10040 => "EMSGSIZE", // WSAEMSGSIZE
- 206 => "ENAMETOOLONG", // ERROR_FILENAME_EXCED_RANGE
- 1231 => "ENETUNREACH", // ERROR_NETWORK_UNREACHABLE
- 10051 => "ENETUNREACH", // WSAENETUNREACH
- 10055 => "ENOBUFS", // WSAENOBUFS
- 161 => "ENOENT", // ERROR_BAD_PATHNAME
- 267 => "ENOENT", // ERROR_DIRECTORY
- 203 => "ENOENT", // ERROR_ENVVAR_NOT_FOUND
- 2 => "ENOENT", // ERROR_FILE_NOT_FOUND
- 123 => "ENOENT", // ERROR_INVALID_NAME
- 15 => "ENOENT", // ERROR_INVALID_DRIVE
- 4392 => "ENOENT", // ERROR_INVALID_REPARSE_DATA
- 126 => "ENOENT", // ERROR_MOD_NOT_FOUND
- 3 => "ENOENT", // ERROR_PATH_NOT_FOUND
- 11001 => "ENOENT", // WSAHOST_NOT_FOUND
- 11004 => "ENOENT", // WSANO_DATA
- 8 => "ENOMEM", // ERROR_NOT_ENOUGH_MEMORY
- 14 => "ENOMEM", // ERROR_OUTOFMEMORY
- 82 => "ENOSPC", // ERROR_CANNOT_MAKE
- 112 => "ENOSPC", // ERROR_DISK_FULL
- 277 => "ENOSPC", // ERROR_EA_TABLE_FULL
- 1100 => "ENOSPC", // ERROR_END_OF_MEDIA
- 39 => "ENOSPC", // ERROR_HANDLE_DISK_FULL
- 2250 => "ENOTCONN", // ERROR_NOT_CONNECTED
- 10057 => "ENOTCONN", // WSAENOTCONN
- 145 => "ENOTEMPTY", // ERROR_DIR_NOT_EMPTY
- 10038 => "ENOTSOCK", // WSAENOTSOCK
- 50 => "ENOTSUP", // ERROR_NOT_SUPPORTED
- 5 => "EPERM", // ERROR_ACCESS_DENIED
- 1314 => "EPERM", // ERROR_PRIVILEGE_NOT_HELD
- 230 => "EPIPE", // ERROR_BAD_PIPE
- 232 => "EPIPE", // ERROR_NO_DATA
- 233 => "EPIPE", // ERROR_PIPE_NOT_CONNECTED
- 10058 => "EPIPE", // WSAESHUTDOWN
- 10043 => "EPROTONOSUPPORT", // WSAEPROTONOSUPPORT
- 19 => "EROFS", // ERROR_WRITE_PROTECT
- 121 => "ETIMEDOUT", // ERROR_SEM_TIMEOUT
- 10060 => "ETIMEDOUT", // WSAETIMEDOUT
- 17 => "EXDEV", // ERROR_NOT_SAME_DEVICE
- 1 => "EISDIR", // ERROR_INVALID_FUNCTION
- 208 => "E2BIG", // ERROR_META_EXPANSION_TOO_LONG
- 10044 => "ESOCKTNOSUPPORT", // WSAESOCKTNOSUPPORT
- _ => "",
- }
-}
diff --git a/core/examples/disable_ops.rs b/core/examples/disable_ops.rs
deleted file mode 100644
index c75af1c3f..000000000
--- a/core/examples/disable_ops.rs
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-//! This example shows you how to define ops in Rust and then call them from
-//! JavaScript.
-
-use deno_core::Extension;
-use deno_core::JsRuntime;
-use deno_core::RuntimeOptions;
-
-fn main() {
- let my_ext = Extension::builder("my_ext")
- .middleware(|op| match op.name {
- "op_print" => op.disable(),
- _ => op,
- })
- .build();
-
- // Initialize a runtime instance
- let mut runtime = JsRuntime::new(RuntimeOptions {
- extensions: vec![my_ext],
- ..Default::default()
- });
-
- // Deno.core.print() will now be a NOP
- runtime
- .execute_script_static("<usage>", r#"Deno.core.print("I'm broken")"#)
- .unwrap();
-}
diff --git a/core/examples/eval_js_value.rs b/core/examples/eval_js_value.rs
deleted file mode 100644
index a752d7100..000000000
--- a/core/examples/eval_js_value.rs
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-//! This example shows you how to evaluate JavaScript expression and deserialize
-//! return value into a Rust object.
-
-// NOTE:
-// Here we are deserializing to `serde_json::Value` but you can
-// deserialize to any other type that implements the `Deserialize` trait.
-
-use deno_core::v8;
-use deno_core::JsRuntime;
-use deno_core::RuntimeOptions;
-
-fn main() {
- let mut runtime = JsRuntime::new(RuntimeOptions::default());
-
- // Evaluate some code
- let code = "let a = 1+4; a*2";
- let output: serde_json::Value =
- eval(&mut runtime, code).expect("Eval failed");
-
- println!("Output: {output:?}");
-
- let expected_output = serde_json::json!(10);
- assert_eq!(expected_output, output);
-}
-
-fn eval(
- context: &mut JsRuntime,
- code: &'static str,
-) -> Result<serde_json::Value, String> {
- let res = context.execute_script_static("<anon>", code);
- match res {
- Ok(global) => {
- let scope = &mut context.handle_scope();
- let local = v8::Local::new(scope, global);
- // Deserialize a `v8` object into a Rust type using `serde_v8`,
- // in this case deserialize to a JSON `Value`.
- let deserialized_value =
- serde_v8::from_v8::<serde_json::Value>(scope, local);
-
- match deserialized_value {
- Ok(value) => Ok(value),
- Err(err) => Err(format!("Cannot deserialize value: {err:?}")),
- }
- }
- Err(err) => Err(format!("Evaling error: {err:?}")),
- }
-}
diff --git a/core/examples/fs_module_loader.rs b/core/examples/fs_module_loader.rs
deleted file mode 100644
index 737ff1d5c..000000000
--- a/core/examples/fs_module_loader.rs
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-
-use anyhow::Context;
-use deno_core::anyhow::Error;
-use deno_core::FsModuleLoader;
-use deno_core::JsRuntime;
-use deno_core::RuntimeOptions;
-use std::rc::Rc;
-
-fn main() -> Result<(), Error> {
- let args: Vec<String> = std::env::args().collect();
- if args.len() < 2 {
- println!("Usage: target/examples/debug/fs_module_loader <path_to_module>");
- std::process::exit(1);
- }
- let main_url = &args[1];
- println!("Run {main_url}");
-
- let mut js_runtime = JsRuntime::new(RuntimeOptions {
- module_loader: Some(Rc::new(FsModuleLoader)),
- ..Default::default()
- });
-
- let runtime = tokio::runtime::Builder::new_current_thread()
- .enable_all()
- .build()?;
-
- let main_module = deno_core::resolve_path(
- main_url,
- &std::env::current_dir().context("Unable to get CWD")?,
- )?;
-
- let future = async move {
- let mod_id = js_runtime.load_main_module(&main_module, None).await?;
- let result = js_runtime.mod_evaluate(mod_id);
- js_runtime.run_event_loop(false).await?;
- result.await?
- };
- runtime.block_on(future)
-}
diff --git a/core/examples/hello_world.rs b/core/examples/hello_world.rs
deleted file mode 100644
index cce6e2218..000000000
--- a/core/examples/hello_world.rs
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-//! This example shows you how to define ops in Rust and then call them from
-//! JavaScript.
-
-use deno_core::op;
-use deno_core::Extension;
-use deno_core::JsRuntime;
-use deno_core::RuntimeOptions;
-
-// This is a hack to make the `#[op]` macro work with
-// deno_core examples.
-// You can remove this:
-use deno_core::*;
-
-#[op]
-fn op_sum(nums: Vec<f64>) -> Result<f64, deno_core::error::AnyError> {
- // Sum inputs
- let sum = nums.iter().fold(0.0, |a, v| a + v);
- // return as a Result<f64, AnyError>
- Ok(sum)
-}
-
-fn main() {
- // Build a deno_core::Extension providing custom ops
- let ext = Extension::builder("my_ext")
- .ops(vec![
- // An op for summing an array of numbers
- // The op-layer automatically deserializes inputs
- // and serializes the returned Result & value
- op_sum::decl(),
- ])
- .build();
-
- // Initialize a runtime instance
- let mut runtime = JsRuntime::new(RuntimeOptions {
- extensions: vec![ext],
- ..Default::default()
- });
-
- // Now we see how to invoke the op we just defined. The runtime automatically
- // contains a Deno.core object with several functions for interacting with it.
- // You can find its definition in core.js.
- runtime
- .execute_script_static(
- "<usage>",
- r#"
-// Print helper function, calling Deno.core.print()
-function print(value) {
- Deno.core.print(value.toString()+"\n");
-}
-
-const arr = [1, 2, 3];
-print("The sum of");
-print(arr);
-print("is");
-print(Deno.core.ops.op_sum(arr));
-
-// And incorrect usage
-try {
- print(Deno.core.ops.op_sum(0));
-} catch(e) {
- print('Exception:');
- print(e);
-}
-"#,
- )
- .unwrap();
-}
diff --git a/core/examples/http_bench_json_ops/http_bench_json_ops.js b/core/examples/http_bench_json_ops/http_bench_json_ops.js
deleted file mode 100644
index a840e4e9f..000000000
--- a/core/examples/http_bench_json_ops/http_bench_json_ops.js
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-// This is not a real HTTP server. We read blindly one time into 'requestBuf',
-// then write this fixed 'responseBuf'. The point of this benchmark is to
-// exercise the event loop in a simple yet semi-realistic way.
-
-// deno-lint-ignore-file camelcase
-
-const { op_listen } = Deno.core.ops;
-const {
- op_accept,
- op_read_socket,
-} = Deno.core.ensureFastOps();
-
-const requestBuf = new Uint8Array(64 * 1024);
-const responseBuf = new Uint8Array(
- "HTTP/1.1 200 OK\r\nContent-Length: 12\r\n\r\nHello World\n"
- .split("")
- .map((c) => c.charCodeAt(0)),
-);
-
-async function serve(rid) {
- try {
- while (true) {
- await op_read_socket(rid, requestBuf);
- if (!ops.op_try_write(rid, responseBuf)) {
- await Deno.core.writeAll(rid, responseBuf);
- }
- }
- } catch {
- // pass
- }
- Deno.core.close(rid);
-}
-
-async function main() {
- /** Listens on 0.0.0.0:4570, returns rid. */
- const listenerRid = op_listen();
- Deno.core.print(`http_bench_ops listening on http://127.0.0.1:4570/\n`);
-
- while (true) {
- const rid = await op_accept(listenerRid);
- serve(rid);
- }
-}
-
-main();
diff --git a/core/examples/http_bench_json_ops/main.rs b/core/examples/http_bench_json_ops/main.rs
deleted file mode 100644
index a4d6afe31..000000000
--- a/core/examples/http_bench_json_ops/main.rs
+++ /dev/null
@@ -1,176 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-use deno_core::anyhow::Error;
-use deno_core::op;
-use deno_core::AsyncRefCell;
-use deno_core::AsyncResult;
-use deno_core::JsBuffer;
-use deno_core::JsRuntimeForSnapshot;
-use deno_core::OpState;
-use deno_core::Resource;
-use deno_core::ResourceId;
-use std::cell::RefCell;
-use std::env;
-use std::net::SocketAddr;
-use std::rc::Rc;
-use tokio::io::AsyncReadExt;
-use tokio::io::AsyncWriteExt;
-
-// This is a hack to make the `#[op]` macro work with
-// deno_core examples.
-// You can remove this:
-use deno_core::*;
-
-// Note: a `tokio::net::TcpListener` doesn't need to be wrapped in a cell,
-// because it only supports one op (`accept`) which does not require a mutable
-// reference to the listener.
-struct TcpListener {
- inner: tokio::net::TcpListener,
-}
-
-impl TcpListener {
- async fn accept(self: Rc<Self>) -> Result<TcpStream, std::io::Error> {
- let stream = self.inner.accept().await?.0.into();
- Ok(stream)
- }
-}
-
-impl Resource for TcpListener {
- fn close(self: Rc<Self>) {}
-}
-
-impl TryFrom<std::net::TcpListener> for TcpListener {
- type Error = std::io::Error;
- fn try_from(
- std_listener: std::net::TcpListener,
- ) -> Result<Self, Self::Error> {
- tokio::net::TcpListener::try_from(std_listener).map(|tokio_listener| Self {
- inner: tokio_listener,
- })
- }
-}
-
-struct TcpStream {
- rd: AsyncRefCell<tokio::net::tcp::OwnedReadHalf>,
- wr: AsyncRefCell<tokio::net::tcp::OwnedWriteHalf>,
-}
-
-impl TcpStream {
- async fn read(self: Rc<Self>, data: &mut [u8]) -> Result<usize, Error> {
- let mut rd = RcRef::map(&self, |r| &r.rd).borrow_mut().await;
- let nread = rd.read(data).await?;
- Ok(nread)
- }
-
- async fn write(self: Rc<Self>, data: &[u8]) -> Result<usize, Error> {
- let mut wr = RcRef::map(self, |r| &r.wr).borrow_mut().await;
- let nwritten = wr.write(data).await?;
- Ok(nwritten)
- }
-
- fn try_write(self: Rc<Self>, data: &[u8]) -> Result<usize, Error> {
- let wr = RcRef::map(self, |r| &r.wr)
- .try_borrow_mut()
- .ok_or_else(|| Error::msg("Failed to acquire lock on TcpStream"))?;
- let nwritten = wr.try_write(data)?;
- Ok(nwritten)
- }
-}
-
-impl Resource for TcpStream {
- deno_core::impl_readable_byob!();
- deno_core::impl_writable!();
-
- fn close(self: Rc<Self>) {}
-}
-
-impl From<tokio::net::TcpStream> for TcpStream {
- fn from(s: tokio::net::TcpStream) -> Self {
- let (rd, wr) = s.into_split();
- Self {
- rd: rd.into(),
- wr: wr.into(),
- }
- }
-}
-
-fn create_js_runtime() -> JsRuntimeForSnapshot {
- let ext = deno_core::Extension::builder("my_ext")
- .ops(vec![
- op_listen::decl(),
- op_accept::decl(),
- op_try_write::decl(),
- op_read_socket::decl(),
- ])
- .build();
-
- JsRuntimeForSnapshot::new(
- deno_core::RuntimeOptions {
- extensions: vec![ext],
- ..Default::default()
- },
- Default::default(),
- )
-}
-
-#[op]
-async fn op_read_socket(
- state: Rc<RefCell<OpState>>,
- rid: ResourceId,
- mut data: JsBuffer,
-) -> Result<u32, Error> {
- let resource = state.borrow_mut().resource_table.get::<TcpStream>(rid)?;
- let nread = resource.read(&mut data).await?;
- Ok(nread as u32)
-}
-
-#[op]
-fn op_listen(state: &mut OpState) -> Result<ResourceId, Error> {
- let addr = "127.0.0.1:4570".parse::<SocketAddr>().unwrap();
- let std_listener = std::net::TcpListener::bind(addr)?;
- std_listener.set_nonblocking(true)?;
- let listener = TcpListener::try_from(std_listener)?;
- let rid = state.resource_table.add(listener);
- Ok(rid)
-}
-
-#[op]
-async fn op_accept(
- state: Rc<RefCell<OpState>>,
- rid: ResourceId,
-) -> Result<ResourceId, Error> {
- let listener = state.borrow().resource_table.get::<TcpListener>(rid)?;
- let stream = listener.accept().await?;
- let rid = state.borrow_mut().resource_table.add(stream);
- Ok(rid)
-}
-
-#[op(fast)]
-fn op_try_write(
- state: &mut OpState,
- rid: u32,
- value: &[u8],
-) -> Result<bool, Error> {
- let stream = state.resource_table.get::<TcpStream>(rid)?;
- Ok(stream.try_write(value).is_ok())
-}
-
-fn main() {
- // NOTE: `--help` arg will display V8 help and exit
- deno_core::v8_set_flags(env::args().collect());
-
- let mut js_runtime = create_js_runtime();
- let runtime = tokio::runtime::Builder::new_current_thread()
- .enable_io()
- .build()
- .unwrap();
- let future = async move {
- js_runtime
- .execute_script(
- "http_bench_json_ops.js",
- include_ascii_string!("http_bench_json_ops.js"),
- )
- .unwrap();
- js_runtime.run_event_loop(false).await
- };
- runtime.block_on(future).unwrap();
-}
diff --git a/core/examples/panik.rs b/core/examples/panik.rs
deleted file mode 100644
index 54b46d337..000000000
--- a/core/examples/panik.rs
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-//! This example shows that op-panics currently result in UB (likely "failed to initiate panic")
-//! without a custom panic hook that aborts the process or -C panic=abort.
-//!
-//! This happens due to the UB of panicking in an extern "C",
-//! given how ops are reduced via rusty_v8::MapFnTo
-//! See:
-//! - https://github.com/rust-lang/rust/issues/74990
-//! - https://rust-lang.github.io/rfcs/2945-c-unwind-abi.html
-
-use deno_core::op;
-use deno_core::Extension;
-use deno_core::JsRuntime;
-use deno_core::RuntimeOptions;
-
-// This is a hack to make the `#[op]` macro work with
-// deno_core examples.
-// You can remove this:
-use deno_core::*;
-
-fn main() {
- #[op]
- fn op_panik() {
- panic!("panik !!!")
- }
-
- let extensions = vec![Extension::builder("my_ext")
- .ops(vec![op_panik::decl()])
- .build()];
- let mut rt = JsRuntime::new(RuntimeOptions {
- extensions,
- ..Default::default()
- });
- rt.execute_script_static("panik", "Deno.core.ops.op_panik()")
- .unwrap();
-}
diff --git a/core/examples/schedule_task.rs b/core/examples/schedule_task.rs
deleted file mode 100644
index 348ba7666..000000000
--- a/core/examples/schedule_task.rs
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-
-use deno_core::anyhow::Error;
-use deno_core::op;
-use deno_core::Extension;
-use deno_core::JsRuntime;
-use deno_core::OpState;
-use deno_core::RuntimeOptions;
-use futures::channel::mpsc;
-use futures::stream::StreamExt;
-use std::task::Poll;
-
-// This is a hack to make the `#[op]` macro work with
-// deno_core examples.
-// You can remove this:
-use deno_core::*;
-
-type Task = Box<dyn FnOnce()>;
-
-fn main() {
- let my_ext = Extension::builder("my_ext")
- .ops(vec![op_schedule_task::decl()])
- .event_loop_middleware(|state_rc, cx| {
- let mut state = state_rc.borrow_mut();
- let recv = state.borrow_mut::<mpsc::UnboundedReceiver<Task>>();
- let mut ref_loop = false;
- while let Poll::Ready(Some(call)) = recv.poll_next_unpin(cx) {
- call();
- ref_loop = true; // `call` can callback into runtime and schedule new callbacks :-)
- }
- ref_loop
- })
- .state(move |state| {
- let (tx, rx) = mpsc::unbounded::<Task>();
- state.put(tx);
- state.put(rx);
- })
- .build();
-
- // Initialize a runtime instance
- let mut js_runtime = JsRuntime::new(RuntimeOptions {
- extensions: vec![my_ext],
- ..Default::default()
- });
- let runtime = tokio::runtime::Builder::new_current_thread()
- .enable_all()
- .build()
- .unwrap();
-
- let future = async move {
- // Schedule 10 tasks.
- js_runtime
- .execute_script_static(
- "<usage>",
- r#"for (let i = 1; i <= 10; i++) Deno.core.ops.op_schedule_task(i);"#,
- )
- .unwrap();
- js_runtime.run_event_loop(false).await
- };
- runtime.block_on(future).unwrap();
-}
-
-#[op]
-fn op_schedule_task(state: &mut OpState, i: u8) -> Result<(), Error> {
- let tx = state.borrow_mut::<mpsc::UnboundedSender<Task>>();
- tx.unbounded_send(Box::new(move || println!("Hello, world! x{i}")))
- .expect("unbounded_send failed");
- Ok(())
-}
diff --git a/core/examples/ts_module_loader.rs b/core/examples/ts_module_loader.rs
deleted file mode 100644
index 6adb27977..000000000
--- a/core/examples/ts_module_loader.rs
+++ /dev/null
@@ -1,128 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-//! This example shows how to use swc to transpile TypeScript and JSX/TSX
-//! modules.
-//!
-//! It will only transpile, not typecheck (like Deno's `--no-check` flag).
-
-use std::pin::Pin;
-use std::rc::Rc;
-
-use anyhow::anyhow;
-use anyhow::bail;
-use anyhow::Context;
-use anyhow::Error;
-use deno_ast::MediaType;
-use deno_ast::ParseParams;
-use deno_ast::SourceTextInfo;
-use deno_core::error::AnyError;
-use deno_core::resolve_import;
-use deno_core::resolve_path;
-use deno_core::JsRuntime;
-use deno_core::ModuleLoader;
-use deno_core::ModuleSource;
-use deno_core::ModuleSourceFuture;
-use deno_core::ModuleSpecifier;
-use deno_core::ModuleType;
-use deno_core::ResolutionKind;
-use deno_core::RuntimeOptions;
-use futures::FutureExt;
-
-struct TypescriptModuleLoader;
-
-impl ModuleLoader for TypescriptModuleLoader {
- fn resolve(
- &self,
- specifier: &str,
- referrer: &str,
- _kind: ResolutionKind,
- ) -> Result<ModuleSpecifier, Error> {
- Ok(resolve_import(specifier, referrer)?)
- }
-
- fn load(
- &self,
- module_specifier: &ModuleSpecifier,
- _maybe_referrer: Option<&ModuleSpecifier>,
- _is_dyn_import: bool,
- ) -> Pin<Box<ModuleSourceFuture>> {
- fn load(
- module_specifier: &ModuleSpecifier,
- ) -> Result<ModuleSource, AnyError> {
- let path = module_specifier
- .to_file_path()
- .map_err(|_| anyhow!("Only file:// URLs are supported."))?;
-
- let media_type = MediaType::from_path(&path);
- let (module_type, should_transpile) = match MediaType::from_path(&path) {
- MediaType::JavaScript | MediaType::Mjs | MediaType::Cjs => {
- (ModuleType::JavaScript, false)
- }
- MediaType::Jsx => (ModuleType::JavaScript, true),
- MediaType::TypeScript
- | MediaType::Mts
- | MediaType::Cts
- | MediaType::Dts
- | MediaType::Dmts
- | MediaType::Dcts
- | MediaType::Tsx => (ModuleType::JavaScript, true),
- MediaType::Json => (ModuleType::Json, false),
- _ => bail!("Unknown extension {:?}", path.extension()),
- };
-
- let code = std::fs::read_to_string(&path)?;
- let code = if should_transpile {
- let parsed = deno_ast::parse_module(ParseParams {
- specifier: module_specifier.to_string(),
- text_info: SourceTextInfo::from_string(code),
- media_type,
- capture_tokens: false,
- scope_analysis: false,
- maybe_syntax: None,
- })?;
- parsed.transpile(&Default::default())?.text
- } else {
- code
- };
- Ok(ModuleSource::new(
- module_type,
- code.into(),
- module_specifier,
- ))
- }
-
- futures::future::ready(load(module_specifier)).boxed_local()
- }
-}
-
-fn main() -> Result<(), Error> {
- let args: Vec<String> = std::env::args().collect();
- if args.len() < 2 {
- println!("Usage: target/examples/debug/ts_module_loader <path_to_module>");
- std::process::exit(1);
- }
- let main_url = &args[1];
- println!("Run {main_url}");
-
- let mut js_runtime = JsRuntime::new(RuntimeOptions {
- module_loader: Some(Rc::new(TypescriptModuleLoader)),
- ..Default::default()
- });
-
- let main_module = resolve_path(
- main_url,
- &std::env::current_dir().context("Unable to get CWD")?,
- )?;
-
- let future = async move {
- let mod_id = js_runtime.load_main_module(&main_module, None).await?;
- let result = js_runtime.mod_evaluate(mod_id);
- js_runtime.run_event_loop(false).await?;
- result.await?
- };
-
- tokio::runtime::Builder::new_current_thread()
- .enable_all()
- .build()
- .unwrap()
- .block_on(future)
-}
diff --git a/core/examples/wasm.js b/core/examples/wasm.js
deleted file mode 100644
index cb6a4af52..000000000
--- a/core/examples/wasm.js
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-
-// asc wasm.ts --exportStart --initialMemory 6400 -O -o wasm.wasm
-// deno-fmt-ignore
-const bytes = new Uint8Array([
- 0, 97, 115, 109, 1, 0, 0, 0, 1, 4, 1, 96, 0, 0, 2,
- 15, 1, 3, 111, 112, 115, 7, 111, 112, 95, 119, 97, 115, 109, 0,
- 0, 3, 3, 2, 0, 0, 5, 4, 1, 0, 128, 50, 7, 36, 4,
- 7, 111, 112, 95, 119, 97, 115, 109, 0, 0, 4, 99, 97, 108, 108,
- 0, 1, 6, 109, 101, 109, 111, 114, 121, 2, 0, 6, 95, 115, 116,
- 97, 114, 116, 0, 2, 10, 10, 2, 4, 0, 16, 0, 11, 3, 0,
- 1, 11
- ]);
-
-const { ops } = Deno.core;
-
-const module = new WebAssembly.Module(bytes);
-const instance = new WebAssembly.Instance(module, { ops });
-ops.op_set_wasm_mem(instance.exports.memory);
-
-instance.exports.call();
-
-const memory = instance.exports.memory;
-const view = new Uint8Array(memory.buffer);
-
-if (view[0] !== 69) {
- throw new Error("Expected first byte to be 69");
-}
diff --git a/core/examples/wasm.rs b/core/examples/wasm.rs
deleted file mode 100644
index 5d5c5f6ff..000000000
--- a/core/examples/wasm.rs
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-
-use deno_core::op;
-use deno_core::Extension;
-use deno_core::JsRuntime;
-use deno_core::RuntimeOptions;
-use std::mem::transmute;
-use std::ptr::NonNull;
-
-// This is a hack to make the `#[op]` macro work with
-// deno_core examples.
-// You can remove this:
-
-use deno_core::*;
-
-struct WasmMemory(NonNull<v8::WasmMemoryObject>);
-
-fn wasm_memory_unchecked(state: &mut OpState) -> &mut [u8] {
- let WasmMemory(global) = state.borrow::<WasmMemory>();
- // SAFETY: `v8::Local` is always non-null pointer; the `HandleScope` is
- // already on the stack, but we don't have access to it.
- let memory_object = unsafe {
- transmute::<NonNull<v8::WasmMemoryObject>, v8::Local<v8::WasmMemoryObject>>(
- *global,
- )
- };
- let backing_store = memory_object.buffer().get_backing_store();
- let ptr = backing_store.data().unwrap().as_ptr() as *mut u8;
- let len = backing_store.byte_length();
- // SAFETY: `ptr` is a valid pointer to `len` bytes.
- unsafe { std::slice::from_raw_parts_mut(ptr, len) }
-}
-
-#[op(wasm)]
-fn op_wasm(state: &mut OpState, memory: Option<&mut [u8]>) {
- let memory = memory.unwrap_or_else(|| wasm_memory_unchecked(state));
- memory[0] = 69;
-}
-
-#[op(v8)]
-fn op_set_wasm_mem(
- scope: &mut v8::HandleScope,
- state: &mut OpState,
- memory: serde_v8::Value,
-) {
- let memory =
- v8::Local::<v8::WasmMemoryObject>::try_from(memory.v8_value).unwrap();
- let global = v8::Global::new(scope, memory);
- state.put(WasmMemory(global.into_raw()));
-}
-
-fn main() {
- // Build a deno_core::Extension providing custom ops
- let ext = Extension::builder("my_ext")
- .ops(vec![op_wasm::decl(), op_set_wasm_mem::decl()])
- .build();
-
- // Initialize a runtime instance
- let mut runtime = JsRuntime::new(RuntimeOptions {
- extensions: vec![ext],
- ..Default::default()
- });
-
- runtime
- .execute_script("<usage>", include_ascii_string!("wasm.js"))
- .unwrap();
-}
diff --git a/core/examples/wasm.ts b/core/examples/wasm.ts
deleted file mode 100644
index 4cf364c3a..000000000
--- a/core/examples/wasm.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-
-export declare function op_wasm(): void;
-
-export function call(): void {
- op_wasm();
-}
diff --git a/core/extensions.rs b/core/extensions.rs
deleted file mode 100644
index dac19ec50..000000000
--- a/core/extensions.rs
+++ /dev/null
@@ -1,645 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-use crate::modules::ModuleCode;
-use crate::OpState;
-use anyhow::Context as _;
-use anyhow::Error;
-use std::cell::RefCell;
-use std::path::PathBuf;
-use std::rc::Rc;
-use std::task::Context;
-use v8::fast_api::FastFunction;
-
-#[derive(Clone, Debug)]
-pub enum ExtensionFileSourceCode {
- /// Source code is included in the binary produced. Either by being defined
- /// inline, or included using `include_str!()`. If you are snapshotting, this
- /// will result in two copies of the source code being included - one in the
- /// snapshot, the other the static string in the `Extension`.
- IncludedInBinary(&'static str),
-
- // Source code is loaded from a file on disk. It's meant to be used if the
- // embedder is creating snapshots. Files will be loaded from the filesystem
- // during the build time and they will only be present in the V8 snapshot.
- LoadedFromFsDuringSnapshot(PathBuf),
-}
-
-#[derive(Clone, Debug)]
-pub struct ExtensionFileSource {
- pub specifier: &'static str,
- pub code: ExtensionFileSourceCode,
-}
-
-impl ExtensionFileSource {
- fn find_non_ascii(s: &str) -> String {
- s.chars().filter(|c| !c.is_ascii()).collect::<String>()
- }
-
- pub fn load(&self) -> Result<ModuleCode, Error> {
- match &self.code {
- ExtensionFileSourceCode::IncludedInBinary(code) => {
- debug_assert!(
- code.is_ascii(),
- "Extension code must be 7-bit ASCII: {} (found {})",
- self.specifier,
- Self::find_non_ascii(code)
- );
- Ok(ModuleCode::from_static(code))
- }
- ExtensionFileSourceCode::LoadedFromFsDuringSnapshot(path) => {
- let msg = || format!("Failed to read \"{}\"", path.display());
- let s = std::fs::read_to_string(path).with_context(msg)?;
- debug_assert!(
- s.is_ascii(),
- "Extension code must be 7-bit ASCII: {} (found {})",
- self.specifier,
- Self::find_non_ascii(&s)
- );
- Ok(s.into())
- }
- }
- }
-}
-
-pub type OpFnRef = v8::FunctionCallback;
-pub type OpMiddlewareFn = dyn Fn(OpDecl) -> OpDecl;
-pub type OpStateFn = dyn FnOnce(&mut OpState);
-pub type OpEventLoopFn = dyn Fn(Rc<RefCell<OpState>>, &mut Context) -> bool;
-
-/// Trait implemented by all generated ops.
-pub trait Op {
- const NAME: &'static str;
- const DECL: OpDecl;
-}
-
-pub struct OpDecl {
- pub name: &'static str,
- pub v8_fn_ptr: OpFnRef,
- pub enabled: bool,
- pub is_async: bool,
- pub is_unstable: bool,
- pub is_v8: bool,
- pub arg_count: u8,
- pub fast_fn: Option<FastFunction>,
-}
-
-impl OpDecl {
- pub fn enabled(self, enabled: bool) -> Self {
- Self { enabled, ..self }
- }
-
- pub fn disable(self) -> Self {
- self.enabled(false)
- }
-}
-
-/// Declares a block of Deno `#[op]`s. The first parameter determines the name of the
-/// op declaration block, and is usually `deno_ops`. This block generates a function that
-/// returns a [`Vec<OpDecl>`].
-///
-/// This can be either a compact form like:
-///
-/// ```no_compile
-/// # use deno_core::*;
-/// #[op]
-/// fn op_xyz() {}
-///
-/// deno_core::ops!(deno_ops, [
-/// op_xyz
-/// ]);
-///
-/// // Use the ops:
-/// deno_ops()
-/// ```
-///
-/// ... or a parameterized form like so that allows passing a number of type parameters
-/// to each `#[op]`:
-///
-/// ```no_compile
-/// # use deno_core::*;
-/// #[op]
-/// fn op_xyz<P>() where P: Clone {}
-///
-/// deno_core::ops!(deno_ops,
-/// parameters = [P: Clone],
-/// ops = [
-/// op_xyz<P>
-/// ]
-/// );
-///
-/// // Use the ops, with `String` as the parameter `P`:
-/// deno_ops::<String>()
-/// ```
-#[macro_export]
-macro_rules! ops {
- ($name:ident, parameters = [ $( $param:ident : $type:ident ),+ ], ops = [ $( $(#[$m:meta])* $( $op:ident )::+ $( < $op_param:ident > )? ),+ $(,)? ]) => {
- pub(crate) fn $name < $( $param : $type + 'static ),+ > () -> Vec<$crate::OpDecl> {
- vec![
- $(
- $( #[ $m ] )*
- $( $op )::+ :: decl $( :: <$op_param> )? () ,
- )+
- ]
- }
- };
- ($name:ident, [ $( $(#[$m:meta])* $( $op:ident )::+ ),+ $(,)? ] ) => {
- pub(crate) fn $name() -> Vec<$crate::OpDecl> {
- vec![
- $( $( #[ $m ] )* $( $op )::+ :: decl(), )+
- ]
- }
- }
-}
-
-/// Defines a Deno extension. The first parameter is the name of the extension symbol namespace to create. This is the symbol you
-/// will use to refer to the extension.
-///
-/// Most extensions will define a combination of ops and ESM files, like so:
-///
-/// ```no_compile
-/// #[op]
-/// fn op_xyz() {
-/// }
-///
-/// deno_core::extension!(
-/// my_extension,
-/// ops = [ op_xyz ],
-/// esm = [ "my_script.js" ],
-/// );
-/// ```
-///
-/// The following options are available for the [`extension`] macro:
-///
-/// * deps: a comma-separated list of module dependencies, eg: `deps = [ my_other_extension ]`
-/// * parameters: a comma-separated list of parameters and base traits, eg: `parameters = [ P: MyTrait ]`
-/// * bounds: a comma-separated list of additional type bounds, eg: `bounds = [ P::MyAssociatedType: MyTrait ]`
-/// * ops: a comma-separated list of [`OpDecl`]s to provide, eg: `ops = [ op_foo, op_bar ]`
-/// * esm: a comma-separated list of ESM module filenames (see [`include_js_files`]), eg: `esm = [ dir "dir", "my_file.js" ]`
-/// * js: a comma-separated list of JS filenames (see [`include_js_files`]), eg: `js = [ dir "dir", "my_file.js" ]`
-/// * config: a structure-like definition for configuration parameters which will be required when initializing this extension, eg: `config = { my_param: Option<usize> }`
-/// * middleware: an [`OpDecl`] middleware function with the signature `fn (OpDecl) -> OpDecl`
-/// * state: a state initialization function, with the signature `fn (&mut OpState, ...) -> ()`, where `...` are parameters matching the fields of the config struct
-/// * event_loop_middleware: an event-loop middleware function (see [`ExtensionBuilder::event_loop_middleware`])
-#[macro_export]
-macro_rules! extension {
- (
- $name:ident
- $(, deps = [ $( $dep:ident ),* ] )?
- $(, parameters = [ $( $param:ident : $type:ident ),+ ] )?
- $(, bounds = [ $( $bound:path : $bound_type:ident ),+ ] )?
- $(, ops_fn = $ops_symbol:ident $( < $ops_param:ident > )? )?
- $(, ops = [ $( $(#[$m:meta])* $( $op:ident )::+ $( < $( $op_param:ident ),* > )? ),+ $(,)? ] )?
- $(, esm_entry_point = $esm_entry_point:literal )?
- $(, esm = [ $( dir $dir_esm:literal , )? $( $esm:literal ),* $(,)? ] )?
- $(, js = [ $( dir $dir_js:literal , )? $( $js:literal ),* $(,)? ] )?
- $(, options = { $( $options_id:ident : $options_type:ty ),* $(,)? } )?
- $(, middleware = $middleware_fn:expr )?
- $(, state = $state_fn:expr )?
- $(, event_loop_middleware = $event_loop_middleware_fn:ident )?
- $(, customizer = $customizer_fn:expr )?
- $(,)?
- ) => {
- /// Extension struct for
- #[doc = stringify!($name)]
- /// .
- #[allow(non_camel_case_types)]
- pub struct $name {
- }
-
- impl $name {
- #[inline(always)]
- fn ext() -> $crate::ExtensionBuilder {
- $crate::Extension::builder_with_deps(stringify!($name), &[ $( $( stringify!($dep) ),* )? ])
- }
-
- /// If ESM or JS was specified, add those files to the extension.
- #[inline(always)]
- #[allow(unused_variables)]
- fn with_js(ext: &mut $crate::ExtensionBuilder) {
- $( ext.esm(
- $crate::include_js_files!( $name $( dir $dir_esm , )? $( $esm , )* )
- ); )?
- $(
- ext.esm_entry_point($esm_entry_point);
- )?
- $( ext.js(
- $crate::include_js_files!( $name $( dir $dir_js , )? $( $js , )* )
- ); )?
- }
-
- // If ops were specified, add those ops to the extension.
- #[inline(always)]
- #[allow(unused_variables)]
- fn with_ops $( < $( $param : $type + 'static ),+ > )?(ext: &mut $crate::ExtensionBuilder)
- $( where $( $bound : $bound_type ),+ )?
- {
- // If individual ops are specified, roll them up into a vector and apply them
- $(
- ext.ops(vec![
- $(
- $( #[ $m ] )*
- $( $op )::+ $( :: < $($op_param),* > )? :: decl ()
- ),+
- ]);
- )?
-
- // Otherwise use the ops_fn, if provided
- $crate::extension!(! __ops__ ext $( $ops_symbol $( < $ops_param > )? )? __eot__);
- }
-
- // Includes the state and middleware functions, if defined.
- #[inline(always)]
- #[allow(unused_variables)]
- fn with_state_and_middleware$( < $( $param : $type + 'static ),+ > )?(ext: &mut $crate::ExtensionBuilder, $( $( $options_id : $options_type ),* )? )
- $( where $( $bound : $bound_type ),+ )?
- {
- $crate::extension!(! __config__ ext $( parameters = [ $( $param : $type ),* ] )? $( config = { $( $options_id : $options_type ),* } )? $( state_fn = $state_fn )? );
-
- $(
- ext.event_loop_middleware($event_loop_middleware_fn);
- )?
-
- $(
- ext.middleware($middleware_fn);
- )?
- }
-
- #[inline(always)]
- #[allow(unused_variables)]
- #[allow(clippy::redundant_closure_call)]
- fn with_customizer(ext: &mut $crate::ExtensionBuilder) {
- $( ($customizer_fn)(ext); )?
- }
-
- #[allow(dead_code)]
- pub fn init_js_only $( < $( $param : $type + 'static ),* > )? () -> $crate::Extension
- $( where $( $bound : $bound_type ),+ )?
- {
- let mut ext = Self::ext();
- // If esm or JS was specified, add JS files
- Self::with_js(&mut ext);
- Self::with_ops $( ::< $( $param ),+ > )?(&mut ext);
- Self::with_customizer(&mut ext);
- ext.take()
- }
-
- #[allow(dead_code)]
- pub fn init_ops_and_esm $( < $( $param : $type + 'static ),+ > )? ( $( $( $options_id : $options_type ),* )? ) -> $crate::Extension
- $( where $( $bound : $bound_type ),+ )?
- {
- let mut ext = Self::ext();
- // If esm or JS was specified, add JS files
- Self::with_js(&mut ext);
- Self::with_ops $( ::< $( $param ),+ > )?(&mut ext);
- Self::with_state_and_middleware $( ::< $( $param ),+ > )?(&mut ext, $( $( $options_id , )* )? );
- Self::with_customizer(&mut ext);
- ext.take()
- }
-
- #[allow(dead_code)]
- pub fn init_ops $( < $( $param : $type + 'static ),+ > )? ( $( $( $options_id : $options_type ),* )? ) -> $crate::Extension
- $( where $( $bound : $bound_type ),+ )?
- {
- let mut ext = Self::ext();
- Self::with_ops $( ::< $( $param ),+ > )?(&mut ext);
- Self::with_state_and_middleware $( ::< $( $param ),+ > )?(&mut ext, $( $( $options_id , )* )? );
- Self::with_customizer(&mut ext);
- ext.take()
- }
- }
- };
-
- // This branch of the macro generates a config object that calls the state function with itself.
- (! __config__ $ext:ident $( parameters = [ $( $param:ident : $type:ident ),+ ] )? config = { $( $options_id:ident : $options_type:ty ),* } $( state_fn = $state_fn:expr )? ) => {
- {
- #[doc(hidden)]
- struct Config $( < $( $param : $type + 'static ),+ > )? {
- $( pub $options_id : $options_type , )*
- $( __phantom_data: ::std::marker::PhantomData<($( $param ),+)>, )?
- }
- let config = Config {
- $( $options_id , )*
- $( __phantom_data: ::std::marker::PhantomData::<($( $param ),+)>::default() )?
- };
-
- let state_fn: fn(&mut $crate::OpState, Config $( < $( $param ),+ > )? ) = $( $state_fn )?;
- $ext.state(move |state: &mut $crate::OpState| {
- state_fn(state, config);
- });
- }
- };
-
- (! __config__ $ext:ident $( parameters = [ $( $param:ident : $type:ident ),+ ] )? $( state_fn = $state_fn:expr )? ) => {
- $( $ext.state($state_fn); )?
- };
-
- (! __ops__ $ext:ident __eot__) => {
- };
-
- (! __ops__ $ext:ident $ops_symbol:ident __eot__) => {
- $ext.ops($ops_symbol())
- };
-
- (! __ops__ $ext:ident $ops_symbol:ident < $ops_param:ident > __eot__) => {
- $ext.ops($ops_symbol::<$ops_param>())
- };
-}
-
-#[derive(Default)]
-pub struct Extension {
- pub(crate) name: &'static str,
- js_files: Vec<ExtensionFileSource>,
- esm_files: Vec<ExtensionFileSource>,
- esm_entry_point: Option<&'static str>,
- ops: Option<Vec<OpDecl>>,
- opstate_fn: Option<Box<OpStateFn>>,
- middleware_fn: Option<Box<OpMiddlewareFn>>,
- event_loop_middleware: Option<Box<OpEventLoopFn>>,
- initialized: bool,
- enabled: bool,
- deps: Option<&'static [&'static str]>,
-}
-
-// Note: this used to be a trait, but we "downgraded" it to a single concrete type
-// for the initial iteration, it will likely become a trait in the future
-impl Extension {
- pub fn builder(name: &'static str) -> ExtensionBuilder {
- ExtensionBuilder {
- name,
- ..Default::default()
- }
- }
-
- pub fn builder_with_deps(
- name: &'static str,
- deps: &'static [&'static str],
- ) -> ExtensionBuilder {
- ExtensionBuilder {
- name,
- deps,
- ..Default::default()
- }
- }
-
- /// Check if dependencies have been loaded, and errors if either:
- /// - The extension is depending on itself or an extension with the same name.
- /// - A dependency hasn't been loaded yet.
- pub fn check_dependencies(&self, previous_exts: &[Extension]) {
- if let Some(deps) = self.deps {
- 'dep_loop: for dep in deps {
- if dep == &self.name {
- panic!("Extension '{}' is either depending on itself or there is another extension with the same name", self.name);
- }
-
- for ext in previous_exts {
- if dep == &ext.name {
- continue 'dep_loop;
- }
- }
-
- panic!("Extension '{}' is missing dependency '{dep}'", self.name);
- }
- }
- }
-
- /// returns JS source code to be loaded into the isolate (either at snapshotting,
- /// or at startup). as a vector of a tuple of the file name, and the source code.
- pub fn get_js_sources(&self) -> &Vec<ExtensionFileSource> {
- &self.js_files
- }
-
- pub fn get_esm_sources(&self) -> &Vec<ExtensionFileSource> {
- &self.esm_files
- }
-
- pub fn get_esm_entry_point(&self) -> Option<&'static str> {
- self.esm_entry_point
- }
-
- /// Called at JsRuntime startup to initialize ops in the isolate.
- pub fn init_ops(&mut self) -> Option<Vec<OpDecl>> {
- // TODO(@AaronO): maybe make op registration idempotent
- if self.initialized {
- panic!("init_ops called twice: not idempotent or correct");
- }
- self.initialized = true;
-
- let mut ops = self.ops.take()?;
- for op in ops.iter_mut() {
- op.enabled = self.enabled && op.enabled;
- }
- Some(ops)
- }
-
- /// Allows setting up the initial op-state of an isolate at startup.
- pub fn init_state(&mut self, state: &mut OpState) {
- if let Some(op_fn) = self.opstate_fn.take() {
- op_fn(state);
- }
- }
-
- /// init_middleware lets us middleware op registrations, it's called before init_ops
- pub fn init_middleware(&mut self) -> Option<Box<OpMiddlewareFn>> {
- self.middleware_fn.take()
- }
-
- pub fn init_event_loop_middleware(&mut self) -> Option<Box<OpEventLoopFn>> {
- self.event_loop_middleware.take()
- }
-
- pub fn run_event_loop_middleware(
- &self,
- op_state_rc: Rc<RefCell<OpState>>,
- cx: &mut Context,
- ) -> bool {
- self
- .event_loop_middleware
- .as_ref()
- .map(|f| f(op_state_rc, cx))
- .unwrap_or(false)
- }
-
- pub fn enabled(self, enabled: bool) -> Self {
- Self { enabled, ..self }
- }
-
- pub fn disable(self) -> Self {
- self.enabled(false)
- }
-}
-
-// Provides a convenient builder pattern to declare Extensions
-#[derive(Default)]
-pub struct ExtensionBuilder {
- js: Vec<ExtensionFileSource>,
- esm: Vec<ExtensionFileSource>,
- esm_entry_point: Option<&'static str>,
- ops: Vec<OpDecl>,
- state: Option<Box<OpStateFn>>,
- middleware: Option<Box<OpMiddlewareFn>>,
- event_loop_middleware: Option<Box<OpEventLoopFn>>,
- name: &'static str,
- deps: &'static [&'static str],
-}
-
-impl ExtensionBuilder {
- pub fn js(&mut self, js_files: Vec<ExtensionFileSource>) -> &mut Self {
- self.js.extend(js_files);
- self
- }
-
- pub fn esm(&mut self, esm_files: Vec<ExtensionFileSource>) -> &mut Self {
- self.esm.extend(esm_files);
- self
- }
-
- pub fn esm_entry_point(&mut self, entry_point: &'static str) -> &mut Self {
- self.esm_entry_point = Some(entry_point);
- self
- }
-
- pub fn ops(&mut self, ops: Vec<OpDecl>) -> &mut Self {
- self.ops.extend(ops);
- self
- }
-
- pub fn state<F>(&mut self, opstate_fn: F) -> &mut Self
- where
- F: FnOnce(&mut OpState) + 'static,
- {
- self.state = Some(Box::new(opstate_fn));
- self
- }
-
- pub fn middleware<F>(&mut self, middleware_fn: F) -> &mut Self
- where
- F: Fn(OpDecl) -> OpDecl + 'static,
- {
- self.middleware = Some(Box::new(middleware_fn));
- self
- }
-
- pub fn event_loop_middleware<F>(&mut self, middleware_fn: F) -> &mut Self
- where
- F: Fn(Rc<RefCell<OpState>>, &mut Context) -> bool + 'static,
- {
- self.event_loop_middleware = Some(Box::new(middleware_fn));
- self
- }
-
- /// Consume the [`ExtensionBuilder`] and return an [`Extension`].
- pub fn take(self) -> Extension {
- let ops = Some(self.ops);
- let deps = Some(self.deps);
- Extension {
- js_files: self.js,
- esm_files: self.esm,
- esm_entry_point: self.esm_entry_point,
- ops,
- opstate_fn: self.state,
- middleware_fn: self.middleware,
- event_loop_middleware: self.event_loop_middleware,
- initialized: false,
- enabled: true,
- name: self.name,
- deps,
- }
- }
-
- pub fn build(&mut self) -> Extension {
- let ops = Some(std::mem::take(&mut self.ops));
- let deps = Some(std::mem::take(&mut self.deps));
- Extension {
- js_files: std::mem::take(&mut self.js),
- esm_files: std::mem::take(&mut self.esm),
- esm_entry_point: self.esm_entry_point.take(),
- ops,
- opstate_fn: self.state.take(),
- middleware_fn: self.middleware.take(),
- event_loop_middleware: self.event_loop_middleware.take(),
- initialized: false,
- enabled: true,
- name: self.name,
- deps,
- }
- }
-}
-
-/// Helps embed JS files in an extension. Returns a vector of
-/// `ExtensionFileSource`, that represent the filename and source code. All
-/// specified files are rewritten into "ext:<extension_name>/<file_name>".
-///
-/// An optional "dir" option can be specified to prefix all files with a
-/// directory name.
-///
-/// Example (for "my_extension"):
-/// ```ignore
-/// include_js_files!(
-/// "01_hello.js",
-/// "02_goodbye.js",
-/// )
-/// // Produces following specifiers:
-/// - "ext:my_extension/01_hello.js"
-/// - "ext:my_extension/02_goodbye.js"
-///
-/// /// Example with "dir" option (for "my_extension"):
-/// ```ignore
-/// include_js_files!(
-/// dir "js",
-/// "01_hello.js",
-/// "02_goodbye.js",
-/// )
-/// // Produces following specifiers:
-/// - "ext:my_extension/js/01_hello.js"
-/// - "ext:my_extension/js/02_goodbye.js"
-/// ```
-#[cfg(not(feature = "include_js_files_for_snapshotting"))]
-#[macro_export]
-macro_rules! include_js_files {
- ($name:ident dir $dir:literal, $($file:literal,)+) => {
- vec![
- $($crate::ExtensionFileSource {
- specifier: concat!("ext:", stringify!($name), "/", $file),
- code: $crate::ExtensionFileSourceCode::IncludedInBinary(
- include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/", $dir, "/", $file))
- ),
- },)+
- ]
- };
-
- ($name:ident $($file:literal,)+) => {
- vec![
- $($crate::ExtensionFileSource {
- specifier: concat!("ext:", stringify!($name), "/", $file),
- code: $crate::ExtensionFileSourceCode::IncludedInBinary(
- include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/", $file))
- ),
- },)+
- ]
- };
-}
-
-#[cfg(feature = "include_js_files_for_snapshotting")]
-#[macro_export]
-macro_rules! include_js_files {
- ($name:ident dir $dir:literal, $($file:literal,)+) => {
- vec![
- $($crate::ExtensionFileSource {
- specifier: concat!("ext:", stringify!($name), "/", $file),
- code: $crate::ExtensionFileSourceCode::LoadedFromFsDuringSnapshot(
- std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")).join($dir).join($file)
- ),
- },)+
- ]
- };
-
- ($name:ident $($file:literal,)+) => {
- vec![
- $($crate::ExtensionFileSource {
- specifier: concat!("ext:", stringify!($name), "/", $file),
- code: $crate::ExtensionFileSourceCode::LoadedFromFsDuringSnapshot(
- std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")).join($file)
- ),
- },)+
- ]
- };
-}
diff --git a/core/fast_string.rs b/core/fast_string.rs
deleted file mode 100644
index 95dfb4939..000000000
--- a/core/fast_string.rs
+++ /dev/null
@@ -1,243 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-
-use std::borrow::Borrow;
-use std::fmt::Debug;
-use std::hash::Hash;
-use std::sync::Arc;
-use url::Url;
-use v8::NewStringType;
-
-/// Module names and code can be sourced from strings or bytes that are either owned or borrowed. This enumeration allows us
-/// to perform a minimal amount of cloning and format-shifting of the underlying data.
-///
-/// Note that any [`FastString`] created from a `'static` byte array or string must contain ASCII characters.
-///
-/// Examples of ways to construct a [`FastString`]:
-///
-/// ```rust
-/// # use deno_core::{ascii_str, FastString};
-///
-/// let code: FastString = ascii_str!("a string");
-/// let code: FastString = format!("a string").into();
-/// ```
-pub enum FastString {
- /// Created from static data.
- Static(&'static str),
-
- /// Created from static data, known to contain only ASCII chars.
- StaticAscii(&'static str),
-
- /// An owned chunk of data. Note that we use `Box` rather than `Vec` to avoid the
- /// storage overhead.
- Owned(Box<str>),
-
- // Scripts loaded from the `deno_graph` infrastructure.
- Arc(Arc<str>),
-}
-
-impl FastString {
- /// Compile-time function to determine if a string is ASCII. Note that UTF-8 chars
- /// longer than one byte have the high-bit set and thus, are not ASCII.
- const fn is_ascii(s: &'static [u8]) -> bool {
- let mut i = 0;
- while i < s.len() {
- if !s[i].is_ascii() {
- return false;
- }
- i += 1;
- }
- true
- }
-
- /// Create a [`FastString`] from a static string. The string may contain non-ASCII characters, and if
- /// so, will take the slower path when used in v8.
- pub const fn from_static(s: &'static str) -> Self {
- if Self::is_ascii(s.as_bytes()) {
- Self::StaticAscii(s)
- } else {
- Self::Static(s)
- }
- }
-
- /// Create a [`FastString`] from a static string. If the string contains non-ASCII characters, the compiler
- /// will abort.
- pub const fn ensure_static_ascii(s: &'static str) -> Self {
- if Self::is_ascii(s.as_bytes()) {
- Self::StaticAscii(s)
- } else {
- panic!("This string contained non-ASCII characters and cannot be created with ensure_static_ascii")
- }
- }
-
- /// Creates a cheap copy of this [`FastString`], potentially transmuting it to a faster form. Note that this
- /// is not a clone operation as it consumes the old [`FastString`].
- pub fn into_cheap_copy(self) -> (Self, Self) {
- match self {
- Self::Static(s) => (Self::Static(s), Self::Static(s)),
- Self::StaticAscii(s) => (Self::StaticAscii(s), Self::StaticAscii(s)),
- Self::Arc(s) => (Self::Arc(s.clone()), Self::Arc(s)),
- Self::Owned(s) => {
- let s: Arc<str> = s.into();
- (Self::Arc(s.clone()), Self::Arc(s))
- }
- }
- }
-
- pub const fn try_static_ascii(&self) -> Option<&'static [u8]> {
- match self {
- Self::StaticAscii(s) => Some(s.as_bytes()),
- _ => None,
- }
- }
-
- pub fn as_bytes(&self) -> &[u8] {
- // TODO(mmastrac): This can be const eventually (waiting for Arc const deref)
- match self {
- Self::Arc(s) => s.as_bytes(),
- Self::Owned(s) => s.as_bytes(),
- Self::Static(s) => s.as_bytes(),
- Self::StaticAscii(s) => s.as_bytes(),
- }
- }
-
- pub fn as_str(&self) -> &str {
- // TODO(mmastrac): This can be const eventually (waiting for Arc const deref)
- match self {
- Self::Arc(s) => s,
- Self::Owned(s) => s,
- Self::Static(s) => s,
- Self::StaticAscii(s) => s,
- }
- }
-
- /// Create a v8 string from this [`FastString`]. If the string is static and contains only ASCII characters,
- /// an external one-byte static is created.
- pub fn v8<'a>(
- &self,
- scope: &mut v8::HandleScope<'a>,
- ) -> v8::Local<'a, v8::String> {
- match self.try_static_ascii() {
- Some(s) => v8::String::new_external_onebyte_static(scope, s).unwrap(),
- None => {
- v8::String::new_from_utf8(scope, self.as_bytes(), NewStringType::Normal)
- .unwrap()
- }
- }
- }
-
- /// Truncates a [`FastString`] value, possibly re-allocating or memcpy'ing. May be slow.
- pub fn truncate(&mut self, index: usize) {
- match self {
- Self::Static(b) => *self = Self::Static(&b[..index]),
- Self::StaticAscii(b) => *self = Self::StaticAscii(&b[..index]),
- Self::Owned(b) => *self = Self::Owned(b[..index].to_owned().into()),
- // We can't do much if we have an Arc<str>, so we'll just take ownership of the truncated version
- Self::Arc(s) => *self = s[..index].to_owned().into(),
- }
- }
-}
-
-impl Hash for FastString {
- fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
- self.as_str().hash(state)
- }
-}
-
-impl AsRef<str> for FastString {
- fn as_ref(&self) -> &str {
- self.as_str()
- }
-}
-
-impl Borrow<str> for FastString {
- fn borrow(&self) -> &str {
- self.as_str()
- }
-}
-
-impl Debug for FastString {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- Debug::fmt(self.as_str(), f)
- }
-}
-
-impl Default for FastString {
- fn default() -> Self {
- Self::StaticAscii("")
- }
-}
-
-impl PartialEq for FastString {
- fn eq(&self, other: &Self) -> bool {
- self.as_bytes() == other.as_bytes()
- }
-}
-
-impl Eq for FastString {}
-
-/// [`FastString`] can be made cheaply from [`Url`] as we know it's owned and don't need to do an
-/// ASCII check.
-impl From<Url> for FastString {
- fn from(value: Url) -> Self {
- let s: String = value.into();
- s.into()
- }
-}
-
-/// [`FastString`] can be made cheaply from [`String`] as we know it's owned and don't need to do an
-/// ASCII check.
-impl From<String> for FastString {
- fn from(value: String) -> Self {
- FastString::Owned(value.into_boxed_str())
- }
-}
-
-/// [`FastString`] can be made cheaply from [`Arc<str>`] as we know it's shared and don't need to do an
-/// ASCII check.
-impl From<Arc<str>> for FastString {
- fn from(value: Arc<str>) -> Self {
- FastString::Arc(value)
- }
-}
-
-/// Include a fast string in the binary. This string is asserted at compile-time to be 7-bit ASCII for optimal
-/// v8 performance.
-#[macro_export]
-macro_rules! include_ascii_string {
- ($file:literal) => {
- $crate::FastString::ensure_static_ascii(include_str!($file))
- };
-}
-
-/// Include a fast string in the binary from a string literal. This string is asserted at compile-time to be
-/// 7-bit ASCII for optimal v8 performance.
-#[macro_export]
-macro_rules! ascii_str {
- ($str:literal) => {
- $crate::FastString::ensure_static_ascii($str)
- };
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- #[test]
- fn truncate() {
- let mut s = "123456".to_owned();
- s.truncate(3);
-
- let mut code: FastString = FastString::from_static("123456");
- code.truncate(3);
- assert_eq!(s, code.as_ref());
-
- let mut code: FastString = "123456".to_owned().into();
- code.truncate(3);
- assert_eq!(s, code.as_ref());
-
- let arc_str: Arc<str> = "123456".into();
- let mut code: FastString = arc_str.into();
- code.truncate(3);
- assert_eq!(s, code.as_ref());
- }
-}
diff --git a/core/flags.rs b/core/flags.rs
deleted file mode 100644
index f68d0a422..000000000
--- a/core/flags.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-
-/// Pass the command line arguments to v8.
-/// Returns a vector of command line arguments that V8 did not understand.
-pub fn v8_set_flags(args: Vec<String>) -> Vec<String> {
- v8::V8::set_flags_from_command_line(args)
-}
diff --git a/core/gotham_state.rs b/core/gotham_state.rs
deleted file mode 100644
index 422499f2f..000000000
--- a/core/gotham_state.rs
+++ /dev/null
@@ -1,193 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-// Forked from Gotham:
-// https://github.com/gotham-rs/gotham/blob/bcbbf8923789e341b7a0e62c59909428ca4e22e2/gotham/src/state/mod.rs
-// Copyright 2017 Gotham Project Developers. MIT license.
-
-use log::trace;
-use std::any::type_name;
-use std::any::Any;
-use std::any::TypeId;
-use std::collections::BTreeMap;
-
-#[derive(Default)]
-pub struct GothamState {
- data: BTreeMap<TypeId, Box<dyn Any>>,
-}
-
-impl GothamState {
- /// Puts a value into the `GothamState` storage. One value of each type is retained.
- /// Successive calls to `put` will overwrite the existing value of the same
- /// type.
- pub fn put<T: 'static>(&mut self, t: T) {
- let type_id = TypeId::of::<T>();
- trace!(" inserting record to state for type_id `{:?}`", type_id);
- self.data.insert(type_id, Box::new(t));
- }
-
- /// Determines if the current value exists in `GothamState` storage.
- pub fn has<T: 'static>(&self) -> bool {
- let type_id = TypeId::of::<T>();
- self.data.get(&type_id).is_some()
- }
-
- /// Tries to borrow a value from the `GothamState` storage.
- pub fn try_borrow<T: 'static>(&self) -> Option<&T> {
- let type_id = TypeId::of::<T>();
- trace!(" borrowing state data for type_id `{:?}`", type_id);
- self.data.get(&type_id).and_then(|b| b.downcast_ref())
- }
-
- /// Borrows a value from the `GothamState` storage.
- pub fn borrow<T: 'static>(&self) -> &T {
- self.try_borrow().unwrap_or_else(|| missing::<T>())
- }
-
- /// Tries to mutably borrow a value from the `GothamState` storage.
- pub fn try_borrow_mut<T: 'static>(&mut self) -> Option<&mut T> {
- let type_id = TypeId::of::<T>();
- trace!(" mutably borrowing state data for type_id `{:?}`", type_id);
- self.data.get_mut(&type_id).and_then(|b| b.downcast_mut())
- }
-
- /// Mutably borrows a value from the `GothamState` storage.
- pub fn borrow_mut<T: 'static>(&mut self) -> &mut T {
- self.try_borrow_mut().unwrap_or_else(|| missing::<T>())
- }
-
- /// Tries to move a value out of the `GothamState` storage and return ownership.
- pub fn try_take<T: 'static>(&mut self) -> Option<T> {
- let type_id = TypeId::of::<T>();
- trace!(
- " taking ownership from state data for type_id `{:?}`",
- type_id
- );
- self
- .data
- .remove(&type_id)
- .and_then(|b| b.downcast().ok())
- .map(|b| *b)
- }
-
- /// Moves a value out of the `GothamState` storage and returns ownership.
- ///
- /// # Panics
- ///
- /// If a value of type `T` is not present in `GothamState`.
- pub fn take<T: 'static>(&mut self) -> T {
- self.try_take().unwrap_or_else(|| missing::<T>())
- }
-}
-
-fn missing<T: 'static>() -> ! {
- panic!(
- "required type {} is not present in GothamState container",
- type_name::<T>()
- );
-}
-
-#[cfg(test)]
-mod tests {
- use super::GothamState;
-
- struct MyStruct {
- value: i32,
- }
-
- struct AnotherStruct {
- value: &'static str,
- }
-
- type Alias1 = String;
- type Alias2 = String;
-
- #[test]
- fn put_borrow1() {
- let mut state = GothamState::default();
- state.put(MyStruct { value: 1 });
- assert_eq!(state.borrow::<MyStruct>().value, 1);
- }
-
- #[test]
- fn put_borrow2() {
- let mut state = GothamState::default();
- assert!(!state.has::<AnotherStruct>());
- state.put(AnotherStruct { value: "a string" });
- assert!(state.has::<AnotherStruct>());
- assert!(!state.has::<MyStruct>());
- state.put(MyStruct { value: 100 });
- assert!(state.has::<MyStruct>());
- assert_eq!(state.borrow::<MyStruct>().value, 100);
- assert_eq!(state.borrow::<AnotherStruct>().value, "a string");
- }
-
- #[test]
- fn try_borrow() {
- let mut state = GothamState::default();
- state.put(MyStruct { value: 100 });
- assert!(state.try_borrow::<MyStruct>().is_some());
- assert_eq!(state.try_borrow::<MyStruct>().unwrap().value, 100);
- assert!(state.try_borrow::<AnotherStruct>().is_none());
- }
-
- #[test]
- fn try_borrow_mut() {
- let mut state = GothamState::default();
- state.put(MyStruct { value: 100 });
- if let Some(a) = state.try_borrow_mut::<MyStruct>() {
- a.value += 10;
- }
- assert_eq!(state.borrow::<MyStruct>().value, 110);
- }
-
- #[test]
- fn borrow_mut() {
- let mut state = GothamState::default();
- state.put(MyStruct { value: 100 });
- {
- let a = state.borrow_mut::<MyStruct>();
- a.value += 10;
- }
- assert_eq!(state.borrow::<MyStruct>().value, 110);
- assert!(state.try_borrow_mut::<AnotherStruct>().is_none());
- }
-
- #[test]
- fn try_take() {
- let mut state = GothamState::default();
- state.put(MyStruct { value: 100 });
- assert_eq!(state.try_take::<MyStruct>().unwrap().value, 100);
- assert!(state.try_take::<MyStruct>().is_none());
- assert!(state.try_borrow_mut::<MyStruct>().is_none());
- assert!(state.try_borrow::<MyStruct>().is_none());
- assert!(state.try_take::<AnotherStruct>().is_none());
- }
-
- #[test]
- fn take() {
- let mut state = GothamState::default();
- state.put(MyStruct { value: 110 });
- assert_eq!(state.take::<MyStruct>().value, 110);
- assert!(state.try_take::<MyStruct>().is_none());
- assert!(state.try_borrow_mut::<MyStruct>().is_none());
- assert!(state.try_borrow::<MyStruct>().is_none());
- }
-
- #[test]
- fn type_alias() {
- let mut state = GothamState::default();
- state.put::<Alias1>("alias1".to_string());
- state.put::<Alias2>("alias2".to_string());
- assert_eq!(state.take::<Alias1>(), "alias2");
- assert!(state.try_take::<Alias1>().is_none());
- assert!(state.try_take::<Alias2>().is_none());
- }
-
- #[test]
- #[should_panic(
- expected = "required type deno_core::gotham_state::tests::MyStruct is not present in GothamState container"
- )]
- fn missing() {
- let state = GothamState::default();
- let _ = state.borrow::<MyStruct>();
- }
-}
diff --git a/core/inspector.rs b/core/inspector.rs
deleted file mode 100644
index bd1080a94..000000000
--- a/core/inspector.rs
+++ /dev/null
@@ -1,853 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-
-//! The documentation for the inspector API is sparse, but these are helpful:
-//! <https://chromedevtools.github.io/devtools-protocol/>
-//! <https://hyperandroid.com/2020/02/12/v8-inspector-from-an-embedder-standpoint/>
-
-use crate::error::generic_error;
-use crate::futures::channel::mpsc;
-use crate::futures::channel::mpsc::UnboundedReceiver;
-use crate::futures::channel::mpsc::UnboundedSender;
-use crate::futures::channel::oneshot;
-use crate::futures::future::select;
-use crate::futures::future::Either;
-use crate::futures::prelude::*;
-use crate::futures::stream::SelectAll;
-use crate::futures::stream::StreamExt;
-use crate::futures::task;
-use crate::futures::task::Context;
-use crate::futures::task::Poll;
-use crate::serde_json;
-use crate::serde_json::json;
-use crate::serde_json::Value;
-use anyhow::Error;
-use parking_lot::Mutex;
-use std::cell::BorrowMutError;
-use std::cell::RefCell;
-use std::collections::HashMap;
-use std::ffi::c_void;
-use std::mem::take;
-use std::mem::MaybeUninit;
-use std::pin::Pin;
-use std::ptr;
-use std::ptr::NonNull;
-use std::rc::Rc;
-use std::sync::Arc;
-use std::thread;
-use v8::HandleScope;
-
-pub enum InspectorMsgKind {
- Notification,
- Message(i32),
-}
-pub struct InspectorMsg {
- pub kind: InspectorMsgKind,
- pub content: String,
-}
-pub type SessionProxySender = UnboundedSender<InspectorMsg>;
-pub type SessionProxyReceiver = UnboundedReceiver<String>;
-
-/// Encapsulates an UnboundedSender/UnboundedReceiver pair that together form
-/// a duplex channel for sending/receiving messages in V8 session.
-pub struct InspectorSessionProxy {
- pub tx: SessionProxySender,
- pub rx: SessionProxyReceiver,
-}
-
-#[derive(Clone, Copy)]
-enum PollState {
- Idle,
- Woken,
- Polling,
- Parked,
- Dropped,
-}
-
-/// This structure is used responsible for providing inspector interface
-/// to the `JsRuntime`.
-///
-/// It stores an instance of `v8::inspector::V8Inspector` and additionally
-/// implements `v8::inspector::V8InspectorClientImpl`.
-///
-/// After creating this structure it's possible to connect multiple sessions
-/// to the inspector, in case of Deno it's either: a "websocket session" that
-/// provides integration with Chrome Devtools, or an "in-memory session" that
-/// is used for REPL or coverage collection.
-pub struct JsRuntimeInspector {
- v8_inspector_client: v8::inspector::V8InspectorClientBase,
- v8_inspector: Rc<RefCell<v8::UniquePtr<v8::inspector::V8Inspector>>>,
- new_session_tx: UnboundedSender<InspectorSessionProxy>,
- sessions: RefCell<SessionContainer>,
- flags: RefCell<InspectorFlags>,
- waker: Arc<InspectorWaker>,
- deregister_tx: Option<oneshot::Sender<()>>,
- is_dispatching_message: RefCell<bool>,
-}
-
-impl Drop for JsRuntimeInspector {
- fn drop(&mut self) {
- // Since the waker is cloneable, it might outlive the inspector itself.
- // Set the poll state to 'dropped' so it doesn't attempt to request an
- // interrupt from the isolate.
- self.waker.update(|w| w.poll_state = PollState::Dropped);
-
- // V8 automatically deletes all sessions when an `V8Inspector` instance is
- // deleted, however InspectorSession also has a drop handler that cleans
- // up after itself. To avoid a double free, make sure the inspector is
- // dropped last.
- self.sessions.borrow_mut().drop_sessions();
-
- // Notify counterparty that this instance is being destroyed. Ignoring
- // result because counterparty waiting for the signal might have already
- // dropped the other end of channel.
- if let Some(deregister_tx) = self.deregister_tx.take() {
- let _ = deregister_tx.send(());
- }
- }
-}
-
-impl v8::inspector::V8InspectorClientImpl for JsRuntimeInspector {
- fn base(&self) -> &v8::inspector::V8InspectorClientBase {
- &self.v8_inspector_client
- }
-
- unsafe fn base_ptr(
- this: *const Self,
- ) -> *const v8::inspector::V8InspectorClientBase
- where
- Self: Sized,
- {
- // SAFETY: this pointer is valid for the whole lifetime of inspector
- unsafe { std::ptr::addr_of!((*this).v8_inspector_client) }
- }
-
- fn base_mut(&mut self) -> &mut v8::inspector::V8InspectorClientBase {
- &mut self.v8_inspector_client
- }
-
- fn run_message_loop_on_pause(&mut self, context_group_id: i32) {
- assert_eq!(context_group_id, JsRuntimeInspector::CONTEXT_GROUP_ID);
- self.flags.borrow_mut().on_pause = true;
- let _ = self.poll_sessions(None);
- }
-
- fn quit_message_loop_on_pause(&mut self) {
- self.flags.borrow_mut().on_pause = false;
- }
-
- fn run_if_waiting_for_debugger(&mut self, context_group_id: i32) {
- assert_eq!(context_group_id, JsRuntimeInspector::CONTEXT_GROUP_ID);
- self.flags.borrow_mut().waiting_for_session = false;
- }
-}
-
-impl JsRuntimeInspector {
- /// Currently Deno supports only a single context in `JsRuntime`
- /// and thus it's id is provided as an associated constant.
- const CONTEXT_GROUP_ID: i32 = 1;
-
- pub fn new(
- scope: &mut v8::HandleScope,
- context: v8::Local<v8::Context>,
- is_main: bool,
- ) -> Rc<RefCell<Self>> {
- let (new_session_tx, new_session_rx) =
- mpsc::unbounded::<InspectorSessionProxy>();
-
- let v8_inspector_client =
- v8::inspector::V8InspectorClientBase::new::<Self>();
-
- let waker = InspectorWaker::new(scope.thread_safe_handle());
-
- // Create JsRuntimeInspector instance.
- let self__ = Rc::new(RefCell::new(Self {
- v8_inspector_client,
- v8_inspector: Default::default(),
- sessions: RefCell::new(SessionContainer::temporary_placeholder()),
- new_session_tx,
- flags: Default::default(),
- waker,
- deregister_tx: None,
- is_dispatching_message: Default::default(),
- }));
- let mut self_ = self__.borrow_mut();
- self_.v8_inspector = Rc::new(RefCell::new(
- v8::inspector::V8Inspector::create(scope, &mut *self_).into(),
- ));
- self_.sessions = RefCell::new(SessionContainer::new(
- self_.v8_inspector.clone(),
- new_session_rx,
- ));
-
- // Tell the inspector about the global context.
- let context_name = v8::inspector::StringView::from(&b"global context"[..]);
- // NOTE(bartlomieju): this is what Node.js does and it turns out some
- // debuggers (like VSCode) rely on this information to disconnect after
- // program completes
- let aux_data = if is_main {
- r#"{"isDefault": true}"#
- } else {
- r#"{"isDefault": false}"#
- };
- let aux_data_view = v8::inspector::StringView::from(aux_data.as_bytes());
- self_
- .v8_inspector
- .borrow_mut()
- .as_mut()
- .unwrap()
- .context_created(
- context,
- Self::CONTEXT_GROUP_ID,
- context_name,
- aux_data_view,
- );
-
- // Poll the session handler so we will get notified whenever there is
- // new incoming debugger activity.
- let _ = self_.poll_sessions(None).unwrap();
- drop(self_);
-
- self__
- }
-
- pub fn is_dispatching_message(&self) -> bool {
- *self.is_dispatching_message.borrow()
- }
-
- pub fn context_destroyed(
- &mut self,
- scope: &mut HandleScope,
- context: v8::Global<v8::Context>,
- ) {
- let context = v8::Local::new(scope, context);
- self
- .v8_inspector
- .borrow_mut()
- .as_mut()
- .unwrap()
- .context_destroyed(context);
- }
-
- pub fn exception_thrown(
- &self,
- scope: &mut HandleScope,
- exception: v8::Local<'_, v8::Value>,
- in_promise: bool,
- ) {
- let context = scope.get_current_context();
- let message = v8::Exception::create_message(scope, exception);
- let stack_trace = message.get_stack_trace(scope).unwrap();
- let mut v8_inspector_ref = self.v8_inspector.borrow_mut();
- let v8_inspector = v8_inspector_ref.as_mut().unwrap();
- let stack_trace = v8_inspector.create_stack_trace(stack_trace);
- v8_inspector.exception_thrown(
- context,
- if in_promise {
- v8::inspector::StringView::from("Uncaught (in promise)".as_bytes())
- } else {
- v8::inspector::StringView::from("Uncaught".as_bytes())
- },
- exception,
- v8::inspector::StringView::from("".as_bytes()),
- v8::inspector::StringView::from("".as_bytes()),
- 0,
- 0,
- stack_trace,
- 0,
- );
- }
-
- pub fn has_active_sessions(&self) -> bool {
- self.sessions.borrow().has_active_sessions()
- }
-
- pub fn has_blocking_sessions(&self) -> bool {
- self.sessions.borrow().has_blocking_sessions()
- }
-
- pub fn poll_sessions(
- &self,
- mut invoker_cx: Option<&mut Context>,
- ) -> Result<Poll<()>, BorrowMutError> {
- // The futures this function uses do not have re-entrant poll() functions.
- // However it is can happen that poll_sessions() gets re-entered, e.g.
- // when an interrupt request is honored while the inspector future is polled
- // by the task executor. We let the caller know by returning some error.
- let mut sessions = self.sessions.try_borrow_mut()?;
-
- self.waker.update(|w| {
- match w.poll_state {
- PollState::Idle | PollState::Woken => w.poll_state = PollState::Polling,
- _ => unreachable!(),
- };
- });
-
- // Create a new Context object that will make downstream futures
- // use the InspectorWaker when they are ready to be polled again.
- let waker_ref = task::waker_ref(&self.waker);
- let cx = &mut Context::from_waker(&waker_ref);
-
- loop {
- loop {
- // Do one "handshake" with a newly connected session at a time.
- if let Some(mut session) = sessions.handshake.take() {
- let poll_result = session.poll_next_unpin(cx);
- match poll_result {
- Poll::Pending => {
- sessions.established.push(session);
- continue;
- }
- Poll::Ready(Some(session_stream_item)) => {
- let (v8_session_ptr, msg) = session_stream_item;
- InspectorSession::dispatch_message(v8_session_ptr, msg);
- sessions.established.push(session);
- continue;
- }
- Poll::Ready(None) => {}
- }
- }
-
- // Accept new connections.
- let poll_result = sessions.session_rx.poll_next_unpin(cx);
- if let Poll::Ready(Some(session_proxy)) = poll_result {
- let session = InspectorSession::new(
- sessions.v8_inspector.clone(),
- session_proxy,
- false,
- );
- let prev = sessions.handshake.replace(session);
- assert!(prev.is_none());
- }
-
- // Poll established sessions.
- match sessions.established.poll_next_unpin(cx) {
- Poll::Ready(Some(session_stream_item)) => {
- let (v8_session_ptr, msg) = session_stream_item;
- *self.is_dispatching_message.borrow_mut() = true;
- InspectorSession::dispatch_message(v8_session_ptr, msg);
- *self.is_dispatching_message.borrow_mut() = false;
- continue;
- }
- Poll::Ready(None) => break,
- Poll::Pending => break,
- };
- }
-
- let should_block =
- self.flags.borrow().on_pause || self.flags.borrow().waiting_for_session;
-
- let new_state = self.waker.update(|w| {
- match w.poll_state {
- PollState::Woken => {
- // The inspector was woken while the session handler was being
- // polled, so we poll it another time.
- w.poll_state = PollState::Polling;
- }
- PollState::Polling if !should_block => {
- // The session handler doesn't need to be polled any longer, and
- // there's no reason to block (execution is not paused), so this
- // function is about to return.
- w.poll_state = PollState::Idle;
- // Register the task waker that can be used to wake the parent
- // task that will poll the inspector future.
- if let Some(cx) = invoker_cx.take() {
- w.task_waker.replace(cx.waker().clone());
- }
- // Register the address of the inspector, which allows the waker
- // to request an interrupt from the isolate.
- w.inspector_ptr = NonNull::new(self as *const _ as *mut Self);
- }
- PollState::Polling if should_block => {
- // Isolate execution has been paused but there are no more
- // events to process, so this thread will be parked. Therefore,
- // store the current thread handle in the waker so it knows
- // which thread to unpark when new events arrive.
- w.poll_state = PollState::Parked;
- w.parked_thread.replace(thread::current());
- }
- _ => unreachable!(),
- };
- w.poll_state
- });
- match new_state {
- PollState::Idle => break Ok(Poll::Pending), // Yield to task.
- PollState::Polling => {} // Poll the session handler again.
- PollState::Parked => thread::park(), // Park the thread.
- _ => unreachable!(),
- };
- }
- }
-
- /// This function blocks the thread until at least one inspector client has
- /// established a websocket connection.
- pub fn wait_for_session(&mut self) {
- loop {
- match self.sessions.get_mut().established.iter_mut().next() {
- Some(_session) => {
- self.flags.get_mut().waiting_for_session = false;
- break;
- }
- None => {
- self.flags.get_mut().waiting_for_session = true;
- let _ = self.poll_sessions(None).unwrap();
- }
- };
- }
- }
-
- /// This function blocks the thread until at least one inspector client has
- /// established a websocket connection.
- ///
- /// After that, it instructs V8 to pause at the next statement.
- /// Frontend must send "Runtime.runIfWaitingForDebugger" message to resume
- /// execution.
- pub fn wait_for_session_and_break_on_next_statement(&mut self) {
- loop {
- match self.sessions.get_mut().established.iter_mut().next() {
- Some(session) => break session.break_on_next_statement(),
- None => {
- self.flags.get_mut().waiting_for_session = true;
- let _ = self.poll_sessions(None).unwrap();
- }
- };
- }
- }
-
- /// Obtain a sender for proxy channels.
- pub fn get_session_sender(&self) -> UnboundedSender<InspectorSessionProxy> {
- self.new_session_tx.clone()
- }
-
- /// Create a channel that notifies the frontend when inspector is dropped.
- ///
- /// NOTE: Only a single handler is currently available.
- pub fn add_deregister_handler(&mut self) -> oneshot::Receiver<()> {
- let (tx, rx) = oneshot::channel::<()>();
- let prev = self.deregister_tx.replace(tx);
- assert!(
- prev.is_none(),
- "Only a single deregister handler is allowed"
- );
- rx
- }
-
- /// Create a local inspector session that can be used on
- /// the same thread as the isolate.
- pub fn create_local_session(&self) -> LocalInspectorSession {
- // The 'outbound' channel carries messages sent to the session.
- let (outbound_tx, outbound_rx) = mpsc::unbounded();
-
- // The 'inbound' channel carries messages received from the session.
- let (inbound_tx, inbound_rx) = mpsc::unbounded();
-
- let proxy = InspectorSessionProxy {
- tx: outbound_tx,
- rx: inbound_rx,
- };
-
- // InspectorSessions for a local session is added directly to the "established"
- // sessions, so it doesn't need to go through the session sender.
- let inspector_session =
- InspectorSession::new(self.v8_inspector.clone(), proxy, true);
- self
- .sessions
- .borrow_mut()
- .established
- .push(inspector_session);
- take(&mut self.flags.borrow_mut().waiting_for_session);
-
- LocalInspectorSession::new(inbound_tx, outbound_rx)
- }
-}
-
-#[derive(Default)]
-struct InspectorFlags {
- waiting_for_session: bool,
- on_pause: bool,
-}
-
-/// A helper structure that helps coordinate sessions during different
-/// parts of their lifecycle.
-struct SessionContainer {
- v8_inspector: Rc<RefCell<v8::UniquePtr<v8::inspector::V8Inspector>>>,
- session_rx: UnboundedReceiver<InspectorSessionProxy>,
- handshake: Option<Box<InspectorSession>>,
- established: SelectAll<Box<InspectorSession>>,
-}
-
-impl SessionContainer {
- fn new(
- v8_inspector: Rc<RefCell<v8::UniquePtr<v8::inspector::V8Inspector>>>,
- new_session_rx: UnboundedReceiver<InspectorSessionProxy>,
- ) -> Self {
- Self {
- v8_inspector,
- session_rx: new_session_rx,
- handshake: None,
- established: SelectAll::new(),
- }
- }
-
- /// V8 automatically deletes all sessions when an `V8Inspector` instance is
- /// deleted, however InspectorSession also has a drop handler that cleans
- /// up after itself. To avoid a double free, we need to manually drop
- /// all sessions before dropping the inspector instance.
- fn drop_sessions(&mut self) {
- self.v8_inspector = Default::default();
- self.handshake.take();
- self.established.clear();
- }
-
- fn has_active_sessions(&self) -> bool {
- !self.established.is_empty() || self.handshake.is_some()
- }
-
- fn has_blocking_sessions(&self) -> bool {
- self.established.iter().any(|s| s.blocking)
- }
-
- /// A temporary placeholder that should be used before actual
- /// instance of V8Inspector is created. It's used in favor
- /// of `Default` implementation to signal that it's not meant
- /// for actual use.
- fn temporary_placeholder() -> Self {
- let (_tx, rx) = mpsc::unbounded::<InspectorSessionProxy>();
- Self {
- v8_inspector: Default::default(),
- session_rx: rx,
- handshake: None,
- established: SelectAll::new(),
- }
- }
-}
-
-struct InspectorWakerInner {
- poll_state: PollState,
- task_waker: Option<task::Waker>,
- parked_thread: Option<thread::Thread>,
- inspector_ptr: Option<NonNull<JsRuntimeInspector>>,
- isolate_handle: v8::IsolateHandle,
-}
-
-// SAFETY: unsafe trait must have unsafe implementation
-unsafe impl Send for InspectorWakerInner {}
-
-struct InspectorWaker(Mutex<InspectorWakerInner>);
-
-impl InspectorWaker {
- fn new(isolate_handle: v8::IsolateHandle) -> Arc<Self> {
- let inner = InspectorWakerInner {
- poll_state: PollState::Idle,
- task_waker: None,
- parked_thread: None,
- inspector_ptr: None,
- isolate_handle,
- };
- Arc::new(Self(Mutex::new(inner)))
- }
-
- fn update<F, R>(&self, update_fn: F) -> R
- where
- F: FnOnce(&mut InspectorWakerInner) -> R,
- {
- let mut g = self.0.lock();
- update_fn(&mut g)
- }
-}
-
-impl task::ArcWake for InspectorWaker {
- fn wake_by_ref(arc_self: &Arc<Self>) {
- arc_self.update(|w| {
- match w.poll_state {
- PollState::Idle => {
- // Wake the task, if any, that has polled the Inspector future last.
- if let Some(waker) = w.task_waker.take() {
- waker.wake()
- }
- // Request an interrupt from the isolate if it's running and there's
- // not unhandled interrupt request in flight.
- if let Some(arg) = w
- .inspector_ptr
- .take()
- .map(|ptr| ptr.as_ptr() as *mut c_void)
- {
- w.isolate_handle.request_interrupt(handle_interrupt, arg);
- }
- extern "C" fn handle_interrupt(
- _isolate: &mut v8::Isolate,
- arg: *mut c_void,
- ) {
- // SAFETY: `InspectorWaker` is owned by `JsRuntimeInspector`, so the
- // pointer to the latter is valid as long as waker is alive.
- let inspector = unsafe { &*(arg as *mut JsRuntimeInspector) };
- let _ = inspector.poll_sessions(None);
- }
- }
- PollState::Parked => {
- // Unpark the isolate thread.
- let parked_thread = w.parked_thread.take().unwrap();
- assert_ne!(parked_thread.id(), thread::current().id());
- parked_thread.unpark();
- }
- _ => {}
- };
- w.poll_state = PollState::Woken;
- });
- }
-}
-
-/// An inspector session that proxies messages to concrete "transport layer",
-/// eg. Websocket or another set of channels.
-struct InspectorSession {
- v8_channel: v8::inspector::ChannelBase,
- v8_session: v8::UniqueRef<v8::inspector::V8InspectorSession>,
- proxy: InspectorSessionProxy,
- // Describes if session should keep event loop alive, eg. a local REPL
- // session should keep event loop alive, but a Websocket session shouldn't.
- blocking: bool,
-}
-
-impl InspectorSession {
- const CONTEXT_GROUP_ID: i32 = 1;
-
- pub fn new(
- v8_inspector_rc: Rc<RefCell<v8::UniquePtr<v8::inspector::V8Inspector>>>,
- session_proxy: InspectorSessionProxy,
- blocking: bool,
- ) -> Box<Self> {
- new_box_with(move |self_ptr| {
- let v8_channel = v8::inspector::ChannelBase::new::<Self>();
- let mut v8_inspector = v8_inspector_rc.borrow_mut();
- let v8_inspector_ptr = v8_inspector.as_mut().unwrap();
- // TODO(piscisaureus): safety comment
- #[allow(clippy::undocumented_unsafe_blocks)]
- let v8_session = v8_inspector_ptr.connect(
- Self::CONTEXT_GROUP_ID,
- // Todo(piscisaureus): V8Inspector::connect() should require that
- // the 'v8_channel' argument cannot move.
- unsafe { &mut *self_ptr },
- v8::inspector::StringView::empty(),
- v8::inspector::V8InspectorClientTrustLevel::FullyTrusted,
- );
-
- Self {
- v8_channel,
- v8_session,
- proxy: session_proxy,
- blocking,
- }
- })
- }
-
- // Dispatch message to V8 session
- fn dispatch_message(
- v8_session_ptr: *mut v8::inspector::V8InspectorSession,
- msg: String,
- ) {
- let msg = v8::inspector::StringView::from(msg.as_bytes());
- // SAFETY: `InspectorSession` is the only owner of `v8_session_ptr`, so
- // the pointer is valid for as long the struct.
- unsafe {
- (*v8_session_ptr).dispatch_protocol_message(msg);
- };
- }
-
- fn send_message(
- &self,
- msg_kind: InspectorMsgKind,
- msg: v8::UniquePtr<v8::inspector::StringBuffer>,
- ) {
- let msg = msg.unwrap().string().to_string();
- let _ = self.proxy.tx.unbounded_send(InspectorMsg {
- kind: msg_kind,
- content: msg,
- });
- }
-
- pub fn break_on_next_statement(&mut self) {
- let reason = v8::inspector::StringView::from(&b"debugCommand"[..]);
- let detail = v8::inspector::StringView::empty();
- // TODO(bartlomieju): use raw `*mut V8InspectorSession` pointer, as this
- // reference may become aliased.
- (*self.v8_session).schedule_pause_on_next_statement(reason, detail);
- }
-}
-
-impl v8::inspector::ChannelImpl for InspectorSession {
- fn base(&self) -> &v8::inspector::ChannelBase {
- &self.v8_channel
- }
-
- unsafe fn base_ptr(this: *const Self) -> *const v8::inspector::ChannelBase
- where
- Self: Sized,
- {
- // SAFETY: this pointer is valid for the whole lifetime of inspector
- unsafe { std::ptr::addr_of!((*this).v8_channel) }
- }
-
- fn base_mut(&mut self) -> &mut v8::inspector::ChannelBase {
- &mut self.v8_channel
- }
-
- fn send_response(
- &mut self,
- call_id: i32,
- message: v8::UniquePtr<v8::inspector::StringBuffer>,
- ) {
- self.send_message(InspectorMsgKind::Message(call_id), message);
- }
-
- fn send_notification(
- &mut self,
- message: v8::UniquePtr<v8::inspector::StringBuffer>,
- ) {
- self.send_message(InspectorMsgKind::Notification, message);
- }
-
- fn flush_protocol_notifications(&mut self) {}
-}
-
-impl Stream for InspectorSession {
- type Item = (*mut v8::inspector::V8InspectorSession, String);
-
- fn poll_next(
- self: Pin<&mut Self>,
- cx: &mut Context,
- ) -> Poll<Option<Self::Item>> {
- let inner = self.get_mut();
- if let Poll::Ready(maybe_msg) = inner.proxy.rx.poll_next_unpin(cx) {
- if let Some(msg) = maybe_msg {
- return Poll::Ready(Some((&mut *inner.v8_session, msg)));
- } else {
- return Poll::Ready(None);
- }
- }
-
- Poll::Pending
- }
-}
-
-/// A local inspector session that can be used to send and receive protocol messages directly on
-/// the same thread as an isolate.
-pub struct LocalInspectorSession {
- v8_session_tx: UnboundedSender<String>,
- v8_session_rx: UnboundedReceiver<InspectorMsg>,
- response_tx_map: HashMap<i32, oneshot::Sender<serde_json::Value>>,
- next_message_id: i32,
- notification_tx: UnboundedSender<Value>,
- notification_rx: Option<UnboundedReceiver<Value>>,
-}
-
-impl LocalInspectorSession {
- pub fn new(
- v8_session_tx: UnboundedSender<String>,
- v8_session_rx: UnboundedReceiver<InspectorMsg>,
- ) -> Self {
- let response_tx_map = HashMap::new();
- let next_message_id = 0;
-
- let (notification_tx, notification_rx) = mpsc::unbounded::<Value>();
-
- Self {
- v8_session_tx,
- v8_session_rx,
- response_tx_map,
- next_message_id,
- notification_tx,
- notification_rx: Some(notification_rx),
- }
- }
-
- pub fn take_notification_rx(&mut self) -> UnboundedReceiver<Value> {
- self.notification_rx.take().unwrap()
- }
-
- pub async fn post_message<T: serde::Serialize>(
- &mut self,
- method: &str,
- params: Option<T>,
- ) -> Result<serde_json::Value, Error> {
- let id = self.next_message_id;
- self.next_message_id += 1;
-
- let (response_tx, mut response_rx) =
- oneshot::channel::<serde_json::Value>();
- self.response_tx_map.insert(id, response_tx);
-
- let message = json!({
- "id": id,
- "method": method,
- "params": params,
- });
-
- let stringified_msg = serde_json::to_string(&message).unwrap();
- self.v8_session_tx.unbounded_send(stringified_msg).unwrap();
-
- loop {
- let receive_fut = self.receive_from_v8_session().boxed_local();
- match select(receive_fut, &mut response_rx).await {
- Either::Left(_) => continue,
- Either::Right((result, _)) => {
- let response = result?;
- if let Some(error) = response.get("error") {
- return Err(generic_error(error.to_string()));
- }
-
- let result = response.get("result").unwrap().clone();
- return Ok(result);
- }
- }
- }
- }
-
- async fn receive_from_v8_session(&mut self) {
- let inspector_msg = self.v8_session_rx.next().await.unwrap();
- if let InspectorMsgKind::Message(msg_id) = inspector_msg.kind {
- let message: serde_json::Value =
- match serde_json::from_str(&inspector_msg.content) {
- Ok(v) => v,
- Err(error) => match error.classify() {
- serde_json::error::Category::Syntax => json!({
- "id": msg_id,
- "result": {
- "result": {
- "type": "error",
- "description": "Unterminated string literal",
- "value": "Unterminated string literal",
- },
- "exceptionDetails": {
- "exceptionId": 0,
- "text": "Unterminated string literal",
- "lineNumber": 0,
- "columnNumber": 0
- },
- },
- }),
- _ => panic!("Could not parse inspector message"),
- },
- };
-
- self
- .response_tx_map
- .remove(&msg_id)
- .unwrap()
- .send(message)
- .unwrap();
- } else {
- let message = serde_json::from_str(&inspector_msg.content).unwrap();
- // Ignore if the receiver has been dropped.
- let _ = self.notification_tx.unbounded_send(message);
- }
- }
-}
-
-fn new_box_with<T>(new_fn: impl FnOnce(*mut T) -> T) -> Box<T> {
- let b = Box::new(MaybeUninit::<T>::uninit());
- let p = Box::into_raw(b) as *mut T;
- // SAFETY: memory layout for `T` is ensured on first line of this function
- unsafe {
- ptr::write(p, new_fn(p));
- Box::from_raw(p)
- }
-}
diff --git a/core/internal.d.ts b/core/internal.d.ts
deleted file mode 100644
index b09d188d8..000000000
--- a/core/internal.d.ts
+++ /dev/null
@@ -1,1079 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-
-// Based on https://github.com/nodejs/node/blob/889ad35d3d41e376870f785b0c1b669cb732013d/typings/primordials.d.ts
-// Copyright Joyent, Inc. and other Node contributors.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a
-// copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to permit
-// persons to whom the Software is furnished to do so, subject to the
-// following conditions:
-//
-// The above copyright notice and this permission notice shall be included
-// in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
-// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
-// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
-// USE OR OTHER DEALINGS IN THE SOFTWARE.
-// This file subclasses and stores the JS builtins that come from the VM
-// so that Node.js's builtin modules do not need to later look these up from
-// the global proxy, which can be mutated by users.
-
-/// <reference no-default-lib="true" />
-/// <reference lib="esnext" />
-
-declare namespace __bootstrap {
- /**
- * Primordials are a way to safely use globals without fear of global mutation
- * Generally, this means removing `this` parameter usage and instead using
- * a regular parameter:
- *
- * @example
- *
- * ```js
- * 'thing'.startsWith('hello');
- * ```
- *
- * becomes
- *
- * ```js
- * primordials.StringPrototypeStartsWith('thing', 'hello')
- * ```
- */
- declare namespace primordials {
- type UncurryThis<T extends (this: unknown, ...args: unknown[]) => unknown> =
- (self: ThisParameterType<T>, ...args: Parameters<T>) => ReturnType<T>;
- type UncurryThisStaticApply<
- T extends (this: unknown, ...args: unknown[]) => unknown,
- > = (self: ThisParameterType<T>, args: Parameters<T>) => ReturnType<T>;
- type StaticApply<T extends (this: unknown, ...args: unknown[]) => unknown> =
- (args: Parameters<T>) => ReturnType<T>;
-
- export function uncurryThis<T extends (...args: unknown[]) => unknown>(
- fn: T,
- ): (self: ThisType<T>, ...args: Parameters<T>) => ReturnType<T>;
- export function applyBind<T extends (...args: unknown[]) => unknown>(
- fn: T,
- ): (self: ThisType<T>, args: Parameters<T>) => ReturnType<T>;
-
- // safe objects
- export function makeSafe<T extends NewableFunction>(
- unsafe: NewableFunction,
- safe: T,
- ): T;
- export const SafeMap: typeof globalThis.Map;
- export const SafeWeakMap: typeof globalThis.WeakMap;
- export const SafeSet: typeof globalThis.Set;
- export const SafeWeakSet: typeof globalThis.WeakSet;
- export const SafeFinalizationRegistry:
- typeof globalThis.FinalizationRegistry;
- export const SafeWeakRef: typeof globalThis.WeakRef;
- export const SafePromiseAll: typeof Promise.all;
- // NOTE: Uncomment the following functions when you need to use them
- // export const SafePromiseAllSettled: typeof Promise.allSettled;
- // export const SafePromiseAny: typeof Promise.any;
- // export const SafePromiseRace: typeof Promise.race;
- export const SafePromisePrototypeFinally: UncurryThis<
- Promise.prototype.finally
- >;
- export const SafeRegExp: typeof RegExp;
-
- // safe iterators
- export const SafeArrayIterator: new <T>(array: T[]) => IterableIterator<T>;
- export const SafeSetIterator: new <T>(set: Set<T>) => IterableIterator<T>;
- export const SafeMapIterator: new <K, V>(
- map: Map<K, V>,
- ) => IterableIterator<[K, V]>;
- export const SafeStringIterator: new (
- str: string,
- ) => IterableIterator<string>;
-
- // intrinsic objects
- export const indirectEval: typeof globalThis.eval;
- export const isNaN: typeof globalThis.isNaN;
- export const decodeURI: typeof globalThis.decodeURI;
- export const decodeURIComponent: typeof globalThis.decodeURIComponent;
- export const encodeURI: typeof globalThis.encodeURI;
- export const encodeURIComponent: typeof globalThis.encodeURIComponent;
- export const queueMicrotask: typeof globalThis.queueMicrotask;
- export const setQueueMicrotask: (
- queueMicrotask: typeof globalThis.queueMicrotask,
- ) => void;
- export const JSONParse: typeof JSON.parse;
- export const JSONStringify: typeof JSON.stringify;
- export const MathAbs: typeof Math.abs;
- export const MathAcos: typeof Math.acos;
- export const MathAcosh: typeof Math.acosh;
- export const MathAsin: typeof Math.asin;
- export const MathAsinh: typeof Math.asinh;
- export const MathAtan: typeof Math.atan;
- export const MathAtanh: typeof Math.atanh;
- export const MathAtan2: typeof Math.atan2;
- export const MathCeil: typeof Math.ceil;
- export const MathCbrt: typeof Math.cbrt;
- export const MathExpm1: typeof Math.expm1;
- export const MathClz32: typeof Math.clz32;
- export const MathCos: typeof Math.cos;
- export const MathCosh: typeof Math.cosh;
- export const MathExp: typeof Math.exp;
- export const MathFloor: typeof Math.floor;
- export const MathFround: typeof Math.fround;
- export const MathHypot: typeof Math.hypot;
- export const MathHypotApply: StaticApply<typeof Math.hypot>;
- export const MathImul: typeof Math.imul;
- export const MathLog: typeof Math.log;
- export const MathLog1p: typeof Math.log1p;
- export const MathLog2: typeof Math.log2;
- export const MathLog10: typeof Math.log10;
- export const MathMax: typeof Math.max;
- export const MathMaxApply: StaticApply<typeof Math.max>;
- export const MathMin: typeof Math.min;
- export const MathMinApply: StaticApply<typeof Math.min>;
- export const MathPow: typeof Math.pow;
- export const MathRandom: typeof Math.random;
- export const MathRound: typeof Math.round;
- export const MathSign: typeof Math.sign;
- export const MathSin: typeof Math.sin;
- export const MathSinh: typeof Math.sinh;
- export const MathSqrt: typeof Math.sqrt;
- export const MathTan: typeof Math.tan;
- export const MathTanh: typeof Math.tanh;
- export const MathTrunc: typeof Math.trunc;
- export const MathE: typeof Math.E;
- export const MathLN10: typeof Math.LN10;
- export const MathLN2: typeof Math.LN2;
- export const MathLOG10E: typeof Math.LOG10E;
- export const MathLOG2E: typeof Math.LOG2E;
- export const MathPI: typeof Math.PI;
- export const MathSQRT1_2: typeof Math.SQRT1_2;
- export const MathSQRT2: typeof Math.SQRT2;
- export const Proxy: typeof globalThis.Proxy;
- export const ProxyLength: typeof Proxy.length;
- export const ProxyName: typeof Proxy.name;
- export const ProxyRevocable: typeof Proxy.revocable;
- export const ReflectDefineProperty: typeof Reflect.defineProperty;
- export const ReflectDeleteProperty: typeof Reflect.deleteProperty;
- export const ReflectApply: typeof Reflect.apply;
- export const ReflectConstruct: typeof Reflect.construct;
- export const ReflectGet: typeof Reflect.get;
- export const ReflectGetOwnPropertyDescriptor:
- typeof Reflect.getOwnPropertyDescriptor;
- export const ReflectGetPrototypeOf: typeof Reflect.getPrototypeOf;
- export const ReflectHas: typeof Reflect.has;
- export const ReflectIsExtensible: typeof Reflect.isExtensible;
- export const ReflectOwnKeys: typeof Reflect.ownKeys;
- export const ReflectPreventExtensions: typeof Reflect.preventExtensions;
- export const ReflectSet: typeof Reflect.set;
- export const ReflectSetPrototypeOf: typeof Reflect.setPrototypeOf;
- export const AggregateError: typeof globalThis.AggregateError;
- export const AggregateErrorLength: typeof AggregateError.length;
- export const AggregateErrorName: typeof AggregateError.name;
- export const AggregateErrorPrototype: typeof AggregateError.prototype;
- export const Array: typeof globalThis.Array;
- export const ArrayLength: typeof Array.length;
- export const ArrayName: typeof Array.name;
- export const ArrayPrototype: typeof Array.prototype;
- export const ArrayIsArray: typeof Array.isArray;
- export const ArrayFrom: typeof Array.from;
- export const ArrayOf: typeof Array.of;
- export const ArrayOfApply: StaticApply<typeof Array.of>;
- export const ArrayPrototypeAt: UncurryThis<typeof Array.prototype.at>;
- export const ArrayPrototypeConcat: UncurryThis<
- typeof Array.prototype.concat
- >;
- export const ArrayPrototypeCopyWithin: UncurryThis<
- typeof Array.prototype.copyWithin
- >;
- export const ArrayPrototypeFill: UncurryThis<typeof Array.prototype.fill>;
- export const ArrayPrototypeFind: UncurryThis<typeof Array.prototype.find>;
- export const ArrayPrototypeFindIndex: UncurryThis<
- typeof Array.prototype.findIndex
- >;
- export const ArrayPrototypeLastIndexOf: UncurryThis<
- typeof Array.prototype.lastIndexOf
- >;
- export const ArrayPrototypePop: UncurryThis<typeof Array.prototype.pop>;
- export const ArrayPrototypePush: UncurryThis<typeof Array.prototype.push>;
- export const ArrayPrototypePushApply: UncurryThisStaticApply<
- typeof Array.prototype.push
- >;
- export const ArrayPrototypeReverse: UncurryThis<
- typeof Array.prototype.reverse
- >;
- export const ArrayPrototypeShift: UncurryThis<typeof Array.prototype.shift>;
- export const ArrayPrototypeUnshift: UncurryThis<
- typeof Array.prototype.unshift
- >;
- export const ArrayPrototypeUnshiftApply: UncurryThisStaticApply<
- typeof Array.prototype.unshift
- >;
- export const ArrayPrototypeSlice: UncurryThis<typeof Array.prototype.slice>;
- export const ArrayPrototypeSort: UncurryThis<typeof Array.prototype.sort>;
- export const ArrayPrototypeSplice: UncurryThis<
- typeof Array.prototype.splice
- >;
- export const ArrayPrototypeIncludes: UncurryThis<
- typeof Array.prototype.includes
- >;
- export const ArrayPrototypeIndexOf: UncurryThis<
- typeof Array.prototype.indexOf
- >;
- export const ArrayPrototypeJoin: UncurryThis<typeof Array.prototype.join>;
- export const ArrayPrototypeKeys: UncurryThis<typeof Array.prototype.keys>;
- export const ArrayPrototypeEntries: UncurryThis<
- typeof Array.prototype.entries
- >;
- export const ArrayPrototypeValues: UncurryThis<
- typeof Array.prototype.values
- >;
- export const ArrayPrototypeForEach: UncurryThis<
- typeof Array.prototype.forEach
- >;
- export const ArrayPrototypeFilter: UncurryThis<
- typeof Array.prototype.filter
- >;
- export const ArrayPrototypeFlat: UncurryThis<typeof Array.prototype.flat>;
- export const ArrayPrototypeFlatMap: UncurryThis<
- typeof Array.prototype.flatMap
- >;
- export const ArrayPrototypeMap: UncurryThis<typeof Array.prototype.map>;
- export const ArrayPrototypeEvery: UncurryThis<typeof Array.prototype.every>;
- export const ArrayPrototypeSome: UncurryThis<typeof Array.prototype.some>;
- export const ArrayPrototypeReduce: UncurryThis<
- typeof Array.prototype.reduce
- >;
- export const ArrayPrototypeReduceRight: UncurryThis<
- typeof Array.prototype.reduceRight
- >;
- export const ArrayPrototypeToLocaleString: UncurryThis<
- typeof Array.prototype.toLocaleString
- >;
- export const ArrayPrototypeToString: UncurryThis<
- typeof Array.prototype.toString
- >;
- export const ArrayBuffer: typeof globalThis.ArrayBuffer;
- export const ArrayBufferLength: typeof ArrayBuffer.length;
- export const ArrayBufferName: typeof ArrayBuffer.name;
- export const ArrayBufferIsView: typeof ArrayBuffer.isView;
- export const ArrayBufferPrototype: typeof ArrayBuffer.prototype;
- export const ArrayBufferPrototypeGetByteLength: (
- buffer: ArrayBuffer,
- ) => number;
- export const ArrayBufferPrototypeSlice: UncurryThis<
- typeof ArrayBuffer.prototype.slice
- >;
- export const BigInt: typeof globalThis.BigInt;
- export const BigIntLength: typeof BigInt.length;
- export const BigIntName: typeof BigInt.name;
- export const BigIntPrototype: typeof BigInt.prototype;
- export const BigIntAsUintN: typeof BigInt.asUintN;
- export const BigIntAsIntN: typeof BigInt.asIntN;
- export const BigIntPrototypeToLocaleString: UncurryThis<
- typeof BigInt.prototype.toLocaleString
- >;
- export const BigIntPrototypeToString: UncurryThis<
- typeof BigInt.prototype.toString
- >;
- export const BigIntPrototypeValueOf: UncurryThis<
- typeof BigInt.prototype.valueOf
- >;
- export const BigInt64Array: typeof globalThis.BigInt64Array;
- export const BigInt64ArrayLength: typeof BigInt64Array.length;
- export const BigInt64ArrayName: typeof BigInt64Array.name;
- export const BigInt64ArrayPrototype: typeof BigInt64Array.prototype;
- export const BigInt64ArrayBYTES_PER_ELEMENT:
- typeof BigInt64Array.BYTES_PER_ELEMENT;
- export const BigUint64Array: typeof globalThis.BigUint64Array;
- export const BigUint64ArrayLength: typeof BigUint64Array.length;
- export const BigUint64ArrayName: typeof BigUint64Array.name;
- export const BigUint64ArrayPrototype: typeof BigUint64Array.prototype;
- export const BigUint64ArrayBYTES_PER_ELEMENT:
- typeof BigUint64Array.BYTES_PER_ELEMENT;
- export const Boolean: typeof globalThis.Boolean;
- export const BooleanLength: typeof Boolean.length;
- export const BooleanName: typeof Boolean.name;
- export const BooleanPrototype: typeof Boolean.prototype;
- export const BooleanPrototypeToString: UncurryThis<
- typeof Boolean.prototype.toString
- >;
- export const BooleanPrototypeValueOf: UncurryThis<
- typeof Boolean.prototype.valueOf
- >;
- export const DataView: typeof globalThis.DataView;
- export const DataViewLength: typeof DataView.length;
- export const DataViewName: typeof DataView.name;
- export const DataViewPrototype: typeof DataView.prototype;
- export const DataViewPrototypeGetBuffer: (
- view: DataView,
- ) => ArrayBuffer | SharedArrayBuffer;
- export const DataViewPrototypeGetByteLength: (view: DataView) => number;
- export const DataViewPrototypeGetByteOffset: (view: DataView) => number;
- export const DataViewPrototypeGetInt8: UncurryThis<
- typeof DataView.prototype.getInt8
- >;
- export const DataViewPrototypeSetInt8: UncurryThis<
- typeof DataView.prototype.setInt8
- >;
- export const DataViewPrototypeGetUint8: UncurryThis<
- typeof DataView.prototype.getUint8
- >;
- export const DataViewPrototypeSetUint8: UncurryThis<
- typeof DataView.prototype.setUint8
- >;
- export const DataViewPrototypeGetInt16: UncurryThis<
- typeof DataView.prototype.getInt16
- >;
- export const DataViewPrototypeSetInt16: UncurryThis<
- typeof DataView.prototype.setInt16
- >;
- export const DataViewPrototypeGetUint16: UncurryThis<
- typeof DataView.prototype.getUint16
- >;
- export const DataViewPrototypeSetUint16: UncurryThis<
- typeof DataView.prototype.setUint16
- >;
- export const DataViewPrototypeGetInt32: UncurryThis<
- typeof DataView.prototype.getInt32
- >;
- export const DataViewPrototypeSetInt32: UncurryThis<
- typeof DataView.prototype.setInt32
- >;
- export const DataViewPrototypeGetUint32: UncurryThis<
- typeof DataView.prototype.getUint32
- >;
- export const DataViewPrototypeSetUint32: UncurryThis<
- typeof DataView.prototype.setUint32
- >;
- export const DataViewPrototypeGetFloat32: UncurryThis<
- typeof DataView.prototype.getFloat32
- >;
- export const DataViewPrototypeSetFloat32: UncurryThis<
- typeof DataView.prototype.setFloat32
- >;
- export const DataViewPrototypeGetFloat64: UncurryThis<
- typeof DataView.prototype.getFloat64
- >;
- export const DataViewPrototypeSetFloat64: UncurryThis<
- typeof DataView.prototype.setFloat64
- >;
- export const DataViewPrototypeGetBigInt64: UncurryThis<
- typeof DataView.prototype.getBigInt64
- >;
- export const DataViewPrototypeSetBigInt64: UncurryThis<
- typeof DataView.prototype.setBigInt64
- >;
- export const DataViewPrototypeGetBigUint64: UncurryThis<
- typeof DataView.prototype.getBigUint64
- >;
- export const DataViewPrototypeSetBigUint64: UncurryThis<
- typeof DataView.prototype.setBigUint64
- >;
- export const Date: typeof globalThis.Date;
- export const DateLength: typeof Date.length;
- export const DateName: typeof Date.name;
- export const DatePrototype: typeof Date.prototype;
- export const DateNow: typeof Date.now;
- export const DateParse: typeof Date.parse;
- export const DateUTC: typeof Date.UTC;
- export const DatePrototypeToString: UncurryThis<
- typeof Date.prototype.toString
- >;
- export const DatePrototypeToDateString: UncurryThis<
- typeof Date.prototype.toDateString
- >;
- export const DatePrototypeToTimeString: UncurryThis<
- typeof Date.prototype.toTimeString
- >;
- export const DatePrototypeToISOString: UncurryThis<
- typeof Date.prototype.toISOString
- >;
- export const DatePrototypeToUTCString: UncurryThis<
- typeof Date.prototype.toUTCString
- >;
- export const DatePrototypeToGMTString: UncurryThis<
- typeof Date.prototype.toGMTString
- >;
- export const DatePrototypeGetDate: UncurryThis<
- typeof Date.prototype.getDate
- >;
- export const DatePrototypeSetDate: UncurryThis<
- typeof Date.prototype.setDate
- >;
- export const DatePrototypeGetDay: UncurryThis<typeof Date.prototype.getDay>;
- export const DatePrototypeGetFullYear: UncurryThis<
- typeof Date.prototype.getFullYear
- >;
- export const DatePrototypeSetFullYear: UncurryThis<
- typeof Date.prototype.setFullYear
- >;
- export const DatePrototypeGetHours: UncurryThis<
- typeof Date.prototype.getHours
- >;
- export const DatePrototypeSetHours: UncurryThis<
- typeof Date.prototype.setHours
- >;
- export const DatePrototypeGetMilliseconds: UncurryThis<
- typeof Date.prototype.getMilliseconds
- >;
- export const DatePrototypeSetMilliseconds: UncurryThis<
- typeof Date.prototype.setMilliseconds
- >;
- export const DatePrototypeGetMinutes: UncurryThis<
- typeof Date.prototype.getMinutes
- >;
- export const DatePrototypeSetMinutes: UncurryThis<
- typeof Date.prototype.setMinutes
- >;
- export const DatePrototypeGetMonth: UncurryThis<
- typeof Date.prototype.getMonth
- >;
- export const DatePrototypeSetMonth: UncurryThis<
- typeof Date.prototype.setMonth
- >;
- export const DatePrototypeGetSeconds: UncurryThis<
- typeof Date.prototype.getSeconds
- >;
- export const DatePrototypeSetSeconds: UncurryThis<
- typeof Date.prototype.setSeconds
- >;
- export const DatePrototypeGetTime: UncurryThis<
- typeof Date.prototype.getTime
- >;
- export const DatePrototypeSetTime: UncurryThis<
- typeof Date.prototype.setTime
- >;
- export const DatePrototypeGetTimezoneOffset: UncurryThis<
- typeof Date.prototype.getTimezoneOffset
- >;
- export const DatePrototypeGetUTCDate: UncurryThis<
- typeof Date.prototype.getUTCDate
- >;
- export const DatePrototypeSetUTCDate: UncurryThis<
- typeof Date.prototype.setUTCDate
- >;
- export const DatePrototypeGetUTCDay: UncurryThis<
- typeof Date.prototype.getUTCDay
- >;
- export const DatePrototypeGetUTCFullYear: UncurryThis<
- typeof Date.prototype.getUTCFullYear
- >;
- export const DatePrototypeSetUTCFullYear: UncurryThis<
- typeof Date.prototype.setUTCFullYear
- >;
- export const DatePrototypeGetUTCHours: UncurryThis<
- typeof Date.prototype.getUTCHours
- >;
- export const DatePrototypeSetUTCHours: UncurryThis<
- typeof Date.prototype.setUTCHours
- >;
- export const DatePrototypeGetUTCMilliseconds: UncurryThis<
- typeof Date.prototype.getUTCMilliseconds
- >;
- export const DatePrototypeSetUTCMilliseconds: UncurryThis<
- typeof Date.prototype.setUTCMilliseconds
- >;
- export const DatePrototypeGetUTCMinutes: UncurryThis<
- typeof Date.prototype.getUTCMinutes
- >;
- export const DatePrototypeSetUTCMinutes: UncurryThis<
- typeof Date.prototype.setUTCMinutes
- >;
- export const DatePrototypeGetUTCMonth: UncurryThis<
- typeof Date.prototype.getUTCMonth
- >;
- export const DatePrototypeSetUTCMonth: UncurryThis<
- typeof Date.prototype.setUTCMonth
- >;
- export const DatePrototypeGetUTCSeconds: UncurryThis<
- typeof Date.prototype.getUTCSeconds
- >;
- export const DatePrototypeSetUTCSeconds: UncurryThis<
- typeof Date.prototype.setUTCSeconds
- >;
- export const DatePrototypeValueOf: UncurryThis<
- typeof Date.prototype.valueOf
- >;
- export const DatePrototypeGetYear: UncurryThis<
- typeof Date.prototype.getYear
- >;
- export const DatePrototypeSetYear: UncurryThis<
- typeof Date.prototype.setYear
- >;
- export const DatePrototypeToJSON: UncurryThis<typeof Date.prototype.toJSON>;
- export const DatePrototypeToLocaleString: UncurryThis<
- typeof Date.prototype.toLocaleString
- >;
- export const DatePrototypeToLocaleDateString: UncurryThis<
- typeof Date.prototype.toLocaleDateString
- >;
- export const DatePrototypeToLocaleTimeString: UncurryThis<
- typeof Date.prototype.toLocaleTimeString
- >;
- export const Error: typeof globalThis.Error;
- export const ErrorLength: typeof Error.length;
- export const ErrorName: typeof Error.name;
- export const ErrorPrototype: typeof Error.prototype;
- export const ErrorCaptureStackTrace: typeof Error.captureStackTrace;
- export const ErrorStackTraceLimit: typeof Error.stackTraceLimit;
- export const ErrorPrototypeToString: UncurryThis<
- typeof Error.prototype.toString
- >;
- export const EvalError: typeof globalThis.EvalError;
- export const EvalErrorLength: typeof EvalError.length;
- export const EvalErrorName: typeof EvalError.name;
- export const EvalErrorPrototype: typeof EvalError.prototype;
- export const FinalizationRegistry: typeof globalThis.FinalizationRegistry;
- export const FinalizationRegistryLength: typeof FinalizationRegistry.length;
- export const FinalizationRegistryName: typeof FinalizationRegistry.name;
- export const FinalizationRegistryPrototype:
- typeof FinalizationRegistry.prototype;
- export const FinalizationRegistryPrototypeRegister: UncurryThis<
- typeof FinalizationRegistry.prototype.register
- >;
- export const FinalizationRegistryPrototypeUnregister: UncurryThis<
- typeof FinalizationRegistry.prototype.unregister
- >;
- export const Float32Array: typeof globalThis.Float32Array;
- export const Float32ArrayLength: typeof Float32Array.length;
- export const Float32ArrayName: typeof Float32Array.name;
- export const Float32ArrayPrototype: typeof Float32Array.prototype;
- export const Float32ArrayBYTES_PER_ELEMENT:
- typeof Float32Array.BYTES_PER_ELEMENT;
- export const Float64Array: typeof globalThis.Float64Array;
- export const Float64ArrayLength: typeof Float64Array.length;
- export const Float64ArrayName: typeof Float64Array.name;
- export const Float64ArrayPrototype: typeof Float64Array.prototype;
- export const Float64ArrayBYTES_PER_ELEMENT:
- typeof Float64Array.BYTES_PER_ELEMENT;
- export const Function: typeof globalThis.Function;
- export const FunctionLength: typeof Function.length;
- export const FunctionName: typeof Function.name;
- export const FunctionPrototype: typeof Function.prototype;
- export const FunctionPrototypeApply: UncurryThis<
- typeof Function.prototype.apply
- >;
- export const FunctionPrototypeBind: UncurryThis<
- typeof Function.prototype.bind
- >;
- export const FunctionPrototypeCall: UncurryThis<
- typeof Function.prototype.call
- >;
- export const FunctionPrototypeToString: UncurryThis<
- typeof Function.prototype.toString
- >;
- export const Int16Array: typeof globalThis.Int16Array;
- export const Int16ArrayLength: typeof Int16Array.length;
- export const Int16ArrayName: typeof Int16Array.name;
- export const Int16ArrayPrototype: typeof Int16Array.prototype;
- export const Int16ArrayBYTES_PER_ELEMENT:
- typeof Int16Array.BYTES_PER_ELEMENT;
- export const Int32Array: typeof globalThis.Int32Array;
- export const Int32ArrayLength: typeof Int32Array.length;
- export const Int32ArrayName: typeof Int32Array.name;
- export const Int32ArrayPrototype: typeof Int32Array.prototype;
- export const Int32ArrayBYTES_PER_ELEMENT:
- typeof Int32Array.BYTES_PER_ELEMENT;
- export const Int8Array: typeof globalThis.Int8Array;
- export const Int8ArrayLength: typeof Int8Array.length;
- export const Int8ArrayName: typeof Int8Array.name;
- export const Int8ArrayPrototype: typeof Int8Array.prototype;
- export const Int8ArrayBYTES_PER_ELEMENT: typeof Int8Array.BYTES_PER_ELEMENT;
- export const Map: typeof globalThis.Map;
- export const MapLength: typeof Map.length;
- export const MapName: typeof Map.name;
- export const MapPrototype: typeof Map.prototype;
- export const MapPrototypeGetSize: (map: Map) => number;
- export const MapPrototypeGet: UncurryThis<typeof Map.prototype.get>;
- export const MapPrototypeSet: UncurryThis<typeof Map.prototype.set>;
- export const MapPrototypeHas: UncurryThis<typeof Map.prototype.has>;
- export const MapPrototypeDelete: UncurryThis<typeof Map.prototype.delete>;
- export const MapPrototypeClear: UncurryThis<typeof Map.prototype.clear>;
- export const MapPrototypeEntries: UncurryThis<typeof Map.prototype.entries>;
- export const MapPrototypeForEach: UncurryThis<typeof Map.prototype.forEach>;
- export const MapPrototypeKeys: UncurryThis<typeof Map.prototype.keys>;
- export const MapPrototypeValues: UncurryThis<typeof Map.prototype.values>;
- export const Number: typeof globalThis.Number;
- export const NumberLength: typeof Number.length;
- export const NumberName: typeof Number.name;
- export const NumberPrototype: typeof Number.prototype;
- export const NumberIsFinite: typeof Number.isFinite;
- export const NumberIsInteger: typeof Number.isInteger;
- export const NumberIsNaN: typeof Number.isNaN;
- export const NumberIsSafeInteger: typeof Number.isSafeInteger;
- export const NumberParseFloat: typeof Number.parseFloat;
- export const NumberParseInt: typeof Number.parseInt;
- export const NumberMAX_VALUE: typeof Number.MAX_VALUE;
- export const NumberMIN_VALUE: typeof Number.MIN_VALUE;
- export const NumberNaN: typeof Number.NaN;
- export const NumberNEGATIVE_INFINITY: typeof Number.NEGATIVE_INFINITY;
- export const NumberPOSITIVE_INFINITY: typeof Number.POSITIVE_INFINITY;
- export const NumberMAX_SAFE_INTEGER: typeof Number.MAX_SAFE_INTEGER;
- export const NumberMIN_SAFE_INTEGER: typeof Number.MIN_SAFE_INTEGER;
- export const NumberEPSILON: typeof Number.EPSILON;
- export const NumberPrototypeToExponential: UncurryThis<
- typeof Number.prototype.toExponential
- >;
- export const NumberPrototypeToFixed: UncurryThis<
- typeof Number.prototype.toFixed
- >;
- export const NumberPrototypeToPrecision: UncurryThis<
- typeof Number.prototype.toPrecision
- >;
- export const NumberPrototypeToString: UncurryThis<
- typeof Number.prototype.toString
- >;
- export const NumberPrototypeValueOf: UncurryThis<
- typeof Number.prototype.valueOf
- >;
- export const NumberPrototypeToLocaleString: UncurryThis<
- typeof Number.prototype.toLocaleString
- >;
- export const Object: typeof globalThis.Object;
- export const ObjectLength: typeof Object.length;
- export const ObjectName: typeof Object.name;
- export const ObjectAssign: typeof Object.assign;
- export const ObjectGetOwnPropertyDescriptor:
- typeof Object.getOwnPropertyDescriptor;
- export const ObjectGetOwnPropertyDescriptors:
- typeof Object.getOwnPropertyDescriptors;
- export const ObjectGetOwnPropertyNames: typeof Object.getOwnPropertyNames;
- export const ObjectGetOwnPropertySymbols:
- typeof Object.getOwnPropertySymbols;
- export const ObjectHasOwn: typeof Object.hasOwn;
- export const ObjectIs: typeof Object.is;
- export const ObjectPreventExtensions: typeof Object.preventExtensions;
- export const ObjectSeal: typeof Object.seal;
- export const ObjectCreate: typeof Object.create;
- export const ObjectDefineProperties: typeof Object.defineProperties;
- export const ObjectDefineProperty: typeof Object.defineProperty;
- export const ObjectFreeze: typeof Object.freeze;
- export const ObjectGetPrototypeOf: typeof Object.getPrototypeOf;
- export const ObjectSetPrototypeOf: typeof Object.setPrototypeOf;
- export const ObjectIsExtensible: typeof Object.isExtensible;
- export const ObjectIsFrozen: typeof Object.isFrozen;
- export const ObjectIsSealed: typeof Object.isSealed;
- export const ObjectKeys: typeof Object.keys;
- export const ObjectEntries: typeof Object.entries;
- export const ObjectFromEntries: typeof Object.fromEntries;
- export const ObjectValues: typeof Object.values;
- export const ObjectPrototype: typeof Object.prototype;
- export const ObjectPrototype__defineGetter__: UncurryThis<
- typeof Object.prototype.__defineGetter__
- >;
- export const ObjectPrototype__defineSetter__: UncurryThis<
- typeof Object.prototype.__defineSetter__
- >;
- export const ObjectPrototypeHasOwnProperty: UncurryThis<
- typeof Object.prototype.hasOwnProperty
- >;
- export const ObjectPrototype__lookupGetter__: UncurryThis<
- typeof Object.prototype.__lookupGetter__
- >;
- export const ObjectPrototype__lookupSetter__: UncurryThis<
- typeof Object.prototype.__lookupSetter__
- >;
- export const ObjectPrototypeIsPrototypeOf: UncurryThis<
- typeof Object.prototype.isPrototypeOf
- >;
- export const ObjectPrototypePropertyIsEnumerable: UncurryThis<
- typeof Object.prototype.propertyIsEnumerable
- >;
- export const ObjectPrototypeToString: UncurryThis<
- typeof Object.prototype.toString
- >;
- export const ObjectPrototypeValueOf: UncurryThis<
- typeof Object.prototype.valueOf
- >;
- export const ObjectPrototypeToLocaleString: UncurryThis<
- typeof Object.prototype.toLocaleString
- >;
- export const RangeError: typeof globalThis.RangeError;
- export const RangeErrorLength: typeof RangeError.length;
- export const RangeErrorName: typeof RangeError.name;
- export const RangeErrorPrototype: typeof RangeError.prototype;
- export const ReferenceError: typeof globalThis.ReferenceError;
- export const ReferenceErrorLength: typeof ReferenceError.length;
- export const ReferenceErrorName: typeof ReferenceError.name;
- export const ReferenceErrorPrototype: typeof ReferenceError.prototype;
- export const RegExp: typeof globalThis.RegExp;
- export const RegExpLength: typeof RegExp.length;
- export const RegExpName: typeof RegExp.name;
- export const RegExpPrototype: typeof RegExp.prototype;
- export const RegExpPrototypeExec: UncurryThis<typeof RegExp.prototype.exec>;
- export const RegExpPrototypeCompile: UncurryThis<
- typeof RegExp.prototype.compile
- >;
- export const RegExpPrototypeToString: UncurryThis<
- typeof RegExp.prototype.toString
- >;
- export const RegExpPrototypeTest: UncurryThis<typeof RegExp.prototype.test>;
- export const Set: typeof globalThis.Set;
- export const SetLength: typeof Set.length;
- export const SetName: typeof Set.name;
- export const SetPrototype: typeof Set.prototype;
- export const SetPrototypeGetSize: (set: Set) => number;
- export const SetPrototypeHas: UncurryThis<typeof Set.prototype.has>;
- export const SetPrototypeAdd: UncurryThis<typeof Set.prototype.add>;
- export const SetPrototypeDelete: UncurryThis<typeof Set.prototype.delete>;
- export const SetPrototypeClear: UncurryThis<typeof Set.prototype.clear>;
- export const SetPrototypeEntries: UncurryThis<typeof Set.prototype.entries>;
- export const SetPrototypeForEach: UncurryThis<typeof Set.prototype.forEach>;
- export const SetPrototypeValues: UncurryThis<typeof Set.prototype.values>;
- export const SetPrototypeKeys: UncurryThis<typeof Set.prototype.keys>;
- export const String: typeof globalThis.String;
- export const StringLength: typeof String.length;
- export const StringName: typeof String.name;
- export const StringPrototype: typeof String.prototype;
- export const StringFromCharCode: typeof String.fromCharCode;
- export const StringFromCodePoint: typeof String.fromCodePoint;
- export const StringRaw: typeof String.raw;
- export const StringPrototypeAnchor: UncurryThis<
- typeof String.prototype.anchor
- >;
- export const StringPrototypeBig: UncurryThis<typeof String.prototype.big>;
- export const StringPrototypeBlink: UncurryThis<
- typeof String.prototype.blink
- >;
- export const StringPrototypeBold: UncurryThis<typeof String.prototype.bold>;
- export const StringPrototypeCharAt: UncurryThis<
- typeof String.prototype.charAt
- >;
- export const StringPrototypeCharCodeAt: UncurryThis<
- typeof String.prototype.charCodeAt
- >;
- export const StringPrototypeCodePointAt: UncurryThis<
- typeof String.prototype.codePointAt
- >;
- export const StringPrototypeConcat: UncurryThis<
- typeof String.prototype.concat
- >;
- export const StringPrototypeConcatApply: UncurryThisStaticApply<
- typeof String.prototype.concat
- >;
- export const StringPrototypeEndsWith: UncurryThis<
- typeof String.prototype.endsWith
- >;
- export const StringPrototypeFontcolor: UncurryThis<
- typeof String.prototype.fontcolor
- >;
- export const StringPrototypeFontsize: UncurryThis<
- typeof String.prototype.fontsize
- >;
- export const StringPrototypeFixed: UncurryThis<
- typeof String.prototype.fixed
- >;
- export const StringPrototypeIncludes: UncurryThis<
- typeof String.prototype.includes
- >;
- export const StringPrototypeIndexOf: UncurryThis<
- typeof String.prototype.indexOf
- >;
- export const StringPrototypeItalics: UncurryThis<
- typeof String.prototype.italics
- >;
- export const StringPrototypeLastIndexOf: UncurryThis<
- typeof String.prototype.lastIndexOf
- >;
- export const StringPrototypeLink: UncurryThis<typeof String.prototype.link>;
- export const StringPrototypeLocaleCompare: UncurryThis<
- typeof String.prototype.localeCompare
- >;
- export const StringPrototypeMatch: UncurryThis<
- typeof String.prototype.match
- >;
- export const StringPrototypeMatchAll: UncurryThis<
- typeof String.prototype.matchAll
- >;
- export const StringPrototypeNormalize: UncurryThis<
- typeof String.prototype.normalize
- >;
- export const StringPrototypePadEnd: UncurryThis<
- typeof String.prototype.padEnd
- >;
- export const StringPrototypePadStart: UncurryThis<
- typeof String.prototype.padStart
- >;
- export const StringPrototypeRepeat: UncurryThis<
- typeof String.prototype.repeat
- >;
- export const StringPrototypeReplace: UncurryThis<
- typeof String.prototype.replace
- >;
- export const StringPrototypeSearch: UncurryThis<
- typeof String.prototype.search
- >;
- export const StringPrototypeSlice: UncurryThis<
- typeof String.prototype.slice
- >;
- export const StringPrototypeSmall: UncurryThis<
- typeof String.prototype.small
- >;
- export const StringPrototypeSplit: UncurryThis<
- typeof String.prototype.split
- >;
- export const StringPrototypeStrike: UncurryThis<
- typeof String.prototype.strike
- >;
- export const StringPrototypeSub: UncurryThis<typeof String.prototype.sub>;
- export const StringPrototypeSubstr: UncurryThis<
- typeof String.prototype.substr
- >;
- export const StringPrototypeSubstring: UncurryThis<
- typeof String.prototype.substring
- >;
- export const StringPrototypeSup: UncurryThis<typeof String.prototype.sup>;
- export const StringPrototypeStartsWith: UncurryThis<
- typeof String.prototype.startsWith
- >;
- export const StringPrototypeToString: UncurryThis<
- typeof String.prototype.toString
- >;
- export const StringPrototypeTrim: UncurryThis<typeof String.prototype.trim>;
- export const StringPrototypeTrimStart: UncurryThis<
- typeof String.prototype.trimStart
- >;
- export const StringPrototypeTrimLeft: UncurryThis<
- typeof String.prototype.trimLeft
- >;
- export const StringPrototypeTrimEnd: UncurryThis<
- typeof String.prototype.trimEnd
- >;
- export const StringPrototypeTrimRight: UncurryThis<
- typeof String.prototype.trimRight
- >;
- export const StringPrototypeToLocaleLowerCase: UncurryThis<
- typeof String.prototype.toLocaleLowerCase
- >;
- export const StringPrototypeToLocaleUpperCase: UncurryThis<
- typeof String.prototype.toLocaleUpperCase
- >;
- export const StringPrototypeToLowerCase: UncurryThis<
- typeof String.prototype.toLowerCase
- >;
- export const StringPrototypeToUpperCase: UncurryThis<
- typeof String.prototype.toUpperCase
- >;
- export const StringPrototypeValueOf: UncurryThis<
- typeof String.prototype.valueOf
- >;
- export const StringPrototypeReplaceAll: UncurryThis<
- typeof String.prototype.replaceAll
- >;
- export const Symbol: typeof globalThis.Symbol;
- export const SymbolLength: typeof Symbol.length;
- export const SymbolName: typeof Symbol.name;
- export const SymbolPrototype: typeof Symbol.prototype;
- export const SymbolPrototypeGetDescription: (symbol: symbol) => string;
- export const SymbolFor: typeof Symbol.for;
- export const SymbolKeyFor: typeof Symbol.keyFor;
- export const SymbolAsyncIterator: typeof Symbol.asyncIterator;
- export const SymbolHasInstance: typeof Symbol.hasInstance;
- export const SymbolIsConcatSpreadable: typeof Symbol.isConcatSpreadable;
- export const SymbolIterator: typeof Symbol.iterator;
- export const SymbolMatch: typeof Symbol.match;
- export const SymbolMatchAll: typeof Symbol.matchAll;
- export const SymbolReplace: typeof Symbol.replace;
- export const SymbolSearch: typeof Symbol.search;
- export const SymbolSpecies: typeof Symbol.species;
- export const SymbolSplit: typeof Symbol.split;
- export const SymbolToPrimitive: typeof Symbol.toPrimitive;
- export const SymbolToStringTag: typeof Symbol.toStringTag;
- export const SymbolUnscopables: typeof Symbol.unscopables;
- export const SymbolPrototypeToString: UncurryThis<
- typeof Symbol.prototype.toString
- >;
- export const SymbolPrototypeValueOf: UncurryThis<
- typeof Symbol.prototype.valueOf
- >;
- export const SyntaxError: typeof globalThis.SyntaxError;
- export const SyntaxErrorLength: typeof SyntaxError.length;
- export const SyntaxErrorName: typeof SyntaxError.name;
- export const SyntaxErrorPrototype: typeof SyntaxError.prototype;
- export const TypeError: typeof globalThis.TypeError;
- export const TypeErrorLength: typeof TypeError.length;
- export const TypeErrorName: typeof TypeError.name;
- export const TypeErrorPrototype: typeof TypeError.prototype;
- export const URIError: typeof globalThis.URIError;
- export const URIErrorLength: typeof URIError.length;
- export const URIErrorName: typeof URIError.name;
- export const URIErrorPrototype: typeof URIError.prototype;
- export const Uint16Array: typeof globalThis.Uint16Array;
- export const Uint16ArrayLength: typeof Uint16Array.length;
- export const Uint16ArrayName: typeof Uint16Array.name;
- export const Uint16ArrayPrototype: typeof Uint16Array.prototype;
- export const Uint16ArrayBYTES_PER_ELEMENT:
- typeof Uint16Array.BYTES_PER_ELEMENT;
- export const Uint32Array: typeof globalThis.Uint32Array;
- export const Uint32ArrayLength: typeof Uint32Array.length;
- export const Uint32ArrayName: typeof Uint32Array.name;
- export const Uint32ArrayPrototype: typeof Uint32Array.prototype;
- export const Uint32ArrayBYTES_PER_ELEMENT:
- typeof Uint32Array.BYTES_PER_ELEMENT;
- export const Uint8Array: typeof globalThis.Uint8Array;
- export const Uint8ArrayLength: typeof Uint8Array.length;
- export const Uint8ArrayName: typeof Uint8Array.name;
- export const Uint8ArrayPrototype: typeof Uint8Array.prototype;
- export const Uint8ArrayBYTES_PER_ELEMENT:
- typeof Uint8Array.BYTES_PER_ELEMENT;
- export const Uint8ClampedArray: typeof globalThis.Uint8ClampedArray;
- export const Uint8ClampedArrayLength: typeof Uint8ClampedArray.length;
- export const Uint8ClampedArrayName: typeof Uint8ClampedArray.name;
- export const Uint8ClampedArrayPrototype: typeof Uint8ClampedArray.prototype;
- export const Uint8ClampedArrayBYTES_PER_ELEMENT:
- typeof Uint8ClampedArray.BYTES_PER_ELEMENT;
- export const WeakMap: typeof globalThis.WeakMap;
- export const WeakMapLength: typeof WeakMap.length;
- export const WeakMapName: typeof WeakMap.name;
- export const WeakMapPrototype: typeof WeakMap.prototype;
- export const WeakMapPrototypeDelete: UncurryThis<
- typeof WeakMap.prototype.delete
- >;
- export const WeakMapPrototypeGet: UncurryThis<typeof WeakMap.prototype.get>;
- export const WeakMapPrototypeSet: UncurryThis<typeof WeakMap.prototype.set>;
- export const WeakMapPrototypeHas: UncurryThis<typeof WeakMap.prototype.has>;
- export const WeakRef: typeof globalThis.WeakRef;
- export const WeakRefLength: typeof WeakRef.length;
- export const WeakRefName: typeof WeakRef.name;
- export const WeakRefPrototype: typeof WeakRef.prototype;
- export const WeakRefPrototypeDeref: UncurryThis<
- typeof WeakRef.prototype.deref
- >;
- export const WeakSet: typeof globalThis.WeakSet;
- export const WeakSetLength: typeof WeakSet.length;
- export const WeakSetName: typeof WeakSet.name;
- export const WeakSetPrototype: typeof WeakSet.prototype;
- export const WeakSetPrototypeDelete: UncurryThis<
- typeof WeakSet.prototype.delete
- >;
- export const WeakSetPrototypeHas: UncurryThis<typeof WeakSet.prototype.has>;
- export const WeakSetPrototypeAdd: UncurryThis<typeof WeakSet.prototype.add>;
- export const Promise: typeof globalThis.Promise;
- export const PromiseLength: typeof Promise.length;
- export const PromiseName: typeof Promise.name;
- export const PromisePrototype: typeof Promise.prototype;
- export const PromiseAll: typeof Promise.all;
- export const PromiseRace: typeof Promise.race;
- export const PromiseResolve: typeof Promise.resolve;
- export const PromiseReject: typeof Promise.reject;
- export const PromiseAllSettled: typeof Promise.allSettled;
- export const PromiseAny: typeof Promise.any;
- export const PromisePrototypeThen: UncurryThis<
- typeof Promise.prototype.then
- >;
- export const PromisePrototypeCatch: UncurryThis<
- typeof Promise.prototype.catch
- >;
- export const PromisePrototypeFinally: UncurryThis<
- typeof Promise.prototype.finally
- >;
-
- // abstract intrinsic objects
- export const ArrayIteratorPrototypeNext: <T>(
- iterator: IterableIterator<T>,
- ) => IteratorResult<T>;
- export const SetIteratorPrototypeNext: <T>(
- iterator: IterableIterator<T>,
- ) => IteratorResult<T>;
- export const MapIteratorPrototypeNext: <T>(
- iterator: IterableIterator<T>,
- ) => IteratorResult<T>;
- export const StringIteratorPrototypeNext: <T>(
- iterator: IterableIterator<T>,
- ) => IteratorResult<T>;
- export const GeneratorPrototypeNext: <T>(
- generator: Generator<T>,
- ) => IteratorResult<T>;
- export const AsyncGeneratorPrototypeNext: <T>(
- asyncGenerator: AsyncGenerator<T>,
- ) => Promise<IteratorResult<T>>;
- export const TypedArrayFrom: (
- constructor: Uint8ArrayConstructor,
- arrayLike: ArrayLike<number>,
- ) => Uint8Array;
- export const TypedArrayPrototypeGetBuffer: (
- array: Uint8Array,
- ) => ArrayBuffer | SharedArrayBuffer;
- export const TypedArrayPrototypeGetByteLength: (
- array: Uint8Array,
- ) => number;
- export const TypedArrayPrototypeGetByteOffset: (
- array: Uint8Array,
- ) => number;
- export const TypedArrayPrototypeGetLength: (array: Uint8Array) => number;
- export const TypedArrayPrototypeGetSymbolToStringTag: (
- v: unknown,
- ) => string | undefined;
- export const TypedArrayPrototypeCopyWithin: UncurryThis<
- typeof Uint8Array.prototype.copyWithin
- >;
- export const TypedArrayPrototypeEvery: UncurryThis<
- typeof Uint8Array.prototype.every
- >;
- export const TypedArrayPrototypeFill: UncurryThis<
- typeof Uint8Array.prototype.fill
- >;
- export const TypedArrayPrototypeFilter: UncurryThis<
- typeof Uint8Array.prototype.filter
- >;
- export const TypedArrayPrototypeFind: UncurryThis<
- typeof Uint8Array.prototype.find
- >;
- export const TypedArrayPrototypeFindIndex: UncurryThis<
- typeof Uint8Array.prototype.findIndex
- >;
- export const TypedArrayPrototypeForEach: UncurryThis<
- typeof Uint8Array.prototype.forEach
- >;
- export const TypedArrayPrototypeIndexOf: UncurryThis<
- typeof Uint8Array.prototype.indexOf
- >;
- export const TypedArrayPrototypeJoin: UncurryThis<
- typeof Uint8Array.prototype.join
- >;
- export const TypedArrayPrototypeLastIndexOf: UncurryThis<
- typeof Uint8Array.prototype.lastIndexOf
- >;
- export const TypedArrayPrototypeMap: UncurryThis<
- typeof Uint8Array.prototype.map
- >;
- export const TypedArrayPrototypeReduce: UncurryThis<
- typeof Uint8Array.prototype.reduce
- >;
- export const TypedArrayPrototypeReduceRight: UncurryThis<
- typeof Uint8Array.prototype.reduceRight
- >;
- export const TypedArrayPrototypeReverse: UncurryThis<
- typeof Uint8Array.prototype.reverse
- >;
- export const TypedArrayPrototypeSet: UncurryThis<
- typeof Uint8Array.prototype.set
- >;
- export const TypedArrayPrototypeSlice: UncurryThis<
- typeof Uint8Array.prototype.slice
- >;
- export const TypedArrayPrototypeSome: UncurryThis<
- typeof Uint8Array.prototype.some
- >;
- export const TypedArrayPrototypeSort: UncurryThis<
- typeof Uint8Array.prototype.sort
- >;
- export const TypedArrayPrototypeSubarray: UncurryThis<
- typeof Uint8Array.prototype.subarray
- >;
- export const TypedArrayPrototypeToLocaleString: UncurryThis<
- typeof Uint8Array.prototype.toLocaleString
- >;
- export const TypedArrayPrototypeToString: UncurryThis<
- typeof Uint8Array.prototype.toString
- >;
- export const TypedArrayPrototypeValueOf: UncurryThis<
- typeof Uint8Array.prototype.valueOf
- >;
- }
-}
diff --git a/core/io.rs b/core/io.rs
deleted file mode 100644
index c7a56d942..000000000
--- a/core/io.rs
+++ /dev/null
@@ -1,300 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-
-use std::ops::Deref;
-use std::ops::DerefMut;
-
-use bytes::Buf;
-use serde_v8::JsBuffer;
-
-/// BufView is a wrapper around an underlying contiguous chunk of bytes. It can
-/// be created from a [JsBuffer], [bytes::Bytes], or [Vec<u8>] and implements
-/// `Deref<[u8]>` and `AsRef<[u8]>`.
-///
-/// The wrapper has the ability to constrain the exposed view to a sub-region of
-/// the underlying buffer. This is useful for write operations, because they may
-/// have to be called multiple times, with different views onto the buffer to be
-/// able to write it entirely.
-pub struct BufView {
- inner: BufViewInner,
- cursor: usize,
-}
-
-enum BufViewInner {
- Empty,
- Bytes(bytes::Bytes),
- JsBuffer(JsBuffer),
- Vec(Vec<u8>),
-}
-
-impl BufView {
- const fn from_inner(inner: BufViewInner) -> Self {
- Self { inner, cursor: 0 }
- }
-
- pub const fn empty() -> Self {
- Self::from_inner(BufViewInner::Empty)
- }
-
- /// Get the length of the buffer view. This is the length of the underlying
- /// buffer minus the cursor position.
- pub fn len(&self) -> usize {
- match &self.inner {
- BufViewInner::Empty => 0,
- BufViewInner::Bytes(bytes) => bytes.len() - self.cursor,
- BufViewInner::JsBuffer(js_buf) => js_buf.len() - self.cursor,
- BufViewInner::Vec(vec) => vec.len() - self.cursor,
- }
- }
-
- /// Is the buffer view empty?
- pub fn is_empty(&self) -> bool {
- self.len() == 0
- }
-
- /// Advance the internal cursor of the buffer view by `n` bytes.
- pub fn advance_cursor(&mut self, n: usize) {
- assert!(self.len() >= n);
- self.cursor += n;
- }
-
- /// Reset the internal cursor of the buffer view to the beginning of the
- /// buffer. Returns the old cursor position.
- pub fn reset_cursor(&mut self) -> usize {
- let old = self.cursor;
- self.cursor = 0;
- old
- }
-}
-
-impl Buf for BufView {
- fn remaining(&self) -> usize {
- self.len()
- }
-
- fn chunk(&self) -> &[u8] {
- self.deref()
- }
-
- fn advance(&mut self, cnt: usize) {
- self.advance_cursor(cnt)
- }
-}
-
-impl Deref for BufView {
- type Target = [u8];
-
- fn deref(&self) -> &[u8] {
- let buf = match &self.inner {
- BufViewInner::Empty => &[],
- BufViewInner::Bytes(bytes) => bytes.deref(),
- BufViewInner::JsBuffer(js_buf) => js_buf.deref(),
- BufViewInner::Vec(vec) => vec.deref(),
- };
- &buf[self.cursor..]
- }
-}
-
-impl AsRef<[u8]> for BufView {
- fn as_ref(&self) -> &[u8] {
- self.deref()
- }
-}
-
-impl From<JsBuffer> for BufView {
- fn from(buf: JsBuffer) -> Self {
- Self::from_inner(BufViewInner::JsBuffer(buf))
- }
-}
-
-impl From<Vec<u8>> for BufView {
- fn from(vec: Vec<u8>) -> Self {
- Self::from_inner(BufViewInner::Vec(vec))
- }
-}
-
-impl From<bytes::Bytes> for BufView {
- fn from(buf: bytes::Bytes) -> Self {
- Self::from_inner(BufViewInner::Bytes(buf))
- }
-}
-
-impl From<BufView> for bytes::Bytes {
- fn from(buf: BufView) -> Self {
- match buf.inner {
- BufViewInner::Empty => bytes::Bytes::new(),
- BufViewInner::Bytes(bytes) => bytes,
- BufViewInner::JsBuffer(js_buf) => js_buf.into(),
- BufViewInner::Vec(vec) => vec.into(),
- }
- }
-}
-
-/// BufMutView is a wrapper around an underlying contiguous chunk of writable
-/// bytes. It can be created from a `JsBuffer` or a `Vec<u8>` and implements
-/// `DerefMut<[u8]>` and `AsMut<[u8]>`.
-///
-/// The wrapper has the ability to constrain the exposed view to a sub-region of
-/// the underlying buffer. This is useful for write operations, because they may
-/// have to be called multiple times, with different views onto the buffer to be
-/// able to write it entirely.
-///
-/// A `BufMutView` can be turned into a `BufView` by calling `BufMutView::into_view`.
-pub struct BufMutView {
- inner: BufMutViewInner,
- cursor: usize,
-}
-
-enum BufMutViewInner {
- JsBuffer(JsBuffer),
- Vec(Vec<u8>),
-}
-
-impl BufMutView {
- fn from_inner(inner: BufMutViewInner) -> Self {
- Self { inner, cursor: 0 }
- }
-
- pub fn new(len: usize) -> Self {
- Self::from_inner(BufMutViewInner::Vec(vec![0; len]))
- }
-
- /// Get the length of the buffer view. This is the length of the underlying
- /// buffer minus the cursor position.
- pub fn len(&self) -> usize {
- match &self.inner {
- BufMutViewInner::JsBuffer(js_buf) => js_buf.len() - self.cursor,
- BufMutViewInner::Vec(vec) => vec.len() - self.cursor,
- }
- }
-
- /// Is the buffer view empty?
- pub fn is_empty(&self) -> bool {
- self.len() == 0
- }
-
- /// Advance the internal cursor of the buffer view by `n` bytes.
- pub fn advance_cursor(&mut self, n: usize) {
- assert!(self.len() >= n);
- self.cursor += n;
- }
-
- /// Reset the internal cursor of the buffer view to the beginning of the
- /// buffer. Returns the old cursor position.
- pub fn reset_cursor(&mut self) -> usize {
- let old = self.cursor;
- self.cursor = 0;
- old
- }
-
- /// Turn this `BufMutView` into a `BufView`.
- pub fn into_view(self) -> BufView {
- let inner = match self.inner {
- BufMutViewInner::JsBuffer(js_buf) => BufViewInner::JsBuffer(js_buf),
- BufMutViewInner::Vec(vec) => BufViewInner::Vec(vec),
- };
- BufView {
- inner,
- cursor: self.cursor,
- }
- }
-
- /// Unwrap the underlying buffer into a `Vec<u8>`, consuming the `BufMutView`.
- ///
- /// This method panics when called on a `BufMutView` that was created from a
- /// `JsBuffer`.
- pub fn unwrap_vec(self) -> Vec<u8> {
- match self.inner {
- BufMutViewInner::JsBuffer(_) => {
- panic!("Cannot unwrap a JsBuffer backed BufMutView into a Vec");
- }
- BufMutViewInner::Vec(vec) => vec,
- }
- }
-
- /// Get a mutable reference to an underlying `Vec<u8>`.
- ///
- /// This method panics when called on a `BufMutView` that was created from a
- /// `JsBuffer`.
- pub fn get_mut_vec(&mut self) -> &mut Vec<u8> {
- match &mut self.inner {
- BufMutViewInner::JsBuffer(_) => {
- panic!("Cannot unwrap a JsBuffer backed BufMutView into a Vec");
- }
- BufMutViewInner::Vec(vec) => vec,
- }
- }
-}
-
-impl Buf for BufMutView {
- fn remaining(&self) -> usize {
- self.len()
- }
-
- fn chunk(&self) -> &[u8] {
- self.deref()
- }
-
- fn advance(&mut self, cnt: usize) {
- self.advance_cursor(cnt)
- }
-}
-
-impl Deref for BufMutView {
- type Target = [u8];
-
- fn deref(&self) -> &[u8] {
- let buf = match &self.inner {
- BufMutViewInner::JsBuffer(js_buf) => js_buf.deref(),
- BufMutViewInner::Vec(vec) => vec.deref(),
- };
- &buf[self.cursor..]
- }
-}
-
-impl DerefMut for BufMutView {
- fn deref_mut(&mut self) -> &mut [u8] {
- let buf = match &mut self.inner {
- BufMutViewInner::JsBuffer(js_buf) => js_buf.deref_mut(),
- BufMutViewInner::Vec(vec) => vec.deref_mut(),
- };
- &mut buf[self.cursor..]
- }
-}
-
-impl AsRef<[u8]> for BufMutView {
- fn as_ref(&self) -> &[u8] {
- self.deref()
- }
-}
-
-impl AsMut<[u8]> for BufMutView {
- fn as_mut(&mut self) -> &mut [u8] {
- self.deref_mut()
- }
-}
-
-impl From<JsBuffer> for BufMutView {
- fn from(buf: JsBuffer) -> Self {
- Self::from_inner(BufMutViewInner::JsBuffer(buf))
- }
-}
-
-impl From<Vec<u8>> for BufMutView {
- fn from(buf: Vec<u8>) -> Self {
- Self::from_inner(BufMutViewInner::Vec(buf))
- }
-}
-
-pub enum WriteOutcome {
- Partial { nwritten: usize, view: BufView },
- Full { nwritten: usize },
-}
-
-impl WriteOutcome {
- pub fn nwritten(&self) -> usize {
- match self {
- WriteOutcome::Partial { nwritten, .. } => *nwritten,
- WriteOutcome::Full { nwritten } => *nwritten,
- }
- }
-}
diff --git a/core/joinset.rs b/core/joinset.rs
deleted file mode 100644
index f80c95712..000000000
--- a/core/joinset.rs
+++ /dev/null
@@ -1,92 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-// Some code and comments under MIT license where adapted from Tokio code
-// Copyright (c) 2023 Tokio Contributors
-
-use std::task::Context;
-use std::task::Poll;
-use std::task::Waker;
-
-use futures::Future;
-use tokio::task::AbortHandle;
-use tokio::task::JoinError;
-
-use crate::task::MaskFutureAsSend;
-use crate::task::MaskResultAsSend;
-
-/// Wraps the tokio [`JoinSet`] to make it !Send-friendly and to make it easier and safer for us to
-/// poll while empty.
-pub(crate) struct JoinSet<T> {
- joinset: tokio::task::JoinSet<MaskResultAsSend<T>>,
- /// If join_next returns Ready(None), we stash the waker
- waker: Option<Waker>,
-}
-
-impl<T> Default for JoinSet<T> {
- fn default() -> Self {
- Self {
- joinset: Default::default(),
- waker: None,
- }
- }
-}
-
-impl<T: 'static> JoinSet<T> {
- /// Spawn the provided task on the `JoinSet`, returning an [`AbortHandle`]
- /// that can be used to remotely cancel the task.
- ///
- /// The provided future will start running in the background immediately
- /// when this method is called, even if you don't await anything on this
- /// `JoinSet`.
- ///
- /// # Panics
- ///
- /// This method panics if called outside of a Tokio runtime.
- ///
- /// [`AbortHandle`]: tokio::task::AbortHandle
- #[track_caller]
- pub fn spawn<F>(&mut self, task: F) -> AbortHandle
- where
- F: Future<Output = T>,
- F: 'static,
- T: 'static,
- {
- // SAFETY: We only use this with the single-thread executor
- let handle = self.joinset.spawn(unsafe { MaskFutureAsSend::new(task) });
-
- // If someone had called poll_join_next while we were empty, ask them to poll again
- // so we can properly register the waker with the underlying JoinSet.
- if let Some(waker) = self.waker.take() {
- waker.wake();
- }
- handle
- }
-
- /// Returns the number of tasks currently in the `JoinSet`.
- pub fn len(&self) -> usize {
- self.joinset.len()
- }
-
- /// Waits until one of the tasks in the set completes and returns its output.
- ///
- /// # Cancel Safety
- ///
- /// This method is cancel safe. If `join_next` is used as the event in a `tokio::select!`
- /// statement and some other branch completes first, it is guaranteed that no tasks were
- /// removed from this `JoinSet`.
- pub fn poll_join_next(
- &mut self,
- cx: &mut Context,
- ) -> Poll<Result<T, JoinError>> {
- // TODO(mmastrac): Use poll_join_next from Tokio
- let next = std::pin::pin!(self.joinset.join_next());
- match next.poll(cx) {
- Poll::Ready(Some(res)) => Poll::Ready(res.map(|res| res.into_inner())),
- Poll::Ready(None) => {
- // Stash waker
- self.waker = Some(cx.waker().clone());
- Poll::Pending
- }
- Poll::Pending => Poll::Pending,
- }
- }
-}
diff --git a/core/lib.deno_core.d.ts b/core/lib.deno_core.d.ts
deleted file mode 100644
index fc7865829..000000000
--- a/core/lib.deno_core.d.ts
+++ /dev/null
@@ -1,212 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-
-// deno-lint-ignore-file no-explicit-any
-
-/// <reference no-default-lib="true" />
-/// <reference lib="esnext" />
-
-declare namespace Deno {
- namespace core {
- /** Call an op in Rust, and asynchronously receive the result. */
- function opAsync(
- opName: string,
- ...args: any[]
- ): Promise<any>;
-
- /** Mark following promise as "ref", ie. event loop won't exit
- * until all "ref" promises are resolved. All async ops are "ref" by default. */
- function refOp(promiseId: number): void;
-
- /** Mark following promise as "unref", ie. event loop will exit
- * if there are only "unref" promises left. */
- function unrefOp(promiseId: number): void;
-
- /**
- * List of all registered ops, in the form of a map that maps op
- * name to function.
- */
- const ops: Record<string, (...args: unknown[]) => any>;
-
- /**
- * List of all registered async ops, in the form of a map that maps op
- * name to function.
- */
- const asyncOps: Record<string, (...args: unknown[]) => any>;
-
- /**
- * Retrieve a list of all open resources, in the form of a map that maps
- * resource id to the resource name.
- */
- function resources(): Record<string, string>;
-
- /**
- * Close the resource with the specified op id. Throws `BadResource` error
- * if resource doesn't exist in resource table.
- */
- function close(rid: number): void;
-
- /**
- * Try close the resource with the specified op id; if resource with given
- * id doesn't exist do nothing.
- */
- function tryClose(rid: number): void;
-
- /**
- * Read from a (stream) resource that implements read()
- */
- function read(rid: number, buf: Uint8Array): Promise<number>;
-
- /**
- * Write to a (stream) resource that implements write()
- */
- function write(rid: number, buf: Uint8Array): Promise<number>;
-
- /**
- * Write to a (stream) resource that implements write()
- */
- function writeAll(rid: number, buf: Uint8Array): Promise<void>;
-
- /**
- * Synchronously read from a (stream) resource that implements readSync().
- */
- function readSync(rid: number, buf: Uint8Array): number;
-
- /**
- * Synchronously write to a (stream) resource that implements writeSync().
- */
- function writeSync(rid: number, buf: Uint8Array): number;
-
- /**
- * Print a message to stdout or stderr
- */
- function print(message: string, is_err?: boolean): void;
-
- /**
- * Shutdown a resource
- */
- function shutdown(rid: number): Promise<void>;
-
- /** Encode a string to its Uint8Array representation. */
- function encode(input: string): Uint8Array;
-
- /**
- * Set a callback that will be called when the WebAssembly streaming APIs
- * (`WebAssembly.compileStreaming` and `WebAssembly.instantiateStreaming`)
- * are called in order to feed the source's bytes to the wasm compiler.
- * The callback is called with the source argument passed to the streaming
- * APIs and an rid to use with the wasm streaming ops.
- *
- * The callback should eventually invoke the following ops:
- * - `op_wasm_streaming_feed`. Feeds bytes from the wasm resource to the
- * compiler. Takes the rid and a `Uint8Array`.
- * - `op_wasm_streaming_abort`. Aborts the wasm compilation. Takes the rid
- * and an exception. Invalidates the resource.
- * - `op_wasm_streaming_set_url`. Sets a source URL for the wasm module.
- * Takes the rid and a string.
- * - To indicate the end of the resource, use `Deno.core.close()` with the
- * rid.
- */
- function setWasmStreamingCallback(
- cb: (source: any, rid: number) => void,
- ): void;
-
- /**
- * Set a callback that will be called after resolving ops and before resolving
- * macrotasks.
- */
- function setNextTickCallback(
- cb: () => void,
- ): void;
-
- /** Check if there's a scheduled "next tick". */
- function hasNextTickScheduled(): boolean;
-
- /** Set a value telling the runtime if there are "next ticks" scheduled */
- function setHasNextTickScheduled(value: boolean): void;
-
- /**
- * Set a callback that will be called after resolving ops and "next ticks".
- */
- function setMacrotaskCallback(
- cb: () => boolean,
- ): void;
-
- /**
- * Set a callback that will be called when a promise without a .catch
- * handler is rejected. Returns the old handler or undefined.
- */
- function setPromiseRejectCallback(
- cb: PromiseRejectCallback,
- ): undefined | PromiseRejectCallback;
-
- export type PromiseRejectCallback = (
- type: number,
- promise: Promise<unknown>,
- reason: any,
- ) => void;
-
- /**
- * Set a callback that will be called when an exception isn't caught
- * by any try/catch handlers. Currently only invoked when the callback
- * to setPromiseRejectCallback() throws an exception but that is expected
- * to change in the future. Returns the old handler or undefined.
- */
- function setUncaughtExceptionCallback(
- cb: UncaughtExceptionCallback,
- ): undefined | UncaughtExceptionCallback;
-
- export type UncaughtExceptionCallback = (err: any) => void;
-
- /**
- * Enables collection of stack traces of all async ops. This allows for
- * debugging of where a given async op was started. Deno CLI uses this for
- * improving error message in op sanitizer errors for `deno test`.
- *
- * **NOTE:** enabling tracing has a significant negative performance impact.
- * To get high level metrics on async ops with no added performance cost,
- * use `Deno.core.metrics()`.
- */
- function enableOpCallTracing(): void;
-
- export interface OpCallTrace {
- opName: string;
- stack: string;
- }
-
- /**
- * A map containing traces for all ongoing async ops. The key is the op id.
- * Tracing only occurs when `Deno.core.enableOpCallTracing()` was previously
- * enabled.
- */
- const opCallTraces: Map<number, OpCallTrace>;
-
- /**
- * Adds a callback for the given Promise event. If this function is called
- * multiple times, the callbacks are called in the order they were added.
- * - `init_hook` is called when a new promise is created. When a new promise
- * is created as part of the chain in the case of `Promise.then` or in the
- * intermediate promises created by `Promise.{race, all}`/`AsyncFunctionAwait`,
- * we pass the parent promise otherwise we pass undefined.
- * - `before_hook` is called at the beginning of the promise reaction.
- * - `after_hook` is called at the end of the promise reaction.
- * - `resolve_hook` is called at the beginning of resolve or reject function.
- */
- function setPromiseHooks(
- init_hook?: (
- promise: Promise<unknown>,
- parentPromise?: Promise<unknown>,
- ) => void,
- before_hook?: (promise: Promise<unknown>) => void,
- after_hook?: (promise: Promise<unknown>) => void,
- resolve_hook?: (promise: Promise<unknown>) => void,
- ): void;
-
- const build: {
- target: string;
- arch: string;
- os: string;
- vendor: string;
- env: string | undefined;
- };
- }
-}
diff --git a/core/lib.rs b/core/lib.rs
deleted file mode 100644
index 2f8d9142c..000000000
--- a/core/lib.rs
+++ /dev/null
@@ -1,204 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-mod async_cancel;
-mod async_cell;
-pub mod error;
-mod error_codes;
-mod extensions;
-mod fast_string;
-mod flags;
-mod gotham_state;
-mod inspector;
-mod io;
-mod joinset;
-mod module_specifier;
-mod modules;
-mod normalize_path;
-mod ops;
-mod ops_builtin;
-mod ops_builtin_v8;
-mod ops_metrics;
-mod path;
-mod resources;
-mod runtime;
-mod source_map;
-pub mod task;
-mod task_queue;
-
-// Re-exports
-pub use anyhow;
-pub use futures;
-pub use parking_lot;
-pub use serde;
-pub use serde_json;
-pub use serde_v8;
-pub use serde_v8::ByteString;
-pub use serde_v8::DetachedBuffer;
-pub use serde_v8::JsBuffer;
-pub use serde_v8::StringOrBuffer;
-pub use serde_v8::ToJsBuffer;
-pub use serde_v8::U16String;
-pub use sourcemap;
-pub use url;
-pub use v8;
-
-pub use deno_ops::op;
-pub use deno_ops::op2;
-
-pub use crate::async_cancel::CancelFuture;
-pub use crate::async_cancel::CancelHandle;
-pub use crate::async_cancel::CancelTryFuture;
-pub use crate::async_cancel::Cancelable;
-pub use crate::async_cancel::Canceled;
-pub use crate::async_cancel::TryCancelable;
-pub use crate::async_cell::AsyncMut;
-pub use crate::async_cell::AsyncMutFuture;
-pub use crate::async_cell::AsyncRef;
-pub use crate::async_cell::AsyncRefCell;
-pub use crate::async_cell::AsyncRefFuture;
-pub use crate::async_cell::RcLike;
-pub use crate::async_cell::RcRef;
-pub use crate::error::GetErrorClassFn;
-pub use crate::error::JsErrorCreateFn;
-pub use crate::extensions::Extension;
-pub use crate::extensions::ExtensionBuilder;
-pub use crate::extensions::ExtensionFileSource;
-pub use crate::extensions::ExtensionFileSourceCode;
-pub use crate::extensions::OpDecl;
-pub use crate::extensions::OpMiddlewareFn;
-pub use crate::fast_string::FastString;
-pub use crate::flags::v8_set_flags;
-pub use crate::inspector::InspectorMsg;
-pub use crate::inspector::InspectorMsgKind;
-pub use crate::inspector::InspectorSessionProxy;
-pub use crate::inspector::JsRuntimeInspector;
-pub use crate::inspector::LocalInspectorSession;
-pub use crate::io::BufMutView;
-pub use crate::io::BufView;
-pub use crate::io::WriteOutcome;
-pub use crate::module_specifier::resolve_import;
-pub use crate::module_specifier::resolve_path;
-pub use crate::module_specifier::resolve_url;
-pub use crate::module_specifier::resolve_url_or_path;
-pub use crate::module_specifier::ModuleResolutionError;
-pub use crate::module_specifier::ModuleSpecifier;
-pub use crate::modules::ExtModuleLoaderCb;
-pub use crate::modules::FsModuleLoader;
-pub use crate::modules::ModuleCode;
-pub use crate::modules::ModuleId;
-pub use crate::modules::ModuleLoader;
-pub use crate::modules::ModuleSource;
-pub use crate::modules::ModuleSourceFuture;
-pub use crate::modules::ModuleType;
-pub use crate::modules::NoopModuleLoader;
-pub use crate::modules::ResolutionKind;
-pub use crate::normalize_path::normalize_path;
-pub use crate::ops::OpCall;
-pub use crate::ops::OpError;
-pub use crate::ops::OpId;
-pub use crate::ops::OpResult;
-pub use crate::ops::OpState;
-pub use crate::ops::PromiseId;
-pub use crate::ops_builtin::op_close;
-pub use crate::ops_builtin::op_print;
-pub use crate::ops_builtin::op_resources;
-pub use crate::ops_builtin::op_void_async;
-pub use crate::ops_builtin::op_void_sync;
-pub use crate::ops_metrics::OpsTracker;
-pub use crate::path::strip_unc_prefix;
-pub use crate::resources::AsyncResult;
-pub use crate::resources::Resource;
-pub use crate::resources::ResourceId;
-pub use crate::resources::ResourceTable;
-pub use crate::runtime::CompiledWasmModuleStore;
-pub use crate::runtime::CrossIsolateStore;
-pub use crate::runtime::JsRealm;
-pub use crate::runtime::JsRuntime;
-pub use crate::runtime::JsRuntimeForSnapshot;
-pub use crate::runtime::RuntimeOptions;
-pub use crate::runtime::SharedArrayBufferStore;
-pub use crate::runtime::Snapshot;
-pub use crate::runtime::V8_WRAPPER_OBJECT_INDEX;
-pub use crate::runtime::V8_WRAPPER_TYPE_INDEX;
-pub use crate::source_map::SourceMapGetter;
-pub use crate::task_queue::TaskQueue;
-pub use crate::task_queue::TaskQueuePermit;
-
-pub fn v8_version() -> &'static str {
- v8::V8::get_version()
-}
-
-/// An internal module re-exporting functions used by the #[op] (`deno_ops`) macro
-#[doc(hidden)]
-pub mod _ops {
- pub use super::error::throw_type_error;
- pub use super::error_codes::get_error_code;
- pub use super::extensions::Op;
- pub use super::extensions::OpDecl;
- pub use super::ops::to_op_result;
- pub use super::ops::OpCtx;
- pub use super::ops::OpResult;
- pub use super::runtime::ops::map_async_op1;
- pub use super::runtime::ops::map_async_op2;
- pub use super::runtime::ops::map_async_op3;
- pub use super::runtime::ops::map_async_op4;
- pub use super::runtime::ops::queue_async_op;
- pub use super::runtime::ops::queue_fast_async_op;
- pub use super::runtime::ops::to_i32;
- pub use super::runtime::ops::to_str;
- pub use super::runtime::ops::to_str_ptr;
- pub use super::runtime::ops::to_string_ptr;
- pub use super::runtime::ops::to_u32;
- pub use super::runtime::V8_WRAPPER_OBJECT_INDEX;
- pub use super::runtime::V8_WRAPPER_TYPE_INDEX;
-}
-
-// TODO(mmastrac): Temporary while we move code around
-pub mod snapshot_util {
- pub use crate::runtime::create_snapshot;
- pub use crate::runtime::get_js_files;
- pub use crate::runtime::CreateSnapshotOptions;
- pub use crate::runtime::CreateSnapshotOutput;
- pub use crate::runtime::FilterFn;
-}
-
-/// A helper macro that will return a call site in Rust code. Should be
-/// used when executing internal one-line scripts for JsRuntime lifecycle.
-///
-/// Returns a string in form of: "`[ext:<filename>:<line>:<column>]`"
-#[macro_export]
-macro_rules! located_script_name {
- () => {
- concat!(
- "[ext:",
- std::file!(),
- ":",
- std::line!(),
- ":",
- std::column!(),
- "]"
- )
- };
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- #[test]
- fn located_script_name() {
- // Note that this test will fail if this file is moved. We don't
- // test line locations because that's just too brittle.
- let name = located_script_name!();
- let expected = if cfg!(windows) {
- "[ext:core\\lib.rs:"
- } else {
- "[ext:core/lib.rs:"
- };
- assert_eq!(&name[..expected.len()], expected);
- }
-
- #[test]
- fn test_v8_version() {
- assert!(v8_version().len() > 3);
- }
-}
diff --git a/core/module_specifier.rs b/core/module_specifier.rs
deleted file mode 100644
index 20358e79c..000000000
--- a/core/module_specifier.rs
+++ /dev/null
@@ -1,500 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-
-use crate::normalize_path;
-use std::error::Error;
-use std::fmt;
-use std::path::Path;
-use std::path::PathBuf;
-use url::ParseError;
-use url::Url;
-
-/// Error indicating the reason resolving a module specifier failed.
-#[derive(Clone, Debug, Eq, PartialEq)]
-pub enum ModuleResolutionError {
- InvalidUrl(ParseError),
- InvalidBaseUrl(ParseError),
- InvalidPath(PathBuf),
- ImportPrefixMissing(String, Option<String>),
-}
-use ModuleResolutionError::*;
-
-impl Error for ModuleResolutionError {
- fn source(&self) -> Option<&(dyn Error + 'static)> {
- match self {
- InvalidUrl(ref err) | InvalidBaseUrl(ref err) => Some(err),
- _ => None,
- }
- }
-}
-
-impl fmt::Display for ModuleResolutionError {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match self {
- InvalidUrl(ref err) => write!(f, "invalid URL: {err}"),
- InvalidBaseUrl(ref err) => {
- write!(f, "invalid base URL for relative import: {err}")
- }
- InvalidPath(ref path) => write!(f, "invalid module path: {path:?}"),
- ImportPrefixMissing(ref specifier, ref maybe_referrer) => write!(
- f,
- "Relative import path \"{}\" not prefixed with / or ./ or ../{}",
- specifier,
- match maybe_referrer {
- Some(referrer) => format!(" from \"{referrer}\""),
- None => String::new(),
- }
- ),
- }
- }
-}
-
-/// Resolved module specifier
-pub type ModuleSpecifier = Url;
-
-/// Resolves module using this algorithm:
-/// <https://html.spec.whatwg.org/multipage/webappapis.html#resolve-a-module-specifier>
-pub fn resolve_import(
- specifier: &str,
- base: &str,
-) -> Result<ModuleSpecifier, ModuleResolutionError> {
- let url = match Url::parse(specifier) {
- // 1. Apply the URL parser to specifier.
- // If the result is not failure, return he result.
- Ok(url) => url,
-
- // 2. If specifier does not start with the character U+002F SOLIDUS (/),
- // the two-character sequence U+002E FULL STOP, U+002F SOLIDUS (./),
- // or the three-character sequence U+002E FULL STOP, U+002E FULL STOP,
- // U+002F SOLIDUS (../), return failure.
- Err(ParseError::RelativeUrlWithoutBase)
- if !(specifier.starts_with('/')
- || specifier.starts_with("./")
- || specifier.starts_with("../")) =>
- {
- let maybe_referrer = if base.is_empty() {
- None
- } else {
- Some(base.to_string())
- };
- return Err(ImportPrefixMissing(specifier.to_string(), maybe_referrer));
- }
-
- // 3. Return the result of applying the URL parser to specifier with base
- // URL as the base URL.
- Err(ParseError::RelativeUrlWithoutBase) => {
- let base = Url::parse(base).map_err(InvalidBaseUrl)?;
- base.join(specifier).map_err(InvalidUrl)?
- }
-
- // If parsing the specifier as a URL failed for a different reason than
- // it being relative, always return the original error. We don't want to
- // return `ImportPrefixMissing` or `InvalidBaseUrl` if the real
- // problem lies somewhere else.
- Err(err) => return Err(InvalidUrl(err)),
- };
-
- Ok(url)
-}
-
-/// Converts a string representing an absolute URL into a ModuleSpecifier.
-pub fn resolve_url(
- url_str: &str,
-) -> Result<ModuleSpecifier, ModuleResolutionError> {
- Url::parse(url_str).map_err(ModuleResolutionError::InvalidUrl)
-}
-
-/// Takes a string representing either an absolute URL or a file path,
-/// as it may be passed to deno as a command line argument.
-/// The string is interpreted as a URL if it starts with a valid URI scheme,
-/// e.g. 'http:' or 'file:' or 'git+ssh:'. If not, it's interpreted as a
-/// file path; if it is a relative path it's resolved relative to passed
-/// `current_dir`.
-pub fn resolve_url_or_path(
- specifier: &str,
- current_dir: &Path,
-) -> Result<ModuleSpecifier, ModuleResolutionError> {
- if specifier_has_uri_scheme(specifier) {
- resolve_url(specifier)
- } else {
- resolve_path(specifier, current_dir)
- }
-}
-
-/// Converts a string representing a relative or absolute path into a
-/// ModuleSpecifier. A relative path is considered relative to the passed
-/// `current_dir`.
-pub fn resolve_path(
- path_str: &str,
- current_dir: &Path,
-) -> Result<ModuleSpecifier, ModuleResolutionError> {
- let path = current_dir.join(path_str);
- let path = normalize_path(path);
- Url::from_file_path(&path)
- .map_err(|()| ModuleResolutionError::InvalidPath(path))
-}
-
-/// Returns true if the input string starts with a sequence of characters
-/// that could be a valid URI scheme, like 'https:', 'git+ssh:' or 'data:'.
-///
-/// According to RFC 3986 (https://tools.ietf.org/html/rfc3986#section-3.1),
-/// a valid scheme has the following format:
-/// scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
-///
-/// We additionally require the scheme to be at least 2 characters long,
-/// because otherwise a windows path like c:/foo would be treated as a URL,
-/// while no schemes with a one-letter name actually exist.
-fn specifier_has_uri_scheme(specifier: &str) -> bool {
- let mut chars = specifier.chars();
- let mut len = 0usize;
- // THe first character must be a letter.
- match chars.next() {
- Some(c) if c.is_ascii_alphabetic() => len += 1,
- _ => return false,
- }
- // Second and following characters must be either a letter, number,
- // plus sign, minus sign, or dot.
- loop {
- match chars.next() {
- Some(c) if c.is_ascii_alphanumeric() || "+-.".contains(c) => len += 1,
- Some(':') if len >= 2 => return true,
- _ => return false,
- }
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
- use crate::serde_json::from_value;
- use crate::serde_json::json;
- use std::env::current_dir;
- use std::path::Path;
-
- #[test]
- fn test_resolve_import() {
- let tests = vec![
- (
- "./005_more_imports.ts",
- "http://deno.land/core/tests/006_url_imports.ts",
- "http://deno.land/core/tests/005_more_imports.ts",
- ),
- (
- "../005_more_imports.ts",
- "http://deno.land/core/tests/006_url_imports.ts",
- "http://deno.land/core/005_more_imports.ts",
- ),
- (
- "http://deno.land/core/tests/005_more_imports.ts",
- "http://deno.land/core/tests/006_url_imports.ts",
- "http://deno.land/core/tests/005_more_imports.ts",
- ),
- (
- "data:text/javascript,export default 'grapes';",
- "http://deno.land/core/tests/006_url_imports.ts",
- "data:text/javascript,export default 'grapes';",
- ),
- (
- "blob:https://whatwg.org/d0360e2f-caee-469f-9a2f-87d5b0456f6f",
- "http://deno.land/core/tests/006_url_imports.ts",
- "blob:https://whatwg.org/d0360e2f-caee-469f-9a2f-87d5b0456f6f",
- ),
- (
- "javascript:export default 'artichokes';",
- "http://deno.land/core/tests/006_url_imports.ts",
- "javascript:export default 'artichokes';",
- ),
- (
- "data:text/plain,export default 'kale';",
- "http://deno.land/core/tests/006_url_imports.ts",
- "data:text/plain,export default 'kale';",
- ),
- (
- "/dev/core/tests/005_more_imports.ts",
- "file:///home/yeti",
- "file:///dev/core/tests/005_more_imports.ts",
- ),
- (
- "//zombo.com/1999.ts",
- "https://cherry.dev/its/a/thing",
- "https://zombo.com/1999.ts",
- ),
- (
- "http://deno.land/this/url/is/valid",
- "base is clearly not a valid url",
- "http://deno.land/this/url/is/valid",
- ),
- (
- "//server/some/dir/file",
- "file:///home/yeti/deno",
- "file://server/some/dir/file",
- ),
- // This test is disabled because the url crate does not follow the spec,
- // dropping the server part from the final result.
- // (
- // "/another/path/at/the/same/server",
- // "file://server/some/dir/file",
- // "file://server/another/path/at/the/same/server",
- // ),
- ];
-
- for (specifier, base, expected_url) in tests {
- let url = resolve_import(specifier, base).unwrap().to_string();
- assert_eq!(url, expected_url);
- }
- }
-
- #[test]
- fn test_resolve_import_error() {
- use url::ParseError::*;
- use ModuleResolutionError::*;
-
- let tests = vec![
- (
- "awesome.ts",
- "<unknown>",
- ImportPrefixMissing(
- "awesome.ts".to_string(),
- Some("<unknown>".to_string()),
- ),
- ),
- (
- "005_more_imports.ts",
- "http://deno.land/core/tests/006_url_imports.ts",
- ImportPrefixMissing(
- "005_more_imports.ts".to_string(),
- Some("http://deno.land/core/tests/006_url_imports.ts".to_string()),
- ),
- ),
- (
- ".tomato",
- "http://deno.land/core/tests/006_url_imports.ts",
- ImportPrefixMissing(
- ".tomato".to_string(),
- Some("http://deno.land/core/tests/006_url_imports.ts".to_string()),
- ),
- ),
- (
- "..zucchini.mjs",
- "http://deno.land/core/tests/006_url_imports.ts",
- ImportPrefixMissing(
- "..zucchini.mjs".to_string(),
- Some("http://deno.land/core/tests/006_url_imports.ts".to_string()),
- ),
- ),
- (
- r".\yam.es",
- "http://deno.land/core/tests/006_url_imports.ts",
- ImportPrefixMissing(
- r".\yam.es".to_string(),
- Some("http://deno.land/core/tests/006_url_imports.ts".to_string()),
- ),
- ),
- (
- r"..\yam.es",
- "http://deno.land/core/tests/006_url_imports.ts",
- ImportPrefixMissing(
- r"..\yam.es".to_string(),
- Some("http://deno.land/core/tests/006_url_imports.ts".to_string()),
- ),
- ),
- (
- "https://eggplant:b/c",
- "http://deno.land/core/tests/006_url_imports.ts",
- InvalidUrl(InvalidPort),
- ),
- (
- "https://eggplant@/c",
- "http://deno.land/core/tests/006_url_imports.ts",
- InvalidUrl(EmptyHost),
- ),
- (
- "./foo.ts",
- "/relative/base/url",
- InvalidBaseUrl(RelativeUrlWithoutBase),
- ),
- ];
-
- for (specifier, base, expected_err) in tests {
- let err = resolve_import(specifier, base).unwrap_err();
- assert_eq!(err, expected_err);
- }
- }
-
- #[test]
- fn test_resolve_url_or_path() {
- // Absolute URL.
- let mut tests: Vec<(&str, String)> = vec![
- (
- "http://deno.land/core/tests/006_url_imports.ts",
- "http://deno.land/core/tests/006_url_imports.ts".to_string(),
- ),
- (
- "https://deno.land/core/tests/006_url_imports.ts",
- "https://deno.land/core/tests/006_url_imports.ts".to_string(),
- ),
- ];
-
- // The local path tests assume that the cwd is the deno repo root.
- let cwd = current_dir().unwrap();
- let cwd_str = cwd.to_str().unwrap();
-
- if cfg!(target_os = "windows") {
- // Absolute local path.
- let expected_url = "file:///C:/deno/tests/006_url_imports.ts";
- tests.extend(vec![
- (
- r"C:/deno/tests/006_url_imports.ts",
- expected_url.to_string(),
- ),
- (
- r"C:\deno\tests\006_url_imports.ts",
- expected_url.to_string(),
- ),
- (
- r"\\?\C:\deno\tests\006_url_imports.ts",
- expected_url.to_string(),
- ),
- // Not supported: `Url::from_file_path()` fails.
- // (r"\\.\C:\deno\tests\006_url_imports.ts", expected_url.to_string()),
- // Not supported: `Url::from_file_path()` performs the wrong conversion.
- // (r"//./C:/deno/tests/006_url_imports.ts", expected_url.to_string()),
- ]);
-
- // Rooted local path without drive letter.
- let expected_url = format!(
- "file:///{}:/deno/tests/006_url_imports.ts",
- cwd_str.get(..1).unwrap(),
- );
- tests.extend(vec![
- (r"/deno/tests/006_url_imports.ts", expected_url.to_string()),
- (r"\deno\tests\006_url_imports.ts", expected_url.to_string()),
- (
- r"\deno\..\deno\tests\006_url_imports.ts",
- expected_url.to_string(),
- ),
- (r"\deno\.\tests\006_url_imports.ts", expected_url),
- ]);
-
- // Relative local path.
- let expected_url = format!(
- "file:///{}/tests/006_url_imports.ts",
- cwd_str.replace('\\', "/")
- );
- tests.extend(vec![
- (r"tests/006_url_imports.ts", expected_url.to_string()),
- (r"tests\006_url_imports.ts", expected_url.to_string()),
- (r"./tests/006_url_imports.ts", (*expected_url).to_string()),
- (r".\tests\006_url_imports.ts", (*expected_url).to_string()),
- ]);
-
- // UNC network path.
- let expected_url = "file://server/share/deno/cool";
- tests.extend(vec![
- (r"\\server\share\deno\cool", expected_url.to_string()),
- (r"\\server/share/deno/cool", expected_url.to_string()),
- // Not supported: `Url::from_file_path()` performs the wrong conversion.
- // (r"//server/share/deno/cool", expected_url.to_string()),
- ]);
- } else {
- // Absolute local path.
- let expected_url = "file:///deno/tests/006_url_imports.ts";
- tests.extend(vec![
- ("/deno/tests/006_url_imports.ts", expected_url.to_string()),
- ("//deno/tests/006_url_imports.ts", expected_url.to_string()),
- ]);
-
- // Relative local path.
- let expected_url = format!("file://{cwd_str}/tests/006_url_imports.ts");
- tests.extend(vec![
- ("tests/006_url_imports.ts", expected_url.to_string()),
- ("./tests/006_url_imports.ts", expected_url.to_string()),
- (
- "tests/../tests/006_url_imports.ts",
- expected_url.to_string(),
- ),
- ("tests/./006_url_imports.ts", expected_url),
- ]);
- }
-
- for (specifier, expected_url) in tests {
- let url = resolve_url_or_path(specifier, &cwd).unwrap().to_string();
- assert_eq!(url, expected_url);
- }
- }
-
- #[test]
- fn test_resolve_url_or_path_deprecated_error() {
- use url::ParseError::*;
- use ModuleResolutionError::*;
-
- let mut tests = vec![
- ("https://eggplant:b/c", InvalidUrl(InvalidPort)),
- ("https://:8080/a/b/c", InvalidUrl(EmptyHost)),
- ];
- if cfg!(target_os = "windows") {
- let p = r"\\.\c:/stuff/deno/script.ts";
- tests.push((p, InvalidPath(PathBuf::from(p))));
- }
-
- for (specifier, expected_err) in tests {
- let err =
- resolve_url_or_path(specifier, &PathBuf::from("/")).unwrap_err();
- assert_eq!(err, expected_err);
- }
- }
-
- #[test]
- fn test_specifier_has_uri_scheme() {
- let tests = vec![
- ("http://foo.bar/etc", true),
- ("HTTP://foo.bar/etc", true),
- ("http:ftp:", true),
- ("http:", true),
- ("hTtP:", true),
- ("ftp:", true),
- ("mailto:spam@please.me", true),
- ("git+ssh://git@github.com/denoland/deno", true),
- ("blob:https://whatwg.org/mumbojumbo", true),
- ("abc.123+DEF-ghi:", true),
- ("abc.123+def-ghi:@", true),
- ("", false),
- (":not", false),
- ("http", false),
- ("c:dir", false),
- ("X:", false),
- ("./http://not", false),
- ("1abc://kinda/but/no", false),
- ("schluẞ://no/more", false),
- ];
-
- for (specifier, expected) in tests {
- let result = specifier_has_uri_scheme(specifier);
- assert_eq!(result, expected);
- }
- }
-
- #[test]
- fn test_normalize_path() {
- assert_eq!(normalize_path(Path::new("a/../b")), PathBuf::from("b"));
- assert_eq!(normalize_path(Path::new("a/./b/")), PathBuf::from("a/b/"));
- assert_eq!(
- normalize_path(Path::new("a/./b/../c")),
- PathBuf::from("a/c")
- );
-
- if cfg!(windows) {
- assert_eq!(
- normalize_path(Path::new("C:\\a\\.\\b\\..\\c")),
- PathBuf::from("C:\\a\\c")
- );
- }
- }
-
- #[test]
- fn test_deserialize_module_specifier() {
- let actual: ModuleSpecifier =
- from_value(json!("http://deno.land/x/mod.ts")).unwrap();
- let expected = resolve_url("http://deno.land/x/mod.ts").unwrap();
- assert_eq!(actual, expected);
- }
-}
diff --git a/core/modules/loaders.rs b/core/modules/loaders.rs
deleted file mode 100644
index bc645567e..000000000
--- a/core/modules/loaders.rs
+++ /dev/null
@@ -1,253 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-use crate::error::generic_error;
-use crate::error::AnyError;
-use crate::extensions::ExtensionFileSource;
-use crate::module_specifier::ModuleSpecifier;
-use crate::modules::ModuleCode;
-use crate::modules::ModuleSource;
-use crate::modules::ModuleSourceFuture;
-use crate::modules::ModuleType;
-use crate::modules::ResolutionKind;
-use crate::resolve_import;
-use crate::Extension;
-use anyhow::anyhow;
-use anyhow::Error;
-use futures::future::FutureExt;
-use std::cell::RefCell;
-use std::collections::HashMap;
-use std::collections::HashSet;
-use std::future::Future;
-use std::pin::Pin;
-use std::rc::Rc;
-
-pub trait ModuleLoader {
- /// Returns an absolute URL.
- /// When implementing an spec-complaint VM, this should be exactly the
- /// algorithm described here:
- /// <https://html.spec.whatwg.org/multipage/webappapis.html#resolve-a-module-specifier>
- ///
- /// `is_main` can be used to resolve from current working directory or
- /// apply import map for child imports.
- ///
- /// `is_dyn_import` can be used to check permissions or deny
- /// dynamic imports altogether.
- fn resolve(
- &self,
- specifier: &str,
- referrer: &str,
- kind: ResolutionKind,
- ) -> Result<ModuleSpecifier, Error>;
-
- /// Given ModuleSpecifier, load its source code.
- ///
- /// `is_dyn_import` can be used to check permissions or deny
- /// dynamic imports altogether.
- fn load(
- &self,
- module_specifier: &ModuleSpecifier,
- maybe_referrer: Option<&ModuleSpecifier>,
- is_dyn_import: bool,
- ) -> Pin<Box<ModuleSourceFuture>>;
-
- /// This hook can be used by implementors to do some preparation
- /// work before starting loading of modules.
- ///
- /// For example implementor might download multiple modules in
- /// parallel and transpile them to final JS sources before
- /// yielding control back to the runtime.
- ///
- /// It's not required to implement this method.
- fn prepare_load(
- &self,
- _module_specifier: &ModuleSpecifier,
- _maybe_referrer: Option<String>,
- _is_dyn_import: bool,
- ) -> Pin<Box<dyn Future<Output = Result<(), Error>>>> {
- async { Ok(()) }.boxed_local()
- }
-}
-
-/// Placeholder structure used when creating
-/// a runtime that doesn't support module loading.
-pub struct NoopModuleLoader;
-
-impl ModuleLoader for NoopModuleLoader {
- fn resolve(
- &self,
- specifier: &str,
- referrer: &str,
- _kind: ResolutionKind,
- ) -> Result<ModuleSpecifier, Error> {
- Err(generic_error(
- format!("Module loading is not supported; attempted to resolve: \"{specifier}\" from \"{referrer}\"")
- ))
- }
-
- fn load(
- &self,
- module_specifier: &ModuleSpecifier,
- maybe_referrer: Option<&ModuleSpecifier>,
- _is_dyn_import: bool,
- ) -> Pin<Box<ModuleSourceFuture>> {
- let err = generic_error(
- format!(
- "Module loading is not supported; attempted to load: \"{module_specifier}\" from \"{maybe_referrer:?}\"",
- )
- );
- async move { Err(err) }.boxed_local()
- }
-}
-
-/// Function that can be passed to the `ExtModuleLoader` that allows to
-/// transpile sources before passing to V8.
-pub type ExtModuleLoaderCb =
- Box<dyn Fn(&ExtensionFileSource) -> Result<ModuleCode, Error>>;
-
-pub(crate) struct ExtModuleLoader {
- maybe_load_callback: Option<Rc<ExtModuleLoaderCb>>,
- sources: RefCell<HashMap<String, ExtensionFileSource>>,
- used_specifiers: RefCell<HashSet<String>>,
-}
-
-impl ExtModuleLoader {
- pub fn new(
- extensions: &[Extension],
- maybe_load_callback: Option<Rc<ExtModuleLoaderCb>>,
- ) -> Self {
- let mut sources = HashMap::new();
- sources.extend(
- extensions
- .iter()
- .flat_map(|e| e.get_esm_sources())
- .map(|s| (s.specifier.to_string(), s.clone())),
- );
- ExtModuleLoader {
- maybe_load_callback,
- sources: RefCell::new(sources),
- used_specifiers: Default::default(),
- }
- }
-}
-
-impl ModuleLoader for ExtModuleLoader {
- fn resolve(
- &self,
- specifier: &str,
- referrer: &str,
- _kind: ResolutionKind,
- ) -> Result<ModuleSpecifier, Error> {
- Ok(resolve_import(specifier, referrer)?)
- }
-
- fn load(
- &self,
- specifier: &ModuleSpecifier,
- _maybe_referrer: Option<&ModuleSpecifier>,
- _is_dyn_import: bool,
- ) -> Pin<Box<ModuleSourceFuture>> {
- let sources = self.sources.borrow();
- let source = match sources.get(specifier.as_str()) {
- Some(source) => source,
- None => return futures::future::err(anyhow!("Specifier \"{}\" was not passed as an extension module and was not included in the snapshot.", specifier)).boxed_local(),
- };
- self
- .used_specifiers
- .borrow_mut()
- .insert(specifier.to_string());
- let result = if let Some(load_callback) = &self.maybe_load_callback {
- load_callback(source)
- } else {
- source.load()
- };
- match result {
- Ok(code) => {
- let res = ModuleSource::new(ModuleType::JavaScript, code, specifier);
- return futures::future::ok(res).boxed_local();
- }
- Err(err) => return futures::future::err(err).boxed_local(),
- }
- }
-
- fn prepare_load(
- &self,
- _specifier: &ModuleSpecifier,
- _maybe_referrer: Option<String>,
- _is_dyn_import: bool,
- ) -> Pin<Box<dyn Future<Output = Result<(), Error>>>> {
- async { Ok(()) }.boxed_local()
- }
-}
-
-impl Drop for ExtModuleLoader {
- fn drop(&mut self) {
- let sources = self.sources.get_mut();
- let used_specifiers = self.used_specifiers.get_mut();
- let unused_modules: Vec<_> = sources
- .iter()
- .filter(|(k, _)| !used_specifiers.contains(k.as_str()))
- .collect();
-
- if !unused_modules.is_empty() {
- let mut msg =
- "Following modules were passed to ExtModuleLoader but never used:\n"
- .to_string();
- for m in unused_modules {
- msg.push_str(" - ");
- msg.push_str(m.0);
- msg.push('\n');
- }
- panic!("{}", msg);
- }
- }
-}
-
-/// Basic file system module loader.
-///
-/// Note that this loader will **block** event loop
-/// when loading file as it uses synchronous FS API
-/// from standard library.
-pub struct FsModuleLoader;
-
-impl ModuleLoader for FsModuleLoader {
- fn resolve(
- &self,
- specifier: &str,
- referrer: &str,
- _kind: ResolutionKind,
- ) -> Result<ModuleSpecifier, Error> {
- Ok(resolve_import(specifier, referrer)?)
- }
-
- fn load(
- &self,
- module_specifier: &ModuleSpecifier,
- _maybe_referrer: Option<&ModuleSpecifier>,
- _is_dynamic: bool,
- ) -> Pin<Box<ModuleSourceFuture>> {
- fn load(
- module_specifier: &ModuleSpecifier,
- ) -> Result<ModuleSource, AnyError> {
- let path = module_specifier.to_file_path().map_err(|_| {
- generic_error(format!(
- "Provided module specifier \"{module_specifier}\" is not a file URL."
- ))
- })?;
- let module_type = if let Some(extension) = path.extension() {
- let ext = extension.to_string_lossy().to_lowercase();
- if ext == "json" {
- ModuleType::Json
- } else {
- ModuleType::JavaScript
- }
- } else {
- ModuleType::JavaScript
- };
-
- let code = std::fs::read_to_string(path)?.into();
- let module = ModuleSource::new(module_type, code, module_specifier);
- Ok(module)
- }
-
- futures::future::ready(load(module_specifier)).boxed_local()
- }
-}
diff --git a/core/modules/map.rs b/core/modules/map.rs
deleted file mode 100644
index 786772e5b..000000000
--- a/core/modules/map.rs
+++ /dev/null
@@ -1,1014 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-use crate::error::exception_to_err_result;
-use crate::error::generic_error;
-use crate::error::throw_type_error;
-use crate::fast_string::FastString;
-use crate::modules::get_asserted_module_type_from_assertions;
-use crate::modules::parse_import_assertions;
-use crate::modules::validate_import_assertions;
-use crate::modules::ImportAssertionsKind;
-use crate::modules::ModuleCode;
-use crate::modules::ModuleError;
-use crate::modules::ModuleId;
-use crate::modules::ModuleInfo;
-use crate::modules::ModuleLoadId;
-use crate::modules::ModuleLoader;
-use crate::modules::ModuleName;
-use crate::modules::ModuleRequest;
-use crate::modules::ModuleType;
-use crate::modules::NoopModuleLoader;
-use crate::modules::PrepareLoadFuture;
-use crate::modules::RecursiveModuleLoad;
-use crate::modules::ResolutionKind;
-use crate::runtime::JsRuntime;
-use crate::runtime::SnapshottedData;
-use anyhow::Error;
-use futures::future::FutureExt;
-use futures::stream::FuturesUnordered;
-use futures::stream::StreamFuture;
-use std::cell::RefCell;
-use std::collections::HashMap;
-use std::pin::Pin;
-use std::rc::Rc;
-
-use super::AssertedModuleType;
-
-pub const BOM_CHAR: &[u8] = &[0xef, 0xbb, 0xbf];
-
-/// Strips the byte order mark from the provided text if it exists.
-fn strip_bom(source_code: &[u8]) -> &[u8] {
- if source_code.starts_with(BOM_CHAR) {
- &source_code[BOM_CHAR.len()..]
- } else {
- source_code
- }
-}
-
-/// A symbolic module entity.
-#[derive(Debug, PartialEq)]
-pub(crate) enum SymbolicModule {
- /// This module is an alias to another module.
- /// This is useful such that multiple names could point to
- /// the same underlying module (particularly due to redirects).
- Alias(ModuleName),
- /// This module associates with a V8 module by id.
- Mod(ModuleId),
-}
-
-/// A collection of JS modules.
-pub(crate) struct ModuleMap {
- // Handling of specifiers and v8 objects
- pub handles: Vec<v8::Global<v8::Module>>,
- pub info: Vec<ModuleInfo>,
- pub(crate) by_name_js: HashMap<ModuleName, SymbolicModule>,
- pub(crate) by_name_json: HashMap<ModuleName, SymbolicModule>,
- pub(crate) next_load_id: ModuleLoadId,
-
- // Handling of futures for loading module sources
- pub loader: Rc<dyn ModuleLoader>,
- pub(crate) dynamic_import_map:
- HashMap<ModuleLoadId, v8::Global<v8::PromiseResolver>>,
- pub(crate) preparing_dynamic_imports:
- FuturesUnordered<Pin<Box<PrepareLoadFuture>>>,
- pub(crate) pending_dynamic_imports:
- FuturesUnordered<StreamFuture<RecursiveModuleLoad>>,
-
- // This store is used temporarily, to forward parsed JSON
- // value from `new_json_module` to `json_module_evaluation_steps`
- json_value_store: HashMap<v8::Global<v8::Module>, v8::Global<v8::Value>>,
-}
-
-impl ModuleMap {
- pub fn collect_modules(
- &self,
- ) -> Vec<(AssertedModuleType, &ModuleName, &SymbolicModule)> {
- let mut output = vec![];
- for module_type in [
- AssertedModuleType::JavaScriptOrWasm,
- AssertedModuleType::Json,
- ] {
- output.extend(
- self
- .by_name(module_type)
- .iter()
- .map(|x| (module_type, x.0, x.1)),
- )
- }
- output
- }
-
- #[cfg(debug_assertions)]
- pub(crate) fn assert_all_modules_evaluated(
- &self,
- scope: &mut v8::HandleScope,
- ) {
- let mut not_evaluated = vec![];
-
- for (i, handle) in self.handles.iter().enumerate() {
- let module = v8::Local::new(scope, handle);
- if !matches!(module.get_status(), v8::ModuleStatus::Evaluated) {
- not_evaluated.push(self.info[i].name.as_str().to_string());
- }
- }
-
- if !not_evaluated.is_empty() {
- let mut msg = "Following modules were not evaluated; make sure they are imported from other code:\n".to_string();
- for m in not_evaluated {
- msg.push_str(&format!(" - {}\n", m));
- }
- panic!("{}", msg);
- }
- }
-
- pub fn serialize_for_snapshotting(
- &self,
- scope: &mut v8::HandleScope,
- ) -> SnapshottedData {
- let array = v8::Array::new(scope, 3);
-
- let next_load_id = v8::Integer::new(scope, self.next_load_id);
- array.set_index(scope, 0, next_load_id.into());
-
- let info_arr = v8::Array::new(scope, self.info.len() as i32);
- for (i, info) in self.info.iter().enumerate() {
- let module_info_arr = v8::Array::new(scope, 5);
-
- let id = v8::Integer::new(scope, info.id as i32);
- module_info_arr.set_index(scope, 0, id.into());
-
- let main = v8::Boolean::new(scope, info.main);
- module_info_arr.set_index(scope, 1, main.into());
-
- let name = info.name.v8(scope);
- module_info_arr.set_index(scope, 2, name.into());
-
- let array_len = 2 * info.requests.len() as i32;
- let requests_arr = v8::Array::new(scope, array_len);
- for (i, request) in info.requests.iter().enumerate() {
- let specifier = v8::String::new_from_one_byte(
- scope,
- request.specifier.as_bytes(),
- v8::NewStringType::Normal,
- )
- .unwrap();
- requests_arr.set_index(scope, 2 * i as u32, specifier.into());
-
- let asserted_module_type =
- v8::Integer::new(scope, request.asserted_module_type as i32);
- requests_arr.set_index(
- scope,
- (2 * i) as u32 + 1,
- asserted_module_type.into(),
- );
- }
- module_info_arr.set_index(scope, 3, requests_arr.into());
-
- let module_type = v8::Integer::new(scope, info.module_type as i32);
- module_info_arr.set_index(scope, 4, module_type.into());
-
- info_arr.set_index(scope, i as u32, module_info_arr.into());
- }
- array.set_index(scope, 1, info_arr.into());
-
- let by_name = self.collect_modules();
- let by_name_array = v8::Array::new(scope, by_name.len() as i32);
- {
- for (i, (module_type, name, module)) in by_name.into_iter().enumerate() {
- let arr = v8::Array::new(scope, 3);
-
- let specifier = name.v8(scope);
- arr.set_index(scope, 0, specifier.into());
-
- let asserted_module_type = v8::Integer::new(scope, module_type as i32);
- arr.set_index(scope, 1, asserted_module_type.into());
-
- let symbolic_module: v8::Local<v8::Value> = match module {
- SymbolicModule::Alias(alias) => {
- let alias = v8::String::new_from_one_byte(
- scope,
- alias.as_bytes(),
- v8::NewStringType::Normal,
- )
- .unwrap();
- alias.into()
- }
- SymbolicModule::Mod(id) => {
- let id = v8::Integer::new(scope, *id as i32);
- id.into()
- }
- };
- arr.set_index(scope, 2, symbolic_module);
-
- by_name_array.set_index(scope, i as u32, arr.into());
- }
- }
- array.set_index(scope, 2, by_name_array.into());
-
- let array_global = v8::Global::new(scope, array);
-
- let handles = self.handles.clone();
- SnapshottedData {
- module_map_data: array_global,
- module_handles: handles,
- }
- }
-
- pub fn update_with_snapshotted_data(
- &mut self,
- scope: &mut v8::HandleScope,
- snapshotted_data: SnapshottedData,
- ) {
- let local_data: v8::Local<v8::Array> =
- v8::Local::new(scope, snapshotted_data.module_map_data);
-
- {
- let next_load_id = local_data.get_index(scope, 0).unwrap();
- assert!(next_load_id.is_int32());
- let integer = next_load_id.to_integer(scope).unwrap();
- let val = integer.int32_value(scope).unwrap();
- self.next_load_id = val;
- }
-
- {
- let info_val = local_data.get_index(scope, 1).unwrap();
-
- let info_arr: v8::Local<v8::Array> = info_val.try_into().unwrap();
- let len = info_arr.length() as usize;
- // Over allocate so executing a few scripts doesn't have to resize this vec.
- let mut info = Vec::with_capacity(len + 16);
-
- for i in 0..len {
- let module_info_arr: v8::Local<v8::Array> = info_arr
- .get_index(scope, i as u32)
- .unwrap()
- .try_into()
- .unwrap();
- let id = module_info_arr
- .get_index(scope, 0)
- .unwrap()
- .to_integer(scope)
- .unwrap()
- .value() as ModuleId;
-
- let main = module_info_arr
- .get_index(scope, 1)
- .unwrap()
- .to_boolean(scope)
- .is_true();
-
- let name = module_info_arr
- .get_index(scope, 2)
- .unwrap()
- .to_rust_string_lossy(scope)
- .into();
-
- let requests_arr: v8::Local<v8::Array> = module_info_arr
- .get_index(scope, 3)
- .unwrap()
- .try_into()
- .unwrap();
- let len = (requests_arr.length() as usize) / 2;
- let mut requests = Vec::with_capacity(len);
- for i in 0..len {
- let specifier = requests_arr
- .get_index(scope, (2 * i) as u32)
- .unwrap()
- .to_rust_string_lossy(scope);
- let asserted_module_type_no = requests_arr
- .get_index(scope, (2 * i + 1) as u32)
- .unwrap()
- .to_integer(scope)
- .unwrap()
- .value();
- let asserted_module_type = match asserted_module_type_no {
- 0 => AssertedModuleType::JavaScriptOrWasm,
- 1 => AssertedModuleType::Json,
- _ => unreachable!(),
- };
- requests.push(ModuleRequest {
- specifier,
- asserted_module_type,
- });
- }
-
- let module_type_no = module_info_arr
- .get_index(scope, 4)
- .unwrap()
- .to_integer(scope)
- .unwrap()
- .value();
- let module_type = match module_type_no {
- 0 => ModuleType::JavaScript,
- 1 => ModuleType::Json,
- _ => unreachable!(),
- };
-
- let module_info = ModuleInfo {
- id,
- main,
- name,
- requests,
- module_type,
- };
- info.push(module_info);
- }
-
- self.info = info;
- }
-
- self
- .by_name_mut(AssertedModuleType::JavaScriptOrWasm)
- .clear();
- self.by_name_mut(AssertedModuleType::Json).clear();
-
- {
- let by_name_arr: v8::Local<v8::Array> =
- local_data.get_index(scope, 2).unwrap().try_into().unwrap();
- let len = by_name_arr.length() as usize;
-
- for i in 0..len {
- let arr: v8::Local<v8::Array> = by_name_arr
- .get_index(scope, i as u32)
- .unwrap()
- .try_into()
- .unwrap();
-
- let specifier =
- arr.get_index(scope, 0).unwrap().to_rust_string_lossy(scope);
- let asserted_module_type = match arr
- .get_index(scope, 1)
- .unwrap()
- .to_integer(scope)
- .unwrap()
- .value()
- {
- 0 => AssertedModuleType::JavaScriptOrWasm,
- 1 => AssertedModuleType::Json,
- _ => unreachable!(),
- };
-
- let symbolic_module_val = arr.get_index(scope, 2).unwrap();
- let val = if symbolic_module_val.is_number() {
- SymbolicModule::Mod(
- symbolic_module_val
- .to_integer(scope)
- .unwrap()
- .value()
- .try_into()
- .unwrap(),
- )
- } else {
- SymbolicModule::Alias(
- symbolic_module_val.to_rust_string_lossy(scope).into(),
- )
- };
-
- self
- .by_name_mut(asserted_module_type)
- .insert(specifier.into(), val);
- }
- }
-
- self.handles = snapshotted_data.module_handles;
- }
-
- pub(crate) fn new(loader: Rc<dyn ModuleLoader>) -> ModuleMap {
- Self {
- handles: vec![],
- info: vec![],
- by_name_js: HashMap::new(),
- by_name_json: HashMap::new(),
- next_load_id: 1,
- loader,
- dynamic_import_map: HashMap::new(),
- preparing_dynamic_imports: FuturesUnordered::new(),
- pending_dynamic_imports: FuturesUnordered::new(),
- json_value_store: HashMap::new(),
- }
- }
-
- /// Get module id, following all aliases in case of module specifier
- /// that had been redirected.
- pub(crate) fn get_id(
- &self,
- name: impl AsRef<str>,
- asserted_module_type: AssertedModuleType,
- ) -> Option<ModuleId> {
- let map = self.by_name(asserted_module_type);
- let first_symbolic_module = map.get(name.as_ref())?;
- let mut mod_name = match first_symbolic_module {
- SymbolicModule::Mod(mod_id) => return Some(*mod_id),
- SymbolicModule::Alias(target) => target,
- };
- loop {
- let symbolic_module = map.get(mod_name.as_ref())?;
- match symbolic_module {
- SymbolicModule::Alias(target) => {
- debug_assert!(mod_name != target);
- mod_name = target;
- }
- SymbolicModule::Mod(mod_id) => return Some(*mod_id),
- }
- }
- }
-
- pub(crate) fn new_json_module(
- &mut self,
- scope: &mut v8::HandleScope,
- name: ModuleName,
- source: ModuleCode,
- ) -> Result<ModuleId, ModuleError> {
- let name_str = name.v8(scope);
- let source_str = v8::String::new_from_utf8(
- scope,
- strip_bom(source.as_bytes()),
- v8::NewStringType::Normal,
- )
- .unwrap();
-
- let tc_scope = &mut v8::TryCatch::new(scope);
-
- let parsed_json = match v8::json::parse(tc_scope, source_str) {
- Some(parsed_json) => parsed_json,
- None => {
- assert!(tc_scope.has_caught());
- let exception = tc_scope.exception().unwrap();
- let exception = v8::Global::new(tc_scope, exception);
- return Err(ModuleError::Exception(exception));
- }
- };
-
- let export_names = [v8::String::new(tc_scope, "default").unwrap()];
- let module = v8::Module::create_synthetic_module(
- tc_scope,
- name_str,
- &export_names,
- json_module_evaluation_steps,
- );
-
- let handle = v8::Global::<v8::Module>::new(tc_scope, module);
- let value_handle = v8::Global::<v8::Value>::new(tc_scope, parsed_json);
- self.json_value_store.insert(handle.clone(), value_handle);
-
- let id =
- self.create_module_info(name, ModuleType::Json, handle, false, vec![]);
-
- Ok(id)
- }
-
- /// Create and compile an ES module.
- pub(crate) fn new_es_module(
- &mut self,
- scope: &mut v8::HandleScope,
- main: bool,
- name: ModuleName,
- source: ModuleCode,
- is_dynamic_import: bool,
- ) -> Result<ModuleId, ModuleError> {
- let name_str = name.v8(scope);
- let source_str = source.v8(scope);
-
- let origin = module_origin(scope, name_str);
- let source = v8::script_compiler::Source::new(source_str, Some(&origin));
-
- let tc_scope = &mut v8::TryCatch::new(scope);
-
- let maybe_module = v8::script_compiler::compile_module(tc_scope, source);
-
- if tc_scope.has_caught() {
- assert!(maybe_module.is_none());
- let exception = tc_scope.exception().unwrap();
- let exception = v8::Global::new(tc_scope, exception);
- return Err(ModuleError::Exception(exception));
- }
-
- let module = maybe_module.unwrap();
-
- let mut requests: Vec<ModuleRequest> = vec![];
- let module_requests = module.get_module_requests();
- for i in 0..module_requests.length() {
- let module_request = v8::Local::<v8::ModuleRequest>::try_from(
- module_requests.get(tc_scope, i).unwrap(),
- )
- .unwrap();
- let import_specifier = module_request
- .get_specifier()
- .to_rust_string_lossy(tc_scope);
-
- let import_assertions = module_request.get_import_assertions();
-
- let assertions = parse_import_assertions(
- tc_scope,
- import_assertions,
- ImportAssertionsKind::StaticImport,
- );
-
- // FIXME(bartomieju): there are no stack frames if exception
- // is thrown here
- validate_import_assertions(tc_scope, &assertions);
- if tc_scope.has_caught() {
- let exception = tc_scope.exception().unwrap();
- let exception = v8::Global::new(tc_scope, exception);
- return Err(ModuleError::Exception(exception));
- }
-
- let module_specifier = match self.loader.resolve(
- &import_specifier,
- name.as_ref(),
- if is_dynamic_import {
- ResolutionKind::DynamicImport
- } else {
- ResolutionKind::Import
- },
- ) {
- Ok(s) => s,
- Err(e) => return Err(ModuleError::Other(e)),
- };
- let asserted_module_type =
- get_asserted_module_type_from_assertions(&assertions);
- let request = ModuleRequest {
- specifier: module_specifier.to_string(),
- asserted_module_type,
- };
- requests.push(request);
- }
-
- if main {
- let maybe_main_module = self.info.iter().find(|module| module.main);
- if let Some(main_module) = maybe_main_module {
- return Err(ModuleError::Other(generic_error(
- format!("Trying to create \"main\" module ({:?}), when one already exists ({:?})",
- name.as_ref(),
- main_module.name,
- ))));
- }
- }
-
- let handle = v8::Global::<v8::Module>::new(tc_scope, module);
- let id = self.create_module_info(
- name,
- ModuleType::JavaScript,
- handle,
- main,
- requests,
- );
-
- Ok(id)
- }
-
- pub(crate) fn instantiate_module(
- &mut self,
- scope: &mut v8::HandleScope,
- id: ModuleId,
- ) -> Result<(), v8::Global<v8::Value>> {
- let tc_scope = &mut v8::TryCatch::new(scope);
-
- let module = self
- .get_handle(id)
- .map(|handle| v8::Local::new(tc_scope, handle))
- .expect("ModuleInfo not found");
-
- if module.get_status() == v8::ModuleStatus::Errored {
- return Err(v8::Global::new(tc_scope, module.get_exception()));
- }
-
- tc_scope.set_slot(self as *const _);
- let instantiate_result =
- module.instantiate_module(tc_scope, Self::module_resolve_callback);
- tc_scope.remove_slot::<*const Self>();
- if instantiate_result.is_none() {
- let exception = tc_scope.exception().unwrap();
- return Err(v8::Global::new(tc_scope, exception));
- }
-
- Ok(())
- }
-
- /// Called by V8 during `JsRuntime::instantiate_module`. This is only used internally, so we use the Isolate's annex
- /// to propagate a &Self.
- fn module_resolve_callback<'s>(
- context: v8::Local<'s, v8::Context>,
- specifier: v8::Local<'s, v8::String>,
- import_assertions: v8::Local<'s, v8::FixedArray>,
- referrer: v8::Local<'s, v8::Module>,
- ) -> Option<v8::Local<'s, v8::Module>> {
- // SAFETY: `CallbackScope` can be safely constructed from `Local<Context>`
- let scope = &mut unsafe { v8::CallbackScope::new(context) };
-
- let module_map =
- // SAFETY: We retrieve the pointer from the slot, having just set it a few stack frames up
- unsafe { scope.get_slot::<*const Self>().unwrap().as_ref().unwrap() };
-
- let referrer_global = v8::Global::new(scope, referrer);
-
- let referrer_info = module_map
- .get_info(&referrer_global)
- .expect("ModuleInfo not found");
- let referrer_name = referrer_info.name.as_str();
-
- let specifier_str = specifier.to_rust_string_lossy(scope);
-
- let assertions = parse_import_assertions(
- scope,
- import_assertions,
- ImportAssertionsKind::StaticImport,
- );
- let maybe_module = module_map.resolve_callback(
- scope,
- &specifier_str,
- referrer_name,
- assertions,
- );
- if let Some(module) = maybe_module {
- return Some(module);
- }
-
- let msg = format!(
- r#"Cannot resolve module "{specifier_str}" from "{referrer_name}""#
- );
- throw_type_error(scope, msg);
- None
- }
-
- /// Called by `module_resolve_callback` during module instantiation.
- fn resolve_callback<'s>(
- &self,
- scope: &mut v8::HandleScope<'s>,
- specifier: &str,
- referrer: &str,
- import_assertions: HashMap<String, String>,
- ) -> Option<v8::Local<'s, v8::Module>> {
- let resolved_specifier = self
- .loader
- .resolve(specifier, referrer, ResolutionKind::Import)
- .expect("Module should have been already resolved");
-
- let module_type =
- get_asserted_module_type_from_assertions(&import_assertions);
-
- if let Some(id) = self.get_id(resolved_specifier.as_str(), module_type) {
- if let Some(handle) = self.get_handle(id) {
- return Some(v8::Local::new(scope, handle));
- }
- }
-
- None
- }
-
- pub(crate) fn clear(&mut self) {
- *self = Self::new(self.loader.clone())
- }
-
- pub(crate) fn get_handle_by_name(
- &self,
- name: impl AsRef<str>,
- ) -> Option<v8::Global<v8::Module>> {
- let id = self
- .get_id(name.as_ref(), AssertedModuleType::JavaScriptOrWasm)
- .or_else(|| self.get_id(name.as_ref(), AssertedModuleType::Json))?;
- self.get_handle(id)
- }
-
- pub(crate) fn inject_handle(
- &mut self,
- name: ModuleName,
- module_type: ModuleType,
- handle: v8::Global<v8::Module>,
- ) {
- self.create_module_info(name, module_type, handle, false, vec![]);
- }
-
- fn create_module_info(
- &mut self,
- name: FastString,
- module_type: ModuleType,
- handle: v8::Global<v8::Module>,
- main: bool,
- requests: Vec<ModuleRequest>,
- ) -> ModuleId {
- let id = self.handles.len();
- let (name1, name2) = name.into_cheap_copy();
- self
- .by_name_mut(module_type.into())
- .insert(name1, SymbolicModule::Mod(id));
- self.handles.push(handle);
- self.info.push(ModuleInfo {
- id,
- main,
- name: name2,
- requests,
- module_type,
- });
-
- id
- }
-
- pub(crate) fn get_requested_modules(
- &self,
- id: ModuleId,
- ) -> Option<&Vec<ModuleRequest>> {
- self.info.get(id).map(|i| &i.requests)
- }
-
- fn is_registered(
- &self,
- specifier: impl AsRef<str>,
- asserted_module_type: AssertedModuleType,
- ) -> bool {
- if let Some(id) = self.get_id(specifier.as_ref(), asserted_module_type) {
- let info = self.get_info_by_id(id).unwrap();
- return asserted_module_type == info.module_type.into();
- }
-
- false
- }
-
- pub(crate) fn by_name(
- &self,
- asserted_module_type: AssertedModuleType,
- ) -> &HashMap<ModuleName, SymbolicModule> {
- match asserted_module_type {
- AssertedModuleType::Json => &self.by_name_json,
- AssertedModuleType::JavaScriptOrWasm => &self.by_name_js,
- }
- }
-
- pub(crate) fn by_name_mut(
- &mut self,
- asserted_module_type: AssertedModuleType,
- ) -> &mut HashMap<ModuleName, SymbolicModule> {
- match asserted_module_type {
- AssertedModuleType::Json => &mut self.by_name_json,
- AssertedModuleType::JavaScriptOrWasm => &mut self.by_name_js,
- }
- }
-
- pub(crate) fn alias(
- &mut self,
- name: FastString,
- asserted_module_type: AssertedModuleType,
- target: FastString,
- ) {
- debug_assert_ne!(name, target);
- self
- .by_name_mut(asserted_module_type)
- .insert(name, SymbolicModule::Alias(target));
- }
-
- #[cfg(test)]
- pub(crate) fn is_alias(
- &self,
- name: &str,
- asserted_module_type: AssertedModuleType,
- ) -> bool {
- let cond = self.by_name(asserted_module_type).get(name);
- matches!(cond, Some(SymbolicModule::Alias(_)))
- }
-
- pub(crate) fn get_handle(
- &self,
- id: ModuleId,
- ) -> Option<v8::Global<v8::Module>> {
- self.handles.get(id).cloned()
- }
-
- pub(crate) fn get_info(
- &self,
- global: &v8::Global<v8::Module>,
- ) -> Option<&ModuleInfo> {
- if let Some(id) = self.handles.iter().position(|module| module == global) {
- return self.info.get(id);
- }
-
- None
- }
-
- pub(crate) fn get_info_by_id(&self, id: ModuleId) -> Option<&ModuleInfo> {
- self.info.get(id)
- }
-
- pub(crate) async fn load_main(
- module_map_rc: Rc<RefCell<ModuleMap>>,
- specifier: impl AsRef<str>,
- ) -> Result<RecursiveModuleLoad, Error> {
- let load =
- RecursiveModuleLoad::main(specifier.as_ref(), module_map_rc.clone());
- load.prepare().await?;
- Ok(load)
- }
-
- pub(crate) async fn load_side(
- module_map_rc: Rc<RefCell<ModuleMap>>,
- specifier: impl AsRef<str>,
- ) -> Result<RecursiveModuleLoad, Error> {
- let load =
- RecursiveModuleLoad::side(specifier.as_ref(), module_map_rc.clone());
- load.prepare().await?;
- Ok(load)
- }
-
- // Initiate loading of a module graph imported using `import()`.
- pub(crate) fn load_dynamic_import(
- module_map_rc: Rc<RefCell<ModuleMap>>,
- specifier: &str,
- referrer: &str,
- asserted_module_type: AssertedModuleType,
- resolver_handle: v8::Global<v8::PromiseResolver>,
- ) {
- let load = RecursiveModuleLoad::dynamic_import(
- specifier,
- referrer,
- asserted_module_type,
- module_map_rc.clone(),
- );
- module_map_rc
- .borrow_mut()
- .dynamic_import_map
- .insert(load.id, resolver_handle);
-
- let loader = module_map_rc.borrow().loader.clone();
- let resolve_result =
- loader.resolve(specifier, referrer, ResolutionKind::DynamicImport);
- let fut = match resolve_result {
- Ok(module_specifier) => {
- if module_map_rc
- .borrow()
- .is_registered(module_specifier, asserted_module_type)
- {
- async move { (load.id, Ok(load)) }.boxed_local()
- } else {
- async move { (load.id, load.prepare().await.map(|()| load)) }
- .boxed_local()
- }
- }
- Err(error) => async move { (load.id, Err(error)) }.boxed_local(),
- };
- module_map_rc
- .borrow_mut()
- .preparing_dynamic_imports
- .push(fut);
- }
-
- pub(crate) fn has_pending_dynamic_imports(&self) -> bool {
- !(self.preparing_dynamic_imports.is_empty()
- && self.pending_dynamic_imports.is_empty())
- }
-
- /// Returns the namespace object of a module.
- ///
- /// This is only available after module evaluation has completed.
- /// This function panics if module has not been instantiated.
- pub fn get_module_namespace(
- &self,
- scope: &mut v8::HandleScope,
- module_id: ModuleId,
- ) -> Result<v8::Global<v8::Object>, Error> {
- let module_handle =
- self.get_handle(module_id).expect("ModuleInfo not found");
-
- let module = module_handle.open(scope);
-
- if module.get_status() == v8::ModuleStatus::Errored {
- let exception = module.get_exception();
- return exception_to_err_result(scope, exception, false);
- }
-
- assert!(matches!(
- module.get_status(),
- v8::ModuleStatus::Instantiated | v8::ModuleStatus::Evaluated
- ));
-
- let module_namespace: v8::Local<v8::Object> =
- v8::Local::try_from(module.get_module_namespace())
- .map_err(|err: v8::DataError| generic_error(err.to_string()))?;
-
- Ok(v8::Global::new(scope, module_namespace))
- }
-
- /// Clear the module map, meant to be used after initializing extensions.
- /// Optionally pass a list of exceptions `(old_name, new_name)` representing
- /// specifiers which will be renamed and preserved in the module map.
- pub fn clear_module_map(
- &mut self,
- exceptions: impl Iterator<Item = (&'static str, &'static str)>,
- ) {
- let handles = exceptions
- .map(|(old_name, new_name)| {
- (self.get_handle_by_name(old_name).unwrap(), new_name)
- })
- .collect::<Vec<_>>();
- self.clear();
- for (handle, new_name) in handles {
- self.inject_handle(
- ModuleName::from_static(new_name),
- ModuleType::JavaScript,
- handle,
- )
- }
- }
-
- fn get_stalled_top_level_await_message_for_module(
- &self,
- scope: &mut v8::HandleScope,
- module_id: ModuleId,
- ) -> Vec<v8::Global<v8::Message>> {
- let module_handle = self.handles.get(module_id).unwrap();
-
- let module = v8::Local::new(scope, module_handle);
- let stalled = module.get_stalled_top_level_await_message(scope);
- let mut messages = vec![];
- for (_, message) in stalled {
- messages.push(v8::Global::new(scope, message));
- }
- messages
- }
-
- pub(crate) fn find_stalled_top_level_await(
- &self,
- scope: &mut v8::HandleScope,
- ) -> Vec<v8::Global<v8::Message>> {
- // First check if that's root module
- let root_module_id =
- self.info.iter().filter(|m| m.main).map(|m| m.id).next();
-
- if let Some(root_module_id) = root_module_id {
- let messages = self
- .get_stalled_top_level_await_message_for_module(scope, root_module_id);
- if !messages.is_empty() {
- return messages;
- }
- }
-
- // It wasn't a top module, so iterate over all modules and try to find
- // any with stalled top level await
- for module_id in 0..self.handles.len() {
- let messages =
- self.get_stalled_top_level_await_message_for_module(scope, module_id);
- if !messages.is_empty() {
- return messages;
- }
- }
-
- unreachable!()
- }
-}
-
-impl Default for ModuleMap {
- fn default() -> Self {
- Self::new(Rc::new(NoopModuleLoader))
- }
-}
-
-// Clippy thinks the return value doesn't need to be an Option, it's unaware
-// of the mapping that MapFnFrom<F> does for ResolveModuleCallback.
-#[allow(clippy::unnecessary_wraps)]
-fn json_module_evaluation_steps<'a>(
- context: v8::Local<'a, v8::Context>,
- module: v8::Local<v8::Module>,
-) -> Option<v8::Local<'a, v8::Value>> {
- // SAFETY: `CallbackScope` can be safely constructed from `Local<Context>`
- let scope = &mut unsafe { v8::CallbackScope::new(context) };
- let tc_scope = &mut v8::TryCatch::new(scope);
- let module_map = JsRuntime::module_map_from(tc_scope);
-
- let handle = v8::Global::<v8::Module>::new(tc_scope, module);
- let value_handle = module_map
- .borrow_mut()
- .json_value_store
- .remove(&handle)
- .unwrap();
- let value_local = v8::Local::new(tc_scope, value_handle);
-
- let name = v8::String::new(tc_scope, "default").unwrap();
- // This should never fail
- assert!(
- module.set_synthetic_module_export(tc_scope, name, value_local)
- == Some(true)
- );
- assert!(!tc_scope.has_caught());
-
- // Since TLA is active we need to return a promise.
- let resolver = v8::PromiseResolver::new(tc_scope).unwrap();
- let undefined = v8::undefined(tc_scope);
- resolver.resolve(tc_scope, undefined.into());
- Some(resolver.get_promise(tc_scope).into())
-}
-
-pub fn module_origin<'a>(
- s: &mut v8::HandleScope<'a>,
- resource_name: v8::Local<'a, v8::String>,
-) -> v8::ScriptOrigin<'a> {
- let source_map_url = v8::String::empty(s);
- v8::ScriptOrigin::new(
- s,
- resource_name.into(),
- 0,
- 0,
- false,
- 123,
- source_map_url.into(),
- true,
- false,
- true,
- )
-}
diff --git a/core/modules/mod.rs b/core/modules/mod.rs
deleted file mode 100644
index 83f10bc72..000000000
--- a/core/modules/mod.rs
+++ /dev/null
@@ -1,689 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-use crate::error::generic_error;
-use crate::fast_string::FastString;
-use crate::module_specifier::ModuleSpecifier;
-use crate::resolve_url;
-use anyhow::Error;
-use futures::future::FutureExt;
-use futures::stream::FuturesUnordered;
-use futures::stream::Stream;
-use futures::stream::TryStreamExt;
-use log::debug;
-use serde::Deserialize;
-use serde::Serialize;
-use std::cell::RefCell;
-use std::collections::HashMap;
-use std::collections::HashSet;
-use std::collections::VecDeque;
-use std::future::Future;
-use std::pin::Pin;
-use std::rc::Rc;
-use std::task::Context;
-use std::task::Poll;
-
-mod loaders;
-mod map;
-
-#[cfg(test)]
-mod tests;
-
-pub(crate) use loaders::ExtModuleLoader;
-pub use loaders::ExtModuleLoaderCb;
-pub use loaders::FsModuleLoader;
-pub use loaders::ModuleLoader;
-pub use loaders::NoopModuleLoader;
-pub(crate) use map::ModuleMap;
-#[cfg(test)]
-pub(crate) use map::SymbolicModule;
-
-pub type ModuleId = usize;
-pub(crate) type ModuleLoadId = i32;
-pub type ModuleCode = FastString;
-pub type ModuleName = FastString;
-
-const SUPPORTED_TYPE_ASSERTIONS: &[&str] = &["json"];
-
-/// Throws V8 exception if assertions are invalid
-pub(crate) fn validate_import_assertions(
- scope: &mut v8::HandleScope,
- assertions: &HashMap<String, String>,
-) {
- for (key, value) in assertions {
- if key == "type" && !SUPPORTED_TYPE_ASSERTIONS.contains(&value.as_str()) {
- let message = v8::String::new(
- scope,
- &format!("\"{value}\" is not a valid module type."),
- )
- .unwrap();
- let exception = v8::Exception::type_error(scope, message);
- scope.throw_exception(exception);
- return;
- }
- }
-}
-
-#[derive(Debug)]
-pub(crate) enum ImportAssertionsKind {
- StaticImport,
- DynamicImport,
-}
-
-pub(crate) fn parse_import_assertions(
- scope: &mut v8::HandleScope,
- import_assertions: v8::Local<v8::FixedArray>,
- kind: ImportAssertionsKind,
-) -> HashMap<String, String> {
- let mut assertions: HashMap<String, String> = HashMap::default();
-
- let assertions_per_line = match kind {
- // For static imports, assertions are triples of (keyword, value and source offset)
- // Also used in `module_resolve_callback`.
- ImportAssertionsKind::StaticImport => 3,
- // For dynamic imports, assertions are tuples of (keyword, value)
- ImportAssertionsKind::DynamicImport => 2,
- };
- assert_eq!(import_assertions.length() % assertions_per_line, 0);
- let no_of_assertions = import_assertions.length() / assertions_per_line;
-
- for i in 0..no_of_assertions {
- let assert_key = import_assertions
- .get(scope, assertions_per_line * i)
- .unwrap();
- let assert_key_val = v8::Local::<v8::Value>::try_from(assert_key).unwrap();
- let assert_value = import_assertions
- .get(scope, (assertions_per_line * i) + 1)
- .unwrap();
- let assert_value_val =
- v8::Local::<v8::Value>::try_from(assert_value).unwrap();
- assertions.insert(
- assert_key_val.to_rust_string_lossy(scope),
- assert_value_val.to_rust_string_lossy(scope),
- );
- }
-
- assertions
-}
-
-pub(crate) fn get_asserted_module_type_from_assertions(
- assertions: &HashMap<String, String>,
-) -> AssertedModuleType {
- assertions
- .get("type")
- .map(|ty| {
- if ty == "json" {
- AssertedModuleType::Json
- } else {
- AssertedModuleType::JavaScriptOrWasm
- }
- })
- .unwrap_or(AssertedModuleType::JavaScriptOrWasm)
-}
-
-/// A type of module to be executed.
-///
-/// For non-`JavaScript` modules, this value doesn't tell
-/// how to interpret the module; it is only used to validate
-/// the module against an import assertion (if one is present
-/// in the import statement).
-#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
-#[repr(u32)]
-pub enum ModuleType {
- JavaScript,
- Json,
-}
-
-impl std::fmt::Display for ModuleType {
- fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
- match self {
- Self::JavaScript => write!(f, "JavaScript"),
- Self::Json => write!(f, "JSON"),
- }
- }
-}
-
-/// EsModule source code that will be loaded into V8.
-///
-/// Users can implement `Into<ModuleInfo>` for different file types that
-/// can be transpiled to valid EsModule.
-///
-/// Found module URL might be different from specified URL
-/// used for loading due to redirections (like HTTP 303).
-/// Eg. Both "`https://example.com/a.ts`" and
-/// "`https://example.com/b.ts`" may point to "`https://example.com/c.ts`"
-/// By keeping track of specified and found URL we can alias modules and avoid
-/// recompiling the same code 3 times.
-// TODO(bartlomieju): I have a strong opinion we should store all redirects
-// that happened; not only first and final target. It would simplify a lot
-// of things throughout the codebase otherwise we may end up requesting
-// intermediate redirects from file loader.
-// NOTE: This should _not_ be made #[derive(Clone)] unless we take some precautions to avoid excessive string copying.
-#[derive(Debug)]
-pub struct ModuleSource {
- pub code: ModuleCode,
- pub module_type: ModuleType,
- module_url_specified: ModuleName,
- /// If the module was found somewhere other than the specified address, this will be [`Some`].
- module_url_found: Option<ModuleName>,
-}
-
-impl ModuleSource {
- /// Create a [`ModuleSource`] without a redirect.
- pub fn new(
- module_type: impl Into<ModuleType>,
- code: ModuleCode,
- specifier: &ModuleSpecifier,
- ) -> Self {
- let module_url_specified = specifier.as_ref().to_owned().into();
- Self {
- code,
- module_type: module_type.into(),
- module_url_specified,
- module_url_found: None,
- }
- }
-
- /// Create a [`ModuleSource`] with a potential redirect. If the `specifier_found` parameter is the same as the
- /// specifier, the code behaves the same was as `ModuleSource::new`.
- pub fn new_with_redirect(
- module_type: impl Into<ModuleType>,
- code: ModuleCode,
- specifier: &ModuleSpecifier,
- specifier_found: &ModuleSpecifier,
- ) -> Self {
- let module_url_found = if specifier == specifier_found {
- None
- } else {
- Some(specifier_found.as_ref().to_owned().into())
- };
- let module_url_specified = specifier.as_ref().to_owned().into();
- Self {
- code,
- module_type: module_type.into(),
- module_url_specified,
- module_url_found,
- }
- }
-
- #[cfg(test)]
- pub fn for_test(code: &'static str, file: impl AsRef<str>) -> Self {
- Self {
- code: ModuleCode::from_static(code),
- module_type: ModuleType::JavaScript,
- module_url_specified: file.as_ref().to_owned().into(),
- module_url_found: None,
- }
- }
-
- /// If the `found` parameter is the same as the `specified` parameter, the code behaves the same was as `ModuleSource::for_test`.
- #[cfg(test)]
- pub fn for_test_with_redirect(
- code: &'static str,
- specified: impl AsRef<str>,
- found: impl AsRef<str>,
- ) -> Self {
- let specified = specified.as_ref().to_string();
- let found = found.as_ref().to_string();
- let found = if found == specified {
- None
- } else {
- Some(found.into())
- };
- Self {
- code: ModuleCode::from_static(code),
- module_type: ModuleType::JavaScript,
- module_url_specified: specified.into(),
- module_url_found: found,
- }
- }
-}
-
-pub(crate) type PrepareLoadFuture =
- dyn Future<Output = (ModuleLoadId, Result<RecursiveModuleLoad, Error>)>;
-pub type ModuleSourceFuture = dyn Future<Output = Result<ModuleSource, Error>>;
-
-type ModuleLoadFuture =
- dyn Future<Output = Result<(ModuleRequest, ModuleSource), Error>>;
-
-#[derive(Debug, PartialEq, Eq)]
-pub enum ResolutionKind {
- /// This kind is used in only one situation: when a module is loaded via
- /// `JsRuntime::load_main_module` and is the top-level module, ie. the one
- /// passed as an argument to `JsRuntime::load_main_module`.
- MainModule,
- /// This kind is returned for all other modules during module load, that are
- /// static imports.
- Import,
- /// This kind is returned for all modules that are loaded as a result of a
- /// call to `import()` API (ie. top-level module as well as all its
- /// dependencies, and any other `import()` calls from that load).
- DynamicImport,
-}
-
-/// Describes the entrypoint of a recursive module load.
-#[derive(Debug)]
-enum LoadInit {
- /// Main module specifier.
- Main(String),
- /// Module specifier for side module.
- Side(String),
- /// Dynamic import specifier with referrer and expected
- /// module type (which is determined by import assertion).
- DynamicImport(String, String, AssertedModuleType),
-}
-
-#[derive(Debug, Eq, PartialEq)]
-pub enum LoadState {
- Init,
- LoadingRoot,
- LoadingImports,
- Done,
-}
-
-/// This future is used to implement parallel async module loading.
-pub(crate) struct RecursiveModuleLoad {
- pub id: ModuleLoadId,
- pub root_module_id: Option<ModuleId>,
- init: LoadInit,
- root_asserted_module_type: Option<AssertedModuleType>,
- root_module_type: Option<ModuleType>,
- state: LoadState,
- module_map_rc: Rc<RefCell<ModuleMap>>,
- pending: FuturesUnordered<Pin<Box<ModuleLoadFuture>>>,
- visited: HashSet<ModuleRequest>,
- // The loader is copied from `module_map_rc`, but its reference is cloned
- // ahead of time to avoid already-borrowed errors.
- loader: Rc<dyn ModuleLoader>,
-}
-
-impl RecursiveModuleLoad {
- /// Starts a new asynchronous load of the module graph for given specifier.
- ///
- /// The module corresponding for the given `specifier` will be marked as
- // "the main module" (`import.meta.main` will return `true` for this module).
- fn main(specifier: &str, module_map_rc: Rc<RefCell<ModuleMap>>) -> Self {
- Self::new(LoadInit::Main(specifier.to_string()), module_map_rc)
- }
-
- /// Starts a new asynchronous load of the module graph for given specifier.
- fn side(specifier: &str, module_map_rc: Rc<RefCell<ModuleMap>>) -> Self {
- Self::new(LoadInit::Side(specifier.to_string()), module_map_rc)
- }
-
- /// Starts a new asynchronous load of the module graph for given specifier
- /// that was imported using `import()`.
- fn dynamic_import(
- specifier: &str,
- referrer: &str,
- asserted_module_type: AssertedModuleType,
- module_map_rc: Rc<RefCell<ModuleMap>>,
- ) -> Self {
- Self::new(
- LoadInit::DynamicImport(
- specifier.to_string(),
- referrer.to_string(),
- asserted_module_type,
- ),
- module_map_rc,
- )
- }
-
- fn new(init: LoadInit, module_map_rc: Rc<RefCell<ModuleMap>>) -> Self {
- let id = {
- let mut module_map = module_map_rc.borrow_mut();
- let id = module_map.next_load_id;
- module_map.next_load_id += 1;
- id
- };
- let loader = module_map_rc.borrow().loader.clone();
- let asserted_module_type = match init {
- LoadInit::DynamicImport(_, _, module_type) => module_type,
- _ => AssertedModuleType::JavaScriptOrWasm,
- };
- let mut load = Self {
- id,
- root_module_id: None,
- root_asserted_module_type: None,
- root_module_type: None,
- init,
- state: LoadState::Init,
- module_map_rc: module_map_rc.clone(),
- loader,
- pending: FuturesUnordered::new(),
- visited: HashSet::new(),
- };
- // FIXME(bartlomieju): this seems fishy
- // Ignore the error here, let it be hit in `Stream::poll_next()`.
- if let Ok(root_specifier) = load.resolve_root() {
- if let Some(module_id) = module_map_rc
- .borrow()
- .get_id(root_specifier, asserted_module_type)
- {
- load.root_module_id = Some(module_id);
- load.root_asserted_module_type = Some(asserted_module_type);
- load.root_module_type = Some(
- module_map_rc
- .borrow()
- .get_info_by_id(module_id)
- .unwrap()
- .module_type,
- );
- }
- }
- load
- }
-
- fn resolve_root(&self) -> Result<ModuleSpecifier, Error> {
- match self.init {
- LoadInit::Main(ref specifier) => {
- self
- .loader
- .resolve(specifier, ".", ResolutionKind::MainModule)
- }
- LoadInit::Side(ref specifier) => {
- self.loader.resolve(specifier, ".", ResolutionKind::Import)
- }
- LoadInit::DynamicImport(ref specifier, ref referrer, _) => self
- .loader
- .resolve(specifier, referrer, ResolutionKind::DynamicImport),
- }
- }
-
- async fn prepare(&self) -> Result<(), Error> {
- let (module_specifier, maybe_referrer) = match self.init {
- LoadInit::Main(ref specifier) => {
- let spec =
- self
- .loader
- .resolve(specifier, ".", ResolutionKind::MainModule)?;
- (spec, None)
- }
- LoadInit::Side(ref specifier) => {
- let spec =
- self
- .loader
- .resolve(specifier, ".", ResolutionKind::Import)?;
- (spec, None)
- }
- LoadInit::DynamicImport(ref specifier, ref referrer, _) => {
- let spec = self.loader.resolve(
- specifier,
- referrer,
- ResolutionKind::DynamicImport,
- )?;
- (spec, Some(referrer.to_string()))
- }
- };
-
- self
- .loader
- .prepare_load(&module_specifier, maybe_referrer, self.is_dynamic_import())
- .await
- }
-
- fn is_currently_loading_main_module(&self) -> bool {
- !self.is_dynamic_import()
- && matches!(self.init, LoadInit::Main(..))
- && self.state == LoadState::LoadingRoot
- }
-
- fn is_dynamic_import(&self) -> bool {
- matches!(self.init, LoadInit::DynamicImport(..))
- }
-
- pub(crate) fn register_and_recurse(
- &mut self,
- scope: &mut v8::HandleScope,
- module_request: &ModuleRequest,
- module_source: ModuleSource,
- ) -> Result<(), ModuleError> {
- let expected_asserted_module_type = module_source.module_type.into();
- let module_url_found = module_source.module_url_found;
- let module_url_specified = module_source.module_url_specified;
-
- if module_request.asserted_module_type != expected_asserted_module_type {
- return Err(ModuleError::Other(generic_error(format!(
- "Expected a \"{}\" module but loaded a \"{}\" module.",
- module_request.asserted_module_type, module_source.module_type,
- ))));
- }
-
- // Register the module in the module map unless it's already there. If the
- // specified URL and the "true" URL are different, register the alias.
- let module_url_found = if let Some(module_url_found) = module_url_found {
- let (module_url_found1, module_url_found2) =
- module_url_found.into_cheap_copy();
- self.module_map_rc.borrow_mut().alias(
- module_url_specified,
- expected_asserted_module_type,
- module_url_found1,
- );
- module_url_found2
- } else {
- module_url_specified
- };
-
- let maybe_module_id = self
- .module_map_rc
- .borrow()
- .get_id(&module_url_found, expected_asserted_module_type);
- let module_id = match maybe_module_id {
- Some(id) => {
- debug!(
- "Already-registered module fetched again: {:?}",
- module_url_found
- );
- id
- }
- None => match module_source.module_type {
- ModuleType::JavaScript => {
- self.module_map_rc.borrow_mut().new_es_module(
- scope,
- self.is_currently_loading_main_module(),
- module_url_found,
- module_source.code,
- self.is_dynamic_import(),
- )?
- }
- ModuleType::Json => self.module_map_rc.borrow_mut().new_json_module(
- scope,
- module_url_found,
- module_source.code,
- )?,
- },
- };
-
- // Recurse the module's imports. There are two cases for each import:
- // 1. If the module is not in the module map, start a new load for it in
- // `self.pending`. The result of that load should eventually be passed to
- // this function for recursion.
- // 2. If the module is already in the module map, queue it up to be
- // recursed synchronously here.
- // This robustly ensures that the whole graph is in the module map before
- // `LoadState::Done` is set.
- let mut already_registered = VecDeque::new();
- already_registered.push_back((module_id, module_request.clone()));
- self.visited.insert(module_request.clone());
- while let Some((module_id, module_request)) = already_registered.pop_front()
- {
- let referrer = ModuleSpecifier::parse(&module_request.specifier).unwrap();
- let imports = self
- .module_map_rc
- .borrow()
- .get_requested_modules(module_id)
- .unwrap()
- .clone();
- for module_request in imports {
- if !self.visited.contains(&module_request) {
- if let Some(module_id) = self.module_map_rc.borrow().get_id(
- module_request.specifier.as_str(),
- module_request.asserted_module_type,
- ) {
- already_registered.push_back((module_id, module_request.clone()));
- } else {
- let request = module_request.clone();
- let specifier =
- ModuleSpecifier::parse(&module_request.specifier).unwrap();
- let referrer = referrer.clone();
- let loader = self.loader.clone();
- let is_dynamic_import = self.is_dynamic_import();
- let fut = async move {
- let load_result = loader
- .load(&specifier, Some(&referrer), is_dynamic_import)
- .await;
- load_result.map(|s| (request, s))
- };
- self.pending.push(fut.boxed_local());
- }
- self.visited.insert(module_request);
- }
- }
- }
-
- // Update `self.state` however applicable.
- if self.state == LoadState::LoadingRoot {
- self.root_module_id = Some(module_id);
- self.root_asserted_module_type = Some(module_source.module_type.into());
- self.state = LoadState::LoadingImports;
- }
- if self.pending.is_empty() {
- self.state = LoadState::Done;
- }
-
- Ok(())
- }
-}
-
-impl Stream for RecursiveModuleLoad {
- type Item = Result<(ModuleRequest, ModuleSource), Error>;
-
- fn poll_next(
- self: Pin<&mut Self>,
- cx: &mut Context,
- ) -> Poll<Option<Self::Item>> {
- let inner = self.get_mut();
- // IMPORTANT: Do not borrow `inner.module_map_rc` here. It may not be
- // available.
- match inner.state {
- LoadState::Init => {
- let module_specifier = match inner.resolve_root() {
- Ok(url) => url,
- Err(error) => return Poll::Ready(Some(Err(error))),
- };
- let load_fut = if let Some(_module_id) = inner.root_module_id {
- // FIXME(bartlomieju): this is very bad
- // The root module is already in the module map.
- // TODO(nayeemrmn): In this case we would ideally skip to
- // `LoadState::LoadingImports` and synchronously recurse the imports
- // like the bottom of `RecursiveModuleLoad::register_and_recurse()`.
- // But the module map cannot be borrowed here. Instead fake a load
- // event so it gets passed to that function and recursed eventually.
- let asserted_module_type = inner.root_asserted_module_type.unwrap();
- let module_type = inner.root_module_type.unwrap();
- let module_request = ModuleRequest {
- specifier: module_specifier.to_string(),
- asserted_module_type,
- };
- // The code will be discarded, since this module is already in the
- // module map.
- let module_source = ModuleSource::new(
- module_type,
- Default::default(),
- &module_specifier,
- );
- futures::future::ok((module_request, module_source)).boxed()
- } else {
- let maybe_referrer = match inner.init {
- LoadInit::DynamicImport(_, ref referrer, _) => {
- resolve_url(referrer).ok()
- }
- _ => None,
- };
- let asserted_module_type = match inner.init {
- LoadInit::DynamicImport(_, _, module_type) => module_type,
- _ => AssertedModuleType::JavaScriptOrWasm,
- };
- let module_request = ModuleRequest {
- specifier: module_specifier.to_string(),
- asserted_module_type,
- };
- let loader = inner.loader.clone();
- let is_dynamic_import = inner.is_dynamic_import();
- async move {
- let result = loader
- .load(
- &module_specifier,
- maybe_referrer.as_ref(),
- is_dynamic_import,
- )
- .await;
- result.map(|s| (module_request, s))
- }
- .boxed_local()
- };
- inner.pending.push(load_fut);
- inner.state = LoadState::LoadingRoot;
- inner.try_poll_next_unpin(cx)
- }
- LoadState::LoadingRoot | LoadState::LoadingImports => {
- match inner.pending.try_poll_next_unpin(cx)? {
- Poll::Ready(None) => unreachable!(),
- Poll::Ready(Some(info)) => Poll::Ready(Some(Ok(info))),
- Poll::Pending => Poll::Pending,
- }
- }
- LoadState::Done => Poll::Ready(None),
- }
- }
-}
-
-#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
-#[repr(u32)]
-pub(crate) enum AssertedModuleType {
- JavaScriptOrWasm,
- Json,
-}
-
-impl From<ModuleType> for AssertedModuleType {
- fn from(module_type: ModuleType) -> AssertedModuleType {
- match module_type {
- ModuleType::JavaScript => AssertedModuleType::JavaScriptOrWasm,
- ModuleType::Json => AssertedModuleType::Json,
- }
- }
-}
-
-impl std::fmt::Display for AssertedModuleType {
- fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
- match self {
- Self::JavaScriptOrWasm => write!(f, "JavaScriptOrWasm"),
- Self::Json => write!(f, "JSON"),
- }
- }
-}
-
-/// Describes a request for a module as parsed from the source code.
-/// Usually executable (`JavaScriptOrWasm`) is used, except when an
-/// import assertions explicitly constrains an import to JSON, in
-/// which case this will have a `AssertedModuleType::Json`.
-#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
-pub(crate) struct ModuleRequest {
- pub specifier: String,
- pub asserted_module_type: AssertedModuleType,
-}
-
-#[derive(Debug, PartialEq)]
-pub(crate) struct ModuleInfo {
- #[allow(unused)]
- pub id: ModuleId,
- // Used in "bindings.rs" for "import.meta.main" property value.
- pub main: bool,
- pub name: ModuleName,
- pub requests: Vec<ModuleRequest>,
- pub module_type: ModuleType,
-}
-
-#[derive(Debug)]
-pub(crate) enum ModuleError {
- Exception(v8::Global<v8::Value>),
- Other(Error),
-}
diff --git a/core/modules/tests.rs b/core/modules/tests.rs
deleted file mode 100644
index 0eb7ce514..000000000
--- a/core/modules/tests.rs
+++ /dev/null
@@ -1,1252 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-use crate::ascii_str;
-use crate::resolve_import;
-use crate::runtime::JsRuntime;
-use crate::runtime::JsRuntimeForSnapshot;
-use crate::RuntimeOptions;
-use crate::Snapshot;
-use deno_ops::op;
-use futures::future::poll_fn;
-use futures::future::FutureExt;
-use parking_lot::Mutex;
-use std::fmt;
-use std::future::Future;
-use std::io;
-use std::path::PathBuf;
-use std::sync::atomic::AtomicUsize;
-use std::sync::atomic::Ordering;
-use std::sync::Arc;
-
-use super::*;
-
-// deno_ops macros generate code assuming deno_core in scope.
-mod deno_core {
- pub use crate::*;
-}
-
-#[derive(Default)]
-struct MockLoader {
- pub loads: Arc<Mutex<Vec<String>>>,
-}
-
-impl MockLoader {
- fn new() -> Rc<Self> {
- Default::default()
- }
-}
-
-fn mock_source_code(url: &str) -> Option<(&'static str, &'static str)> {
- const A_SRC: &str = r#"
-import { b } from "/b.js";
-import { c } from "/c.js";
-if (b() != 'b') throw Error();
-if (c() != 'c') throw Error();
-if (!import.meta.main) throw Error();
-if (import.meta.url != 'file:///a.js') throw Error();
-"#;
-
- const B_SRC: &str = r#"
-import { c } from "/c.js";
-if (c() != 'c') throw Error();
-export function b() { return 'b'; }
-if (import.meta.main) throw Error();
-if (import.meta.url != 'file:///b.js') throw Error();
-"#;
-
- const C_SRC: &str = r#"
-import { d } from "/d.js";
-export function c() { return 'c'; }
-if (d() != 'd') throw Error();
-if (import.meta.main) throw Error();
-if (import.meta.url != 'file:///c.js') throw Error();
-"#;
-
- const D_SRC: &str = r#"
-export function d() { return 'd'; }
-if (import.meta.main) throw Error();
-if (import.meta.url != 'file:///d.js') throw Error();
-"#;
-
- const CIRCULAR1_SRC: &str = r#"
-import "/circular2.js";
-Deno.core.print("circular1");
-"#;
-
- const CIRCULAR2_SRC: &str = r#"
-import "/circular3.js";
-Deno.core.print("circular2");
-"#;
-
- const CIRCULAR3_SRC: &str = r#"
-import "/circular1.js";
-import "/circular2.js";
-Deno.core.print("circular3");
-"#;
-
- const REDIRECT1_SRC: &str = r#"
-import "./redirect2.js";
-Deno.core.print("redirect1");
-"#;
-
- const REDIRECT2_SRC: &str = r#"
-import "./redirect3.js";
-Deno.core.print("redirect2");
-"#;
-
- const REDIRECT3_SRC: &str = r#"Deno.core.print("redirect3");"#;
-
- const MAIN_SRC: &str = r#"
-// never_ready.js never loads.
-import "/never_ready.js";
-// slow.js resolves after one tick.
-import "/slow.js";
-"#;
-
- const SLOW_SRC: &str = r#"
-// Circular import of never_ready.js
-// Does this trigger two ModuleLoader calls? It shouldn't.
-import "/never_ready.js";
-import "/a.js";
-"#;
-
- const BAD_IMPORT_SRC: &str = r#"import "foo";"#;
-
- // (code, real_module_name)
- let spec: Vec<&str> = url.split("file://").collect();
- match spec[1] {
- "/a.js" => Some((A_SRC, "file:///a.js")),
- "/b.js" => Some((B_SRC, "file:///b.js")),
- "/c.js" => Some((C_SRC, "file:///c.js")),
- "/d.js" => Some((D_SRC, "file:///d.js")),
- "/circular1.js" => Some((CIRCULAR1_SRC, "file:///circular1.js")),
- "/circular2.js" => Some((CIRCULAR2_SRC, "file:///circular2.js")),
- "/circular3.js" => Some((CIRCULAR3_SRC, "file:///circular3.js")),
- "/redirect1.js" => Some((REDIRECT1_SRC, "file:///redirect1.js")),
- // pretend redirect - real module name is different than one requested
- "/redirect2.js" => Some((REDIRECT2_SRC, "file:///dir/redirect2.js")),
- "/dir/redirect3.js" => Some((REDIRECT3_SRC, "file:///redirect3.js")),
- "/slow.js" => Some((SLOW_SRC, "file:///slow.js")),
- "/never_ready.js" => {
- Some(("should never be Ready", "file:///never_ready.js"))
- }
- "/main.js" => Some((MAIN_SRC, "file:///main.js")),
- "/bad_import.js" => Some((BAD_IMPORT_SRC, "file:///bad_import.js")),
- // deliberately empty code.
- "/main_with_code.js" => Some(("", "file:///main_with_code.js")),
- _ => None,
- }
-}
-
-#[derive(Debug, PartialEq)]
-enum MockError {
- ResolveErr,
- LoadErr,
-}
-
-impl fmt::Display for MockError {
- fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
- unimplemented!()
- }
-}
-
-impl std::error::Error for MockError {
- fn cause(&self) -> Option<&dyn std::error::Error> {
- unimplemented!()
- }
-}
-
-struct DelayedSourceCodeFuture {
- url: String,
- counter: u32,
-}
-
-impl Future for DelayedSourceCodeFuture {
- type Output = Result<ModuleSource, Error>;
-
- fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
- let inner = self.get_mut();
- inner.counter += 1;
- if inner.url == "file:///never_ready.js" {
- return Poll::Pending;
- }
- if inner.url == "file:///slow.js" && inner.counter < 2 {
- // TODO(ry) Hopefully in the future we can remove current task
- // notification.
- cx.waker().wake_by_ref();
- return Poll::Pending;
- }
- match mock_source_code(&inner.url) {
- Some(src) => Poll::Ready(Ok(ModuleSource::for_test_with_redirect(
- src.0,
- inner.url.as_str(),
- src.1,
- ))),
- None => Poll::Ready(Err(MockError::LoadErr.into())),
- }
- }
-}
-
-impl ModuleLoader for MockLoader {
- fn resolve(
- &self,
- specifier: &str,
- referrer: &str,
- _kind: ResolutionKind,
- ) -> Result<ModuleSpecifier, Error> {
- let referrer = if referrer == "." {
- "file:///"
- } else {
- referrer
- };
-
- let output_specifier = match resolve_import(specifier, referrer) {
- Ok(specifier) => specifier,
- Err(..) => return Err(MockError::ResolveErr.into()),
- };
-
- if mock_source_code(output_specifier.as_ref()).is_some() {
- Ok(output_specifier)
- } else {
- Err(MockError::ResolveErr.into())
- }
- }
-
- fn load(
- &self,
- module_specifier: &ModuleSpecifier,
- _maybe_referrer: Option<&ModuleSpecifier>,
- _is_dyn_import: bool,
- ) -> Pin<Box<ModuleSourceFuture>> {
- let mut loads = self.loads.lock();
- loads.push(module_specifier.to_string());
- let url = module_specifier.to_string();
- DelayedSourceCodeFuture { url, counter: 0 }.boxed()
- }
-}
-
-#[test]
-fn test_recursive_load() {
- let loader = MockLoader::new();
- let loads = loader.loads.clone();
- let mut runtime = JsRuntime::new(RuntimeOptions {
- module_loader: Some(loader),
- ..Default::default()
- });
- let spec = resolve_url("file:///a.js").unwrap();
- let a_id_fut = runtime.load_main_module(&spec, None);
- let a_id = futures::executor::block_on(a_id_fut).unwrap();
-
- #[allow(clippy::let_underscore_future)]
- let _ = runtime.mod_evaluate(a_id);
- futures::executor::block_on(runtime.run_event_loop(false)).unwrap();
- let l = loads.lock();
- assert_eq!(
- l.to_vec(),
- vec![
- "file:///a.js",
- "file:///b.js",
- "file:///c.js",
- "file:///d.js"
- ]
- );
-
- let module_map_rc = runtime.module_map();
- let modules = module_map_rc.borrow();
-
- assert_eq!(
- modules.get_id("file:///a.js", AssertedModuleType::JavaScriptOrWasm),
- Some(a_id)
- );
- let b_id = modules
- .get_id("file:///b.js", AssertedModuleType::JavaScriptOrWasm)
- .unwrap();
- let c_id = modules
- .get_id("file:///c.js", AssertedModuleType::JavaScriptOrWasm)
- .unwrap();
- let d_id = modules
- .get_id("file:///d.js", AssertedModuleType::JavaScriptOrWasm)
- .unwrap();
- assert_eq!(
- modules.get_requested_modules(a_id),
- Some(&vec![
- ModuleRequest {
- specifier: "file:///b.js".to_string(),
- asserted_module_type: AssertedModuleType::JavaScriptOrWasm,
- },
- ModuleRequest {
- specifier: "file:///c.js".to_string(),
- asserted_module_type: AssertedModuleType::JavaScriptOrWasm,
- },
- ])
- );
- assert_eq!(
- modules.get_requested_modules(b_id),
- Some(&vec![ModuleRequest {
- specifier: "file:///c.js".to_string(),
- asserted_module_type: AssertedModuleType::JavaScriptOrWasm,
- },])
- );
- assert_eq!(
- modules.get_requested_modules(c_id),
- Some(&vec![ModuleRequest {
- specifier: "file:///d.js".to_string(),
- asserted_module_type: AssertedModuleType::JavaScriptOrWasm,
- },])
- );
- assert_eq!(modules.get_requested_modules(d_id), Some(&vec![]));
-}
-
-#[test]
-fn test_mods() {
- #[derive(Default)]
- struct ModsLoader {
- pub count: Arc<AtomicUsize>,
- }
-
- impl ModuleLoader for ModsLoader {
- fn resolve(
- &self,
- specifier: &str,
- referrer: &str,
- _kind: ResolutionKind,
- ) -> Result<ModuleSpecifier, Error> {
- self.count.fetch_add(1, Ordering::Relaxed);
- assert_eq!(specifier, "./b.js");
- assert_eq!(referrer, "file:///a.js");
- let s = resolve_import(specifier, referrer).unwrap();
- Ok(s)
- }
-
- fn load(
- &self,
- _module_specifier: &ModuleSpecifier,
- _maybe_referrer: Option<&ModuleSpecifier>,
- _is_dyn_import: bool,
- ) -> Pin<Box<ModuleSourceFuture>> {
- unreachable!()
- }
- }
-
- let loader = Rc::new(ModsLoader::default());
-
- let resolve_count = loader.count.clone();
- static DISPATCH_COUNT: AtomicUsize = AtomicUsize::new(0);
-
- #[op]
- fn op_test(control: u8) -> u8 {
- DISPATCH_COUNT.fetch_add(1, Ordering::Relaxed);
- assert_eq!(control, 42);
- 43
- }
-
- deno_core::extension!(test_ext, ops = [op_test]);
-
- let mut runtime = JsRuntime::new(RuntimeOptions {
- extensions: vec![test_ext::init_ops()],
- module_loader: Some(loader),
- ..Default::default()
- });
-
- runtime
- .execute_script_static(
- "setup.js",
- r#"
- function assert(cond) {
- if (!cond) {
- throw Error("assert");
- }
- }
- "#,
- )
- .unwrap();
-
- assert_eq!(DISPATCH_COUNT.load(Ordering::Relaxed), 0);
-
- let module_map_rc = runtime.module_map().clone();
-
- let (mod_a, mod_b) = {
- let scope = &mut runtime.handle_scope();
- let mut module_map = module_map_rc.borrow_mut();
- let specifier_a = ascii_str!("file:///a.js");
- let mod_a = module_map
- .new_es_module(
- scope,
- true,
- specifier_a,
- ascii_str!(
- r#"
- import { b } from './b.js'
- if (b() != 'b') throw Error();
- let control = 42;
- Deno.core.ops.op_test(control);
- "#
- ),
- false,
- )
- .unwrap();
-
- assert_eq!(DISPATCH_COUNT.load(Ordering::Relaxed), 0);
- let imports = module_map.get_requested_modules(mod_a);
- assert_eq!(
- imports,
- Some(&vec![ModuleRequest {
- specifier: "file:///b.js".to_string(),
- asserted_module_type: AssertedModuleType::JavaScriptOrWasm,
- },])
- );
-
- let mod_b = module_map
- .new_es_module(
- scope,
- false,
- ascii_str!("file:///b.js"),
- ascii_str!("export function b() { return 'b' }"),
- false,
- )
- .unwrap();
- let imports = module_map.get_requested_modules(mod_b).unwrap();
- assert_eq!(imports.len(), 0);
- (mod_a, mod_b)
- };
-
- runtime.instantiate_module(mod_b).unwrap();
- assert_eq!(DISPATCH_COUNT.load(Ordering::Relaxed), 0);
- assert_eq!(resolve_count.load(Ordering::SeqCst), 1);
-
- runtime.instantiate_module(mod_a).unwrap();
- assert_eq!(DISPATCH_COUNT.load(Ordering::Relaxed), 0);
-
- #[allow(clippy::let_underscore_future)]
- let _ = runtime.mod_evaluate(mod_a);
- assert_eq!(DISPATCH_COUNT.load(Ordering::Relaxed), 1);
-}
-
-#[test]
-fn test_json_module() {
- #[derive(Default)]
- struct ModsLoader {
- pub count: Arc<AtomicUsize>,
- }
-
- impl ModuleLoader for ModsLoader {
- fn resolve(
- &self,
- specifier: &str,
- referrer: &str,
- _kind: ResolutionKind,
- ) -> Result<ModuleSpecifier, Error> {
- self.count.fetch_add(1, Ordering::Relaxed);
- assert_eq!(specifier, "./b.json");
- assert_eq!(referrer, "file:///a.js");
- let s = resolve_import(specifier, referrer).unwrap();
- Ok(s)
- }
-
- fn load(
- &self,
- _module_specifier: &ModuleSpecifier,
- _maybe_referrer: Option<&ModuleSpecifier>,
- _is_dyn_import: bool,
- ) -> Pin<Box<ModuleSourceFuture>> {
- unreachable!()
- }
- }
-
- let loader = Rc::new(ModsLoader::default());
-
- let resolve_count = loader.count.clone();
-
- let mut runtime = JsRuntime::new(RuntimeOptions {
- module_loader: Some(loader),
- ..Default::default()
- });
-
- runtime
- .execute_script_static(
- "setup.js",
- r#"
- function assert(cond) {
- if (!cond) {
- throw Error("assert");
- }
- }
- "#,
- )
- .unwrap();
-
- let module_map_rc = runtime.module_map().clone();
-
- let (mod_a, mod_b) = {
- let scope = &mut runtime.handle_scope();
- let mut module_map = module_map_rc.borrow_mut();
- let specifier_a = ascii_str!("file:///a.js");
- let mod_a = module_map
- .new_es_module(
- scope,
- true,
- specifier_a,
- ascii_str!(
- r#"
- import jsonData from './b.json' assert {type: "json"};
- assert(jsonData.a == "b");
- assert(jsonData.c.d == 10);
- "#
- ),
- false,
- )
- .unwrap();
-
- let imports = module_map.get_requested_modules(mod_a);
- assert_eq!(
- imports,
- Some(&vec![ModuleRequest {
- specifier: "file:///b.json".to_string(),
- asserted_module_type: AssertedModuleType::Json,
- },])
- );
-
- let mod_b = module_map
- .new_json_module(
- scope,
- ascii_str!("file:///b.json"),
- ascii_str!("{\"a\": \"b\", \"c\": {\"d\": 10}}"),
- )
- .unwrap();
- let imports = module_map.get_requested_modules(mod_b).unwrap();
- assert_eq!(imports.len(), 0);
- (mod_a, mod_b)
- };
-
- runtime.instantiate_module(mod_b).unwrap();
- assert_eq!(resolve_count.load(Ordering::SeqCst), 1);
-
- runtime.instantiate_module(mod_a).unwrap();
-
- let receiver = runtime.mod_evaluate(mod_a);
- futures::executor::block_on(runtime.run_event_loop(false)).unwrap();
- futures::executor::block_on(receiver).unwrap().unwrap();
-}
-
-#[tokio::test]
-async fn dyn_import_err() {
- #[derive(Clone, Default)]
- struct DynImportErrLoader {
- pub count: Arc<AtomicUsize>,
- }
-
- impl ModuleLoader for DynImportErrLoader {
- fn resolve(
- &self,
- specifier: &str,
- referrer: &str,
- _kind: ResolutionKind,
- ) -> Result<ModuleSpecifier, Error> {
- self.count.fetch_add(1, Ordering::Relaxed);
- assert_eq!(specifier, "/foo.js");
- assert_eq!(referrer, "file:///dyn_import2.js");
- let s = resolve_import(specifier, referrer).unwrap();
- Ok(s)
- }
-
- fn load(
- &self,
- _module_specifier: &ModuleSpecifier,
- _maybe_referrer: Option<&ModuleSpecifier>,
- _is_dyn_import: bool,
- ) -> Pin<Box<ModuleSourceFuture>> {
- async { Err(io::Error::from(io::ErrorKind::NotFound).into()) }.boxed()
- }
- }
-
- let loader = Rc::new(DynImportErrLoader::default());
- let count = loader.count.clone();
- let mut runtime = JsRuntime::new(RuntimeOptions {
- module_loader: Some(loader),
- ..Default::default()
- });
-
- // Test an erroneous dynamic import where the specified module isn't found.
- poll_fn(move |cx| {
- runtime
- .execute_script_static(
- "file:///dyn_import2.js",
- r#"
- (async () => {
- await import("/foo.js");
- })();
- "#,
- )
- .unwrap();
-
- // We should get an error here.
- let result = runtime.poll_event_loop(cx, false);
- if let Poll::Ready(Ok(_)) = result {
- unreachable!();
- }
- assert_eq!(count.load(Ordering::Relaxed), 4);
- Poll::Ready(())
- })
- .await;
-}
-
-#[derive(Clone, Default)]
-struct DynImportOkLoader {
- pub prepare_load_count: Arc<AtomicUsize>,
- pub resolve_count: Arc<AtomicUsize>,
- pub load_count: Arc<AtomicUsize>,
-}
-
-impl ModuleLoader for DynImportOkLoader {
- fn resolve(
- &self,
- specifier: &str,
- referrer: &str,
- _kind: ResolutionKind,
- ) -> Result<ModuleSpecifier, Error> {
- let c = self.resolve_count.fetch_add(1, Ordering::Relaxed);
- assert!(c < 7);
- assert_eq!(specifier, "./b.js");
- assert_eq!(referrer, "file:///dyn_import3.js");
- let s = resolve_import(specifier, referrer).unwrap();
- Ok(s)
- }
-
- fn load(
- &self,
- specifier: &ModuleSpecifier,
- _maybe_referrer: Option<&ModuleSpecifier>,
- _is_dyn_import: bool,
- ) -> Pin<Box<ModuleSourceFuture>> {
- self.load_count.fetch_add(1, Ordering::Relaxed);
- let info =
- ModuleSource::for_test("export function b() { return 'b' }", specifier);
- async move { Ok(info) }.boxed()
- }
-
- fn prepare_load(
- &self,
- _module_specifier: &ModuleSpecifier,
- _maybe_referrer: Option<String>,
- _is_dyn_import: bool,
- ) -> Pin<Box<dyn Future<Output = Result<(), Error>>>> {
- self.prepare_load_count.fetch_add(1, Ordering::Relaxed);
- async { Ok(()) }.boxed_local()
- }
-}
-
-#[tokio::test]
-async fn dyn_import_ok() {
- let loader = Rc::new(DynImportOkLoader::default());
- let prepare_load_count = loader.prepare_load_count.clone();
- let resolve_count = loader.resolve_count.clone();
- let load_count = loader.load_count.clone();
- let mut runtime = JsRuntime::new(RuntimeOptions {
- module_loader: Some(loader),
- ..Default::default()
- });
- poll_fn(move |cx| {
- // Dynamically import mod_b
- runtime
- .execute_script_static(
- "file:///dyn_import3.js",
- r#"
- (async () => {
- let mod = await import("./b.js");
- if (mod.b() !== 'b') {
- throw Error("bad1");
- }
- // And again!
- mod = await import("./b.js");
- if (mod.b() !== 'b') {
- throw Error("bad2");
- }
- })();
- "#,
- )
- .unwrap();
-
- assert!(matches!(
- runtime.poll_event_loop(cx, false),
- Poll::Ready(Ok(_))
- ));
- assert_eq!(prepare_load_count.load(Ordering::Relaxed), 1);
- assert_eq!(resolve_count.load(Ordering::Relaxed), 7);
- assert_eq!(load_count.load(Ordering::Relaxed), 1);
- assert!(matches!(
- runtime.poll_event_loop(cx, false),
- Poll::Ready(Ok(_))
- ));
- assert_eq!(resolve_count.load(Ordering::Relaxed), 7);
- assert_eq!(load_count.load(Ordering::Relaxed), 1);
- Poll::Ready(())
- })
- .await;
-}
-
-#[tokio::test]
-async fn dyn_import_borrow_mut_error() {
- // https://github.com/denoland/deno/issues/6054
- let loader = Rc::new(DynImportOkLoader::default());
- let prepare_load_count = loader.prepare_load_count.clone();
- let mut runtime = JsRuntime::new(RuntimeOptions {
- module_loader: Some(loader),
- ..Default::default()
- });
-
- poll_fn(move |cx| {
- runtime
- .execute_script_static(
- "file:///dyn_import3.js",
- r#"
- (async () => {
- let mod = await import("./b.js");
- if (mod.b() !== 'b') {
- throw Error("bad");
- }
- })();
- "#,
- )
- .unwrap();
- // First poll runs `prepare_load` hook.
- let _ = runtime.poll_event_loop(cx, false);
- assert_eq!(prepare_load_count.load(Ordering::Relaxed), 1);
- // Second poll triggers error
- let _ = runtime.poll_event_loop(cx, false);
- Poll::Ready(())
- })
- .await;
-}
-
-// Regression test for https://github.com/denoland/deno/issues/3736.
-#[test]
-fn dyn_concurrent_circular_import() {
- #[derive(Clone, Default)]
- struct DynImportCircularLoader {
- pub resolve_count: Arc<AtomicUsize>,
- pub load_count: Arc<AtomicUsize>,
- }
-
- impl ModuleLoader for DynImportCircularLoader {
- fn resolve(
- &self,
- specifier: &str,
- referrer: &str,
- _kind: ResolutionKind,
- ) -> Result<ModuleSpecifier, Error> {
- self.resolve_count.fetch_add(1, Ordering::Relaxed);
- let s = resolve_import(specifier, referrer).unwrap();
- Ok(s)
- }
-
- fn load(
- &self,
- specifier: &ModuleSpecifier,
- _maybe_referrer: Option<&ModuleSpecifier>,
- _is_dyn_import: bool,
- ) -> Pin<Box<ModuleSourceFuture>> {
- self.load_count.fetch_add(1, Ordering::Relaxed);
- let filename = PathBuf::from(specifier.to_string())
- .file_name()
- .unwrap()
- .to_string_lossy()
- .to_string();
- let code = match filename.as_str() {
- "a.js" => "import './b.js';",
- "b.js" => "import './c.js';\nimport './a.js';",
- "c.js" => "import './d.js';",
- "d.js" => "// pass",
- _ => unreachable!(),
- };
- let info = ModuleSource::for_test(code, specifier);
- async move { Ok(info) }.boxed()
- }
- }
-
- let loader = Rc::new(DynImportCircularLoader::default());
- let mut runtime = JsRuntime::new(RuntimeOptions {
- module_loader: Some(loader),
- ..Default::default()
- });
-
- runtime
- .execute_script_static(
- "file:///entry.js",
- "import('./b.js');\nimport('./a.js');",
- )
- .unwrap();
-
- let result = futures::executor::block_on(runtime.run_event_loop(false));
- assert!(result.is_ok());
-}
-
-#[test]
-fn test_circular_load() {
- let loader = MockLoader::new();
- let loads = loader.loads.clone();
- let mut runtime = JsRuntime::new(RuntimeOptions {
- module_loader: Some(loader),
- ..Default::default()
- });
-
- let fut = async move {
- let spec = resolve_url("file:///circular1.js").unwrap();
- let result = runtime.load_main_module(&spec, None).await;
- assert!(result.is_ok());
- let circular1_id = result.unwrap();
- #[allow(clippy::let_underscore_future)]
- let _ = runtime.mod_evaluate(circular1_id);
- runtime.run_event_loop(false).await.unwrap();
-
- let l = loads.lock();
- assert_eq!(
- l.to_vec(),
- vec![
- "file:///circular1.js",
- "file:///circular2.js",
- "file:///circular3.js"
- ]
- );
-
- let module_map_rc = runtime.module_map();
- let modules = module_map_rc.borrow();
-
- assert_eq!(
- modules
- .get_id("file:///circular1.js", AssertedModuleType::JavaScriptOrWasm),
- Some(circular1_id)
- );
- let circular2_id = modules
- .get_id("file:///circular2.js", AssertedModuleType::JavaScriptOrWasm)
- .unwrap();
-
- assert_eq!(
- modules.get_requested_modules(circular1_id),
- Some(&vec![ModuleRequest {
- specifier: "file:///circular2.js".to_string(),
- asserted_module_type: AssertedModuleType::JavaScriptOrWasm,
- }])
- );
-
- assert_eq!(
- modules.get_requested_modules(circular2_id),
- Some(&vec![ModuleRequest {
- specifier: "file:///circular3.js".to_string(),
- asserted_module_type: AssertedModuleType::JavaScriptOrWasm,
- }])
- );
-
- assert!(modules
- .get_id("file:///circular3.js", AssertedModuleType::JavaScriptOrWasm)
- .is_some());
- let circular3_id = modules
- .get_id("file:///circular3.js", AssertedModuleType::JavaScriptOrWasm)
- .unwrap();
- assert_eq!(
- modules.get_requested_modules(circular3_id),
- Some(&vec![
- ModuleRequest {
- specifier: "file:///circular1.js".to_string(),
- asserted_module_type: AssertedModuleType::JavaScriptOrWasm,
- },
- ModuleRequest {
- specifier: "file:///circular2.js".to_string(),
- asserted_module_type: AssertedModuleType::JavaScriptOrWasm,
- }
- ])
- );
- }
- .boxed_local();
-
- futures::executor::block_on(fut);
-}
-
-#[test]
-fn test_redirect_load() {
- let loader = MockLoader::new();
- let loads = loader.loads.clone();
- let mut runtime = JsRuntime::new(RuntimeOptions {
- module_loader: Some(loader),
- ..Default::default()
- });
-
- let fut = async move {
- let spec = resolve_url("file:///redirect1.js").unwrap();
- let result = runtime.load_main_module(&spec, None).await;
- assert!(result.is_ok());
- let redirect1_id = result.unwrap();
- #[allow(clippy::let_underscore_future)]
- let _ = runtime.mod_evaluate(redirect1_id);
- runtime.run_event_loop(false).await.unwrap();
- let l = loads.lock();
- assert_eq!(
- l.to_vec(),
- vec![
- "file:///redirect1.js",
- "file:///redirect2.js",
- "file:///dir/redirect3.js"
- ]
- );
-
- let module_map_rc = runtime.module_map();
- let modules = module_map_rc.borrow();
-
- assert_eq!(
- modules
- .get_id("file:///redirect1.js", AssertedModuleType::JavaScriptOrWasm),
- Some(redirect1_id)
- );
-
- let redirect2_id = modules
- .get_id(
- "file:///dir/redirect2.js",
- AssertedModuleType::JavaScriptOrWasm,
- )
- .unwrap();
- assert!(modules
- .is_alias("file:///redirect2.js", AssertedModuleType::JavaScriptOrWasm));
- assert!(!modules.is_alias(
- "file:///dir/redirect2.js",
- AssertedModuleType::JavaScriptOrWasm
- ));
- assert_eq!(
- modules
- .get_id("file:///redirect2.js", AssertedModuleType::JavaScriptOrWasm),
- Some(redirect2_id)
- );
-
- let redirect3_id = modules
- .get_id("file:///redirect3.js", AssertedModuleType::JavaScriptOrWasm)
- .unwrap();
- assert!(modules.is_alias(
- "file:///dir/redirect3.js",
- AssertedModuleType::JavaScriptOrWasm
- ));
- assert!(!modules
- .is_alias("file:///redirect3.js", AssertedModuleType::JavaScriptOrWasm));
- assert_eq!(
- modules.get_id(
- "file:///dir/redirect3.js",
- AssertedModuleType::JavaScriptOrWasm
- ),
- Some(redirect3_id)
- );
- }
- .boxed_local();
-
- futures::executor::block_on(fut);
-}
-
-#[tokio::test]
-async fn slow_never_ready_modules() {
- let loader = MockLoader::new();
- let loads = loader.loads.clone();
- let mut runtime = JsRuntime::new(RuntimeOptions {
- module_loader: Some(loader),
- ..Default::default()
- });
-
- poll_fn(move |cx| {
- let spec = resolve_url("file:///main.js").unwrap();
- let mut recursive_load =
- runtime.load_main_module(&spec, None).boxed_local();
-
- let result = recursive_load.poll_unpin(cx);
- assert!(result.is_pending());
-
- // TODO(ry) Arguably the first time we poll only the following modules
- // should be loaded:
- // "file:///main.js",
- // "file:///never_ready.js",
- // "file:///slow.js"
- // But due to current task notification in DelayedSourceCodeFuture they
- // all get loaded in a single poll.
-
- for _ in 0..10 {
- let result = recursive_load.poll_unpin(cx);
- assert!(result.is_pending());
- let l = loads.lock();
- assert_eq!(
- l.to_vec(),
- vec![
- "file:///main.js",
- "file:///never_ready.js",
- "file:///slow.js",
- "file:///a.js",
- "file:///b.js",
- "file:///c.js",
- "file:///d.js"
- ]
- );
- }
- Poll::Ready(())
- })
- .await;
-}
-
-#[tokio::test]
-async fn loader_disappears_after_error() {
- let loader = MockLoader::new();
- let mut runtime = JsRuntime::new(RuntimeOptions {
- module_loader: Some(loader),
- ..Default::default()
- });
-
- let spec = resolve_url("file:///bad_import.js").unwrap();
- let result = runtime.load_main_module(&spec, None).await;
- let err = result.unwrap_err();
- assert_eq!(
- err.downcast_ref::<MockError>().unwrap(),
- &MockError::ResolveErr
- );
-}
-
-#[test]
-fn recursive_load_main_with_code() {
- const MAIN_WITH_CODE_SRC: FastString = ascii_str!(
- r#"
-import { b } from "/b.js";
-import { c } from "/c.js";
-if (b() != 'b') throw Error();
-if (c() != 'c') throw Error();
-if (!import.meta.main) throw Error();
-if (import.meta.url != 'file:///main_with_code.js') throw Error();
-"#
- );
-
- let loader = MockLoader::new();
- let loads = loader.loads.clone();
- let mut runtime = JsRuntime::new(RuntimeOptions {
- module_loader: Some(loader),
- ..Default::default()
- });
- // In default resolution code should be empty.
- // Instead we explicitly pass in our own code.
- // The behavior should be very similar to /a.js.
- let spec = resolve_url("file:///main_with_code.js").unwrap();
- let main_id_fut = runtime
- .load_main_module(&spec, Some(MAIN_WITH_CODE_SRC))
- .boxed_local();
- let main_id = futures::executor::block_on(main_id_fut).unwrap();
-
- #[allow(clippy::let_underscore_future)]
- let _ = runtime.mod_evaluate(main_id);
- futures::executor::block_on(runtime.run_event_loop(false)).unwrap();
-
- let l = loads.lock();
- assert_eq!(
- l.to_vec(),
- vec!["file:///b.js", "file:///c.js", "file:///d.js"]
- );
-
- let module_map_rc = runtime.module_map();
- let modules = module_map_rc.borrow();
-
- assert_eq!(
- modules.get_id(
- "file:///main_with_code.js",
- AssertedModuleType::JavaScriptOrWasm
- ),
- Some(main_id)
- );
- let b_id = modules
- .get_id("file:///b.js", AssertedModuleType::JavaScriptOrWasm)
- .unwrap();
- let c_id = modules
- .get_id("file:///c.js", AssertedModuleType::JavaScriptOrWasm)
- .unwrap();
- let d_id = modules
- .get_id("file:///d.js", AssertedModuleType::JavaScriptOrWasm)
- .unwrap();
-
- assert_eq!(
- modules.get_requested_modules(main_id),
- Some(&vec![
- ModuleRequest {
- specifier: "file:///b.js".to_string(),
- asserted_module_type: AssertedModuleType::JavaScriptOrWasm,
- },
- ModuleRequest {
- specifier: "file:///c.js".to_string(),
- asserted_module_type: AssertedModuleType::JavaScriptOrWasm,
- }
- ])
- );
- assert_eq!(
- modules.get_requested_modules(b_id),
- Some(&vec![ModuleRequest {
- specifier: "file:///c.js".to_string(),
- asserted_module_type: AssertedModuleType::JavaScriptOrWasm,
- }])
- );
- assert_eq!(
- modules.get_requested_modules(c_id),
- Some(&vec![ModuleRequest {
- specifier: "file:///d.js".to_string(),
- asserted_module_type: AssertedModuleType::JavaScriptOrWasm,
- }])
- );
- assert_eq!(modules.get_requested_modules(d_id), Some(&vec![]));
-}
-
-#[test]
-fn main_and_side_module() {
- struct ModsLoader {}
-
- let main_specifier = resolve_url("file:///main_module.js").unwrap();
- let side_specifier = resolve_url("file:///side_module.js").unwrap();
-
- impl ModuleLoader for ModsLoader {
- fn resolve(
- &self,
- specifier: &str,
- referrer: &str,
- _kind: ResolutionKind,
- ) -> Result<ModuleSpecifier, Error> {
- let s = resolve_import(specifier, referrer).unwrap();
- Ok(s)
- }
-
- fn load(
- &self,
- module_specifier: &ModuleSpecifier,
- _maybe_referrer: Option<&ModuleSpecifier>,
- _is_dyn_import: bool,
- ) -> Pin<Box<ModuleSourceFuture>> {
- let module_source = match module_specifier.as_str() {
- "file:///main_module.js" => ModuleSource::for_test(
- "if (!import.meta.main) throw Error();",
- "file:///main_module.js",
- ),
- "file:///side_module.js" => ModuleSource::for_test(
- "if (import.meta.main) throw Error();",
- "file:///side_module.js",
- ),
- _ => unreachable!(),
- };
- async move { Ok(module_source) }.boxed()
- }
- }
-
- let loader = Rc::new(ModsLoader {});
- let mut runtime = JsRuntime::new(RuntimeOptions {
- module_loader: Some(loader),
- ..Default::default()
- });
-
- let main_id_fut = runtime
- .load_main_module(&main_specifier, None)
- .boxed_local();
- let main_id = futures::executor::block_on(main_id_fut).unwrap();
-
- #[allow(clippy::let_underscore_future)]
- let _ = runtime.mod_evaluate(main_id);
- futures::executor::block_on(runtime.run_event_loop(false)).unwrap();
-
- // Try to add another main module - it should error.
- let side_id_fut = runtime
- .load_main_module(&side_specifier, None)
- .boxed_local();
- futures::executor::block_on(side_id_fut).unwrap_err();
-
- // And now try to load it as a side module
- let side_id_fut = runtime
- .load_side_module(&side_specifier, None)
- .boxed_local();
- let side_id = futures::executor::block_on(side_id_fut).unwrap();
-
- #[allow(clippy::let_underscore_future)]
- let _ = runtime.mod_evaluate(side_id);
- futures::executor::block_on(runtime.run_event_loop(false)).unwrap();
-}
-
-#[test]
-fn dynamic_imports_snapshot() {
- //TODO: Once the issue with the ModuleNamespaceEntryGetter is fixed, we can maintain a reference to the module
- // and use it when loading the snapshot
- let snapshot = {
- const MAIN_WITH_CODE_SRC: FastString = ascii_str!(
- r#"
- await import("./b.js");
- "#
- );
-
- let loader = MockLoader::new();
- let mut runtime = JsRuntimeForSnapshot::new(
- RuntimeOptions {
- module_loader: Some(loader),
- ..Default::default()
- },
- Default::default(),
- );
- // In default resolution code should be empty.
- // Instead we explicitly pass in our own code.
- // The behavior should be very similar to /a.js.
- let spec = resolve_url("file:///main_with_code.js").unwrap();
- let main_id_fut = runtime
- .load_main_module(&spec, Some(MAIN_WITH_CODE_SRC))
- .boxed_local();
- let main_id = futures::executor::block_on(main_id_fut).unwrap();
-
- #[allow(clippy::let_underscore_future)]
- let _ = runtime.mod_evaluate(main_id);
- futures::executor::block_on(runtime.run_event_loop(false)).unwrap();
- runtime.snapshot()
- };
-
- let snapshot = Snapshot::JustCreated(snapshot);
- let mut runtime2 = JsRuntime::new(RuntimeOptions {
- startup_snapshot: Some(snapshot),
- ..Default::default()
- });
-
- //Evaluate the snapshot with an empty function
- runtime2.execute_script_static("check.js", "true").unwrap();
-}
-
-#[test]
-fn import_meta_snapshot() {
- let snapshot = {
- const MAIN_WITH_CODE_SRC: ModuleCode = ascii_str!(
- r#"
- if (import.meta.url != 'file:///main_with_code.js') throw Error();
- globalThis.meta = import.meta;
- globalThis.url = import.meta.url;
- "#
- );
-
- let loader = MockLoader::new();
- let mut runtime = JsRuntimeForSnapshot::new(
- RuntimeOptions {
- module_loader: Some(loader),
- ..Default::default()
- },
- Default::default(),
- );
- // In default resolution code should be empty.
- // Instead we explicitly pass in our own code.
- // The behavior should be very similar to /a.js.
- let spec = resolve_url("file:///main_with_code.js").unwrap();
- let main_id_fut = runtime
- .load_main_module(&spec, Some(MAIN_WITH_CODE_SRC))
- .boxed_local();
- let main_id = futures::executor::block_on(main_id_fut).unwrap();
-
- #[allow(clippy::let_underscore_future)]
- let _ = runtime.mod_evaluate(main_id);
- futures::executor::block_on(runtime.run_event_loop(false)).unwrap();
- runtime.snapshot()
- };
-
- let snapshot = Snapshot::JustCreated(snapshot);
- let mut runtime2 = JsRuntime::new(RuntimeOptions {
- startup_snapshot: Some(snapshot),
- ..Default::default()
- });
-
- runtime2
- .execute_script_static(
- "check.js",
- "if (globalThis.url !== 'file:///main_with_code.js') throw Error('x')",
- )
- .unwrap();
-}
diff --git a/core/normalize_path.rs b/core/normalize_path.rs
deleted file mode 100644
index 43af6fea6..000000000
--- a/core/normalize_path.rs
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-
-use std::path::Component;
-use std::path::Path;
-use std::path::PathBuf;
-
-/// Normalize all intermediate components of the path (ie. remove "./" and "../" components).
-/// Similar to `fs::canonicalize()` but doesn't resolve symlinks.
-///
-/// Taken from Cargo
-/// <https://github.com/rust-lang/cargo/blob/af307a38c20a753ec60f0ad18be5abed3db3c9ac/src/cargo/util/paths.rs#L60-L85>
-#[inline]
-pub fn normalize_path<P: AsRef<Path>>(path: P) -> PathBuf {
- let mut components = path.as_ref().components().peekable();
- let mut ret =
- if let Some(c @ Component::Prefix(..)) = components.peek().cloned() {
- components.next();
- PathBuf::from(c.as_os_str())
- } else {
- PathBuf::new()
- };
-
- for component in components {
- match component {
- Component::Prefix(..) => unreachable!(),
- Component::RootDir => {
- ret.push(component.as_os_str());
- }
- Component::CurDir => {}
- Component::ParentDir => {
- ret.pop();
- }
- Component::Normal(c) => {
- ret.push(c);
- }
- }
- }
- ret
-}
diff --git a/core/ops.rs b/core/ops.rs
deleted file mode 100644
index 7d4bc1e7d..000000000
--- a/core/ops.rs
+++ /dev/null
@@ -1,234 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-
-use crate::error::AnyError;
-use crate::error::GetErrorClassFn;
-use crate::gotham_state::GothamState;
-use crate::resources::ResourceTable;
-use crate::runtime::ContextState;
-use crate::runtime::JsRuntimeState;
-use crate::OpDecl;
-use crate::OpsTracker;
-use anyhow::Error;
-use futures::task::AtomicWaker;
-use futures::Future;
-use pin_project::pin_project;
-use serde::Serialize;
-use std::cell::RefCell;
-use std::cell::UnsafeCell;
-use std::ops::Deref;
-use std::ops::DerefMut;
-use std::ptr::NonNull;
-use std::rc::Rc;
-use std::rc::Weak;
-use std::sync::Arc;
-use v8::fast_api::CFunctionInfo;
-use v8::fast_api::CTypeInfo;
-use v8::fast_api::Int64Representation;
-
-pub type PromiseId = i32;
-pub type OpId = u16;
-
-#[pin_project]
-pub struct OpCall<F: Future<Output = OpResult>> {
- promise_id: PromiseId,
- op_id: OpId,
- /// Future is not necessarily Unpin, so we need to pin_project.
- #[pin]
- fut: F,
-}
-
-impl<F: Future<Output = OpResult>> OpCall<F> {
- /// Wraps a future; the inner future is polled the usual way (lazily).
- pub fn new(op_ctx: &OpCtx, promise_id: PromiseId, fut: F) -> Self {
- Self {
- op_id: op_ctx.id,
- promise_id,
- fut,
- }
- }
-}
-
-impl<F: Future<Output = OpResult>> Future for OpCall<F> {
- type Output = (PromiseId, OpId, OpResult);
-
- fn poll(
- self: std::pin::Pin<&mut Self>,
- cx: &mut std::task::Context<'_>,
- ) -> std::task::Poll<Self::Output> {
- let promise_id = self.promise_id;
- let op_id = self.op_id;
- let fut = self.project().fut;
- fut.poll(cx).map(move |res| (promise_id, op_id, res))
- }
-}
-
-pub enum OpResult {
- Ok(serde_v8::SerializablePkg),
- Err(OpError),
-}
-
-impl OpResult {
- pub fn to_v8<'a>(
- &mut self,
- scope: &mut v8::HandleScope<'a>,
- ) -> Result<v8::Local<'a, v8::Value>, serde_v8::Error> {
- match self {
- Self::Ok(x) => x.to_v8(scope),
- Self::Err(err) => serde_v8::to_v8(scope, err),
- }
- }
-}
-
-#[derive(Debug, Serialize)]
-#[serde(rename_all = "camelCase")]
-pub struct OpError {
- #[serde(rename = "$err_class_name")]
- class_name: &'static str,
- message: String,
- code: Option<&'static str>,
-}
-
-impl OpError {
- pub fn new(get_class: GetErrorClassFn, err: Error) -> Self {
- Self {
- class_name: (get_class)(&err),
- message: format!("{err:#}"),
- code: crate::error_codes::get_error_code(&err),
- }
- }
-}
-
-pub fn to_op_result<R: Serialize + 'static>(
- get_class: GetErrorClassFn,
- result: Result<R, Error>,
-) -> OpResult {
- match result {
- Ok(v) => OpResult::Ok(v.into()),
- Err(err) => OpResult::Err(OpError::new(get_class, err)),
- }
-}
-
-/// Per-op context.
-///
-// Note: We don't worry too much about the size of this struct because it's allocated once per realm, and is
-// stored in a contiguous array.
-pub struct OpCtx {
- pub id: OpId,
- pub state: Rc<RefCell<OpState>>,
- pub decl: Rc<OpDecl>,
- pub fast_fn_c_info: Option<NonNull<v8::fast_api::CFunctionInfo>>,
- pub runtime_state: Weak<RefCell<JsRuntimeState>>,
- pub(crate) context_state: Rc<RefCell<ContextState>>,
- /// If the last fast op failed, stores the error to be picked up by the slow op.
- pub(crate) last_fast_error: UnsafeCell<Option<AnyError>>,
-}
-
-impl OpCtx {
- pub(crate) fn new(
- id: OpId,
- context_state: Rc<RefCell<ContextState>>,
- decl: Rc<OpDecl>,
- state: Rc<RefCell<OpState>>,
- runtime_state: Weak<RefCell<JsRuntimeState>>,
- ) -> Self {
- let mut fast_fn_c_info = None;
-
- if let Some(fast_fn) = &decl.fast_fn {
- let args = CTypeInfo::new_from_slice(fast_fn.args);
- let ret = CTypeInfo::new(fast_fn.return_type);
-
- // SAFETY: all arguments are coming from the trait and they have
- // static lifetime
- let c_fn = unsafe {
- CFunctionInfo::new(
- args.as_ptr(),
- fast_fn.args.len(),
- ret.as_ptr(),
- // TODO(bartlomieju): in the future we might want to change it
- // to use BigInt representation.
- Int64Representation::Number,
- )
- };
- fast_fn_c_info = Some(c_fn);
- }
-
- OpCtx {
- id,
- state,
- runtime_state,
- decl,
- context_state,
- fast_fn_c_info,
- last_fast_error: UnsafeCell::new(None),
- }
- }
-
- /// This takes the last error from an [`OpCtx`], assuming that no other code anywhere
- /// can hold a `&mut` to the last_fast_error field.
- ///
- /// # Safety
- ///
- /// Must only be called from op implementations.
- #[inline(always)]
- pub unsafe fn unsafely_take_last_error_for_ops_only(
- &self,
- ) -> Option<AnyError> {
- let opt_mut = &mut *self.last_fast_error.get();
- opt_mut.take()
- }
-
- /// This set the last error for an [`OpCtx`], assuming that no other code anywhere
- /// can hold a `&mut` to the last_fast_error field.
- ///
- /// # Safety
- ///
- /// Must only be called from op implementations.
- #[inline(always)]
- pub unsafe fn unsafely_set_last_error_for_ops_only(&self, error: AnyError) {
- let opt_mut = &mut *self.last_fast_error.get();
- *opt_mut = Some(error);
- }
-}
-
-/// Maintains the resources and ops inside a JS runtime.
-pub struct OpState {
- pub resource_table: ResourceTable,
- pub get_error_class_fn: GetErrorClassFn,
- pub tracker: OpsTracker,
- pub last_fast_op_error: Option<AnyError>,
- pub(crate) gotham_state: GothamState,
- pub waker: Arc<AtomicWaker>,
-}
-
-impl OpState {
- pub fn new(ops_count: usize) -> OpState {
- OpState {
- resource_table: Default::default(),
- get_error_class_fn: &|_| "Error",
- gotham_state: Default::default(),
- last_fast_op_error: None,
- tracker: OpsTracker::new(ops_count),
- waker: Arc::new(AtomicWaker::new()),
- }
- }
-
- /// Clear all user-provided resources and state.
- pub(crate) fn clear(&mut self) {
- std::mem::take(&mut self.gotham_state);
- std::mem::take(&mut self.resource_table);
- }
-}
-
-impl Deref for OpState {
- type Target = GothamState;
-
- fn deref(&self) -> &Self::Target {
- &self.gotham_state
- }
-}
-
-impl DerefMut for OpState {
- fn deref_mut(&mut self) -> &mut Self::Target {
- &mut self.gotham_state
- }
-}
diff --git a/core/ops_builtin.rs b/core/ops_builtin.rs
deleted file mode 100644
index eeb753d5a..000000000
--- a/core/ops_builtin.rs
+++ /dev/null
@@ -1,369 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-use crate::error::format_file_name;
-use crate::error::type_error;
-use crate::io::BufMutView;
-use crate::io::BufView;
-use crate::ops_builtin_v8;
-use crate::ops_metrics::OpMetrics;
-use crate::resources::ResourceId;
-use crate::JsBuffer;
-use crate::OpState;
-use crate::Resource;
-use anyhow::Error;
-use deno_ops::op;
-use deno_ops::op2;
-use serde_v8::ToJsBuffer;
-use std::cell::RefCell;
-use std::io::stderr;
-use std::io::stdout;
-use std::io::Write;
-use std::rc::Rc;
-
-crate::extension!(
- core,
- ops = [
- op_close,
- op_try_close,
- op_print,
- op_resources,
- op_wasm_streaming_feed,
- op_wasm_streaming_set_url,
- op_void_sync,
- op_error_async,
- op_error_async_deferred,
- op_void_async,
- op_void_async_deferred,
- op_add,
- op_add_async,
- // TODO(@AaronO): track IO metrics for builtin streams
- op_read,
- op_read_all,
- op_write,
- op_read_sync,
- op_write_sync,
- op_write_all,
- op_shutdown,
- op_metrics,
- op_format_file_name,
- op_is_proxy,
- op_str_byte_length,
- ops_builtin_v8::op_ref_op,
- ops_builtin_v8::op_unref_op,
- ops_builtin_v8::op_set_promise_reject_callback,
- ops_builtin_v8::op_run_microtasks,
- ops_builtin_v8::op_has_tick_scheduled,
- ops_builtin_v8::op_set_has_tick_scheduled,
- ops_builtin_v8::op_eval_context,
- ops_builtin_v8::op_queue_microtask,
- ops_builtin_v8::op_create_host_object,
- ops_builtin_v8::op_encode,
- ops_builtin_v8::op_decode,
- ops_builtin_v8::op_serialize,
- ops_builtin_v8::op_deserialize,
- ops_builtin_v8::op_set_promise_hooks,
- ops_builtin_v8::op_get_promise_details,
- ops_builtin_v8::op_get_proxy_details,
- ops_builtin_v8::op_get_non_index_property_names,
- ops_builtin_v8::op_get_constructor_name,
- ops_builtin_v8::op_memory_usage,
- ops_builtin_v8::op_set_wasm_streaming_callback,
- ops_builtin_v8::op_abort_wasm_streaming,
- ops_builtin_v8::op_destructure_error,
- ops_builtin_v8::op_dispatch_exception,
- ops_builtin_v8::op_op_names,
- ops_builtin_v8::op_apply_source_map,
- ops_builtin_v8::op_set_format_exception_callback,
- ops_builtin_v8::op_event_loop_has_more_work,
- ops_builtin_v8::op_store_pending_promise_rejection,
- ops_builtin_v8::op_remove_pending_promise_rejection,
- ops_builtin_v8::op_has_pending_promise_rejection,
- ops_builtin_v8::op_arraybuffer_was_detached,
- ],
-);
-
-/// Return map of resources with id as key
-/// and string representation as value.
-#[op]
-pub fn op_resources(state: &mut OpState) -> Vec<(ResourceId, String)> {
- state
- .resource_table
- .names()
- .map(|(rid, name)| (rid, name.to_string()))
- .collect()
-}
-
-#[op2(core, fast)]
-fn op_add(a: i32, b: i32) -> i32 {
- a + b
-}
-
-#[op]
-pub async fn op_add_async(a: i32, b: i32) -> i32 {
- a + b
-}
-
-#[op(fast)]
-pub fn op_void_sync() {}
-
-#[op]
-pub async fn op_void_async() {}
-
-#[op]
-pub async fn op_error_async() -> Result<(), Error> {
- Err(Error::msg("error"))
-}
-
-#[op(deferred)]
-pub async fn op_error_async_deferred() -> Result<(), Error> {
- Err(Error::msg("error"))
-}
-
-#[op(deferred)]
-pub async fn op_void_async_deferred() {}
-
-/// Remove a resource from the resource table.
-#[op]
-pub fn op_close(
- state: &mut OpState,
- rid: Option<ResourceId>,
-) -> Result<(), Error> {
- // TODO(@AaronO): drop Option after improving type-strictness balance in
- // serde_v8
- let rid = rid.ok_or_else(|| type_error("missing or invalid `rid`"))?;
- state.resource_table.close(rid)?;
- Ok(())
-}
-
-/// Try to remove a resource from the resource table. If there is no resource
-/// with the specified `rid`, this is a no-op.
-#[op]
-pub fn op_try_close(
- state: &mut OpState,
- rid: Option<ResourceId>,
-) -> Result<(), Error> {
- // TODO(@AaronO): drop Option after improving type-strictness balance in
- // serde_v8.
- let rid = rid.ok_or_else(|| type_error("missing or invalid `rid`"))?;
- let _ = state.resource_table.close(rid);
- Ok(())
-}
-
-#[op]
-pub fn op_metrics(state: &mut OpState) -> (OpMetrics, Vec<OpMetrics>) {
- let aggregate = state.tracker.aggregate();
- let per_op = state.tracker.per_op();
- (aggregate, per_op)
-}
-
-/// Builtin utility to print to stdout/stderr
-#[op]
-pub fn op_print(msg: &str, is_err: bool) -> Result<(), Error> {
- if is_err {
- stderr().write_all(msg.as_bytes())?;
- stderr().flush().unwrap();
- } else {
- stdout().write_all(msg.as_bytes())?;
- stdout().flush().unwrap();
- }
- Ok(())
-}
-
-pub struct WasmStreamingResource(pub(crate) RefCell<v8::WasmStreaming>);
-
-impl Resource for WasmStreamingResource {
- fn close(self: Rc<Self>) {
- // At this point there are no clones of Rc<WasmStreamingResource> on the
- // resource table, and no one should own a reference outside of the stack.
- // Therefore, we can be sure `self` is the only reference.
- if let Ok(wsr) = Rc::try_unwrap(self) {
- wsr.0.into_inner().finish();
- } else {
- panic!("Couldn't consume WasmStreamingResource.");
- }
- }
-}
-
-/// Feed bytes to WasmStreamingResource.
-#[op]
-pub fn op_wasm_streaming_feed(
- state: &mut OpState,
- rid: ResourceId,
- bytes: &[u8],
-) -> Result<(), Error> {
- let wasm_streaming =
- state.resource_table.get::<WasmStreamingResource>(rid)?;
-
- wasm_streaming.0.borrow_mut().on_bytes_received(bytes);
-
- Ok(())
-}
-
-#[op]
-pub fn op_wasm_streaming_set_url(
- state: &mut OpState,
- rid: ResourceId,
- url: &str,
-) -> Result<(), Error> {
- let wasm_streaming =
- state.resource_table.get::<WasmStreamingResource>(rid)?;
-
- wasm_streaming.0.borrow_mut().set_url(url);
-
- Ok(())
-}
-
-#[op]
-async fn op_read(
- state: Rc<RefCell<OpState>>,
- rid: ResourceId,
- buf: JsBuffer,
-) -> Result<u32, Error> {
- let resource = state.borrow().resource_table.get_any(rid)?;
- let view = BufMutView::from(buf);
- resource.read_byob(view).await.map(|(n, _)| n as u32)
-}
-
-#[op]
-async fn op_read_all(
- state: Rc<RefCell<OpState>>,
- rid: ResourceId,
-) -> Result<ToJsBuffer, Error> {
- let resource = state.borrow().resource_table.get_any(rid)?;
-
- // The number of bytes we attempt to grow the buffer by each time it fills
- // up and we have more data to read. We start at 64 KB. The grow_len is
- // doubled if the nread returned from a single read is equal or greater than
- // the grow_len. This allows us to reduce allocations for resources that can
- // read large chunks of data at a time.
- let mut grow_len: usize = 64 * 1024;
-
- let (min, maybe_max) = resource.size_hint();
- // Try to determine an optimal starting buffer size for this resource based
- // on the size hint.
- let initial_size = match (min, maybe_max) {
- (min, Some(max)) if min == max => min as usize,
- (_min, Some(max)) if (max as usize) < grow_len => max as usize,
- (min, _) if (min as usize) < grow_len => grow_len,
- (min, _) => min as usize,
- };
-
- let mut buf = BufMutView::new(initial_size);
- loop {
- // if the buffer does not have much remaining space, we may have to grow it.
- if buf.len() < grow_len {
- let vec = buf.get_mut_vec();
- match maybe_max {
- Some(max) if vec.len() >= max as usize => {
- // no need to resize the vec, because the vec is already large enough
- // to accommodate the maximum size of the read data.
- }
- Some(max) if (max as usize) < vec.len() + grow_len => {
- // grow the vec to the maximum size of the read data
- vec.resize(max as usize, 0);
- }
- _ => {
- // grow the vec by grow_len
- vec.resize(vec.len() + grow_len, 0);
- }
- }
- }
- let (n, new_buf) = resource.clone().read_byob(buf).await?;
- buf = new_buf;
- buf.advance_cursor(n);
- if n == 0 {
- break;
- }
- if n >= grow_len {
- // we managed to read more or equal data than fits in a single grow_len in
- // a single go, so let's attempt to read even more next time. this reduces
- // allocations for resources that can read large chunks of data at a time.
- grow_len *= 2;
- }
- }
-
- let nread = buf.reset_cursor();
- let mut vec = buf.unwrap_vec();
- // If the buffer is larger than the amount of data read, shrink it to the
- // amount of data read.
- if nread < vec.len() {
- vec.truncate(nread);
- }
-
- Ok(ToJsBuffer::from(vec))
-}
-
-#[op]
-async fn op_write(
- state: Rc<RefCell<OpState>>,
- rid: ResourceId,
- buf: JsBuffer,
-) -> Result<u32, Error> {
- let resource = state.borrow().resource_table.get_any(rid)?;
- let view = BufView::from(buf);
- let resp = resource.write(view).await?;
- Ok(resp.nwritten() as u32)
-}
-
-#[op(fast)]
-fn op_read_sync(
- state: &mut OpState,
- rid: ResourceId,
- data: &mut [u8],
-) -> Result<u32, Error> {
- let resource = state.resource_table.get_any(rid)?;
- resource.read_byob_sync(data).map(|n| n as u32)
-}
-
-#[op]
-fn op_write_sync(
- state: &mut OpState,
- rid: ResourceId,
- data: &[u8],
-) -> Result<u32, Error> {
- let resource = state.resource_table.get_any(rid)?;
- let nwritten = resource.write_sync(data)?;
- Ok(nwritten as u32)
-}
-
-#[op]
-async fn op_write_all(
- state: Rc<RefCell<OpState>>,
- rid: ResourceId,
- buf: JsBuffer,
-) -> Result<(), Error> {
- let resource = state.borrow().resource_table.get_any(rid)?;
- let view = BufView::from(buf);
- resource.write_all(view).await?;
- Ok(())
-}
-
-#[op]
-async fn op_shutdown(
- state: Rc<RefCell<OpState>>,
- rid: ResourceId,
-) -> Result<(), Error> {
- let resource = state.borrow().resource_table.get_any(rid)?;
- resource.shutdown().await
-}
-
-#[op]
-fn op_format_file_name(file_name: String) -> String {
- format_file_name(&file_name)
-}
-
-#[op(fast)]
-fn op_is_proxy(value: serde_v8::Value) -> bool {
- value.v8_value.is_proxy()
-}
-
-#[op(v8)]
-fn op_str_byte_length(
- scope: &mut v8::HandleScope,
- value: serde_v8::Value,
-) -> u32 {
- if let Ok(string) = v8::Local::<v8::String>::try_from(value.v8_value) {
- string.utf8_length(scope) as u32
- } else {
- 0
- }
-}
diff --git a/core/ops_builtin_v8.rs b/core/ops_builtin_v8.rs
deleted file mode 100644
index 034a3810d..000000000
--- a/core/ops_builtin_v8.rs
+++ /dev/null
@@ -1,939 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-use crate::error::custom_error;
-use crate::error::is_instance_of_error;
-use crate::error::range_error;
-use crate::error::type_error;
-use crate::error::JsError;
-use crate::ops_builtin::WasmStreamingResource;
-use crate::resolve_url;
-use crate::runtime::script_origin;
-use crate::serde_v8::from_v8;
-use crate::source_map::apply_source_map;
-use crate::JsBuffer;
-use crate::JsRealm;
-use crate::JsRuntime;
-use crate::ToJsBuffer;
-use anyhow::Error;
-use deno_ops::op;
-use serde::Deserialize;
-use serde::Serialize;
-use std::cell::RefCell;
-use std::rc::Rc;
-use v8::ValueDeserializerHelper;
-use v8::ValueSerializerHelper;
-
-fn to_v8_fn(
- scope: &mut v8::HandleScope,
- value: serde_v8::Value,
-) -> Result<v8::Global<v8::Function>, Error> {
- v8::Local::<v8::Function>::try_from(value.v8_value)
- .map(|cb| v8::Global::new(scope, cb))
- .map_err(|err| type_error(err.to_string()))
-}
-
-#[inline]
-fn to_v8_local_fn(
- value: serde_v8::Value,
-) -> Result<v8::Local<v8::Function>, Error> {
- v8::Local::<v8::Function>::try_from(value.v8_value)
- .map_err(|err| type_error(err.to_string()))
-}
-
-#[op(v8)]
-fn op_ref_op(scope: &mut v8::HandleScope, promise_id: i32) {
- let context_state = JsRealm::state_from_scope(scope);
- context_state.borrow_mut().unrefed_ops.remove(&promise_id);
-}
-
-#[op(v8)]
-fn op_unref_op(scope: &mut v8::HandleScope, promise_id: i32) {
- let context_state = JsRealm::state_from_scope(scope);
- context_state.borrow_mut().unrefed_ops.insert(promise_id);
-}
-
-#[op(v8)]
-fn op_set_promise_reject_callback<'a>(
- scope: &mut v8::HandleScope<'a>,
- cb: serde_v8::Value,
-) -> Result<Option<serde_v8::Value<'a>>, Error> {
- let cb = to_v8_fn(scope, cb)?;
- let context_state_rc = JsRealm::state_from_scope(scope);
- let old = context_state_rc
- .borrow_mut()
- .js_promise_reject_cb
- .replace(Rc::new(cb));
- let old = old.map(|v| v8::Local::new(scope, &*v));
- Ok(old.map(|v| from_v8(scope, v.into()).unwrap()))
-}
-
-#[op(v8)]
-fn op_run_microtasks(scope: &mut v8::HandleScope) {
- scope.perform_microtask_checkpoint();
-}
-
-#[op(v8)]
-fn op_has_tick_scheduled(scope: &mut v8::HandleScope) -> bool {
- let state_rc = JsRuntime::state_from(scope);
- let state = state_rc.borrow();
- state.has_tick_scheduled
-}
-
-#[op(v8)]
-fn op_set_has_tick_scheduled(scope: &mut v8::HandleScope, v: bool) {
- let state_rc = JsRuntime::state_from(scope);
- state_rc.borrow_mut().has_tick_scheduled = v;
-}
-
-#[derive(Serialize)]
-#[serde(rename_all = "camelCase")]
-struct EvalContextError<'s> {
- thrown: serde_v8::Value<'s>,
- is_native_error: bool,
- is_compile_error: bool,
-}
-
-#[derive(Serialize)]
-struct EvalContextResult<'s>(
- Option<serde_v8::Value<'s>>,
- Option<EvalContextError<'s>>,
-);
-
-#[op(v8)]
-fn op_eval_context<'a>(
- scope: &mut v8::HandleScope<'a>,
- source: serde_v8::Value<'a>,
- specifier: String,
-) -> Result<EvalContextResult<'a>, Error> {
- let tc_scope = &mut v8::TryCatch::new(scope);
- let source = v8::Local::<v8::String>::try_from(source.v8_value)
- .map_err(|_| type_error("Invalid source"))?;
- let specifier = resolve_url(&specifier)?.to_string();
- let specifier = v8::String::new(tc_scope, &specifier).unwrap();
- let origin = script_origin(tc_scope, specifier);
-
- let script = match v8::Script::compile(tc_scope, source, Some(&origin)) {
- Some(s) => s,
- None => {
- assert!(tc_scope.has_caught());
- let exception = tc_scope.exception().unwrap();
- return Ok(EvalContextResult(
- None,
- Some(EvalContextError {
- thrown: exception.into(),
- is_native_error: is_instance_of_error(tc_scope, exception),
- is_compile_error: true,
- }),
- ));
- }
- };
-
- match script.run(tc_scope) {
- Some(result) => Ok(EvalContextResult(Some(result.into()), None)),
- None => {
- assert!(tc_scope.has_caught());
- let exception = tc_scope.exception().unwrap();
- Ok(EvalContextResult(
- None,
- Some(EvalContextError {
- thrown: exception.into(),
- is_native_error: is_instance_of_error(tc_scope, exception),
- is_compile_error: false,
- }),
- ))
- }
- }
-}
-
-#[op(v8)]
-fn op_queue_microtask(
- scope: &mut v8::HandleScope,
- cb: serde_v8::Value,
-) -> Result<(), Error> {
- scope.enqueue_microtask(to_v8_local_fn(cb)?);
- Ok(())
-}
-
-#[op(v8)]
-fn op_create_host_object<'a>(
- scope: &mut v8::HandleScope<'a>,
-) -> serde_v8::Value<'a> {
- let template = v8::ObjectTemplate::new(scope);
- template.set_internal_field_count(1);
- let object = template.new_instance(scope).unwrap();
- from_v8(scope, object.into()).unwrap()
-}
-
-#[op(v8)]
-fn op_encode<'a>(
- scope: &mut v8::HandleScope<'a>,
- text: serde_v8::Value<'a>,
-) -> Result<serde_v8::Value<'a>, Error> {
- let text = v8::Local::<v8::String>::try_from(text.v8_value)
- .map_err(|_| type_error("Invalid argument"))?;
- let text_str = serde_v8::to_utf8(text, scope);
- let bytes = text_str.into_bytes();
- let len = bytes.len();
- let backing_store =
- v8::ArrayBuffer::new_backing_store_from_vec(bytes).make_shared();
- let buffer = v8::ArrayBuffer::with_backing_store(scope, &backing_store);
- let u8array = v8::Uint8Array::new(scope, buffer, 0, len).unwrap();
- Ok((from_v8(scope, u8array.into()))?)
-}
-
-#[op(v8)]
-fn op_decode<'a>(
- scope: &mut v8::HandleScope<'a>,
- zero_copy: &[u8],
-) -> Result<serde_v8::Value<'a>, Error> {
- let buf = &zero_copy;
-
- // Strip BOM
- let buf =
- if buf.len() >= 3 && buf[0] == 0xef && buf[1] == 0xbb && buf[2] == 0xbf {
- &buf[3..]
- } else {
- buf
- };
-
- // If `String::new_from_utf8()` returns `None`, this means that the
- // length of the decoded string would be longer than what V8 can
- // handle. In this case we return `RangeError`.
- //
- // For more details see:
- // - https://encoding.spec.whatwg.org/#dom-textdecoder-decode
- // - https://github.com/denoland/deno/issues/6649
- // - https://github.com/v8/v8/blob/d68fb4733e39525f9ff0a9222107c02c28096e2a/include/v8.h#L3277-L3278
- match v8::String::new_from_utf8(scope, buf, v8::NewStringType::Normal) {
- Some(text) => Ok(from_v8(scope, text.into())?),
- None => Err(range_error("string too long")),
- }
-}
-
-struct SerializeDeserialize<'a> {
- host_objects: Option<v8::Local<'a, v8::Array>>,
- error_callback: Option<v8::Local<'a, v8::Function>>,
- for_storage: bool,
-}
-
-impl<'a> v8::ValueSerializerImpl for SerializeDeserialize<'a> {
- #[allow(unused_variables)]
- fn throw_data_clone_error<'s>(
- &mut self,
- scope: &mut v8::HandleScope<'s>,
- message: v8::Local<'s, v8::String>,
- ) {
- if let Some(cb) = self.error_callback {
- let scope = &mut v8::TryCatch::new(scope);
- let undefined = v8::undefined(scope).into();
- cb.call(scope, undefined, &[message.into()]);
- if scope.has_caught() || scope.has_terminated() {
- scope.rethrow();
- return;
- };
- }
- let error = v8::Exception::type_error(scope, message);
- scope.throw_exception(error);
- }
-
- fn get_shared_array_buffer_id<'s>(
- &mut self,
- scope: &mut v8::HandleScope<'s>,
- shared_array_buffer: v8::Local<'s, v8::SharedArrayBuffer>,
- ) -> Option<u32> {
- if self.for_storage {
- return None;
- }
- let state_rc = JsRuntime::state_from(scope);
- let state = state_rc.borrow_mut();
- if let Some(shared_array_buffer_store) = &state.shared_array_buffer_store {
- let backing_store = shared_array_buffer.get_backing_store();
- let id = shared_array_buffer_store.insert(backing_store);
- Some(id)
- } else {
- None
- }
- }
-
- fn get_wasm_module_transfer_id(
- &mut self,
- scope: &mut v8::HandleScope<'_>,
- module: v8::Local<v8::WasmModuleObject>,
- ) -> Option<u32> {
- if self.for_storage {
- let message = v8::String::new(scope, "Wasm modules cannot be stored")?;
- self.throw_data_clone_error(scope, message);
- return None;
- }
- let state_rc = JsRuntime::state_from(scope);
- let state = state_rc.borrow_mut();
- if let Some(compiled_wasm_module_store) = &state.compiled_wasm_module_store
- {
- let compiled_wasm_module = module.get_compiled_module();
- let id = compiled_wasm_module_store.insert(compiled_wasm_module);
- Some(id)
- } else {
- None
- }
- }
-
- fn write_host_object<'s>(
- &mut self,
- scope: &mut v8::HandleScope<'s>,
- object: v8::Local<'s, v8::Object>,
- value_serializer: &mut dyn v8::ValueSerializerHelper,
- ) -> Option<bool> {
- if let Some(host_objects) = self.host_objects {
- for i in 0..host_objects.length() {
- let value = host_objects.get_index(scope, i).unwrap();
- if value == object {
- value_serializer.write_uint32(i);
- return Some(true);
- }
- }
- }
- let message = v8::String::new(scope, "Unsupported object type").unwrap();
- self.throw_data_clone_error(scope, message);
- None
- }
-}
-
-impl<'a> v8::ValueDeserializerImpl for SerializeDeserialize<'a> {
- fn get_shared_array_buffer_from_id<'s>(
- &mut self,
- scope: &mut v8::HandleScope<'s>,
- transfer_id: u32,
- ) -> Option<v8::Local<'s, v8::SharedArrayBuffer>> {
- if self.for_storage {
- return None;
- }
- let state_rc = JsRuntime::state_from(scope);
- let state = state_rc.borrow_mut();
- if let Some(shared_array_buffer_store) = &state.shared_array_buffer_store {
- let backing_store = shared_array_buffer_store.take(transfer_id)?;
- let shared_array_buffer =
- v8::SharedArrayBuffer::with_backing_store(scope, &backing_store);
- Some(shared_array_buffer)
- } else {
- None
- }
- }
-
- fn get_wasm_module_from_id<'s>(
- &mut self,
- scope: &mut v8::HandleScope<'s>,
- clone_id: u32,
- ) -> Option<v8::Local<'s, v8::WasmModuleObject>> {
- if self.for_storage {
- return None;
- }
- let state_rc = JsRuntime::state_from(scope);
- let state = state_rc.borrow_mut();
- if let Some(compiled_wasm_module_store) = &state.compiled_wasm_module_store
- {
- let compiled_module = compiled_wasm_module_store.take(clone_id)?;
- v8::WasmModuleObject::from_compiled_module(scope, &compiled_module)
- } else {
- None
- }
- }
-
- fn read_host_object<'s>(
- &mut self,
- scope: &mut v8::HandleScope<'s>,
- value_deserializer: &mut dyn v8::ValueDeserializerHelper,
- ) -> Option<v8::Local<'s, v8::Object>> {
- if let Some(host_objects) = self.host_objects {
- let mut i = 0;
- if !value_deserializer.read_uint32(&mut i) {
- return None;
- }
- let maybe_value = host_objects.get_index(scope, i);
- if let Some(value) = maybe_value {
- return value.to_object(scope);
- }
- }
-
- let message: v8::Local<v8::String> =
- v8::String::new(scope, "Failed to deserialize host object").unwrap();
- let error = v8::Exception::error(scope, message);
- scope.throw_exception(error);
- None
- }
-}
-
-#[derive(Default, Deserialize)]
-#[serde(rename_all = "camelCase")]
-struct SerializeDeserializeOptions<'a> {
- host_objects: Option<serde_v8::Value<'a>>,
- transferred_array_buffers: Option<serde_v8::Value<'a>>,
- #[serde(default)]
- for_storage: bool,
-}
-
-#[op(v8)]
-fn op_serialize(
- scope: &mut v8::HandleScope,
- value: serde_v8::Value,
- options: Option<SerializeDeserializeOptions>,
- error_callback: Option<serde_v8::Value>,
-) -> Result<ToJsBuffer, Error> {
- let options = options.unwrap_or_default();
- let error_callback = match error_callback {
- Some(cb) => Some(
- v8::Local::<v8::Function>::try_from(cb.v8_value)
- .map_err(|_| type_error("Invalid error callback"))?,
- ),
- None => None,
- };
- let host_objects = match options.host_objects {
- Some(value) => Some(
- v8::Local::<v8::Array>::try_from(value.v8_value)
- .map_err(|_| type_error("hostObjects not an array"))?,
- ),
- None => None,
- };
- let transferred_array_buffers = match options.transferred_array_buffers {
- Some(value) => Some(
- v8::Local::<v8::Array>::try_from(value.v8_value)
- .map_err(|_| type_error("transferredArrayBuffers not an array"))?,
- ),
- None => None,
- };
-
- let serialize_deserialize = Box::new(SerializeDeserialize {
- host_objects,
- error_callback,
- for_storage: options.for_storage,
- });
- let mut value_serializer =
- v8::ValueSerializer::new(scope, serialize_deserialize);
- value_serializer.write_header();
-
- if let Some(transferred_array_buffers) = transferred_array_buffers {
- let state_rc = JsRuntime::state_from(scope);
- let state = state_rc.borrow_mut();
- for index in 0..transferred_array_buffers.length() {
- let i = v8::Number::new(scope, index as f64).into();
- let buf = transferred_array_buffers.get(scope, i).unwrap();
- let buf = v8::Local::<v8::ArrayBuffer>::try_from(buf).map_err(|_| {
- type_error("item in transferredArrayBuffers not an ArrayBuffer")
- })?;
- if let Some(shared_array_buffer_store) = &state.shared_array_buffer_store
- {
- if !buf.is_detachable() {
- return Err(type_error(
- "item in transferredArrayBuffers is not transferable",
- ));
- }
-
- if buf.was_detached() {
- return Err(custom_error(
- "DOMExceptionOperationError",
- format!("ArrayBuffer at index {index} is already detached"),
- ));
- }
-
- let backing_store = buf.get_backing_store();
- buf.detach(None);
- let id = shared_array_buffer_store.insert(backing_store);
- value_serializer.transfer_array_buffer(id, buf);
- let id = v8::Number::new(scope, id as f64).into();
- transferred_array_buffers.set(scope, i, id);
- }
- }
- }
-
- let scope = &mut v8::TryCatch::new(scope);
- let ret =
- value_serializer.write_value(scope.get_current_context(), value.v8_value);
- if scope.has_caught() || scope.has_terminated() {
- scope.rethrow();
- // Dummy value, this result will be discarded because an error was thrown.
- Ok(ToJsBuffer::empty())
- } else if let Some(true) = ret {
- let vector = value_serializer.release();
- Ok(vector.into())
- } else {
- Err(type_error("Failed to serialize response"))
- }
-}
-
-#[op(v8)]
-fn op_deserialize<'a>(
- scope: &mut v8::HandleScope<'a>,
- zero_copy: JsBuffer,
- options: Option<SerializeDeserializeOptions>,
-) -> Result<serde_v8::Value<'a>, Error> {
- let options = options.unwrap_or_default();
- let host_objects = match options.host_objects {
- Some(value) => Some(
- v8::Local::<v8::Array>::try_from(value.v8_value)
- .map_err(|_| type_error("hostObjects not an array"))?,
- ),
- None => None,
- };
- let transferred_array_buffers = match options.transferred_array_buffers {
- Some(value) => Some(
- v8::Local::<v8::Array>::try_from(value.v8_value)
- .map_err(|_| type_error("transferredArrayBuffers not an array"))?,
- ),
- None => None,
- };
-
- let serialize_deserialize = Box::new(SerializeDeserialize {
- host_objects,
- error_callback: None,
- for_storage: options.for_storage,
- });
- let mut value_deserializer =
- v8::ValueDeserializer::new(scope, serialize_deserialize, &zero_copy);
- let parsed_header = value_deserializer
- .read_header(scope.get_current_context())
- .unwrap_or_default();
- if !parsed_header {
- return Err(range_error("could not deserialize value"));
- }
-
- if let Some(transferred_array_buffers) = transferred_array_buffers {
- let state_rc = JsRuntime::state_from(scope);
- let state = state_rc.borrow_mut();
- if let Some(shared_array_buffer_store) = &state.shared_array_buffer_store {
- for i in 0..transferred_array_buffers.length() {
- let i = v8::Number::new(scope, i as f64).into();
- let id_val = transferred_array_buffers.get(scope, i).unwrap();
- let id = match id_val.number_value(scope) {
- Some(id) => id as u32,
- None => {
- return Err(type_error(
- "item in transferredArrayBuffers not number",
- ))
- }
- };
- if let Some(backing_store) = shared_array_buffer_store.take(id) {
- let array_buffer =
- v8::ArrayBuffer::with_backing_store(scope, &backing_store);
- value_deserializer.transfer_array_buffer(id, array_buffer);
- transferred_array_buffers.set(scope, id_val, array_buffer.into());
- } else {
- return Err(type_error(
- "transferred array buffer not present in shared_array_buffer_store",
- ));
- }
- }
- }
- }
-
- let value = value_deserializer.read_value(scope.get_current_context());
- match value {
- Some(deserialized) => Ok(deserialized.into()),
- None => Err(range_error("could not deserialize value")),
- }
-}
-
-#[derive(Serialize)]
-struct PromiseDetails<'s>(u32, Option<serde_v8::Value<'s>>);
-
-#[op(v8)]
-fn op_get_promise_details<'a>(
- scope: &mut v8::HandleScope<'a>,
- promise: serde_v8::Value<'a>,
-) -> Result<PromiseDetails<'a>, Error> {
- let promise = v8::Local::<v8::Promise>::try_from(promise.v8_value)
- .map_err(|_| type_error("Invalid argument"))?;
- match promise.state() {
- v8::PromiseState::Pending => Ok(PromiseDetails(0, None)),
- v8::PromiseState::Fulfilled => {
- Ok(PromiseDetails(1, Some(promise.result(scope).into())))
- }
- v8::PromiseState::Rejected => {
- Ok(PromiseDetails(2, Some(promise.result(scope).into())))
- }
- }
-}
-
-#[op(v8)]
-fn op_set_promise_hooks(
- scope: &mut v8::HandleScope,
- init_hook: serde_v8::Value,
- before_hook: serde_v8::Value,
- after_hook: serde_v8::Value,
- resolve_hook: serde_v8::Value,
-) -> Result<(), Error> {
- let v8_fns = [init_hook, before_hook, after_hook, resolve_hook]
- .into_iter()
- .enumerate()
- .filter(|(_, hook)| !hook.v8_value.is_undefined())
- .try_fold([None; 4], |mut v8_fns, (i, hook)| {
- let v8_fn = v8::Local::<v8::Function>::try_from(hook.v8_value)
- .map_err(|err| type_error(err.to_string()))?;
- v8_fns[i] = Some(v8_fn);
- Ok::<_, Error>(v8_fns)
- })?;
-
- scope.set_promise_hooks(
- v8_fns[0], // init
- v8_fns[1], // before
- v8_fns[2], // after
- v8_fns[3], // resolve
- );
-
- Ok(())
-}
-
-// Based on https://github.com/nodejs/node/blob/1e470510ff74391d7d4ec382909ea8960d2d2fbc/src/node_util.cc
-// Copyright Joyent, Inc. and other Node contributors.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a
-// copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to permit
-// persons to whom the Software is furnished to do so, subject to the
-// following conditions:
-//
-// The above copyright notice and this permission notice shall be included
-// in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
-// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
-// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
-// USE OR OTHER DEALINGS IN THE SOFTWARE.
-#[op(v8)]
-fn op_get_proxy_details<'a>(
- scope: &mut v8::HandleScope<'a>,
- proxy: serde_v8::Value<'a>,
-) -> Option<(serde_v8::Value<'a>, serde_v8::Value<'a>)> {
- let proxy = match v8::Local::<v8::Proxy>::try_from(proxy.v8_value) {
- Ok(proxy) => proxy,
- Err(_) => return None,
- };
- let target = proxy.get_target(scope);
- let handler = proxy.get_handler(scope);
- Some((target.into(), handler.into()))
-}
-
-#[op(v8)]
-fn op_get_non_index_property_names<'a>(
- scope: &mut v8::HandleScope<'a>,
- obj: serde_v8::Value<'a>,
- filter: u32,
-) -> Option<serde_v8::Value<'a>> {
- let obj = match v8::Local::<v8::Object>::try_from(obj.v8_value) {
- Ok(proxy) => proxy,
- Err(_) => return None,
- };
-
- let mut property_filter = v8::PropertyFilter::ALL_PROPERTIES;
- if filter & 1 == 1 {
- property_filter = property_filter | v8::PropertyFilter::ONLY_WRITABLE
- }
- if filter & 2 == 2 {
- property_filter = property_filter | v8::PropertyFilter::ONLY_ENUMERABLE
- }
- if filter & 4 == 4 {
- property_filter = property_filter | v8::PropertyFilter::ONLY_CONFIGURABLE
- }
- if filter & 8 == 8 {
- property_filter = property_filter | v8::PropertyFilter::SKIP_STRINGS
- }
- if filter & 16 == 16 {
- property_filter = property_filter | v8::PropertyFilter::SKIP_SYMBOLS
- }
-
- let maybe_names = obj.get_property_names(
- scope,
- v8::GetPropertyNamesArgs {
- mode: v8::KeyCollectionMode::OwnOnly,
- property_filter,
- index_filter: v8::IndexFilter::SkipIndices,
- ..Default::default()
- },
- );
-
- if let Some(names) = maybe_names {
- let names_val: v8::Local<v8::Value> = names.into();
- Some(names_val.into())
- } else {
- None
- }
-}
-
-#[op(v8)]
-fn op_get_constructor_name<'a>(
- scope: &mut v8::HandleScope<'a>,
- obj: serde_v8::Value<'a>,
-) -> Option<String> {
- let obj = match v8::Local::<v8::Object>::try_from(obj.v8_value) {
- Ok(proxy) => proxy,
- Err(_) => return None,
- };
-
- let name = obj.get_constructor_name().to_rust_string_lossy(scope);
- Some(name)
-}
-
-// HeapStats stores values from a isolate.get_heap_statistics() call
-#[derive(Serialize)]
-#[serde(rename_all = "camelCase")]
-struct MemoryUsage {
- physical_total: usize,
- heap_total: usize,
- heap_used: usize,
- external: usize,
- // TODO: track ArrayBuffers, would require using a custom allocator to track
- // but it's otherwise a subset of external so can be indirectly tracked
- // array_buffers: usize,
-}
-
-#[op(v8)]
-fn op_memory_usage(scope: &mut v8::HandleScope) -> MemoryUsage {
- let mut s = v8::HeapStatistics::default();
- scope.get_heap_statistics(&mut s);
- MemoryUsage {
- physical_total: s.total_physical_size(),
- heap_total: s.total_heap_size(),
- heap_used: s.used_heap_size(),
- external: s.external_memory(),
- }
-}
-
-#[op(v8)]
-fn op_set_wasm_streaming_callback(
- scope: &mut v8::HandleScope,
- cb: serde_v8::Value,
-) -> Result<(), Error> {
- let cb = to_v8_fn(scope, cb)?;
- let context_state_rc = JsRealm::state_from_scope(scope);
- let mut context_state = context_state_rc.borrow_mut();
- // The callback to pass to the v8 API has to be a unit type, so it can't
- // borrow or move any local variables. Therefore, we're storing the JS
- // callback in a JsRuntimeState slot.
- if context_state.js_wasm_streaming_cb.is_some() {
- return Err(type_error("op_set_wasm_streaming_callback already called"));
- }
- context_state.js_wasm_streaming_cb = Some(Rc::new(cb));
-
- scope.set_wasm_streaming_callback(|scope, arg, wasm_streaming| {
- let (cb_handle, streaming_rid) = {
- let context_state_rc = JsRealm::state_from_scope(scope);
- let cb_handle = context_state_rc
- .borrow()
- .js_wasm_streaming_cb
- .as_ref()
- .unwrap()
- .clone();
- let state_rc = JsRuntime::state_from(scope);
- let streaming_rid = state_rc
- .borrow()
- .op_state
- .borrow_mut()
- .resource_table
- .add(WasmStreamingResource(RefCell::new(wasm_streaming)));
- (cb_handle, streaming_rid)
- };
-
- let undefined = v8::undefined(scope);
- let rid = serde_v8::to_v8(scope, streaming_rid).unwrap();
- cb_handle
- .open(scope)
- .call(scope, undefined.into(), &[arg, rid]);
- });
- Ok(())
-}
-
-#[allow(clippy::let_and_return)]
-#[op(v8)]
-fn op_abort_wasm_streaming(
- scope: &mut v8::HandleScope,
- rid: u32,
- error: serde_v8::Value,
-) -> Result<(), Error> {
- let wasm_streaming = {
- let state_rc = JsRuntime::state_from(scope);
- let state = state_rc.borrow();
- let wsr = state
- .op_state
- .borrow_mut()
- .resource_table
- .take::<WasmStreamingResource>(rid)?;
- wsr
- };
-
- // At this point there are no clones of Rc<WasmStreamingResource> on the
- // resource table, and no one should own a reference because we're never
- // cloning them. So we can be sure `wasm_streaming` is the only reference.
- if let Ok(wsr) = std::rc::Rc::try_unwrap(wasm_streaming) {
- // NOTE: v8::WasmStreaming::abort can't be called while `state` is borrowed;
- // see https://github.com/denoland/deno/issues/13917
- wsr.0.into_inner().abort(Some(error.v8_value));
- } else {
- panic!("Couldn't consume WasmStreamingResource.");
- }
- Ok(())
-}
-
-#[op(v8)]
-fn op_destructure_error(
- scope: &mut v8::HandleScope,
- error: serde_v8::Value,
-) -> JsError {
- JsError::from_v8_exception(scope, error.v8_value)
-}
-
-/// Effectively throw an uncatchable error. This will terminate runtime
-/// execution before any more JS code can run, except in the REPL where it
-/// should just output the error to the console.
-#[op(v8)]
-fn op_dispatch_exception(
- scope: &mut v8::HandleScope,
- exception: serde_v8::Value,
-) {
- let state_rc = JsRuntime::state_from(scope);
- let mut state = state_rc.borrow_mut();
- if let Some(inspector) = &state.inspector {
- let inspector = inspector.borrow();
- inspector.exception_thrown(scope, exception.v8_value, false);
- // This indicates that the op is being called from a REPL. Skip termination.
- if inspector.is_dispatching_message() {
- return;
- }
- }
- state.dispatched_exception = Some(v8::Global::new(scope, exception.v8_value));
- scope.terminate_execution();
-}
-
-#[op(v8)]
-fn op_op_names(scope: &mut v8::HandleScope) -> Vec<String> {
- let state_rc = JsRealm::state_from_scope(scope);
- let state = state_rc.borrow();
- state
- .op_ctxs
- .iter()
- .map(|o| o.decl.name.to_string())
- .collect()
-}
-
-#[derive(Deserialize, Serialize)]
-#[serde(rename_all = "camelCase")]
-struct Location {
- file_name: String,
- line_number: u32,
- column_number: u32,
-}
-
-#[op(v8)]
-fn op_apply_source_map(
- scope: &mut v8::HandleScope,
- location: Location,
-) -> Result<Location, Error> {
- let state_rc = JsRuntime::state_from(scope);
- let (getter, cache) = {
- let state = state_rc.borrow();
- (
- state.source_map_getter.clone(),
- state.source_map_cache.clone(),
- )
- };
-
- if let Some(source_map_getter) = getter {
- let mut cache = cache.borrow_mut();
- let mut location = location;
- let (f, l, c) = apply_source_map(
- location.file_name,
- location.line_number.into(),
- location.column_number.into(),
- &mut cache,
- &**source_map_getter,
- );
- location.file_name = f;
- location.line_number = l as u32;
- location.column_number = c as u32;
- Ok(location)
- } else {
- Ok(location)
- }
-}
-
-/// Set a callback which formats exception messages as stored in
-/// `JsError::exception_message`. The callback is passed the error value and
-/// should return a string or `null`. If no callback is set or the callback
-/// returns `null`, the built-in default formatting will be used.
-#[op(v8)]
-fn op_set_format_exception_callback<'a>(
- scope: &mut v8::HandleScope<'a>,
- cb: serde_v8::Value<'a>,
-) -> Result<Option<serde_v8::Value<'a>>, Error> {
- let cb = to_v8_fn(scope, cb)?;
- let context_state_rc = JsRealm::state_from_scope(scope);
- let old = context_state_rc
- .borrow_mut()
- .js_format_exception_cb
- .replace(Rc::new(cb));
- let old = old.map(|v| v8::Local::new(scope, &*v));
- Ok(old.map(|v| from_v8(scope, v.into()).unwrap()))
-}
-
-#[op(v8)]
-fn op_event_loop_has_more_work(scope: &mut v8::HandleScope) -> bool {
- JsRuntime::event_loop_pending_state_from_scope(scope).is_pending()
-}
-
-#[op(v8)]
-fn op_store_pending_promise_rejection<'a>(
- scope: &mut v8::HandleScope<'a>,
- promise: serde_v8::Value<'a>,
- reason: serde_v8::Value<'a>,
-) {
- let context_state_rc = JsRealm::state_from_scope(scope);
- let mut context_state = context_state_rc.borrow_mut();
- let promise_value =
- v8::Local::<v8::Promise>::try_from(promise.v8_value).unwrap();
- let promise_global = v8::Global::new(scope, promise_value);
- let error_global = v8::Global::new(scope, reason.v8_value);
- context_state
- .pending_promise_rejections
- .push_back((promise_global, error_global));
-}
-
-#[op(v8)]
-fn op_remove_pending_promise_rejection<'a>(
- scope: &mut v8::HandleScope<'a>,
- promise: serde_v8::Value<'a>,
-) {
- let context_state_rc = JsRealm::state_from_scope(scope);
- let mut context_state = context_state_rc.borrow_mut();
- let promise_value =
- v8::Local::<v8::Promise>::try_from(promise.v8_value).unwrap();
- let promise_global = v8::Global::new(scope, promise_value);
- context_state
- .pending_promise_rejections
- .retain(|(key, _)| key != &promise_global);
-}
-
-#[op(v8)]
-fn op_has_pending_promise_rejection<'a>(
- scope: &mut v8::HandleScope<'a>,
- promise: serde_v8::Value<'a>,
-) -> bool {
- let context_state_rc = JsRealm::state_from_scope(scope);
- let context_state = context_state_rc.borrow();
- let promise_value =
- v8::Local::<v8::Promise>::try_from(promise.v8_value).unwrap();
- let promise_global = v8::Global::new(scope, promise_value);
- context_state
- .pending_promise_rejections
- .iter()
- .any(|(key, _)| key == &promise_global)
-}
-
-#[op(v8)]
-fn op_arraybuffer_was_detached<'a>(
- _scope: &mut v8::HandleScope<'a>,
- input: serde_v8::Value<'a>,
-) -> Result<bool, Error> {
- let ab = v8::Local::<v8::ArrayBuffer>::try_from(input.v8_value)?;
- Ok(ab.was_detached())
-}
diff --git a/core/ops_metrics.rs b/core/ops_metrics.rs
deleted file mode 100644
index b25368bd0..000000000
--- a/core/ops_metrics.rs
+++ /dev/null
@@ -1,91 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-
-use crate::serde::Serialize;
-use crate::OpId;
-use std::cell::RefCell;
-use std::cell::RefMut;
-
-// TODO(@AaronO): split into AggregateMetrics & PerOpMetrics
-#[derive(Clone, Default, Debug, Serialize)]
-#[serde(rename_all = "camelCase")]
-pub struct OpMetrics {
- pub ops_dispatched: u64,
- pub ops_dispatched_sync: u64,
- pub ops_dispatched_async: u64,
- // TODO(bartlomieju): this field is never updated
- pub ops_dispatched_async_unref: u64,
- pub ops_completed: u64,
- pub ops_completed_sync: u64,
- pub ops_completed_async: u64,
- // TODO(bartlomieju): this field is never updated
- pub ops_completed_async_unref: u64,
- pub bytes_sent_control: u64,
- pub bytes_sent_data: u64,
- pub bytes_received: u64,
-}
-
-// TODO(@AaronO): track errors
-#[derive(Default, Debug)]
-pub struct OpsTracker {
- ops: RefCell<Vec<OpMetrics>>,
-}
-
-impl OpsTracker {
- pub fn new(ops_count: usize) -> Self {
- Self {
- ops: RefCell::new(vec![Default::default(); ops_count]),
- }
- }
-
- pub fn per_op(&self) -> Vec<OpMetrics> {
- self.ops.borrow().clone()
- }
-
- pub fn aggregate(&self) -> OpMetrics {
- let mut sum = OpMetrics::default();
-
- for metrics in self.ops.borrow().iter() {
- sum.ops_dispatched += metrics.ops_dispatched;
- sum.ops_dispatched_sync += metrics.ops_dispatched_sync;
- sum.ops_dispatched_async += metrics.ops_dispatched_async;
- sum.ops_dispatched_async_unref += metrics.ops_dispatched_async_unref;
- sum.ops_completed += metrics.ops_completed;
- sum.ops_completed_sync += metrics.ops_completed_sync;
- sum.ops_completed_async += metrics.ops_completed_async;
- sum.ops_completed_async_unref += metrics.ops_completed_async_unref;
- sum.bytes_sent_control += metrics.bytes_sent_control;
- sum.bytes_sent_data += metrics.bytes_sent_data;
- sum.bytes_received += metrics.bytes_received;
- }
-
- sum
- }
-
- #[inline]
- fn metrics_mut(&self, id: OpId) -> RefMut<OpMetrics> {
- RefMut::map(self.ops.borrow_mut(), |ops| &mut ops[id as usize])
- }
-
- #[inline]
- pub fn track_sync(&self, id: OpId) {
- let mut metrics = self.metrics_mut(id);
- metrics.ops_dispatched += 1;
- metrics.ops_completed += 1;
- metrics.ops_dispatched_sync += 1;
- metrics.ops_completed_sync += 1;
- }
-
- #[inline]
- pub fn track_async(&self, id: OpId) {
- let mut metrics = self.metrics_mut(id);
- metrics.ops_dispatched += 1;
- metrics.ops_dispatched_async += 1;
- }
-
- #[inline]
- pub fn track_async_completed(&self, id: OpId) {
- let mut metrics = self.metrics_mut(id);
- metrics.ops_completed += 1;
- metrics.ops_completed_async += 1;
- }
-}
diff --git a/core/path.rs b/core/path.rs
deleted file mode 100644
index fd8b1a9b6..000000000
--- a/core/path.rs
+++ /dev/null
@@ -1,91 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-
-use std::path::PathBuf;
-
-#[cfg(not(windows))]
-#[inline]
-pub fn strip_unc_prefix(path: PathBuf) -> PathBuf {
- path
-}
-
-/// Strips the unc prefix (ex. \\?\) from Windows paths.
-#[cfg(windows)]
-pub fn strip_unc_prefix(path: PathBuf) -> PathBuf {
- use std::path::Component;
- use std::path::Prefix;
-
- let mut components = path.components();
- match components.next() {
- Some(Component::Prefix(prefix)) => {
- match prefix.kind() {
- // \\?\device
- Prefix::Verbatim(device) => {
- let mut path = PathBuf::new();
- path.push(format!(r"\\{}\", device.to_string_lossy()));
- path.extend(components.filter(|c| !matches!(c, Component::RootDir)));
- path
- }
- // \\?\c:\path
- Prefix::VerbatimDisk(_) => {
- let mut path = PathBuf::new();
- path.push(prefix.as_os_str().to_string_lossy().replace(r"\\?\", ""));
- path.extend(components);
- path
- }
- // \\?\UNC\hostname\share_name\path
- Prefix::VerbatimUNC(hostname, share_name) => {
- let mut path = PathBuf::new();
- path.push(format!(
- r"\\{}\{}\",
- hostname.to_string_lossy(),
- share_name.to_string_lossy()
- ));
- path.extend(components.filter(|c| !matches!(c, Component::RootDir)));
- path
- }
- _ => path,
- }
- }
- _ => path,
- }
-}
-
-#[cfg(test)]
-mod test {
- #[cfg(windows)]
- #[test]
- fn test_strip_unc_prefix() {
- use std::path::PathBuf;
-
- run_test(r"C:\", r"C:\");
- run_test(r"C:\test\file.txt", r"C:\test\file.txt");
-
- run_test(r"\\?\C:\", r"C:\");
- run_test(r"\\?\C:\test\file.txt", r"C:\test\file.txt");
-
- run_test(r"\\.\C:\", r"\\.\C:\");
- run_test(r"\\.\C:\Test\file.txt", r"\\.\C:\Test\file.txt");
-
- run_test(r"\\?\UNC\localhost\", r"\\localhost");
- run_test(r"\\?\UNC\localhost\c$\", r"\\localhost\c$");
- run_test(
- r"\\?\UNC\localhost\c$\Windows\file.txt",
- r"\\localhost\c$\Windows\file.txt",
- );
- run_test(r"\\?\UNC\wsl$\deno.json", r"\\wsl$\deno.json");
-
- run_test(r"\\?\server1", r"\\server1");
- run_test(r"\\?\server1\e$\", r"\\server1\e$\");
- run_test(
- r"\\?\server1\e$\test\file.txt",
- r"\\server1\e$\test\file.txt",
- );
-
- fn run_test(input: &str, expected: &str) {
- assert_eq!(
- super::strip_unc_prefix(PathBuf::from(input)),
- PathBuf::from(expected)
- );
- }
- }
-}
diff --git a/core/resources.rs b/core/resources.rs
deleted file mode 100644
index 94d2a2306..000000000
--- a/core/resources.rs
+++ /dev/null
@@ -1,429 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-
-// Think of Resources as File Descriptors. They are integers that are allocated
-// by the privileged side of Deno which refer to various rust objects that need
-// to be persisted between various ops. For example, network sockets are
-// resources. Resources may or may not correspond to a real operating system
-// file descriptor (hence the different name).
-
-use crate::error::bad_resource_id;
-use crate::error::not_supported;
-use crate::io::BufMutView;
-use crate::io::BufView;
-use crate::io::WriteOutcome;
-use anyhow::Error;
-use futures::Future;
-use std::any::type_name;
-use std::any::Any;
-use std::any::TypeId;
-use std::borrow::Cow;
-use std::collections::BTreeMap;
-use std::iter::Iterator;
-use std::pin::Pin;
-use std::rc::Rc;
-
-/// Returned by resource read/write/shutdown methods
-pub type AsyncResult<T> = Pin<Box<dyn Future<Output = Result<T, Error>>>>;
-
-/// Resources are Rust objects that are attached to a [deno_core::JsRuntime].
-/// They are identified in JS by a numeric ID (the resource ID, or rid).
-/// Resources can be created in ops. Resources can also be retrieved in ops by
-/// their rid. Resources are not thread-safe - they can only be accessed from
-/// the thread that the JsRuntime lives on.
-///
-/// Resources are reference counted in Rust. This means that they can be
-/// cloned and passed around. When the last reference is dropped, the resource
-/// is automatically closed. As long as the resource exists in the resource
-/// table, the reference count is at least 1.
-///
-/// ### Readable
-///
-/// Readable resources are resources that can have data read from. Examples of
-/// this are files, sockets, or HTTP streams.
-///
-/// Readables can be read from from either JS or Rust. In JS one can use
-/// `Deno.core.read()` to read from a single chunk of data from a readable. In
-/// Rust one can directly call `read()` or `read_byob()`. The Rust side code is
-/// used to implement ops like `op_slice`.
-///
-/// A distinction can be made between readables that produce chunks of data
-/// themselves (they allocate the chunks), and readables that fill up
-/// bring-your-own-buffers (BYOBs). The former is often the case for framed
-/// protocols like HTTP, while the latter is often the case for kernel backed
-/// resources like files and sockets.
-///
-/// All readables must implement `read()`. If resources can support an optimized
-/// path for BYOBs, they should also implement `read_byob()`. For kernel backed
-/// resources it often makes sense to implement `read_byob()` first, and then
-/// implement `read()` as an operation that allocates a new chunk with
-/// `len == limit`, then calls `read_byob()`, and then returns a chunk sliced to
-/// the number of bytes read. Kernel backed resources can use the
-/// [deno_core::impl_readable_byob] macro to implement optimized `read_byob()`
-/// and `read()` implementations from a single `Self::read()` method.
-///
-/// ### Writable
-///
-/// Writable resources are resources that can have data written to. Examples of
-/// this are files, sockets, or HTTP streams.
-///
-/// Writables can be written to from either JS or Rust. In JS one can use
-/// `Deno.core.write()` to write to a single chunk of data to a writable. In
-/// Rust one can directly call `write()`. The latter is used to implement ops
-/// like `op_slice`.
-pub trait Resource: Any + 'static {
- /// Returns a string representation of the resource which is made available
- /// to JavaScript code through `op_resources`. The default implementation
- /// returns the Rust type name, but specific resource types may override this
- /// trait method.
- fn name(&self) -> Cow<str> {
- type_name::<Self>().into()
- }
-
- /// Read a single chunk of data from the resource. This operation returns a
- /// `BufView` that represents the data that was read. If a zero length buffer
- /// is returned, it indicates that the resource has reached EOF.
- ///
- /// If this method is not implemented, the default implementation will error
- /// with a "not supported" error.
- ///
- /// If a readable can provide an optimized path for BYOBs, it should also
- /// implement `read_byob()`.
- fn read(self: Rc<Self>, limit: usize) -> AsyncResult<BufView> {
- _ = limit;
- Box::pin(futures::future::err(not_supported()))
- }
-
- /// Read a single chunk of data from the resource into the provided `BufMutView`.
- ///
- /// This operation returns the number of bytes read. If zero bytes are read,
- /// it indicates that the resource has reached EOF.
- ///
- /// If this method is not implemented explicitly, the default implementation
- /// will call `read()` and then copy the data into the provided buffer. For
- /// readable resources that can provide an optimized path for BYOBs, it is
- /// strongly recommended to override this method.
- fn read_byob(
- self: Rc<Self>,
- mut buf: BufMutView,
- ) -> AsyncResult<(usize, BufMutView)> {
- Box::pin(async move {
- let read = self.read(buf.len()).await?;
- let nread = read.len();
- buf[..nread].copy_from_slice(&read);
- Ok((nread, buf))
- })
- }
-
- /// Write a single chunk of data to the resource. The operation may not be
- /// able to write the entire chunk, in which case it should return the number
- /// of bytes written. Additionally it should return the `BufView` that was
- /// passed in.
- ///
- /// If this method is not implemented, the default implementation will error
- /// with a "not supported" error.
- fn write(self: Rc<Self>, buf: BufView) -> AsyncResult<WriteOutcome> {
- _ = buf;
- Box::pin(futures::future::err(not_supported()))
- }
-
- /// Write an entire chunk of data to the resource. Unlike `write()`, this will
- /// ensure the entire chunk is written. If the operation is not able to write
- /// the entire chunk, an error is to be returned.
- ///
- /// By default this method will call `write()` repeatedly until the entire
- /// chunk is written. Resources that can write the entire chunk in a single
- /// operation using an optimized path should override this method.
- fn write_all(self: Rc<Self>, view: BufView) -> AsyncResult<()> {
- Box::pin(async move {
- let mut view = view;
- let this = self;
- while !view.is_empty() {
- let resp = this.clone().write(view).await?;
- match resp {
- WriteOutcome::Partial {
- nwritten,
- view: new_view,
- } => {
- view = new_view;
- view.advance_cursor(nwritten);
- }
- WriteOutcome::Full { .. } => break,
- }
- }
- Ok(())
- })
- }
-
- /// The same as [`read_byob()`][Resource::read_byob], but synchronous.
- fn read_byob_sync(self: Rc<Self>, data: &mut [u8]) -> Result<usize, Error> {
- _ = data;
- Err(not_supported())
- }
-
- /// The same as [`write()`][Resource::write], but synchronous.
- fn write_sync(self: Rc<Self>, data: &[u8]) -> Result<usize, Error> {
- _ = data;
- Err(not_supported())
- }
-
- /// The shutdown method can be used to asynchronously close the resource. It
- /// is not automatically called when the resource is dropped or closed.
- ///
- /// If this method is not implemented, the default implementation will error
- /// with a "not supported" error.
- fn shutdown(self: Rc<Self>) -> AsyncResult<()> {
- Box::pin(futures::future::err(not_supported()))
- }
-
- /// Resources may implement the `close()` trait method if they need to do
- /// resource specific clean-ups, such as cancelling pending futures, after a
- /// resource has been removed from the resource table.
- fn close(self: Rc<Self>) {}
-
- /// Resources backed by a file descriptor can let ops know to allow for
- /// low-level optimizations.
- #[cfg(unix)]
- fn backing_fd(self: Rc<Self>) -> Option<std::os::unix::prelude::RawFd> {
- None
- }
-
- /// Resources backed by a file descriptor can let ops know to allow for
- /// low-level optimizations.
- #[cfg(windows)]
- fn backing_fd(self: Rc<Self>) -> Option<std::os::windows::io::RawHandle> {
- None
- }
-
- fn size_hint(&self) -> (u64, Option<u64>) {
- (0, None)
- }
-}
-
-impl dyn Resource {
- #[inline(always)]
- fn is<T: Resource>(&self) -> bool {
- self.type_id() == TypeId::of::<T>()
- }
-
- #[inline(always)]
- #[allow(clippy::needless_lifetimes)]
- pub fn downcast_rc<'a, T: Resource>(self: &'a Rc<Self>) -> Option<&'a Rc<T>> {
- if self.is::<T>() {
- let ptr = self as *const Rc<_> as *const Rc<T>;
- // TODO(piscisaureus): safety comment
- #[allow(clippy::undocumented_unsafe_blocks)]
- Some(unsafe { &*ptr })
- } else {
- None
- }
- }
-}
-
-/// A `ResourceId` is an integer value referencing a resource. It could be
-/// considered to be the Deno equivalent of a `file descriptor` in POSIX like
-/// operating systems. Elsewhere in the code base it is commonly abbreviated
-/// to `rid`.
-// TODO: use `u64` instead?
-pub type ResourceId = u32;
-
-/// Map-like data structure storing Deno's resources (equivalent to file
-/// descriptors).
-///
-/// Provides basic methods for element access. A resource can be of any type.
-/// Different types of resources can be stored in the same map, and provided
-/// with a name for description.
-///
-/// Each resource is identified through a _resource ID (rid)_, which acts as
-/// the key in the map.
-#[derive(Default)]
-pub struct ResourceTable {
- index: BTreeMap<ResourceId, Rc<dyn Resource>>,
- next_rid: ResourceId,
-}
-
-impl ResourceTable {
- /// Inserts resource into the resource table, which takes ownership of it.
- ///
- /// The resource type is erased at runtime and must be statically known
- /// when retrieving it through `get()`.
- ///
- /// Returns a unique resource ID, which acts as a key for this resource.
- pub fn add<T: Resource>(&mut self, resource: T) -> ResourceId {
- self.add_rc(Rc::new(resource))
- }
-
- /// Inserts a `Rc`-wrapped resource into the resource table.
- ///
- /// The resource type is erased at runtime and must be statically known
- /// when retrieving it through `get()`.
- ///
- /// Returns a unique resource ID, which acts as a key for this resource.
- pub fn add_rc<T: Resource>(&mut self, resource: Rc<T>) -> ResourceId {
- let resource = resource as Rc<dyn Resource>;
- self.add_rc_dyn(resource)
- }
-
- pub fn add_rc_dyn(&mut self, resource: Rc<dyn Resource>) -> ResourceId {
- let rid = self.next_rid;
- let removed_resource = self.index.insert(rid, resource);
- assert!(removed_resource.is_none());
- self.next_rid += 1;
- rid
- }
-
- /// Returns true if any resource with the given `rid` exists.
- pub fn has(&self, rid: ResourceId) -> bool {
- self.index.contains_key(&rid)
- }
-
- /// Returns a reference counted pointer to the resource of type `T` with the
- /// given `rid`. If `rid` is not present or has a type different than `T`,
- /// this function returns `None`.
- pub fn get<T: Resource>(&self, rid: ResourceId) -> Result<Rc<T>, Error> {
- self
- .index
- .get(&rid)
- .and_then(|rc| rc.downcast_rc::<T>())
- .map(Clone::clone)
- .ok_or_else(bad_resource_id)
- }
-
- pub fn get_any(&self, rid: ResourceId) -> Result<Rc<dyn Resource>, Error> {
- self
- .index
- .get(&rid)
- .map(Clone::clone)
- .ok_or_else(bad_resource_id)
- }
-
- /// Replaces a resource with a new resource.
- ///
- /// Panics if the resource does not exist.
- pub fn replace<T: Resource>(&mut self, rid: ResourceId, resource: T) {
- let result = self
- .index
- .insert(rid, Rc::new(resource) as Rc<dyn Resource>);
- assert!(result.is_some());
- }
-
- /// Removes a resource of type `T` from the resource table and returns it.
- /// If a resource with the given `rid` exists but its type does not match `T`,
- /// it is not removed from the resource table. Note that the resource's
- /// `close()` method is *not* called.
- ///
- /// Also note that there might be a case where
- /// the returned `Rc<T>` is referenced by other variables. That is, we cannot
- /// assume that `Rc::strong_count(&returned_rc)` is always equal to 1 on success.
- /// In particular, be really careful when you want to extract the inner value of
- /// type `T` from `Rc<T>`.
- pub fn take<T: Resource>(&mut self, rid: ResourceId) -> Result<Rc<T>, Error> {
- let resource = self.get::<T>(rid)?;
- self.index.remove(&rid);
- Ok(resource)
- }
-
- /// Removes a resource from the resource table and returns it. Note that the
- /// resource's `close()` method is *not* called.
- ///
- /// Also note that there might be a
- /// case where the returned `Rc<T>` is referenced by other variables. That is,
- /// we cannot assume that `Rc::strong_count(&returned_rc)` is always equal to 1
- /// on success. In particular, be really careful when you want to extract the
- /// inner value of type `T` from `Rc<T>`.
- pub fn take_any(
- &mut self,
- rid: ResourceId,
- ) -> Result<Rc<dyn Resource>, Error> {
- self.index.remove(&rid).ok_or_else(bad_resource_id)
- }
-
- /// Removes the resource with the given `rid` from the resource table. If the
- /// only reference to this resource existed in the resource table, this will
- /// cause the resource to be dropped. However, since resources are reference
- /// counted, therefore pending ops are not automatically cancelled. A resource
- /// may implement the `close()` method to perform clean-ups such as canceling
- /// ops.
- pub fn close(&mut self, rid: ResourceId) -> Result<(), Error> {
- self
- .index
- .remove(&rid)
- .ok_or_else(bad_resource_id)
- .map(|resource| resource.close())
- }
-
- /// Returns an iterator that yields a `(id, name)` pair for every resource
- /// that's currently in the resource table. This can be used for debugging
- /// purposes or to implement the `op_resources` op. Note that the order in
- /// which items appear is not specified.
- ///
- /// # Example
- ///
- /// ```
- /// # use deno_core::ResourceTable;
- /// # let resource_table = ResourceTable::default();
- /// let resource_names = resource_table.names().collect::<Vec<_>>();
- /// ```
- pub fn names(&self) -> impl Iterator<Item = (ResourceId, Cow<str>)> {
- self
- .index
- .iter()
- .map(|(&id, resource)| (id, resource.name()))
- }
-}
-
-#[macro_export]
-macro_rules! impl_readable_byob {
- () => {
- fn read(self: Rc<Self>, limit: usize) -> AsyncResult<$crate::BufView> {
- Box::pin(async move {
- let mut vec = vec![0; limit];
- let nread = self.read(&mut vec).await?;
- if nread != vec.len() {
- vec.truncate(nread);
- }
- let view = $crate::BufView::from(vec);
- Ok(view)
- })
- }
-
- fn read_byob(
- self: Rc<Self>,
- mut buf: $crate::BufMutView,
- ) -> AsyncResult<(usize, $crate::BufMutView)> {
- Box::pin(async move {
- let nread = self.read(buf.as_mut()).await?;
- Ok((nread, buf))
- })
- }
- };
-}
-
-#[macro_export]
-macro_rules! impl_writable {
- (__write) => {
- fn write(
- self: Rc<Self>,
- view: $crate::BufView,
- ) -> AsyncResult<$crate::WriteOutcome> {
- Box::pin(async move {
- let nwritten = self.write(&view).await?;
- Ok($crate::WriteOutcome::Partial { nwritten, view })
- })
- }
- };
- (__write_all) => {
- fn write_all(self: Rc<Self>, view: $crate::BufView) -> AsyncResult<()> {
- Box::pin(async move {
- self.write_all(&view).await?;
- Ok(())
- })
- }
- };
- () => {
- $crate::impl_writable!(__write);
- };
- (with_all) => {
- $crate::impl_writable!(__write);
- $crate::impl_writable!(__write_all);
- };
-}
diff --git a/core/runtime/bindings.js b/core/runtime/bindings.js
deleted file mode 100644
index 21d27a2c3..000000000
--- a/core/runtime/bindings.js
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-if (!globalThis.Deno) {
- globalThis.Deno = {
- core: {
- ops: {},
- asyncOps: {},
- },
- };
-}
-
-Deno.__op__console = function (callConsole, console) {
- Deno.core.callConsole = callConsole;
- Deno.core.console = console;
-};
-
-Deno.__op__registerOp = function (isAsync, op, opName) {
- const core = Deno.core;
- if (isAsync) {
- if (core.ops[opName] !== undefined) {
- return;
- }
- core.asyncOps[opName] = op;
- const fn = function (...args) {
- if (this !== core.ops) {
- // deno-lint-ignore prefer-primordials
- throw new Error(
- "An async stub cannot be separated from Deno.core.ops. Use ???",
- );
- }
- return core.asyncStub(opName, args);
- };
- fn.name = opName;
- core.ops[opName] = fn;
- } else {
- core.ops[opName] = op;
- }
-};
-
-Deno.__op__unregisterOp = function (isAsync, opName) {
- if (isAsync) {
- delete Deno.core.asyncOps[opName];
- }
- delete Deno.core.ops[opName];
-};
-
-Deno.__op__cleanup = function () {
- delete Deno.__op__console;
- delete Deno.__op__registerOp;
- delete Deno.__op__unregisterOp;
- delete Deno.__op__cleanup;
-};
diff --git a/core/runtime/bindings.rs b/core/runtime/bindings.rs
deleted file mode 100644
index 55911825f..000000000
--- a/core/runtime/bindings.rs
+++ /dev/null
@@ -1,545 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-
-use log::debug;
-use std::fmt::Write;
-use std::option::Option;
-use std::os::raw::c_void;
-use v8::MapFnTo;
-
-use crate::error::is_instance_of_error;
-use crate::error::throw_type_error;
-use crate::error::JsStackFrame;
-use crate::modules::get_asserted_module_type_from_assertions;
-use crate::modules::parse_import_assertions;
-use crate::modules::validate_import_assertions;
-use crate::modules::ImportAssertionsKind;
-use crate::modules::ModuleMap;
-use crate::modules::ResolutionKind;
-use crate::ops::OpCtx;
-use crate::runtime::InitMode;
-use crate::JsRealm;
-use crate::JsRuntime;
-
-pub(crate) fn external_references(ops: &[OpCtx]) -> v8::ExternalReferences {
- // Overallocate a bit, it's better than having to resize the vector.
- let mut references = Vec::with_capacity(4 + ops.len() * 4);
-
- references.push(v8::ExternalReference {
- function: call_console.map_fn_to(),
- });
- references.push(v8::ExternalReference {
- function: import_meta_resolve.map_fn_to(),
- });
- references.push(v8::ExternalReference {
- function: catch_dynamic_import_promise_error.map_fn_to(),
- });
- references.push(v8::ExternalReference {
- function: empty_fn.map_fn_to(),
- });
-
- for ctx in ops {
- let ctx_ptr = ctx as *const OpCtx as _;
- references.push(v8::ExternalReference { pointer: ctx_ptr });
- references.push(v8::ExternalReference {
- function: ctx.decl.v8_fn_ptr,
- });
- if let Some(fast_fn) = &ctx.decl.fast_fn {
- references.push(v8::ExternalReference {
- pointer: fast_fn.function as _,
- });
- references.push(v8::ExternalReference {
- pointer: ctx.fast_fn_c_info.unwrap().as_ptr() as _,
- });
- }
- }
-
- let refs = v8::ExternalReferences::new(&references);
- // Leak, V8 takes ownership of the references.
- std::mem::forget(references);
- refs
-}
-
-// TODO(nayeemrmn): Move to runtime and/or make `pub(crate)`.
-pub fn script_origin<'a>(
- s: &mut v8::HandleScope<'a>,
- resource_name: v8::Local<'a, v8::String>,
-) -> v8::ScriptOrigin<'a> {
- let source_map_url = v8::String::empty(s);
- v8::ScriptOrigin::new(
- s,
- resource_name.into(),
- 0,
- 0,
- false,
- 123,
- source_map_url.into(),
- true,
- false,
- false,
- )
-}
-
-fn get<'s, T>(
- scope: &mut v8::HandleScope<'s>,
- from: v8::Local<v8::Object>,
- key: &'static [u8],
- path: &'static str,
-) -> T
-where
- v8::Local<'s, v8::Value>: TryInto<T>,
-{
- let key = v8::String::new_external_onebyte_static(scope, key).unwrap();
- from
- .get(scope, key.into())
- .unwrap_or_else(|| panic!("{path} exists"))
- .try_into()
- .unwrap_or_else(|_| panic!("unable to convert"))
-}
-
-pub(crate) fn initialize_context<'s>(
- scope: &mut v8::HandleScope<'s>,
- context: v8::Local<'s, v8::Context>,
- op_ctxs: &[OpCtx],
- init_mode: InitMode,
-) -> v8::Local<'s, v8::Context> {
- let global = context.global(scope);
-
- let mut codegen = String::with_capacity(op_ctxs.len() * 200);
- codegen.push_str(include_str!("bindings.js"));
- _ = writeln!(
- codegen,
- "Deno.__op__ = function(opFns, callConsole, console) {{"
- );
- if init_mode == InitMode::New {
- _ = writeln!(codegen, "Deno.__op__console(callConsole, console);");
- }
- for op_ctx in op_ctxs {
- if op_ctx.decl.enabled {
- _ = writeln!(
- codegen,
- "Deno.__op__registerOp({}, opFns[{}], \"{}\");",
- op_ctx.decl.is_async, op_ctx.id, op_ctx.decl.name
- );
- } else {
- _ = writeln!(
- codegen,
- "Deno.__op__unregisterOp({}, \"{}\");",
- op_ctx.decl.is_async, op_ctx.decl.name
- );
- }
- }
- codegen.push_str("Deno.__op__cleanup();");
- _ = writeln!(codegen, "}}");
-
- let script = v8::String::new_from_one_byte(
- scope,
- codegen.as_bytes(),
- v8::NewStringType::Normal,
- )
- .unwrap();
- let script = v8::Script::compile(scope, script, None).unwrap();
- script.run(scope);
-
- let deno = get(scope, global, b"Deno", "Deno");
- let op_fn: v8::Local<v8::Function> =
- get(scope, deno, b"__op__", "Deno.__op__");
- let recv = v8::undefined(scope);
- let op_fns = v8::Array::new(scope, op_ctxs.len() as i32);
- for op_ctx in op_ctxs {
- let op_fn = op_ctx_function(scope, op_ctx);
- op_fns.set_index(scope, op_ctx.id as u32, op_fn.into());
- }
- if init_mode == InitMode::FromSnapshot {
- op_fn.call(scope, recv.into(), &[op_fns.into()]);
- } else {
- // Bind functions to Deno.core.*
- let call_console_fn = v8::Function::new(scope, call_console).unwrap();
-
- // Bind v8 console object to Deno.core.console
- let extra_binding_obj = context.get_extras_binding_object(scope);
- let console_obj: v8::Local<v8::Object> = get(
- scope,
- extra_binding_obj,
- b"console",
- "ExtrasBindingObject.console",
- );
-
- op_fn.call(
- scope,
- recv.into(),
- &[op_fns.into(), call_console_fn.into(), console_obj.into()],
- );
- }
-
- context
-}
-
-fn op_ctx_function<'s>(
- scope: &mut v8::HandleScope<'s>,
- op_ctx: &OpCtx,
-) -> v8::Local<'s, v8::Function> {
- let op_ctx_ptr = op_ctx as *const OpCtx as *const c_void;
- let external = v8::External::new(scope, op_ctx_ptr as *mut c_void);
- let v8name =
- v8::String::new_external_onebyte_static(scope, op_ctx.decl.name.as_bytes())
- .unwrap();
- let builder: v8::FunctionBuilder<v8::FunctionTemplate> =
- v8::FunctionTemplate::builder_raw(op_ctx.decl.v8_fn_ptr)
- .data(external.into())
- .length(op_ctx.decl.arg_count as i32);
-
- let template = if let Some(fast_function) = &op_ctx.decl.fast_fn {
- builder.build_fast(
- scope,
- fast_function,
- Some(op_ctx.fast_fn_c_info.unwrap().as_ptr()),
- None,
- None,
- )
- } else {
- builder.build(scope)
- };
-
- let v8fn = template.get_function(scope).unwrap();
- v8fn.set_name(v8name);
- v8fn
-}
-
-pub extern "C" fn wasm_async_resolve_promise_callback(
- _isolate: *mut v8::Isolate,
- context: v8::Local<v8::Context>,
- resolver: v8::Local<v8::PromiseResolver>,
- compilation_result: v8::Local<v8::Value>,
- success: v8::WasmAsyncSuccess,
-) {
- // SAFETY: `CallbackScope` can be safely constructed from `Local<Context>`
- let scope = &mut unsafe { v8::CallbackScope::new(context) };
- if success == v8::WasmAsyncSuccess::Success {
- resolver.resolve(scope, compilation_result).unwrap();
- } else {
- resolver.reject(scope, compilation_result).unwrap();
- }
-}
-
-pub fn host_import_module_dynamically_callback<'s>(
- scope: &mut v8::HandleScope<'s>,
- _host_defined_options: v8::Local<'s, v8::Data>,
- resource_name: v8::Local<'s, v8::Value>,
- specifier: v8::Local<'s, v8::String>,
- import_assertions: v8::Local<'s, v8::FixedArray>,
-) -> Option<v8::Local<'s, v8::Promise>> {
- // NOTE(bartlomieju): will crash for non-UTF-8 specifier
- let specifier_str = specifier
- .to_string(scope)
- .unwrap()
- .to_rust_string_lossy(scope);
- let referrer_name_str = resource_name
- .to_string(scope)
- .unwrap()
- .to_rust_string_lossy(scope);
-
- let resolver = v8::PromiseResolver::new(scope).unwrap();
- let promise = resolver.get_promise(scope);
-
- let assertions = parse_import_assertions(
- scope,
- import_assertions,
- ImportAssertionsKind::DynamicImport,
- );
-
- {
- let tc_scope = &mut v8::TryCatch::new(scope);
- validate_import_assertions(tc_scope, &assertions);
- if tc_scope.has_caught() {
- let e = tc_scope.exception().unwrap();
- resolver.reject(tc_scope, e);
- }
- }
- let asserted_module_type =
- get_asserted_module_type_from_assertions(&assertions);
-
- let resolver_handle = v8::Global::new(scope, resolver);
- {
- let state_rc = JsRuntime::state_from(scope);
- let module_map_rc = JsRuntime::module_map_from(scope);
-
- debug!(
- "dyn_import specifier {} referrer {} ",
- specifier_str, referrer_name_str
- );
- ModuleMap::load_dynamic_import(
- module_map_rc,
- &specifier_str,
- &referrer_name_str,
- asserted_module_type,
- resolver_handle,
- );
- state_rc.borrow_mut().notify_new_dynamic_import();
- }
- // Map errors from module resolution (not JS errors from module execution) to
- // ones rethrown from this scope, so they include the call stack of the
- // dynamic import site. Error objects without any stack frames are assumed to
- // be module resolution errors, other exception values are left as they are.
- let builder = v8::FunctionBuilder::new(catch_dynamic_import_promise_error);
-
- let map_err =
- v8::FunctionBuilder::<v8::Function>::build(builder, scope).unwrap();
-
- let promise = promise.catch(scope, map_err).unwrap();
-
- Some(promise)
-}
-
-pub extern "C" fn host_initialize_import_meta_object_callback(
- context: v8::Local<v8::Context>,
- module: v8::Local<v8::Module>,
- meta: v8::Local<v8::Object>,
-) {
- // SAFETY: `CallbackScope` can be safely constructed from `Local<Context>`
- let scope = &mut unsafe { v8::CallbackScope::new(context) };
- let module_map_rc = JsRuntime::module_map_from(scope);
- let module_map = module_map_rc.borrow();
-
- let module_global = v8::Global::new(scope, module);
- let info = module_map
- .get_info(&module_global)
- .expect("Module not found");
-
- let url_key = v8::String::new_external_onebyte_static(scope, b"url").unwrap();
- let url_val = info.name.v8(scope);
- meta.create_data_property(scope, url_key.into(), url_val.into());
-
- let main_key =
- v8::String::new_external_onebyte_static(scope, b"main").unwrap();
- let main_val = v8::Boolean::new(scope, info.main);
- meta.create_data_property(scope, main_key.into(), main_val.into());
-
- let builder =
- v8::FunctionBuilder::new(import_meta_resolve).data(url_val.into());
- let val = v8::FunctionBuilder::<v8::Function>::build(builder, scope).unwrap();
- let resolve_key =
- v8::String::new_external_onebyte_static(scope, b"resolve").unwrap();
- meta.set(scope, resolve_key.into(), val.into());
-}
-
-fn import_meta_resolve(
- scope: &mut v8::HandleScope,
- args: v8::FunctionCallbackArguments,
- mut rv: v8::ReturnValue,
-) {
- if args.length() > 1 {
- return throw_type_error(scope, "Invalid arguments");
- }
-
- let maybe_arg_str = args.get(0).to_string(scope);
- if maybe_arg_str.is_none() {
- return throw_type_error(scope, "Invalid arguments");
- }
- let specifier = maybe_arg_str.unwrap();
- let referrer = {
- let url_prop = args.data();
- url_prop.to_rust_string_lossy(scope)
- };
- let module_map_rc = JsRuntime::module_map_from(scope);
- let loader = module_map_rc.borrow().loader.clone();
- let specifier_str = specifier.to_rust_string_lossy(scope);
-
- if specifier_str.starts_with("npm:") {
- throw_type_error(scope, "\"npm:\" specifiers are currently not supported in import.meta.resolve()");
- return;
- }
-
- match loader.resolve(&specifier_str, &referrer, ResolutionKind::DynamicImport)
- {
- Ok(resolved) => {
- let resolved_val = serde_v8::to_v8(scope, resolved.as_str()).unwrap();
- rv.set(resolved_val);
- }
- Err(err) => {
- throw_type_error(scope, &err.to_string());
- }
- };
-}
-
-fn empty_fn(
- _scope: &mut v8::HandleScope,
- _args: v8::FunctionCallbackArguments,
- _rv: v8::ReturnValue,
-) {
- //Do Nothing
-}
-
-//It creates a reference to an empty function which can be maintained after the snapshots
-pub fn create_empty_fn<'s>(
- scope: &mut v8::HandleScope<'s>,
-) -> Option<v8::Local<'s, v8::Function>> {
- let empty_fn = v8::FunctionTemplate::new(scope, empty_fn);
- empty_fn.get_function(scope)
-}
-
-fn catch_dynamic_import_promise_error(
- scope: &mut v8::HandleScope,
- args: v8::FunctionCallbackArguments,
- _rv: v8::ReturnValue,
-) {
- let arg = args.get(0);
- if is_instance_of_error(scope, arg) {
- let e: crate::error::NativeJsError = serde_v8::from_v8(scope, arg).unwrap();
- let name = e.name.unwrap_or_else(|| "Error".to_string());
- let msg = v8::Exception::create_message(scope, arg);
- if msg.get_stack_trace(scope).unwrap().get_frame_count() == 0 {
- let arg: v8::Local<v8::Object> = arg.try_into().unwrap();
- let message_key =
- v8::String::new_external_onebyte_static(scope, b"message").unwrap();
- let message = arg.get(scope, message_key.into()).unwrap();
- let mut message: v8::Local<v8::String> = message.try_into().unwrap();
- if let Some(stack_frame) = JsStackFrame::from_v8_message(scope, msg) {
- if let Some(location) = stack_frame.maybe_format_location() {
- let str =
- format!("{} at {location}", message.to_rust_string_lossy(scope));
- message = v8::String::new(scope, &str).unwrap();
- }
- }
- let exception = match name.as_str() {
- "RangeError" => v8::Exception::range_error(scope, message),
- "TypeError" => v8::Exception::type_error(scope, message),
- "SyntaxError" => v8::Exception::syntax_error(scope, message),
- "ReferenceError" => v8::Exception::reference_error(scope, message),
- _ => v8::Exception::error(scope, message),
- };
- let code_key =
- v8::String::new_external_onebyte_static(scope, b"code").unwrap();
- let code_value =
- v8::String::new_external_onebyte_static(scope, b"ERR_MODULE_NOT_FOUND")
- .unwrap();
- let exception_obj = exception.to_object(scope).unwrap();
- exception_obj.set(scope, code_key.into(), code_value.into());
- scope.throw_exception(exception);
- return;
- }
- }
- scope.throw_exception(arg);
-}
-
-pub extern "C" fn promise_reject_callback(message: v8::PromiseRejectMessage) {
- use v8::PromiseRejectEvent::*;
-
- // SAFETY: `CallbackScope` can be safely constructed from `&PromiseRejectMessage`
- let scope = &mut unsafe { v8::CallbackScope::new(&message) };
-
- let context_state_rc = JsRealm::state_from_scope(scope);
- let mut context_state = context_state_rc.borrow_mut();
-
- if let Some(js_promise_reject_cb) = context_state.js_promise_reject_cb.clone()
- {
- drop(context_state);
-
- let tc_scope = &mut v8::TryCatch::new(scope);
- let undefined: v8::Local<v8::Value> = v8::undefined(tc_scope).into();
- let type_ = v8::Integer::new(tc_scope, message.get_event() as i32);
- let promise = message.get_promise();
-
- let reason = match message.get_event() {
- PromiseRejectWithNoHandler
- | PromiseRejectAfterResolved
- | PromiseResolveAfterResolved => message.get_value().unwrap_or(undefined),
- PromiseHandlerAddedAfterReject => undefined,
- };
-
- let promise_global = v8::Global::new(tc_scope, promise);
- let args = &[type_.into(), promise.into(), reason];
- let maybe_has_unhandled_rejection_handler = js_promise_reject_cb
- .open(tc_scope)
- .call(tc_scope, undefined, args);
-
- let has_unhandled_rejection_handler =
- if let Some(value) = maybe_has_unhandled_rejection_handler {
- value.is_true()
- } else {
- false
- };
-
- if has_unhandled_rejection_handler {
- let state_rc = JsRuntime::state_from(tc_scope);
- let mut state = state_rc.borrow_mut();
- if let Some(pending_mod_evaluate) = state.pending_mod_evaluate.as_mut() {
- if !pending_mod_evaluate.has_evaluated {
- pending_mod_evaluate
- .handled_promise_rejections
- .push(promise_global);
- }
- }
- }
- } else {
- let promise = message.get_promise();
- let promise_global = v8::Global::new(scope, promise);
- match message.get_event() {
- PromiseRejectWithNoHandler => {
- let error = message.get_value().unwrap();
- let error_global = v8::Global::new(scope, error);
- context_state
- .pending_promise_rejections
- .push_back((promise_global, error_global));
- }
- PromiseHandlerAddedAfterReject => {
- context_state
- .pending_promise_rejections
- .retain(|(key, _)| key != &promise_global);
- }
- PromiseRejectAfterResolved => {}
- PromiseResolveAfterResolved => {
- // Should not warn. See #1272
- }
- }
- }
-}
-
-/// This binding should be used if there's a custom console implementation
-/// available. Using it will make sure that proper stack frames are displayed
-/// in the inspector console.
-///
-/// Each method on console object should be bound to this function, eg:
-/// ```ignore
-/// function wrapConsole(consoleFromDeno, consoleFromV8) {
-/// const callConsole = core.callConsole;
-///
-/// for (const key of Object.keys(consoleFromV8)) {
-/// if (consoleFromDeno.hasOwnProperty(key)) {
-/// consoleFromDeno[key] = callConsole.bind(
-/// consoleFromDeno,
-/// consoleFromV8[key],
-/// consoleFromDeno[key],
-/// );
-/// }
-/// }
-/// }
-/// ```
-///
-/// Inspired by:
-/// https://github.com/nodejs/node/blob/1317252dfe8824fd9cfee125d2aaa94004db2f3b/src/inspector_js_api.cc#L194-L222
-fn call_console(
- scope: &mut v8::HandleScope,
- args: v8::FunctionCallbackArguments,
- _rv: v8::ReturnValue,
-) {
- if args.length() < 2
- || !args.get(0).is_function()
- || !args.get(1).is_function()
- {
- return throw_type_error(scope, "Invalid arguments");
- }
-
- let mut call_args = vec![];
- for i in 2..args.length() {
- call_args.push(args.get(i));
- }
-
- let receiver = args.this();
- let inspector_console_method =
- v8::Local::<v8::Function>::try_from(args.get(0)).unwrap();
- let deno_console_method =
- v8::Local::<v8::Function>::try_from(args.get(1)).unwrap();
-
- inspector_console_method.call(scope, receiver.into(), &call_args);
- deno_console_method.call(scope, receiver.into(), &call_args);
-}
diff --git a/core/runtime/encode_decode_test.js b/core/runtime/encode_decode_test.js
deleted file mode 100644
index 0f4668765..000000000
--- a/core/runtime/encode_decode_test.js
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-"use strict";
-function assert(cond) {
- if (!cond) {
- throw Error("assert");
- }
-}
-
-function assertArrayEquals(a1, a2) {
- if (a1.length !== a2.length) throw Error("assert");
-
- for (const index in a1) {
- if (a1[index] !== a2[index]) {
- throw Error("assert");
- }
- }
-}
-
-function main() {
- // deno-fmt-ignore
- const fixture1 = [
- 0xf0, 0x9d, 0x93, 0xbd,
- 0xf0, 0x9d, 0x93, 0xae,
- 0xf0, 0x9d, 0x94, 0x81,
- 0xf0, 0x9d, 0x93, 0xbd
- ];
- // deno-fmt-ignore
- const fixture2 = [
- 72, 101, 108, 108,
- 111, 32, 239, 191,
- 189, 239, 191, 189,
- 32, 87, 111, 114,
- 108, 100
- ];
-
- const empty = Deno.core.ops.op_encode("");
- if (empty.length !== 0) throw new Error("assert");
-
- assertArrayEquals(
- Array.from(Deno.core.ops.op_encode("𝓽𝓮𝔁𝓽")),
- fixture1,
- );
- assertArrayEquals(
- Array.from(Deno.core.ops.op_encode("Hello \udc12\ud834 World")),
- fixture2,
- );
-
- const emptyBuf = Deno.core.ops.op_decode(new Uint8Array(0));
- if (emptyBuf !== "") throw new Error("assert");
-
- assert(Deno.core.ops.op_decode(new Uint8Array(fixture1)) === "𝓽𝓮𝔁𝓽");
- assert(
- Deno.core.ops.op_decode(new Uint8Array(fixture2)) ===
- "Hello �� World",
- );
-
- // See https://github.com/denoland/deno/issues/6649
- let thrown = false;
- try {
- Deno.core.ops.op_decode(new Uint8Array(2 ** 29));
- } catch (e) {
- thrown = true;
- assert(e instanceof RangeError);
- assert(e.message === "string too long");
- }
- assert(thrown);
-}
-
-main();
diff --git a/core/runtime/error_builder_test.js b/core/runtime/error_builder_test.js
deleted file mode 100644
index f442819cb..000000000
--- a/core/runtime/error_builder_test.js
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-const { core } = Deno;
-const { ops } = core;
-
-class DOMException {
- constructor(message, code) {
- this.msg = message;
- this.code = code;
- }
-}
-
-core.registerErrorBuilder(
- "DOMExceptionOperationError",
- function DOMExceptionOperationError(msg) {
- return new DOMException(msg, "OperationError");
- },
-);
-
-try {
- ops.op_err();
- throw new Error("op_err didn't throw!");
-} catch (err) {
- if (!(err instanceof DOMException)) {
- throw new Error("err not DOMException");
- }
- if (err.msg !== "abc") {
- throw new Error("err.message is incorrect");
- }
- if (err.code !== "OperationError") {
- throw new Error("err.code is incorrect");
- }
-}
diff --git a/core/runtime/icudtl.dat b/core/runtime/icudtl.dat
deleted file mode 100644
index d1f10917a..000000000
--- a/core/runtime/icudtl.dat
+++ /dev/null
Binary files differ
diff --git a/core/runtime/jsrealm.rs b/core/runtime/jsrealm.rs
deleted file mode 100644
index 72818eebe..000000000
--- a/core/runtime/jsrealm.rs
+++ /dev/null
@@ -1,365 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-use super::bindings;
-use crate::error::exception_to_err_result;
-use crate::joinset::JoinSet;
-use crate::modules::ModuleCode;
-use crate::ops::OpCtx;
-use crate::runtime::JsRuntimeState;
-use crate::JsRuntime;
-use crate::OpId;
-use crate::OpResult;
-use crate::PromiseId;
-use anyhow::Error;
-use std::cell::RefCell;
-use std::collections::HashSet;
-use std::collections::VecDeque;
-use std::hash::BuildHasherDefault;
-use std::hash::Hasher;
-use std::option::Option;
-use std::rc::Rc;
-use v8::HandleScope;
-use v8::Local;
-
-// Hasher used for `unrefed_ops`. Since these are rolling i32, there's no
-// need to actually hash them.
-#[derive(Default)]
-pub(crate) struct IdentityHasher(u64);
-
-impl Hasher for IdentityHasher {
- fn write_i32(&mut self, i: i32) {
- self.0 = i as u64;
- }
-
- fn finish(&self) -> u64 {
- self.0
- }
-
- fn write(&mut self, _bytes: &[u8]) {
- unreachable!()
- }
-}
-
-#[derive(Default)]
-pub(crate) struct ContextState {
- pub(crate) js_event_loop_tick_cb: Option<Rc<v8::Global<v8::Function>>>,
- pub(crate) js_build_custom_error_cb: Option<Rc<v8::Global<v8::Function>>>,
- pub(crate) js_promise_reject_cb: Option<Rc<v8::Global<v8::Function>>>,
- pub(crate) js_format_exception_cb: Option<Rc<v8::Global<v8::Function>>>,
- pub(crate) js_wasm_streaming_cb: Option<Rc<v8::Global<v8::Function>>>,
- pub(crate) pending_promise_rejections:
- VecDeque<(v8::Global<v8::Promise>, v8::Global<v8::Value>)>,
- pub(crate) unrefed_ops: HashSet<i32, BuildHasherDefault<IdentityHasher>>,
- pub(crate) pending_ops: JoinSet<(PromiseId, OpId, OpResult)>,
- // We don't explicitly re-read this prop but need the slice to live alongside
- // the context
- pub(crate) op_ctxs: Box<[OpCtx]>,
- pub(crate) isolate: Option<*mut v8::OwnedIsolate>,
-}
-
-/// A representation of a JavaScript realm tied to a [`JsRuntime`], that allows
-/// execution in the realm's context.
-///
-/// A [`JsRealm`] instance is a reference to an already existing realm, which
-/// does not hold ownership of it, so instances can be created and dropped as
-/// needed. As such, calling [`JsRealm::new`] doesn't create a new realm, and
-/// cloning a [`JsRealm`] only creates a new reference. See
-/// [`JsRuntime::create_realm`] to create new realms instead.
-///
-/// Despite [`JsRealm`] instances being references, multiple instances that
-/// point to the same realm won't overlap because every operation requires
-/// passing a mutable reference to the [`v8::Isolate`]. Therefore, no operation
-/// on two [`JsRealm`] instances tied to the same isolate can be run at the same
-/// time, regardless of whether they point to the same realm.
-///
-/// # Panics
-///
-/// Every method of [`JsRealm`] will panic if you call it with a reference to a
-/// [`v8::Isolate`] other than the one that corresponds to the current context.
-///
-/// In other words, the [`v8::Isolate`] parameter for all the related [`JsRealm`] methods
-/// must be extracted from the pre-existing [`JsRuntime`].
-///
-/// Example usage with the [`JsRealm::execute_script`] method:
-/// ```
-/// use deno_core::JsRuntime;
-/// use deno_core::RuntimeOptions;
-///
-/// let mut runtime = JsRuntime::new(RuntimeOptions::default());
-/// let new_realm = runtime
-/// .create_realm()
-/// .expect("Handle the error properly");
-/// let source_code = "var a = 0; a + 1";
-/// let result = new_realm
-/// .execute_script_static(runtime.v8_isolate(), "<anon>", source_code)
-/// .expect("Handle the error properly");
-/// # drop(result);
-/// ```
-///
-/// # Lifetime of the realm
-///
-/// As long as the corresponding isolate is alive, a [`JsRealm`] instance will
-/// keep the underlying V8 context alive even if it would have otherwise been
-/// garbage collected.
-#[derive(Clone)]
-#[repr(transparent)]
-pub struct JsRealm(pub(crate) JsRealmInner);
-
-#[derive(Clone)]
-pub(crate) struct JsRealmInner {
- context_state: Rc<RefCell<ContextState>>,
- context: Rc<v8::Global<v8::Context>>,
- runtime_state: Rc<RefCell<JsRuntimeState>>,
- is_global: bool,
-}
-
-impl JsRealmInner {
- pub(crate) fn new(
- context_state: Rc<RefCell<ContextState>>,
- context: v8::Global<v8::Context>,
- runtime_state: Rc<RefCell<JsRuntimeState>>,
- is_global: bool,
- ) -> Self {
- Self {
- context_state,
- context: context.into(),
- runtime_state,
- is_global,
- }
- }
-
- pub fn num_pending_ops(&self) -> usize {
- self.context_state.borrow().pending_ops.len()
- }
-
- pub fn num_unrefed_ops(&self) -> usize {
- self.context_state.borrow().unrefed_ops.len()
- }
-
- #[inline(always)]
- pub fn context(&self) -> &v8::Global<v8::Context> {
- &self.context
- }
-
- #[inline(always)]
- pub(crate) fn state(&self) -> Rc<RefCell<ContextState>> {
- self.context_state.clone()
- }
-
- /// For info on the [`v8::Isolate`] parameter, check [`JsRealm#panics`].
- #[inline(always)]
- pub fn handle_scope<'s>(
- &self,
- isolate: &'s mut v8::Isolate,
- ) -> v8::HandleScope<'s> {
- v8::HandleScope::with_context(isolate, &*self.context)
- }
-
- pub(crate) fn check_promise_rejections(
- &self,
- scope: &mut v8::HandleScope,
- ) -> Result<(), Error> {
- let Some((_, handle)) = self.context_state.borrow_mut().pending_promise_rejections.pop_front() else {
- return Ok(());
- };
-
- let exception = v8::Local::new(scope, handle);
- let state_rc = JsRuntime::state_from(scope);
- let state = state_rc.borrow();
- if let Some(inspector) = &state.inspector {
- let inspector = inspector.borrow();
- inspector.exception_thrown(scope, exception, true);
- if inspector.has_blocking_sessions() {
- return Ok(());
- }
- }
- exception_to_err_result(scope, exception, true)
- }
-
- pub(crate) fn is_same(&self, other: &Rc<v8::Global<v8::Context>>) -> bool {
- Rc::ptr_eq(&self.context, other)
- }
-
- pub fn destroy(self) {
- let state = self.state();
- let raw_ptr = self.state().borrow().isolate.unwrap();
- // SAFETY: We know the isolate outlives the realm
- let isolate = unsafe { raw_ptr.as_mut().unwrap() };
- let mut realm_state = state.borrow_mut();
- // These globals will prevent snapshots from completing, take them
- std::mem::take(&mut realm_state.js_event_loop_tick_cb);
- std::mem::take(&mut realm_state.js_build_custom_error_cb);
- std::mem::take(&mut realm_state.js_promise_reject_cb);
- std::mem::take(&mut realm_state.js_format_exception_cb);
- std::mem::take(&mut realm_state.js_wasm_streaming_cb);
- // The OpCtx slice may contain a circular reference
- std::mem::take(&mut realm_state.op_ctxs);
-
- self.context().open(isolate).clear_all_slots(isolate);
-
- // Expect that this context is dead (we only check this in debug mode)
- // TODO(mmastrac): This check fails for some tests, will need to fix this
- // debug_assert_eq!(Rc::strong_count(&self.context), 1, "Realm was still alive when we wanted to destroy it. Not dropped?");
- }
-}
-
-impl JsRealm {
- pub(crate) fn new(inner: JsRealmInner) -> Self {
- Self(inner)
- }
-
- #[inline(always)]
- pub(crate) fn state_from_scope(
- scope: &mut v8::HandleScope,
- ) -> Rc<RefCell<ContextState>> {
- let context = scope.get_current_context();
- context
- .get_slot::<Rc<RefCell<ContextState>>>(scope)
- .unwrap()
- .clone()
- }
-
- #[inline(always)]
- pub fn num_pending_ops(&self) -> usize {
- self.0.num_pending_ops()
- }
-
- #[inline(always)]
- pub fn num_unrefed_ops(&self) -> usize {
- self.0.num_unrefed_ops()
- }
-
- /// For info on the [`v8::Isolate`] parameter, check [`JsRealm#panics`].
- #[inline(always)]
- pub fn handle_scope<'s>(
- &self,
- isolate: &'s mut v8::Isolate,
- ) -> v8::HandleScope<'s> {
- self.0.handle_scope(isolate)
- }
-
- #[inline(always)]
- pub fn context(&self) -> &v8::Global<v8::Context> {
- self.0.context()
- }
-
- /// For info on the [`v8::Isolate`] parameter, check [`JsRealm#panics`].
- pub fn global_object<'s>(
- &self,
- isolate: &'s mut v8::Isolate,
- ) -> v8::Local<'s, v8::Object> {
- let scope = &mut self.0.handle_scope(isolate);
- self.0.context.open(scope).global(scope)
- }
-
- fn string_from_code<'a>(
- scope: &mut HandleScope<'a>,
- code: &ModuleCode,
- ) -> Option<Local<'a, v8::String>> {
- if let Some(code) = code.try_static_ascii() {
- v8::String::new_external_onebyte_static(scope, code)
- } else {
- v8::String::new_from_utf8(
- scope,
- code.as_bytes(),
- v8::NewStringType::Normal,
- )
- }
- }
-
- /// Executes traditional JavaScript code (traditional = not ES modules) in the
- /// realm's context.
- ///
- /// For info on the [`v8::Isolate`] parameter, check [`JsRealm#panics`].
- ///
- /// The `name` parameter can be a filepath or any other string. E.g.:
- ///
- /// - "/some/file/path.js"
- /// - "<anon>"
- /// - "[native code]"
- ///
- /// The same `name` value can be used for multiple executions.
- ///
- /// `Error` can usually be downcast to `JsError`.
- pub fn execute_script_static(
- &self,
- isolate: &mut v8::Isolate,
- name: &'static str,
- source_code: &'static str,
- ) -> Result<v8::Global<v8::Value>, Error> {
- self.execute_script(isolate, name, ModuleCode::from_static(source_code))
- }
-
- /// Executes traditional JavaScript code (traditional = not ES modules) in the
- /// realm's context.
- ///
- /// For info on the [`v8::Isolate`] parameter, check [`JsRealm#panics`].
- ///
- /// The `name` parameter can be a filepath or any other string. E.g.:
- ///
- /// - "/some/file/path.js"
- /// - "<anon>"
- /// - "[native code]"
- ///
- /// The same `name` value can be used for multiple executions.
- ///
- /// `Error` can usually be downcast to `JsError`.
- pub fn execute_script(
- &self,
- isolate: &mut v8::Isolate,
- name: &'static str,
- source_code: ModuleCode,
- ) -> Result<v8::Global<v8::Value>, Error> {
- let scope = &mut self.0.handle_scope(isolate);
-
- let source = Self::string_from_code(scope, &source_code).unwrap();
- debug_assert!(name.is_ascii());
- let name =
- v8::String::new_external_onebyte_static(scope, name.as_bytes()).unwrap();
- let origin = bindings::script_origin(scope, name);
-
- let tc_scope = &mut v8::TryCatch::new(scope);
-
- let script = match v8::Script::compile(tc_scope, source, Some(&origin)) {
- Some(script) => script,
- None => {
- let exception = tc_scope.exception().unwrap();
- return exception_to_err_result(tc_scope, exception, false);
- }
- };
-
- match script.run(tc_scope) {
- Some(value) => {
- let value_handle = v8::Global::new(tc_scope, value);
- Ok(value_handle)
- }
- None => {
- assert!(tc_scope.has_caught());
- let exception = tc_scope.exception().unwrap();
- exception_to_err_result(tc_scope, exception, false)
- }
- }
- }
-
- // TODO(andreubotella): `mod_evaluate`, `load_main_module`, `load_side_module`
-}
-
-impl Drop for JsRealm {
- fn drop(&mut self) {
- // Don't do anything special with the global realm
- if self.0.is_global {
- return;
- }
-
- // There's us and there's the runtime
- if Rc::strong_count(&self.0.context) == 2 {
- self
- .0
- .runtime_state
- .borrow_mut()
- .remove_realm(&self.0.context);
- assert_eq!(Rc::strong_count(&self.0.context), 1);
- self.0.clone().destroy();
- assert_eq!(Rc::strong_count(&self.0.context_state), 1);
- }
- }
-}
diff --git a/core/runtime/jsruntime.rs b/core/runtime/jsruntime.rs
deleted file mode 100644
index cea8fcb1f..000000000
--- a/core/runtime/jsruntime.rs
+++ /dev/null
@@ -1,2316 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-
-use super::bindings;
-use super::jsrealm::JsRealmInner;
-use super::snapshot_util;
-use crate::error::exception_to_err_result;
-use crate::error::generic_error;
-use crate::error::to_v8_type_error;
-use crate::error::GetErrorClassFn;
-use crate::error::JsError;
-use crate::extensions::OpDecl;
-use crate::extensions::OpEventLoopFn;
-use crate::include_js_files;
-use crate::inspector::JsRuntimeInspector;
-use crate::module_specifier::ModuleSpecifier;
-use crate::modules::AssertedModuleType;
-use crate::modules::ExtModuleLoader;
-use crate::modules::ExtModuleLoaderCb;
-use crate::modules::ModuleCode;
-use crate::modules::ModuleError;
-use crate::modules::ModuleId;
-use crate::modules::ModuleLoadId;
-use crate::modules::ModuleLoader;
-use crate::modules::ModuleMap;
-use crate::ops::*;
-use crate::runtime::ContextState;
-use crate::runtime::JsRealm;
-use crate::source_map::SourceMapCache;
-use crate::source_map::SourceMapGetter;
-use crate::Extension;
-use crate::ExtensionFileSource;
-use crate::NoopModuleLoader;
-use crate::OpMiddlewareFn;
-use crate::OpResult;
-use crate::OpState;
-use crate::V8_WRAPPER_OBJECT_INDEX;
-use crate::V8_WRAPPER_TYPE_INDEX;
-use anyhow::Context as AnyhowContext;
-use anyhow::Error;
-use futures::channel::oneshot;
-use futures::future::poll_fn;
-use futures::stream::StreamExt;
-use once_cell::sync::Lazy;
-use smallvec::SmallVec;
-use std::any::Any;
-use std::cell::RefCell;
-use std::collections::HashMap;
-use std::ffi::c_void;
-use std::mem::ManuallyDrop;
-use std::ops::Deref;
-use std::ops::DerefMut;
-use std::option::Option;
-use std::rc::Rc;
-use std::sync::atomic::AtomicBool;
-use std::sync::atomic::Ordering;
-use std::sync::Arc;
-use std::sync::Mutex;
-use std::sync::Once;
-use std::task::Context;
-use std::task::Poll;
-
-const STATE_DATA_OFFSET: u32 = 0;
-const MODULE_MAP_DATA_OFFSET: u32 = 1;
-
-pub enum Snapshot {
- Static(&'static [u8]),
- JustCreated(v8::StartupData),
- Boxed(Box<[u8]>),
-}
-
-/// Objects that need to live as long as the isolate
-#[derive(Default)]
-pub(crate) struct IsolateAllocations {
- pub(crate) near_heap_limit_callback_data:
- Option<(Box<RefCell<dyn Any>>, v8::NearHeapLimitCallback)>,
-}
-
-/// ManuallyDrop<Rc<...>> is clone, but it returns a ManuallyDrop<Rc<...>> which is a massive
-/// memory-leak footgun.
-pub(crate) struct ManuallyDropRc<T>(ManuallyDrop<Rc<T>>);
-
-impl<T> ManuallyDropRc<T> {
- pub fn clone(&self) -> Rc<T> {
- self.0.deref().clone()
- }
-}
-
-impl<T> Deref for ManuallyDropRc<T> {
- type Target = Rc<T>;
- fn deref(&self) -> &Self::Target {
- self.0.deref()
- }
-}
-
-impl<T> DerefMut for ManuallyDropRc<T> {
- fn deref_mut(&mut self) -> &mut Self::Target {
- self.0.deref_mut()
- }
-}
-
-/// This struct contains the [`JsRuntimeState`] and [`v8::OwnedIsolate`] that are required
-/// to do an orderly shutdown of V8. We keep these in a separate struct to allow us to control
-/// the destruction more closely, as snapshots require the isolate to be destroyed by the
-/// snapshot process, not the destructor.
-///
-/// The way rusty_v8 works w/snapshots is that the [`v8::OwnedIsolate`] gets consumed by a
-/// [`v8::snapshot::SnapshotCreator`] that is stored in its annex. It's a bit awkward, because this
-/// means we cannot let it drop (because we don't have it after a snapshot). On top of that, we have
-/// to consume it in the snapshot creator because otherwise it panics.
-///
-/// This inner struct allows us to let the outer JsRuntime drop normally without a Drop impl, while we
-/// control dropping more closely here using ManuallyDrop.
-pub(crate) struct InnerIsolateState {
- will_snapshot: bool,
- pub(crate) state: ManuallyDropRc<RefCell<JsRuntimeState>>,
- v8_isolate: ManuallyDrop<v8::OwnedIsolate>,
-}
-
-impl InnerIsolateState {
- /// Clean out the opstate and take the inspector to prevent the inspector from getting destroyed
- /// after we've torn down the contexts. If the inspector is not correctly torn down, random crashes
- /// happen in tests (and possibly for users using the inspector).
- pub fn prepare_for_cleanup(&mut self) {
- let mut state = self.state.borrow_mut();
- let inspector = state.inspector.take();
- state.op_state.borrow_mut().clear();
- if let Some(inspector) = inspector {
- assert_eq!(
- Rc::strong_count(&inspector),
- 1,
- "The inspector must be dropped before the runtime"
- );
- }
- }
-
- pub fn cleanup(&mut self) {
- self.prepare_for_cleanup();
-
- let state_ptr = self.v8_isolate.get_data(STATE_DATA_OFFSET);
- // SAFETY: We are sure that it's a valid pointer for whole lifetime of
- // the runtime.
- _ = unsafe { Rc::from_raw(state_ptr as *const RefCell<JsRuntimeState>) };
-
- let module_map_ptr = self.v8_isolate.get_data(MODULE_MAP_DATA_OFFSET);
- // SAFETY: We are sure that it's a valid pointer for whole lifetime of
- // the runtime.
- _ = unsafe { Rc::from_raw(module_map_ptr as *const RefCell<ModuleMap>) };
-
- self.state.borrow_mut().destroy_all_realms();
-
- debug_assert_eq!(Rc::strong_count(&self.state), 1);
- }
-
- pub fn prepare_for_snapshot(mut self) -> v8::OwnedIsolate {
- self.cleanup();
- // SAFETY: We're copying out of self and then immediately forgetting self
- let (state, isolate) = unsafe {
- (
- ManuallyDrop::take(&mut self.state.0),
- ManuallyDrop::take(&mut self.v8_isolate),
- )
- };
- std::mem::forget(self);
- drop(state);
- isolate
- }
-}
-
-impl Drop for InnerIsolateState {
- fn drop(&mut self) {
- self.cleanup();
- // SAFETY: We gotta drop these
- unsafe {
- ManuallyDrop::drop(&mut self.state.0);
- if self.will_snapshot {
- // Create the snapshot and just drop it.
- eprintln!("WARNING: v8::OwnedIsolate for snapshot was leaked");
- } else {
- ManuallyDrop::drop(&mut self.v8_isolate);
- }
- }
- }
-}
-
-#[derive(Copy, Clone, Debug, Eq, PartialEq)]
-pub(crate) enum InitMode {
- /// We have no snapshot -- this is a pristine context.
- New,
- /// We are using a snapshot, thus certain initialization steps are skipped.
- FromSnapshot,
-}
-
-impl InitMode {
- fn from_options(options: &RuntimeOptions) -> Self {
- match options.startup_snapshot {
- None => Self::New,
- Some(_) => Self::FromSnapshot,
- }
- }
-}
-
-pub(crate) static BUILTIN_SOURCES: Lazy<Vec<ExtensionFileSource>> =
- Lazy::new(|| {
- include_js_files!(
- core
- "00_primordials.js",
- "01_core.js",
- "02_error.js",
- )
- });
-
-/// A single execution context of JavaScript. Corresponds roughly to the "Web
-/// Worker" concept in the DOM.
-////
-/// The JsRuntime future completes when there is an error or when all
-/// pending ops have completed.
-///
-/// Use [`JsRuntimeForSnapshot`] to be able to create a snapshot.
-pub struct JsRuntime {
- pub(crate) inner: InnerIsolateState,
- pub(crate) module_map: Rc<RefCell<ModuleMap>>,
- pub(crate) allocations: IsolateAllocations,
- extensions: Vec<Extension>,
- event_loop_middlewares: Vec<Box<OpEventLoopFn>>,
- init_mode: InitMode,
- // Marks if this is considered the top-level runtime. Used only be inspector.
- is_main: bool,
-}
-
-/// The runtime type used for snapshot creation.
-pub struct JsRuntimeForSnapshot(JsRuntime);
-
-impl Deref for JsRuntimeForSnapshot {
- type Target = JsRuntime;
-
- fn deref(&self) -> &Self::Target {
- &self.0
- }
-}
-
-impl DerefMut for JsRuntimeForSnapshot {
- fn deref_mut(&mut self) -> &mut Self::Target {
- &mut self.0
- }
-}
-
-pub(crate) struct DynImportModEvaluate {
- load_id: ModuleLoadId,
- module_id: ModuleId,
- promise: v8::Global<v8::Promise>,
- module: v8::Global<v8::Module>,
-}
-
-pub(crate) struct ModEvaluate {
- pub(crate) promise: Option<v8::Global<v8::Promise>>,
- pub(crate) has_evaluated: bool,
- pub(crate) handled_promise_rejections: Vec<v8::Global<v8::Promise>>,
- sender: oneshot::Sender<Result<(), Error>>,
-}
-
-pub struct CrossIsolateStore<T>(Arc<Mutex<CrossIsolateStoreInner<T>>>);
-
-struct CrossIsolateStoreInner<T> {
- map: HashMap<u32, T>,
- last_id: u32,
-}
-
-impl<T> CrossIsolateStore<T> {
- pub(crate) fn insert(&self, value: T) -> u32 {
- let mut store = self.0.lock().unwrap();
- let last_id = store.last_id;
- store.map.insert(last_id, value);
- store.last_id += 1;
- last_id
- }
-
- pub(crate) fn take(&self, id: u32) -> Option<T> {
- let mut store = self.0.lock().unwrap();
- store.map.remove(&id)
- }
-}
-
-impl<T> Default for CrossIsolateStore<T> {
- fn default() -> Self {
- CrossIsolateStore(Arc::new(Mutex::new(CrossIsolateStoreInner {
- map: Default::default(),
- last_id: 0,
- })))
- }
-}
-
-impl<T> Clone for CrossIsolateStore<T> {
- fn clone(&self) -> Self {
- Self(self.0.clone())
- }
-}
-
-pub type SharedArrayBufferStore =
- CrossIsolateStore<v8::SharedRef<v8::BackingStore>>;
-
-pub type CompiledWasmModuleStore = CrossIsolateStore<v8::CompiledWasmModule>;
-
-/// Internal state for JsRuntime which is stored in one of v8::Isolate's
-/// embedder slots.
-pub struct JsRuntimeState {
- global_realm: Option<JsRealm>,
- known_realms: Vec<JsRealmInner>,
- pub(crate) has_tick_scheduled: bool,
- pub(crate) pending_dyn_mod_evaluate: Vec<DynImportModEvaluate>,
- pub(crate) pending_mod_evaluate: Option<ModEvaluate>,
- /// A counter used to delay our dynamic import deadlock detection by one spin
- /// of the event loop.
- dyn_module_evaluate_idle_counter: u32,
- pub(crate) source_map_getter: Option<Rc<Box<dyn SourceMapGetter>>>,
- pub(crate) source_map_cache: Rc<RefCell<SourceMapCache>>,
- pub(crate) op_state: Rc<RefCell<OpState>>,
- pub(crate) shared_array_buffer_store: Option<SharedArrayBufferStore>,
- pub(crate) compiled_wasm_module_store: Option<CompiledWasmModuleStore>,
- /// The error that was passed to an `op_dispatch_exception` call.
- /// It will be retrieved by `exception_to_err_result` and used as an error
- /// instead of any other exceptions.
- // TODO(nayeemrmn): This is polled in `exception_to_err_result()` which is
- // flimsy. Try to poll it similarly to `pending_promise_rejections`.
- pub(crate) dispatched_exception: Option<v8::Global<v8::Value>>,
- pub(crate) inspector: Option<Rc<RefCell<JsRuntimeInspector>>>,
-}
-
-impl JsRuntimeState {
- pub(crate) fn destroy_all_realms(&mut self) {
- self.global_realm.take();
- for realm in self.known_realms.drain(..) {
- realm.destroy()
- }
- }
-
- pub(crate) fn remove_realm(
- &mut self,
- realm_context: &Rc<v8::Global<v8::Context>>,
- ) {
- self
- .known_realms
- .retain(|realm| !realm.is_same(realm_context));
- }
-}
-
-fn v8_init(
- v8_platform: Option<v8::SharedRef<v8::Platform>>,
- predictable: bool,
-) {
- // Include 10MB ICU data file.
- #[repr(C, align(16))]
- struct IcuData([u8; 10541264]);
- static ICU_DATA: IcuData = IcuData(*include_bytes!("icudtl.dat"));
- v8::icu::set_common_data_72(&ICU_DATA.0).unwrap();
-
- let flags = concat!(
- " --wasm-test-streaming",
- " --harmony-import-assertions",
- " --no-validate-asm",
- " --turbo_fast_api_calls",
- " --harmony-change-array-by-copy",
- );
-
- if predictable {
- v8::V8::set_flags_from_string(&format!(
- "{}{}",
- flags, " --predictable --random-seed=42"
- ));
- } else {
- v8::V8::set_flags_from_string(flags);
- }
-
- let v8_platform = v8_platform
- .unwrap_or_else(|| v8::new_default_platform(0, false).make_shared());
- v8::V8::initialize_platform(v8_platform);
- v8::V8::initialize();
-}
-
-#[derive(Default)]
-pub struct RuntimeOptions {
- /// Source map reference for errors.
- pub source_map_getter: Option<Box<dyn SourceMapGetter>>,
-
- /// Allows to map error type to a string "class" used to represent
- /// error in JavaScript.
- pub get_error_class_fn: Option<GetErrorClassFn>,
-
- /// Implementation of `ModuleLoader` which will be
- /// called when V8 requests to load ES modules.
- ///
- /// If not provided runtime will error if code being
- /// executed tries to load modules.
- pub module_loader: Option<Rc<dyn ModuleLoader>>,
-
- /// JsRuntime extensions, not to be confused with ES modules.
- /// Only ops registered by extensions will be initialized. If you need
- /// to execute JS code from extensions, pass source files in `js` or `esm`
- /// option on `ExtensionBuilder`.
- ///
- /// If you are creating a runtime from a snapshot take care not to include
- /// JavaScript sources in the extensions.
- pub extensions: Vec<Extension>,
-
- /// If provided, the module map will be cleared and left only with the specifiers
- /// in this list, with the new names provided. If not provided, the module map is
- /// left intact.
- pub rename_modules: Option<Vec<(&'static str, &'static str)>>,
-
- /// V8 snapshot that should be loaded on startup.
- pub startup_snapshot: Option<Snapshot>,
-
- /// Isolate creation parameters.
- pub create_params: Option<v8::CreateParams>,
-
- /// V8 platform instance to use. Used when Deno initializes V8
- /// (which it only does once), otherwise it's silently dropped.
- pub v8_platform: Option<v8::SharedRef<v8::Platform>>,
-
- /// The store to use for transferring SharedArrayBuffers between isolates.
- /// If multiple isolates should have the possibility of sharing
- /// SharedArrayBuffers, they should use the same [SharedArrayBufferStore]. If
- /// no [SharedArrayBufferStore] is specified, SharedArrayBuffer can not be
- /// serialized.
- pub shared_array_buffer_store: Option<SharedArrayBufferStore>,
-
- /// The store to use for transferring `WebAssembly.Module` objects between
- /// isolates.
- /// If multiple isolates should have the possibility of sharing
- /// `WebAssembly.Module` objects, they should use the same
- /// [CompiledWasmModuleStore]. If no [CompiledWasmModuleStore] is specified,
- /// `WebAssembly.Module` objects cannot be serialized.
- pub compiled_wasm_module_store: Option<CompiledWasmModuleStore>,
-
- /// Start inspector instance to allow debuggers to connect.
- pub inspector: bool,
-
- /// Describe if this is the main runtime instance, used by debuggers in some
- /// situation - like disconnecting when program finishes running.
- pub is_main: bool,
-}
-
-#[derive(Default)]
-pub struct RuntimeSnapshotOptions {
- /// An optional callback that will be called for each module that is loaded
- /// during snapshotting. This callback can be used to transpile source on the
- /// fly, during snapshotting, eg. to transpile TypeScript to JavaScript.
- pub snapshot_module_load_cb: Option<ExtModuleLoaderCb>,
-}
-
-impl JsRuntime {
- /// Only constructor, configuration is done through `options`.
- pub fn new(mut options: RuntimeOptions) -> JsRuntime {
- JsRuntime::init_v8(options.v8_platform.take(), cfg!(test));
- JsRuntime::new_inner(options, false, None)
- }
-
- pub(crate) fn state_from(
- isolate: &v8::Isolate,
- ) -> Rc<RefCell<JsRuntimeState>> {
- let state_ptr = isolate.get_data(STATE_DATA_OFFSET);
- let state_rc =
- // SAFETY: We are sure that it's a valid pointer for whole lifetime of
- // the runtime.
- unsafe { Rc::from_raw(state_ptr as *const RefCell<JsRuntimeState>) };
- let state = state_rc.clone();
- std::mem::forget(state_rc);
- state
- }
-
- pub(crate) fn module_map_from(
- isolate: &v8::Isolate,
- ) -> Rc<RefCell<ModuleMap>> {
- let module_map_ptr = isolate.get_data(MODULE_MAP_DATA_OFFSET);
- let module_map_rc =
- // SAFETY: We are sure that it's a valid pointer for whole lifetime of
- // the runtime.
- unsafe { Rc::from_raw(module_map_ptr as *const RefCell<ModuleMap>) };
- let module_map = module_map_rc.clone();
- std::mem::forget(module_map_rc);
- module_map
- }
-
- pub(crate) fn event_loop_pending_state_from_scope(
- scope: &mut v8::HandleScope,
- ) -> EventLoopPendingState {
- let state = JsRuntime::state_from(scope);
- let module_map = JsRuntime::module_map_from(scope);
- let state = EventLoopPendingState::new(
- scope,
- &mut state.borrow_mut(),
- &module_map.borrow(),
- );
- state
- }
-
- fn init_v8(
- v8_platform: Option<v8::SharedRef<v8::Platform>>,
- predictable: bool,
- ) {
- static DENO_INIT: Once = Once::new();
- static DENO_PREDICTABLE: AtomicBool = AtomicBool::new(false);
- static DENO_PREDICTABLE_SET: AtomicBool = AtomicBool::new(false);
-
- if DENO_PREDICTABLE_SET.load(Ordering::SeqCst) {
- let current = DENO_PREDICTABLE.load(Ordering::SeqCst);
- assert_eq!(current, predictable, "V8 may only be initialized once in either snapshotting or non-snapshotting mode. Either snapshotting or non-snapshotting mode may be used in a single process, not both.");
- DENO_PREDICTABLE_SET.store(true, Ordering::SeqCst);
- DENO_PREDICTABLE.store(predictable, Ordering::SeqCst);
- }
-
- DENO_INIT.call_once(move || v8_init(v8_platform, predictable));
- }
-
- fn new_inner(
- mut options: RuntimeOptions,
- will_snapshot: bool,
- maybe_load_callback: Option<ExtModuleLoaderCb>,
- ) -> JsRuntime {
- let init_mode = InitMode::from_options(&options);
- let (op_state, ops) = Self::create_opstate(&mut options);
- let op_state = Rc::new(RefCell::new(op_state));
-
- // Collect event-loop middleware
- let mut event_loop_middlewares =
- Vec::with_capacity(options.extensions.len());
- for extension in &mut options.extensions {
- if let Some(middleware) = extension.init_event_loop_middleware() {
- event_loop_middlewares.push(middleware);
- }
- }
-
- let align = std::mem::align_of::<usize>();
- let layout = std::alloc::Layout::from_size_align(
- std::mem::size_of::<*mut v8::OwnedIsolate>(),
- align,
- )
- .unwrap();
- assert!(layout.size() > 0);
- let isolate_ptr: *mut v8::OwnedIsolate =
- // SAFETY: we just asserted that layout has non-0 size.
- unsafe { std::alloc::alloc(layout) as *mut _ };
-
- let state_rc = Rc::new(RefCell::new(JsRuntimeState {
- pending_dyn_mod_evaluate: vec![],
- pending_mod_evaluate: None,
- dyn_module_evaluate_idle_counter: 0,
- has_tick_scheduled: false,
- source_map_getter: options.source_map_getter.map(Rc::new),
- source_map_cache: Default::default(),
- shared_array_buffer_store: options.shared_array_buffer_store,
- compiled_wasm_module_store: options.compiled_wasm_module_store,
- op_state: op_state.clone(),
- dispatched_exception: None,
- // Some fields are initialized later after isolate is created
- inspector: None,
- global_realm: None,
- known_realms: Vec::with_capacity(1),
- }));
-
- let weak = Rc::downgrade(&state_rc);
- let context_state = Rc::new(RefCell::new(ContextState::default()));
- let op_ctxs = ops
- .into_iter()
- .enumerate()
- .map(|(id, decl)| {
- OpCtx::new(
- id as u16,
- context_state.clone(),
- Rc::new(decl),
- op_state.clone(),
- weak.clone(),
- )
- })
- .collect::<Vec<_>>()
- .into_boxed_slice();
- context_state.borrow_mut().op_ctxs = op_ctxs;
- context_state.borrow_mut().isolate = Some(isolate_ptr);
-
- let refs = bindings::external_references(&context_state.borrow().op_ctxs);
- // V8 takes ownership of external_references.
- let refs: &'static v8::ExternalReferences = Box::leak(Box::new(refs));
-
- let mut isolate = if will_snapshot {
- snapshot_util::create_snapshot_creator(
- refs,
- options.startup_snapshot.take(),
- )
- } else {
- let mut params = options
- .create_params
- .take()
- .unwrap_or_default()
- .embedder_wrapper_type_info_offsets(
- V8_WRAPPER_TYPE_INDEX,
- V8_WRAPPER_OBJECT_INDEX,
- )
- .external_references(&**refs);
- if let Some(snapshot) = options.startup_snapshot.take() {
- params = match snapshot {
- Snapshot::Static(data) => params.snapshot_blob(data),
- Snapshot::JustCreated(data) => params.snapshot_blob(data),
- Snapshot::Boxed(data) => params.snapshot_blob(data),
- };
- }
- v8::Isolate::new(params)
- };
- isolate.set_capture_stack_trace_for_uncaught_exceptions(true, 10);
- isolate.set_promise_reject_callback(bindings::promise_reject_callback);
- isolate.set_host_initialize_import_meta_object_callback(
- bindings::host_initialize_import_meta_object_callback,
- );
- isolate.set_host_import_module_dynamically_callback(
- bindings::host_import_module_dynamically_callback,
- );
- isolate.set_wasm_async_resolve_promise_callback(
- bindings::wasm_async_resolve_promise_callback,
- );
-
- let (global_context, snapshotted_data) = {
- let scope = &mut v8::HandleScope::new(&mut isolate);
- let context = v8::Context::new(scope);
-
- // Get module map data from the snapshot
- let snapshotted_data = if init_mode == InitMode::FromSnapshot {
- Some(snapshot_util::get_snapshotted_data(scope, context))
- } else {
- None
- };
-
- (v8::Global::new(scope, context), snapshotted_data)
- };
-
- // SAFETY: this is first use of `isolate_ptr` so we are sure we're
- // not overwriting an existing pointer.
- isolate = unsafe {
- isolate_ptr.write(isolate);
- isolate_ptr.read()
- };
-
- let mut context_scope: v8::HandleScope =
- v8::HandleScope::with_context(&mut isolate, global_context.clone());
- let scope = &mut context_scope;
- let context = v8::Local::new(scope, global_context.clone());
-
- bindings::initialize_context(
- scope,
- context,
- &context_state.borrow().op_ctxs,
- init_mode,
- );
-
- context.set_slot(scope, context_state.clone());
-
- op_state.borrow_mut().put(isolate_ptr);
- let inspector = if options.inspector {
- Some(JsRuntimeInspector::new(scope, context, options.is_main))
- } else {
- None
- };
-
- let loader = options
- .module_loader
- .unwrap_or_else(|| Rc::new(NoopModuleLoader));
-
- {
- let global_realm = JsRealmInner::new(
- context_state,
- global_context,
- state_rc.clone(),
- true,
- );
- let mut state = state_rc.borrow_mut();
- state.global_realm = Some(JsRealm::new(global_realm.clone()));
- state.inspector = inspector;
- state.known_realms.push(global_realm);
- }
- scope.set_data(
- STATE_DATA_OFFSET,
- Rc::into_raw(state_rc.clone()) as *mut c_void,
- );
- let module_map_rc = Rc::new(RefCell::new(ModuleMap::new(loader)));
- if let Some(snapshotted_data) = snapshotted_data {
- let mut module_map = module_map_rc.borrow_mut();
- module_map.update_with_snapshotted_data(scope, snapshotted_data);
- }
- scope.set_data(
- MODULE_MAP_DATA_OFFSET,
- Rc::into_raw(module_map_rc.clone()) as *mut c_void,
- );
-
- drop(context_scope);
-
- let mut js_runtime = JsRuntime {
- inner: InnerIsolateState {
- will_snapshot,
- state: ManuallyDropRc(ManuallyDrop::new(state_rc)),
- v8_isolate: ManuallyDrop::new(isolate),
- },
- init_mode,
- allocations: IsolateAllocations::default(),
- event_loop_middlewares,
- extensions: options.extensions,
- module_map: module_map_rc,
- is_main: options.is_main,
- };
-
- let realm = js_runtime.global_realm();
- // TODO(mmastrac): We should thread errors back out of the runtime
- js_runtime
- .init_extension_js(&realm, maybe_load_callback)
- .unwrap();
-
- // If the user has requested that we rename modules
- if let Some(rename_modules) = options.rename_modules {
- js_runtime
- .module_map
- .borrow_mut()
- .clear_module_map(rename_modules.into_iter());
- }
-
- js_runtime
- }
-
- #[cfg(test)]
- #[inline]
- pub(crate) fn module_map(&self) -> &Rc<RefCell<ModuleMap>> {
- &self.module_map
- }
-
- #[inline]
- pub fn global_context(&self) -> v8::Global<v8::Context> {
- self
- .inner
- .state
- .borrow()
- .known_realms
- .get(0)
- .unwrap()
- .context()
- .clone()
- }
-
- #[inline]
- pub fn v8_isolate(&mut self) -> &mut v8::OwnedIsolate {
- &mut self.inner.v8_isolate
- }
-
- #[inline]
- pub fn inspector(&mut self) -> Rc<RefCell<JsRuntimeInspector>> {
- self.inner.state.borrow().inspector()
- }
-
- #[inline]
- pub fn global_realm(&mut self) -> JsRealm {
- let state = self.inner.state.borrow();
- state.global_realm.clone().unwrap()
- }
-
- /// Returns the extensions that this runtime is using (including internal ones).
- pub fn extensions(&self) -> &Vec<Extension> {
- &self.extensions
- }
-
- /// Creates a new realm (V8 context) in this JS execution context,
- /// pre-initialized with all of the extensions that were passed in
- /// [`RuntimeOptions::extensions`] when the [`JsRuntime`] was
- /// constructed.
- pub fn create_realm(&mut self) -> Result<JsRealm, Error> {
- let realm = {
- let context_state = Rc::new(RefCell::new(ContextState::default()));
- let op_ctxs: Box<[OpCtx]> = self
- .global_realm()
- .0
- .state()
- .borrow()
- .op_ctxs
- .iter()
- .map(|op_ctx| {
- OpCtx::new(
- op_ctx.id,
- context_state.clone(),
- op_ctx.decl.clone(),
- op_ctx.state.clone(),
- op_ctx.runtime_state.clone(),
- )
- })
- .collect();
- context_state.borrow_mut().op_ctxs = op_ctxs;
- context_state.borrow_mut().isolate = Some(self.v8_isolate() as _);
-
- let raw_ptr = self.v8_isolate() as *mut v8::OwnedIsolate;
- // SAFETY: Having the scope tied to self's lifetime makes it impossible to
- // reference JsRuntimeState::op_ctxs while the scope is alive. Here we
- // turn it into an unbound lifetime, which is sound because 1. it only
- // lives until the end of this block, and 2. the HandleScope only has
- // access to the isolate, and nothing else we're accessing from self does.
- let isolate = unsafe { raw_ptr.as_mut() }.unwrap();
- let scope = &mut v8::HandleScope::new(isolate);
- let context = v8::Context::new(scope);
- let scope = &mut v8::ContextScope::new(scope, context);
-
- let context = bindings::initialize_context(
- scope,
- context,
- &context_state.borrow().op_ctxs,
- self.init_mode,
- );
- context.set_slot(scope, context_state.clone());
- let realm = JsRealmInner::new(
- context_state,
- v8::Global::new(scope, context),
- self.inner.state.clone(),
- false,
- );
- let mut state = self.inner.state.borrow_mut();
- state.known_realms.push(realm.clone());
- JsRealm::new(realm)
- };
-
- self.init_extension_js(&realm, None)?;
- Ok(realm)
- }
-
- #[inline]
- pub fn handle_scope(&mut self) -> v8::HandleScope {
- self.global_realm().handle_scope(self.v8_isolate())
- }
-
- /// Initializes JS of provided Extensions in the given realm.
- fn init_extension_js(
- &mut self,
- realm: &JsRealm,
- maybe_load_callback: Option<ExtModuleLoaderCb>,
- ) -> Result<(), Error> {
- // Initialization of JS happens in phases:
- // 1. Iterate through all extensions:
- // a. Execute all extension "script" JS files
- // b. Load all extension "module" JS files (but do not execute them yet)
- // 2. Iterate through all extensions:
- // a. If an extension has a `esm_entry_point`, execute it.
-
- // Take extensions temporarily so we can avoid have a mutable reference to self
- let extensions = std::mem::take(&mut self.extensions);
-
- // TODO(nayeemrmn): Module maps should be per-realm.
- let loader = self.module_map.borrow().loader.clone();
- let ext_loader = Rc::new(ExtModuleLoader::new(
- &extensions,
- maybe_load_callback.map(Rc::new),
- ));
- self.module_map.borrow_mut().loader = ext_loader;
-
- let mut esm_entrypoints = vec![];
-
- futures::executor::block_on(async {
- if self.init_mode == InitMode::New {
- for file_source in &*BUILTIN_SOURCES {
- realm.execute_script(
- self.v8_isolate(),
- file_source.specifier,
- file_source.load()?,
- )?;
- }
- }
- self.init_cbs(realm);
-
- for extension in &extensions {
- let maybe_esm_entry_point = extension.get_esm_entry_point();
-
- for file_source in extension.get_esm_sources() {
- self
- .load_side_module(
- &ModuleSpecifier::parse(file_source.specifier)?,
- None,
- )
- .await?;
- }
-
- if let Some(entry_point) = maybe_esm_entry_point {
- esm_entrypoints.push(entry_point);
- }
-
- for file_source in extension.get_js_sources() {
- realm.execute_script(
- self.v8_isolate(),
- file_source.specifier,
- file_source.load()?,
- )?;
- }
- }
-
- for specifier in esm_entrypoints {
- let mod_id = {
- self
- .module_map
- .borrow()
- .get_id(specifier, AssertedModuleType::JavaScriptOrWasm)
- .unwrap_or_else(|| {
- panic!("{} not present in the module map", specifier)
- })
- };
- let receiver = self.mod_evaluate(mod_id);
- self.run_event_loop(false).await?;
- receiver
- .await?
- .with_context(|| format!("Couldn't execute '{specifier}'"))?;
- }
-
- #[cfg(debug_assertions)]
- {
- let module_map_rc = self.module_map.clone();
- let mut scope = realm.handle_scope(self.v8_isolate());
- let module_map = module_map_rc.borrow();
- module_map.assert_all_modules_evaluated(&mut scope);
- }
-
- Ok::<_, anyhow::Error>(())
- })?;
-
- self.extensions = extensions;
- self.module_map.borrow_mut().loader = loader;
- Ok(())
- }
-
- /// Collects ops from extensions & applies middleware
- fn collect_ops(exts: &mut [Extension]) -> Vec<OpDecl> {
- for (ext, previous_exts) in
- exts.iter().enumerate().map(|(i, ext)| (ext, &exts[..i]))
- {
- ext.check_dependencies(previous_exts);
- }
-
- // Middleware
- let middleware: Vec<Box<OpMiddlewareFn>> = exts
- .iter_mut()
- .filter_map(|e| e.init_middleware())
- .collect();
-
- // macroware wraps an opfn in all the middleware
- let macroware = move |d| middleware.iter().fold(d, |d, m| m(d));
-
- // Flatten ops, apply middleware & override disabled ops
- let ops: Vec<_> = exts
- .iter_mut()
- .filter_map(|e| e.init_ops())
- .flatten()
- .map(|d| OpDecl {
- name: d.name,
- ..macroware(d)
- })
- .collect();
-
- // In debug build verify there are no duplicate ops.
- #[cfg(debug_assertions)]
- {
- let mut count_by_name = HashMap::new();
-
- for op in ops.iter() {
- count_by_name
- .entry(&op.name)
- .or_insert(vec![])
- .push(op.name.to_string());
- }
-
- let mut duplicate_ops = vec![];
- for (op_name, _count) in
- count_by_name.iter().filter(|(_k, v)| v.len() > 1)
- {
- duplicate_ops.push(op_name.to_string());
- }
- if !duplicate_ops.is_empty() {
- let mut msg = "Found ops with duplicate names:\n".to_string();
- for op_name in duplicate_ops {
- msg.push_str(&format!(" - {}\n", op_name));
- }
- msg.push_str("Op names need to be unique.");
- panic!("{}", msg);
- }
- }
-
- ops
- }
-
- /// Initializes ops of provided Extensions
- fn create_opstate(options: &mut RuntimeOptions) -> (OpState, Vec<OpDecl>) {
- // Add built-in extension
- options
- .extensions
- .insert(0, crate::ops_builtin::core::init_ops());
-
- let ops = Self::collect_ops(&mut options.extensions);
-
- let mut op_state = OpState::new(ops.len());
-
- if let Some(get_error_class_fn) = options.get_error_class_fn {
- op_state.get_error_class_fn = get_error_class_fn;
- }
-
- // Setup state
- for e in &mut options.extensions {
- // ops are already registered during in bindings::initialize_context();
- e.init_state(&mut op_state);
- }
-
- (op_state, ops)
- }
-
- pub fn eval<'s, T>(
- scope: &mut v8::HandleScope<'s>,
- code: &str,
- ) -> Option<v8::Local<'s, T>>
- where
- v8::Local<'s, T>: TryFrom<v8::Local<'s, v8::Value>, Error = v8::DataError>,
- {
- let scope = &mut v8::EscapableHandleScope::new(scope);
- let source = v8::String::new(scope, code).unwrap();
- let script = v8::Script::compile(scope, source, None).unwrap();
- let v = script.run(scope)?;
- scope.escape(v).try_into().ok()
- }
-
- /// Grabs a reference to core.js' eventLoopTick & buildCustomError
- fn init_cbs(&mut self, realm: &JsRealm) {
- let (event_loop_tick_cb, build_custom_error_cb) = {
- let scope = &mut realm.handle_scope(self.v8_isolate());
- let context = realm.context();
- let context_local = v8::Local::new(scope, context);
- let global = context_local.global(scope);
- let deno_str =
- v8::String::new_external_onebyte_static(scope, b"Deno").unwrap();
- let core_str =
- v8::String::new_external_onebyte_static(scope, b"core").unwrap();
- let event_loop_tick_str =
- v8::String::new_external_onebyte_static(scope, b"eventLoopTick")
- .unwrap();
- let build_custom_error_str =
- v8::String::new_external_onebyte_static(scope, b"buildCustomError")
- .unwrap();
-
- let deno_obj: v8::Local<v8::Object> = global
- .get(scope, deno_str.into())
- .unwrap()
- .try_into()
- .unwrap();
- let core_obj: v8::Local<v8::Object> = deno_obj
- .get(scope, core_str.into())
- .unwrap()
- .try_into()
- .unwrap();
-
- let event_loop_tick_cb: v8::Local<v8::Function> = core_obj
- .get(scope, event_loop_tick_str.into())
- .unwrap()
- .try_into()
- .unwrap();
- let build_custom_error_cb: v8::Local<v8::Function> = core_obj
- .get(scope, build_custom_error_str.into())
- .unwrap()
- .try_into()
- .unwrap();
- (
- v8::Global::new(scope, event_loop_tick_cb),
- v8::Global::new(scope, build_custom_error_cb),
- )
- };
-
- // Put global handles in the realm's ContextState
- let state_rc = realm.0.state();
- let mut state = state_rc.borrow_mut();
- state
- .js_event_loop_tick_cb
- .replace(Rc::new(event_loop_tick_cb));
- state
- .js_build_custom_error_cb
- .replace(Rc::new(build_custom_error_cb));
- }
-
- /// Returns the runtime's op state, which can be used to maintain ops
- /// and access resources between op calls.
- pub fn op_state(&mut self) -> Rc<RefCell<OpState>> {
- let state = self.inner.state.borrow();
- state.op_state.clone()
- }
-
- /// Executes traditional JavaScript code (traditional = not ES modules).
- ///
- /// The execution takes place on the current global context, so it is possible
- /// to maintain local JS state and invoke this method multiple times.
- ///
- /// `name` can be a filepath or any other string, but it is required to be 7-bit ASCII, eg.
- ///
- /// - "/some/file/path.js"
- /// - "<anon>"
- /// - "[native code]"
- ///
- /// The same `name` value can be used for multiple executions.
- ///
- /// `Error` can usually be downcast to `JsError`.
- pub fn execute_script(
- &mut self,
- name: &'static str,
- source_code: ModuleCode,
- ) -> Result<v8::Global<v8::Value>, Error> {
- self
- .global_realm()
- .execute_script(self.v8_isolate(), name, source_code)
- }
-
- /// Executes traditional JavaScript code (traditional = not ES modules).
- ///
- /// The execution takes place on the current global context, so it is possible
- /// to maintain local JS state and invoke this method multiple times.
- ///
- /// `name` can be a filepath or any other string, but it is required to be 7-bit ASCII, eg.
- ///
- /// - "/some/file/path.js"
- /// - "<anon>"
- /// - "[native code]"
- ///
- /// The same `name` value can be used for multiple executions.
- ///
- /// `Error` can usually be downcast to `JsError`.
- pub fn execute_script_static(
- &mut self,
- name: &'static str,
- source_code: &'static str,
- ) -> Result<v8::Global<v8::Value>, Error> {
- self.global_realm().execute_script(
- self.v8_isolate(),
- name,
- ModuleCode::from_static(source_code),
- )
- }
-
- /// Call a function. If it returns a promise, run the event loop until that
- /// promise is settled. If the promise rejects or there is an uncaught error
- /// in the event loop, return `Err(error)`. Or return `Ok(<await returned>)`.
- pub async fn call_and_await(
- &mut self,
- function: &v8::Global<v8::Function>,
- ) -> Result<v8::Global<v8::Value>, Error> {
- let promise = {
- let scope = &mut self.handle_scope();
- let cb = function.open(scope);
- let this = v8::undefined(scope).into();
- let promise = cb.call(scope, this, &[]);
- if promise.is_none() || scope.is_execution_terminating() {
- let undefined = v8::undefined(scope).into();
- return exception_to_err_result(scope, undefined, false);
- }
- v8::Global::new(scope, promise.unwrap())
- };
- self.resolve_value(promise).await
- }
-
- /// Returns the namespace object of a module.
- ///
- /// This is only available after module evaluation has completed.
- /// This function panics if module has not been instantiated.
- pub fn get_module_namespace(
- &mut self,
- module_id: ModuleId,
- ) -> Result<v8::Global<v8::Object>, Error> {
- self
- .module_map
- .clone()
- .borrow()
- .get_module_namespace(&mut self.handle_scope(), module_id)
- }
-
- /// Registers a callback on the isolate when the memory limits are approached.
- /// Use this to prevent V8 from crashing the process when reaching the limit.
- ///
- /// Calls the closure with the current heap limit and the initial heap limit.
- /// The return value of the closure is set as the new limit.
- pub fn add_near_heap_limit_callback<C>(&mut self, cb: C)
- where
- C: FnMut(usize, usize) -> usize + 'static,
- {
- let boxed_cb = Box::new(RefCell::new(cb));
- let data = boxed_cb.as_ptr() as *mut c_void;
-
- let prev = self
- .allocations
- .near_heap_limit_callback_data
- .replace((boxed_cb, near_heap_limit_callback::<C>));
- if let Some((_, prev_cb)) = prev {
- self
- .v8_isolate()
- .remove_near_heap_limit_callback(prev_cb, 0);
- }
-
- self
- .v8_isolate()
- .add_near_heap_limit_callback(near_heap_limit_callback::<C>, data);
- }
-
- pub fn remove_near_heap_limit_callback(&mut self, heap_limit: usize) {
- if let Some((_, cb)) = self.allocations.near_heap_limit_callback_data.take()
- {
- self
- .v8_isolate()
- .remove_near_heap_limit_callback(cb, heap_limit);
- }
- }
-
- fn pump_v8_message_loop(&mut self) -> Result<(), Error> {
- let scope = &mut self.handle_scope();
- while v8::Platform::pump_message_loop(
- &v8::V8::get_current_platform(),
- scope,
- false, // don't block if there are no tasks
- ) {
- // do nothing
- }
-
- let tc_scope = &mut v8::TryCatch::new(scope);
- tc_scope.perform_microtask_checkpoint();
- match tc_scope.exception() {
- None => Ok(()),
- Some(exception) => exception_to_err_result(tc_scope, exception, false),
- }
- }
-
- pub fn maybe_init_inspector(&mut self) {
- if self.inner.state.borrow().inspector.is_some() {
- return;
- }
-
- let context = self.global_context();
- let scope = &mut v8::HandleScope::with_context(
- self.inner.v8_isolate.as_mut(),
- context.clone(),
- );
- let context = v8::Local::new(scope, context);
-
- let mut state = self.inner.state.borrow_mut();
- state.inspector =
- Some(JsRuntimeInspector::new(scope, context, self.is_main));
- }
-
- pub fn poll_value(
- &mut self,
- global: &v8::Global<v8::Value>,
- cx: &mut Context,
- ) -> Poll<Result<v8::Global<v8::Value>, Error>> {
- let state = self.poll_event_loop(cx, false);
-
- let mut scope = self.handle_scope();
- let local = v8::Local::<v8::Value>::new(&mut scope, global);
-
- if let Ok(promise) = v8::Local::<v8::Promise>::try_from(local) {
- match promise.state() {
- v8::PromiseState::Pending => match state {
- Poll::Ready(Ok(_)) => {
- let msg = "Promise resolution is still pending but the event loop has already resolved.";
- Poll::Ready(Err(generic_error(msg)))
- }
- Poll::Ready(Err(e)) => Poll::Ready(Err(e)),
- Poll::Pending => Poll::Pending,
- },
- v8::PromiseState::Fulfilled => {
- let value = promise.result(&mut scope);
- let value_handle = v8::Global::new(&mut scope, value);
- Poll::Ready(Ok(value_handle))
- }
- v8::PromiseState::Rejected => {
- let exception = promise.result(&mut scope);
- Poll::Ready(exception_to_err_result(&mut scope, exception, false))
- }
- }
- } else {
- let value_handle = v8::Global::new(&mut scope, local);
- Poll::Ready(Ok(value_handle))
- }
- }
-
- /// Waits for the given value to resolve while polling the event loop.
- ///
- /// This future resolves when either the value is resolved or the event loop runs to
- /// completion.
- pub async fn resolve_value(
- &mut self,
- global: v8::Global<v8::Value>,
- ) -> Result<v8::Global<v8::Value>, Error> {
- poll_fn(|cx| self.poll_value(&global, cx)).await
- }
-
- /// Runs event loop to completion
- ///
- /// This future resolves when:
- /// - there are no more pending dynamic imports
- /// - there are no more pending ops
- /// - there are no more active inspector sessions (only if `wait_for_inspector` is set to true)
- pub async fn run_event_loop(
- &mut self,
- wait_for_inspector: bool,
- ) -> Result<(), Error> {
- poll_fn(|cx| self.poll_event_loop(cx, wait_for_inspector)).await
- }
-
- /// Runs a single tick of event loop
- ///
- /// If `wait_for_inspector` is set to true event loop
- /// will return `Poll::Pending` if there are active inspector sessions.
- pub fn poll_event_loop(
- &mut self,
- cx: &mut Context,
- wait_for_inspector: bool,
- ) -> Poll<Result<(), Error>> {
- let has_inspector: bool;
-
- {
- let state = self.inner.state.borrow();
- has_inspector = state.inspector.is_some();
- state.op_state.borrow().waker.register(cx.waker());
- }
-
- if has_inspector {
- // We poll the inspector first.
- let _ = self.inspector().borrow().poll_sessions(Some(cx)).unwrap();
- }
-
- let module_map = self.module_map.clone();
- self.pump_v8_message_loop()?;
-
- // Dynamic module loading - ie. modules loaded using "import()"
- {
- // Run in a loop so that dynamic imports that only depend on another
- // dynamic import can be resolved in this event loop iteration.
- //
- // For example, a dynamically imported module like the following can be
- // immediately resolved after `dependency.ts` is fully evaluated, but it
- // wouldn't if not for this loop.
- //
- // await delay(1000);
- // await import("./dependency.ts");
- // console.log("test")
- //
- loop {
- let poll_imports = self.prepare_dyn_imports(cx)?;
- assert!(poll_imports.is_ready());
-
- let poll_imports = self.poll_dyn_imports(cx)?;
- assert!(poll_imports.is_ready());
-
- if !self.evaluate_dyn_imports() {
- break;
- }
- }
- }
-
- // Resolve async ops, run all next tick callbacks and macrotasks callbacks
- // and only then check for any promise exceptions (`unhandledrejection`
- // handlers are run in macrotasks callbacks so we need to let them run
- // first).
- self.do_js_event_loop_tick(cx)?;
- self.check_promise_rejections()?;
-
- // Event loop middlewares
- let mut maybe_scheduling = false;
- {
- let op_state = self.inner.state.borrow().op_state.clone();
- for f in &self.event_loop_middlewares {
- if f(op_state.clone(), cx) {
- maybe_scheduling = true;
- }
- }
- }
-
- // Top level module
- self.evaluate_pending_module();
-
- let pending_state = self.event_loop_pending_state();
- if !pending_state.is_pending() && !maybe_scheduling {
- if has_inspector {
- let inspector = self.inspector();
- let has_active_sessions = inspector.borrow().has_active_sessions();
- let has_blocking_sessions = inspector.borrow().has_blocking_sessions();
-
- if wait_for_inspector && has_active_sessions {
- // If there are no blocking sessions (eg. REPL) we can now notify
- // debugger that the program has finished running and we're ready
- // to exit the process once debugger disconnects.
- if !has_blocking_sessions {
- let context = self.global_context();
- let scope = &mut self.handle_scope();
- inspector.borrow_mut().context_destroyed(scope, context);
- println!("Program finished. Waiting for inspector to disconnect to exit the process...");
- }
-
- return Poll::Pending;
- }
- }
-
- return Poll::Ready(Ok(()));
- }
-
- let state = self.inner.state.borrow();
-
- // Check if more async ops have been dispatched
- // during this turn of event loop.
- // If there are any pending background tasks, we also wake the runtime to
- // make sure we don't miss them.
- // TODO(andreubotella) The event loop will spin as long as there are pending
- // background tasks. We should look into having V8 notify us when a
- // background task is done.
- if pending_state.has_pending_background_tasks
- || pending_state.has_tick_scheduled
- || maybe_scheduling
- {
- state.op_state.borrow().waker.wake();
- }
-
- drop(state);
-
- if pending_state.has_pending_module_evaluation {
- if pending_state.has_pending_refed_ops
- || pending_state.has_pending_dyn_imports
- || pending_state.has_pending_dyn_module_evaluation
- || pending_state.has_pending_background_tasks
- || pending_state.has_tick_scheduled
- || maybe_scheduling
- {
- // pass, will be polled again
- } else {
- let scope = &mut self.handle_scope();
- let messages = module_map.borrow().find_stalled_top_level_await(scope);
- // We are gonna print only a single message to provide a nice formatting
- // with source line of offending promise shown. Once user fixed it, then
- // they will get another error message for the next promise (but this
- // situation is gonna be very rare, if ever happening).
- assert!(!messages.is_empty());
- let msg = v8::Local::new(scope, messages[0].clone());
- let js_error = JsError::from_v8_message(scope, msg);
- return Poll::Ready(Err(js_error.into()));
- }
- }
-
- if pending_state.has_pending_dyn_module_evaluation {
- if pending_state.has_pending_refed_ops
- || pending_state.has_pending_dyn_imports
- || pending_state.has_pending_background_tasks
- || pending_state.has_tick_scheduled
- {
- // pass, will be polled again
- } else if self.inner.state.borrow().dyn_module_evaluate_idle_counter >= 1
- {
- let scope = &mut self.handle_scope();
- let messages = module_map.borrow().find_stalled_top_level_await(scope);
- // We are gonna print only a single message to provide a nice formatting
- // with source line of offending promise shown. Once user fixed it, then
- // they will get another error message for the next promise (but this
- // situation is gonna be very rare, if ever happening).
- assert!(!messages.is_empty());
- let msg = v8::Local::new(scope, messages[0].clone());
- let js_error = JsError::from_v8_message(scope, msg);
- return Poll::Ready(Err(js_error.into()));
- } else {
- let mut state = self.inner.state.borrow_mut();
- // Delay the above error by one spin of the event loop. A dynamic import
- // evaluation may complete during this, in which case the counter will
- // reset.
- state.dyn_module_evaluate_idle_counter += 1;
- state.op_state.borrow().waker.wake();
- }
- }
-
- Poll::Pending
- }
-
- fn event_loop_pending_state(&mut self) -> EventLoopPendingState {
- let mut scope = v8::HandleScope::new(self.inner.v8_isolate.as_mut());
- EventLoopPendingState::new(
- &mut scope,
- &mut self.inner.state.borrow_mut(),
- &self.module_map.borrow(),
- )
- }
-}
-
-impl JsRuntimeForSnapshot {
- pub fn new(
- mut options: RuntimeOptions,
- runtime_snapshot_options: RuntimeSnapshotOptions,
- ) -> JsRuntimeForSnapshot {
- JsRuntime::init_v8(options.v8_platform.take(), true);
- JsRuntimeForSnapshot(JsRuntime::new_inner(
- options,
- true,
- runtime_snapshot_options.snapshot_module_load_cb,
- ))
- }
-
- /// Takes a snapshot and consumes the runtime.
- ///
- /// `Error` can usually be downcast to `JsError`.
- pub fn snapshot(mut self) -> v8::StartupData {
- // Ensure there are no live inspectors to prevent crashes.
- self.inner.prepare_for_cleanup();
-
- // Set the context to be snapshot's default context
- {
- let context = self.global_context();
- let mut scope = self.handle_scope();
- let local_context = v8::Local::new(&mut scope, context);
- scope.set_default_context(local_context);
- }
-
- // Serialize the module map and store its data in the snapshot.
- {
- let snapshotted_data = {
- // `self.module_map` points directly to the v8 isolate data slot, which
- // we must explicitly drop before destroying the isolate. We have to
- // take and drop this `Rc` before that.
- let module_map_rc = std::mem::take(&mut self.module_map);
- let module_map = module_map_rc.borrow();
- module_map.serialize_for_snapshotting(&mut self.handle_scope())
- };
-
- let context = self.global_context();
- let mut scope = self.handle_scope();
- snapshot_util::set_snapshotted_data(
- &mut scope,
- context,
- snapshotted_data,
- );
- }
-
- self
- .0
- .inner
- .prepare_for_snapshot()
- .create_blob(v8::FunctionCodeHandling::Keep)
- .unwrap()
- }
-}
-
-#[derive(Clone, Copy, PartialEq, Eq, Debug)]
-pub(crate) struct EventLoopPendingState {
- has_pending_refed_ops: bool,
- has_pending_dyn_imports: bool,
- has_pending_dyn_module_evaluation: bool,
- has_pending_module_evaluation: bool,
- has_pending_background_tasks: bool,
- has_tick_scheduled: bool,
-}
-impl EventLoopPendingState {
- pub fn new(
- scope: &mut v8::HandleScope<()>,
- state: &mut JsRuntimeState,
- module_map: &ModuleMap,
- ) -> EventLoopPendingState {
- let mut num_unrefed_ops = 0;
- let mut num_pending_ops = 0;
- for realm in &state.known_realms {
- num_unrefed_ops += realm.num_unrefed_ops();
- num_pending_ops += realm.num_pending_ops();
- }
-
- EventLoopPendingState {
- has_pending_refed_ops: num_pending_ops > num_unrefed_ops,
- has_pending_dyn_imports: module_map.has_pending_dynamic_imports(),
- has_pending_dyn_module_evaluation: !state
- .pending_dyn_mod_evaluate
- .is_empty(),
- has_pending_module_evaluation: state.pending_mod_evaluate.is_some(),
- has_pending_background_tasks: scope.has_pending_background_tasks(),
- has_tick_scheduled: state.has_tick_scheduled,
- }
- }
-
- pub fn is_pending(&self) -> bool {
- self.has_pending_refed_ops
- || self.has_pending_dyn_imports
- || self.has_pending_dyn_module_evaluation
- || self.has_pending_module_evaluation
- || self.has_pending_background_tasks
- || self.has_tick_scheduled
- }
-}
-
-extern "C" fn near_heap_limit_callback<F>(
- data: *mut c_void,
- current_heap_limit: usize,
- initial_heap_limit: usize,
-) -> usize
-where
- F: FnMut(usize, usize) -> usize,
-{
- // SAFETY: The data is a pointer to the Rust callback function. It is stored
- // in `JsRuntime::allocations` and thus is guaranteed to outlive the isolate.
- let callback = unsafe { &mut *(data as *mut F) };
- callback(current_heap_limit, initial_heap_limit)
-}
-
-impl JsRuntimeState {
- pub(crate) fn inspector(&self) -> Rc<RefCell<JsRuntimeInspector>> {
- self.inspector.as_ref().unwrap().clone()
- }
-
- /// Called by `bindings::host_import_module_dynamically_callback`
- /// after initiating new dynamic import load.
- pub fn notify_new_dynamic_import(&mut self) {
- // Notify event loop to poll again soon.
- self.op_state.borrow().waker.wake();
- }
-}
-
-// Related to module loading
-impl JsRuntime {
- pub(crate) fn instantiate_module(
- &mut self,
- id: ModuleId,
- ) -> Result<(), v8::Global<v8::Value>> {
- self
- .module_map
- .clone()
- .borrow_mut()
- .instantiate_module(&mut self.handle_scope(), id)
- }
-
- fn dynamic_import_module_evaluate(
- &mut self,
- load_id: ModuleLoadId,
- id: ModuleId,
- ) -> Result<(), Error> {
- let module_handle = self
- .module_map
- .borrow()
- .get_handle(id)
- .expect("ModuleInfo not found");
-
- let status = {
- let scope = &mut self.handle_scope();
- let module = module_handle.open(scope);
- module.get_status()
- };
-
- match status {
- v8::ModuleStatus::Instantiated | v8::ModuleStatus::Evaluated => {}
- _ => return Ok(()),
- }
-
- // IMPORTANT: Top-level-await is enabled, which means that return value
- // of module evaluation is a promise.
- //
- // This promise is internal, and not the same one that gets returned to
- // the user. We add an empty `.catch()` handler so that it does not result
- // in an exception if it rejects. That will instead happen for the other
- // promise if not handled by the user.
- //
- // For more details see:
- // https://github.com/denoland/deno/issues/4908
- // https://v8.dev/features/top-level-await#module-execution-order
- let global_realm =
- self.inner.state.borrow_mut().global_realm.clone().unwrap();
- let scope = &mut global_realm.handle_scope(&mut self.inner.v8_isolate);
- let tc_scope = &mut v8::TryCatch::new(scope);
- let module = v8::Local::new(tc_scope, &module_handle);
- let maybe_value = module.evaluate(tc_scope);
-
- // Update status after evaluating.
- let status = module.get_status();
-
- if let Some(value) = maybe_value {
- assert!(
- status == v8::ModuleStatus::Evaluated
- || status == v8::ModuleStatus::Errored
- );
- let promise = v8::Local::<v8::Promise>::try_from(value)
- .expect("Expected to get promise as module evaluation result");
- let empty_fn = bindings::create_empty_fn(tc_scope).unwrap();
- promise.catch(tc_scope, empty_fn);
- let promise_global = v8::Global::new(tc_scope, promise);
- let module_global = v8::Global::new(tc_scope, module);
-
- let dyn_import_mod_evaluate = DynImportModEvaluate {
- load_id,
- module_id: id,
- promise: promise_global,
- module: module_global,
- };
-
- self
- .inner
- .state
- .borrow_mut()
- .pending_dyn_mod_evaluate
- .push(dyn_import_mod_evaluate);
- } else if tc_scope.has_terminated() || tc_scope.is_execution_terminating() {
- return Err(
- generic_error("Cannot evaluate dynamically imported module, because JavaScript execution has been terminated.")
- );
- } else {
- assert!(status == v8::ModuleStatus::Errored);
- }
-
- Ok(())
- }
-
- // TODO(bartlomieju): make it return `ModuleEvaluationFuture`?
- /// Evaluates an already instantiated ES module.
- ///
- /// Returns a receiver handle that resolves when module promise resolves.
- /// Implementors must manually call [`JsRuntime::run_event_loop`] to drive
- /// module evaluation future.
- ///
- /// `Error` can usually be downcast to `JsError` and should be awaited and
- /// checked after [`JsRuntime::run_event_loop`] completion.
- ///
- /// This function panics if module has not been instantiated.
- pub fn mod_evaluate(
- &mut self,
- id: ModuleId,
- ) -> oneshot::Receiver<Result<(), Error>> {
- let global_realm = self.global_realm();
- let state_rc = self.inner.state.clone();
- let module_map_rc = self.module_map.clone();
- let scope = &mut self.handle_scope();
- let tc_scope = &mut v8::TryCatch::new(scope);
-
- let module = module_map_rc
- .borrow()
- .get_handle(id)
- .map(|handle| v8::Local::new(tc_scope, handle))
- .expect("ModuleInfo not found");
- let mut status = module.get_status();
- assert_eq!(
- status,
- v8::ModuleStatus::Instantiated,
- "Module not instantiated {id}"
- );
-
- let (sender, receiver) = oneshot::channel();
-
- // IMPORTANT: Top-level-await is enabled, which means that return value
- // of module evaluation is a promise.
- //
- // Because that promise is created internally by V8, when error occurs during
- // module evaluation the promise is rejected, and since the promise has no rejection
- // handler it will result in call to `bindings::promise_reject_callback` adding
- // the promise to pending promise rejection table - meaning JsRuntime will return
- // error on next poll().
- //
- // This situation is not desirable as we want to manually return error at the
- // end of this function to handle it further. It means we need to manually
- // remove this promise from pending promise rejection table.
- //
- // For more details see:
- // https://github.com/denoland/deno/issues/4908
- // https://v8.dev/features/top-level-await#module-execution-order
- {
- let mut state = state_rc.borrow_mut();
- assert!(
- state.pending_mod_evaluate.is_none(),
- "There is already pending top level module evaluation"
- );
- state.pending_mod_evaluate = Some(ModEvaluate {
- promise: None,
- has_evaluated: false,
- handled_promise_rejections: vec![],
- sender,
- });
- }
-
- let maybe_value = module.evaluate(tc_scope);
- {
- let mut state = state_rc.borrow_mut();
- let pending_mod_evaluate = state.pending_mod_evaluate.as_mut().unwrap();
- pending_mod_evaluate.has_evaluated = true;
- }
-
- // Update status after evaluating.
- status = module.get_status();
-
- let has_dispatched_exception =
- state_rc.borrow_mut().dispatched_exception.is_some();
- if has_dispatched_exception {
- // This will be overridden in `exception_to_err_result()`.
- let exception = v8::undefined(tc_scope).into();
- let pending_mod_evaluate = {
- let mut state = state_rc.borrow_mut();
- state.pending_mod_evaluate.take().unwrap()
- };
- pending_mod_evaluate
- .sender
- .send(exception_to_err_result(tc_scope, exception, false))
- .expect("Failed to send module evaluation error.");
- } else if let Some(value) = maybe_value {
- assert!(
- status == v8::ModuleStatus::Evaluated
- || status == v8::ModuleStatus::Errored
- );
- let promise = v8::Local::<v8::Promise>::try_from(value)
- .expect("Expected to get promise as module evaluation result");
- let promise_global = v8::Global::new(tc_scope, promise);
- let mut state = state_rc.borrow_mut();
- {
- let pending_mod_evaluate = state.pending_mod_evaluate.as_ref().unwrap();
- let pending_rejection_was_already_handled = pending_mod_evaluate
- .handled_promise_rejections
- .contains(&promise_global);
- if !pending_rejection_was_already_handled {
- global_realm
- .0
- .state()
- .borrow_mut()
- .pending_promise_rejections
- .retain(|(key, _)| key != &promise_global);
- }
- }
- let promise_global = v8::Global::new(tc_scope, promise);
- state.pending_mod_evaluate.as_mut().unwrap().promise =
- Some(promise_global);
- tc_scope.perform_microtask_checkpoint();
- } else if tc_scope.has_terminated() || tc_scope.is_execution_terminating() {
- let pending_mod_evaluate = {
- let mut state = state_rc.borrow_mut();
- state.pending_mod_evaluate.take().unwrap()
- };
- pending_mod_evaluate.sender.send(Err(
- generic_error("Cannot evaluate module, because JavaScript execution has been terminated.")
- )).expect("Failed to send module evaluation error.");
- } else {
- assert!(status == v8::ModuleStatus::Errored);
- }
-
- receiver
- }
-
- fn dynamic_import_reject(
- &mut self,
- id: ModuleLoadId,
- exception: v8::Global<v8::Value>,
- ) {
- let module_map_rc = self.module_map.clone();
- let scope = &mut self.handle_scope();
-
- let resolver_handle = module_map_rc
- .borrow_mut()
- .dynamic_import_map
- .remove(&id)
- .expect("Invalid dynamic import id");
- let resolver = resolver_handle.open(scope);
-
- // IMPORTANT: No borrows to `ModuleMap` can be held at this point because
- // rejecting the promise might initiate another `import()` which will
- // in turn call `bindings::host_import_module_dynamically_callback` which
- // will reach into `ModuleMap` from within the isolate.
- let exception = v8::Local::new(scope, exception);
- resolver.reject(scope, exception).unwrap();
- scope.perform_microtask_checkpoint();
- }
-
- fn dynamic_import_resolve(&mut self, id: ModuleLoadId, mod_id: ModuleId) {
- let state_rc = self.inner.state.clone();
- let module_map_rc = self.module_map.clone();
- let scope = &mut self.handle_scope();
-
- let resolver_handle = module_map_rc
- .borrow_mut()
- .dynamic_import_map
- .remove(&id)
- .expect("Invalid dynamic import id");
- let resolver = resolver_handle.open(scope);
-
- let module = {
- module_map_rc
- .borrow()
- .get_handle(mod_id)
- .map(|handle| v8::Local::new(scope, handle))
- .expect("Dyn import module info not found")
- };
- // Resolution success
- assert_eq!(module.get_status(), v8::ModuleStatus::Evaluated);
-
- // IMPORTANT: No borrows to `ModuleMap` can be held at this point because
- // resolving the promise might initiate another `import()` which will
- // in turn call `bindings::host_import_module_dynamically_callback` which
- // will reach into `ModuleMap` from within the isolate.
- let module_namespace = module.get_module_namespace();
- resolver.resolve(scope, module_namespace).unwrap();
- state_rc.borrow_mut().dyn_module_evaluate_idle_counter = 0;
- scope.perform_microtask_checkpoint();
- }
-
- fn prepare_dyn_imports(
- &mut self,
- cx: &mut Context,
- ) -> Poll<Result<(), Error>> {
- if self
- .module_map
- .borrow()
- .preparing_dynamic_imports
- .is_empty()
- {
- return Poll::Ready(Ok(()));
- }
-
- loop {
- let poll_result = self
- .module_map
- .borrow_mut()
- .preparing_dynamic_imports
- .poll_next_unpin(cx);
-
- if let Poll::Ready(Some(prepare_poll)) = poll_result {
- let dyn_import_id = prepare_poll.0;
- let prepare_result = prepare_poll.1;
-
- match prepare_result {
- Ok(load) => {
- self
- .module_map
- .borrow_mut()
- .pending_dynamic_imports
- .push(load.into_future());
- }
- Err(err) => {
- let exception = to_v8_type_error(&mut self.handle_scope(), err);
- self.dynamic_import_reject(dyn_import_id, exception);
- }
- }
- // Continue polling for more prepared dynamic imports.
- continue;
- }
-
- // There are no active dynamic import loads, or none are ready.
- return Poll::Ready(Ok(()));
- }
- }
-
- fn poll_dyn_imports(&mut self, cx: &mut Context) -> Poll<Result<(), Error>> {
- if self.module_map.borrow().pending_dynamic_imports.is_empty() {
- return Poll::Ready(Ok(()));
- }
-
- loop {
- let poll_result = self
- .module_map
- .borrow_mut()
- .pending_dynamic_imports
- .poll_next_unpin(cx);
-
- if let Poll::Ready(Some(load_stream_poll)) = poll_result {
- let maybe_result = load_stream_poll.0;
- let mut load = load_stream_poll.1;
- let dyn_import_id = load.id;
-
- if let Some(load_stream_result) = maybe_result {
- match load_stream_result {
- Ok((request, info)) => {
- // A module (not necessarily the one dynamically imported) has been
- // fetched. Create and register it, and if successful, poll for the
- // next recursive-load event related to this dynamic import.
- let register_result = load.register_and_recurse(
- &mut self.handle_scope(),
- &request,
- info,
- );
-
- match register_result {
- Ok(()) => {
- // Keep importing until it's fully drained
- self
- .module_map
- .borrow_mut()
- .pending_dynamic_imports
- .push(load.into_future());
- }
- Err(err) => {
- let exception = match err {
- ModuleError::Exception(e) => e,
- ModuleError::Other(e) => {
- to_v8_type_error(&mut self.handle_scope(), e)
- }
- };
- self.dynamic_import_reject(dyn_import_id, exception)
- }
- }
- }
- Err(err) => {
- // A non-javascript error occurred; this could be due to a an invalid
- // module specifier, or a problem with the source map, or a failure
- // to fetch the module source code.
- let exception = to_v8_type_error(&mut self.handle_scope(), err);
- self.dynamic_import_reject(dyn_import_id, exception);
- }
- }
- } else {
- // The top-level module from a dynamic import has been instantiated.
- // Load is done.
- let module_id =
- load.root_module_id.expect("Root module should be loaded");
- let result = self.instantiate_module(module_id);
- if let Err(exception) = result {
- self.dynamic_import_reject(dyn_import_id, exception);
- }
- self.dynamic_import_module_evaluate(dyn_import_id, module_id)?;
- }
-
- // Continue polling for more ready dynamic imports.
- continue;
- }
-
- // There are no active dynamic import loads, or none are ready.
- return Poll::Ready(Ok(()));
- }
- }
-
- /// "deno_core" runs V8 with Top Level Await enabled. It means that each
- /// module evaluation returns a promise from V8.
- /// Feature docs: https://v8.dev/features/top-level-await
- ///
- /// This promise resolves after all dependent modules have also
- /// resolved. Each dependent module may perform calls to "import()" and APIs
- /// using async ops will add futures to the runtime's event loop.
- /// It means that the promise returned from module evaluation will
- /// resolve only after all futures in the event loop are done.
- ///
- /// Thus during turn of event loop we need to check if V8 has
- /// resolved or rejected the promise. If the promise is still pending
- /// then another turn of event loop must be performed.
- fn evaluate_pending_module(&mut self) {
- let maybe_module_evaluation =
- self.inner.state.borrow_mut().pending_mod_evaluate.take();
-
- if maybe_module_evaluation.is_none() {
- return;
- }
-
- let mut module_evaluation = maybe_module_evaluation.unwrap();
- let state_rc = self.inner.state.clone();
- let scope = &mut self.handle_scope();
-
- let promise_global = module_evaluation.promise.clone().unwrap();
- let promise = promise_global.open(scope);
- let promise_state = promise.state();
-
- match promise_state {
- v8::PromiseState::Pending => {
- // NOTE: `poll_event_loop` will decide if
- // runtime would be woken soon
- state_rc.borrow_mut().pending_mod_evaluate = Some(module_evaluation);
- }
- v8::PromiseState::Fulfilled => {
- scope.perform_microtask_checkpoint();
- // Receiver end might have been already dropped, ignore the result
- let _ = module_evaluation.sender.send(Ok(()));
- module_evaluation.handled_promise_rejections.clear();
- }
- v8::PromiseState::Rejected => {
- let exception = promise.result(scope);
- scope.perform_microtask_checkpoint();
-
- // Receiver end might have been already dropped, ignore the result
- if module_evaluation
- .handled_promise_rejections
- .contains(&promise_global)
- {
- let _ = module_evaluation.sender.send(Ok(()));
- module_evaluation.handled_promise_rejections.clear();
- } else {
- let _ = module_evaluation
- .sender
- .send(exception_to_err_result(scope, exception, false));
- }
- }
- }
- }
-
- // Returns true if some dynamic import was resolved.
- fn evaluate_dyn_imports(&mut self) -> bool {
- let pending = std::mem::take(
- &mut self.inner.state.borrow_mut().pending_dyn_mod_evaluate,
- );
- if pending.is_empty() {
- return false;
- }
- let mut resolved_any = false;
- let mut still_pending = vec![];
- for pending_dyn_evaluate in pending {
- let maybe_result = {
- let scope = &mut self.handle_scope();
-
- let module_id = pending_dyn_evaluate.module_id;
- let promise = pending_dyn_evaluate.promise.open(scope);
- let _module = pending_dyn_evaluate.module.open(scope);
- let promise_state = promise.state();
-
- match promise_state {
- v8::PromiseState::Pending => {
- still_pending.push(pending_dyn_evaluate);
- None
- }
- v8::PromiseState::Fulfilled => {
- Some(Ok((pending_dyn_evaluate.load_id, module_id)))
- }
- v8::PromiseState::Rejected => {
- let exception = promise.result(scope);
- let exception = v8::Global::new(scope, exception);
- Some(Err((pending_dyn_evaluate.load_id, exception)))
- }
- }
- };
-
- if let Some(result) = maybe_result {
- resolved_any = true;
- match result {
- Ok((dyn_import_id, module_id)) => {
- self.dynamic_import_resolve(dyn_import_id, module_id);
- }
- Err((dyn_import_id, exception)) => {
- self.dynamic_import_reject(dyn_import_id, exception);
- }
- }
- }
- }
- self.inner.state.borrow_mut().pending_dyn_mod_evaluate = still_pending;
- resolved_any
- }
-
- /// Asynchronously load specified module and all of its dependencies.
- ///
- /// The module will be marked as "main", and because of that
- /// "import.meta.main" will return true when checked inside that module.
- ///
- /// User must call [`JsRuntime::mod_evaluate`] with returned `ModuleId`
- /// manually after load is finished.
- pub async fn load_main_module(
- &mut self,
- specifier: &ModuleSpecifier,
- code: Option<ModuleCode>,
- ) -> Result<ModuleId, Error> {
- let module_map_rc = self.module_map.clone();
- if let Some(code) = code {
- let specifier = specifier.as_str().to_owned().into();
- let scope = &mut self.handle_scope();
- // true for main module
- module_map_rc
- .borrow_mut()
- .new_es_module(scope, true, specifier, code, false)
- .map_err(|e| match e {
- ModuleError::Exception(exception) => {
- let exception = v8::Local::new(scope, exception);
- exception_to_err_result::<()>(scope, exception, false).unwrap_err()
- }
- ModuleError::Other(error) => error,
- })?;
- }
-
- let mut load =
- ModuleMap::load_main(module_map_rc.clone(), &specifier).await?;
-
- while let Some(load_result) = load.next().await {
- let (request, info) = load_result?;
- let scope = &mut self.handle_scope();
- load.register_and_recurse(scope, &request, info).map_err(
- |e| match e {
- ModuleError::Exception(exception) => {
- let exception = v8::Local::new(scope, exception);
- exception_to_err_result::<()>(scope, exception, false).unwrap_err()
- }
- ModuleError::Other(error) => error,
- },
- )?;
- }
-
- let root_id = load.root_module_id.expect("Root module should be loaded");
- self.instantiate_module(root_id).map_err(|e| {
- let scope = &mut self.handle_scope();
- let exception = v8::Local::new(scope, e);
- exception_to_err_result::<()>(scope, exception, false).unwrap_err()
- })?;
- Ok(root_id)
- }
-
- /// Asynchronously load specified ES module and all of its dependencies.
- ///
- /// This method is meant to be used when loading some utility code that
- /// might be later imported by the main module (ie. an entry point module).
- ///
- /// User must call [`JsRuntime::mod_evaluate`] with returned `ModuleId`
- /// manually after load is finished.
- pub async fn load_side_module(
- &mut self,
- specifier: &ModuleSpecifier,
- code: Option<ModuleCode>,
- ) -> Result<ModuleId, Error> {
- let module_map_rc = self.module_map.clone();
- if let Some(code) = code {
- let specifier = specifier.as_str().to_owned().into();
- let scope = &mut self.handle_scope();
- // false for side module (not main module)
- module_map_rc
- .borrow_mut()
- .new_es_module(scope, false, specifier, code, false)
- .map_err(|e| match e {
- ModuleError::Exception(exception) => {
- let exception = v8::Local::new(scope, exception);
- exception_to_err_result::<()>(scope, exception, false).unwrap_err()
- }
- ModuleError::Other(error) => error,
- })?;
- }
-
- let mut load =
- ModuleMap::load_side(module_map_rc.clone(), &specifier).await?;
-
- while let Some(load_result) = load.next().await {
- let (request, info) = load_result?;
- let scope = &mut self.handle_scope();
- load.register_and_recurse(scope, &request, info).map_err(
- |e| match e {
- ModuleError::Exception(exception) => {
- let exception = v8::Local::new(scope, exception);
- exception_to_err_result::<()>(scope, exception, false).unwrap_err()
- }
- ModuleError::Other(error) => error,
- },
- )?;
- }
-
- let root_id = load.root_module_id.expect("Root module should be loaded");
- self.instantiate_module(root_id).map_err(|e| {
- let scope = &mut self.handle_scope();
- let exception = v8::Local::new(scope, e);
- exception_to_err_result::<()>(scope, exception, false).unwrap_err()
- })?;
- Ok(root_id)
- }
-
- fn check_promise_rejections(&mut self) -> Result<(), Error> {
- let state = self.inner.state.clone();
- let scope = &mut self.handle_scope();
- let state = state.borrow();
- for realm in &state.known_realms {
- realm.check_promise_rejections(scope)?;
- }
- Ok(())
- }
-
- // Polls pending ops and then runs `Deno.core.eventLoopTick` callback.
- fn do_js_event_loop_tick(&mut self, cx: &mut Context) -> Result<(), Error> {
- // Handle responses for each realm.
- let state = self.inner.state.clone();
- let isolate = &mut self.inner.v8_isolate;
- let realm_count = state.borrow().known_realms.len();
- for realm_idx in 0..realm_count {
- let realm = state.borrow().known_realms.get(realm_idx).unwrap().clone();
- let context_state = realm.state();
- let mut context_state = context_state.borrow_mut();
- let scope = &mut realm.handle_scope(isolate);
-
- // We return async responses to JS in unbounded batches (may change),
- // each batch is a flat vector of tuples:
- // `[promise_id1, op_result1, promise_id2, op_result2, ...]`
- // promise_id is a simple integer, op_result is an ops::OpResult
- // which contains a value OR an error, encoded as a tuple.
- // This batch is received in JS via the special `arguments` variable
- // and then each tuple is used to resolve or reject promises
- //
- // This can handle 15 promises futures in a single batch without heap
- // allocations.
- let mut args: SmallVec<[v8::Local<v8::Value>; 32]> =
- SmallVec::with_capacity(32);
-
- loop {
- let Poll::Ready(item) = context_state.pending_ops.poll_join_next(cx) else {
- break;
- };
- // TODO(mmastrac): If this task is really errored, things could be pretty bad
- let (promise_id, op_id, mut resp) = item.unwrap();
- state
- .borrow()
- .op_state
- .borrow()
- .tracker
- .track_async_completed(op_id);
- context_state.unrefed_ops.remove(&promise_id);
- args.push(v8::Integer::new(scope, promise_id).into());
- args.push(match resp.to_v8(scope) {
- Ok(v) => v,
- Err(e) => OpResult::Err(OpError::new(&|_| "TypeError", e.into()))
- .to_v8(scope)
- .unwrap(),
- });
- }
-
- let has_tick_scheduled =
- v8::Boolean::new(scope, self.inner.state.borrow().has_tick_scheduled);
- args.push(has_tick_scheduled.into());
-
- let js_event_loop_tick_cb_handle =
- context_state.js_event_loop_tick_cb.clone().unwrap();
- let tc_scope = &mut v8::TryCatch::new(scope);
- let js_event_loop_tick_cb = js_event_loop_tick_cb_handle.open(tc_scope);
- let this = v8::undefined(tc_scope).into();
- drop(context_state);
- js_event_loop_tick_cb.call(tc_scope, this, args.as_slice());
-
- if let Some(exception) = tc_scope.exception() {
- // TODO(@andreubotella): Returning here can cause async ops in other
- // realms to never resolve.
- return exception_to_err_result(tc_scope, exception, false);
- }
-
- if tc_scope.has_terminated() || tc_scope.is_execution_terminating() {
- return Ok(());
- }
- }
-
- Ok(())
- }
-}
diff --git a/core/runtime/mod.rs b/core/runtime/mod.rs
deleted file mode 100644
index aa546b8c7..000000000
--- a/core/runtime/mod.rs
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-mod bindings;
-mod jsrealm;
-mod jsruntime;
-#[doc(hidden)]
-pub mod ops;
-mod snapshot_util;
-
-#[cfg(test)]
-mod tests;
-
-pub const V8_WRAPPER_TYPE_INDEX: i32 = 0;
-pub const V8_WRAPPER_OBJECT_INDEX: i32 = 1;
-
-pub(crate) use jsrealm::ContextState;
-pub use jsrealm::JsRealm;
-pub use jsruntime::CompiledWasmModuleStore;
-pub use jsruntime::CrossIsolateStore;
-pub(crate) use jsruntime::InitMode;
-pub use jsruntime::JsRuntime;
-pub use jsruntime::JsRuntimeForSnapshot;
-pub use jsruntime::JsRuntimeState;
-pub use jsruntime::RuntimeOptions;
-pub use jsruntime::RuntimeSnapshotOptions;
-pub use jsruntime::SharedArrayBufferStore;
-pub use jsruntime::Snapshot;
-pub use snapshot_util::create_snapshot;
-pub use snapshot_util::get_js_files;
-pub use snapshot_util::CreateSnapshotOptions;
-pub use snapshot_util::CreateSnapshotOutput;
-pub use snapshot_util::FilterFn;
-pub(crate) use snapshot_util::SnapshottedData;
-
-pub use bindings::script_origin;
diff --git a/core/runtime/ops.rs b/core/runtime/ops.rs
deleted file mode 100644
index 5ecab5edf..000000000
--- a/core/runtime/ops.rs
+++ /dev/null
@@ -1,634 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-use crate::ops::*;
-use crate::OpResult;
-use crate::PromiseId;
-use anyhow::Error;
-use futures::future::Either;
-use futures::future::Future;
-use futures::future::FutureExt;
-use futures::task::noop_waker_ref;
-use std::borrow::Cow;
-use std::cell::RefCell;
-use std::future::ready;
-use std::mem::MaybeUninit;
-use std::option::Option;
-use std::task::Context;
-use std::task::Poll;
-
-#[inline]
-pub fn queue_fast_async_op<R: serde::Serialize + 'static>(
- ctx: &OpCtx,
- promise_id: PromiseId,
- op: impl Future<Output = Result<R, Error>> + 'static,
-) {
- let get_class = {
- let state = RefCell::borrow(&ctx.state);
- state.tracker.track_async(ctx.id);
- state.get_error_class_fn
- };
- let fut = op.map(|result| crate::_ops::to_op_result(get_class, result));
- ctx
- .context_state
- .borrow_mut()
- .pending_ops
- .spawn(OpCall::new(ctx, promise_id, fut));
-}
-
-#[inline]
-pub fn map_async_op1<R: serde::Serialize + 'static>(
- ctx: &OpCtx,
- op: impl Future<Output = Result<R, Error>> + 'static,
-) -> impl Future<Output = OpResult> {
- let get_class = {
- let state = RefCell::borrow(&ctx.state);
- state.tracker.track_async(ctx.id);
- state.get_error_class_fn
- };
-
- op.map(|res| crate::_ops::to_op_result(get_class, res))
-}
-
-#[inline]
-pub fn map_async_op2<R: serde::Serialize + 'static>(
- ctx: &OpCtx,
- op: impl Future<Output = R> + 'static,
-) -> impl Future<Output = OpResult> {
- let state = RefCell::borrow(&ctx.state);
- state.tracker.track_async(ctx.id);
-
- op.map(|res| OpResult::Ok(res.into()))
-}
-
-#[inline]
-pub fn map_async_op3<R: serde::Serialize + 'static>(
- ctx: &OpCtx,
- op: Result<impl Future<Output = Result<R, Error>> + 'static, Error>,
-) -> impl Future<Output = OpResult> {
- let get_class = {
- let state = RefCell::borrow(&ctx.state);
- state.tracker.track_async(ctx.id);
- state.get_error_class_fn
- };
-
- match op {
- Err(err) => {
- Either::Left(ready(OpResult::Err(OpError::new(get_class, err))))
- }
- Ok(fut) => {
- Either::Right(fut.map(|res| crate::_ops::to_op_result(get_class, res)))
- }
- }
-}
-
-#[inline]
-pub fn map_async_op4<R: serde::Serialize + 'static>(
- ctx: &OpCtx,
- op: Result<impl Future<Output = R> + 'static, Error>,
-) -> impl Future<Output = OpResult> {
- let get_class = {
- let state = RefCell::borrow(&ctx.state);
- state.tracker.track_async(ctx.id);
- state.get_error_class_fn
- };
-
- match op {
- Err(err) => {
- Either::Left(ready(OpResult::Err(OpError::new(get_class, err))))
- }
- Ok(fut) => Either::Right(fut.map(|r| OpResult::Ok(r.into()))),
- }
-}
-
-pub fn queue_async_op<'s>(
- ctx: &OpCtx,
- scope: &'s mut v8::HandleScope,
- deferred: bool,
- promise_id: PromiseId,
- op: impl Future<Output = OpResult> + 'static,
-) -> Option<v8::Local<'s, v8::Value>> {
- // An op's realm (as given by `OpCtx::realm_idx`) must match the realm in
- // which it is invoked. Otherwise, we might have cross-realm object exposure.
- // deno_core doesn't currently support such exposure, even though embedders
- // can cause them, so we panic in debug mode (since the check is expensive).
- // TODO(mmastrac): Restore this
- // debug_assert_eq!(
- // runtime_state.borrow().context(ctx.realm_idx as usize, scope),
- // Some(scope.get_current_context())
- // );
-
- let id = ctx.id;
-
- // TODO(mmastrac): We have to poll every future here because that assumption is baked into a large number
- // of ops. If we can figure out a way around this, we can remove this call to boxed_local and save a malloc per future.
- let mut pinned = op.map(move |res| (promise_id, id, res)).boxed_local();
-
- match pinned.poll_unpin(&mut Context::from_waker(noop_waker_ref())) {
- Poll::Pending => {}
- Poll::Ready(mut res) => {
- if deferred {
- ctx.context_state.borrow_mut().pending_ops.spawn(ready(res));
- return None;
- } else {
- ctx.state.borrow_mut().tracker.track_async_completed(ctx.id);
- return Some(res.2.to_v8(scope).unwrap());
- }
- }
- }
-
- ctx.context_state.borrow_mut().pending_ops.spawn(pinned);
- None
-}
-
-macro_rules! try_number {
- ($n:ident $type:ident $is:ident) => {
- if $n.$is() {
- // SAFETY: v8 handles can be transmuted
- let n: &v8::Uint32 = unsafe { std::mem::transmute($n) };
- return n.value() as _;
- }
- };
-}
-
-pub fn to_u32(number: &v8::Value) -> u32 {
- try_number!(number Uint32 is_uint32);
- try_number!(number Int32 is_int32);
- try_number!(number Number is_number);
- if number.is_big_int() {
- // SAFETY: v8 handles can be transmuted
- let n: &v8::BigInt = unsafe { std::mem::transmute(number) };
- return n.u64_value().0 as _;
- }
- 0
-}
-
-pub fn to_i32(number: &v8::Value) -> i32 {
- try_number!(number Uint32 is_uint32);
- try_number!(number Int32 is_int32);
- try_number!(number Number is_number);
- if number.is_big_int() {
- // SAFETY: v8 handles can be transmuted
- let n: &v8::BigInt = unsafe { std::mem::transmute(number) };
- return n.i64_value().0 as _;
- }
- 0
-}
-
-#[allow(unused)]
-pub fn to_u64(number: &v8::Value) -> u32 {
- try_number!(number Uint32 is_uint32);
- try_number!(number Int32 is_int32);
- try_number!(number Number is_number);
- if number.is_big_int() {
- // SAFETY: v8 handles can be transmuted
- let n: &v8::BigInt = unsafe { std::mem::transmute(number) };
- return n.u64_value().0 as _;
- }
- 0
-}
-
-#[allow(unused)]
-pub fn to_i64(number: &v8::Value) -> i32 {
- try_number!(number Uint32 is_uint32);
- try_number!(number Int32 is_int32);
- try_number!(number Number is_number);
- if number.is_big_int() {
- // SAFETY: v8 handles can be transmuted
- let n: &v8::BigInt = unsafe { std::mem::transmute(number) };
- return n.i64_value().0 as _;
- }
- 0
-}
-
-/// Expands `inbuf` to `outbuf`, assuming that `outbuf` has at least 2x `input_length`.
-#[inline(always)]
-unsafe fn latin1_to_utf8(
- input_length: usize,
- inbuf: *const u8,
- outbuf: *mut u8,
-) -> usize {
- let mut output = 0;
- let mut input = 0;
- while input < input_length {
- let char = *(inbuf.add(input));
- if char < 0x80 {
- *(outbuf.add(output)) = char;
- output += 1;
- } else {
- // Top two bits
- *(outbuf.add(output)) = (char >> 6) | 0b1100_0000;
- // Bottom six bits
- *(outbuf.add(output + 1)) = (char & 0b0011_1111) | 0b1000_0000;
- output += 2;
- }
- input += 1;
- }
- output
-}
-
-/// Converts a [`v8::fast_api::FastApiOneByteString`] to either an owned string, or a borrowed string, depending on whether it fits into the
-/// provided buffer.
-pub fn to_str_ptr<'a, const N: usize>(
- string: &mut v8::fast_api::FastApiOneByteString,
- buffer: &'a mut [MaybeUninit<u8>; N],
-) -> Cow<'a, str> {
- let input_buf = string.as_bytes();
- let input_len = input_buf.len();
- let output_len = buffer.len();
-
- // We know that this string is full of either one or two-byte UTF-8 chars, so if it's < 1/2 of N we
- // can skip the ASCII check and just start copying.
- if input_len < N / 2 {
- debug_assert!(output_len >= input_len * 2);
- let buffer = buffer.as_mut_ptr() as *mut u8;
-
- let written =
- // SAFETY: We checked that buffer is at least 2x the size of input_buf
- unsafe { latin1_to_utf8(input_buf.len(), input_buf.as_ptr(), buffer) };
-
- debug_assert!(written <= output_len);
-
- let slice = std::ptr::slice_from_raw_parts(buffer, written);
- // SAFETY: We know it's valid UTF-8, so make a string
- Cow::Borrowed(unsafe { std::str::from_utf8_unchecked(&*slice) })
- } else {
- // TODO(mmastrac): We could be smarter here about not allocating
- Cow::Owned(to_string_ptr(string))
- }
-}
-
-/// Converts a [`v8::fast_api::FastApiOneByteString`] to an owned string. May over-allocate to avoid
-/// re-allocation.
-pub fn to_string_ptr(
- string: &mut v8::fast_api::FastApiOneByteString,
-) -> String {
- let input_buf = string.as_bytes();
- let capacity = input_buf.len() * 2;
-
- // SAFETY: We're allocating a buffer of 2x the input size, writing valid UTF-8, then turning that into a string
- unsafe {
- // Create an uninitialized buffer of `capacity` bytes. We need to be careful here to avoid
- // accidentally creating a slice of u8 which would be invalid.
- let layout = std::alloc::Layout::from_size_align(capacity, 1).unwrap();
- let out = std::alloc::alloc(layout);
-
- let written = latin1_to_utf8(input_buf.len(), input_buf.as_ptr(), out);
-
- debug_assert!(written <= capacity);
- // We know it's valid UTF-8, so make a string
- String::from_raw_parts(out, written, capacity)
- }
-}
-
-/// Converts a [`v8::String`] to either an owned string, or a borrowed string, depending on whether it fits into the
-/// provided buffer.
-#[inline(always)]
-pub fn to_str<'a, const N: usize>(
- scope: &mut v8::Isolate,
- string: &v8::Value,
- buffer: &'a mut [MaybeUninit<u8>; N],
-) -> Cow<'a, str> {
- if !string.is_string() {
- return Cow::Borrowed("");
- }
-
- // SAFETY: We checked is_string above
- let string: &v8::String = unsafe { std::mem::transmute(string) };
-
- string.to_rust_cow_lossy(scope, buffer)
-}
-
-#[cfg(test)]
-mod tests {
- use crate::error::generic_error;
- use crate::error::AnyError;
- use crate::error::JsError;
- use crate::FastString;
- use crate::JsRuntime;
- use crate::RuntimeOptions;
- use deno_ops::op2;
- use std::borrow::Cow;
- use std::cell::Cell;
-
- crate::extension!(
- testing,
- ops = [
- op_test_fail,
- op_test_add,
- op_test_add_option,
- op_test_result_void_switch,
- op_test_result_void_ok,
- op_test_result_void_err,
- op_test_result_primitive_ok,
- op_test_result_primitive_err,
- op_test_string_owned,
- op_test_string_ref,
- op_test_string_cow,
- op_test_string_roundtrip_char,
- op_test_string_return,
- op_test_string_option_return,
- op_test_string_roundtrip,
- op_test_generics<String>,
- ]
- );
-
- thread_local! {
- static FAIL: Cell<bool> = Cell::new(false)
- }
-
- #[op2(core, fast)]
- pub fn op_test_fail() {
- FAIL.with(|b| b.set(true))
- }
-
- /// Run a test for a single op.
- fn run_test2(repeat: usize, op: &str, test: &str) -> Result<(), AnyError> {
- let mut runtime = JsRuntime::new(RuntimeOptions {
- extensions: vec![testing::init_ops_and_esm()],
- ..Default::default()
- });
- runtime
- .execute_script(
- "",
- FastString::Owned(
- format!(
- r"
- const {{ op_test_fail, {op} }} = Deno.core.ensureFastOps();
- function assert(b) {{
- if (!b) {{
- op_test_fail();
- }}
- }}
- "
- )
- .into(),
- ),
- )
- .unwrap();
- FAIL.with(|b| b.set(false));
- runtime.execute_script(
- "",
- FastString::Owned(
- format!(
- r"
- for (let __index__ = 0; __index__ < {repeat}; __index__++) {{
- {test}
- }}
- "
- )
- .into(),
- ),
- )?;
- if FAIL.with(|b| b.get()) {
- Err(generic_error(format!("{op} test failed ({test})")))
- } else {
- Ok(())
- }
- }
-
- #[tokio::test(flavor = "current_thread")]
- pub async fn test_op_fail() {
- assert!(run_test2(1, "", "assert(false)").is_err());
- }
-
- #[op2(core, fast)]
- pub fn op_test_add(a: u32, b: u32) -> u32 {
- a + b
- }
-
- #[tokio::test(flavor = "current_thread")]
- pub async fn test_op_add() -> Result<(), Box<dyn std::error::Error>> {
- Ok(run_test2(
- 10000,
- "op_test_add",
- "assert(op_test_add(1, 11) == 12)",
- )?)
- }
-
- #[op2(core)]
- pub fn op_test_add_option(a: u32, b: Option<u32>) -> u32 {
- a + b.unwrap_or(100)
- }
-
- #[tokio::test(flavor = "current_thread")]
- pub async fn test_op_add_option() -> Result<(), Box<dyn std::error::Error>> {
- // This isn't fast, so we don't repeat it
- run_test2(
- 1,
- "op_test_add_option",
- "assert(op_test_add_option(1, 11) == 12)",
- )?;
- run_test2(
- 1,
- "op_test_add_option",
- "assert(op_test_add_option(1, null) == 101)",
- )?;
- Ok(())
- }
-
- thread_local! {
- static RETURN_COUNT: Cell<usize> = Cell::new(0);
- }
-
- #[op2(core, fast)]
- pub fn op_test_result_void_switch() -> Result<(), AnyError> {
- let count = RETURN_COUNT.with(|count| {
- let new = count.get() + 1;
- count.set(new);
- new
- });
- if count > 5000 {
- Err(generic_error("failed!!!"))
- } else {
- Ok(())
- }
- }
-
- #[op2(core, fast)]
- pub fn op_test_result_void_err() -> Result<(), AnyError> {
- Err(generic_error("failed!!!"))
- }
-
- #[op2(core, fast)]
- pub fn op_test_result_void_ok() -> Result<(), AnyError> {
- Ok(())
- }
-
- #[tokio::test(flavor = "current_thread")]
- pub async fn test_op_result_void() -> Result<(), Box<dyn std::error::Error>> {
- // Test the non-switching kinds
- run_test2(
- 10000,
- "op_test_result_void_err",
- "try { op_test_result_void_err(); assert(false) } catch (e) {}",
- )?;
- run_test2(10000, "op_test_result_void_ok", "op_test_result_void_ok()")?;
- Ok(())
- }
-
- #[tokio::test(flavor = "current_thread")]
- pub async fn test_op_result_void_switch(
- ) -> Result<(), Box<dyn std::error::Error>> {
- RETURN_COUNT.with(|count| count.set(0));
- let err = run_test2(
- 10000,
- "op_test_result_void_switch",
- "op_test_result_void_switch();",
- )
- .expect_err("Expected this to fail");
- let js_err = err.downcast::<JsError>().unwrap();
- assert_eq!(js_err.message, Some("failed!!!".into()));
- assert_eq!(RETURN_COUNT.with(|count| count.get()), 5001);
- Ok(())
- }
-
- #[op2(core, fast)]
- pub fn op_test_result_primitive_err() -> Result<u32, AnyError> {
- Err(generic_error("failed!!!"))
- }
-
- #[op2(core, fast)]
- pub fn op_test_result_primitive_ok() -> Result<u32, AnyError> {
- Ok(123)
- }
-
- #[tokio::test]
- pub async fn test_op_result_primitive(
- ) -> Result<(), Box<dyn std::error::Error>> {
- run_test2(
- 10000,
- "op_test_result_primitive_err",
- "try { op_test_result_primitive_err(); assert(false) } catch (e) {}",
- )?;
- run_test2(
- 10000,
- "op_test_result_primitive_ok",
- "op_test_result_primitive_ok()",
- )?;
- Ok(())
- }
-
- #[op2(core, fast)]
- pub fn op_test_string_owned(#[string] s: String) -> u32 {
- s.len() as _
- }
-
- #[op2(core, fast)]
- pub fn op_test_string_ref(#[string] s: &str) -> u32 {
- s.len() as _
- }
-
- #[op2(core, fast)]
- pub fn op_test_string_cow(#[string] s: Cow<str>) -> u32 {
- s.len() as _
- }
-
- #[op2(core, fast)]
- pub fn op_test_string_roundtrip_char(#[string] s: Cow<str>) -> u32 {
- s.chars().next().unwrap() as u32
- }
-
- #[tokio::test]
- pub async fn test_op_strings() -> Result<(), Box<dyn std::error::Error>> {
- for op in [
- "op_test_string_owned",
- "op_test_string_cow",
- "op_test_string_ref",
- ] {
- for (len, str) in [
- // ASCII
- (3, "'abc'"),
- // Latin-1 (one byte but two UTF-8 chars)
- (2, "'\\u00a0'"),
- // ASCII
- (10000, "'a'.repeat(10000)"),
- // Latin-1
- (20000, "'\\u00a0'.repeat(10000)"),
- // 4-byte UTF-8 emoji (1F995 = 🦕)
- (40000, "'\\u{1F995}'.repeat(10000)"),
- ] {
- let test = format!("assert({op}({str}) == {len})");
- run_test2(10000, op, &test)?;
- }
- }
-
- // Ensure that we're correctly encoding UTF-8
- run_test2(
- 10000,
- "op_test_string_roundtrip_char",
- "assert(op_test_string_roundtrip_char('\\u00a0') == 0xa0)",
- )?;
- run_test2(
- 10000,
- "op_test_string_roundtrip_char",
- "assert(op_test_string_roundtrip_char('\\u00ff') == 0xff)",
- )?;
- run_test2(
- 10000,
- "op_test_string_roundtrip_char",
- "assert(op_test_string_roundtrip_char('\\u0080') == 0x80)",
- )?;
- run_test2(
- 10000,
- "op_test_string_roundtrip_char",
- "assert(op_test_string_roundtrip_char('\\u0100') == 0x100)",
- )?;
- Ok(())
- }
-
- #[op2(core)]
- #[string]
- pub fn op_test_string_return(
- #[string] a: Cow<str>,
- #[string] b: Cow<str>,
- ) -> String {
- (a + b).to_string()
- }
-
- #[op2(core)]
- #[string]
- pub fn op_test_string_option_return(
- #[string] a: Cow<str>,
- #[string] b: Cow<str>,
- ) -> Option<String> {
- if a == "none" {
- return None;
- }
- Some((a + b).to_string())
- }
-
- #[op2(core)]
- #[string]
- pub fn op_test_string_roundtrip(#[string] s: String) -> String {
- s
- }
-
- #[tokio::test]
- pub async fn test_op_string_returns() -> Result<(), Box<dyn std::error::Error>>
- {
- run_test2(
- 1,
- "op_test_string_return",
- "assert(op_test_string_return('a', 'b') == 'ab')",
- )?;
- run_test2(
- 1,
- "op_test_string_option_return",
- "assert(op_test_string_option_return('a', 'b') == 'ab')",
- )?;
- run_test2(
- 1,
- "op_test_string_option_return",
- "assert(op_test_string_option_return('none', 'b') == null)",
- )?;
- run_test2(
- 1,
- "op_test_string_roundtrip",
- "assert(op_test_string_roundtrip('\\u0080\\u00a0\\u00ff') == '\\u0080\\u00a0\\u00ff')",
- )?;
- Ok(())
- }
-
- // We don't actually test this one -- we just want it to compile
- #[op2(core, fast)]
- pub fn op_test_generics<T: Clone>() {}
-}
diff --git a/core/runtime/serialize_deserialize_test.js b/core/runtime/serialize_deserialize_test.js
deleted file mode 100644
index 70397cdf8..000000000
--- a/core/runtime/serialize_deserialize_test.js
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-"use strict";
-
-function assert(cond) {
- if (!cond) {
- throw Error("assert");
- }
-}
-
-function assertArrayEquals(a1, a2) {
- if (a1.length !== a2.length) throw Error("assert");
-
- for (const index in a1) {
- if (a1[index] !== a2[index]) {
- throw Error(`assert: (index ${index}) ${a1[index]} !== ${a2[index]}`);
- }
- }
-}
-
-function main() {
- const emptyString = "";
- const emptyStringSerialized = [255, 15, 34, 0];
- assertArrayEquals(
- Deno.core.ops.op_serialize(emptyString),
- emptyStringSerialized,
- );
- assert(
- Deno.core.ops.op_deserialize(
- new Uint8Array(emptyStringSerialized),
- ) ===
- emptyString,
- );
-
- const primitiveValueArray = ["test", "a", null, undefined];
- // deno-fmt-ignore
- const primitiveValueArraySerialized = [
- 255, 15, 65, 4, 34, 4, 116, 101, 115, 116,
- 34, 1, 97, 48, 95, 36, 0, 4,
- ];
- assertArrayEquals(
- Deno.core.ops.op_serialize(primitiveValueArray),
- primitiveValueArraySerialized,
- );
-
- assertArrayEquals(
- Deno.core.ops.op_deserialize(
- new Uint8Array(primitiveValueArraySerialized),
- ),
- primitiveValueArray,
- );
-
- const circularObject = { test: null, test2: "dd", test3: "aa" };
- circularObject.test = circularObject;
- // deno-fmt-ignore
- const circularObjectSerialized = [
- 255, 15, 111, 34, 4, 116, 101, 115,
- 116, 94, 0, 34, 5, 116, 101, 115,
- 116, 50, 34, 2, 100, 100, 34, 5,
- 116, 101, 115, 116, 51, 34, 2, 97,
- 97, 123, 3,
- ];
-
- assertArrayEquals(
- Deno.core.ops.op_serialize(circularObject),
- circularObjectSerialized,
- );
-
- const deserializedCircularObject = Deno.core.ops.op_deserialize(
- new Uint8Array(circularObjectSerialized),
- );
- assert(deserializedCircularObject.test == deserializedCircularObject);
-}
-
-main();
diff --git a/core/runtime/snapshot_util.rs b/core/runtime/snapshot_util.rs
deleted file mode 100644
index e664856c6..000000000
--- a/core/runtime/snapshot_util.rs
+++ /dev/null
@@ -1,259 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-
-use std::path::Path;
-use std::path::PathBuf;
-use std::time::Instant;
-
-use crate::runtime::jsruntime::BUILTIN_SOURCES;
-use crate::runtime::RuntimeSnapshotOptions;
-use crate::ExtModuleLoaderCb;
-use crate::Extension;
-use crate::ExtensionFileSourceCode;
-use crate::JsRuntimeForSnapshot;
-use crate::RuntimeOptions;
-use crate::Snapshot;
-
-pub type CompressionCb = dyn Fn(&mut Vec<u8>, &[u8]);
-
-pub struct CreateSnapshotOptions {
- pub cargo_manifest_dir: &'static str,
- pub snapshot_path: PathBuf,
- pub startup_snapshot: Option<Snapshot>,
- pub extensions: Vec<Extension>,
- pub compression_cb: Option<Box<CompressionCb>>,
- pub snapshot_module_load_cb: Option<ExtModuleLoaderCb>,
-}
-
-pub struct CreateSnapshotOutput {
- /// Any files marked as LoadedFromFsDuringSnapshot are collected here and should be
- /// printed as 'cargo:rerun-if-changed' lines from your build script.
- pub files_loaded_during_snapshot: Vec<PathBuf>,
-}
-
-#[must_use = "The files listed by create_snapshot should be printed as 'cargo:rerun-if-changed' lines"]
-pub fn create_snapshot(
- create_snapshot_options: CreateSnapshotOptions,
-) -> CreateSnapshotOutput {
- let mut mark = Instant::now();
-
- let js_runtime = JsRuntimeForSnapshot::new(
- RuntimeOptions {
- startup_snapshot: create_snapshot_options.startup_snapshot,
- extensions: create_snapshot_options.extensions,
- ..Default::default()
- },
- RuntimeSnapshotOptions {
- snapshot_module_load_cb: create_snapshot_options.snapshot_module_load_cb,
- },
- );
- println!(
- "JsRuntime for snapshot prepared, took {:#?} ({})",
- Instant::now().saturating_duration_since(mark),
- create_snapshot_options.snapshot_path.display()
- );
- mark = Instant::now();
-
- let mut files_loaded_during_snapshot = vec![];
- for source in &*BUILTIN_SOURCES {
- if let ExtensionFileSourceCode::LoadedFromFsDuringSnapshot(path) =
- &source.code
- {
- files_loaded_during_snapshot.push(path.clone());
- }
- }
- for source in js_runtime
- .extensions()
- .iter()
- .flat_map(|e| vec![e.get_esm_sources(), e.get_js_sources()])
- .flatten()
- {
- if let ExtensionFileSourceCode::LoadedFromFsDuringSnapshot(path) =
- &source.code
- {
- files_loaded_during_snapshot.push(path.clone());
- }
- }
-
- let snapshot = js_runtime.snapshot();
- let snapshot_slice: &[u8] = &snapshot;
- println!(
- "Snapshot size: {}, took {:#?} ({})",
- snapshot_slice.len(),
- Instant::now().saturating_duration_since(mark),
- create_snapshot_options.snapshot_path.display()
- );
- mark = Instant::now();
-
- let maybe_compressed_snapshot: Box<dyn AsRef<[u8]>> =
- if let Some(compression_cb) = create_snapshot_options.compression_cb {
- let mut vec = vec![];
-
- vec.extend_from_slice(
- &u32::try_from(snapshot.len())
- .expect("snapshot larger than 4gb")
- .to_le_bytes(),
- );
-
- (compression_cb)(&mut vec, snapshot_slice);
-
- println!(
- "Snapshot compressed size: {}, took {:#?} ({})",
- vec.len(),
- Instant::now().saturating_duration_since(mark),
- create_snapshot_options.snapshot_path.display()
- );
- mark = std::time::Instant::now();
-
- Box::new(vec)
- } else {
- Box::new(snapshot_slice)
- };
-
- std::fs::write(
- &create_snapshot_options.snapshot_path,
- &*maybe_compressed_snapshot,
- )
- .unwrap();
- println!(
- "Snapshot written, took: {:#?} ({})",
- Instant::now().saturating_duration_since(mark),
- create_snapshot_options.snapshot_path.display(),
- );
- CreateSnapshotOutput {
- files_loaded_during_snapshot,
- }
-}
-
-pub type FilterFn = Box<dyn Fn(&PathBuf) -> bool>;
-
-pub fn get_js_files(
- cargo_manifest_dir: &'static str,
- directory: &str,
- filter: Option<FilterFn>,
-) -> Vec<PathBuf> {
- let manifest_dir = Path::new(cargo_manifest_dir);
- let mut js_files = std::fs::read_dir(directory)
- .unwrap()
- .map(|dir_entry| {
- let file = dir_entry.unwrap();
- manifest_dir.join(file.path())
- })
- .filter(|path| {
- path.extension().unwrap_or_default() == "js"
- && filter.as_ref().map(|filter| filter(path)).unwrap_or(true)
- })
- .collect::<Vec<PathBuf>>();
- js_files.sort();
- js_files
-}
-
-fn data_error_to_panic(err: v8::DataError) -> ! {
- match err {
- v8::DataError::BadType { actual, expected } => {
- panic!(
- "Invalid type for snapshot data: expected {expected}, got {actual}"
- );
- }
- v8::DataError::NoData { expected } => {
- panic!("No data for snapshot data: expected {expected}");
- }
- }
-}
-
-pub(crate) struct SnapshottedData {
- pub module_map_data: v8::Global<v8::Array>,
- pub module_handles: Vec<v8::Global<v8::Module>>,
-}
-
-static MODULE_MAP_CONTEXT_DATA_INDEX: usize = 0;
-
-pub(crate) fn get_snapshotted_data(
- scope: &mut v8::HandleScope<()>,
- context: v8::Local<v8::Context>,
-) -> SnapshottedData {
- let mut scope = v8::ContextScope::new(scope, context);
-
- // The 0th element is the module map itself, followed by X number of module
- // handles. We need to deserialize the "next_module_id" field from the
- // map to see how many module handles we expect.
- let result = scope.get_context_data_from_snapshot_once::<v8::Array>(
- MODULE_MAP_CONTEXT_DATA_INDEX,
- );
-
- let val = match result {
- Ok(v) => v,
- Err(err) => data_error_to_panic(err),
- };
-
- let next_module_id = {
- let info_data: v8::Local<v8::Array> =
- val.get_index(&mut scope, 1).unwrap().try_into().unwrap();
- info_data.length()
- };
-
- // Over allocate so executing a few scripts doesn't have to resize this vec.
- let mut module_handles = Vec::with_capacity(next_module_id as usize + 16);
- for i in 1..=next_module_id {
- match scope.get_context_data_from_snapshot_once::<v8::Module>(i as usize) {
- Ok(val) => {
- let module_global = v8::Global::new(&mut scope, val);
- module_handles.push(module_global);
- }
- Err(err) => data_error_to_panic(err),
- }
- }
-
- SnapshottedData {
- module_map_data: v8::Global::new(&mut scope, val),
- module_handles,
- }
-}
-
-pub(crate) fn set_snapshotted_data(
- scope: &mut v8::HandleScope<()>,
- context: v8::Global<v8::Context>,
- snapshotted_data: SnapshottedData,
-) {
- let local_context = v8::Local::new(scope, context);
- let local_data = v8::Local::new(scope, snapshotted_data.module_map_data);
- let offset = scope.add_context_data(local_context, local_data);
- assert_eq!(offset, MODULE_MAP_CONTEXT_DATA_INDEX);
-
- for (index, handle) in snapshotted_data.module_handles.into_iter().enumerate()
- {
- let module_handle = v8::Local::new(scope, handle);
- let offset = scope.add_context_data(local_context, module_handle);
- assert_eq!(offset, index + 1);
- }
-}
-
-/// Returns an isolate set up for snapshotting.
-pub(crate) fn create_snapshot_creator(
- external_refs: &'static v8::ExternalReferences,
- maybe_startup_snapshot: Option<Snapshot>,
-) -> v8::OwnedIsolate {
- if let Some(snapshot) = maybe_startup_snapshot {
- match snapshot {
- Snapshot::Static(data) => {
- v8::Isolate::snapshot_creator_from_existing_snapshot(
- data,
- Some(external_refs),
- )
- }
- Snapshot::JustCreated(data) => {
- v8::Isolate::snapshot_creator_from_existing_snapshot(
- data,
- Some(external_refs),
- )
- }
- Snapshot::Boxed(data) => {
- v8::Isolate::snapshot_creator_from_existing_snapshot(
- data,
- Some(external_refs),
- )
- }
- }
- } else {
- v8::Isolate::snapshot_creator(Some(external_refs))
- }
-}
diff --git a/core/runtime/tests.rs b/core/runtime/tests.rs
deleted file mode 100644
index 663645bb1..000000000
--- a/core/runtime/tests.rs
+++ /dev/null
@@ -1,2396 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-use crate::ascii_str;
-use crate::error::custom_error;
-use crate::error::generic_error;
-use crate::error::AnyError;
-use crate::error::JsError;
-use crate::extensions::OpDecl;
-use crate::include_ascii_string;
-use crate::module_specifier::ModuleSpecifier;
-use crate::modules::AssertedModuleType;
-use crate::modules::ModuleCode;
-use crate::modules::ModuleInfo;
-use crate::modules::ModuleLoadId;
-use crate::modules::ModuleLoader;
-use crate::modules::ModuleSource;
-use crate::modules::ModuleSourceFuture;
-use crate::modules::ModuleType;
-use crate::modules::ResolutionKind;
-use crate::modules::SymbolicModule;
-use crate::Extension;
-use crate::JsBuffer;
-use crate::*;
-use anyhow::Error;
-use cooked_waker::IntoWaker;
-use cooked_waker::Wake;
-use cooked_waker::WakeRef;
-use deno_ops::op;
-use futures::future::poll_fn;
-use futures::future::Future;
-use futures::FutureExt;
-use std::cell::RefCell;
-use std::pin::Pin;
-use std::rc::Rc;
-use std::sync::atomic::AtomicBool;
-use std::sync::atomic::AtomicI8;
-use std::sync::atomic::AtomicUsize;
-use std::sync::atomic::Ordering;
-use std::sync::Arc;
-use std::task::Context;
-use std::task::Poll;
-use std::time::Duration;
-
-// deno_ops macros generate code assuming deno_core in scope.
-mod deno_core {
- pub use crate::*;
-}
-
-#[derive(Copy, Clone)]
-pub enum Mode {
- Async,
- AsyncDeferred,
- AsyncZeroCopy(bool),
-}
-
-struct TestState {
- mode: Mode,
- dispatch_count: Arc<AtomicUsize>,
-}
-
-#[op]
-async fn op_test(
- rc_op_state: Rc<RefCell<OpState>>,
- control: u8,
- buf: Option<JsBuffer>,
-) -> Result<u8, AnyError> {
- #![allow(clippy::await_holding_refcell_ref)] // False positive.
- let op_state_ = rc_op_state.borrow();
- let test_state = op_state_.borrow::<TestState>();
- test_state.dispatch_count.fetch_add(1, Ordering::Relaxed);
- let mode = test_state.mode;
- drop(op_state_);
- match mode {
- Mode::Async => {
- assert_eq!(control, 42);
- Ok(43)
- }
- Mode::AsyncDeferred => {
- tokio::task::yield_now().await;
- assert_eq!(control, 42);
- Ok(43)
- }
- Mode::AsyncZeroCopy(has_buffer) => {
- assert_eq!(buf.is_some(), has_buffer);
- if let Some(buf) = buf {
- assert_eq!(buf.len(), 1);
- }
- Ok(43)
- }
- }
-}
-
-fn setup(mode: Mode) -> (JsRuntime, Arc<AtomicUsize>) {
- let dispatch_count = Arc::new(AtomicUsize::new(0));
- deno_core::extension!(
- test_ext,
- ops = [op_test],
- options = {
- mode: Mode,
- dispatch_count: Arc<AtomicUsize>,
- },
- state = |state, options| {
- state.put(TestState {
- mode: options.mode,
- dispatch_count: options.dispatch_count
- })
- }
- );
- let mut runtime = JsRuntime::new(RuntimeOptions {
- extensions: vec![test_ext::init_ops(mode, dispatch_count.clone())],
- get_error_class_fn: Some(&|error| {
- crate::error::get_custom_error_class(error).unwrap()
- }),
- ..Default::default()
- });
-
- runtime
- .execute_script_static(
- "setup.js",
- r#"
- function assert(cond) {
- if (!cond) {
- throw Error("assert");
- }
- }
- "#,
- )
- .unwrap();
- assert_eq!(dispatch_count.load(Ordering::Relaxed), 0);
- (runtime, dispatch_count)
-}
-
-#[tokio::test]
-async fn test_ref_unref_ops() {
- let (mut runtime, _dispatch_count) = setup(Mode::AsyncDeferred);
- runtime
- .execute_script_static(
- "filename.js",
- r#"
-
- var promiseIdSymbol = Symbol.for("Deno.core.internalPromiseId");
- var p1 = Deno.core.opAsync("op_test", 42);
- var p2 = Deno.core.opAsync("op_test", 42);
- "#,
- )
- .unwrap();
- {
- let realm = runtime.global_realm();
- assert_eq!(realm.num_pending_ops(), 2);
- assert_eq!(realm.num_unrefed_ops(), 0);
- }
- runtime
- .execute_script_static(
- "filename.js",
- r#"
- Deno.core.ops.op_unref_op(p1[promiseIdSymbol]);
- Deno.core.ops.op_unref_op(p2[promiseIdSymbol]);
- "#,
- )
- .unwrap();
- {
- let realm = runtime.global_realm();
- assert_eq!(realm.num_pending_ops(), 2);
- assert_eq!(realm.num_unrefed_ops(), 2);
- }
- runtime
- .execute_script_static(
- "filename.js",
- r#"
- Deno.core.ops.op_ref_op(p1[promiseIdSymbol]);
- Deno.core.ops.op_ref_op(p2[promiseIdSymbol]);
- "#,
- )
- .unwrap();
- {
- let realm = runtime.global_realm();
- assert_eq!(realm.num_pending_ops(), 2);
- assert_eq!(realm.num_unrefed_ops(), 0);
- }
-}
-
-#[test]
-fn test_dispatch() {
- let (mut runtime, dispatch_count) = setup(Mode::Async);
- runtime
- .execute_script_static(
- "filename.js",
- r#"
- let control = 42;
-
- Deno.core.opAsync("op_test", control);
- async function main() {
- Deno.core.opAsync("op_test", control);
- }
- main();
- "#,
- )
- .unwrap();
- assert_eq!(dispatch_count.load(Ordering::Relaxed), 2);
-}
-
-#[test]
-fn test_op_async_promise_id() {
- let (mut runtime, _dispatch_count) = setup(Mode::Async);
- runtime
- .execute_script_static(
- "filename.js",
- r#"
-
- const p = Deno.core.opAsync("op_test", 42);
- if (p[Symbol.for("Deno.core.internalPromiseId")] == undefined) {
- throw new Error("missing id on returned promise");
- }
- "#,
- )
- .unwrap();
-}
-
-#[test]
-fn test_dispatch_no_zero_copy_buf() {
- let (mut runtime, dispatch_count) = setup(Mode::AsyncZeroCopy(false));
- runtime
- .execute_script_static(
- "filename.js",
- r#"
-
- Deno.core.opAsync("op_test", 0);
- "#,
- )
- .unwrap();
- assert_eq!(dispatch_count.load(Ordering::Relaxed), 1);
-}
-
-#[test]
-fn test_dispatch_stack_zero_copy_bufs() {
- let (mut runtime, dispatch_count) = setup(Mode::AsyncZeroCopy(true));
- runtime
- .execute_script_static(
- "filename.js",
- r#"
- const { op_test } = Deno.core.ensureFastOps();
- let zero_copy_a = new Uint8Array([0]);
- op_test(0, zero_copy_a);
- "#,
- )
- .unwrap();
- assert_eq!(dispatch_count.load(Ordering::Relaxed), 1);
-}
-
-#[test]
-fn test_execute_script_return_value() {
- let mut runtime = JsRuntime::new(Default::default());
- let value_global =
- runtime.execute_script_static("a.js", "a = 1 + 2").unwrap();
- {
- let scope = &mut runtime.handle_scope();
- let value = value_global.open(scope);
- assert_eq!(value.integer_value(scope).unwrap(), 3);
- }
- let value_global = runtime
- .execute_script_static("b.js", "b = 'foobar'")
- .unwrap();
- {
- let scope = &mut runtime.handle_scope();
- let value = value_global.open(scope);
- assert!(value.is_string());
- assert_eq!(
- value.to_string(scope).unwrap().to_rust_string_lossy(scope),
- "foobar"
- );
- }
-}
-
-#[derive(Default)]
-struct LoggingWaker {
- woken: AtomicBool,
-}
-
-impl Wake for LoggingWaker {
- fn wake(self) {
- self.woken.store(true, Ordering::SeqCst);
- }
-}
-
-impl WakeRef for LoggingWaker {
- fn wake_by_ref(&self) {
- self.woken.store(true, Ordering::SeqCst);
- }
-}
-
-/// This is a reproduction for a very obscure bug where the Deno runtime locks up we end up polling
-/// an empty JoinSet and attempt to resolve ops after-the-fact. There's a small footgun in the JoinSet
-/// API where polling it while empty returns Ready(None), which means that it never holds on to the
-/// waker. This means that if we aren't testing for this particular return value and don't stash the waker
-/// ourselves for a future async op to eventually queue, we can end up losing the waker entirely and the
-/// op wakes up, notifies tokio, which notifies the JoinSet, which then has nobody to notify )`:.
-#[tokio::test]
-async fn test_wakers_for_async_ops() {
- static STATE: AtomicI8 = AtomicI8::new(0);
-
- #[op]
- async fn op_async_sleep() -> Result<(), Error> {
- STATE.store(1, Ordering::SeqCst);
- tokio::time::sleep(std::time::Duration::from_millis(1)).await;
- STATE.store(2, Ordering::SeqCst);
- Ok(())
- }
-
- STATE.store(0, Ordering::SeqCst);
-
- let logging_waker = Arc::new(LoggingWaker::default());
- let waker = logging_waker.clone().into_waker();
-
- deno_core::extension!(test_ext, ops = [op_async_sleep]);
- let mut runtime = JsRuntime::new(RuntimeOptions {
- extensions: vec![test_ext::init_ops()],
- ..Default::default()
- });
-
- // Drain events until we get to Ready
- loop {
- logging_waker.woken.store(false, Ordering::SeqCst);
- let res = runtime.poll_event_loop(&mut Context::from_waker(&waker), false);
- let ready = matches!(res, Poll::Ready(Ok(())));
- assert!(ready || logging_waker.woken.load(Ordering::SeqCst));
- if ready {
- break;
- }
- }
-
- // Start the AIIFE
- runtime
- .execute_script(
- "",
- FastString::from_static(
- "(async () => { await Deno.core.opAsync('op_async_sleep'); })()",
- ),
- )
- .unwrap();
-
- // Wait for future to finish
- while STATE.load(Ordering::SeqCst) < 2 {
- tokio::time::sleep(Duration::from_millis(1)).await;
- }
-
- // This shouldn't take one minute, but if it does, things are definitely locked up
- for _ in 0..Duration::from_secs(60).as_millis() {
- if logging_waker.woken.load(Ordering::SeqCst) {
- // Success
- return;
- }
- tokio::time::sleep(Duration::from_millis(1)).await;
- }
-
- panic!("The waker was never woken after the future completed");
-}
-
-#[tokio::test]
-async fn test_poll_value() {
- let mut runtime = JsRuntime::new(Default::default());
- poll_fn(move |cx| {
- let value_global = runtime
- .execute_script_static("a.js", "Promise.resolve(1 + 2)")
- .unwrap();
- let v = runtime.poll_value(&value_global, cx);
- {
- let scope = &mut runtime.handle_scope();
- assert!(
- matches!(v, Poll::Ready(Ok(v)) if v.open(scope).integer_value(scope).unwrap() == 3)
- );
- }
-
- let value_global = runtime
- .execute_script_static(
- "a.js",
- "Promise.resolve(new Promise(resolve => resolve(2 + 2)))",
- )
- .unwrap();
- let v = runtime.poll_value(&value_global, cx);
- {
- let scope = &mut runtime.handle_scope();
- assert!(
- matches!(v, Poll::Ready(Ok(v)) if v.open(scope).integer_value(scope).unwrap() == 4)
- );
- }
-
- let value_global = runtime
- .execute_script_static("a.js", "Promise.reject(new Error('fail'))")
- .unwrap();
- let v = runtime.poll_value(&value_global, cx);
- assert!(
- matches!(v, Poll::Ready(Err(e)) if e.downcast_ref::<JsError>().unwrap().exception_message == "Uncaught Error: fail")
- );
-
- let value_global = runtime
- .execute_script_static("a.js", "new Promise(resolve => {})")
- .unwrap();
- let v = runtime.poll_value(&value_global, cx);
- matches!(v, Poll::Ready(Err(e)) if e.to_string() == "Promise resolution is still pending but the event loop has already resolved.");
- Poll::Ready(())
- }).await;
-}
-
-#[tokio::test]
-async fn test_resolve_value() {
- let mut runtime = JsRuntime::new(Default::default());
- let value_global = runtime
- .execute_script_static("a.js", "Promise.resolve(1 + 2)")
- .unwrap();
- let result_global = runtime.resolve_value(value_global).await.unwrap();
- {
- let scope = &mut runtime.handle_scope();
- let value = result_global.open(scope);
- assert_eq!(value.integer_value(scope).unwrap(), 3);
- }
-
- let value_global = runtime
- .execute_script_static(
- "a.js",
- "Promise.resolve(new Promise(resolve => resolve(2 + 2)))",
- )
- .unwrap();
- let result_global = runtime.resolve_value(value_global).await.unwrap();
- {
- let scope = &mut runtime.handle_scope();
- let value = result_global.open(scope);
- assert_eq!(value.integer_value(scope).unwrap(), 4);
- }
-
- let value_global = runtime
- .execute_script_static("a.js", "Promise.reject(new Error('fail'))")
- .unwrap();
- let err = runtime.resolve_value(value_global).await.unwrap_err();
- assert_eq!(
- "Uncaught Error: fail",
- err.downcast::<JsError>().unwrap().exception_message
- );
-
- let value_global = runtime
- .execute_script_static("a.js", "new Promise(resolve => {})")
- .unwrap();
- let error_string = runtime
- .resolve_value(value_global)
- .await
- .unwrap_err()
- .to_string();
- assert_eq!(
- "Promise resolution is still pending but the event loop has already resolved.",
- error_string,
- );
-}
-
-#[test]
-fn terminate_execution_webassembly() {
- let (mut runtime, _dispatch_count) = setup(Mode::Async);
- let v8_isolate_handle = runtime.v8_isolate().thread_safe_handle();
-
- // Run an infinite loop in WebAssembly code, which should be terminated.
- let promise = runtime.execute_script_static("infinite_wasm_loop.js",
- r#"
- (async () => {
- const wasmCode = new Uint8Array([
- 0, 97, 115, 109, 1, 0, 0, 0, 1, 4, 1,
- 96, 0, 0, 3, 2, 1, 0, 7, 17, 1, 13,
- 105, 110, 102, 105, 110, 105, 116, 101, 95, 108, 111,
- 111, 112, 0, 0, 10, 9, 1, 7, 0, 3, 64,
- 12, 0, 11, 11,
- ]);
- const wasmModule = await WebAssembly.compile(wasmCode);
- globalThis.wasmInstance = new WebAssembly.Instance(wasmModule);
- })()
- "#).unwrap();
- futures::executor::block_on(runtime.resolve_value(promise)).unwrap();
- let terminator_thread = std::thread::spawn(move || {
- std::thread::sleep(std::time::Duration::from_millis(1000));
-
- // terminate execution
- let ok = v8_isolate_handle.terminate_execution();
- assert!(ok);
- });
- let err = runtime
- .execute_script_static(
- "infinite_wasm_loop2.js",
- "globalThis.wasmInstance.exports.infinite_loop();",
- )
- .unwrap_err();
- assert_eq!(err.to_string(), "Uncaught Error: execution terminated");
- // Cancel the execution-terminating exception in order to allow script
- // execution again.
- let ok = runtime.v8_isolate().cancel_terminate_execution();
- assert!(ok);
-
- // Verify that the isolate usable again.
- runtime
- .execute_script_static("simple.js", "1 + 1")
- .expect("execution should be possible again");
-
- terminator_thread.join().unwrap();
-}
-
-#[test]
-fn terminate_execution() {
- let (mut isolate, _dispatch_count) = setup(Mode::Async);
- let v8_isolate_handle = isolate.v8_isolate().thread_safe_handle();
-
- let terminator_thread = std::thread::spawn(move || {
- // allow deno to boot and run
- std::thread::sleep(std::time::Duration::from_millis(100));
-
- // terminate execution
- let ok = v8_isolate_handle.terminate_execution();
- assert!(ok);
- });
-
- // Rn an infinite loop, which should be terminated.
- match isolate.execute_script_static("infinite_loop.js", "for(;;) {}") {
- Ok(_) => panic!("execution should be terminated"),
- Err(e) => {
- assert_eq!(e.to_string(), "Uncaught Error: execution terminated")
- }
- };
-
- // Cancel the execution-terminating exception in order to allow script
- // execution again.
- let ok = isolate.v8_isolate().cancel_terminate_execution();
- assert!(ok);
-
- // Verify that the isolate usable again.
- isolate
- .execute_script_static("simple.js", "1 + 1")
- .expect("execution should be possible again");
-
- terminator_thread.join().unwrap();
-}
-
-#[test]
-fn dangling_shared_isolate() {
- let v8_isolate_handle = {
- // isolate is dropped at the end of this block
- let (mut runtime, _dispatch_count) = setup(Mode::Async);
- runtime.v8_isolate().thread_safe_handle()
- };
-
- // this should not SEGFAULT
- v8_isolate_handle.terminate_execution();
-}
-
-#[test]
-fn syntax_error() {
- let mut runtime = JsRuntime::new(Default::default());
- let src = "hocuspocus(";
- let r = runtime.execute_script_static("i.js", src);
- let e = r.unwrap_err();
- let js_error = e.downcast::<JsError>().unwrap();
- let frame = js_error.frames.first().unwrap();
- assert_eq!(frame.column_number, Some(12));
-}
-
-#[tokio::test]
-async fn test_encode_decode() {
- let (mut runtime, _dispatch_count) = setup(Mode::Async);
- poll_fn(move |cx| {
- runtime
- .execute_script(
- "encode_decode_test.js",
- // Note: We make this to_owned because it contains non-ASCII chars
- include_str!("encode_decode_test.js").to_owned().into(),
- )
- .unwrap();
- if let Poll::Ready(Err(_)) = runtime.poll_event_loop(cx, false) {
- unreachable!();
- }
- Poll::Ready(())
- })
- .await;
-}
-
-#[tokio::test]
-async fn test_serialize_deserialize() {
- let (mut runtime, _dispatch_count) = setup(Mode::Async);
- poll_fn(move |cx| {
- runtime
- .execute_script(
- "serialize_deserialize_test.js",
- include_ascii_string!("serialize_deserialize_test.js"),
- )
- .unwrap();
- if let Poll::Ready(Err(_)) = runtime.poll_event_loop(cx, false) {
- unreachable!();
- }
- Poll::Ready(())
- })
- .await;
-}
-
-#[tokio::test]
-async fn test_error_builder() {
- #[op]
- fn op_err() -> Result<(), Error> {
- Err(custom_error("DOMExceptionOperationError", "abc"))
- }
-
- pub fn get_error_class_name(_: &Error) -> &'static str {
- "DOMExceptionOperationError"
- }
-
- deno_core::extension!(test_ext, ops = [op_err]);
- let mut runtime = JsRuntime::new(RuntimeOptions {
- extensions: vec![test_ext::init_ops()],
- get_error_class_fn: Some(&get_error_class_name),
- ..Default::default()
- });
- poll_fn(move |cx| {
- runtime
- .execute_script_static(
- "error_builder_test.js",
- include_str!("error_builder_test.js"),
- )
- .unwrap();
- if let Poll::Ready(Err(_)) = runtime.poll_event_loop(cx, false) {
- unreachable!();
- }
- Poll::Ready(())
- })
- .await;
-}
-
-/// Ensure that putting the inspector into OpState doesn't cause crashes. The only valid place we currently allow
-/// the inspector to be stashed without cleanup is the OpState, and this should not actually cause crashes.
-#[test]
-fn inspector() {
- let mut runtime = JsRuntime::new(RuntimeOptions {
- inspector: true,
- ..Default::default()
- });
- // This was causing a crash
- runtime.op_state().borrow_mut().put(runtime.inspector());
- runtime.execute_script_static("check.js", "null").unwrap();
-}
-
-#[test]
-fn will_snapshot() {
- let snapshot = {
- let mut runtime =
- JsRuntimeForSnapshot::new(Default::default(), Default::default());
- runtime.execute_script_static("a.js", "a = 1 + 2").unwrap();
- runtime.snapshot()
- };
-
- let snapshot = Snapshot::JustCreated(snapshot);
- let mut runtime2 = JsRuntime::new(RuntimeOptions {
- startup_snapshot: Some(snapshot),
- ..Default::default()
- });
- runtime2
- .execute_script_static("check.js", "if (a != 3) throw Error('x')")
- .unwrap();
-}
-
-#[test]
-fn will_snapshot2() {
- let startup_data = {
- let mut runtime =
- JsRuntimeForSnapshot::new(Default::default(), Default::default());
- runtime
- .execute_script_static("a.js", "let a = 1 + 2")
- .unwrap();
- runtime.snapshot()
- };
-
- let snapshot = Snapshot::JustCreated(startup_data);
- let mut runtime = JsRuntimeForSnapshot::new(
- RuntimeOptions {
- startup_snapshot: Some(snapshot),
- ..Default::default()
- },
- Default::default(),
- );
-
- let startup_data = {
- runtime
- .execute_script_static("check_a.js", "if (a != 3) throw Error('x')")
- .unwrap();
- runtime.execute_script_static("b.js", "b = 2 + 3").unwrap();
- runtime.snapshot()
- };
-
- let snapshot = Snapshot::JustCreated(startup_data);
- {
- let mut runtime = JsRuntime::new(RuntimeOptions {
- startup_snapshot: Some(snapshot),
- ..Default::default()
- });
- runtime
- .execute_script_static("check_b.js", "if (b != 5) throw Error('x')")
- .unwrap();
- runtime
- .execute_script_static("check2.js", "if (!Deno.core) throw Error('x')")
- .unwrap();
- }
-}
-
-#[test]
-fn test_snapshot_callbacks() {
- let snapshot = {
- let mut runtime =
- JsRuntimeForSnapshot::new(Default::default(), Default::default());
- runtime
- .execute_script_static(
- "a.js",
- r#"
- Deno.core.setMacrotaskCallback(() => {
- return true;
- });
- Deno.core.ops.op_set_format_exception_callback(()=> {
- return null;
- })
- Deno.core.setPromiseRejectCallback(() => {
- return false;
- });
- a = 1 + 2;
- "#,
- )
- .unwrap();
- runtime.snapshot()
- };
-
- let snapshot = Snapshot::JustCreated(snapshot);
- let mut runtime2 = JsRuntime::new(RuntimeOptions {
- startup_snapshot: Some(snapshot),
- ..Default::default()
- });
- runtime2
- .execute_script_static("check.js", "if (a != 3) throw Error('x')")
- .unwrap();
-}
-
-#[test]
-fn test_from_boxed_snapshot() {
- let snapshot = {
- let mut runtime =
- JsRuntimeForSnapshot::new(Default::default(), Default::default());
- runtime.execute_script_static("a.js", "a = 1 + 2").unwrap();
- let snap: &[u8] = &runtime.snapshot();
- Vec::from(snap).into_boxed_slice()
- };
-
- let snapshot = Snapshot::Boxed(snapshot);
- let mut runtime2 = JsRuntime::new(RuntimeOptions {
- startup_snapshot: Some(snapshot),
- ..Default::default()
- });
- runtime2
- .execute_script_static("check.js", "if (a != 3) throw Error('x')")
- .unwrap();
-}
-
-#[test]
-fn test_get_module_namespace() {
- #[derive(Default)]
- struct ModsLoader;
-
- impl ModuleLoader for ModsLoader {
- fn resolve(
- &self,
- specifier: &str,
- referrer: &str,
- _kind: ResolutionKind,
- ) -> Result<ModuleSpecifier, Error> {
- assert_eq!(specifier, "file:///main.js");
- assert_eq!(referrer, ".");
- let s = crate::resolve_import(specifier, referrer).unwrap();
- Ok(s)
- }
-
- fn load(
- &self,
- _module_specifier: &ModuleSpecifier,
- _maybe_referrer: Option<&ModuleSpecifier>,
- _is_dyn_import: bool,
- ) -> Pin<Box<ModuleSourceFuture>> {
- async { Err(generic_error("Module loading is not supported")) }
- .boxed_local()
- }
- }
-
- let loader = std::rc::Rc::new(ModsLoader::default());
- let mut runtime = JsRuntime::new(RuntimeOptions {
- module_loader: Some(loader),
- ..Default::default()
- });
-
- let specifier = crate::resolve_url("file:///main.js").unwrap();
- let source_code = ascii_str!(
- r#"
- export const a = "b";
- export default 1 + 2;
- "#
- );
-
- let module_id = futures::executor::block_on(
- runtime.load_main_module(&specifier, Some(source_code)),
- )
- .unwrap();
-
- #[allow(clippy::let_underscore_future)]
- let _ = runtime.mod_evaluate(module_id);
-
- let module_namespace = runtime.get_module_namespace(module_id).unwrap();
-
- let scope = &mut runtime.handle_scope();
-
- let module_namespace = v8::Local::<v8::Object>::new(scope, module_namespace);
-
- assert!(module_namespace.is_module_namespace_object());
-
- let unknown_export_name = v8::String::new(scope, "none").unwrap();
- let binding = module_namespace.get(scope, unknown_export_name.into());
-
- assert!(binding.is_some());
- assert!(binding.unwrap().is_undefined());
-
- let empty_export_name = v8::String::new(scope, "").unwrap();
- let binding = module_namespace.get(scope, empty_export_name.into());
-
- assert!(binding.is_some());
- assert!(binding.unwrap().is_undefined());
-
- let a_export_name = v8::String::new(scope, "a").unwrap();
- let binding = module_namespace.get(scope, a_export_name.into());
-
- assert!(binding.unwrap().is_string());
- assert_eq!(binding.unwrap(), v8::String::new(scope, "b").unwrap());
-
- let default_export_name = v8::String::new(scope, "default").unwrap();
- let binding = module_namespace.get(scope, default_export_name.into());
-
- assert!(binding.unwrap().is_number());
- assert_eq!(binding.unwrap(), v8::Number::new(scope, 3_f64));
-}
-
-#[test]
-fn test_heap_limits() {
- let create_params =
- v8::Isolate::create_params().heap_limits(0, 5 * 1024 * 1024);
- let mut runtime = JsRuntime::new(RuntimeOptions {
- create_params: Some(create_params),
- ..Default::default()
- });
- let cb_handle = runtime.v8_isolate().thread_safe_handle();
-
- let callback_invoke_count = Rc::new(AtomicUsize::new(0));
- let inner_invoke_count = Rc::clone(&callback_invoke_count);
-
- runtime.add_near_heap_limit_callback(move |current_limit, _initial_limit| {
- inner_invoke_count.fetch_add(1, Ordering::SeqCst);
- cb_handle.terminate_execution();
- current_limit * 2
- });
- let err = runtime
- .execute_script_static(
- "script name",
- r#"let s = ""; while(true) { s += "Hello"; }"#,
- )
- .expect_err("script should fail");
- assert_eq!(
- "Uncaught Error: execution terminated",
- err.downcast::<JsError>().unwrap().exception_message
- );
- assert!(callback_invoke_count.load(Ordering::SeqCst) > 0)
-}
-
-#[test]
-fn test_heap_limit_cb_remove() {
- let mut runtime = JsRuntime::new(Default::default());
-
- runtime.add_near_heap_limit_callback(|current_limit, _initial_limit| {
- current_limit * 2
- });
- runtime.remove_near_heap_limit_callback(3 * 1024 * 1024);
- assert!(runtime.allocations.near_heap_limit_callback_data.is_none());
-}
-
-#[test]
-fn test_heap_limit_cb_multiple() {
- let create_params =
- v8::Isolate::create_params().heap_limits(0, 5 * 1024 * 1024);
- let mut runtime = JsRuntime::new(RuntimeOptions {
- create_params: Some(create_params),
- ..Default::default()
- });
- let cb_handle = runtime.v8_isolate().thread_safe_handle();
-
- let callback_invoke_count_first = Rc::new(AtomicUsize::new(0));
- let inner_invoke_count_first = Rc::clone(&callback_invoke_count_first);
- runtime.add_near_heap_limit_callback(move |current_limit, _initial_limit| {
- inner_invoke_count_first.fetch_add(1, Ordering::SeqCst);
- current_limit * 2
- });
-
- let callback_invoke_count_second = Rc::new(AtomicUsize::new(0));
- let inner_invoke_count_second = Rc::clone(&callback_invoke_count_second);
- runtime.add_near_heap_limit_callback(move |current_limit, _initial_limit| {
- inner_invoke_count_second.fetch_add(1, Ordering::SeqCst);
- cb_handle.terminate_execution();
- current_limit * 2
- });
-
- let err = runtime
- .execute_script_static(
- "script name",
- r#"let s = ""; while(true) { s += "Hello"; }"#,
- )
- .expect_err("script should fail");
- assert_eq!(
- "Uncaught Error: execution terminated",
- err.downcast::<JsError>().unwrap().exception_message
- );
- assert_eq!(0, callback_invoke_count_first.load(Ordering::SeqCst));
- assert!(callback_invoke_count_second.load(Ordering::SeqCst) > 0);
-}
-
-#[test]
-fn es_snapshot() {
- #[derive(Default)]
- struct ModsLoader;
-
- impl ModuleLoader for ModsLoader {
- fn resolve(
- &self,
- specifier: &str,
- referrer: &str,
- _kind: ResolutionKind,
- ) -> Result<ModuleSpecifier, Error> {
- let s = crate::resolve_import(specifier, referrer).unwrap();
- Ok(s)
- }
-
- fn load(
- &self,
- _module_specifier: &ModuleSpecifier,
- _maybe_referrer: Option<&ModuleSpecifier>,
- _is_dyn_import: bool,
- ) -> Pin<Box<ModuleSourceFuture>> {
- eprintln!("load() should not be called");
- unreachable!()
- }
- }
-
- fn create_module(
- runtime: &mut JsRuntime,
- i: usize,
- main: bool,
- ) -> ModuleInfo {
- let specifier = crate::resolve_url(&format!("file:///{i}.js")).unwrap();
- let prev = i - 1;
- let source_code = format!(
- r#"
- import {{ f{prev} }} from "file:///{prev}.js";
- export function f{i}() {{ return f{prev}() }}
- "#
- )
- .into();
-
- let id = if main {
- futures::executor::block_on(
- runtime.load_main_module(&specifier, Some(source_code)),
- )
- .unwrap()
- } else {
- futures::executor::block_on(
- runtime.load_side_module(&specifier, Some(source_code)),
- )
- .unwrap()
- };
- assert_eq!(i, id);
-
- #[allow(clippy::let_underscore_future)]
- let _ = runtime.mod_evaluate(id);
- futures::executor::block_on(runtime.run_event_loop(false)).unwrap();
-
- ModuleInfo {
- id,
- main,
- name: specifier.into(),
- requests: vec![crate::modules::ModuleRequest {
- specifier: format!("file:///{prev}.js"),
- asserted_module_type: AssertedModuleType::JavaScriptOrWasm,
- }],
- module_type: ModuleType::JavaScript,
- }
- }
-
- fn assert_module_map(runtime: &mut JsRuntime, modules: &Vec<ModuleInfo>) {
- let module_map = runtime.module_map.borrow();
- assert_eq!(module_map.handles.len(), modules.len());
- assert_eq!(module_map.info.len(), modules.len());
- assert_eq!(
- module_map.by_name(AssertedModuleType::Json).len()
- + module_map
- .by_name(AssertedModuleType::JavaScriptOrWasm)
- .len(),
- modules.len()
- );
-
- assert_eq!(module_map.next_load_id, (modules.len() + 1) as ModuleLoadId);
-
- for info in modules {
- assert!(module_map.handles.get(info.id).is_some());
- assert_eq!(module_map.info.get(info.id).unwrap(), info);
- assert_eq!(
- module_map
- .by_name(AssertedModuleType::JavaScriptOrWasm)
- .get(&info.name)
- .unwrap(),
- &SymbolicModule::Mod(info.id)
- );
- }
- }
-
- #[op]
- fn op_test() -> Result<String, Error> {
- Ok(String::from("test"))
- }
-
- let loader = Rc::new(ModsLoader::default());
- let mut runtime = JsRuntimeForSnapshot::new(
- RuntimeOptions {
- module_loader: Some(loader.clone()),
- extensions: vec![Extension::builder("text_ext")
- .ops(vec![op_test::decl()])
- .build()],
- ..Default::default()
- },
- Default::default(),
- );
-
- let specifier = crate::resolve_url("file:///0.js").unwrap();
- let source_code =
- ascii_str!(r#"export function f0() { return "hello world" }"#);
- let id = futures::executor::block_on(
- runtime.load_side_module(&specifier, Some(source_code)),
- )
- .unwrap();
-
- #[allow(clippy::let_underscore_future)]
- let _ = runtime.mod_evaluate(id);
- futures::executor::block_on(runtime.run_event_loop(false)).unwrap();
-
- let mut modules = vec![];
- modules.push(ModuleInfo {
- id,
- main: false,
- name: specifier.into(),
- requests: vec![],
- module_type: ModuleType::JavaScript,
- });
-
- modules.extend((1..200).map(|i| create_module(&mut runtime, i, false)));
-
- assert_module_map(&mut runtime, &modules);
-
- let snapshot = runtime.snapshot();
-
- let mut runtime2 = JsRuntimeForSnapshot::new(
- RuntimeOptions {
- module_loader: Some(loader.clone()),
- startup_snapshot: Some(Snapshot::JustCreated(snapshot)),
- extensions: vec![Extension::builder("text_ext")
- .ops(vec![op_test::decl()])
- .build()],
- ..Default::default()
- },
- Default::default(),
- );
-
- assert_module_map(&mut runtime2, &modules);
-
- modules.extend((200..400).map(|i| create_module(&mut runtime2, i, false)));
- modules.push(create_module(&mut runtime2, 400, true));
-
- assert_module_map(&mut runtime2, &modules);
-
- let snapshot2 = runtime2.snapshot();
-
- let mut runtime3 = JsRuntime::new(RuntimeOptions {
- module_loader: Some(loader),
- startup_snapshot: Some(Snapshot::JustCreated(snapshot2)),
- extensions: vec![Extension::builder("text_ext")
- .ops(vec![op_test::decl()])
- .build()],
- ..Default::default()
- });
-
- assert_module_map(&mut runtime3, &modules);
-
- let source_code = r#"(async () => {
- const mod = await import("file:///400.js");
- return mod.f400() + " " + Deno.core.ops.op_test();
- })();"#;
- let val = runtime3.execute_script_static(".", source_code).unwrap();
- let val = futures::executor::block_on(runtime3.resolve_value(val)).unwrap();
- {
- let scope = &mut runtime3.handle_scope();
- let value = v8::Local::new(scope, val);
- let str_ = value.to_string(scope).unwrap().to_rust_string_lossy(scope);
- assert_eq!(str_, "hello world test");
- }
-}
-
-#[test]
-fn test_error_without_stack() {
- let mut runtime = JsRuntime::new(RuntimeOptions::default());
- // SyntaxError
- let result = runtime.execute_script_static(
- "error_without_stack.js",
- r#"
-function main() {
- console.log("asdf);
-}
-main();
-"#,
- );
- let expected_error = r#"Uncaught SyntaxError: Invalid or unexpected token
- at error_without_stack.js:3:15"#;
- assert_eq!(result.unwrap_err().to_string(), expected_error);
-}
-
-#[test]
-fn test_error_stack() {
- let mut runtime = JsRuntime::new(RuntimeOptions::default());
- let result = runtime.execute_script_static(
- "error_stack.js",
- r#"
-function assert(cond) {
- if (!cond) {
- throw Error("assert");
- }
-}
-function main() {
- assert(false);
-}
-main();
- "#,
- );
- let expected_error = r#"Error: assert
- at assert (error_stack.js:4:11)
- at main (error_stack.js:8:3)
- at error_stack.js:10:1"#;
- assert_eq!(result.unwrap_err().to_string(), expected_error);
-}
-
-#[tokio::test]
-async fn test_error_async_stack() {
- let mut runtime = JsRuntime::new(RuntimeOptions::default());
- poll_fn(move |cx| {
- runtime
- .execute_script_static(
- "error_async_stack.js",
- r#"
- (async () => {
- const p = (async () => {
- await Promise.resolve().then(() => {
- throw new Error("async");
- });
- })();
- try {
- await p;
- } catch (error) {
- console.log(error.stack);
- throw error;
- }
- })();"#,
- )
- .unwrap();
- let expected_error = r#"Error: async
- at error_async_stack.js:5:13
- at async error_async_stack.js:4:5
- at async error_async_stack.js:9:5"#;
-
- match runtime.poll_event_loop(cx, false) {
- Poll::Ready(Err(e)) => {
- assert_eq!(e.to_string(), expected_error);
- }
- _ => panic!(),
- };
- Poll::Ready(())
- })
- .await;
-}
-
-#[tokio::test]
-async fn test_error_context() {
- use anyhow::anyhow;
-
- #[op]
- fn op_err_sync() -> Result<(), Error> {
- Err(anyhow!("original sync error").context("higher-level sync error"))
- }
-
- #[op]
- async fn op_err_async() -> Result<(), Error> {
- Err(anyhow!("original async error").context("higher-level async error"))
- }
-
- deno_core::extension!(test_ext, ops = [op_err_sync, op_err_async]);
- let mut runtime = JsRuntime::new(RuntimeOptions {
- extensions: vec![test_ext::init_ops()],
- ..Default::default()
- });
-
- poll_fn(move |cx| {
- runtime
- .execute_script_static(
- "test_error_context_sync.js",
- r#"
-let errMessage;
-try {
- Deno.core.ops.op_err_sync();
-} catch (err) {
- errMessage = err.message;
-}
-if (errMessage !== "higher-level sync error: original sync error") {
- throw new Error("unexpected error message from op_err_sync: " + errMessage);
-}
-"#,
- )
- .unwrap();
-
- let promise = runtime
- .execute_script_static(
- "test_error_context_async.js",
- r#"
-
-(async () => {
-let errMessage;
-try {
- await Deno.core.opAsync("op_err_async");
-} catch (err) {
- errMessage = err.message;
-}
-if (errMessage !== "higher-level async error: original async error") {
- throw new Error("unexpected error message from op_err_async: " + errMessage);
-}
-})()
-"#,
- )
- .unwrap();
-
- match runtime.poll_value(&promise, cx) {
- Poll::Ready(Ok(_)) => {}
- Poll::Ready(Err(err)) => panic!("{err:?}"),
- _ => panic!(),
- }
- Poll::Ready(())
- })
- .await;
-}
-
-#[tokio::test]
-async fn test_pump_message_loop() {
- let mut runtime = JsRuntime::new(RuntimeOptions::default());
- poll_fn(move |cx| {
- runtime
- .execute_script_static(
- "pump_message_loop.js",
- r#"
-function assertEquals(a, b) {
-if (a === b) return;
-throw a + " does not equal " + b;
-}
-const sab = new SharedArrayBuffer(16);
-const i32a = new Int32Array(sab);
-globalThis.resolved = false;
-(function() {
-const result = Atomics.waitAsync(i32a, 0, 0);
-result.value.then(
- (value) => { assertEquals("ok", value); globalThis.resolved = true; },
- () => { assertUnreachable();
-});
-})();
-const notify_return_value = Atomics.notify(i32a, 0, 1);
-assertEquals(1, notify_return_value);
-"#,
- )
- .unwrap();
-
- match runtime.poll_event_loop(cx, false) {
- Poll::Ready(Ok(())) => {}
- _ => panic!(),
- };
-
- // noop script, will resolve promise from first script
- runtime
- .execute_script_static("pump_message_loop2.js", r#"assertEquals(1, 1);"#)
- .unwrap();
-
- // check that promise from `Atomics.waitAsync` has been resolved
- runtime
- .execute_script_static(
- "pump_message_loop3.js",
- r#"assertEquals(globalThis.resolved, true);"#,
- )
- .unwrap();
- Poll::Ready(())
- })
- .await;
-}
-
-#[test]
-fn test_v8_platform() {
- let options = RuntimeOptions {
- v8_platform: Some(v8::new_default_platform(0, false).make_shared()),
- ..Default::default()
- };
- let mut runtime = JsRuntime::new(options);
- runtime.execute_script_static("<none>", "").unwrap();
-}
-
-#[ignore] // TODO(@littledivy): Fast API ops when snapshot is not loaded.
-#[test]
-fn test_is_proxy() {
- let mut runtime = JsRuntime::new(RuntimeOptions::default());
- let all_true: v8::Global<v8::Value> = runtime
- .execute_script_static(
- "is_proxy.js",
- r#"
- (function () {
- const o = { a: 1, b: 2};
- const p = new Proxy(o, {});
- return Deno.core.ops.op_is_proxy(p) && !Deno.core.ops.op_is_proxy(o) && !Deno.core.ops.op_is_proxy(42);
- })()
- "#,
- )
- .unwrap();
- let mut scope = runtime.handle_scope();
- let all_true = v8::Local::<v8::Value>::new(&mut scope, &all_true);
- assert!(all_true.is_true());
-}
-
-#[tokio::test]
-async fn test_async_opstate_borrow() {
- struct InnerState(u64);
-
- #[op]
- async fn op_async_borrow(
- op_state: Rc<RefCell<OpState>>,
- ) -> Result<(), Error> {
- let n = {
- let op_state = op_state.borrow();
- let inner_state = op_state.borrow::<InnerState>();
- inner_state.0
- };
- // Future must be Poll::Pending on first call
- tokio::time::sleep(std::time::Duration::from_millis(1)).await;
- if n != 42 {
- unreachable!();
- }
- Ok(())
- }
-
- deno_core::extension!(
- test_ext,
- ops = [op_async_borrow],
- state = |state| state.put(InnerState(42))
- );
- let mut runtime = JsRuntime::new(RuntimeOptions {
- extensions: vec![test_ext::init_ops()],
- ..Default::default()
- });
-
- runtime
- .execute_script_static(
- "op_async_borrow.js",
- "Deno.core.opAsync(\"op_async_borrow\")",
- )
- .unwrap();
- runtime.run_event_loop(false).await.unwrap();
-}
-
-#[tokio::test]
-async fn test_sync_op_serialize_object_with_numbers_as_keys() {
- #[op]
- fn op_sync_serialize_object_with_numbers_as_keys(
- value: serde_json::Value,
- ) -> Result<(), Error> {
- assert_eq!(
- value.to_string(),
- r#"{"lines":{"100":{"unit":"m"},"200":{"unit":"cm"}}}"#
- );
- Ok(())
- }
-
- deno_core::extension!(
- test_ext,
- ops = [op_sync_serialize_object_with_numbers_as_keys]
- );
- let mut runtime = JsRuntime::new(RuntimeOptions {
- extensions: vec![test_ext::init_ops()],
- ..Default::default()
- });
-
- runtime
- .execute_script_static(
- "op_sync_serialize_object_with_numbers_as_keys.js",
- r#"
-Deno.core.ops.op_sync_serialize_object_with_numbers_as_keys({
-lines: {
- 100: {
- unit: "m"
- },
- 200: {
- unit: "cm"
- }
-}
-})
-"#,
- )
- .unwrap();
- runtime.run_event_loop(false).await.unwrap();
-}
-
-#[tokio::test]
-async fn test_async_op_serialize_object_with_numbers_as_keys() {
- #[op]
- async fn op_async_serialize_object_with_numbers_as_keys(
- value: serde_json::Value,
- ) -> Result<(), Error> {
- assert_eq!(
- value.to_string(),
- r#"{"lines":{"100":{"unit":"m"},"200":{"unit":"cm"}}}"#
- );
- Ok(())
- }
-
- deno_core::extension!(
- test_ext,
- ops = [op_async_serialize_object_with_numbers_as_keys]
- );
- let mut runtime = JsRuntime::new(RuntimeOptions {
- extensions: vec![test_ext::init_ops()],
- ..Default::default()
- });
-
- runtime
- .execute_script_static(
- "op_async_serialize_object_with_numbers_as_keys.js",
- r#"
-
-Deno.core.opAsync("op_async_serialize_object_with_numbers_as_keys", {
-lines: {
- 100: {
- unit: "m"
- },
- 200: {
- unit: "cm"
- }
-}
-})
-"#,
- )
- .unwrap();
- runtime.run_event_loop(false).await.unwrap();
-}
-
-#[tokio::test]
-async fn test_set_macrotask_callback_set_next_tick_callback() {
- #[op]
- async fn op_async_sleep() -> Result<(), Error> {
- // Future must be Poll::Pending on first call
- tokio::time::sleep(std::time::Duration::from_millis(1)).await;
- Ok(())
- }
-
- deno_core::extension!(test_ext, ops = [op_async_sleep]);
- let mut runtime = JsRuntime::new(RuntimeOptions {
- extensions: vec![test_ext::init_ops()],
- ..Default::default()
- });
-
- runtime
- .execute_script_static(
- "macrotasks_and_nextticks.js",
- r#"
-
- (async function () {
- const results = [];
- Deno.core.setMacrotaskCallback(() => {
- results.push("macrotask");
- return true;
- });
- Deno.core.setNextTickCallback(() => {
- results.push("nextTick");
- Deno.core.ops.op_set_has_tick_scheduled(false);
- });
- Deno.core.ops.op_set_has_tick_scheduled(true);
- await Deno.core.opAsync('op_async_sleep');
- if (results[0] != "nextTick") {
- throw new Error(`expected nextTick, got: ${results[0]}`);
- }
- if (results[1] != "macrotask") {
- throw new Error(`expected macrotask, got: ${results[1]}`);
- }
- })();
- "#,
- )
- .unwrap();
- runtime.run_event_loop(false).await.unwrap();
-}
-
-#[test]
-fn test_has_tick_scheduled() {
- use futures::task::ArcWake;
-
- static MACROTASK: AtomicUsize = AtomicUsize::new(0);
- static NEXT_TICK: AtomicUsize = AtomicUsize::new(0);
-
- #[op]
- fn op_macrotask() -> Result<(), AnyError> {
- MACROTASK.fetch_add(1, Ordering::Relaxed);
- Ok(())
- }
-
- #[op]
- fn op_next_tick() -> Result<(), AnyError> {
- NEXT_TICK.fetch_add(1, Ordering::Relaxed);
- Ok(())
- }
-
- deno_core::extension!(test_ext, ops = [op_macrotask, op_next_tick]);
- let mut runtime = JsRuntime::new(RuntimeOptions {
- extensions: vec![test_ext::init_ops()],
- ..Default::default()
- });
-
- runtime
- .execute_script_static(
- "has_tick_scheduled.js",
- r#"
- Deno.core.setMacrotaskCallback(() => {
- Deno.core.ops.op_macrotask();
- return true; // We're done.
- });
- Deno.core.setNextTickCallback(() => Deno.core.ops.op_next_tick());
- Deno.core.ops.op_set_has_tick_scheduled(true);
- "#,
- )
- .unwrap();
-
- struct ArcWakeImpl(Arc<AtomicUsize>);
- impl ArcWake for ArcWakeImpl {
- fn wake_by_ref(arc_self: &Arc<Self>) {
- arc_self.0.fetch_add(1, Ordering::Relaxed);
- }
- }
-
- let awoken_times = Arc::new(AtomicUsize::new(0));
- let waker = futures::task::waker(Arc::new(ArcWakeImpl(awoken_times.clone())));
- let cx = &mut Context::from_waker(&waker);
-
- assert!(matches!(runtime.poll_event_loop(cx, false), Poll::Pending));
- assert_eq!(1, MACROTASK.load(Ordering::Relaxed));
- assert_eq!(1, NEXT_TICK.load(Ordering::Relaxed));
- assert_eq!(awoken_times.swap(0, Ordering::Relaxed), 1);
- assert!(matches!(runtime.poll_event_loop(cx, false), Poll::Pending));
- assert_eq!(awoken_times.swap(0, Ordering::Relaxed), 1);
- assert!(matches!(runtime.poll_event_loop(cx, false), Poll::Pending));
- assert_eq!(awoken_times.swap(0, Ordering::Relaxed), 1);
- assert!(matches!(runtime.poll_event_loop(cx, false), Poll::Pending));
- assert_eq!(awoken_times.swap(0, Ordering::Relaxed), 1);
-
- runtime.inner.state.borrow_mut().has_tick_scheduled = false;
- assert!(matches!(
- runtime.poll_event_loop(cx, false),
- Poll::Ready(Ok(()))
- ));
- assert_eq!(awoken_times.load(Ordering::Relaxed), 0);
- assert!(matches!(
- runtime.poll_event_loop(cx, false),
- Poll::Ready(Ok(()))
- ));
- assert_eq!(awoken_times.load(Ordering::Relaxed), 0);
-}
-
-#[test]
-fn terminate_during_module_eval() {
- #[derive(Default)]
- struct ModsLoader;
-
- impl ModuleLoader for ModsLoader {
- fn resolve(
- &self,
- specifier: &str,
- referrer: &str,
- _kind: ResolutionKind,
- ) -> Result<ModuleSpecifier, Error> {
- assert_eq!(specifier, "file:///main.js");
- assert_eq!(referrer, ".");
- let s = crate::resolve_import(specifier, referrer).unwrap();
- Ok(s)
- }
-
- fn load(
- &self,
- _module_specifier: &ModuleSpecifier,
- _maybe_referrer: Option<&ModuleSpecifier>,
- _is_dyn_import: bool,
- ) -> Pin<Box<ModuleSourceFuture>> {
- async move {
- Ok(ModuleSource::for_test(
- "console.log('hello world');",
- "file:///main.js",
- ))
- }
- .boxed_local()
- }
- }
-
- let loader = std::rc::Rc::new(ModsLoader::default());
- let mut runtime = JsRuntime::new(RuntimeOptions {
- module_loader: Some(loader),
- ..Default::default()
- });
-
- let specifier = crate::resolve_url("file:///main.js").unwrap();
- let source_code = ascii_str!("Deno.core.print('hello\\n')");
-
- let module_id = futures::executor::block_on(
- runtime.load_main_module(&specifier, Some(source_code)),
- )
- .unwrap();
-
- runtime.v8_isolate().terminate_execution();
-
- let mod_result =
- futures::executor::block_on(runtime.mod_evaluate(module_id)).unwrap();
- assert!(mod_result
- .unwrap_err()
- .to_string()
- .contains("JavaScript execution has been terminated"));
-}
-
-#[tokio::test]
-async fn test_unhandled_rejection_order() {
- let mut runtime = JsRuntime::new(Default::default());
- runtime
- .execute_script_static(
- "",
- r#"
- for (let i = 0; i < 100; i++) {
- Promise.reject(i);
- }
- "#,
- )
- .unwrap();
- let err = runtime.run_event_loop(false).await.unwrap_err();
- assert_eq!(err.to_string(), "Uncaught (in promise) 0");
-}
-
-#[tokio::test]
-async fn test_set_promise_reject_callback() {
- static PROMISE_REJECT: AtomicUsize = AtomicUsize::new(0);
-
- #[op]
- fn op_promise_reject() -> Result<(), AnyError> {
- PROMISE_REJECT.fetch_add(1, Ordering::Relaxed);
- Ok(())
- }
-
- deno_core::extension!(test_ext, ops = [op_promise_reject]);
- let mut runtime = JsRuntime::new(RuntimeOptions {
- extensions: vec![test_ext::init_ops()],
- ..Default::default()
- });
-
- runtime
- .execute_script_static(
- "promise_reject_callback.js",
- r#"
- // Note: |promise| is not the promise created below, it's a child.
- Deno.core.ops.op_set_promise_reject_callback((type, promise, reason) => {
- if (type !== /* PromiseRejectWithNoHandler */ 0) {
- throw Error("unexpected type: " + type);
- }
- if (reason.message !== "reject") {
- throw Error("unexpected reason: " + reason);
- }
- Deno.core.ops.op_store_pending_promise_rejection(promise);
- Deno.core.ops.op_promise_reject();
- });
- new Promise((_, reject) => reject(Error("reject")));
- "#,
- )
- .unwrap();
- runtime.run_event_loop(false).await.unwrap_err();
-
- assert_eq!(1, PROMISE_REJECT.load(Ordering::Relaxed));
-
- runtime
- .execute_script_static(
- "promise_reject_callback.js",
- r#"
- {
- const prev = Deno.core.ops.op_set_promise_reject_callback((...args) => {
- prev(...args);
- });
- }
- new Promise((_, reject) => reject(Error("reject")));
- "#,
- )
- .unwrap();
- runtime.run_event_loop(false).await.unwrap_err();
-
- assert_eq!(2, PROMISE_REJECT.load(Ordering::Relaxed));
-}
-
-#[tokio::test]
-async fn test_set_promise_reject_callback_realms() {
- let mut runtime = JsRuntime::new(RuntimeOptions::default());
- let global_realm = runtime.global_realm();
- let realm1 = runtime.create_realm().unwrap();
- let realm2 = runtime.create_realm().unwrap();
-
- let realm_expectations = &[
- (&global_realm, "global_realm", 42),
- (&realm1, "realm1", 140),
- (&realm2, "realm2", 720),
- ];
-
- // Set up promise reject callbacks.
- for (realm, realm_name, number) in realm_expectations {
- realm
- .execute_script(
- runtime.v8_isolate(),
- "",
- format!(
- r#"
-
- globalThis.rejectValue = undefined;
- Deno.core.setPromiseRejectCallback((_type, _promise, reason) => {{
- globalThis.rejectValue = `{realm_name}/${{reason}}`;
- }});
- Deno.core.opAsync("op_void_async").then(() => Promise.reject({number}));
- "#
- ).into()
- )
- .unwrap();
- }
-
- runtime.run_event_loop(false).await.unwrap();
-
- for (realm, realm_name, number) in realm_expectations {
- let reject_value = realm
- .execute_script_static(runtime.v8_isolate(), "", "globalThis.rejectValue")
- .unwrap();
- let scope = &mut realm.handle_scope(runtime.v8_isolate());
- let reject_value = v8::Local::new(scope, reject_value);
- assert!(reject_value.is_string());
- let reject_value_string = reject_value.to_rust_string_lossy(scope);
- assert_eq!(reject_value_string, format!("{realm_name}/{number}"));
- }
-}
-
-#[tokio::test]
-async fn test_set_promise_reject_callback_top_level_await() {
- static PROMISE_REJECT: AtomicUsize = AtomicUsize::new(0);
-
- #[op]
- fn op_promise_reject() -> Result<(), AnyError> {
- PROMISE_REJECT.fetch_add(1, Ordering::Relaxed);
- Ok(())
- }
-
- deno_core::extension!(test_ext, ops = [op_promise_reject]);
-
- #[derive(Default)]
- struct ModsLoader;
-
- impl ModuleLoader for ModsLoader {
- fn resolve(
- &self,
- specifier: &str,
- referrer: &str,
- _kind: ResolutionKind,
- ) -> Result<ModuleSpecifier, Error> {
- assert_eq!(specifier, "file:///main.js");
- assert_eq!(referrer, ".");
- let s = crate::resolve_import(specifier, referrer).unwrap();
- Ok(s)
- }
-
- fn load(
- &self,
- _module_specifier: &ModuleSpecifier,
- _maybe_referrer: Option<&ModuleSpecifier>,
- _is_dyn_import: bool,
- ) -> Pin<Box<ModuleSourceFuture>> {
- let code = r#"
- Deno.core.ops.op_set_promise_reject_callback((type, promise, reason) => {
- Deno.core.ops.op_promise_reject();
- });
- throw new Error('top level throw');
- "#;
-
- async move { Ok(ModuleSource::for_test(code, "file:///main.js")) }
- .boxed_local()
- }
- }
-
- let mut runtime = JsRuntime::new(RuntimeOptions {
- extensions: vec![test_ext::init_ops()],
- module_loader: Some(Rc::new(ModsLoader)),
- ..Default::default()
- });
-
- let id = runtime
- .load_main_module(&crate::resolve_url("file:///main.js").unwrap(), None)
- .await
- .unwrap();
- let receiver = runtime.mod_evaluate(id);
- runtime.run_event_loop(false).await.unwrap();
- receiver.await.unwrap().unwrap_err();
-
- assert_eq!(1, PROMISE_REJECT.load(Ordering::Relaxed));
-}
-
-#[test]
-fn test_op_return_serde_v8_error() {
- #[op]
- fn op_err() -> Result<std::collections::BTreeMap<u64, u64>, anyhow::Error> {
- Ok([(1, 2), (3, 4)].into_iter().collect()) // Maps can't have non-string keys in serde_v8
- }
-
- deno_core::extension!(test_ext, ops = [op_err]);
- let mut runtime = JsRuntime::new(RuntimeOptions {
- extensions: vec![test_ext::init_ops()],
- ..Default::default()
- });
- assert!(runtime
- .execute_script_static(
- "test_op_return_serde_v8_error.js",
- "Deno.core.ops.op_err()"
- )
- .is_err());
-}
-
-#[test]
-fn test_op_high_arity() {
- #[op]
- fn op_add_4(
- x1: i64,
- x2: i64,
- x3: i64,
- x4: i64,
- ) -> Result<i64, anyhow::Error> {
- Ok(x1 + x2 + x3 + x4)
- }
-
- deno_core::extension!(test_ext, ops = [op_add_4]);
- let mut runtime = JsRuntime::new(RuntimeOptions {
- extensions: vec![test_ext::init_ops()],
- ..Default::default()
- });
- let r = runtime
- .execute_script_static("test.js", "Deno.core.ops.op_add_4(1, 2, 3, 4)")
- .unwrap();
- let scope = &mut runtime.handle_scope();
- assert_eq!(r.open(scope).integer_value(scope), Some(10));
-}
-
-#[test]
-fn test_op_disabled() {
- #[op]
- fn op_foo() -> Result<i64, anyhow::Error> {
- Ok(42)
- }
-
- fn ops() -> Vec<OpDecl> {
- vec![op_foo::decl().disable()]
- }
-
- deno_core::extension!(test_ext, ops_fn = ops);
- let mut runtime = JsRuntime::new(RuntimeOptions {
- extensions: vec![test_ext::init_ops()],
- ..Default::default()
- });
- let err = runtime
- .execute_script_static("test.js", "Deno.core.ops.op_foo()")
- .unwrap_err();
- assert!(err
- .to_string()
- .contains("TypeError: Deno.core.ops.op_foo is not a function"));
-}
-
-#[test]
-fn test_op_detached_buffer() {
- use serde_v8::DetachedBuffer;
-
- #[op]
- fn op_sum_take(b: DetachedBuffer) -> Result<u64, anyhow::Error> {
- Ok(b.as_ref().iter().clone().map(|x| *x as u64).sum())
- }
-
- #[op]
- fn op_boomerang(b: DetachedBuffer) -> Result<DetachedBuffer, anyhow::Error> {
- Ok(b)
- }
-
- deno_core::extension!(test_ext, ops = [op_sum_take, op_boomerang]);
- let mut runtime = JsRuntime::new(RuntimeOptions {
- extensions: vec![test_ext::init_ops()],
- ..Default::default()
- });
-
- runtime
- .execute_script_static(
- "test.js",
- r#"
- const a1 = new Uint8Array([1,2,3]);
- const a1b = a1.subarray(0, 3);
- const a2 = new Uint8Array([5,10,15]);
- const a2b = a2.subarray(0, 3);
- if (!(a1.length > 0 && a1b.length > 0)) {
- throw new Error("a1 & a1b should have a length");
- }
- let sum = Deno.core.ops.op_sum_take(a1b);
- if (sum !== 6) {
- throw new Error(`Bad sum: ${sum}`);
- }
- if (a1.length > 0 || a1b.length > 0) {
- throw new Error("expecting a1 & a1b to be detached");
- }
- const a3 = Deno.core.ops.op_boomerang(a2b);
- if (a3.byteLength != 3) {
- throw new Error(`Expected a3.byteLength === 3, got ${a3.byteLength}`);
- }
- if (a3[0] !== 5 || a3[1] !== 10) {
- throw new Error(`Invalid a3: ${a3[0]}, ${a3[1]}`);
- }
- if (a2.byteLength > 0 || a2b.byteLength > 0) {
- throw new Error("expecting a2 & a2b to be detached, a3 re-attached");
- }
- const wmem = new WebAssembly.Memory({ initial: 1, maximum: 2 });
- const w32 = new Uint32Array(wmem.buffer);
- w32[0] = 1; w32[1] = 2; w32[2] = 3;
- const assertWasmThrow = (() => {
- try {
- let sum = Deno.core.ops.op_sum_take(w32.subarray(0, 2));
- return false;
- } catch(e) {
- return e.message.includes('invalid type; expected: detachable');
- }
- });
- if (!assertWasmThrow()) {
- throw new Error("expected wasm mem to not be detachable");
- }
- "#,
- )
- .unwrap();
-}
-
-#[test]
-fn test_op_unstable_disabling() {
- #[op]
- fn op_foo() -> Result<i64, anyhow::Error> {
- Ok(42)
- }
-
- #[op(unstable)]
- fn op_bar() -> Result<i64, anyhow::Error> {
- Ok(42)
- }
-
- deno_core::extension!(
- test_ext,
- ops = [op_foo, op_bar],
- middleware = |op| if op.is_unstable { op.disable() } else { op }
- );
- let mut runtime = JsRuntime::new(RuntimeOptions {
- extensions: vec![test_ext::init_ops()],
- ..Default::default()
- });
- runtime
- .execute_script_static(
- "test.js",
- r#"
- if (Deno.core.ops.op_foo() !== 42) {
- throw new Error("Expected op_foo() === 42");
- }
- if (typeof Deno.core.ops.op_bar !== "undefined") {
- throw new Error("Expected op_bar to be disabled")
- }
- "#,
- )
- .unwrap();
-}
-
-#[test]
-fn js_realm_simple() {
- let mut runtime = JsRuntime::new(Default::default());
- let main_context = runtime.global_context();
- let main_global = {
- let scope = &mut runtime.handle_scope();
- let local_global = main_context.open(scope).global(scope);
- v8::Global::new(scope, local_global)
- };
-
- let realm = runtime.create_realm().unwrap();
- assert_ne!(realm.context(), &main_context);
- assert_ne!(realm.global_object(runtime.v8_isolate()), main_global);
-
- let main_object = runtime.execute_script_static("", "Object").unwrap();
- let realm_object = realm
- .execute_script_static(runtime.v8_isolate(), "", "Object")
- .unwrap();
- assert_ne!(main_object, realm_object);
-}
-
-#[test]
-fn js_realm_init() {
- #[op]
- fn op_test() -> Result<String, Error> {
- Ok(String::from("Test"))
- }
-
- deno_core::extension!(test_ext, ops = [op_test]);
- let mut runtime = JsRuntime::new(RuntimeOptions {
- extensions: vec![test_ext::init_ops()],
- ..Default::default()
- });
- let realm = runtime.create_realm().unwrap();
- let ret = realm
- .execute_script_static(runtime.v8_isolate(), "", "Deno.core.ops.op_test()")
- .unwrap();
-
- let scope = &mut realm.handle_scope(runtime.v8_isolate());
- assert_eq!(ret, serde_v8::to_v8(scope, "Test").unwrap());
-}
-
-#[test]
-fn js_realm_init_snapshot() {
- let snapshot = {
- let runtime =
- JsRuntimeForSnapshot::new(Default::default(), Default::default());
- let snap: &[u8] = &runtime.snapshot();
- Vec::from(snap).into_boxed_slice()
- };
-
- #[op]
- fn op_test() -> Result<String, Error> {
- Ok(String::from("Test"))
- }
-
- deno_core::extension!(test_ext, ops = [op_test]);
- let mut runtime = JsRuntime::new(RuntimeOptions {
- startup_snapshot: Some(Snapshot::Boxed(snapshot)),
- extensions: vec![test_ext::init_ops()],
- ..Default::default()
- });
- let realm = runtime.create_realm().unwrap();
- let ret = realm
- .execute_script_static(runtime.v8_isolate(), "", "Deno.core.ops.op_test()")
- .unwrap();
-
- let scope = &mut realm.handle_scope(runtime.v8_isolate());
- assert_eq!(ret, serde_v8::to_v8(scope, "Test").unwrap());
-}
-
-#[test]
-fn js_realm_sync_ops() {
- // Test that returning a RustToV8Buf and throwing an exception from a sync
- // op result in objects with prototypes from the right realm. Note that we
- // don't test the result of returning structs, because they will be
- // serialized to objects with null prototype.
-
- #[op]
- fn op_test(fail: bool) -> Result<ToJsBuffer, Error> {
- if !fail {
- Ok(ToJsBuffer::empty())
- } else {
- Err(crate::error::type_error("Test"))
- }
- }
-
- deno_core::extension!(test_ext, ops = [op_test]);
- let mut runtime = JsRuntime::new(RuntimeOptions {
- extensions: vec![test_ext::init_ops()],
- get_error_class_fn: Some(&|error| {
- crate::error::get_custom_error_class(error).unwrap()
- }),
- ..Default::default()
- });
- let new_realm = runtime.create_realm().unwrap();
-
- // Test in both realms
- for realm in [runtime.global_realm(), new_realm].into_iter() {
- let ret = realm
- .execute_script_static(
- runtime.v8_isolate(),
- "",
- r#"
- const buf = Deno.core.ops.op_test(false);
- try {
- Deno.core.ops.op_test(true);
- } catch(e) {
- err = e;
- }
- buf instanceof Uint8Array && buf.byteLength === 0 &&
- err instanceof TypeError && err.message === "Test"
- "#,
- )
- .unwrap();
- assert!(ret.open(runtime.v8_isolate()).is_true());
- }
-}
-
-#[tokio::test]
-async fn js_realm_async_ops() {
- // Test that returning a RustToV8Buf and throwing an exception from a async
- // op result in objects with prototypes from the right realm. Note that we
- // don't test the result of returning structs, because they will be
- // serialized to objects with null prototype.
-
- #[op]
- async fn op_test(fail: bool) -> Result<ToJsBuffer, Error> {
- if !fail {
- Ok(ToJsBuffer::empty())
- } else {
- Err(crate::error::type_error("Test"))
- }
- }
-
- deno_core::extension!(test_ext, ops = [op_test]);
- let mut runtime = JsRuntime::new(RuntimeOptions {
- extensions: vec![test_ext::init_ops()],
- get_error_class_fn: Some(&|error| {
- crate::error::get_custom_error_class(error).unwrap()
- }),
- ..Default::default()
- });
-
- let global_realm = runtime.global_realm();
- let new_realm = runtime.create_realm().unwrap();
-
- let mut rets = vec![];
-
- // Test in both realms
- for realm in [global_realm, new_realm].into_iter() {
- let ret = realm
- .execute_script_static(
- runtime.v8_isolate(),
- "",
- r#"
-
- (async function () {
- const buf = await Deno.core.opAsync("op_test", false);
- let err;
- try {
- await Deno.core.opAsync("op_test", true);
- } catch(e) {
- err = e;
- }
- return buf instanceof Uint8Array && buf.byteLength === 0 &&
- err instanceof TypeError && err.message === "Test" ;
- })();
- "#,
- )
- .unwrap();
- rets.push((realm, ret));
- }
-
- runtime.run_event_loop(false).await.unwrap();
-
- for ret in rets {
- let scope = &mut ret.0.handle_scope(runtime.v8_isolate());
- let value = v8::Local::new(scope, ret.1);
- let promise = v8::Local::<v8::Promise>::try_from(value).unwrap();
- let result = promise.result(scope);
-
- assert!(result.is_boolean() && result.is_true());
- }
-}
-
-#[ignore]
-#[tokio::test]
-async fn js_realm_gc() {
- static INVOKE_COUNT: AtomicUsize = AtomicUsize::new(0);
- struct PendingFuture {}
-
- impl Future for PendingFuture {
- type Output = ();
- fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<()> {
- Poll::Pending
- }
- }
-
- impl Drop for PendingFuture {
- fn drop(&mut self) {
- assert_eq!(INVOKE_COUNT.fetch_sub(1, Ordering::SeqCst), 1);
- }
- }
-
- // Never resolves.
- #[op]
- async fn op_pending() {
- assert_eq!(INVOKE_COUNT.fetch_add(1, Ordering::SeqCst), 0);
- PendingFuture {}.await
- }
-
- deno_core::extension!(test_ext, ops = [op_pending]);
- let mut runtime = JsRuntime::new(RuntimeOptions {
- extensions: vec![test_ext::init_ops()],
- ..Default::default()
- });
-
- // Detect a drop in OpState
- let opstate_drop_detect = Rc::new(());
- runtime
- .op_state()
- .borrow_mut()
- .put(opstate_drop_detect.clone());
- assert_eq!(Rc::strong_count(&opstate_drop_detect), 2);
-
- let other_realm = runtime.create_realm().unwrap();
- other_realm
- .execute_script(
- runtime.v8_isolate(),
- "future",
- ModuleCode::from_static("Deno.core.opAsync('op_pending')"),
- )
- .unwrap();
- while INVOKE_COUNT.load(Ordering::SeqCst) == 0 {
- poll_fn(|cx: &mut Context| runtime.poll_event_loop(cx, false))
- .await
- .unwrap();
- }
- drop(other_realm);
- while INVOKE_COUNT.load(Ordering::SeqCst) == 1 {
- poll_fn(|cx| runtime.poll_event_loop(cx, false))
- .await
- .unwrap();
- }
- drop(runtime);
-
- // Make sure the OpState was dropped properly when the runtime dropped
- assert_eq!(Rc::strong_count(&opstate_drop_detect), 1);
-}
-
-#[tokio::test]
-async fn js_realm_ref_unref_ops() {
- // Never resolves.
- #[op]
- async fn op_pending() {
- futures::future::pending().await
- }
-
- deno_core::extension!(test_ext, ops = [op_pending]);
- let mut runtime = JsRuntime::new(RuntimeOptions {
- extensions: vec![test_ext::init_ops()],
- ..Default::default()
- });
-
- poll_fn(move |cx| {
- let main_realm = runtime.global_realm();
- let other_realm = runtime.create_realm().unwrap();
-
- main_realm
- .execute_script_static(
- runtime.v8_isolate(),
- "",
- r#"
-
- var promise = Deno.core.opAsync("op_pending");
- "#,
- )
- .unwrap();
- other_realm
- .execute_script_static(
- runtime.v8_isolate(),
- "",
- r#"
-
- var promise = Deno.core.opAsync("op_pending");
- "#,
- )
- .unwrap();
- assert!(matches!(runtime.poll_event_loop(cx, false), Poll::Pending));
-
- main_realm
- .execute_script_static(
- runtime.v8_isolate(),
- "",
- r#"
- let promiseIdSymbol = Symbol.for("Deno.core.internalPromiseId");
- Deno.core.unrefOp(promise[promiseIdSymbol]);
- "#,
- )
- .unwrap();
- assert!(matches!(runtime.poll_event_loop(cx, false), Poll::Pending));
-
- other_realm
- .execute_script_static(
- runtime.v8_isolate(),
- "",
- r#"
- let promiseIdSymbol = Symbol.for("Deno.core.internalPromiseId");
- Deno.core.unrefOp(promise[promiseIdSymbol]);
- "#,
- )
- .unwrap();
- assert!(matches!(
- runtime.poll_event_loop(cx, false),
- Poll::Ready(Ok(()))
- ));
- Poll::Ready(())
- })
- .await;
-}
-
-#[test]
-fn test_array_by_copy() {
- // Verify that "array by copy" proposal is enabled (https://github.com/tc39/proposal-change-array-by-copy)
- let mut runtime = JsRuntime::new(Default::default());
- assert!(runtime
- .execute_script_static(
- "test_array_by_copy.js",
- "const a = [1, 2, 3];
- const b = a.toReversed();
- if (!(a[0] === 1 && a[1] === 2 && a[2] === 3)) {
- throw new Error('Expected a to be intact');
- }
- if (!(b[0] === 3 && b[1] === 2 && b[2] === 1)) {
- throw new Error('Expected b to be reversed');
- }",
- )
- .is_ok());
-}
-
-#[cfg(debug_assertions)]
-#[test]
-#[should_panic(expected = "Found ops with duplicate names:")]
-fn duplicate_op_names() {
- mod a {
- use super::*;
-
- #[op]
- fn op_test() -> Result<String, Error> {
- Ok(String::from("Test"))
- }
- }
-
- #[op]
- fn op_test() -> Result<String, Error> {
- Ok(String::from("Test"))
- }
-
- deno_core::extension!(test_ext, ops = [a::op_test, op_test]);
- JsRuntime::new(RuntimeOptions {
- extensions: vec![test_ext::init_ops()],
- ..Default::default()
- });
-}
-
-#[test]
-fn ops_in_js_have_proper_names() {
- #[op]
- fn op_test_sync() -> Result<String, Error> {
- Ok(String::from("Test"))
- }
-
- #[op]
- async fn op_test_async() -> Result<String, Error> {
- Ok(String::from("Test"))
- }
-
- deno_core::extension!(test_ext, ops = [op_test_sync, op_test_async]);
- let mut runtime = JsRuntime::new(RuntimeOptions {
- extensions: vec![test_ext::init_ops()],
- ..Default::default()
- });
-
- let src = r#"
- if (Deno.core.ops.op_test_sync.name !== "op_test_sync") {
- throw new Error();
- }
-
- if (Deno.core.ops.op_test_async.name !== "op_test_async") {
- throw new Error();
- }
-
- const { op_test_async } = Deno.core.ensureFastOps();
- if (op_test_async.name !== "op_test_async") {
- throw new Error();
- }
- "#;
- runtime.execute_script_static("test", src).unwrap();
-}
diff --git a/core/source_map.rs b/core/source_map.rs
deleted file mode 100644
index 9172ce341..000000000
--- a/core/source_map.rs
+++ /dev/null
@@ -1,109 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-
-//! This mod provides functions to remap a `JsError` based on a source map.
-
-use crate::resolve_url;
-pub use sourcemap::SourceMap;
-use std::collections::HashMap;
-use std::rc::Rc;
-use std::str;
-
-pub trait SourceMapGetter {
- /// Returns the raw source map file.
- fn get_source_map(&self, file_name: &str) -> Option<Vec<u8>>;
- fn get_source_line(
- &self,
- file_name: &str,
- line_number: usize,
- ) -> Option<String>;
-}
-
-impl<T> SourceMapGetter for Rc<T>
-where
- T: SourceMapGetter,
-{
- fn get_source_map(&self, file_name: &str) -> Option<Vec<u8>> {
- (**self).get_source_map(file_name)
- }
-
- fn get_source_line(
- &self,
- file_name: &str,
- line_number: usize,
- ) -> Option<String> {
- (**self).get_source_line(file_name, line_number)
- }
-}
-
-#[derive(Debug, Default)]
-pub struct SourceMapCache {
- maps: HashMap<String, Option<SourceMap>>,
- source_lines: HashMap<(String, i64), Option<String>>,
-}
-
-pub fn apply_source_map<G: SourceMapGetter + ?Sized>(
- file_name: String,
- line_number: i64,
- column_number: i64,
- cache: &mut SourceMapCache,
- getter: &G,
-) -> (String, i64, i64) {
- // Lookup expects 0-based line and column numbers, but ours are 1-based.
- let line_number = line_number - 1;
- let column_number = column_number - 1;
-
- let default_pos = (file_name.clone(), line_number, column_number);
- let maybe_source_map =
- cache.maps.entry(file_name.clone()).or_insert_with(|| {
- getter
- .get_source_map(&file_name)
- .and_then(|raw_source_map| SourceMap::from_slice(&raw_source_map).ok())
- });
- let (file_name, line_number, column_number) = match maybe_source_map {
- None => default_pos,
- Some(source_map) => {
- match source_map.lookup_token(line_number as u32, column_number as u32) {
- None => default_pos,
- Some(token) => match token.get_source() {
- None => default_pos,
- Some(source_file_name) => {
- // The `source_file_name` written by tsc in the source map is
- // sometimes only the basename of the URL, or has unwanted `<`/`>`
- // around it. Use the `file_name` we get from V8 if
- // `source_file_name` does not parse as a URL.
- let file_name = match resolve_url(source_file_name) {
- Ok(m) if m.scheme() == "blob" => file_name,
- Ok(m) => m.to_string(),
- Err(_) => file_name,
- };
- (
- file_name,
- i64::from(token.get_src_line()),
- i64::from(token.get_src_col()),
- )
- }
- },
- }
- }
- };
- (file_name, line_number + 1, column_number + 1)
-}
-
-const MAX_SOURCE_LINE_LENGTH: usize = 150;
-
-pub fn get_source_line<G: SourceMapGetter + ?Sized>(
- file_name: &str,
- line_number: i64,
- cache: &mut SourceMapCache,
- getter: &G,
-) -> Option<String> {
- cache
- .source_lines
- .entry((file_name.to_string(), line_number))
- .or_insert_with(|| {
- // Source lookup expects a 0-based line number, ours are 1-based.
- let s = getter.get_source_line(file_name, (line_number - 1) as usize);
- s.filter(|s| s.len() <= MAX_SOURCE_LINE_LENGTH)
- })
- .clone()
-}
diff --git a/core/task.rs b/core/task.rs
deleted file mode 100644
index 3e728a08f..000000000
--- a/core/task.rs
+++ /dev/null
@@ -1,135 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-use core::pin::Pin;
-use core::task::Context;
-use core::task::Poll;
-use futures::Future;
-use std::marker::PhantomData;
-use tokio::runtime::Handle;
-use tokio::runtime::RuntimeFlavor;
-
-/// Equivalent to [`tokio::task::JoinHandle`].
-#[repr(transparent)]
-pub struct JoinHandle<R> {
- handle: tokio::task::JoinHandle<MaskResultAsSend<R>>,
- _r: PhantomData<R>,
-}
-
-impl<R> JoinHandle<R> {
- /// Equivalent to [`tokio::task::JoinHandle::abort`].
- pub fn abort(&self) {
- self.handle.abort()
- }
-}
-
-impl<R> Future for JoinHandle<R> {
- type Output = Result<R, tokio::task::JoinError>;
-
- fn poll(
- self: Pin<&mut Self>,
- cx: &mut std::task::Context<'_>,
- ) -> std::task::Poll<Self::Output> {
- // SAFETY: We are sure that handle is valid here
- unsafe {
- let me: &mut Self = Pin::into_inner_unchecked(self);
- let handle = Pin::new_unchecked(&mut me.handle);
- match handle.poll(cx) {
- Poll::Pending => Poll::Pending,
- Poll::Ready(Ok(r)) => Poll::Ready(Ok(r.into_inner())),
- Poll::Ready(Err(e)) => Poll::Ready(Err(e)),
- }
- }
- }
-}
-
-/// Equivalent to [`tokio::task::spawn`], but does not require the future to be [`Send`]. Must only be
-/// used on a [`RuntimeFlavor::CurrentThread`] executor, though this is only checked when running with
-/// debug assertions.
-#[inline(always)]
-pub fn spawn<F: Future<Output = R> + 'static, R: 'static>(
- f: F,
-) -> JoinHandle<R> {
- debug_assert!(
- Handle::current().runtime_flavor() == RuntimeFlavor::CurrentThread
- );
- // SAFETY: we know this is a current-thread executor
- let future = unsafe { MaskFutureAsSend::new(f) };
- JoinHandle {
- handle: tokio::task::spawn(future),
- _r: Default::default(),
- }
-}
-
-/// Equivalent to [`tokio::task::spawn_blocking`]. Currently a thin wrapper around the tokio API, but this
-/// may change in the future.
-#[inline(always)]
-pub fn spawn_blocking<
- F: (FnOnce() -> R) + Send + 'static,
- R: Send + 'static,
->(
- f: F,
-) -> JoinHandle<R> {
- let handle = tokio::task::spawn_blocking(|| MaskResultAsSend { result: f() });
- JoinHandle {
- handle,
- _r: Default::default(),
- }
-}
-
-#[repr(transparent)]
-#[doc(hidden)]
-pub struct MaskResultAsSend<R> {
- result: R,
-}
-
-/// SAFETY: We ensure that Send bounds are only faked when tokio is running on a current-thread executor
-unsafe impl<R> Send for MaskResultAsSend<R> {}
-
-impl<R> MaskResultAsSend<R> {
- #[inline(always)]
- pub fn into_inner(self) -> R {
- self.result
- }
-}
-
-#[repr(transparent)]
-pub struct MaskFutureAsSend<F> {
- future: F,
-}
-
-impl<F> MaskFutureAsSend<F> {
- /// Mark a non-`Send` future as `Send`. This is a trick to be able to use
- /// `tokio::spawn()` (which requires `Send` futures) in a current thread
- /// runtime.
- ///
- /// # Safety
- ///
- /// You must ensure that the future is actually used on the same
- /// thread, ie. always use current thread runtime flavor from Tokio.
- #[inline(always)]
- pub unsafe fn new(future: F) -> Self {
- Self { future }
- }
-}
-
-// SAFETY: we are cheating here - this struct is NOT really Send,
-// but we need to mark it Send so that we can use `spawn()` in Tokio.
-unsafe impl<F> Send for MaskFutureAsSend<F> {}
-
-impl<F: Future> Future for MaskFutureAsSend<F> {
- type Output = MaskResultAsSend<F::Output>;
-
- fn poll(
- self: Pin<&mut Self>,
- cx: &mut Context<'_>,
- ) -> Poll<MaskResultAsSend<F::Output>> {
- // SAFETY: We are sure that future is valid here
- unsafe {
- let me: &mut MaskFutureAsSend<F> = Pin::into_inner_unchecked(self);
- let future = Pin::new_unchecked(&mut me.future);
- match future.poll(cx) {
- Poll::Pending => Poll::Pending,
- Poll::Ready(result) => Poll::Ready(MaskResultAsSend { result }),
- }
- }
- }
-}
diff --git a/core/task_queue.rs b/core/task_queue.rs
deleted file mode 100644
index adb25a4f6..000000000
--- a/core/task_queue.rs
+++ /dev/null
@@ -1,143 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-
-use futures::task::AtomicWaker;
-use futures::Future;
-use parking_lot::Mutex;
-use std::collections::LinkedList;
-use std::sync::atomic::AtomicBool;
-use std::sync::atomic::Ordering;
-use std::sync::Arc;
-
-#[derive(Debug, Default)]
-struct TaskQueueTaskWaker {
- is_ready: AtomicBool,
- waker: AtomicWaker,
-}
-
-#[derive(Debug, Default)]
-struct TaskQueueTasks {
- is_running: bool,
- wakers: LinkedList<Arc<TaskQueueTaskWaker>>,
-}
-
-/// A queue that executes tasks sequentially one after the other
-/// ensuring order and that no task runs at the same time as another.
-///
-/// Note that tokio's semaphore doesn't seem to maintain order
-/// and so we can't use that in the code that uses this or use
-/// that here.
-#[derive(Debug, Default)]
-pub struct TaskQueue {
- tasks: Mutex<TaskQueueTasks>,
-}
-
-impl TaskQueue {
- /// Acquires a permit where the tasks are executed one at a time
- /// and in the order that they were acquired.
- pub async fn acquire(&self) -> TaskQueuePermit {
- let acquire = TaskQueuePermitAcquire::new(self);
- acquire.await;
- TaskQueuePermit(self)
- }
-
- /// Alternate API that acquires a permit internally
- /// for the duration of the future.
- pub async fn queue<R>(&self, future: impl Future<Output = R>) -> R {
- let _permit = self.acquire().await;
- future.await
- }
-}
-
-/// A permit that when dropped will allow another task to proceed.
-pub struct TaskQueuePermit<'a>(&'a TaskQueue);
-
-impl<'a> Drop for TaskQueuePermit<'a> {
- fn drop(&mut self) {
- let next_item = {
- let mut tasks = self.0.tasks.lock();
- let next_item = tasks.wakers.pop_front();
- tasks.is_running = next_item.is_some();
- next_item
- };
- if let Some(next_item) = next_item {
- next_item.is_ready.store(true, Ordering::SeqCst);
- next_item.waker.wake();
- }
- }
-}
-
-struct TaskQueuePermitAcquire<'a> {
- task_queue: &'a TaskQueue,
- initialized: AtomicBool,
- waker: Arc<TaskQueueTaskWaker>,
-}
-
-impl<'a> TaskQueuePermitAcquire<'a> {
- pub fn new(task_queue: &'a TaskQueue) -> Self {
- Self {
- task_queue,
- initialized: Default::default(),
- waker: Default::default(),
- }
- }
-}
-
-impl<'a> Future for TaskQueuePermitAcquire<'a> {
- type Output = ();
-
- fn poll(
- self: std::pin::Pin<&mut Self>,
- cx: &mut std::task::Context<'_>,
- ) -> std::task::Poll<Self::Output> {
- // update with the latest waker
- self.waker.waker.register(cx.waker());
-
- // ensure this is initialized
- if !self.initialized.swap(true, Ordering::SeqCst) {
- let mut tasks = self.task_queue.tasks.lock();
- if !tasks.is_running {
- tasks.is_running = true;
- return std::task::Poll::Ready(());
- }
- tasks.wakers.push_back(self.waker.clone());
- return std::task::Poll::Pending;
- }
-
- // check if we're ready to run
- if self.waker.is_ready.load(Ordering::SeqCst) {
- std::task::Poll::Ready(())
- } else {
- std::task::Poll::Pending
- }
- }
-}
-
-#[cfg(test)]
-mod tests {
- use parking_lot::Mutex;
- use std::sync::Arc;
-
- use super::TaskQueue;
-
- #[tokio::test]
- async fn task_queue_runs_one_after_other() {
- let task_queue = TaskQueue::default();
- let mut tasks = Vec::new();
- let data = Arc::new(Mutex::new(0));
- for i in 0..100 {
- let data = data.clone();
- tasks.push(task_queue.queue(async move {
- crate::task::spawn_blocking(move || {
- let mut data = data.lock();
- if *data != i {
- panic!("Value was not equal.");
- }
- *data = i + 1;
- })
- .await
- .unwrap();
- }));
- }
- futures::future::join_all(tasks).await;
- }
-}
diff --git a/ops/Cargo.toml b/ops/Cargo.toml
deleted file mode 100644
index f9951f4e6..000000000
--- a/ops/Cargo.toml
+++ /dev/null
@@ -1,37 +0,0 @@
-# Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-
-[package]
-name = "deno_ops"
-version = "0.69.0"
-authors.workspace = true
-edition.workspace = true
-license.workspace = true
-readme = "README.md"
-repository.workspace = true
-description = "Proc macro for writing Deno Ops"
-
-[lib]
-path = "./lib.rs"
-proc-macro = true
-
-[dependencies]
-deno-proc-macro-rules.workspace = true
-lazy-regex.workspace = true
-once_cell.workspace = true
-pmutil = "0.5.3"
-proc-macro-crate = "1.1.3"
-proc-macro2.workspace = true
-quote.workspace = true
-regex.workspace = true
-strum.workspace = true
-strum_macros.workspace = true
-syn.workspace = true
-syn2.workspace = true
-thiserror.workspace = true
-v8.workspace = true
-
-[dev-dependencies]
-pretty_assertions.workspace = true
-prettyplease = "0.1.21"
-testing_macros = "0.2.7"
-trybuild = "1.0.71"
diff --git a/ops/README.md b/ops/README.md
deleted file mode 100644
index 39d860663..000000000
--- a/ops/README.md
+++ /dev/null
@@ -1,62 +0,0 @@
-# deno_ops
-
-`proc_macro` for generating highly optimized V8 functions from Deno ops.
-
-```rust
-// Declare an op.
-#[op(fast)]
-pub fn op_add(_: &mut OpState, a: i32, b: i32) -> i32 {
- a + b
-}
-
-// Register with an extension.
-Extension::builder()
- .ops(vec![op_add::decl()])
- .build();
-```
-
-## Performance
-
-The macro can optimize away code, short circuit fast paths and generate a Fast
-API impl.
-
-Cases where code is optimized away:
-
-- `-> ()` skips serde_v8 and `rv.set` calls.
-- `-> Result<(), E>` skips serde_v8 and `rv.set` calls for `Ok()` branch.
-- `-> ResourceId` or `-> [int]` types will use specialized method like
- `v8::ReturnValue::set_uint32`. A fast path for SMI.
-- `-> Result<ResourceId, E>` or `-> Result<[int], E>` types will be optimized
- like above for the `Ok()` branch.
-
-### Fast calls
-
-The macro will infer and try to auto generate V8 fast API call trait impl for
-`sync` ops with:
-
-- arguments: integers, bool, `&mut OpState`, `&[u8]`, `&mut [u8]`, `&[u32]`,
- `&mut [u32]`
-- return_type: integers, bool
-
-The `#[op(fast)]` attribute should be used to enforce fast call generation at
-compile time.
-
-Trait gen for `async` ops & a ZeroCopyBuf equivalent type is planned and will be
-added soon.
-
-### Wasm calls
-
-The `#[op(wasm)]` attribute should be used for calls expected to be called from
-Wasm. This enables the fast call generation and allows seamless `WasmMemory`
-integration for generic and fast calls.
-
-```rust
-#[op(wasm)]
-pub fn op_args_get(
- offset: i32,
- buffer_offset: i32,
- memory: Option<&[u8]>, // Must be last parameter. Some(..) when entered from Wasm.
-) {
- // ...
-}
-```
diff --git a/ops/attrs.rs b/ops/attrs.rs
deleted file mode 100644
index d0182fc69..000000000
--- a/ops/attrs.rs
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-use syn::parse::Parse;
-use syn::parse::ParseStream;
-use syn::Error;
-use syn::Ident;
-use syn::Result;
-use syn::Token;
-
-#[derive(Clone, Debug, Default)]
-pub struct Attributes {
- pub is_unstable: bool,
- pub is_v8: bool,
- pub must_be_fast: bool,
- pub deferred: bool,
- pub is_wasm: bool,
- pub relation: Option<Ident>,
-}
-
-impl Parse for Attributes {
- fn parse(input: ParseStream) -> Result<Self> {
- let mut self_ = Self::default();
- let mut fast = false;
- while let Ok(v) = input.parse::<Ident>() {
- match v.to_string().as_str() {
- "unstable" => self_.is_unstable = true,
- "v8" => self_.is_v8 = true,
- "fast" => fast = true,
- "deferred" => self_.deferred = true,
- "wasm" => self_.is_wasm = true,
- "slow" => {
- if !fast {
- return Err(Error::new(
- input.span(),
- "relational attributes can only be used with fast attribute",
- ));
- }
- input.parse::<Token![=]>()?;
- self_.relation = Some(input.parse()?);
- }
- _ => {
- return Err(Error::new(
- input.span(),
- "invalid attribute, expected one of: unstable, v8, fast, deferred, wasm",
- ));
- }
- };
- let _ = input.parse::<Token![,]>();
- }
-
- self_.must_be_fast = self_.is_wasm || fast;
-
- Ok(self_)
- }
-}
diff --git a/ops/deno.rs b/ops/deno.rs
deleted file mode 100644
index fbaf2a9e6..000000000
--- a/ops/deno.rs
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-#![cfg(not(test))]
-
-use proc_macro2::Span;
-use proc_macro2::TokenStream;
-use proc_macro_crate::crate_name;
-use proc_macro_crate::FoundCrate;
-use quote::quote;
-use syn::Ident;
-
-/// Identifier to the `deno_core` crate.
-///
-/// If macro called in deno_core, `crate` is used.
-/// If macro called outside deno_core, `deno_core` OR the renamed
-/// version from Cargo.toml is used.
-pub(crate) fn import() -> TokenStream {
- let found_crate =
- crate_name("deno_core").expect("deno_core not present in `Cargo.toml`");
-
- match found_crate {
- FoundCrate::Itself => {
- // TODO(@littledivy): This won't work for `deno_core` examples
- // since `crate` does not refer to `deno_core`.
- // examples must re-export deno_core to make this work
- // until Span inspection APIs are stabilized.
- //
- // https://github.com/rust-lang/rust/issues/54725
- quote!(crate)
- }
- FoundCrate::Name(name) => {
- let ident = Ident::new(&name, Span::call_site());
- quote!(#ident)
- }
- }
-}
diff --git a/ops/fast_call.rs b/ops/fast_call.rs
deleted file mode 100644
index 63cff4c62..000000000
--- a/ops/fast_call.rs
+++ /dev/null
@@ -1,363 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-//! Code generation for V8 fast calls.
-
-use pmutil::q;
-use pmutil::Quote;
-use pmutil::ToTokensExt;
-use proc_macro2::Span;
-use proc_macro2::TokenStream;
-use quote::quote;
-use syn::parse_quote;
-use syn::punctuated::Punctuated;
-use syn::token::Comma;
-use syn::Generics;
-use syn::Ident;
-use syn::ItemFn;
-
-use crate::optimizer::FastValue;
-use crate::optimizer::Optimizer;
-
-pub(crate) struct FastImplItems {
- pub(crate) impl_and_fn: TokenStream,
- pub(crate) decl: TokenStream,
- pub(crate) active: bool,
-}
-
-pub(crate) fn generate(
- core: &TokenStream,
- optimizer: &mut Optimizer,
- item_fn: &ItemFn,
-) -> FastImplItems {
- if !optimizer.fast_compatible {
- return FastImplItems {
- impl_and_fn: TokenStream::new(),
- decl: quote! { None },
- active: false,
- };
- }
-
- // TODO(@littledivy): Use `let..else` on 1.65.0
- let output_ty = match &optimizer.fast_result {
- // Assert that the optimizer did not set a return type.
- //
- // @littledivy: This *could* potentially be used to optimize resolving
- // promises but knowing the return type at compile time instead of
- // serde_v8 serialization.
- Some(_) if optimizer.is_async => &FastValue::Void,
- Some(ty) => ty,
- None if optimizer.is_async => &FastValue::Void,
- None => {
- return FastImplItems {
- impl_and_fn: TokenStream::new(),
- decl: quote! { None },
- active: false,
- }
- }
- };
-
- // We've got 2 idents.
- //
- // - op_foo, the public op declaration contains the user function.
- // - op_foo_fast_fn, the fast call function.
- let ident = item_fn.sig.ident.clone();
- let fast_fn_ident =
- Ident::new(&format!("{ident}_fast_fn"), Span::call_site());
-
- // Deal with generics.
- let generics = &item_fn.sig.generics;
- let (impl_generics, _, where_clause) = generics.split_for_impl();
-
- // This goes in the FastFunction impl block.
- // let mut segments = Punctuated::new();
- // {
- // let mut arguments = PathArguments::None;
- // if let Some(ref struct_generics) = struct_generics {
- // arguments = PathArguments::AngleBracketed(parse_quote! {
- // #struct_generics
- // });
- // }
- // segments.push_value(PathSegment {
- // ident: fast_ident.clone(),
- // arguments,
- // });
- // }
-
- // Original inputs.
- let mut inputs = item_fn.sig.inputs.clone();
- let mut transforms = q!({});
- let mut pre_transforms = q!({});
-
- // Apply parameter transforms
- for (index, input) in inputs.iter_mut().enumerate() {
- if let Some(transform) = optimizer.transforms.get(&index) {
- let quo: Quote = transform.apply_for_fast_call(core, input);
- transforms.push_tokens(&quo);
- }
- }
-
- // Collect idents to be passed into function call, we can now freely
- // modify the inputs.
- let idents = inputs
- .iter()
- .map(|input| match input {
- syn::FnArg::Typed(pat_type) => match &*pat_type.pat {
- syn::Pat::Ident(pat_ident) => pat_ident.ident.clone(),
- _ => panic!("unexpected pattern"),
- },
- _ => panic!("unexpected argument"),
- })
- .collect::<Punctuated<_, Comma>>();
-
- // Retain only *pure* parameters.
- let mut fast_fn_inputs = if optimizer.has_opstate_in_parameters() {
- inputs.into_iter().skip(1).collect()
- } else {
- inputs
- };
-
- let mut input_variants = optimizer
- .fast_parameters
- .iter()
- .map(q_fast_ty_variant)
- .collect::<Punctuated<_, Comma>>();
-
- // Apply *hard* optimizer hints.
- if optimizer.has_fast_callback_option
- || optimizer.has_wasm_memory
- || optimizer.needs_opstate()
- || optimizer.is_async
- || optimizer.needs_fast_callback_option
- {
- let decl = parse_quote! {
- fast_api_callback_options: *mut #core::v8::fast_api::FastApiCallbackOptions
- };
-
- if optimizer.has_fast_callback_option || optimizer.has_wasm_memory {
- // Replace last parameter.
- assert!(fast_fn_inputs.pop().is_some());
- fast_fn_inputs.push(decl);
- } else {
- fast_fn_inputs.push(decl);
- }
-
- input_variants.push(q!({ CallbackOptions }));
- }
-
- // (recv, p_id, ...)
- //
- // Optimizer has already set it in the fast parameter variant list.
- if optimizer.is_async {
- if fast_fn_inputs.is_empty() {
- fast_fn_inputs.push(parse_quote! { __promise_id: i32 });
- } else {
- fast_fn_inputs.insert(0, parse_quote! { __promise_id: i32 });
- }
- }
-
- let mut output_transforms = q!({});
-
- if optimizer.needs_opstate()
- || optimizer.is_async
- || optimizer.has_fast_callback_option
- || optimizer.has_wasm_memory
- {
- // Dark arts 🪄 ✨
- //
- // - V8 calling convention guarantees that the callback options pointer is non-null.
- // - `data` union is always initialized as the `v8::Local<v8::Value>` variant.
- // - deno_core guarantees that `data` is a v8 External pointing to an OpCtx for the
- // isolate's lifetime.
- let prelude = q!({
- let __opts: &mut v8::fast_api::FastApiCallbackOptions =
- unsafe { &mut *fast_api_callback_options };
- });
-
- pre_transforms.push_tokens(&prelude);
- }
-
- if optimizer.needs_opstate() || optimizer.is_async {
- // Grab the op_state identifier, the first one. ¯\_(ツ)_/¯
- let op_state = match idents.first() {
- Some(ident) if optimizer.has_opstate_in_parameters() => ident.clone(),
- // fn op_foo() -> Result<...>
- _ => Ident::new("op_state", Span::call_site()),
- };
-
- let ctx = q!({
- let __ctx = unsafe {
- &*(v8::Local::<v8::External>::cast(unsafe { __opts.data.data }).value()
- as *const _ops::OpCtx)
- };
- });
-
- pre_transforms.push_tokens(&ctx);
- pre_transforms.push_tokens(&match optimizer.is_async {
- false => q!(
- Vars {
- op_state: &op_state
- },
- {
- let op_state = &mut ::std::cell::RefCell::borrow_mut(&__ctx.state);
- }
- ),
- true => q!(
- Vars {
- op_state: &op_state
- },
- {
- let op_state = __ctx.state.clone();
- }
- ),
- });
-
- if optimizer.returns_result && !optimizer.is_async {
- // Magic fallback 🪄
- //
- // If Result<T, E> is Ok(T), return T as fast value.
- //
- // Err(E) gets put into `last_fast_op_error` slot and
- //
- // V8 calls the slow path so we can take the slot
- // value and throw.
- let default = optimizer.fast_result.as_ref().unwrap().default_value();
- let result_wrap = q!(Vars { op_state, default }, {
- match result {
- Ok(result) => result,
- Err(err) => {
- op_state.last_fast_op_error.replace(err);
- __opts.fallback = true;
- default
- }
- }
- });
-
- output_transforms.push_tokens(&result_wrap);
- }
- }
-
- if optimizer.is_async {
- let queue_future = if optimizer.returns_result {
- q!({
- let result = _ops::queue_fast_async_op(__ctx, __promise_id, result);
- })
- } else {
- q!({
- let result =
- _ops::queue_fast_async_op(__ctx, __promise_id, async move {
- Ok(result.await)
- });
- })
- };
-
- output_transforms.push_tokens(&queue_future);
- }
-
- if !optimizer.returns_result {
- let default_output = q!({ result });
- output_transforms.push_tokens(&default_output);
- }
-
- let output = q_fast_ty(output_ty);
- // Generate the function body.
- //
- // fn f <S> (_: Local<Object>, a: T, b: U) -> R {
- // /* Transforms */
- // let a = a.into();
- // let b = b.into();
- //
- // let r = op::call(a, b);
- //
- // /* Return transform */
- // r.into()
- // }
- let fast_fn = q!(
- Vars { core, pre_transforms, op_name_fast: &fast_fn_ident, op_name: &ident, fast_fn_inputs, generics, where_clause, idents, transforms, output_transforms, output: &output },
- {
- impl generics op_name generics where_clause {
- #[allow(clippy::too_many_arguments)]
- fn op_name_fast (_: core::v8::Local<core::v8::Object>, fast_fn_inputs) -> output {
- use core::v8;
- use core::_ops;
- pre_transforms
- transforms
- let result = Self::call (idents);
- output_transforms
- }
- }
- }
- );
-
- let output_variant = q_fast_ty_variant(output_ty);
- let mut generics: Generics = parse_quote! { #impl_generics };
- generics.where_clause = where_clause.cloned();
-
- // fast_api::FastFunction::new(&[ CType::T, CType::U ], CType::T, f::<P> as *const ::std::ffi::c_void)
- let decl = q!(
- Vars {
- core: core,
- fast_fn_ident: fast_fn_ident,
- inputs: input_variants,
- output: output_variant
- },
- {
- {
- use core::v8::fast_api::CType;
- use core::v8::fast_api::Type::*;
- Some(core::v8::fast_api::FastFunction::new(
- &[inputs],
- CType::output,
- Self::fast_fn_ident as *const ::std::ffi::c_void,
- ))
- }
- }
- )
- .dump();
-
- let impl_and_fn = fast_fn.dump();
-
- FastImplItems {
- impl_and_fn,
- decl,
- active: true,
- }
-}
-
-/// Quote fast value type.
-fn q_fast_ty(v: &FastValue) -> Quote {
- match v {
- FastValue::Void => q!({ () }),
- FastValue::Bool => q!({ bool }),
- FastValue::U32 => q!({ u32 }),
- FastValue::I32 => q!({ i32 }),
- FastValue::U64 => q!({ u64 }),
- FastValue::I64 => q!({ i64 }),
- FastValue::F32 => q!({ f32 }),
- FastValue::F64 => q!({ f64 }),
- FastValue::Pointer => q!({ *mut ::std::ffi::c_void }),
- FastValue::V8Value => q!({ v8::Local<v8::Value> }),
- FastValue::Uint8Array
- | FastValue::Uint32Array
- | FastValue::Float64Array
- | FastValue::SeqOneByteString => unreachable!(),
- }
-}
-
-/// Quote fast value type's variant.
-fn q_fast_ty_variant(v: &FastValue) -> Quote {
- match v {
- FastValue::Void => q!({ Void }),
- FastValue::Bool => q!({ Bool }),
- FastValue::U32 => q!({ Uint32 }),
- FastValue::I32 => q!({ Int32 }),
- FastValue::U64 => q!({ Uint64 }),
- FastValue::I64 => q!({ Int64 }),
- FastValue::F32 => q!({ Float32 }),
- FastValue::F64 => q!({ Float64 }),
- FastValue::Pointer => q!({ Pointer }),
- FastValue::V8Value => q!({ V8Value }),
- FastValue::Uint8Array => q!({ TypedArray(CType::Uint8) }),
- FastValue::Uint32Array => q!({ TypedArray(CType::Uint32) }),
- FastValue::Float64Array => q!({ TypedArray(CType::Float64) }),
- FastValue::SeqOneByteString => q!({ SeqOneByteString }),
- }
-}
diff --git a/ops/lib.rs b/ops/lib.rs
deleted file mode 100644
index 31398a14d..000000000
--- a/ops/lib.rs
+++ /dev/null
@@ -1,1025 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-
-use attrs::Attributes;
-use optimizer::BailoutReason;
-use optimizer::Optimizer;
-use proc_macro::TokenStream;
-use proc_macro2::Span;
-use proc_macro2::TokenStream as TokenStream2;
-use quote::quote;
-use quote::ToTokens;
-use std::error::Error;
-use syn::parse;
-use syn::parse_macro_input;
-use syn::punctuated::Punctuated;
-use syn::token::Comma;
-use syn::FnArg;
-use syn::GenericParam;
-use syn::Ident;
-use syn::ItemFn;
-use syn::Lifetime;
-use syn::LifetimeDef;
-
-mod attrs;
-mod deno;
-mod fast_call;
-mod op2;
-mod optimizer;
-
-const SCOPE_LIFETIME: &str = "'scope";
-
-/// Add the 'scope lifetime to the function signature.
-fn add_scope_lifetime(func: &mut ItemFn) {
- let span = Span::call_site();
- let lifetime = LifetimeDef::new(Lifetime::new(SCOPE_LIFETIME, span));
- let generics = &mut func.sig.generics;
- if !generics.lifetimes().any(|def| *def == lifetime) {
- generics.params.push(GenericParam::Lifetime(lifetime));
- }
-}
-
-struct Op {
- orig: ItemFn,
- item: ItemFn,
- /// Is this an async op?
- /// - `async fn`
- /// - returns a Future
- is_async: bool,
- // optimizer: Optimizer,
- core: TokenStream2,
- attrs: Attributes,
-}
-
-impl Op {
- fn new(item: ItemFn, attrs: Attributes) -> Self {
- // Preserve the original function. Change the name to `call`.
- //
- // impl op_foo {
- // fn call() {}
- // ...
- // }
- let mut orig = item.clone();
- orig.sig.ident = Ident::new("call", Span::call_site());
-
- let is_async = item.sig.asyncness.is_some() || is_future(&item.sig.output);
- let scope_params = exclude_non_lifetime_params(&item.sig.generics.params);
- orig.sig.generics.params = scope_params;
- orig.sig.generics.where_clause.take();
- add_scope_lifetime(&mut orig);
-
- #[cfg(test)]
- let core = quote!(deno_core);
- #[cfg(not(test))]
- let core = deno::import();
-
- Self {
- orig,
- item,
- is_async,
- core,
- attrs,
- }
- }
-
- fn gen(mut self) -> TokenStream2 {
- let mut optimizer = Optimizer::new();
- match optimizer.analyze(&mut self) {
- Err(BailoutReason::MustBeSingleSegment)
- | Err(BailoutReason::FastUnsupportedParamType) => {
- optimizer.fast_compatible = false;
- }
- _ => {}
- };
-
- let Self {
- core,
- item,
- is_async,
- orig,
- attrs,
- } = self;
- let name = &item.sig.ident;
-
- // TODO(mmastrac): this code is a little awkward but eventually it'll disappear in favour of op2
- let mut generics = item.sig.generics.clone();
- generics.where_clause.take();
- generics.params = exclude_lifetime_params(&generics.params);
- let params = &generics.params.iter().collect::<Vec<_>>();
- let where_clause = &item.sig.generics.where_clause;
-
- // First generate fast call bindings to opt-in to error handling in slow call
- let fast_call::FastImplItems {
- impl_and_fn,
- decl,
- active,
- } = fast_call::generate(&core, &mut optimizer, &item);
-
- let docline = format!("Use `{name}::decl()` to get an op-declaration");
-
- let is_v8 = attrs.is_v8;
- let is_unstable = attrs.is_unstable;
-
- if let Some(v8_fn) = attrs.relation {
- return quote! {
- #[allow(non_camel_case_types)]
- #[doc="Auto-generated by `deno_ops`, i.e: `#[op]`"]
- #[doc=""]
- #[doc=#docline]
- #[doc="you can include in a `deno_core::Extension`."]
- pub struct #name #generics {
- _phantom_data: ::std::marker::PhantomData<(#(#params),*)>
- }
-
- impl #generics #core::_ops::Op for #name #generics #where_clause {
- const NAME: &'static str = stringify!(#name);
- const DECL: #core::OpDecl = #core::OpDecl {
- name: Self::name(),
- v8_fn_ptr: #v8_fn::v8_fn_ptr as _,
- enabled: true,
- fast_fn: #decl,
- is_async: #is_async,
- is_unstable: #is_unstable,
- is_v8: #is_v8,
- // TODO(mmastrac)
- arg_count: 0,
- };
- }
-
- #[doc(hidden)]
- impl #generics #name #generics #where_clause {
- pub const fn name() -> &'static str {
- stringify!(#name)
- }
-
- pub const fn decl () -> #core::OpDecl {
- #core::OpDecl {
- name: Self::name(),
- v8_fn_ptr: #v8_fn::v8_fn_ptr as _,
- enabled: true,
- fast_fn: #decl,
- is_async: #is_async,
- is_unstable: #is_unstable,
- is_v8: #is_v8,
- // TODO(mmastrac)
- arg_count: 0,
- }
- }
-
- #[inline]
- #[allow(clippy::too_many_arguments)]
- #[allow(clippy::extra_unused_lifetimes)]
- #orig
- }
-
- #impl_and_fn
- };
- }
-
- let has_fallible_fast_call = active && optimizer.returns_result;
-
- let (v8_body, arg_count) = if is_async {
- let deferred: bool = attrs.deferred;
- codegen_v8_async(
- &core,
- &item,
- attrs,
- item.sig.asyncness.is_some(),
- deferred,
- )
- } else {
- codegen_v8_sync(&core, &item, attrs, has_fallible_fast_call)
- };
-
- // Generate wrapper
- quote! {
- #[allow(non_camel_case_types)]
- #[doc="Auto-generated by `deno_ops`, i.e: `#[op]`"]
- #[doc=""]
- #[doc=#docline]
- #[doc="you can include in a `deno_core::Extension`."]
- pub struct #name #generics {
- _phantom_data: ::std::marker::PhantomData<(#(#params),*)>
- }
-
- impl #generics #core::_ops::Op for #name #generics #where_clause {
- const NAME: &'static str = stringify!(#name);
- const DECL: #core::OpDecl = #core::OpDecl {
- name: Self::name(),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: #decl,
- is_async: #is_async,
- is_unstable: #is_unstable,
- is_v8: #is_v8,
- // TODO(mmastrac)
- arg_count: 0,
- };
- }
-
- #[doc(hidden)]
- impl #generics #name #generics #where_clause {
- pub const fn name() -> &'static str {
- stringify!(#name)
- }
-
- #[allow(clippy::not_unsafe_ptr_arg_deref)]
- pub extern "C" fn v8_fn_ptr (info: *const #core::v8::FunctionCallbackInfo) {
- let info = unsafe { &*info };
- let scope = &mut unsafe { #core::v8::CallbackScope::new(info) };
- let args = #core::v8::FunctionCallbackArguments::from_function_callback_info(info);
- let rv = #core::v8::ReturnValue::from_function_callback_info(info);
- Self::v8_func(scope, args, rv);
- }
-
- pub const fn decl () -> #core::OpDecl {
- #core::OpDecl {
- name: Self::name(),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: #decl,
- is_async: #is_async,
- is_unstable: #is_unstable,
- is_v8: #is_v8,
- arg_count: #arg_count as u8,
- }
- }
-
- #[inline]
- #[allow(clippy::too_many_arguments)]
- #[allow(clippy::extra_unused_lifetimes)]
- #orig
-
- pub fn v8_func<'scope>(
- scope: &mut #core::v8::HandleScope<'scope>,
- args: #core::v8::FunctionCallbackArguments,
- mut rv: #core::v8::ReturnValue,
- ) {
- #v8_body
- }
- }
-
- #impl_and_fn
- }
- }
-}
-
-#[proc_macro_attribute]
-pub fn op(attr: TokenStream, item: TokenStream) -> TokenStream {
- let margs = parse_macro_input!(attr as Attributes);
- let func = parse::<ItemFn>(item).expect("expected a function");
- let op = Op::new(func, margs);
- op.gen().into()
-}
-
-#[proc_macro_attribute]
-pub fn op2(attr: TokenStream, item: TokenStream) -> TokenStream {
- match crate::op2::op2(attr.into(), item.into()) {
- Ok(output) => output.into(),
- Err(err) => {
- let mut err: &dyn Error = &err;
- let mut output = "Failed to parse #[op2]:\n".to_owned();
- loop {
- output += &format!(" - {err}\n");
- if let Some(source) = err.source() {
- err = source;
- } else {
- break;
- }
- }
- panic!("{output}");
- }
- }
-}
-
-/// Generate the body of a v8 func for an async op
-fn codegen_v8_async(
- core: &TokenStream2,
- f: &syn::ItemFn,
- margs: Attributes,
- asyncness: bool,
- deferred: bool,
-) -> (TokenStream2, usize) {
- let Attributes { is_v8, .. } = margs;
- let special_args = f
- .sig
- .inputs
- .iter()
- .map_while(|a| {
- (if is_v8 { scope_arg(a) } else { None })
- .or_else(|| rc_refcell_opstate_arg(a))
- })
- .collect::<Vec<_>>();
- let rust_i0 = special_args.len();
- let args_head = special_args.into_iter().collect::<TokenStream2>();
-
- let (arg_decls, args_tail, _) = codegen_args(core, f, rust_i0, 1, asyncness);
-
- let wrapper = match (asyncness, is_result(&f.sig.output)) {
- (true, true) => {
- quote! {
- let fut = #core::_ops::map_async_op1(ctx, Self::call(#args_head #args_tail));
- let maybe_response = #core::_ops::queue_async_op(
- ctx,
- scope,
- #deferred,
- promise_id,
- fut,
- );
- }
- }
- (true, false) => {
- quote! {
- let fut = #core::_ops::map_async_op2(ctx, Self::call(#args_head #args_tail));
- let maybe_response = #core::_ops::queue_async_op(
- ctx,
- scope,
- #deferred,
- promise_id,
- fut,
- );
- }
- }
- (false, true) => {
- quote! {
- let fut = #core::_ops::map_async_op3(ctx, Self::call(#args_head #args_tail));
- let maybe_response = #core::_ops::queue_async_op(
- ctx,
- scope,
- #deferred,
- promise_id,
- fut,
- );
- }
- }
- (false, false) => {
- quote! {
- let fut = #core::_ops::map_async_op4(ctx, Self::call(#args_head #args_tail));
- let maybe_response = #core::_ops::queue_async_op(
- ctx,
- scope,
- #deferred,
- promise_id,
- fut,
- );
- }
- }
- };
-
- let token_stream = quote! {
- use #core::futures::FutureExt;
- // SAFETY: #core guarantees args.data() is a v8 External pointing to an OpCtx for the isolates lifetime
- let ctx = unsafe {
- &*(#core::v8::Local::<#core::v8::External>::cast(args.data()).value()
- as *const #core::_ops::OpCtx)
- };
-
- let promise_id = args.get(0);
- let promise_id = #core::v8::Local::<#core::v8::Integer>::try_from(promise_id)
- .map(|l| l.value() as #core::PromiseId)
- .map_err(#core::anyhow::Error::from);
- // Fail if promise id invalid (not an int)
- let promise_id: #core::PromiseId = match promise_id {
- Ok(promise_id) => promise_id,
- Err(err) => {
- #core::_ops::throw_type_error(scope, format!("invalid promise id: {}", err));
- return;
- }
- };
-
- #arg_decls
- #wrapper
-
- if let Some(response) = maybe_response {
- rv.set(response);
- }
- };
-
- // +1 arg for the promise ID
- (token_stream, 1 + f.sig.inputs.len() - rust_i0)
-}
-
-fn scope_arg(arg: &FnArg) -> Option<TokenStream2> {
- if is_handle_scope(arg) {
- Some(quote! { scope, })
- } else {
- None
- }
-}
-
-fn opstate_arg(arg: &FnArg) -> Option<TokenStream2> {
- match arg {
- arg if is_rc_refcell_opstate(arg) => Some(quote! { ctx.state.clone(), }),
- arg if is_mut_ref_opstate(arg) => {
- Some(quote! { &mut std::cell::RefCell::borrow_mut(&ctx.state), })
- }
- _ => None,
- }
-}
-
-fn rc_refcell_opstate_arg(arg: &FnArg) -> Option<TokenStream2> {
- match arg {
- arg if is_rc_refcell_opstate(arg) => Some(quote! { ctx.state.clone(), }),
- arg if is_mut_ref_opstate(arg) => Some(
- quote! { compile_error!("mutable opstate is not supported in async ops"), },
- ),
- _ => None,
- }
-}
-
-/// Generate the body of a v8 func for a sync op
-fn codegen_v8_sync(
- core: &TokenStream2,
- f: &syn::ItemFn,
- margs: Attributes,
- has_fallible_fast_call: bool,
-) -> (TokenStream2, usize) {
- let Attributes { is_v8, .. } = margs;
- let special_args = f
- .sig
- .inputs
- .iter()
- .map_while(|a| {
- (if is_v8 { scope_arg(a) } else { None }).or_else(|| opstate_arg(a))
- })
- .collect::<Vec<_>>();
- let rust_i0 = special_args.len();
- let args_head = special_args.into_iter().collect::<TokenStream2>();
- let (arg_decls, args_tail, _) = codegen_args(core, f, rust_i0, 0, false);
- let ret = codegen_sync_ret(core, &f.sig.output);
-
- let fast_error_handler = if has_fallible_fast_call {
- quote! {
- {
- let op_state = &mut std::cell::RefCell::borrow_mut(&ctx.state);
- if let Some(err) = op_state.last_fast_op_error.take() {
- let exception = #core::error::to_v8_error(scope, op_state.get_error_class_fn, &err);
- scope.throw_exception(exception);
- return;
- }
- }
- }
- } else {
- quote! {}
- };
-
- let token_stream = quote! {
- // SAFETY: #core guarantees args.data() is a v8 External pointing to an OpCtx for the isolates lifetime
- let ctx = unsafe {
- &*(#core::v8::Local::<#core::v8::External>::cast(args.data()).value()
- as *const #core::_ops::OpCtx)
- };
-
- #fast_error_handler
- #arg_decls
-
- let result = Self::call(#args_head #args_tail);
-
- // use RefCell::borrow instead of state.borrow to avoid clash with std::borrow::Borrow
- let op_state = ::std::cell::RefCell::borrow(&*ctx.state);
- op_state.tracker.track_sync(ctx.id);
-
- #ret
- };
-
- (token_stream, f.sig.inputs.len() - rust_i0)
-}
-
-/// (full declarations, idents, v8 argument count)
-type ArgumentDecl = (TokenStream2, TokenStream2, usize);
-
-fn codegen_args(
- core: &TokenStream2,
- f: &syn::ItemFn,
- rust_i0: usize, // Index of first generic arg in rust
- v8_i0: usize, // Index of first generic arg in v8/js
- asyncness: bool,
-) -> ArgumentDecl {
- let inputs = &f.sig.inputs.iter().skip(rust_i0).enumerate();
- let ident_seq: TokenStream2 = inputs
- .clone()
- .map(|(i, _)| format!("arg_{i}"))
- .collect::<Vec<_>>()
- .join(", ")
- .parse()
- .unwrap();
- let decls: TokenStream2 = inputs
- .clone()
- .map(|(i, arg)| {
- codegen_arg(core, arg, format!("arg_{i}").as_ref(), v8_i0 + i, asyncness)
- })
- .collect();
- (decls, ident_seq, inputs.len())
-}
-
-fn codegen_arg(
- core: &TokenStream2,
- arg: &syn::FnArg,
- name: &str,
- idx: usize,
- asyncness: bool,
-) -> TokenStream2 {
- let ident = quote::format_ident!("{name}");
- let (pat, ty) = match arg {
- syn::FnArg::Typed(pat) => {
- if is_optional_fast_callback_option(&pat.ty)
- || is_optional_wasm_memory(&pat.ty)
- {
- return quote! { let #ident = None; };
- }
- (&pat.pat, &pat.ty)
- }
- _ => unreachable!(),
- };
- // Fast path if arg should be skipped
- if matches!(**pat, syn::Pat::Wild(_)) {
- return quote! { let #ident = (); };
- }
- // Fast path for `String`
- if let Some(is_ref) = is_string(&**ty) {
- let ref_block = if is_ref {
- quote! { let #ident = #ident.as_ref(); }
- } else {
- quote! {}
- };
- return quote! {
- let #ident = match #core::v8::Local::<#core::v8::String>::try_from(args.get(#idx as i32)) {
- Ok(v8_string) => #core::serde_v8::to_utf8(v8_string, scope),
- Err(_) => {
- return #core::_ops::throw_type_error(scope, format!("Expected string at position {}", #idx));
- }
- };
- #ref_block
- };
- }
- // Fast path for `Cow<'_, str>`
- if is_cow_str(&**ty) {
- return quote! {
- let #ident = match #core::v8::Local::<#core::v8::String>::try_from(args.get(#idx as i32)) {
- Ok(v8_string) => ::std::borrow::Cow::Owned(#core::serde_v8::to_utf8(v8_string, scope)),
- Err(_) => {
- return #core::_ops::throw_type_error(scope, format!("Expected string at position {}", #idx));
- }
- };
- };
- }
- // Fast path for `Option<String>`
- if is_option_string(&**ty) {
- return quote! {
- let #ident = match #core::v8::Local::<#core::v8::String>::try_from(args.get(#idx as i32)) {
- Ok(v8_string) => Some(#core::serde_v8::to_utf8(v8_string, scope)),
- Err(_) => None
- };
- };
- }
- // Fast path for &/&mut [u8] and &/&mut [u32]
- match is_ref_slice(&**ty) {
- None => {}
- Some(SliceType::U32Mut) => {
- assert!(!asyncness, "Memory slices are not allowed in async ops");
- let blck = codegen_u32_mut_slice(core, idx);
- return quote! {
- let #ident = #blck;
- };
- }
- Some(SliceType::F64Mut) => {
- assert!(!asyncness, "Memory slices are not allowed in async ops");
- let blck = codegen_f64_mut_slice(core, idx);
- return quote! {
- let #ident = #blck;
- };
- }
- Some(_) => {
- assert!(!asyncness, "Memory slices are not allowed in async ops");
- let blck = codegen_u8_slice(core, idx);
- return quote! {
- let #ident = #blck;
- };
- }
- }
- // Fast path for `*const u8`
- if is_ptr_u8(&**ty) {
- let blk = codegen_u8_ptr(core, idx);
- return quote! {
- let #ident = #blk;
- };
- }
- // Fast path for `*const c_void` and `*mut c_void`
- if is_ptr_cvoid(&**ty) {
- let blk = codegen_cvoid_ptr(core, idx);
- return quote! {
- let #ident = #blk;
- };
- }
- // Otherwise deserialize it via serde_v8
- quote! {
- let #ident = args.get(#idx as i32);
- let #ident = match #core::serde_v8::from_v8(scope, #ident) {
- Ok(v) => v,
- Err(err) => {
- let msg = format!("Error parsing args at position {}: {}", #idx, #core::anyhow::Error::from(err));
- return #core::_ops::throw_type_error(scope, msg);
- }
- };
- }
-}
-
-fn codegen_u8_slice(core: &TokenStream2, idx: usize) -> TokenStream2 {
- quote! {{
- let value = args.get(#idx as i32);
- match #core::v8::Local::<#core::v8::ArrayBuffer>::try_from(value) {
- Ok(b) => {
- let byte_length = b.byte_length();
- if let Some(data) = b.data() {
- let store = data.cast::<u8>().as_ptr();
- // SAFETY: rust guarantees that lifetime of slice is no longer than the call.
- unsafe { ::std::slice::from_raw_parts_mut(store, byte_length) }
- } else {
- &mut []
- }
- },
- Err(_) => {
- if let Ok(view) = #core::v8::Local::<#core::v8::ArrayBufferView>::try_from(value) {
- let len = view.byte_length();
- let offset = view.byte_offset();
- let buffer = match view.buffer(scope) {
- Some(v) => v,
- None => {
- return #core::_ops::throw_type_error(scope, format!("Expected ArrayBufferView at position {}", #idx));
- }
- };
- if let Some(data) = buffer.data() {
- let store = data.cast::<u8>().as_ptr();
- // SAFETY: rust guarantees that lifetime of slice is no longer than the call.
- unsafe { ::std::slice::from_raw_parts_mut(store.add(offset), len) }
- } else {
- &mut []
- }
- } else {
- return #core::_ops::throw_type_error(scope, format!("Expected ArrayBufferView at position {}", #idx));
- }
- }
- }}
- }
-}
-
-fn codegen_u8_ptr(core: &TokenStream2, idx: usize) -> TokenStream2 {
- quote! {{
- let value = args.get(#idx as i32);
- match #core::v8::Local::<#core::v8::ArrayBuffer>::try_from(value) {
- Ok(b) => {
- if let Some(data) = b.data() {
- data.cast::<u8>().as_ptr()
- } else {
- std::ptr::null::<u8>()
- }
- },
- Err(_) => {
- if let Ok(view) = #core::v8::Local::<#core::v8::ArrayBufferView>::try_from(value) {
- let offset = view.byte_offset();
- let buffer = match view.buffer(scope) {
- Some(v) => v,
- None => {
- return #core::_ops::throw_type_error(scope, format!("Expected ArrayBufferView at position {}", #idx));
- }
- };
- let store = if let Some(data) = buffer.data() {
- data.cast::<u8>().as_ptr()
- } else {
- std::ptr::null_mut::<u8>()
- };
- unsafe { store.add(offset) }
- } else {
- return #core::_ops::throw_type_error(scope, format!("Expected ArrayBufferView at position {}", #idx));
- }
- }
- }
- }}
-}
-
-fn codegen_cvoid_ptr(core: &TokenStream2, idx: usize) -> TokenStream2 {
- quote! {{
- let value = args.get(#idx as i32);
- if value.is_null() {
- std::ptr::null_mut()
- } else if let Ok(b) = #core::v8::Local::<#core::v8::External>::try_from(value) {
- b.value()
- } else {
- return #core::_ops::throw_type_error(scope, format!("Expected External at position {}", #idx));
- }
- }}
-}
-
-fn codegen_u32_mut_slice(core: &TokenStream2, idx: usize) -> TokenStream2 {
- quote! {
- if let Ok(view) = #core::v8::Local::<#core::v8::Uint32Array>::try_from(args.get(#idx as i32)) {
- let (offset, len) = (view.byte_offset(), view.byte_length());
- let buffer = match view.buffer(scope) {
- Some(v) => v,
- None => {
- return #core::_ops::throw_type_error(scope, format!("Expected Uint32Array at position {}", #idx));
- }
- };
- if let Some(data) = buffer.data() {
- let store = data.cast::<u8>().as_ptr();
- // SAFETY: buffer from Uint32Array. Rust guarantees that lifetime of slice is no longer than the call.
- unsafe { ::std::slice::from_raw_parts_mut(store.add(offset) as *mut u32, len / 4) }
- } else {
- &mut []
- }
- } else {
- return #core::_ops::throw_type_error(scope, format!("Expected Uint32Array at position {}", #idx));
- }
- }
-}
-
-fn codegen_f64_mut_slice(core: &TokenStream2, idx: usize) -> TokenStream2 {
- quote! {
- if let Ok(view) = #core::v8::Local::<#core::v8::Float64Array>::try_from(args.get(#idx as i32)) {
- let (offset, len) = (view.byte_offset(), view.byte_length());
- let buffer = match view.buffer(scope) {
- Some(v) => v,
- None => {
- return #core::_ops::throw_type_error(scope, format!("Expected Float64Array at position {}", #idx));
- }
- };
- if let Some(data) = buffer.data() {
- let store = data.cast::<u8>().as_ptr();
- unsafe { ::std::slice::from_raw_parts_mut(store.add(offset) as *mut f64, len / 8) }
- } else {
- &mut []
- }
- } else {
- return #core::_ops::throw_type_error(scope, format!("Expected Float64Array at position {}", #idx));
- }
- }
-}
-
-fn codegen_sync_ret(
- core: &TokenStream2,
- output: &syn::ReturnType,
-) -> TokenStream2 {
- if is_void(output) {
- return quote! {};
- }
-
- if is_u32_rv(output) {
- return quote! {
- rv.set_uint32(result as u32);
- };
- }
-
- // Optimize Result<(), Err> to skip serde_v8 when Ok(...)
- let ok_block = if is_unit_result(output) {
- quote! {}
- } else if is_u32_rv_result(output) {
- quote! {
- rv.set_uint32(result as u32);
- }
- } else if is_ptr_cvoid(output) || is_ptr_cvoid_rv(output) {
- quote! {
- if result.is_null() {
- // External cannot contain a null pointer, null pointers are instead represented as null.
- rv.set_null();
- } else {
- rv.set(v8::External::new(scope, result as *mut ::std::ffi::c_void).into());
- }
- }
- } else {
- quote! {
- match #core::serde_v8::to_v8(scope, result) {
- Ok(ret) => rv.set(ret),
- Err(err) => #core::_ops::throw_type_error(
- scope,
- format!("Error serializing return: {}", #core::anyhow::Error::from(err)),
- ),
- };
- }
- };
-
- if !is_result(output) {
- return ok_block;
- }
-
- quote! {
- match result {
- Ok(result) => {
- #ok_block
- },
- Err(err) => {
- let exception = #core::error::to_v8_error(scope, op_state.get_error_class_fn, &err);
- scope.throw_exception(exception);
- },
- };
- }
-}
-
-fn is_void(ty: impl ToTokens) -> bool {
- tokens(ty).is_empty()
-}
-
-fn is_result(ty: impl ToTokens) -> bool {
- let tokens = tokens(ty);
- if tokens.trim_start_matches("-> ").starts_with("Result <") {
- return true;
- }
- // Detect `io::Result<...>`, `anyhow::Result<...>`, etc...
- // i.e: Result aliases/shorthands which are unfortunately "opaque" at macro-time
- match tokens.find(":: Result <") {
- Some(idx) => !tokens.split_at(idx).0.contains('<'),
- None => false,
- }
-}
-
-fn is_string(ty: impl ToTokens) -> Option<bool> {
- let toks = tokens(ty);
- if toks == "String" {
- return Some(false);
- }
- if toks == "& str" {
- return Some(true);
- }
- None
-}
-
-fn is_option_string(ty: impl ToTokens) -> bool {
- tokens(ty) == "Option < String >"
-}
-
-fn is_cow_str(ty: impl ToTokens) -> bool {
- tokens(&ty).starts_with("Cow <") && tokens(&ty).ends_with("str >")
-}
-
-enum SliceType {
- U8,
- U8Mut,
- U32Mut,
- F64Mut,
-}
-
-fn is_ref_slice(ty: impl ToTokens) -> Option<SliceType> {
- if is_u8_slice(&ty) {
- return Some(SliceType::U8);
- }
- if is_u8_slice_mut(&ty) {
- return Some(SliceType::U8Mut);
- }
- if is_u32_slice_mut(&ty) {
- return Some(SliceType::U32Mut);
- }
- if is_f64_slice_mut(&ty) {
- return Some(SliceType::F64Mut);
- }
- None
-}
-
-fn is_u8_slice(ty: impl ToTokens) -> bool {
- tokens(ty) == "& [u8]"
-}
-
-fn is_u8_slice_mut(ty: impl ToTokens) -> bool {
- tokens(ty) == "& mut [u8]"
-}
-
-fn is_u32_slice_mut(ty: impl ToTokens) -> bool {
- tokens(ty) == "& mut [u32]"
-}
-
-fn is_f64_slice_mut(ty: impl ToTokens) -> bool {
- tokens(ty) == "& mut [f64]"
-}
-
-fn is_ptr_u8(ty: impl ToTokens) -> bool {
- tokens(ty) == "* const u8"
-}
-
-fn is_ptr_cvoid(ty: impl ToTokens) -> bool {
- tokens(&ty) == "* const c_void" || tokens(&ty) == "* mut c_void"
-}
-
-fn is_ptr_cvoid_rv(ty: impl ToTokens) -> bool {
- tokens(&ty).contains("Result < * const c_void")
- || tokens(&ty).contains("Result < * mut c_void")
-}
-
-fn is_optional_fast_callback_option(ty: impl ToTokens) -> bool {
- tokens(&ty).contains("Option < & mut FastApiCallbackOptions")
-}
-
-fn is_optional_wasm_memory(ty: impl ToTokens) -> bool {
- tokens(&ty).contains("Option < & mut [u8]")
-}
-
-/// Detects if the type can be set using `rv.set_uint32` fast path
-fn is_u32_rv(ty: impl ToTokens) -> bool {
- ["u32", "u8", "u16"].iter().any(|&s| tokens(&ty) == s) || is_resource_id(&ty)
-}
-
-/// Detects if the type is of the format Result<u32/u8/u16, Err>
-fn is_u32_rv_result(ty: impl ToTokens) -> bool {
- is_result(&ty)
- && (tokens(&ty).contains("Result < u32")
- || tokens(&ty).contains("Result < u8")
- || tokens(&ty).contains("Result < u16")
- || is_resource_id(&ty))
-}
-
-/// Detects if a type is of the form Result<(), Err>
-fn is_unit_result(ty: impl ToTokens) -> bool {
- is_result(&ty) && tokens(&ty).contains("Result < ()")
-}
-
-fn is_resource_id(arg: impl ToTokens) -> bool {
- let re = lazy_regex::regex!(r#": (?:deno_core :: )?ResourceId$"#);
- re.is_match(&tokens(arg))
-}
-
-fn is_mut_ref_opstate(arg: impl ToTokens) -> bool {
- let re = lazy_regex::regex!(r#": & mut (?:deno_core :: )?OpState$"#);
- re.is_match(&tokens(arg))
-}
-
-fn is_rc_refcell_opstate(arg: &syn::FnArg) -> bool {
- let re =
- lazy_regex::regex!(r#": Rc < RefCell < (?:deno_core :: )?OpState > >$"#);
- re.is_match(&tokens(arg))
-}
-
-fn is_handle_scope(arg: &syn::FnArg) -> bool {
- let re = lazy_regex::regex!(
- r#": & mut (?:deno_core :: )?v8 :: HandleScope(?: < '\w+ >)?$"#
- );
- re.is_match(&tokens(arg))
-}
-
-fn is_future(ty: impl ToTokens) -> bool {
- tokens(&ty).contains("impl Future < Output =")
-}
-
-fn tokens(x: impl ToTokens) -> String {
- x.to_token_stream().to_string()
-}
-
-fn exclude_lifetime_params(
- generic_params: &Punctuated<GenericParam, Comma>,
-) -> Punctuated<GenericParam, Comma> {
- generic_params
- .iter()
- .filter(|t| !tokens(t).starts_with('\''))
- .cloned()
- .collect::<Punctuated<GenericParam, Comma>>()
-}
-
-fn exclude_non_lifetime_params(
- generic_params: &Punctuated<GenericParam, Comma>,
-) -> Punctuated<GenericParam, Comma> {
- generic_params
- .iter()
- .filter(|t| tokens(t).starts_with('\''))
- .cloned()
- .collect::<Punctuated<GenericParam, Comma>>()
-}
-
-#[cfg(test)]
-mod tests {
- use crate::Attributes;
- use crate::Op;
- use pretty_assertions::assert_eq;
- use std::path::PathBuf;
-
- #[testing_macros::fixture("optimizer_tests/**/*.rs")]
- fn test_codegen(input: PathBuf) {
- let update_expected = std::env::var("UPDATE_EXPECTED").is_ok();
-
- let source =
- std::fs::read_to_string(&input).expect("Failed to read test file");
-
- let mut attrs = Attributes::default();
- if source.contains("// @test-attr:fast") {
- attrs.must_be_fast = true;
- }
- if source.contains("// @test-attr:wasm") {
- attrs.is_wasm = true;
- attrs.must_be_fast = true;
- }
-
- let item = syn::parse_str(&source).expect("Failed to parse test file");
- let op = Op::new(item, attrs);
-
- let expected = std::fs::read_to_string(input.with_extension("out"))
- .expect("Failed to read expected output file");
-
- // Print the raw tokens in case we fail to parse
- let actual = op.gen();
- println!("-----Raw tokens-----\n{}----------\n", actual);
-
- // Validate syntax tree.
- let tree = syn::parse2(actual).unwrap();
- let actual = prettyplease::unparse(&tree);
- if update_expected {
- std::fs::write(input.with_extension("out"), actual)
- .expect("Failed to write expected file");
- } else {
- assert_eq!(actual, expected);
- }
- }
-}
diff --git a/ops/op2/dispatch_fast.rs b/ops/op2/dispatch_fast.rs
deleted file mode 100644
index f9d74416a..000000000
--- a/ops/op2/dispatch_fast.rs
+++ /dev/null
@@ -1,327 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-use super::generator_state::GeneratorState;
-use super::signature::Arg;
-use super::signature::NumericArg;
-use super::signature::ParsedSignature;
-use super::signature::RetVal;
-use super::signature::Special;
-use super::V8MappingError;
-use proc_macro2::Ident;
-use proc_macro2::TokenStream;
-use quote::format_ident;
-use quote::quote;
-use std::iter::zip;
-
-#[allow(unused)]
-#[derive(Debug, Default, PartialEq, Clone)]
-pub(crate) enum V8FastCallType {
- #[default]
- Void,
- Bool,
- U32,
- I32,
- U64,
- I64,
- F32,
- F64,
- Pointer,
- V8Value,
- Uint8Array,
- Uint32Array,
- Float64Array,
- SeqOneByteString,
- CallbackOptions,
-}
-
-impl V8FastCallType {
- /// Quote fast value type.
- fn quote_rust_type(&self, deno_core: &TokenStream) -> TokenStream {
- match self {
- V8FastCallType::Void => quote!(()),
- V8FastCallType::Bool => quote!(bool),
- V8FastCallType::U32 => quote!(u32),
- V8FastCallType::I32 => quote!(i32),
- V8FastCallType::U64 => quote!(u64),
- V8FastCallType::I64 => quote!(i64),
- V8FastCallType::F32 => quote!(f32),
- V8FastCallType::F64 => quote!(f64),
- V8FastCallType::Pointer => quote!(*mut ::std::ffi::c_void),
- V8FastCallType::V8Value => {
- quote!(#deno_core::v8::Local<#deno_core::v8::Value>)
- }
- V8FastCallType::CallbackOptions => {
- quote!(*mut #deno_core::v8::fast_api::FastApiCallbackOptions)
- }
- V8FastCallType::SeqOneByteString => {
- quote!(*mut #deno_core::v8::fast_api::FastApiOneByteString)
- }
- V8FastCallType::Uint8Array
- | V8FastCallType::Uint32Array
- | V8FastCallType::Float64Array => unreachable!(),
- }
- }
-
- /// Quote fast value type's variant.
- fn quote_ctype(&self) -> TokenStream {
- match &self {
- V8FastCallType::Void => quote!(CType::Void),
- V8FastCallType::Bool => quote!(CType::Bool),
- V8FastCallType::U32 => quote!(CType::Uint32),
- V8FastCallType::I32 => quote!(CType::Int32),
- V8FastCallType::U64 => quote!(CType::Uint64),
- V8FastCallType::I64 => quote!(CType::Int64),
- V8FastCallType::F32 => quote!(CType::Float32),
- V8FastCallType::F64 => quote!(CType::Float64),
- V8FastCallType::Pointer => quote!(CType::Pointer),
- V8FastCallType::V8Value => quote!(CType::V8Value),
- V8FastCallType::CallbackOptions => quote!(CType::CallbackOptions),
- V8FastCallType::Uint8Array => unreachable!(),
- V8FastCallType::Uint32Array => unreachable!(),
- V8FastCallType::Float64Array => unreachable!(),
- V8FastCallType::SeqOneByteString => quote!(CType::SeqOneByteString),
- }
- }
-
- /// Quote fast value type's variant.
- fn quote_type(&self) -> TokenStream {
- match &self {
- V8FastCallType::Void => quote!(Type::Void),
- V8FastCallType::Bool => quote!(Type::Bool),
- V8FastCallType::U32 => quote!(Type::Uint32),
- V8FastCallType::I32 => quote!(Type::Int32),
- V8FastCallType::U64 => quote!(Type::Uint64),
- V8FastCallType::I64 => quote!(Type::Int64),
- V8FastCallType::F32 => quote!(Type::Float32),
- V8FastCallType::F64 => quote!(Type::Float64),
- V8FastCallType::Pointer => quote!(Type::Pointer),
- V8FastCallType::V8Value => quote!(Type::V8Value),
- V8FastCallType::CallbackOptions => quote!(Type::CallbackOptions),
- V8FastCallType::Uint8Array => quote!(Type::TypedArray(CType::Uint8)),
- V8FastCallType::Uint32Array => quote!(Type::TypedArray(CType::Uint32)),
- V8FastCallType::Float64Array => quote!(Type::TypedArray(CType::Float64)),
- V8FastCallType::SeqOneByteString => quote!(Type::SeqOneByteString),
- }
- }
-}
-
-pub fn generate_dispatch_fast(
- generator_state: &mut GeneratorState,
- signature: &ParsedSignature,
-) -> Result<Option<(TokenStream, TokenStream)>, V8MappingError> {
- let mut inputs = vec![];
- for arg in &signature.args {
- let Some(fv) = map_arg_to_v8_fastcall_type(arg)? else {
- return Ok(None);
- };
- inputs.push(fv);
- }
- let mut names = inputs
- .iter()
- .enumerate()
- .map(|(i, _)| format_ident!("arg{i}"))
- .collect::<Vec<_>>();
-
- let ret_val = match &signature.ret_val {
- RetVal::Infallible(arg) => arg,
- RetVal::Result(arg) => arg,
- };
-
- let output = match map_retval_to_v8_fastcall_type(ret_val)? {
- None => return Ok(None),
- Some(rv) => rv,
- };
-
- let GeneratorState {
- fast_function,
- deno_core,
- result,
- opctx,
- fast_api_callback_options,
- needs_fast_api_callback_options,
- needs_fast_opctx,
- ..
- } = generator_state;
-
- let handle_error = match signature.ret_val {
- RetVal::Infallible(_) => quote!(),
- RetVal::Result(_) => {
- *needs_fast_api_callback_options = true;
- *needs_fast_opctx = true;
- inputs.push(V8FastCallType::CallbackOptions);
- quote! {
- let #result = match #result {
- Ok(#result) => #result,
- Err(err) => {
- // FASTCALL FALLBACK: This is where we set the errors for the slow-call error pickup path. There
- // is no code running between this and the other FASTCALL FALLBACK comment, except some V8 code
- // required to perform the fallback process. This is why the below call is safe.
-
- // The reason we need to do this is because V8 does not allow exceptions to be thrown from the
- // fast call. Instead, you are required to set the fallback flag, which indicates to V8 that it
- // should re-call the slow version of the function. Technically the slow call should perform the
- // same operation and then throw the same error (because it should be idempotent), but in our
- // case we stash the error and pick it up on the slow path before doing any work.
-
- // TODO(mmastrac): We should allow an #[op] flag to re-perform slow calls without the error path when
- // the method is performance sensitive.
-
- // SAFETY: We guarantee that OpCtx has no mutable references once ops are live and being called,
- // allowing us to perform this one little bit of mutable magic.
- unsafe { #opctx.unsafely_set_last_error_for_ops_only(err); }
- #fast_api_callback_options.fallback = true;
- return ::std::default::Default::default();
- }
- };
- }
- }
- };
-
- let input_types = inputs.iter().map(|fv| fv.quote_type()).collect::<Vec<_>>();
- let output_type = output.quote_ctype();
-
- let fast_definition = quote! {
- use #deno_core::v8::fast_api::Type;
- use #deno_core::v8::fast_api::CType;
- #deno_core::v8::fast_api::FastFunction::new(
- &[ Type::V8Value, #( #input_types ),* ],
- #output_type,
- Self::#fast_function as *const ::std::ffi::c_void
- )
- };
-
- let output_type = output.quote_rust_type(deno_core);
- let mut types = inputs
- .iter()
- .map(|rv| rv.quote_rust_type(deno_core))
- .collect::<Vec<_>>();
-
- let call_idents = names.clone();
- let call_args = zip(names.iter(), signature.args.iter())
- .map(|(name, arg)| map_v8_fastcall_arg_to_arg(deno_core, name, arg))
- .collect::<Vec<_>>();
-
- let with_fast_api_callback_options = if *needs_fast_api_callback_options {
- types.push(V8FastCallType::CallbackOptions.quote_rust_type(deno_core));
- names.push(fast_api_callback_options.clone());
- quote! {
- let #fast_api_callback_options = unsafe { &mut *#fast_api_callback_options };
- }
- } else {
- quote!()
- };
- let with_opctx = if *needs_fast_opctx {
- quote!(
- let #opctx = unsafe {
- &*(#deno_core::v8::Local::<v8::External>::cast(unsafe { #fast_api_callback_options.data.data }).value()
- as *const #deno_core::_ops::OpCtx)
- };
- )
- } else {
- quote!()
- };
-
- let fast_fn = quote!(
- fn #fast_function(
- _: #deno_core::v8::Local<#deno_core::v8::Object>,
- #( #names: #types, )*
- ) -> #output_type {
- #with_fast_api_callback_options
- #with_opctx
- #(#call_args)*
- let #result = Self::call(#(#call_idents),*);
- #handle_error
- #result
- }
- );
-
- Ok(Some((fast_definition, fast_fn)))
-}
-
-fn map_v8_fastcall_arg_to_arg(
- deno_core: &TokenStream,
- arg_ident: &Ident,
- arg: &Arg,
-) -> TokenStream {
- let arg_temp = format_ident!("{}_temp", arg_ident);
- match arg {
- Arg::Special(Special::RefStr) => {
- quote! {
- let mut #arg_temp: [::std::mem::MaybeUninit<u8>; 1024] = [::std::mem::MaybeUninit::uninit(); 1024];
- let #arg_ident = &#deno_core::_ops::to_str_ptr(unsafe { &mut *#arg_ident }, &mut #arg_temp);
- }
- }
- Arg::Special(Special::String) => {
- quote!(let #arg_ident = #deno_core::_ops::to_string_ptr(unsafe { &mut *#arg_ident });)
- }
- Arg::Special(Special::CowStr) => {
- quote! {
- let mut #arg_temp: [::std::mem::MaybeUninit<u8>; 1024] = [::std::mem::MaybeUninit::uninit(); 1024];
- let #arg_ident = #deno_core::_ops::to_str_ptr(unsafe { &mut *#arg_ident }, &mut #arg_temp);
- }
- }
- _ => quote!(let #arg_ident = #arg_ident as _;),
- }
-}
-
-fn map_arg_to_v8_fastcall_type(
- arg: &Arg,
-) -> Result<Option<V8FastCallType>, V8MappingError> {
- let rv = match arg {
- Arg::OptionNumeric(_) | Arg::SerdeV8(_) => return Ok(None),
- Arg::Numeric(NumericArg::bool) => V8FastCallType::Bool,
- Arg::Numeric(NumericArg::u32)
- | Arg::Numeric(NumericArg::u16)
- | Arg::Numeric(NumericArg::u8) => V8FastCallType::U32,
- Arg::Numeric(NumericArg::i32)
- | Arg::Numeric(NumericArg::i16)
- | Arg::Numeric(NumericArg::i8)
- | Arg::Numeric(NumericArg::__SMI__) => V8FastCallType::I32,
- Arg::Numeric(NumericArg::u64) | Arg::Numeric(NumericArg::usize) => {
- V8FastCallType::U64
- }
- Arg::Numeric(NumericArg::i64) | Arg::Numeric(NumericArg::isize) => {
- V8FastCallType::I64
- }
- // Ref strings that are one byte internally may be passed as a SeqOneByteString,
- // which gives us a FastApiOneByteString.
- Arg::Special(Special::RefStr) => V8FastCallType::SeqOneByteString,
- // Owned strings can be fast, but we'll have to copy them.
- Arg::Special(Special::String) => V8FastCallType::SeqOneByteString,
- // Cow strings can be fast, but may require copying
- Arg::Special(Special::CowStr) => V8FastCallType::SeqOneByteString,
- _ => return Err(V8MappingError::NoMapping("a fast argument", arg.clone())),
- };
- Ok(Some(rv))
-}
-
-fn map_retval_to_v8_fastcall_type(
- arg: &Arg,
-) -> Result<Option<V8FastCallType>, V8MappingError> {
- let rv = match arg {
- Arg::OptionNumeric(_) | Arg::SerdeV8(_) => return Ok(None),
- Arg::Void => V8FastCallType::Void,
- Arg::Numeric(NumericArg::bool) => V8FastCallType::Bool,
- Arg::Numeric(NumericArg::u32)
- | Arg::Numeric(NumericArg::u16)
- | Arg::Numeric(NumericArg::u8) => V8FastCallType::U32,
- Arg::Numeric(NumericArg::i32)
- | Arg::Numeric(NumericArg::i16)
- | Arg::Numeric(NumericArg::i8) => V8FastCallType::I32,
- Arg::Numeric(NumericArg::u64) | Arg::Numeric(NumericArg::usize) => {
- V8FastCallType::U64
- }
- Arg::Numeric(NumericArg::i64) | Arg::Numeric(NumericArg::isize) => {
- V8FastCallType::I64
- }
- // We don't return special return types
- Arg::Option(_) => return Ok(None),
- Arg::Special(_) => return Ok(None),
- _ => {
- return Err(V8MappingError::NoMapping(
- "a fast return value",
- arg.clone(),
- ))
- }
- };
- Ok(Some(rv))
-}
diff --git a/ops/op2/dispatch_slow.rs b/ops/op2/dispatch_slow.rs
deleted file mode 100644
index 2ec67cc76..000000000
--- a/ops/op2/dispatch_slow.rs
+++ /dev/null
@@ -1,401 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-use super::generator_state::GeneratorState;
-use super::signature::Arg;
-use super::signature::NumericArg;
-use super::signature::ParsedSignature;
-use super::signature::RetVal;
-use super::signature::Special;
-use super::MacroConfig;
-use super::V8MappingError;
-use proc_macro2::TokenStream;
-use quote::format_ident;
-use quote::quote;
-
-pub(crate) fn generate_dispatch_slow(
- config: &MacroConfig,
- generator_state: &mut GeneratorState,
- signature: &ParsedSignature,
-) -> Result<TokenStream, V8MappingError> {
- let mut output = TokenStream::new();
-
- // Fast ops require the slow op to check op_ctx for the last error
- if config.fast && matches!(signature.ret_val, RetVal::Result(_)) {
- generator_state.needs_opctx = true;
- let throw_exception = throw_exception(generator_state)?;
- // If the fast op returned an error, we must throw it rather than doing work.
- output.extend(quote!{
- // FASTCALL FALLBACK: This is where we pick up the errors for the slow-call error pickup
- // path. There is no code running between this and the other FASTCALL FALLBACK comment,
- // except some V8 code required to perform the fallback process. This is why the below call is safe.
-
- // SAFETY: We guarantee that OpCtx has no mutable references once ops are live and being called,
- // allowing us to perform this one little bit of mutable magic.
- if let Some(err) = unsafe { opctx.unsafely_take_last_error_for_ops_only() } {
- #throw_exception
- }
- });
- }
-
- for (index, arg) in signature.args.iter().enumerate() {
- output.extend(extract_arg(generator_state, index)?);
- output.extend(from_arg(generator_state, index, arg)?);
- }
- output.extend(call(generator_state)?);
- output.extend(return_value(generator_state, &signature.ret_val)?);
-
- let with_scope = if generator_state.needs_scope {
- with_scope(generator_state)
- } else {
- quote!()
- };
-
- let with_opctx = if generator_state.needs_opctx {
- with_opctx(generator_state)
- } else {
- quote!()
- };
-
- let with_retval = if generator_state.needs_retval {
- with_retval(generator_state)
- } else {
- quote!()
- };
-
- let with_args = if generator_state.needs_args {
- with_fn_args(generator_state)
- } else {
- quote!()
- };
-
- let GeneratorState {
- deno_core,
- info,
- slow_function,
- ..
- } = &generator_state;
-
- Ok(quote! {
- extern "C" fn #slow_function(#info: *const #deno_core::v8::FunctionCallbackInfo) {
- #with_scope
- #with_retval
- #with_args
- #with_opctx
-
- #output
- }})
-}
-
-fn with_scope(generator_state: &mut GeneratorState) -> TokenStream {
- let GeneratorState {
- deno_core,
- scope,
- info,
- ..
- } = &generator_state;
-
- quote!(let #scope = &mut unsafe { #deno_core::v8::CallbackScope::new(&*#info) };)
-}
-
-fn with_retval(generator_state: &mut GeneratorState) -> TokenStream {
- let GeneratorState {
- deno_core,
- retval,
- info,
- ..
- } = &generator_state;
-
- quote!(let mut #retval = #deno_core::v8::ReturnValue::from_function_callback_info(unsafe { &*#info });)
-}
-
-fn with_fn_args(generator_state: &mut GeneratorState) -> TokenStream {
- let GeneratorState {
- deno_core,
- fn_args,
- info,
- ..
- } = &generator_state;
-
- quote!(let #fn_args = #deno_core::v8::FunctionCallbackArguments::from_function_callback_info(unsafe { &*#info });)
-}
-
-fn with_opctx(generator_state: &mut GeneratorState) -> TokenStream {
- let GeneratorState {
- deno_core,
- opctx,
- fn_args,
- needs_args,
- ..
- } = generator_state;
-
- *needs_args = true;
- quote!(let #opctx = unsafe {
- &*(#deno_core::v8::Local::<#deno_core::v8::External>::cast(#fn_args.data()).value()
- as *const #deno_core::_ops::OpCtx)
- };)
-}
-
-pub fn extract_arg(
- generator_state: &mut GeneratorState,
- index: usize,
-) -> Result<TokenStream, V8MappingError> {
- let GeneratorState { fn_args, .. } = &generator_state;
- let arg_ident = generator_state.args.get(index);
-
- Ok(quote!(
- let #arg_ident = #fn_args.get(#index as i32);
- ))
-}
-
-pub fn from_arg(
- mut generator_state: &mut GeneratorState,
- index: usize,
- arg: &Arg,
-) -> Result<TokenStream, V8MappingError> {
- let GeneratorState {
- deno_core,
- args,
- scope,
- needs_scope,
- ..
- } = &mut generator_state;
- let arg_ident = args.get_mut(index).expect("Argument at index was missing");
- let arg_temp = format_ident!("{}_temp", arg_ident);
- let res = match arg {
- Arg::Numeric(NumericArg::bool) => quote! {
- let #arg_ident = #arg_ident.is_true();
- },
- Arg::Numeric(NumericArg::u8)
- | Arg::Numeric(NumericArg::u16)
- | Arg::Numeric(NumericArg::u32) => {
- quote! {
- let #arg_ident = #deno_core::_ops::to_u32(&#arg_ident) as _;
- }
- }
- Arg::Numeric(NumericArg::i8)
- | Arg::Numeric(NumericArg::i16)
- | Arg::Numeric(NumericArg::i32)
- | Arg::Numeric(NumericArg::__SMI__) => {
- quote! {
- let #arg_ident = #deno_core::_ops::to_i32(&#arg_ident) as _;
- }
- }
- Arg::Numeric(NumericArg::u64) | Arg::Numeric(NumericArg::usize) => {
- quote! {
- let #arg_ident = #deno_core::_ops::to_u64(&#arg_ident) as _;
- }
- }
- Arg::Numeric(NumericArg::i64) | Arg::Numeric(NumericArg::isize) => {
- quote! {
- let #arg_ident = #deno_core::_ops::to_i64(&#arg_ident) as _;
- }
- }
- Arg::OptionNumeric(numeric) => {
- // Ends the borrow of generator_state
- let arg_ident = arg_ident.clone();
- let some = from_arg(generator_state, index, &Arg::Numeric(*numeric))?;
- quote! {
- let #arg_ident = if #arg_ident.is_null_or_undefined() {
- None
- } else {
- #some
- Some(#arg_ident)
- };
- }
- }
- Arg::Option(Special::String) => {
- *needs_scope = true;
- quote! {
- let #arg_ident = #arg_ident.to_rust_string_lossy(#scope);
- }
- }
- Arg::Special(Special::String) => {
- *needs_scope = true;
- quote! {
- let #arg_ident = #arg_ident.to_rust_string_lossy(#scope);
- }
- }
- Arg::Special(Special::RefStr) => {
- *needs_scope = true;
- quote! {
- // Trade 1024 bytes of stack space for potentially non-allocating strings
- let mut #arg_temp: [::std::mem::MaybeUninit<u8>; 1024] = [::std::mem::MaybeUninit::uninit(); 1024];
- let #arg_ident = &#deno_core::_ops::to_str(#scope, &#arg_ident, &mut #arg_temp);
- }
- }
- Arg::Special(Special::CowStr) => {
- *needs_scope = true;
- quote! {
- // Trade 1024 bytes of stack space for potentially non-allocating strings
- let mut #arg_temp: [::std::mem::MaybeUninit<u8>; 1024] = [::std::mem::MaybeUninit::uninit(); 1024];
- let #arg_ident = #deno_core::_ops::to_str(#scope, &#arg_ident, &mut #arg_temp);
- }
- }
- _ => return Err(V8MappingError::NoMapping("a slow argument", arg.clone())),
- };
- Ok(res)
-}
-
-pub fn call(
- generator_state: &mut GeneratorState,
-) -> Result<TokenStream, V8MappingError> {
- let GeneratorState { result, .. } = &generator_state;
-
- let mut tokens = TokenStream::new();
- for arg in &generator_state.args {
- tokens.extend(quote!( #arg , ));
- }
- Ok(quote! {
- let #result = Self::call( #tokens );
- })
-}
-
-pub fn return_value(
- generator_state: &mut GeneratorState,
- ret_type: &RetVal,
-) -> Result<TokenStream, V8MappingError> {
- match ret_type {
- RetVal::Infallible(ret_type) => {
- return_value_infallible(generator_state, ret_type)
- }
- RetVal::Result(ret_type) => return_value_result(generator_state, ret_type),
- }
-}
-
-pub fn return_value_infallible(
- generator_state: &mut GeneratorState,
- ret_type: &Arg,
-) -> Result<TokenStream, V8MappingError> {
- let GeneratorState {
- deno_core,
- scope,
- result,
- retval,
- needs_retval,
- needs_scope,
- ..
- } = generator_state;
-
- let res = match ret_type {
- Arg::Void => {
- quote! {/* void */}
- }
- Arg::Numeric(NumericArg::u8)
- | Arg::Numeric(NumericArg::u16)
- | Arg::Numeric(NumericArg::u32) => {
- *needs_retval = true;
- quote!(#retval.set_uint32(#result as u32);)
- }
- Arg::Numeric(NumericArg::i8)
- | Arg::Numeric(NumericArg::i16)
- | Arg::Numeric(NumericArg::i32) => {
- *needs_retval = true;
- quote!(#retval.set_int32(#result as i32);)
- }
- Arg::Special(Special::String) => {
- *needs_retval = true;
- *needs_scope = true;
- quote! {
- if #result.is_empty() {
- #retval.set_empty_string();
- } else {
- // This should not fail in normal cases
- // TODO(mmastrac): This has extra allocations that we need to get rid of, especially if the string
- // is ASCII. We could make an "external Rust String" string in V8 from these and re-use the allocation.
- let temp = #deno_core::v8::String::new(#scope, &#result).unwrap();
- #retval.set(temp.into());
- }
- }
- }
- Arg::Option(Special::String) => {
- *needs_retval = true;
- *needs_scope = true;
- // End the generator_state borrow
- let (result, retval) = (result.clone(), retval.clone());
- let some = return_value_infallible(
- generator_state,
- &Arg::Special(Special::String),
- )?;
- quote! {
- if let Some(#result) = #result {
- #some
- } else {
- #retval.set_null();
- }
- }
- }
- _ => {
- return Err(V8MappingError::NoMapping(
- "a slow return value",
- ret_type.clone(),
- ))
- }
- };
-
- Ok(res)
-}
-
-fn return_value_result(
- generator_state: &mut GeneratorState,
- ret_type: &Arg,
-) -> Result<TokenStream, V8MappingError> {
- let infallible = return_value_infallible(generator_state, ret_type)?;
- let exception = throw_exception(generator_state)?;
-
- let GeneratorState { result, .. } = &generator_state;
-
- let tokens = quote!(
- match #result {
- Ok(#result) => {
- #infallible
- }
- Err(err) => {
- #exception
- }
- };
- );
- Ok(tokens)
-}
-
-/// Generates code to throw an exception, adding required additional dependencies as needed.
-fn throw_exception(
- generator_state: &mut GeneratorState,
-) -> Result<TokenStream, V8MappingError> {
- let maybe_scope = if generator_state.needs_scope {
- quote!()
- } else {
- with_scope(generator_state)
- };
-
- let maybe_opctx = if generator_state.needs_opctx {
- quote!()
- } else {
- with_opctx(generator_state)
- };
-
- let maybe_args = if generator_state.needs_args {
- quote!()
- } else {
- with_fn_args(generator_state)
- };
-
- let GeneratorState {
- deno_core,
- scope,
- opctx,
- ..
- } = &generator_state;
-
- Ok(quote! {
- #maybe_scope
- #maybe_args
- #maybe_opctx
- let opstate = ::std::cell::RefCell::borrow(&*#opctx.state);
- let exception = #deno_core::error::to_v8_error(
- #scope,
- opstate.get_error_class_fn,
- &err,
- );
- scope.throw_exception(exception);
- return;
- })
-}
diff --git a/ops/op2/generator_state.rs b/ops/op2/generator_state.rs
deleted file mode 100644
index e437ea47c..000000000
--- a/ops/op2/generator_state.rs
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-use proc_macro2::Ident;
-use proc_macro2::TokenStream;
-
-pub struct GeneratorState {
- /// The path to the `deno_core` crate (either `deno_core` or `crate`, the latter used if the op is `(core)`).
- pub deno_core: TokenStream,
-
- /// Identifiers for each of the arguments of the original function
- pub args: Vec<Ident>,
- /// The new identifier for the original function's contents.
- pub call: Ident,
- /// The result of the `call` function
- pub result: Ident,
-
- /// The `v8::CallbackScope` used if necessary for the function.
- pub scope: Ident,
- /// The `v8::FunctionCallbackInfo` used to pass args into the slow function.
- pub info: Ident,
- /// The `v8::FunctionCallbackArguments` used to pass args into the slow function.
- pub fn_args: Ident,
- /// The `OpCtx` used for various information required for some ops.
- pub opctx: Ident,
- /// The `FastApiCallbackOptions` used in fast calls for fallback returns.
- pub fast_api_callback_options: Ident,
- /// The `v8::ReturnValue` used in the slow function
- pub retval: Ident,
- /// The "slow" function (ie: the one that isn't a fastcall)
- pub slow_function: Ident,
- /// The "fast" function (ie: a fastcall)
- pub fast_function: Ident,
-
- pub needs_args: bool,
- pub needs_retval: bool,
- pub needs_scope: bool,
- pub needs_opstate: bool,
- pub needs_opctx: bool,
- pub needs_fast_opctx: bool,
- pub needs_fast_api_callback_options: bool,
-}
diff --git a/ops/op2/mod.rs b/ops/op2/mod.rs
deleted file mode 100644
index 7f652fe1b..000000000
--- a/ops/op2/mod.rs
+++ /dev/null
@@ -1,326 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-use deno_proc_macro_rules::rules;
-use proc_macro2::Ident;
-use proc_macro2::Span;
-use proc_macro2::TokenStream;
-use quote::format_ident;
-use quote::quote;
-use quote::ToTokens;
-use std::iter::zip;
-use syn2::parse2;
-use syn2::parse_str;
-use syn2::FnArg;
-use syn2::ItemFn;
-use syn2::Path;
-use thiserror::Error;
-
-use self::dispatch_fast::generate_dispatch_fast;
-use self::dispatch_slow::generate_dispatch_slow;
-use self::generator_state::GeneratorState;
-use self::signature::parse_signature;
-use self::signature::Arg;
-use self::signature::SignatureError;
-
-pub mod dispatch_fast;
-pub mod dispatch_slow;
-pub mod generator_state;
-pub mod signature;
-
-#[derive(Debug, Error)]
-pub enum Op2Error {
- #[error("Failed to match a pattern for '{0}': (input was '{1}')")]
- PatternMatchFailed(&'static str, String),
- #[error("Invalid attribute: '{0}'")]
- InvalidAttribute(String),
- #[error("Failed to parse syntax tree")]
- ParseError(#[from] syn2::Error),
- #[error("Failed to map a parsed signature to a V8 call")]
- V8MappingError(#[from] V8MappingError),
- #[error("Failed to parse signature")]
- SignatureError(#[from] SignatureError),
- #[error("This op is fast-compatible and should be marked as (fast)")]
- ShouldBeFast,
- #[error("This op is not fast-compatible and should not be marked as (fast)")]
- ShouldNotBeFast,
-}
-
-#[derive(Debug, Error)]
-pub enum V8MappingError {
- #[error("Unable to map {1:?} to {0}")]
- NoMapping(&'static str, Arg),
-}
-
-#[derive(Default)]
-pub(crate) struct MacroConfig {
- pub core: bool,
- pub fast: bool,
-}
-
-impl MacroConfig {
- pub fn from_flags(flags: Vec<Ident>) -> Result<Self, Op2Error> {
- let mut config: MacroConfig = Self::default();
- for flag in flags {
- if flag == "core" {
- config.core = true;
- } else if flag == "fast" {
- config.fast = true;
- } else {
- return Err(Op2Error::InvalidAttribute(flag.to_string()));
- }
- }
- Ok(config)
- }
-
- pub fn from_tokens(tokens: TokenStream) -> Result<Self, Op2Error> {
- let attr_string = tokens.to_string();
- let config = std::panic::catch_unwind(|| {
- rules!(tokens => {
- () => {
- Ok(MacroConfig::default())
- }
- ($($flags:ident),+) => {
- Self::from_flags(flags)
- }
- })
- })
- .map_err(|_| Op2Error::PatternMatchFailed("attribute", attr_string))??;
- Ok(config)
- }
-}
-
-pub fn op2(
- attr: TokenStream,
- item: TokenStream,
-) -> Result<TokenStream, Op2Error> {
- let func = parse2::<ItemFn>(item)?;
- let config = MacroConfig::from_tokens(attr)?;
- generate_op2(config, func)
-}
-
-fn generate_op2(
- config: MacroConfig,
- func: ItemFn,
-) -> Result<TokenStream, Op2Error> {
- // Create a copy of the original function, named "call"
- let call = Ident::new("call", Span::call_site());
- let mut op_fn = func.clone();
- op_fn.attrs.clear();
- op_fn.sig.generics.params.clear();
- op_fn.sig.ident = call.clone();
-
- // Clear inert attributes
- // TODO(mmastrac): This should limit itself to clearing ours only
- for arg in op_fn.sig.inputs.iter_mut() {
- match arg {
- FnArg::Receiver(slf) => slf.attrs.clear(),
- FnArg::Typed(ty) => ty.attrs.clear(),
- }
- }
-
- let signature = parse_signature(func.attrs, func.sig.clone())?;
- let processed_args =
- zip(signature.args.iter(), &func.sig.inputs).collect::<Vec<_>>();
-
- let mut args = vec![];
- let mut needs_args = false;
- for (index, _) in processed_args.iter().enumerate() {
- let input = format_ident!("arg{index}");
- args.push(input);
- needs_args = true;
- }
-
- let retval = Ident::new("rv", Span::call_site());
- let result = Ident::new("result", Span::call_site());
- let fn_args = Ident::new("args", Span::call_site());
- let scope = Ident::new("scope", Span::call_site());
- let info = Ident::new("info", Span::call_site());
- let opctx = Ident::new("opctx", Span::call_site());
- let slow_function = Ident::new("v8_fn_ptr", Span::call_site());
- let fast_function = Ident::new("v8_fn_ptr_fast", Span::call_site());
- let fast_api_callback_options =
- Ident::new("fast_api_callback_options", Span::call_site());
-
- let deno_core = if config.core {
- syn2::parse_str::<Path>("crate")
- } else {
- syn2::parse_str::<Path>("deno_core")
- }
- .expect("Parsing crate should not fail")
- .into_token_stream();
-
- let mut generator_state = GeneratorState {
- args,
- fn_args,
- call,
- scope,
- info,
- opctx,
- fast_api_callback_options,
- deno_core,
- result,
- retval,
- needs_args,
- slow_function,
- fast_function,
- needs_retval: false,
- needs_scope: false,
- needs_opctx: false,
- needs_opstate: false,
- needs_fast_opctx: false,
- needs_fast_api_callback_options: false,
- };
-
- let name = func.sig.ident;
-
- let slow_fn =
- generate_dispatch_slow(&config, &mut generator_state, &signature)?;
- let (fast_definition, fast_fn) =
- match generate_dispatch_fast(&mut generator_state, &signature)? {
- Some((fast_definition, fast_fn)) => {
- if !config.fast {
- return Err(Op2Error::ShouldBeFast);
- }
- (quote!(Some({#fast_definition})), fast_fn)
- }
- None => {
- if config.fast {
- return Err(Op2Error::ShouldNotBeFast);
- }
- (quote!(None), quote!())
- }
- };
-
- let GeneratorState {
- deno_core,
- slow_function,
- ..
- } = &generator_state;
-
- let arg_count: usize = generator_state.args.len();
- let vis = func.vis;
- let generic = signature
- .generic_bounds
- .keys()
- .map(|s| format_ident!("{s}"))
- .collect::<Vec<_>>();
- let bound = signature
- .generic_bounds
- .values()
- .map(|p| parse_str::<Path>(p).expect("Failed to reparse path"))
- .collect::<Vec<_>>();
-
- Ok(quote! {
- #[allow(non_camel_case_types)]
- #vis struct #name <#(#generic),*> {
- // We need to mark these type parameters as used, so we use a PhantomData
- _unconstructable: ::std::marker::PhantomData<(#(#generic),*)>
- }
-
- impl <#(#generic : #bound),*> #deno_core::_ops::Op for #name <#(#generic),*> {
- const NAME: &'static str = stringify!(#name);
- const DECL: #deno_core::_ops::OpDecl = #deno_core::_ops::OpDecl {
- name: stringify!(#name),
- v8_fn_ptr: Self::#slow_function as _,
- enabled: true,
- fast_fn: #fast_definition,
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: #arg_count as u8,
- };
- }
-
- impl <#(#generic : #bound),*> #name <#(#generic),*> {
- pub const fn name() -> &'static str {
- stringify!(#name)
- }
-
- pub const fn decl() -> #deno_core::_ops::OpDecl {
- #deno_core::_ops::OpDecl {
- name: stringify!(#name),
- v8_fn_ptr: Self::#slow_function as _,
- enabled: true,
- fast_fn: #fast_definition,
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: #arg_count as u8,
- }
- }
-
- #fast_fn
- #slow_fn
-
- #[inline(always)]
- #op_fn
- }
- })
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
- use pretty_assertions::assert_eq;
- use std::path::PathBuf;
- use syn2::parse_str;
- use syn2::File;
- use syn2::Item;
-
- #[testing_macros::fixture("op2/test_cases/**/*.rs")]
- fn test_signature_parser(input: PathBuf) {
- let update_expected = std::env::var("UPDATE_EXPECTED").is_ok();
-
- let source =
- std::fs::read_to_string(&input).expect("Failed to read test file");
- let file = parse_str::<File>(&source).expect("Failed to parse Rust file");
- let mut expected_out = vec![];
- for item in file.items {
- if let Item::Fn(mut func) = item {
- let mut config = None;
- func.attrs.retain(|attr| {
- let tokens = attr.into_token_stream();
- let attr_string = attr.clone().into_token_stream().to_string();
- println!("{}", attr_string);
- use syn2 as syn;
- if let Some(new_config) = rules!(tokens => {
- (#[op2]) => {
- Some(MacroConfig::default())
- }
- (#[op2( $($x:ident),* )]) => {
- Some(MacroConfig::from_flags(x).expect("Failed to parse attribute"))
- }
- (#[$_attr:meta]) => {
- None
- }
- }) {
- config = Some(new_config);
- false
- } else {
- true
- }
- });
- let tokens =
- generate_op2(config.unwrap(), func).expect("Failed to generate op");
- println!("======== Raw tokens ========:\n{}", tokens.clone());
- let tree = syn::parse2(tokens).unwrap();
- let actual = prettyplease::unparse(&tree);
- println!("======== Generated ========:\n{}", actual);
- expected_out.push(actual);
- }
- }
-
- let expected_out = expected_out.join("\n");
-
- if update_expected {
- std::fs::write(input.with_extension("out"), expected_out)
- .expect("Failed to write expectation file");
- } else {
- let expected = std::fs::read_to_string(input.with_extension("out"))
- .expect("Failed to read expectation file");
- assert_eq!(
- expected, expected_out,
- "Failed to match expectation. Use UPDATE_EXPECTED=1."
- );
- }
- }
-}
diff --git a/ops/op2/signature.rs b/ops/op2/signature.rs
deleted file mode 100644
index 5d472fcf3..000000000
--- a/ops/op2/signature.rs
+++ /dev/null
@@ -1,741 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-use deno_proc_macro_rules::rules;
-use proc_macro2::Ident;
-use proc_macro2::Span;
-use quote::quote;
-use quote::ToTokens;
-use std::collections::BTreeMap;
-use strum::IntoEnumIterator;
-use strum::IntoStaticStr;
-use strum_macros::EnumIter;
-use strum_macros::EnumString;
-use syn2::Attribute;
-use syn2::FnArg;
-use syn2::GenericParam;
-use syn2::Generics;
-use syn2::Pat;
-use syn2::ReturnType;
-use syn2::Signature;
-use syn2::Type;
-use syn2::TypePath;
-use thiserror::Error;
-
-#[allow(non_camel_case_types)]
-#[derive(
- Copy, Clone, Debug, Eq, PartialEq, IntoStaticStr, EnumString, EnumIter,
-)]
-pub enum NumericArg {
- /// A placeholder argument for arguments annotated with #[smi].
- __SMI__,
- /// A placeholder argument for void data.
- __VOID__,
- bool,
- i8,
- u8,
- i16,
- u16,
- i32,
- u32,
- i64,
- u64,
- f32,
- f64,
- isize,
- usize,
-}
-
-impl ToTokens for NumericArg {
- fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
- let ident = Ident::new(self.into(), Span::call_site());
- tokens.extend(quote! { #ident })
- }
-}
-
-#[derive(
- Copy, Clone, Debug, Eq, PartialEq, IntoStaticStr, EnumString, EnumIter,
-)]
-pub enum V8Arg {
- External,
- Object,
- Array,
- ArrayBuffer,
- ArrayBufferView,
- DataView,
- TypedArray,
- BigInt64Array,
- BigUint64Array,
- Float32Array,
- Float64Array,
- Int16Array,
- Int32Array,
- Int8Array,
- Uint16Array,
- Uint32Array,
- Uint8Array,
- Uint8ClampedArray,
- BigIntObject,
- BooleanObject,
- Date,
- Function,
- Map,
- NumberObject,
- Promise,
- PromiseResolver,
- Proxy,
- RegExp,
- Set,
- SharedArrayBuffer,
- StringObject,
- SymbolObject,
- WasmMemoryObject,
- WasmModuleObject,
- Primitive,
- BigInt,
- Boolean,
- Name,
- String,
- Symbol,
- Number,
- Integer,
- Int32,
- Uint32,
-}
-
-#[derive(Copy, Clone, Debug, Eq, PartialEq)]
-pub enum Special {
- HandleScope,
- OpState,
- String,
- CowStr,
- RefStr,
- FastApiCallbackOptions,
-}
-
-#[derive(Copy, Clone, Debug, Eq, PartialEq)]
-pub enum RefType {
- Ref,
- Mut,
-}
-
-#[derive(Clone, Debug, Eq, PartialEq)]
-pub enum Arg {
- Void,
- Special(Special),
- Ref(RefType, Special),
- RcRefCell(Special),
- Option(Special),
- OptionNumeric(NumericArg),
- Slice(RefType, NumericArg),
- Ptr(RefType, NumericArg),
- V8Local(V8Arg),
- Numeric(NumericArg),
- SerdeV8(String),
-}
-
-#[derive(Clone, Debug, Eq, PartialEq)]
-pub enum RetVal {
- Infallible(Arg),
- Result(Arg),
-}
-
-#[derive(Clone, Debug, Eq, PartialEq)]
-pub struct ParsedSignature {
- // The parsed arguments
- pub args: Vec<Arg>,
- // The argument names
- pub names: Vec<String>,
- // The parsed return value
- pub ret_val: RetVal,
- // One and only one lifetime allowed
- pub lifetime: Option<String>,
- // Generic bounds: each generic must have one and only simple trait bound
- pub generic_bounds: BTreeMap<String, String>,
-}
-
-#[derive(Copy, Clone, Debug, Eq, PartialEq)]
-enum AttributeModifier {
- /// #[serde], for serde_v8 types.
- Serde,
- /// #[smi], for small integers
- Smi,
- /// #[string], for strings.
- String,
-}
-
-#[derive(Error, Debug)]
-pub enum SignatureError {
- #[error("Invalid argument: '{0}'")]
- ArgError(String, #[source] ArgError),
- #[error("Invalid return type")]
- RetError(#[from] ArgError),
- #[error("Only one lifetime is permitted")]
- TooManyLifetimes,
- #[error("Generic '{0}' must have one and only bound (either <T> and 'where T: Trait', or <T: Trait>)")]
- GenericBoundCardinality(String),
- #[error("Where clause predicate '{0}' (eg: where T: Trait) must appear in generics list (eg: <T>)")]
- WherePredicateMustAppearInGenerics(String),
- #[error("All generics must appear only once in the generics parameter list or where clause")]
- DuplicateGeneric(String),
- #[error("Generic lifetime '{0}' may not have bounds (eg: <'a: 'b>)")]
- LifetimesMayNotHaveBounds(String),
- #[error("Invalid generic: '{0}' Only simple generics bounds are allowed (eg: T: Trait)")]
- InvalidGeneric(String),
- #[error("Invalid predicate: '{0}' Only simple where predicates are allowed (eg: T: Trait)")]
- InvalidWherePredicate(String),
-}
-
-#[derive(Error, Debug)]
-pub enum ArgError {
- #[error("Invalid self argument")]
- InvalidSelf,
- #[error("Invalid argument type: {0}")]
- InvalidType(String),
- #[error(
- "Invalid argument type path (should this be #[smi] or #[serde]?): {0}"
- )]
- InvalidTypePath(String),
- #[error("Too many attributes")]
- TooManyAttributes,
- #[error("Invalid #[serde] type: {0}")]
- InvalidSerdeType(String),
- #[error("Cannot use #[serde] for type: {0}")]
- InvalidSerdeAttributeType(String),
- #[error("Invalid v8 type: {0}")]
- InvalidV8Type(String),
- #[error("Internal error: {0}")]
- InternalError(String),
- #[error("Missing a #[string] attribute")]
- MissingStringAttribute,
-}
-
-#[derive(Copy, Clone, Default)]
-struct Attributes {
- primary: Option<AttributeModifier>,
-}
-
-fn stringify_token(tokens: impl ToTokens) -> String {
- tokens
- .into_token_stream()
- .into_iter()
- .map(|s| s.to_string())
- .collect::<Vec<_>>()
- .join("")
-}
-
-pub fn parse_signature(
- attributes: Vec<Attribute>,
- signature: Signature,
-) -> Result<ParsedSignature, SignatureError> {
- let mut args = vec![];
- let mut names = vec![];
- for input in signature.inputs {
- let name = match &input {
- FnArg::Receiver(_) => "self".to_owned(),
- FnArg::Typed(ty) => match &*ty.pat {
- Pat::Ident(ident) => ident.ident.to_string(),
- _ => "(complex)".to_owned(),
- },
- };
- names.push(name.clone());
- args.push(
- parse_arg(input).map_err(|err| SignatureError::ArgError(name, err))?,
- );
- }
- let ret_val =
- parse_return(parse_attributes(&attributes)?, &signature.output)?;
- let lifetime = parse_lifetime(&signature.generics)?;
- let generic_bounds = parse_generics(&signature.generics)?;
- Ok(ParsedSignature {
- args,
- names,
- ret_val,
- lifetime,
- generic_bounds,
- })
-}
-
-/// Extract one lifetime from the [`syn2::Generics`], ensuring that the lifetime is valid
-/// and has no bounds.
-fn parse_lifetime(
- generics: &Generics,
-) -> Result<Option<String>, SignatureError> {
- let mut res = None;
- for param in &generics.params {
- if let GenericParam::Lifetime(lt) = param {
- if !lt.bounds.is_empty() {
- return Err(SignatureError::LifetimesMayNotHaveBounds(
- lt.lifetime.to_string(),
- ));
- }
- if res.is_some() {
- return Err(SignatureError::TooManyLifetimes);
- }
- res = Some(lt.lifetime.ident.to_string());
- }
- }
- Ok(res)
-}
-
-/// Parse and validate generics. We require one and only one trait bound for each generic
-/// parameter. Tries to sanity check and return reasonable errors for possible signature errors.
-fn parse_generics(
- generics: &Generics,
-) -> Result<BTreeMap<String, String>, SignatureError> {
- let mut where_clauses = BTreeMap::new();
-
- // First, extract the where clause so we can detect duplicated predicates
- if let Some(where_clause) = &generics.where_clause {
- for predicate in &where_clause.predicates {
- let predicate = predicate.to_token_stream();
- let (generic_name, bound) = std::panic::catch_unwind(|| {
- use syn2 as syn;
- rules!(predicate => {
- ($t:ident : $bound:path) => (t.to_string(), stringify_token(bound)),
- })
- })
- .map_err(|_| {
- SignatureError::InvalidWherePredicate(predicate.to_string())
- })?;
- if where_clauses.insert(generic_name.clone(), bound).is_some() {
- return Err(SignatureError::DuplicateGeneric(generic_name));
- }
- }
- }
-
- let mut res = BTreeMap::new();
- for param in &generics.params {
- if let GenericParam::Type(ty) = param {
- let ty = ty.to_token_stream();
- let (name, bound) = std::panic::catch_unwind(|| {
- use syn2 as syn;
- rules!(ty => {
- ($t:ident : $bound:path) => (t.to_string(), Some(stringify_token(bound))),
- ($t:ident) => (t.to_string(), None),
- })
- }).map_err(|_| SignatureError::InvalidGeneric(ty.to_string()))?;
- let bound = match bound {
- Some(bound) => {
- if where_clauses.contains_key(&name) {
- return Err(SignatureError::GenericBoundCardinality(name));
- }
- bound
- }
- None => {
- let Some(bound) = where_clauses.remove(&name) else {
- return Err(SignatureError::GenericBoundCardinality(name));
- };
- bound
- }
- };
- if res.contains_key(&name) {
- return Err(SignatureError::DuplicateGeneric(name));
- }
- res.insert(name, bound);
- }
- }
- if !where_clauses.is_empty() {
- return Err(SignatureError::WherePredicateMustAppearInGenerics(
- where_clauses.into_keys().next().unwrap(),
- ));
- }
-
- Ok(res)
-}
-
-fn parse_attributes(attributes: &[Attribute]) -> Result<Attributes, ArgError> {
- let attrs = attributes
- .iter()
- .filter_map(parse_attribute)
- .collect::<Vec<_>>();
-
- if attrs.is_empty() {
- return Ok(Attributes::default());
- }
- if attrs.len() > 1 {
- return Err(ArgError::TooManyAttributes);
- }
- Ok(Attributes {
- primary: Some(*attrs.get(0).unwrap()),
- })
-}
-
-fn parse_attribute(attr: &Attribute) -> Option<AttributeModifier> {
- let tokens = attr.into_token_stream();
- use syn2 as syn;
- std::panic::catch_unwind(|| {
- rules!(tokens => {
- (#[serde]) => Some(AttributeModifier::Serde),
- (#[smi]) => Some(AttributeModifier::Smi),
- (#[string]) => Some(AttributeModifier::String),
- (#[$_attr:meta]) => None,
- })
- })
- .expect("Failed to parse an attribute")
-}
-
-fn parse_return(
- attrs: Attributes,
- rt: &ReturnType,
-) -> Result<RetVal, ArgError> {
- match rt {
- ReturnType::Default => Ok(RetVal::Infallible(Arg::Void)),
- ReturnType::Type(_, ty) => {
- let s = stringify_token(ty);
- let tokens = ty.into_token_stream();
- use syn2 as syn;
-
- std::panic::catch_unwind(|| {
- rules!(tokens => {
- // x::y::Result<Value>, like io::Result and other specialty result types
- ($($_package:ident ::)* Result < $ty:ty >) => {
- Ok(RetVal::Result(parse_type(attrs, &ty)?))
- }
- // x::y::Result<Value, Error>
- ($($_package:ident ::)* Result < $ty:ty, $_error:ty >) => {
- Ok(RetVal::Result(parse_type(attrs, &ty)?))
- }
- ($ty:ty) => {
- Ok(RetVal::Infallible(parse_type(attrs, &ty)?))
- }
- })
- })
- .map_err(|e| {
- ArgError::InternalError(format!(
- "parse_return({}) {}",
- s,
- e.downcast::<&str>().unwrap_or_default()
- ))
- })?
- }
- }
-}
-
-fn parse_type_path(attrs: Attributes, tp: &TypePath) -> Result<Arg, ArgError> {
- if tp.path.segments.len() == 1 {
- let segment = tp.path.segments.first().unwrap().ident.to_string();
- for numeric in NumericArg::iter() {
- if Into::<&'static str>::into(numeric) == segment.as_str() {
- return Ok(Arg::Numeric(numeric));
- }
- }
- }
-
- use syn2 as syn;
-
- let tokens = tp.clone().into_token_stream();
- std::panic::catch_unwind(|| {
- rules!(tokens => {
- ( $( std :: str :: )? String ) => {
- if attrs.primary == Some(AttributeModifier::String) {
- Ok(Arg::Special(Special::String))
- } else {
- Err(ArgError::MissingStringAttribute)
- }
- }
- ( $( std :: str :: )? str ) => {
- // We should not hit this path with a #[string] argument
- Err(ArgError::MissingStringAttribute)
- }
- ( $( std :: borrow :: )? Cow < str > ) => {
- if attrs.primary == Some(AttributeModifier::String) {
- Ok(Arg::Special(Special::CowStr))
- } else {
- Err(ArgError::MissingStringAttribute)
- }
- }
- ( $( std :: ffi :: )? c_void ) => Ok(Arg::Numeric(NumericArg::__VOID__)),
- ( OpState ) => Ok(Arg::Special(Special::OpState)),
- ( v8 :: HandleScope ) => Ok(Arg::Special(Special::HandleScope)),
- ( v8 :: FastApiCallbackOptions ) => Ok(Arg::Special(Special::FastApiCallbackOptions)),
- ( v8 :: Local < $( $_scope:lifetime , )? v8 :: $v8:ident >) => Ok(Arg::V8Local(parse_v8_type(&v8)?)),
- ( Rc < RefCell < $ty:ty > > ) => Ok(Arg::RcRefCell(parse_type_special(attrs, &ty)?)),
- ( Option < $ty:ty > ) => {
- match parse_type(attrs, &ty)? {
- Arg::Special(special) => Ok(Arg::Option(special)),
- Arg::Numeric(numeric) => Ok(Arg::OptionNumeric(numeric)),
- _ => Err(ArgError::InvalidType(stringify_token(ty)))
- }
- }
- ( $any:ty ) => Err(ArgError::InvalidTypePath(stringify_token(any))),
- })
- }).map_err(|e| ArgError::InternalError(format!("parse_type_path {e:?}")))?
-}
-
-fn parse_v8_type(v8: &Ident) -> Result<V8Arg, ArgError> {
- let v8 = v8.to_string();
- V8Arg::try_from(v8.as_str()).map_err(|_| ArgError::InvalidV8Type(v8))
-}
-
-fn parse_type_special(
- attrs: Attributes,
- ty: &Type,
-) -> Result<Special, ArgError> {
- match parse_type(attrs, ty)? {
- Arg::Special(special) => Ok(special),
- _ => Err(ArgError::InvalidType(stringify_token(ty))),
- }
-}
-
-fn parse_type(attrs: Attributes, ty: &Type) -> Result<Arg, ArgError> {
- if let Some(primary) = attrs.primary {
- match primary {
- AttributeModifier::Serde => match ty {
- Type::Path(of) => {
- // If this type will parse without #[serde], it is illegal to use this type with #[serde]
- if parse_type_path(Attributes::default(), of).is_ok() {
- return Err(ArgError::InvalidSerdeAttributeType(stringify_token(
- ty,
- )));
- }
- return Ok(Arg::SerdeV8(stringify_token(of.path.clone())));
- }
- _ => return Err(ArgError::InvalidSerdeType(stringify_token(ty))),
- },
- AttributeModifier::String => match ty {
- Type::Path(of) => {
- return parse_type_path(attrs, of);
- }
- Type::Reference(of) => {
- let mut_type = if of.mutability.is_some() {
- RefType::Mut
- } else {
- RefType::Ref
- };
- let tokens = of.elem.clone().into_token_stream();
- use syn2 as syn;
- return rules!(tokens => {
- (str) => Ok(Arg::Special(Special::RefStr)),
- ($_ty:ty) => Ok(Arg::Ref(mut_type, parse_type_special(attrs, &of.elem)?)),
- });
- }
- _ => return Err(ArgError::InvalidSerdeType(stringify_token(ty))),
- },
- AttributeModifier::Smi => {
- return Ok(Arg::Numeric(NumericArg::__SMI__));
- }
- }
- };
- match ty {
- Type::Tuple(of) => {
- if of.elems.is_empty() {
- Ok(Arg::Void)
- } else {
- Err(ArgError::InvalidType(stringify_token(ty)))
- }
- }
- Type::Reference(of) => {
- let mut_type = if of.mutability.is_some() {
- RefType::Mut
- } else {
- RefType::Ref
- };
- match &*of.elem {
- Type::Slice(of) => match parse_type(attrs, &of.elem)? {
- Arg::Numeric(numeric) => Ok(Arg::Slice(mut_type, numeric)),
- _ => Err(ArgError::InvalidType(stringify_token(ty))),
- },
- Type::Path(of) => match parse_type_path(attrs, of)? {
- Arg::Special(special) => Ok(Arg::Ref(mut_type, special)),
- _ => Err(ArgError::InvalidType(stringify_token(ty))),
- },
- _ => Err(ArgError::InvalidType(stringify_token(ty))),
- }
- }
- Type::Ptr(of) => {
- let mut_type = if of.mutability.is_some() {
- RefType::Mut
- } else {
- RefType::Ref
- };
- match &*of.elem {
- Type::Path(of) => match parse_type_path(attrs, of)? {
- Arg::Numeric(numeric) => Ok(Arg::Ptr(mut_type, numeric)),
- _ => Err(ArgError::InvalidType(stringify_token(ty))),
- },
- _ => Err(ArgError::InvalidType(stringify_token(ty))),
- }
- }
- Type::Path(of) => parse_type_path(attrs, of),
- _ => Err(ArgError::InvalidType(stringify_token(ty))),
- }
-}
-
-fn parse_arg(arg: FnArg) -> Result<Arg, ArgError> {
- let FnArg::Typed(typed) = arg else {
- return Err(ArgError::InvalidSelf);
- };
- parse_type(parse_attributes(&typed.attrs)?, &typed.ty)
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
- use crate::op2::signature::parse_signature;
- use syn2::parse_str;
- use syn2::ItemFn;
-
- // We can't test pattern args :/
- // https://github.com/rust-lang/rfcs/issues/2688
- macro_rules! test {
- (
- // Function attributes
- $(# [ $fn_attr:ident ])?
- // fn name < 'scope, GENERIC1, GENERIC2, ... >
- fn $name:ident $( < $scope:lifetime $( , $generic:ident)* >)?
- (
- // Argument attribute, argument
- $( $(# [ $attr:ident ])? $ident:ident : $ty:ty ),*
- )
- // Return value
- $(-> $(# [ $ret_attr:ident ])? $ret:ty)?
- // Where clause
- $( where $($trait:ident : $bounds:path),* )?
- ;
- // Expected return value
- $( < $( $lifetime_res:lifetime )? $(, $generic_res:ident : $bounds_res:path )* >)? ( $( $arg_res:expr ),* ) -> $ret_res:expr ) => {
- #[test]
- fn $name() {
- test(
- stringify!($( #[$fn_attr] )? fn op $( < $scope $( , $generic)* >)? ( $( $( #[$attr] )? $ident : $ty ),* ) $(-> $( #[$ret_attr] )? $ret)? $( where $($trait : $bounds),* )? {}),
- stringify!($( < $( $lifetime_res )? $(, $generic_res : $bounds_res)* > )?),
- stringify!($($arg_res),*),
- stringify!($ret_res)
- );
- }
- };
- }
-
- fn test(
- op: &str,
- generics_expected: &str,
- args_expected: &str,
- return_expected: &str,
- ) {
- // Parse the provided macro input as an ItemFn
- let item_fn = parse_str::<ItemFn>(op)
- .unwrap_or_else(|_| panic!("Failed to parse {op} as a ItemFn"));
-
- let attrs = item_fn.attrs;
- let sig = parse_signature(attrs, item_fn.sig).unwrap_or_else(|err| {
- panic!("Failed to successfully parse signature from {op} ({err:?})")
- });
- println!("Raw parsed signatures = {sig:?}");
-
- let mut generics_res = vec![];
- if let Some(lifetime) = sig.lifetime {
- generics_res.push(format!("'{lifetime}"));
- }
- for (name, bounds) in sig.generic_bounds {
- generics_res.push(format!("{name} : {bounds}"));
- }
- if !generics_res.is_empty() {
- assert_eq!(
- generics_expected,
- format!("< {} >", generics_res.join(", "))
- );
- }
- assert_eq!(
- args_expected,
- format!("{:?}", sig.args).trim_matches(|c| c == '[' || c == ']')
- );
- assert_eq!(return_expected, format!("{:?}", sig.ret_val));
- }
-
- macro_rules! expect_fail {
- ($name:ident, $error:expr, $f:item) => {
- #[test]
- pub fn $name() {
- expect_fail(stringify!($f), stringify!($error));
- }
- };
- }
-
- fn expect_fail(op: &str, error: &str) {
- // Parse the provided macro input as an ItemFn
- let item_fn = parse_str::<ItemFn>(op)
- .unwrap_or_else(|_| panic!("Failed to parse {op} as a ItemFn"));
- let attrs = item_fn.attrs;
- let err = parse_signature(attrs, item_fn.sig)
- .expect_err("Expected function to fail to parse");
- assert_eq!(format!("{err:?}"), error.to_owned());
- }
-
- test!(
- fn op_state_and_number(opstate: &mut OpState, a: u32) -> ();
- (Ref(Mut, OpState), Numeric(u32)) -> Infallible(Void)
- );
- test!(
- fn op_slices(r#in: &[u8], out: &mut [u8]);
- (Slice(Ref, u8), Slice(Mut, u8)) -> Infallible(Void)
- );
- test!(
- #[serde] fn op_serde(#[serde] input: package::SerdeInputType) -> Result<package::SerdeReturnType, Error>;
- (SerdeV8("package::SerdeInputType")) -> Result(SerdeV8("package::SerdeReturnType"))
- );
- test!(
- fn op_local(input: v8::Local<v8::String>) -> Result<v8::Local<v8::String>, Error>;
- (V8Local(String)) -> Result(V8Local(String))
- );
- test!(
- fn op_resource(#[smi] rid: ResourceId, buffer: &[u8]);
- (Numeric(__SMI__), Slice(Ref, u8)) -> Infallible(Void)
- );
- test!(
- fn op_option_numeric_result(state: &mut OpState) -> Result<Option<u32>, AnyError>;
- (Ref(Mut, OpState)) -> Result(OptionNumeric(u32))
- );
- test!(
- fn op_ffi_read_f64(state: &mut OpState, ptr: * mut c_void, offset: isize) -> Result <f64, AnyError>;
- (Ref(Mut, OpState), Ptr(Mut, __VOID__), Numeric(isize)) -> Result(Numeric(f64))
- );
- test!(
- fn op_print(#[string] msg: &str, is_err: bool) -> Result<(), Error>;
- (Special(RefStr), Numeric(bool)) -> Result(Void)
- );
- test!(
- fn op_scope<'s>(#[string] msg: &'s str);
- <'s> (Special(RefStr)) -> Infallible(Void)
- );
- test!(
- fn op_scope_and_generics<'s, AB, BC>(#[string] msg: &'s str) where AB: some::Trait, BC: OtherTrait;
- <'s, AB: some::Trait, BC: OtherTrait> (Special(RefStr)) -> Infallible(Void)
- );
-
- expect_fail!(op_with_two_lifetimes, TooManyLifetimes, fn f<'a, 'b>() {});
- expect_fail!(
- op_with_lifetime_bounds,
- LifetimesMayNotHaveBounds("'a"),
- fn f<'a: 'b, 'b>() {}
- );
- expect_fail!(
- op_with_missing_bounds,
- GenericBoundCardinality("B"),
- fn f<'a, B>() {}
- );
- expect_fail!(
- op_with_duplicate_bounds,
- GenericBoundCardinality("B"),
- fn f<'a, B: Trait>()
- where
- B: Trait,
- {
- }
- );
- expect_fail!(
- op_with_extra_bounds,
- WherePredicateMustAppearInGenerics("C"),
- fn f<'a, B>()
- where
- B: Trait,
- C: Trait,
- {
- }
- );
-
- #[test]
- fn test_parse_result() {
- let rt = parse_str::<ReturnType>("-> Result < (), Error >")
- .expect("Failed to parse");
- println!("{:?}", parse_return(Attributes::default(), &rt));
- }
-}
diff --git a/ops/op2/test_cases/sync/add.out b/ops/op2/test_cases/sync/add.out
deleted file mode 100644
index a73f032aa..000000000
--- a/ops/op2/test_cases/sync/add.out
+++ /dev/null
@@ -1,78 +0,0 @@
-#[allow(non_camel_case_types)]
-struct op_add {
- _unconstructable: ::std::marker::PhantomData<()>,
-}
-impl deno_core::_ops::Op for op_add {
- const NAME: &'static str = stringify!(op_add);
- const DECL: deno_core::_ops::OpDecl = deno_core::_ops::OpDecl {
- name: stringify!(op_add),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: Some({
- use deno_core::v8::fast_api::Type;
- use deno_core::v8::fast_api::CType;
- deno_core::v8::fast_api::FastFunction::new(
- &[Type::V8Value, Type::Uint32, Type::Uint32],
- CType::Uint32,
- Self::v8_fn_ptr_fast as *const ::std::ffi::c_void,
- )
- }),
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 2usize as u8,
- };
-}
-impl op_add {
- pub const fn name() -> &'static str {
- stringify!(op_add)
- }
- pub const fn decl() -> deno_core::_ops::OpDecl {
- deno_core::_ops::OpDecl {
- name: stringify!(op_add),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: Some({
- use deno_core::v8::fast_api::Type;
- use deno_core::v8::fast_api::CType;
- deno_core::v8::fast_api::FastFunction::new(
- &[Type::V8Value, Type::Uint32, Type::Uint32],
- CType::Uint32,
- Self::v8_fn_ptr_fast as *const ::std::ffi::c_void,
- )
- }),
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 2usize as u8,
- }
- }
- fn v8_fn_ptr_fast(
- _: deno_core::v8::Local<deno_core::v8::Object>,
- arg0: u32,
- arg1: u32,
- ) -> u32 {
- let arg0 = arg0 as _;
- let arg1 = arg1 as _;
- let result = Self::call(arg0, arg1);
- result
- }
- extern "C" fn v8_fn_ptr(info: *const deno_core::v8::FunctionCallbackInfo) {
- let mut rv = deno_core::v8::ReturnValue::from_function_callback_info(unsafe {
- &*info
- });
- let args = deno_core::v8::FunctionCallbackArguments::from_function_callback_info(unsafe {
- &*info
- });
- let arg0 = args.get(0usize as i32);
- let arg0 = deno_core::_ops::to_u32(&arg0) as _;
- let arg1 = args.get(1usize as i32);
- let arg1 = deno_core::_ops::to_u32(&arg1) as _;
- let result = Self::call(arg0, arg1);
- rv.set_uint32(result as u32);
- }
- #[inline(always)]
- fn call(a: u32, b: u32) -> u32 {
- a + b
- }
-}
diff --git a/ops/op2/test_cases/sync/add.rs b/ops/op2/test_cases/sync/add.rs
deleted file mode 100644
index 74dbb1893..000000000
--- a/ops/op2/test_cases/sync/add.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-
-#[op2(fast)]
-fn op_add(a: u32, b: u32) -> u32 {
- a + b
-}
diff --git a/ops/op2/test_cases/sync/add_options.out b/ops/op2/test_cases/sync/add_options.out
deleted file mode 100644
index 9fada187f..000000000
--- a/ops/op2/test_cases/sync/add_options.out
+++ /dev/null
@@ -1,57 +0,0 @@
-#[allow(non_camel_case_types)]
-pub struct op_test_add_option {
- _unconstructable: ::std::marker::PhantomData<()>,
-}
-impl crate::_ops::Op for op_test_add_option {
- const NAME: &'static str = stringify!(op_test_add_option);
- const DECL: crate::_ops::OpDecl = crate::_ops::OpDecl {
- name: stringify!(op_test_add_option),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: None,
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 2usize as u8,
- };
-}
-impl op_test_add_option {
- pub const fn name() -> &'static str {
- stringify!(op_test_add_option)
- }
- pub const fn decl() -> crate::_ops::OpDecl {
- crate::_ops::OpDecl {
- name: stringify!(op_test_add_option),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: None,
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 2usize as u8,
- }
- }
- extern "C" fn v8_fn_ptr(info: *const crate::v8::FunctionCallbackInfo) {
- let mut rv = crate::v8::ReturnValue::from_function_callback_info(unsafe {
- &*info
- });
- let args = crate::v8::FunctionCallbackArguments::from_function_callback_info(unsafe {
- &*info
- });
- let arg0 = args.get(0usize as i32);
- let arg0 = crate::_ops::to_u32(&arg0) as _;
- let arg1 = args.get(1usize as i32);
- let arg1 = if arg1.is_null_or_undefined() {
- None
- } else {
- let arg1 = crate::_ops::to_u32(&arg1) as _;
- Some(arg1)
- };
- let result = Self::call(arg0, arg1);
- rv.set_uint32(result as u32);
- }
- #[inline(always)]
- pub fn call(a: u32, b: Option<u32>) -> u32 {
- a + b.unwrap_or(100)
- }
-}
diff --git a/ops/op2/test_cases/sync/add_options.rs b/ops/op2/test_cases/sync/add_options.rs
deleted file mode 100644
index a5f2c8f4a..000000000
--- a/ops/op2/test_cases/sync/add_options.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-
-#[op2(core)]
-pub fn op_test_add_option(a: u32, b: Option<u32>) -> u32 {
- a + b.unwrap_or(100)
-}
diff --git a/ops/op2/test_cases/sync/doc_comment.out b/ops/op2/test_cases/sync/doc_comment.out
deleted file mode 100644
index d7e8005d9..000000000
--- a/ops/op2/test_cases/sync/doc_comment.out
+++ /dev/null
@@ -1,59 +0,0 @@
-#[allow(non_camel_case_types)]
-pub struct op_has_doc_comment {
- _unconstructable: ::std::marker::PhantomData<()>,
-}
-impl deno_core::_ops::Op for op_has_doc_comment {
- const NAME: &'static str = stringify!(op_has_doc_comment);
- const DECL: deno_core::_ops::OpDecl = deno_core::_ops::OpDecl {
- name: stringify!(op_has_doc_comment),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: Some({
- use deno_core::v8::fast_api::Type;
- use deno_core::v8::fast_api::CType;
- deno_core::v8::fast_api::FastFunction::new(
- &[Type::V8Value],
- CType::Void,
- Self::v8_fn_ptr_fast as *const ::std::ffi::c_void,
- )
- }),
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 0usize as u8,
- };
-}
-impl op_has_doc_comment {
- pub const fn name() -> &'static str {
- stringify!(op_has_doc_comment)
- }
- pub const fn decl() -> deno_core::_ops::OpDecl {
- deno_core::_ops::OpDecl {
- name: stringify!(op_has_doc_comment),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: Some({
- use deno_core::v8::fast_api::Type;
- use deno_core::v8::fast_api::CType;
- deno_core::v8::fast_api::FastFunction::new(
- &[Type::V8Value],
- CType::Void,
- Self::v8_fn_ptr_fast as *const ::std::ffi::c_void,
- )
- }),
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 0usize as u8,
- }
- }
- fn v8_fn_ptr_fast(_: deno_core::v8::Local<deno_core::v8::Object>) -> () {
- let result = Self::call();
- result
- }
- extern "C" fn v8_fn_ptr(info: *const deno_core::v8::FunctionCallbackInfo) {
- let result = Self::call();
- }
- #[inline(always)]
- pub fn call() -> () {}
-}
diff --git a/ops/op2/test_cases/sync/doc_comment.rs b/ops/op2/test_cases/sync/doc_comment.rs
deleted file mode 100644
index b729a64bd..000000000
--- a/ops/op2/test_cases/sync/doc_comment.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-
-/// This is a doc comment.
-#[op2(fast)]
-pub fn op_has_doc_comment() -> () {}
diff --git a/ops/op2/test_cases/sync/generics.out b/ops/op2/test_cases/sync/generics.out
deleted file mode 100644
index 26e3af9b7..000000000
--- a/ops/op2/test_cases/sync/generics.out
+++ /dev/null
@@ -1,59 +0,0 @@
-#[allow(non_camel_case_types)]
-pub struct op_generics<T> {
- _unconstructable: ::std::marker::PhantomData<(T)>,
-}
-impl<T: Trait> deno_core::_ops::Op for op_generics<T> {
- const NAME: &'static str = stringify!(op_generics);
- const DECL: deno_core::_ops::OpDecl = deno_core::_ops::OpDecl {
- name: stringify!(op_generics),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: Some({
- use deno_core::v8::fast_api::Type;
- use deno_core::v8::fast_api::CType;
- deno_core::v8::fast_api::FastFunction::new(
- &[Type::V8Value],
- CType::Void,
- Self::v8_fn_ptr_fast as *const ::std::ffi::c_void,
- )
- }),
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 0usize as u8,
- };
-}
-impl<T: Trait> op_generics<T> {
- pub const fn name() -> &'static str {
- stringify!(op_generics)
- }
- pub const fn decl() -> deno_core::_ops::OpDecl {
- deno_core::_ops::OpDecl {
- name: stringify!(op_generics),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: Some({
- use deno_core::v8::fast_api::Type;
- use deno_core::v8::fast_api::CType;
- deno_core::v8::fast_api::FastFunction::new(
- &[Type::V8Value],
- CType::Void,
- Self::v8_fn_ptr_fast as *const ::std::ffi::c_void,
- )
- }),
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 0usize as u8,
- }
- }
- fn v8_fn_ptr_fast(_: deno_core::v8::Local<deno_core::v8::Object>) -> () {
- let result = Self::call();
- result
- }
- extern "C" fn v8_fn_ptr(info: *const deno_core::v8::FunctionCallbackInfo) {
- let result = Self::call();
- }
- #[inline(always)]
- pub fn call() {}
-}
diff --git a/ops/op2/test_cases/sync/generics.rs b/ops/op2/test_cases/sync/generics.rs
deleted file mode 100644
index b412a7f93..000000000
--- a/ops/op2/test_cases/sync/generics.rs
+++ /dev/null
@@ -1,4 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-
-#[op2(fast)]
-pub fn op_generics<T: Trait>() {}
diff --git a/ops/op2/test_cases/sync/result_primitive.out b/ops/op2/test_cases/sync/result_primitive.out
deleted file mode 100644
index 4f296a893..000000000
--- a/ops/op2/test_cases/sync/result_primitive.out
+++ /dev/null
@@ -1,122 +0,0 @@
-#[allow(non_camel_case_types)]
-pub struct op_u32_with_result {
- _unconstructable: ::std::marker::PhantomData<()>,
-}
-impl deno_core::_ops::Op for op_u32_with_result {
- const NAME: &'static str = stringify!(op_u32_with_result);
- const DECL: deno_core::_ops::OpDecl = deno_core::_ops::OpDecl {
- name: stringify!(op_u32_with_result),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: Some({
- use deno_core::v8::fast_api::Type;
- use deno_core::v8::fast_api::CType;
- deno_core::v8::fast_api::FastFunction::new(
- &[Type::V8Value, Type::CallbackOptions],
- CType::Uint32,
- Self::v8_fn_ptr_fast as *const ::std::ffi::c_void,
- )
- }),
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 0usize as u8,
- };
-}
-impl op_u32_with_result {
- pub const fn name() -> &'static str {
- stringify!(op_u32_with_result)
- }
- pub const fn decl() -> deno_core::_ops::OpDecl {
- deno_core::_ops::OpDecl {
- name: stringify!(op_u32_with_result),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: Some({
- use deno_core::v8::fast_api::Type;
- use deno_core::v8::fast_api::CType;
- deno_core::v8::fast_api::FastFunction::new(
- &[Type::V8Value, Type::CallbackOptions],
- CType::Uint32,
- Self::v8_fn_ptr_fast as *const ::std::ffi::c_void,
- )
- }),
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 0usize as u8,
- }
- }
- fn v8_fn_ptr_fast(
- _: deno_core::v8::Local<deno_core::v8::Object>,
- fast_api_callback_options: *mut deno_core::v8::fast_api::FastApiCallbackOptions,
- ) -> u32 {
- let fast_api_callback_options = unsafe { &mut *fast_api_callback_options };
- let opctx = unsafe {
- &*(deno_core::v8::Local::<
- v8::External,
- >::cast(unsafe { fast_api_callback_options.data.data })
- .value() as *const deno_core::_ops::OpCtx)
- };
- let result = Self::call();
- let result = match result {
- Ok(result) => result,
- Err(err) => {
- unsafe {
- opctx.unsafely_set_last_error_for_ops_only(err);
- }
- fast_api_callback_options.fallback = true;
- return ::std::default::Default::default();
- }
- };
- result
- }
- extern "C" fn v8_fn_ptr(info: *const deno_core::v8::FunctionCallbackInfo) {
- let mut rv = deno_core::v8::ReturnValue::from_function_callback_info(unsafe {
- &*info
- });
- let args = deno_core::v8::FunctionCallbackArguments::from_function_callback_info(unsafe {
- &*info
- });
- let opctx = unsafe {
- &*(deno_core::v8::Local::<deno_core::v8::External>::cast(args.data()).value()
- as *const deno_core::_ops::OpCtx)
- };
- if let Some(err) = unsafe { opctx.unsafely_take_last_error_for_ops_only() } {
- let scope = &mut unsafe { deno_core::v8::CallbackScope::new(&*info) };
- let args = deno_core::v8::FunctionCallbackArguments::from_function_callback_info(unsafe {
- &*info
- });
- let opstate = ::std::cell::RefCell::borrow(&*opctx.state);
- let exception = deno_core::error::to_v8_error(
- scope,
- opstate.get_error_class_fn,
- &err,
- );
- scope.throw_exception(exception);
- return;
- }
- let result = Self::call();
- match result {
- Ok(result) => {
- rv.set_uint32(result as u32);
- }
- Err(err) => {
- let scope = &mut unsafe { deno_core::v8::CallbackScope::new(&*info) };
- let args = deno_core::v8::FunctionCallbackArguments::from_function_callback_info(unsafe {
- &*info
- });
- let opstate = ::std::cell::RefCell::borrow(&*opctx.state);
- let exception = deno_core::error::to_v8_error(
- scope,
- opstate.get_error_class_fn,
- &err,
- );
- scope.throw_exception(exception);
- return;
- }
- };
- }
- #[inline(always)]
- pub fn call() -> Result<u32, AnyError> {}
-}
diff --git a/ops/op2/test_cases/sync/result_primitive.rs b/ops/op2/test_cases/sync/result_primitive.rs
deleted file mode 100644
index df89c2432..000000000
--- a/ops/op2/test_cases/sync/result_primitive.rs
+++ /dev/null
@@ -1,4 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-
-#[op2(fast)]
-pub fn op_u32_with_result() -> Result<u32, AnyError> {}
diff --git a/ops/op2/test_cases/sync/result_void.out b/ops/op2/test_cases/sync/result_void.out
deleted file mode 100644
index 74aa84a8d..000000000
--- a/ops/op2/test_cases/sync/result_void.out
+++ /dev/null
@@ -1,117 +0,0 @@
-#[allow(non_camel_case_types)]
-pub struct op_void_with_result {
- _unconstructable: ::std::marker::PhantomData<()>,
-}
-impl deno_core::_ops::Op for op_void_with_result {
- const NAME: &'static str = stringify!(op_void_with_result);
- const DECL: deno_core::_ops::OpDecl = deno_core::_ops::OpDecl {
- name: stringify!(op_void_with_result),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: Some({
- use deno_core::v8::fast_api::Type;
- use deno_core::v8::fast_api::CType;
- deno_core::v8::fast_api::FastFunction::new(
- &[Type::V8Value, Type::CallbackOptions],
- CType::Void,
- Self::v8_fn_ptr_fast as *const ::std::ffi::c_void,
- )
- }),
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 0usize as u8,
- };
-}
-impl op_void_with_result {
- pub const fn name() -> &'static str {
- stringify!(op_void_with_result)
- }
- pub const fn decl() -> deno_core::_ops::OpDecl {
- deno_core::_ops::OpDecl {
- name: stringify!(op_void_with_result),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: Some({
- use deno_core::v8::fast_api::Type;
- use deno_core::v8::fast_api::CType;
- deno_core::v8::fast_api::FastFunction::new(
- &[Type::V8Value, Type::CallbackOptions],
- CType::Void,
- Self::v8_fn_ptr_fast as *const ::std::ffi::c_void,
- )
- }),
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 0usize as u8,
- }
- }
- fn v8_fn_ptr_fast(
- _: deno_core::v8::Local<deno_core::v8::Object>,
- fast_api_callback_options: *mut deno_core::v8::fast_api::FastApiCallbackOptions,
- ) -> () {
- let fast_api_callback_options = unsafe { &mut *fast_api_callback_options };
- let opctx = unsafe {
- &*(deno_core::v8::Local::<
- v8::External,
- >::cast(unsafe { fast_api_callback_options.data.data })
- .value() as *const deno_core::_ops::OpCtx)
- };
- let result = Self::call();
- let result = match result {
- Ok(result) => result,
- Err(err) => {
- unsafe {
- opctx.unsafely_set_last_error_for_ops_only(err);
- }
- fast_api_callback_options.fallback = true;
- return ::std::default::Default::default();
- }
- };
- result
- }
- extern "C" fn v8_fn_ptr(info: *const deno_core::v8::FunctionCallbackInfo) {
- let args = deno_core::v8::FunctionCallbackArguments::from_function_callback_info(unsafe {
- &*info
- });
- let opctx = unsafe {
- &*(deno_core::v8::Local::<deno_core::v8::External>::cast(args.data()).value()
- as *const deno_core::_ops::OpCtx)
- };
- if let Some(err) = unsafe { opctx.unsafely_take_last_error_for_ops_only() } {
- let scope = &mut unsafe { deno_core::v8::CallbackScope::new(&*info) };
- let args = deno_core::v8::FunctionCallbackArguments::from_function_callback_info(unsafe {
- &*info
- });
- let opstate = ::std::cell::RefCell::borrow(&*opctx.state);
- let exception = deno_core::error::to_v8_error(
- scope,
- opstate.get_error_class_fn,
- &err,
- );
- scope.throw_exception(exception);
- return;
- }
- let result = Self::call();
- match result {
- Ok(result) => {}
- Err(err) => {
- let scope = &mut unsafe { deno_core::v8::CallbackScope::new(&*info) };
- let args = deno_core::v8::FunctionCallbackArguments::from_function_callback_info(unsafe {
- &*info
- });
- let opstate = ::std::cell::RefCell::borrow(&*opctx.state);
- let exception = deno_core::error::to_v8_error(
- scope,
- opstate.get_error_class_fn,
- &err,
- );
- scope.throw_exception(exception);
- return;
- }
- };
- }
- #[inline(always)]
- pub fn call() -> Result<(), AnyError> {}
-}
diff --git a/ops/op2/test_cases/sync/result_void.rs b/ops/op2/test_cases/sync/result_void.rs
deleted file mode 100644
index ef3aa7b32..000000000
--- a/ops/op2/test_cases/sync/result_void.rs
+++ /dev/null
@@ -1,4 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-
-#[op2(fast)]
-pub fn op_void_with_result() -> Result<(), AnyError> {}
diff --git a/ops/op2/test_cases/sync/smi.out b/ops/op2/test_cases/sync/smi.out
deleted file mode 100644
index 24b81ae47..000000000
--- a/ops/op2/test_cases/sync/smi.out
+++ /dev/null
@@ -1,76 +0,0 @@
-#[allow(non_camel_case_types)]
-struct op_add {
- _unconstructable: ::std::marker::PhantomData<()>,
-}
-impl deno_core::_ops::Op for op_add {
- const NAME: &'static str = stringify!(op_add);
- const DECL: deno_core::_ops::OpDecl = deno_core::_ops::OpDecl {
- name: stringify!(op_add),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: Some({
- use deno_core::v8::fast_api::Type;
- use deno_core::v8::fast_api::CType;
- deno_core::v8::fast_api::FastFunction::new(
- &[Type::V8Value, Type::Int32, Type::Uint32],
- CType::Uint32,
- Self::v8_fn_ptr_fast as *const ::std::ffi::c_void,
- )
- }),
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 2usize as u8,
- };
-}
-impl op_add {
- pub const fn name() -> &'static str {
- stringify!(op_add)
- }
- pub const fn decl() -> deno_core::_ops::OpDecl {
- deno_core::_ops::OpDecl {
- name: stringify!(op_add),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: Some({
- use deno_core::v8::fast_api::Type;
- use deno_core::v8::fast_api::CType;
- deno_core::v8::fast_api::FastFunction::new(
- &[Type::V8Value, Type::Int32, Type::Uint32],
- CType::Uint32,
- Self::v8_fn_ptr_fast as *const ::std::ffi::c_void,
- )
- }),
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 2usize as u8,
- }
- }
- fn v8_fn_ptr_fast(
- _: deno_core::v8::Local<deno_core::v8::Object>,
- arg0: i32,
- arg1: u32,
- ) -> u32 {
- let arg0 = arg0 as _;
- let arg1 = arg1 as _;
- let result = Self::call(arg0, arg1);
- result
- }
- extern "C" fn v8_fn_ptr(info: *const deno_core::v8::FunctionCallbackInfo) {
- let mut rv = deno_core::v8::ReturnValue::from_function_callback_info(unsafe {
- &*info
- });
- let args = deno_core::v8::FunctionCallbackArguments::from_function_callback_info(unsafe {
- &*info
- });
- let arg0 = args.get(0usize as i32);
- let arg0 = deno_core::_ops::to_i32(&arg0) as _;
- let arg1 = args.get(1usize as i32);
- let arg1 = deno_core::_ops::to_u32(&arg1) as _;
- let result = Self::call(arg0, arg1);
- rv.set_uint32(result as u32);
- }
- #[inline(always)]
- fn call(id: ResourceId, extra: u16) -> u32 {}
-}
diff --git a/ops/op2/test_cases/sync/smi.rs b/ops/op2/test_cases/sync/smi.rs
deleted file mode 100644
index a5a441845..000000000
--- a/ops/op2/test_cases/sync/smi.rs
+++ /dev/null
@@ -1,4 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-
-#[op2(fast)]
-fn op_add(#[smi] id: ResourceId, extra: u16) -> u32 {}
diff --git a/ops/op2/test_cases/sync/string_cow.out b/ops/op2/test_cases/sync/string_cow.out
deleted file mode 100644
index 7d388e598..000000000
--- a/ops/op2/test_cases/sync/string_cow.out
+++ /dev/null
@@ -1,75 +0,0 @@
-#[allow(non_camel_case_types)]
-struct op_string_cow {
- _unconstructable: ::std::marker::PhantomData<()>,
-}
-impl deno_core::_ops::Op for op_string_cow {
- const NAME: &'static str = stringify!(op_string_cow);
- const DECL: deno_core::_ops::OpDecl = deno_core::_ops::OpDecl {
- name: stringify!(op_string_cow),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: Some({
- use deno_core::v8::fast_api::Type;
- use deno_core::v8::fast_api::CType;
- deno_core::v8::fast_api::FastFunction::new(
- &[Type::V8Value, Type::SeqOneByteString],
- CType::Uint32,
- Self::v8_fn_ptr_fast as *const ::std::ffi::c_void,
- )
- }),
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 1usize as u8,
- };
-}
-impl op_string_cow {
- pub const fn name() -> &'static str {
- stringify!(op_string_cow)
- }
- pub const fn decl() -> deno_core::_ops::OpDecl {
- deno_core::_ops::OpDecl {
- name: stringify!(op_string_cow),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: Some({
- use deno_core::v8::fast_api::Type;
- use deno_core::v8::fast_api::CType;
- deno_core::v8::fast_api::FastFunction::new(
- &[Type::V8Value, Type::SeqOneByteString],
- CType::Uint32,
- Self::v8_fn_ptr_fast as *const ::std::ffi::c_void,
- )
- }),
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 1usize as u8,
- }
- }
- fn v8_fn_ptr_fast(
- _: deno_core::v8::Local<deno_core::v8::Object>,
- arg0: *mut deno_core::v8::fast_api::FastApiOneByteString,
- ) -> u32 {
- let mut arg0_temp: [::std::mem::MaybeUninit<u8>; 1024] = [::std::mem::MaybeUninit::uninit(); 1024];
- let arg0 = deno_core::_ops::to_str_ptr(unsafe { &mut *arg0 }, &mut arg0_temp);
- let result = Self::call(arg0);
- result
- }
- extern "C" fn v8_fn_ptr(info: *const deno_core::v8::FunctionCallbackInfo) {
- let scope = &mut unsafe { deno_core::v8::CallbackScope::new(&*info) };
- let mut rv = deno_core::v8::ReturnValue::from_function_callback_info(unsafe {
- &*info
- });
- let args = deno_core::v8::FunctionCallbackArguments::from_function_callback_info(unsafe {
- &*info
- });
- let arg0 = args.get(0usize as i32);
- let mut arg0_temp: [::std::mem::MaybeUninit<u8>; 1024] = [::std::mem::MaybeUninit::uninit(); 1024];
- let arg0 = deno_core::_ops::to_str(scope, &arg0, &mut arg0_temp);
- let result = Self::call(arg0);
- rv.set_uint32(result as u32);
- }
- #[inline(always)]
- fn call(s: Cow<str>) -> u32 {}
-}
diff --git a/ops/op2/test_cases/sync/string_cow.rs b/ops/op2/test_cases/sync/string_cow.rs
deleted file mode 100644
index ed4dfca82..000000000
--- a/ops/op2/test_cases/sync/string_cow.rs
+++ /dev/null
@@ -1,4 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-
-#[op2(fast)]
-fn op_string_cow(#[string] s: Cow<str>) -> u32 {}
diff --git a/ops/op2/test_cases/sync/string_option_return.out b/ops/op2/test_cases/sync/string_option_return.out
deleted file mode 100644
index 6143ac217..000000000
--- a/ops/op2/test_cases/sync/string_option_return.out
+++ /dev/null
@@ -1,53 +0,0 @@
-#[allow(non_camel_case_types)]
-pub struct op_string_return {
- _unconstructable: ::std::marker::PhantomData<()>,
-}
-impl deno_core::_ops::Op for op_string_return {
- const NAME: &'static str = stringify!(op_string_return);
- const DECL: deno_core::_ops::OpDecl = deno_core::_ops::OpDecl {
- name: stringify!(op_string_return),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: None,
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 0usize as u8,
- };
-}
-impl op_string_return {
- pub const fn name() -> &'static str {
- stringify!(op_string_return)
- }
- pub const fn decl() -> deno_core::_ops::OpDecl {
- deno_core::_ops::OpDecl {
- name: stringify!(op_string_return),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: None,
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 0usize as u8,
- }
- }
- extern "C" fn v8_fn_ptr(info: *const deno_core::v8::FunctionCallbackInfo) {
- let scope = &mut unsafe { deno_core::v8::CallbackScope::new(&*info) };
- let mut rv = deno_core::v8::ReturnValue::from_function_callback_info(unsafe {
- &*info
- });
- let result = Self::call();
- if let Some(result) = result {
- if result.is_empty() {
- rv.set_empty_string();
- } else {
- let temp = deno_core::v8::String::new(scope, &result).unwrap();
- rv.set(temp.into());
- }
- } else {
- rv.set_null();
- }
- }
- #[inline(always)]
- pub fn call() -> Option<String> {}
-}
diff --git a/ops/op2/test_cases/sync/string_option_return.rs b/ops/op2/test_cases/sync/string_option_return.rs
deleted file mode 100644
index 932836d2f..000000000
--- a/ops/op2/test_cases/sync/string_option_return.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-
-#[op2]
-#[string]
-pub fn op_string_return() -> Option<String> {}
diff --git a/ops/op2/test_cases/sync/string_owned.out b/ops/op2/test_cases/sync/string_owned.out
deleted file mode 100644
index 7418a311c..000000000
--- a/ops/op2/test_cases/sync/string_owned.out
+++ /dev/null
@@ -1,73 +0,0 @@
-#[allow(non_camel_case_types)]
-struct op_string_owned {
- _unconstructable: ::std::marker::PhantomData<()>,
-}
-impl deno_core::_ops::Op for op_string_owned {
- const NAME: &'static str = stringify!(op_string_owned);
- const DECL: deno_core::_ops::OpDecl = deno_core::_ops::OpDecl {
- name: stringify!(op_string_owned),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: Some({
- use deno_core::v8::fast_api::Type;
- use deno_core::v8::fast_api::CType;
- deno_core::v8::fast_api::FastFunction::new(
- &[Type::V8Value, Type::SeqOneByteString],
- CType::Uint32,
- Self::v8_fn_ptr_fast as *const ::std::ffi::c_void,
- )
- }),
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 1usize as u8,
- };
-}
-impl op_string_owned {
- pub const fn name() -> &'static str {
- stringify!(op_string_owned)
- }
- pub const fn decl() -> deno_core::_ops::OpDecl {
- deno_core::_ops::OpDecl {
- name: stringify!(op_string_owned),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: Some({
- use deno_core::v8::fast_api::Type;
- use deno_core::v8::fast_api::CType;
- deno_core::v8::fast_api::FastFunction::new(
- &[Type::V8Value, Type::SeqOneByteString],
- CType::Uint32,
- Self::v8_fn_ptr_fast as *const ::std::ffi::c_void,
- )
- }),
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 1usize as u8,
- }
- }
- fn v8_fn_ptr_fast(
- _: deno_core::v8::Local<deno_core::v8::Object>,
- arg0: *mut deno_core::v8::fast_api::FastApiOneByteString,
- ) -> u32 {
- let arg0 = deno_core::_ops::to_string_ptr(unsafe { &mut *arg0 });
- let result = Self::call(arg0);
- result
- }
- extern "C" fn v8_fn_ptr(info: *const deno_core::v8::FunctionCallbackInfo) {
- let scope = &mut unsafe { deno_core::v8::CallbackScope::new(&*info) };
- let mut rv = deno_core::v8::ReturnValue::from_function_callback_info(unsafe {
- &*info
- });
- let args = deno_core::v8::FunctionCallbackArguments::from_function_callback_info(unsafe {
- &*info
- });
- let arg0 = args.get(0usize as i32);
- let arg0 = arg0.to_rust_string_lossy(scope);
- let result = Self::call(arg0);
- rv.set_uint32(result as u32);
- }
- #[inline(always)]
- fn call(s: String) -> u32 {}
-}
diff --git a/ops/op2/test_cases/sync/string_owned.rs b/ops/op2/test_cases/sync/string_owned.rs
deleted file mode 100644
index b81d7ece9..000000000
--- a/ops/op2/test_cases/sync/string_owned.rs
+++ /dev/null
@@ -1,4 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-
-#[op2(fast)]
-fn op_string_owned(#[string] s: String) -> u32 {}
diff --git a/ops/op2/test_cases/sync/string_ref.out b/ops/op2/test_cases/sync/string_ref.out
deleted file mode 100644
index 1b853fccc..000000000
--- a/ops/op2/test_cases/sync/string_ref.out
+++ /dev/null
@@ -1,75 +0,0 @@
-#[allow(non_camel_case_types)]
-struct op_string_owned {
- _unconstructable: ::std::marker::PhantomData<()>,
-}
-impl deno_core::_ops::Op for op_string_owned {
- const NAME: &'static str = stringify!(op_string_owned);
- const DECL: deno_core::_ops::OpDecl = deno_core::_ops::OpDecl {
- name: stringify!(op_string_owned),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: Some({
- use deno_core::v8::fast_api::Type;
- use deno_core::v8::fast_api::CType;
- deno_core::v8::fast_api::FastFunction::new(
- &[Type::V8Value, Type::SeqOneByteString],
- CType::Uint32,
- Self::v8_fn_ptr_fast as *const ::std::ffi::c_void,
- )
- }),
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 1usize as u8,
- };
-}
-impl op_string_owned {
- pub const fn name() -> &'static str {
- stringify!(op_string_owned)
- }
- pub const fn decl() -> deno_core::_ops::OpDecl {
- deno_core::_ops::OpDecl {
- name: stringify!(op_string_owned),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: Some({
- use deno_core::v8::fast_api::Type;
- use deno_core::v8::fast_api::CType;
- deno_core::v8::fast_api::FastFunction::new(
- &[Type::V8Value, Type::SeqOneByteString],
- CType::Uint32,
- Self::v8_fn_ptr_fast as *const ::std::ffi::c_void,
- )
- }),
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 1usize as u8,
- }
- }
- fn v8_fn_ptr_fast(
- _: deno_core::v8::Local<deno_core::v8::Object>,
- arg0: *mut deno_core::v8::fast_api::FastApiOneByteString,
- ) -> u32 {
- let mut arg0_temp: [::std::mem::MaybeUninit<u8>; 1024] = [::std::mem::MaybeUninit::uninit(); 1024];
- let arg0 = &deno_core::_ops::to_str_ptr(unsafe { &mut *arg0 }, &mut arg0_temp);
- let result = Self::call(arg0);
- result
- }
- extern "C" fn v8_fn_ptr(info: *const deno_core::v8::FunctionCallbackInfo) {
- let scope = &mut unsafe { deno_core::v8::CallbackScope::new(&*info) };
- let mut rv = deno_core::v8::ReturnValue::from_function_callback_info(unsafe {
- &*info
- });
- let args = deno_core::v8::FunctionCallbackArguments::from_function_callback_info(unsafe {
- &*info
- });
- let arg0 = args.get(0usize as i32);
- let mut arg0_temp: [::std::mem::MaybeUninit<u8>; 1024] = [::std::mem::MaybeUninit::uninit(); 1024];
- let arg0 = &deno_core::_ops::to_str(scope, &arg0, &mut arg0_temp);
- let result = Self::call(arg0);
- rv.set_uint32(result as u32);
- }
- #[inline(always)]
- fn call(s: &str) -> u32 {}
-}
diff --git a/ops/op2/test_cases/sync/string_ref.rs b/ops/op2/test_cases/sync/string_ref.rs
deleted file mode 100644
index a7efa9f0c..000000000
--- a/ops/op2/test_cases/sync/string_ref.rs
+++ /dev/null
@@ -1,4 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-
-#[op2(fast)]
-fn op_string_owned(#[string] s: &str) -> u32 {}
diff --git a/ops/op2/test_cases/sync/string_return.out b/ops/op2/test_cases/sync/string_return.out
deleted file mode 100644
index 5e68b9314..000000000
--- a/ops/op2/test_cases/sync/string_return.out
+++ /dev/null
@@ -1,49 +0,0 @@
-#[allow(non_camel_case_types)]
-pub struct op_string_return {
- _unconstructable: ::std::marker::PhantomData<()>,
-}
-impl deno_core::_ops::Op for op_string_return {
- const NAME: &'static str = stringify!(op_string_return);
- const DECL: deno_core::_ops::OpDecl = deno_core::_ops::OpDecl {
- name: stringify!(op_string_return),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: None,
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 0usize as u8,
- };
-}
-impl op_string_return {
- pub const fn name() -> &'static str {
- stringify!(op_string_return)
- }
- pub const fn decl() -> deno_core::_ops::OpDecl {
- deno_core::_ops::OpDecl {
- name: stringify!(op_string_return),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: None,
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 0usize as u8,
- }
- }
- extern "C" fn v8_fn_ptr(info: *const deno_core::v8::FunctionCallbackInfo) {
- let scope = &mut unsafe { deno_core::v8::CallbackScope::new(&*info) };
- let mut rv = deno_core::v8::ReturnValue::from_function_callback_info(unsafe {
- &*info
- });
- let result = Self::call();
- if result.is_empty() {
- rv.set_empty_string();
- } else {
- let temp = deno_core::v8::String::new(scope, &result).unwrap();
- rv.set(temp.into());
- }
- }
- #[inline(always)]
- pub fn call() -> String {}
-}
diff --git a/ops/op2/test_cases/sync/string_return.rs b/ops/op2/test_cases/sync/string_return.rs
deleted file mode 100644
index 667b68a14..000000000
--- a/ops/op2/test_cases/sync/string_return.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-
-#[op2]
-#[string]
-pub fn op_string_return() -> String {}
diff --git a/ops/optimizer.rs b/ops/optimizer.rs
deleted file mode 100644
index 28911162f..000000000
--- a/ops/optimizer.rs
+++ /dev/null
@@ -1,1004 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-//! Optimizer for #[op]
-
-use std::collections::BTreeMap;
-use std::fmt::Debug;
-use std::fmt::Formatter;
-
-use pmutil::q;
-use pmutil::Quote;
-use proc_macro2::TokenStream;
-
-use syn::parse_quote;
-use syn::punctuated::Punctuated;
-use syn::token::Colon2;
-use syn::AngleBracketedGenericArguments;
-use syn::FnArg;
-use syn::GenericArgument;
-use syn::PatType;
-use syn::Path;
-use syn::PathArguments;
-use syn::PathSegment;
-use syn::ReturnType;
-use syn::Signature;
-use syn::Type;
-use syn::TypePath;
-use syn::TypePtr;
-use syn::TypeReference;
-use syn::TypeSlice;
-use syn::TypeTuple;
-
-use crate::Op;
-
-#[derive(Debug)]
-pub(crate) enum BailoutReason {
- // Recoverable errors
- MustBeSingleSegment,
- FastUnsupportedParamType,
-}
-
-#[derive(Debug, PartialEq)]
-enum StringType {
- Cow,
- Ref,
- Owned,
-}
-
-#[derive(Debug, PartialEq)]
-enum TransformKind {
- // serde_v8::Value
- V8Value,
- SliceU32(bool),
- SliceU8(bool),
- SliceF64(bool),
- SeqOneByteString(StringType),
- PtrU8,
- PtrVoid,
- WasmMemory,
-}
-
-impl Transform {
- fn serde_v8_value(index: usize) -> Self {
- Transform {
- kind: TransformKind::V8Value,
- index,
- }
- }
-
- fn slice_u32(index: usize, is_mut: bool) -> Self {
- Transform {
- kind: TransformKind::SliceU32(is_mut),
- index,
- }
- }
-
- fn slice_u8(index: usize, is_mut: bool) -> Self {
- Transform {
- kind: TransformKind::SliceU8(is_mut),
- index,
- }
- }
-
- fn slice_f64(index: usize, is_mut: bool) -> Self {
- Transform {
- kind: TransformKind::SliceF64(is_mut),
- index,
- }
- }
-
- fn seq_one_byte_string(index: usize, is_ref: StringType) -> Self {
- Transform {
- kind: TransformKind::SeqOneByteString(is_ref),
- index,
- }
- }
-
- fn wasm_memory(index: usize) -> Self {
- Transform {
- kind: TransformKind::WasmMemory,
- index,
- }
- }
-
- fn u8_ptr(index: usize) -> Self {
- Transform {
- kind: TransformKind::PtrU8,
- index,
- }
- }
-
- fn void_ptr(index: usize) -> Self {
- Transform {
- kind: TransformKind::PtrVoid,
- index,
- }
- }
-}
-
-#[derive(Debug, PartialEq)]
-pub(crate) struct Transform {
- kind: TransformKind,
- index: usize,
-}
-
-impl Transform {
- pub(crate) fn apply_for_fast_call(
- &self,
- core: &TokenStream,
- input: &mut FnArg,
- ) -> Quote {
- let (ty, ident) = match input {
- FnArg::Typed(PatType {
- ref mut ty,
- ref pat,
- ..
- }) => {
- let ident = match &**pat {
- syn::Pat::Ident(ident) => &ident.ident,
- _ => unreachable!("error not recovered"),
- };
- (ty, ident)
- }
- _ => unreachable!("error not recovered"),
- };
-
- match &self.kind {
- // serde_v8::Value
- TransformKind::V8Value => {
- *ty = parse_quote! { #core::v8::Local<#core::v8::Value> };
-
- q!(Vars { var: &ident }, {
- let var = serde_v8::Value { v8_value: var };
- })
- }
- // &[u32]
- TransformKind::SliceU32(_) => {
- *ty =
- parse_quote! { *const #core::v8::fast_api::FastApiTypedArray<u32> };
-
- q!(Vars { var: &ident }, {
- // V8 guarantees that ArrayBuffers are always 4-byte aligned
- // (seems to be always 8-byte aligned on 64-bit machines)
- // but Deno FFI makes it possible to create ArrayBuffers at any
- // alignment. Thus this check is needed.
- let var = match unsafe { &*var }.get_storage_if_aligned() {
- Some(v) => v,
- None => {
- unsafe { &mut *fast_api_callback_options }.fallback = true;
- return Default::default();
- }
- };
- })
- }
- // &[u8]
- TransformKind::SliceU8(_) => {
- *ty =
- parse_quote! { *const #core::v8::fast_api::FastApiTypedArray<u8> };
-
- q!(Vars { var: &ident }, {
- // SAFETY: U8 slice is always byte-aligned.
- let var =
- unsafe { (&*var).get_storage_if_aligned().unwrap_unchecked() };
- })
- }
- TransformKind::SliceF64(_) => {
- *ty =
- parse_quote! { *const #core::v8::fast_api::FastApiTypedArray<f64> };
-
- q!(Vars { var: &ident }, {
- let var = match unsafe { &*var }.get_storage_if_aligned() {
- Some(v) => v,
- None => {
- unsafe { &mut *fast_api_callback_options }.fallback = true;
- return Default::default();
- }
- };
- })
- }
- // &str
- TransformKind::SeqOneByteString(str_ty) => {
- *ty = parse_quote! { *const #core::v8::fast_api::FastApiOneByteString };
- match str_ty {
- StringType::Ref => q!(Vars { var: &ident }, {
- let var = match ::std::str::from_utf8(unsafe { &*var }.as_bytes()) {
- Ok(v) => v,
- Err(_) => {
- unsafe { &mut *fast_api_callback_options }.fallback = true;
- return Default::default();
- }
- };
- }),
- StringType::Cow => q!(Vars { var: &ident }, {
- let var = ::std::borrow::Cow::Borrowed(
- match ::std::str::from_utf8(unsafe { &*var }.as_bytes()) {
- Ok(v) => v,
- Err(_) => {
- unsafe { &mut *fast_api_callback_options }.fallback = true;
- return Default::default();
- }
- },
- );
- }),
- StringType::Owned => q!(Vars { var: &ident }, {
- let var = match ::std::str::from_utf8(unsafe { &*var }.as_bytes()) {
- Ok(v) => v.to_owned(),
- Err(_) => {
- unsafe { &mut *fast_api_callback_options }.fallback = true;
- return Default::default();
- }
- };
- }),
- }
- }
- TransformKind::WasmMemory => {
- // Note: `ty` is correctly set to __opts by the fast call tier.
- // U8 slice is always byte-aligned.
- q!(Vars { var: &ident, core }, {
- let var = unsafe {
- &*(__opts.wasm_memory
- as *const core::v8::fast_api::FastApiTypedArray<u8>)
- }
- .get_storage_if_aligned();
- })
- }
- // *const u8
- TransformKind::PtrU8 => {
- *ty =
- parse_quote! { *const #core::v8::fast_api::FastApiTypedArray<u8> };
-
- q!(Vars { var: &ident }, {
- // SAFETY: U8 slice is always byte-aligned.
- let var =
- unsafe { (&*var).get_storage_if_aligned().unwrap_unchecked() }
- .as_ptr();
- })
- }
- TransformKind::PtrVoid => {
- *ty = parse_quote! { *mut ::std::ffi::c_void };
-
- q!(Vars {}, {})
- }
- }
- }
-}
-
-fn get_fast_scalar(s: &str) -> Option<FastValue> {
- match s {
- "bool" => Some(FastValue::Bool),
- "u32" => Some(FastValue::U32),
- "i32" => Some(FastValue::I32),
- "u64" | "usize" => Some(FastValue::U64),
- "i64" | "isize" => Some(FastValue::I64),
- "f32" => Some(FastValue::F32),
- "f64" => Some(FastValue::F64),
- "* const c_void" | "* mut c_void" => Some(FastValue::Pointer),
- "ResourceId" => Some(FastValue::U32),
- _ => None,
- }
-}
-
-fn can_return_fast(v: &FastValue) -> bool {
- !matches!(
- v,
- FastValue::U64
- | FastValue::I64
- | FastValue::Uint8Array
- | FastValue::Uint32Array
- )
-}
-
-#[derive(Debug, PartialEq, Clone)]
-pub(crate) enum FastValue {
- Void,
- Bool,
- U32,
- I32,
- U64,
- I64,
- F32,
- F64,
- Pointer,
- V8Value,
- Uint8Array,
- Uint32Array,
- Float64Array,
- SeqOneByteString,
-}
-
-impl FastValue {
- pub fn default_value(&self) -> Quote {
- match self {
- FastValue::Pointer => q!({ ::std::ptr::null_mut() }),
- FastValue::Void => q!({}),
- _ => q!({ Default::default() }),
- }
- }
-}
-
-impl Default for FastValue {
- fn default() -> Self {
- Self::Void
- }
-}
-
-#[derive(Default, PartialEq)]
-pub(crate) struct Optimizer {
- pub(crate) returns_result: bool,
-
- pub(crate) has_ref_opstate: bool,
-
- pub(crate) has_rc_opstate: bool,
-
- // Do we need an explicit FastApiCallbackOptions argument?
- pub(crate) has_fast_callback_option: bool,
- // Do we depend on FastApiCallbackOptions?
- pub(crate) needs_fast_callback_option: bool,
-
- pub(crate) has_wasm_memory: bool,
-
- pub(crate) fast_result: Option<FastValue>,
- pub(crate) fast_parameters: Vec<FastValue>,
-
- pub(crate) transforms: BTreeMap<usize, Transform>,
- pub(crate) fast_compatible: bool,
-
- pub(crate) is_async: bool,
-}
-
-impl Debug for Optimizer {
- fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
- writeln!(f, "=== Optimizer Dump ===")?;
- writeln!(f, "returns_result: {}", self.returns_result)?;
- writeln!(f, "has_ref_opstate: {}", self.has_ref_opstate)?;
- writeln!(f, "has_rc_opstate: {}", self.has_rc_opstate)?;
- writeln!(
- f,
- "has_fast_callback_option: {}",
- self.has_fast_callback_option
- )?;
- writeln!(
- f,
- "needs_fast_callback_option: {}",
- self.needs_fast_callback_option
- )?;
- writeln!(f, "fast_result: {:?}", self.fast_result)?;
- writeln!(f, "fast_parameters: {:?}", self.fast_parameters)?;
- writeln!(f, "transforms: {:?}", self.transforms)?;
- writeln!(f, "is_async: {}", self.is_async)?;
- writeln!(f, "fast_compatible: {}", self.fast_compatible)?;
- Ok(())
- }
-}
-
-impl Optimizer {
- pub(crate) fn new() -> Self {
- Default::default()
- }
-
- pub(crate) const fn has_opstate_in_parameters(&self) -> bool {
- self.has_ref_opstate || self.has_rc_opstate
- }
-
- pub(crate) const fn needs_opstate(&self) -> bool {
- self.has_ref_opstate || self.has_rc_opstate || self.returns_result
- }
-
- pub(crate) fn analyze(&mut self, op: &mut Op) -> Result<(), BailoutReason> {
- // Fast async ops are opt-in as they have a lazy polling behavior.
- if op.is_async && !op.attrs.must_be_fast {
- self.fast_compatible = false;
- return Ok(());
- }
-
- if op.attrs.is_v8 {
- self.fast_compatible = false;
- return Ok(());
- }
-
- self.is_async = op.is_async;
- self.fast_compatible = true;
- // Just assume for now. We will validate later.
- self.has_wasm_memory = op.attrs.is_wasm;
-
- let sig = &op.item.sig;
-
- // Analyze return type
- match &sig {
- Signature {
- output: ReturnType::Default,
- ..
- } => self.fast_result = Some(FastValue::default()),
- Signature {
- output: ReturnType::Type(_, ty),
- ..
- } if !self.is_async => self.analyze_return_type(ty)?,
-
- // No need to error on the return type for async ops, its OK if
- // it's not a fast value.
- Signature {
- output: ReturnType::Type(_, ty),
- ..
- } => {
- let _ = self.analyze_return_type(ty);
- // Recover.
- self.fast_result = None;
- self.fast_compatible = true;
- }
- };
-
- // The receiver, which we don't actually care about.
- self.fast_parameters.push(FastValue::V8Value);
-
- if self.is_async {
- // The promise ID.
- self.fast_parameters.push(FastValue::I32);
- }
-
- // Analyze parameters
- for (index, param) in sig.inputs.iter().enumerate() {
- self.analyze_param_type(index, param)?;
- }
-
- // TODO(@littledivy): https://github.com/denoland/deno/issues/17159
- if self.returns_result
- && self.fast_parameters.contains(&FastValue::SeqOneByteString)
- {
- self.fast_compatible = false;
- }
-
- Ok(())
- }
-
- fn analyze_return_type(&mut self, ty: &Type) -> Result<(), BailoutReason> {
- match ty {
- Type::Tuple(TypeTuple { elems, .. }) if elems.is_empty() => {
- self.fast_result = Some(FastValue::Void);
- }
- Type::Path(TypePath {
- path: Path { segments, .. },
- ..
- }) => {
- let segment = single_segment(segments)?;
-
- match segment {
- // Result<T, E>
- PathSegment {
- ident, arguments, ..
- } if ident == "Result" => {
- self.returns_result = true;
-
- if let PathArguments::AngleBracketed(
- AngleBracketedGenericArguments { args, .. },
- ) = arguments
- {
- match args.first() {
- Some(GenericArgument::Type(Type::Path(TypePath {
- path: Path { segments, .. },
- ..
- }))) => {
- let PathSegment { ident, .. } = single_segment(segments)?;
- // Is `T` a scalar FastValue?
- if let Some(val) = get_fast_scalar(ident.to_string().as_str())
- {
- if can_return_fast(&val) {
- self.fast_result = Some(val);
- return Ok(());
- }
- }
-
- self.fast_compatible = false;
- return Err(BailoutReason::FastUnsupportedParamType);
- }
- Some(GenericArgument::Type(Type::Tuple(TypeTuple {
- elems,
- ..
- })))
- if elems.is_empty() =>
- {
- self.fast_result = Some(FastValue::Void);
- }
- Some(GenericArgument::Type(Type::Ptr(TypePtr {
- mutability: Some(_),
- elem,
- ..
- }))) => {
- match &**elem {
- Type::Path(TypePath {
- path: Path { segments, .. },
- ..
- }) => {
- // Is `T` a c_void?
- let segment = single_segment(segments)?;
- match segment {
- PathSegment { ident, .. } if ident == "c_void" => {
- self.fast_result = Some(FastValue::Pointer);
- return Ok(());
- }
- _ => {
- return Err(BailoutReason::FastUnsupportedParamType)
- }
- }
- }
- _ => return Err(BailoutReason::FastUnsupportedParamType),
- }
- }
- _ => return Err(BailoutReason::FastUnsupportedParamType),
- }
- }
- }
- // Is `T` a scalar FastValue?
- PathSegment { ident, .. } => {
- if let Some(val) = get_fast_scalar(ident.to_string().as_str()) {
- self.fast_result = Some(val);
- return Ok(());
- }
-
- self.fast_compatible = false;
- return Err(BailoutReason::FastUnsupportedParamType);
- }
- };
- }
- Type::Ptr(TypePtr {
- mutability: Some(_),
- elem,
- ..
- }) => {
- match &**elem {
- Type::Path(TypePath {
- path: Path { segments, .. },
- ..
- }) => {
- // Is `T` a c_void?
- let segment = single_segment(segments)?;
- match segment {
- PathSegment { ident, .. } if ident == "c_void" => {
- self.fast_result = Some(FastValue::Pointer);
- return Ok(());
- }
- _ => return Err(BailoutReason::FastUnsupportedParamType),
- }
- }
- _ => return Err(BailoutReason::FastUnsupportedParamType),
- }
- }
- _ => return Err(BailoutReason::FastUnsupportedParamType),
- };
-
- Ok(())
- }
-
- fn analyze_param_type(
- &mut self,
- index: usize,
- arg: &FnArg,
- ) -> Result<(), BailoutReason> {
- match arg {
- FnArg::Typed(typed) => match &*typed.ty {
- Type::Path(TypePath {
- path: Path { segments, .. },
- ..
- }) if segments.len() == 2 => {
- match double_segment(segments)? {
- // -> serde_v8::Value
- [PathSegment { ident: first, .. }, PathSegment { ident: last, .. }]
- if first == "serde_v8" && last == "Value" =>
- {
- self.fast_parameters.push(FastValue::V8Value);
- assert!(self
- .transforms
- .insert(index, Transform::serde_v8_value(index))
- .is_none());
- }
- _ => return Err(BailoutReason::FastUnsupportedParamType),
- }
- }
- Type::Path(TypePath {
- path: Path { segments, .. },
- ..
- }) => {
- let segment = single_segment(segments)?;
-
- match segment {
- // -> Option<T>
- PathSegment {
- ident, arguments, ..
- } if ident == "Option" => {
- if let PathArguments::AngleBracketed(
- AngleBracketedGenericArguments { args, .. },
- ) = arguments
- {
- // -> Option<&mut T>
- if let Some(GenericArgument::Type(Type::Reference(
- TypeReference { elem, .. },
- ))) = args.last()
- {
- if self.has_wasm_memory {
- // -> Option<&mut [u8]>
- if let Type::Slice(TypeSlice { elem, .. }) = &**elem {
- if let Type::Path(TypePath {
- path: Path { segments, .. },
- ..
- }) = &**elem
- {
- let segment = single_segment(segments)?;
-
- match segment {
- // Is `T` a u8?
- PathSegment { ident, .. } if ident == "u8" => {
- assert!(self
- .transforms
- .insert(index, Transform::wasm_memory(index))
- .is_none());
- }
- _ => {
- return Err(BailoutReason::FastUnsupportedParamType)
- }
- }
- }
- }
- } else if let Type::Path(TypePath {
- path: Path { segments, .. },
- ..
- }) = &**elem
- {
- let segment = single_segment(segments)?;
- match segment {
- // Is `T` a FastApiCallbackOptions?
- PathSegment { ident, .. }
- if ident == "FastApiCallbackOptions" =>
- {
- self.has_fast_callback_option = true;
- }
- _ => return Err(BailoutReason::FastUnsupportedParamType),
- }
- } else {
- return Err(BailoutReason::FastUnsupportedParamType);
- }
- } else {
- return Err(BailoutReason::FastUnsupportedParamType);
- }
- }
- }
- // -> Rc<T>
- PathSegment {
- ident, arguments, ..
- } if ident == "Rc" => {
- if let PathArguments::AngleBracketed(
- AngleBracketedGenericArguments { args, .. },
- ) = arguments
- {
- match args.last() {
- Some(GenericArgument::Type(Type::Path(TypePath {
- path: Path { segments, .. },
- ..
- }))) => {
- let segment = single_segment(segments)?;
- match segment {
- // -> Rc<RefCell<T>>
- PathSegment {
- ident, arguments, ..
- } if ident == "RefCell" => {
- if let PathArguments::AngleBracketed(
- AngleBracketedGenericArguments { args, .. },
- ) = arguments
- {
- match args.last() {
- // -> Rc<RefCell<OpState>>
- Some(GenericArgument::Type(Type::Path(
- TypePath {
- path: Path { segments, .. },
- ..
- },
- ))) => {
- let segment = single_segment(segments)?;
- match segment {
- PathSegment { ident, .. }
- if ident == "OpState" =>
- {
- self.has_rc_opstate = true;
- }
- _ => {
- return Err(
- BailoutReason::FastUnsupportedParamType,
- )
- }
- }
- }
- _ => {
- return Err(
- BailoutReason::FastUnsupportedParamType,
- )
- }
- }
- }
- }
- _ => return Err(BailoutReason::FastUnsupportedParamType),
- }
- }
- _ => return Err(BailoutReason::FastUnsupportedParamType),
- }
- }
- }
- // Cow<'_, str>
- PathSegment {
- ident, arguments, ..
- } if ident == "Cow" => {
- if let PathArguments::AngleBracketed(
- AngleBracketedGenericArguments { args, .. },
- ) = arguments
- {
- assert_eq!(args.len(), 2);
-
- let ty = &args[1];
- match ty {
- GenericArgument::Type(Type::Path(TypePath {
- path: Path { segments, .. },
- ..
- })) => {
- let segment = single_segment(segments)?;
- match segment {
- PathSegment { ident, .. } if ident == "str" => {
- self.needs_fast_callback_option = true;
- self.fast_parameters.push(FastValue::SeqOneByteString);
- assert!(self
- .transforms
- .insert(
- index,
- Transform::seq_one_byte_string(
- index,
- StringType::Cow
- )
- )
- .is_none());
- }
- _ => return Err(BailoutReason::FastUnsupportedParamType),
- }
- }
- _ => return Err(BailoutReason::FastUnsupportedParamType),
- }
- }
- }
- // Is `T` a fast scalar?
- PathSegment { ident, .. } => {
- if let Some(val) = get_fast_scalar(ident.to_string().as_str()) {
- self.fast_parameters.push(val);
- } else if ident == "String" {
- self.needs_fast_callback_option = true;
- // Is `T` an owned String?
- self.fast_parameters.push(FastValue::SeqOneByteString);
- assert!(self
- .transforms
- .insert(
- index,
- Transform::seq_one_byte_string(index, StringType::Owned)
- )
- .is_none());
- } else {
- return Err(BailoutReason::FastUnsupportedParamType);
- }
- }
- };
- }
- // &mut T
- Type::Reference(TypeReference {
- elem, mutability, ..
- }) => match &**elem {
- Type::Path(TypePath {
- path: Path { segments, .. },
- ..
- }) => {
- let segment = single_segment(segments)?;
- match segment {
- // Is `T` a OpState?
- PathSegment { ident, .. }
- if ident == "OpState" && !self.is_async =>
- {
- self.has_ref_opstate = true;
- }
- // Is `T` a str?
- PathSegment { ident, .. } if ident == "str" => {
- self.needs_fast_callback_option = true;
- self.fast_parameters.push(FastValue::SeqOneByteString);
- assert!(self
- .transforms
- .insert(
- index,
- Transform::seq_one_byte_string(index, StringType::Ref)
- )
- .is_none());
- }
- _ => return Err(BailoutReason::FastUnsupportedParamType),
- }
- }
- // &mut [T]
- Type::Slice(TypeSlice { elem, .. }) => match &**elem {
- Type::Path(TypePath {
- path: Path { segments, .. },
- ..
- }) => {
- let segment = single_segment(segments)?;
- let is_mut_ref = mutability.is_some();
- match segment {
- // Is `T` a u8?
- PathSegment { ident, .. } if ident == "u8" => {
- self.fast_parameters.push(FastValue::Uint8Array);
- assert!(self
- .transforms
- .insert(index, Transform::slice_u8(index, is_mut_ref))
- .is_none());
- }
- // Is `T` a u32?
- PathSegment { ident, .. } if ident == "u32" => {
- self.needs_fast_callback_option = true;
- self.fast_parameters.push(FastValue::Uint32Array);
- assert!(self
- .transforms
- .insert(index, Transform::slice_u32(index, is_mut_ref))
- .is_none());
- }
- // Is `T` a f64?
- PathSegment { ident, .. } if ident == "f64" => {
- self.needs_fast_callback_option = true;
- self.fast_parameters.push(FastValue::Float64Array);
- assert!(self
- .transforms
- .insert(index, Transform::slice_f64(index, is_mut_ref))
- .is_none());
- }
- _ => return Err(BailoutReason::FastUnsupportedParamType),
- }
- }
- _ => return Err(BailoutReason::FastUnsupportedParamType),
- },
- _ => return Err(BailoutReason::FastUnsupportedParamType),
- },
- // *const T
- Type::Ptr(TypePtr {
- elem,
- const_token: Some(_),
- ..
- }) => match &**elem {
- Type::Path(TypePath {
- path: Path { segments, .. },
- ..
- }) => {
- let segment = single_segment(segments)?;
- match segment {
- // Is `T` a u8?
- PathSegment { ident, .. } if ident == "u8" => {
- self.fast_parameters.push(FastValue::Uint8Array);
- assert!(self
- .transforms
- .insert(index, Transform::u8_ptr(index))
- .is_none());
- }
- _ => return Err(BailoutReason::FastUnsupportedParamType),
- }
- }
- _ => return Err(BailoutReason::FastUnsupportedParamType),
- },
- // *const T
- Type::Ptr(TypePtr {
- elem,
- mutability: Some(_),
- ..
- }) => match &**elem {
- Type::Path(TypePath {
- path: Path { segments, .. },
- ..
- }) => {
- let segment = single_segment(segments)?;
- match segment {
- // Is `T` a c_void?
- PathSegment { ident, .. } if ident == "c_void" => {
- self.fast_parameters.push(FastValue::Pointer);
- assert!(self
- .transforms
- .insert(index, Transform::void_ptr(index))
- .is_none());
- }
- _ => return Err(BailoutReason::FastUnsupportedParamType),
- }
- }
- _ => return Err(BailoutReason::FastUnsupportedParamType),
- },
- _ => return Err(BailoutReason::FastUnsupportedParamType),
- },
- _ => return Err(BailoutReason::FastUnsupportedParamType),
- };
- Ok(())
- }
-}
-
-fn single_segment(
- segments: &Punctuated<PathSegment, Colon2>,
-) -> Result<&PathSegment, BailoutReason> {
- if segments.len() != 1 {
- return Err(BailoutReason::MustBeSingleSegment);
- }
-
- match segments.last() {
- Some(segment) => Ok(segment),
- None => Err(BailoutReason::MustBeSingleSegment),
- }
-}
-
-fn double_segment(
- segments: &Punctuated<PathSegment, Colon2>,
-) -> Result<[&PathSegment; 2], BailoutReason> {
- match (segments.first(), segments.last()) {
- (Some(first), Some(last)) => Ok([first, last]),
- // Caller ensures that there are only two segments.
- _ => unreachable!(),
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
- use crate::Attributes;
- use crate::Op;
- use pretty_assertions::assert_eq;
- use std::path::PathBuf;
- use syn::parse_quote;
-
- #[test]
- fn test_single_segment() {
- let segments = parse_quote!(foo);
- assert!(single_segment(&segments).is_ok());
-
- let segments = parse_quote!(foo::bar);
- assert!(single_segment(&segments).is_err());
- }
-
- #[test]
- fn test_double_segment() {
- let segments = parse_quote!(foo::bar);
- assert!(double_segment(&segments).is_ok());
- assert_eq!(double_segment(&segments).unwrap()[0].ident, "foo");
- assert_eq!(double_segment(&segments).unwrap()[1].ident, "bar");
- }
-
- #[testing_macros::fixture("optimizer_tests/**/*.rs")]
- fn test_analyzer(input: PathBuf) {
- let update_expected = std::env::var("UPDATE_EXPECTED").is_ok();
-
- let source =
- std::fs::read_to_string(&input).expect("Failed to read test file");
- let expected = std::fs::read_to_string(input.with_extension("expected"))
- .expect("Failed to read expected file");
-
- let mut attrs = Attributes::default();
- if source.contains("// @test-attr:wasm") {
- attrs.must_be_fast = true;
- attrs.is_wasm = true;
- }
- if source.contains("// @test-attr:fast") {
- attrs.must_be_fast = true;
- }
-
- let item = syn::parse_str(&source).expect("Failed to parse test file");
- let mut op = Op::new(item, attrs);
- let mut optimizer = Optimizer::new();
- if let Err(e) = optimizer.analyze(&mut op) {
- let e_str = format!("{e:?}");
- if update_expected {
- std::fs::write(input.with_extension("expected"), e_str)
- .expect("Failed to write expected file");
- } else {
- assert_eq!(e_str, expected);
- }
- return;
- }
-
- if update_expected {
- std::fs::write(
- input.with_extension("expected"),
- format!("{optimizer:#?}"),
- )
- .expect("Failed to write expected file");
- } else {
- assert_eq!(format!("{optimizer:#?}"), expected);
- }
- }
-}
diff --git a/ops/optimizer_tests/async_nop.expected b/ops/optimizer_tests/async_nop.expected
deleted file mode 100644
index 42a1180bd..000000000
--- a/ops/optimizer_tests/async_nop.expected
+++ /dev/null
@@ -1,11 +0,0 @@
-=== Optimizer Dump ===
-returns_result: false
-has_ref_opstate: false
-has_rc_opstate: false
-has_fast_callback_option: false
-needs_fast_callback_option: false
-fast_result: Some(Void)
-fast_parameters: [V8Value, I32]
-transforms: {}
-is_async: true
-fast_compatible: true
diff --git a/ops/optimizer_tests/async_nop.out b/ops/optimizer_tests/async_nop.out
deleted file mode 100644
index 85c55f2f4..000000000
--- a/ops/optimizer_tests/async_nop.out
+++ /dev/null
@@ -1,137 +0,0 @@
-#[allow(non_camel_case_types)]
-///Auto-generated by `deno_ops`, i.e: `#[op]`
-///
-///Use `op_void_async::decl()` to get an op-declaration
-///you can include in a `deno_core::Extension`.
-pub struct op_void_async {
- _phantom_data: ::std::marker::PhantomData<()>,
-}
-impl deno_core::_ops::Op for op_void_async {
- const NAME: &'static str = stringify!(op_void_async);
- const DECL: deno_core::OpDecl = deno_core::OpDecl {
- name: Self::name(),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: {
- use deno_core::v8::fast_api::CType;
- use deno_core::v8::fast_api::Type::*;
- Some(
- deno_core::v8::fast_api::FastFunction::new(
- &[V8Value, Int32, CallbackOptions],
- CType::Void,
- Self::op_void_async_fast_fn as *const ::std::ffi::c_void,
- ),
- )
- },
- is_async: true,
- is_unstable: false,
- is_v8: false,
- arg_count: 0,
- };
-}
-#[doc(hidden)]
-impl op_void_async {
- pub const fn name() -> &'static str {
- stringify!(op_void_async)
- }
- #[allow(clippy::not_unsafe_ptr_arg_deref)]
- pub extern "C" fn v8_fn_ptr(info: *const deno_core::v8::FunctionCallbackInfo) {
- let info = unsafe { &*info };
- let scope = &mut unsafe { deno_core::v8::CallbackScope::new(info) };
- let args = deno_core::v8::FunctionCallbackArguments::from_function_callback_info(
- info,
- );
- let rv = deno_core::v8::ReturnValue::from_function_callback_info(info);
- Self::v8_func(scope, args, rv);
- }
- pub const fn decl() -> deno_core::OpDecl {
- deno_core::OpDecl {
- name: Self::name(),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: {
- use deno_core::v8::fast_api::CType;
- use deno_core::v8::fast_api::Type::*;
- Some(
- deno_core::v8::fast_api::FastFunction::new(
- &[V8Value, Int32, CallbackOptions],
- CType::Void,
- Self::op_void_async_fast_fn as *const ::std::ffi::c_void,
- ),
- )
- },
- is_async: true,
- is_unstable: false,
- is_v8: false,
- arg_count: 1usize as u8,
- }
- }
- #[inline]
- #[allow(clippy::too_many_arguments)]
- #[allow(clippy::extra_unused_lifetimes)]
- async fn call<'scope>() {}
- pub fn v8_func<'scope>(
- scope: &mut deno_core::v8::HandleScope<'scope>,
- args: deno_core::v8::FunctionCallbackArguments,
- mut rv: deno_core::v8::ReturnValue,
- ) {
- use deno_core::futures::FutureExt;
- let ctx = unsafe {
- &*(deno_core::v8::Local::<deno_core::v8::External>::cast(args.data()).value()
- as *const deno_core::_ops::OpCtx)
- };
- let promise_id = args.get(0);
- let promise_id = deno_core::v8::Local::<
- deno_core::v8::Integer,
- >::try_from(promise_id)
- .map(|l| l.value() as deno_core::PromiseId)
- .map_err(deno_core::anyhow::Error::from);
- let promise_id: deno_core::PromiseId = match promise_id {
- Ok(promise_id) => promise_id,
- Err(err) => {
- deno_core::_ops::throw_type_error(
- scope,
- format!("invalid promise id: {}", err),
- );
- return;
- }
- };
- let fut = deno_core::_ops::map_async_op2(ctx, Self::call());
- let maybe_response = deno_core::_ops::queue_async_op(
- ctx,
- scope,
- false,
- promise_id,
- fut,
- );
- if let Some(response) = maybe_response {
- rv.set(response);
- }
- }
-}
-impl op_void_async {
- #[allow(clippy::too_many_arguments)]
- fn op_void_async_fast_fn(
- _: deno_core::v8::Local<deno_core::v8::Object>,
- __promise_id: i32,
- fast_api_callback_options: *mut deno_core::v8::fast_api::FastApiCallbackOptions,
- ) -> () {
- use deno_core::v8;
- use deno_core::_ops;
- let __opts: &mut v8::fast_api::FastApiCallbackOptions = unsafe {
- &mut *fast_api_callback_options
- };
- let __ctx = unsafe {
- &*(v8::Local::<v8::External>::cast(unsafe { __opts.data.data }).value()
- as *const _ops::OpCtx)
- };
- let op_state = __ctx.state.clone();
- let result = Self::call();
- let result = _ops::queue_fast_async_op(
- __ctx,
- __promise_id,
- async move { Ok(result.await) },
- );
- result
- }
-}
diff --git a/ops/optimizer_tests/async_nop.rs b/ops/optimizer_tests/async_nop.rs
deleted file mode 100644
index 95a1522f1..000000000
--- a/ops/optimizer_tests/async_nop.rs
+++ /dev/null
@@ -1,3 +0,0 @@
-async fn op_void_async() {
- // @test-attr:fast
-}
diff --git a/ops/optimizer_tests/async_result.expected b/ops/optimizer_tests/async_result.expected
deleted file mode 100644
index 87d46977d..000000000
--- a/ops/optimizer_tests/async_result.expected
+++ /dev/null
@@ -1,11 +0,0 @@
-=== Optimizer Dump ===
-returns_result: true
-has_ref_opstate: false
-has_rc_opstate: true
-has_fast_callback_option: false
-needs_fast_callback_option: false
-fast_result: None
-fast_parameters: [V8Value, I32, U32]
-transforms: {}
-is_async: true
-fast_compatible: true
diff --git a/ops/optimizer_tests/async_result.out b/ops/optimizer_tests/async_result.out
deleted file mode 100644
index 91117e4a1..000000000
--- a/ops/optimizer_tests/async_result.out
+++ /dev/null
@@ -1,150 +0,0 @@
-#[allow(non_camel_case_types)]
-///Auto-generated by `deno_ops`, i.e: `#[op]`
-///
-///Use `op_async_result::decl()` to get an op-declaration
-///you can include in a `deno_core::Extension`.
-pub struct op_async_result {
- _phantom_data: ::std::marker::PhantomData<()>,
-}
-impl deno_core::_ops::Op for op_async_result {
- const NAME: &'static str = stringify!(op_async_result);
- const DECL: deno_core::OpDecl = deno_core::OpDecl {
- name: Self::name(),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: {
- use deno_core::v8::fast_api::CType;
- use deno_core::v8::fast_api::Type::*;
- Some(
- deno_core::v8::fast_api::FastFunction::new(
- &[V8Value, Int32, Uint32, CallbackOptions],
- CType::Void,
- Self::op_async_result_fast_fn as *const ::std::ffi::c_void,
- ),
- )
- },
- is_async: true,
- is_unstable: false,
- is_v8: false,
- arg_count: 0,
- };
-}
-#[doc(hidden)]
-impl op_async_result {
- pub const fn name() -> &'static str {
- stringify!(op_async_result)
- }
- #[allow(clippy::not_unsafe_ptr_arg_deref)]
- pub extern "C" fn v8_fn_ptr(info: *const deno_core::v8::FunctionCallbackInfo) {
- let info = unsafe { &*info };
- let scope = &mut unsafe { deno_core::v8::CallbackScope::new(info) };
- let args = deno_core::v8::FunctionCallbackArguments::from_function_callback_info(
- info,
- );
- let rv = deno_core::v8::ReturnValue::from_function_callback_info(info);
- Self::v8_func(scope, args, rv);
- }
- pub const fn decl() -> deno_core::OpDecl {
- deno_core::OpDecl {
- name: Self::name(),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: {
- use deno_core::v8::fast_api::CType;
- use deno_core::v8::fast_api::Type::*;
- Some(
- deno_core::v8::fast_api::FastFunction::new(
- &[V8Value, Int32, Uint32, CallbackOptions],
- CType::Void,
- Self::op_async_result_fast_fn as *const ::std::ffi::c_void,
- ),
- )
- },
- is_async: true,
- is_unstable: false,
- is_v8: false,
- arg_count: 2usize as u8,
- }
- }
- #[inline]
- #[allow(clippy::too_many_arguments)]
- #[allow(clippy::extra_unused_lifetimes)]
- async fn call<'scope>(
- state: Rc<RefCell<OpState>>,
- rid: ResourceId,
- ) -> Result<u32, Error> {}
- pub fn v8_func<'scope>(
- scope: &mut deno_core::v8::HandleScope<'scope>,
- args: deno_core::v8::FunctionCallbackArguments,
- mut rv: deno_core::v8::ReturnValue,
- ) {
- use deno_core::futures::FutureExt;
- let ctx = unsafe {
- &*(deno_core::v8::Local::<deno_core::v8::External>::cast(args.data()).value()
- as *const deno_core::_ops::OpCtx)
- };
- let promise_id = args.get(0);
- let promise_id = deno_core::v8::Local::<
- deno_core::v8::Integer,
- >::try_from(promise_id)
- .map(|l| l.value() as deno_core::PromiseId)
- .map_err(deno_core::anyhow::Error::from);
- let promise_id: deno_core::PromiseId = match promise_id {
- Ok(promise_id) => promise_id,
- Err(err) => {
- deno_core::_ops::throw_type_error(
- scope,
- format!("invalid promise id: {}", err),
- );
- return;
- }
- };
- let arg_0 = args.get(1usize as i32);
- let arg_0 = match deno_core::serde_v8::from_v8(scope, arg_0) {
- Ok(v) => v,
- Err(err) => {
- let msg = format!(
- "Error parsing args at position {}: {}", 1usize,
- deno_core::anyhow::Error::from(err)
- );
- return deno_core::_ops::throw_type_error(scope, msg);
- }
- };
- let fut = deno_core::_ops::map_async_op1(
- ctx,
- Self::call(ctx.state.clone(), arg_0),
- );
- let maybe_response = deno_core::_ops::queue_async_op(
- ctx,
- scope,
- false,
- promise_id,
- fut,
- );
- if let Some(response) = maybe_response {
- rv.set(response);
- }
- }
-}
-impl op_async_result {
- #[allow(clippy::too_many_arguments)]
- fn op_async_result_fast_fn(
- _: deno_core::v8::Local<deno_core::v8::Object>,
- __promise_id: i32,
- rid: ResourceId,
- fast_api_callback_options: *mut deno_core::v8::fast_api::FastApiCallbackOptions,
- ) -> () {
- use deno_core::v8;
- use deno_core::_ops;
- let __opts: &mut v8::fast_api::FastApiCallbackOptions = unsafe {
- &mut *fast_api_callback_options
- };
- let __ctx = unsafe {
- &*(v8::Local::<v8::External>::cast(unsafe { __opts.data.data }).value()
- as *const _ops::OpCtx)
- };
- let state = __ctx.state.clone();
- let result = Self::call(state, rid);
- let result = _ops::queue_fast_async_op(__ctx, __promise_id, result);
- }
-}
diff --git a/ops/optimizer_tests/async_result.rs b/ops/optimizer_tests/async_result.rs
deleted file mode 100644
index 54ac20d3c..000000000
--- a/ops/optimizer_tests/async_result.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-async fn op_async_result(
- state: Rc<RefCell<OpState>>,
- rid: ResourceId,
-) -> Result<u32, Error> {
- // @test-attr:fast
-}
diff --git a/ops/optimizer_tests/callback_options.expected b/ops/optimizer_tests/callback_options.expected
deleted file mode 100644
index 245fdfd55..000000000
--- a/ops/optimizer_tests/callback_options.expected
+++ /dev/null
@@ -1,11 +0,0 @@
-=== Optimizer Dump ===
-returns_result: false
-has_ref_opstate: false
-has_rc_opstate: false
-has_fast_callback_option: true
-needs_fast_callback_option: false
-fast_result: Some(Void)
-fast_parameters: [V8Value]
-transforms: {}
-is_async: false
-fast_compatible: true
diff --git a/ops/optimizer_tests/callback_options.out b/ops/optimizer_tests/callback_options.out
deleted file mode 100644
index a868d6393..000000000
--- a/ops/optimizer_tests/callback_options.out
+++ /dev/null
@@ -1,106 +0,0 @@
-#[allow(non_camel_case_types)]
-///Auto-generated by `deno_ops`, i.e: `#[op]`
-///
-///Use `op_fallback::decl()` to get an op-declaration
-///you can include in a `deno_core::Extension`.
-pub struct op_fallback {
- _phantom_data: ::std::marker::PhantomData<()>,
-}
-impl deno_core::_ops::Op for op_fallback {
- const NAME: &'static str = stringify!(op_fallback);
- const DECL: deno_core::OpDecl = deno_core::OpDecl {
- name: Self::name(),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: {
- use deno_core::v8::fast_api::CType;
- use deno_core::v8::fast_api::Type::*;
- Some(
- deno_core::v8::fast_api::FastFunction::new(
- &[V8Value, CallbackOptions],
- CType::Void,
- Self::op_fallback_fast_fn as *const ::std::ffi::c_void,
- ),
- )
- },
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 0,
- };
-}
-#[doc(hidden)]
-impl op_fallback {
- pub const fn name() -> &'static str {
- stringify!(op_fallback)
- }
- #[allow(clippy::not_unsafe_ptr_arg_deref)]
- pub extern "C" fn v8_fn_ptr(info: *const deno_core::v8::FunctionCallbackInfo) {
- let info = unsafe { &*info };
- let scope = &mut unsafe { deno_core::v8::CallbackScope::new(info) };
- let args = deno_core::v8::FunctionCallbackArguments::from_function_callback_info(
- info,
- );
- let rv = deno_core::v8::ReturnValue::from_function_callback_info(info);
- Self::v8_func(scope, args, rv);
- }
- pub const fn decl() -> deno_core::OpDecl {
- deno_core::OpDecl {
- name: Self::name(),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: {
- use deno_core::v8::fast_api::CType;
- use deno_core::v8::fast_api::Type::*;
- Some(
- deno_core::v8::fast_api::FastFunction::new(
- &[V8Value, CallbackOptions],
- CType::Void,
- Self::op_fallback_fast_fn as *const ::std::ffi::c_void,
- ),
- )
- },
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 1usize as u8,
- }
- }
- #[inline]
- #[allow(clippy::too_many_arguments)]
- #[allow(clippy::extra_unused_lifetimes)]
- fn call<'scope>(options: Option<&mut FastApiCallbackOptions>) {
- if let Some(options) = options {
- options.fallback = true;
- }
- }
- pub fn v8_func<'scope>(
- scope: &mut deno_core::v8::HandleScope<'scope>,
- args: deno_core::v8::FunctionCallbackArguments,
- mut rv: deno_core::v8::ReturnValue,
- ) {
- let ctx = unsafe {
- &*(deno_core::v8::Local::<deno_core::v8::External>::cast(args.data()).value()
- as *const deno_core::_ops::OpCtx)
- };
- let arg_0 = None;
- let result = Self::call(arg_0);
- let op_state = ::std::cell::RefCell::borrow(&*ctx.state);
- op_state.tracker.track_sync(ctx.id);
- }
-}
-impl op_fallback {
- #[allow(clippy::too_many_arguments)]
- fn op_fallback_fast_fn(
- _: deno_core::v8::Local<deno_core::v8::Object>,
- fast_api_callback_options: *mut deno_core::v8::fast_api::FastApiCallbackOptions,
- ) -> () {
- use deno_core::v8;
- use deno_core::_ops;
- let __opts: &mut v8::fast_api::FastApiCallbackOptions = unsafe {
- &mut *fast_api_callback_options
- };
- let result = Self::call(options);
- result
- }
-}
diff --git a/ops/optimizer_tests/callback_options.rs b/ops/optimizer_tests/callback_options.rs
deleted file mode 100644
index c210171d2..000000000
--- a/ops/optimizer_tests/callback_options.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-fn op_fallback(options: Option<&mut FastApiCallbackOptions>) {
- if let Some(options) = options {
- options.fallback = true;
- }
-}
diff --git a/ops/optimizer_tests/cow_str.expected b/ops/optimizer_tests/cow_str.expected
deleted file mode 100644
index 9db8cfaf3..000000000
--- a/ops/optimizer_tests/cow_str.expected
+++ /dev/null
@@ -1,11 +0,0 @@
-=== Optimizer Dump ===
-returns_result: false
-has_ref_opstate: false
-has_rc_opstate: false
-has_fast_callback_option: false
-needs_fast_callback_option: true
-fast_result: Some(Void)
-fast_parameters: [V8Value, SeqOneByteString]
-transforms: {0: Transform { kind: SeqOneByteString(Cow), index: 0 }}
-is_async: false
-fast_compatible: true
diff --git a/ops/optimizer_tests/cow_str.out b/ops/optimizer_tests/cow_str.out
deleted file mode 100644
index 15c92f346..000000000
--- a/ops/optimizer_tests/cow_str.out
+++ /dev/null
@@ -1,121 +0,0 @@
-#[allow(non_camel_case_types)]
-///Auto-generated by `deno_ops`, i.e: `#[op]`
-///
-///Use `op_cow_str::decl()` to get an op-declaration
-///you can include in a `deno_core::Extension`.
-pub struct op_cow_str {
- _phantom_data: ::std::marker::PhantomData<()>,
-}
-impl deno_core::_ops::Op for op_cow_str {
- const NAME: &'static str = stringify!(op_cow_str);
- const DECL: deno_core::OpDecl = deno_core::OpDecl {
- name: Self::name(),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: {
- use deno_core::v8::fast_api::CType;
- use deno_core::v8::fast_api::Type::*;
- Some(
- deno_core::v8::fast_api::FastFunction::new(
- &[V8Value, SeqOneByteString, CallbackOptions],
- CType::Void,
- Self::op_cow_str_fast_fn as *const ::std::ffi::c_void,
- ),
- )
- },
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 0,
- };
-}
-#[doc(hidden)]
-impl op_cow_str {
- pub const fn name() -> &'static str {
- stringify!(op_cow_str)
- }
- #[allow(clippy::not_unsafe_ptr_arg_deref)]
- pub extern "C" fn v8_fn_ptr(info: *const deno_core::v8::FunctionCallbackInfo) {
- let info = unsafe { &*info };
- let scope = &mut unsafe { deno_core::v8::CallbackScope::new(info) };
- let args = deno_core::v8::FunctionCallbackArguments::from_function_callback_info(
- info,
- );
- let rv = deno_core::v8::ReturnValue::from_function_callback_info(info);
- Self::v8_func(scope, args, rv);
- }
- pub const fn decl() -> deno_core::OpDecl {
- deno_core::OpDecl {
- name: Self::name(),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: {
- use deno_core::v8::fast_api::CType;
- use deno_core::v8::fast_api::Type::*;
- Some(
- deno_core::v8::fast_api::FastFunction::new(
- &[V8Value, SeqOneByteString, CallbackOptions],
- CType::Void,
- Self::op_cow_str_fast_fn as *const ::std::ffi::c_void,
- ),
- )
- },
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 1usize as u8,
- }
- }
- #[inline]
- #[allow(clippy::too_many_arguments)]
- #[allow(clippy::extra_unused_lifetimes)]
- fn call<'scope>(c: Cow<'_, str>) {}
- pub fn v8_func<'scope>(
- scope: &mut deno_core::v8::HandleScope<'scope>,
- args: deno_core::v8::FunctionCallbackArguments,
- mut rv: deno_core::v8::ReturnValue,
- ) {
- let ctx = unsafe {
- &*(deno_core::v8::Local::<deno_core::v8::External>::cast(args.data()).value()
- as *const deno_core::_ops::OpCtx)
- };
- let arg_0 = match deno_core::v8::Local::<
- deno_core::v8::String,
- >::try_from(args.get(0usize as i32)) {
- Ok(v8_string) => {
- ::std::borrow::Cow::Owned(deno_core::serde_v8::to_utf8(v8_string, scope))
- }
- Err(_) => {
- return deno_core::_ops::throw_type_error(
- scope,
- format!("Expected string at position {}", 0usize),
- );
- }
- };
- let result = Self::call(arg_0);
- let op_state = ::std::cell::RefCell::borrow(&*ctx.state);
- op_state.tracker.track_sync(ctx.id);
- }
-}
-impl op_cow_str {
- #[allow(clippy::too_many_arguments)]
- fn op_cow_str_fast_fn(
- _: deno_core::v8::Local<deno_core::v8::Object>,
- c: *const deno_core::v8::fast_api::FastApiOneByteString,
- fast_api_callback_options: *mut deno_core::v8::fast_api::FastApiCallbackOptions,
- ) -> () {
- use deno_core::v8;
- use deno_core::_ops;
- let c = ::std::borrow::Cow::Borrowed(
- match ::std::str::from_utf8(unsafe { &*c }.as_bytes()) {
- Ok(v) => v,
- Err(_) => {
- unsafe { &mut *fast_api_callback_options }.fallback = true;
- return Default::default();
- }
- },
- );
- let result = Self::call(c);
- result
- }
-}
diff --git a/ops/optimizer_tests/cow_str.rs b/ops/optimizer_tests/cow_str.rs
deleted file mode 100644
index b7214bdc7..000000000
--- a/ops/optimizer_tests/cow_str.rs
+++ /dev/null
@@ -1,3 +0,0 @@
-fn op_cow_str(c: Cow<'_, str>) {
- // ...
-}
diff --git a/ops/optimizer_tests/f64_slice.expected b/ops/optimizer_tests/f64_slice.expected
deleted file mode 100644
index 32182b004..000000000
--- a/ops/optimizer_tests/f64_slice.expected
+++ /dev/null
@@ -1,11 +0,0 @@
-=== Optimizer Dump ===
-returns_result: false
-has_ref_opstate: false
-has_rc_opstate: false
-has_fast_callback_option: false
-needs_fast_callback_option: true
-fast_result: Some(Void)
-fast_parameters: [V8Value, Float64Array]
-transforms: {0: Transform { kind: SliceF64(true), index: 0 }}
-is_async: false
-fast_compatible: true
diff --git a/ops/optimizer_tests/f64_slice.out b/ops/optimizer_tests/f64_slice.out
deleted file mode 100644
index 183677731..000000000
--- a/ops/optimizer_tests/f64_slice.out
+++ /dev/null
@@ -1,137 +0,0 @@
-#[allow(non_camel_case_types)]
-///Auto-generated by `deno_ops`, i.e: `#[op]`
-///
-///Use `op_f64_buf::decl()` to get an op-declaration
-///you can include in a `deno_core::Extension`.
-pub struct op_f64_buf {
- _phantom_data: ::std::marker::PhantomData<()>,
-}
-impl deno_core::_ops::Op for op_f64_buf {
- const NAME: &'static str = stringify!(op_f64_buf);
- const DECL: deno_core::OpDecl = deno_core::OpDecl {
- name: Self::name(),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: {
- use deno_core::v8::fast_api::CType;
- use deno_core::v8::fast_api::Type::*;
- Some(
- deno_core::v8::fast_api::FastFunction::new(
- &[V8Value, TypedArray(CType::Float64), CallbackOptions],
- CType::Void,
- Self::op_f64_buf_fast_fn as *const ::std::ffi::c_void,
- ),
- )
- },
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 0,
- };
-}
-#[doc(hidden)]
-impl op_f64_buf {
- pub const fn name() -> &'static str {
- stringify!(op_f64_buf)
- }
- #[allow(clippy::not_unsafe_ptr_arg_deref)]
- pub extern "C" fn v8_fn_ptr(info: *const deno_core::v8::FunctionCallbackInfo) {
- let info = unsafe { &*info };
- let scope = &mut unsafe { deno_core::v8::CallbackScope::new(info) };
- let args = deno_core::v8::FunctionCallbackArguments::from_function_callback_info(
- info,
- );
- let rv = deno_core::v8::ReturnValue::from_function_callback_info(info);
- Self::v8_func(scope, args, rv);
- }
- pub const fn decl() -> deno_core::OpDecl {
- deno_core::OpDecl {
- name: Self::name(),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: {
- use deno_core::v8::fast_api::CType;
- use deno_core::v8::fast_api::Type::*;
- Some(
- deno_core::v8::fast_api::FastFunction::new(
- &[V8Value, TypedArray(CType::Float64), CallbackOptions],
- CType::Void,
- Self::op_f64_buf_fast_fn as *const ::std::ffi::c_void,
- ),
- )
- },
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 1usize as u8,
- }
- }
- #[inline]
- #[allow(clippy::too_many_arguments)]
- #[allow(clippy::extra_unused_lifetimes)]
- fn call<'scope>(buffer: &mut [f64]) {}
- pub fn v8_func<'scope>(
- scope: &mut deno_core::v8::HandleScope<'scope>,
- args: deno_core::v8::FunctionCallbackArguments,
- mut rv: deno_core::v8::ReturnValue,
- ) {
- let ctx = unsafe {
- &*(deno_core::v8::Local::<deno_core::v8::External>::cast(args.data()).value()
- as *const deno_core::_ops::OpCtx)
- };
- let arg_0 = if let Ok(view)
- = deno_core::v8::Local::<
- deno_core::v8::Float64Array,
- >::try_from(args.get(0usize as i32)) {
- let (offset, len) = (view.byte_offset(), view.byte_length());
- let buffer = match view.buffer(scope) {
- Some(v) => v,
- None => {
- return deno_core::_ops::throw_type_error(
- scope,
- format!("Expected Float64Array at position {}", 0usize),
- );
- }
- };
- if let Some(data) = buffer.data() {
- let store = data.cast::<u8>().as_ptr();
- unsafe {
- ::std::slice::from_raw_parts_mut(
- store.add(offset) as *mut f64,
- len / 8,
- )
- }
- } else {
- &mut []
- }
- } else {
- return deno_core::_ops::throw_type_error(
- scope,
- format!("Expected Float64Array at position {}", 0usize),
- );
- };
- let result = Self::call(arg_0);
- let op_state = ::std::cell::RefCell::borrow(&*ctx.state);
- op_state.tracker.track_sync(ctx.id);
- }
-}
-impl op_f64_buf {
- #[allow(clippy::too_many_arguments)]
- fn op_f64_buf_fast_fn(
- _: deno_core::v8::Local<deno_core::v8::Object>,
- buffer: *const deno_core::v8::fast_api::FastApiTypedArray<f64>,
- fast_api_callback_options: *mut deno_core::v8::fast_api::FastApiCallbackOptions,
- ) -> () {
- use deno_core::v8;
- use deno_core::_ops;
- let buffer = match unsafe { &*buffer }.get_storage_if_aligned() {
- Some(v) => v,
- None => {
- unsafe { &mut *fast_api_callback_options }.fallback = true;
- return Default::default();
- }
- };
- let result = Self::call(buffer);
- result
- }
-}
diff --git a/ops/optimizer_tests/f64_slice.rs b/ops/optimizer_tests/f64_slice.rs
deleted file mode 100644
index fa2778531..000000000
--- a/ops/optimizer_tests/f64_slice.rs
+++ /dev/null
@@ -1,3 +0,0 @@
-fn op_f64_buf(buffer: &mut [f64]) {
- // @test-attr:fast
-}
diff --git a/ops/optimizer_tests/incompatible_1.expected b/ops/optimizer_tests/incompatible_1.expected
deleted file mode 100644
index 250ff1022..000000000
--- a/ops/optimizer_tests/incompatible_1.expected
+++ /dev/null
@@ -1 +0,0 @@
-FastUnsupportedParamType \ No newline at end of file
diff --git a/ops/optimizer_tests/incompatible_1.out b/ops/optimizer_tests/incompatible_1.out
deleted file mode 100644
index d51a1eda8..000000000
--- a/ops/optimizer_tests/incompatible_1.out
+++ /dev/null
@@ -1,93 +0,0 @@
-#[allow(non_camel_case_types)]
-///Auto-generated by `deno_ops`, i.e: `#[op]`
-///
-///Use `op_sync_serialize_object_with_numbers_as_keys::decl()` to get an op-declaration
-///you can include in a `deno_core::Extension`.
-pub struct op_sync_serialize_object_with_numbers_as_keys {
- _phantom_data: ::std::marker::PhantomData<()>,
-}
-impl deno_core::_ops::Op for op_sync_serialize_object_with_numbers_as_keys {
- const NAME: &'static str = stringify!(op_sync_serialize_object_with_numbers_as_keys);
- const DECL: deno_core::OpDecl = deno_core::OpDecl {
- name: Self::name(),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: None,
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 0,
- };
-}
-#[doc(hidden)]
-impl op_sync_serialize_object_with_numbers_as_keys {
- pub const fn name() -> &'static str {
- stringify!(op_sync_serialize_object_with_numbers_as_keys)
- }
- #[allow(clippy::not_unsafe_ptr_arg_deref)]
- pub extern "C" fn v8_fn_ptr(info: *const deno_core::v8::FunctionCallbackInfo) {
- let info = unsafe { &*info };
- let scope = &mut unsafe { deno_core::v8::CallbackScope::new(info) };
- let args = deno_core::v8::FunctionCallbackArguments::from_function_callback_info(
- info,
- );
- let rv = deno_core::v8::ReturnValue::from_function_callback_info(info);
- Self::v8_func(scope, args, rv);
- }
- pub const fn decl() -> deno_core::OpDecl {
- deno_core::OpDecl {
- name: Self::name(),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: None,
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 1usize as u8,
- }
- }
- #[inline]
- #[allow(clippy::too_many_arguments)]
- #[allow(clippy::extra_unused_lifetimes)]
- fn call<'scope>(value: serde_json::Value) -> Result<(), Error> {
- assert_eq!(
- value.to_string(), r#"{"lines":{"100":{"unit":"m"},"200":{"unit":"cm"}}}"#
- );
- Ok(())
- }
- pub fn v8_func<'scope>(
- scope: &mut deno_core::v8::HandleScope<'scope>,
- args: deno_core::v8::FunctionCallbackArguments,
- mut rv: deno_core::v8::ReturnValue,
- ) {
- let ctx = unsafe {
- &*(deno_core::v8::Local::<deno_core::v8::External>::cast(args.data()).value()
- as *const deno_core::_ops::OpCtx)
- };
- let arg_0 = args.get(0usize as i32);
- let arg_0 = match deno_core::serde_v8::from_v8(scope, arg_0) {
- Ok(v) => v,
- Err(err) => {
- let msg = format!(
- "Error parsing args at position {}: {}", 0usize,
- deno_core::anyhow::Error::from(err)
- );
- return deno_core::_ops::throw_type_error(scope, msg);
- }
- };
- let result = Self::call(arg_0);
- let op_state = ::std::cell::RefCell::borrow(&*ctx.state);
- op_state.tracker.track_sync(ctx.id);
- match result {
- Ok(result) => {}
- Err(err) => {
- let exception = deno_core::error::to_v8_error(
- scope,
- op_state.get_error_class_fn,
- &err,
- );
- scope.throw_exception(exception);
- }
- };
- }
-}
diff --git a/ops/optimizer_tests/incompatible_1.rs b/ops/optimizer_tests/incompatible_1.rs
deleted file mode 100644
index 326189aa1..000000000
--- a/ops/optimizer_tests/incompatible_1.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-fn op_sync_serialize_object_with_numbers_as_keys(
- value: serde_json::Value,
-) -> Result<(), Error> {
- assert_eq!(
- value.to_string(),
- r#"{"lines":{"100":{"unit":"m"},"200":{"unit":"cm"}}}"#
- );
- Ok(())
-}
diff --git a/ops/optimizer_tests/issue16934.expected b/ops/optimizer_tests/issue16934.expected
deleted file mode 100644
index 6b75ff5bf..000000000
--- a/ops/optimizer_tests/issue16934.expected
+++ /dev/null
@@ -1,11 +0,0 @@
-=== Optimizer Dump ===
-returns_result: false
-has_ref_opstate: false
-has_rc_opstate: false
-has_fast_callback_option: false
-needs_fast_callback_option: false
-fast_result: None
-fast_parameters: []
-transforms: {}
-is_async: false
-fast_compatible: false
diff --git a/ops/optimizer_tests/issue16934.out b/ops/optimizer_tests/issue16934.out
deleted file mode 100644
index 0f85b1157..000000000
--- a/ops/optimizer_tests/issue16934.out
+++ /dev/null
@@ -1,115 +0,0 @@
-#[allow(non_camel_case_types)]
-///Auto-generated by `deno_ops`, i.e: `#[op]`
-///
-///Use `send_stdin::decl()` to get an op-declaration
-///you can include in a `deno_core::Extension`.
-pub struct send_stdin {
- _phantom_data: ::std::marker::PhantomData<()>,
-}
-impl deno_core::_ops::Op for send_stdin {
- const NAME: &'static str = stringify!(send_stdin);
- const DECL: deno_core::OpDecl = deno_core::OpDecl {
- name: Self::name(),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: None,
- is_async: true,
- is_unstable: false,
- is_v8: false,
- arg_count: 0,
- };
-}
-#[doc(hidden)]
-impl send_stdin {
- pub const fn name() -> &'static str {
- stringify!(send_stdin)
- }
- #[allow(clippy::not_unsafe_ptr_arg_deref)]
- pub extern "C" fn v8_fn_ptr(info: *const deno_core::v8::FunctionCallbackInfo) {
- let info = unsafe { &*info };
- let scope = &mut unsafe { deno_core::v8::CallbackScope::new(info) };
- let args = deno_core::v8::FunctionCallbackArguments::from_function_callback_info(
- info,
- );
- let rv = deno_core::v8::ReturnValue::from_function_callback_info(info);
- Self::v8_func(scope, args, rv);
- }
- pub const fn decl() -> deno_core::OpDecl {
- deno_core::OpDecl {
- name: Self::name(),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: None,
- is_async: true,
- is_unstable: false,
- is_v8: false,
- arg_count: 2usize as u8,
- }
- }
- #[inline]
- #[allow(clippy::too_many_arguments)]
- #[allow(clippy::extra_unused_lifetimes)]
- async fn call<'scope>(
- state: &mut OpState,
- cmd: String,
- ) -> Result<(), anyhow::Error> {
- let instance = state.borrow::<MinecraftInstance>().clone();
- instance.send_command(&cmd, CausedBy::Unknown).await?;
- Ok(())
- }
- pub fn v8_func<'scope>(
- scope: &mut deno_core::v8::HandleScope<'scope>,
- args: deno_core::v8::FunctionCallbackArguments,
- mut rv: deno_core::v8::ReturnValue,
- ) {
- use deno_core::futures::FutureExt;
- let ctx = unsafe {
- &*(deno_core::v8::Local::<deno_core::v8::External>::cast(args.data()).value()
- as *const deno_core::_ops::OpCtx)
- };
- let promise_id = args.get(0);
- let promise_id = deno_core::v8::Local::<
- deno_core::v8::Integer,
- >::try_from(promise_id)
- .map(|l| l.value() as deno_core::PromiseId)
- .map_err(deno_core::anyhow::Error::from);
- let promise_id: deno_core::PromiseId = match promise_id {
- Ok(promise_id) => promise_id,
- Err(err) => {
- deno_core::_ops::throw_type_error(
- scope,
- format!("invalid promise id: {}", err),
- );
- return;
- }
- };
- let arg_0 = match deno_core::v8::Local::<
- deno_core::v8::String,
- >::try_from(args.get(1usize as i32)) {
- Ok(v8_string) => deno_core::serde_v8::to_utf8(v8_string, scope),
- Err(_) => {
- return deno_core::_ops::throw_type_error(
- scope,
- format!("Expected string at position {}", 1usize),
- );
- }
- };
- let fut = deno_core::_ops::map_async_op1(
- ctx,
- Self::call(
- compile_error!("mutable opstate is not supported in async ops"),
- arg_0,
- ),
- );
- let maybe_response = deno_core::_ops::queue_async_op(
- ctx,
- scope,
- false,
- promise_id,
- fut,
- );
- if let Some(response) = maybe_response {
- rv.set(response);
- }
- }
-}
diff --git a/ops/optimizer_tests/issue16934.rs b/ops/optimizer_tests/issue16934.rs
deleted file mode 100644
index 1e77f1281..000000000
--- a/ops/optimizer_tests/issue16934.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-async fn send_stdin(
- state: &mut OpState,
- cmd: String,
-) -> Result<(), anyhow::Error> {
- // https://github.com/denoland/deno/issues/16934
- //
- // OpState borrowed across await point is not allowed, as it will likely panic at runtime.
- let instance = state.borrow::<MinecraftInstance>().clone();
- instance.send_command(&cmd, CausedBy::Unknown).await?;
- Ok(())
-}
diff --git a/ops/optimizer_tests/issue16934_fast.expected b/ops/optimizer_tests/issue16934_fast.expected
deleted file mode 100644
index 250ff1022..000000000
--- a/ops/optimizer_tests/issue16934_fast.expected
+++ /dev/null
@@ -1 +0,0 @@
-FastUnsupportedParamType \ No newline at end of file
diff --git a/ops/optimizer_tests/issue16934_fast.out b/ops/optimizer_tests/issue16934_fast.out
deleted file mode 100644
index 2bbbc02bb..000000000
--- a/ops/optimizer_tests/issue16934_fast.out
+++ /dev/null
@@ -1,110 +0,0 @@
-#[allow(non_camel_case_types)]
-///Auto-generated by `deno_ops`, i.e: `#[op]`
-///
-///Use `send_stdin::decl()` to get an op-declaration
-///you can include in a `deno_core::Extension`.
-pub struct send_stdin {
- _phantom_data: ::std::marker::PhantomData<()>,
-}
-impl deno_core::_ops::Op for send_stdin {
- const NAME: &'static str = stringify!(send_stdin);
- const DECL: deno_core::OpDecl = deno_core::OpDecl {
- name: Self::name(),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: None,
- is_async: true,
- is_unstable: false,
- is_v8: false,
- arg_count: 0,
- };
-}
-#[doc(hidden)]
-impl send_stdin {
- pub const fn name() -> &'static str {
- stringify!(send_stdin)
- }
- #[allow(clippy::not_unsafe_ptr_arg_deref)]
- pub extern "C" fn v8_fn_ptr(info: *const deno_core::v8::FunctionCallbackInfo) {
- let info = unsafe { &*info };
- let scope = &mut unsafe { deno_core::v8::CallbackScope::new(info) };
- let args = deno_core::v8::FunctionCallbackArguments::from_function_callback_info(
- info,
- );
- let rv = deno_core::v8::ReturnValue::from_function_callback_info(info);
- Self::v8_func(scope, args, rv);
- }
- pub const fn decl() -> deno_core::OpDecl {
- deno_core::OpDecl {
- name: Self::name(),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: None,
- is_async: true,
- is_unstable: false,
- is_v8: false,
- arg_count: 2usize as u8,
- }
- }
- #[inline]
- #[allow(clippy::too_many_arguments)]
- #[allow(clippy::extra_unused_lifetimes)]
- async fn call<'scope>(state: &mut OpState, v: i32) -> Result<(), anyhow::Error> {
- Ok(())
- }
- pub fn v8_func<'scope>(
- scope: &mut deno_core::v8::HandleScope<'scope>,
- args: deno_core::v8::FunctionCallbackArguments,
- mut rv: deno_core::v8::ReturnValue,
- ) {
- use deno_core::futures::FutureExt;
- let ctx = unsafe {
- &*(deno_core::v8::Local::<deno_core::v8::External>::cast(args.data()).value()
- as *const deno_core::_ops::OpCtx)
- };
- let promise_id = args.get(0);
- let promise_id = deno_core::v8::Local::<
- deno_core::v8::Integer,
- >::try_from(promise_id)
- .map(|l| l.value() as deno_core::PromiseId)
- .map_err(deno_core::anyhow::Error::from);
- let promise_id: deno_core::PromiseId = match promise_id {
- Ok(promise_id) => promise_id,
- Err(err) => {
- deno_core::_ops::throw_type_error(
- scope,
- format!("invalid promise id: {}", err),
- );
- return;
- }
- };
- let arg_0 = args.get(1usize as i32);
- let arg_0 = match deno_core::serde_v8::from_v8(scope, arg_0) {
- Ok(v) => v,
- Err(err) => {
- let msg = format!(
- "Error parsing args at position {}: {}", 1usize,
- deno_core::anyhow::Error::from(err)
- );
- return deno_core::_ops::throw_type_error(scope, msg);
- }
- };
- let fut = deno_core::_ops::map_async_op1(
- ctx,
- Self::call(
- compile_error!("mutable opstate is not supported in async ops"),
- arg_0,
- ),
- );
- let maybe_response = deno_core::_ops::queue_async_op(
- ctx,
- scope,
- false,
- promise_id,
- fut,
- );
- if let Some(response) = maybe_response {
- rv.set(response);
- }
- }
-}
diff --git a/ops/optimizer_tests/issue16934_fast.rs b/ops/optimizer_tests/issue16934_fast.rs
deleted file mode 100644
index 8d3488e9d..000000000
--- a/ops/optimizer_tests/issue16934_fast.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-async fn send_stdin(state: &mut OpState, v: i32) -> Result<(), anyhow::Error> {
- // @test-attr:fast
- //
- // https://github.com/denoland/deno/issues/16934
- //
- // OpState borrowed across await point is not allowed, as it will likely panic at runtime.
- Ok(())
-}
diff --git a/ops/optimizer_tests/op_blob_revoke_object_url.expected b/ops/optimizer_tests/op_blob_revoke_object_url.expected
deleted file mode 100644
index a412eceb8..000000000
--- a/ops/optimizer_tests/op_blob_revoke_object_url.expected
+++ /dev/null
@@ -1,11 +0,0 @@
-=== Optimizer Dump ===
-returns_result: true
-has_ref_opstate: true
-has_rc_opstate: false
-has_fast_callback_option: false
-needs_fast_callback_option: true
-fast_result: Some(Void)
-fast_parameters: [V8Value, SeqOneByteString]
-transforms: {1: Transform { kind: SeqOneByteString(Owned), index: 1 }}
-is_async: false
-fast_compatible: false
diff --git a/ops/optimizer_tests/op_blob_revoke_object_url.out b/ops/optimizer_tests/op_blob_revoke_object_url.out
deleted file mode 100644
index 85c6460e9..000000000
--- a/ops/optimizer_tests/op_blob_revoke_object_url.out
+++ /dev/null
@@ -1,93 +0,0 @@
-#[allow(non_camel_case_types)]
-///Auto-generated by `deno_ops`, i.e: `#[op]`
-///
-///Use `op_blob_revoke_object_url::decl()` to get an op-declaration
-///you can include in a `deno_core::Extension`.
-pub struct op_blob_revoke_object_url {
- _phantom_data: ::std::marker::PhantomData<()>,
-}
-impl deno_core::_ops::Op for op_blob_revoke_object_url {
- const NAME: &'static str = stringify!(op_blob_revoke_object_url);
- const DECL: deno_core::OpDecl = deno_core::OpDecl {
- name: Self::name(),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: None,
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 0,
- };
-}
-#[doc(hidden)]
-impl op_blob_revoke_object_url {
- pub const fn name() -> &'static str {
- stringify!(op_blob_revoke_object_url)
- }
- #[allow(clippy::not_unsafe_ptr_arg_deref)]
- pub extern "C" fn v8_fn_ptr(info: *const deno_core::v8::FunctionCallbackInfo) {
- let info = unsafe { &*info };
- let scope = &mut unsafe { deno_core::v8::CallbackScope::new(info) };
- let args = deno_core::v8::FunctionCallbackArguments::from_function_callback_info(
- info,
- );
- let rv = deno_core::v8::ReturnValue::from_function_callback_info(info);
- Self::v8_func(scope, args, rv);
- }
- pub const fn decl() -> deno_core::OpDecl {
- deno_core::OpDecl {
- name: Self::name(),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: None,
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 1usize as u8,
- }
- }
- #[inline]
- #[allow(clippy::too_many_arguments)]
- #[allow(clippy::extra_unused_lifetimes)]
- pub fn call<'scope>(state: &mut OpState, url: String) -> Result<(), AnyError> {
- let url = Url::parse(&url)?;
- let blob_store = state.borrow::<Arc<BlobStore>>();
- blob_store.remove_object_url(&url);
- Ok(())
- }
- pub fn v8_func<'scope>(
- scope: &mut deno_core::v8::HandleScope<'scope>,
- args: deno_core::v8::FunctionCallbackArguments,
- mut rv: deno_core::v8::ReturnValue,
- ) {
- let ctx = unsafe {
- &*(deno_core::v8::Local::<deno_core::v8::External>::cast(args.data()).value()
- as *const deno_core::_ops::OpCtx)
- };
- let arg_0 = match deno_core::v8::Local::<
- deno_core::v8::String,
- >::try_from(args.get(0usize as i32)) {
- Ok(v8_string) => deno_core::serde_v8::to_utf8(v8_string, scope),
- Err(_) => {
- return deno_core::_ops::throw_type_error(
- scope,
- format!("Expected string at position {}", 0usize),
- );
- }
- };
- let result = Self::call(&mut std::cell::RefCell::borrow_mut(&ctx.state), arg_0);
- let op_state = ::std::cell::RefCell::borrow(&*ctx.state);
- op_state.tracker.track_sync(ctx.id);
- match result {
- Ok(result) => {}
- Err(err) => {
- let exception = deno_core::error::to_v8_error(
- scope,
- op_state.get_error_class_fn,
- &err,
- );
- scope.throw_exception(exception);
- }
- };
- }
-}
diff --git a/ops/optimizer_tests/op_blob_revoke_object_url.rs b/ops/optimizer_tests/op_blob_revoke_object_url.rs
deleted file mode 100644
index 9e82d7b37..000000000
--- a/ops/optimizer_tests/op_blob_revoke_object_url.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-pub fn op_blob_revoke_object_url(
- state: &mut OpState,
- url: String,
-) -> Result<(), AnyError> {
- // TODO(@littledivy): fast compatible https://github.com/denoland/deno/issues/17159
- let url = Url::parse(&url)?;
- let blob_store = state.borrow::<Arc<BlobStore>>();
- blob_store.remove_object_url(&url);
- Ok(())
-}
diff --git a/ops/optimizer_tests/op_ffi_ptr_value.expected b/ops/optimizer_tests/op_ffi_ptr_value.expected
deleted file mode 100644
index 00a28591c..000000000
--- a/ops/optimizer_tests/op_ffi_ptr_value.expected
+++ /dev/null
@@ -1,11 +0,0 @@
-=== Optimizer Dump ===
-returns_result: false
-has_ref_opstate: false
-has_rc_opstate: false
-has_fast_callback_option: false
-needs_fast_callback_option: true
-fast_result: Some(Void)
-fast_parameters: [V8Value, Pointer, Uint32Array]
-transforms: {0: Transform { kind: PtrVoid, index: 0 }, 1: Transform { kind: SliceU32(true), index: 1 }}
-is_async: false
-fast_compatible: true
diff --git a/ops/optimizer_tests/op_ffi_ptr_value.out b/ops/optimizer_tests/op_ffi_ptr_value.out
deleted file mode 100644
index 8fcce53c6..000000000
--- a/ops/optimizer_tests/op_ffi_ptr_value.out
+++ /dev/null
@@ -1,152 +0,0 @@
-#[allow(non_camel_case_types)]
-///Auto-generated by `deno_ops`, i.e: `#[op]`
-///
-///Use `op_ffi_ptr_value::decl()` to get an op-declaration
-///you can include in a `deno_core::Extension`.
-pub struct op_ffi_ptr_value {
- _phantom_data: ::std::marker::PhantomData<()>,
-}
-impl deno_core::_ops::Op for op_ffi_ptr_value {
- const NAME: &'static str = stringify!(op_ffi_ptr_value);
- const DECL: deno_core::OpDecl = deno_core::OpDecl {
- name: Self::name(),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: {
- use deno_core::v8::fast_api::CType;
- use deno_core::v8::fast_api::Type::*;
- Some(
- deno_core::v8::fast_api::FastFunction::new(
- &[V8Value, Pointer, TypedArray(CType::Uint32), CallbackOptions],
- CType::Void,
- Self::op_ffi_ptr_value_fast_fn as *const ::std::ffi::c_void,
- ),
- )
- },
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 0,
- };
-}
-#[doc(hidden)]
-impl op_ffi_ptr_value {
- pub const fn name() -> &'static str {
- stringify!(op_ffi_ptr_value)
- }
- #[allow(clippy::not_unsafe_ptr_arg_deref)]
- pub extern "C" fn v8_fn_ptr(info: *const deno_core::v8::FunctionCallbackInfo) {
- let info = unsafe { &*info };
- let scope = &mut unsafe { deno_core::v8::CallbackScope::new(info) };
- let args = deno_core::v8::FunctionCallbackArguments::from_function_callback_info(
- info,
- );
- let rv = deno_core::v8::ReturnValue::from_function_callback_info(info);
- Self::v8_func(scope, args, rv);
- }
- pub const fn decl() -> deno_core::OpDecl {
- deno_core::OpDecl {
- name: Self::name(),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: {
- use deno_core::v8::fast_api::CType;
- use deno_core::v8::fast_api::Type::*;
- Some(
- deno_core::v8::fast_api::FastFunction::new(
- &[V8Value, Pointer, TypedArray(CType::Uint32), CallbackOptions],
- CType::Void,
- Self::op_ffi_ptr_value_fast_fn as *const ::std::ffi::c_void,
- ),
- )
- },
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 2usize as u8,
- }
- }
- #[inline]
- #[allow(clippy::too_many_arguments)]
- #[allow(clippy::extra_unused_lifetimes)]
- pub fn call<'scope>(ptr: *mut c_void, out: &mut [u32]) {}
- pub fn v8_func<'scope>(
- scope: &mut deno_core::v8::HandleScope<'scope>,
- args: deno_core::v8::FunctionCallbackArguments,
- mut rv: deno_core::v8::ReturnValue,
- ) {
- let ctx = unsafe {
- &*(deno_core::v8::Local::<deno_core::v8::External>::cast(args.data()).value()
- as *const deno_core::_ops::OpCtx)
- };
- let arg_0 = {
- let value = args.get(0usize as i32);
- if value.is_null() {
- std::ptr::null_mut()
- } else if let Ok(b)
- = deno_core::v8::Local::<deno_core::v8::External>::try_from(value) {
- b.value()
- } else {
- return deno_core::_ops::throw_type_error(
- scope,
- format!("Expected External at position {}", 0usize),
- );
- }
- };
- let arg_1 = if let Ok(view)
- = deno_core::v8::Local::<
- deno_core::v8::Uint32Array,
- >::try_from(args.get(1usize as i32)) {
- let (offset, len) = (view.byte_offset(), view.byte_length());
- let buffer = match view.buffer(scope) {
- Some(v) => v,
- None => {
- return deno_core::_ops::throw_type_error(
- scope,
- format!("Expected Uint32Array at position {}", 1usize),
- );
- }
- };
- if let Some(data) = buffer.data() {
- let store = data.cast::<u8>().as_ptr();
- unsafe {
- ::std::slice::from_raw_parts_mut(
- store.add(offset) as *mut u32,
- len / 4,
- )
- }
- } else {
- &mut []
- }
- } else {
- return deno_core::_ops::throw_type_error(
- scope,
- format!("Expected Uint32Array at position {}", 1usize),
- );
- };
- let result = Self::call(arg_0, arg_1);
- let op_state = ::std::cell::RefCell::borrow(&*ctx.state);
- op_state.tracker.track_sync(ctx.id);
- }
-}
-impl op_ffi_ptr_value {
- #[allow(clippy::too_many_arguments)]
- fn op_ffi_ptr_value_fast_fn(
- _: deno_core::v8::Local<deno_core::v8::Object>,
- ptr: *mut ::std::ffi::c_void,
- out: *const deno_core::v8::fast_api::FastApiTypedArray<u32>,
- fast_api_callback_options: *mut deno_core::v8::fast_api::FastApiCallbackOptions,
- ) -> () {
- use deno_core::v8;
- use deno_core::_ops;
- let out = match unsafe { &*out }.get_storage_if_aligned() {
- Some(v) => v,
- None => {
- unsafe { &mut *fast_api_callback_options }.fallback = true;
- return Default::default();
- }
- };
- let result = Self::call(ptr, out);
- result
- }
-}
diff --git a/ops/optimizer_tests/op_ffi_ptr_value.rs b/ops/optimizer_tests/op_ffi_ptr_value.rs
deleted file mode 100644
index 4c3364507..000000000
--- a/ops/optimizer_tests/op_ffi_ptr_value.rs
+++ /dev/null
@@ -1,3 +0,0 @@
-pub fn op_ffi_ptr_value(ptr: *mut c_void, out: &mut [u32]) {
- // ...
-}
diff --git a/ops/optimizer_tests/op_print.expected b/ops/optimizer_tests/op_print.expected
deleted file mode 100644
index 6095c138e..000000000
--- a/ops/optimizer_tests/op_print.expected
+++ /dev/null
@@ -1,11 +0,0 @@
-=== Optimizer Dump ===
-returns_result: true
-has_ref_opstate: true
-has_rc_opstate: false
-has_fast_callback_option: false
-needs_fast_callback_option: true
-fast_result: Some(Void)
-fast_parameters: [V8Value, SeqOneByteString, Bool]
-transforms: {1: Transform { kind: SeqOneByteString(Ref), index: 1 }}
-is_async: false
-fast_compatible: false
diff --git a/ops/optimizer_tests/op_print.out b/ops/optimizer_tests/op_print.out
deleted file mode 100644
index 5023a6b03..000000000
--- a/ops/optimizer_tests/op_print.out
+++ /dev/null
@@ -1,108 +0,0 @@
-#[allow(non_camel_case_types)]
-///Auto-generated by `deno_ops`, i.e: `#[op]`
-///
-///Use `op_print::decl()` to get an op-declaration
-///you can include in a `deno_core::Extension`.
-pub struct op_print {
- _phantom_data: ::std::marker::PhantomData<()>,
-}
-impl deno_core::_ops::Op for op_print {
- const NAME: &'static str = stringify!(op_print);
- const DECL: deno_core::OpDecl = deno_core::OpDecl {
- name: Self::name(),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: None,
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 0,
- };
-}
-#[doc(hidden)]
-impl op_print {
- pub const fn name() -> &'static str {
- stringify!(op_print)
- }
- #[allow(clippy::not_unsafe_ptr_arg_deref)]
- pub extern "C" fn v8_fn_ptr(info: *const deno_core::v8::FunctionCallbackInfo) {
- let info = unsafe { &*info };
- let scope = &mut unsafe { deno_core::v8::CallbackScope::new(info) };
- let args = deno_core::v8::FunctionCallbackArguments::from_function_callback_info(
- info,
- );
- let rv = deno_core::v8::ReturnValue::from_function_callback_info(info);
- Self::v8_func(scope, args, rv);
- }
- pub const fn decl() -> deno_core::OpDecl {
- deno_core::OpDecl {
- name: Self::name(),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: None,
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 2usize as u8,
- }
- }
- #[inline]
- #[allow(clippy::too_many_arguments)]
- #[allow(clippy::extra_unused_lifetimes)]
- fn call<'scope>(
- state: &mut OpState,
- msg: &str,
- is_err: bool,
- ) -> Result<(), AnyError> {}
- pub fn v8_func<'scope>(
- scope: &mut deno_core::v8::HandleScope<'scope>,
- args: deno_core::v8::FunctionCallbackArguments,
- mut rv: deno_core::v8::ReturnValue,
- ) {
- let ctx = unsafe {
- &*(deno_core::v8::Local::<deno_core::v8::External>::cast(args.data()).value()
- as *const deno_core::_ops::OpCtx)
- };
- let arg_0 = match deno_core::v8::Local::<
- deno_core::v8::String,
- >::try_from(args.get(0usize as i32)) {
- Ok(v8_string) => deno_core::serde_v8::to_utf8(v8_string, scope),
- Err(_) => {
- return deno_core::_ops::throw_type_error(
- scope,
- format!("Expected string at position {}", 0usize),
- );
- }
- };
- let arg_0 = arg_0.as_ref();
- let arg_1 = args.get(1usize as i32);
- let arg_1 = match deno_core::serde_v8::from_v8(scope, arg_1) {
- Ok(v) => v,
- Err(err) => {
- let msg = format!(
- "Error parsing args at position {}: {}", 1usize,
- deno_core::anyhow::Error::from(err)
- );
- return deno_core::_ops::throw_type_error(scope, msg);
- }
- };
- let result = Self::call(
- &mut std::cell::RefCell::borrow_mut(&ctx.state),
- arg_0,
- arg_1,
- );
- let op_state = ::std::cell::RefCell::borrow(&*ctx.state);
- op_state.tracker.track_sync(ctx.id);
- match result {
- Ok(result) => {}
- Err(err) => {
- let exception = deno_core::error::to_v8_error(
- scope,
- op_state.get_error_class_fn,
- &err,
- );
- scope.throw_exception(exception);
- }
- };
- }
-}
diff --git a/ops/optimizer_tests/op_print.rs b/ops/optimizer_tests/op_print.rs
deleted file mode 100644
index 776ee8418..000000000
--- a/ops/optimizer_tests/op_print.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-fn op_print(
- state: &mut OpState,
- msg: &str,
- is_err: bool,
-) -> Result<(), AnyError> {
- // TODO(@littledivy): fast compatible https://github.com/denoland/deno/issues/17159
-}
diff --git a/ops/optimizer_tests/op_state.expected b/ops/optimizer_tests/op_state.expected
deleted file mode 100644
index 241ea7693..000000000
--- a/ops/optimizer_tests/op_state.expected
+++ /dev/null
@@ -1,11 +0,0 @@
-=== Optimizer Dump ===
-returns_result: false
-has_ref_opstate: true
-has_rc_opstate: false
-has_fast_callback_option: false
-needs_fast_callback_option: false
-fast_result: Some(Void)
-fast_parameters: [V8Value, I32]
-transforms: {}
-is_async: false
-fast_compatible: true
diff --git a/ops/optimizer_tests/op_state.out b/ops/optimizer_tests/op_state.out
deleted file mode 100644
index 1b6d86b06..000000000
--- a/ops/optimizer_tests/op_state.out
+++ /dev/null
@@ -1,120 +0,0 @@
-#[allow(non_camel_case_types)]
-///Auto-generated by `deno_ops`, i.e: `#[op]`
-///
-///Use `op_set_exit_code::decl()` to get an op-declaration
-///you can include in a `deno_core::Extension`.
-pub struct op_set_exit_code {
- _phantom_data: ::std::marker::PhantomData<()>,
-}
-impl deno_core::_ops::Op for op_set_exit_code {
- const NAME: &'static str = stringify!(op_set_exit_code);
- const DECL: deno_core::OpDecl = deno_core::OpDecl {
- name: Self::name(),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: {
- use deno_core::v8::fast_api::CType;
- use deno_core::v8::fast_api::Type::*;
- Some(
- deno_core::v8::fast_api::FastFunction::new(
- &[V8Value, Int32, CallbackOptions],
- CType::Void,
- Self::op_set_exit_code_fast_fn as *const ::std::ffi::c_void,
- ),
- )
- },
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 0,
- };
-}
-#[doc(hidden)]
-impl op_set_exit_code {
- pub const fn name() -> &'static str {
- stringify!(op_set_exit_code)
- }
- #[allow(clippy::not_unsafe_ptr_arg_deref)]
- pub extern "C" fn v8_fn_ptr(info: *const deno_core::v8::FunctionCallbackInfo) {
- let info = unsafe { &*info };
- let scope = &mut unsafe { deno_core::v8::CallbackScope::new(info) };
- let args = deno_core::v8::FunctionCallbackArguments::from_function_callback_info(
- info,
- );
- let rv = deno_core::v8::ReturnValue::from_function_callback_info(info);
- Self::v8_func(scope, args, rv);
- }
- pub const fn decl() -> deno_core::OpDecl {
- deno_core::OpDecl {
- name: Self::name(),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: {
- use deno_core::v8::fast_api::CType;
- use deno_core::v8::fast_api::Type::*;
- Some(
- deno_core::v8::fast_api::FastFunction::new(
- &[V8Value, Int32, CallbackOptions],
- CType::Void,
- Self::op_set_exit_code_fast_fn as *const ::std::ffi::c_void,
- ),
- )
- },
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 1usize as u8,
- }
- }
- #[inline]
- #[allow(clippy::too_many_arguments)]
- #[allow(clippy::extra_unused_lifetimes)]
- fn call<'scope>(state: &mut OpState, code: i32) {
- state.borrow_mut::<ExitCode>().set(code);
- }
- pub fn v8_func<'scope>(
- scope: &mut deno_core::v8::HandleScope<'scope>,
- args: deno_core::v8::FunctionCallbackArguments,
- mut rv: deno_core::v8::ReturnValue,
- ) {
- let ctx = unsafe {
- &*(deno_core::v8::Local::<deno_core::v8::External>::cast(args.data()).value()
- as *const deno_core::_ops::OpCtx)
- };
- let arg_0 = args.get(0usize as i32);
- let arg_0 = match deno_core::serde_v8::from_v8(scope, arg_0) {
- Ok(v) => v,
- Err(err) => {
- let msg = format!(
- "Error parsing args at position {}: {}", 0usize,
- deno_core::anyhow::Error::from(err)
- );
- return deno_core::_ops::throw_type_error(scope, msg);
- }
- };
- let result = Self::call(&mut std::cell::RefCell::borrow_mut(&ctx.state), arg_0);
- let op_state = ::std::cell::RefCell::borrow(&*ctx.state);
- op_state.tracker.track_sync(ctx.id);
- }
-}
-impl op_set_exit_code {
- #[allow(clippy::too_many_arguments)]
- fn op_set_exit_code_fast_fn(
- _: deno_core::v8::Local<deno_core::v8::Object>,
- code: i32,
- fast_api_callback_options: *mut deno_core::v8::fast_api::FastApiCallbackOptions,
- ) -> () {
- use deno_core::v8;
- use deno_core::_ops;
- let __opts: &mut v8::fast_api::FastApiCallbackOptions = unsafe {
- &mut *fast_api_callback_options
- };
- let __ctx = unsafe {
- &*(v8::Local::<v8::External>::cast(unsafe { __opts.data.data }).value()
- as *const _ops::OpCtx)
- };
- let state = &mut ::std::cell::RefCell::borrow_mut(&__ctx.state);
- let result = Self::call(state, code);
- result
- }
-}
diff --git a/ops/optimizer_tests/op_state.rs b/ops/optimizer_tests/op_state.rs
deleted file mode 100644
index 04e9a886d..000000000
--- a/ops/optimizer_tests/op_state.rs
+++ /dev/null
@@ -1,3 +0,0 @@
-fn op_set_exit_code(state: &mut OpState, code: i32) {
- state.borrow_mut::<ExitCode>().set(code);
-}
diff --git a/ops/optimizer_tests/op_state_basic1.expected b/ops/optimizer_tests/op_state_basic1.expected
deleted file mode 100644
index e325dd2f7..000000000
--- a/ops/optimizer_tests/op_state_basic1.expected
+++ /dev/null
@@ -1,11 +0,0 @@
-=== Optimizer Dump ===
-returns_result: false
-has_ref_opstate: true
-has_rc_opstate: false
-has_fast_callback_option: false
-needs_fast_callback_option: false
-fast_result: Some(U32)
-fast_parameters: [V8Value, U32, U32]
-transforms: {}
-is_async: false
-fast_compatible: true
diff --git a/ops/optimizer_tests/op_state_basic1.out b/ops/optimizer_tests/op_state_basic1.out
deleted file mode 100644
index 284232a3a..000000000
--- a/ops/optimizer_tests/op_state_basic1.out
+++ /dev/null
@@ -1,148 +0,0 @@
-#[allow(non_camel_case_types)]
-///Auto-generated by `deno_ops`, i.e: `#[op]`
-///
-///Use `foo::decl()` to get an op-declaration
-///you can include in a `deno_core::Extension`.
-pub struct foo {
- _phantom_data: ::std::marker::PhantomData<()>,
-}
-impl deno_core::_ops::Op for foo {
- const NAME: &'static str = stringify!(foo);
- const DECL: deno_core::OpDecl = deno_core::OpDecl {
- name: Self::name(),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: {
- use deno_core::v8::fast_api::CType;
- use deno_core::v8::fast_api::Type::*;
- Some(
- deno_core::v8::fast_api::FastFunction::new(
- &[V8Value, Uint32, Uint32, CallbackOptions],
- CType::Uint32,
- Self::foo_fast_fn as *const ::std::ffi::c_void,
- ),
- )
- },
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 0,
- };
-}
-#[doc(hidden)]
-impl foo {
- pub const fn name() -> &'static str {
- stringify!(foo)
- }
- #[allow(clippy::not_unsafe_ptr_arg_deref)]
- pub extern "C" fn v8_fn_ptr(info: *const deno_core::v8::FunctionCallbackInfo) {
- let info = unsafe { &*info };
- let scope = &mut unsafe { deno_core::v8::CallbackScope::new(info) };
- let args = deno_core::v8::FunctionCallbackArguments::from_function_callback_info(
- info,
- );
- let rv = deno_core::v8::ReturnValue::from_function_callback_info(info);
- Self::v8_func(scope, args, rv);
- }
- pub const fn decl() -> deno_core::OpDecl {
- deno_core::OpDecl {
- name: Self::name(),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: {
- use deno_core::v8::fast_api::CType;
- use deno_core::v8::fast_api::Type::*;
- Some(
- deno_core::v8::fast_api::FastFunction::new(
- &[V8Value, Uint32, Uint32, CallbackOptions],
- CType::Uint32,
- Self::foo_fast_fn as *const ::std::ffi::c_void,
- ),
- )
- },
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 2usize as u8,
- }
- }
- #[inline]
- #[allow(clippy::too_many_arguments)]
- #[allow(clippy::extra_unused_lifetimes)]
- fn call<'scope>(state: &mut OpState, a: u32, b: u32) -> u32 {
- a + b
- }
- pub fn v8_func<'scope>(
- scope: &mut deno_core::v8::HandleScope<'scope>,
- args: deno_core::v8::FunctionCallbackArguments,
- mut rv: deno_core::v8::ReturnValue,
- ) {
- let ctx = unsafe {
- &*(deno_core::v8::Local::<deno_core::v8::External>::cast(args.data()).value()
- as *const deno_core::_ops::OpCtx)
- };
- let arg_0 = args.get(0usize as i32);
- let arg_0 = match deno_core::serde_v8::from_v8(scope, arg_0) {
- Ok(v) => v,
- Err(err) => {
- let msg = format!(
- "Error parsing args at position {}: {}", 0usize,
- deno_core::anyhow::Error::from(err)
- );
- return deno_core::_ops::throw_type_error(scope, msg);
- }
- };
- let arg_1 = args.get(1usize as i32);
- let arg_1 = match deno_core::serde_v8::from_v8(scope, arg_1) {
- Ok(v) => v,
- Err(err) => {
- let msg = format!(
- "Error parsing args at position {}: {}", 1usize,
- deno_core::anyhow::Error::from(err)
- );
- return deno_core::_ops::throw_type_error(scope, msg);
- }
- };
- let result = Self::call(
- &mut std::cell::RefCell::borrow_mut(&ctx.state),
- arg_0,
- arg_1,
- );
- let op_state = ::std::cell::RefCell::borrow(&*ctx.state);
- op_state.tracker.track_sync(ctx.id);
- match deno_core::serde_v8::to_v8(scope, result) {
- Ok(ret) => rv.set(ret),
- Err(err) => {
- deno_core::_ops::throw_type_error(
- scope,
- format!(
- "Error serializing return: {}",
- deno_core::anyhow::Error::from(err)
- ),
- )
- }
- };
- }
-}
-impl foo {
- #[allow(clippy::too_many_arguments)]
- fn foo_fast_fn(
- _: deno_core::v8::Local<deno_core::v8::Object>,
- a: u32,
- b: u32,
- fast_api_callback_options: *mut deno_core::v8::fast_api::FastApiCallbackOptions,
- ) -> u32 {
- use deno_core::v8;
- use deno_core::_ops;
- let __opts: &mut v8::fast_api::FastApiCallbackOptions = unsafe {
- &mut *fast_api_callback_options
- };
- let __ctx = unsafe {
- &*(v8::Local::<v8::External>::cast(unsafe { __opts.data.data }).value()
- as *const _ops::OpCtx)
- };
- let state = &mut ::std::cell::RefCell::borrow_mut(&__ctx.state);
- let result = Self::call(state, a, b);
- result
- }
-}
diff --git a/ops/optimizer_tests/op_state_basic1.rs b/ops/optimizer_tests/op_state_basic1.rs
deleted file mode 100644
index 9c89b41ce..000000000
--- a/ops/optimizer_tests/op_state_basic1.rs
+++ /dev/null
@@ -1,3 +0,0 @@
-fn foo(state: &mut OpState, a: u32, b: u32) -> u32 {
- a + b
-}
diff --git a/ops/optimizer_tests/op_state_generics.expected b/ops/optimizer_tests/op_state_generics.expected
deleted file mode 100644
index c29258d75..000000000
--- a/ops/optimizer_tests/op_state_generics.expected
+++ /dev/null
@@ -1,11 +0,0 @@
-=== Optimizer Dump ===
-returns_result: false
-has_ref_opstate: true
-has_rc_opstate: false
-has_fast_callback_option: false
-needs_fast_callback_option: false
-fast_result: Some(Void)
-fast_parameters: [V8Value]
-transforms: {}
-is_async: false
-fast_compatible: true
diff --git a/ops/optimizer_tests/op_state_generics.out b/ops/optimizer_tests/op_state_generics.out
deleted file mode 100644
index a3e476d9e..000000000
--- a/ops/optimizer_tests/op_state_generics.out
+++ /dev/null
@@ -1,115 +0,0 @@
-#[allow(non_camel_case_types)]
-///Auto-generated by `deno_ops`, i.e: `#[op]`
-///
-///Use `op_foo::decl()` to get an op-declaration
-///you can include in a `deno_core::Extension`.
-pub struct op_foo<SP> {
- _phantom_data: ::std::marker::PhantomData<(SP)>,
-}
-impl<SP> deno_core::_ops::Op for op_foo<SP>
-where
- SP: SomePermission + 'static,
-{
- const NAME: &'static str = stringify!(op_foo);
- const DECL: deno_core::OpDecl = deno_core::OpDecl {
- name: Self::name(),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: {
- use deno_core::v8::fast_api::CType;
- use deno_core::v8::fast_api::Type::*;
- Some(
- deno_core::v8::fast_api::FastFunction::new(
- &[V8Value, CallbackOptions],
- CType::Void,
- Self::op_foo_fast_fn as *const ::std::ffi::c_void,
- ),
- )
- },
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 0,
- };
-}
-#[doc(hidden)]
-impl<SP> op_foo<SP>
-where
- SP: SomePermission + 'static,
-{
- pub const fn name() -> &'static str {
- stringify!(op_foo)
- }
- #[allow(clippy::not_unsafe_ptr_arg_deref)]
- pub extern "C" fn v8_fn_ptr(info: *const deno_core::v8::FunctionCallbackInfo) {
- let info = unsafe { &*info };
- let scope = &mut unsafe { deno_core::v8::CallbackScope::new(info) };
- let args = deno_core::v8::FunctionCallbackArguments::from_function_callback_info(
- info,
- );
- let rv = deno_core::v8::ReturnValue::from_function_callback_info(info);
- Self::v8_func(scope, args, rv);
- }
- pub const fn decl() -> deno_core::OpDecl {
- deno_core::OpDecl {
- name: Self::name(),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: {
- use deno_core::v8::fast_api::CType;
- use deno_core::v8::fast_api::Type::*;
- Some(
- deno_core::v8::fast_api::FastFunction::new(
- &[V8Value, CallbackOptions],
- CType::Void,
- Self::op_foo_fast_fn as *const ::std::ffi::c_void,
- ),
- )
- },
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 0usize as u8,
- }
- }
- #[inline]
- #[allow(clippy::too_many_arguments)]
- #[allow(clippy::extra_unused_lifetimes)]
- pub fn call<'scope>(state: &mut OpState) {}
- pub fn v8_func<'scope>(
- scope: &mut deno_core::v8::HandleScope<'scope>,
- args: deno_core::v8::FunctionCallbackArguments,
- mut rv: deno_core::v8::ReturnValue,
- ) {
- let ctx = unsafe {
- &*(deno_core::v8::Local::<deno_core::v8::External>::cast(args.data()).value()
- as *const deno_core::_ops::OpCtx)
- };
- let result = Self::call(&mut std::cell::RefCell::borrow_mut(&ctx.state));
- let op_state = ::std::cell::RefCell::borrow(&*ctx.state);
- op_state.tracker.track_sync(ctx.id);
- }
-}
-impl<SP> op_foo<SP>
-where
- SP: SomePermission + 'static,
-{
- #[allow(clippy::too_many_arguments)]
- fn op_foo_fast_fn(
- _: deno_core::v8::Local<deno_core::v8::Object>,
- fast_api_callback_options: *mut deno_core::v8::fast_api::FastApiCallbackOptions,
- ) -> () {
- use deno_core::v8;
- use deno_core::_ops;
- let __opts: &mut v8::fast_api::FastApiCallbackOptions = unsafe {
- &mut *fast_api_callback_options
- };
- let __ctx = unsafe {
- &*(v8::Local::<v8::External>::cast(unsafe { __opts.data.data }).value()
- as *const _ops::OpCtx)
- };
- let state = &mut ::std::cell::RefCell::borrow_mut(&__ctx.state);
- let result = Self::call(state);
- result
- }
-}
diff --git a/ops/optimizer_tests/op_state_generics.rs b/ops/optimizer_tests/op_state_generics.rs
deleted file mode 100644
index 7fa498981..000000000
--- a/ops/optimizer_tests/op_state_generics.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-pub fn op_foo<SP>(state: &mut OpState)
-where
- SP: SomePermission + 'static,
-{
-}
diff --git a/ops/optimizer_tests/op_state_result.expected b/ops/optimizer_tests/op_state_result.expected
deleted file mode 100644
index 15ac033f3..000000000
--- a/ops/optimizer_tests/op_state_result.expected
+++ /dev/null
@@ -1,11 +0,0 @@
-=== Optimizer Dump ===
-returns_result: true
-has_ref_opstate: true
-has_rc_opstate: false
-has_fast_callback_option: false
-needs_fast_callback_option: false
-fast_result: Some(U32)
-fast_parameters: [V8Value, U32, U32]
-transforms: {}
-is_async: false
-fast_compatible: true
diff --git a/ops/optimizer_tests/op_state_result.out b/ops/optimizer_tests/op_state_result.out
deleted file mode 100644
index 67793d93a..000000000
--- a/ops/optimizer_tests/op_state_result.out
+++ /dev/null
@@ -1,168 +0,0 @@
-#[allow(non_camel_case_types)]
-///Auto-generated by `deno_ops`, i.e: `#[op]`
-///
-///Use `foo::decl()` to get an op-declaration
-///you can include in a `deno_core::Extension`.
-pub struct foo {
- _phantom_data: ::std::marker::PhantomData<()>,
-}
-impl deno_core::_ops::Op for foo {
- const NAME: &'static str = stringify!(foo);
- const DECL: deno_core::OpDecl = deno_core::OpDecl {
- name: Self::name(),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: {
- use deno_core::v8::fast_api::CType;
- use deno_core::v8::fast_api::Type::*;
- Some(
- deno_core::v8::fast_api::FastFunction::new(
- &[V8Value, Uint32, Uint32, CallbackOptions],
- CType::Uint32,
- Self::foo_fast_fn as *const ::std::ffi::c_void,
- ),
- )
- },
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 0,
- };
-}
-#[doc(hidden)]
-impl foo {
- pub const fn name() -> &'static str {
- stringify!(foo)
- }
- #[allow(clippy::not_unsafe_ptr_arg_deref)]
- pub extern "C" fn v8_fn_ptr(info: *const deno_core::v8::FunctionCallbackInfo) {
- let info = unsafe { &*info };
- let scope = &mut unsafe { deno_core::v8::CallbackScope::new(info) };
- let args = deno_core::v8::FunctionCallbackArguments::from_function_callback_info(
- info,
- );
- let rv = deno_core::v8::ReturnValue::from_function_callback_info(info);
- Self::v8_func(scope, args, rv);
- }
- pub const fn decl() -> deno_core::OpDecl {
- deno_core::OpDecl {
- name: Self::name(),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: {
- use deno_core::v8::fast_api::CType;
- use deno_core::v8::fast_api::Type::*;
- Some(
- deno_core::v8::fast_api::FastFunction::new(
- &[V8Value, Uint32, Uint32, CallbackOptions],
- CType::Uint32,
- Self::foo_fast_fn as *const ::std::ffi::c_void,
- ),
- )
- },
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 2usize as u8,
- }
- }
- #[inline]
- #[allow(clippy::too_many_arguments)]
- #[allow(clippy::extra_unused_lifetimes)]
- fn call<'scope>(state: &mut OpState, a: u32, b: u32) -> Result<u32, AnyError> {
- Ok(a + b)
- }
- pub fn v8_func<'scope>(
- scope: &mut deno_core::v8::HandleScope<'scope>,
- args: deno_core::v8::FunctionCallbackArguments,
- mut rv: deno_core::v8::ReturnValue,
- ) {
- let ctx = unsafe {
- &*(deno_core::v8::Local::<deno_core::v8::External>::cast(args.data()).value()
- as *const deno_core::_ops::OpCtx)
- };
- {
- let op_state = &mut std::cell::RefCell::borrow_mut(&ctx.state);
- if let Some(err) = op_state.last_fast_op_error.take() {
- let exception = deno_core::error::to_v8_error(
- scope,
- op_state.get_error_class_fn,
- &err,
- );
- scope.throw_exception(exception);
- return;
- }
- }
- let arg_0 = args.get(0usize as i32);
- let arg_0 = match deno_core::serde_v8::from_v8(scope, arg_0) {
- Ok(v) => v,
- Err(err) => {
- let msg = format!(
- "Error parsing args at position {}: {}", 0usize,
- deno_core::anyhow::Error::from(err)
- );
- return deno_core::_ops::throw_type_error(scope, msg);
- }
- };
- let arg_1 = args.get(1usize as i32);
- let arg_1 = match deno_core::serde_v8::from_v8(scope, arg_1) {
- Ok(v) => v,
- Err(err) => {
- let msg = format!(
- "Error parsing args at position {}: {}", 1usize,
- deno_core::anyhow::Error::from(err)
- );
- return deno_core::_ops::throw_type_error(scope, msg);
- }
- };
- let result = Self::call(
- &mut std::cell::RefCell::borrow_mut(&ctx.state),
- arg_0,
- arg_1,
- );
- let op_state = ::std::cell::RefCell::borrow(&*ctx.state);
- op_state.tracker.track_sync(ctx.id);
- match result {
- Ok(result) => {
- rv.set_uint32(result as u32);
- }
- Err(err) => {
- let exception = deno_core::error::to_v8_error(
- scope,
- op_state.get_error_class_fn,
- &err,
- );
- scope.throw_exception(exception);
- }
- };
- }
-}
-impl foo {
- #[allow(clippy::too_many_arguments)]
- fn foo_fast_fn(
- _: deno_core::v8::Local<deno_core::v8::Object>,
- a: u32,
- b: u32,
- fast_api_callback_options: *mut deno_core::v8::fast_api::FastApiCallbackOptions,
- ) -> u32 {
- use deno_core::v8;
- use deno_core::_ops;
- let __opts: &mut v8::fast_api::FastApiCallbackOptions = unsafe {
- &mut *fast_api_callback_options
- };
- let __ctx = unsafe {
- &*(v8::Local::<v8::External>::cast(unsafe { __opts.data.data }).value()
- as *const _ops::OpCtx)
- };
- let state = &mut ::std::cell::RefCell::borrow_mut(&__ctx.state);
- let result = Self::call(state, a, b);
- match result {
- Ok(result) => result,
- Err(err) => {
- state.last_fast_op_error.replace(err);
- __opts.fallback = true;
- Default::default()
- }
- }
- }
-}
diff --git a/ops/optimizer_tests/op_state_result.rs b/ops/optimizer_tests/op_state_result.rs
deleted file mode 100644
index 331005c08..000000000
--- a/ops/optimizer_tests/op_state_result.rs
+++ /dev/null
@@ -1,3 +0,0 @@
-fn foo(state: &mut OpState, a: u32, b: u32) -> Result<u32, AnyError> {
- Ok(a + b)
-}
diff --git a/ops/optimizer_tests/op_state_warning.expected b/ops/optimizer_tests/op_state_warning.expected
deleted file mode 100644
index 7b33ad1ef..000000000
--- a/ops/optimizer_tests/op_state_warning.expected
+++ /dev/null
@@ -1,11 +0,0 @@
-=== Optimizer Dump ===
-returns_result: true
-has_ref_opstate: true
-has_rc_opstate: false
-has_fast_callback_option: false
-needs_fast_callback_option: false
-fast_result: Some(U32)
-fast_parameters: [V8Value]
-transforms: {}
-is_async: false
-fast_compatible: true
diff --git a/ops/optimizer_tests/op_state_warning.out b/ops/optimizer_tests/op_state_warning.out
deleted file mode 100644
index 51947f90a..000000000
--- a/ops/optimizer_tests/op_state_warning.out
+++ /dev/null
@@ -1,157 +0,0 @@
-#[allow(non_camel_case_types)]
-///Auto-generated by `deno_ops`, i.e: `#[op]`
-///
-///Use `op_listen::decl()` to get an op-declaration
-///you can include in a `deno_core::Extension`.
-pub struct op_listen {
- _phantom_data: ::std::marker::PhantomData<()>,
-}
-impl deno_core::_ops::Op for op_listen {
- const NAME: &'static str = stringify!(op_listen);
- const DECL: deno_core::OpDecl = deno_core::OpDecl {
- name: Self::name(),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: {
- use deno_core::v8::fast_api::CType;
- use deno_core::v8::fast_api::Type::*;
- Some(
- deno_core::v8::fast_api::FastFunction::new(
- &[V8Value, CallbackOptions],
- CType::Uint32,
- Self::op_listen_fast_fn as *const ::std::ffi::c_void,
- ),
- )
- },
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 0,
- };
-}
-#[doc(hidden)]
-impl op_listen {
- pub const fn name() -> &'static str {
- stringify!(op_listen)
- }
- #[allow(clippy::not_unsafe_ptr_arg_deref)]
- pub extern "C" fn v8_fn_ptr(info: *const deno_core::v8::FunctionCallbackInfo) {
- let info = unsafe { &*info };
- let scope = &mut unsafe { deno_core::v8::CallbackScope::new(info) };
- let args = deno_core::v8::FunctionCallbackArguments::from_function_callback_info(
- info,
- );
- let rv = deno_core::v8::ReturnValue::from_function_callback_info(info);
- Self::v8_func(scope, args, rv);
- }
- pub const fn decl() -> deno_core::OpDecl {
- deno_core::OpDecl {
- name: Self::name(),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: {
- use deno_core::v8::fast_api::CType;
- use deno_core::v8::fast_api::Type::*;
- Some(
- deno_core::v8::fast_api::FastFunction::new(
- &[V8Value, CallbackOptions],
- CType::Uint32,
- Self::op_listen_fast_fn as *const ::std::ffi::c_void,
- ),
- )
- },
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 0usize as u8,
- }
- }
- #[inline]
- #[allow(clippy::too_many_arguments)]
- #[allow(clippy::extra_unused_lifetimes)]
- fn call<'scope>(state: &mut OpState) -> Result<ResourceId, Error> {
- log::debug!("listen");
- let addr = "127.0.0.1:4570".parse::<SocketAddr>().unwrap();
- let std_listener = std::net::TcpListener::bind(&addr)?;
- std_listener.set_nonblocking(true)?;
- let listener = TcpListener::try_from(std_listener)?;
- let rid = state.resource_table.add(listener);
- Ok(rid)
- }
- pub fn v8_func<'scope>(
- scope: &mut deno_core::v8::HandleScope<'scope>,
- args: deno_core::v8::FunctionCallbackArguments,
- mut rv: deno_core::v8::ReturnValue,
- ) {
- let ctx = unsafe {
- &*(deno_core::v8::Local::<deno_core::v8::External>::cast(args.data()).value()
- as *const deno_core::_ops::OpCtx)
- };
- {
- let op_state = &mut std::cell::RefCell::borrow_mut(&ctx.state);
- if let Some(err) = op_state.last_fast_op_error.take() {
- let exception = deno_core::error::to_v8_error(
- scope,
- op_state.get_error_class_fn,
- &err,
- );
- scope.throw_exception(exception);
- return;
- }
- }
- let result = Self::call(&mut std::cell::RefCell::borrow_mut(&ctx.state));
- let op_state = ::std::cell::RefCell::borrow(&*ctx.state);
- op_state.tracker.track_sync(ctx.id);
- match result {
- Ok(result) => {
- match deno_core::serde_v8::to_v8(scope, result) {
- Ok(ret) => rv.set(ret),
- Err(err) => {
- deno_core::_ops::throw_type_error(
- scope,
- format!(
- "Error serializing return: {}",
- deno_core::anyhow::Error::from(err)
- ),
- )
- }
- };
- }
- Err(err) => {
- let exception = deno_core::error::to_v8_error(
- scope,
- op_state.get_error_class_fn,
- &err,
- );
- scope.throw_exception(exception);
- }
- };
- }
-}
-impl op_listen {
- #[allow(clippy::too_many_arguments)]
- fn op_listen_fast_fn(
- _: deno_core::v8::Local<deno_core::v8::Object>,
- fast_api_callback_options: *mut deno_core::v8::fast_api::FastApiCallbackOptions,
- ) -> u32 {
- use deno_core::v8;
- use deno_core::_ops;
- let __opts: &mut v8::fast_api::FastApiCallbackOptions = unsafe {
- &mut *fast_api_callback_options
- };
- let __ctx = unsafe {
- &*(v8::Local::<v8::External>::cast(unsafe { __opts.data.data }).value()
- as *const _ops::OpCtx)
- };
- let state = &mut ::std::cell::RefCell::borrow_mut(&__ctx.state);
- let result = Self::call(state);
- match result {
- Ok(result) => result,
- Err(err) => {
- state.last_fast_op_error.replace(err);
- __opts.fallback = true;
- Default::default()
- }
- }
- }
-}
diff --git a/ops/optimizer_tests/op_state_warning.rs b/ops/optimizer_tests/op_state_warning.rs
deleted file mode 100644
index a725e6f7e..000000000
--- a/ops/optimizer_tests/op_state_warning.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-fn op_listen(state: &mut OpState) -> Result<ResourceId, Error> {
- log::debug!("listen");
- let addr = "127.0.0.1:4570".parse::<SocketAddr>().unwrap();
- let std_listener = std::net::TcpListener::bind(&addr)?;
- std_listener.set_nonblocking(true)?;
- let listener = TcpListener::try_from(std_listener)?;
- let rid = state.resource_table.add(listener);
- Ok(rid)
-}
diff --git a/ops/optimizer_tests/op_state_with_transforms.expected b/ops/optimizer_tests/op_state_with_transforms.expected
deleted file mode 100644
index f5f236b7d..000000000
--- a/ops/optimizer_tests/op_state_with_transforms.expected
+++ /dev/null
@@ -1,11 +0,0 @@
-=== Optimizer Dump ===
-returns_result: false
-has_ref_opstate: true
-has_rc_opstate: false
-has_fast_callback_option: false
-needs_fast_callback_option: false
-fast_result: Some(Void)
-fast_parameters: [V8Value, Uint8Array]
-transforms: {1: Transform { kind: SliceU8(true), index: 1 }}
-is_async: false
-fast_compatible: true
diff --git a/ops/optimizer_tests/op_state_with_transforms.out b/ops/optimizer_tests/op_state_with_transforms.out
deleted file mode 100644
index 09303e269..000000000
--- a/ops/optimizer_tests/op_state_with_transforms.out
+++ /dev/null
@@ -1,162 +0,0 @@
-#[allow(non_camel_case_types)]
-///Auto-generated by `deno_ops`, i.e: `#[op]`
-///
-///Use `op_now::decl()` to get an op-declaration
-///you can include in a `deno_core::Extension`.
-pub struct op_now<TP> {
- _phantom_data: ::std::marker::PhantomData<(TP)>,
-}
-impl<TP> deno_core::_ops::Op for op_now<TP>
-where
- TP: TimersPermission + 'static,
-{
- const NAME: &'static str = stringify!(op_now);
- const DECL: deno_core::OpDecl = deno_core::OpDecl {
- name: Self::name(),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: {
- use deno_core::v8::fast_api::CType;
- use deno_core::v8::fast_api::Type::*;
- Some(
- deno_core::v8::fast_api::FastFunction::new(
- &[V8Value, TypedArray(CType::Uint8), CallbackOptions],
- CType::Void,
- Self::op_now_fast_fn as *const ::std::ffi::c_void,
- ),
- )
- },
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 0,
- };
-}
-#[doc(hidden)]
-impl<TP> op_now<TP>
-where
- TP: TimersPermission + 'static,
-{
- pub const fn name() -> &'static str {
- stringify!(op_now)
- }
- #[allow(clippy::not_unsafe_ptr_arg_deref)]
- pub extern "C" fn v8_fn_ptr(info: *const deno_core::v8::FunctionCallbackInfo) {
- let info = unsafe { &*info };
- let scope = &mut unsafe { deno_core::v8::CallbackScope::new(info) };
- let args = deno_core::v8::FunctionCallbackArguments::from_function_callback_info(
- info,
- );
- let rv = deno_core::v8::ReturnValue::from_function_callback_info(info);
- Self::v8_func(scope, args, rv);
- }
- pub const fn decl() -> deno_core::OpDecl {
- deno_core::OpDecl {
- name: Self::name(),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: {
- use deno_core::v8::fast_api::CType;
- use deno_core::v8::fast_api::Type::*;
- Some(
- deno_core::v8::fast_api::FastFunction::new(
- &[V8Value, TypedArray(CType::Uint8), CallbackOptions],
- CType::Void,
- Self::op_now_fast_fn as *const ::std::ffi::c_void,
- ),
- )
- },
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 1usize as u8,
- }
- }
- #[inline]
- #[allow(clippy::too_many_arguments)]
- #[allow(clippy::extra_unused_lifetimes)]
- pub fn call<'scope>(state: &mut OpState, buf: &mut [u8]) {}
- pub fn v8_func<'scope>(
- scope: &mut deno_core::v8::HandleScope<'scope>,
- args: deno_core::v8::FunctionCallbackArguments,
- mut rv: deno_core::v8::ReturnValue,
- ) {
- let ctx = unsafe {
- &*(deno_core::v8::Local::<deno_core::v8::External>::cast(args.data()).value()
- as *const deno_core::_ops::OpCtx)
- };
- let arg_0 = {
- let value = args.get(0usize as i32);
- match deno_core::v8::Local::<deno_core::v8::ArrayBuffer>::try_from(value) {
- Ok(b) => {
- let byte_length = b.byte_length();
- if let Some(data) = b.data() {
- let store = data.cast::<u8>().as_ptr();
- unsafe { ::std::slice::from_raw_parts_mut(store, byte_length) }
- } else {
- &mut []
- }
- }
- Err(_) => {
- if let Ok(view)
- = deno_core::v8::Local::<
- deno_core::v8::ArrayBufferView,
- >::try_from(value) {
- let len = view.byte_length();
- let offset = view.byte_offset();
- let buffer = match view.buffer(scope) {
- Some(v) => v,
- None => {
- return deno_core::_ops::throw_type_error(
- scope,
- format!("Expected ArrayBufferView at position {}", 0usize),
- );
- }
- };
- if let Some(data) = buffer.data() {
- let store = data.cast::<u8>().as_ptr();
- unsafe {
- ::std::slice::from_raw_parts_mut(store.add(offset), len)
- }
- } else {
- &mut []
- }
- } else {
- return deno_core::_ops::throw_type_error(
- scope,
- format!("Expected ArrayBufferView at position {}", 0usize),
- );
- }
- }
- }
- };
- let result = Self::call(&mut std::cell::RefCell::borrow_mut(&ctx.state), arg_0);
- let op_state = ::std::cell::RefCell::borrow(&*ctx.state);
- op_state.tracker.track_sync(ctx.id);
- }
-}
-impl<TP> op_now<TP>
-where
- TP: TimersPermission + 'static,
-{
- #[allow(clippy::too_many_arguments)]
- fn op_now_fast_fn(
- _: deno_core::v8::Local<deno_core::v8::Object>,
- buf: *const deno_core::v8::fast_api::FastApiTypedArray<u8>,
- fast_api_callback_options: *mut deno_core::v8::fast_api::FastApiCallbackOptions,
- ) -> () {
- use deno_core::v8;
- use deno_core::_ops;
- let __opts: &mut v8::fast_api::FastApiCallbackOptions = unsafe {
- &mut *fast_api_callback_options
- };
- let __ctx = unsafe {
- &*(v8::Local::<v8::External>::cast(unsafe { __opts.data.data }).value()
- as *const _ops::OpCtx)
- };
- let state = &mut ::std::cell::RefCell::borrow_mut(&__ctx.state);
- let buf = unsafe { (&*buf).get_storage_if_aligned().unwrap_unchecked() };
- let result = Self::call(state, buf);
- result
- }
-}
diff --git a/ops/optimizer_tests/op_state_with_transforms.rs b/ops/optimizer_tests/op_state_with_transforms.rs
deleted file mode 100644
index 4e7e616f3..000000000
--- a/ops/optimizer_tests/op_state_with_transforms.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-pub fn op_now<TP>(state: &mut OpState, buf: &mut [u8])
-where
- TP: TimersPermission + 'static,
-{
-}
diff --git a/ops/optimizer_tests/opstate_with_arity.expected b/ops/optimizer_tests/opstate_with_arity.expected
deleted file mode 100644
index b38455d0d..000000000
--- a/ops/optimizer_tests/opstate_with_arity.expected
+++ /dev/null
@@ -1,11 +0,0 @@
-=== Optimizer Dump ===
-returns_result: true
-has_ref_opstate: false
-has_rc_opstate: false
-has_fast_callback_option: false
-needs_fast_callback_option: false
-fast_result: Some(U32)
-fast_parameters: [V8Value, U32, U32, U32, U32]
-transforms: {}
-is_async: false
-fast_compatible: true
diff --git a/ops/optimizer_tests/opstate_with_arity.out b/ops/optimizer_tests/opstate_with_arity.out
deleted file mode 100644
index d7e85328a..000000000
--- a/ops/optimizer_tests/opstate_with_arity.out
+++ /dev/null
@@ -1,188 +0,0 @@
-#[allow(non_camel_case_types)]
-///Auto-generated by `deno_ops`, i.e: `#[op]`
-///
-///Use `op_add_4::decl()` to get an op-declaration
-///you can include in a `deno_core::Extension`.
-pub struct op_add_4 {
- _phantom_data: ::std::marker::PhantomData<()>,
-}
-impl deno_core::_ops::Op for op_add_4 {
- const NAME: &'static str = stringify!(op_add_4);
- const DECL: deno_core::OpDecl = deno_core::OpDecl {
- name: Self::name(),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: {
- use deno_core::v8::fast_api::CType;
- use deno_core::v8::fast_api::Type::*;
- Some(
- deno_core::v8::fast_api::FastFunction::new(
- &[V8Value, Uint32, Uint32, Uint32, Uint32, CallbackOptions],
- CType::Uint32,
- Self::op_add_4_fast_fn as *const ::std::ffi::c_void,
- ),
- )
- },
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 0,
- };
-}
-#[doc(hidden)]
-impl op_add_4 {
- pub const fn name() -> &'static str {
- stringify!(op_add_4)
- }
- #[allow(clippy::not_unsafe_ptr_arg_deref)]
- pub extern "C" fn v8_fn_ptr(info: *const deno_core::v8::FunctionCallbackInfo) {
- let info = unsafe { &*info };
- let scope = &mut unsafe { deno_core::v8::CallbackScope::new(info) };
- let args = deno_core::v8::FunctionCallbackArguments::from_function_callback_info(
- info,
- );
- let rv = deno_core::v8::ReturnValue::from_function_callback_info(info);
- Self::v8_func(scope, args, rv);
- }
- pub const fn decl() -> deno_core::OpDecl {
- deno_core::OpDecl {
- name: Self::name(),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: {
- use deno_core::v8::fast_api::CType;
- use deno_core::v8::fast_api::Type::*;
- Some(
- deno_core::v8::fast_api::FastFunction::new(
- &[V8Value, Uint32, Uint32, Uint32, Uint32, CallbackOptions],
- CType::Uint32,
- Self::op_add_4_fast_fn as *const ::std::ffi::c_void,
- ),
- )
- },
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 4usize as u8,
- }
- }
- #[inline]
- #[allow(clippy::too_many_arguments)]
- #[allow(clippy::extra_unused_lifetimes)]
- fn call<'scope>(x1: u32, x2: u32, x3: u32, x4: u32) -> Result<u32, anyhow::Error> {
- Ok(x1 + x2 + x3 + x4)
- }
- pub fn v8_func<'scope>(
- scope: &mut deno_core::v8::HandleScope<'scope>,
- args: deno_core::v8::FunctionCallbackArguments,
- mut rv: deno_core::v8::ReturnValue,
- ) {
- let ctx = unsafe {
- &*(deno_core::v8::Local::<deno_core::v8::External>::cast(args.data()).value()
- as *const deno_core::_ops::OpCtx)
- };
- {
- let op_state = &mut std::cell::RefCell::borrow_mut(&ctx.state);
- if let Some(err) = op_state.last_fast_op_error.take() {
- let exception = deno_core::error::to_v8_error(
- scope,
- op_state.get_error_class_fn,
- &err,
- );
- scope.throw_exception(exception);
- return;
- }
- }
- let arg_0 = args.get(0usize as i32);
- let arg_0 = match deno_core::serde_v8::from_v8(scope, arg_0) {
- Ok(v) => v,
- Err(err) => {
- let msg = format!(
- "Error parsing args at position {}: {}", 0usize,
- deno_core::anyhow::Error::from(err)
- );
- return deno_core::_ops::throw_type_error(scope, msg);
- }
- };
- let arg_1 = args.get(1usize as i32);
- let arg_1 = match deno_core::serde_v8::from_v8(scope, arg_1) {
- Ok(v) => v,
- Err(err) => {
- let msg = format!(
- "Error parsing args at position {}: {}", 1usize,
- deno_core::anyhow::Error::from(err)
- );
- return deno_core::_ops::throw_type_error(scope, msg);
- }
- };
- let arg_2 = args.get(2usize as i32);
- let arg_2 = match deno_core::serde_v8::from_v8(scope, arg_2) {
- Ok(v) => v,
- Err(err) => {
- let msg = format!(
- "Error parsing args at position {}: {}", 2usize,
- deno_core::anyhow::Error::from(err)
- );
- return deno_core::_ops::throw_type_error(scope, msg);
- }
- };
- let arg_3 = args.get(3usize as i32);
- let arg_3 = match deno_core::serde_v8::from_v8(scope, arg_3) {
- Ok(v) => v,
- Err(err) => {
- let msg = format!(
- "Error parsing args at position {}: {}", 3usize,
- deno_core::anyhow::Error::from(err)
- );
- return deno_core::_ops::throw_type_error(scope, msg);
- }
- };
- let result = Self::call(arg_0, arg_1, arg_2, arg_3);
- let op_state = ::std::cell::RefCell::borrow(&*ctx.state);
- op_state.tracker.track_sync(ctx.id);
- match result {
- Ok(result) => {
- rv.set_uint32(result as u32);
- }
- Err(err) => {
- let exception = deno_core::error::to_v8_error(
- scope,
- op_state.get_error_class_fn,
- &err,
- );
- scope.throw_exception(exception);
- }
- };
- }
-}
-impl op_add_4 {
- #[allow(clippy::too_many_arguments)]
- fn op_add_4_fast_fn(
- _: deno_core::v8::Local<deno_core::v8::Object>,
- x1: u32,
- x2: u32,
- x3: u32,
- x4: u32,
- fast_api_callback_options: *mut deno_core::v8::fast_api::FastApiCallbackOptions,
- ) -> u32 {
- use deno_core::v8;
- use deno_core::_ops;
- let __opts: &mut v8::fast_api::FastApiCallbackOptions = unsafe {
- &mut *fast_api_callback_options
- };
- let __ctx = unsafe {
- &*(v8::Local::<v8::External>::cast(unsafe { __opts.data.data }).value()
- as *const _ops::OpCtx)
- };
- let op_state = &mut ::std::cell::RefCell::borrow_mut(&__ctx.state);
- let result = Self::call(x1, x2, x3, x4);
- match result {
- Ok(result) => result,
- Err(err) => {
- op_state.last_fast_op_error.replace(err);
- __opts.fallback = true;
- Default::default()
- }
- }
- }
-}
diff --git a/ops/optimizer_tests/opstate_with_arity.rs b/ops/optimizer_tests/opstate_with_arity.rs
deleted file mode 100644
index 7212ca975..000000000
--- a/ops/optimizer_tests/opstate_with_arity.rs
+++ /dev/null
@@ -1,3 +0,0 @@
-fn op_add_4(x1: u32, x2: u32, x3: u32, x4: u32) -> Result<u32, anyhow::Error> {
- Ok(x1 + x2 + x3 + x4)
-}
diff --git a/ops/optimizer_tests/option_arg.expected b/ops/optimizer_tests/option_arg.expected
deleted file mode 100644
index 250ff1022..000000000
--- a/ops/optimizer_tests/option_arg.expected
+++ /dev/null
@@ -1 +0,0 @@
-FastUnsupportedParamType \ No newline at end of file
diff --git a/ops/optimizer_tests/option_arg.out b/ops/optimizer_tests/option_arg.out
deleted file mode 100644
index 5880ec88e..000000000
--- a/ops/optimizer_tests/option_arg.out
+++ /dev/null
@@ -1,91 +0,0 @@
-#[allow(non_camel_case_types)]
-///Auto-generated by `deno_ops`, i.e: `#[op]`
-///
-///Use `op_try_close::decl()` to get an op-declaration
-///you can include in a `deno_core::Extension`.
-pub struct op_try_close {
- _phantom_data: ::std::marker::PhantomData<()>,
-}
-impl deno_core::_ops::Op for op_try_close {
- const NAME: &'static str = stringify!(op_try_close);
- const DECL: deno_core::OpDecl = deno_core::OpDecl {
- name: Self::name(),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: None,
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 0,
- };
-}
-#[doc(hidden)]
-impl op_try_close {
- pub const fn name() -> &'static str {
- stringify!(op_try_close)
- }
- #[allow(clippy::not_unsafe_ptr_arg_deref)]
- pub extern "C" fn v8_fn_ptr(info: *const deno_core::v8::FunctionCallbackInfo) {
- let info = unsafe { &*info };
- let scope = &mut unsafe { deno_core::v8::CallbackScope::new(info) };
- let args = deno_core::v8::FunctionCallbackArguments::from_function_callback_info(
- info,
- );
- let rv = deno_core::v8::ReturnValue::from_function_callback_info(info);
- Self::v8_func(scope, args, rv);
- }
- pub const fn decl() -> deno_core::OpDecl {
- deno_core::OpDecl {
- name: Self::name(),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: None,
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 1usize as u8,
- }
- }
- #[inline]
- #[allow(clippy::too_many_arguments)]
- #[allow(clippy::extra_unused_lifetimes)]
- pub fn call<'scope>(
- state: &mut OpState,
- rid: Option<ResourceId>,
- ) -> Result<(), Error> {}
- pub fn v8_func<'scope>(
- scope: &mut deno_core::v8::HandleScope<'scope>,
- args: deno_core::v8::FunctionCallbackArguments,
- mut rv: deno_core::v8::ReturnValue,
- ) {
- let ctx = unsafe {
- &*(deno_core::v8::Local::<deno_core::v8::External>::cast(args.data()).value()
- as *const deno_core::_ops::OpCtx)
- };
- let arg_0 = args.get(0usize as i32);
- let arg_0 = match deno_core::serde_v8::from_v8(scope, arg_0) {
- Ok(v) => v,
- Err(err) => {
- let msg = format!(
- "Error parsing args at position {}: {}", 0usize,
- deno_core::anyhow::Error::from(err)
- );
- return deno_core::_ops::throw_type_error(scope, msg);
- }
- };
- let result = Self::call(&mut std::cell::RefCell::borrow_mut(&ctx.state), arg_0);
- let op_state = ::std::cell::RefCell::borrow(&*ctx.state);
- op_state.tracker.track_sync(ctx.id);
- match result {
- Ok(result) => {}
- Err(err) => {
- let exception = deno_core::error::to_v8_error(
- scope,
- op_state.get_error_class_fn,
- &err,
- );
- scope.throw_exception(exception);
- }
- };
- }
-}
diff --git a/ops/optimizer_tests/option_arg.rs b/ops/optimizer_tests/option_arg.rs
deleted file mode 100644
index 47a02974d..000000000
--- a/ops/optimizer_tests/option_arg.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-pub fn op_try_close(
- state: &mut OpState,
- rid: Option<ResourceId>,
-) -> Result<(), Error> {
- // ...
-}
diff --git a/ops/optimizer_tests/owned_string.expected b/ops/optimizer_tests/owned_string.expected
deleted file mode 100644
index 4c47a0525..000000000
--- a/ops/optimizer_tests/owned_string.expected
+++ /dev/null
@@ -1,11 +0,0 @@
-=== Optimizer Dump ===
-returns_result: false
-has_ref_opstate: false
-has_rc_opstate: false
-has_fast_callback_option: false
-needs_fast_callback_option: true
-fast_result: Some(U32)
-fast_parameters: [V8Value, SeqOneByteString]
-transforms: {0: Transform { kind: SeqOneByteString(Owned), index: 0 }}
-is_async: false
-fast_compatible: true
diff --git a/ops/optimizer_tests/owned_string.out b/ops/optimizer_tests/owned_string.out
deleted file mode 100644
index 58c7f72ae..000000000
--- a/ops/optimizer_tests/owned_string.out
+++ /dev/null
@@ -1,131 +0,0 @@
-#[allow(non_camel_case_types)]
-///Auto-generated by `deno_ops`, i.e: `#[op]`
-///
-///Use `op_string_length::decl()` to get an op-declaration
-///you can include in a `deno_core::Extension`.
-pub struct op_string_length {
- _phantom_data: ::std::marker::PhantomData<()>,
-}
-impl deno_core::_ops::Op for op_string_length {
- const NAME: &'static str = stringify!(op_string_length);
- const DECL: deno_core::OpDecl = deno_core::OpDecl {
- name: Self::name(),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: {
- use deno_core::v8::fast_api::CType;
- use deno_core::v8::fast_api::Type::*;
- Some(
- deno_core::v8::fast_api::FastFunction::new(
- &[V8Value, SeqOneByteString, CallbackOptions],
- CType::Uint32,
- Self::op_string_length_fast_fn as *const ::std::ffi::c_void,
- ),
- )
- },
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 0,
- };
-}
-#[doc(hidden)]
-impl op_string_length {
- pub const fn name() -> &'static str {
- stringify!(op_string_length)
- }
- #[allow(clippy::not_unsafe_ptr_arg_deref)]
- pub extern "C" fn v8_fn_ptr(info: *const deno_core::v8::FunctionCallbackInfo) {
- let info = unsafe { &*info };
- let scope = &mut unsafe { deno_core::v8::CallbackScope::new(info) };
- let args = deno_core::v8::FunctionCallbackArguments::from_function_callback_info(
- info,
- );
- let rv = deno_core::v8::ReturnValue::from_function_callback_info(info);
- Self::v8_func(scope, args, rv);
- }
- pub const fn decl() -> deno_core::OpDecl {
- deno_core::OpDecl {
- name: Self::name(),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: {
- use deno_core::v8::fast_api::CType;
- use deno_core::v8::fast_api::Type::*;
- Some(
- deno_core::v8::fast_api::FastFunction::new(
- &[V8Value, SeqOneByteString, CallbackOptions],
- CType::Uint32,
- Self::op_string_length_fast_fn as *const ::std::ffi::c_void,
- ),
- )
- },
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 1usize as u8,
- }
- }
- #[inline]
- #[allow(clippy::too_many_arguments)]
- #[allow(clippy::extra_unused_lifetimes)]
- fn call<'scope>(string: String) -> u32 {
- string.len() as u32
- }
- pub fn v8_func<'scope>(
- scope: &mut deno_core::v8::HandleScope<'scope>,
- args: deno_core::v8::FunctionCallbackArguments,
- mut rv: deno_core::v8::ReturnValue,
- ) {
- let ctx = unsafe {
- &*(deno_core::v8::Local::<deno_core::v8::External>::cast(args.data()).value()
- as *const deno_core::_ops::OpCtx)
- };
- let arg_0 = match deno_core::v8::Local::<
- deno_core::v8::String,
- >::try_from(args.get(0usize as i32)) {
- Ok(v8_string) => deno_core::serde_v8::to_utf8(v8_string, scope),
- Err(_) => {
- return deno_core::_ops::throw_type_error(
- scope,
- format!("Expected string at position {}", 0usize),
- );
- }
- };
- let result = Self::call(arg_0);
- let op_state = ::std::cell::RefCell::borrow(&*ctx.state);
- op_state.tracker.track_sync(ctx.id);
- match deno_core::serde_v8::to_v8(scope, result) {
- Ok(ret) => rv.set(ret),
- Err(err) => {
- deno_core::_ops::throw_type_error(
- scope,
- format!(
- "Error serializing return: {}",
- deno_core::anyhow::Error::from(err)
- ),
- )
- }
- };
- }
-}
-impl op_string_length {
- #[allow(clippy::too_many_arguments)]
- fn op_string_length_fast_fn(
- _: deno_core::v8::Local<deno_core::v8::Object>,
- string: *const deno_core::v8::fast_api::FastApiOneByteString,
- fast_api_callback_options: *mut deno_core::v8::fast_api::FastApiCallbackOptions,
- ) -> u32 {
- use deno_core::v8;
- use deno_core::_ops;
- let string = match ::std::str::from_utf8(unsafe { &*string }.as_bytes()) {
- Ok(v) => v.to_owned(),
- Err(_) => {
- unsafe { &mut *fast_api_callback_options }.fallback = true;
- return Default::default();
- }
- };
- let result = Self::call(string);
- result
- }
-}
diff --git a/ops/optimizer_tests/owned_string.rs b/ops/optimizer_tests/owned_string.rs
deleted file mode 100644
index 102cf00fb..000000000
--- a/ops/optimizer_tests/owned_string.rs
+++ /dev/null
@@ -1,3 +0,0 @@
-fn op_string_length(string: String) -> u32 {
- string.len() as u32
-}
diff --git a/ops/optimizer_tests/param_mut_binding_warning.expected b/ops/optimizer_tests/param_mut_binding_warning.expected
deleted file mode 100644
index 250ff1022..000000000
--- a/ops/optimizer_tests/param_mut_binding_warning.expected
+++ /dev/null
@@ -1 +0,0 @@
-FastUnsupportedParamType \ No newline at end of file
diff --git a/ops/optimizer_tests/param_mut_binding_warning.out b/ops/optimizer_tests/param_mut_binding_warning.out
deleted file mode 100644
index 43a33d6e3..000000000
--- a/ops/optimizer_tests/param_mut_binding_warning.out
+++ /dev/null
@@ -1,111 +0,0 @@
-#[allow(non_camel_case_types)]
-///Auto-generated by `deno_ops`, i.e: `#[op]`
-///
-///Use `op_read_sync::decl()` to get an op-declaration
-///you can include in a `deno_core::Extension`.
-pub struct op_read_sync {
- _phantom_data: ::std::marker::PhantomData<()>,
-}
-impl deno_core::_ops::Op for op_read_sync {
- const NAME: &'static str = stringify!(op_read_sync);
- const DECL: deno_core::OpDecl = deno_core::OpDecl {
- name: Self::name(),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: None,
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 0,
- };
-}
-#[doc(hidden)]
-impl op_read_sync {
- pub const fn name() -> &'static str {
- stringify!(op_read_sync)
- }
- #[allow(clippy::not_unsafe_ptr_arg_deref)]
- pub extern "C" fn v8_fn_ptr(info: *const deno_core::v8::FunctionCallbackInfo) {
- let info = unsafe { &*info };
- let scope = &mut unsafe { deno_core::v8::CallbackScope::new(info) };
- let args = deno_core::v8::FunctionCallbackArguments::from_function_callback_info(
- info,
- );
- let rv = deno_core::v8::ReturnValue::from_function_callback_info(info);
- Self::v8_func(scope, args, rv);
- }
- pub const fn decl() -> deno_core::OpDecl {
- deno_core::OpDecl {
- name: Self::name(),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: None,
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 2usize as u8,
- }
- }
- #[inline]
- #[allow(clippy::too_many_arguments)]
- #[allow(clippy::extra_unused_lifetimes)]
- fn call<'scope>(
- state: &mut OpState,
- rid: ResourceId,
- mut buf: ZeroCopyBuf,
- ) -> Result<u32, AnyError> {
- Ok(23)
- }
- pub fn v8_func<'scope>(
- scope: &mut deno_core::v8::HandleScope<'scope>,
- args: deno_core::v8::FunctionCallbackArguments,
- mut rv: deno_core::v8::ReturnValue,
- ) {
- let ctx = unsafe {
- &*(deno_core::v8::Local::<deno_core::v8::External>::cast(args.data()).value()
- as *const deno_core::_ops::OpCtx)
- };
- let arg_0 = args.get(0usize as i32);
- let arg_0 = match deno_core::serde_v8::from_v8(scope, arg_0) {
- Ok(v) => v,
- Err(err) => {
- let msg = format!(
- "Error parsing args at position {}: {}", 0usize,
- deno_core::anyhow::Error::from(err)
- );
- return deno_core::_ops::throw_type_error(scope, msg);
- }
- };
- let arg_1 = args.get(1usize as i32);
- let arg_1 = match deno_core::serde_v8::from_v8(scope, arg_1) {
- Ok(v) => v,
- Err(err) => {
- let msg = format!(
- "Error parsing args at position {}: {}", 1usize,
- deno_core::anyhow::Error::from(err)
- );
- return deno_core::_ops::throw_type_error(scope, msg);
- }
- };
- let result = Self::call(
- &mut std::cell::RefCell::borrow_mut(&ctx.state),
- arg_0,
- arg_1,
- );
- let op_state = ::std::cell::RefCell::borrow(&*ctx.state);
- op_state.tracker.track_sync(ctx.id);
- match result {
- Ok(result) => {
- rv.set_uint32(result as u32);
- }
- Err(err) => {
- let exception = deno_core::error::to_v8_error(
- scope,
- op_state.get_error_class_fn,
- &err,
- );
- scope.throw_exception(exception);
- }
- };
- }
-}
diff --git a/ops/optimizer_tests/param_mut_binding_warning.rs b/ops/optimizer_tests/param_mut_binding_warning.rs
deleted file mode 100644
index c47122728..000000000
--- a/ops/optimizer_tests/param_mut_binding_warning.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-fn op_read_sync(
- state: &mut OpState,
- rid: ResourceId,
- mut buf: ZeroCopyBuf,
-) -> Result<u32, AnyError> {
- // Should not warn about unused `mut buf` binding.
- //
- // This was caused due to incorrect codegen by fast_call.rs
- // on an incompatible op function.
- Ok(23)
-}
diff --git a/ops/optimizer_tests/raw_ptr.expected b/ops/optimizer_tests/raw_ptr.expected
deleted file mode 100644
index badd6e3f4..000000000
--- a/ops/optimizer_tests/raw_ptr.expected
+++ /dev/null
@@ -1,11 +0,0 @@
-=== Optimizer Dump ===
-returns_result: false
-has_ref_opstate: true
-has_rc_opstate: false
-has_fast_callback_option: false
-needs_fast_callback_option: true
-fast_result: Some(Void)
-fast_parameters: [V8Value, Uint8Array, Uint32Array]
-transforms: {1: Transform { kind: PtrU8, index: 1 }, 2: Transform { kind: SliceU32(true), index: 2 }}
-is_async: false
-fast_compatible: true
diff --git a/ops/optimizer_tests/raw_ptr.out b/ops/optimizer_tests/raw_ptr.out
deleted file mode 100644
index 18d2aaa4a..000000000
--- a/ops/optimizer_tests/raw_ptr.out
+++ /dev/null
@@ -1,211 +0,0 @@
-#[allow(non_camel_case_types)]
-///Auto-generated by `deno_ops`, i.e: `#[op]`
-///
-///Use `op_ffi_ptr_of::decl()` to get an op-declaration
-///you can include in a `deno_core::Extension`.
-pub struct op_ffi_ptr_of<FP> {
- _phantom_data: ::std::marker::PhantomData<(FP)>,
-}
-impl<FP> deno_core::_ops::Op for op_ffi_ptr_of<FP>
-where
- FP: FfiPermissions + 'static,
-{
- const NAME: &'static str = stringify!(op_ffi_ptr_of);
- const DECL: deno_core::OpDecl = deno_core::OpDecl {
- name: Self::name(),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: {
- use deno_core::v8::fast_api::CType;
- use deno_core::v8::fast_api::Type::*;
- Some(
- deno_core::v8::fast_api::FastFunction::new(
- &[
- V8Value,
- TypedArray(CType::Uint8),
- TypedArray(CType::Uint32),
- CallbackOptions,
- ],
- CType::Void,
- Self::op_ffi_ptr_of_fast_fn as *const ::std::ffi::c_void,
- ),
- )
- },
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 0,
- };
-}
-#[doc(hidden)]
-impl<FP> op_ffi_ptr_of<FP>
-where
- FP: FfiPermissions + 'static,
-{
- pub const fn name() -> &'static str {
- stringify!(op_ffi_ptr_of)
- }
- #[allow(clippy::not_unsafe_ptr_arg_deref)]
- pub extern "C" fn v8_fn_ptr(info: *const deno_core::v8::FunctionCallbackInfo) {
- let info = unsafe { &*info };
- let scope = &mut unsafe { deno_core::v8::CallbackScope::new(info) };
- let args = deno_core::v8::FunctionCallbackArguments::from_function_callback_info(
- info,
- );
- let rv = deno_core::v8::ReturnValue::from_function_callback_info(info);
- Self::v8_func(scope, args, rv);
- }
- pub const fn decl() -> deno_core::OpDecl {
- deno_core::OpDecl {
- name: Self::name(),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: {
- use deno_core::v8::fast_api::CType;
- use deno_core::v8::fast_api::Type::*;
- Some(
- deno_core::v8::fast_api::FastFunction::new(
- &[
- V8Value,
- TypedArray(CType::Uint8),
- TypedArray(CType::Uint32),
- CallbackOptions,
- ],
- CType::Void,
- Self::op_ffi_ptr_of_fast_fn as *const ::std::ffi::c_void,
- ),
- )
- },
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 2usize as u8,
- }
- }
- #[inline]
- #[allow(clippy::too_many_arguments)]
- #[allow(clippy::extra_unused_lifetimes)]
- fn call<'scope>(state: &mut OpState, buf: *const u8, out: &mut [u32]) {}
- pub fn v8_func<'scope>(
- scope: &mut deno_core::v8::HandleScope<'scope>,
- args: deno_core::v8::FunctionCallbackArguments,
- mut rv: deno_core::v8::ReturnValue,
- ) {
- let ctx = unsafe {
- &*(deno_core::v8::Local::<deno_core::v8::External>::cast(args.data()).value()
- as *const deno_core::_ops::OpCtx)
- };
- let arg_0 = {
- let value = args.get(0usize as i32);
- match deno_core::v8::Local::<deno_core::v8::ArrayBuffer>::try_from(value) {
- Ok(b) => {
- if let Some(data) = b.data() {
- data.cast::<u8>().as_ptr()
- } else {
- std::ptr::null::<u8>()
- }
- }
- Err(_) => {
- if let Ok(view)
- = deno_core::v8::Local::<
- deno_core::v8::ArrayBufferView,
- >::try_from(value) {
- let offset = view.byte_offset();
- let buffer = match view.buffer(scope) {
- Some(v) => v,
- None => {
- return deno_core::_ops::throw_type_error(
- scope,
- format!("Expected ArrayBufferView at position {}", 0usize),
- );
- }
- };
- let store = if let Some(data) = buffer.data() {
- data.cast::<u8>().as_ptr()
- } else {
- std::ptr::null_mut::<u8>()
- };
- unsafe { store.add(offset) }
- } else {
- return deno_core::_ops::throw_type_error(
- scope,
- format!("Expected ArrayBufferView at position {}", 0usize),
- );
- }
- }
- }
- };
- let arg_1 = if let Ok(view)
- = deno_core::v8::Local::<
- deno_core::v8::Uint32Array,
- >::try_from(args.get(1usize as i32)) {
- let (offset, len) = (view.byte_offset(), view.byte_length());
- let buffer = match view.buffer(scope) {
- Some(v) => v,
- None => {
- return deno_core::_ops::throw_type_error(
- scope,
- format!("Expected Uint32Array at position {}", 1usize),
- );
- }
- };
- if let Some(data) = buffer.data() {
- let store = data.cast::<u8>().as_ptr();
- unsafe {
- ::std::slice::from_raw_parts_mut(
- store.add(offset) as *mut u32,
- len / 4,
- )
- }
- } else {
- &mut []
- }
- } else {
- return deno_core::_ops::throw_type_error(
- scope,
- format!("Expected Uint32Array at position {}", 1usize),
- );
- };
- let result = Self::call(
- &mut std::cell::RefCell::borrow_mut(&ctx.state),
- arg_0,
- arg_1,
- );
- let op_state = ::std::cell::RefCell::borrow(&*ctx.state);
- op_state.tracker.track_sync(ctx.id);
- }
-}
-impl<FP> op_ffi_ptr_of<FP>
-where
- FP: FfiPermissions + 'static,
-{
- #[allow(clippy::too_many_arguments)]
- fn op_ffi_ptr_of_fast_fn(
- _: deno_core::v8::Local<deno_core::v8::Object>,
- buf: *const deno_core::v8::fast_api::FastApiTypedArray<u8>,
- out: *const deno_core::v8::fast_api::FastApiTypedArray<u32>,
- fast_api_callback_options: *mut deno_core::v8::fast_api::FastApiCallbackOptions,
- ) -> () {
- use deno_core::v8;
- use deno_core::_ops;
- let __opts: &mut v8::fast_api::FastApiCallbackOptions = unsafe {
- &mut *fast_api_callback_options
- };
- let __ctx = unsafe {
- &*(v8::Local::<v8::External>::cast(unsafe { __opts.data.data }).value()
- as *const _ops::OpCtx)
- };
- let state = &mut ::std::cell::RefCell::borrow_mut(&__ctx.state);
- let buf = unsafe { (&*buf).get_storage_if_aligned().unwrap_unchecked() }
- .as_ptr();
- let out = match unsafe { &*out }.get_storage_if_aligned() {
- Some(v) => v,
- None => {
- unsafe { &mut *fast_api_callback_options }.fallback = true;
- return Default::default();
- }
- };
- let result = Self::call(state, buf, out);
- result
- }
-}
diff --git a/ops/optimizer_tests/raw_ptr.rs b/ops/optimizer_tests/raw_ptr.rs
deleted file mode 100644
index 249b3b35b..000000000
--- a/ops/optimizer_tests/raw_ptr.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-fn op_ffi_ptr_of<FP>(state: &mut OpState, buf: *const u8, out: &mut [u32])
-where
- FP: FfiPermissions + 'static,
-{
- // ..
-}
diff --git a/ops/optimizer_tests/serde_v8_value.expected b/ops/optimizer_tests/serde_v8_value.expected
deleted file mode 100644
index 411fbec0b..000000000
--- a/ops/optimizer_tests/serde_v8_value.expected
+++ /dev/null
@@ -1,11 +0,0 @@
-=== Optimizer Dump ===
-returns_result: false
-has_ref_opstate: false
-has_rc_opstate: false
-has_fast_callback_option: false
-needs_fast_callback_option: false
-fast_result: Some(Bool)
-fast_parameters: [V8Value, V8Value]
-transforms: {0: Transform { kind: V8Value, index: 0 }}
-is_async: false
-fast_compatible: true
diff --git a/ops/optimizer_tests/serde_v8_value.out b/ops/optimizer_tests/serde_v8_value.out
deleted file mode 100644
index 20cc97584..000000000
--- a/ops/optimizer_tests/serde_v8_value.out
+++ /dev/null
@@ -1,124 +0,0 @@
-#[allow(non_camel_case_types)]
-///Auto-generated by `deno_ops`, i.e: `#[op]`
-///
-///Use `op_is_proxy::decl()` to get an op-declaration
-///you can include in a `deno_core::Extension`.
-pub struct op_is_proxy {
- _phantom_data: ::std::marker::PhantomData<()>,
-}
-impl deno_core::_ops::Op for op_is_proxy {
- const NAME: &'static str = stringify!(op_is_proxy);
- const DECL: deno_core::OpDecl = deno_core::OpDecl {
- name: Self::name(),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: {
- use deno_core::v8::fast_api::CType;
- use deno_core::v8::fast_api::Type::*;
- Some(
- deno_core::v8::fast_api::FastFunction::new(
- &[V8Value, V8Value],
- CType::Bool,
- Self::op_is_proxy_fast_fn as *const ::std::ffi::c_void,
- ),
- )
- },
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 0,
- };
-}
-#[doc(hidden)]
-impl op_is_proxy {
- pub const fn name() -> &'static str {
- stringify!(op_is_proxy)
- }
- #[allow(clippy::not_unsafe_ptr_arg_deref)]
- pub extern "C" fn v8_fn_ptr(info: *const deno_core::v8::FunctionCallbackInfo) {
- let info = unsafe { &*info };
- let scope = &mut unsafe { deno_core::v8::CallbackScope::new(info) };
- let args = deno_core::v8::FunctionCallbackArguments::from_function_callback_info(
- info,
- );
- let rv = deno_core::v8::ReturnValue::from_function_callback_info(info);
- Self::v8_func(scope, args, rv);
- }
- pub const fn decl() -> deno_core::OpDecl {
- deno_core::OpDecl {
- name: Self::name(),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: {
- use deno_core::v8::fast_api::CType;
- use deno_core::v8::fast_api::Type::*;
- Some(
- deno_core::v8::fast_api::FastFunction::new(
- &[V8Value, V8Value],
- CType::Bool,
- Self::op_is_proxy_fast_fn as *const ::std::ffi::c_void,
- ),
- )
- },
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 1usize as u8,
- }
- }
- #[inline]
- #[allow(clippy::too_many_arguments)]
- #[allow(clippy::extra_unused_lifetimes)]
- fn call<'scope>(value: serde_v8::Value) -> bool {
- value.v8_value.is_proxy()
- }
- pub fn v8_func<'scope>(
- scope: &mut deno_core::v8::HandleScope<'scope>,
- args: deno_core::v8::FunctionCallbackArguments,
- mut rv: deno_core::v8::ReturnValue,
- ) {
- let ctx = unsafe {
- &*(deno_core::v8::Local::<deno_core::v8::External>::cast(args.data()).value()
- as *const deno_core::_ops::OpCtx)
- };
- let arg_0 = args.get(0usize as i32);
- let arg_0 = match deno_core::serde_v8::from_v8(scope, arg_0) {
- Ok(v) => v,
- Err(err) => {
- let msg = format!(
- "Error parsing args at position {}: {}", 0usize,
- deno_core::anyhow::Error::from(err)
- );
- return deno_core::_ops::throw_type_error(scope, msg);
- }
- };
- let result = Self::call(arg_0);
- let op_state = ::std::cell::RefCell::borrow(&*ctx.state);
- op_state.tracker.track_sync(ctx.id);
- match deno_core::serde_v8::to_v8(scope, result) {
- Ok(ret) => rv.set(ret),
- Err(err) => {
- deno_core::_ops::throw_type_error(
- scope,
- format!(
- "Error serializing return: {}",
- deno_core::anyhow::Error::from(err)
- ),
- )
- }
- };
- }
-}
-impl op_is_proxy {
- #[allow(clippy::too_many_arguments)]
- fn op_is_proxy_fast_fn(
- _: deno_core::v8::Local<deno_core::v8::Object>,
- value: deno_core::v8::Local<deno_core::v8::Value>,
- ) -> bool {
- use deno_core::v8;
- use deno_core::_ops;
- let value = serde_v8::Value { v8_value: value };
- let result = Self::call(value);
- result
- }
-}
diff --git a/ops/optimizer_tests/serde_v8_value.rs b/ops/optimizer_tests/serde_v8_value.rs
deleted file mode 100644
index c986930d9..000000000
--- a/ops/optimizer_tests/serde_v8_value.rs
+++ /dev/null
@@ -1,3 +0,0 @@
-fn op_is_proxy(value: serde_v8::Value) -> bool {
- value.v8_value.is_proxy()
-}
diff --git a/ops/optimizer_tests/strings.expected b/ops/optimizer_tests/strings.expected
deleted file mode 100644
index 4a6bb1556..000000000
--- a/ops/optimizer_tests/strings.expected
+++ /dev/null
@@ -1,11 +0,0 @@
-=== Optimizer Dump ===
-returns_result: false
-has_ref_opstate: false
-has_rc_opstate: false
-has_fast_callback_option: false
-needs_fast_callback_option: true
-fast_result: Some(U32)
-fast_parameters: [V8Value, SeqOneByteString]
-transforms: {0: Transform { kind: SeqOneByteString(Ref), index: 0 }}
-is_async: false
-fast_compatible: true
diff --git a/ops/optimizer_tests/strings.out b/ops/optimizer_tests/strings.out
deleted file mode 100644
index c59214f6a..000000000
--- a/ops/optimizer_tests/strings.out
+++ /dev/null
@@ -1,132 +0,0 @@
-#[allow(non_camel_case_types)]
-///Auto-generated by `deno_ops`, i.e: `#[op]`
-///
-///Use `op_string_length::decl()` to get an op-declaration
-///you can include in a `deno_core::Extension`.
-pub struct op_string_length {
- _phantom_data: ::std::marker::PhantomData<()>,
-}
-impl deno_core::_ops::Op for op_string_length {
- const NAME: &'static str = stringify!(op_string_length);
- const DECL: deno_core::OpDecl = deno_core::OpDecl {
- name: Self::name(),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: {
- use deno_core::v8::fast_api::CType;
- use deno_core::v8::fast_api::Type::*;
- Some(
- deno_core::v8::fast_api::FastFunction::new(
- &[V8Value, SeqOneByteString, CallbackOptions],
- CType::Uint32,
- Self::op_string_length_fast_fn as *const ::std::ffi::c_void,
- ),
- )
- },
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 0,
- };
-}
-#[doc(hidden)]
-impl op_string_length {
- pub const fn name() -> &'static str {
- stringify!(op_string_length)
- }
- #[allow(clippy::not_unsafe_ptr_arg_deref)]
- pub extern "C" fn v8_fn_ptr(info: *const deno_core::v8::FunctionCallbackInfo) {
- let info = unsafe { &*info };
- let scope = &mut unsafe { deno_core::v8::CallbackScope::new(info) };
- let args = deno_core::v8::FunctionCallbackArguments::from_function_callback_info(
- info,
- );
- let rv = deno_core::v8::ReturnValue::from_function_callback_info(info);
- Self::v8_func(scope, args, rv);
- }
- pub const fn decl() -> deno_core::OpDecl {
- deno_core::OpDecl {
- name: Self::name(),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: {
- use deno_core::v8::fast_api::CType;
- use deno_core::v8::fast_api::Type::*;
- Some(
- deno_core::v8::fast_api::FastFunction::new(
- &[V8Value, SeqOneByteString, CallbackOptions],
- CType::Uint32,
- Self::op_string_length_fast_fn as *const ::std::ffi::c_void,
- ),
- )
- },
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 1usize as u8,
- }
- }
- #[inline]
- #[allow(clippy::too_many_arguments)]
- #[allow(clippy::extra_unused_lifetimes)]
- fn call<'scope>(string: &str) -> u32 {
- string.len() as u32
- }
- pub fn v8_func<'scope>(
- scope: &mut deno_core::v8::HandleScope<'scope>,
- args: deno_core::v8::FunctionCallbackArguments,
- mut rv: deno_core::v8::ReturnValue,
- ) {
- let ctx = unsafe {
- &*(deno_core::v8::Local::<deno_core::v8::External>::cast(args.data()).value()
- as *const deno_core::_ops::OpCtx)
- };
- let arg_0 = match deno_core::v8::Local::<
- deno_core::v8::String,
- >::try_from(args.get(0usize as i32)) {
- Ok(v8_string) => deno_core::serde_v8::to_utf8(v8_string, scope),
- Err(_) => {
- return deno_core::_ops::throw_type_error(
- scope,
- format!("Expected string at position {}", 0usize),
- );
- }
- };
- let arg_0 = arg_0.as_ref();
- let result = Self::call(arg_0);
- let op_state = ::std::cell::RefCell::borrow(&*ctx.state);
- op_state.tracker.track_sync(ctx.id);
- match deno_core::serde_v8::to_v8(scope, result) {
- Ok(ret) => rv.set(ret),
- Err(err) => {
- deno_core::_ops::throw_type_error(
- scope,
- format!(
- "Error serializing return: {}",
- deno_core::anyhow::Error::from(err)
- ),
- )
- }
- };
- }
-}
-impl op_string_length {
- #[allow(clippy::too_many_arguments)]
- fn op_string_length_fast_fn(
- _: deno_core::v8::Local<deno_core::v8::Object>,
- string: *const deno_core::v8::fast_api::FastApiOneByteString,
- fast_api_callback_options: *mut deno_core::v8::fast_api::FastApiCallbackOptions,
- ) -> u32 {
- use deno_core::v8;
- use deno_core::_ops;
- let string = match ::std::str::from_utf8(unsafe { &*string }.as_bytes()) {
- Ok(v) => v,
- Err(_) => {
- unsafe { &mut *fast_api_callback_options }.fallback = true;
- return Default::default();
- }
- };
- let result = Self::call(string);
- result
- }
-}
diff --git a/ops/optimizer_tests/strings.rs b/ops/optimizer_tests/strings.rs
deleted file mode 100644
index 860f1e8ec..000000000
--- a/ops/optimizer_tests/strings.rs
+++ /dev/null
@@ -1,3 +0,0 @@
-fn op_string_length(string: &str) -> u32 {
- string.len() as u32
-}
diff --git a/ops/optimizer_tests/strings_result.expected b/ops/optimizer_tests/strings_result.expected
deleted file mode 100644
index 3866751fd..000000000
--- a/ops/optimizer_tests/strings_result.expected
+++ /dev/null
@@ -1,11 +0,0 @@
-=== Optimizer Dump ===
-returns_result: true
-has_ref_opstate: false
-has_rc_opstate: false
-has_fast_callback_option: false
-needs_fast_callback_option: true
-fast_result: Some(U32)
-fast_parameters: [V8Value, SeqOneByteString]
-transforms: {0: Transform { kind: SeqOneByteString(Ref), index: 0 }}
-is_async: false
-fast_compatible: false
diff --git a/ops/optimizer_tests/strings_result.out b/ops/optimizer_tests/strings_result.out
deleted file mode 100644
index 45ca1fac7..000000000
--- a/ops/optimizer_tests/strings_result.out
+++ /dev/null
@@ -1,93 +0,0 @@
-#[allow(non_camel_case_types)]
-///Auto-generated by `deno_ops`, i.e: `#[op]`
-///
-///Use `op_string_length::decl()` to get an op-declaration
-///you can include in a `deno_core::Extension`.
-pub struct op_string_length {
- _phantom_data: ::std::marker::PhantomData<()>,
-}
-impl deno_core::_ops::Op for op_string_length {
- const NAME: &'static str = stringify!(op_string_length);
- const DECL: deno_core::OpDecl = deno_core::OpDecl {
- name: Self::name(),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: None,
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 0,
- };
-}
-#[doc(hidden)]
-impl op_string_length {
- pub const fn name() -> &'static str {
- stringify!(op_string_length)
- }
- #[allow(clippy::not_unsafe_ptr_arg_deref)]
- pub extern "C" fn v8_fn_ptr(info: *const deno_core::v8::FunctionCallbackInfo) {
- let info = unsafe { &*info };
- let scope = &mut unsafe { deno_core::v8::CallbackScope::new(info) };
- let args = deno_core::v8::FunctionCallbackArguments::from_function_callback_info(
- info,
- );
- let rv = deno_core::v8::ReturnValue::from_function_callback_info(info);
- Self::v8_func(scope, args, rv);
- }
- pub const fn decl() -> deno_core::OpDecl {
- deno_core::OpDecl {
- name: Self::name(),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: None,
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 1usize as u8,
- }
- }
- #[inline]
- #[allow(clippy::too_many_arguments)]
- #[allow(clippy::extra_unused_lifetimes)]
- fn call<'scope>(string: &str) -> Result<u32, AnyError> {
- Ok(string.len() as u32)
- }
- pub fn v8_func<'scope>(
- scope: &mut deno_core::v8::HandleScope<'scope>,
- args: deno_core::v8::FunctionCallbackArguments,
- mut rv: deno_core::v8::ReturnValue,
- ) {
- let ctx = unsafe {
- &*(deno_core::v8::Local::<deno_core::v8::External>::cast(args.data()).value()
- as *const deno_core::_ops::OpCtx)
- };
- let arg_0 = match deno_core::v8::Local::<
- deno_core::v8::String,
- >::try_from(args.get(0usize as i32)) {
- Ok(v8_string) => deno_core::serde_v8::to_utf8(v8_string, scope),
- Err(_) => {
- return deno_core::_ops::throw_type_error(
- scope,
- format!("Expected string at position {}", 0usize),
- );
- }
- };
- let arg_0 = arg_0.as_ref();
- let result = Self::call(arg_0);
- let op_state = ::std::cell::RefCell::borrow(&*ctx.state);
- op_state.tracker.track_sync(ctx.id);
- match result {
- Ok(result) => {
- rv.set_uint32(result as u32);
- }
- Err(err) => {
- let exception = deno_core::error::to_v8_error(
- scope,
- op_state.get_error_class_fn,
- &err,
- );
- scope.throw_exception(exception);
- }
- };
- }
-}
diff --git a/ops/optimizer_tests/strings_result.rs b/ops/optimizer_tests/strings_result.rs
deleted file mode 100644
index f89efaab1..000000000
--- a/ops/optimizer_tests/strings_result.rs
+++ /dev/null
@@ -1,4 +0,0 @@
-// https://github.com/denoland/deno/issues/16979
-fn op_string_length(string: &str) -> Result<u32, AnyError> {
- Ok(string.len() as u32)
-}
diff --git a/ops/optimizer_tests/u64_result.expected b/ops/optimizer_tests/u64_result.expected
deleted file mode 100644
index 250ff1022..000000000
--- a/ops/optimizer_tests/u64_result.expected
+++ /dev/null
@@ -1 +0,0 @@
-FastUnsupportedParamType \ No newline at end of file
diff --git a/ops/optimizer_tests/u64_result.out b/ops/optimizer_tests/u64_result.out
deleted file mode 100644
index 5a4df68b1..000000000
--- a/ops/optimizer_tests/u64_result.out
+++ /dev/null
@@ -1,94 +0,0 @@
-#[allow(non_camel_case_types)]
-///Auto-generated by `deno_ops`, i.e: `#[op]`
-///
-///Use `op_bench_now::decl()` to get an op-declaration
-///you can include in a `deno_core::Extension`.
-pub struct op_bench_now {
- _phantom_data: ::std::marker::PhantomData<()>,
-}
-impl deno_core::_ops::Op for op_bench_now {
- const NAME: &'static str = stringify!(op_bench_now);
- const DECL: deno_core::OpDecl = deno_core::OpDecl {
- name: Self::name(),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: None,
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 0,
- };
-}
-#[doc(hidden)]
-impl op_bench_now {
- pub const fn name() -> &'static str {
- stringify!(op_bench_now)
- }
- #[allow(clippy::not_unsafe_ptr_arg_deref)]
- pub extern "C" fn v8_fn_ptr(info: *const deno_core::v8::FunctionCallbackInfo) {
- let info = unsafe { &*info };
- let scope = &mut unsafe { deno_core::v8::CallbackScope::new(info) };
- let args = deno_core::v8::FunctionCallbackArguments::from_function_callback_info(
- info,
- );
- let rv = deno_core::v8::ReturnValue::from_function_callback_info(info);
- Self::v8_func(scope, args, rv);
- }
- pub const fn decl() -> deno_core::OpDecl {
- deno_core::OpDecl {
- name: Self::name(),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: None,
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 0usize as u8,
- }
- }
- #[inline]
- #[allow(clippy::too_many_arguments)]
- #[allow(clippy::extra_unused_lifetimes)]
- fn call<'scope>(state: &mut OpState) -> Result<u64, AnyError> {
- let ns = state.borrow::<time::Instant>().elapsed().as_nanos();
- let ns_u64 = u64::try_from(ns)?;
- Ok(ns_u64)
- }
- pub fn v8_func<'scope>(
- scope: &mut deno_core::v8::HandleScope<'scope>,
- args: deno_core::v8::FunctionCallbackArguments,
- mut rv: deno_core::v8::ReturnValue,
- ) {
- let ctx = unsafe {
- &*(deno_core::v8::Local::<deno_core::v8::External>::cast(args.data()).value()
- as *const deno_core::_ops::OpCtx)
- };
- let result = Self::call(&mut std::cell::RefCell::borrow_mut(&ctx.state));
- let op_state = ::std::cell::RefCell::borrow(&*ctx.state);
- op_state.tracker.track_sync(ctx.id);
- match result {
- Ok(result) => {
- match deno_core::serde_v8::to_v8(scope, result) {
- Ok(ret) => rv.set(ret),
- Err(err) => {
- deno_core::_ops::throw_type_error(
- scope,
- format!(
- "Error serializing return: {}",
- deno_core::anyhow::Error::from(err)
- ),
- )
- }
- };
- }
- Err(err) => {
- let exception = deno_core::error::to_v8_error(
- scope,
- op_state.get_error_class_fn,
- &err,
- );
- scope.throw_exception(exception);
- }
- };
- }
-}
diff --git a/ops/optimizer_tests/u64_result.rs b/ops/optimizer_tests/u64_result.rs
deleted file mode 100644
index 1cc783db8..000000000
--- a/ops/optimizer_tests/u64_result.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-fn op_bench_now(state: &mut OpState) -> Result<u64, AnyError> {
- let ns = state.borrow::<time::Instant>().elapsed().as_nanos();
- let ns_u64 = u64::try_from(ns)?;
- Ok(ns_u64)
-}
diff --git a/ops/optimizer_tests/uint8array.expected b/ops/optimizer_tests/uint8array.expected
deleted file mode 100644
index 49554a2e8..000000000
--- a/ops/optimizer_tests/uint8array.expected
+++ /dev/null
@@ -1,11 +0,0 @@
-=== Optimizer Dump ===
-returns_result: false
-has_ref_opstate: false
-has_rc_opstate: false
-has_fast_callback_option: false
-needs_fast_callback_option: false
-fast_result: Some(Bool)
-fast_parameters: [V8Value, Uint8Array, Uint8Array]
-transforms: {0: Transform { kind: SliceU8(false), index: 0 }, 1: Transform { kind: SliceU8(true), index: 1 }}
-is_async: false
-fast_compatible: true
diff --git a/ops/optimizer_tests/uint8array.out b/ops/optimizer_tests/uint8array.out
deleted file mode 100644
index 335bf42f6..000000000
--- a/ops/optimizer_tests/uint8array.out
+++ /dev/null
@@ -1,205 +0,0 @@
-#[allow(non_camel_case_types)]
-///Auto-generated by `deno_ops`, i.e: `#[op]`
-///
-///Use `op_import_spki_x25519::decl()` to get an op-declaration
-///you can include in a `deno_core::Extension`.
-pub struct op_import_spki_x25519 {
- _phantom_data: ::std::marker::PhantomData<()>,
-}
-impl deno_core::_ops::Op for op_import_spki_x25519 {
- const NAME: &'static str = stringify!(op_import_spki_x25519);
- const DECL: deno_core::OpDecl = deno_core::OpDecl {
- name: Self::name(),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: {
- use deno_core::v8::fast_api::CType;
- use deno_core::v8::fast_api::Type::*;
- Some(
- deno_core::v8::fast_api::FastFunction::new(
- &[V8Value, TypedArray(CType::Uint8), TypedArray(CType::Uint8)],
- CType::Bool,
- Self::op_import_spki_x25519_fast_fn as *const ::std::ffi::c_void,
- ),
- )
- },
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 0,
- };
-}
-#[doc(hidden)]
-impl op_import_spki_x25519 {
- pub const fn name() -> &'static str {
- stringify!(op_import_spki_x25519)
- }
- #[allow(clippy::not_unsafe_ptr_arg_deref)]
- pub extern "C" fn v8_fn_ptr(info: *const deno_core::v8::FunctionCallbackInfo) {
- let info = unsafe { &*info };
- let scope = &mut unsafe { deno_core::v8::CallbackScope::new(info) };
- let args = deno_core::v8::FunctionCallbackArguments::from_function_callback_info(
- info,
- );
- let rv = deno_core::v8::ReturnValue::from_function_callback_info(info);
- Self::v8_func(scope, args, rv);
- }
- pub const fn decl() -> deno_core::OpDecl {
- deno_core::OpDecl {
- name: Self::name(),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: {
- use deno_core::v8::fast_api::CType;
- use deno_core::v8::fast_api::Type::*;
- Some(
- deno_core::v8::fast_api::FastFunction::new(
- &[V8Value, TypedArray(CType::Uint8), TypedArray(CType::Uint8)],
- CType::Bool,
- Self::op_import_spki_x25519_fast_fn as *const ::std::ffi::c_void,
- ),
- )
- },
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 2usize as u8,
- }
- }
- #[inline]
- #[allow(clippy::too_many_arguments)]
- #[allow(clippy::extra_unused_lifetimes)]
- pub fn call<'scope>(key_data: &[u8], out: &mut [u8]) -> bool {}
- pub fn v8_func<'scope>(
- scope: &mut deno_core::v8::HandleScope<'scope>,
- args: deno_core::v8::FunctionCallbackArguments,
- mut rv: deno_core::v8::ReturnValue,
- ) {
- let ctx = unsafe {
- &*(deno_core::v8::Local::<deno_core::v8::External>::cast(args.data()).value()
- as *const deno_core::_ops::OpCtx)
- };
- let arg_0 = {
- let value = args.get(0usize as i32);
- match deno_core::v8::Local::<deno_core::v8::ArrayBuffer>::try_from(value) {
- Ok(b) => {
- let byte_length = b.byte_length();
- if let Some(data) = b.data() {
- let store = data.cast::<u8>().as_ptr();
- unsafe { ::std::slice::from_raw_parts_mut(store, byte_length) }
- } else {
- &mut []
- }
- }
- Err(_) => {
- if let Ok(view)
- = deno_core::v8::Local::<
- deno_core::v8::ArrayBufferView,
- >::try_from(value) {
- let len = view.byte_length();
- let offset = view.byte_offset();
- let buffer = match view.buffer(scope) {
- Some(v) => v,
- None => {
- return deno_core::_ops::throw_type_error(
- scope,
- format!("Expected ArrayBufferView at position {}", 0usize),
- );
- }
- };
- if let Some(data) = buffer.data() {
- let store = data.cast::<u8>().as_ptr();
- unsafe {
- ::std::slice::from_raw_parts_mut(store.add(offset), len)
- }
- } else {
- &mut []
- }
- } else {
- return deno_core::_ops::throw_type_error(
- scope,
- format!("Expected ArrayBufferView at position {}", 0usize),
- );
- }
- }
- }
- };
- let arg_1 = {
- let value = args.get(1usize as i32);
- match deno_core::v8::Local::<deno_core::v8::ArrayBuffer>::try_from(value) {
- Ok(b) => {
- let byte_length = b.byte_length();
- if let Some(data) = b.data() {
- let store = data.cast::<u8>().as_ptr();
- unsafe { ::std::slice::from_raw_parts_mut(store, byte_length) }
- } else {
- &mut []
- }
- }
- Err(_) => {
- if let Ok(view)
- = deno_core::v8::Local::<
- deno_core::v8::ArrayBufferView,
- >::try_from(value) {
- let len = view.byte_length();
- let offset = view.byte_offset();
- let buffer = match view.buffer(scope) {
- Some(v) => v,
- None => {
- return deno_core::_ops::throw_type_error(
- scope,
- format!("Expected ArrayBufferView at position {}", 1usize),
- );
- }
- };
- if let Some(data) = buffer.data() {
- let store = data.cast::<u8>().as_ptr();
- unsafe {
- ::std::slice::from_raw_parts_mut(store.add(offset), len)
- }
- } else {
- &mut []
- }
- } else {
- return deno_core::_ops::throw_type_error(
- scope,
- format!("Expected ArrayBufferView at position {}", 1usize),
- );
- }
- }
- }
- };
- let result = Self::call(arg_0, arg_1);
- let op_state = ::std::cell::RefCell::borrow(&*ctx.state);
- op_state.tracker.track_sync(ctx.id);
- match deno_core::serde_v8::to_v8(scope, result) {
- Ok(ret) => rv.set(ret),
- Err(err) => {
- deno_core::_ops::throw_type_error(
- scope,
- format!(
- "Error serializing return: {}",
- deno_core::anyhow::Error::from(err)
- ),
- )
- }
- };
- }
-}
-impl op_import_spki_x25519 {
- #[allow(clippy::too_many_arguments)]
- fn op_import_spki_x25519_fast_fn(
- _: deno_core::v8::Local<deno_core::v8::Object>,
- key_data: *const deno_core::v8::fast_api::FastApiTypedArray<u8>,
- out: *const deno_core::v8::fast_api::FastApiTypedArray<u8>,
- ) -> bool {
- use deno_core::v8;
- use deno_core::_ops;
- let key_data = unsafe {
- (&*key_data).get_storage_if_aligned().unwrap_unchecked()
- };
- let out = unsafe { (&*out).get_storage_if_aligned().unwrap_unchecked() };
- let result = Self::call(key_data, out);
- result
- }
-}
diff --git a/ops/optimizer_tests/uint8array.rs b/ops/optimizer_tests/uint8array.rs
deleted file mode 100644
index f4507b21f..000000000
--- a/ops/optimizer_tests/uint8array.rs
+++ /dev/null
@@ -1,3 +0,0 @@
-pub fn op_import_spki_x25519(key_data: &[u8], out: &mut [u8]) -> bool {
- // ...
-}
diff --git a/ops/optimizer_tests/unit_result.expected b/ops/optimizer_tests/unit_result.expected
deleted file mode 100644
index 693a771e9..000000000
--- a/ops/optimizer_tests/unit_result.expected
+++ /dev/null
@@ -1,11 +0,0 @@
-=== Optimizer Dump ===
-returns_result: true
-has_ref_opstate: false
-has_rc_opstate: false
-has_fast_callback_option: false
-needs_fast_callback_option: false
-fast_result: Some(Void)
-fast_parameters: [V8Value]
-transforms: {}
-is_async: false
-fast_compatible: true
diff --git a/ops/optimizer_tests/unit_result.out b/ops/optimizer_tests/unit_result.out
deleted file mode 100644
index 894297255..000000000
--- a/ops/optimizer_tests/unit_result.out
+++ /dev/null
@@ -1,137 +0,0 @@
-#[allow(non_camel_case_types)]
-///Auto-generated by `deno_ops`, i.e: `#[op]`
-///
-///Use `op_unit_result::decl()` to get an op-declaration
-///you can include in a `deno_core::Extension`.
-pub struct op_unit_result {
- _phantom_data: ::std::marker::PhantomData<()>,
-}
-impl deno_core::_ops::Op for op_unit_result {
- const NAME: &'static str = stringify!(op_unit_result);
- const DECL: deno_core::OpDecl = deno_core::OpDecl {
- name: Self::name(),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: {
- use deno_core::v8::fast_api::CType;
- use deno_core::v8::fast_api::Type::*;
- Some(
- deno_core::v8::fast_api::FastFunction::new(
- &[V8Value, CallbackOptions],
- CType::Void,
- Self::op_unit_result_fast_fn as *const ::std::ffi::c_void,
- ),
- )
- },
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 0,
- };
-}
-#[doc(hidden)]
-impl op_unit_result {
- pub const fn name() -> &'static str {
- stringify!(op_unit_result)
- }
- #[allow(clippy::not_unsafe_ptr_arg_deref)]
- pub extern "C" fn v8_fn_ptr(info: *const deno_core::v8::FunctionCallbackInfo) {
- let info = unsafe { &*info };
- let scope = &mut unsafe { deno_core::v8::CallbackScope::new(info) };
- let args = deno_core::v8::FunctionCallbackArguments::from_function_callback_info(
- info,
- );
- let rv = deno_core::v8::ReturnValue::from_function_callback_info(info);
- Self::v8_func(scope, args, rv);
- }
- pub const fn decl() -> deno_core::OpDecl {
- deno_core::OpDecl {
- name: Self::name(),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: {
- use deno_core::v8::fast_api::CType;
- use deno_core::v8::fast_api::Type::*;
- Some(
- deno_core::v8::fast_api::FastFunction::new(
- &[V8Value, CallbackOptions],
- CType::Void,
- Self::op_unit_result_fast_fn as *const ::std::ffi::c_void,
- ),
- )
- },
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 0usize as u8,
- }
- }
- #[inline]
- #[allow(clippy::too_many_arguments)]
- #[allow(clippy::extra_unused_lifetimes)]
- fn call<'scope>() -> Result<(), AnyError> {
- Ok(())
- }
- pub fn v8_func<'scope>(
- scope: &mut deno_core::v8::HandleScope<'scope>,
- args: deno_core::v8::FunctionCallbackArguments,
- mut rv: deno_core::v8::ReturnValue,
- ) {
- let ctx = unsafe {
- &*(deno_core::v8::Local::<deno_core::v8::External>::cast(args.data()).value()
- as *const deno_core::_ops::OpCtx)
- };
- {
- let op_state = &mut std::cell::RefCell::borrow_mut(&ctx.state);
- if let Some(err) = op_state.last_fast_op_error.take() {
- let exception = deno_core::error::to_v8_error(
- scope,
- op_state.get_error_class_fn,
- &err,
- );
- scope.throw_exception(exception);
- return;
- }
- }
- let result = Self::call();
- let op_state = ::std::cell::RefCell::borrow(&*ctx.state);
- op_state.tracker.track_sync(ctx.id);
- match result {
- Ok(result) => {}
- Err(err) => {
- let exception = deno_core::error::to_v8_error(
- scope,
- op_state.get_error_class_fn,
- &err,
- );
- scope.throw_exception(exception);
- }
- };
- }
-}
-impl op_unit_result {
- #[allow(clippy::too_many_arguments)]
- fn op_unit_result_fast_fn(
- _: deno_core::v8::Local<deno_core::v8::Object>,
- fast_api_callback_options: *mut deno_core::v8::fast_api::FastApiCallbackOptions,
- ) -> () {
- use deno_core::v8;
- use deno_core::_ops;
- let __opts: &mut v8::fast_api::FastApiCallbackOptions = unsafe {
- &mut *fast_api_callback_options
- };
- let __ctx = unsafe {
- &*(v8::Local::<v8::External>::cast(unsafe { __opts.data.data }).value()
- as *const _ops::OpCtx)
- };
- let op_state = &mut ::std::cell::RefCell::borrow_mut(&__ctx.state);
- let result = Self::call();
- match result {
- Ok(result) => result,
- Err(err) => {
- op_state.last_fast_op_error.replace(err);
- __opts.fallback = true;
- }
- }
- }
-}
diff --git a/ops/optimizer_tests/unit_result.rs b/ops/optimizer_tests/unit_result.rs
deleted file mode 100644
index 207896929..000000000
--- a/ops/optimizer_tests/unit_result.rs
+++ /dev/null
@@ -1,3 +0,0 @@
-fn op_unit_result() -> Result<(), AnyError> {
- Ok(())
-}
diff --git a/ops/optimizer_tests/unit_result2.expected b/ops/optimizer_tests/unit_result2.expected
deleted file mode 100644
index d799a77b2..000000000
--- a/ops/optimizer_tests/unit_result2.expected
+++ /dev/null
@@ -1,11 +0,0 @@
-=== Optimizer Dump ===
-returns_result: true
-has_ref_opstate: true
-has_rc_opstate: false
-has_fast_callback_option: false
-needs_fast_callback_option: false
-fast_result: Some(Void)
-fast_parameters: [V8Value, U32, Bool]
-transforms: {}
-is_async: false
-fast_compatible: true
diff --git a/ops/optimizer_tests/unit_result2.out b/ops/optimizer_tests/unit_result2.out
deleted file mode 100644
index d091b91cd..000000000
--- a/ops/optimizer_tests/unit_result2.out
+++ /dev/null
@@ -1,172 +0,0 @@
-#[allow(non_camel_case_types)]
-///Auto-generated by `deno_ops`, i.e: `#[op]`
-///
-///Use `op_set_nodelay::decl()` to get an op-declaration
-///you can include in a `deno_core::Extension`.
-pub struct op_set_nodelay {
- _phantom_data: ::std::marker::PhantomData<()>,
-}
-impl deno_core::_ops::Op for op_set_nodelay {
- const NAME: &'static str = stringify!(op_set_nodelay);
- const DECL: deno_core::OpDecl = deno_core::OpDecl {
- name: Self::name(),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: {
- use deno_core::v8::fast_api::CType;
- use deno_core::v8::fast_api::Type::*;
- Some(
- deno_core::v8::fast_api::FastFunction::new(
- &[V8Value, Uint32, Bool, CallbackOptions],
- CType::Void,
- Self::op_set_nodelay_fast_fn as *const ::std::ffi::c_void,
- ),
- )
- },
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 0,
- };
-}
-#[doc(hidden)]
-impl op_set_nodelay {
- pub const fn name() -> &'static str {
- stringify!(op_set_nodelay)
- }
- #[allow(clippy::not_unsafe_ptr_arg_deref)]
- pub extern "C" fn v8_fn_ptr(info: *const deno_core::v8::FunctionCallbackInfo) {
- let info = unsafe { &*info };
- let scope = &mut unsafe { deno_core::v8::CallbackScope::new(info) };
- let args = deno_core::v8::FunctionCallbackArguments::from_function_callback_info(
- info,
- );
- let rv = deno_core::v8::ReturnValue::from_function_callback_info(info);
- Self::v8_func(scope, args, rv);
- }
- pub const fn decl() -> deno_core::OpDecl {
- deno_core::OpDecl {
- name: Self::name(),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: {
- use deno_core::v8::fast_api::CType;
- use deno_core::v8::fast_api::Type::*;
- Some(
- deno_core::v8::fast_api::FastFunction::new(
- &[V8Value, Uint32, Bool, CallbackOptions],
- CType::Void,
- Self::op_set_nodelay_fast_fn as *const ::std::ffi::c_void,
- ),
- )
- },
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 2usize as u8,
- }
- }
- #[inline]
- #[allow(clippy::too_many_arguments)]
- #[allow(clippy::extra_unused_lifetimes)]
- pub fn call<'scope>(
- state: &mut OpState,
- rid: ResourceId,
- nodelay: bool,
- ) -> Result<(), AnyError> {
- let resource: Rc<TcpStreamResource> = state
- .resource_table
- .get::<TcpStreamResource>(rid)?;
- resource.set_nodelay(nodelay)
- }
- pub fn v8_func<'scope>(
- scope: &mut deno_core::v8::HandleScope<'scope>,
- args: deno_core::v8::FunctionCallbackArguments,
- mut rv: deno_core::v8::ReturnValue,
- ) {
- let ctx = unsafe {
- &*(deno_core::v8::Local::<deno_core::v8::External>::cast(args.data()).value()
- as *const deno_core::_ops::OpCtx)
- };
- {
- let op_state = &mut std::cell::RefCell::borrow_mut(&ctx.state);
- if let Some(err) = op_state.last_fast_op_error.take() {
- let exception = deno_core::error::to_v8_error(
- scope,
- op_state.get_error_class_fn,
- &err,
- );
- scope.throw_exception(exception);
- return;
- }
- }
- let arg_0 = args.get(0usize as i32);
- let arg_0 = match deno_core::serde_v8::from_v8(scope, arg_0) {
- Ok(v) => v,
- Err(err) => {
- let msg = format!(
- "Error parsing args at position {}: {}", 0usize,
- deno_core::anyhow::Error::from(err)
- );
- return deno_core::_ops::throw_type_error(scope, msg);
- }
- };
- let arg_1 = args.get(1usize as i32);
- let arg_1 = match deno_core::serde_v8::from_v8(scope, arg_1) {
- Ok(v) => v,
- Err(err) => {
- let msg = format!(
- "Error parsing args at position {}: {}", 1usize,
- deno_core::anyhow::Error::from(err)
- );
- return deno_core::_ops::throw_type_error(scope, msg);
- }
- };
- let result = Self::call(
- &mut std::cell::RefCell::borrow_mut(&ctx.state),
- arg_0,
- arg_1,
- );
- let op_state = ::std::cell::RefCell::borrow(&*ctx.state);
- op_state.tracker.track_sync(ctx.id);
- match result {
- Ok(result) => {}
- Err(err) => {
- let exception = deno_core::error::to_v8_error(
- scope,
- op_state.get_error_class_fn,
- &err,
- );
- scope.throw_exception(exception);
- }
- };
- }
-}
-impl op_set_nodelay {
- #[allow(clippy::too_many_arguments)]
- fn op_set_nodelay_fast_fn(
- _: deno_core::v8::Local<deno_core::v8::Object>,
- rid: ResourceId,
- nodelay: bool,
- fast_api_callback_options: *mut deno_core::v8::fast_api::FastApiCallbackOptions,
- ) -> () {
- use deno_core::v8;
- use deno_core::_ops;
- let __opts: &mut v8::fast_api::FastApiCallbackOptions = unsafe {
- &mut *fast_api_callback_options
- };
- let __ctx = unsafe {
- &*(v8::Local::<v8::External>::cast(unsafe { __opts.data.data }).value()
- as *const _ops::OpCtx)
- };
- let state = &mut ::std::cell::RefCell::borrow_mut(&__ctx.state);
- let result = Self::call(state, rid, nodelay);
- match result {
- Ok(result) => result,
- Err(err) => {
- state.last_fast_op_error.replace(err);
- __opts.fallback = true;
- }
- }
- }
-}
diff --git a/ops/optimizer_tests/unit_result2.rs b/ops/optimizer_tests/unit_result2.rs
deleted file mode 100644
index 83b73e194..000000000
--- a/ops/optimizer_tests/unit_result2.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-pub fn op_set_nodelay(
- state: &mut OpState,
- rid: ResourceId,
- nodelay: bool,
-) -> Result<(), AnyError> {
- let resource: Rc<TcpStreamResource> =
- state.resource_table.get::<TcpStreamResource>(rid)?;
- resource.set_nodelay(nodelay)
-}
diff --git a/ops/optimizer_tests/unit_ret.expected b/ops/optimizer_tests/unit_ret.expected
deleted file mode 100644
index 5d414e1e3..000000000
--- a/ops/optimizer_tests/unit_ret.expected
+++ /dev/null
@@ -1,11 +0,0 @@
-=== Optimizer Dump ===
-returns_result: false
-has_ref_opstate: false
-has_rc_opstate: false
-has_fast_callback_option: false
-needs_fast_callback_option: false
-fast_result: Some(Void)
-fast_parameters: [V8Value]
-transforms: {}
-is_async: false
-fast_compatible: true
diff --git a/ops/optimizer_tests/unit_ret.out b/ops/optimizer_tests/unit_ret.out
deleted file mode 100644
index 1a721c407..000000000
--- a/ops/optimizer_tests/unit_ret.out
+++ /dev/null
@@ -1,109 +0,0 @@
-#[allow(non_camel_case_types)]
-///Auto-generated by `deno_ops`, i.e: `#[op]`
-///
-///Use `op_unit::decl()` to get an op-declaration
-///you can include in a `deno_core::Extension`.
-pub struct op_unit {
- _phantom_data: ::std::marker::PhantomData<()>,
-}
-impl deno_core::_ops::Op for op_unit {
- const NAME: &'static str = stringify!(op_unit);
- const DECL: deno_core::OpDecl = deno_core::OpDecl {
- name: Self::name(),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: {
- use deno_core::v8::fast_api::CType;
- use deno_core::v8::fast_api::Type::*;
- Some(
- deno_core::v8::fast_api::FastFunction::new(
- &[V8Value],
- CType::Void,
- Self::op_unit_fast_fn as *const ::std::ffi::c_void,
- ),
- )
- },
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 0,
- };
-}
-#[doc(hidden)]
-impl op_unit {
- pub const fn name() -> &'static str {
- stringify!(op_unit)
- }
- #[allow(clippy::not_unsafe_ptr_arg_deref)]
- pub extern "C" fn v8_fn_ptr(info: *const deno_core::v8::FunctionCallbackInfo) {
- let info = unsafe { &*info };
- let scope = &mut unsafe { deno_core::v8::CallbackScope::new(info) };
- let args = deno_core::v8::FunctionCallbackArguments::from_function_callback_info(
- info,
- );
- let rv = deno_core::v8::ReturnValue::from_function_callback_info(info);
- Self::v8_func(scope, args, rv);
- }
- pub const fn decl() -> deno_core::OpDecl {
- deno_core::OpDecl {
- name: Self::name(),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: {
- use deno_core::v8::fast_api::CType;
- use deno_core::v8::fast_api::Type::*;
- Some(
- deno_core::v8::fast_api::FastFunction::new(
- &[V8Value],
- CType::Void,
- Self::op_unit_fast_fn as *const ::std::ffi::c_void,
- ),
- )
- },
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 0usize as u8,
- }
- }
- #[inline]
- #[allow(clippy::too_many_arguments)]
- #[allow(clippy::extra_unused_lifetimes)]
- fn call<'scope>() -> () {
- ()
- }
- pub fn v8_func<'scope>(
- scope: &mut deno_core::v8::HandleScope<'scope>,
- args: deno_core::v8::FunctionCallbackArguments,
- mut rv: deno_core::v8::ReturnValue,
- ) {
- let ctx = unsafe {
- &*(deno_core::v8::Local::<deno_core::v8::External>::cast(args.data()).value()
- as *const deno_core::_ops::OpCtx)
- };
- let result = Self::call();
- let op_state = ::std::cell::RefCell::borrow(&*ctx.state);
- op_state.tracker.track_sync(ctx.id);
- match deno_core::serde_v8::to_v8(scope, result) {
- Ok(ret) => rv.set(ret),
- Err(err) => {
- deno_core::_ops::throw_type_error(
- scope,
- format!(
- "Error serializing return: {}",
- deno_core::anyhow::Error::from(err)
- ),
- )
- }
- };
- }
-}
-impl op_unit {
- #[allow(clippy::too_many_arguments)]
- fn op_unit_fast_fn(_: deno_core::v8::Local<deno_core::v8::Object>) -> () {
- use deno_core::v8;
- use deno_core::_ops;
- let result = Self::call();
- result
- }
-}
diff --git a/ops/optimizer_tests/unit_ret.rs b/ops/optimizer_tests/unit_ret.rs
deleted file mode 100644
index 4cf3651db..000000000
--- a/ops/optimizer_tests/unit_ret.rs
+++ /dev/null
@@ -1,3 +0,0 @@
-fn op_unit() -> () {
- ()
-}
diff --git a/ops/optimizer_tests/wasm_op.expected b/ops/optimizer_tests/wasm_op.expected
deleted file mode 100644
index 8d3719cf7..000000000
--- a/ops/optimizer_tests/wasm_op.expected
+++ /dev/null
@@ -1,11 +0,0 @@
-=== Optimizer Dump ===
-returns_result: false
-has_ref_opstate: false
-has_rc_opstate: false
-has_fast_callback_option: false
-needs_fast_callback_option: false
-fast_result: Some(Void)
-fast_parameters: [V8Value]
-transforms: {0: Transform { kind: WasmMemory, index: 0 }}
-is_async: false
-fast_compatible: true
diff --git a/ops/optimizer_tests/wasm_op.out b/ops/optimizer_tests/wasm_op.out
deleted file mode 100644
index 023506fc2..000000000
--- a/ops/optimizer_tests/wasm_op.out
+++ /dev/null
@@ -1,107 +0,0 @@
-#[allow(non_camel_case_types)]
-///Auto-generated by `deno_ops`, i.e: `#[op]`
-///
-///Use `op_wasm::decl()` to get an op-declaration
-///you can include in a `deno_core::Extension`.
-pub struct op_wasm {
- _phantom_data: ::std::marker::PhantomData<()>,
-}
-impl deno_core::_ops::Op for op_wasm {
- const NAME: &'static str = stringify!(op_wasm);
- const DECL: deno_core::OpDecl = deno_core::OpDecl {
- name: Self::name(),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: {
- use deno_core::v8::fast_api::CType;
- use deno_core::v8::fast_api::Type::*;
- Some(
- deno_core::v8::fast_api::FastFunction::new(
- &[V8Value, CallbackOptions],
- CType::Void,
- Self::op_wasm_fast_fn as *const ::std::ffi::c_void,
- ),
- )
- },
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 0,
- };
-}
-#[doc(hidden)]
-impl op_wasm {
- pub const fn name() -> &'static str {
- stringify!(op_wasm)
- }
- #[allow(clippy::not_unsafe_ptr_arg_deref)]
- pub extern "C" fn v8_fn_ptr(info: *const deno_core::v8::FunctionCallbackInfo) {
- let info = unsafe { &*info };
- let scope = &mut unsafe { deno_core::v8::CallbackScope::new(info) };
- let args = deno_core::v8::FunctionCallbackArguments::from_function_callback_info(
- info,
- );
- let rv = deno_core::v8::ReturnValue::from_function_callback_info(info);
- Self::v8_func(scope, args, rv);
- }
- pub const fn decl() -> deno_core::OpDecl {
- deno_core::OpDecl {
- name: Self::name(),
- v8_fn_ptr: Self::v8_fn_ptr as _,
- enabled: true,
- fast_fn: {
- use deno_core::v8::fast_api::CType;
- use deno_core::v8::fast_api::Type::*;
- Some(
- deno_core::v8::fast_api::FastFunction::new(
- &[V8Value, CallbackOptions],
- CType::Void,
- Self::op_wasm_fast_fn as *const ::std::ffi::c_void,
- ),
- )
- },
- is_async: false,
- is_unstable: false,
- is_v8: false,
- arg_count: 1usize as u8,
- }
- }
- #[inline]
- #[allow(clippy::too_many_arguments)]
- #[allow(clippy::extra_unused_lifetimes)]
- fn call<'scope>(memory: Option<&mut [u8]>) {}
- pub fn v8_func<'scope>(
- scope: &mut deno_core::v8::HandleScope<'scope>,
- args: deno_core::v8::FunctionCallbackArguments,
- mut rv: deno_core::v8::ReturnValue,
- ) {
- let ctx = unsafe {
- &*(deno_core::v8::Local::<deno_core::v8::External>::cast(args.data()).value()
- as *const deno_core::_ops::OpCtx)
- };
- let arg_0 = None;
- let result = Self::call(arg_0);
- let op_state = ::std::cell::RefCell::borrow(&*ctx.state);
- op_state.tracker.track_sync(ctx.id);
- }
-}
-impl op_wasm {
- #[allow(clippy::too_many_arguments)]
- fn op_wasm_fast_fn(
- _: deno_core::v8::Local<deno_core::v8::Object>,
- fast_api_callback_options: *mut deno_core::v8::fast_api::FastApiCallbackOptions,
- ) -> () {
- use deno_core::v8;
- use deno_core::_ops;
- let __opts: &mut v8::fast_api::FastApiCallbackOptions = unsafe {
- &mut *fast_api_callback_options
- };
- let memory = unsafe {
- &*(__opts.wasm_memory
- as *const deno_core::v8::fast_api::FastApiTypedArray<u8>)
- }
- .get_storage_if_aligned();
- let result = Self::call(memory);
- result
- }
-}
diff --git a/ops/optimizer_tests/wasm_op.rs b/ops/optimizer_tests/wasm_op.rs
deleted file mode 100644
index b18f32fd1..000000000
--- a/ops/optimizer_tests/wasm_op.rs
+++ /dev/null
@@ -1,3 +0,0 @@
-fn op_wasm(memory: Option<&mut [u8]>) {
- // @test-attr:wasm
-}
diff --git a/ops/tests/compile_fail/mem_slices.rs b/ops/tests/compile_fail/mem_slices.rs
deleted file mode 100644
index da74ac577..000000000
--- a/ops/tests/compile_fail/mem_slices.rs
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-
-use deno_ops::op;
-
-#[op]
-fn sync_test(slice: &mut [u32]) {
- //
-}
-
-#[op]
-async fn async_test(slice: &[u8]) {
- // Memory slices are not allowed in async ops.
-}
-
-#[op]
-fn async_test2(slice: &mut [u8]) -> impl Future<Output = ()> {
- // Memory slices are not allowed in async ops, even when not implemented as an
- // async function.
- async {}
-}
-
-fn main() {
- // pass
-}
diff --git a/ops/tests/compile_fail/mem_slices.stderr b/ops/tests/compile_fail/mem_slices.stderr
deleted file mode 100644
index c45acfcf9..000000000
--- a/ops/tests/compile_fail/mem_slices.stderr
+++ /dev/null
@@ -1,15 +0,0 @@
-error: custom attribute panicked
- --> tests/compile_fail/mem_slices.rs:10:1
- |
-10 | #[op]
- | ^^^^^
- |
- = help: message: Memory slices are not allowed in async ops
-
-error: custom attribute panicked
- --> tests/compile_fail/mem_slices.rs:15:1
- |
-15 | #[op]
- | ^^^^^
- |
- = help: message: Memory slices are not allowed in async ops
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();
-}