feat(napi): add napi8 features
This commit is contained in:
parent
e9bb6d19ca
commit
daef1956b2
22 changed files with 366 additions and 21 deletions
2
.github/workflows/test.yaml
vendored
2
.github/workflows/test.yaml
vendored
|
@ -14,7 +14,7 @@ jobs:
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
node: ['10', '12', '14', '15']
|
node: ['12', '14', '16']
|
||||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||||
|
|
||||||
name: stable - ${{ matrix.os }} - node@${{ matrix.node }}
|
name: stable - ${{ matrix.os }} - node@${{ matrix.node }}
|
||||||
|
|
38
README.md
38
README.md
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
> This project was initialized from [xray](https://github.com/atom/xray)
|
> This project was initialized from [xray](https://github.com/atom/xray)
|
||||||
|
|
||||||
A minimal library for building compiled `NodeJS` add-ons in `Rust`.
|
A minimal library for building compiled `Node.js` add-ons in `Rust`.
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<a href="https://docs.rs/crate/napi"><img src="https://docs.rs/napi/badge.svg"></img></a>
|
<a href="https://docs.rs/crate/napi"><img src="https://docs.rs/napi/badge.svg"></img></a>
|
||||||
|
@ -22,17 +22,18 @@ A minimal library for building compiled `NodeJS` add-ons in `Rust`.
|
||||||
![Windows i686](https://github.com/napi-rs/napi-rs/workflows/Windows%20i686/badge.svg)
|
![Windows i686](https://github.com/napi-rs/napi-rs/workflows/Windows%20i686/badge.svg)
|
||||||
[![FreeBSD](https://api.cirrus-ci.com/github/napi-rs/napi-rs.svg)](https://cirrus-ci.com/github/napi-rs/napi-rs?branch=main)
|
[![FreeBSD](https://api.cirrus-ci.com/github/napi-rs/napi-rs.svg)](https://cirrus-ci.com/github/napi-rs/napi-rs?branch=main)
|
||||||
|
|
||||||
## Operating Systems
|
| | node12 | node14 | node16 |
|
||||||
|
| --------------------- | ------ | ------ | ------ |
|
||||||
| Linux | macOS | Windows | FreeBSD |
|
| Windows x64 | ✓ | ✓ | ✓ |
|
||||||
| ----- | ----- | ------- | ------- |
|
| Windows x86 | ✓ | ✓ | ✓ |
|
||||||
| ✓ | ✓ | ✓ | ✓ |
|
| macOS x64 | ✓ | ✓ | ✓ |
|
||||||
|
| macOS aarch64 | ✓ | ✓ | ✓ |
|
||||||
## Node.js
|
| Linux x64 gnu | ✓ | ✓ | ✓ |
|
||||||
|
| Linux x64 musl | ✓ | ✓ | ✓ |
|
||||||
| Node10 | Node12 | Node14 | Node15 |
|
| Linux aarch64 gnu | ✓ | ✓ | ✓ |
|
||||||
| ------ | ------ | ------ | ------ |
|
| Linux arm gnueabihf | ✓ | ✓ | ✓ |
|
||||||
| ✓ | ✓ | ✓ | ✓ |
|
| Linux aarch64 android | ✓ | ✓ | ✓ |
|
||||||
|
| FreeBSD x64 | ✓ | ✓ | ✓ |
|
||||||
|
|
||||||
This library depends on N-API and requires `Node@10.0.0` or later.
|
This library depends on N-API and requires `Node@10.0.0` or later.
|
||||||
|
|
||||||
|
@ -47,7 +48,7 @@ One nice feature is that this crate allows you to build add-ons purely with the
|
||||||
### Define JavaScript functions
|
### Define JavaScript functions
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
#[js_function(1)] // ------> arguments length, omit for zero
|
#[js_function(1)] // ------> arguments length
|
||||||
fn fibonacci(ctx: CallContext) -> Result<JsNumber> {
|
fn fibonacci(ctx: CallContext) -> Result<JsNumber> {
|
||||||
let n = ctx.get::<JsNumber>(0)?.try_into()?;
|
let n = ctx.get::<JsNumber>(0)?.try_into()?;
|
||||||
ctx.env.create_int64(fibonacci_native(n))
|
ctx.env.create_int64(fibonacci_native(n))
|
||||||
|
@ -108,11 +109,11 @@ name = "awesome"
|
||||||
crate-type = ["cdylib"]
|
crate-type = ["cdylib"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
napi = "1.0"
|
napi = "1"
|
||||||
napi-derive = "1.0"
|
napi-derive = "1"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
napi-build = "1.0"
|
napi-build = "1"
|
||||||
```
|
```
|
||||||
|
|
||||||
And create `build.rs` in your own project:
|
And create `build.rs` in your own project:
|
||||||
|
@ -209,6 +210,9 @@ yarn test
|
||||||
| [napi_create_string_latin1](https://nodejs.org/api/n-api.html#n_api_napi_create_string_latin1) | 1 | v8.0.0 | ✅ |
|
| [napi_create_string_latin1](https://nodejs.org/api/n-api.html#n_api_napi_create_string_latin1) | 1 | v8.0.0 | ✅ |
|
||||||
| [napi_create_string_utf16](https://nodejs.org/api/n-api.html#n_api_napi_create_string_utf16) | 1 | v8.0.0 | ✅ |
|
| [napi_create_string_utf16](https://nodejs.org/api/n-api.html#n_api_napi_create_string_utf16) | 1 | v8.0.0 | ✅ |
|
||||||
| [napi_create_string_utf8](https://nodejs.org/api/n-api.html#n_api_napi_create_string_utf8) | 1 | v8.0.0 | ✅ |
|
| [napi_create_string_utf8](https://nodejs.org/api/n-api.html#n_api_napi_create_string_utf8) | 1 | v8.0.0 | ✅ |
|
||||||
|
| [napi_type_tag](https://nodejs.org/api/n-api.html#n_api_napi_type_tag) | 8 | v14.8.0, v12.19.0 | ⚠️ |
|
||||||
|
|
||||||
|
> I have no plan to implement `nape_type_tag` and related API in `napi-rs`, because we have implemented a `rust` replacement in [TaggedObject](https://github.com/napi-rs/napi-rs/blob/main/napi/src/js_values/tagged_object.rs) which is more convenient and more compatible.
|
||||||
|
|
||||||
### [Functions to convert from N-API to C types](https://nodejs.org/api/n-api.html#n_api_functions_to_convert_from_n_api_to_c_types)
|
### [Functions to convert from N-API to C types](https://nodejs.org/api/n-api.html#n_api_functions_to_convert_from_n_api_to_c_types)
|
||||||
|
|
||||||
|
@ -258,3 +262,5 @@ yarn test
|
||||||
| [napi_strict_equals](https://nodejs.org/api/n-api.html#n_api_napi_strict_equals) | 1 | v8.0.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) | 7 | 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 | ✅ |
|
| [napi_is_detached_arraybuffer](https://nodejs.org/api/n-api.html#n_api_napi_is_detached_arraybuffer) | 7 | v13.3.0 | ✅ |
|
||||||
|
| [napi_object_freeze](https://nodejs.org/api/n-api.html#n_api_napi_object_freeze) | 8 | v14.14.0, v12.20.0 | ✅ |
|
||||||
|
| [napi_object_seal](https://nodejs.org/api/n-api.html#n_api_napi_object_seal) | 8 | v14.14.0, v12.20.0 | ✅ |
|
||||||
|
|
|
@ -19,6 +19,7 @@ napi4 = ["napi3", "napi-sys/napi4"]
|
||||||
napi5 = ["napi4", "napi-sys/napi5"]
|
napi5 = ["napi4", "napi-sys/napi5"]
|
||||||
napi6 = ["napi5", "napi-sys/napi6"]
|
napi6 = ["napi5", "napi-sys/napi6"]
|
||||||
napi7 = ["napi6", "napi-sys/napi7"]
|
napi7 = ["napi6", "napi-sys/napi7"]
|
||||||
|
napi8 = ["napi7", "napi-sys/napi8"]
|
||||||
serde-json = ["serde", "serde_json"]
|
serde-json = ["serde", "serde_json"]
|
||||||
tokio_rt = ["futures", "tokio", "once_cell", "napi4"]
|
tokio_rt = ["futures", "tokio", "once_cell", "napi4"]
|
||||||
|
|
||||||
|
|
28
napi/src/async_cleanup_hook.rs
Normal file
28
napi/src/async_cleanup_hook.rs
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
use std::mem;
|
||||||
|
|
||||||
|
use crate::{sys, Status};
|
||||||
|
|
||||||
|
/// Notice
|
||||||
|
/// The hook will be removed if `AsyncCleanupHook` was `dropped`.
|
||||||
|
/// If you want keep the hook until node process exited, call the `AsyncCleanupHook::forget`.
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct AsyncCleanupHook(pub(crate) sys::napi_async_cleanup_hook_handle);
|
||||||
|
|
||||||
|
impl AsyncCleanupHook {
|
||||||
|
/// Safe to forget it.
|
||||||
|
/// Things will be cleanup before process exited.
|
||||||
|
pub fn forget(self) {
|
||||||
|
mem::forget(self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for AsyncCleanupHook {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
let status = unsafe { sys::napi_remove_async_cleanup_hook(self.0) };
|
||||||
|
assert!(
|
||||||
|
status == sys::Status::napi_ok,
|
||||||
|
"Delete async cleanup hook failed: {}",
|
||||||
|
Status::from(status)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,8 +14,10 @@ use crate::{
|
||||||
Error, ExtendedErrorInfo, NodeVersion, Result, Status,
|
Error, ExtendedErrorInfo, NodeVersion, Result, Status,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[cfg(feature = "napi8")]
|
||||||
|
use crate::async_cleanup_hook::AsyncCleanupHook;
|
||||||
#[cfg(feature = "napi3")]
|
#[cfg(feature = "napi3")]
|
||||||
use super::cleanup_env::{CleanupEnvHook, CleanupEnvHookData};
|
use crate::cleanup_env::{CleanupEnvHook, CleanupEnvHookData};
|
||||||
#[cfg(all(feature = "serde-json"))]
|
#[cfg(all(feature = "serde-json"))]
|
||||||
use crate::js_values::{De, Ser};
|
use crate::js_values::{De, Ser};
|
||||||
#[cfg(all(feature = "tokio_rt", feature = "napi4"))]
|
#[cfg(all(feature = "tokio_rt", feature = "napi4"))]
|
||||||
|
@ -1191,6 +1193,58 @@ impl Env {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "napi8")]
|
||||||
|
/// Registers hook, which is a function of type `FnOnce(Arg)`, as a function to be run with the `arg` parameter once the current Node.js environment exits.
|
||||||
|
///
|
||||||
|
/// Unlike [`add_env_cleanup_hook`](https://docs.rs/napi/latest/napi/struct.Env.html#method.add_env_cleanup_hook), the hook is allowed to be asynchronous.
|
||||||
|
///
|
||||||
|
/// Otherwise, behavior generally matches that of [`add_env_cleanup_hook`](https://docs.rs/napi/latest/napi/struct.Env.html#method.add_env_cleanup_hook).
|
||||||
|
pub fn add_removable_async_cleanup_hook<Arg, F>(
|
||||||
|
&self,
|
||||||
|
arg: Arg,
|
||||||
|
cleanup_fn: F,
|
||||||
|
) -> Result<AsyncCleanupHook>
|
||||||
|
where
|
||||||
|
F: FnOnce(Arg),
|
||||||
|
Arg: 'static,
|
||||||
|
{
|
||||||
|
let mut handle = ptr::null_mut();
|
||||||
|
check_status!(unsafe {
|
||||||
|
sys::napi_add_async_cleanup_hook(
|
||||||
|
self.0,
|
||||||
|
Some(
|
||||||
|
async_finalize::<Arg, F>
|
||||||
|
as unsafe extern "C" fn(handle: sys::napi_async_cleanup_hook_handle, data: *mut c_void),
|
||||||
|
),
|
||||||
|
Box::leak(Box::new((arg, cleanup_fn))) as *mut (Arg, F) as *mut c_void,
|
||||||
|
&mut handle,
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
Ok(AsyncCleanupHook(handle))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "napi8")]
|
||||||
|
/// This API is very similar to [`add_removable_async_cleanup_hook`](https://docs.rs/napi/latest/napi/struct.Env.html#method.add_removable_async_cleanup_hook)
|
||||||
|
///
|
||||||
|
/// Use this one if you don't want remove the cleanup hook anymore.
|
||||||
|
pub fn add_async_cleanup_hook<Arg, F>(&self, arg: Arg, cleanup_fn: F) -> Result<()>
|
||||||
|
where
|
||||||
|
F: FnOnce(Arg),
|
||||||
|
Arg: 'static,
|
||||||
|
{
|
||||||
|
check_status!(unsafe {
|
||||||
|
sys::napi_add_async_cleanup_hook(
|
||||||
|
self.0,
|
||||||
|
Some(
|
||||||
|
async_finalize::<Arg, F>
|
||||||
|
as unsafe extern "C" fn(handle: sys::napi_async_cleanup_hook_handle, data: *mut c_void),
|
||||||
|
),
|
||||||
|
Box::leak(Box::new((arg, cleanup_fn))) as *mut (Arg, F) as *mut c_void,
|
||||||
|
ptr::null_mut(),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// # Serialize `Rust Struct` into `JavaScript Value`
|
/// # Serialize `Rust Struct` into `JavaScript Value`
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
|
@ -1341,3 +1395,22 @@ unsafe extern "C" fn raw_finalize_with_custom_callback<Hint, Finalize>(
|
||||||
let (hint, callback) = *Box::from_raw(finalize_hint as *mut (Hint, Finalize));
|
let (hint, callback) = *Box::from_raw(finalize_hint as *mut (Hint, Finalize));
|
||||||
callback(hint, Env::from_raw(env));
|
callback(hint, Env::from_raw(env));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "napi8")]
|
||||||
|
unsafe extern "C" fn async_finalize<Arg, F>(
|
||||||
|
handle: sys::napi_async_cleanup_hook_handle,
|
||||||
|
data: *mut c_void,
|
||||||
|
) where
|
||||||
|
Arg: 'static,
|
||||||
|
F: FnOnce(Arg),
|
||||||
|
{
|
||||||
|
let (arg, callback) = *Box::from_raw(data as *mut (Arg, F));
|
||||||
|
callback(arg);
|
||||||
|
if !handle.is_null() {
|
||||||
|
let status = sys::napi_remove_async_cleanup_hook(handle);
|
||||||
|
assert!(
|
||||||
|
status == sys::Status::napi_ok,
|
||||||
|
"Remove async cleanup hook failed after async cleanup callback"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -239,6 +239,18 @@ macro_rules! impl_js_value_methods {
|
||||||
})?;
|
})?;
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "napi8")]
|
||||||
|
#[inline]
|
||||||
|
pub fn freeze(&mut self) -> Result<()> {
|
||||||
|
check_status!(unsafe { sys::napi_object_freeze(self.0.env, self.0.value) })
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "napi8")]
|
||||||
|
#[inline]
|
||||||
|
pub fn seal(&mut self) -> Result<()> {
|
||||||
|
check_status!(unsafe { sys::napi_object_seal(self.0.env, self.0.value) })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
//!
|
//!
|
||||||
//! ## Feature flags
|
//! ## Feature flags
|
||||||
//!
|
//!
|
||||||
//! ### napi1 ~ napi7
|
//! ### napi1 ~ napi8
|
||||||
//!
|
//!
|
||||||
//! Because `NodeJS` N-API has versions. So there are feature flags to choose what version of `N-API` you want to build for.
|
//! Because `NodeJS` N-API has versions. So there are feature flags to choose what version of `N-API` you want to build for.
|
||||||
//! For example, if you want build a library which can be used by `node@10.17.0`, you should choose the `napi5` or lower.
|
//! For example, if you want build a library which can be used by `node@10.17.0`, you should choose the `napi5` or lower.
|
||||||
|
@ -75,6 +75,10 @@
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
|
|
||||||
|
#[cfg(feature = "napi8")]
|
||||||
|
mod async_cleanup_hook;
|
||||||
|
#[cfg(feature = "napi8")]
|
||||||
|
pub use async_cleanup_hook::AsyncCleanupHook;
|
||||||
mod async_work;
|
mod async_work;
|
||||||
mod call_context;
|
mod call_context;
|
||||||
#[cfg(feature = "napi3")]
|
#[cfg(feature = "napi3")]
|
||||||
|
|
|
@ -29,7 +29,7 @@ pub enum Status {
|
||||||
ArrayBufferExpected,
|
ArrayBufferExpected,
|
||||||
DetachableArraybufferExpected,
|
DetachableArraybufferExpected,
|
||||||
WouldDeadlock,
|
WouldDeadlock,
|
||||||
Unknown = 1024, // unknown status. for example, using napi3 module in napi7 NodeJS, and generate an invalid napi3 status
|
Unknown = 1024, // unknown status. for example, using napi3 module in napi7 Node.js, and generate an invalid napi3 status
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for Status {
|
impl Display for Status {
|
||||||
|
|
|
@ -18,3 +18,4 @@ napi4 = ["napi3"]
|
||||||
napi5 = ["napi4"]
|
napi5 = ["napi4"]
|
||||||
napi6 = ["napi5"]
|
napi6 = ["napi5"]
|
||||||
napi7 = ["napi6"]
|
napi7 = ["napi6"]
|
||||||
|
napi8 = ["napi7"]
|
||||||
|
|
|
@ -181,6 +181,18 @@ pub enum napi_key_conversion {
|
||||||
napi_key_numbers_to_strings,
|
napi_key_numbers_to_strings,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "napi8")]
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
pub struct napi_async_cleanup_hook_handle__ {
|
||||||
|
_unused: [u8; 0],
|
||||||
|
}
|
||||||
|
#[cfg(feature = "napi8")]
|
||||||
|
pub type napi_async_cleanup_hook_handle = *mut napi_async_cleanup_hook_handle__;
|
||||||
|
#[cfg(feature = "napi8")]
|
||||||
|
pub type napi_async_cleanup_hook =
|
||||||
|
Option<unsafe extern "C" fn(handle: napi_async_cleanup_hook_handle, data: *mut c_void)>;
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
pub fn napi_get_last_error_info(
|
pub fn napi_get_last_error_info(
|
||||||
env: napi_env,
|
env: napi_env,
|
||||||
|
@ -801,6 +813,25 @@ extern "C" {
|
||||||
result: *mut bool,
|
result: *mut bool,
|
||||||
) -> napi_status;
|
) -> napi_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "napi8")]
|
||||||
|
extern "C" {
|
||||||
|
pub fn napi_add_async_cleanup_hook(
|
||||||
|
env: napi_env,
|
||||||
|
hook: napi_async_cleanup_hook,
|
||||||
|
arg: *mut c_void,
|
||||||
|
remove_handle: *mut napi_async_cleanup_hook_handle,
|
||||||
|
) -> napi_status;
|
||||||
|
|
||||||
|
pub fn napi_remove_async_cleanup_hook(
|
||||||
|
remove_handle: napi_async_cleanup_hook_handle,
|
||||||
|
) -> napi_status;
|
||||||
|
|
||||||
|
pub fn napi_object_freeze(env: napi_env, object: napi_value) -> napi_status;
|
||||||
|
|
||||||
|
pub fn napi_object_seal(env: napi_env, object: napi_value) -> napi_status;
|
||||||
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub struct napi_callback_scope__ {
|
pub struct napi_callback_scope__ {
|
||||||
|
|
|
@ -8,7 +8,7 @@ version = "0.1.0"
|
||||||
crate-type = ["cdylib"]
|
crate-type = ["cdylib"]
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
latest = ["napi/napi7"]
|
latest = ["napi/napi8"]
|
||||||
napi3 = ["napi/napi3"]
|
napi3 = ["napi/napi3"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|
33
test_module/__test__/napi7/arraybuffer.spec.ts
Normal file
33
test_module/__test__/napi7/arraybuffer.spec.ts
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
import ava from 'ava'
|
||||||
|
|
||||||
|
import { napiVersion } from '../napi-version'
|
||||||
|
|
||||||
|
const bindings = require('../../index.node')
|
||||||
|
|
||||||
|
const test = napiVersion >= 7 ? ava : ava.skip
|
||||||
|
|
||||||
|
test('should be able to detach ArrayBuffer', (t) => {
|
||||||
|
const buf = Buffer.from('hello world')
|
||||||
|
const ab = buf.buffer.slice(0, buf.length)
|
||||||
|
try {
|
||||||
|
bindings.testDetachArrayBuffer(ab)
|
||||||
|
t.is(ab.byteLength, 0)
|
||||||
|
} catch (e) {
|
||||||
|
t.is(e.code, 'DetachableArraybufferExpected')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
test('is detached arraybuffer should work fine', (t) => {
|
||||||
|
const buf = Buffer.from('hello world')
|
||||||
|
const ab = buf.buffer.slice(0, buf.length)
|
||||||
|
try {
|
||||||
|
bindings.testDetachArrayBuffer(ab)
|
||||||
|
const nonDetachedArrayBuffer = new ArrayBuffer(10)
|
||||||
|
const detachedArrayBuffer = new ArrayBuffer(0)
|
||||||
|
t.true(bindings.testIsDetachedArrayBuffer(ab))
|
||||||
|
t.false(bindings.testIsDetachedArrayBuffer(nonDetachedArrayBuffer))
|
||||||
|
t.true(bindings.testIsDetachedArrayBuffer(detachedArrayBuffer))
|
||||||
|
} catch (e) {
|
||||||
|
t.is(e.code, 'DetachableArraybufferExpected')
|
||||||
|
}
|
||||||
|
})
|
28
test_module/__test__/napi8/async-cleanup.spec.ts
Normal file
28
test_module/__test__/napi8/async-cleanup.spec.ts
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
import { execSync } from 'child_process'
|
||||||
|
import { join } from 'path'
|
||||||
|
|
||||||
|
import ava from 'ava'
|
||||||
|
|
||||||
|
import { napiVersion } from '../napi-version'
|
||||||
|
|
||||||
|
const bindings = require('../../index.node')
|
||||||
|
|
||||||
|
const test = napiVersion >= 8 ? ava : ava.skip
|
||||||
|
|
||||||
|
test('should be able to add async cleanup hook', (t) => {
|
||||||
|
const output = execSync(
|
||||||
|
`node ${join(__dirname, 'sub-process.js')}`,
|
||||||
|
).toString()
|
||||||
|
t.is(output.trim(), 'Exit from sub process')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('should be able to add removable async cleanup hook', (t) => {
|
||||||
|
const output = execSync(
|
||||||
|
`node ${join(__dirname, 'sub-process-removable.js')}`,
|
||||||
|
).toString()
|
||||||
|
t.is(output.trim(), 'Exit from sub process')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('should be able to remove cleanup hook after added', (t) => {
|
||||||
|
t.notThrows(() => bindings.testRemoveAsyncCleanupHook())
|
||||||
|
})
|
25
test_module/__test__/napi8/object.spec.ts
Normal file
25
test_module/__test__/napi8/object.spec.ts
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
import ava from 'ava'
|
||||||
|
|
||||||
|
import { napiVersion } from '../napi-version'
|
||||||
|
|
||||||
|
const bindings = require('../../index.node')
|
||||||
|
|
||||||
|
const test = napiVersion >= 8 ? ava : ava.skip
|
||||||
|
|
||||||
|
test('should be able to freeze object', (t) => {
|
||||||
|
const obj: any = {}
|
||||||
|
bindings.testFreezeObject(obj)
|
||||||
|
t.true(Object.isFrozen(obj))
|
||||||
|
t.throws(() => {
|
||||||
|
obj.a = 1
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
test('should be able to seal object', (t) => {
|
||||||
|
const obj: any = {}
|
||||||
|
bindings.testSealObject(obj)
|
||||||
|
t.true(Object.isSealed(obj))
|
||||||
|
t.throws(() => {
|
||||||
|
obj.a = 1
|
||||||
|
})
|
||||||
|
})
|
3
test_module/__test__/napi8/sub-process-removable.js
Normal file
3
test_module/__test__/napi8/sub-process-removable.js
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
const bindings = require('../../index.node')
|
||||||
|
|
||||||
|
bindings.testAddRemovableAsyncCleanupHook()
|
3
test_module/__test__/napi8/sub-process.js
Normal file
3
test_module/__test__/napi8/sub-process.js
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
const bindings = require('../../index.node')
|
||||||
|
|
||||||
|
bindings.testAddAsyncCleanupHook()
|
|
@ -13,6 +13,10 @@ mod napi5;
|
||||||
#[cfg(feature = "latest")]
|
#[cfg(feature = "latest")]
|
||||||
mod napi6;
|
mod napi6;
|
||||||
#[cfg(feature = "latest")]
|
#[cfg(feature = "latest")]
|
||||||
|
mod napi7;
|
||||||
|
#[cfg(feature = "latest")]
|
||||||
|
mod napi8;
|
||||||
|
#[cfg(feature = "latest")]
|
||||||
mod tokio_rt;
|
mod tokio_rt;
|
||||||
|
|
||||||
mod array;
|
mod array;
|
||||||
|
@ -61,5 +65,9 @@ fn init(mut exports: JsObject, env: Env) -> Result<()> {
|
||||||
napi5::register_js(&mut exports)?;
|
napi5::register_js(&mut exports)?;
|
||||||
#[cfg(feature = "latest")]
|
#[cfg(feature = "latest")]
|
||||||
napi6::register_js(&mut exports)?;
|
napi6::register_js(&mut exports)?;
|
||||||
|
#[cfg(feature = "latest")]
|
||||||
|
napi7::register_js(&mut exports)?;
|
||||||
|
#[cfg(feature = "latest")]
|
||||||
|
napi8::register_js(&mut exports)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
14
test_module/src/napi7/buffer.rs
Normal file
14
test_module/src/napi7/buffer.rs
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
use napi::*;
|
||||||
|
|
||||||
|
#[js_function(1)]
|
||||||
|
pub fn detach_arraybuffer(ctx: CallContext) -> Result<JsUndefined> {
|
||||||
|
let input = ctx.get::<JsArrayBuffer>(0)?;
|
||||||
|
input.detach()?;
|
||||||
|
ctx.env.get_undefined()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[js_function(1)]
|
||||||
|
pub fn is_detach_arraybuffer(ctx: CallContext) -> Result<JsBoolean> {
|
||||||
|
let input = ctx.get::<JsArrayBuffer>(0)?;
|
||||||
|
ctx.env.get_boolean(input.is_detached()?)
|
||||||
|
}
|
11
test_module/src/napi7/mod.rs
Normal file
11
test_module/src/napi7/mod.rs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
use napi::{JsObject, Result};
|
||||||
|
|
||||||
|
mod buffer;
|
||||||
|
|
||||||
|
use buffer::*;
|
||||||
|
|
||||||
|
pub fn register_js(exports: &mut JsObject) -> Result<()> {
|
||||||
|
exports.create_named_method("testDetachArrayBuffer", detach_arraybuffer)?;
|
||||||
|
exports.create_named_method("testIsDetachedArrayBuffer", is_detach_arraybuffer)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
30
test_module/src/napi8/async_cleanup.rs
Normal file
30
test_module/src/napi8/async_cleanup.rs
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
use napi::*;
|
||||||
|
|
||||||
|
#[js_function]
|
||||||
|
pub fn add_removable_async_cleanup_hook(ctx: CallContext) -> Result<JsUndefined> {
|
||||||
|
let cleanup_hook = ctx
|
||||||
|
.env
|
||||||
|
.add_removable_async_cleanup_hook(1u32, |_arg: u32| {
|
||||||
|
println!("Exit from sub process");
|
||||||
|
})?;
|
||||||
|
cleanup_hook.forget();
|
||||||
|
ctx.env.get_undefined()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[js_function]
|
||||||
|
pub fn add_async_cleanup_hook(ctx: CallContext) -> Result<JsUndefined> {
|
||||||
|
ctx.env.add_async_cleanup_hook(1u32, |_arg: u32| {
|
||||||
|
println!("Exit from sub process");
|
||||||
|
})?;
|
||||||
|
ctx.env.get_undefined()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[js_function]
|
||||||
|
pub fn remove_async_cleanup_hook(ctx: CallContext) -> Result<JsUndefined> {
|
||||||
|
ctx
|
||||||
|
.env
|
||||||
|
.add_removable_async_cleanup_hook(1u32, |_arg: u32| {
|
||||||
|
println!("Exit from sub process");
|
||||||
|
})?;
|
||||||
|
ctx.env.get_undefined()
|
||||||
|
}
|
19
test_module/src/napi8/mod.rs
Normal file
19
test_module/src/napi8/mod.rs
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
use napi::{JsObject, Result};
|
||||||
|
|
||||||
|
mod async_cleanup;
|
||||||
|
mod object;
|
||||||
|
|
||||||
|
use async_cleanup::*;
|
||||||
|
use object::*;
|
||||||
|
|
||||||
|
pub fn register_js(exports: &mut JsObject) -> Result<()> {
|
||||||
|
exports.create_named_method("testSealObject", seal_object)?;
|
||||||
|
exports.create_named_method("testFreezeObject", freeze_object)?;
|
||||||
|
exports.create_named_method(
|
||||||
|
"testAddRemovableAsyncCleanupHook",
|
||||||
|
add_removable_async_cleanup_hook,
|
||||||
|
)?;
|
||||||
|
exports.create_named_method("testRemoveAsyncCleanupHook", remove_async_cleanup_hook)?;
|
||||||
|
exports.create_named_method("testAddAsyncCleanupHook", add_async_cleanup_hook)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
15
test_module/src/napi8/object.rs
Normal file
15
test_module/src/napi8/object.rs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
use napi::*;
|
||||||
|
|
||||||
|
#[js_function(1)]
|
||||||
|
pub fn seal_object(ctx: CallContext) -> Result<JsUndefined> {
|
||||||
|
let mut obj: JsObject = ctx.get(0)?;
|
||||||
|
obj.seal()?;
|
||||||
|
ctx.env.get_undefined()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[js_function(1)]
|
||||||
|
pub fn freeze_object(ctx: CallContext) -> Result<JsUndefined> {
|
||||||
|
let mut obj: JsObject = ctx.get(0)?;
|
||||||
|
obj.freeze()?;
|
||||||
|
ctx.env.get_undefined()
|
||||||
|
}
|
Loading…
Reference in a new issue