From e0d75d145391540e3e724917a27fa4a8e5964f26 Mon Sep 17 00:00:00 2001 From: LongYinan Date: Sat, 10 Oct 2020 18:17:32 +0800 Subject: [PATCH 1/5] feat(napi): implement napi_is_promise --- napi/src/js_values/mod.rs | 9 +++++++-- test_module/__test__/object.spec.ts | 18 ++++++++++++++++++ test_module/src/object.rs | 8 ++++++++ 3 files changed, 33 insertions(+), 2 deletions(-) diff --git a/napi/src/js_values/mod.rs b/napi/src/js_values/mod.rs index d17fc07b..4d4e433c 100644 --- a/napi/src/js_values/mod.rs +++ b/napi/src/js_values/mod.rs @@ -174,11 +174,16 @@ macro_rules! impl_js_value_methods { #[cfg(napi5)] pub fn is_date(&self) -> Result { let mut is_date = true; - let status = unsafe { sys::napi_is_date(self.0.env, self.0.value, &mut is_date) }; - check_status(status)?; + check_status(unsafe { sys::napi_is_date(self.0.env, self.0.value, &mut is_date) })?; Ok(is_date) } + pub fn is_promise(&self) -> Result { + let mut is_promise = true; + check_status(unsafe { sys::napi_is_promise(self.0.env, self.0.value, &mut is_promise) })?; + Ok(is_promise) + } + #[inline] pub fn is_error(&self) -> Result { let mut result = false; diff --git a/test_module/__test__/object.spec.ts b/test_module/__test__/object.spec.ts index 91c2d685..865113e5 100644 --- a/test_module/__test__/object.spec.ts +++ b/test_module/__test__/object.spec.ts @@ -224,3 +224,21 @@ test('testDefineProperties', (t) => { const descriptor = Object.getOwnPropertyDescriptor(obj, 'ro') t.is(descriptor?.value ?? descriptor?.get?.(), 'readonly') }) + +test('is promise', (t) => { + t.false(bindings.testIsPromise(1)) + t.false(bindings.testIsPromise('hello')) + t.false(bindings.testIsPromise({})) + t.false(bindings.testIsPromise(new Date())) + t.false(bindings.testIsPromise(Symbol())) + + t.true(bindings.testIsPromise(Promise.resolve())) + t.true(bindings.testIsPromise(Promise.reject().catch(() => {}))) + t.true( + bindings.testIsPromise( + new Promise((resolve) => { + resolve() + }), + ), + ) +}) diff --git a/test_module/src/object.rs b/test_module/src/object.rs index 63c09e60..fef07abc 100644 --- a/test_module/src/object.rs +++ b/test_module/src/object.rs @@ -158,6 +158,12 @@ fn readonly_getter(ctx: CallContext) -> Result { ctx.env.create_string("readonly") } +#[js_function(1)] +fn test_is_promise(ctx: CallContext) -> Result { + let obj = ctx.get::(0)?; + ctx.env.get_boolean(obj.is_promise()?) +} + pub fn register_js(module: &mut Module) -> Result<()> { module.create_named_method("testSetProperty", test_set_property)?; module.create_named_method("testGetProperty", test_get_property)?; @@ -179,5 +185,7 @@ pub fn register_js(module: &mut Module) -> Result<()> { module.create_named_method("testGetElement", test_get_element)?; module.create_named_method("testDeleteElement", test_delete_element)?; module.create_named_method("testDefineProperties", test_define_properties)?; + + module.create_named_method("testIsPromise", test_is_promise)?; Ok(()) } From 3da8daf192bbae52bdd5526624261018f21bcb72 Mon Sep 17 00:00:00 2001 From: LongYinan Date: Sat, 10 Oct 2020 18:21:11 +0800 Subject: [PATCH 2/5] feat(napi): implement napi_reference_ref --- napi/src/js_values/value_ref.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/napi/src/js_values/value_ref.rs b/napi/src/js_values/value_ref.rs index c130e9d9..4f49957a 100644 --- a/napi/src/js_values/value_ref.rs +++ b/napi/src/js_values/value_ref.rs @@ -32,6 +32,11 @@ impl Ref { }) } + pub fn reference(&mut self, env: &Env) -> Result { + check_status(unsafe { sys::napi_reference_ref(env.0, self.raw_ref, &mut self.count) })?; + Ok(self.count) + } + #[must_use] pub fn unref(mut self, env: Env) -> Result { check_status(unsafe { sys::napi_reference_unref(env.0, self.raw_ref, &mut self.count) })?; From 0deb9f77553701a5e569515124aa8e356678de70 Mon Sep 17 00:00:00 2001 From: LongYinan Date: Sat, 10 Oct 2020 18:54:05 +0800 Subject: [PATCH 3/5] feat(napi): implement TypedArray related APIs --- napi/src/js_values/arraybuffer.rs | 125 +++++++++++++++++++++++++++++- napi/src/js_values/mod.rs | 4 +- test_module/src/arraybuffer.rs | 25 +----- 3 files changed, 128 insertions(+), 26 deletions(-) diff --git a/napi/src/js_values/arraybuffer.rs b/napi/src/js_values/arraybuffer.rs index c49a807f..d8017209 100644 --- a/napi/src/js_values/arraybuffer.rs +++ b/napi/src/js_values/arraybuffer.rs @@ -2,7 +2,7 @@ use std::mem; use std::ops::Deref; use std::ptr; -use super::Value; +use super::{Value, ValueType}; use crate::error::check_status; use crate::{sys, JsUnknown, NapiValue, Ref, Result}; @@ -16,6 +16,70 @@ pub struct JsArrayBufferValue { data: mem::ManuallyDrop>, } +#[repr(transparent)] +#[derive(Debug, Clone, Copy)] +pub struct JsTypedArray(pub(crate) Value); + +#[derive(Debug)] +pub struct JsTypedArrayValue { + pub arraybuffer: JsArrayBuffer, + pub data: mem::ManuallyDrop>, + pub byte_offset: u64, + pub length: u64, + pub typedarray_type: TypedArrayType, +} + +#[derive(Debug)] +pub enum TypedArrayType { + Int8, + Uint8, + Uint8Clamped, + Int16, + Uint16, + Int32, + Uint32, + Float32, + Float64, + BigInt64, + BigUint64, +} + +impl From for TypedArrayType { + fn from(value: sys::napi_typedarray_type) -> Self { + match value { + sys::napi_typedarray_type::napi_int8_array => Self::Int8, + sys::napi_typedarray_type::napi_uint8_array => Self::Uint8, + sys::napi_typedarray_type::napi_uint8_clamped_array => Self::Uint8Clamped, + sys::napi_typedarray_type::napi_int16_array => Self::Int16, + sys::napi_typedarray_type::napi_uint16_array => Self::Uint16, + sys::napi_typedarray_type::napi_int32_array => Self::Int32, + sys::napi_typedarray_type::napi_uint32_array => Self::Uint32, + sys::napi_typedarray_type::napi_float32_array => Self::Float32, + sys::napi_typedarray_type::napi_float64_array => Self::Float64, + sys::napi_typedarray_type::napi_bigint64_array => Self::BigInt64, + sys::napi_typedarray_type::napi_biguint64_array => Self::BigUint64, + } + } +} + +impl From for sys::napi_typedarray_type { + fn from(value: TypedArrayType) -> Self { + match value { + TypedArrayType::Int8 => sys::napi_typedarray_type::napi_int8_array, + TypedArrayType::Uint8 => sys::napi_typedarray_type::napi_uint8_array, + TypedArrayType::Uint8Clamped => sys::napi_typedarray_type::napi_uint8_clamped_array, + TypedArrayType::Int16 => sys::napi_typedarray_type::napi_int16_array, + TypedArrayType::Uint16 => sys::napi_typedarray_type::napi_uint16_array, + TypedArrayType::Int32 => sys::napi_typedarray_type::napi_int32_array, + TypedArrayType::Uint32 => sys::napi_typedarray_type::napi_uint32_array, + TypedArrayType::Float32 => sys::napi_typedarray_type::napi_float32_array, + TypedArrayType::Float64 => sys::napi_typedarray_type::napi_float64_array, + TypedArrayType::BigInt64 => sys::napi_typedarray_type::napi_bigint64_array, + TypedArrayType::BigUint64 => sys::napi_typedarray_type::napi_biguint64_array, + } + } +} + impl JsArrayBuffer { pub fn into_value(self) -> Result { let mut data = ptr::null_mut(); @@ -31,6 +95,30 @@ impl JsArrayBuffer { }) } + pub fn create_typed_array( + &self, + typedarray_type: TypedArrayType, + length: u64, + byte_offset: u64, + ) -> Result { + let mut typedarray_value = ptr::null_mut(); + check_status(unsafe { + sys::napi_create_typedarray( + self.0.env, + typedarray_type.into(), + length, + self.0.value, + byte_offset, + &mut typedarray_value, + ) + })?; + Ok(JsTypedArray(Value { + env: self.0.env, + value: typedarray_value, + value_type: ValueType::Object, + })) + } + #[inline] pub fn into_ref(self) -> Result> { Ref::new(self.0, 1, self.into_value()?) @@ -67,3 +155,38 @@ impl Deref for JsArrayBufferValue { self.data.as_slice() } } + +impl JsTypedArray { + /// get TypeArray info + /// https://nodejs.org/api/n-api.html#n_api_napi_get_typedarray_info + /// + /// ***Warning***: Use caution while using this API since the underlying data buffer is managed by the VM. + pub fn into_value(self) -> Result> { + let mut typedarray_type = sys::napi_typedarray_type::napi_int8_array; + let mut len = 0u64; + let mut data = ptr::null_mut(); + let mut array_buffer = ptr::null_mut(); + let mut byte_offset = 0u64; + check_status(unsafe { + sys::napi_get_typedarray_info( + self.0.env, + self.0.value, + &mut typedarray_type, + &mut len, + &mut data, + &mut array_buffer, + &mut byte_offset, + ) + })?; + + Ok(JsTypedArrayValue { + data: mem::ManuallyDrop::new(unsafe { + Vec::from_raw_parts(data as *mut T, len as usize, len as usize) + }), + length: len, + byte_offset, + typedarray_type: typedarray_type.into(), + arraybuffer: JsArrayBuffer::from_raw_unchecked(self.0.env, array_buffer), + }) + } +} diff --git a/napi/src/js_values/mod.rs b/napi/src/js_values/mod.rs index 4d4e433c..4ab0376c 100644 --- a/napi/src/js_values/mod.rs +++ b/napi/src/js_values/mod.rs @@ -443,8 +443,9 @@ impl_js_value_methods!(JsUnknown); impl_js_value_methods!(JsUndefined); impl_js_value_methods!(JsNull); impl_js_value_methods!(JsBoolean); -impl_js_value_methods!(JsArrayBuffer); impl_js_value_methods!(JsBuffer); +impl_js_value_methods!(JsArrayBuffer); +impl_js_value_methods!(JsTypedArray); impl_js_value_methods!(JsNumber); impl_js_value_methods!(JsString); impl_js_value_methods!(JsObject); @@ -468,6 +469,7 @@ impl_napi_value_trait!(JsNull, Null); impl_napi_value_trait!(JsBoolean, Boolean); impl_napi_value_trait!(JsBuffer, Object); impl_napi_value_trait!(JsArrayBuffer, Object); +impl_napi_value_trait!(JsTypedArray, Object); impl_napi_value_trait!(JsNumber, Number); impl_napi_value_trait!(JsString, String); impl_napi_value_trait!(JsObject, Object); diff --git a/test_module/src/arraybuffer.rs b/test_module/src/arraybuffer.rs index e5931f73..8acb8b74 100644 --- a/test_module/src/arraybuffer.rs +++ b/test_module/src/arraybuffer.rs @@ -1,7 +1,6 @@ -use std::ffi::CStr; use std::str; -use napi::{CallContext, JsArrayBuffer, JsNumber, JsString, Module, Result}; +use napi::{CallContext, JsArrayBuffer, JsNumber, Module, Result}; #[js_function(1)] pub fn get_arraybuffer_length(ctx: CallContext) -> Result { @@ -9,29 +8,7 @@ pub fn get_arraybuffer_length(ctx: CallContext) -> Result { ctx.env.create_uint32((&buffer).len() as u32) } -#[js_function(1)] -pub fn arraybuffer_to_string(ctx: CallContext) -> Result { - let buffer = ctx.get::(0)?.into_value()?; - ctx - .env - .create_string(str_from_null_terminated_utf8_safe(&buffer)) -} - -fn str_from_null_terminated_utf8_safe(s: &[u8]) -> &str { - if s.iter().any(|&x| x == 0) { - unsafe { str_from_null_terminated_utf8(s) } - } else { - str::from_utf8(s).unwrap() - } -} - -// unsafe: s must contain a null byte -unsafe fn str_from_null_terminated_utf8(s: &[u8]) -> &str { - CStr::from_ptr(s.as_ptr() as *const _).to_str().unwrap() -} - pub fn register_js(module: &mut Module) -> Result<()> { module.create_named_method("getArraybufferLength", get_arraybuffer_length)?; - module.create_named_method("arraybufferToString", arraybuffer_to_string)?; Ok(()) } From 364082ca7ae55dc68abb303c204b2b7d34e16922 Mon Sep 17 00:00:00 2001 From: LongYinan Date: Sat, 10 Oct 2020 18:58:36 +0800 Subject: [PATCH 4/5] docs: update README --- README.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 5e23a903..933e0fd0 100644 --- a/README.md +++ b/README.md @@ -152,7 +152,6 @@ yarn test | NAPI | NAPI Version | Minimal Node version | Status | | ------------------------------------------------------------------------------------------------------------ | ------------ | -------------------- | ------ | -| [Enum types](https://nodejs.org/api/n-api.html#n_api_enum_types) | 6 | v13.7.0 | ⛔️ | | [napi_create_array](https://nodejs.org/api/n-api.html#n_api_napi_create_array) | 1 | v8.0.0 | ✅ | | [napi_create_array_with_length](https://nodejs.org/api/n-api.html#n_api_napi_create_array_with_length) | 1 | v8.0.0 | ✅ | | [napi_create_arraybuffer](https://nodejs.org/api/n-api.html#n_api_napi_create_arraybuffer) | 1 | v8.0.0 | ✅ | @@ -164,7 +163,7 @@ yarn test | [napi_create_external_buffer](https://nodejs.org/api/n-api.html#n_api_napi_create_external_buffer) | 1 | v8.0.0 | ✅ | | [napi_create_object](https://nodejs.org/api/n-api.html#n_api_napi_create_object) | 1 | v8.0.0 | ✅ | | [napi_create_symbol](https://nodejs.org/api/n-api.html#n_api_napi_create_symbol) | 1 | v8.0.0 | ✅ | -| [napi_create_typedarray](https://nodejs.org/api/n-api.html#n_api_napi_create_typedarray) | 1 | v8.0.0 | ⛔️ | +| [napi_create_typedarray](https://nodejs.org/api/n-api.html#n_api_napi_create_typedarray) | 1 | v8.0.0 | ✅ | | [napi_create_dataview](https://nodejs.org/api/n-api.html#n_api_napi_create_dataview) | 1 | v8.3.0 | ⛔️ | | [napi_create_int32](https://nodejs.org/api/n-api.html#n_api_napi_create_int32) | 1 | v8.4.0 | ✅ | | [napi_create_uint32](https://nodejs.org/api/n-api.html#n_api_napi_create_uint32) | 1 | v8.4.0 | ✅ | @@ -185,7 +184,7 @@ yarn test | [napi_get_arraybuffer_info](https://nodejs.org/api/n-api.html#n_api_napi_get_arraybuffer_info) | 1 | v8.0.0 | ✅ | | [napi_get_buffer_info](https://nodejs.org/api/n-api.html#n_api_napi_get_buffer_info) | 1 | v8.0.0 | ✅ | | [napi_get_prototype](https://nodejs.org/api/n-api.html#n_api_napi_get_prototype) | 1 | v8.0.0 | ✅ | -| [napi_get_typedarray_info](https://nodejs.org/api/n-api.html#n_api_napi_get_typedarray_info) | 1 | v8.0.0 | ⛔️ | +| [napi_get_typedarray_info](https://nodejs.org/api/n-api.html#n_api_napi_get_typedarray_info) | 1 | v8.0.0 | ✅ | | [napi_get_dataview_info](https://nodejs.org/api/n-api.html#n_api_napi_get_dataview_info) | 1 | v8.3.0 | ⛔️ | | [napi_get_date_value](https://nodejs.org/api/n-api.html#n_api_napi_get_date_value) | 5 | v11.11.0 | ✅ | | [napi_get_value_bool](https://nodejs.org/api/n-api.html#n_api_napi_get_value_bool) | 1 | v8.0.0 | ✅ | @@ -223,5 +222,5 @@ yarn test | [napi_is_typedarray](https://nodejs.org/api/n-api.html#n_api_napi_is_typedarray) | 1 | v8.0.0 | ✅ | | [napi_is_dataview](https://nodejs.org/api/n-api.html#n_api_napi_is_dataview) | 1 | v8.3.0 | ✅ | | [napi_strict_equals](https://nodejs.org/api/n-api.html#n_api_napi_strict_equals) | 1 | v8.0.0 | ✅ | -| [napi_detach_arraybuffer](https://nodejs.org/api/n-api.html#n_api_napi_detach_arraybuffer) | Experimental | v13.3.0 | ⛔️ | -| [napi_is_detached_arraybuffer](https://nodejs.org/api/n-api.html#n_api_napi_is_detached_arraybuffer) | Experimental | v13.3.0 | ⛔️ | +| [napi_detach_arraybuffer](https://nodejs.org/api/n-api.html#n_api_napi_detach_arraybuffer) | 7 | v13.3.0 | ⛔️ | +| [napi_is_detached_arraybuffer](https://nodejs.org/api/n-api.html#n_api_napi_is_detached_arraybuffer) | 7 | v13.3.0 | ⛔️ | From d151318131d461e070fb65ebd0306cffd475d02b Mon Sep 17 00:00:00 2001 From: LongYinan Date: Sat, 10 Oct 2020 19:00:21 +0800 Subject: [PATCH 5/5] fix(napi): TypedArray napi < 6 compatible issue --- napi/src/js_values/arraybuffer.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/napi/src/js_values/arraybuffer.rs b/napi/src/js_values/arraybuffer.rs index d8017209..3aac6a65 100644 --- a/napi/src/js_values/arraybuffer.rs +++ b/napi/src/js_values/arraybuffer.rs @@ -40,7 +40,9 @@ pub enum TypedArrayType { Uint32, Float32, Float64, + #[cfg(napi6)] BigInt64, + #[cfg(napi6)] BigUint64, } @@ -56,7 +58,9 @@ impl From for TypedArrayType { sys::napi_typedarray_type::napi_uint32_array => Self::Uint32, sys::napi_typedarray_type::napi_float32_array => Self::Float32, sys::napi_typedarray_type::napi_float64_array => Self::Float64, + #[cfg(napi6)] sys::napi_typedarray_type::napi_bigint64_array => Self::BigInt64, + #[cfg(napi6)] sys::napi_typedarray_type::napi_biguint64_array => Self::BigUint64, } } @@ -74,7 +78,9 @@ impl From for sys::napi_typedarray_type { TypedArrayType::Uint32 => sys::napi_typedarray_type::napi_uint32_array, TypedArrayType::Float32 => sys::napi_typedarray_type::napi_float32_array, TypedArrayType::Float64 => sys::napi_typedarray_type::napi_float64_array, + #[cfg(napi6)] TypedArrayType::BigInt64 => sys::napi_typedarray_type::napi_bigint64_array, + #[cfg(napi6)] TypedArrayType::BigUint64 => sys::napi_typedarray_type::napi_biguint64_array, } }