Merge pull request #224 from napi-rs/more-bindings

More bindings
This commit is contained in:
LongYinan 2020-10-10 20:31:09 +08:00 committed by GitHub
commit edc8d91902
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 176 additions and 33 deletions

View file

@ -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 | ⛔️ |

View file

@ -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,76 @@ pub struct JsArrayBufferValue {
data: mem::ManuallyDrop<Vec<u8>>,
}
#[repr(transparent)]
#[derive(Debug, Clone, Copy)]
pub struct JsTypedArray(pub(crate) Value);
#[derive(Debug)]
pub struct JsTypedArrayValue<T> {
pub arraybuffer: JsArrayBuffer,
pub data: mem::ManuallyDrop<Vec<T>>,
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,
#[cfg(napi6)]
BigInt64,
#[cfg(napi6)]
BigUint64,
}
impl From<sys::napi_typedarray_type> 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,
#[cfg(napi6)]
sys::napi_typedarray_type::napi_bigint64_array => Self::BigInt64,
#[cfg(napi6)]
sys::napi_typedarray_type::napi_biguint64_array => Self::BigUint64,
}
}
}
impl From<TypedArrayType> 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,
#[cfg(napi6)]
TypedArrayType::BigInt64 => sys::napi_typedarray_type::napi_bigint64_array,
#[cfg(napi6)]
TypedArrayType::BigUint64 => sys::napi_typedarray_type::napi_biguint64_array,
}
}
}
impl JsArrayBuffer {
pub fn into_value(self) -> Result<JsArrayBufferValue> {
let mut data = ptr::null_mut();
@ -31,6 +101,30 @@ impl JsArrayBuffer {
})
}
pub fn create_typed_array(
&self,
typedarray_type: TypedArrayType,
length: u64,
byte_offset: u64,
) -> Result<JsTypedArray> {
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<JsArrayBufferValue>> {
Ref::new(self.0, 1, self.into_value()?)
@ -67,3 +161,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<T>(self) -> Result<JsTypedArrayValue<T>> {
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),
})
}
}

View file

@ -174,11 +174,16 @@ macro_rules! impl_js_value_methods {
#[cfg(napi5)]
pub fn is_date(&self) -> Result<bool> {
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<bool> {
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<bool> {
let mut result = false;
@ -438,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);
@ -463,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);

View file

@ -32,6 +32,11 @@ impl<T> Ref<T> {
})
}
pub fn reference(&mut self, env: &Env) -> Result<u32> {
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<u32> {
check_status(unsafe { sys::napi_reference_unref(env.0, self.raw_ref, &mut self.count) })?;

View file

@ -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()
}),
),
)
})

View file

@ -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<JsNumber> {
@ -9,29 +8,7 @@ pub fn get_arraybuffer_length(ctx: CallContext) -> Result<JsNumber> {
ctx.env.create_uint32((&buffer).len() as u32)
}
#[js_function(1)]
pub fn arraybuffer_to_string(ctx: CallContext) -> Result<JsString> {
let buffer = ctx.get::<JsArrayBuffer>(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(())
}

View file

@ -158,6 +158,12 @@ fn readonly_getter(ctx: CallContext) -> Result<JsString> {
ctx.env.create_string("readonly")
}
#[js_function(1)]
fn test_is_promise(ctx: CallContext) -> Result<JsBoolean> {
let obj = ctx.get::<JsObject>(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(())
}