summaryrefslogtreecommitdiff
path: root/cli/napi
diff options
context:
space:
mode:
authorhaturau <135221985+haturatu@users.noreply.github.com>2024-11-20 01:20:47 +0900
committerGitHub <noreply@github.com>2024-11-20 01:20:47 +0900
commit85719a67e59c7aa45bead26e4942d7df8b1b42d4 (patch)
treeface0aecaac53e93ce2f23b53c48859bcf1a36ec /cli/napi
parent67697bc2e4a62a9670699fd18ad0dd8efc5bd955 (diff)
parent186b52731c6bb326c4d32905c5e732d082e83465 (diff)
Merge branch 'denoland:main' into main
Diffstat (limited to 'cli/napi')
-rw-r--r--cli/napi/README.md114
-rw-r--r--cli/napi/generated_symbol_exports_list_linux.def1
-rw-r--r--cli/napi/generated_symbol_exports_list_macos.def160
-rw-r--r--cli/napi/generated_symbol_exports_list_windows.def162
-rw-r--r--cli/napi/js_native_api.rs3614
-rw-r--r--cli/napi/mod.rs21
-rw-r--r--cli/napi/node_api.rs1004
-rw-r--r--cli/napi/sym/Cargo.toml21
-rw-r--r--cli/napi/sym/README.md37
-rw-r--r--cli/napi/sym/lib.rs31
-rw-r--r--cli/napi/sym/symbol_exports.json164
-rw-r--r--cli/napi/util.rs289
-rw-r--r--cli/napi/uv.rs231
13 files changed, 0 insertions, 5849 deletions
diff --git a/cli/napi/README.md b/cli/napi/README.md
deleted file mode 100644
index 7b359ac6e..000000000
--- a/cli/napi/README.md
+++ /dev/null
@@ -1,114 +0,0 @@
-# napi
-
-This directory contains source for Deno's Node-API implementation. It depends on
-`napi_sym` and `deno_napi`.
-
-Files are generally organized the same as in Node.js's implementation to ease in
-ensuring compatibility.
-
-## Adding a new function
-
-Add the symbol name to
-[`cli/napi_sym/symbol_exports.json`](../napi_sym/symbol_exports.json).
-
-```diff
-{
- "symbols": [
- ...
- "napi_get_undefined",
-- "napi_get_null"
-+ "napi_get_null",
-+ "napi_get_boolean"
- ]
-}
-```
-
-Determine where to place the implementation. `napi_get_boolean` is related to JS
-values so we will place it in `js_native_api.rs`. If something is not clear,
-just create a new file module.
-
-See [`napi_sym`](../napi_sym/) for writing the implementation:
-
-```rust
-#[napi_sym::napi_sym]
-pub fn napi_get_boolean(
- env: *mut Env,
- value: bool,
- result: *mut napi_value,
-) -> Result {
- // ...
- Ok(())
-}
-```
-
-Update the generated symbol lists using the script:
-
-```
-deno run --allow-write tools/napi/generate_symbols_lists.js
-```
-
-Add a test in [`/tests/napi`](../../tests/napi/). You can also refer to Node.js
-test suite for Node-API.
-
-```js
-// tests/napi/boolean_test.js
-import { assertEquals, loadTestLibrary } from "./common.js";
-const lib = loadTestLibrary();
-Deno.test("napi get boolean", function () {
- assertEquals(lib.test_get_boolean(true), true);
- assertEquals(lib.test_get_boolean(false), false);
-});
-```
-
-```rust
-// tests/napi/src/boolean.rs
-
-use napi_sys::Status::napi_ok;
-use napi_sys::ValueType::napi_boolean;
-use napi_sys::*;
-
-extern "C" fn test_boolean(
- env: napi_env,
- info: napi_callback_info,
-) -> napi_value {
- let (args, argc, _) = crate::get_callback_info!(env, info, 1);
- assert_eq!(argc, 1);
-
- let mut ty = -1;
- assert!(unsafe { napi_typeof(env, args[0], &mut ty) } == napi_ok);
- assert_eq!(ty, napi_boolean);
-
- // Use napi_get_boolean here...
-
- value
-}
-
-pub fn init(env: napi_env, exports: napi_value) {
- let properties = &[crate::new_property!(env, "test_boolean\0", test_boolean)];
-
- unsafe {
- napi_define_properties(env, exports, properties.len(), properties.as_ptr())
- };
-}
-```
-
-```diff
-// tests/napi/src/lib.rs
-
-+ mod boolean;
-
-...
-
-#[no_mangle]
-unsafe extern "C" fn napi_register_module_v1(
- env: napi_env,
- exports: napi_value,
-) -> napi_value {
- ...
-+ boolean::init(env, exports);
-
- exports
-}
-```
-
-Run the test using `cargo test -p tests/napi`.
diff --git a/cli/napi/generated_symbol_exports_list_linux.def b/cli/napi/generated_symbol_exports_list_linux.def
deleted file mode 100644
index 614880ebf..000000000
--- a/cli/napi/generated_symbol_exports_list_linux.def
+++ /dev/null
@@ -1 +0,0 @@
-{ "node_api_create_syntax_error"; "napi_make_callback"; "napi_has_named_property"; "napi_async_destroy"; "napi_coerce_to_object"; "napi_get_arraybuffer_info"; "napi_detach_arraybuffer"; "napi_get_undefined"; "napi_reference_unref"; "napi_fatal_error"; "napi_open_callback_scope"; "napi_close_callback_scope"; "napi_get_value_uint32"; "napi_create_function"; "napi_create_arraybuffer"; "napi_get_value_int64"; "napi_get_all_property_names"; "napi_resolve_deferred"; "napi_is_detached_arraybuffer"; "napi_create_string_utf8"; "napi_create_threadsafe_function"; "node_api_throw_syntax_error"; "napi_create_bigint_int64"; "napi_wrap"; "napi_set_property"; "napi_get_value_bigint_int64"; "napi_open_handle_scope"; "napi_create_error"; "napi_create_buffer"; "napi_cancel_async_work"; "napi_is_exception_pending"; "napi_acquire_threadsafe_function"; "napi_create_external"; "napi_get_threadsafe_function_context"; "napi_get_null"; "napi_create_string_utf16"; "node_api_create_external_string_utf16"; "napi_get_value_bigint_uint64"; "napi_module_register"; "napi_is_typedarray"; "napi_create_external_buffer"; "napi_get_new_target"; "napi_get_instance_data"; "napi_close_handle_scope"; "napi_get_value_string_utf16"; "napi_get_property_names"; "napi_is_arraybuffer"; "napi_get_cb_info"; "napi_define_properties"; "napi_add_env_cleanup_hook"; "node_api_get_module_file_name"; "napi_get_node_version"; "napi_create_int64"; "napi_create_double"; "napi_get_and_clear_last_exception"; "napi_create_reference"; "napi_get_typedarray_info"; "napi_call_threadsafe_function"; "napi_get_last_error_info"; "napi_create_array_with_length"; "napi_coerce_to_number"; "napi_get_global"; "napi_is_error"; "napi_set_instance_data"; "napi_create_typedarray"; "napi_throw_type_error"; "napi_has_property"; "napi_get_value_external"; "napi_create_range_error"; "napi_typeof"; "napi_ref_threadsafe_function"; "napi_create_bigint_uint64"; "napi_get_prototype"; "napi_adjust_external_memory"; "napi_release_threadsafe_function"; "napi_delete_async_work"; "napi_create_string_latin1"; "node_api_create_external_string_latin1"; "napi_is_array"; "napi_unref_threadsafe_function"; "napi_throw_error"; "napi_has_own_property"; "napi_get_reference_value"; "napi_remove_env_cleanup_hook"; "napi_get_value_string_utf8"; "napi_is_promise"; "napi_get_boolean"; "napi_run_script"; "napi_get_element"; "napi_get_named_property"; "napi_get_buffer_info"; "napi_get_value_bool"; "napi_reference_ref"; "napi_create_object"; "napi_create_promise"; "napi_create_int32"; "napi_escape_handle"; "napi_open_escapable_handle_scope"; "napi_throw"; "napi_get_value_double"; "napi_set_named_property"; "napi_call_function"; "napi_create_date"; "napi_object_freeze"; "napi_get_uv_event_loop"; "napi_get_value_string_latin1"; "napi_reject_deferred"; "napi_add_finalizer"; "napi_create_array"; "napi_delete_reference"; "napi_get_date_value"; "napi_create_dataview"; "napi_get_version"; "napi_define_class"; "napi_is_date"; "napi_remove_wrap"; "napi_delete_property"; "napi_instanceof"; "napi_create_buffer_copy"; "napi_delete_element"; "napi_object_seal"; "napi_queue_async_work"; "napi_get_value_bigint_words"; "napi_is_buffer"; "napi_get_array_length"; "napi_get_property"; "napi_new_instance"; "napi_set_element"; "napi_create_bigint_words"; "napi_strict_equals"; "napi_is_dataview"; "napi_close_escapable_handle_scope"; "napi_get_dataview_info"; "napi_get_value_int32"; "napi_unwrap"; "napi_throw_range_error"; "napi_coerce_to_bool"; "napi_create_uint32"; "napi_has_element"; "napi_create_external_arraybuffer"; "napi_create_symbol"; "node_api_symbol_for"; "napi_coerce_to_string"; "napi_create_type_error"; "napi_fatal_exception"; "napi_create_async_work"; "napi_async_init"; "node_api_create_property_key_utf16"; "napi_type_tag_object"; "napi_check_object_type_tag"; "node_api_post_finalizer"; "napi_add_async_cleanup_hook"; "napi_remove_async_cleanup_hook"; "uv_mutex_init"; "uv_mutex_lock"; "uv_mutex_unlock"; "uv_mutex_destroy"; "uv_async_init"; "uv_async_send"; "uv_close"; }; \ No newline at end of file
diff --git a/cli/napi/generated_symbol_exports_list_macos.def b/cli/napi/generated_symbol_exports_list_macos.def
deleted file mode 100644
index 36b2f37fa..000000000
--- a/cli/napi/generated_symbol_exports_list_macos.def
+++ /dev/null
@@ -1,160 +0,0 @@
-_node_api_create_syntax_error
-_napi_make_callback
-_napi_has_named_property
-_napi_async_destroy
-_napi_coerce_to_object
-_napi_get_arraybuffer_info
-_napi_detach_arraybuffer
-_napi_get_undefined
-_napi_reference_unref
-_napi_fatal_error
-_napi_open_callback_scope
-_napi_close_callback_scope
-_napi_get_value_uint32
-_napi_create_function
-_napi_create_arraybuffer
-_napi_get_value_int64
-_napi_get_all_property_names
-_napi_resolve_deferred
-_napi_is_detached_arraybuffer
-_napi_create_string_utf8
-_napi_create_threadsafe_function
-_node_api_throw_syntax_error
-_napi_create_bigint_int64
-_napi_wrap
-_napi_set_property
-_napi_get_value_bigint_int64
-_napi_open_handle_scope
-_napi_create_error
-_napi_create_buffer
-_napi_cancel_async_work
-_napi_is_exception_pending
-_napi_acquire_threadsafe_function
-_napi_create_external
-_napi_get_threadsafe_function_context
-_napi_get_null
-_napi_create_string_utf16
-_node_api_create_external_string_utf16
-_napi_get_value_bigint_uint64
-_napi_module_register
-_napi_is_typedarray
-_napi_create_external_buffer
-_napi_get_new_target
-_napi_get_instance_data
-_napi_close_handle_scope
-_napi_get_value_string_utf16
-_napi_get_property_names
-_napi_is_arraybuffer
-_napi_get_cb_info
-_napi_define_properties
-_napi_add_env_cleanup_hook
-_node_api_get_module_file_name
-_napi_get_node_version
-_napi_create_int64
-_napi_create_double
-_napi_get_and_clear_last_exception
-_napi_create_reference
-_napi_get_typedarray_info
-_napi_call_threadsafe_function
-_napi_get_last_error_info
-_napi_create_array_with_length
-_napi_coerce_to_number
-_napi_get_global
-_napi_is_error
-_napi_set_instance_data
-_napi_create_typedarray
-_napi_throw_type_error
-_napi_has_property
-_napi_get_value_external
-_napi_create_range_error
-_napi_typeof
-_napi_ref_threadsafe_function
-_napi_create_bigint_uint64
-_napi_get_prototype
-_napi_adjust_external_memory
-_napi_release_threadsafe_function
-_napi_delete_async_work
-_napi_create_string_latin1
-_node_api_create_external_string_latin1
-_napi_is_array
-_napi_unref_threadsafe_function
-_napi_throw_error
-_napi_has_own_property
-_napi_get_reference_value
-_napi_remove_env_cleanup_hook
-_napi_get_value_string_utf8
-_napi_is_promise
-_napi_get_boolean
-_napi_run_script
-_napi_get_element
-_napi_get_named_property
-_napi_get_buffer_info
-_napi_get_value_bool
-_napi_reference_ref
-_napi_create_object
-_napi_create_promise
-_napi_create_int32
-_napi_escape_handle
-_napi_open_escapable_handle_scope
-_napi_throw
-_napi_get_value_double
-_napi_set_named_property
-_napi_call_function
-_napi_create_date
-_napi_object_freeze
-_napi_get_uv_event_loop
-_napi_get_value_string_latin1
-_napi_reject_deferred
-_napi_add_finalizer
-_napi_create_array
-_napi_delete_reference
-_napi_get_date_value
-_napi_create_dataview
-_napi_get_version
-_napi_define_class
-_napi_is_date
-_napi_remove_wrap
-_napi_delete_property
-_napi_instanceof
-_napi_create_buffer_copy
-_napi_delete_element
-_napi_object_seal
-_napi_queue_async_work
-_napi_get_value_bigint_words
-_napi_is_buffer
-_napi_get_array_length
-_napi_get_property
-_napi_new_instance
-_napi_set_element
-_napi_create_bigint_words
-_napi_strict_equals
-_napi_is_dataview
-_napi_close_escapable_handle_scope
-_napi_get_dataview_info
-_napi_get_value_int32
-_napi_unwrap
-_napi_throw_range_error
-_napi_coerce_to_bool
-_napi_create_uint32
-_napi_has_element
-_napi_create_external_arraybuffer
-_napi_create_symbol
-_node_api_symbol_for
-_napi_coerce_to_string
-_napi_create_type_error
-_napi_fatal_exception
-_napi_create_async_work
-_napi_async_init
-_node_api_create_property_key_utf16
-_napi_type_tag_object
-_napi_check_object_type_tag
-_node_api_post_finalizer
-_napi_add_async_cleanup_hook
-_napi_remove_async_cleanup_hook
-_uv_mutex_init
-_uv_mutex_lock
-_uv_mutex_unlock
-_uv_mutex_destroy
-_uv_async_init
-_uv_async_send
-_uv_close \ No newline at end of file
diff --git a/cli/napi/generated_symbol_exports_list_windows.def b/cli/napi/generated_symbol_exports_list_windows.def
deleted file mode 100644
index b7355112e..000000000
--- a/cli/napi/generated_symbol_exports_list_windows.def
+++ /dev/null
@@ -1,162 +0,0 @@
-LIBRARY
-EXPORTS
- node_api_create_syntax_error
- napi_make_callback
- napi_has_named_property
- napi_async_destroy
- napi_coerce_to_object
- napi_get_arraybuffer_info
- napi_detach_arraybuffer
- napi_get_undefined
- napi_reference_unref
- napi_fatal_error
- napi_open_callback_scope
- napi_close_callback_scope
- napi_get_value_uint32
- napi_create_function
- napi_create_arraybuffer
- napi_get_value_int64
- napi_get_all_property_names
- napi_resolve_deferred
- napi_is_detached_arraybuffer
- napi_create_string_utf8
- napi_create_threadsafe_function
- node_api_throw_syntax_error
- napi_create_bigint_int64
- napi_wrap
- napi_set_property
- napi_get_value_bigint_int64
- napi_open_handle_scope
- napi_create_error
- napi_create_buffer
- napi_cancel_async_work
- napi_is_exception_pending
- napi_acquire_threadsafe_function
- napi_create_external
- napi_get_threadsafe_function_context
- napi_get_null
- napi_create_string_utf16
- node_api_create_external_string_utf16
- napi_get_value_bigint_uint64
- napi_module_register
- napi_is_typedarray
- napi_create_external_buffer
- napi_get_new_target
- napi_get_instance_data
- napi_close_handle_scope
- napi_get_value_string_utf16
- napi_get_property_names
- napi_is_arraybuffer
- napi_get_cb_info
- napi_define_properties
- napi_add_env_cleanup_hook
- node_api_get_module_file_name
- napi_get_node_version
- napi_create_int64
- napi_create_double
- napi_get_and_clear_last_exception
- napi_create_reference
- napi_get_typedarray_info
- napi_call_threadsafe_function
- napi_get_last_error_info
- napi_create_array_with_length
- napi_coerce_to_number
- napi_get_global
- napi_is_error
- napi_set_instance_data
- napi_create_typedarray
- napi_throw_type_error
- napi_has_property
- napi_get_value_external
- napi_create_range_error
- napi_typeof
- napi_ref_threadsafe_function
- napi_create_bigint_uint64
- napi_get_prototype
- napi_adjust_external_memory
- napi_release_threadsafe_function
- napi_delete_async_work
- napi_create_string_latin1
- node_api_create_external_string_latin1
- napi_is_array
- napi_unref_threadsafe_function
- napi_throw_error
- napi_has_own_property
- napi_get_reference_value
- napi_remove_env_cleanup_hook
- napi_get_value_string_utf8
- napi_is_promise
- napi_get_boolean
- napi_run_script
- napi_get_element
- napi_get_named_property
- napi_get_buffer_info
- napi_get_value_bool
- napi_reference_ref
- napi_create_object
- napi_create_promise
- napi_create_int32
- napi_escape_handle
- napi_open_escapable_handle_scope
- napi_throw
- napi_get_value_double
- napi_set_named_property
- napi_call_function
- napi_create_date
- napi_object_freeze
- napi_get_uv_event_loop
- napi_get_value_string_latin1
- napi_reject_deferred
- napi_add_finalizer
- napi_create_array
- napi_delete_reference
- napi_get_date_value
- napi_create_dataview
- napi_get_version
- napi_define_class
- napi_is_date
- napi_remove_wrap
- napi_delete_property
- napi_instanceof
- napi_create_buffer_copy
- napi_delete_element
- napi_object_seal
- napi_queue_async_work
- napi_get_value_bigint_words
- napi_is_buffer
- napi_get_array_length
- napi_get_property
- napi_new_instance
- napi_set_element
- napi_create_bigint_words
- napi_strict_equals
- napi_is_dataview
- napi_close_escapable_handle_scope
- napi_get_dataview_info
- napi_get_value_int32
- napi_unwrap
- napi_throw_range_error
- napi_coerce_to_bool
- napi_create_uint32
- napi_has_element
- napi_create_external_arraybuffer
- napi_create_symbol
- node_api_symbol_for
- napi_coerce_to_string
- napi_create_type_error
- napi_fatal_exception
- napi_create_async_work
- napi_async_init
- node_api_create_property_key_utf16
- napi_type_tag_object
- napi_check_object_type_tag
- node_api_post_finalizer
- napi_add_async_cleanup_hook
- napi_remove_async_cleanup_hook
- uv_mutex_init
- uv_mutex_lock
- uv_mutex_unlock
- uv_mutex_destroy
- uv_async_init
- uv_async_send
- uv_close \ No newline at end of file
diff --git a/cli/napi/js_native_api.rs b/cli/napi/js_native_api.rs
deleted file mode 100644
index e922d8c3f..000000000
--- a/cli/napi/js_native_api.rs
+++ /dev/null
@@ -1,3614 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-
-#![allow(non_upper_case_globals)]
-#![deny(unsafe_op_in_unsafe_fn)]
-
-const NAPI_VERSION: u32 = 9;
-
-use deno_runtime::deno_napi::*;
-use libc::INT_MAX;
-
-use super::util::check_new_from_utf8;
-use super::util::check_new_from_utf8_len;
-use super::util::get_array_buffer_ptr;
-use super::util::make_external_backing_store;
-use super::util::napi_clear_last_error;
-use super::util::napi_set_last_error;
-use super::util::v8_name_from_property_descriptor;
-use crate::check_arg;
-use crate::check_env;
-use deno_runtime::deno_napi::function::create_function;
-use deno_runtime::deno_napi::function::create_function_template;
-use deno_runtime::deno_napi::function::CallbackInfo;
-use napi_sym::napi_sym;
-use std::ptr::NonNull;
-
-#[derive(Debug, Clone, Copy, PartialEq)]
-enum ReferenceOwnership {
- Runtime,
- Userland,
-}
-
-enum ReferenceState {
- Strong(v8::Global<v8::Value>),
- Weak(v8::Weak<v8::Value>),
-}
-
-struct Reference {
- env: *mut Env,
- state: ReferenceState,
- ref_count: u32,
- ownership: ReferenceOwnership,
- finalize_cb: Option<napi_finalize>,
- finalize_data: *mut c_void,
- finalize_hint: *mut c_void,
-}
-
-impl Reference {
- fn new(
- env: *mut Env,
- value: v8::Local<v8::Value>,
- initial_ref_count: u32,
- ownership: ReferenceOwnership,
- finalize_cb: Option<napi_finalize>,
- finalize_data: *mut c_void,
- finalize_hint: *mut c_void,
- ) -> Box<Self> {
- let isolate = unsafe { (*env).isolate() };
-
- let mut reference = Box::new(Reference {
- env,
- state: ReferenceState::Strong(v8::Global::new(isolate, value)),
- ref_count: initial_ref_count,
- ownership,
- finalize_cb,
- finalize_data,
- finalize_hint,
- });
-
- if initial_ref_count == 0 {
- reference.set_weak();
- }
-
- reference
- }
-
- fn ref_(&mut self) -> u32 {
- self.ref_count += 1;
- if self.ref_count == 1 {
- self.set_strong();
- }
- self.ref_count
- }
-
- fn unref(&mut self) -> u32 {
- let old_ref_count = self.ref_count;
- if self.ref_count > 0 {
- self.ref_count -= 1;
- }
- if old_ref_count == 1 && self.ref_count == 0 {
- self.set_weak();
- }
- self.ref_count
- }
-
- fn reset(&mut self) {
- self.finalize_cb = None;
- self.finalize_data = std::ptr::null_mut();
- self.finalize_hint = std::ptr::null_mut();
- }
-
- fn set_strong(&mut self) {
- if let ReferenceState::Weak(w) = &self.state {
- let isolate = unsafe { (*self.env).isolate() };
- if let Some(g) = w.to_global(isolate) {
- self.state = ReferenceState::Strong(g);
- }
- }
- }
-
- fn set_weak(&mut self) {
- let reference = self as *mut Reference;
- if let ReferenceState::Strong(g) = &self.state {
- let cb = Box::new(move |_: &mut v8::Isolate| {
- Reference::weak_callback(reference)
- });
- let isolate = unsafe { (*self.env).isolate() };
- self.state =
- ReferenceState::Weak(v8::Weak::with_finalizer(isolate, g, cb));
- }
- }
-
- fn weak_callback(reference: *mut Reference) {
- let reference = unsafe { &mut *reference };
-
- let finalize_cb = reference.finalize_cb;
- let finalize_data = reference.finalize_data;
- let finalize_hint = reference.finalize_hint;
- reference.reset();
-
- // copy this value before the finalize callback, since
- // it might free the reference (which would be a UAF)
- let ownership = reference.ownership;
- if let Some(finalize_cb) = finalize_cb {
- unsafe {
- finalize_cb(reference.env as _, finalize_data, finalize_hint);
- }
- }
-
- if ownership == ReferenceOwnership::Runtime {
- unsafe { drop(Reference::from_raw(reference)) }
- }
- }
-
- fn into_raw(r: Box<Reference>) -> *mut Reference {
- Box::into_raw(r)
- }
-
- unsafe fn from_raw(r: *mut Reference) -> Box<Reference> {
- unsafe { Box::from_raw(r) }
- }
-
- unsafe fn remove(r: *mut Reference) {
- let r = unsafe { &mut *r };
- if r.ownership == ReferenceOwnership::Userland {
- r.reset();
- } else {
- unsafe { drop(Reference::from_raw(r)) }
- }
- }
-}
-
-#[napi_sym]
-fn napi_get_last_error_info(
- env: *mut Env,
- result: *mut *const napi_extended_error_info,
-) -> napi_status {
- let env = check_env!(env);
- check_arg!(env, result);
-
- if env.last_error.error_code == napi_ok {
- napi_clear_last_error(env);
- } else {
- env.last_error.error_message =
- ERROR_MESSAGES[env.last_error.error_code as usize].as_ptr();
- }
-
- unsafe {
- *result = &env.last_error;
- }
-
- napi_ok
-}
-
-#[napi_sym]
-fn napi_create_function<'s>(
- env: &'s mut Env,
- name: *const c_char,
- length: usize,
- cb: Option<napi_callback>,
- cb_info: napi_callback_info,
- result: *mut napi_value<'s>,
-) -> napi_status {
- let env_ptr = env as *mut Env;
- check_arg!(env, result);
- check_arg!(env, cb);
-
- let name = if !name.is_null() {
- match unsafe { check_new_from_utf8_len(env, name, length) } {
- Ok(s) => Some(s),
- Err(status) => return status,
- }
- } else {
- None
- };
-
- unsafe {
- *result =
- create_function(&mut env.scope(), env_ptr, name, cb.unwrap(), cb_info)
- .into();
- }
-
- napi_ok
-}
-
-#[napi_sym]
-#[allow(clippy::too_many_arguments)]
-fn napi_define_class<'s>(
- env: &'s mut Env,
- utf8name: *const c_char,
- length: usize,
- constructor: Option<napi_callback>,
- callback_data: *mut c_void,
- property_count: usize,
- properties: *const napi_property_descriptor,
- result: *mut napi_value<'s>,
-) -> napi_status {
- let env_ptr = env as *mut Env;
- check_arg!(env, result);
- check_arg!(env, constructor);
-
- if property_count > 0 {
- check_arg!(env, properties);
- }
-
- let name = match unsafe { check_new_from_utf8_len(env, utf8name, length) } {
- Ok(string) => string,
- Err(status) => return status,
- };
-
- let tpl = create_function_template(
- &mut env.scope(),
- env_ptr,
- Some(name),
- constructor.unwrap(),
- callback_data,
- );
-
- let napi_properties: &[napi_property_descriptor] = if property_count > 0 {
- unsafe { std::slice::from_raw_parts(properties, property_count) }
- } else {
- &[]
- };
- let mut static_property_count = 0;
-
- for p in napi_properties {
- if p.attributes & napi_static != 0 {
- // Will be handled below
- static_property_count += 1;
- continue;
- }
-
- let name = match unsafe { v8_name_from_property_descriptor(env_ptr, p) } {
- Ok(name) => name,
- Err(status) => return status,
- };
-
- if p.getter.is_some() || p.setter.is_some() {
- let getter = p.getter.map(|g| {
- create_function_template(&mut env.scope(), env_ptr, None, g, p.data)
- });
- let setter = p.setter.map(|s| {
- create_function_template(&mut env.scope(), env_ptr, None, s, p.data)
- });
-
- let mut accessor_property = v8::PropertyAttribute::NONE;
- if getter.is_some()
- && setter.is_some()
- && (p.attributes & napi_writable) == 0
- {
- accessor_property =
- accessor_property | v8::PropertyAttribute::READ_ONLY;
- }
- if p.attributes & napi_enumerable == 0 {
- accessor_property =
- accessor_property | v8::PropertyAttribute::DONT_ENUM;
- }
- if p.attributes & napi_configurable == 0 {
- accessor_property =
- accessor_property | v8::PropertyAttribute::DONT_DELETE;
- }
-
- let proto = tpl.prototype_template(&mut env.scope());
- proto.set_accessor_property(name, getter, setter, accessor_property);
- } else if let Some(method) = p.method {
- let function = create_function_template(
- &mut env.scope(),
- env_ptr,
- None,
- method,
- p.data,
- );
- let proto = tpl.prototype_template(&mut env.scope());
- proto.set(name, function.into());
- } else {
- let proto = tpl.prototype_template(&mut env.scope());
- proto.set(name, p.value.unwrap().into());
- }
- }
-
- let value: v8::Local<v8::Value> =
- tpl.get_function(&mut env.scope()).unwrap().into();
-
- unsafe {
- *result = value.into();
- }
-
- if static_property_count > 0 {
- let mut static_descriptors = Vec::with_capacity(static_property_count);
-
- for p in napi_properties {
- if p.attributes & napi_static != 0 {
- static_descriptors.push(*p);
- }
- }
-
- crate::status_call!(unsafe {
- napi_define_properties(
- env_ptr,
- *result,
- static_descriptors.len(),
- static_descriptors.as_ptr(),
- )
- });
- }
-
- napi_ok
-}
-
-#[napi_sym]
-fn napi_get_property_names(
- env: *mut Env,
- object: napi_value,
- result: *mut napi_value,
-) -> napi_status {
- unsafe {
- napi_get_all_property_names(
- env,
- object,
- napi_key_include_prototypes,
- napi_key_enumerable | napi_key_skip_symbols,
- napi_key_numbers_to_strings,
- result,
- )
- }
-}
-
-#[napi_sym]
-fn napi_get_all_property_names<'s>(
- env: &'s mut Env,
- object: napi_value,
- key_mode: napi_key_collection_mode,
- key_filter: napi_key_filter,
- key_conversion: napi_key_conversion,
- result: *mut napi_value<'s>,
-) -> napi_status {
- check_arg!(env, result);
-
- let scope = &mut env.scope();
-
- let Some(obj) = object.and_then(|o| o.to_object(scope)) else {
- return napi_object_expected;
- };
-
- let mut filter = v8::PropertyFilter::ALL_PROPERTIES;
-
- if key_filter & napi_key_writable != 0 {
- filter = filter | v8::PropertyFilter::ONLY_WRITABLE;
- }
- if key_filter & napi_key_enumerable != 0 {
- filter = filter | v8::PropertyFilter::ONLY_ENUMERABLE;
- }
- if key_filter & napi_key_configurable != 0 {
- filter = filter | v8::PropertyFilter::ONLY_CONFIGURABLE;
- }
- if key_filter & napi_key_skip_strings != 0 {
- filter = filter | v8::PropertyFilter::SKIP_STRINGS;
- }
- if key_filter & napi_key_skip_symbols != 0 {
- filter = filter | v8::PropertyFilter::SKIP_SYMBOLS;
- }
-
- let key_mode = match key_mode {
- napi_key_include_prototypes => v8::KeyCollectionMode::IncludePrototypes,
- napi_key_own_only => v8::KeyCollectionMode::OwnOnly,
- _ => return napi_invalid_arg,
- };
-
- let key_conversion = match key_conversion {
- napi_key_keep_numbers => v8::KeyConversionMode::KeepNumbers,
- napi_key_numbers_to_strings => v8::KeyConversionMode::ConvertToString,
- _ => return napi_invalid_arg,
- };
-
- let filter = v8::GetPropertyNamesArgsBuilder::new()
- .mode(key_mode)
- .property_filter(filter)
- .index_filter(v8::IndexFilter::IncludeIndices)
- .key_conversion(key_conversion)
- .build();
-
- let property_names = match obj.get_property_names(scope, filter) {
- Some(n) => n,
- None => return napi_generic_failure,
- };
-
- unsafe {
- *result = property_names.into();
- }
-
- napi_ok
-}
-
-#[napi_sym]
-fn napi_set_property(
- env: &mut Env,
- object: napi_value,
- key: napi_value,
- value: napi_value,
-) -> napi_status {
- check_arg!(env, key);
- check_arg!(env, value);
-
- let scope = &mut env.scope();
-
- let Some(object) = object.and_then(|o| o.to_object(scope)) else {
- return napi_object_expected;
- };
-
- if object.set(scope, key.unwrap(), value.unwrap()).is_none() {
- return napi_generic_failure;
- };
-
- napi_ok
-}
-
-#[napi_sym]
-fn napi_has_property(
- env: &mut Env,
- object: napi_value,
- key: napi_value,
- result: *mut bool,
-) -> napi_status {
- check_arg!(env, key);
- check_arg!(env, result);
-
- let scope = &mut env.scope();
-
- let Some(object) = object.and_then(|o| o.to_object(scope)) else {
- return napi_object_expected;
- };
-
- let Some(has) = object.has(scope, key.unwrap()) else {
- return napi_generic_failure;
- };
-
- unsafe {
- *result = has;
- }
-
- napi_ok
-}
-
-#[napi_sym]
-fn napi_get_property<'s>(
- env: &'s mut Env,
- object: napi_value,
- key: napi_value,
- result: *mut napi_value<'s>,
-) -> napi_status {
- check_arg!(env, key);
- check_arg!(env, result);
-
- let scope = &mut env.scope();
-
- let Some(object) = object.and_then(|o| o.to_object(scope)) else {
- return napi_object_expected;
- };
-
- let Some(value) = object.get(scope, key.unwrap()) else {
- return napi_generic_failure;
- };
-
- unsafe {
- *result = value.into();
- }
-
- napi_ok
-}
-
-#[napi_sym]
-fn napi_delete_property(
- env: &mut Env,
- object: napi_value,
- key: napi_value,
- result: *mut bool,
-) -> napi_status {
- check_arg!(env, key);
-
- let scope = &mut env.scope();
-
- let Some(object) = object.and_then(|o| o.to_object(scope)) else {
- return napi_object_expected;
- };
-
- let Some(deleted) = object.delete(scope, key.unwrap()) else {
- return napi_generic_failure;
- };
-
- if !result.is_null() {
- unsafe {
- *result = deleted;
- }
- }
-
- napi_ok
-}
-
-#[napi_sym]
-fn napi_has_own_property(
- env: &mut Env,
- object: napi_value,
- key: napi_value,
- result: *mut bool,
-) -> napi_status {
- check_arg!(env, key);
- check_arg!(env, result);
-
- let scope = &mut env.scope();
-
- let Some(object) = object.and_then(|o| o.to_object(scope)) else {
- return napi_object_expected;
- };
-
- let Ok(key) = v8::Local::<v8::Name>::try_from(key.unwrap()) else {
- return napi_name_expected;
- };
-
- let Some(has_own) = object.has_own_property(scope, key) else {
- return napi_generic_failure;
- };
-
- unsafe {
- *result = has_own;
- }
-
- napi_ok
-}
-
-#[napi_sym]
-fn napi_has_named_property<'s>(
- env: &'s mut Env,
- object: napi_value<'s>,
- utf8name: *const c_char,
- result: *mut bool,
-) -> napi_status {
- let env_ptr = env as *mut Env;
- check_arg!(env, result);
-
- let Some(object) = object.and_then(|o| o.to_object(&mut env.scope())) else {
- return napi_object_expected;
- };
-
- let key = match unsafe { check_new_from_utf8(env_ptr, utf8name) } {
- Ok(key) => key,
- Err(status) => return status,
- };
-
- let Some(has_property) = object.has(&mut env.scope(), key.into()) else {
- return napi_generic_failure;
- };
-
- unsafe {
- *result = has_property;
- }
-
- napi_ok
-}
-
-#[napi_sym]
-fn napi_set_named_property<'s>(
- env: &'s mut Env,
- object: napi_value<'s>,
- utf8name: *const c_char,
- value: napi_value<'s>,
-) -> napi_status {
- check_arg!(env, value);
- let env_ptr = env as *mut Env;
-
- let Some(object) = object.and_then(|o| o.to_object(&mut env.scope())) else {
- return napi_object_expected;
- };
-
- let key = match unsafe { check_new_from_utf8(env_ptr, utf8name) } {
- Ok(key) => key,
- Err(status) => return status,
- };
-
- let value = value.unwrap();
-
- if !object
- .set(&mut env.scope(), key.into(), value)
- .unwrap_or(false)
- {
- return napi_generic_failure;
- }
-
- napi_ok
-}
-
-#[napi_sym]
-fn napi_get_named_property<'s>(
- env: &'s mut Env,
- object: napi_value<'s>,
- utf8name: *const c_char,
- result: *mut napi_value<'s>,
-) -> napi_status {
- check_arg!(env, result);
- let env_ptr = env as *mut Env;
-
- let Some(object) = object.and_then(|o| o.to_object(&mut env.scope())) else {
- return napi_object_expected;
- };
-
- let key = match unsafe { check_new_from_utf8(env_ptr, utf8name) } {
- Ok(key) => key,
- Err(status) => return status,
- };
-
- let Some(value) = object.get(&mut env.scope(), key.into()) else {
- return napi_generic_failure;
- };
-
- unsafe {
- *result = value.into();
- }
-
- napi_ok
-}
-
-#[napi_sym]
-fn napi_set_element<'s>(
- env: &'s mut Env,
- object: napi_value<'s>,
- index: u32,
- value: napi_value<'s>,
-) -> napi_status {
- check_arg!(env, value);
-
- let scope = &mut env.scope();
-
- let Some(object) = object.and_then(|o| o.to_object(scope)) else {
- return napi_object_expected;
- };
-
- if !object
- .set_index(scope, index, value.unwrap())
- .unwrap_or(false)
- {
- return napi_generic_failure;
- }
-
- napi_ok
-}
-
-#[napi_sym]
-fn napi_has_element(
- env: &mut Env,
- object: napi_value,
- index: u32,
- result: *mut bool,
-) -> napi_status {
- check_arg!(env, result);
-
- let scope = &mut env.scope();
-
- let Some(object) = object.and_then(|o| o.to_object(scope)) else {
- return napi_object_expected;
- };
-
- let Some(has) = object.has_index(scope, index) else {
- return napi_generic_failure;
- };
-
- unsafe {
- *result = has;
- }
-
- napi_ok
-}
-
-#[napi_sym]
-fn napi_get_element<'s>(
- env: &'s mut Env,
- object: napi_value,
- index: u32,
- result: *mut napi_value<'s>,
-) -> napi_status {
- check_arg!(env, result);
-
- let scope = &mut env.scope();
-
- let Some(object) = object.and_then(|o| o.to_object(scope)) else {
- return napi_object_expected;
- };
-
- let Some(value) = object.get_index(scope, index) else {
- return napi_generic_failure;
- };
-
- unsafe {
- *result = value.into();
- }
-
- napi_ok
-}
-
-#[napi_sym]
-fn napi_delete_element(
- env: &mut Env,
- object: napi_value,
- index: u32,
- result: *mut bool,
-) -> napi_status {
- let scope = &mut env.scope();
-
- let Some(object) = object.and_then(|o| o.to_object(scope)) else {
- return napi_object_expected;
- };
-
- let Some(deleted) = object.delete_index(scope, index) else {
- return napi_generic_failure;
- };
-
- if !result.is_null() {
- unsafe {
- *result = deleted;
- }
- }
-
- napi_ok
-}
-
-#[napi_sym]
-fn napi_define_properties(
- env: &mut Env,
- object: napi_value,
- property_count: usize,
- properties: *const napi_property_descriptor,
-) -> napi_status {
- let env_ptr = env as *mut Env;
-
- if property_count > 0 {
- check_arg!(env, properties);
- }
-
- let scope = &mut env.scope();
-
- let Some(object) = object.and_then(|o| o.to_object(scope)) else {
- return napi_object_expected;
- };
-
- let properties = if property_count == 0 {
- &[]
- } else {
- unsafe { std::slice::from_raw_parts(properties, property_count) }
- };
- for property in properties {
- let property_name =
- match unsafe { v8_name_from_property_descriptor(env_ptr, property) } {
- Ok(name) => name,
- Err(status) => return status,
- };
-
- let writable = property.attributes & napi_writable != 0;
- let enumerable = property.attributes & napi_enumerable != 0;
- let configurable = property.attributes & napi_configurable != 0;
-
- if property.getter.is_some() || property.setter.is_some() {
- let local_getter: v8::Local<v8::Value> = if let Some(getter) =
- property.getter
- {
- create_function(&mut env.scope(), env_ptr, None, getter, property.data)
- .into()
- } else {
- v8::undefined(scope).into()
- };
- let local_setter: v8::Local<v8::Value> = if let Some(setter) =
- property.setter
- {
- create_function(&mut env.scope(), env_ptr, None, setter, property.data)
- .into()
- } else {
- v8::undefined(scope).into()
- };
-
- let mut desc =
- v8::PropertyDescriptor::new_from_get_set(local_getter, local_setter);
- desc.set_enumerable(enumerable);
- desc.set_configurable(configurable);
-
- if !object
- .define_property(scope, property_name, &desc)
- .unwrap_or(false)
- {
- return napi_invalid_arg;
- }
- } else if let Some(method) = property.method {
- let method: v8::Local<v8::Value> = {
- let function = create_function(
- &mut env.scope(),
- env_ptr,
- None,
- method,
- property.data,
- );
- function.into()
- };
-
- let mut desc =
- v8::PropertyDescriptor::new_from_value_writable(method, writable);
- desc.set_enumerable(enumerable);
- desc.set_configurable(configurable);
-
- if !object
- .define_property(scope, property_name, &desc)
- .unwrap_or(false)
- {
- return napi_generic_failure;
- }
- } else {
- let value = property.value.unwrap();
-
- if enumerable & writable & configurable {
- if !object
- .create_data_property(scope, property_name, value)
- .unwrap_or(false)
- {
- return napi_invalid_arg;
- }
- } else {
- let mut desc =
- v8::PropertyDescriptor::new_from_value_writable(value, writable);
- desc.set_enumerable(enumerable);
- desc.set_configurable(configurable);
-
- if !object
- .define_property(scope, property_name, &desc)
- .unwrap_or(false)
- {
- return napi_invalid_arg;
- }
- }
- }
- }
-
- napi_ok
-}
-
-#[napi_sym]
-fn napi_object_freeze(env: &mut Env, object: napi_value) -> napi_status {
- let scope = &mut env.scope();
-
- let Some(object) = object.and_then(|o| o.to_object(scope)) else {
- return napi_object_expected;
- };
-
- if !object
- .set_integrity_level(scope, v8::IntegrityLevel::Frozen)
- .unwrap_or(false)
- {
- return napi_generic_failure;
- }
-
- napi_ok
-}
-
-#[napi_sym]
-fn napi_object_seal(env: &mut Env, object: napi_value) -> napi_status {
- let scope = &mut env.scope();
-
- let Some(object) = object.and_then(|o| o.to_object(scope)) else {
- return napi_object_expected;
- };
-
- if !object
- .set_integrity_level(scope, v8::IntegrityLevel::Sealed)
- .unwrap_or(false)
- {
- return napi_generic_failure;
- }
-
- napi_ok
-}
-
-#[napi_sym]
-fn napi_is_array(
- env: *mut Env,
- value: napi_value,
- result: *mut bool,
-) -> napi_status {
- let env = check_env!(env);
- check_arg!(env, value);
- check_arg!(env, result);
-
- let value = value.unwrap();
-
- unsafe {
- *result = value.is_array();
- }
-
- napi_clear_last_error(env)
-}
-
-#[napi_sym]
-fn napi_get_array_length(
- env: &mut Env,
- value: napi_value,
- result: *mut u32,
-) -> napi_status {
- check_arg!(env, value);
- check_arg!(env, result);
-
- let value = value.unwrap();
-
- match v8::Local::<v8::Array>::try_from(value) {
- Ok(array) => {
- unsafe {
- *result = array.length();
- }
- napi_ok
- }
- Err(_) => napi_array_expected,
- }
-}
-
-#[napi_sym]
-fn napi_strict_equals(
- env: &mut Env,
- lhs: napi_value,
- rhs: napi_value,
- result: *mut bool,
-) -> napi_status {
- check_arg!(env, lhs);
- check_arg!(env, rhs);
- check_arg!(env, result);
-
- unsafe {
- *result = lhs.unwrap().strict_equals(rhs.unwrap());
- }
-
- napi_ok
-}
-
-#[napi_sym]
-fn napi_get_prototype<'s>(
- env: &'s mut Env,
- object: napi_value,
- result: *mut napi_value<'s>,
-) -> napi_status {
- check_arg!(env, result);
-
- let scope = &mut env.scope();
-
- let Some(object) = object.and_then(|o| o.to_object(scope)) else {
- return napi_object_expected;
- };
-
- let Some(proto) = object.get_prototype(scope) else {
- return napi_generic_failure;
- };
-
- unsafe {
- *result = proto.into();
- }
-
- napi_ok
-}
-
-#[napi_sym]
-fn napi_create_object(
- env_ptr: *mut Env,
- result: *mut napi_value,
-) -> napi_status {
- let env = check_env!(env_ptr);
- check_arg!(env, result);
-
- unsafe {
- *result = v8::Object::new(&mut env.scope()).into();
- }
-
- return napi_clear_last_error(env_ptr);
-}
-
-#[napi_sym]
-fn napi_create_array(
- env_ptr: *mut Env,
- result: *mut napi_value,
-) -> napi_status {
- let env = check_env!(env_ptr);
- check_arg!(env, result);
-
- unsafe {
- *result = v8::Array::new(&mut env.scope(), 0).into();
- }
-
- return napi_clear_last_error(env_ptr);
-}
-
-#[napi_sym]
-fn napi_create_array_with_length(
- env_ptr: *mut Env,
- length: usize,
- result: *mut napi_value,
-) -> napi_status {
- let env = check_env!(env_ptr);
- check_arg!(env, result);
-
- unsafe {
- *result = v8::Array::new(&mut env.scope(), length as _).into();
- }
-
- return napi_clear_last_error(env_ptr);
-}
-
-#[napi_sym]
-fn napi_create_string_latin1(
- env_ptr: *mut Env,
- string: *const c_char,
- length: usize,
- result: *mut napi_value,
-) -> napi_status {
- let env = check_env!(env_ptr);
- if length > 0 {
- check_arg!(env, string);
- }
- crate::return_status_if_false!(
- env,
- (length == NAPI_AUTO_LENGTH) || length <= INT_MAX as _,
- napi_invalid_arg
- );
-
- let buffer = if length > 0 {
- unsafe {
- std::slice::from_raw_parts(
- string as _,
- if length == NAPI_AUTO_LENGTH {
- std::ffi::CStr::from_ptr(string).to_bytes().len()
- } else {
- length
- },
- )
- }
- } else {
- &[]
- };
-
- let Some(string) = v8::String::new_from_one_byte(
- &mut env.scope(),
- buffer,
- v8::NewStringType::Normal,
- ) else {
- return napi_set_last_error(env_ptr, napi_generic_failure);
- };
-
- unsafe {
- *result = string.into();
- }
-
- return napi_clear_last_error(env_ptr);
-}
-
-#[napi_sym]
-fn napi_create_string_utf8(
- env_ptr: *mut Env,
- string: *const c_char,
- length: usize,
- result: *mut napi_value,
-) -> napi_status {
- let env = check_env!(env_ptr);
- if length > 0 {
- check_arg!(env, string);
- }
- crate::return_status_if_false!(
- env,
- (length == NAPI_AUTO_LENGTH) || length <= INT_MAX as _,
- napi_invalid_arg
- );
-
- let buffer = if length > 0 {
- unsafe {
- std::slice::from_raw_parts(
- string as _,
- if length == NAPI_AUTO_LENGTH {
- std::ffi::CStr::from_ptr(string).to_bytes().len()
- } else {
- length
- },
- )
- }
- } else {
- &[]
- };
-
- let Some(string) = v8::String::new_from_utf8(
- &mut env.scope(),
- buffer,
- v8::NewStringType::Normal,
- ) else {
- return napi_set_last_error(env_ptr, napi_generic_failure);
- };
-
- unsafe {
- *result = string.into();
- }
-
- return napi_clear_last_error(env_ptr);
-}
-
-#[napi_sym]
-fn napi_create_string_utf16(
- env_ptr: *mut Env,
- string: *const u16,
- length: usize,
- result: *mut napi_value,
-) -> napi_status {
- let env = check_env!(env_ptr);
- if length > 0 {
- check_arg!(env, string);
- }
- crate::return_status_if_false!(
- env,
- (length == NAPI_AUTO_LENGTH) || length <= INT_MAX as _,
- napi_invalid_arg
- );
-
- let buffer = if length > 0 {
- unsafe {
- std::slice::from_raw_parts(
- string,
- if length == NAPI_AUTO_LENGTH {
- let mut length = 0;
- while *(string.add(length)) != 0 {
- length += 1;
- }
- length
- } else {
- length
- },
- )
- }
- } else {
- &[]
- };
-
- let Some(string) = v8::String::new_from_two_byte(
- &mut env.scope(),
- buffer,
- v8::NewStringType::Normal,
- ) else {
- return napi_set_last_error(env_ptr, napi_generic_failure);
- };
-
- unsafe {
- *result = string.into();
- }
-
- return napi_clear_last_error(env_ptr);
-}
-
-#[napi_sym]
-fn node_api_create_external_string_latin1(
- env_ptr: *mut Env,
- string: *const c_char,
- length: usize,
- nogc_finalize_callback: Option<napi_finalize>,
- finalize_hint: *mut c_void,
- result: *mut napi_value,
- copied: *mut bool,
-) -> napi_status {
- let status =
- unsafe { napi_create_string_latin1(env_ptr, string, length, result) };
-
- if status == napi_ok {
- unsafe {
- *copied = true;
- }
-
- if let Some(finalize) = nogc_finalize_callback {
- unsafe {
- finalize(env_ptr as napi_env, string as *mut c_void, finalize_hint);
- }
- }
- }
-
- status
-}
-
-#[napi_sym]
-fn node_api_create_external_string_utf16(
- env_ptr: *mut Env,
- string: *const u16,
- length: usize,
- nogc_finalize_callback: Option<napi_finalize>,
- finalize_hint: *mut c_void,
- result: *mut napi_value,
- copied: *mut bool,
-) -> napi_status {
- let status =
- unsafe { napi_create_string_utf16(env_ptr, string, length, result) };
-
- if status == napi_ok {
- unsafe {
- *copied = true;
- }
-
- if let Some(finalize) = nogc_finalize_callback {
- unsafe {
- finalize(env_ptr as napi_env, string as *mut c_void, finalize_hint);
- }
- }
- }
-
- status
-}
-
-#[napi_sym]
-fn node_api_create_property_key_utf16(
- env_ptr: *mut Env,
- string: *const u16,
- length: usize,
- result: *mut napi_value,
-) -> napi_status {
- let env = check_env!(env_ptr);
- if length > 0 {
- check_arg!(env, string);
- }
- crate::return_status_if_false!(
- env,
- (length == NAPI_AUTO_LENGTH) || length <= INT_MAX as _,
- napi_invalid_arg
- );
-
- let buffer = if length > 0 {
- unsafe {
- std::slice::from_raw_parts(
- string,
- if length == NAPI_AUTO_LENGTH {
- let mut length = 0;
- while *(string.add(length)) != 0 {
- length += 1;
- }
- length
- } else {
- length
- },
- )
- }
- } else {
- &[]
- };
-
- let Some(string) = v8::String::new_from_two_byte(
- &mut env.scope(),
- buffer,
- v8::NewStringType::Internalized,
- ) else {
- return napi_set_last_error(env_ptr, napi_generic_failure);
- };
-
- unsafe {
- *result = string.into();
- }
-
- return napi_clear_last_error(env_ptr);
-}
-
-#[napi_sym]
-fn napi_create_double(
- env_ptr: *mut Env,
- value: f64,
- result: *mut napi_value,
-) -> napi_status {
- let env = check_env!(env_ptr);
- check_arg!(env, result);
-
- unsafe {
- *result = v8::Number::new(&mut env.scope(), value).into();
- }
-
- napi_clear_last_error(env_ptr)
-}
-
-#[napi_sym]
-fn napi_create_int32(
- env_ptr: *mut Env,
- value: i32,
- result: *mut napi_value,
-) -> napi_status {
- let env = check_env!(env_ptr);
- check_arg!(env, result);
-
- unsafe {
- *result = v8::Integer::new(&mut env.scope(), value).into();
- }
-
- napi_clear_last_error(env_ptr)
-}
-
-#[napi_sym]
-fn napi_create_uint32(
- env_ptr: *mut Env,
- value: u32,
- result: *mut napi_value,
-) -> napi_status {
- let env = check_env!(env_ptr);
- check_arg!(env, result);
-
- unsafe {
- *result = v8::Integer::new_from_unsigned(&mut env.scope(), value).into();
- }
-
- napi_clear_last_error(env_ptr)
-}
-
-#[napi_sym]
-fn napi_create_int64(
- env_ptr: *mut Env,
- value: i64,
- result: *mut napi_value,
-) -> napi_status {
- let env = check_env!(env_ptr);
- check_arg!(env, result);
-
- unsafe {
- *result = v8::Number::new(&mut env.scope(), value as _).into();
- }
-
- napi_clear_last_error(env_ptr)
-}
-
-#[napi_sym]
-fn napi_create_bigint_int64(
- env_ptr: *mut Env,
- value: i64,
- result: *mut napi_value,
-) -> napi_status {
- let env = check_env!(env_ptr);
- check_arg!(env, result);
-
- unsafe {
- *result = v8::BigInt::new_from_i64(&mut env.scope(), value).into();
- }
-
- napi_clear_last_error(env_ptr)
-}
-
-#[napi_sym]
-fn napi_create_bigint_uint64(
- env_ptr: *mut Env,
- value: u64,
- result: *mut napi_value,
-) -> napi_status {
- let env = check_env!(env_ptr);
- check_arg!(env, result);
-
- unsafe {
- *result = v8::BigInt::new_from_u64(&mut env.scope(), value).into();
- }
-
- napi_clear_last_error(env_ptr)
-}
-
-#[napi_sym]
-fn napi_create_bigint_words<'s>(
- env: &'s mut Env,
- sign_bit: bool,
- word_count: usize,
- words: *const u64,
- result: *mut napi_value<'s>,
-) -> napi_status {
- check_arg!(env, words);
- check_arg!(env, result);
-
- if word_count > INT_MAX as _ {
- return napi_invalid_arg;
- }
-
- match v8::BigInt::new_from_words(&mut env.scope(), sign_bit, unsafe {
- std::slice::from_raw_parts(words, word_count)
- }) {
- Some(value) => unsafe {
- *result = value.into();
- },
- None => {
- return napi_generic_failure;
- }
- }
-
- napi_ok
-}
-
-#[napi_sym]
-fn napi_get_boolean(
- env: *mut Env,
- value: bool,
- result: *mut napi_value,
-) -> napi_status {
- let env = check_env!(env);
- check_arg!(env, result);
-
- unsafe {
- *result = v8::Boolean::new(env.isolate(), value).into();
- }
-
- return napi_clear_last_error(env);
-}
-
-#[napi_sym]
-fn napi_create_symbol(
- env_ptr: *mut Env,
- description: napi_value,
- result: *mut napi_value,
-) -> napi_status {
- let env = check_env!(env_ptr);
- check_arg!(env, result);
-
- let description = if let Some(d) = *description {
- let Some(d) = d.to_string(&mut env.scope()) else {
- return napi_set_last_error(env, napi_string_expected);
- };
- Some(d)
- } else {
- None
- };
-
- unsafe {
- *result = v8::Symbol::new(&mut env.scope(), description).into();
- }
-
- return napi_clear_last_error(env_ptr);
-}
-
-#[napi_sym]
-fn node_api_symbol_for(
- env: *mut Env,
- utf8description: *const c_char,
- length: usize,
- result: *mut napi_value,
-) -> napi_status {
- {
- let env = check_env!(env);
- check_arg!(env, result);
-
- let description_string =
- match unsafe { check_new_from_utf8_len(env, utf8description, length) } {
- Ok(s) => s,
- Err(status) => return napi_set_last_error(env, status),
- };
-
- unsafe {
- *result =
- v8::Symbol::for_key(&mut env.scope(), description_string).into();
- }
- }
-
- napi_clear_last_error(env)
-}
-
-macro_rules! napi_create_error_impl {
- ($env_ptr:ident, $code:ident, $msg:ident, $result:ident, $error:ident) => {{
- let env_ptr = $env_ptr;
- let code = $code;
- let msg = $msg;
- let result = $result;
-
- let env = check_env!(env_ptr);
- check_arg!(env, msg);
- check_arg!(env, result);
-
- let Some(message) =
- msg.and_then(|v| v8::Local::<v8::String>::try_from(v).ok())
- else {
- return napi_set_last_error(env_ptr, napi_string_expected);
- };
-
- let error = v8::Exception::$error(&mut env.scope(), message);
-
- if let Some(code) = *code {
- let error_obj: v8::Local<v8::Object> = error.try_into().unwrap();
- let code_key = v8::String::new(&mut env.scope(), "code").unwrap();
- if !error_obj
- .set(&mut env.scope(), code_key.into(), code)
- .unwrap_or(false)
- {
- return napi_set_last_error(env_ptr, napi_generic_failure);
- }
- }
-
- unsafe {
- *result = error.into();
- }
-
- return napi_clear_last_error(env_ptr);
- }};
-}
-
-#[napi_sym]
-fn napi_create_error(
- env_ptr: *mut Env,
- code: napi_value,
- msg: napi_value,
- result: *mut napi_value,
-) -> napi_status {
- napi_create_error_impl!(env_ptr, code, msg, result, error)
-}
-
-#[napi_sym]
-fn napi_create_type_error(
- env_ptr: *mut Env,
- code: napi_value,
- msg: napi_value,
- result: *mut napi_value,
-) -> napi_status {
- napi_create_error_impl!(env_ptr, code, msg, result, type_error)
-}
-
-#[napi_sym]
-fn napi_create_range_error(
- env_ptr: *mut Env,
- code: napi_value,
- msg: napi_value,
- result: *mut napi_value,
-) -> napi_status {
- napi_create_error_impl!(env_ptr, code, msg, result, range_error)
-}
-
-#[napi_sym]
-fn node_api_create_syntax_error(
- env_ptr: *mut Env,
- code: napi_value,
- msg: napi_value,
- result: *mut napi_value,
-) -> napi_status {
- napi_create_error_impl!(env_ptr, code, msg, result, syntax_error)
-}
-
-pub fn get_value_type(value: v8::Local<v8::Value>) -> Option<napi_valuetype> {
- if value.is_undefined() {
- Some(napi_undefined)
- } else if value.is_null() {
- Some(napi_null)
- } else if value.is_external() {
- Some(napi_external)
- } else if value.is_boolean() {
- Some(napi_boolean)
- } else if value.is_number() {
- Some(napi_number)
- } else if value.is_big_int() {
- Some(napi_bigint)
- } else if value.is_string() {
- Some(napi_string)
- } else if value.is_symbol() {
- Some(napi_symbol)
- } else if value.is_function() {
- Some(napi_function)
- } else if value.is_object() {
- Some(napi_object)
- } else {
- None
- }
-}
-
-#[napi_sym]
-fn napi_typeof(
- env: *mut Env,
- value: napi_value,
- result: *mut napi_valuetype,
-) -> napi_status {
- let env = check_env!(env);
- check_arg!(env, value);
- check_arg!(env, result);
-
- let Some(ty) = get_value_type(value.unwrap()) else {
- return napi_set_last_error(env, napi_invalid_arg);
- };
-
- unsafe {
- *result = ty;
- }
-
- napi_clear_last_error(env)
-}
-
-#[napi_sym]
-fn napi_get_undefined(env: *mut Env, result: *mut napi_value) -> napi_status {
- let env = check_env!(env);
- check_arg!(env, result);
-
- unsafe {
- *result = v8::undefined(&mut env.scope()).into();
- }
-
- return napi_clear_last_error(env);
-}
-
-#[napi_sym]
-fn napi_get_null(env: *mut Env, result: *mut napi_value) -> napi_status {
- let env = check_env!(env);
- check_arg!(env, result);
-
- unsafe {
- *result = v8::null(&mut env.scope()).into();
- }
-
- return napi_clear_last_error(env);
-}
-
-#[napi_sym]
-fn napi_get_cb_info(
- env: *mut Env,
- cbinfo: napi_callback_info,
- argc: *mut i32,
- argv: *mut napi_value,
- this_arg: *mut napi_value,
- data: *mut *mut c_void,
-) -> napi_status {
- let env = check_env!(env);
- check_arg!(env, cbinfo);
-
- let cbinfo: &CallbackInfo = unsafe { &*(cbinfo as *const CallbackInfo) };
- let args = unsafe { &*(cbinfo.args as *const v8::FunctionCallbackArguments) };
-
- if !argv.is_null() {
- check_arg!(env, argc);
- let argc = unsafe { *argc as usize };
- for i in 0..argc {
- let mut arg = args.get(i as _);
- unsafe {
- *argv.add(i) = arg.into();
- }
- }
- }
-
- if !argc.is_null() {
- unsafe {
- *argc = args.length();
- }
- }
-
- if !this_arg.is_null() {
- unsafe {
- *this_arg = args.this().into();
- }
- }
-
- if !data.is_null() {
- unsafe {
- *data = cbinfo.cb_info;
- }
- }
-
- napi_clear_last_error(env);
- napi_ok
-}
-
-#[napi_sym]
-fn napi_get_new_target(
- env: *mut Env,
- cbinfo: napi_callback_info,
- result: *mut napi_value,
-) -> napi_status {
- let env = check_env!(env);
- check_arg!(env, cbinfo);
- check_arg!(env, result);
-
- let cbinfo: &CallbackInfo = unsafe { &*(cbinfo as *const CallbackInfo) };
- let args = unsafe { &*(cbinfo.args as *const v8::FunctionCallbackArguments) };
-
- unsafe {
- *result = args.new_target().into();
- }
-
- return napi_clear_last_error(env);
-}
-
-#[napi_sym]
-fn napi_call_function(
- env_ptr: *mut Env,
- recv: napi_value,
- func: napi_value,
- argc: usize,
- argv: *const napi_value,
- result: *mut napi_value,
-) -> napi_status {
- let env = check_env!(env_ptr);
- check_arg!(env, recv);
- let args = if argc > 0 {
- check_arg!(env, argv);
- unsafe {
- std::slice::from_raw_parts(argv as *mut v8::Local<v8::Value>, argc)
- }
- } else {
- &[]
- };
-
- let Some(func) =
- func.and_then(|f| v8::Local::<v8::Function>::try_from(f).ok())
- else {
- return napi_set_last_error(env, napi_function_expected);
- };
-
- let Some(v) = func.call(&mut env.scope(), recv.unwrap(), args) else {
- return napi_set_last_error(env_ptr, napi_generic_failure);
- };
-
- if !result.is_null() {
- unsafe {
- *result = v.into();
- }
- }
-
- return napi_clear_last_error(env_ptr);
-}
-
-#[napi_sym]
-fn napi_get_global(env_ptr: *mut Env, result: *mut napi_value) -> napi_status {
- let env = check_env!(env_ptr);
- check_arg!(env, result);
-
- let global = v8::Local::new(&mut env.scope(), &env.global);
- unsafe {
- *result = global.into();
- }
-
- return napi_clear_last_error(env_ptr);
-}
-
-#[napi_sym]
-fn napi_throw(env: *mut Env, error: napi_value) -> napi_status {
- let env = check_env!(env);
- check_arg!(env, error);
-
- if env.last_exception.is_some() {
- return napi_pending_exception;
- }
-
- let error = error.unwrap();
- env.scope().throw_exception(error);
- let error = v8::Global::new(&mut env.scope(), error);
- env.last_exception = Some(error);
-
- napi_clear_last_error(env)
-}
-
-macro_rules! napi_throw_error_impl {
- ($env:ident, $code:ident, $msg:ident, $error:ident) => {{
- let env = check_env!($env);
- let env_ptr = env as *mut Env;
- let code = $code;
- let msg = $msg;
-
- if env.last_exception.is_some() {
- return napi_pending_exception;
- }
-
- let str_ = match unsafe { check_new_from_utf8(env, msg) } {
- Ok(s) => s,
- Err(status) => return status,
- };
-
- let error = v8::Exception::$error(&mut env.scope(), str_);
-
- if !code.is_null() {
- let error_obj: v8::Local<v8::Object> = error.try_into().unwrap();
- let code = match unsafe { check_new_from_utf8(env_ptr, code) } {
- Ok(s) => s,
- Err(status) => return napi_set_last_error(env, status),
- };
- let code_key = v8::String::new(&mut env.scope(), "code").unwrap();
- if !error_obj
- .set(&mut env.scope(), code_key.into(), code.into())
- .unwrap_or(false)
- {
- return napi_set_last_error(env, napi_generic_failure);
- }
- }
-
- env.scope().throw_exception(error);
- let error = v8::Global::new(&mut env.scope(), error);
- env.last_exception = Some(error);
-
- napi_clear_last_error(env)
- }};
-}
-
-#[napi_sym]
-fn napi_throw_error(
- env: *mut Env,
- code: *const c_char,
- msg: *const c_char,
-) -> napi_status {
- napi_throw_error_impl!(env, code, msg, error)
-}
-
-#[napi_sym]
-fn napi_throw_type_error(
- env: *mut Env,
- code: *const c_char,
- msg: *const c_char,
-) -> napi_status {
- napi_throw_error_impl!(env, code, msg, type_error)
-}
-
-#[napi_sym]
-fn napi_throw_range_error(
- env: *mut Env,
- code: *const c_char,
- msg: *const c_char,
-) -> napi_status {
- napi_throw_error_impl!(env, code, msg, range_error)
-}
-
-#[napi_sym]
-fn node_api_throw_syntax_error(
- env: *mut Env,
- code: *const c_char,
- msg: *const c_char,
-) -> napi_status {
- napi_throw_error_impl!(env, code, msg, syntax_error)
-}
-
-#[napi_sym]
-fn napi_is_error(
- env: *mut Env,
- value: napi_value,
- result: *mut bool,
-) -> napi_status {
- let env = check_env!(env);
- check_arg!(env, value);
- check_arg!(env, result);
-
- unsafe {
- *result = value.unwrap().is_native_error();
- }
-
- return napi_clear_last_error(env);
-}
-
-#[napi_sym]
-fn napi_get_value_double(
- env_ptr: *mut Env,
- value: napi_value,
- result: *mut f64,
-) -> napi_status {
- let env = check_env!(env_ptr);
- check_arg!(env, value);
- check_arg!(env, result);
-
- let Some(number) =
- value.and_then(|v| v8::Local::<v8::Number>::try_from(v).ok())
- else {
- return napi_set_last_error(env_ptr, napi_number_expected);
- };
-
- unsafe {
- *result = number.value();
- }
-
- return napi_clear_last_error(env_ptr);
-}
-
-#[napi_sym]
-fn napi_get_value_int32(
- env_ptr: *mut Env,
- value: napi_value,
- result: *mut i32,
-) -> napi_status {
- let env = check_env!(env_ptr);
- check_arg!(env, value);
- check_arg!(env, result);
-
- let Some(value) = value.unwrap().int32_value(&mut env.scope()) else {
- return napi_set_last_error(env, napi_number_expected);
- };
-
- unsafe {
- *result = value;
- }
-
- return napi_clear_last_error(env_ptr);
-}
-
-#[napi_sym]
-fn napi_get_value_uint32(
- env_ptr: *mut Env,
- value: napi_value,
- result: *mut u32,
-) -> napi_status {
- let env = check_env!(env_ptr);
- check_arg!(env, value);
- check_arg!(env, result);
-
- let Some(value) = value.unwrap().uint32_value(&mut env.scope()) else {
- return napi_set_last_error(env, napi_number_expected);
- };
-
- unsafe {
- *result = value;
- }
-
- return napi_clear_last_error(env_ptr);
-}
-
-#[napi_sym]
-fn napi_get_value_int64(
- env_ptr: *mut Env,
- value: napi_value,
- result: *mut i64,
-) -> napi_status {
- let env = check_env!(env_ptr);
- check_arg!(env, value);
- check_arg!(env, result);
-
- let Some(number) =
- value.and_then(|v| v8::Local::<v8::Number>::try_from(v).ok())
- else {
- return napi_set_last_error(env_ptr, napi_number_expected);
- };
-
- let value = number.value();
-
- unsafe {
- if value.is_finite() {
- *result = value as _;
- } else {
- *result = 0;
- }
- }
-
- return napi_clear_last_error(env_ptr);
-}
-
-#[napi_sym]
-fn napi_get_value_bigint_int64(
- env_ptr: *mut Env,
- value: napi_value,
- result: *mut i64,
- lossless: *mut bool,
-) -> napi_status {
- let env = check_env!(env_ptr);
- check_arg!(env, value);
- check_arg!(env, result);
- check_arg!(env, lossless);
-
- let Some(bigint) =
- value.and_then(|v| v8::Local::<v8::BigInt>::try_from(v).ok())
- else {
- return napi_set_last_error(env_ptr, napi_bigint_expected);
- };
-
- let (result_, lossless_) = bigint.i64_value();
-
- unsafe {
- *result = result_;
- *lossless = lossless_;
- }
-
- return napi_clear_last_error(env_ptr);
-}
-
-#[napi_sym]
-fn napi_get_value_bigint_uint64(
- env_ptr: *mut Env,
- value: napi_value,
- result: *mut u64,
- lossless: *mut bool,
-) -> napi_status {
- let env = check_env!(env_ptr);
- check_arg!(env, value);
- check_arg!(env, result);
- check_arg!(env, lossless);
-
- let Some(bigint) =
- value.and_then(|v| v8::Local::<v8::BigInt>::try_from(v).ok())
- else {
- return napi_set_last_error(env_ptr, napi_bigint_expected);
- };
-
- let (result_, lossless_) = bigint.u64_value();
-
- unsafe {
- *result = result_;
- *lossless = lossless_;
- }
-
- return napi_clear_last_error(env_ptr);
-}
-
-#[napi_sym]
-fn napi_get_value_bigint_words(
- env_ptr: *mut Env,
- value: napi_value,
- sign_bit: *mut i32,
- word_count: *mut usize,
- words: *mut u64,
-) -> napi_status {
- let env = check_env!(env_ptr);
- check_arg!(env, value);
- check_arg!(env, word_count);
-
- let Some(bigint) =
- value.and_then(|v| v8::Local::<v8::BigInt>::try_from(v).ok())
- else {
- return napi_set_last_error(env_ptr, napi_bigint_expected);
- };
-
- let word_count_int;
-
- if sign_bit.is_null() && words.is_null() {
- word_count_int = bigint.word_count();
- } else {
- check_arg!(env, sign_bit);
- check_arg!(env, words);
- let out_words =
- unsafe { std::slice::from_raw_parts_mut(words, *word_count) };
- let (sign, slice_) = bigint.to_words_array(out_words);
- word_count_int = slice_.len();
- unsafe {
- *sign_bit = sign as i32;
- }
- }
-
- unsafe {
- *word_count = word_count_int;
- }
-
- return napi_clear_last_error(env_ptr);
-}
-
-#[napi_sym]
-fn napi_get_value_bool(
- env_ptr: *mut Env,
- value: napi_value,
- result: *mut bool,
-) -> napi_status {
- let env = check_env!(env_ptr);
- check_arg!(env, value);
- check_arg!(env, result);
-
- let Some(boolean) =
- value.and_then(|v| v8::Local::<v8::Boolean>::try_from(v).ok())
- else {
- return napi_set_last_error(env_ptr, napi_boolean_expected);
- };
-
- unsafe {
- *result = boolean.is_true();
- }
-
- return napi_clear_last_error(env_ptr);
-}
-
-#[napi_sym]
-fn napi_get_value_string_latin1(
- env_ptr: *mut Env,
- value: napi_value,
- buf: *mut c_char,
- bufsize: usize,
- result: *mut usize,
-) -> napi_status {
- let env = check_env!(env_ptr);
- check_arg!(env, value);
-
- let Some(value) =
- value.and_then(|v| v8::Local::<v8::String>::try_from(v).ok())
- else {
- return napi_set_last_error(env_ptr, napi_string_expected);
- };
-
- if buf.is_null() {
- check_arg!(env, result);
- unsafe {
- *result = value.length();
- }
- } else if bufsize != 0 {
- let buffer =
- unsafe { std::slice::from_raw_parts_mut(buf as _, bufsize - 1) };
- let copied = value.write_one_byte(
- &mut env.scope(),
- buffer,
- 0,
- v8::WriteOptions::NO_NULL_TERMINATION,
- );
- unsafe {
- buf.add(copied).write(0);
- }
- if !result.is_null() {
- unsafe {
- *result = copied;
- }
- }
- } else if !result.is_null() {
- unsafe {
- *result = 0;
- }
- }
-
- napi_clear_last_error(env_ptr)
-}
-
-#[napi_sym]
-fn napi_get_value_string_utf8(
- env_ptr: *mut Env,
- value: napi_value,
- buf: *mut u8,
- bufsize: usize,
- result: *mut usize,
-) -> napi_status {
- let env = check_env!(env_ptr);
- check_arg!(env, value);
-
- let Some(value) =
- value.and_then(|v| v8::Local::<v8::String>::try_from(v).ok())
- else {
- return napi_set_last_error(env_ptr, napi_string_expected);
- };
-
- if buf.is_null() {
- check_arg!(env, result);
- unsafe {
- *result = value.utf8_length(env.isolate());
- }
- } else if bufsize != 0 {
- let buffer =
- unsafe { std::slice::from_raw_parts_mut(buf as _, bufsize - 1) };
- let copied = value.write_utf8(
- &mut env.scope(),
- buffer,
- None,
- v8::WriteOptions::REPLACE_INVALID_UTF8
- | v8::WriteOptions::NO_NULL_TERMINATION,
- );
- unsafe {
- buf.add(copied).write(0);
- }
- if !result.is_null() {
- unsafe {
- *result = copied;
- }
- }
- } else if !result.is_null() {
- unsafe {
- *result = 0;
- }
- }
-
- napi_clear_last_error(env_ptr)
-}
-
-#[napi_sym]
-fn napi_get_value_string_utf16(
- env_ptr: *mut Env,
- value: napi_value,
- buf: *mut u16,
- bufsize: usize,
- result: *mut usize,
-) -> napi_status {
- let env = check_env!(env_ptr);
- check_arg!(env, value);
-
- let Some(value) =
- value.and_then(|v| v8::Local::<v8::String>::try_from(v).ok())
- else {
- return napi_set_last_error(env_ptr, napi_string_expected);
- };
-
- if buf.is_null() {
- check_arg!(env, result);
- unsafe {
- *result = value.length();
- }
- } else if bufsize != 0 {
- let buffer =
- unsafe { std::slice::from_raw_parts_mut(buf as _, bufsize - 1) };
- let copied = value.write(
- &mut env.scope(),
- buffer,
- 0,
- v8::WriteOptions::NO_NULL_TERMINATION,
- );
- unsafe {
- buf.add(copied).write(0);
- }
- if !result.is_null() {
- unsafe {
- *result = copied;
- }
- }
- } else if !result.is_null() {
- unsafe {
- *result = 0;
- }
- }
-
- napi_clear_last_error(env_ptr)
-}
-
-#[napi_sym]
-fn napi_coerce_to_bool<'s>(
- env: &'s mut Env,
- value: napi_value,
- result: *mut napi_value<'s>,
-) -> napi_status {
- check_arg!(env, value);
- check_arg!(env, result);
-
- let coerced = value.unwrap().to_boolean(&mut env.scope());
-
- unsafe {
- *result = coerced.into();
- }
-
- napi_ok
-}
-
-#[napi_sym]
-fn napi_coerce_to_number<'s>(
- env: &'s mut Env,
- value: napi_value,
- result: *mut napi_value<'s>,
-) -> napi_status {
- check_arg!(env, value);
- check_arg!(env, result);
-
- let Some(coerced) = value.unwrap().to_number(&mut env.scope()) else {
- return napi_number_expected;
- };
-
- unsafe {
- *result = coerced.into();
- }
-
- napi_ok
-}
-
-#[napi_sym]
-fn napi_coerce_to_object<'s>(
- env: &'s mut Env,
- value: napi_value,
- result: *mut napi_value<'s>,
-) -> napi_status {
- check_arg!(env, value);
- check_arg!(env, result);
-
- let Some(coerced) = value.unwrap().to_object(&mut env.scope()) else {
- return napi_object_expected;
- };
-
- unsafe {
- *result = coerced.into();
- }
-
- napi_ok
-}
-
-#[napi_sym]
-fn napi_coerce_to_string<'s>(
- env: &'s mut Env,
- value: napi_value,
- result: *mut napi_value<'s>,
-) -> napi_status {
- check_arg!(env, value);
- check_arg!(env, result);
-
- let Some(coerced) = value.unwrap().to_string(&mut env.scope()) else {
- return napi_string_expected;
- };
-
- unsafe {
- *result = coerced.into();
- }
-
- napi_ok
-}
-
-#[napi_sym]
-fn napi_wrap(
- env: &mut Env,
- js_object: napi_value,
- native_object: *mut c_void,
- finalize_cb: Option<napi_finalize>,
- finalize_hint: *mut c_void,
- result: *mut napi_ref,
-) -> napi_status {
- check_arg!(env, js_object);
- let env_ptr = env as *mut Env;
-
- let Some(obj) =
- js_object.and_then(|v| v8::Local::<v8::Object>::try_from(v).ok())
- else {
- return napi_invalid_arg;
- };
-
- let napi_wrap = v8::Local::new(&mut env.scope(), &env.shared().napi_wrap);
-
- if obj
- .has_private(&mut env.scope(), napi_wrap)
- .unwrap_or(false)
- {
- return napi_invalid_arg;
- }
-
- if !result.is_null() {
- check_arg!(env, finalize_cb);
- }
-
- let ownership = if result.is_null() {
- ReferenceOwnership::Runtime
- } else {
- ReferenceOwnership::Userland
- };
- let reference = Reference::new(
- env_ptr,
- obj.into(),
- 0,
- ownership,
- finalize_cb,
- native_object,
- finalize_hint,
- );
-
- let reference = Reference::into_raw(reference) as *mut c_void;
-
- if !result.is_null() {
- check_arg!(env, finalize_cb);
- unsafe {
- *result = reference;
- }
- }
-
- let external = v8::External::new(&mut env.scope(), reference);
- assert!(obj
- .set_private(&mut env.scope(), napi_wrap, external.into())
- .unwrap());
-
- napi_ok
-}
-
-fn unwrap(
- env: &mut Env,
- obj: napi_value,
- result: *mut *mut c_void,
- keep: bool,
-) -> napi_status {
- check_arg!(env, obj);
- if keep {
- check_arg!(env, result);
- }
-
- let Some(obj) = obj.and_then(|v| v8::Local::<v8::Object>::try_from(v).ok())
- else {
- return napi_invalid_arg;
- };
-
- let napi_wrap = v8::Local::new(&mut env.scope(), &env.shared().napi_wrap);
- let Some(val) = obj.get_private(&mut env.scope(), napi_wrap) else {
- return napi_invalid_arg;
- };
-
- let Ok(external) = v8::Local::<v8::External>::try_from(val) else {
- return napi_invalid_arg;
- };
-
- let reference = external.value() as *mut Reference;
- let reference = unsafe { &mut *reference };
-
- if !result.is_null() {
- unsafe {
- *result = reference.finalize_data;
- }
- }
-
- if !keep {
- assert!(obj
- .delete_private(&mut env.scope(), napi_wrap)
- .unwrap_or(false));
- unsafe { Reference::remove(reference) };
- }
-
- napi_ok
-}
-
-#[napi_sym]
-fn napi_unwrap(
- env: &mut Env,
- obj: napi_value,
- result: *mut *mut c_void,
-) -> napi_status {
- unwrap(env, obj, result, true)
-}
-
-#[napi_sym]
-fn napi_remove_wrap(
- env: &mut Env,
- obj: napi_value,
- result: *mut *mut c_void,
-) -> napi_status {
- unwrap(env, obj, result, false)
-}
-
-struct ExternalWrapper {
- data: *mut c_void,
- type_tag: Option<napi_type_tag>,
-}
-
-#[napi_sym]
-fn napi_create_external<'s>(
- env: &'s mut Env,
- data: *mut c_void,
- finalize_cb: Option<napi_finalize>,
- finalize_hint: *mut c_void,
- result: *mut napi_value<'s>,
-) -> napi_status {
- let env_ptr = env as *mut Env;
- check_arg!(env, result);
-
- let wrapper = Box::new(ExternalWrapper {
- data,
- type_tag: None,
- });
-
- let wrapper = Box::into_raw(wrapper);
- let external = v8::External::new(&mut env.scope(), wrapper as _);
-
- if let Some(finalize_cb) = finalize_cb {
- Reference::into_raw(Reference::new(
- env_ptr,
- external.into(),
- 0,
- ReferenceOwnership::Runtime,
- Some(finalize_cb),
- data,
- finalize_hint,
- ));
- }
-
- unsafe {
- *result = external.into();
- }
-
- napi_ok
-}
-
-#[napi_sym]
-fn napi_type_tag_object(
- env: &mut Env,
- object_or_external: napi_value,
- type_tag: *const napi_type_tag,
-) -> napi_status {
- check_arg!(env, object_or_external);
- check_arg!(env, type_tag);
-
- let val = object_or_external.unwrap();
-
- if let Ok(external) = v8::Local::<v8::External>::try_from(val) {
- let wrapper_ptr = external.value() as *mut ExternalWrapper;
- let wrapper = unsafe { &mut *wrapper_ptr };
- if wrapper.type_tag.is_some() {
- return napi_invalid_arg;
- }
- wrapper.type_tag = Some(unsafe { *type_tag });
- return napi_ok;
- }
-
- let Some(object) = val.to_object(&mut env.scope()) else {
- return napi_object_expected;
- };
-
- let key = v8::Local::new(&mut env.scope(), &env.shared().type_tag);
-
- if object.has_private(&mut env.scope(), key).unwrap_or(false) {
- return napi_invalid_arg;
- }
-
- let slice = unsafe { std::slice::from_raw_parts(type_tag as *const u64, 2) };
- let Some(tag) = v8::BigInt::new_from_words(&mut env.scope(), false, slice)
- else {
- return napi_generic_failure;
- };
-
- if !object
- .set_private(&mut env.scope(), key, tag.into())
- .unwrap_or(false)
- {
- return napi_generic_failure;
- }
-
- napi_ok
-}
-
-#[napi_sym]
-fn napi_check_object_type_tag(
- env: &mut Env,
- object_or_external: napi_value,
- type_tag: *const napi_type_tag,
- result: *mut bool,
-) -> napi_status {
- check_arg!(env, object_or_external);
- check_arg!(env, type_tag);
- check_arg!(env, result);
-
- let type_tag = unsafe { *type_tag };
-
- let val = object_or_external.unwrap();
-
- if let Ok(external) = v8::Local::<v8::External>::try_from(val) {
- let wrapper_ptr = external.value() as *mut ExternalWrapper;
- let wrapper = unsafe { &mut *wrapper_ptr };
- unsafe {
- *result = match wrapper.type_tag {
- Some(t) => t == type_tag,
- None => false,
- };
- };
- return napi_ok;
- }
-
- let Some(object) = val.to_object(&mut env.scope()) else {
- return napi_object_expected;
- };
-
- let key = v8::Local::new(&mut env.scope(), &env.shared().type_tag);
-
- let Some(val) = object.get_private(&mut env.scope(), key) else {
- return napi_generic_failure;
- };
-
- unsafe {
- *result = false;
- }
-
- if let Ok(bigint) = v8::Local::<v8::BigInt>::try_from(val) {
- let mut words = [0u64; 2];
- let (sign, words) = bigint.to_words_array(&mut words);
- if !sign {
- let pass = if words.len() == 2 {
- type_tag.lower == words[0] && type_tag.upper == words[1]
- } else if words.len() == 1 {
- type_tag.lower == words[0] && type_tag.upper == 0
- } else if words.is_empty() {
- type_tag.lower == 0 && type_tag.upper == 0
- } else {
- false
- };
- unsafe {
- *result = pass;
- }
- }
- }
-
- napi_ok
-}
-
-#[napi_sym]
-fn napi_get_value_external(
- env: *mut Env,
- value: napi_value,
- result: *mut *mut c_void,
-) -> napi_status {
- let env = check_env!(env);
- check_arg!(env, value);
- check_arg!(env, result);
-
- let Some(external) =
- value.and_then(|v| v8::Local::<v8::External>::try_from(v).ok())
- else {
- return napi_set_last_error(env, napi_invalid_arg);
- };
-
- let wrapper_ptr = external.value() as *const ExternalWrapper;
- let wrapper = unsafe { &*wrapper_ptr };
-
- unsafe {
- *result = wrapper.data;
- }
-
- napi_clear_last_error(env)
-}
-
-#[napi_sym]
-fn napi_create_reference(
- env: *mut Env,
- value: napi_value,
- initial_refcount: u32,
- result: *mut napi_ref,
-) -> napi_status {
- let env = check_env!(env);
- check_arg!(env, value);
- check_arg!(env, result);
-
- let value = value.unwrap();
-
- let reference = Reference::new(
- env,
- value,
- initial_refcount,
- ReferenceOwnership::Userland,
- None,
- std::ptr::null_mut(),
- std::ptr::null_mut(),
- );
-
- let ptr = Reference::into_raw(reference);
-
- unsafe {
- *result = ptr as _;
- }
-
- napi_clear_last_error(env)
-}
-
-#[napi_sym]
-fn napi_delete_reference(env: *mut Env, ref_: napi_ref) -> napi_status {
- let env = check_env!(env);
- check_arg!(env, ref_);
-
- let reference = unsafe { Reference::from_raw(ref_ as _) };
-
- drop(reference);
-
- napi_clear_last_error(env)
-}
-
-#[napi_sym]
-fn napi_reference_ref(
- env: *mut Env,
- ref_: napi_ref,
- result: *mut u32,
-) -> napi_status {
- let env = check_env!(env);
- check_arg!(env, ref_);
-
- let reference = unsafe { &mut *(ref_ as *mut Reference) };
-
- let count = reference.ref_();
-
- if !result.is_null() {
- unsafe {
- *result = count;
- }
- }
-
- napi_clear_last_error(env)
-}
-
-#[napi_sym]
-fn napi_reference_unref(
- env: *mut Env,
- ref_: napi_ref,
- result: *mut u32,
-) -> napi_status {
- let env = check_env!(env);
- check_arg!(env, ref_);
-
- let reference = unsafe { &mut *(ref_ as *mut Reference) };
-
- if reference.ref_count == 0 {
- return napi_set_last_error(env, napi_generic_failure);
- }
-
- let count = reference.unref();
-
- if !result.is_null() {
- unsafe {
- *result = count;
- }
- }
-
- napi_clear_last_error(env)
-}
-
-#[napi_sym]
-fn napi_get_reference_value(
- env_ptr: *mut Env,
- ref_: napi_ref,
- result: *mut napi_value,
-) -> napi_status {
- let env = check_env!(env_ptr);
- check_arg!(env, ref_);
- check_arg!(env, result);
-
- let reference = unsafe { &mut *(ref_ as *mut Reference) };
-
- let value = match &reference.state {
- ReferenceState::Strong(g) => Some(v8::Local::new(&mut env.scope(), g)),
- ReferenceState::Weak(w) => w.to_local(&mut env.scope()),
- };
-
- unsafe {
- *result = value.into();
- }
-
- napi_clear_last_error(env_ptr)
-}
-
-#[napi_sym]
-fn napi_open_handle_scope(
- env: *mut Env,
- _result: *mut napi_handle_scope,
-) -> napi_status {
- let env = check_env!(env);
- napi_clear_last_error(env)
-}
-
-#[napi_sym]
-fn napi_close_handle_scope(
- env: *mut Env,
- _scope: napi_handle_scope,
-) -> napi_status {
- let env = check_env!(env);
- napi_clear_last_error(env)
-}
-
-#[napi_sym]
-fn napi_open_escapable_handle_scope(
- env: *mut Env,
- _result: *mut napi_escapable_handle_scope,
-) -> napi_status {
- let env = check_env!(env);
- napi_clear_last_error(env)
-}
-
-#[napi_sym]
-fn napi_close_escapable_handle_scope(
- env: *mut Env,
- _scope: napi_escapable_handle_scope,
-) -> napi_status {
- let env = check_env!(env);
- napi_clear_last_error(env)
-}
-
-#[napi_sym]
-fn napi_escape_handle<'s>(
- env: *mut Env,
- _scope: napi_escapable_handle_scope,
- escapee: napi_value<'s>,
- result: *mut napi_value<'s>,
-) -> napi_status {
- let env = check_env!(env);
-
- unsafe {
- *result = escapee;
- }
-
- napi_clear_last_error(env)
-}
-
-#[napi_sym]
-fn napi_new_instance<'s>(
- env: &'s mut Env,
- constructor: napi_value,
- argc: usize,
- argv: *const napi_value,
- result: *mut napi_value<'s>,
-) -> napi_status {
- check_arg!(env, constructor);
- if argc > 0 {
- check_arg!(env, argv);
- }
- check_arg!(env, result);
-
- let Some(func) =
- constructor.and_then(|v| v8::Local::<v8::Function>::try_from(v).ok())
- else {
- return napi_invalid_arg;
- };
-
- let args = if argc > 0 {
- unsafe {
- std::slice::from_raw_parts(argv as *mut v8::Local<v8::Value>, argc)
- }
- } else {
- &[]
- };
-
- let Some(value) = func.new_instance(&mut env.scope(), args) else {
- return napi_pending_exception;
- };
-
- unsafe {
- *result = value.into();
- }
-
- napi_ok
-}
-
-#[napi_sym]
-fn napi_instanceof(
- env: &mut Env,
- object: napi_value,
- constructor: napi_value,
- result: *mut bool,
-) -> napi_status {
- check_arg!(env, object);
- check_arg!(env, result);
-
- let Some(ctor) = constructor.and_then(|v| v.to_object(&mut env.scope()))
- else {
- return napi_object_expected;
- };
-
- if !ctor.is_function() {
- unsafe {
- napi_throw_type_error(
- env,
- c"ERR_NAPI_CONS_FUNCTION".as_ptr(),
- c"Constructor must be a function".as_ptr(),
- );
- }
- return napi_function_expected;
- }
-
- let Some(res) = object.unwrap().instance_of(&mut env.scope(), ctor) else {
- return napi_generic_failure;
- };
-
- unsafe {
- *result = res;
- }
-
- napi_ok
-}
-
-#[napi_sym]
-fn napi_is_exception_pending(
- env_ptr: *mut Env,
- result: *mut bool,
-) -> napi_status {
- let env = check_env!(env_ptr);
- check_arg!(env, result);
-
- unsafe {
- *result = env.last_exception.is_some();
- }
-
- napi_clear_last_error(env_ptr)
-}
-
-#[napi_sym]
-fn napi_get_and_clear_last_exception(
- env_ptr: *mut Env,
- result: *mut napi_value,
-) -> napi_status {
- let env = check_env!(env_ptr);
- check_arg!(env, result);
-
- let ex: v8::Local<v8::Value> =
- if let Some(last_exception) = env.last_exception.take() {
- v8::Local::new(&mut env.scope(), last_exception)
- } else {
- v8::undefined(&mut env.scope()).into()
- };
-
- unsafe {
- *result = ex.into();
- }
-
- napi_clear_last_error(env_ptr)
-}
-
-#[napi_sym]
-fn napi_is_arraybuffer(
- env: *mut Env,
- value: napi_value,
- result: *mut bool,
-) -> napi_status {
- let env = check_env!(env);
- check_arg!(env, value);
- check_arg!(env, result);
-
- unsafe {
- *result = value.unwrap().is_array_buffer();
- }
-
- napi_clear_last_error(env)
-}
-
-#[napi_sym]
-fn napi_create_arraybuffer<'s>(
- env: &'s mut Env,
- len: usize,
- data: *mut *mut c_void,
- result: *mut napi_value<'s>,
-) -> napi_status {
- check_arg!(env, result);
-
- let buffer = v8::ArrayBuffer::new(&mut env.scope(), len);
-
- if !data.is_null() {
- unsafe {
- *data = get_array_buffer_ptr(buffer);
- }
- }
-
- unsafe {
- *result = buffer.into();
- }
-
- napi_ok
-}
-
-#[napi_sym]
-fn napi_create_external_arraybuffer<'s>(
- env: &'s mut Env,
- data: *mut c_void,
- byte_length: usize,
- finalize_cb: napi_finalize,
- finalize_hint: *mut c_void,
- result: *mut napi_value<'s>,
-) -> napi_status {
- check_arg!(env, result);
-
- let store = make_external_backing_store(
- env,
- data,
- byte_length,
- std::ptr::null_mut(),
- finalize_cb,
- finalize_hint,
- );
-
- let ab =
- v8::ArrayBuffer::with_backing_store(&mut env.scope(), &store.make_shared());
- let value: v8::Local<v8::Value> = ab.into();
-
- unsafe {
- *result = value.into();
- }
-
- napi_ok
-}
-
-#[napi_sym]
-fn napi_get_arraybuffer_info(
- env: *mut Env,
- value: napi_value,
- data: *mut *mut c_void,
- length: *mut usize,
-) -> napi_status {
- let env = check_env!(env);
- check_arg!(env, value);
-
- let Some(buf) =
- value.and_then(|v| v8::Local::<v8::ArrayBuffer>::try_from(v).ok())
- else {
- return napi_set_last_error(env, napi_invalid_arg);
- };
-
- if !data.is_null() {
- unsafe {
- *data = get_array_buffer_ptr(buf);
- }
- }
-
- if !length.is_null() {
- unsafe {
- *length = buf.byte_length();
- }
- }
-
- napi_ok
-}
-
-#[napi_sym]
-fn napi_is_typedarray(
- env: *mut Env,
- value: napi_value,
- result: *mut bool,
-) -> napi_status {
- let env = check_env!(env);
- check_arg!(env, value);
- check_arg!(env, result);
-
- unsafe {
- *result = value.unwrap().is_typed_array();
- }
-
- napi_ok
-}
-
-#[napi_sym]
-fn napi_create_typedarray<'s>(
- env: &'s mut Env,
- ty: napi_typedarray_type,
- length: usize,
- arraybuffer: napi_value,
- byte_offset: usize,
- result: *mut napi_value<'s>,
-) -> napi_status {
- check_arg!(env, arraybuffer);
- check_arg!(env, result);
-
- let Some(ab) =
- arraybuffer.and_then(|v| v8::Local::<v8::ArrayBuffer>::try_from(v).ok())
- else {
- return napi_arraybuffer_expected;
- };
-
- macro_rules! create {
- ($TypedArray:ident, $size_of_element:expr) => {{
- let soe = $size_of_element;
- if soe > 1 && byte_offset % soe != 0 {
- let message = v8::String::new(
- &mut env.scope(),
- format!(
- "start offset of {} should be multiple of {}",
- stringify!($TypedArray),
- soe
- )
- .as_str(),
- )
- .unwrap();
- let exc = v8::Exception::range_error(&mut env.scope(), message);
- env.scope().throw_exception(exc);
- return napi_pending_exception;
- }
-
- if length * soe + byte_offset > ab.byte_length() {
- let message =
- v8::String::new(&mut env.scope(), "Invalid typed array length")
- .unwrap();
- let exc = v8::Exception::range_error(&mut env.scope(), message);
- env.scope().throw_exception(exc);
- return napi_pending_exception;
- }
-
- let Some(ta) =
- v8::$TypedArray::new(&mut env.scope(), ab, byte_offset, length)
- else {
- return napi_generic_failure;
- };
- ta.into()
- }};
- }
-
- let typedarray: v8::Local<v8::Value> = match ty {
- napi_uint8_array => create!(Uint8Array, 1),
- napi_uint8_clamped_array => create!(Uint8ClampedArray, 1),
- napi_int8_array => create!(Int8Array, 1),
- napi_uint16_array => create!(Uint16Array, 2),
- napi_int16_array => create!(Int16Array, 2),
- napi_uint32_array => create!(Uint32Array, 4),
- napi_int32_array => create!(Int32Array, 4),
- napi_float32_array => create!(Float32Array, 4),
- napi_float64_array => create!(Float64Array, 8),
- napi_bigint64_array => create!(BigInt64Array, 8),
- napi_biguint64_array => create!(BigUint64Array, 8),
- _ => {
- return napi_invalid_arg;
- }
- };
-
- unsafe {
- *result = typedarray.into();
- }
-
- napi_ok
-}
-
-#[napi_sym]
-fn napi_get_typedarray_info(
- env_ptr: *mut Env,
- typedarray: napi_value,
- type_: *mut napi_typedarray_type,
- length: *mut usize,
- data: *mut *mut c_void,
- arraybuffer: *mut napi_value,
- byte_offset: *mut usize,
-) -> napi_status {
- let env = check_env!(env_ptr);
- check_arg!(env, typedarray);
-
- let Some(array) =
- typedarray.and_then(|v| v8::Local::<v8::TypedArray>::try_from(v).ok())
- else {
- return napi_set_last_error(env_ptr, napi_invalid_arg);
- };
-
- if !type_.is_null() {
- let tatype = if array.is_int8_array() {
- napi_int8_array
- } else if array.is_uint8_array() {
- napi_uint8_array
- } else if array.is_uint8_clamped_array() {
- napi_uint8_clamped_array
- } else if array.is_int16_array() {
- napi_int16_array
- } else if array.is_uint16_array() {
- napi_uint16_array
- } else if array.is_int32_array() {
- napi_int32_array
- } else if array.is_uint32_array() {
- napi_uint32_array
- } else if array.is_float32_array() {
- napi_float32_array
- } else if array.is_float64_array() {
- napi_float64_array
- } else if array.is_big_int64_array() {
- napi_bigint64_array
- } else if array.is_big_uint64_array() {
- napi_biguint64_array
- } else {
- unreachable!();
- };
-
- unsafe {
- *type_ = tatype;
- }
- }
-
- if !length.is_null() {
- unsafe {
- *length = array.length();
- }
- }
-
- if !data.is_null() {
- unsafe {
- *data = array.data();
- }
- }
-
- if !arraybuffer.is_null() {
- let buf = array.buffer(&mut env.scope()).unwrap();
- unsafe {
- *arraybuffer = buf.into();
- }
- }
-
- if !byte_offset.is_null() {
- unsafe {
- *byte_offset = array.byte_offset();
- }
- }
-
- napi_clear_last_error(env_ptr)
-}
-
-#[napi_sym]
-fn napi_create_dataview<'s>(
- env: &'s mut Env,
- byte_length: usize,
- arraybuffer: napi_value<'s>,
- byte_offset: usize,
- result: *mut napi_value<'s>,
-) -> napi_status {
- check_arg!(env, arraybuffer);
- check_arg!(env, result);
-
- let Some(buffer) =
- arraybuffer.and_then(|v| v8::Local::<v8::ArrayBuffer>::try_from(v).ok())
- else {
- return napi_invalid_arg;
- };
-
- if byte_length + byte_offset > buffer.byte_length() {
- unsafe {
- return napi_throw_range_error(
- env,
- c"ERR_NAPI_INVALID_DATAVIEW_ARGS".as_ptr(),
- c"byte_offset + byte_length should be less than or equal to the size in bytes of the array passed in".as_ptr(),
- );
- }
- }
-
- let dataview =
- v8::DataView::new(&mut env.scope(), buffer, byte_offset, byte_length);
-
- unsafe {
- *result = dataview.into();
- }
-
- napi_ok
-}
-
-#[napi_sym]
-fn napi_is_dataview(
- env: *mut Env,
- value: napi_value,
- result: *mut bool,
-) -> napi_status {
- let env = check_env!(env);
- check_arg!(env, value);
- check_arg!(env, result);
-
- unsafe {
- *result = value.unwrap().is_data_view();
- }
-
- napi_clear_last_error(env)
-}
-
-#[napi_sym]
-fn napi_get_dataview_info(
- env_ptr: *mut Env,
- dataview: napi_value,
- byte_length: *mut usize,
- data: *mut *mut c_void,
- arraybuffer: *mut napi_value,
- byte_offset: *mut usize,
-) -> napi_status {
- let env = check_env!(env_ptr);
- check_arg!(env, dataview);
-
- let Some(array) =
- dataview.and_then(|v| v8::Local::<v8::DataView>::try_from(v).ok())
- else {
- return napi_invalid_arg;
- };
-
- if !byte_length.is_null() {
- unsafe {
- *byte_length = array.byte_length();
- }
- }
-
- if !arraybuffer.is_null() {
- let Some(buffer) = array.buffer(&mut env.scope()) else {
- return napi_generic_failure;
- };
-
- unsafe {
- *arraybuffer = buffer.into();
- }
- }
-
- if !data.is_null() {
- unsafe {
- *data = array.data();
- }
- }
-
- if !byte_offset.is_null() {
- unsafe {
- *byte_offset = array.byte_offset();
- }
- }
-
- napi_clear_last_error(env_ptr)
-}
-
-#[napi_sym]
-fn napi_get_version(env: *mut Env, result: *mut u32) -> napi_status {
- let env = check_env!(env);
- check_arg!(env, result);
-
- unsafe {
- *result = NAPI_VERSION;
- }
-
- napi_clear_last_error(env)
-}
-
-#[napi_sym]
-fn napi_create_promise<'s>(
- env: &'s mut Env,
- deferred: *mut napi_deferred,
- promise: *mut napi_value<'s>,
-) -> napi_status {
- check_arg!(env, deferred);
- check_arg!(env, promise);
-
- let resolver = v8::PromiseResolver::new(&mut env.scope()).unwrap();
-
- let global = v8::Global::new(&mut env.scope(), resolver);
- let global_ptr = global.into_raw().as_ptr() as napi_deferred;
-
- let p = resolver.get_promise(&mut env.scope());
-
- unsafe {
- *deferred = global_ptr;
- }
-
- unsafe {
- *promise = p.into();
- }
-
- napi_ok
-}
-
-#[napi_sym]
-fn napi_resolve_deferred(
- env: &mut Env,
- deferred: napi_deferred,
- result: napi_value,
-) -> napi_status {
- check_arg!(env, result);
- check_arg!(env, deferred);
-
- // Make sure microtasks don't run and call back into JS
- env
- .scope()
- .set_microtasks_policy(v8::MicrotasksPolicy::Explicit);
-
- let deferred_ptr =
- unsafe { NonNull::new_unchecked(deferred as *mut v8::PromiseResolver) };
- let global = unsafe { v8::Global::from_raw(env.isolate(), deferred_ptr) };
- let resolver = v8::Local::new(&mut env.scope(), global);
-
- let success = resolver
- .resolve(&mut env.scope(), result.unwrap())
- .unwrap_or(false);
-
- // Restore policy
- env
- .scope()
- .set_microtasks_policy(v8::MicrotasksPolicy::Auto);
-
- if success {
- napi_ok
- } else {
- napi_generic_failure
- }
-}
-
-#[napi_sym]
-fn napi_reject_deferred(
- env: &mut Env,
- deferred: napi_deferred,
- result: napi_value,
-) -> napi_status {
- check_arg!(env, result);
- check_arg!(env, deferred);
-
- let deferred_ptr =
- unsafe { NonNull::new_unchecked(deferred as *mut v8::PromiseResolver) };
- let global = unsafe { v8::Global::from_raw(env.isolate(), deferred_ptr) };
- let resolver = v8::Local::new(&mut env.scope(), global);
-
- if !resolver
- .reject(&mut env.scope(), result.unwrap())
- .unwrap_or(false)
- {
- return napi_generic_failure;
- }
-
- napi_ok
-}
-
-#[napi_sym]
-fn napi_is_promise(
- env: *mut Env,
- value: napi_value,
- is_promise: *mut bool,
-) -> napi_status {
- let env = check_env!(env);
- check_arg!(env, value);
- check_arg!(env, is_promise);
-
- unsafe {
- *is_promise = value.unwrap().is_promise();
- }
-
- napi_clear_last_error(env)
-}
-
-#[napi_sym]
-fn napi_create_date<'s>(
- env: &'s mut Env,
- time: f64,
- result: *mut napi_value<'s>,
-) -> napi_status {
- check_arg!(env, result);
-
- let Some(date) = v8::Date::new(&mut env.scope(), time) else {
- return napi_generic_failure;
- };
-
- unsafe {
- *result = date.into();
- }
-
- napi_ok
-}
-
-#[napi_sym]
-fn napi_is_date(
- env: *mut Env,
- value: napi_value,
- is_date: *mut bool,
-) -> napi_status {
- let env = check_env!(env);
- check_arg!(env, value);
- check_arg!(env, is_date);
-
- unsafe {
- *is_date = value.unwrap().is_date();
- }
-
- napi_clear_last_error(env)
-}
-
-#[napi_sym]
-fn napi_get_date_value(
- env: &mut Env,
- value: napi_value,
- result: *mut f64,
-) -> napi_status {
- check_arg!(env, result);
-
- let Some(date) = value.and_then(|v| v8::Local::<v8::Date>::try_from(v).ok())
- else {
- return napi_date_expected;
- };
-
- unsafe {
- *result = date.value_of();
- }
-
- napi_ok
-}
-
-#[napi_sym]
-fn napi_run_script<'s>(
- env: &'s mut Env,
- script: napi_value,
- result: *mut napi_value<'s>,
-) -> napi_status {
- check_arg!(env, script);
- check_arg!(env, result);
-
- let Some(script) =
- script.and_then(|v| v8::Local::<v8::String>::try_from(v).ok())
- else {
- return napi_string_expected;
- };
-
- let Some(script) = v8::Script::compile(&mut env.scope(), script, None) else {
- return napi_generic_failure;
- };
-
- let Some(rv) = script.run(&mut env.scope()) else {
- return napi_generic_failure;
- };
-
- unsafe {
- *result = rv.into();
- }
-
- napi_ok
-}
-
-#[napi_sym]
-fn napi_add_finalizer(
- env_ptr: *mut Env,
- value: napi_value,
- finalize_data: *mut c_void,
- finalize_cb: Option<napi_finalize>,
- finalize_hint: *mut c_void,
- result: *mut napi_ref,
-) -> napi_status {
- let env = check_env!(env_ptr);
- check_arg!(env, value);
- check_arg!(env, finalize_cb);
-
- let Some(value) =
- value.and_then(|v| v8::Local::<v8::Object>::try_from(v).ok())
- else {
- return napi_set_last_error(env, napi_invalid_arg);
- };
-
- let ownership = if result.is_null() {
- ReferenceOwnership::Runtime
- } else {
- ReferenceOwnership::Userland
- };
- let reference = Reference::new(
- env,
- value.into(),
- 0,
- ownership,
- finalize_cb,
- finalize_data,
- finalize_hint,
- );
-
- if !result.is_null() {
- unsafe {
- *result = Reference::into_raw(reference) as _;
- }
- }
-
- napi_clear_last_error(env_ptr)
-}
-
-#[napi_sym]
-fn node_api_post_finalizer(
- env: *mut Env,
- _finalize_cb: napi_finalize,
- _finalize_data: *mut c_void,
- _finalize_hint: *mut c_void,
-) -> napi_status {
- napi_clear_last_error(env)
-}
-
-#[napi_sym]
-fn napi_adjust_external_memory(
- env: *mut Env,
- change_in_bytes: i64,
- adjusted_value: *mut i64,
-) -> napi_status {
- let env = check_env!(env);
- check_arg!(env, adjusted_value);
-
- unsafe {
- *adjusted_value = env
- .isolate()
- .adjust_amount_of_external_allocated_memory(change_in_bytes);
- }
-
- napi_clear_last_error(env)
-}
-
-#[napi_sym]
-fn napi_set_instance_data(
- env: *mut Env,
- data: *mut c_void,
- finalize_cb: Option<napi_finalize>,
- finalize_hint: *mut c_void,
-) -> napi_status {
- let env = check_env!(env);
-
- env.shared_mut().instance_data = Some(InstanceData {
- data,
- finalize_cb,
- finalize_hint,
- });
-
- napi_clear_last_error(env)
-}
-
-#[napi_sym]
-fn napi_get_instance_data(
- env: *mut Env,
- data: *mut *mut c_void,
-) -> napi_status {
- let env = check_env!(env);
- check_arg!(env, data);
-
- let instance_data = match &env.shared().instance_data {
- Some(v) => v.data,
- None => std::ptr::null_mut(),
- };
-
- unsafe { *data = instance_data };
-
- napi_clear_last_error(env)
-}
-
-#[napi_sym]
-fn napi_detach_arraybuffer(env: *mut Env, value: napi_value) -> napi_status {
- let env = check_env!(env);
- check_arg!(env, value);
-
- let Some(ab) =
- value.and_then(|v| v8::Local::<v8::ArrayBuffer>::try_from(v).ok())
- else {
- return napi_set_last_error(env, napi_arraybuffer_expected);
- };
-
- if !ab.is_detachable() {
- return napi_set_last_error(env, napi_detachable_arraybuffer_expected);
- }
-
- // Expected to crash for None.
- ab.detach(None).unwrap();
-
- napi_clear_last_error(env);
- napi_ok
-}
-
-#[napi_sym]
-fn napi_is_detached_arraybuffer(
- env_ptr: *mut Env,
- arraybuffer: napi_value,
- result: *mut bool,
-) -> napi_status {
- let env = check_env!(env_ptr);
- check_arg!(env, arraybuffer);
- check_arg!(env, result);
-
- let is_detached = match arraybuffer
- .and_then(|v| v8::Local::<v8::ArrayBuffer>::try_from(v).ok())
- {
- Some(ab) => ab.was_detached(),
- None => false,
- };
-
- unsafe {
- *result = is_detached;
- }
-
- napi_clear_last_error(env)
-}
diff --git a/cli/napi/mod.rs b/cli/napi/mod.rs
deleted file mode 100644
index 811efb1ec..000000000
--- a/cli/napi/mod.rs
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-
-#![allow(unused_mut)]
-#![allow(non_camel_case_types)]
-#![allow(clippy::undocumented_unsafe_blocks)]
-
-//! Symbols to be exported are now defined in this JSON file.
-//! The `#[napi_sym]` macro checks for missing entries and panics.
-//!
-//! `./tools/napi/generate_symbols_list.js` is used to generate the LINK `cli/exports.def` on Windows,
-//! which is also checked into git.
-//!
-//! To add a new napi function:
-//! 1. Place `#[napi_sym]` on top of your implementation.
-//! 2. Add the function's identifier to this JSON list.
-//! 3. Finally, run `tools/napi/generate_symbols_list.js` to update `cli/napi/generated_symbol_exports_list_*.def`.
-
-pub mod js_native_api;
-pub mod node_api;
-pub mod util;
-pub mod uv;
diff --git a/cli/napi/node_api.rs b/cli/napi/node_api.rs
deleted file mode 100644
index 2efb71c26..000000000
--- a/cli/napi/node_api.rs
+++ /dev/null
@@ -1,1004 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-
-#![deny(unsafe_op_in_unsafe_fn)]
-
-use super::util::get_array_buffer_ptr;
-use super::util::make_external_backing_store;
-use super::util::napi_clear_last_error;
-use super::util::napi_set_last_error;
-use super::util::SendPtr;
-use crate::check_arg;
-use crate::check_env;
-use deno_core::parking_lot::Condvar;
-use deno_core::parking_lot::Mutex;
-use deno_core::V8CrossThreadTaskSpawner;
-use deno_runtime::deno_napi::*;
-use napi_sym::napi_sym;
-use std::sync::atomic::AtomicBool;
-use std::sync::atomic::AtomicU8;
-use std::sync::atomic::AtomicUsize;
-use std::sync::atomic::Ordering;
-use std::sync::Arc;
-
-#[napi_sym]
-fn napi_module_register(module: *const NapiModule) -> napi_status {
- MODULE_TO_REGISTER.with(|cell| {
- let mut slot = cell.borrow_mut();
- let prev = slot.replace(module);
- assert!(prev.is_none());
- });
- napi_ok
-}
-
-#[napi_sym]
-fn napi_add_env_cleanup_hook(
- env: *mut Env,
- fun: Option<napi_cleanup_hook>,
- arg: *mut c_void,
-) -> napi_status {
- let env = check_env!(env);
- check_arg!(env, fun);
-
- let fun = fun.unwrap();
-
- env.add_cleanup_hook(fun, arg);
-
- napi_ok
-}
-
-#[napi_sym]
-fn napi_remove_env_cleanup_hook(
- env: *mut Env,
- fun: Option<napi_cleanup_hook>,
- arg: *mut c_void,
-) -> napi_status {
- let env = check_env!(env);
- check_arg!(env, fun);
-
- let fun = fun.unwrap();
-
- env.remove_cleanup_hook(fun, arg);
-
- napi_ok
-}
-
-struct AsyncCleanupHandle {
- env: *mut Env,
- hook: napi_async_cleanup_hook,
- data: *mut c_void,
-}
-
-unsafe extern "C" fn async_cleanup_handler(arg: *mut c_void) {
- unsafe {
- let handle = Box::<AsyncCleanupHandle>::from_raw(arg as _);
- (handle.hook)(arg, handle.data);
- }
-}
-
-#[napi_sym]
-fn napi_add_async_cleanup_hook(
- env: *mut Env,
- hook: Option<napi_async_cleanup_hook>,
- arg: *mut c_void,
- remove_handle: *mut napi_async_cleanup_hook_handle,
-) -> napi_status {
- let env = check_env!(env);
- check_arg!(env, hook);
-
- let hook = hook.unwrap();
-
- let handle = Box::into_raw(Box::new(AsyncCleanupHandle {
- env,
- hook,
- data: arg,
- })) as *mut c_void;
-
- env.add_cleanup_hook(async_cleanup_handler, handle);
-
- if !remove_handle.is_null() {
- unsafe {
- *remove_handle = handle;
- }
- }
-
- napi_clear_last_error(env)
-}
-
-#[napi_sym]
-fn napi_remove_async_cleanup_hook(
- remove_handle: napi_async_cleanup_hook_handle,
-) -> napi_status {
- if remove_handle.is_null() {
- return napi_invalid_arg;
- }
-
- let handle =
- unsafe { Box::<AsyncCleanupHandle>::from_raw(remove_handle as _) };
-
- let env = unsafe { &mut *handle.env };
-
- env.remove_cleanup_hook(async_cleanup_handler, remove_handle);
-
- napi_ok
-}
-
-#[napi_sym]
-fn napi_fatal_exception(env: &mut Env, err: napi_value) -> napi_status {
- check_arg!(env, err);
-
- let report_error = v8::Local::new(&mut env.scope(), &env.report_error);
-
- let this = v8::undefined(&mut env.scope());
- if report_error
- .call(&mut env.scope(), this.into(), &[err.unwrap()])
- .is_none()
- {
- return napi_generic_failure;
- }
-
- napi_ok
-}
-
-#[napi_sym]
-#[allow(clippy::print_stderr)]
-fn napi_fatal_error(
- location: *const c_char,
- location_len: usize,
- message: *const c_char,
- message_len: usize,
-) -> napi_status {
- let location = if location.is_null() {
- None
- } else {
- unsafe {
- Some(if location_len == NAPI_AUTO_LENGTH {
- std::ffi::CStr::from_ptr(location).to_str().unwrap()
- } else {
- let slice = std::slice::from_raw_parts(
- location as *const u8,
- location_len as usize,
- );
- std::str::from_utf8(slice).unwrap()
- })
- }
- };
-
- let message = if message_len == NAPI_AUTO_LENGTH {
- unsafe { std::ffi::CStr::from_ptr(message).to_str().unwrap() }
- } else {
- let slice = unsafe {
- std::slice::from_raw_parts(message as *const u8, message_len as usize)
- };
- std::str::from_utf8(slice).unwrap()
- };
-
- if let Some(location) = location {
- eprintln!("NODE API FATAL ERROR: {} {}", location, message);
- } else {
- eprintln!("NODE API FATAL ERROR: {}", message);
- }
-
- std::process::abort();
-}
-
-#[napi_sym]
-fn napi_open_callback_scope(
- env: *mut Env,
- _resource_object: napi_value,
- _context: napi_value,
- result: *mut napi_callback_scope,
-) -> napi_status {
- let env = check_env!(env);
- check_arg!(env, result);
-
- // we open scope automatically when it's needed
- unsafe {
- *result = std::ptr::null_mut();
- }
-
- napi_clear_last_error(env)
-}
-
-#[napi_sym]
-fn napi_close_callback_scope(
- env: *mut Env,
- scope: napi_callback_scope,
-) -> napi_status {
- let env = check_env!(env);
- // we close scope automatically when it's needed
- assert!(scope.is_null());
- napi_clear_last_error(env)
-}
-
-// NOTE: we don't support "async_hooks::AsyncContext" so these APIs are noops.
-#[napi_sym]
-fn napi_async_init(
- env: *mut Env,
- _async_resource: napi_value,
- _async_resource_name: napi_value,
- result: *mut napi_async_context,
-) -> napi_status {
- let env = check_env!(env);
- unsafe {
- *result = ptr::null_mut();
- }
- napi_clear_last_error(env)
-}
-
-#[napi_sym]
-fn napi_async_destroy(
- env: *mut Env,
- async_context: napi_async_context,
-) -> napi_status {
- let env = check_env!(env);
- assert!(async_context.is_null());
- napi_clear_last_error(env)
-}
-
-#[napi_sym]
-fn napi_make_callback<'s>(
- env: &'s mut Env,
- _async_context: napi_async_context,
- recv: napi_value,
- func: napi_value,
- argc: usize,
- argv: *const napi_value<'s>,
- result: *mut napi_value<'s>,
-) -> napi_status {
- check_arg!(env, recv);
- if argc > 0 {
- check_arg!(env, argv);
- }
-
- let Some(recv) = recv.and_then(|v| v.to_object(&mut env.scope())) else {
- return napi_object_expected;
- };
-
- let Some(func) =
- func.and_then(|v| v8::Local::<v8::Function>::try_from(v).ok())
- else {
- return napi_function_expected;
- };
-
- let args = if argc > 0 {
- unsafe {
- std::slice::from_raw_parts(argv as *mut v8::Local<v8::Value>, argc)
- }
- } else {
- &[]
- };
-
- // TODO: async_context
-
- let Some(v) = func.call(&mut env.scope(), recv.into(), args) else {
- return napi_generic_failure;
- };
-
- unsafe {
- *result = v.into();
- }
-
- napi_ok
-}
-
-#[napi_sym]
-fn napi_create_buffer<'s>(
- env: &'s mut Env,
- length: usize,
- data: *mut *mut c_void,
- result: *mut napi_value<'s>,
-) -> napi_status {
- check_arg!(env, result);
-
- let ab = v8::ArrayBuffer::new(&mut env.scope(), length);
-
- let buffer_constructor =
- v8::Local::new(&mut env.scope(), &env.buffer_constructor);
- let Some(buffer) =
- buffer_constructor.new_instance(&mut env.scope(), &[ab.into()])
- else {
- return napi_generic_failure;
- };
-
- if !data.is_null() {
- unsafe {
- *data = get_array_buffer_ptr(ab);
- }
- }
-
- unsafe {
- *result = buffer.into();
- }
-
- napi_ok
-}
-
-#[napi_sym]
-fn napi_create_external_buffer<'s>(
- env: &'s mut Env,
- length: usize,
- data: *mut c_void,
- finalize_cb: napi_finalize,
- finalize_hint: *mut c_void,
- result: *mut napi_value<'s>,
-) -> napi_status {
- check_arg!(env, result);
-
- let store = make_external_backing_store(
- env,
- data,
- length,
- ptr::null_mut(),
- finalize_cb,
- finalize_hint,
- );
-
- let ab =
- v8::ArrayBuffer::with_backing_store(&mut env.scope(), &store.make_shared());
-
- let buffer_constructor =
- v8::Local::new(&mut env.scope(), &env.buffer_constructor);
- let Some(buffer) =
- buffer_constructor.new_instance(&mut env.scope(), &[ab.into()])
- else {
- return napi_generic_failure;
- };
-
- unsafe {
- *result = buffer.into();
- }
-
- napi_ok
-}
-
-#[napi_sym]
-fn napi_create_buffer_copy<'s>(
- env: &'s mut Env,
- length: usize,
- data: *mut c_void,
- result_data: *mut *mut c_void,
- result: *mut napi_value<'s>,
-) -> napi_status {
- check_arg!(env, result);
-
- let ab = v8::ArrayBuffer::new(&mut env.scope(), length);
-
- let buffer_constructor =
- v8::Local::new(&mut env.scope(), &env.buffer_constructor);
- let Some(buffer) =
- buffer_constructor.new_instance(&mut env.scope(), &[ab.into()])
- else {
- return napi_generic_failure;
- };
-
- let ptr = get_array_buffer_ptr(ab);
- unsafe {
- std::ptr::copy(data, ptr, length);
- }
-
- if !result_data.is_null() {
- unsafe {
- *result_data = ptr;
- }
- }
-
- unsafe {
- *result = buffer.into();
- }
-
- napi_ok
-}
-
-#[napi_sym]
-fn napi_is_buffer(
- env: *mut Env,
- value: napi_value,
- result: *mut bool,
-) -> napi_status {
- let env = check_env!(env);
- check_arg!(env, value);
- check_arg!(env, result);
-
- let buffer_constructor =
- v8::Local::new(&mut env.scope(), &env.buffer_constructor);
-
- let Some(is_buffer) = value
- .unwrap()
- .instance_of(&mut env.scope(), buffer_constructor.into())
- else {
- return napi_set_last_error(env, napi_generic_failure);
- };
-
- unsafe {
- *result = is_buffer;
- }
-
- napi_clear_last_error(env)
-}
-
-#[napi_sym]
-fn napi_get_buffer_info(
- env: *mut Env,
- value: napi_value,
- data: *mut *mut c_void,
- length: *mut usize,
-) -> napi_status {
- let env = check_env!(env);
- check_arg!(env, value);
-
- // NB: Any TypedArray instance seems to be accepted by this function
- // in Node.js.
- let Some(ta) =
- value.and_then(|v| v8::Local::<v8::TypedArray>::try_from(v).ok())
- else {
- return napi_set_last_error(env, napi_invalid_arg);
- };
-
- if !data.is_null() {
- unsafe {
- *data = ta.data();
- }
- }
-
- if !length.is_null() {
- unsafe {
- *length = ta.byte_length();
- }
- }
-
- napi_clear_last_error(env)
-}
-
-#[napi_sym]
-fn napi_get_node_version(
- env: *mut Env,
- result: *mut *const napi_node_version,
-) -> napi_status {
- let env = check_env!(env);
- check_arg!(env, result);
-
- const NODE_VERSION: napi_node_version = napi_node_version {
- major: 20,
- minor: 11,
- patch: 1,
- release: c"Deno".as_ptr(),
- };
-
- unsafe {
- *result = &NODE_VERSION as *const napi_node_version;
- }
-
- napi_clear_last_error(env)
-}
-
-struct AsyncWork {
- state: AtomicU8,
- env: *mut Env,
- _async_resource: v8::Global<v8::Object>,
- _async_resource_name: String,
- execute: napi_async_execute_callback,
- complete: Option<napi_async_complete_callback>,
- data: *mut c_void,
-}
-
-impl AsyncWork {
- const IDLE: u8 = 0;
- const QUEUED: u8 = 1;
- const RUNNING: u8 = 2;
-}
-
-#[napi_sym]
-fn napi_create_async_work(
- env: *mut Env,
- async_resource: napi_value,
- async_resource_name: napi_value,
- execute: Option<napi_async_execute_callback>,
- complete: Option<napi_async_complete_callback>,
- data: *mut c_void,
- result: *mut napi_async_work,
-) -> napi_status {
- let env_ptr = env;
- let env = check_env!(env);
- check_arg!(env, execute);
- check_arg!(env, result);
-
- let resource = if let Some(v) = *async_resource {
- let Some(resource) = v.to_object(&mut env.scope()) else {
- return napi_set_last_error(env, napi_object_expected);
- };
- resource
- } else {
- v8::Object::new(&mut env.scope())
- };
-
- let Some(resource_name) =
- async_resource_name.and_then(|v| v.to_string(&mut env.scope()))
- else {
- return napi_set_last_error(env, napi_string_expected);
- };
-
- let resource_name = resource_name.to_rust_string_lossy(&mut env.scope());
-
- let work = Box::new(AsyncWork {
- state: AtomicU8::new(AsyncWork::IDLE),
- env: env_ptr,
- _async_resource: v8::Global::new(&mut env.scope(), resource),
- _async_resource_name: resource_name,
- execute: execute.unwrap(),
- complete,
- data,
- });
-
- unsafe {
- *result = Box::into_raw(work) as _;
- }
-
- napi_clear_last_error(env)
-}
-
-#[napi_sym]
-fn napi_delete_async_work(env: *mut Env, work: napi_async_work) -> napi_status {
- let env = check_env!(env);
- check_arg!(env, work);
-
- drop(unsafe { Box::<AsyncWork>::from_raw(work as _) });
-
- napi_clear_last_error(env)
-}
-
-#[napi_sym]
-fn napi_get_uv_event_loop(
- env_ptr: *mut Env,
- uv_loop: *mut *mut (),
-) -> napi_status {
- let env = check_env!(env_ptr);
- check_arg!(env, uv_loop);
- unsafe {
- *uv_loop = env_ptr.cast();
- }
- 0
-}
-
-#[napi_sym]
-fn napi_queue_async_work(env: *mut Env, work: napi_async_work) -> napi_status {
- let env = check_env!(env);
- check_arg!(env, work);
-
- let work = unsafe { &*(work as *mut AsyncWork) };
-
- let result =
- work
- .state
- .fetch_update(Ordering::SeqCst, Ordering::SeqCst, |state| {
- // allow queue if idle or if running, but not if already queued.
- if state == AsyncWork::IDLE || state == AsyncWork::RUNNING {
- Some(AsyncWork::QUEUED)
- } else {
- None
- }
- });
-
- if result.is_err() {
- return napi_clear_last_error(env);
- }
-
- let work = SendPtr(work);
-
- env.add_async_work(move || {
- let work = work.take();
- let work = unsafe { &*work };
-
- let state = work.state.compare_exchange(
- AsyncWork::QUEUED,
- AsyncWork::RUNNING,
- Ordering::SeqCst,
- Ordering::SeqCst,
- );
-
- if state.is_ok() {
- unsafe {
- (work.execute)(work.env as _, work.data);
- }
-
- // reset back to idle if its still marked as running
- let _ = work.state.compare_exchange(
- AsyncWork::RUNNING,
- AsyncWork::IDLE,
- Ordering::SeqCst,
- Ordering::Relaxed,
- );
- }
-
- if let Some(complete) = work.complete {
- let status = if state.is_ok() {
- napi_ok
- } else if state == Err(AsyncWork::IDLE) {
- napi_cancelled
- } else {
- napi_generic_failure
- };
-
- unsafe {
- complete(work.env as _, status, work.data);
- }
- }
-
- // `complete` probably deletes this `work`, so don't use it here.
- });
-
- napi_clear_last_error(env)
-}
-
-#[napi_sym]
-fn napi_cancel_async_work(env: *mut Env, work: napi_async_work) -> napi_status {
- let env = check_env!(env);
- check_arg!(env, work);
-
- let work = unsafe { &*(work as *mut AsyncWork) };
-
- let _ = work.state.compare_exchange(
- AsyncWork::QUEUED,
- AsyncWork::IDLE,
- Ordering::SeqCst,
- Ordering::Relaxed,
- );
-
- napi_clear_last_error(env)
-}
-
-extern "C" fn default_call_js_cb(
- env: napi_env,
- js_callback: napi_value,
- _context: *mut c_void,
- _data: *mut c_void,
-) {
- if let Some(js_callback) = *js_callback {
- if let Ok(js_callback) = v8::Local::<v8::Function>::try_from(js_callback) {
- let env = unsafe { &mut *(env as *mut Env) };
- let scope = &mut env.scope();
- let recv = v8::undefined(scope);
- js_callback.call(scope, recv.into(), &[]);
- }
- }
-}
-
-struct TsFn {
- env: *mut Env,
- func: Option<v8::Global<v8::Function>>,
- max_queue_size: usize,
- queue_size: Mutex<usize>,
- queue_cond: Condvar,
- thread_count: AtomicUsize,
- thread_finalize_data: *mut c_void,
- thread_finalize_cb: Option<napi_finalize>,
- context: *mut c_void,
- call_js_cb: napi_threadsafe_function_call_js,
- _resource: v8::Global<v8::Object>,
- _resource_name: String,
- is_closing: AtomicBool,
- is_closed: Arc<AtomicBool>,
- sender: V8CrossThreadTaskSpawner,
- is_ref: AtomicBool,
-}
-
-impl Drop for TsFn {
- fn drop(&mut self) {
- assert!(self
- .is_closed
- .compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed)
- .is_ok());
-
- self.unref();
-
- if let Some(finalizer) = self.thread_finalize_cb {
- unsafe {
- (finalizer)(self.env as _, self.thread_finalize_data, ptr::null_mut());
- }
- }
- }
-}
-
-impl TsFn {
- pub fn acquire(&self) -> napi_status {
- if self.is_closing.load(Ordering::SeqCst) {
- return napi_closing;
- }
- self.thread_count.fetch_add(1, Ordering::Relaxed);
- napi_ok
- }
-
- pub fn release(
- tsfn: *mut TsFn,
- mode: napi_threadsafe_function_release_mode,
- ) -> napi_status {
- let tsfn = unsafe { &mut *tsfn };
-
- let result = tsfn.thread_count.fetch_update(
- Ordering::Relaxed,
- Ordering::Relaxed,
- |x| {
- if x == 0 {
- None
- } else {
- Some(x - 1)
- }
- },
- );
-
- if result.is_err() {
- return napi_invalid_arg;
- }
-
- if (result == Ok(1) || mode == napi_tsfn_abort)
- && tsfn
- .is_closing
- .compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst)
- .is_ok()
- {
- tsfn.queue_cond.notify_all();
- let tsfnptr = SendPtr(tsfn);
- // drop must be queued in order to preserve ordering consistent
- // with Node.js and so that the finalizer runs on the main thread.
- tsfn.sender.spawn(move |_| {
- let tsfn = unsafe { Box::from_raw(tsfnptr.take() as *mut TsFn) };
- drop(tsfn);
- });
- }
-
- napi_ok
- }
-
- pub fn ref_(&self) -> napi_status {
- if self
- .is_ref
- .compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst)
- .is_ok()
- {
- let env = unsafe { &mut *self.env };
- env.threadsafe_function_ref();
- }
- napi_ok
- }
-
- pub fn unref(&self) -> napi_status {
- if self
- .is_ref
- .compare_exchange(true, false, Ordering::SeqCst, Ordering::SeqCst)
- .is_ok()
- {
- let env = unsafe { &mut *self.env };
- env.threadsafe_function_unref();
- }
-
- napi_ok
- }
-
- pub fn call(
- &self,
- data: *mut c_void,
- mode: napi_threadsafe_function_call_mode,
- ) -> napi_status {
- if self.is_closing.load(Ordering::SeqCst) {
- return napi_closing;
- }
-
- if self.max_queue_size > 0 {
- let mut queue_size = self.queue_size.lock();
- while *queue_size >= self.max_queue_size {
- if mode == napi_tsfn_blocking {
- self.queue_cond.wait(&mut queue_size);
-
- if self.is_closing.load(Ordering::SeqCst) {
- return napi_closing;
- }
- } else {
- return napi_queue_full;
- }
- }
- *queue_size += 1;
- }
-
- let is_closed = self.is_closed.clone();
- let tsfn = SendPtr(self);
- let data = SendPtr(data);
- let context = SendPtr(self.context);
- let call_js_cb = self.call_js_cb;
-
- self.sender.spawn(move |scope: &mut v8::HandleScope| {
- let data = data.take();
-
- // if is_closed then tsfn is freed, don't read from it.
- if is_closed.load(Ordering::Relaxed) {
- unsafe {
- call_js_cb(
- std::ptr::null_mut(),
- None::<v8::Local<v8::Value>>.into(),
- context.take() as _,
- data as _,
- );
- }
- } else {
- let tsfn = tsfn.take();
-
- let tsfn = unsafe { &*tsfn };
-
- if tsfn.max_queue_size > 0 {
- let mut queue_size = tsfn.queue_size.lock();
- let size = *queue_size;
- *queue_size -= 1;
- if size == tsfn.max_queue_size {
- tsfn.queue_cond.notify_one();
- }
- }
-
- let func = tsfn.func.as_ref().map(|f| v8::Local::new(scope, f));
-
- unsafe {
- (tsfn.call_js_cb)(
- tsfn.env as _,
- func.into(),
- tsfn.context,
- data as _,
- );
- }
- }
- });
-
- napi_ok
- }
-}
-
-#[napi_sym]
-#[allow(clippy::too_many_arguments)]
-fn napi_create_threadsafe_function(
- env: *mut Env,
- func: napi_value,
- async_resource: napi_value,
- async_resource_name: napi_value,
- max_queue_size: usize,
- initial_thread_count: usize,
- thread_finalize_data: *mut c_void,
- thread_finalize_cb: Option<napi_finalize>,
- context: *mut c_void,
- call_js_cb: Option<napi_threadsafe_function_call_js>,
- result: *mut napi_threadsafe_function,
-) -> napi_status {
- let env = check_env!(env);
- check_arg!(env, async_resource_name);
- if initial_thread_count == 0 {
- return napi_set_last_error(env, napi_invalid_arg);
- }
- check_arg!(env, result);
-
- let func = if let Some(value) = *func {
- let Ok(func) = v8::Local::<v8::Function>::try_from(value) else {
- return napi_set_last_error(env, napi_function_expected);
- };
- Some(v8::Global::new(&mut env.scope(), func))
- } else {
- check_arg!(env, call_js_cb);
- None
- };
-
- let resource = if let Some(v) = *async_resource {
- let Some(resource) = v.to_object(&mut env.scope()) else {
- return napi_set_last_error(env, napi_object_expected);
- };
- resource
- } else {
- v8::Object::new(&mut env.scope())
- };
- let resource = v8::Global::new(&mut env.scope(), resource);
-
- let Some(resource_name) =
- async_resource_name.and_then(|v| v.to_string(&mut env.scope()))
- else {
- return napi_set_last_error(env, napi_string_expected);
- };
- let resource_name = resource_name.to_rust_string_lossy(&mut env.scope());
-
- let mut tsfn = Box::new(TsFn {
- env,
- func,
- max_queue_size,
- queue_size: Mutex::new(0),
- queue_cond: Condvar::new(),
- thread_count: AtomicUsize::new(initial_thread_count),
- thread_finalize_data,
- thread_finalize_cb,
- context,
- call_js_cb: call_js_cb.unwrap_or(default_call_js_cb),
- _resource: resource,
- _resource_name: resource_name,
- is_closing: AtomicBool::new(false),
- is_closed: Arc::new(AtomicBool::new(false)),
- is_ref: AtomicBool::new(false),
- sender: env.async_work_sender.clone(),
- });
-
- tsfn.ref_();
-
- unsafe {
- *result = Box::into_raw(tsfn) as _;
- }
-
- napi_clear_last_error(env)
-}
-
-/// Maybe called from any thread.
-#[napi_sym]
-fn napi_get_threadsafe_function_context(
- func: napi_threadsafe_function,
- result: *mut *const c_void,
-) -> napi_status {
- assert!(!func.is_null());
- let tsfn = unsafe { &*(func as *const TsFn) };
- unsafe {
- *result = tsfn.context;
- }
- napi_ok
-}
-
-#[napi_sym]
-fn napi_call_threadsafe_function(
- func: napi_threadsafe_function,
- data: *mut c_void,
- is_blocking: napi_threadsafe_function_call_mode,
-) -> napi_status {
- assert!(!func.is_null());
- let tsfn = unsafe { &*(func as *mut TsFn) };
- tsfn.call(data, is_blocking)
-}
-
-#[napi_sym]
-fn napi_acquire_threadsafe_function(
- tsfn: napi_threadsafe_function,
-) -> napi_status {
- assert!(!tsfn.is_null());
- let tsfn = unsafe { &*(tsfn as *mut TsFn) };
- tsfn.acquire()
-}
-
-#[napi_sym]
-fn napi_release_threadsafe_function(
- tsfn: napi_threadsafe_function,
- mode: napi_threadsafe_function_release_mode,
-) -> napi_status {
- assert!(!tsfn.is_null());
- TsFn::release(tsfn as _, mode)
-}
-
-#[napi_sym]
-fn napi_unref_threadsafe_function(
- _env: &mut Env,
- func: napi_threadsafe_function,
-) -> napi_status {
- assert!(!func.is_null());
- let tsfn = unsafe { &*(func as *mut TsFn) };
- tsfn.unref()
-}
-
-#[napi_sym]
-fn napi_ref_threadsafe_function(
- _env: &mut Env,
- func: napi_threadsafe_function,
-) -> napi_status {
- assert!(!func.is_null());
- let tsfn = unsafe { &*(func as *mut TsFn) };
- tsfn.ref_()
-}
-
-#[napi_sym]
-fn node_api_get_module_file_name(
- env: *mut Env,
- result: *mut *const c_char,
-) -> napi_status {
- let env = check_env!(env);
- check_arg!(env, result);
-
- unsafe {
- *result = env.shared().filename.as_ptr() as _;
- }
-
- napi_clear_last_error(env)
-}
diff --git a/cli/napi/sym/Cargo.toml b/cli/napi/sym/Cargo.toml
deleted file mode 100644
index fef749fc4..000000000
--- a/cli/napi/sym/Cargo.toml
+++ /dev/null
@@ -1,21 +0,0 @@
-# Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-
-[package]
-name = "napi_sym"
-version = "0.101.0"
-authors.workspace = true
-edition.workspace = true
-license.workspace = true
-readme = "README.md"
-repository.workspace = true
-description = "proc macro for writing N-API symbols"
-
-[lib]
-path = "./lib.rs"
-proc-macro = true
-
-[dependencies]
-quote.workspace = true
-serde.workspace = true
-serde_json.workspace = true
-syn.workspace = true
diff --git a/cli/napi/sym/README.md b/cli/napi/sym/README.md
deleted file mode 100644
index de08a8e17..000000000
--- a/cli/napi/sym/README.md
+++ /dev/null
@@ -1,37 +0,0 @@
-# napi_sym
-
-A proc_macro for Deno's Node-API implementation. It does the following things:
-
-- Marks the symbol as `#[no_mangle]` and rewrites it as `pub extern "C" $name`.
-- Asserts that the function symbol is present in
- [`symbol_exports.json`](./symbol_exports.json).
-- Maps `deno_napi::Result` to raw `napi_result`.
-
-```rust
-use deno_napi::napi_value;
-use deno_napi::Env;
-use deno_napi::Error;
-use deno_napi::Result;
-
-#[napi_sym::napi_sym]
-fn napi_get_boolean(
- env: *mut Env,
- value: bool,
- result: *mut napi_value,
-) -> Result {
- let _env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
- // *result = ...
- Ok(())
-}
-```
-
-### `symbol_exports.json`
-
-A file containing the symbols that need to be put into the executable's dynamic
-symbol table at link-time.
-
-This is done using `/DEF:` on Windows, `-exported_symbol,_` on macOS and
-`--export-dynamic-symbol=` on Linux. See [`cli/build.rs`](../build.rs).
-
-On Windows, you need to generate the `.def` file by running
-[`tools/napi/generate_symbols_lists.js`](../../tools/napi/generate_symbols_lists.js).
diff --git a/cli/napi/sym/lib.rs b/cli/napi/sym/lib.rs
deleted file mode 100644
index e2826306b..000000000
--- a/cli/napi/sym/lib.rs
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-
-use proc_macro::TokenStream;
-use quote::quote;
-use serde::Deserialize;
-
-static NAPI_EXPORTS: &str = include_str!("./symbol_exports.json");
-
-#[derive(Deserialize)]
-struct SymbolExports {
- pub symbols: Vec<String>,
-}
-
-#[proc_macro_attribute]
-pub fn napi_sym(_attr: TokenStream, item: TokenStream) -> TokenStream {
- let func = syn::parse::<syn::ItemFn>(item).expect("expected a function");
-
- let exports: SymbolExports =
- serde_json::from_str(NAPI_EXPORTS).expect("failed to parse exports");
- let name = &func.sig.ident;
- assert!(
- exports.symbols.contains(&name.to_string()),
- "cli/napi/sym/symbol_exports.json is out of sync!"
- );
-
- TokenStream::from(quote! {
- crate::napi_wrap! {
- #func
- }
- })
-}
diff --git a/cli/napi/sym/symbol_exports.json b/cli/napi/sym/symbol_exports.json
deleted file mode 100644
index 00946b8ed..000000000
--- a/cli/napi/sym/symbol_exports.json
+++ /dev/null
@@ -1,164 +0,0 @@
-{
- "symbols": [
- "node_api_create_syntax_error",
- "napi_make_callback",
- "napi_has_named_property",
- "napi_async_destroy",
- "napi_coerce_to_object",
- "napi_get_arraybuffer_info",
- "napi_detach_arraybuffer",
- "napi_get_undefined",
- "napi_reference_unref",
- "napi_fatal_error",
- "napi_open_callback_scope",
- "napi_close_callback_scope",
- "napi_get_value_uint32",
- "napi_create_function",
- "napi_create_arraybuffer",
- "napi_get_value_int64",
- "napi_get_all_property_names",
- "napi_resolve_deferred",
- "napi_is_detached_arraybuffer",
- "napi_create_string_utf8",
- "napi_create_threadsafe_function",
- "node_api_throw_syntax_error",
- "napi_create_bigint_int64",
- "napi_wrap",
- "napi_set_property",
- "napi_get_value_bigint_int64",
- "napi_open_handle_scope",
- "napi_create_error",
- "napi_create_buffer",
- "napi_cancel_async_work",
- "napi_is_exception_pending",
- "napi_acquire_threadsafe_function",
- "napi_create_external",
- "napi_get_threadsafe_function_context",
- "napi_get_null",
- "napi_create_string_utf16",
- "node_api_create_external_string_utf16",
- "napi_get_value_bigint_uint64",
- "napi_module_register",
- "napi_is_typedarray",
- "napi_create_external_buffer",
- "napi_get_new_target",
- "napi_get_instance_data",
- "napi_close_handle_scope",
- "napi_get_value_string_utf16",
- "napi_get_property_names",
- "napi_is_arraybuffer",
- "napi_get_cb_info",
- "napi_define_properties",
- "napi_add_env_cleanup_hook",
- "node_api_get_module_file_name",
- "napi_get_node_version",
- "napi_create_int64",
- "napi_create_double",
- "napi_get_and_clear_last_exception",
- "napi_create_reference",
- "napi_get_typedarray_info",
- "napi_call_threadsafe_function",
- "napi_get_last_error_info",
- "napi_create_array_with_length",
- "napi_coerce_to_number",
- "napi_get_global",
- "napi_is_error",
- "napi_set_instance_data",
- "napi_create_typedarray",
- "napi_throw_type_error",
- "napi_has_property",
- "napi_get_value_external",
- "napi_create_range_error",
- "napi_typeof",
- "napi_ref_threadsafe_function",
- "napi_create_bigint_uint64",
- "napi_get_prototype",
- "napi_adjust_external_memory",
- "napi_release_threadsafe_function",
- "napi_delete_async_work",
- "napi_create_string_latin1",
- "node_api_create_external_string_latin1",
- "napi_is_array",
- "napi_unref_threadsafe_function",
- "napi_throw_error",
- "napi_has_own_property",
- "napi_get_reference_value",
- "napi_remove_env_cleanup_hook",
- "napi_get_value_string_utf8",
- "napi_is_promise",
- "napi_get_boolean",
- "napi_run_script",
- "napi_get_element",
- "napi_get_named_property",
- "napi_get_buffer_info",
- "napi_get_value_bool",
- "napi_reference_ref",
- "napi_create_object",
- "napi_create_promise",
- "napi_create_int32",
- "napi_escape_handle",
- "napi_open_escapable_handle_scope",
- "napi_throw",
- "napi_get_value_double",
- "napi_set_named_property",
- "napi_call_function",
- "napi_create_date",
- "napi_object_freeze",
- "napi_get_uv_event_loop",
- "napi_get_value_string_latin1",
- "napi_reject_deferred",
- "napi_add_finalizer",
- "napi_create_array",
- "napi_delete_reference",
- "napi_get_date_value",
- "napi_create_dataview",
- "napi_get_version",
- "napi_define_class",
- "napi_is_date",
- "napi_remove_wrap",
- "napi_delete_property",
- "napi_instanceof",
- "napi_create_buffer_copy",
- "napi_delete_element",
- "napi_object_seal",
- "napi_queue_async_work",
- "napi_get_value_bigint_words",
- "napi_is_buffer",
- "napi_get_array_length",
- "napi_get_property",
- "napi_new_instance",
- "napi_set_element",
- "napi_create_bigint_words",
- "napi_strict_equals",
- "napi_is_dataview",
- "napi_close_escapable_handle_scope",
- "napi_get_dataview_info",
- "napi_get_value_int32",
- "napi_unwrap",
- "napi_throw_range_error",
- "napi_coerce_to_bool",
- "napi_create_uint32",
- "napi_has_element",
- "napi_create_external_arraybuffer",
- "napi_create_symbol",
- "node_api_symbol_for",
- "napi_coerce_to_string",
- "napi_create_type_error",
- "napi_fatal_exception",
- "napi_create_async_work",
- "napi_async_init",
- "node_api_create_property_key_utf16",
- "napi_type_tag_object",
- "napi_check_object_type_tag",
- "node_api_post_finalizer",
- "napi_add_async_cleanup_hook",
- "napi_remove_async_cleanup_hook",
- "uv_mutex_init",
- "uv_mutex_lock",
- "uv_mutex_unlock",
- "uv_mutex_destroy",
- "uv_async_init",
- "uv_async_send",
- "uv_close"
- ]
-}
diff --git a/cli/napi/util.rs b/cli/napi/util.rs
deleted file mode 100644
index 63d8effbf..000000000
--- a/cli/napi/util.rs
+++ /dev/null
@@ -1,289 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-use deno_runtime::deno_napi::*;
-use libc::INT_MAX;
-
-#[repr(transparent)]
-pub struct SendPtr<T>(pub *const T);
-
-impl<T> SendPtr<T> {
- // silly function to get around `clippy::redundant_locals`
- pub fn take(self) -> *const T {
- self.0
- }
-}
-
-unsafe impl<T> Send for SendPtr<T> {}
-unsafe impl<T> Sync for SendPtr<T> {}
-
-pub fn get_array_buffer_ptr(ab: v8::Local<v8::ArrayBuffer>) -> *mut c_void {
- match ab.data() {
- Some(p) => p.as_ptr(),
- None => std::ptr::null_mut(),
- }
-}
-
-struct BufferFinalizer {
- env: *mut Env,
- finalize_cb: napi_finalize,
- finalize_data: *mut c_void,
- finalize_hint: *mut c_void,
-}
-
-impl Drop for BufferFinalizer {
- fn drop(&mut self) {
- unsafe {
- (self.finalize_cb)(self.env as _, self.finalize_data, self.finalize_hint);
- }
- }
-}
-
-pub extern "C" fn backing_store_deleter_callback(
- data: *mut c_void,
- _byte_length: usize,
- deleter_data: *mut c_void,
-) {
- let mut finalizer =
- unsafe { Box::<BufferFinalizer>::from_raw(deleter_data as _) };
-
- finalizer.finalize_data = data;
-
- drop(finalizer);
-}
-
-pub fn make_external_backing_store(
- env: *mut Env,
- data: *mut c_void,
- byte_length: usize,
- finalize_data: *mut c_void,
- finalize_cb: napi_finalize,
- finalize_hint: *mut c_void,
-) -> v8::UniqueRef<v8::BackingStore> {
- let finalizer = Box::new(BufferFinalizer {
- env,
- finalize_data,
- finalize_cb,
- finalize_hint,
- });
-
- unsafe {
- v8::ArrayBuffer::new_backing_store_from_ptr(
- data,
- byte_length,
- backing_store_deleter_callback,
- Box::into_raw(finalizer) as _,
- )
- }
-}
-
-#[macro_export]
-macro_rules! check_env {
- ($env: expr) => {{
- let env = $env;
- if env.is_null() {
- return napi_invalid_arg;
- }
- unsafe { &mut *env }
- }};
-}
-
-#[macro_export]
-macro_rules! return_error_status_if_false {
- ($env: expr, $condition: expr, $status: ident) => {
- if !$condition {
- return Err(
- $crate::napi::util::napi_set_last_error($env, $status).into(),
- );
- }
- };
-}
-
-#[macro_export]
-macro_rules! return_status_if_false {
- ($env: expr, $condition: expr, $status: ident) => {
- if !$condition {
- return $crate::napi::util::napi_set_last_error($env, $status);
- }
- };
-}
-
-pub(crate) unsafe fn check_new_from_utf8_len<'s>(
- env: *mut Env,
- str_: *const c_char,
- len: usize,
-) -> Result<v8::Local<'s, v8::String>, napi_status> {
- let env = unsafe { &mut *env };
- return_error_status_if_false!(
- env,
- (len == NAPI_AUTO_LENGTH) || len <= INT_MAX as _,
- napi_invalid_arg
- );
- return_error_status_if_false!(env, !str_.is_null(), napi_invalid_arg);
- let string = if len == NAPI_AUTO_LENGTH {
- let result = unsafe { std::ffi::CStr::from_ptr(str_ as *const _) }.to_str();
- return_error_status_if_false!(env, result.is_ok(), napi_generic_failure);
- result.unwrap()
- } else {
- let string = unsafe { std::slice::from_raw_parts(str_ as *const u8, len) };
- let result = std::str::from_utf8(string);
- return_error_status_if_false!(env, result.is_ok(), napi_generic_failure);
- result.unwrap()
- };
- let result = {
- let env = unsafe { &mut *(env as *mut Env) };
- v8::String::new(&mut env.scope(), string)
- };
- return_error_status_if_false!(env, result.is_some(), napi_generic_failure);
- Ok(result.unwrap())
-}
-
-#[inline]
-pub(crate) unsafe fn check_new_from_utf8<'s>(
- env: *mut Env,
- str_: *const c_char,
-) -> Result<v8::Local<'s, v8::String>, napi_status> {
- unsafe { check_new_from_utf8_len(env, str_, NAPI_AUTO_LENGTH) }
-}
-
-pub(crate) unsafe fn v8_name_from_property_descriptor<'s>(
- env: *mut Env,
- p: &'s napi_property_descriptor,
-) -> Result<v8::Local<'s, v8::Name>, napi_status> {
- if !p.utf8name.is_null() {
- unsafe { check_new_from_utf8(env, p.utf8name).map(|v| v.into()) }
- } else {
- match *p.name {
- Some(v) => match v.try_into() {
- Ok(name) => Ok(name),
- Err(_) => Err(napi_name_expected),
- },
- None => Err(napi_name_expected),
- }
- }
-}
-
-pub(crate) fn napi_clear_last_error(env: *mut Env) -> napi_status {
- let env = unsafe { &mut *env };
- env.last_error.error_code = napi_ok;
- env.last_error.engine_error_code = 0;
- env.last_error.engine_reserved = std::ptr::null_mut();
- env.last_error.error_message = std::ptr::null_mut();
- napi_ok
-}
-
-pub(crate) fn napi_set_last_error(
- env: *mut Env,
- error_code: napi_status,
-) -> napi_status {
- let env = unsafe { &mut *env };
- env.last_error.error_code = error_code;
- error_code
-}
-
-#[macro_export]
-macro_rules! status_call {
- ($call: expr) => {
- let status = $call;
- if status != napi_ok {
- return status;
- }
- };
-}
-
-pub trait Nullable {
- fn is_null(&self) -> bool;
-}
-
-impl<T> Nullable for *mut T {
- fn is_null(&self) -> bool {
- (*self).is_null()
- }
-}
-
-impl<T> Nullable for *const T {
- fn is_null(&self) -> bool {
- (*self).is_null()
- }
-}
-
-impl<T> Nullable for Option<T> {
- fn is_null(&self) -> bool {
- self.is_none()
- }
-}
-
-impl<'s> Nullable for napi_value<'s> {
- fn is_null(&self) -> bool {
- self.is_none()
- }
-}
-
-#[macro_export]
-macro_rules! check_arg {
- ($env: expr, $ptr: expr) => {
- $crate::return_status_if_false!(
- $env,
- !$crate::napi::util::Nullable::is_null(&$ptr),
- napi_invalid_arg
- );
- };
-}
-
-#[macro_export]
-macro_rules! napi_wrap {
- ( $( # $attr:tt )* fn $name:ident $( < $( $x:lifetime ),* > )? ( $env:ident : & $( $lt:lifetime )? mut Env $( , $ident:ident : $ty:ty )* $(,)? ) -> napi_status $body:block ) => {
- $( # $attr )*
- #[no_mangle]
- pub unsafe extern "C" fn $name $( < $( $x ),* > )? ( env_ptr : *mut Env , $( $ident : $ty ),* ) -> napi_status {
- let env: & $( $lt )? mut Env = $crate::check_env!(env_ptr);
-
- if env.last_exception.is_some() {
- return napi_pending_exception;
- }
-
- $crate::napi::util::napi_clear_last_error(env);
-
- let scope_env = unsafe { &mut *env_ptr };
- let scope = &mut scope_env.scope();
- let try_catch = &mut v8::TryCatch::new(scope);
-
- #[inline(always)]
- fn inner $( < $( $x ),* > )? ( $env: & $( $lt )? mut Env , $( $ident : $ty ),* ) -> napi_status $body
-
- log::trace!("NAPI ENTER: {}", stringify!($name));
-
- let result = inner( env, $( $ident ),* );
-
- log::trace!("NAPI EXIT: {} {}", stringify!($name), result);
-
- if let Some(exception) = try_catch.exception() {
- let env = unsafe { &mut *env_ptr };
- let global = v8::Global::new(env.isolate(), exception);
- env.last_exception = Some(global);
- return $crate::napi::util::napi_set_last_error(env_ptr, napi_pending_exception);
- }
-
- if result != napi_ok {
- return $crate::napi::util::napi_set_last_error(env_ptr, result);
- }
-
- return result;
- }
- };
-
- ( $( # $attr:tt )* fn $name:ident $( < $( $x:lifetime ),* > )? ( $( $ident:ident : $ty:ty ),* $(,)? ) -> napi_status $body:block ) => {
- $( # $attr )*
- #[no_mangle]
- pub unsafe extern "C" fn $name $( < $( $x ),* > )? ( $( $ident : $ty ),* ) -> napi_status {
- #[inline(always)]
- fn inner $( < $( $x ),* > )? ( $( $ident : $ty ),* ) -> napi_status $body
-
- log::trace!("NAPI ENTER: {}", stringify!($name));
-
- let result = inner( $( $ident ),* );
-
- log::trace!("NAPI EXIT: {} {}", stringify!($name), result);
-
- result
- }
- };
-}
diff --git a/cli/napi/uv.rs b/cli/napi/uv.rs
deleted file mode 100644
index d4cb5c0b3..000000000
--- a/cli/napi/uv.rs
+++ /dev/null
@@ -1,231 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-
-use deno_core::parking_lot::Mutex;
-use deno_runtime::deno_napi::*;
-use std::mem::MaybeUninit;
-use std::ptr::addr_of_mut;
-
-#[allow(clippy::print_stderr)]
-fn assert_ok(res: c_int) -> c_int {
- if res != 0 {
- eprintln!("bad result in uv polyfill: {res}");
- // don't panic because that might unwind into
- // c/c++
- std::process::abort();
- }
- res
-}
-
-use crate::napi::js_native_api::napi_create_string_utf8;
-use crate::napi::node_api::napi_create_async_work;
-use crate::napi::node_api::napi_delete_async_work;
-use crate::napi::node_api::napi_queue_async_work;
-use std::ffi::c_int;
-
-const UV_MUTEX_SIZE: usize = {
- #[cfg(unix)]
- {
- std::mem::size_of::<libc::pthread_mutex_t>()
- }
- #[cfg(windows)]
- {
- std::mem::size_of::<windows_sys::Win32::System::Threading::CRITICAL_SECTION>(
- )
- }
-};
-
-#[repr(C)]
-struct uv_mutex_t {
- mutex: Mutex<()>,
- _padding: [MaybeUninit<usize>; const {
- (UV_MUTEX_SIZE - size_of::<Mutex<()>>()) / size_of::<usize>()
- }],
-}
-
-#[no_mangle]
-unsafe extern "C" fn uv_mutex_init(lock: *mut uv_mutex_t) -> c_int {
- unsafe {
- addr_of_mut!((*lock).mutex).write(Mutex::new(()));
- 0
- }
-}
-
-#[no_mangle]
-unsafe extern "C" fn uv_mutex_lock(lock: *mut uv_mutex_t) {
- unsafe {
- let guard = (*lock).mutex.lock();
- // forget the guard so it doesn't unlock when it goes out of scope.
- // we're going to unlock it manually
- std::mem::forget(guard);
- }
-}
-
-#[no_mangle]
-unsafe extern "C" fn uv_mutex_unlock(lock: *mut uv_mutex_t) {
- unsafe {
- (*lock).mutex.force_unlock();
- }
-}
-
-#[no_mangle]
-unsafe extern "C" fn uv_mutex_destroy(_lock: *mut uv_mutex_t) {
- // no cleanup required
-}
-
-#[repr(C)]
-#[derive(Clone, Copy, Debug)]
-#[allow(dead_code)]
-enum uv_handle_type {
- UV_UNKNOWN_HANDLE = 0,
- UV_ASYNC,
- UV_CHECK,
- UV_FS_EVENT,
- UV_FS_POLL,
- UV_HANDLE,
- UV_IDLE,
- UV_NAMED_PIPE,
- UV_POLL,
- UV_PREPARE,
- UV_PROCESS,
- UV_STREAM,
- UV_TCP,
- UV_TIMER,
- UV_TTY,
- UV_UDP,
- UV_SIGNAL,
- UV_FILE,
- UV_HANDLE_TYPE_MAX,
-}
-
-const UV_HANDLE_SIZE: usize = 96;
-
-#[repr(C)]
-struct uv_handle_t {
- // public members
- pub data: *mut c_void,
- pub r#loop: *mut uv_loop_t,
- pub r#type: uv_handle_type,
-
- _padding: [MaybeUninit<usize>; const {
- (UV_HANDLE_SIZE
- - size_of::<*mut c_void>()
- - size_of::<*mut uv_loop_t>()
- - size_of::<uv_handle_type>())
- / size_of::<usize>()
- }],
-}
-
-#[cfg(unix)]
-const UV_ASYNC_SIZE: usize = 128;
-
-#[cfg(windows)]
-const UV_ASYNC_SIZE: usize = 224;
-
-#[repr(C)]
-struct uv_async_t {
- // public members
- pub data: *mut c_void,
- pub r#loop: *mut uv_loop_t,
- pub r#type: uv_handle_type,
- // private
- async_cb: uv_async_cb,
- work: napi_async_work,
- _padding: [MaybeUninit<usize>; const {
- (UV_ASYNC_SIZE
- - size_of::<*mut c_void>()
- - size_of::<*mut uv_loop_t>()
- - size_of::<uv_handle_type>()
- - size_of::<uv_async_cb>()
- - size_of::<napi_async_work>())
- / size_of::<usize>()
- }],
-}
-
-type uv_loop_t = Env;
-type uv_async_cb = extern "C" fn(handle: *mut uv_async_t);
-#[no_mangle]
-unsafe extern "C" fn uv_async_init(
- r#loop: *mut uv_loop_t,
- // probably uninitialized
- r#async: *mut uv_async_t,
- async_cb: uv_async_cb,
-) -> c_int {
- unsafe {
- addr_of_mut!((*r#async).r#loop).write(r#loop);
- addr_of_mut!((*r#async).r#type).write(uv_handle_type::UV_ASYNC);
- addr_of_mut!((*r#async).async_cb).write(async_cb);
-
- let mut resource_name: MaybeUninit<napi_value> = MaybeUninit::uninit();
- assert_ok(napi_create_string_utf8(
- r#loop,
- c"uv_async".as_ptr(),
- usize::MAX,
- resource_name.as_mut_ptr(),
- ));
- let resource_name = resource_name.assume_init();
-
- let res = napi_create_async_work(
- r#loop,
- None::<v8::Local<'static, v8::Value>>.into(),
- resource_name,
- Some(async_exec_wrap),
- None,
- r#async.cast(),
- addr_of_mut!((*r#async).work),
- );
- -res
- }
-}
-
-#[no_mangle]
-unsafe extern "C" fn uv_async_send(handle: *mut uv_async_t) -> c_int {
- unsafe { -napi_queue_async_work((*handle).r#loop, (*handle).work) }
-}
-
-type uv_close_cb = unsafe extern "C" fn(*mut uv_handle_t);
-
-#[no_mangle]
-unsafe extern "C" fn uv_close(handle: *mut uv_handle_t, close: uv_close_cb) {
- unsafe {
- if handle.is_null() {
- close(handle);
- return;
- }
- if let uv_handle_type::UV_ASYNC = (*handle).r#type {
- let handle: *mut uv_async_t = handle.cast();
- napi_delete_async_work((*handle).r#loop, (*handle).work);
- }
- close(handle);
- }
-}
-
-unsafe extern "C" fn async_exec_wrap(_env: napi_env, data: *mut c_void) {
- let data: *mut uv_async_t = data.cast();
- unsafe {
- ((*data).async_cb)(data);
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- #[test]
- fn sizes() {
- assert_eq!(
- std::mem::size_of::<libuv_sys_lite::uv_mutex_t>(),
- UV_MUTEX_SIZE
- );
- assert_eq!(
- std::mem::size_of::<libuv_sys_lite::uv_handle_t>(),
- UV_HANDLE_SIZE
- );
- assert_eq!(
- std::mem::size_of::<libuv_sys_lite::uv_async_t>(),
- UV_ASYNC_SIZE
- );
- assert_eq!(std::mem::size_of::<uv_mutex_t>(), UV_MUTEX_SIZE);
- assert_eq!(std::mem::size_of::<uv_handle_t>(), UV_HANDLE_SIZE);
- assert_eq!(std::mem::size_of::<uv_async_t>(), UV_ASYNC_SIZE);
- }
-}