summaryrefslogtreecommitdiff
path: root/cli/napi/js_native_api.rs
diff options
context:
space:
mode:
Diffstat (limited to 'cli/napi/js_native_api.rs')
-rw-r--r--cli/napi/js_native_api.rs2275
1 files changed, 2275 insertions, 0 deletions
diff --git a/cli/napi/js_native_api.rs b/cli/napi/js_native_api.rs
new file mode 100644
index 000000000..6270dbe5c
--- /dev/null
+++ b/cli/napi/js_native_api.rs
@@ -0,0 +1,2275 @@
+// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
+
+#![allow(non_upper_case_globals)]
+
+use deno_runtime::deno_napi::*;
+use v8::BackingStore;
+use v8::UniqueRef;
+
+use super::util::get_array_buffer_ptr;
+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 std::ptr::NonNull;
+
+// Macro to check napi arguments.
+// If nullptr, return Err(Error::InvalidArg).
+#[macro_export]
+macro_rules! check_arg {
+ ($ptr: expr) => {
+ if $ptr.is_null() {
+ return Err(Error::InvalidArg);
+ }
+ };
+}
+
+/// Returns napi_value that represents a new JavaScript Array.
+#[napi_sym::napi_sym]
+fn napi_create_array(env: *mut Env, result: *mut napi_value) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+ check_arg!(result);
+
+ let value = v8::Array::new(&mut env.scope(), 0);
+ *result = transmute::<v8::Local<v8::Value>, napi_value>(value.into());
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_create_array_with_length(
+ env: *mut Env,
+ len: i32,
+ result: *mut napi_value,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+ check_arg!(result);
+
+ let value = v8::Array::new(&mut env.scope(), len);
+ *result = transmute::<v8::Local<v8::Value>, napi_value>(value.into());
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_create_arraybuffer(
+ env: *mut Env,
+ len: usize,
+ data: *mut *mut u8,
+ result: *mut napi_value,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+ check_arg!(result);
+
+ let value = v8::ArrayBuffer::new(&mut env.scope(), len);
+ if !data.is_null() {
+ *data = get_array_buffer_ptr(value);
+ }
+
+ *result = transmute::<v8::Local<v8::Value>, napi_value>(value.into());
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_create_bigint_int64(
+ env: *mut Env,
+ value: i64,
+ result: *mut napi_value,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+ check_arg!(result);
+
+ let value = v8::BigInt::new_from_i64(&mut env.scope(), value);
+ *result = transmute::<v8::Local<v8::Value>, napi_value>(value.into());
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_create_bigint_uint64(
+ env: *mut Env,
+ value: u64,
+ result: *mut napi_value,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+ let value: v8::Local<v8::Value> =
+ v8::BigInt::new_from_u64(&mut env.scope(), value).into();
+ *result = transmute::<v8::Local<v8::Value>, napi_value>(value);
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_create_bigint_words(
+ env: *mut Env,
+ sign_bit: bool,
+ words: *const u64,
+ word_count: usize,
+ result: *mut napi_value,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+ let value: v8::Local<v8::Value> = v8::BigInt::new_from_words(
+ &mut env.scope(),
+ sign_bit,
+ std::slice::from_raw_parts(words, word_count),
+ )
+ .unwrap()
+ .into();
+ *result = transmute::<v8::Local<v8::Value>, napi_value>(value);
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_create_buffer(
+ env: *mut Env,
+ len: usize,
+ data: *mut *mut u8,
+ result: *mut napi_value,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+ let value = v8::ArrayBuffer::new(&mut env.scope(), len);
+ if !data.is_null() {
+ *data = get_array_buffer_ptr(value);
+ }
+ let value = v8::Uint8Array::new(&mut env.scope(), value, 0, len).unwrap();
+ let value: v8::Local<v8::Value> = value.into();
+ *result = transmute::<v8::Local<v8::Value>, napi_value>(value);
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_create_buffer_copy(
+ env: *mut Env,
+ len: usize,
+ data: *mut u8,
+ result_data: *mut *mut u8,
+ result: *mut napi_value,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+ let value = v8::ArrayBuffer::new(&mut env.scope(), len);
+ let ptr = get_array_buffer_ptr(value);
+ std::ptr::copy(data, ptr, len);
+ if !result_data.is_null() {
+ *result_data = ptr;
+ }
+ let value = v8::Uint8Array::new(&mut env.scope(), value, 0, len).unwrap();
+ let value: v8::Local<v8::Value> = value.into();
+ *result = transmute::<v8::Local<v8::Value>, napi_value>(value);
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_coerce_to_bool(
+ env: *mut Env,
+ value: napi_value,
+ result: *mut napi_value,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+ let value = transmute::<napi_value, v8::Local<v8::Value>>(value);
+ let coerced = value.to_boolean(&mut env.scope());
+ let value: v8::Local<v8::Value> = coerced.into();
+ *result = transmute::<v8::Local<v8::Value>, napi_value>(value);
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_coerce_to_number(
+ env: *mut Env,
+ value: napi_value,
+ result: *mut napi_value,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+ let value = transmute::<napi_value, v8::Local<v8::Value>>(value);
+ let coerced = value
+ .to_number(&mut env.scope())
+ .ok_or(Error::NumberExpected)?;
+ let value: v8::Local<v8::Value> = coerced.into();
+ *result = transmute::<v8::Local<v8::Value>, napi_value>(value);
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_coerce_to_object(
+ env: *mut Env,
+ value: napi_value,
+ result: *mut napi_value,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+ let value = transmute::<napi_value, v8::Local<v8::Value>>(value);
+ let coerced = value.to_object(&mut env.scope()).unwrap();
+ let value: v8::Local<v8::Value> = coerced.into();
+ *result = transmute::<v8::Local<v8::Value>, napi_value>(value);
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_coerce_to_string(
+ env: *mut Env,
+ value: napi_value,
+ result: *mut napi_value,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+ let value = transmute::<napi_value, v8::Local<v8::Value>>(value);
+ let coerced = value.to_string(&mut env.scope()).unwrap();
+ let value: v8::Local<v8::Value> = coerced.into();
+ *result = transmute::<v8::Local<v8::Value>, napi_value>(value);
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_create_dataview(
+ env: *mut Env,
+ len: usize,
+ data: *mut *mut u8,
+ byte_offset: usize,
+ result: *mut napi_value,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+ check_arg!(data);
+ check_arg!(result);
+ let value = v8::ArrayBuffer::new(&mut env.scope(), len);
+ if !data.is_null() {
+ *data = get_array_buffer_ptr(value);
+ }
+ let context = &mut env.scope().get_current_context();
+ let global = context.global(&mut env.scope());
+ let data_view_name = v8::String::new(&mut env.scope(), "DataView").unwrap();
+ let data_view = global.get(&mut env.scope(), data_view_name.into()).unwrap();
+ let data_view = v8::Local::<v8::Function>::try_from(data_view).unwrap();
+ let byte_offset = v8::Number::new(&mut env.scope(), byte_offset as f64);
+ let byte_length = v8::Number::new(&mut env.scope(), len as f64);
+ let value = data_view
+ .new_instance(
+ &mut env.scope(),
+ &[value.into(), byte_offset.into(), byte_length.into()],
+ )
+ .unwrap();
+ let value: v8::Local<v8::Value> = value.into();
+ *result = transmute::<v8::Local<v8::Value>, napi_value>(value);
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_create_date(
+ env: *mut Env,
+ time: f64,
+ result: *mut napi_value,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+ let value: v8::Local<v8::Value> =
+ v8::Date::new(&mut env.scope(), time).unwrap().into();
+ *result = transmute::<v8::Local<v8::Value>, napi_value>(value);
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_create_double(
+ env: *mut Env,
+ value: f64,
+ result: *mut napi_value,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+ let value: v8::Local<v8::Value> =
+ v8::Number::new(&mut env.scope(), value).into();
+ *result = transmute::<v8::Local<v8::Value>, napi_value>(value);
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_create_error(
+ env: *mut Env,
+ code: napi_value,
+ msg: napi_value,
+ result: *mut napi_value,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+
+ let _code = transmute::<napi_value, v8::Local<v8::Value>>(code);
+ let msg = transmute::<napi_value, v8::Local<v8::Value>>(msg);
+
+ let msg = msg.to_string(&mut env.scope()).unwrap();
+
+ let error = v8::Exception::error(&mut env.scope(), msg);
+ *result = transmute::<v8::Local<v8::Value>, napi_value>(error);
+
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_create_external(
+ env: *mut Env,
+ value: *mut c_void,
+ _finalize_cb: napi_finalize,
+ _finalize_hint: *mut c_void,
+ result: *mut napi_value,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+ let value: v8::Local<v8::Value> =
+ v8::External::new(&mut env.scope(), value).into();
+ // TODO: finalization
+ *result = transmute::<v8::Local<v8::Value>, napi_value>(value);
+ Ok(())
+}
+
+pub type BackingStoreDeleterCallback = unsafe extern "C" fn(
+ data: *mut c_void,
+ byte_length: usize,
+ deleter_data: *mut c_void,
+);
+extern "C" {
+ fn v8__ArrayBuffer__NewBackingStore__with_data(
+ data: *mut c_void,
+ byte_length: usize,
+ deleter: BackingStoreDeleterCallback,
+ deleter_data: *mut c_void,
+ ) -> *mut BackingStore;
+}
+
+pub extern "C" fn backing_store_deleter_callback(
+ data: *mut c_void,
+ byte_length: usize,
+ _deleter_data: *mut c_void,
+) {
+ let slice_ptr = ptr::slice_from_raw_parts_mut(data as *mut u8, byte_length);
+ let b = unsafe { Box::from_raw(slice_ptr) };
+ drop(b);
+}
+
+#[napi_sym::napi_sym]
+fn napi_create_external_arraybuffer(
+ env: *mut Env,
+ data: *mut c_void,
+ byte_length: usize,
+ _finalize_cb: napi_finalize,
+ finalize_hint: *mut c_void,
+ result: *mut napi_value,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+ let _slice = std::slice::from_raw_parts(data as *mut u8, byte_length);
+ // TODO: finalization
+ let store: UniqueRef<BackingStore> =
+ transmute(v8__ArrayBuffer__NewBackingStore__with_data(
+ data,
+ byte_length,
+ backing_store_deleter_callback,
+ finalize_hint,
+ ));
+
+ let ab =
+ v8::ArrayBuffer::with_backing_store(&mut env.scope(), &store.make_shared());
+ let value: v8::Local<v8::Value> = ab.into();
+ *result = transmute::<v8::Local<v8::Value>, napi_value>(value);
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_create_external_buffer(
+ env: *mut Env,
+ byte_length: isize,
+ data: *mut c_void,
+ _finalize_cb: napi_finalize,
+ _finalize_hint: *mut c_void,
+ result: *mut napi_value,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+ let slice = if byte_length == -1 {
+ std::ffi::CStr::from_ptr(data as *const _).to_bytes()
+ } else {
+ std::slice::from_raw_parts(data as *mut u8, byte_length as usize)
+ };
+ // TODO: make this not copy the slice
+ // TODO: finalization
+ let store = v8::ArrayBuffer::new_backing_store_from_boxed_slice(
+ slice.to_vec().into_boxed_slice(),
+ );
+ let ab =
+ v8::ArrayBuffer::with_backing_store(&mut env.scope(), &store.make_shared());
+ let value =
+ v8::Uint8Array::new(&mut env.scope(), ab, 0, slice.len()).unwrap();
+ let value: v8::Local<v8::Value> = value.into();
+ *result = transmute::<v8::Local<v8::Value>, napi_value>(value);
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_create_function(
+ env_ptr: *mut Env,
+ name: *const u8,
+ length: isize,
+ cb: napi_callback,
+ cb_info: napi_callback_info,
+ result: *mut napi_value,
+) -> Result {
+ let _: &mut Env = env_ptr.as_mut().ok_or(Error::InvalidArg)?;
+ let name = match name.is_null() {
+ true => None,
+ false => Some(name),
+ };
+ let name = name.map(|name| {
+ if length == -1 {
+ std::ffi::CStr::from_ptr(name as *const _).to_str().unwrap()
+ } else {
+ let name = std::slice::from_raw_parts(name, length as usize);
+ // If ends with NULL
+ if name[name.len() - 1] == 0 {
+ std::str::from_utf8(&name[0..name.len() - 1]).unwrap()
+ } else {
+ std::str::from_utf8(name).unwrap()
+ }
+ }
+ });
+
+ let function = create_function(env_ptr, name, cb, cb_info);
+ let value: v8::Local<v8::Value> = function.into();
+ *result = transmute::<v8::Local<v8::Value>, napi_value>(value);
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_create_int32(
+ env: *mut Env,
+ value: i32,
+ result: *mut napi_value,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+ let value: v8::Local<v8::Value> =
+ v8::Number::new(&mut env.scope(), value as f64).into();
+ *result = transmute::<v8::Local<v8::Value>, napi_value>(value);
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_create_int64(
+ env: *mut Env,
+ value: i64,
+ result: *mut napi_value,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+ let value: v8::Local<v8::Value> =
+ v8::Number::new(&mut env.scope(), value as f64).into();
+ *result = transmute::<v8::Local<v8::Value>, napi_value>(value);
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_create_object(env: *mut Env, result: *mut napi_value) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+ let object = v8::Object::new(&mut env.scope());
+ *result = transmute::<v8::Local<v8::Value>, napi_value>(object.into());
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_create_promise(
+ env: *mut Env,
+ deferred: *mut napi_deferred,
+ promise_out: *mut napi_value,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+ let resolver = v8::PromiseResolver::new(&mut env.scope()).unwrap();
+ let mut global = v8::Global::new(&mut env.scope(), resolver);
+ let mut global_ptr = global.into_raw();
+ let promise = resolver.get_promise(&mut env.scope());
+ *deferred = global_ptr.as_mut() as *mut _ as napi_deferred;
+ *promise_out = transmute::<v8::Local<v8::Value>, napi_value>(promise.into());
+
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_create_range_error(
+ env: *mut Env,
+ _code: napi_value,
+ msg: napi_value,
+ result: *mut napi_value,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+
+ // let code = transmute::<napi_value, v8::Local<v8::Value>>(code);
+ let msg = transmute::<napi_value, v8::Local<v8::Value>>(msg);
+
+ let msg = msg.to_string(&mut env.scope()).unwrap();
+
+ let error = v8::Exception::range_error(&mut env.scope(), msg);
+ *result = transmute::<v8::Local<v8::Value>, napi_value>(error);
+
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_create_reference(
+ env: *mut Env,
+ value: napi_value,
+ _initial_refcount: u32,
+ result: *mut napi_ref,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+
+ let value = transmute::<napi_value, v8::Local<v8::Value>>(value);
+ let global = v8::Global::new(&mut env.scope(), value);
+ let mut global_ptr = global.into_raw();
+ *result = transmute::<NonNull<v8::Value>, napi_ref>(global_ptr);
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_create_string_latin1(
+ env: *mut Env,
+ string: *const u8,
+ length: isize,
+ result: *mut napi_value,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+
+ let string = if length == -1 {
+ std::ffi::CStr::from_ptr(string as *const _)
+ .to_str()
+ .unwrap()
+ .as_bytes()
+ } else {
+ std::slice::from_raw_parts(string, length as usize)
+ };
+ match v8::String::new_from_one_byte(
+ &mut env.scope(),
+ string,
+ v8::NewStringType::Normal,
+ ) {
+ Some(v8str) => {
+ let value: v8::Local<v8::Value> = v8str.into();
+ *result = transmute::<v8::Local<v8::Value>, napi_value>(value);
+ }
+ None => return Err(Error::GenericFailure),
+ }
+
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_create_string_utf16(
+ env: *mut Env,
+ string: *const u16,
+ length: usize,
+ result: *mut napi_value,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+ let string = std::slice::from_raw_parts(string, length);
+ let v8str = v8::String::new_from_two_byte(
+ &mut env.scope(),
+ string,
+ v8::NewStringType::Normal,
+ )
+ .unwrap();
+ let value: v8::Local<v8::Value> = v8str.into();
+ *result = transmute::<v8::Local<v8::Value>, napi_value>(value);
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_create_string_utf8(
+ env: *mut Env,
+ string: *const u8,
+ length: isize,
+ result: *mut napi_value,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+
+ let string = if length == -1 {
+ std::ffi::CStr::from_ptr(string as *const _)
+ .to_str()
+ .unwrap()
+ } else {
+ let string = std::slice::from_raw_parts(string, length as usize);
+ std::str::from_utf8(string).unwrap()
+ };
+ let v8str = v8::String::new(&mut env.scope(), string).unwrap();
+ let value: v8::Local<v8::Value> = v8str.into();
+ *result = transmute::<v8::Local<v8::Value>, napi_value>(value);
+
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_create_symbol(
+ env: *mut Env,
+ description: napi_value,
+ result: *mut napi_value,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+ let description = match description.is_null() {
+ true => None,
+ false => Some(
+ transmute::<napi_value, v8::Local<v8::Value>>(description)
+ .to_string(&mut env.scope())
+ .unwrap(),
+ ),
+ };
+ let sym = v8::Symbol::new(&mut env.scope(), description);
+ *result = transmute::<v8::Local<v8::Value>, napi_value>(sym.into());
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_create_type_error(
+ env: *mut Env,
+ _code: napi_value,
+ msg: napi_value,
+ result: *mut napi_value,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+
+ // let code = transmute::<napi_value, v8::Local<v8::Value>>(code);
+ let msg = transmute::<napi_value, v8::Local<v8::Value>>(msg);
+
+ let msg = msg.to_string(&mut env.scope()).unwrap();
+
+ let error = v8::Exception::type_error(&mut env.scope(), msg);
+ *result = transmute::<v8::Local<v8::Value>, napi_value>(error);
+
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_create_typedarray(
+ env: *mut Env,
+ ty: napi_typedarray_type,
+ length: usize,
+ arraybuffer: napi_value,
+ byte_offset: usize,
+ result: *mut napi_value,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+ let ab = transmute::<napi_value, v8::Local<v8::Value>>(arraybuffer);
+ let ab = v8::Local::<v8::ArrayBuffer>::try_from(ab).unwrap();
+ let typedarray: v8::Local<v8::Value> = match ty {
+ napi_uint8_array => {
+ v8::Uint8Array::new(&mut env.scope(), ab, byte_offset, length)
+ .unwrap()
+ .into()
+ }
+ napi_uint8_clamped_array => {
+ v8::Uint8ClampedArray::new(&mut env.scope(), ab, byte_offset, length)
+ .unwrap()
+ .into()
+ }
+ napi_int8_array => {
+ v8::Int8Array::new(&mut env.scope(), ab, byte_offset, length)
+ .unwrap()
+ .into()
+ }
+ napi_uint16_array => {
+ v8::Uint16Array::new(&mut env.scope(), ab, byte_offset, length)
+ .unwrap()
+ .into()
+ }
+ napi_int16_array => {
+ v8::Int16Array::new(&mut env.scope(), ab, byte_offset, length)
+ .unwrap()
+ .into()
+ }
+ napi_uint32_array => {
+ v8::Uint32Array::new(&mut env.scope(), ab, byte_offset, length)
+ .unwrap()
+ .into()
+ }
+ napi_int32_array => {
+ v8::Int32Array::new(&mut env.scope(), ab, byte_offset, length)
+ .unwrap()
+ .into()
+ }
+ napi_float32_array => {
+ v8::Float32Array::new(&mut env.scope(), ab, byte_offset, length)
+ .unwrap()
+ .into()
+ }
+ napi_float64_array => {
+ v8::Float64Array::new(&mut env.scope(), ab, byte_offset, length)
+ .unwrap()
+ .into()
+ }
+ napi_bigint64_array => {
+ v8::BigInt64Array::new(&mut env.scope(), ab, byte_offset, length)
+ .unwrap()
+ .into()
+ }
+ napi_biguint64_array => {
+ v8::BigUint64Array::new(&mut env.scope(), ab, byte_offset, length)
+ .unwrap()
+ .into()
+ }
+ _ => {
+ return Err(Error::InvalidArg);
+ }
+ };
+ *result = transmute::<v8::Local<v8::Value>, napi_value>(typedarray);
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_create_uint32(
+ env: *mut Env,
+ value: u32,
+ result: *mut napi_value,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+ let value: v8::Local<v8::Value> =
+ v8::Number::new(&mut env.scope(), value as f64).into();
+ *result = transmute::<v8::Local<v8::Value>, napi_value>(value);
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_make_callback(
+ env: *mut Env,
+ async_context: *mut c_void,
+ recv: napi_value,
+ func: napi_value,
+ argc: isize,
+ argv: *const napi_value,
+ result: *mut napi_value,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+ check_arg!(recv);
+ if argc > 0 {
+ check_arg!(argv);
+ }
+
+ if !async_context.is_null() {
+ eprintln!("napi_make_callback: async_context is not supported");
+ }
+
+ let recv = transmute::<napi_value, v8::Local<v8::Value>>(recv);
+ let func = transmute::<napi_value, v8::Local<v8::Value>>(func);
+
+ let func = v8::Local::<v8::Function>::try_from(func)
+ .map_err(|_| Error::FunctionExpected)?;
+ let argv: &[v8::Local<v8::Value>] =
+ transmute(std::slice::from_raw_parts(argv, argc as usize));
+ let ret = func.call(&mut env.scope(), recv, argv);
+ *result = transmute::<Option<v8::Local<v8::Value>>, napi_value>(ret);
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_get_value_bigint_int64(
+ env: *mut Env,
+ value: napi_value,
+ result: *mut i64,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+ let value = transmute::<napi_value, v8::Local<v8::Value>>(value);
+ let bigint = value.to_big_int(&mut env.scope()).unwrap();
+ *result = bigint.i64_value().0;
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_get_value_bigint_uint64(
+ env: *mut Env,
+ value: napi_value,
+ result: *mut u64,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+ let value = transmute::<napi_value, v8::Local<v8::Value>>(value);
+ let bigint = value.to_big_int(&mut env.scope()).unwrap();
+ *result = bigint.u64_value().0;
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_get_value_bigint_words(
+ env: *mut Env,
+ value: napi_value,
+ sign_bit: *mut i32,
+ size: *mut usize,
+ out_words: *mut u64,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+
+ let value = transmute::<napi_value, v8::Local<v8::Value>>(value);
+ let bigint = value.to_big_int(&mut env.scope()).unwrap();
+
+ let out_words = std::slice::from_raw_parts_mut(out_words, *size);
+ let mut words = Vec::with_capacity(bigint.word_count());
+ let (sign, _) = bigint.to_words_array(words.as_mut_slice());
+ *sign_bit = sign as i32;
+
+ for (i, word) in out_words.iter_mut().enumerate() {
+ *word = words[i];
+ }
+
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_get_value_bool(
+ env: *mut Env,
+ value: napi_value,
+ result: *mut bool,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+ let value = transmute::<napi_value, v8::Local<v8::Value>>(value);
+ *result = value.boolean_value(&mut env.scope());
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_get_value_double(
+ env: *mut Env,
+ value: napi_value,
+ result: *mut f64,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+ let value = transmute::<napi_value, v8::Local<v8::Value>>(value);
+ *result = value.number_value(&mut env.scope()).unwrap();
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_get_value_external(
+ _env: *mut Env,
+ value: napi_value,
+ result: *mut *mut c_void,
+) -> Result {
+ let value = transmute::<napi_value, v8::Local<v8::Value>>(value);
+ let ext = v8::Local::<v8::External>::try_from(value).unwrap();
+ *result = ext.value();
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_get_value_int32(
+ env: *mut Env,
+ value: napi_value,
+ result: *mut i32,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+ let value = transmute::<napi_value, v8::Local<v8::Value>>(value);
+ *result = value.int32_value(&mut env.scope()).unwrap();
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_get_value_int64(
+ env: *mut Env,
+ value: napi_value,
+ result: *mut i64,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+ let value = transmute::<napi_value, v8::Local<v8::Value>>(value);
+ *result = value.integer_value(&mut env.scope()).unwrap();
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_get_value_string_latin1(
+ env: *mut Env,
+ value: napi_value,
+ buf: *mut u8,
+ bufsize: usize,
+ result: *mut usize,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+
+ let value = transmute::<napi_value, v8::Local<v8::Value>>(value);
+
+ if !value.is_string() && !value.is_string_object() {
+ return Err(Error::StringExpected);
+ }
+
+ let v8str = value.to_string(&mut env.scope()).unwrap();
+ let string_len = v8str.utf8_length(&mut env.scope());
+
+ if buf.is_null() {
+ *result = string_len;
+ } else if bufsize != 0 {
+ let buffer = std::slice::from_raw_parts_mut(buf, bufsize - 1);
+ let copied = v8str.write_one_byte(
+ &mut env.scope(),
+ buffer,
+ 0,
+ v8::WriteOptions::NO_NULL_TERMINATION,
+ );
+ buf.add(copied).write(0);
+ if !result.is_null() {
+ *result = copied;
+ }
+ } else if !result.is_null() {
+ *result = string_len;
+ }
+
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_get_value_string_utf8(
+ env: *mut Env,
+ value: napi_value,
+ buf: *mut u8,
+ bufsize: usize,
+ result: *mut usize,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+
+ let value = transmute::<napi_value, v8::Local<v8::Value>>(value);
+
+ if !value.is_string() && !value.is_string_object() {
+ return Err(Error::StringExpected);
+ }
+
+ let v8str = value.to_string(&mut env.scope()).unwrap();
+ let string_len = v8str.utf8_length(&mut env.scope());
+
+ if buf.is_null() {
+ *result = string_len;
+ } else if bufsize != 0 {
+ let buffer = std::slice::from_raw_parts_mut(buf, bufsize - 1);
+ let copied = v8str.write_utf8(
+ &mut env.scope(),
+ buffer,
+ None,
+ v8::WriteOptions::NO_NULL_TERMINATION
+ | v8::WriteOptions::REPLACE_INVALID_UTF8,
+ );
+ buf.add(copied).write(0);
+ if !result.is_null() {
+ *result = copied;
+ }
+ } else if !result.is_null() {
+ *result = string_len;
+ }
+
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_get_value_string_utf16(
+ env: *mut Env,
+ value: napi_value,
+ buf: *mut u16,
+ bufsize: usize,
+ result: *mut usize,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+
+ let value = transmute::<napi_value, v8::Local<v8::Value>>(value);
+
+ if !value.is_string() && !value.is_string_object() {
+ return Err(Error::StringExpected);
+ }
+
+ let v8str = value.to_string(&mut env.scope()).unwrap();
+ let string_len = v8str.length();
+
+ if buf.is_null() {
+ *result = string_len;
+ } else if bufsize != 0 {
+ let buffer = std::slice::from_raw_parts_mut(buf, bufsize - 1);
+ let copied = v8str.write(
+ &mut env.scope(),
+ buffer,
+ 0,
+ v8::WriteOptions::NO_NULL_TERMINATION,
+ );
+ buf.add(copied).write(0);
+ if !result.is_null() {
+ *result = copied;
+ }
+ } else if !result.is_null() {
+ *result = string_len;
+ }
+
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_get_value_uint32(
+ env: *mut Env,
+ value: napi_value,
+ result: *mut u32,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+ let value = transmute::<napi_value, v8::Local<v8::Value>>(value);
+ *result = value.uint32_value(&mut env.scope()).unwrap();
+ Ok(())
+}
+
+// TODO
+#[napi_sym::napi_sym]
+fn napi_add_finalizer(
+ _env: *mut Env,
+ _js_object: napi_value,
+ _native_object: *const c_void,
+ _finalize_cb: napi_finalize,
+ _finalize_hint: *const c_void,
+ _result: *mut napi_ref,
+) -> Result {
+ eprintln!("napi_add_finalizer is not yet supported.");
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_adjust_external_memory(
+ env: *mut Env,
+ change_in_bytes: i64,
+ adjusted_value: &mut i64,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+ let isolate = &mut *env.isolate_ptr;
+ *adjusted_value =
+ isolate.adjust_amount_of_external_allocated_memory(change_in_bytes);
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_call_function(
+ env: *mut Env,
+ recv: napi_value,
+ func: napi_value,
+ argc: usize,
+ argv: *const napi_value,
+ result: *mut napi_value,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+ let recv = transmute::<napi_value, v8::Local<v8::Value>>(recv);
+ let func = transmute::<napi_value, v8::Local<v8::Value>>(func);
+ let func = v8::Local::<v8::Function>::try_from(func)
+ .map_err(|_| Error::FunctionExpected)?;
+
+ let argv: &[v8::Local<v8::Value>] =
+ transmute(std::slice::from_raw_parts(argv, argc as usize));
+ let ret = func.call(&mut env.scope(), recv, argv);
+ if !result.is_null() {
+ *result = transmute::<Option<v8::Local<v8::Value>>, napi_value>(ret);
+ }
+
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_close_escapable_handle_scope(
+ env: *mut Env,
+ _scope: napi_escapable_handle_scope,
+) -> Result {
+ let mut _env = &mut *(env as *mut Env);
+ // TODO: do this properly
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_close_handle_scope(env: *mut Env, scope: napi_handle_scope) -> Result {
+ let env = &mut *(env as *mut Env);
+ if env.open_handle_scopes == 0 {
+ return Err(Error::HandleScopeMismatch);
+ }
+ let _scope = &mut *(scope as *mut v8::HandleScope);
+ env.open_handle_scopes -= 1;
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_define_class(
+ env_ptr: *mut Env,
+ name: *const c_char,
+ length: isize,
+ constructor: napi_callback,
+ callback_data: *mut c_void,
+ property_count: usize,
+ properties: *const napi_property_descriptor,
+ result: *mut napi_value,
+) -> Result {
+ let env: &mut Env = env_ptr.as_mut().ok_or(Error::InvalidArg)?;
+ check_arg!(result);
+ // check_arg!(constructor as *const c_void);
+
+ if property_count > 0 {
+ check_arg!(properties);
+ }
+
+ let name = if length == -1 {
+ std::ffi::CStr::from_ptr(name)
+ .to_str()
+ .map_err(|_| Error::InvalidArg)?
+ } else {
+ let slice = std::slice::from_raw_parts(name as *const u8, length as usize);
+ std::str::from_utf8(slice).unwrap()
+ };
+
+ let tpl =
+ create_function_template(env_ptr, Some(name), constructor, callback_data);
+
+ let scope = &mut env.scope();
+ let napi_properties: &[napi_property_descriptor] =
+ std::slice::from_raw_parts(properties, property_count);
+
+ for p in napi_properties {
+ let name = if !p.utf8name.is_null() {
+ let name_str = CStr::from_ptr(p.utf8name).to_str().unwrap();
+ v8::String::new(scope, name_str).unwrap()
+ } else {
+ transmute::<napi_value, v8::Local<v8::String>>(p.name)
+ };
+
+ let method = p.method;
+ let getter = p.getter;
+ let setter = p.setter;
+
+ if getter.is_some() || setter.is_some() {
+ let getter: Option<v8::Local<v8::FunctionTemplate>> = if getter.is_some()
+ {
+ Some(create_function_template(env_ptr, None, p.getter, p.data))
+ } else {
+ None
+ };
+ let setter: Option<v8::Local<v8::FunctionTemplate>> = if setter.is_some()
+ {
+ Some(create_function_template(env_ptr, None, p.setter, p.data))
+ } else {
+ None
+ };
+
+ let mut accessor_property = v8::NONE;
+ if getter.is_some()
+ && setter.is_some()
+ && (p.attributes & napi_writable) == 0
+ {
+ accessor_property = accessor_property | v8::READ_ONLY;
+ }
+ if p.attributes & napi_enumerable == 0 {
+ accessor_property = accessor_property | v8::DONT_ENUM;
+ }
+ if p.attributes & napi_configurable == 0 {
+ accessor_property = accessor_property | v8::DONT_DELETE;
+ }
+
+ let proto = tpl.prototype_template(scope);
+ proto.set_accessor_property(
+ name.into(),
+ getter,
+ setter,
+ accessor_property,
+ );
+
+ // // TODO: use set_accessor & set_accessor_with_setter
+ // match (getter, setter) {
+ // (Some(getter), None) => {
+ // proto.set(name.into(), getter.into());
+ // }
+ // (Some(getter), Some(setter)) => {
+ // proto.set(name.into(), getter.into());
+ // proto.set(name.into(), setter.into());
+ // }
+ // (None, Some(setter)) => {
+ // proto.set(name.into(), setter.into());
+ // }
+ // (None, None) => unreachable!(),
+ // }
+ } else if method.is_some() {
+ let function = create_function_template(env_ptr, None, p.method, p.data);
+ let proto = tpl.prototype_template(scope);
+ proto.set(name.into(), function.into());
+ } else {
+ let proto = tpl.prototype_template(scope);
+ proto.set(
+ name.into(),
+ transmute::<napi_value, v8::Local<v8::Data>>(p.value),
+ );
+ }
+ }
+
+ let value: v8::Local<v8::Value> = tpl.get_function(scope).unwrap().into();
+ *result = transmute::<v8::Local<v8::Value>, napi_value>(value);
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_define_properties(
+ env_ptr: *mut Env,
+ obj: napi_value,
+ property_count: usize,
+ properties: *const napi_property_descriptor,
+) -> Result {
+ let env: &mut Env = env_ptr.as_mut().ok_or(Error::InvalidArg)?;
+ let scope = &mut env.scope();
+ let object = transmute::<napi_value, v8::Local<v8::Object>>(obj);
+ let properties = std::slice::from_raw_parts(properties, property_count);
+
+ for property in properties {
+ let name = if !property.utf8name.is_null() {
+ let name_str = CStr::from_ptr(property.utf8name).to_str().unwrap();
+ v8::String::new(scope, name_str).unwrap()
+ } else {
+ transmute::<napi_value, v8::Local<v8::String>>(property.name)
+ };
+
+ let method_ptr = property.method;
+
+ if method_ptr.is_some() {
+ let function: v8::Local<v8::Value> = {
+ let function =
+ create_function(env_ptr, None, property.method, property.data);
+ function.into()
+ };
+ object.set(scope, name.into(), function).unwrap();
+ }
+ }
+
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_delete_element(
+ env: *mut Env,
+ value: napi_value,
+ index: u32,
+ result: *mut bool,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+ let value = transmute::<napi_value, v8::Local<v8::Value>>(value);
+ let obj = value.to_object(&mut env.scope()).unwrap();
+ *result = obj.delete_index(&mut env.scope(), index).unwrap_or(false);
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_delete_property(
+ env: *mut Env,
+ value: napi_value,
+ key: napi_value,
+ result: *mut bool,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+ let value = transmute::<napi_value, v8::Local<v8::Value>>(value);
+ let obj = value.to_object(&mut env.scope()).unwrap();
+ *result = obj
+ .delete(
+ &mut env.scope(),
+ transmute::<napi_value, v8::Local<v8::Value>>(key),
+ )
+ .unwrap_or(false);
+ Ok(())
+}
+
+// TODO: properly implement ref counting stuff
+#[napi_sym::napi_sym]
+fn napi_delete_reference(env: *mut Env, _nref: napi_ref) -> Result {
+ let mut _env = &mut *(env as *mut Env);
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_detach_arraybuffer(_env: *mut Env, value: napi_value) -> Result {
+ let value = transmute::<napi_value, v8::Local<v8::Value>>(value);
+ let ab = v8::Local::<v8::ArrayBuffer>::try_from(value).unwrap();
+ ab.detach();
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_escape_handle(
+ _env: *mut Env,
+ _handle_scope: napi_escapable_handle_scope,
+ escapee: napi_value,
+ result: *mut napi_value,
+) -> Result {
+ // TODO
+ *result = escapee;
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_get_all_property_names(_env: *mut Env) -> Result {
+ // TODO
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_get_and_clear_last_exception(
+ env: *mut Env,
+ result: *mut napi_value,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+ // TODO: just return undefined for now we don't cache
+ // exceptions in env.
+ let value: v8::Local<v8::Value> = v8::undefined(&mut env.scope()).into();
+ *result = transmute::<v8::Local<v8::Value>, napi_value>(value);
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_get_array_length(
+ _env: *mut Env,
+ value: napi_value,
+ result: *mut u32,
+) -> Result {
+ let value = transmute::<napi_value, v8::Local<v8::Value>>(value);
+ *result = v8::Local::<v8::Array>::try_from(value).unwrap().length();
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_get_arraybuffer_info(
+ _env: *mut Env,
+ value: napi_value,
+ data: *mut *mut u8,
+ length: *mut usize,
+) -> Result {
+ let value = transmute::<napi_value, v8::Local<v8::Value>>(value);
+ let buf = v8::Local::<v8::ArrayBuffer>::try_from(value).unwrap();
+ if !data.is_null() {
+ *data = get_array_buffer_ptr(buf);
+ }
+ *length = buf.byte_length();
+ Ok(())
+}
+
+#[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)?;
+ let value: v8::Local<v8::Value> =
+ v8::Boolean::new(&mut env.scope(), value).into();
+ *result = transmute::<v8::Local<v8::Value>, napi_value>(value);
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_get_buffer_info(
+ env: *mut Env,
+ value: napi_value,
+ data: *mut *mut u8,
+ length: *mut usize,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+ let value = transmute::<napi_value, v8::Local<v8::Value>>(value);
+ let buf = v8::Local::<v8::Uint8Array>::try_from(value).unwrap();
+ let buffer_name = v8::String::new(&mut env.scope(), "buffer").unwrap();
+ let abuf = v8::Local::<v8::ArrayBuffer>::try_from(
+ buf.get(&mut env.scope(), buffer_name.into()).unwrap(),
+ )
+ .unwrap();
+ if !data.is_null() {
+ *data = get_array_buffer_ptr(abuf);
+ }
+ *length = abuf.byte_length();
+ Ok(())
+}
+
+#[napi_sym::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,
+ cb_data: *mut *mut c_void,
+) -> Result {
+ let cbinfo: &CallbackInfo = &*(cbinfo as *const CallbackInfo);
+ let args = &*(cbinfo.args as *const v8::FunctionCallbackArguments);
+
+ if !cb_data.is_null() {
+ *cb_data = cbinfo.cb_info;
+ }
+
+ if !this_arg.is_null() {
+ let mut this = args.this();
+ *this_arg = transmute::<v8::Local<v8::Value>, napi_value>(this.into());
+ }
+
+ let len = args.length();
+ let mut v_argc = len;
+ if !argc.is_null() {
+ *argc = len;
+ }
+
+ if !argv.is_null() {
+ let mut v_argv = std::slice::from_raw_parts_mut(argv, v_argc as usize);
+ for i in 0..v_argc {
+ let mut arg = args.get(i);
+ v_argv[i as usize] = transmute::<v8::Local<v8::Value>, napi_value>(arg);
+ }
+ }
+
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_get_dataview_info(
+ env: *mut Env,
+ value: napi_value,
+ data: *mut *mut u8,
+ length: *mut usize,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+ let value = transmute::<napi_value, v8::Local<v8::Value>>(value);
+ let buf = v8::Local::<v8::DataView>::try_from(value).unwrap();
+ let buffer_name = v8::String::new(&mut env.scope(), "buffer").unwrap();
+ let abuf = v8::Local::<v8::ArrayBuffer>::try_from(
+ buf.get(&mut env.scope(), buffer_name.into()).unwrap(),
+ )
+ .unwrap();
+ if !data.is_null() {
+ *data = get_array_buffer_ptr(abuf);
+ }
+ *length = abuf.byte_length();
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_get_date_value(
+ env: *mut Env,
+ value: napi_value,
+ result: *mut f64,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+ let value = transmute::<napi_value, v8::Local<v8::Value>>(value);
+ let date = v8::Local::<v8::Date>::try_from(value).unwrap();
+ *result = date.number_value(&mut env.scope()).unwrap();
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_get_element(
+ env: *mut Env,
+ object: napi_value,
+ index: u32,
+ result: *mut napi_value,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+ let object = transmute::<napi_value, v8::Local<v8::Value>>(object);
+ let array = v8::Local::<v8::Array>::try_from(object).unwrap();
+ let value: v8::Local<v8::Value> =
+ array.get_index(&mut env.scope(), index).unwrap();
+ *result = transmute::<v8::Local<v8::Value>, napi_value>(value);
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_get_global(env: *mut Env, result: *mut napi_value) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+
+ let context = &mut env.scope().get_current_context();
+ let global = context.global(&mut env.scope());
+ let value: v8::Local<v8::Value> = global.into();
+ *result = transmute::<v8::Local<v8::Value>, napi_value>(value);
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_get_instance_data(env: *mut Env, result: *mut *mut c_void) -> Result {
+ let env = &mut *(env as *mut Env);
+ let shared = env.shared();
+ *result = shared.instance_data;
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_get_last_error_info(
+ _env: *mut Env,
+ error_code: *mut *const napi_extended_error_info,
+) -> Result {
+ let err_info = Box::new(napi_extended_error_info {
+ error_message: std::ptr::null(),
+ engine_reserved: std::ptr::null_mut(),
+ engine_error_code: 0,
+ status_code: napi_ok,
+ });
+
+ *error_code = Box::into_raw(err_info);
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_get_named_property(
+ env: *mut Env,
+ object: napi_value,
+ utf8_name: *const c_char,
+ result: *mut napi_value,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+ let object = transmute::<napi_value, v8::Local<v8::Value>>(object);
+ let utf8_name = std::ffi::CStr::from_ptr(utf8_name);
+ let name =
+ v8::String::new(&mut env.scope(), &utf8_name.to_string_lossy()).unwrap();
+ let value: v8::Local<v8::Value> = object
+ .to_object(&mut env.scope())
+ .unwrap()
+ .get(&mut env.scope(), name.into())
+ .unwrap();
+ *result = transmute::<v8::Local<v8::Value>, napi_value>(value);
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_get_new_target(
+ _env: &mut Env,
+ cbinfo: &CallbackInfo,
+ result: &mut v8::Local<v8::Value>,
+) -> Result {
+ let info = &*(cbinfo.args as *const v8::FunctionCallbackArguments);
+ *result = info.new_target();
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_get_null(env: *mut Env, result: *mut napi_value) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+
+ let value: v8::Local<v8::Value> = v8::null(&mut env.scope()).into();
+ *result = transmute::<v8::Local<v8::Value>, napi_value>(value);
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_get_property(
+ env: *mut Env,
+ object: napi_value,
+ key: napi_value,
+ result: *mut napi_value,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+ let object = transmute::<napi_value, v8::Local<v8::Object>>(object);
+ let key = transmute::<napi_value, v8::Local<v8::Value>>(key);
+ let value: v8::Local<v8::Value> = object.get(&mut env.scope(), key).unwrap();
+ *result = transmute::<v8::Local<v8::Value>, napi_value>(value);
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_get_property_names(
+ env: *mut Env,
+ object: napi_value,
+ result: *mut napi_value,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+ let object = transmute::<napi_value, v8::Local<v8::Value>>(object);
+ let array: v8::Local<v8::Array> = object
+ .to_object(&mut env.scope())
+ .unwrap()
+ .get_property_names(&mut env.scope(), Default::default())
+ .unwrap();
+ let value: v8::Local<v8::Value> = array.into();
+ *result = transmute::<v8::Local<v8::Value>, napi_value>(value);
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_get_prototype(
+ env: *mut Env,
+ value: napi_value,
+ result: *mut napi_value,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+ let value = transmute::<napi_value, v8::Local<v8::Value>>(value);
+ let obj = value.to_object(&mut env.scope()).unwrap();
+ let proto = obj.get_prototype(&mut env.scope()).unwrap();
+ *result = transmute::<v8::Local<v8::Value>, napi_value>(proto);
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_get_reference_value(
+ env: *mut Env,
+ reference: napi_ref,
+ result: *mut napi_value,
+) -> Result {
+ // TODO
+ let _env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+
+ let value = transmute::<napi_ref, v8::Local<v8::Value>>(reference);
+ *result = transmute::<v8::Local<v8::Value>, napi_value>(value);
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_get_typedarray_info(
+ env: *mut Env,
+ value: napi_value,
+ data: *mut *mut u8,
+ length: *mut usize,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+ let value = transmute::<napi_value, v8::Local<v8::Value>>(value);
+ let buf = v8::Local::<v8::TypedArray>::try_from(value).unwrap();
+ let buffer_name = v8::String::new(&mut env.scope(), "buffer").unwrap();
+ let abuf = v8::Local::<v8::ArrayBuffer>::try_from(
+ buf.get(&mut env.scope(), buffer_name.into()).unwrap(),
+ )
+ .unwrap();
+ if !data.is_null() {
+ *data = get_array_buffer_ptr(abuf);
+ }
+ *length = abuf.byte_length();
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_get_undefined(env: *mut Env, result: *mut napi_value) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+ let value: v8::Local<v8::Value> = v8::undefined(&mut env.scope()).into();
+ *result = transmute::<v8::Local<v8::Value>, napi_value>(value);
+ Ok(())
+}
+
+pub const NAPI_VERSION: u32 = 8;
+
+#[napi_sym::napi_sym]
+fn napi_get_version(_: napi_env, version: *mut u32) -> Result {
+ *version = NAPI_VERSION;
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_has_element(
+ env: *mut Env,
+ value: napi_value,
+ index: u32,
+ result: *mut bool,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+ let value = transmute::<napi_value, v8::Local<v8::Value>>(value);
+ let obj = value.to_object(&mut env.scope()).unwrap();
+ *result = obj.has_index(&mut env.scope(), index).unwrap_or(false);
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_has_named_property(
+ env: *mut Env,
+ value: napi_value,
+ key: *const c_char,
+ result: *mut bool,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+ let value = transmute::<napi_value, v8::Local<v8::Value>>(value);
+ let obj = value.to_object(&mut env.scope()).unwrap();
+ let key = CStr::from_ptr(key).to_str().unwrap();
+ let key = v8::String::new(&mut env.scope(), key).unwrap();
+ *result = obj.has(&mut env.scope(), key.into()).unwrap_or(false);
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_has_own_property(
+ env: *mut Env,
+ object: napi_value,
+ key: napi_value,
+ result: *mut bool,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+ let value = transmute::<napi_value, v8::Local<v8::Value>>(object);
+ let object = value.to_object(&mut env.scope()).unwrap();
+
+ let key = transmute::<napi_value, v8::Local<v8::Value>>(key);
+ if !key.is_name() {
+ return Err(Error::NameExpected);
+ }
+
+ let maybe = object
+ .has_own_property(
+ &mut env.scope(),
+ v8::Local::<v8::Name>::try_from(key).unwrap(),
+ )
+ .unwrap_or(false);
+
+ *result = maybe;
+ if !maybe {
+ return Err(Error::GenericFailure);
+ }
+
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_has_property(
+ env: *mut Env,
+ value: napi_value,
+ key: napi_value,
+ result: *mut bool,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+ let value = transmute::<napi_value, v8::Local<v8::Value>>(value);
+ let obj = value.to_object(&mut env.scope()).unwrap();
+ *result = obj
+ .has(
+ &mut env.scope(),
+ transmute::<napi_value, v8::Local<v8::Value>>(key),
+ )
+ .unwrap_or(false);
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_instanceof(
+ env: *mut Env,
+ value: napi_value,
+ constructor: napi_value,
+ result: *mut bool,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+ check_arg!(constructor);
+ check_arg!(value);
+
+ let value = transmute::<napi_value, v8::Local<v8::Value>>(value);
+ let constructor = transmute::<napi_value, v8::Local<v8::Value>>(constructor);
+ let ctor = constructor
+ .to_object(&mut env.scope())
+ .ok_or(Error::ObjectExpected)?;
+ if !ctor.is_function() {
+ return Err(Error::FunctionExpected);
+ }
+ let maybe = value.instance_of(&mut env.scope(), ctor);
+ match maybe {
+ Some(res) => {
+ *result = res;
+ Ok(())
+ }
+ None => Err(Error::GenericFailure),
+ }
+}
+
+#[napi_sym::napi_sym]
+fn napi_is_array(
+ _env: *mut Env,
+ value: napi_value,
+ result: *mut bool,
+) -> Result {
+ let value = transmute::<napi_value, v8::Local<v8::Value>>(value);
+ *result = value.is_array();
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_is_arraybuffer(
+ _env: *mut Env,
+ value: napi_value,
+ result: *mut bool,
+) -> Result {
+ let value = transmute::<napi_value, v8::Local<v8::Value>>(value);
+ *result = value.is_array_buffer();
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_is_buffer(
+ _env: *mut Env,
+ value: napi_value,
+ result: *mut bool,
+) -> Result {
+ let value = transmute::<napi_value, v8::Local<v8::Value>>(value);
+ // TODO: should we assume Buffer as Uint8Array in Deno?
+ // or use std/node polyfill?
+ *result = value.is_typed_array();
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_is_dataview(
+ _env: *mut Env,
+ value: napi_value,
+ result: *mut bool,
+) -> Result {
+ let value = transmute::<napi_value, v8::Local<v8::Value>>(value);
+ *result = value.is_data_view();
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_is_date(
+ _env: *mut Env,
+ value: napi_value,
+ result: *mut bool,
+) -> Result {
+ let value = transmute::<napi_value, v8::Local<v8::Value>>(value);
+ *result = value.is_date();
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_is_detached_arraybuffer(
+ _env: *mut Env,
+ value: napi_value,
+ result: *mut bool,
+) -> Result {
+ let value = transmute::<napi_value, v8::Local<v8::Value>>(value);
+ let _ab = v8::Local::<v8::ArrayBuffer>::try_from(value).unwrap();
+ // TODO: what is API for checking if ArrayBuffer is detached?
+ // there's only is_detachable I could find.
+ *result = false;
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_is_error(
+ _env: *mut Env,
+ value: napi_value,
+ result: *mut bool,
+) -> Result {
+ let value = transmute::<napi_value, v8::Local<v8::Value>>(value);
+ // TODO
+ *result = value.is_object();
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_is_exception_pending(env: *mut Env, result: *mut bool) -> Result {
+ let mut _env = &mut *(env as *mut Env);
+ // TODO
+ *result = false;
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_is_promise(
+ _env: *mut Env,
+ value: napi_value,
+ result: *mut bool,
+) -> Result {
+ let value = transmute::<napi_value, v8::Local<v8::Value>>(value);
+ *result = value.is_promise();
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_is_typedarray(
+ _env: *mut Env,
+ value: napi_value,
+ result: *mut bool,
+) -> Result {
+ let value = transmute::<napi_value, v8::Local<v8::Value>>(value);
+ *result = value.is_typed_array();
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_new_instance(
+ env: *mut Env,
+ constructor: napi_value,
+ argc: usize,
+ argv: *const napi_value,
+ result: *mut napi_value,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+ let constructor = transmute::<napi_value, v8::Local<v8::Value>>(constructor);
+ let constructor = v8::Local::<v8::Function>::try_from(constructor).unwrap();
+ let args: &[v8::Local<v8::Value>] =
+ transmute(std::slice::from_raw_parts(argv, argc));
+ let inst = constructor.new_instance(&mut env.scope(), args).unwrap();
+ let value: v8::Local<v8::Value> = inst.into();
+ *result = transmute::<v8::Local<v8::Value>, napi_value>(value);
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_object_freeze(env: &mut Env, object: v8::Local<v8::Value>) -> Result {
+ let object = object.to_object(&mut env.scope()).unwrap();
+ let maybe =
+ object.set_integrity_level(&mut env.scope(), v8::IntegrityLevel::Frozen);
+
+ match maybe {
+ Some(_) => Ok(()),
+ None => Err(Error::GenericFailure),
+ }
+}
+
+#[napi_sym::napi_sym]
+fn napi_object_seal(env: &mut Env, object: v8::Local<v8::Value>) -> Result {
+ let object = object.to_object(&mut env.scope()).unwrap();
+ let maybe =
+ object.set_integrity_level(&mut env.scope(), v8::IntegrityLevel::Sealed);
+
+ match maybe {
+ Some(_) => Ok(()),
+ None => Err(Error::GenericFailure),
+ }
+}
+
+#[napi_sym::napi_sym]
+fn napi_open_escapable_handle_scope(
+ _env: *mut Env,
+ _result: *mut napi_escapable_handle_scope,
+) -> Result {
+ // TODO: do this properly
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_open_handle_scope(
+ env: *mut Env,
+ _result: *mut napi_handle_scope,
+) -> Result {
+ let env = &mut *(env as *mut Env);
+
+ // *result = &mut env.scope() as *mut _ as napi_handle_scope;
+ env.open_handle_scopes += 1;
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_reference_ref() -> Result {
+ // TODO
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_reference_unref() -> Result {
+ // TODO
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_reject_deferred(
+ env: *mut Env,
+ deferred: napi_deferred,
+ error: napi_value,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+
+ let deferred_ptr =
+ NonNull::new_unchecked(deferred as *mut v8::PromiseResolver);
+ // TODO(@littledivy): Use Global::from_raw instead casting to local.
+ // SAFETY: Isolate is still alive unless the module is doing something weird,
+ // global data is the size of a pointer.
+ // Global pointer is obtained from napi_create_promise
+ let resolver = transmute::<
+ NonNull<v8::PromiseResolver>,
+ v8::Local<v8::PromiseResolver>,
+ >(deferred_ptr);
+ resolver
+ .reject(
+ &mut env.scope(),
+ transmute::<napi_value, v8::Local<v8::Value>>(error),
+ )
+ .unwrap();
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_remove_wrap(env: *mut Env, value: napi_value) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+ let value = transmute::<napi_value, v8::Local<v8::Value>>(value);
+ let obj = value.to_object(&mut env.scope()).unwrap();
+ let shared = &*(env.shared as *const EnvShared);
+ let napi_wrap = v8::Local::new(&mut env.scope(), &shared.napi_wrap);
+ obj.delete_private(&mut env.scope(), napi_wrap).unwrap();
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_resolve_deferred(
+ env: *mut Env,
+ deferred: napi_deferred,
+ result: napi_value,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+ let deferred_ptr =
+ NonNull::new_unchecked(deferred as *mut v8::PromiseResolver);
+ // TODO(@littledivy): Use Global::from_raw instead casting to local.
+ // SAFETY: Isolate is still alive unless the module is doing something weird,
+ // global data is the size of a pointer.
+ // Global pointer is obtained from napi_create_promise
+ let resolver = transmute::<
+ NonNull<v8::PromiseResolver>,
+ v8::Local<v8::PromiseResolver>,
+ >(deferred_ptr);
+ resolver
+ .resolve(
+ &mut env.scope(),
+ transmute::<napi_value, v8::Local<v8::Value>>(result),
+ )
+ .unwrap();
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_run_script(
+ env: *mut Env,
+ script: napi_value,
+ result: *mut napi_value,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+
+ let script = transmute::<napi_value, v8::Local<v8::Value>>(script);
+ if !script.is_string() {
+ return Err(Error::StringExpected);
+ }
+ let script = script.to_string(&mut env.scope()).unwrap();
+
+ let script = v8::Script::compile(&mut env.scope(), script, None);
+ if script.is_none() {
+ return Err(Error::GenericFailure);
+ }
+ let script = script.unwrap();
+ let rv = script.run(&mut env.scope());
+
+ if let Some(rv) = rv {
+ *result = transmute::<v8::Local<v8::Value>, napi_value>(rv);
+ } else {
+ return Err(Error::GenericFailure);
+ }
+
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_set_element(
+ env: *mut Env,
+ object: napi_value,
+ index: u32,
+ value: napi_value,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+ let object = transmute::<napi_value, v8::Local<v8::Value>>(object);
+ let array = v8::Local::<v8::Array>::try_from(object).unwrap();
+ let value = transmute::<napi_value, v8::Local<v8::Value>>(value);
+ array.set_index(&mut env.scope(), index, value).unwrap();
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_set_instance_data(
+ env: *mut Env,
+ data: *mut c_void,
+ finalize_cb: napi_finalize,
+ finalize_hint: *mut c_void,
+) -> Result {
+ let env = &mut *(env as *mut Env);
+ let shared = env.shared_mut();
+ shared.instance_data = data;
+ shared.data_finalize = if !(finalize_cb as *const c_void).is_null() {
+ Some(finalize_cb)
+ } else {
+ None
+ };
+ shared.data_finalize_hint = finalize_hint;
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_set_named_property(
+ env: *mut Env,
+ object: napi_value,
+ name: *const c_char,
+ value: napi_value,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+ let name = CStr::from_ptr(name).to_str().unwrap();
+ let object = transmute::<napi_value, v8::Local<v8::Object>>(object);
+ let value = transmute::<napi_value, v8::Local<v8::Value>>(value);
+ let name = v8::String::new(&mut env.scope(), name).unwrap();
+ object.set(&mut env.scope(), name.into(), value).unwrap();
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_set_property(
+ env: *mut Env,
+ object: napi_value,
+ property: napi_value,
+ value: napi_value,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+ let object = transmute::<napi_value, v8::Local<v8::Value>>(object);
+ let object = object.to_object(&mut env.scope()).unwrap();
+ let property = transmute::<napi_value, v8::Local<v8::Value>>(property);
+ let value = transmute::<napi_value, v8::Local<v8::Value>>(value);
+ object.set(&mut env.scope(), property, value).unwrap();
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_strict_equals(
+ _env: *mut Env,
+ lhs: napi_value,
+ rhs: napi_value,
+ result: *mut bool,
+) -> Result {
+ let lhs = transmute::<napi_value, v8::Local<v8::Value>>(lhs);
+ let rhs = transmute::<napi_value, v8::Local<v8::Value>>(rhs);
+ *result = lhs.strict_equals(rhs);
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_throw(env: *mut Env, error: napi_value) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+ let error = transmute::<napi_value, v8::Local<v8::Value>>(error);
+ env.scope().throw_exception(error);
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_throw_error(
+ env: *mut Env,
+ _code: *const c_char,
+ msg: *const c_char,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+
+ // let code = CStr::from_ptr(code).to_str().unwrap();
+ let msg = CStr::from_ptr(msg).to_str().unwrap();
+
+ // let code = v8::String::new(&mut env.scope(), code).unwrap();
+ let msg = v8::String::new(&mut env.scope(), msg).unwrap();
+
+ let error = v8::Exception::error(&mut env.scope(), msg);
+ env.scope().throw_exception(error);
+
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_throw_range_error(
+ env: *mut Env,
+ _code: *const c_char,
+ msg: *const c_char,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+
+ // let code = CStr::from_ptr(code).to_str().unwrap();
+ let msg = CStr::from_ptr(msg).to_str().unwrap();
+
+ // let code = v8::String::new(&mut env.scope(), code).unwrap();
+ let msg = v8::String::new(&mut env.scope(), msg).unwrap();
+
+ let error = v8::Exception::range_error(&mut env.scope(), msg);
+ env.scope().throw_exception(error);
+
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_throw_type_error(
+ env: *mut Env,
+ _code: *const c_char,
+ msg: *const c_char,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+
+ // let code = CStr::from_ptr(code).to_str().unwrap();
+ let msg = CStr::from_ptr(msg).to_str().unwrap();
+
+ // let code = v8::String::new(&mut env.scope(), code).unwrap();
+ let msg = v8::String::new(&mut env.scope(), msg).unwrap();
+
+ let error = v8::Exception::type_error(&mut env.scope(), msg);
+ env.scope().throw_exception(error);
+
+ Ok(())
+}
+
+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::napi_sym]
+fn napi_typeof(
+ _env: *mut Env,
+ value: napi_value,
+ result: *mut napi_valuetype,
+) -> Result {
+ if value.is_null() {
+ *result = napi_undefined;
+ return Ok(());
+ }
+ let value = transmute::<napi_value, v8::Local<v8::Value>>(value);
+ let ty = get_value_type(value);
+ if let Some(ty) = ty {
+ *result = ty;
+ Ok(())
+ } else {
+ Err(Error::InvalidArg)
+ }
+}
+
+#[napi_sym::napi_sym]
+fn napi_unwrap(
+ env: *mut Env,
+ value: napi_value,
+ result: *mut *mut c_void,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+ let value = transmute::<napi_value, v8::Local<v8::Value>>(value);
+ let obj = value.to_object(&mut env.scope()).unwrap();
+ let shared = &*(env.shared as *const EnvShared);
+ let napi_wrap = v8::Local::new(&mut env.scope(), &shared.napi_wrap);
+ let ext = obj.get_private(&mut env.scope(), napi_wrap).unwrap();
+ let ext = v8::Local::<v8::External>::try_from(ext).unwrap();
+ *result = ext.value();
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn napi_wrap(
+ env: *mut Env,
+ value: napi_value,
+ native_object: *mut c_void,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+ let value = transmute::<napi_value, v8::Local<v8::Value>>(value);
+ let obj = value.to_object(&mut env.scope()).unwrap();
+ let shared = &*(env.shared as *const EnvShared);
+ let napi_wrap = v8::Local::new(&mut env.scope(), &shared.napi_wrap);
+ let ext = v8::External::new(&mut env.scope(), native_object);
+ obj.set_private(&mut env.scope(), napi_wrap, ext.into());
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn node_api_throw_syntax_error(
+ env: *mut Env,
+ _code: *const c_char,
+ msg: *const c_char,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+
+ // let code = CStr::from_ptr(code).to_str().unwrap();
+ let msg = CStr::from_ptr(msg).to_str().unwrap();
+
+ // let code = v8::String::new(&mut env.scope(), code).unwrap();
+ let msg = v8::String::new(&mut env.scope(), msg).unwrap();
+
+ let error = v8::Exception::syntax_error(&mut env.scope(), msg);
+ env.scope().throw_exception(error);
+
+ Ok(())
+}
+
+#[napi_sym::napi_sym]
+fn node_api_create_syntax_error(
+ env: *mut Env,
+ _code: napi_value,
+ msg: napi_value,
+ result: *mut napi_value,
+) -> Result {
+ let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
+
+ // let code = transmute::<napi_value, v8::Local<v8::Value>>(code);
+ let msg = transmute::<napi_value, v8::Local<v8::Value>>(msg);
+
+ let msg = msg.to_string(&mut env.scope()).unwrap();
+
+ let error = v8::Exception::syntax_error(&mut env.scope(), msg);
+ *result = transmute::<v8::Local<v8::Value>, napi_value>(error);
+
+ Ok(())
+}