mirror of
https://github.com/denoland/deno.git
synced 2024-11-22 04:51:22 +00:00
fix: clean up some node-api details (#24178)
- fix a few napi_* types - clean up env hooks - implement blocking queue in tsfn - reduce transmutes - use new `DataView::new` api from rusty_v8
This commit is contained in:
parent
07437acc74
commit
3765e6b3a6
@ -179,14 +179,15 @@ fn napi_get_last_error_info(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[napi_sym]
|
#[napi_sym]
|
||||||
fn napi_create_function(
|
fn napi_create_function<'s>(
|
||||||
env: &mut Env,
|
env: &'s mut Env,
|
||||||
name: *const c_char,
|
name: *const c_char,
|
||||||
length: usize,
|
length: usize,
|
||||||
cb: napi_callback,
|
cb: Option<napi_callback>,
|
||||||
cb_info: napi_callback_info,
|
cb_info: napi_callback_info,
|
||||||
result: *mut napi_value,
|
result: *mut napi_value<'s>,
|
||||||
) -> napi_status {
|
) -> napi_status {
|
||||||
|
let env_ptr = env as *mut Env;
|
||||||
check_arg!(env, result);
|
check_arg!(env, result);
|
||||||
check_arg!(env, cb);
|
check_arg!(env, cb);
|
||||||
|
|
||||||
@ -200,7 +201,9 @@ fn napi_create_function(
|
|||||||
};
|
};
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
*result = create_function(env, name, cb, cb_info).into();
|
*result =
|
||||||
|
create_function(&mut env.scope(), env_ptr, name, cb.unwrap(), cb_info)
|
||||||
|
.into();
|
||||||
}
|
}
|
||||||
|
|
||||||
napi_ok
|
napi_ok
|
||||||
@ -212,12 +215,13 @@ fn napi_define_class<'s>(
|
|||||||
env: &'s mut Env,
|
env: &'s mut Env,
|
||||||
utf8name: *const c_char,
|
utf8name: *const c_char,
|
||||||
length: usize,
|
length: usize,
|
||||||
constructor: napi_callback,
|
constructor: Option<napi_callback>,
|
||||||
callback_data: *mut c_void,
|
callback_data: *mut c_void,
|
||||||
property_count: usize,
|
property_count: usize,
|
||||||
properties: *const napi_property_descriptor,
|
properties: *const napi_property_descriptor,
|
||||||
result: *mut napi_value<'s>,
|
result: *mut napi_value<'s>,
|
||||||
) -> napi_status {
|
) -> napi_status {
|
||||||
|
let env_ptr = env as *mut Env;
|
||||||
check_arg!(env, result);
|
check_arg!(env, result);
|
||||||
check_arg!(env, constructor);
|
check_arg!(env, constructor);
|
||||||
|
|
||||||
@ -230,9 +234,13 @@ fn napi_define_class<'s>(
|
|||||||
Err(status) => return status,
|
Err(status) => return status,
|
||||||
};
|
};
|
||||||
|
|
||||||
let tpl = unsafe {
|
let tpl = create_function_template(
|
||||||
create_function_template(env, Some(name), constructor, callback_data)
|
&mut env.scope(),
|
||||||
};
|
env_ptr,
|
||||||
|
Some(name),
|
||||||
|
constructor.unwrap(),
|
||||||
|
callback_data,
|
||||||
|
);
|
||||||
|
|
||||||
let napi_properties: &[napi_property_descriptor] = if property_count > 0 {
|
let napi_properties: &[napi_property_descriptor] = if property_count > 0 {
|
||||||
unsafe { std::slice::from_raw_parts(properties, property_count) }
|
unsafe { std::slice::from_raw_parts(properties, property_count) }
|
||||||
@ -248,28 +256,18 @@ fn napi_define_class<'s>(
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let name = match unsafe { v8_name_from_property_descriptor(env, p) } {
|
let name = match unsafe { v8_name_from_property_descriptor(env_ptr, p) } {
|
||||||
Ok(name) => name,
|
Ok(name) => name,
|
||||||
Err(status) => return status,
|
Err(status) => return status,
|
||||||
};
|
};
|
||||||
|
|
||||||
let method = p.method;
|
if p.getter.is_some() || p.setter.is_some() {
|
||||||
let getter = p.getter;
|
let getter = p.getter.map(|g| {
|
||||||
let setter = p.setter;
|
create_function_template(&mut env.scope(), env_ptr, None, g, p.data)
|
||||||
|
});
|
||||||
if getter.is_some() || setter.is_some() {
|
let setter = p.setter.map(|s| {
|
||||||
let getter: Option<v8::Local<v8::FunctionTemplate>> = if getter.is_some()
|
create_function_template(&mut env.scope(), env_ptr, None, s, p.data)
|
||||||
{
|
});
|
||||||
Some(unsafe { create_function_template(env, None, p.getter, p.data) })
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
let setter: Option<v8::Local<v8::FunctionTemplate>> = if setter.is_some()
|
|
||||||
{
|
|
||||||
Some(unsafe { create_function_template(env, None, p.setter, p.data) })
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut accessor_property = v8::PropertyAttribute::NONE;
|
let mut accessor_property = v8::PropertyAttribute::NONE;
|
||||||
if getter.is_some()
|
if getter.is_some()
|
||||||
@ -290,9 +288,14 @@ fn napi_define_class<'s>(
|
|||||||
|
|
||||||
let proto = tpl.prototype_template(&mut env.scope());
|
let proto = tpl.prototype_template(&mut env.scope());
|
||||||
proto.set_accessor_property(name, getter, setter, accessor_property);
|
proto.set_accessor_property(name, getter, setter, accessor_property);
|
||||||
} else if method.is_some() {
|
} else if let Some(method) = p.method {
|
||||||
let function =
|
let function = create_function_template(
|
||||||
unsafe { create_function_template(env, None, p.method, p.data) };
|
&mut env.scope(),
|
||||||
|
env_ptr,
|
||||||
|
None,
|
||||||
|
method,
|
||||||
|
p.data,
|
||||||
|
);
|
||||||
let proto = tpl.prototype_template(&mut env.scope());
|
let proto = tpl.prototype_template(&mut env.scope());
|
||||||
proto.set(name, function.into());
|
proto.set(name, function.into());
|
||||||
} else {
|
} else {
|
||||||
@ -301,7 +304,6 @@ fn napi_define_class<'s>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let env_ptr = env as *mut Env;
|
|
||||||
let value: v8::Local<v8::Value> =
|
let value: v8::Local<v8::Value> =
|
||||||
tpl.get_function(&mut env.scope()).unwrap().into();
|
tpl.get_function(&mut env.scope()).unwrap().into();
|
||||||
|
|
||||||
@ -781,17 +783,19 @@ fn napi_define_properties(
|
|||||||
let configurable = property.attributes & napi_configurable != 0;
|
let configurable = property.attributes & napi_configurable != 0;
|
||||||
|
|
||||||
if property.getter.is_some() || property.setter.is_some() {
|
if property.getter.is_some() || property.setter.is_some() {
|
||||||
let local_getter: v8::Local<v8::Value> = if property.getter.is_some() {
|
let local_getter: v8::Local<v8::Value> = if let Some(getter) =
|
||||||
unsafe {
|
property.getter
|
||||||
create_function(env_ptr, None, property.getter, property.data).into()
|
{
|
||||||
}
|
create_function(&mut env.scope(), env_ptr, None, getter, property.data)
|
||||||
|
.into()
|
||||||
} else {
|
} else {
|
||||||
v8::undefined(scope).into()
|
v8::undefined(scope).into()
|
||||||
};
|
};
|
||||||
let local_setter: v8::Local<v8::Value> = if property.setter.is_some() {
|
let local_setter: v8::Local<v8::Value> = if let Some(setter) =
|
||||||
unsafe {
|
property.setter
|
||||||
create_function(env_ptr, None, property.setter, property.data).into()
|
{
|
||||||
}
|
create_function(&mut env.scope(), env_ptr, None, setter, property.data)
|
||||||
|
.into()
|
||||||
} else {
|
} else {
|
||||||
v8::undefined(scope).into()
|
v8::undefined(scope).into()
|
||||||
};
|
};
|
||||||
@ -807,11 +811,15 @@ fn napi_define_properties(
|
|||||||
{
|
{
|
||||||
return napi_invalid_arg;
|
return napi_invalid_arg;
|
||||||
}
|
}
|
||||||
} else if property.method.is_some() {
|
} else if let Some(method) = property.method {
|
||||||
let method: v8::Local<v8::Value> = {
|
let method: v8::Local<v8::Value> = {
|
||||||
let function = unsafe {
|
let function = create_function(
|
||||||
create_function(env_ptr, None, property.method, property.data)
|
&mut env.scope(),
|
||||||
};
|
env_ptr,
|
||||||
|
None,
|
||||||
|
method,
|
||||||
|
property.data,
|
||||||
|
);
|
||||||
function.into()
|
function.into()
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1692,18 +1700,16 @@ fn napi_call_function(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[napi_sym]
|
#[napi_sym]
|
||||||
fn napi_get_global(env: *mut Env, result: *mut napi_value) -> napi_status {
|
fn napi_get_global(env_ptr: *mut Env, result: *mut napi_value) -> napi_status {
|
||||||
let env = check_env!(env);
|
let env = check_env!(env_ptr);
|
||||||
check_arg!(env, result);
|
check_arg!(env, result);
|
||||||
|
|
||||||
|
let global = v8::Local::new(&mut env.scope(), &env.global);
|
||||||
unsafe {
|
unsafe {
|
||||||
*result = std::mem::transmute::<NonNull<v8::Value>, v8::Local<v8::Value>>(
|
*result = global.into();
|
||||||
env.global,
|
|
||||||
)
|
|
||||||
.into();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return napi_clear_last_error(env);
|
return napi_clear_last_error(env_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[napi_sym]
|
#[napi_sym]
|
||||||
@ -2869,7 +2875,7 @@ fn napi_create_arraybuffer<'s>(
|
|||||||
|
|
||||||
if !data.is_null() {
|
if !data.is_null() {
|
||||||
unsafe {
|
unsafe {
|
||||||
*data = get_array_buffer_ptr(buffer) as _;
|
*data = get_array_buffer_ptr(buffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2915,7 +2921,7 @@ fn napi_create_external_arraybuffer<'s>(
|
|||||||
fn napi_get_arraybuffer_info(
|
fn napi_get_arraybuffer_info(
|
||||||
env: *mut Env,
|
env: *mut Env,
|
||||||
value: napi_value,
|
value: napi_value,
|
||||||
data: *mut *mut u8,
|
data: *mut *mut c_void,
|
||||||
length: *mut usize,
|
length: *mut usize,
|
||||||
) -> napi_status {
|
) -> napi_status {
|
||||||
let env = check_env!(env);
|
let env = check_env!(env);
|
||||||
@ -3121,7 +3127,7 @@ fn napi_get_typedarray_info(
|
|||||||
fn napi_create_dataview<'s>(
|
fn napi_create_dataview<'s>(
|
||||||
env: &'s mut Env,
|
env: &'s mut Env,
|
||||||
byte_length: usize,
|
byte_length: usize,
|
||||||
arraybuffer: napi_value,
|
arraybuffer: napi_value<'s>,
|
||||||
byte_offset: usize,
|
byte_offset: usize,
|
||||||
result: *mut napi_value<'s>,
|
result: *mut napi_value<'s>,
|
||||||
) -> napi_status {
|
) -> napi_status {
|
||||||
@ -3144,26 +3150,8 @@ fn napi_create_dataview<'s>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// let dataview = v8::DataView::new(&mut env, buffer, byte_offset, byte_length);
|
let dataview =
|
||||||
let dataview = {
|
v8::DataView::new(&mut env.scope(), buffer, byte_offset, byte_length);
|
||||||
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 Ok(data_view) = v8::Local::<v8::Function>::try_from(data_view) else {
|
|
||||||
return napi_function_expected;
|
|
||||||
};
|
|
||||||
let byte_offset = v8::Number::new(&mut env.scope(), byte_offset as f64);
|
|
||||||
let byte_length = v8::Number::new(&mut env.scope(), byte_length as f64);
|
|
||||||
let Some(dv) = data_view.new_instance(
|
|
||||||
&mut env.scope(),
|
|
||||||
&[buffer.into(), byte_offset.into(), byte_length.into()],
|
|
||||||
) else {
|
|
||||||
return napi_generic_failure;
|
|
||||||
};
|
|
||||||
dv
|
|
||||||
};
|
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
*result = dataview.into();
|
*result = dataview.into();
|
||||||
|
@ -9,10 +9,11 @@ use super::util::napi_set_last_error;
|
|||||||
use super::util::SendPtr;
|
use super::util::SendPtr;
|
||||||
use crate::check_arg;
|
use crate::check_arg;
|
||||||
use crate::check_env;
|
use crate::check_env;
|
||||||
|
use deno_core::parking_lot::Condvar;
|
||||||
|
use deno_core::parking_lot::Mutex;
|
||||||
use deno_core::V8CrossThreadTaskSpawner;
|
use deno_core::V8CrossThreadTaskSpawner;
|
||||||
use deno_runtime::deno_napi::*;
|
use deno_runtime::deno_napi::*;
|
||||||
use napi_sym::napi_sym;
|
use napi_sym::napi_sym;
|
||||||
use std::ptr::NonNull;
|
|
||||||
use std::sync::atomic::AtomicBool;
|
use std::sync::atomic::AtomicBool;
|
||||||
use std::sync::atomic::AtomicU8;
|
use std::sync::atomic::AtomicU8;
|
||||||
use std::sync::atomic::AtomicUsize;
|
use std::sync::atomic::AtomicUsize;
|
||||||
@ -40,14 +41,7 @@ fn napi_add_env_cleanup_hook(
|
|||||||
|
|
||||||
let fun = fun.unwrap();
|
let fun = fun.unwrap();
|
||||||
|
|
||||||
let mut env_cleanup_hooks = env.cleanup_hooks.borrow_mut();
|
env.add_cleanup_hook(fun, arg);
|
||||||
if env_cleanup_hooks
|
|
||||||
.iter()
|
|
||||||
.any(|pair| pair.0 == fun && pair.1 == arg)
|
|
||||||
{
|
|
||||||
panic!("Cleanup hook with this data already registered");
|
|
||||||
}
|
|
||||||
env_cleanup_hooks.push((fun, arg));
|
|
||||||
|
|
||||||
napi_ok
|
napi_ok
|
||||||
}
|
}
|
||||||
@ -63,27 +57,21 @@ fn napi_remove_env_cleanup_hook(
|
|||||||
|
|
||||||
let fun = fun.unwrap();
|
let fun = fun.unwrap();
|
||||||
|
|
||||||
let mut env_cleanup_hooks = env.cleanup_hooks.borrow_mut();
|
env.remove_cleanup_hook(fun, arg);
|
||||||
// Hooks are supposed to be removed in LIFO order
|
|
||||||
let maybe_index = env_cleanup_hooks
|
|
||||||
.iter()
|
|
||||||
.rposition(|&pair| pair.0 == fun && pair.1 == arg);
|
|
||||||
|
|
||||||
if let Some(index) = maybe_index {
|
|
||||||
env_cleanup_hooks.remove(index);
|
|
||||||
} else {
|
|
||||||
panic!("Cleanup hook with this data not found");
|
|
||||||
}
|
|
||||||
|
|
||||||
napi_ok
|
napi_ok
|
||||||
}
|
}
|
||||||
|
|
||||||
type AsyncCleanupHandle = (*mut Env, napi_async_cleanup_hook, *mut c_void);
|
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 extern "C" fn async_cleanup_handler(arg: *mut c_void) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let (env, hook, arg) = *Box::<AsyncCleanupHandle>::from_raw(arg as _);
|
let handle = Box::<AsyncCleanupHandle>::from_raw(arg as _);
|
||||||
hook(env as _, arg);
|
(handle.hook)(arg, handle.data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,12 +87,13 @@ fn napi_add_async_cleanup_hook(
|
|||||||
|
|
||||||
let hook = hook.unwrap();
|
let hook = hook.unwrap();
|
||||||
|
|
||||||
let handle =
|
let handle = Box::into_raw(Box::new(AsyncCleanupHandle {
|
||||||
Box::into_raw(Box::<AsyncCleanupHandle>::new((env, hook, arg))) as _;
|
env,
|
||||||
|
hook,
|
||||||
|
data: arg,
|
||||||
|
})) as *mut c_void;
|
||||||
|
|
||||||
unsafe {
|
env.add_cleanup_hook(async_cleanup_handler, handle);
|
||||||
napi_add_env_cleanup_hook(env, Some(async_cleanup_handler), handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
if !remove_handle.is_null() {
|
if !remove_handle.is_null() {
|
||||||
unsafe {
|
unsafe {
|
||||||
@ -123,17 +112,12 @@ fn napi_remove_async_cleanup_hook(
|
|||||||
return napi_invalid_arg;
|
return napi_invalid_arg;
|
||||||
}
|
}
|
||||||
|
|
||||||
let handle = unsafe { &*(remove_handle as *mut AsyncCleanupHandle) };
|
let handle =
|
||||||
|
unsafe { Box::<AsyncCleanupHandle>::from_raw(remove_handle as _) };
|
||||||
|
|
||||||
let env = unsafe { &mut *handle.0 };
|
let env = unsafe { &mut *handle.env };
|
||||||
|
|
||||||
unsafe {
|
env.remove_cleanup_hook(async_cleanup_handler, remove_handle);
|
||||||
napi_remove_env_cleanup_hook(
|
|
||||||
env,
|
|
||||||
Some(async_cleanup_handler),
|
|
||||||
remove_handle,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
napi_ok
|
napi_ok
|
||||||
}
|
}
|
||||||
@ -142,11 +126,7 @@ fn napi_remove_async_cleanup_hook(
|
|||||||
fn napi_fatal_exception(env: &mut Env, err: napi_value) -> napi_status {
|
fn napi_fatal_exception(env: &mut Env, err: napi_value) -> napi_status {
|
||||||
check_arg!(env, err);
|
check_arg!(env, err);
|
||||||
|
|
||||||
let report_error = unsafe {
|
let report_error = v8::Local::new(&mut env.scope(), &env.report_error);
|
||||||
std::mem::transmute::<NonNull<v8::Function>, v8::Local<v8::Function>>(
|
|
||||||
env.report_error,
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
let this = v8::undefined(&mut env.scope());
|
let this = v8::undefined(&mut env.scope());
|
||||||
if report_error
|
if report_error
|
||||||
@ -262,7 +242,7 @@ fn napi_make_callback<'s>(
|
|||||||
recv: napi_value,
|
recv: napi_value,
|
||||||
func: napi_value,
|
func: napi_value,
|
||||||
argc: usize,
|
argc: usize,
|
||||||
argv: *const napi_value,
|
argv: *const napi_value<'s>,
|
||||||
result: *mut napi_value<'s>,
|
result: *mut napi_value<'s>,
|
||||||
) -> napi_status {
|
) -> napi_status {
|
||||||
check_arg!(env, recv);
|
check_arg!(env, recv);
|
||||||
@ -312,11 +292,8 @@ fn napi_create_buffer<'s>(
|
|||||||
|
|
||||||
let ab = v8::ArrayBuffer::new(&mut env.scope(), length);
|
let ab = v8::ArrayBuffer::new(&mut env.scope(), length);
|
||||||
|
|
||||||
let buffer_constructor = unsafe {
|
let buffer_constructor =
|
||||||
std::mem::transmute::<NonNull<v8::Function>, v8::Local<v8::Function>>(
|
v8::Local::new(&mut env.scope(), &env.buffer_constructor);
|
||||||
env.buffer_constructor,
|
|
||||||
)
|
|
||||||
};
|
|
||||||
let Some(buffer) =
|
let Some(buffer) =
|
||||||
buffer_constructor.new_instance(&mut env.scope(), &[ab.into()])
|
buffer_constructor.new_instance(&mut env.scope(), &[ab.into()])
|
||||||
else {
|
else {
|
||||||
@ -325,7 +302,7 @@ fn napi_create_buffer<'s>(
|
|||||||
|
|
||||||
if !data.is_null() {
|
if !data.is_null() {
|
||||||
unsafe {
|
unsafe {
|
||||||
*data = get_array_buffer_ptr(ab) as _;
|
*data = get_array_buffer_ptr(ab);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -359,11 +336,8 @@ fn napi_create_external_buffer<'s>(
|
|||||||
let ab =
|
let ab =
|
||||||
v8::ArrayBuffer::with_backing_store(&mut env.scope(), &store.make_shared());
|
v8::ArrayBuffer::with_backing_store(&mut env.scope(), &store.make_shared());
|
||||||
|
|
||||||
let buffer_constructor = unsafe {
|
let buffer_constructor =
|
||||||
std::mem::transmute::<NonNull<v8::Function>, v8::Local<v8::Function>>(
|
v8::Local::new(&mut env.scope(), &env.buffer_constructor);
|
||||||
env.buffer_constructor,
|
|
||||||
)
|
|
||||||
};
|
|
||||||
let Some(buffer) =
|
let Some(buffer) =
|
||||||
buffer_constructor.new_instance(&mut env.scope(), &[ab.into()])
|
buffer_constructor.new_instance(&mut env.scope(), &[ab.into()])
|
||||||
else {
|
else {
|
||||||
@ -389,18 +363,15 @@ fn napi_create_buffer_copy<'s>(
|
|||||||
|
|
||||||
let ab = v8::ArrayBuffer::new(&mut env.scope(), length);
|
let ab = v8::ArrayBuffer::new(&mut env.scope(), length);
|
||||||
|
|
||||||
let buffer_constructor = unsafe {
|
let buffer_constructor =
|
||||||
std::mem::transmute::<NonNull<v8::Function>, v8::Local<v8::Function>>(
|
v8::Local::new(&mut env.scope(), &env.buffer_constructor);
|
||||||
env.buffer_constructor,
|
|
||||||
)
|
|
||||||
};
|
|
||||||
let Some(buffer) =
|
let Some(buffer) =
|
||||||
buffer_constructor.new_instance(&mut env.scope(), &[ab.into()])
|
buffer_constructor.new_instance(&mut env.scope(), &[ab.into()])
|
||||||
else {
|
else {
|
||||||
return napi_generic_failure;
|
return napi_generic_failure;
|
||||||
};
|
};
|
||||||
|
|
||||||
let ptr = get_array_buffer_ptr(ab) as *mut c_void;
|
let ptr = get_array_buffer_ptr(ab);
|
||||||
unsafe {
|
unsafe {
|
||||||
std::ptr::copy(data, ptr, length);
|
std::ptr::copy(data, ptr, length);
|
||||||
}
|
}
|
||||||
@ -428,11 +399,8 @@ fn napi_is_buffer(
|
|||||||
check_arg!(env, value);
|
check_arg!(env, value);
|
||||||
check_arg!(env, result);
|
check_arg!(env, result);
|
||||||
|
|
||||||
let buffer_constructor = unsafe {
|
let buffer_constructor =
|
||||||
std::mem::transmute::<NonNull<v8::Function>, v8::Local<v8::Function>>(
|
v8::Local::new(&mut env.scope(), &env.buffer_constructor);
|
||||||
env.buffer_constructor,
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
let Some(is_buffer) = value
|
let Some(is_buffer) = value
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@ -464,11 +432,8 @@ fn napi_get_buffer_info(
|
|||||||
return napi_set_last_error(env, napi_invalid_arg);
|
return napi_set_last_error(env, napi_invalid_arg);
|
||||||
};
|
};
|
||||||
|
|
||||||
let buffer_constructor = unsafe {
|
let buffer_constructor =
|
||||||
std::mem::transmute::<NonNull<v8::Function>, v8::Local<v8::Function>>(
|
v8::Local::new(&mut env.scope(), &env.buffer_constructor);
|
||||||
env.buffer_constructor,
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
if !ta
|
if !ta
|
||||||
.instance_of(&mut env.scope(), buffer_constructor.into())
|
.instance_of(&mut env.scope(), buffer_constructor.into())
|
||||||
@ -703,7 +668,9 @@ extern "C" fn default_call_js_cb(
|
|||||||
struct TsFn {
|
struct TsFn {
|
||||||
env: *mut Env,
|
env: *mut Env,
|
||||||
func: Option<v8::Global<v8::Function>>,
|
func: Option<v8::Global<v8::Function>>,
|
||||||
_max_queue_size: usize,
|
max_queue_size: usize,
|
||||||
|
queue_size: Mutex<usize>,
|
||||||
|
queue_cond: Condvar,
|
||||||
thread_count: AtomicUsize,
|
thread_count: AtomicUsize,
|
||||||
thread_finalize_data: *mut c_void,
|
thread_finalize_data: *mut c_void,
|
||||||
thread_finalize_cb: Option<napi_finalize>,
|
thread_finalize_cb: Option<napi_finalize>,
|
||||||
@ -771,6 +738,7 @@ impl TsFn {
|
|||||||
.compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst)
|
.compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst)
|
||||||
.is_ok()
|
.is_ok()
|
||||||
{
|
{
|
||||||
|
tsfn.queue_cond.notify_all();
|
||||||
let tsfnptr = SendPtr(tsfn);
|
let tsfnptr = SendPtr(tsfn);
|
||||||
// drop must be queued in order to preserve ordering consistent
|
// drop must be queued in order to preserve ordering consistent
|
||||||
// with Node.js and so that the finalizer runs on the main thread.
|
// with Node.js and so that the finalizer runs on the main thread.
|
||||||
@ -811,26 +779,34 @@ impl TsFn {
|
|||||||
pub fn call(
|
pub fn call(
|
||||||
&self,
|
&self,
|
||||||
data: *mut c_void,
|
data: *mut c_void,
|
||||||
_mode: napi_threadsafe_function_call_mode,
|
mode: napi_threadsafe_function_call_mode,
|
||||||
) -> napi_status {
|
) -> napi_status {
|
||||||
// TODO:
|
|
||||||
// if self.max_queue_size > 0 && queued >= self.max_queue_size {
|
|
||||||
// if mode == napi_tsfn_blocking {
|
|
||||||
// wait somehow
|
|
||||||
// } else {
|
|
||||||
// return napi_queue_full;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
if self.is_closing.load(Ordering::SeqCst) {
|
if self.is_closing.load(Ordering::SeqCst) {
|
||||||
return napi_closing;
|
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 is_closed = self.is_closed.clone();
|
||||||
let tsfn = SendPtr(self);
|
let tsfn = SendPtr(self);
|
||||||
let data = SendPtr(data);
|
let data = SendPtr(data);
|
||||||
let context = SendPtr(self.context);
|
let context = SendPtr(self.context);
|
||||||
let call_js_cb = self.call_js_cb;
|
let call_js_cb = self.call_js_cb;
|
||||||
|
|
||||||
self.sender.spawn(move |scope: &mut v8::HandleScope| {
|
self.sender.spawn(move |scope: &mut v8::HandleScope| {
|
||||||
let data = data.take();
|
let data = data.take();
|
||||||
|
|
||||||
@ -849,6 +825,15 @@ impl TsFn {
|
|||||||
|
|
||||||
let tsfn = unsafe { &*tsfn };
|
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));
|
let func = tsfn.func.as_ref().map(|f| v8::Local::new(scope, f));
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
@ -918,7 +903,9 @@ fn napi_create_threadsafe_function(
|
|||||||
let mut tsfn = Box::new(TsFn {
|
let mut tsfn = Box::new(TsFn {
|
||||||
env,
|
env,
|
||||||
func,
|
func,
|
||||||
_max_queue_size: max_queue_size,
|
max_queue_size,
|
||||||
|
queue_size: Mutex::new(0),
|
||||||
|
queue_cond: Condvar::new(),
|
||||||
thread_count: AtomicUsize::new(initial_thread_count),
|
thread_count: AtomicUsize::new(initial_thread_count),
|
||||||
thread_finalize_data,
|
thread_finalize_data,
|
||||||
thread_finalize_cb,
|
thread_finalize_cb,
|
||||||
|
@ -15,10 +15,11 @@ impl<T> SendPtr<T> {
|
|||||||
unsafe impl<T> Send for SendPtr<T> {}
|
unsafe impl<T> Send for SendPtr<T> {}
|
||||||
unsafe impl<T> Sync for SendPtr<T> {}
|
unsafe impl<T> Sync for SendPtr<T> {}
|
||||||
|
|
||||||
pub fn get_array_buffer_ptr(ab: v8::Local<v8::ArrayBuffer>) -> *mut u8 {
|
pub fn get_array_buffer_ptr(ab: v8::Local<v8::ArrayBuffer>) -> *mut c_void {
|
||||||
// SAFETY: Thanks to the null pointer optimization, NonNull<T> and Option<NonNull<T>> are guaranteed
|
match ab.data() {
|
||||||
// to have the same size and alignment.
|
Some(p) => p.as_ptr(),
|
||||||
unsafe { std::mem::transmute(ab.data()) }
|
None => std::ptr::null_mut(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct BufferFinalizer {
|
struct BufferFinalizer {
|
||||||
@ -216,10 +217,6 @@ impl<'s> Nullable for napi_value<'s> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: replace Nullable with some sort of "CheckedUnwrap" trait
|
|
||||||
// *mut T -> &mut MaybeUninit<T>
|
|
||||||
// Option<T> -> T
|
|
||||||
// napi_value -> Local<Value>
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! check_arg {
|
macro_rules! check_arg {
|
||||||
($env: expr, $ptr: expr) => {
|
($env: expr, $ptr: expr) => {
|
||||||
|
@ -4,7 +4,7 @@ use crate::*;
|
|||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct CallbackInfo {
|
pub struct CallbackInfo {
|
||||||
pub env: napi_env,
|
pub env: *mut Env,
|
||||||
pub cb: napi_callback,
|
pub cb: napi_callback,
|
||||||
pub cb_info: napi_callback_info,
|
pub cb_info: napi_callback_info,
|
||||||
pub args: *const c_void,
|
pub args: *const c_void,
|
||||||
@ -13,7 +13,7 @@ pub struct CallbackInfo {
|
|||||||
impl CallbackInfo {
|
impl CallbackInfo {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new_raw(
|
pub fn new_raw(
|
||||||
env: napi_env,
|
env: *mut Env,
|
||||||
cb: napi_callback,
|
cb: napi_callback,
|
||||||
cb_info: napi_callback_info,
|
cb_info: napi_callback_info,
|
||||||
) -> *mut Self {
|
) -> *mut Self {
|
||||||
@ -41,38 +41,27 @@ extern "C" fn call_fn(info: *const v8::FunctionCallbackInfo) {
|
|||||||
let info = unsafe { &mut *info_ptr };
|
let info = unsafe { &mut *info_ptr };
|
||||||
info.args = &args as *const _ as *const c_void;
|
info.args = &args as *const _ as *const c_void;
|
||||||
|
|
||||||
if let Some(f) = info.cb {
|
// SAFETY: calling user provided function pointer.
|
||||||
// SAFETY: calling user provided function pointer.
|
let value = unsafe { (info.cb)(info.env as napi_env, info_ptr as *mut _) };
|
||||||
let value = unsafe { f(info.env, info_ptr as *mut _) };
|
if let Some(exc) = unsafe { &mut *info.env }.last_exception.take() {
|
||||||
if let Some(exc) = unsafe { &mut *(info.env as *mut Env) }
|
let scope = unsafe { &mut v8::CallbackScope::new(callback_info) };
|
||||||
.last_exception
|
let exc = v8::Local::new(scope, exc);
|
||||||
.take()
|
scope.throw_exception(exc);
|
||||||
{
|
}
|
||||||
let scope = unsafe { &mut v8::CallbackScope::new(callback_info) };
|
if let Some(value) = *value {
|
||||||
let exc = v8::Local::new(scope, exc);
|
rv.set(value);
|
||||||
scope.throw_exception(exc);
|
|
||||||
}
|
|
||||||
if let Some(value) = *value {
|
|
||||||
rv.set(value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// # Safety
|
pub fn create_function<'s>(
|
||||||
/// env_ptr must be valid
|
scope: &mut v8::HandleScope<'s>,
|
||||||
pub unsafe fn create_function<'a>(
|
env: *mut Env,
|
||||||
env_ptr: *mut Env,
|
|
||||||
name: Option<v8::Local<v8::String>>,
|
name: Option<v8::Local<v8::String>>,
|
||||||
cb: napi_callback,
|
cb: napi_callback,
|
||||||
cb_info: napi_callback_info,
|
cb_info: napi_callback_info,
|
||||||
) -> v8::Local<'a, v8::Function> {
|
) -> v8::Local<'s, v8::Function> {
|
||||||
let env = unsafe { &mut *env_ptr };
|
let external =
|
||||||
let scope = &mut env.scope();
|
v8::External::new(scope, CallbackInfo::new_raw(env, cb, cb_info) as *mut _);
|
||||||
|
|
||||||
let external = v8::External::new(
|
|
||||||
scope,
|
|
||||||
CallbackInfo::new_raw(env_ptr as _, cb, cb_info) as *mut _,
|
|
||||||
);
|
|
||||||
let function = v8::Function::builder_raw(call_fn)
|
let function = v8::Function::builder_raw(call_fn)
|
||||||
.data(external.into())
|
.data(external.into())
|
||||||
.build(scope)
|
.build(scope)
|
||||||
@ -85,21 +74,15 @@ pub unsafe fn create_function<'a>(
|
|||||||
function
|
function
|
||||||
}
|
}
|
||||||
|
|
||||||
/// # Safety
|
pub fn create_function_template<'s>(
|
||||||
/// env_ptr must be valid
|
scope: &mut v8::HandleScope<'s>,
|
||||||
pub unsafe fn create_function_template<'a>(
|
env: *mut Env,
|
||||||
env_ptr: *mut Env,
|
|
||||||
name: Option<v8::Local<v8::String>>,
|
name: Option<v8::Local<v8::String>>,
|
||||||
cb: napi_callback,
|
cb: napi_callback,
|
||||||
cb_info: napi_callback_info,
|
cb_info: napi_callback_info,
|
||||||
) -> v8::Local<'a, v8::FunctionTemplate> {
|
) -> v8::Local<'s, v8::FunctionTemplate> {
|
||||||
let env = unsafe { &mut *env_ptr };
|
let external =
|
||||||
let scope = &mut env.scope();
|
v8::External::new(scope, CallbackInfo::new_raw(env, cb, cb_info) as *mut _);
|
||||||
|
|
||||||
let external = v8::External::new(
|
|
||||||
scope,
|
|
||||||
CallbackInfo::new_raw(env_ptr as _, cb, cb_info) as *mut _,
|
|
||||||
);
|
|
||||||
let function = v8::FunctionTemplate::builder_raw(call_fn)
|
let function = v8::FunctionTemplate::builder_raw(call_fn)
|
||||||
.data(external.into())
|
.data(external.into())
|
||||||
.build(scope);
|
.build(scope);
|
||||||
|
@ -187,12 +187,10 @@ pub struct napi_type_tag {
|
|||||||
pub upper: u64,
|
pub upper: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type napi_callback = Option<
|
pub type napi_callback = unsafe extern "C" fn(
|
||||||
unsafe extern "C" fn(
|
env: napi_env,
|
||||||
env: napi_env,
|
info: napi_callback_info,
|
||||||
info: napi_callback_info,
|
) -> napi_value<'static>;
|
||||||
) -> napi_value<'static>,
|
|
||||||
>;
|
|
||||||
|
|
||||||
pub type napi_finalize = unsafe extern "C" fn(
|
pub type napi_finalize = unsafe extern "C" fn(
|
||||||
env: napi_env,
|
env: napi_env,
|
||||||
@ -213,8 +211,10 @@ pub type napi_threadsafe_function_call_js = unsafe extern "C" fn(
|
|||||||
data: *mut c_void,
|
data: *mut c_void,
|
||||||
);
|
);
|
||||||
|
|
||||||
pub type napi_async_cleanup_hook =
|
pub type napi_async_cleanup_hook = unsafe extern "C" fn(
|
||||||
unsafe extern "C" fn(env: napi_env, data: *mut c_void);
|
handle: napi_async_cleanup_hook_handle,
|
||||||
|
data: *mut c_void,
|
||||||
|
);
|
||||||
|
|
||||||
pub type napi_cleanup_hook = unsafe extern "C" fn(data: *mut c_void);
|
pub type napi_cleanup_hook = unsafe extern "C" fn(data: *mut c_void);
|
||||||
|
|
||||||
@ -235,9 +235,9 @@ pub const napi_default_jsproperty: napi_property_attributes =
|
|||||||
pub struct napi_property_descriptor<'a> {
|
pub struct napi_property_descriptor<'a> {
|
||||||
pub utf8name: *const c_char,
|
pub utf8name: *const c_char,
|
||||||
pub name: napi_value<'a>,
|
pub name: napi_value<'a>,
|
||||||
pub method: napi_callback,
|
pub method: Option<napi_callback>,
|
||||||
pub getter: napi_callback,
|
pub getter: Option<napi_callback>,
|
||||||
pub setter: napi_callback,
|
pub setter: Option<napi_callback>,
|
||||||
pub value: napi_value<'a>,
|
pub value: napi_value<'a>,
|
||||||
pub attributes: napi_property_attributes,
|
pub attributes: napi_property_attributes,
|
||||||
pub data: *mut c_void,
|
pub data: *mut c_void,
|
||||||
@ -348,13 +348,13 @@ pub struct Env {
|
|||||||
pub open_handle_scopes: usize,
|
pub open_handle_scopes: usize,
|
||||||
pub shared: *mut EnvShared,
|
pub shared: *mut EnvShared,
|
||||||
pub async_work_sender: V8CrossThreadTaskSpawner,
|
pub async_work_sender: V8CrossThreadTaskSpawner,
|
||||||
pub cleanup_hooks: Rc<RefCell<Vec<(napi_cleanup_hook, *mut c_void)>>>,
|
cleanup_hooks: Rc<RefCell<Vec<(napi_cleanup_hook, *mut c_void)>>>,
|
||||||
pub external_ops_tracker: ExternalOpsTracker,
|
external_ops_tracker: ExternalOpsTracker,
|
||||||
pub last_error: napi_extended_error_info,
|
pub last_error: napi_extended_error_info,
|
||||||
pub last_exception: Option<v8::Global<v8::Value>>,
|
pub last_exception: Option<v8::Global<v8::Value>>,
|
||||||
pub global: NonNull<v8::Value>,
|
pub global: v8::Global<v8::Object>,
|
||||||
pub buffer_constructor: NonNull<v8::Function>,
|
pub buffer_constructor: v8::Global<v8::Function>,
|
||||||
pub report_error: NonNull<v8::Function>,
|
pub report_error: v8::Global<v8::Function>,
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl Send for Env {}
|
unsafe impl Send for Env {}
|
||||||
@ -365,7 +365,7 @@ impl Env {
|
|||||||
pub fn new(
|
pub fn new(
|
||||||
isolate_ptr: *mut v8::OwnedIsolate,
|
isolate_ptr: *mut v8::OwnedIsolate,
|
||||||
context: v8::Global<v8::Context>,
|
context: v8::Global<v8::Context>,
|
||||||
global: v8::Global<v8::Value>,
|
global: v8::Global<v8::Object>,
|
||||||
buffer_constructor: v8::Global<v8::Function>,
|
buffer_constructor: v8::Global<v8::Function>,
|
||||||
report_error: v8::Global<v8::Function>,
|
report_error: v8::Global<v8::Function>,
|
||||||
sender: V8CrossThreadTaskSpawner,
|
sender: V8CrossThreadTaskSpawner,
|
||||||
@ -375,9 +375,9 @@ impl Env {
|
|||||||
Self {
|
Self {
|
||||||
isolate_ptr,
|
isolate_ptr,
|
||||||
context: context.into_raw(),
|
context: context.into_raw(),
|
||||||
global: global.into_raw(),
|
global,
|
||||||
buffer_constructor: buffer_constructor.into_raw(),
|
buffer_constructor,
|
||||||
report_error: report_error.into_raw(),
|
report_error,
|
||||||
shared: std::ptr::null_mut(),
|
shared: std::ptr::null_mut(),
|
||||||
open_handle_scopes: 0,
|
open_handle_scopes: 0,
|
||||||
async_work_sender: sender,
|
async_work_sender: sender,
|
||||||
@ -435,6 +435,35 @@ impl Env {
|
|||||||
pub fn threadsafe_function_unref(&mut self) {
|
pub fn threadsafe_function_unref(&mut self) {
|
||||||
self.external_ops_tracker.unref_op();
|
self.external_ops_tracker.unref_op();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn add_cleanup_hook(
|
||||||
|
&mut self,
|
||||||
|
hook: napi_cleanup_hook,
|
||||||
|
data: *mut c_void,
|
||||||
|
) {
|
||||||
|
let mut hooks = self.cleanup_hooks.borrow_mut();
|
||||||
|
if hooks.iter().any(|pair| pair.0 == hook && pair.1 == data) {
|
||||||
|
panic!("Cannot register cleanup hook with same data twice");
|
||||||
|
}
|
||||||
|
hooks.push((hook, data));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove_cleanup_hook(
|
||||||
|
&mut self,
|
||||||
|
hook: napi_cleanup_hook,
|
||||||
|
data: *mut c_void,
|
||||||
|
) {
|
||||||
|
let mut hooks = self.cleanup_hooks.borrow_mut();
|
||||||
|
match hooks
|
||||||
|
.iter()
|
||||||
|
.rposition(|&pair| pair.0 == hook && pair.1 == data)
|
||||||
|
{
|
||||||
|
Some(index) => {
|
||||||
|
hooks.remove(index);
|
||||||
|
}
|
||||||
|
None => panic!("Cannot remove cleanup hook which was not registered"),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
deno_core::extension!(deno_napi,
|
deno_core::extension!(deno_napi,
|
||||||
@ -468,7 +497,7 @@ fn op_napi_open<NP, 'scope>(
|
|||||||
scope: &mut v8::HandleScope<'scope>,
|
scope: &mut v8::HandleScope<'scope>,
|
||||||
op_state: Rc<RefCell<OpState>>,
|
op_state: Rc<RefCell<OpState>>,
|
||||||
#[string] path: String,
|
#[string] path: String,
|
||||||
global: v8::Local<'scope, v8::Value>,
|
global: v8::Local<'scope, v8::Object>,
|
||||||
buffer_constructor: v8::Local<'scope, v8::Function>,
|
buffer_constructor: v8::Local<'scope, v8::Function>,
|
||||||
report_error: v8::Local<'scope, v8::Function>,
|
report_error: v8::Local<'scope, v8::Function>,
|
||||||
) -> std::result::Result<v8::Local<'scope, v8::Value>, AnyError>
|
) -> std::result::Result<v8::Local<'scope, v8::Value>, AnyError>
|
||||||
@ -499,9 +528,6 @@ where
|
|||||||
let type_tag = v8::Private::new(scope, Some(type_tag_name));
|
let type_tag = v8::Private::new(scope, Some(type_tag_name));
|
||||||
let type_tag = v8::Global::new(scope, type_tag);
|
let type_tag = v8::Global::new(scope, type_tag);
|
||||||
|
|
||||||
// The `module.exports` object.
|
|
||||||
let exports = v8::Object::new(scope);
|
|
||||||
|
|
||||||
let env_shared = EnvShared::new(napi_wrap, type_tag, path.clone());
|
let env_shared = EnvShared::new(napi_wrap, type_tag, path.clone());
|
||||||
|
|
||||||
let ctx = scope.get_current_context();
|
let ctx = scope.get_current_context();
|
||||||
@ -542,6 +568,9 @@ where
|
|||||||
slot.take()
|
slot.take()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// The `module.exports` object.
|
||||||
|
let exports = v8::Object::new(scope);
|
||||||
|
|
||||||
let maybe_exports = if let Some(module_to_register) = maybe_module {
|
let maybe_exports = if let Some(module_to_register) = maybe_module {
|
||||||
// SAFETY: napi_register_module guarantees that `module_to_register` is valid.
|
// SAFETY: napi_register_module guarantees that `module_to_register` is valid.
|
||||||
let nm = unsafe { &*module_to_register };
|
let nm = unsafe { &*module_to_register };
|
||||||
|
@ -31,9 +31,7 @@ where
|
|||||||
v8::Local<'s, T>: Into<v8::Local<'s, v8::Value>>,
|
v8::Local<'s, T>: Into<v8::Local<'s, v8::Value>>,
|
||||||
{
|
{
|
||||||
fn from(v: v8::Local<'s, T>) -> Self {
|
fn from(v: v8::Local<'s, T>) -> Self {
|
||||||
// SAFETY: It is safe to cast v8::Local<T> that implements Into<v8::Local<v8::Value>>.
|
Self(Some(NonNull::from(&*v.into())), std::marker::PhantomData)
|
||||||
// `fn into(self)` transmutes anyways.
|
|
||||||
Self(unsafe { transmute(v) }, std::marker::PhantomData)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user