Merge pull request #1024 from messense/forbid-unsafe_op_in_unsafe_fn

chore: forbid unsafe_op_in_unsafe_fn
This commit is contained in:
LongYinan 2022-01-13 14:30:53 +08:00 committed by GitHub
commit 8a4870c8dd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
29 changed files with 599 additions and 516 deletions

View file

@ -92,7 +92,7 @@ unsafe impl<T: Task> Sync for AsyncWork<T> {}
/// env here is the same with the one in `CallContext`. /// env here is the same with the one in `CallContext`.
/// So it actually could do nothing here, because `execute` function is called in the other thread mostly. /// So it actually could do nothing here, because `execute` function is called in the other thread mostly.
unsafe extern "C" fn execute<T: Task>(_env: sys::napi_env, data: *mut c_void) { unsafe extern "C" fn execute<T: Task>(_env: sys::napi_env, data: *mut c_void) {
let mut work = Box::from_raw(data as *mut AsyncWork<T>); let mut work = unsafe { Box::from_raw(data as *mut AsyncWork<T>) };
let _ = mem::replace( let _ = mem::replace(
&mut work.value, &mut work.value,
work.inner_task.compute().map(mem::MaybeUninit::new), work.inner_task.compute().map(mem::MaybeUninit::new),
@ -105,36 +105,39 @@ unsafe extern "C" fn complete<T: Task>(
status: sys::napi_status, status: sys::napi_status,
data: *mut c_void, data: *mut c_void,
) { ) {
let mut work = Box::from_raw(data as *mut AsyncWork<T>); let mut work = unsafe { Box::from_raw(data as *mut AsyncWork<T>) };
let value_ptr = mem::replace(&mut work.value, Ok(mem::MaybeUninit::zeroed())); let value_ptr = mem::replace(&mut work.value, Ok(mem::MaybeUninit::zeroed()));
let deferred = mem::replace(&mut work.deferred, ptr::null_mut()); let deferred = mem::replace(&mut work.deferred, ptr::null_mut());
let napi_async_work = mem::replace(&mut work.napi_async_work, ptr::null_mut()); let napi_async_work = mem::replace(&mut work.napi_async_work, ptr::null_mut());
let value = match value_ptr { let value = match value_ptr {
Ok(v) => { Ok(v) => {
let output = v.assume_init(); let output = unsafe { v.assume_init() };
work.inner_task.resolve(Env::from_raw(env), output) work
.inner_task
.resolve(unsafe { Env::from_raw(env) }, output)
} }
Err(e) => work.inner_task.reject(Env::from_raw(env), e), Err(e) => work.inner_task.reject(unsafe { Env::from_raw(env) }, e),
}; };
if status != sys::Status::napi_cancelled && work.status.load(Ordering::Relaxed) != 2 { if status != sys::Status::napi_cancelled && work.status.load(Ordering::Relaxed) != 2 {
match check_status!(status) match check_status!(status)
.and_then(move |_| value) .and_then(move |_| value)
.and_then(|v| ToNapiValue::to_napi_value(env, v)) .and_then(|v| unsafe { ToNapiValue::to_napi_value(env, v) })
{ {
Ok(v) => { Ok(v) => {
let status = sys::napi_resolve_deferred(env, deferred, v); let status = unsafe { sys::napi_resolve_deferred(env, deferred, v) };
debug_assert!(status == sys::Status::napi_ok, "Resolve promise failed"); debug_assert!(status == sys::Status::napi_ok, "Resolve promise failed");
} }
Err(e) => { Err(e) => {
let status = sys::napi_reject_deferred(env, deferred, JsError::from(e).into_value(env)); let status =
unsafe { sys::napi_reject_deferred(env, deferred, JsError::from(e).into_value(env)) };
debug_assert!(status == sys::Status::napi_ok, "Reject promise failed"); debug_assert!(status == sys::Status::napi_ok, "Reject promise failed");
} }
}; };
} }
if let Err(e) = work.inner_task.finally(Env::from_raw(env)) { if let Err(e) = work.inner_task.finally(unsafe { Env::from_raw(env) }) {
debug_assert!(false, "Panic in Task finally fn: {:?}", e); debug_assert!(false, "Panic in Task finally fn: {:?}", e);
} }
let delete_status = sys::napi_delete_async_work(env, napi_async_work); let delete_status = unsafe { sys::napi_delete_async_work(env, napi_async_work) };
debug_assert!( debug_assert!(
delete_status == sys::Status::napi_ok, delete_status == sys::Status::napi_ok,
"Delete async work failed" "Delete async work failed"

View file

@ -3,7 +3,8 @@
macro_rules! check_status_or_throw { macro_rules! check_status_or_throw {
($env:expr, $code:expr, $($msg:tt)*) => { ($env:expr, $code:expr, $($msg:tt)*) => {
if let Err(e) = $crate::check_status!($code, $($msg)*) { if let Err(e) = $crate::check_status!($code, $($msg)*) {
$crate::JsError::from(e).throw_into($env); #[allow(unused_unsafe)]
unsafe { $crate::JsError::from(e).throw_into($env) };
return; return;
} }
}; };

View file

@ -68,13 +68,13 @@ impl TypeName for JsUnknown {
impl<T: NapiRaw> ToNapiValue for T { impl<T: NapiRaw> ToNapiValue for T {
unsafe fn to_napi_value(_env: sys::napi_env, val: Self) -> Result<sys::napi_value> { unsafe fn to_napi_value(_env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
Ok(NapiRaw::raw(&val)) Ok(unsafe { NapiRaw::raw(&val) })
} }
} }
impl<T: NapiValue> FromNapiValue for T { impl<T: NapiValue> FromNapiValue for T {
unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> { unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
Ok(T::from_raw_unchecked(env, napi_val)) Ok(unsafe { T::from_raw_unchecked(env, napi_val) })
} }
} }
@ -118,7 +118,7 @@ pub trait ValidateNapiValue: FromNapiValue + TypeName {
let mut result = -1; let mut result = -1;
check_status!( check_status!(
sys::napi_typeof(env, napi_val, &mut result), unsafe { sys::napi_typeof(env, napi_val, &mut result) },
"Failed to detect napi value type", "Failed to detect napi value type",
)?; )?;
@ -162,13 +162,13 @@ where
let mut val_type = 0; let mut val_type = 0;
check_status!( check_status!(
sys::napi_typeof(env, napi_val, &mut val_type), unsafe { sys::napi_typeof(env, napi_val, &mut val_type) },
"Failed to convert napi value into rust type `Option<T>`", "Failed to convert napi value into rust type `Option<T>`",
)?; )?;
match val_type { match val_type {
sys::ValueType::napi_undefined | sys::ValueType::napi_null => Ok(None), sys::ValueType::napi_undefined | sys::ValueType::napi_null => Ok(None),
_ => Ok(Some(T::from_napi_value(env, napi_val)?)), _ => Ok(Some(unsafe { T::from_napi_value(env, napi_val)? })),
} }
} }
} }
@ -179,11 +179,11 @@ where
{ {
unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> { unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
match val { match val {
Some(val) => T::to_napi_value(env, val), Some(val) => unsafe { T::to_napi_value(env, val) },
None => { None => {
let mut ptr = ptr::null_mut(); let mut ptr = ptr::null_mut();
check_status!( check_status!(
sys::napi_get_null(env, &mut ptr), unsafe { sys::napi_get_null(env, &mut ptr) },
"Failed to convert rust type `Option<T>` into napi value", "Failed to convert rust type `Option<T>` into napi value",
)?; )?;
Ok(ptr) Ok(ptr)
@ -198,13 +198,13 @@ where
{ {
unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> { unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
match val { match val {
Ok(v) => T::to_napi_value(env, v), Ok(v) => unsafe { T::to_napi_value(env, v) },
Err(e) => { Err(e) => {
let error_code = String::to_napi_value(env, format!("{:?}", e.status))?; let error_code = unsafe { String::to_napi_value(env, format!("{:?}", e.status))? };
let reason = String::to_napi_value(env, e.reason)?; let reason = unsafe { String::to_napi_value(env, e.reason)? };
let mut error = ptr::null_mut(); let mut error = ptr::null_mut();
check_status!( check_status!(
sys::napi_create_error(env, error_code, reason, &mut error), unsafe { sys::napi_create_error(env, error_code, reason, &mut error) },
"Failed to create napi error" "Failed to create napi error"
)?; )?;

View file

@ -91,7 +91,7 @@ impl FromNapiValue for Array {
unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> { unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
let mut is_arr = false; let mut is_arr = false;
check_status!( check_status!(
sys::napi_is_array(env, napi_val, &mut is_arr), unsafe { sys::napi_is_array(env, napi_val, &mut is_arr) },
"Failed to check given napi value is array" "Failed to check given napi value is array"
)?; )?;
@ -99,7 +99,7 @@ impl FromNapiValue for Array {
let mut len = 0; let mut len = 0;
check_status!( check_status!(
sys::napi_get_array_length(env, napi_val, &mut len), unsafe { sys::napi_get_array_length(env, napi_val, &mut len) },
"Failed to get Array length", "Failed to get Array length",
)?; )?;
@ -182,7 +182,7 @@ where
arr.set(i as u32, v)?; arr.set(i as u32, v)?;
} }
Array::to_napi_value(env, arr) unsafe { Array::to_napi_value(env, arr) }
} }
} }
@ -196,7 +196,7 @@ macro_rules! impl_for_primitive_type {
arr.set(i as u32, *v)?; arr.set(i as u32, *v)?;
} }
Array::to_napi_value(env, arr) unsafe { Array::to_napi_value(env, arr) }
} }
} }
}; };
@ -216,7 +216,7 @@ impl ToNapiValue for &Vec<String> {
arr.set(i as u32, v.as_str())?; arr.set(i as u32, v.as_str())?;
} }
Array::to_napi_value(env, arr) unsafe { Array::to_napi_value(env, arr) }
} }
} }
@ -225,7 +225,7 @@ where
T: FromNapiValue, T: FromNapiValue,
{ {
unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> { unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
let arr = Array::from_napi_value(env, napi_val)?; let arr = unsafe { Array::from_napi_value(env, napi_val)? };
let mut vec = vec![]; let mut vec = vec![];
for i in 0..arr.len() { for i in 0..arr.len() {

View file

@ -117,15 +117,17 @@ macro_rules! impl_typed_array {
let mut array_buffer = ptr::null_mut(); let mut array_buffer = ptr::null_mut();
let mut byte_offset = 0; let mut byte_offset = 0;
check_status!( check_status!(
sys::napi_get_typedarray_info( unsafe {
env, sys::napi_get_typedarray_info(
napi_val, env,
&mut typed_array_type, napi_val,
&mut length, &mut typed_array_type,
&mut data, &mut length,
&mut array_buffer, &mut data,
&mut byte_offset &mut array_buffer,
), &mut byte_offset,
)
},
"Get TypedArray info failed" "Get TypedArray info failed"
)?; )?;
if typed_array_type != $typed_array_type as i32 { if typed_array_type != $typed_array_type as i32 {
@ -155,26 +157,30 @@ macro_rules! impl_typed_array {
val.finalizer_notify, val.finalizer_notify,
))); )));
check_status!( check_status!(
sys::napi_create_external_arraybuffer( unsafe {
env, sys::napi_create_external_arraybuffer(
val.data as *mut c_void, env,
length, val.data as *mut c_void,
Some(finalizer::<$rust_type>), length,
hint_ptr as *mut c_void, Some(finalizer::<$rust_type>),
&mut arraybuffer_value hint_ptr as *mut c_void,
), &mut arraybuffer_value,
)
},
"Create external arraybuffer failed" "Create external arraybuffer failed"
)?; )?;
let mut napi_val = ptr::null_mut(); let mut napi_val = ptr::null_mut();
check_status!( check_status!(
sys::napi_create_typedarray( unsafe {
env, sys::napi_create_typedarray(
$typed_array_type as i32, env,
val.length, $typed_array_type as i32,
arraybuffer_value, val.length,
0, arraybuffer_value,
&mut napi_val, 0,
), &mut napi_val,
)
},
"Create TypedArray failed" "Create TypedArray failed"
)?; )?;
Ok(napi_val) Ok(napi_val)
@ -188,15 +194,16 @@ unsafe extern "C" fn finalizer<T>(
finalize_data: *mut c_void, finalize_data: *mut c_void,
finalize_hint: *mut c_void, finalize_hint: *mut c_void,
) { ) {
let (data_managed_type, length, finalizer_notify) = let (data_managed_type, length, finalizer_notify) = unsafe {
*Box::from_raw(finalize_hint as *mut (DataManagedType, usize, Box<dyn FnOnce(*mut T, usize)>)); *Box::from_raw(finalize_hint as *mut (DataManagedType, usize, Box<dyn FnOnce(*mut T, usize)>))
};
match data_managed_type { match data_managed_type {
DataManagedType::Vm => { DataManagedType::Vm => {
// do nothing // do nothing
} }
DataManagedType::Owned => { DataManagedType::Owned => {
let length = length; let length = length;
Vec::from_raw_parts(finalize_data as *mut T, length, length); unsafe { Vec::from_raw_parts(finalize_data as *mut T, length, length) };
} }
DataManagedType::External => { DataManagedType::External => {
(finalizer_notify)(finalize_data as *mut T, length); (finalizer_notify)(finalize_data as *mut T, length);

View file

@ -41,24 +41,29 @@ impl TypeName for BigInt {
impl FromNapiValue for BigInt { impl FromNapiValue for BigInt {
unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> crate::Result<Self> { unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> crate::Result<Self> {
let mut word_count = 0usize; let mut word_count = 0usize;
check_status!(sys::napi_get_value_bigint_words( check_status!(unsafe {
env, sys::napi_get_value_bigint_words(
napi_val, env,
ptr::null_mut(), napi_val,
&mut word_count, ptr::null_mut(),
ptr::null_mut(), &mut word_count,
))?; ptr::null_mut(),
)
})?;
let mut words: Vec<u64> = Vec::with_capacity(word_count as usize); let mut words: Vec<u64> = Vec::with_capacity(word_count as usize);
let mut sign_bit = 0; let mut sign_bit = 0;
check_status!(sys::napi_get_value_bigint_words(
env,
napi_val,
&mut sign_bit,
&mut word_count,
words.as_mut_ptr(),
))?;
words.set_len(word_count as usize); unsafe {
check_status!(sys::napi_get_value_bigint_words(
env,
napi_val,
&mut sign_bit,
&mut word_count,
words.as_mut_ptr(),
))?;
words.set_len(word_count as usize);
}
Ok(BigInt { Ok(BigInt {
sign_bit: sign_bit == 1, sign_bit: sign_bit == 1,
words, words,
@ -126,16 +131,18 @@ impl ToNapiValue for BigInt {
unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> crate::Result<sys::napi_value> { unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> crate::Result<sys::napi_value> {
let mut raw_value = ptr::null_mut(); let mut raw_value = ptr::null_mut();
let len = val.words.len(); let len = val.words.len();
check_status!(sys::napi_create_bigint_words( check_status!(unsafe {
env, sys::napi_create_bigint_words(
match val.sign_bit { env,
true => 1, match val.sign_bit {
false => 0, true => 1,
}, false => 0,
len, },
val.words.as_ptr(), len,
&mut raw_value, val.words.as_ptr(),
))?; &mut raw_value,
)
})?;
Ok(raw_value) Ok(raw_value)
} }
} }
@ -145,13 +152,9 @@ impl ToNapiValue for i128 {
let mut raw_value = ptr::null_mut(); let mut raw_value = ptr::null_mut();
let sign_bit = if val > 0 { 0 } else { 1 }; let sign_bit = if val > 0 { 0 } else { 1 };
let words = &val as *const i128 as *const u64; let words = &val as *const i128 as *const u64;
check_status!(sys::napi_create_bigint_words( check_status!(unsafe {
env, sys::napi_create_bigint_words(env, sign_bit, 2, words, &mut raw_value)
sign_bit, })?;
2,
words,
&mut raw_value
))?;
Ok(raw_value) Ok(raw_value)
} }
} }
@ -160,13 +163,7 @@ impl ToNapiValue for u128 {
unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> crate::Result<sys::napi_value> { unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> crate::Result<sys::napi_value> {
let mut raw_value = ptr::null_mut(); let mut raw_value = ptr::null_mut();
let words = &val as *const u128 as *const u64; let words = &val as *const u128 as *const u64;
check_status!(sys::napi_create_bigint_words( check_status!(unsafe { sys::napi_create_bigint_words(env, 0, 2, words, &mut raw_value) })?;
env,
0,
2,
words,
&mut raw_value
))?;
Ok(raw_value) Ok(raw_value)
} }
} }
@ -174,7 +171,7 @@ impl ToNapiValue for u128 {
impl ToNapiValue for i64n { impl ToNapiValue for i64n {
unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> crate::Result<sys::napi_value> { unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> crate::Result<sys::napi_value> {
let mut raw_value = ptr::null_mut(); let mut raw_value = ptr::null_mut();
check_status!(sys::napi_create_bigint_int64(env, val.0, &mut raw_value))?; check_status!(unsafe { sys::napi_create_bigint_int64(env, val.0, &mut raw_value) })?;
Ok(raw_value) Ok(raw_value)
} }
} }
@ -182,7 +179,7 @@ impl ToNapiValue for i64n {
impl ToNapiValue for u64 { impl ToNapiValue for u64 {
unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> crate::Result<sys::napi_value> { unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> crate::Result<sys::napi_value> {
let mut raw_value = ptr::null_mut(); let mut raw_value = ptr::null_mut();
check_status!(sys::napi_create_bigint_uint64(env, val, &mut raw_value))?; check_status!(unsafe { sys::napi_create_bigint_uint64(env, val, &mut raw_value) })?;
Ok(raw_value) Ok(raw_value)
} }
} }
@ -190,11 +187,7 @@ impl ToNapiValue for u64 {
impl ToNapiValue for usize { impl ToNapiValue for usize {
unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> crate::Result<sys::napi_value> { unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> crate::Result<sys::napi_value> {
let mut raw_value = ptr::null_mut(); let mut raw_value = ptr::null_mut();
check_status!(sys::napi_create_bigint_uint64( check_status!(unsafe { sys::napi_create_bigint_uint64(env, val as u64, &mut raw_value) })?;
env,
val as u64,
&mut raw_value
))?;
Ok(raw_value) Ok(raw_value)
} }
} }
@ -202,11 +195,7 @@ impl ToNapiValue for usize {
impl ToNapiValue for isize { impl ToNapiValue for isize {
unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> crate::Result<sys::napi_value> { unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> crate::Result<sys::napi_value> {
let mut raw_value = ptr::null_mut(); let mut raw_value = ptr::null_mut();
check_status!(sys::napi_create_bigint_int64( check_status!(unsafe { sys::napi_create_bigint_int64(env, val as i64, &mut raw_value) })?;
env,
val as i64,
&mut raw_value
))?;
Ok(raw_value) Ok(raw_value)
} }
} }

View file

@ -21,7 +21,7 @@ impl ToNapiValue for bool {
let mut ptr = std::ptr::null_mut(); let mut ptr = std::ptr::null_mut();
check_status!( check_status!(
sys::napi_get_boolean(env, val, &mut ptr), unsafe { sys::napi_get_boolean(env, val, &mut ptr) },
"Failed to convert rust type `bool` into napi value", "Failed to convert rust type `bool` into napi value",
)?; )?;
@ -34,7 +34,7 @@ impl FromNapiValue for bool {
let mut ret = false; let mut ret = false;
check_status!( check_status!(
sys::napi_get_value_bool(env, napi_val, &mut ret), unsafe { sys::napi_get_value_bool(env, napi_val, &mut ret) },
"Failed to convert napi value into rust type `bool`", "Failed to convert napi value into rust type `bool`",
)?; )?;

View file

@ -70,12 +70,12 @@ impl FromNapiValue for Buffer {
let mut len = 0; let mut len = 0;
check_status!( check_status!(
sys::napi_get_buffer_info(env, napi_val, &mut buf, &mut len as *mut usize), unsafe { sys::napi_get_buffer_info(env, napi_val, &mut buf, &mut len as *mut usize) },
"Failed to convert napi buffer into rust Vec<u8>" "Failed to convert napi buffer into rust Vec<u8>"
)?; )?;
Ok(Self { Ok(Self {
inner: mem::ManuallyDrop::new(Vec::from_raw_parts(buf as *mut _, len, len)), inner: mem::ManuallyDrop::new(unsafe { Vec::from_raw_parts(buf as *mut _, len, len) }),
}) })
} }
} }
@ -85,14 +85,16 @@ impl ToNapiValue for Buffer {
let len = val.inner.len(); let len = val.inner.len();
let mut ret = ptr::null_mut(); let mut ret = ptr::null_mut();
check_status!( check_status!(
sys::napi_create_external_buffer( unsafe {
env, sys::napi_create_external_buffer(
len, env,
val.inner.as_mut_ptr() as *mut _, len,
Some(drop_buffer), val.inner.as_mut_ptr() as *mut _,
Box::into_raw(Box::new((len, val.inner.capacity()))) as *mut _, Some(drop_buffer),
&mut ret, Box::into_raw(Box::new((len, val.inner.capacity()))) as *mut _,
), &mut ret,
)
},
"Failed to create napi buffer" "Failed to create napi buffer"
)?; )?;

View file

@ -21,8 +21,8 @@ impl<
/// Backward compatible with `Either` in **v1** /// Backward compatible with `Either` in **v1**
pub unsafe fn raw(&self) -> napi_sys::napi_value { pub unsafe fn raw(&self) -> napi_sys::napi_value {
match &self { match &self {
Self::A(a) => a.raw(), Self::A(a) => unsafe { a.raw() },
Self::B(b) => b.raw(), Self::B(b) => unsafe { b.raw() },
} }
} }
} }
@ -68,9 +68,9 @@ impl<A: TypeName + FromNapiValue + ToNapiValue, B: TypeName + FromNapiValue + To
debug_assert!(A::value_type() != B::value_type(), "{}", ERROR_MSG); debug_assert!(A::value_type() != B::value_type(), "{}", ERROR_MSG);
let js_type = type_of!(env, napi_val)?; let js_type = type_of!(env, napi_val)?;
if js_type == A::value_type() { if js_type == A::value_type() {
A::from_napi_value(env, napi_val).map(Self::A) unsafe { A::from_napi_value(env, napi_val).map(Self::A) }
} else if js_type == B::value_type() { } else if js_type == B::value_type() {
B::from_napi_value(env, napi_val).map(Self::B) unsafe { B::from_napi_value(env, napi_val).map(Self::B) }
} else { } else {
Err(crate::Error::new( Err(crate::Error::new(
Status::InvalidArg, Status::InvalidArg,
@ -93,8 +93,8 @@ impl<A: TypeName + FromNapiValue + ToNapiValue, B: TypeName + FromNapiValue + To
value: Self, value: Self,
) -> crate::Result<crate::sys::napi_value> { ) -> crate::Result<crate::sys::napi_value> {
match value { match value {
Self::A(a) => A::to_napi_value(env, a), Self::A(a) => unsafe { A::to_napi_value(env, a) },
Self::B(b) => B::to_napi_value(env, b), Self::B(b) => unsafe { B::to_napi_value(env, b) },
} }
} }
} }
@ -146,11 +146,11 @@ impl<
); );
let js_type = type_of!(env, napi_val)?; let js_type = type_of!(env, napi_val)?;
if js_type == A::value_type() { if js_type == A::value_type() {
A::from_napi_value(env, napi_val).map(Self::A) unsafe { A::from_napi_value(env, napi_val).map(Self::A) }
} else if js_type == B::value_type() { } else if js_type == B::value_type() {
B::from_napi_value(env, napi_val).map(Self::B) unsafe { B::from_napi_value(env, napi_val).map(Self::B) }
} else if js_type == C::value_type() { } else if js_type == C::value_type() {
C::from_napi_value(env, napi_val).map(Self::C) unsafe { C::from_napi_value(env, napi_val).map(Self::C) }
} else { } else {
Err(crate::Error::new( Err(crate::Error::new(
Status::InvalidArg, Status::InvalidArg,
@ -177,9 +177,9 @@ impl<
value: Self, value: Self,
) -> crate::Result<crate::sys::napi_value> { ) -> crate::Result<crate::sys::napi_value> {
match value { match value {
Self::A(a) => A::to_napi_value(env, a), Self::A(a) => unsafe { A::to_napi_value(env, a) },
Self::B(b) => B::to_napi_value(env, b), Self::B(b) => unsafe { B::to_napi_value(env, b) },
Self::C(c) => C::to_napi_value(env, c), Self::C(c) => unsafe { C::to_napi_value(env, c) },
} }
} }
} }
@ -240,13 +240,13 @@ impl<
); );
let js_type = type_of!(env, napi_val)?; let js_type = type_of!(env, napi_val)?;
if js_type == A::value_type() { if js_type == A::value_type() {
A::from_napi_value(env, napi_val).map(Self::A) unsafe { A::from_napi_value(env, napi_val).map(Self::A) }
} else if js_type == B::value_type() { } else if js_type == B::value_type() {
B::from_napi_value(env, napi_val).map(Self::B) unsafe { B::from_napi_value(env, napi_val).map(Self::B) }
} else if js_type == C::value_type() { } else if js_type == C::value_type() {
C::from_napi_value(env, napi_val).map(Self::C) unsafe { C::from_napi_value(env, napi_val).map(Self::C) }
} else if js_type == D::value_type() { } else if js_type == D::value_type() {
D::from_napi_value(env, napi_val).map(Self::D) unsafe { D::from_napi_value(env, napi_val).map(Self::D) }
} else { } else {
Err(crate::Error::new( Err(crate::Error::new(
Status::InvalidArg, Status::InvalidArg,
@ -275,10 +275,10 @@ impl<
value: Self, value: Self,
) -> crate::Result<crate::sys::napi_value> { ) -> crate::Result<crate::sys::napi_value> {
match value { match value {
Self::A(a) => A::to_napi_value(env, a), Self::A(a) => unsafe { A::to_napi_value(env, a) },
Self::B(b) => B::to_napi_value(env, b), Self::B(b) => unsafe { B::to_napi_value(env, b) },
Self::C(c) => C::to_napi_value(env, c), Self::C(c) => unsafe { C::to_napi_value(env, c) },
Self::D(d) => D::to_napi_value(env, d), Self::D(d) => unsafe { D::to_napi_value(env, d) },
} }
} }
} }
@ -344,15 +344,15 @@ impl<
); );
let js_type = type_of!(env, napi_val)?; let js_type = type_of!(env, napi_val)?;
if js_type == A::value_type() { if js_type == A::value_type() {
A::from_napi_value(env, napi_val).map(Self::A) unsafe { A::from_napi_value(env, napi_val).map(Self::A) }
} else if js_type == B::value_type() { } else if js_type == B::value_type() {
B::from_napi_value(env, napi_val).map(Self::B) unsafe { B::from_napi_value(env, napi_val).map(Self::B) }
} else if js_type == C::value_type() { } else if js_type == C::value_type() {
C::from_napi_value(env, napi_val).map(Self::C) unsafe { C::from_napi_value(env, napi_val).map(Self::C) }
} else if js_type == D::value_type() { } else if js_type == D::value_type() {
D::from_napi_value(env, napi_val).map(Self::D) unsafe { D::from_napi_value(env, napi_val).map(Self::D) }
} else if js_type == E::value_type() { } else if js_type == E::value_type() {
E::from_napi_value(env, napi_val).map(Self::E) unsafe { E::from_napi_value(env, napi_val).map(Self::E) }
} else { } else {
Err(crate::Error::new( Err(crate::Error::new(
Status::InvalidArg, Status::InvalidArg,
@ -383,11 +383,11 @@ impl<
value: Self, value: Self,
) -> crate::Result<crate::sys::napi_value> { ) -> crate::Result<crate::sys::napi_value> {
match value { match value {
Self::A(a) => A::to_napi_value(env, a), Self::A(a) => unsafe { A::to_napi_value(env, a) },
Self::B(b) => B::to_napi_value(env, b), Self::B(b) => unsafe { B::to_napi_value(env, b) },
Self::C(c) => C::to_napi_value(env, c), Self::C(c) => unsafe { C::to_napi_value(env, c) },
Self::D(d) => D::to_napi_value(env, d), Self::D(d) => unsafe { D::to_napi_value(env, d) },
Self::E(e) => E::to_napi_value(env, e), Self::E(e) => unsafe { E::to_napi_value(env, e) },
} }
} }
} }

View file

@ -43,12 +43,12 @@ impl<T: 'static> FromNapiValue for External<T> {
) -> crate::Result<Self> { ) -> crate::Result<Self> {
let mut unknown_tagged_object = std::ptr::null_mut(); let mut unknown_tagged_object = std::ptr::null_mut();
check_status!( check_status!(
napi_sys::napi_get_value_external(env, napi_val, &mut unknown_tagged_object), unsafe { napi_sys::napi_get_value_external(env, napi_val, &mut unknown_tagged_object) },
"Failed to get external value" "Failed to get external value"
)?; )?;
let type_id = unknown_tagged_object as *const TypeId; let type_id = unknown_tagged_object as *const TypeId;
if *type_id == TypeId::of::<T>() { if unsafe { *type_id } == TypeId::of::<T>() {
let tagged_object = unknown_tagged_object as *mut TaggedObject<T>; let tagged_object = unknown_tagged_object as *mut TaggedObject<T>;
Ok(Self { Ok(Self {
obj: tagged_object, obj: tagged_object,
@ -97,13 +97,15 @@ impl<T: 'static> ToNapiValue for External<T> {
) -> crate::Result<napi_sys::napi_value> { ) -> crate::Result<napi_sys::napi_value> {
let mut napi_value = std::ptr::null_mut(); let mut napi_value = std::ptr::null_mut();
check_status!( check_status!(
napi_sys::napi_create_external( unsafe {
env, napi_sys::napi_create_external(
val.obj as *mut _, env,
Some(crate::raw_finalize::<T>), val.obj as *mut _,
Box::into_raw(Box::new(Some(val.size_hint as i64))) as *mut _, Some(crate::raw_finalize::<T>),
&mut napi_value Box::into_raw(Box::new(Some(val.size_hint as i64))) as *mut _,
), &mut napi_value,
)
},
"Create external value failed" "Create external value failed"
)?; )?;
@ -111,16 +113,18 @@ impl<T: 'static> ToNapiValue for External<T> {
if val.size_hint != 0 { if val.size_hint != 0 {
check_status!( check_status!(
napi_sys::napi_adjust_external_memory( unsafe {
env, napi_sys::napi_adjust_external_memory(
val.size_hint as i64, env,
adjusted_external_memory_size.as_mut_ptr() val.size_hint as i64,
), adjusted_external_memory_size.as_mut_ptr(),
)
},
"Adjust external memory failed" "Adjust external memory failed"
)?; )?;
}; };
val.adjusted_size = adjusted_external_memory_size.assume_init(); val.adjusted_size = unsafe { adjusted_external_memory_size.assume_init() };
Ok(napi_value) Ok(napi_value)
} }

View file

@ -25,7 +25,7 @@ where
obj.set(k.as_ref(), v)?; obj.set(k.as_ref(), v)?;
} }
Object::to_napi_value(raw_env, obj) unsafe { Object::to_napi_value(raw_env, obj) }
} }
} }
@ -35,7 +35,7 @@ where
V: FromNapiValue, V: FromNapiValue,
{ {
unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> { unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
let obj = Object::from_napi_value(env, napi_val)?; let obj = unsafe { Object::from_napi_value(env, napi_val)? };
let mut map = HashMap::new(); let mut map = HashMap::new();
for key in Object::keys(&obj)?.into_iter() { for key in Object::keys(&obj)?.into_iter() {
if let Some(val) = obj.get(&key)? { if let Some(val) = obj.get(&key)? {

View file

@ -38,7 +38,7 @@ impl ToNapiValue for Null {
let mut ret = ptr::null_mut(); let mut ret = ptr::null_mut();
check_status!( check_status!(
sys::napi_get_null(env, &mut ret), unsafe { sys::napi_get_null(env, &mut ret) },
"Failed to create napi null value" "Failed to create napi null value"
)?; )?;
@ -80,7 +80,7 @@ impl ToNapiValue for Undefined {
let mut ret = ptr::null_mut(); let mut ret = ptr::null_mut();
check_status!( check_status!(
sys::napi_get_undefined(env, &mut ret), unsafe { sys::napi_get_undefined(env, &mut ret) },
"Failed to create napi null value" "Failed to create napi null value"
)?; )?;

View file

@ -27,7 +27,7 @@ macro_rules! impl_number_conversions {
let mut ptr = std::ptr::null_mut(); let mut ptr = std::ptr::null_mut();
check_status!( check_status!(
sys::$create(env, val, &mut ptr), unsafe { sys::$create(env, val, &mut ptr) },
"Failed to convert rust type `{}` into napi value", "Failed to convert rust type `{}` into napi value",
$name, $name,
)?; )?;
@ -42,7 +42,7 @@ macro_rules! impl_number_conversions {
let mut ret = 0 as $t; let mut ret = 0 as $t;
check_status!( check_status!(
sys::$get(env, napi_val, &mut ret), unsafe { sys::$get(env, napi_val, &mut ret) },
"Failed to convert napi value into rust type `{}`", "Failed to convert napi value into rust type `{}`",
$name $name
)?; )?;

View file

@ -22,9 +22,11 @@ impl<T: FromNapiValue> FromNapiValue for Promise<T> {
napi_val: napi_sys::napi_value, napi_val: napi_sys::napi_value,
) -> crate::Result<Self> { ) -> crate::Result<Self> {
let mut then = ptr::null_mut(); let mut then = ptr::null_mut();
let then_c_string = CStr::from_bytes_with_nul_unchecked(b"then\0"); let then_c_string = unsafe { CStr::from_bytes_with_nul_unchecked(b"then\0") };
check_status!( check_status!(
napi_sys::napi_get_named_property(env, napi_val, then_c_string.as_ptr(), &mut then,), unsafe {
napi_sys::napi_get_named_property(env, napi_val, then_c_string.as_ptr(), &mut then)
},
"Failed to get then function" "Failed to get then function"
)?; )?;
let mut promise_after_then = ptr::null_mut(); let mut promise_after_then = ptr::null_mut();
@ -32,59 +34,69 @@ impl<T: FromNapiValue> FromNapiValue for Promise<T> {
let (tx, rx) = channel(); let (tx, rx) = channel();
let tx_ptr = Box::into_raw(Box::new(tx)); let tx_ptr = Box::into_raw(Box::new(tx));
check_status!( check_status!(
napi_sys::napi_create_function( unsafe {
env, napi_sys::napi_create_function(
then_c_string.as_ptr(), env,
4, then_c_string.as_ptr(),
Some(then_callback::<T>), 4,
tx_ptr as *mut _, Some(then_callback::<T>),
&mut then_js_cb, tx_ptr as *mut _,
), &mut then_js_cb,
)
},
"Failed to create then callback" "Failed to create then callback"
)?; )?;
check_status!( check_status!(
napi_sys::napi_call_function( unsafe {
env, napi_sys::napi_call_function(
napi_val, env,
then, napi_val,
1, then,
[then_js_cb].as_ptr(), 1,
&mut promise_after_then, [then_js_cb].as_ptr(),
), &mut promise_after_then,
)
},
"Failed to call then method" "Failed to call then method"
)?; )?;
let mut catch = ptr::null_mut(); let mut catch = ptr::null_mut();
let catch_c_string = CStr::from_bytes_with_nul_unchecked(b"catch\0"); let catch_c_string = unsafe { CStr::from_bytes_with_nul_unchecked(b"catch\0") };
check_status!( check_status!(
napi_sys::napi_get_named_property( unsafe {
env, napi_sys::napi_get_named_property(
promise_after_then, env,
catch_c_string.as_ptr(), promise_after_then,
&mut catch catch_c_string.as_ptr(),
), &mut catch,
)
},
"Failed to get then function" "Failed to get then function"
)?; )?;
let mut catch_js_cb = ptr::null_mut(); let mut catch_js_cb = ptr::null_mut();
check_status!( check_status!(
napi_sys::napi_create_function( unsafe {
env, napi_sys::napi_create_function(
catch_c_string.as_ptr(), env,
5, catch_c_string.as_ptr(),
Some(catch_callback::<T>), 5,
tx_ptr as *mut c_void, Some(catch_callback::<T>),
&mut catch_js_cb tx_ptr as *mut c_void,
), &mut catch_js_cb,
)
},
"Failed to create catch callback" "Failed to create catch callback"
)?; )?;
check_status!( check_status!(
napi_sys::napi_call_function( unsafe {
env, napi_sys::napi_call_function(
promise_after_then, env,
catch, promise_after_then,
1, catch,
[catch_js_cb].as_ptr(), 1,
ptr::null_mut() [catch_js_cb].as_ptr(),
), ptr::null_mut(),
)
},
"Failed to call catch method" "Failed to call catch method"
)?; )?;
Ok(Promise { Ok(Promise {
@ -114,20 +126,22 @@ unsafe extern "C" fn then_callback<T: FromNapiValue>(
let mut data = ptr::null_mut(); let mut data = ptr::null_mut();
let mut resolved_value: [napi_sys::napi_value; 1] = [ptr::null_mut()]; let mut resolved_value: [napi_sys::napi_value; 1] = [ptr::null_mut()];
let mut this = ptr::null_mut(); let mut this = ptr::null_mut();
let get_cb_status = napi_sys::napi_get_cb_info( let get_cb_status = unsafe {
env, napi_sys::napi_get_cb_info(
info, env,
&mut 1, info,
resolved_value.as_mut_ptr(), &mut 1,
&mut this, resolved_value.as_mut_ptr(),
&mut data, &mut this,
); &mut data,
)
};
debug_assert!( debug_assert!(
get_cb_status == napi_sys::Status::napi_ok, get_cb_status == napi_sys::Status::napi_ok,
"Get callback info from Promise::then failed" "Get callback info from Promise::then failed"
); );
let resolve_value_t = Box::new(T::from_napi_value(env, resolved_value[0])); let resolve_value_t = Box::new(unsafe { T::from_napi_value(env, resolved_value[0]) });
let sender = Box::from_raw(data as *mut Sender<*mut Result<T>>); let sender = unsafe { Box::from_raw(data as *mut Sender<*mut Result<T>>) };
sender sender
.send(Box::into_raw(resolve_value_t)) .send(Box::into_raw(resolve_value_t))
.expect("Send Promise resolved value error"); .expect("Send Promise resolved value error");
@ -142,26 +156,29 @@ unsafe extern "C" fn catch_callback<T: FromNapiValue>(
let mut rejected_value: [napi_sys::napi_value; 1] = [ptr::null_mut()]; let mut rejected_value: [napi_sys::napi_value; 1] = [ptr::null_mut()];
let mut this = ptr::null_mut(); let mut this = ptr::null_mut();
let mut argc = 1; let mut argc = 1;
let get_cb_status = napi_sys::napi_get_cb_info( let get_cb_status = unsafe {
env, napi_sys::napi_get_cb_info(
info, env,
&mut argc, info,
rejected_value.as_mut_ptr(), &mut argc,
&mut this, rejected_value.as_mut_ptr(),
&mut data, &mut this,
); &mut data,
)
};
debug_assert!( debug_assert!(
get_cb_status == napi_sys::Status::napi_ok, get_cb_status == napi_sys::Status::napi_ok,
"Get callback info from Promise::catch failed" "Get callback info from Promise::catch failed"
); );
let rejected_value = rejected_value[0]; let rejected_value = rejected_value[0];
let mut error_ref = ptr::null_mut(); let mut error_ref = ptr::null_mut();
let create_ref_status = napi_sys::napi_create_reference(env, rejected_value, 1, &mut error_ref); let create_ref_status =
unsafe { napi_sys::napi_create_reference(env, rejected_value, 1, &mut error_ref) };
debug_assert!( debug_assert!(
create_ref_status == napi_sys::Status::napi_ok, create_ref_status == napi_sys::Status::napi_ok,
"Create Error reference failed" "Create Error reference failed"
); );
let sender = Box::from_raw(data as *mut Sender<*mut Result<T>>); let sender = unsafe { Box::from_raw(data as *mut Sender<*mut Result<T>>) };
sender sender
.send(Box::into_raw(Box::new(Err(Error::from(error_ref))))) .send(Box::into_raw(Box::new(Err(Error::from(error_ref)))))
.expect("Send Promise resolved value error"); .expect("Send Promise resolved value error");

View file

@ -9,25 +9,25 @@ use super::{FromNapiValue, Object, ToNapiValue};
impl ToNapiValue for Value { impl ToNapiValue for Value {
unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> { unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
match val { match val {
Value::Null => Null::to_napi_value(env, Null), Value::Null => unsafe { Null::to_napi_value(env, Null) },
Value::Bool(b) => bool::to_napi_value(env, b), Value::Bool(b) => unsafe { bool::to_napi_value(env, b) },
Value::Number(n) => { Value::Number(n) => {
if n.is_i64() { if n.is_i64() {
i64::to_napi_value(env, n.as_i64().unwrap()) unsafe { i64::to_napi_value(env, n.as_i64().unwrap()) }
} else if n.is_f64() { } else if n.is_f64() {
f64::to_napi_value(env, n.as_f64().unwrap()) unsafe { f64::to_napi_value(env, n.as_f64().unwrap()) }
} else { } else {
let n = n.as_u64().unwrap(); let n = n.as_u64().unwrap();
if n > u32::MAX as u64 { if n > u32::MAX as u64 {
todo!("impl BigInt") todo!("impl BigInt")
} else { } else {
u32::to_napi_value(env, n as u32) unsafe { u32::to_napi_value(env, n as u32) }
} }
} }
} }
Value::String(s) => String::to_napi_value(env, s), Value::String(s) => unsafe { String::to_napi_value(env, s) },
Value::Array(arr) => Vec::<Value>::to_napi_value(env, arr), Value::Array(arr) => unsafe { Vec::<Value>::to_napi_value(env, arr) },
Value::Object(obj) => Map::to_napi_value(env, obj), Value::Object(obj) => unsafe { Map::to_napi_value(env, obj) },
} }
} }
} }
@ -36,25 +36,25 @@ impl FromNapiValue for Value {
unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> { unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
let ty = type_of!(env, napi_val)?; let ty = type_of!(env, napi_val)?;
let val = match ty { let val = match ty {
ValueType::Boolean => Value::Bool(bool::from_napi_value(env, napi_val)?), ValueType::Boolean => Value::Bool(unsafe { bool::from_napi_value(env, napi_val)? }),
ValueType::Number => { ValueType::Number => {
return Err(Error::new( return Err(Error::new(
Status::InvalidArg, Status::InvalidArg,
"Js Number is not be able to convert to rust.".to_owned(), "Js Number is not be able to convert to rust.".to_owned(),
)); ));
} }
ValueType::String => Value::String(String::from_napi_value(env, napi_val)?), ValueType::String => Value::String(unsafe { String::from_napi_value(env, napi_val)? }),
ValueType::Object => { ValueType::Object => {
let mut is_arr = false; let mut is_arr = false;
check_status!( check_status!(
sys::napi_is_array(env, napi_val, &mut is_arr), unsafe { sys::napi_is_array(env, napi_val, &mut is_arr) },
"Failed to detect whether given js is an array" "Failed to detect whether given js is an array"
)?; )?;
if is_arr { if is_arr {
Value::Array(Vec::<Value>::from_napi_value(env, napi_val)?) Value::Array(unsafe { Vec::<Value>::from_napi_value(env, napi_val)? })
} else { } else {
Value::Object(Map::<String, Value>::from_napi_value(env, napi_val)?) Value::Object(unsafe { Map::<String, Value>::from_napi_value(env, napi_val)? })
} }
} }
#[cfg(feature = "napi6")] #[cfg(feature = "napi6")]
@ -74,7 +74,7 @@ impl ToNapiValue for Map<String, Value> {
obj.set(k, v)?; obj.set(k, v)?;
} }
Object::to_napi_value(env, obj) unsafe { Object::to_napi_value(env, obj) }
} }
} }

View file

@ -22,7 +22,7 @@ impl ToNapiValue for String {
let mut ptr = ptr::null_mut(); let mut ptr = ptr::null_mut();
check_status!( check_status!(
sys::napi_create_string_utf8(env, val.as_ptr() as *const _, val.len(), &mut ptr), unsafe { sys::napi_create_string_utf8(env, val.as_ptr() as *const _, val.len(), &mut ptr) },
"Failed to convert rust `String` into napi `string`" "Failed to convert rust `String` into napi `string`"
)?; )?;
@ -35,7 +35,7 @@ impl FromNapiValue for String {
let mut len = 0; let mut len = 0;
check_status!( check_status!(
sys::napi_get_value_string_utf8(env, napi_val, ptr::null_mut(), 0, &mut len), unsafe { sys::napi_get_value_string_utf8(env, napi_val, ptr::null_mut(), 0, &mut len) },
"Failed to convert napi `string` into rust type `String`", "Failed to convert napi `string` into rust type `String`",
)?; )?;
@ -47,11 +47,13 @@ impl FromNapiValue for String {
let mut written_char_count = 0; let mut written_char_count = 0;
check_status!( check_status!(
sys::napi_get_value_string_utf8(env, napi_val, buf_ptr, len, &mut written_char_count), unsafe {
sys::napi_get_value_string_utf8(env, napi_val, buf_ptr, len, &mut written_char_count)
},
"Failed to convert napi `string` into rust type `String`" "Failed to convert napi `string` into rust type `String`"
)?; )?;
match CStr::from_ptr(buf_ptr).to_str() { match unsafe { CStr::from_ptr(buf_ptr) }.to_str() {
Err(e) => Err(Error::new( Err(e) => Err(Error::new(
Status::InvalidArg, Status::InvalidArg,
format!("Failed to read utf8 string, {}", e), format!("Failed to read utf8 string, {}", e),
@ -76,7 +78,7 @@ impl FromNapiValue for &str {
let mut len = 0; let mut len = 0;
check_status!( check_status!(
sys::napi_get_value_string_utf8(env, napi_val, ptr::null_mut(), 0, &mut len), unsafe { sys::napi_get_value_string_utf8(env, napi_val, ptr::null_mut(), 0, &mut len) },
"Failed to convert napi `string` into rust type `String`", "Failed to convert napi `string` into rust type `String`",
)?; )?;
@ -87,7 +89,9 @@ impl FromNapiValue for &str {
let mut written_char_count = 0; let mut written_char_count = 0;
check_status!( check_status!(
sys::napi_get_value_string_utf8(env, napi_val, buf_ptr, len, &mut written_char_count), unsafe {
sys::napi_get_value_string_utf8(env, napi_val, buf_ptr, len, &mut written_char_count)
},
"Failed to convert napi `string` into rust type `String`" "Failed to convert napi `string` into rust type `String`"
)?; )?;
@ -98,16 +102,18 @@ impl FromNapiValue for &str {
// So we can safely forget the `Vec<u8>` here which could fix the memory issue here. // So we can safely forget the `Vec<u8>` here which could fix the memory issue here.
// FIXME: This implementation should be removed in next major release. // FIXME: This implementation should be removed in next major release.
let mut temporary_external_object = ptr::null_mut(); let mut temporary_external_object = ptr::null_mut();
check_status!(sys::napi_create_external( check_status!(unsafe {
env, sys::napi_create_external(
buf_ptr as *mut c_void, env,
Some(release_string), buf_ptr as *mut c_void,
Box::into_raw(Box::new(len)) as *mut c_void, Some(release_string),
&mut temporary_external_object, Box::into_raw(Box::new(len)) as *mut c_void,
))?; &mut temporary_external_object,
)
})?;
std::mem::forget(ret); std::mem::forget(ret);
match CStr::from_ptr(buf_ptr).to_str() { match unsafe { CStr::from_ptr(buf_ptr) }.to_str() {
Err(e) => Err(Error::new( Err(e) => Err(Error::new(
Status::InvalidArg, Status::InvalidArg,
format!("Failed to read utf8 string, {}", e), format!("Failed to read utf8 string, {}", e),
@ -119,7 +125,7 @@ impl FromNapiValue for &str {
impl ToNapiValue for &str { impl ToNapiValue for &str {
unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> { unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
String::to_napi_value(env, val.to_owned()) unsafe { String::to_napi_value(env, val.to_owned()) }
} }
} }
@ -161,7 +167,7 @@ impl FromNapiValue for Utf16String {
let mut len = 0; let mut len = 0;
check_status!( check_status!(
sys::napi_get_value_string_utf16(env, napi_val, ptr::null_mut(), 0, &mut len), unsafe { sys::napi_get_value_string_utf16(env, napi_val, ptr::null_mut(), 0, &mut len) },
"Failed to convert napi `utf16 string` into rust type `String`", "Failed to convert napi `utf16 string` into rust type `String`",
)?; )?;
@ -171,13 +177,15 @@ impl FromNapiValue for Utf16String {
let mut written_char_count = 0; let mut written_char_count = 0;
check_status!( check_status!(
sys::napi_get_value_string_utf16( unsafe {
env, sys::napi_get_value_string_utf16(
napi_val, env,
ret.as_mut_ptr(), napi_val,
len, ret.as_mut_ptr(),
&mut written_char_count len,
), &mut written_char_count,
)
},
"Failed to convert napi `utf16 string` into rust type `String`", "Failed to convert napi `utf16 string` into rust type `String`",
)?; )?;
@ -200,7 +208,9 @@ impl ToNapiValue for Utf16String {
let encoded = val.0.encode_utf16().collect::<Vec<_>>(); let encoded = val.0.encode_utf16().collect::<Vec<_>>();
check_status!( check_status!(
sys::napi_create_string_utf16(env, encoded.as_ptr() as *const _, encoded.len(), &mut ptr), unsafe {
sys::napi_create_string_utf16(env, encoded.as_ptr() as *const _, encoded.len(), &mut ptr)
},
"Failed to convert napi `string` into rust type `String`" "Failed to convert napi `string` into rust type `String`"
)?; )?;
@ -250,7 +260,7 @@ pub mod latin1_string {
let mut len = 0; let mut len = 0;
check_status!( check_status!(
sys::napi_get_value_string_latin1(env, napi_val, ptr::null_mut(), 0, &mut len), unsafe { sys::napi_get_value_string_latin1(env, napi_val, ptr::null_mut(), 0, &mut len) },
"Failed to convert napi `latin1 string` into rust type `String`", "Failed to convert napi `latin1 string` into rust type `String`",
)?; )?;
@ -264,17 +274,22 @@ pub mod latin1_string {
mem::forget(buf); mem::forget(buf);
check_status!( check_status!(
sys::napi_get_value_string_latin1(env, napi_val, buf_ptr, len, &mut written_char_count), unsafe {
sys::napi_get_value_string_latin1(env, napi_val, buf_ptr, len, &mut written_char_count)
},
"Failed to convert napi `latin1 string` into rust type `String`" "Failed to convert napi `latin1 string` into rust type `String`"
)?; )?;
let buf = Vec::from_raw_parts(buf_ptr as *mut _, written_char_count, written_char_count); let buf =
unsafe { Vec::from_raw_parts(buf_ptr as *mut _, written_char_count, written_char_count) };
let mut dst_slice = vec![0; buf.len() * 2]; let mut dst_slice = vec![0; buf.len() * 2];
let written = let written =
encoding_rs::mem::convert_latin1_to_utf8(buf.as_slice(), dst_slice.as_mut_slice()); encoding_rs::mem::convert_latin1_to_utf8(buf.as_slice(), dst_slice.as_mut_slice());
dst_slice.truncate(written); dst_slice.truncate(written);
Ok(Latin1String(String::from_utf8_unchecked(dst_slice))) Ok(Latin1String(unsafe {
String::from_utf8_unchecked(dst_slice)
}))
} }
} }
@ -286,7 +301,9 @@ pub mod latin1_string {
encoding_rs::mem::convert_utf8_to_latin1_lossy(val.0.as_bytes(), dst.as_mut_slice()); encoding_rs::mem::convert_utf8_to_latin1_lossy(val.0.as_bytes(), dst.as_mut_slice());
check_status!( check_status!(
sys::napi_create_string_latin1(env, dst.as_ptr() as *const _, dst.len(), &mut ptr), unsafe {
sys::napi_create_string_latin1(env, dst.as_ptr() as *const _, dst.len(), &mut ptr)
},
"Failed to convert rust type `String` into napi `latin1 string`" "Failed to convert rust type `String` into napi `latin1 string`"
)?; )?;
@ -296,6 +313,6 @@ pub mod latin1_string {
} }
unsafe extern "C" fn release_string(_env: sys::napi_env, data: *mut c_void, len: *mut c_void) { unsafe extern "C" fn release_string(_env: sys::napi_env, data: *mut c_void, len: *mut c_void) {
let len = *Box::from_raw(len as *mut usize); let len = unsafe { *Box::from_raw(len as *mut usize) };
Vec::from_raw_parts(data as *mut u8, len, len); unsafe { Vec::from_raw_parts(data as *mut u8, len, len) };
} }

View file

@ -24,25 +24,27 @@ impl ToNapiValue for Symbol {
val: Self, val: Self,
) -> crate::Result<napi_sys::napi_value> { ) -> crate::Result<napi_sys::napi_value> {
let mut symbol_value = ptr::null_mut(); let mut symbol_value = ptr::null_mut();
check_status!(napi_sys::napi_create_symbol( check_status!(unsafe {
env, napi_sys::napi_create_symbol(
match val.desc { env,
Some(desc) => { match val.desc {
let mut desc_string = ptr::null_mut(); Some(desc) => {
let desc_len = desc.len(); let mut desc_string = ptr::null_mut();
let desc_c_string = CString::new(desc)?; let desc_len = desc.len();
check_status!(napi_sys::napi_create_string_utf8( let desc_c_string = CString::new(desc)?;
env, check_status!(napi_sys::napi_create_string_utf8(
desc_c_string.as_ptr(), env,
desc_len, desc_c_string.as_ptr(),
&mut desc_string desc_len,
))?; &mut desc_string
desc_string ))?;
} desc_string
None => ptr::null_mut(), }
}, None => ptr::null_mut(),
&mut symbol_value },
))?; &mut symbol_value,
)
})?;
Ok(symbol_value) Ok(symbol_value)
} }
} }

View file

@ -56,7 +56,7 @@ impl FromNapiValue for AbortSignal {
env: napi_sys::napi_env, env: napi_sys::napi_env,
napi_val: napi_sys::napi_value, napi_val: napi_sys::napi_value,
) -> crate::Result<Self> { ) -> crate::Result<Self> {
let mut signal = JsObject::from_raw_unchecked(env, napi_val); let mut signal = unsafe { JsObject::from_raw_unchecked(env, napi_val) };
let async_work_inner: Rc<AtomicPtr<napi_sys::napi_async_work__>> = let async_work_inner: Rc<AtomicPtr<napi_sys::napi_async_work__>> =
Rc::new(AtomicPtr::new(ptr::null_mut())); Rc::new(AtomicPtr::new(ptr::null_mut()));
let raw_promise: Rc<AtomicPtr<napi_sys::napi_deferred__>> = let raw_promise: Rc<AtomicPtr<napi_sys::napi_deferred__>> =
@ -67,15 +67,17 @@ impl FromNapiValue for AbortSignal {
raw_deferred: raw_promise.clone(), raw_deferred: raw_promise.clone(),
status: task_status.clone(), status: task_status.clone(),
}; };
let js_env = Env::from_raw(env); let js_env = unsafe { Env::from_raw(env) };
check_status!(napi_sys::napi_wrap( check_status!(unsafe {
env, napi_sys::napi_wrap(
signal.0.value, env,
Box::into_raw(Box::new(abort_controller)) as *mut _, signal.0.value,
Some(async_task_abort_controller_finalize), Box::into_raw(Box::new(abort_controller)) as *mut _,
ptr::null_mut(), Some(async_task_abort_controller_finalize),
ptr::null_mut(), ptr::null_mut(),
))?; ptr::null_mut(),
)
})?;
signal.set_named_property("onabort", js_env.create_function("onabort", on_abort)?)?; signal.set_named_property("onabort", js_env.create_function("onabort", on_abort)?)?;
Ok(AbortSignal { Ok(AbortSignal {
raw_work: async_work_inner, raw_work: async_work_inner,
@ -162,5 +164,5 @@ unsafe extern "C" fn async_task_abort_controller_finalize(
finalize_data: *mut c_void, finalize_data: *mut c_void,
_finalize_hint: *mut c_void, _finalize_hint: *mut c_void,
) { ) {
Box::from_raw(finalize_data as *mut AbortSignal); unsafe { Box::from_raw(finalize_data as *mut AbortSignal) };
} }

View file

@ -22,12 +22,12 @@ pub unsafe extern "C" fn raw_finalize_unchecked<T>(
finalize_hint: *mut c_void, finalize_hint: *mut c_void,
) { ) {
let obj = finalize_data as *mut T; let obj = finalize_data as *mut T;
Box::from_raw(obj); unsafe { Box::from_raw(obj) };
if !finalize_hint.is_null() { if !finalize_hint.is_null() {
let size_hint = *Box::from_raw(finalize_hint as *mut Option<i64>); let size_hint = unsafe { *Box::from_raw(finalize_hint as *mut Option<i64>) };
if let Some(changed) = size_hint { if let Some(changed) = size_hint {
let mut adjusted = 0i64; let mut adjusted = 0i64;
let status = sys::napi_adjust_external_memory(env, -changed, &mut adjusted); let status = unsafe { sys::napi_adjust_external_memory(env, -changed, &mut adjusted) };
debug_assert!( debug_assert!(
status == sys::Status::napi_ok, status == sys::Status::napi_ok,
"Calling napi_adjust_external_memory failed" "Calling napi_adjust_external_memory failed"
@ -45,6 +45,8 @@ pub unsafe extern "C" fn drop_buffer(
finalize_hint: *mut c_void, finalize_hint: *mut c_void,
) { ) {
let length_ptr = finalize_hint as *mut (usize, usize); let length_ptr = finalize_hint as *mut (usize, usize);
let (length, cap) = *Box::from_raw(length_ptr); unsafe {
mem::drop(Vec::from_raw_parts(finalize_data as *mut u8, length, cap)); let (length, cap) = *Box::from_raw(length_ptr);
mem::drop(Vec::from_raw_parts(finalize_data as *mut u8, length, cap));
}
} }

View file

@ -167,18 +167,20 @@ unsafe extern "C" fn napi_register_module_v1(
} else { } else {
check_status_or_throw!( check_status_or_throw!(
env, env,
sys::napi_create_object(env, &mut exports_js_mod), unsafe { sys::napi_create_object(env, &mut exports_js_mod) },
"Create export JavaScript Object [{}] failed", "Create export JavaScript Object [{}] failed",
js_mod_str js_mod_str
); );
check_status_or_throw!( check_status_or_throw!(
env, env,
sys::napi_set_named_property( unsafe {
env, sys::napi_set_named_property(
exports, env,
js_mod_str.as_ptr() as *const _, exports,
exports_js_mod js_mod_str.as_ptr() as *const _,
), exports_js_mod,
)
},
"Set exports Object [{}] into exports object failed", "Set exports Object [{}] into exports object failed",
js_mod_str js_mod_str
); );
@ -186,7 +188,7 @@ unsafe extern "C" fn napi_register_module_v1(
} }
} }
for (name, callback) in items { for (name, callback) in items {
let js_name = CStr::from_bytes_with_nul_unchecked(name.as_bytes()); let js_name = unsafe { CStr::from_bytes_with_nul_unchecked(name.as_bytes()) };
unsafe { unsafe {
if let Err(e) = callback(env).and_then(|v| { if let Err(e) = callback(env).and_then(|v| {
check_status!( check_status!(
@ -299,18 +301,23 @@ unsafe extern "C" fn napi_register_module_v1(
}); });
#[cfg(feature = "compat-mode")] #[cfg(feature = "compat-mode")]
MODULE_EXPORTS.borrow_mut().iter().for_each(|callback| { MODULE_EXPORTS
if let Err(e) = callback(env, exports) { .borrow_mut()
JsError::from(e).throw_into(env); .iter()
} .for_each(|callback| unsafe {
}); if let Err(e) = callback(env, exports) {
JsError::from(e).throw_into(env);
}
});
#[cfg(all(feature = "tokio_rt", feature = "napi4"))] #[cfg(all(feature = "tokio_rt", feature = "napi4"))]
{ {
let _ = crate::tokio_runtime::RT.clone(); let _ = crate::tokio_runtime::RT.clone();
crate::tokio_runtime::TOKIO_RT_REF_COUNT.fetch_add(1, Ordering::Relaxed); crate::tokio_runtime::TOKIO_RT_REF_COUNT.fetch_add(1, Ordering::Relaxed);
assert_eq!( assert_eq!(
sys::napi_add_env_cleanup_hook(env, Some(crate::shutdown_tokio_rt), ptr::null_mut()), unsafe {
sys::napi_add_env_cleanup_hook(env, Some(crate::shutdown_tokio_rt), ptr::null_mut())
},
sys::Status::napi_ok sys::Status::napi_ok
); );
} }
@ -323,12 +330,14 @@ pub(crate) unsafe extern "C" fn noop(
_info: sys::napi_callback_info, _info: sys::napi_callback_info,
) -> sys::napi_value { ) -> sys::napi_value {
if !crate::bindgen_runtime::___CALL_FROM_FACTORY.load(std::sync::atomic::Ordering::Relaxed) { if !crate::bindgen_runtime::___CALL_FROM_FACTORY.load(std::sync::atomic::Ordering::Relaxed) {
sys::napi_throw_error( unsafe {
env, sys::napi_throw_error(
ptr::null_mut(), env,
CStr::from_bytes_with_nul_unchecked(b"Class contains no `constructor`, can not new it!") ptr::null_mut(),
.as_ptr(), CStr::from_bytes_with_nul_unchecked(b"Class contains no `constructor`, can not new it!")
); .as_ptr(),
);
}
} }
ptr::null_mut() ptr::null_mut()
} }

View file

@ -169,13 +169,8 @@ impl Env {
len: usize, len: usize,
) -> Result<JsString> { ) -> Result<JsString> {
let mut raw_value = ptr::null_mut(); let mut raw_value = ptr::null_mut();
check_status!(sys::napi_create_string_utf8( check_status!(unsafe { sys::napi_create_string_utf8(self.0, data_ptr, len, &mut raw_value) })?;
self.0, Ok(unsafe { JsString::from_raw_unchecked(self.0, raw_value) })
data_ptr,
len,
&mut raw_value
))?;
Ok(JsString::from_raw_unchecked(self.0, raw_value))
} }
pub fn create_string_utf16(&self, chars: &[u16]) -> Result<JsString> { pub fn create_string_utf16(&self, chars: &[u16]) -> Result<JsString> {
@ -301,28 +296,30 @@ impl Env {
Finalize: FnOnce(Hint, Env), Finalize: FnOnce(Hint, Env),
{ {
let mut raw_value = ptr::null_mut(); let mut raw_value = ptr::null_mut();
check_status!(sys::napi_create_external_buffer( check_status!(unsafe {
self.0, sys::napi_create_external_buffer(
length, self.0,
data as *mut c_void, length,
Some( data as *mut c_void,
raw_finalize_with_custom_callback::<Hint, Finalize> Some(
as unsafe extern "C" fn( raw_finalize_with_custom_callback::<Hint, Finalize>
env: sys::napi_env, as unsafe extern "C" fn(
finalize_data: *mut c_void, env: sys::napi_env,
finalize_hint: *mut c_void, finalize_data: *mut c_void,
) finalize_hint: *mut c_void,
), ),
Box::into_raw(Box::new((hint, finalize_callback))) as *mut c_void, ),
&mut raw_value, Box::into_raw(Box::new((hint, finalize_callback))) as *mut c_void,
))?; &mut raw_value,
)
})?;
Ok(JsBufferValue::new( Ok(JsBufferValue::new(
JsBuffer(Value { JsBuffer(Value {
env: self.0, env: self.0,
value: raw_value, value: raw_value,
value_type: ValueType::Object, value_type: ValueType::Object,
}), }),
mem::ManuallyDrop::new(Vec::from_raw_parts(data as *mut u8, length, length)), mem::ManuallyDrop::new(unsafe { Vec::from_raw_parts(data as *mut u8, length, length) }),
)) ))
} }
@ -426,21 +423,23 @@ impl Env {
Finalize: FnOnce(Hint, Env), Finalize: FnOnce(Hint, Env),
{ {
let mut raw_value = ptr::null_mut(); let mut raw_value = ptr::null_mut();
check_status!(sys::napi_create_external_arraybuffer( check_status!(unsafe {
self.0, sys::napi_create_external_arraybuffer(
data as *mut c_void, self.0,
length, data as *mut c_void,
Some( length,
raw_finalize_with_custom_callback::<Hint, Finalize> Some(
as unsafe extern "C" fn( raw_finalize_with_custom_callback::<Hint, Finalize>
env: sys::napi_env, as unsafe extern "C" fn(
finalize_data: *mut c_void, env: sys::napi_env,
finalize_hint: *mut c_void, finalize_data: *mut c_void,
) finalize_hint: *mut c_void,
), ),
Box::into_raw(Box::new((hint, finalize_callback))) as *mut c_void, ),
&mut raw_value, Box::into_raw(Box::new((hint, finalize_callback))) as *mut c_void,
))?; &mut raw_value,
)
})?;
Ok(JsArrayBufferValue::new( Ok(JsArrayBufferValue::new(
JsArrayBuffer(Value { JsArrayBuffer(Value {
env: self.0, env: self.0,
@ -505,14 +504,16 @@ impl Env {
let (raw_this, ref raw_args, closure_data_ptr) = { let (raw_this, ref raw_args, closure_data_ptr) = {
let argc = { let argc = {
let mut argc = 0; let mut argc = 0;
let status = sys::napi_get_cb_info( let status = unsafe {
raw_env, sys::napi_get_cb_info(
cb_info, raw_env,
&mut argc, cb_info,
ptr::null_mut(), &mut argc,
ptr::null_mut(), ptr::null_mut(),
ptr::null_mut(), ptr::null_mut(),
); ptr::null_mut(),
)
};
debug_assert!( debug_assert!(
Status::from(status) == Status::Ok, Status::from(status) == Status::Ok,
"napi_get_cb_info failed" "napi_get_cb_info failed"
@ -523,14 +524,16 @@ impl Env {
let mut raw_this = ptr::null_mut(); let mut raw_this = ptr::null_mut();
let mut closure_data_ptr = ptr::null_mut(); let mut closure_data_ptr = ptr::null_mut();
let status = sys::napi_get_cb_info( let status = unsafe {
raw_env, sys::napi_get_cb_info(
cb_info, raw_env,
&mut { argc }, cb_info,
raw_args.as_mut_ptr(), &mut { argc },
&mut raw_this, raw_args.as_mut_ptr(),
&mut closure_data_ptr, &mut raw_this,
); &mut closure_data_ptr,
)
};
debug_assert!( debug_assert!(
Status::from(status) == Status::Ok, Status::from(status) == Status::Ok,
"napi_get_cb_info failed" "napi_get_cb_info failed"
@ -538,13 +541,15 @@ impl Env {
(raw_this, raw_args, closure_data_ptr) (raw_this, raw_args, closure_data_ptr)
}; };
let closure: &F = closure_data_ptr let closure: &F = unsafe {
.cast::<F>() closure_data_ptr
.as_ref() .cast::<F>()
.expect("`napi_get_cb_info` should have yielded non-`NULL` assoc data"); .as_ref()
let env = &mut Env::from_raw(raw_env); .expect("`napi_get_cb_info` should have yielded non-`NULL` assoc data")
};
let env = &mut unsafe { Env::from_raw(raw_env) };
let ctx = CallContext::new(env, cb_info, raw_this, raw_args, raw_args.len()); let ctx = CallContext::new(env, cb_info, raw_this, raw_args, raw_args.len());
closure(ctx).map(|ret: R| ret.raw()) closure(ctx).map(|ret: R| unsafe { ret.raw() })
})) }))
.map_err(|e| { .map_err(|e| {
Error::from_reason(format!( Error::from_reason(format!(
@ -560,7 +565,7 @@ impl Env {
}) })
.and_then(|v| v) .and_then(|v| v)
.unwrap_or_else(|e| { .unwrap_or_else(|e| {
JsError::from(e).throw_into(raw_env); unsafe { JsError::from(e).throw_into(raw_env) };
ptr::null_mut() ptr::null_mut()
}) })
} }
@ -591,7 +596,7 @@ impl Env {
closure_data_ptr: *mut c_void, closure_data_ptr: *mut c_void,
_finalize_hint: *mut c_void, _finalize_hint: *mut c_void,
) { ) {
drop(Box::<F>::from_raw(closure_data_ptr.cast())) drop(unsafe { Box::<F>::from_raw(closure_data_ptr.cast()) })
} }
finalize_box_trampoline::<F> finalize_box_trampoline::<F>
@ -1282,8 +1287,8 @@ unsafe extern "C" fn drop_buffer(
hint: *mut c_void, hint: *mut c_void,
) { ) {
let length_ptr = hint as *mut (usize, usize); let length_ptr = hint as *mut (usize, usize);
let (length, cap) = *Box::from_raw(length_ptr); let (length, cap) = unsafe { *Box::from_raw(length_ptr) };
mem::drop(Vec::from_raw_parts(finalize_data as *mut u8, length, cap)); mem::drop(unsafe { Vec::from_raw_parts(finalize_data as *mut u8, length, cap) });
} }
pub(crate) unsafe extern "C" fn raw_finalize<T>( pub(crate) unsafe extern "C" fn raw_finalize<T>(
@ -1292,13 +1297,13 @@ pub(crate) unsafe extern "C" fn raw_finalize<T>(
finalize_hint: *mut c_void, finalize_hint: *mut c_void,
) { ) {
let tagged_object = finalize_data as *mut TaggedObject<T>; let tagged_object = finalize_data as *mut TaggedObject<T>;
Box::from_raw(tagged_object); unsafe { Box::from_raw(tagged_object) };
if !finalize_hint.is_null() { if !finalize_hint.is_null() {
let size_hint = *Box::from_raw(finalize_hint as *mut Option<i64>); let size_hint = unsafe { *Box::from_raw(finalize_hint as *mut Option<i64>) };
if let Some(changed) = size_hint { if let Some(changed) = size_hint {
if changed != 0 { if changed != 0 {
let mut adjusted = 0i64; let mut adjusted = 0i64;
let status = sys::napi_adjust_external_memory(env, -changed, &mut adjusted); let status = unsafe { sys::napi_adjust_external_memory(env, -changed, &mut adjusted) };
debug_assert!( debug_assert!(
status == sys::Status::napi_ok, status == sys::Status::napi_ok,
"Calling napi_adjust_external_memory failed" "Calling napi_adjust_external_memory failed"
@ -1318,9 +1323,9 @@ unsafe extern "C" fn set_instance_finalize_callback<T, Hint, F>(
Hint: 'static, Hint: 'static,
F: FnOnce(FinalizeContext<T, Hint>), F: FnOnce(FinalizeContext<T, Hint>),
{ {
let (value, callback) = *Box::from_raw(finalize_data as *mut (TaggedObject<T>, F)); let (value, callback) = unsafe { *Box::from_raw(finalize_data as *mut (TaggedObject<T>, F)) };
let hint = *Box::from_raw(finalize_hint as *mut Hint); let hint = unsafe { *Box::from_raw(finalize_hint as *mut Hint) };
let env = Env::from_raw(raw_env); let env = unsafe { Env::from_raw(raw_env) };
callback(FinalizeContext { callback(FinalizeContext {
value: value.object.unwrap(), value: value.object.unwrap(),
hint, hint,
@ -1330,7 +1335,7 @@ unsafe extern "C" fn set_instance_finalize_callback<T, Hint, F>(
#[cfg(feature = "napi3")] #[cfg(feature = "napi3")]
unsafe extern "C" fn cleanup_env<T: 'static>(hook_data: *mut c_void) { unsafe extern "C" fn cleanup_env<T: 'static>(hook_data: *mut c_void) {
let cleanup_env_hook = Box::from_raw(hook_data as *mut CleanupEnvHookData<T>); let cleanup_env_hook = unsafe { Box::from_raw(hook_data as *mut CleanupEnvHookData<T>) };
(cleanup_env_hook.hook)(cleanup_env_hook.data); (cleanup_env_hook.hook)(cleanup_env_hook.data);
} }
@ -1341,8 +1346,8 @@ unsafe extern "C" fn raw_finalize_with_custom_callback<Hint, Finalize>(
) where ) where
Finalize: FnOnce(Hint, Env), Finalize: FnOnce(Hint, Env),
{ {
let (hint, callback) = *Box::from_raw(finalize_hint as *mut (Hint, Finalize)); let (hint, callback) = unsafe { *Box::from_raw(finalize_hint as *mut (Hint, Finalize)) };
callback(hint, Env::from_raw(env)); callback(hint, unsafe { Env::from_raw(env) });
} }
#[cfg(feature = "napi8")] #[cfg(feature = "napi8")]
@ -1353,10 +1358,10 @@ unsafe extern "C" fn async_finalize<Arg, F>(
Arg: 'static, Arg: 'static,
F: FnOnce(Arg), F: FnOnce(Arg),
{ {
let (arg, callback) = *Box::from_raw(data as *mut (Arg, F)); let (arg, callback) = unsafe { *Box::from_raw(data as *mut (Arg, F)) };
callback(arg); callback(arg);
if !handle.is_null() { if !handle.is_null() {
let status = sys::napi_remove_async_cleanup_hook(handle); let status = unsafe { sys::napi_remove_async_cleanup_hook(handle) };
assert!( assert!(
status == sys::Status::napi_ok, status == sys::Status::napi_ok,
"Remove async cleanup hook failed after async cleanup callback" "Remove async cleanup hook failed after async cleanup callback"

View file

@ -176,17 +176,15 @@ macro_rules! impl_object_methods {
let mut error_code = ptr::null_mut(); let mut error_code = ptr::null_mut();
let mut reason_string = ptr::null_mut(); let mut reason_string = ptr::null_mut();
let mut js_error = ptr::null_mut(); let mut js_error = ptr::null_mut();
let create_code_status = sys::napi_create_string_utf8( let create_code_status = unsafe {
env, sys::napi_create_string_utf8(env, error_code_string.as_ptr(), status_len, &mut error_code)
error_code_string.as_ptr(), };
status_len,
&mut error_code,
);
debug_assert!(create_code_status == sys::Status::napi_ok); debug_assert!(create_code_status == sys::Status::napi_ok);
let create_reason_status = let create_reason_status = unsafe {
sys::napi_create_string_utf8(env, reason.as_ptr(), reason_len, &mut reason_string); sys::napi_create_string_utf8(env, reason.as_ptr(), reason_len, &mut reason_string)
};
debug_assert!(create_reason_status == sys::Status::napi_ok); debug_assert!(create_reason_status == sys::Status::napi_ok);
let create_error_status = $kind(env, error_code, reason_string, &mut js_error); let create_error_status = unsafe { $kind(env, error_code, reason_string, &mut js_error) };
debug_assert!(create_error_status == sys::Status::napi_ok); debug_assert!(create_error_status == sys::Status::napi_ok);
js_error js_error
} }
@ -201,10 +199,10 @@ macro_rules! impl_object_methods {
if status == Status::PendingException { if status == Status::PendingException {
return; return;
} }
let js_error = self.into_value(env); let js_error = unsafe { self.into_value(env) };
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
let throw_status = sys::napi_throw(env, js_error); let throw_status = unsafe { sys::napi_throw(env, js_error) };
sys::napi_throw(env, js_error); unsafe { sys::napi_throw(env, js_error) };
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
assert!( assert!(
throw_status == sys::Status::napi_ok, throw_status == sys::Status::napi_ok,

View file

@ -136,13 +136,15 @@ impl<'env> NapiRaw for &'env JsBigInt {
impl NapiValue for JsBigInt { impl NapiValue for JsBigInt {
unsafe fn from_raw(env: sys::napi_env, value: sys::napi_value) -> Result<Self> { unsafe fn from_raw(env: sys::napi_env, value: sys::napi_value) -> Result<Self> {
let mut word_count = 0usize; let mut word_count = 0usize;
check_status!(sys::napi_get_value_bigint_words( check_status!(unsafe {
env, sys::napi_get_value_bigint_words(
value, env,
ptr::null_mut(), value,
&mut word_count, ptr::null_mut(),
ptr::null_mut(), &mut word_count,
))?; ptr::null_mut(),
)
})?;
Ok(JsBigInt { Ok(JsBigInt {
raw: Value { raw: Value {
env, env,
@ -155,13 +157,15 @@ impl NapiValue for JsBigInt {
unsafe fn from_raw_unchecked(env: sys::napi_env, value: sys::napi_value) -> Self { unsafe fn from_raw_unchecked(env: sys::napi_env, value: sys::napi_value) -> Self {
let mut word_count = 0usize; let mut word_count = 0usize;
let status = sys::napi_get_value_bigint_words( let status = unsafe {
env, sys::napi_get_value_bigint_words(
value, env,
ptr::null_mut(), value,
&mut word_count, ptr::null_mut(),
ptr::null_mut(), &mut word_count,
); ptr::null_mut(),
)
};
debug_assert!( debug_assert!(
Status::from(status) == Status::Ok, Status::from(status) == Status::Ok,
"napi_get_value_bigint_words failed" "napi_get_value_bigint_words failed"

View file

@ -681,6 +681,6 @@ impl JsUnknown {
where where
V: NapiValue, V: NapiValue,
{ {
V::from_raw_unchecked(self.0.env, self.0.value) unsafe { V::from_raw_unchecked(self.0.env, self.0.value) }
} }
} }

View file

@ -73,12 +73,13 @@ unsafe extern "C" fn finalize_callback<T, Hint, F>(
Hint: 'static, Hint: 'static,
F: FnOnce(FinalizeContext<T, Hint>), F: FnOnce(FinalizeContext<T, Hint>),
{ {
let (value, callback, raw_ref) = *Box::from_raw(finalize_data as *mut (T, F, sys::napi_ref)); let (value, callback, raw_ref) =
let hint = *Box::from_raw(finalize_hint as *mut Hint); unsafe { *Box::from_raw(finalize_data as *mut (T, F, sys::napi_ref)) };
let env = Env::from_raw(raw_env); let hint = unsafe { *Box::from_raw(finalize_hint as *mut Hint) };
let env = unsafe { Env::from_raw(raw_env) };
callback(FinalizeContext { env, value, hint }); callback(FinalizeContext { env, value, hint });
if !raw_ref.is_null() { if !raw_ref.is_null() {
let status = sys::napi_delete_reference(raw_env, raw_ref); let status = unsafe { sys::napi_delete_reference(raw_env, raw_ref) };
debug_assert!( debug_assert!(
status == sys::Status::napi_ok, status == sys::Status::napi_ok,
"Delete reference in finalize callback failed" "Delete reference in finalize callback failed"

View file

@ -1,4 +1,5 @@
#![deny(clippy::all)] #![deny(clippy::all)]
#![forbid(unsafe_op_in_unsafe_fn)]
//! High level Node.js [N-API](https://nodejs.org/api/n-api.html) binding //! High level Node.js [N-API](https://nodejs.org/api/n-api.html) binding
//! //!
@ -130,7 +131,8 @@ pub type ContextlessResult<T> = Result<Option<T>>;
macro_rules! type_of { macro_rules! type_of {
($env:expr, $value:expr) => {{ ($env:expr, $value:expr) => {{
let mut value_type = 0; let mut value_type = 0;
check_status!($crate::sys::napi_typeof($env, $value, &mut value_type)) #[allow(unused_unsafe)]
check_status!(unsafe { $crate::sys::napi_typeof($env, $value, &mut value_type) })
.and_then(|_| Ok($crate::ValueType::from(value_type))) .and_then(|_| Ok($crate::ValueType::from(value_type)))
}}; }};
} }
@ -166,21 +168,25 @@ pub(crate) unsafe fn log_js_value<V: AsRef<[sys::napi_value]>>(
use std::ptr; use std::ptr;
let mut g = ptr::null_mut(); let mut g = ptr::null_mut();
sys::napi_get_global(env, &mut g); unsafe { sys::napi_get_global(env, &mut g) };
let mut console = ptr::null_mut(); let mut console = ptr::null_mut();
let console_c_string = CString::new("console").unwrap(); let console_c_string = CString::new("console").unwrap();
let method_c_string = CString::new(method).unwrap(); let method_c_string = CString::new(method).unwrap();
sys::napi_get_named_property(env, g, console_c_string.as_ptr(), &mut console); unsafe { sys::napi_get_named_property(env, g, console_c_string.as_ptr(), &mut console) };
let mut method_js_fn = ptr::null_mut(); let mut method_js_fn = ptr::null_mut();
sys::napi_get_named_property(env, console, method_c_string.as_ptr(), &mut method_js_fn); unsafe {
sys::napi_call_function( sys::napi_get_named_property(env, console, method_c_string.as_ptr(), &mut method_js_fn)
env, };
console, unsafe {
method_js_fn, sys::napi_call_function(
values.as_ref().len(), env,
values.as_ref().as_ptr(), console,
ptr::null_mut(), method_js_fn,
); values.as_ref().len(),
values.as_ref().as_ptr(),
ptr::null_mut(),
)
};
} }
pub use crate::bindgen_runtime::ctor as module_init; pub use crate::bindgen_runtime::ctor as module_init;

View file

@ -97,37 +97,39 @@ unsafe extern "C" fn call_js_cb<
context: *mut c_void, context: *mut c_void,
data: *mut c_void, data: *mut c_void,
) { ) {
let future_promise = Box::from_raw(context as *mut FuturePromise<Data, Resolver>); let future_promise = unsafe { Box::from_raw(context as *mut FuturePromise<Data, Resolver>) };
let value = Box::from_raw(data as *mut Result<Data>); let value = unsafe { Box::from_raw(data as *mut Result<Data>) };
let resolver = future_promise.resolver; let resolver = future_promise.resolver;
let deferred = future_promise.deferred; let deferred = future_promise.deferred;
let js_value_to_resolve = value.and_then(move |v| (resolver)(env, v)); let js_value_to_resolve = value.and_then(move |v| (resolver)(env, v));
match js_value_to_resolve { match js_value_to_resolve {
Ok(v) => { Ok(v) => {
let status = sys::napi_resolve_deferred(env, deferred, v); let status = unsafe { sys::napi_resolve_deferred(env, deferred, v) };
debug_assert!(status == sys::Status::napi_ok, "Resolve promise failed"); debug_assert!(status == sys::Status::napi_ok, "Resolve promise failed");
} }
Err(e) => { Err(e) => {
let status = sys::napi_reject_deferred( let status = unsafe {
env, sys::napi_reject_deferred(
deferred, env,
if e.maybe_raw.is_null() { deferred,
JsError::from(e).into_value(env) if e.maybe_raw.is_null() {
} else { JsError::from(e).into_value(env)
let mut err = ptr::null_mut(); } else {
let get_err_status = sys::napi_get_reference_value(env, e.maybe_raw, &mut err); let mut err = ptr::null_mut();
debug_assert!( let get_err_status = sys::napi_get_reference_value(env, e.maybe_raw, &mut err);
get_err_status == sys::Status::napi_ok, debug_assert!(
"Get Error from Reference failed" get_err_status == sys::Status::napi_ok,
); "Get Error from Reference failed"
let delete_reference_status = sys::napi_delete_reference(env, e.maybe_raw); );
debug_assert!( let delete_reference_status = sys::napi_delete_reference(env, e.maybe_raw);
delete_reference_status == sys::Status::napi_ok, debug_assert!(
"Delete Error Reference failed" delete_reference_status == sys::Status::napi_ok,
); "Delete Error Reference failed"
err );
}, err
); },
)
};
debug_assert!(status == sys::Status::napi_ok, "Reject promise failed"); debug_assert!(status == sys::Status::napi_ok, "Reject promise failed");
} }
}; };

View file

@ -329,7 +329,7 @@ unsafe extern "C" fn thread_finalize_cb<T: 'static, V: NapiRaw, R>(
R: 'static + Send + FnMut(ThreadSafeCallContext<T>) -> Result<Vec<V>>, R: 'static + Send + FnMut(ThreadSafeCallContext<T>) -> Result<Vec<V>>,
{ {
// cleanup // cleanup
drop(Box::<R>::from_raw(finalize_data.cast())); drop(unsafe { Box::<R>::from_raw(finalize_data.cast()) });
} }
unsafe extern "C" fn call_js_cb<T: 'static, V: NapiRaw, R, ES>( unsafe extern "C" fn call_js_cb<T: 'static, V: NapiRaw, R, ES>(
@ -341,18 +341,20 @@ unsafe extern "C" fn call_js_cb<T: 'static, V: NapiRaw, R, ES>(
R: 'static + Send + FnMut(ThreadSafeCallContext<T>) -> Result<Vec<V>>, R: 'static + Send + FnMut(ThreadSafeCallContext<T>) -> Result<Vec<V>>,
ES: ErrorStrategy::T, ES: ErrorStrategy::T,
{ {
let ctx: &mut R = &mut *context.cast::<R>(); let ctx: &mut R = unsafe { &mut *context.cast::<R>() };
let val: Result<T> = match ES::VALUE { let val: Result<T> = unsafe {
ErrorStrategy::CalleeHandled::VALUE => *Box::<Result<T>>::from_raw(data.cast()), match ES::VALUE {
ErrorStrategy::Fatal::VALUE => Ok(*Box::<T>::from_raw(data.cast())), ErrorStrategy::CalleeHandled::VALUE => *Box::<Result<T>>::from_raw(data.cast()),
ErrorStrategy::Fatal::VALUE => Ok(*Box::<T>::from_raw(data.cast())),
}
}; };
let mut recv = ptr::null_mut(); let mut recv = ptr::null_mut();
sys::napi_get_undefined(raw_env, &mut recv); unsafe { sys::napi_get_undefined(raw_env, &mut recv) };
let ret = val.and_then(|v| { let ret = val.and_then(|v| {
(ctx)(ThreadSafeCallContext { (ctx)(ThreadSafeCallContext {
env: Env::from_raw(raw_env), env: unsafe { Env::from_raw(raw_env) },
value: v, value: v,
}) })
}); });
@ -364,35 +366,39 @@ unsafe extern "C" fn call_js_cb<T: 'static, V: NapiRaw, R, ES>(
// If the Result is an error, pass that as the first argument. // If the Result is an error, pass that as the first argument.
match ret { match ret {
Ok(values) => { Ok(values) => {
let values = values.iter().map(|v| v.raw()); let values = values.iter().map(|v| unsafe { v.raw() });
let args: Vec<sys::napi_value> = if ES::VALUE == ErrorStrategy::CalleeHandled::VALUE { let args: Vec<sys::napi_value> = if ES::VALUE == ErrorStrategy::CalleeHandled::VALUE {
let mut js_null = ptr::null_mut(); let mut js_null = ptr::null_mut();
sys::napi_get_null(raw_env, &mut js_null); unsafe { sys::napi_get_null(raw_env, &mut js_null) };
::core::iter::once(js_null).chain(values).collect() ::core::iter::once(js_null).chain(values).collect()
} else { } else {
values.collect() values.collect()
}; };
status = sys::napi_call_function( status = unsafe {
raw_env, sys::napi_call_function(
recv, raw_env,
js_callback, recv,
args.len(), js_callback,
args.as_ptr(), args.len(),
ptr::null_mut(), args.as_ptr(),
); ptr::null_mut(),
)
};
} }
Err(e) if ES::VALUE == ErrorStrategy::Fatal::VALUE => { Err(e) if ES::VALUE == ErrorStrategy::Fatal::VALUE => {
status = sys::napi_fatal_exception(raw_env, JsError::from(e).into_value(raw_env)); status = unsafe { sys::napi_fatal_exception(raw_env, JsError::from(e).into_value(raw_env)) };
} }
Err(e) => { Err(e) => {
status = sys::napi_call_function( status = unsafe {
raw_env, sys::napi_call_function(
recv, raw_env,
js_callback, recv,
1, js_callback,
[JsError::from(e).into_value(raw_env)].as_mut_ptr(), 1,
ptr::null_mut(), [JsError::from(e).into_value(raw_env)].as_mut_ptr(),
); ptr::null_mut(),
)
};
} }
} }
if status == sys::Status::napi_ok { if status == sys::Status::napi_ok {
@ -401,11 +407,11 @@ unsafe extern "C" fn call_js_cb<T: 'static, V: NapiRaw, R, ES>(
if status == sys::Status::napi_pending_exception { if status == sys::Status::napi_pending_exception {
let mut error_result = ptr::null_mut(); let mut error_result = ptr::null_mut();
assert_eq!( assert_eq!(
sys::napi_get_and_clear_last_exception(raw_env, &mut error_result), unsafe { sys::napi_get_and_clear_last_exception(raw_env, &mut error_result) },
sys::Status::napi_ok sys::Status::napi_ok
); );
assert_eq!( assert_eq!(
sys::napi_fatal_exception(raw_env, error_result), unsafe { sys::napi_fatal_exception(raw_env, error_result) },
sys::Status::napi_ok sys::Status::napi_ok
); );
} else { } else {
@ -413,32 +419,38 @@ unsafe extern "C" fn call_js_cb<T: 'static, V: NapiRaw, R, ES>(
let error_code_string = format!("{:?}", error_code); let error_code_string = format!("{:?}", error_code);
let mut error_code_value = ptr::null_mut(); let mut error_code_value = ptr::null_mut();
assert_eq!( assert_eq!(
sys::napi_create_string_utf8( unsafe {
raw_env, sys::napi_create_string_utf8(
error_code_string.as_ptr() as *const _, raw_env,
error_code_string.len(), error_code_string.as_ptr() as *const _,
&mut error_code_value error_code_string.len(),
), &mut error_code_value,
)
},
sys::Status::napi_ok, sys::Status::napi_ok,
); );
let error_msg = "Call JavaScript callback failed in thread safe function"; let error_msg = "Call JavaScript callback failed in thread safe function";
let mut error_msg_value = ptr::null_mut(); let mut error_msg_value = ptr::null_mut();
assert_eq!( assert_eq!(
sys::napi_create_string_utf8( unsafe {
raw_env, sys::napi_create_string_utf8(
error_msg.as_ptr() as *const _, raw_env,
error_msg.len(), error_msg.as_ptr() as *const _,
&mut error_msg_value, error_msg.len(),
), &mut error_msg_value,
)
},
sys::Status::napi_ok, sys::Status::napi_ok,
); );
let mut error_value = ptr::null_mut(); let mut error_value = ptr::null_mut();
assert_eq!( assert_eq!(
sys::napi_create_error(raw_env, error_code_value, error_msg_value, &mut error_value), unsafe {
sys::napi_create_error(raw_env, error_code_value, error_msg_value, &mut error_value)
},
sys::Status::napi_ok, sys::Status::napi_ok,
); );
assert_eq!( assert_eq!(
sys::napi_fatal_exception(raw_env, error_value), unsafe { sys::napi_fatal_exception(raw_env, error_value) },
sys::Status::napi_ok sys::Status::napi_ok
); );
} }

View file

@ -27,7 +27,7 @@ unsafe extern "C" fn load_exe_hook(event: u32, info: *const DELAYLOAD_INFO) -> H
return HINSTANCE::default(); return HINSTANCE::default();
} }
let dll_name = CStr::from_ptr((*info).TargetDllName.0 as *mut i8); let dll_name = unsafe { CStr::from_ptr((*info).TargetDllName.0 as *mut i8) };
if !HOST_BINARIES if !HOST_BINARIES
.iter() .iter()
.any(|&host_name| host_name == dll_name.to_bytes()) .any(|&host_name| host_name == dll_name.to_bytes())
@ -35,7 +35,7 @@ unsafe extern "C" fn load_exe_hook(event: u32, info: *const DELAYLOAD_INFO) -> H
return HINSTANCE::default(); return HINSTANCE::default();
} }
GetModuleHandleA(PSTR::default()) unsafe { GetModuleHandleA(PSTR::default()) }
} }
#[no_mangle] #[no_mangle]