Merge pull request #42 from Brooooooklyn/refactor-async
refactor(napi): async and lifetime span
This commit is contained in:
commit
617e9c78b0
24 changed files with 1645 additions and 462 deletions
6
.github/workflows/linux.yaml
vendored
6
.github/workflows/linux.yaml
vendored
|
@ -17,7 +17,7 @@ jobs:
|
|||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
|
@ -62,7 +62,7 @@ jobs:
|
|||
with:
|
||||
command: test
|
||||
args: -p napi-rs --lib -- --nocapture
|
||||
|
||||
|
||||
- name: test scripts
|
||||
run: |
|
||||
yarn
|
||||
|
@ -73,4 +73,4 @@ jobs:
|
|||
- name: Clear the cargo caches
|
||||
run: |
|
||||
cargo install cargo-cache --no-default-features --features ci-autoclean
|
||||
cargo-cache
|
||||
cargo-cache
|
||||
|
|
4
.github/workflows/macos.yaml
vendored
4
.github/workflows/macos.yaml
vendored
|
@ -17,7 +17,7 @@ jobs:
|
|||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
|
@ -73,4 +73,4 @@ jobs:
|
|||
- name: Clear the cargo caches
|
||||
run: |
|
||||
cargo install cargo-cache --no-default-features --features ci-autoclean
|
||||
cargo-cache
|
||||
cargo-cache
|
||||
|
|
6
.github/workflows/windows.yaml
vendored
6
.github/workflows/windows.yaml
vendored
|
@ -19,7 +19,7 @@ jobs:
|
|||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
|
@ -31,7 +31,7 @@ jobs:
|
|||
profile: minimal
|
||||
override: true
|
||||
- name: Install llvm
|
||||
run: choco install -y llvm
|
||||
run: choco install -y llvm
|
||||
- name: set environment variables
|
||||
uses: allenevans/set-env@v1.0.0
|
||||
with:
|
||||
|
@ -68,7 +68,7 @@ jobs:
|
|||
with:
|
||||
command: test
|
||||
args: -p napi-rs --lib -- --nocapture
|
||||
|
||||
|
||||
- name: test scripts
|
||||
run: |
|
||||
yarn
|
||||
|
|
2
.prettierignore
Normal file
2
.prettierignore
Normal file
|
@ -0,0 +1,2 @@
|
|||
target
|
||||
node_modules
|
144
README.md
144
README.md
|
@ -27,6 +27,7 @@ This library depends on N-API and requires Node 8.9 or later. It is still pretty
|
|||
One nice feature is that this crate allows you to build add-ons purely with the Rust toolchain and without involving `node-gyp`.
|
||||
|
||||
## Taste
|
||||
|
||||
```rust
|
||||
#[js_function(1)] // ------> arguments length, omit for zero
|
||||
fn fibonacci(ctx: CallContext) -> Result<Value<Number>> {
|
||||
|
@ -62,7 +63,7 @@ napi-build = "0.1"
|
|||
|
||||
And create `build.rs` in your own project:
|
||||
|
||||
```rs
|
||||
```rust
|
||||
// build.rs
|
||||
extern crate napi_build;
|
||||
|
||||
|
@ -71,14 +72,13 @@ fn main() {
|
|||
}
|
||||
```
|
||||
|
||||
So far, the `napi` build script has only been tested on `macOS` `Linux` and `Windows x64 MSVC`.
|
||||
So far, the `napi` build script has only been tested on `macOS` `Linux` and `Windows x64 MSVC`.
|
||||
|
||||
See the included [test_module](./test_module) for an example add-on.
|
||||
|
||||
Run `cargo build` to produce the `Dynamic lib` file. And install the `napi-rs` to help you copy `Dynamic lib` file to `.node` file in case you can `require` it in your program.
|
||||
|
||||
```json
|
||||
|
||||
{
|
||||
"package": "your pkg",
|
||||
"dependencies": {
|
||||
|
@ -127,78 +127,78 @@ npm test
|
|||
|
||||
### Create JavaScript values
|
||||
|
||||
| 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 | ✅ |
|
||||
| [napi_create_buffer](https://nodejs.org/api/n-api.html#n_api_napi_create_buffer) | 1 | v8.0.0 | ✅ |
|
||||
| [napi_create_buffer_copy](https://nodejs.org/api/n-api.html#n_api_napi_create_buffer_copy) | 1 | v8.0.0 | ⛔️ |
|
||||
| [napi_create_date](https://nodejs.org/api/n-api.html#n_api_napi_create_date) | 5 | v11.11.0 | ⛔️ |
|
||||
| [napi_create_external](https://nodejs.org/api/n-api.html#n_api_napi_create_external) | 1 | v8.0.0 | ⛔️ |
|
||||
| [napi_create_external_arraybuffer](https://nodejs.org/api/n-api.html#n_api_napi_create_external_arraybuffer) | 1 | v8.0.0 | ✅ |
|
||||
| [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_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 | ✅ |
|
||||
| [napi_create_int64](https://nodejs.org/api/n-api.html#n_api_napi_create_int64) | 1 | v8.4.0 | ✅ |
|
||||
| [napi_create_double](https://nodejs.org/api/n-api.html#n_api_napi_create_double) | 1 | v8.4.0 | ✅ |
|
||||
| [napi_create_bigint_int64](https://nodejs.org/api/n-api.html#n_api_napi_create_bigint_int64) | 6 | v10.7.0 | ⛔️ |
|
||||
| [napi_create_bigint_uint64](https://nodejs.org/api/n-api.html#n_api_napi_create_bigint_uint64) | 6 | v10.7.0 | ⛔️ |
|
||||
| [napi_create_bigint_words](https://nodejs.org/api/n-api.html#n_api_napi_create_bigint_words) | 6 | v10.7.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_utf8](https://nodejs.org/api/n-api.html#n_api_napi_create_string_utf8) | 1 | v8.0.0 | ✅ |
|
||||
| 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 | ✅ |
|
||||
| [napi_create_buffer](https://nodejs.org/api/n-api.html#n_api_napi_create_buffer) | 1 | v8.0.0 | ✅ |
|
||||
| [napi_create_buffer_copy](https://nodejs.org/api/n-api.html#n_api_napi_create_buffer_copy) | 1 | v8.0.0 | ⛔️ |
|
||||
| [napi_create_date](https://nodejs.org/api/n-api.html#n_api_napi_create_date) | 5 | v11.11.0 | ⛔️ |
|
||||
| [napi_create_external](https://nodejs.org/api/n-api.html#n_api_napi_create_external) | 1 | v8.0.0 | ⛔️ |
|
||||
| [napi_create_external_arraybuffer](https://nodejs.org/api/n-api.html#n_api_napi_create_external_arraybuffer) | 1 | v8.0.0 | ✅ |
|
||||
| [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_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 | ✅ |
|
||||
| [napi_create_int64](https://nodejs.org/api/n-api.html#n_api_napi_create_int64) | 1 | v8.4.0 | ✅ |
|
||||
| [napi_create_double](https://nodejs.org/api/n-api.html#n_api_napi_create_double) | 1 | v8.4.0 | ✅ |
|
||||
| [napi_create_bigint_int64](https://nodejs.org/api/n-api.html#n_api_napi_create_bigint_int64) | 6 | v10.7.0 | ⛔️ |
|
||||
| [napi_create_bigint_uint64](https://nodejs.org/api/n-api.html#n_api_napi_create_bigint_uint64) | 6 | v10.7.0 | ⛔️ |
|
||||
| [napi_create_bigint_words](https://nodejs.org/api/n-api.html#n_api_napi_create_bigint_words) | 6 | v10.7.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_utf8](https://nodejs.org/api/n-api.html#n_api_napi_create_string_utf8) | 1 | v8.0.0 | ✅ |
|
||||
|
||||
### [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)
|
||||
|
||||
| NAPI | NAPI Version | Minimal Node Version | Status |
|
||||
| ---- | ------------ | -------------------- | ------ |
|
||||
|[napi_get_array_length](https://nodejs.org/api/n-api.html#n_api_napi_get_array_length)| 1 | v8.0.0 | ✅ |
|
||||
|[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_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 | ✅ |
|
||||
|[napi_get_value_double](https://nodejs.org/api/n-api.html#n_api_napi_get_value_double)| 1 | v8.0.0 | ✅ |
|
||||
|[napi_get_value_bigint_int64](https://nodejs.org/api/n-api.html#n_api_napi_get_value_bigint_int64)| 6 | v10.7.0 | ⛔️ |
|
||||
|[napi_get_value_bigint_uint64](https://nodejs.org/api/n-api.html#n_api_napi_get_value_bigint_uint64)| 6 | v10.7.0 | ⛔️ |
|
||||
|[napi_get_value_bigint_words](https://nodejs.org/api/n-api.html#n_api_napi_get_value_bigint_words)| 6 | v10.7.0 | ⛔️ |
|
||||
|[napi_get_value_external](https://nodejs.org/api/n-api.html#n_api_napi_get_value_external)| 1 | v8.0.0 | ⛔️ |
|
||||
|[napi_get_value_int32](https://nodejs.org/api/n-api.html#n_api_napi_get_value_int32)| 1 | v8.0.0 | ✅ |
|
||||
|[napi_get_value_int64](https://nodejs.org/api/n-api.html#n_api_napi_get_value_int64)| 1 | v8.0.0 | ✅ |
|
||||
|[napi_get_value_string_latin1](https://nodejs.org/api/n-api.html#n_api_napi_get_value_string_latin1)| 1 | v8.0.0 | ⛔️ |
|
||||
|[napi_get_value_string_utf8](https://nodejs.org/api/n-api.html#n_api_napi_get_value_string_utf8)| 1 | v8.0.0 | ✅ |
|
||||
|[napi_get_value_string_utf16](https://nodejs.org/api/n-api.html#n_api_napi_get_value_string_utf16)| 1 | v8.0.0 | ✅ |
|
||||
|[napi_get_value_uint32](https://nodejs.org/api/n-api.html#n_api_napi_get_value_uint32)| 1 | v8.0.0 | ✅ |
|
||||
|[napi_get_boolean](https://nodejs.org/api/n-api.html#n_api_napi_get_boolean)| 1 | v8.0.0 | ✅ |
|
||||
|[napi_get_global](https://nodejs.org/api/n-api.html#n_api_napi_get_global)| 1 | v8.0.0 | ⛔️ |
|
||||
|[napi_get_null](https://nodejs.org/api/n-api.html#n_api_napi_get_null)| 1 | v8.0.0 | ✅ |
|
||||
|[napi_get_undefined](https://nodejs.org/api/n-api.html#n_api_napi_get_undefined)| 1 | v8.0.0 | ✅ |
|
||||
| NAPI | NAPI Version | Minimal Node Version | Status |
|
||||
| ---------------------------------------------------------------------------------------------------- | ------------ | -------------------- | ------ |
|
||||
| [napi_get_array_length](https://nodejs.org/api/n-api.html#n_api_napi_get_array_length) | 1 | v8.0.0 | ✅ |
|
||||
| [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_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 | ✅ |
|
||||
| [napi_get_value_double](https://nodejs.org/api/n-api.html#n_api_napi_get_value_double) | 1 | v8.0.0 | ✅ |
|
||||
| [napi_get_value_bigint_int64](https://nodejs.org/api/n-api.html#n_api_napi_get_value_bigint_int64) | 6 | v10.7.0 | ⛔️ |
|
||||
| [napi_get_value_bigint_uint64](https://nodejs.org/api/n-api.html#n_api_napi_get_value_bigint_uint64) | 6 | v10.7.0 | ⛔️ |
|
||||
| [napi_get_value_bigint_words](https://nodejs.org/api/n-api.html#n_api_napi_get_value_bigint_words) | 6 | v10.7.0 | ⛔️ |
|
||||
| [napi_get_value_external](https://nodejs.org/api/n-api.html#n_api_napi_get_value_external) | 1 | v8.0.0 | ⛔️ |
|
||||
| [napi_get_value_int32](https://nodejs.org/api/n-api.html#n_api_napi_get_value_int32) | 1 | v8.0.0 | ✅ |
|
||||
| [napi_get_value_int64](https://nodejs.org/api/n-api.html#n_api_napi_get_value_int64) | 1 | v8.0.0 | ✅ |
|
||||
| [napi_get_value_string_latin1](https://nodejs.org/api/n-api.html#n_api_napi_get_value_string_latin1) | 1 | v8.0.0 | ⛔️ |
|
||||
| [napi_get_value_string_utf8](https://nodejs.org/api/n-api.html#n_api_napi_get_value_string_utf8) | 1 | v8.0.0 | ✅ |
|
||||
| [napi_get_value_string_utf16](https://nodejs.org/api/n-api.html#n_api_napi_get_value_string_utf16) | 1 | v8.0.0 | ✅ |
|
||||
| [napi_get_value_uint32](https://nodejs.org/api/n-api.html#n_api_napi_get_value_uint32) | 1 | v8.0.0 | ✅ |
|
||||
| [napi_get_boolean](https://nodejs.org/api/n-api.html#n_api_napi_get_boolean) | 1 | v8.0.0 | ✅ |
|
||||
| [napi_get_global](https://nodejs.org/api/n-api.html#n_api_napi_get_global) | 1 | v8.0.0 | ⛔️ |
|
||||
| [napi_get_null](https://nodejs.org/api/n-api.html#n_api_napi_get_null) | 1 | v8.0.0 | ✅ |
|
||||
| [napi_get_undefined](https://nodejs.org/api/n-api.html#n_api_napi_get_undefined) | 1 | v8.0.0 | ✅ |
|
||||
|
||||
### [Working with JavaScript Values and Abstract Operations](https://nodejs.org/api/n-api.html#n_api_working_with_javascript_values_and_abstract_operations)
|
||||
|
||||
| NAPI | NAPI Version | Minimal Node Version | Status |
|
||||
| ---- | ------------ | -------------------- | ------ |
|
||||
|[napi_coerce_to_bool](https://nodejs.org/api/n-api.html#n_api_napi_coerce_to_bool)| 1 | v8.0.0 | ✅ |
|
||||
|[napi_coerce_to_number](https://nodejs.org/api/n-api.html#n_api_napi_coerce_to_number)| 1 | v8.0.0 | ✅ |
|
||||
|[napi_coerce_to_object](https://nodejs.org/api/n-api.html#n_api_napi_coerce_to_object)| 1 | v8.0.0 | ✅ |
|
||||
|[napi_coerce_to_string](https://nodejs.org/api/n-api.html#n_api_napi_coerce_to_string)| 1 | v8.0.0 | ✅ |
|
||||
|[napi_typeof](https://nodejs.org/api/n-api.html#n_api_napi_typeof)| 1 | v8.0.0 | ✅ |
|
||||
|[napi_instanceof](https://nodejs.org/api/n-api.html#n_api_napi_instanceof)| 1 | v8.0.0 | ⛔️ |
|
||||
|[napi_is_array](https://nodejs.org/api/n-api.html#n_api_napi_is_array)| 1 | v8.0.0 | ✅ |
|
||||
|[napi_is_arraybuffer](https://nodejs.org/api/n-api.html#n_api_napi_is_arraybuffer)| 1 | v8.0.0 | ✅ |
|
||||
|[napi_is_buffer](https://nodejs.org/api/n-api.html#n_api_napi_is_buffer)| 1 | v8.0.0 | ✅ |
|
||||
|[napi_is_date](https://nodejs.org/api/n-api.html#n_api_napi_is_date)| 1 | v8.0.0 | ⛔️ |
|
||||
|[napi_is_error](https://nodejs.org/api/n-api.html#n_api_napi_is_error_1)| 1 | v8.0.0 | ⛔️ |
|
||||
|[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 | NAPI Version | Minimal Node Version | Status |
|
||||
| ---------------------------------------------------------------------------------------------------- | ------------ | -------------------- | ------ |
|
||||
| [napi_coerce_to_bool](https://nodejs.org/api/n-api.html#n_api_napi_coerce_to_bool) | 1 | v8.0.0 | ✅ |
|
||||
| [napi_coerce_to_number](https://nodejs.org/api/n-api.html#n_api_napi_coerce_to_number) | 1 | v8.0.0 | ✅ |
|
||||
| [napi_coerce_to_object](https://nodejs.org/api/n-api.html#n_api_napi_coerce_to_object) | 1 | v8.0.0 | ✅ |
|
||||
| [napi_coerce_to_string](https://nodejs.org/api/n-api.html#n_api_napi_coerce_to_string) | 1 | v8.0.0 | ✅ |
|
||||
| [napi_typeof](https://nodejs.org/api/n-api.html#n_api_napi_typeof) | 1 | v8.0.0 | ✅ |
|
||||
| [napi_instanceof](https://nodejs.org/api/n-api.html#n_api_napi_instanceof) | 1 | v8.0.0 | ⛔️ |
|
||||
| [napi_is_array](https://nodejs.org/api/n-api.html#n_api_napi_is_array) | 1 | v8.0.0 | ✅ |
|
||||
| [napi_is_arraybuffer](https://nodejs.org/api/n-api.html#n_api_napi_is_arraybuffer) | 1 | v8.0.0 | ✅ |
|
||||
| [napi_is_buffer](https://nodejs.org/api/n-api.html#n_api_napi_is_buffer) | 1 | v8.0.0 | ✅ |
|
||||
| [napi_is_date](https://nodejs.org/api/n-api.html#n_api_napi_is_date) | 1 | v8.0.0 | ⛔️ |
|
||||
| [napi_is_error](https://nodejs.org/api/n-api.html#n_api_napi_is_error_1) | 1 | v8.0.0 | ⛔️ |
|
||||
| [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 | ⛔️ |
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# napi-build
|
||||
|
||||
> Build support for napi-rs
|
||||
|
||||
Setup `N-API` build in your `build.rs`:
|
||||
|
|
|
@ -8,10 +8,7 @@ use std::convert::TryInto;
|
|||
|
||||
register_module!(test_module, init);
|
||||
|
||||
fn init<'env>(
|
||||
env: &'env Env,
|
||||
exports: &'env mut Value<'env, Object>,
|
||||
) -> Result<Option<Value<'env, Object>>> {
|
||||
fn init(env: &Env, exports: &mut Value<Object>) -> Result<Option<Value<Object>>> {
|
||||
exports.set_named_property("testThrow", env.create_function("testThrow", test_throw)?)?;
|
||||
|
||||
exports.set_named_property("fibonacci", env.create_function("fibonacci", fibonacci)?)?;
|
||||
|
@ -20,7 +17,7 @@ fn init<'env>(
|
|||
|
||||
#[js_function]
|
||||
fn test_throw(_ctx: CallContext) -> Result<Value<Any>> {
|
||||
Err(Error::new(Status::GenericFailure))
|
||||
Err(Error::from_status(Status::GenericFailure))
|
||||
}
|
||||
|
||||
#[js_function(1)]
|
||||
|
|
|
@ -102,16 +102,13 @@ pub fn js_function(attr: TokenStream, input: TokenStream) -> TokenStream {
|
|||
}
|
||||
|
||||
let env = Env::from_raw(raw_env);
|
||||
let call_ctx = CallContext::new(&env, raw_this, raw_args, #arg_len_span);
|
||||
let call_ctx = CallContext::new(env, raw_this, raw_args, #arg_len_span);
|
||||
let result = call_ctx.and_then(|ctx| #new_fn_name(ctx));
|
||||
has_error = has_error && result.is_err();
|
||||
|
||||
match result {
|
||||
Ok(result) => result.into_raw(),
|
||||
Err(e) => {
|
||||
if !cfg!(windows) {
|
||||
let _ = writeln!(::std::io::stderr(), "Error calling function: {:?}", e);
|
||||
}
|
||||
let message = format!("{:?}", e);
|
||||
unsafe {
|
||||
napi_rs::sys::napi_throw_error(raw_env, ptr::null(), message.as_ptr() as *const c_char);
|
||||
|
|
|
@ -7,6 +7,7 @@ description = "N-API bindings"
|
|||
readme = "README.md"
|
||||
repository = "https://github.com/Brooooooklyn/napi-rs"
|
||||
keywords = ["NodeJS", "FFI", "NAPI", "n-api"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
futures = { version = "0.3", features = ["default", "thread-pool"] }
|
||||
|
@ -25,7 +26,6 @@ tar = "0.4"
|
|||
|
||||
[build-dependencies]
|
||||
bindgen = "0.53"
|
||||
cc = "1.0"
|
||||
glob = "0.3"
|
||||
napi-build = { version = "0.1", path = "../build" }
|
||||
regex = "1.3"
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
extern crate bindgen;
|
||||
extern crate cc;
|
||||
#[cfg(windows)]
|
||||
extern crate flate2;
|
||||
extern crate glob;
|
||||
|
@ -36,8 +35,6 @@ fn main() {
|
|||
);
|
||||
}
|
||||
|
||||
env::set_var("CARGO_RUSTC_FLAGS", "-Clink-args=-export_dynamic");
|
||||
|
||||
if node_major_version < 10 {
|
||||
panic!("node version is too low")
|
||||
}
|
||||
|
@ -60,31 +57,6 @@ fn main() {
|
|||
.expect("Unable to generate napi bindings")
|
||||
.write_to_file(out_path.join("bindings.rs"))
|
||||
.expect("Unable to write napi bindings");
|
||||
|
||||
let mut bindings_path = PathBuf::from("src");
|
||||
bindings_path.push("sys");
|
||||
bindings_path.push("bindings.cc");
|
||||
|
||||
let mut cc_builder = cc::Build::new();
|
||||
|
||||
cc_builder
|
||||
.cpp(true)
|
||||
.include(&node_include_path)
|
||||
.file(bindings_path);
|
||||
if !cfg!(windows) {
|
||||
cc_builder.flag("-Wno-unused-parameter");
|
||||
};
|
||||
|
||||
if cfg!(target_os = "macos") {
|
||||
cc_builder.flag("-std=c++0x");
|
||||
} else if cfg!(linux) || cfg!(target_env = "gnu") {
|
||||
cc_builder.flag("-std=c++14");
|
||||
}
|
||||
|
||||
cc_builder
|
||||
.cargo_metadata(true)
|
||||
.out_dir(&out_path)
|
||||
.compile("napi-bindings");
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
|
|
|
@ -1,32 +1,35 @@
|
|||
use crate::{sys, Any, Env, Error, Result, Status, Value, ValueType};
|
||||
|
||||
pub struct CallContext<'env, T: ValueType = Any> {
|
||||
pub env: &'env Env,
|
||||
pub this: Value<'env, T>,
|
||||
pub struct CallContext<T: ValueType = Any> {
|
||||
pub env: Env,
|
||||
pub this: Value<T>,
|
||||
args: [sys::napi_value; 8],
|
||||
arg_len: usize,
|
||||
}
|
||||
|
||||
impl<'env, T: ValueType> CallContext<'env, T> {
|
||||
impl<T: ValueType> CallContext<T> {
|
||||
pub fn new(
|
||||
env: &'env Env,
|
||||
env: Env,
|
||||
this: sys::napi_value,
|
||||
args: [sys::napi_value; 8],
|
||||
arg_len: usize,
|
||||
) -> Result<Self> {
|
||||
Ok(Self {
|
||||
env,
|
||||
this: Value::<'env, T>::from_raw(env, this)?,
|
||||
this: Value::<T>::from_raw(env.0, this)?,
|
||||
args,
|
||||
arg_len,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get<ArgType: ValueType>(&'env self, index: usize) -> Result<Value<'env, ArgType>> {
|
||||
pub fn get<ArgType: ValueType>(&self, index: usize) -> Result<Value<ArgType>> {
|
||||
if index + 1 > self.arg_len {
|
||||
Err(Error::new(Status::GenericFailure))
|
||||
Err(Error {
|
||||
status: Status::GenericFailure,
|
||||
reason: Some("Arguments index out of range".to_owned()),
|
||||
})
|
||||
} else {
|
||||
Value::<'env, ArgType>::from_raw(&self.env, self.args[index])
|
||||
Value::<ArgType>::from_raw(self.env.0, self.args[index])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
use super::sys;
|
||||
use futures::task::Poll;
|
||||
use std::future::Future;
|
||||
use std::mem;
|
||||
|
@ -7,16 +6,7 @@ use std::pin::Pin;
|
|||
use std::sync::Arc;
|
||||
use std::task::{Context, RawWaker, RawWakerVTable, Waker};
|
||||
|
||||
pub struct LibuvExecutor {
|
||||
event_loop: *mut sys::uv_loop_s,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct LibuvWaker(*mut sys::uv_async_t);
|
||||
|
||||
unsafe impl Send for LibuvWaker {}
|
||||
|
||||
unsafe impl Sync for LibuvWaker {}
|
||||
use crate::{sys, Error, Result, Status};
|
||||
|
||||
const UV_ASYNC_V_TABLE: RawWakerVTable = RawWakerVTable::new(
|
||||
clone_executor,
|
||||
|
@ -39,46 +29,47 @@ unsafe fn wake_uv_async_by_ref(uv_async_t: *const ()) {
|
|||
assert!(status == 0, "wake_uv_async_by_ref failed");
|
||||
}
|
||||
|
||||
unsafe fn drop_uv_async(uv_async_t_ptr: *const ()) {
|
||||
sys::uv_unref(uv_async_t_ptr as *mut sys::uv_handle_t);
|
||||
}
|
||||
unsafe fn drop_uv_async(_uv_async_t_ptr: *const ()) {}
|
||||
|
||||
struct Task<'a> {
|
||||
future: Pin<Box<dyn Future<Output = ()>>>,
|
||||
context: Context<'a>,
|
||||
}
|
||||
|
||||
impl LibuvExecutor {
|
||||
pub fn new(event_loop: *mut sys::uv_loop_s) -> Self {
|
||||
Self { event_loop }
|
||||
}
|
||||
|
||||
pub fn execute<F: 'static + Future<Output = ()>>(&self, future: F) {
|
||||
let uninit = mem::MaybeUninit::<sys::uv_async_t>::uninit();
|
||||
let uv_async_t: Box<sys::uv_async_t> = unsafe { Box::new(uninit.assume_init()) };
|
||||
let uv_async_t_ref = Box::leak(uv_async_t);
|
||||
unsafe {
|
||||
let status = sys::uv_async_init(self.event_loop, uv_async_t_ref, Some(poll_future));
|
||||
assert!(status == 0, "Non-zero status returned from uv_async_init");
|
||||
};
|
||||
unsafe {
|
||||
let waker = Waker::from_raw(RawWaker::new(
|
||||
uv_async_t_ref as *mut _ as *const (),
|
||||
&UV_ASYNC_V_TABLE,
|
||||
));
|
||||
let context = Context::from_waker(&waker);
|
||||
let mut task = Box::new(Task {
|
||||
future: Box::pin(future),
|
||||
context,
|
||||
pub fn execute<F: 'static + Future<Output = ()>>(
|
||||
event_loop: *mut sys::uv_loop_s,
|
||||
future: F,
|
||||
) -> Result<()> {
|
||||
let uninit = mem::MaybeUninit::<sys::uv_async_t>::uninit();
|
||||
let uv_async_t: Box<sys::uv_async_t> = unsafe { Box::new(uninit.assume_init()) };
|
||||
let uv_async_t_ref = Box::leak(uv_async_t);
|
||||
unsafe {
|
||||
let status = sys::uv_async_init(event_loop, uv_async_t_ref, Some(poll_future));
|
||||
if status != 0 {
|
||||
return Err(Error {
|
||||
status: Status::Unknown,
|
||||
reason: Some("Non-zero status returned from uv_async_init".to_owned()),
|
||||
});
|
||||
if !task.as_mut().poll_future() {
|
||||
let arc_task = Arc::new(task);
|
||||
sys::uv_handle_set_data(
|
||||
uv_async_t_ref as *mut _ as *mut sys::uv_handle_t,
|
||||
Arc::into_raw(arc_task) as *mut c_void,
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
unsafe {
|
||||
let waker = Waker::from_raw(RawWaker::new(
|
||||
uv_async_t_ref as *mut _ as *const (),
|
||||
&UV_ASYNC_V_TABLE,
|
||||
));
|
||||
let context = Context::from_waker(&waker);
|
||||
let mut task = Box::new(Task {
|
||||
future: Box::pin(future),
|
||||
context,
|
||||
});
|
||||
if !task.as_mut().poll_future() {
|
||||
let arc_task = Arc::new(task);
|
||||
sys::uv_handle_set_data(
|
||||
uv_async_t_ref as *mut _ as *mut sys::uv_handle_t,
|
||||
Arc::into_raw(arc_task) as *mut c_void,
|
||||
);
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -96,10 +87,7 @@ unsafe extern "C" fn poll_future(handle: *mut sys::uv_async_t) {
|
|||
let mut task = Arc::from_raw(data_ptr);
|
||||
if let Some(mut_task) = Arc::get_mut(&mut task) {
|
||||
if mut_task.poll_future() {
|
||||
sys::uv_close(
|
||||
handle as *mut sys::uv_handle_t,
|
||||
Some(drop_handle_after_close),
|
||||
);
|
||||
sys::uv_close(handle as *mut sys::uv_handle_t, None);
|
||||
} else {
|
||||
Arc::into_raw(task);
|
||||
};
|
||||
|
@ -107,7 +95,3 @@ unsafe extern "C" fn poll_future(handle: *mut sys::uv_async_t) {
|
|||
Arc::into_raw(task);
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "C" fn drop_handle_after_close(handle: *mut sys::uv_handle_t) {
|
||||
Box::from_raw(handle);
|
||||
}
|
||||
|
|
382
napi/src/lib.rs
382
napi/src/lib.rs
|
@ -1,5 +1,7 @@
|
|||
extern crate futures;
|
||||
|
||||
use core::fmt::Debug;
|
||||
use futures::prelude::*;
|
||||
use std::any::TypeId;
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
use std::ffi::CString;
|
||||
|
@ -14,17 +16,21 @@ use std::string::String as RustString;
|
|||
|
||||
mod call_context;
|
||||
mod executor;
|
||||
mod promise;
|
||||
pub mod sys;
|
||||
mod version;
|
||||
|
||||
pub use call_context::CallContext;
|
||||
pub use sys::{napi_valuetype, Status};
|
||||
pub use version::NodeVersion;
|
||||
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
pub type Callback = extern "C" fn(sys::napi_env, sys::napi_callback_info) -> sys::napi_value;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Error {
|
||||
status: Status,
|
||||
pub status: Status,
|
||||
pub reason: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
|
@ -75,8 +81,8 @@ pub struct ArrayBuffer {
|
|||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Value<'env, T> {
|
||||
env: &'env Env,
|
||||
pub struct Value<T> {
|
||||
env: sys::napi_env,
|
||||
raw_value: sys::napi_value,
|
||||
value: T,
|
||||
}
|
||||
|
@ -87,14 +93,6 @@ pub struct Ref<T> {
|
|||
_marker: PhantomData<T>,
|
||||
}
|
||||
|
||||
pub struct AsyncContext {
|
||||
raw_env: sys::napi_env,
|
||||
raw_context: sys::napi_async_context,
|
||||
raw_resource: sys::napi_ref,
|
||||
}
|
||||
|
||||
pub struct Deferred(sys::napi_deferred);
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Property {
|
||||
name: RustString,
|
||||
|
@ -141,7 +139,7 @@ macro_rules! register_module {
|
|||
raw_exports: sys::napi_value,
|
||||
) -> sys::napi_value {
|
||||
let env = Env::from_raw(raw_env);
|
||||
let mut exports: Value<Object> = Value::from_raw(&env, raw_exports).unwrap();
|
||||
let mut exports: Value<Object> = Value::from_raw(raw_env, raw_exports).unwrap();
|
||||
|
||||
let result = $init(&env, &mut exports);
|
||||
|
||||
|
@ -162,15 +160,19 @@ macro_rules! register_module {
|
|||
}
|
||||
|
||||
impl Error {
|
||||
pub fn new(status: Status) -> Self {
|
||||
Error { status: status }
|
||||
pub fn from_status(status: Status) -> Self {
|
||||
Error {
|
||||
status: status,
|
||||
reason: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::ffi::NulError> for Error {
|
||||
fn from(_error: std::ffi::NulError) -> Self {
|
||||
fn from(error: std::ffi::NulError) -> Self {
|
||||
Error {
|
||||
status: Status::StringExpected,
|
||||
reason: Some(format!("{:?}", error)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -180,14 +182,14 @@ impl Env {
|
|||
Env(env)
|
||||
}
|
||||
|
||||
pub fn get_undefined<'a>(&'a self) -> Result<Value<'a, Undefined>> {
|
||||
pub fn get_undefined(&self) -> Result<Value<Undefined>> {
|
||||
let mut raw_value = ptr::null_mut();
|
||||
let status = unsafe { sys::napi_get_undefined(self.0, &mut raw_value) };
|
||||
check_status(status)?;
|
||||
Ok(Value::from_raw_value(self, raw_value, Undefined))
|
||||
}
|
||||
|
||||
pub fn get_null<'a>(&'a self) -> Result<Value<'a, Null>> {
|
||||
pub fn get_null(&self) -> Result<Value<Null>> {
|
||||
let mut raw_value = ptr::null_mut();
|
||||
let status = unsafe { sys::napi_get_null(self.0, &mut raw_value) };
|
||||
check_status(status)?;
|
||||
|
@ -201,7 +203,7 @@ impl Env {
|
|||
Ok(Value::from_raw_value(self, raw_value, Boolean { value }))
|
||||
}
|
||||
|
||||
pub fn create_int32<'a>(&'a self, int: i32) -> Result<Value<'a, Number>> {
|
||||
pub fn create_int32(&self, int: i32) -> Result<Value<Number>> {
|
||||
let mut raw_value = ptr::null_mut();
|
||||
let status =
|
||||
unsafe { sys::napi_create_int32(self.0, int, (&mut raw_value) as *mut sys::napi_value) };
|
||||
|
@ -209,7 +211,7 @@ impl Env {
|
|||
Ok(Value::from_raw_value(self, raw_value, Number::Int32(int)))
|
||||
}
|
||||
|
||||
pub fn create_int64<'a>(&'a self, int: i64) -> Result<Value<'a, Number>> {
|
||||
pub fn create_int64(&self, int: i64) -> Result<Value<Number>> {
|
||||
let mut raw_value = ptr::null_mut();
|
||||
let status =
|
||||
unsafe { sys::napi_create_int64(self.0, int, (&mut raw_value) as *mut sys::napi_value) };
|
||||
|
@ -217,7 +219,7 @@ impl Env {
|
|||
Ok(Value::from_raw_value(self, raw_value, Number::Int(int)))
|
||||
}
|
||||
|
||||
pub fn create_uint32<'a>(&'a self, number: u32) -> Result<Value<'a, Number>> {
|
||||
pub fn create_uint32(&self, number: u32) -> Result<Value<Number>> {
|
||||
let mut raw_value = ptr::null_mut();
|
||||
let status =
|
||||
unsafe { sys::napi_create_uint32(self.0, number, (&mut raw_value) as *mut sys::napi_value) };
|
||||
|
@ -225,7 +227,7 @@ impl Env {
|
|||
Ok(Value::from_raw_value(self, raw_value, Number::U32(number)))
|
||||
}
|
||||
|
||||
pub fn create_double<'a>(&'a self, double: f64) -> Result<Value<'a, Number>> {
|
||||
pub fn create_double(&self, double: f64) -> Result<Value<Number>> {
|
||||
let mut raw_value = ptr::null_mut();
|
||||
let status =
|
||||
unsafe { sys::napi_create_double(self.0, double, (&mut raw_value) as *mut sys::napi_value) };
|
||||
|
@ -237,7 +239,7 @@ impl Env {
|
|||
))
|
||||
}
|
||||
|
||||
pub fn create_string<'a, 'b>(&'a self, s: &'b str) -> Result<Value<'a, JsString>> {
|
||||
pub fn create_string<'a, 'b>(&'a self, s: &'b str) -> Result<Value<JsString>> {
|
||||
let mut raw_value = ptr::null_mut();
|
||||
let status = unsafe {
|
||||
sys::napi_create_string_utf8(
|
||||
|
@ -260,7 +262,7 @@ impl Env {
|
|||
Ok(Value::from_raw_value(self, raw_value, JsString))
|
||||
}
|
||||
|
||||
pub fn create_object<'a>(&'a self) -> Result<Value<'a, Object>> {
|
||||
pub fn create_object(&self) -> Result<Value<Object>> {
|
||||
let mut raw_value = ptr::null_mut();
|
||||
let status = unsafe { sys::napi_create_object(self.0, &mut raw_value) };
|
||||
check_status(status)?;
|
||||
|
@ -365,11 +367,7 @@ impl Env {
|
|||
))
|
||||
}
|
||||
|
||||
pub fn create_function<'a, 'b>(
|
||||
&'a self,
|
||||
name: &'b str,
|
||||
callback: Callback,
|
||||
) -> Result<Value<'a, Function>> {
|
||||
pub fn create_function(&self, name: &str, callback: Callback) -> Result<Value<Function>> {
|
||||
let mut raw_result = ptr::null_mut();
|
||||
let status = unsafe {
|
||||
sys::napi_create_function(
|
||||
|
@ -414,7 +412,7 @@ impl Env {
|
|||
check_status(status)?;
|
||||
};
|
||||
|
||||
Value::from_raw(self, raw_value)
|
||||
Value::from_raw(self.0, raw_value)
|
||||
}
|
||||
|
||||
pub fn define_class<'a, 'b>(
|
||||
|
@ -422,7 +420,7 @@ impl Env {
|
|||
name: &'b str,
|
||||
constructor_cb: Callback,
|
||||
properties: Vec<Property>,
|
||||
) -> Result<Value<'a, Function>> {
|
||||
) -> Result<Value<Function>> {
|
||||
let mut raw_result = ptr::null_mut();
|
||||
let raw_properties = properties
|
||||
.into_iter()
|
||||
|
@ -473,10 +471,14 @@ impl Env {
|
|||
let tagged_object: *mut TaggedObject<T> = mem::transmute(unknown_tagged_object);
|
||||
(*tagged_object).object.as_mut().ok_or(Error {
|
||||
status: Status::InvalidArg,
|
||||
reason: Some("Invalid argument, nothing attach to js_object".to_owned()),
|
||||
})
|
||||
} else {
|
||||
Err(Error {
|
||||
status: Status::InvalidArg,
|
||||
reason: Some(
|
||||
"Invalid argument, T on unrwap is not the type of wrapped object".to_owned(),
|
||||
),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -496,35 +498,40 @@ impl Env {
|
|||
} else {
|
||||
Err(Error {
|
||||
status: Status::InvalidArg,
|
||||
reason: Some(
|
||||
"Invalid argument, T on drop_wrapped is not the type of wrapped object".to_owned(),
|
||||
),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn async_init(&self, resource: Option<Value<Object>>, name: &str) -> Result<AsyncContext> {
|
||||
let raw_resource = resource
|
||||
.map(|r| Ok(r.into_raw()))
|
||||
.unwrap_or_else(|| self.create_object().map(|o| o.into_raw()))?;
|
||||
let raw_name = self.create_string(name)?.into_raw();
|
||||
|
||||
let mut raw_context = ptr::null_mut();
|
||||
let mut raw_resource_ref = ptr::null_mut();
|
||||
unsafe {
|
||||
let status = sys::napi_async_init(self.0, raw_resource, raw_name, &mut raw_context);
|
||||
check_status(status)?;
|
||||
|
||||
let status = sys::napi_create_reference(self.0, raw_resource, 1, &mut raw_resource_ref);
|
||||
check_status(status)?;
|
||||
}
|
||||
|
||||
Ok(AsyncContext {
|
||||
raw_env: self.0,
|
||||
raw_resource: raw_resource_ref,
|
||||
raw_context,
|
||||
})
|
||||
pub fn create_error(&self, e: Error) -> Result<Value<Object>> {
|
||||
let reason = e.reason.unwrap_or("".to_owned());
|
||||
let reason_string = self.create_string(reason.as_str())?;
|
||||
let mut result = ptr::null_mut();
|
||||
let status = unsafe {
|
||||
sys::napi_create_error(
|
||||
self.0,
|
||||
ptr::null_mut(),
|
||||
reason_string.into_raw(),
|
||||
&mut result,
|
||||
)
|
||||
};
|
||||
check_status(status)?;
|
||||
Ok(Value::from_raw_value(self, result, Object))
|
||||
}
|
||||
|
||||
pub fn create_promise(&self) -> Result<(Value<Object>, Deferred)> {
|
||||
pub fn perform_async_operation<
|
||||
T: 'static,
|
||||
V: 'static + ValueType,
|
||||
F: 'static + Future<Output = Result<T>>,
|
||||
R: 'static + FnOnce(&mut Env, T) -> Result<Value<V>>,
|
||||
>(
|
||||
&self,
|
||||
deferred: F,
|
||||
resolver: R,
|
||||
) -> Result<Value<Object>> {
|
||||
let mut raw_promise = ptr::null_mut();
|
||||
let mut raw_deferred = ptr::null_mut();
|
||||
|
||||
|
@ -533,28 +540,41 @@ impl Env {
|
|||
check_status(status)?;
|
||||
}
|
||||
|
||||
Ok((
|
||||
Value::from_raw_value(self, raw_promise, Object),
|
||||
Deferred(raw_deferred),
|
||||
))
|
||||
}
|
||||
|
||||
pub fn resolve_deferred<T: ValueType>(&self, deferred: Deferred, value: Value<T>) -> Result<()> {
|
||||
unsafe {
|
||||
let status = sys::napi_resolve_deferred(self.0, deferred.0, value.into_raw());
|
||||
check_status(status)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_executor(&self) -> executor::LibuvExecutor {
|
||||
let event_loop = unsafe { sys::uv_default_loop() };
|
||||
executor::LibuvExecutor::new(event_loop)
|
||||
let raw_env = self.0;
|
||||
executor::execute(
|
||||
event_loop,
|
||||
promise::resolve(self.0, deferred, resolver, raw_deferred).map(move |v| match v {
|
||||
Ok(value) => value,
|
||||
Err(e) => {
|
||||
let cloned_error = e.clone();
|
||||
unsafe {
|
||||
sys::napi_throw_error(
|
||||
raw_env,
|
||||
ptr::null(),
|
||||
e.reason.unwrap_or(format!("{:?}", e.status)).as_ptr() as *const _,
|
||||
);
|
||||
};
|
||||
eprintln!("{:?}", &cloned_error);
|
||||
panic!(cloned_error);
|
||||
}
|
||||
}),
|
||||
)?;
|
||||
|
||||
Ok(Value::from_raw_value(self, raw_promise, Object))
|
||||
}
|
||||
|
||||
pub fn get_node_version(&self) -> Result<NodeVersion> {
|
||||
let mut result = ptr::null();
|
||||
check_status(unsafe { sys::napi_get_node_version(self.0, &mut result) })?;
|
||||
let version = unsafe { *result };
|
||||
version.try_into()
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ValueType: Copy {
|
||||
pub trait ValueType: Copy + Debug {
|
||||
fn from_raw(env: sys::napi_env, raw: sys::napi_value) -> Result<Self>;
|
||||
fn matches_raw_type(env: sys::napi_env, raw: sys::napi_value) -> bool;
|
||||
fn matches_raw_type(env: sys::napi_env, raw: sys::napi_value) -> Result<bool>;
|
||||
}
|
||||
|
||||
impl ValueType for Any {
|
||||
|
@ -562,8 +582,8 @@ impl ValueType for Any {
|
|||
Ok(Any)
|
||||
}
|
||||
|
||||
fn matches_raw_type(_env: sys::napi_env, _raw: sys::napi_value) -> bool {
|
||||
true
|
||||
fn matches_raw_type(_env: sys::napi_env, _raw: sys::napi_value) -> Result<bool> {
|
||||
Ok(true)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -572,8 +592,8 @@ impl ValueType for Undefined {
|
|||
Ok(Undefined)
|
||||
}
|
||||
|
||||
fn matches_raw_type(env: sys::napi_env, raw: sys::napi_value) -> bool {
|
||||
get_raw_type(env, raw) == sys::napi_valuetype::napi_undefined
|
||||
fn matches_raw_type(env: sys::napi_env, raw: sys::napi_value) -> Result<bool> {
|
||||
Ok(get_raw_type(env, raw)? == sys::napi_valuetype::napi_undefined)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -582,8 +602,8 @@ impl ValueType for Null {
|
|||
Ok(Null)
|
||||
}
|
||||
|
||||
fn matches_raw_type(env: sys::napi_env, raw: sys::napi_value) -> bool {
|
||||
get_raw_type(env, raw) == sys::napi_valuetype::napi_null
|
||||
fn matches_raw_type(env: sys::napi_env, raw: sys::napi_value) -> Result<bool> {
|
||||
Ok(get_raw_type(env, raw)? == sys::napi_valuetype::napi_null)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -595,8 +615,8 @@ impl ValueType for Boolean {
|
|||
Ok(Boolean { value })
|
||||
}
|
||||
|
||||
fn matches_raw_type(env: sys::napi_env, raw: sys::napi_value) -> bool {
|
||||
get_raw_type(env, raw) == sys::napi_valuetype::napi_boolean
|
||||
fn matches_raw_type(env: sys::napi_env, raw: sys::napi_value) -> Result<bool> {
|
||||
Ok(get_raw_type(env, raw)? == sys::napi_valuetype::napi_boolean)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -608,8 +628,8 @@ impl ValueType for Number {
|
|||
Ok(Number::Double(double))
|
||||
}
|
||||
|
||||
fn matches_raw_type(env: sys::napi_env, raw: sys::napi_value) -> bool {
|
||||
get_raw_type(env, raw) == sys::napi_valuetype::napi_number
|
||||
fn matches_raw_type(env: sys::napi_env, raw: sys::napi_value) -> Result<bool> {
|
||||
Ok(get_raw_type(env, raw)? == sys::napi_valuetype::napi_number)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -618,8 +638,8 @@ impl ValueType for JsString {
|
|||
Ok(JsString {})
|
||||
}
|
||||
|
||||
fn matches_raw_type(env: sys::napi_env, raw: sys::napi_value) -> bool {
|
||||
get_raw_type(env, raw) == sys::napi_valuetype::napi_string
|
||||
fn matches_raw_type(env: sys::napi_env, raw: sys::napi_value) -> Result<bool> {
|
||||
Ok(get_raw_type(env, raw)? == sys::napi_valuetype::napi_string)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -628,8 +648,8 @@ impl ValueType for Object {
|
|||
Ok(Object {})
|
||||
}
|
||||
|
||||
fn matches_raw_type(env: sys::napi_env, raw: sys::napi_value) -> bool {
|
||||
get_raw_type(env, raw) == sys::napi_valuetype::napi_object
|
||||
fn matches_raw_type(env: sys::napi_env, raw: sys::napi_value) -> Result<bool> {
|
||||
Ok(get_raw_type(env, raw)? == sys::napi_valuetype::napi_object)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -645,13 +665,13 @@ impl ValueType for Buffer {
|
|||
})
|
||||
}
|
||||
|
||||
fn matches_raw_type(env: sys::napi_env, raw: sys::napi_value) -> bool {
|
||||
fn matches_raw_type(env: sys::napi_env, raw: sys::napi_value) -> Result<bool> {
|
||||
let mut result = false;
|
||||
unsafe {
|
||||
let status = sys::napi_is_buffer(env, raw, &mut result);
|
||||
debug_assert!(Status::from(status) == Status::Ok);
|
||||
check_status(status)?;
|
||||
}
|
||||
result
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -667,21 +687,21 @@ impl ValueType for ArrayBuffer {
|
|||
})
|
||||
}
|
||||
|
||||
fn matches_raw_type(env: sys::napi_env, raw: sys::napi_value) -> bool {
|
||||
fn matches_raw_type(env: sys::napi_env, raw: sys::napi_value) -> Result<bool> {
|
||||
let mut result = false;
|
||||
unsafe {
|
||||
let status = sys::napi_is_arraybuffer(env, raw, &mut result);
|
||||
debug_assert!(Status::from(status) == Status::Ok);
|
||||
check_status(status)?;
|
||||
}
|
||||
result
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'env> Value<'env, Buffer> {
|
||||
impl Value<Buffer> {
|
||||
#[inline]
|
||||
pub fn from_value(env: &'env Env, value: &Value<'env, Any>) -> Result<Value<'env, Buffer>> {
|
||||
pub fn from_value(env: &Env, value: &Value<Any>) -> Result<Value<Buffer>> {
|
||||
Ok(Value {
|
||||
env,
|
||||
env: env.0,
|
||||
raw_value: value.raw_value,
|
||||
value: Buffer::from_raw(env.0, value.into_raw())?,
|
||||
})
|
||||
|
@ -693,25 +713,25 @@ impl ValueType for Function {
|
|||
Ok(Function {})
|
||||
}
|
||||
|
||||
fn matches_raw_type(env: sys::napi_env, raw: sys::napi_value) -> bool {
|
||||
get_raw_type(env, raw) == sys::napi_valuetype::napi_function
|
||||
fn matches_raw_type(env: sys::napi_env, raw: sys::napi_value) -> Result<bool> {
|
||||
Ok(get_raw_type(env, raw)? == sys::napi_valuetype::napi_function)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'env, T: ValueType> Value<'env, T> {
|
||||
pub fn from_raw_value(env: &'env Env, raw_value: sys::napi_value, value: T) -> Self {
|
||||
impl<T: ValueType> Value<T> {
|
||||
pub fn from_raw_value(env: &Env, raw_value: sys::napi_value, value: T) -> Self {
|
||||
Self {
|
||||
env,
|
||||
env: env.0,
|
||||
raw_value,
|
||||
value,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_raw(env: &'env Env, raw_value: sys::napi_value) -> Result<Self> {
|
||||
pub fn from_raw(env: sys::napi_env, raw_value: sys::napi_value) -> Result<Self> {
|
||||
Ok(Self {
|
||||
env,
|
||||
raw_value,
|
||||
value: T::from_raw(env.0, raw_value)?,
|
||||
value: T::from_raw(env, raw_value)?,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -719,22 +739,22 @@ impl<'env, T: ValueType> Value<'env, T> {
|
|||
self.raw_value
|
||||
}
|
||||
|
||||
pub fn coerce_to_number(self) -> Result<Value<'env, Number>> {
|
||||
pub fn coerce_to_number(self) -> Result<Value<Number>> {
|
||||
let mut new_raw_value = ptr::null_mut();
|
||||
let status =
|
||||
unsafe { sys::napi_coerce_to_number(self.env.0, self.raw_value, &mut new_raw_value) };
|
||||
unsafe { sys::napi_coerce_to_number(self.env, self.raw_value, &mut new_raw_value) };
|
||||
check_status(status)?;
|
||||
Ok(Value {
|
||||
env: self.env,
|
||||
raw_value: self.raw_value,
|
||||
value: Number::from_raw(self.env.0, self.raw_value)?,
|
||||
value: Number::from_raw(self.env, self.raw_value)?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn coerce_to_string(self) -> Result<Value<'env, JsString>> {
|
||||
pub fn coerce_to_string(self) -> Result<Value<JsString>> {
|
||||
let mut new_raw_value = ptr::null_mut();
|
||||
let status =
|
||||
unsafe { sys::napi_coerce_to_string(self.env.0, self.raw_value, &mut new_raw_value) };
|
||||
unsafe { sys::napi_coerce_to_string(self.env, self.raw_value, &mut new_raw_value) };
|
||||
check_status(status)?;
|
||||
Ok(Value {
|
||||
env: self.env,
|
||||
|
@ -743,11 +763,11 @@ impl<'env, T: ValueType> Value<'env, T> {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn coerce_to_object(self) -> Result<Value<'env, Object>> {
|
||||
pub fn coerce_to_object(self) -> Result<Value<Object>> {
|
||||
let mut new_raw_value = ptr::null_mut();
|
||||
let status = unsafe {
|
||||
sys::napi_coerce_to_object(
|
||||
self.env.0,
|
||||
self.env,
|
||||
self.raw_value,
|
||||
(&mut new_raw_value) as *mut sys::napi_value,
|
||||
)
|
||||
|
@ -761,7 +781,7 @@ impl<'env, T: ValueType> Value<'env, T> {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn into_any(self) -> Value<'env, Any> {
|
||||
pub fn into_any(self) -> Value<Any> {
|
||||
Value {
|
||||
env: self.env,
|
||||
raw_value: self.raw_value,
|
||||
|
@ -771,27 +791,26 @@ impl<'env, T: ValueType> Value<'env, T> {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
fn get_raw_type(env: sys::napi_env, raw_value: sys::napi_value) -> sys::napi_valuetype {
|
||||
fn get_raw_type(env: sys::napi_env, raw_value: sys::napi_value) -> Result<sys::napi_valuetype> {
|
||||
unsafe {
|
||||
let value_type = ptr::null_mut();
|
||||
let status = sys::napi_typeof(env, raw_value, value_type);
|
||||
debug_assert!(Status::from(status) == Status::Ok);
|
||||
*value_type
|
||||
check_status(sys::napi_typeof(env, raw_value, value_type))?;
|
||||
Ok(*value_type)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'env> Value<'env, Boolean> {
|
||||
impl Value<Boolean> {
|
||||
pub fn get_value(&self) -> bool {
|
||||
self.value.value
|
||||
}
|
||||
}
|
||||
|
||||
impl<'env> Value<'env, JsString> {
|
||||
impl Value<JsString> {
|
||||
pub fn len(&self) -> Result<usize> {
|
||||
let mut raw_length = ptr::null_mut();
|
||||
unsafe {
|
||||
let status = sys::napi_get_named_property(
|
||||
self.env.0,
|
||||
self.env,
|
||||
self.raw_value,
|
||||
"length\0".as_ptr() as *const c_char,
|
||||
&mut raw_length,
|
||||
|
@ -803,7 +822,7 @@ impl<'env> Value<'env, JsString> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'env> Value<'env, JsString> {
|
||||
impl Value<JsString> {
|
||||
#[inline]
|
||||
pub fn get_ref(&self) -> Result<&[u8]> {
|
||||
let mut written_char_count: u64 = 0;
|
||||
|
@ -811,7 +830,7 @@ impl<'env> Value<'env, JsString> {
|
|||
let mut result = Vec::with_capacity(len);
|
||||
unsafe {
|
||||
let status = sys::napi_get_value_string_utf8(
|
||||
self.env.0,
|
||||
self.env,
|
||||
self.raw_value,
|
||||
result.as_mut_ptr(),
|
||||
len as u64,
|
||||
|
@ -829,7 +848,10 @@ impl<'env> Value<'env, JsString> {
|
|||
}
|
||||
|
||||
pub fn as_str(&self) -> Result<&str> {
|
||||
str::from_utf8(self.get_ref()?).map_err(|_| Error::new(Status::GenericFailure))
|
||||
str::from_utf8(self.get_ref()?).map_err(|e| Error {
|
||||
status: Status::GenericFailure,
|
||||
reason: Some(format!("{:?}", e)),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_ref_mut(&mut self) -> Result<&mut [u8]> {
|
||||
|
@ -838,7 +860,7 @@ impl<'env> Value<'env, JsString> {
|
|||
let mut result = Vec::with_capacity(len);
|
||||
unsafe {
|
||||
let status = sys::napi_get_value_string_utf8(
|
||||
self.env.0,
|
||||
self.env,
|
||||
self.raw_value,
|
||||
result.as_mut_ptr(),
|
||||
len as u64,
|
||||
|
@ -856,16 +878,16 @@ impl<'env> Value<'env, JsString> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'env> TryFrom<Value<'env, JsString>> for Vec<u16> {
|
||||
impl TryFrom<Value<JsString>> for Vec<u16> {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(value: Value<'env, JsString>) -> Result<Vec<u16>> {
|
||||
fn try_from(value: Value<JsString>) -> Result<Vec<u16>> {
|
||||
let mut result = Vec::with_capacity(value.len()? + 1); // Leave room for trailing null byte
|
||||
|
||||
unsafe {
|
||||
let mut written_char_count = 0;
|
||||
let status = sys::napi_get_value_string_utf16(
|
||||
value.env.0,
|
||||
value.env,
|
||||
value.raw_value,
|
||||
result.as_mut_ptr(),
|
||||
result.capacity() as u64,
|
||||
|
@ -879,63 +901,63 @@ impl<'env> TryFrom<Value<'env, JsString>> for Vec<u16> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'env> TryFrom<Value<'env, Number>> for usize {
|
||||
impl TryFrom<Value<Number>> for usize {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(value: Value<'env, Number>) -> Result<usize> {
|
||||
fn try_from(value: Value<Number>) -> Result<usize> {
|
||||
let mut result = 0;
|
||||
let status = unsafe { sys::napi_get_value_int64(value.env.0, value.raw_value, &mut result) };
|
||||
let status = unsafe { sys::napi_get_value_int64(value.env, value.raw_value, &mut result) };
|
||||
check_status(status)?;
|
||||
Ok(result as usize)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'env> TryFrom<Value<'env, Number>> for u32 {
|
||||
impl TryFrom<Value<Number>> for u32 {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(value: Value<'env, Number>) -> Result<u32> {
|
||||
fn try_from(value: Value<Number>) -> Result<u32> {
|
||||
let mut result = 0;
|
||||
let status = unsafe { sys::napi_get_value_uint32(value.env.0, value.raw_value, &mut result) };
|
||||
let status = unsafe { sys::napi_get_value_uint32(value.env, value.raw_value, &mut result) };
|
||||
check_status(status)?;
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'env> TryFrom<Value<'env, Number>> for i32 {
|
||||
impl TryFrom<Value<Number>> for i32 {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(value: Value<'env, Number>) -> Result<i32> {
|
||||
fn try_from(value: Value<Number>) -> Result<i32> {
|
||||
let mut result = 0;
|
||||
let status = unsafe { sys::napi_get_value_int32(value.env.0, value.raw_value, &mut result) };
|
||||
let status = unsafe { sys::napi_get_value_int32(value.env, value.raw_value, &mut result) };
|
||||
check_status(status)?;
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'env> TryFrom<Value<'env, Number>> for i64 {
|
||||
impl TryFrom<Value<Number>> for i64 {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(value: Value<'env, Number>) -> Result<i64> {
|
||||
fn try_from(value: Value<Number>) -> Result<i64> {
|
||||
let mut result = 0;
|
||||
let status = unsafe { sys::napi_get_value_int64(value.env.0, value.raw_value, &mut result) };
|
||||
let status = unsafe { sys::napi_get_value_int64(value.env, value.raw_value, &mut result) };
|
||||
check_status(status)?;
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'env> TryFrom<Value<'env, Number>> for f64 {
|
||||
impl TryFrom<Value<Number>> for f64 {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(value: Value<'env, Number>) -> Result<f64> {
|
||||
fn try_from(value: Value<Number>) -> Result<f64> {
|
||||
let mut result = 0_f64;
|
||||
let status = unsafe { sys::napi_get_value_double(value.env.0, value.raw_value, &mut result) };
|
||||
let status = unsafe { sys::napi_get_value_double(value.env, value.raw_value, &mut result) };
|
||||
check_status(status)?;
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'env> Value<'env, Object> {
|
||||
pub fn set_property<'a, K, V>(&mut self, key: Value<K>, value: Value<V>) -> Result<()> {
|
||||
impl Value<Object> {
|
||||
pub fn set_property<K, V>(&mut self, key: Value<K>, value: Value<V>) -> Result<()> {
|
||||
let status = unsafe {
|
||||
sys::napi_set_property(
|
||||
self.raw_env(),
|
||||
|
@ -948,11 +970,7 @@ impl<'env> Value<'env, Object> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn set_named_property<'a, T, V: Into<Value<'a, T>>>(
|
||||
&mut self,
|
||||
name: &'a str,
|
||||
value: V,
|
||||
) -> Result<()> {
|
||||
pub fn set_named_property<T, V: Into<Value<T>>>(&mut self, name: &str, value: V) -> Result<()> {
|
||||
let key = CString::new(name)?;
|
||||
let status = unsafe {
|
||||
sys::napi_set_named_property(
|
||||
|
@ -990,7 +1008,7 @@ impl<'env> Value<'env, Object> {
|
|||
}
|
||||
|
||||
pub fn set_index<'a, T>(&mut self, index: usize, value: Value<T>) -> Result<()> {
|
||||
self.set_property(self.env.create_int64(index as i64)?, value)
|
||||
self.set_property(Env::from_raw(self.env).create_int64(index as i64)?, value)
|
||||
}
|
||||
|
||||
pub fn get_index<T: ValueType>(&self, index: u32) -> Result<Value<T>> {
|
||||
|
@ -1015,7 +1033,7 @@ impl<'env> Value<'env, Object> {
|
|||
Ok(is_buffer)
|
||||
}
|
||||
|
||||
pub fn to_buffer(&self) -> Result<Value<'env, Buffer>> {
|
||||
pub fn to_buffer(&self) -> Result<Value<Buffer>> {
|
||||
Value::from_raw(self.env, self.raw_value)
|
||||
}
|
||||
|
||||
|
@ -1023,6 +1041,7 @@ impl<'env> Value<'env, Object> {
|
|||
if self.is_array()? != true {
|
||||
return Err(Error {
|
||||
status: Status::ArrayExpected,
|
||||
reason: Some("Object is not array".to_owned()),
|
||||
});
|
||||
}
|
||||
let mut length: u32 = 0;
|
||||
|
@ -1037,17 +1056,17 @@ impl<'env> Value<'env, Object> {
|
|||
}
|
||||
|
||||
fn raw_env(&self) -> sys::napi_env {
|
||||
self.env.0
|
||||
self.env
|
||||
}
|
||||
}
|
||||
|
||||
impl<'env> AsRef<[u8]> for Value<'env, Buffer> {
|
||||
impl AsRef<[u8]> for Value<Buffer> {
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
self.deref()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'env> Deref for Value<'env, Buffer> {
|
||||
impl Deref for Value<Buffer> {
|
||||
type Target = [u8];
|
||||
|
||||
fn deref(&self) -> &[u8] {
|
||||
|
@ -1055,13 +1074,13 @@ impl<'env> Deref for Value<'env, Buffer> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'env> DerefMut for Value<'env, Buffer> {
|
||||
impl DerefMut for Value<Buffer> {
|
||||
fn deref_mut(&mut self) -> &mut [u8] {
|
||||
unsafe { slice::from_raw_parts_mut(self.value.data as *mut _, self.value.size as usize) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'env> Deref for Value<'env, ArrayBuffer> {
|
||||
impl Deref for Value<ArrayBuffer> {
|
||||
type Target = [u8];
|
||||
|
||||
fn deref(&self) -> &[u8] {
|
||||
|
@ -1069,22 +1088,26 @@ impl<'env> Deref for Value<'env, ArrayBuffer> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'env> DerefMut for Value<'env, ArrayBuffer> {
|
||||
impl DerefMut for Value<ArrayBuffer> {
|
||||
fn deref_mut(&mut self) -> &mut [u8] {
|
||||
unsafe { slice::from_raw_parts_mut(self.value.data as *mut _, self.value.size as usize) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'env> Value<'env, Function> {
|
||||
pub fn call(
|
||||
&self,
|
||||
this: Option<&Value<'env, Object>>,
|
||||
args: &[Value<'env, Any>],
|
||||
) -> Result<Value<'env, Any>> {
|
||||
impl Value<Function> {
|
||||
pub fn call(&self, this: Option<&Value<Object>>, args: &[Value<Any>]) -> Result<Value<Any>> {
|
||||
let raw_this = this
|
||||
.map(|v| v.into_raw())
|
||||
.or_else(|| self.env.get_undefined().ok().map(|u| u.into_raw()))
|
||||
.ok_or(Error::new(Status::Unknown))?;
|
||||
.or_else(|| {
|
||||
Env::from_raw(self.env)
|
||||
.get_undefined()
|
||||
.ok()
|
||||
.map(|u| u.into_raw())
|
||||
})
|
||||
.ok_or(Error {
|
||||
status: Status::Unknown,
|
||||
reason: Some("Get raw this failed".to_owned()),
|
||||
})?;
|
||||
let mut raw_args = unsafe { mem::MaybeUninit::<[sys::napi_value; 8]>::uninit().assume_init() };
|
||||
for (i, arg) in args.into_iter().enumerate() {
|
||||
raw_args[i] = arg.raw_value;
|
||||
|
@ -1092,7 +1115,7 @@ impl<'env> Value<'env, Function> {
|
|||
let mut return_value = ptr::null_mut();
|
||||
let status = unsafe {
|
||||
sys::napi_call_function(
|
||||
self.env.0,
|
||||
self.env,
|
||||
raw_this,
|
||||
self.raw_value,
|
||||
args.len() as u64,
|
||||
|
@ -1106,9 +1129,9 @@ impl<'env> Value<'env, Function> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'env> Value<'env, Any> {
|
||||
pub fn get_type(&self) -> sys::napi_valuetype {
|
||||
get_raw_type(self.env.0, self.raw_value)
|
||||
impl Value<Any> {
|
||||
pub fn get_type(&self) -> Result<sys::napi_valuetype> {
|
||||
get_raw_type(self.env, self.raw_value)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1127,34 +1150,6 @@ impl<T> Drop for Ref<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl AsyncContext {
|
||||
pub fn enter<'a, F: 'a + FnOnce(&mut Env)>(&'a self, run_in_context: F) {
|
||||
let mut env = Env::from_raw(self.raw_env);
|
||||
let mut handle_scope = ptr::null_mut();
|
||||
let mut callback_scope = ptr::null_mut();
|
||||
let mut raw_resource = ptr::null_mut();
|
||||
|
||||
unsafe {
|
||||
sys::napi_open_handle_scope(env.0, &mut handle_scope);
|
||||
sys::napi_get_reference_value(env.0, self.raw_resource, &mut raw_resource);
|
||||
sys::extras_open_callback_scope(self.raw_context, raw_resource, &mut callback_scope);
|
||||
}
|
||||
run_in_context(&mut env);
|
||||
unsafe {
|
||||
sys::extras_close_callback_scope(callback_scope);
|
||||
sys::napi_close_handle_scope(env.0, handle_scope);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for AsyncContext {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
sys::napi_delete_reference(self.raw_env, self.raw_resource);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Property {
|
||||
pub fn new(name: &str) -> Self {
|
||||
Property {
|
||||
|
@ -1202,11 +1197,12 @@ impl<T: 'static> TaggedObject<T> {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn check_status(code: sys::napi_status) -> Result<()> {
|
||||
let status = Status::from(code);
|
||||
match status {
|
||||
Status::Ok => Ok(()),
|
||||
_ => Err(Error { status }),
|
||||
_ => Err(Error::from_status(status)),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
65
napi/src/promise.rs
Normal file
65
napi/src/promise.rs
Normal file
|
@ -0,0 +1,65 @@
|
|||
use futures::prelude::*;
|
||||
use std::os::raw::c_char;
|
||||
use std::ptr;
|
||||
|
||||
use crate::{check_status, sys, Env, Result, Value, ValueType};
|
||||
|
||||
#[inline]
|
||||
pub async fn resolve<
|
||||
T,
|
||||
V: ValueType,
|
||||
R: FnOnce(&mut Env, T) -> Result<Value<V>>,
|
||||
F: Future<Output = Result<T>>,
|
||||
>(
|
||||
env: sys::napi_env,
|
||||
fut: F,
|
||||
resolver: R,
|
||||
raw_deferred: sys::napi_deferred,
|
||||
) -> Result<()> {
|
||||
let mut raw_resource = ptr::null_mut();
|
||||
let status = unsafe { sys::napi_create_object(env, &mut raw_resource) };
|
||||
check_status(status)?;
|
||||
let mut raw_name = ptr::null_mut();
|
||||
let s = "napi_async_context";
|
||||
let status = unsafe {
|
||||
sys::napi_create_string_utf8(
|
||||
env,
|
||||
s.as_ptr() as *const c_char,
|
||||
s.len() as u64,
|
||||
&mut raw_name,
|
||||
)
|
||||
};
|
||||
check_status(status)?;
|
||||
let mut raw_context = ptr::null_mut();
|
||||
unsafe {
|
||||
let status = sys::napi_async_init(env, raw_resource, raw_name, &mut raw_context);
|
||||
check_status(status)?;
|
||||
}
|
||||
let mut handle_scope = ptr::null_mut();
|
||||
match fut.await {
|
||||
Ok(v) => unsafe {
|
||||
check_status(sys::napi_open_handle_scope(env, &mut handle_scope))?;
|
||||
let mut tmp_env = Env::from_raw(env);
|
||||
let js_value = resolver(&mut tmp_env, v)?;
|
||||
check_status(sys::napi_resolve_deferred(
|
||||
env,
|
||||
raw_deferred,
|
||||
js_value.raw_value,
|
||||
))?;
|
||||
check_status(sys::napi_close_handle_scope(env, handle_scope))?;
|
||||
},
|
||||
Err(e) => unsafe {
|
||||
check_status(sys::napi_open_handle_scope(env, &mut handle_scope))?;
|
||||
check_status(sys::napi_reject_deferred(
|
||||
env,
|
||||
raw_deferred,
|
||||
Env::from_raw(env)
|
||||
.create_error(e)
|
||||
.map(|e| e.into_raw())
|
||||
.unwrap_or(ptr::null_mut()),
|
||||
))?;
|
||||
check_status(sys::napi_close_handle_scope(env, handle_scope))?;
|
||||
},
|
||||
};
|
||||
Ok(())
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
#include "bindings.h"
|
||||
#include <stdio.h>
|
||||
#include <node.h>
|
||||
#include <v8.h>
|
||||
|
||||
static v8::Local<v8::Value> V8LocalValueFromJsValue(napi_value v)
|
||||
{
|
||||
v8::Local<v8::Value> local;
|
||||
memcpy(&local, &v, sizeof(v));
|
||||
return local;
|
||||
}
|
||||
|
||||
EXTERN_C_START
|
||||
|
||||
NAPI_EXTERN void extras_open_callback_scope(napi_async_context napi_async_context,
|
||||
napi_value napi_resource_object,
|
||||
extras_callback_scope *result)
|
||||
{
|
||||
v8::Isolate *isolate = v8::Isolate::GetCurrent();
|
||||
v8::Local<v8::Context> context = isolate->GetCurrentContext();
|
||||
v8::Local<v8::Object> resource_object = V8LocalValueFromJsValue(napi_resource_object)->ToObject(context).ToLocalChecked();
|
||||
node::async_context *node_async_context = reinterpret_cast<node::async_context *>(napi_async_context);
|
||||
*result = reinterpret_cast<extras_callback_scope>(new node::CallbackScope(isolate, resource_object, *node_async_context));
|
||||
}
|
||||
|
||||
NAPI_EXTERN void extras_close_callback_scope(extras_callback_scope callback_scope)
|
||||
{
|
||||
delete reinterpret_cast<node::CallbackScope *>(callback_scope);
|
||||
}
|
||||
|
||||
EXTERN_C_END
|
|
@ -1,15 +1,2 @@
|
|||
#include <node_api.h>
|
||||
#include <uv.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef struct extras_callback_scope__ *extras_callback_scope;
|
||||
|
||||
EXTERN_C_START
|
||||
|
||||
NAPI_EXTERN void extras_open_callback_scope(napi_async_context napi_async_context,
|
||||
napi_value napi_resource_object,
|
||||
extras_callback_scope *result);
|
||||
|
||||
NAPI_EXTERN void extras_close_callback_scope(extras_callback_scope callback_scope);
|
||||
|
||||
EXTERN_C_END
|
||||
#include <uv.h>
|
|
@ -1,6 +1,6 @@
|
|||
use super::napi_status;
|
||||
|
||||
#[derive(Eq, PartialEq, Debug)]
|
||||
#[derive(Eq, PartialEq, Debug, Clone, Copy)]
|
||||
pub enum Status {
|
||||
Ok,
|
||||
InvalidArg,
|
||||
|
|
29
napi/src/version.rs
Normal file
29
napi/src/version.rs
Normal file
|
@ -0,0 +1,29 @@
|
|||
use crate::{sys, Error, Status};
|
||||
use std::convert::TryFrom;
|
||||
use std::ffi::CStr;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct NodeVersion {
|
||||
pub major: u32,
|
||||
pub minor: u32,
|
||||
pub patch: u32,
|
||||
pub release: &'static str,
|
||||
}
|
||||
|
||||
impl TryFrom<sys::napi_node_version> for NodeVersion {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(value: sys::napi_node_version) -> Result<NodeVersion, Error> {
|
||||
Ok(NodeVersion {
|
||||
major: value.major,
|
||||
minor: value.minor,
|
||||
patch: value.patch,
|
||||
release: unsafe {
|
||||
CStr::from_ptr(value.release).to_str().map_err(|_| Error {
|
||||
status: Status::StringExpected,
|
||||
reason: Some("Invalid release name".to_owned()),
|
||||
})?
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
26
package.json
26
package.json
|
@ -17,6 +17,13 @@
|
|||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"format": "run-p format:md format:json format:yaml format:source",
|
||||
"format:md": "prettier --parser markdown --write './**/*.md'",
|
||||
"format:json": "prettier --parser json --write './**/*.json'",
|
||||
"format:source": "prettier --config ./package.json --write './**/*.js'",
|
||||
"format:yaml": "prettier --parser yaml --write './**/*.{yml,yaml}'"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/Brooooooklyn/napi-rs/issues"
|
||||
},
|
||||
|
@ -32,12 +39,23 @@
|
|||
"trailingComma": "all",
|
||||
"arrowParens": "always"
|
||||
},
|
||||
"files": [
|
||||
"scripts/napi.js",
|
||||
"LICENSE"
|
||||
],
|
||||
"files": ["scripts/napi.js", "LICENSE"],
|
||||
"lint-staged": {
|
||||
"*.js": ["prettier --write"],
|
||||
"*.@(yml|yaml)": ["prettier --parser yaml --write"],
|
||||
"*.json": ["prettier --parser json --write"],
|
||||
"*.md": ["prettier --parser markdown --write"]
|
||||
},
|
||||
"husky": {
|
||||
"hooks": {
|
||||
"pre-commit": "lint-staged && cargo fmt --all"
|
||||
}
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^13.13.5",
|
||||
"husky": "^4.2.5",
|
||||
"lint-staged": "^10.2.2",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"prettier": "^2.0.5"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,10 @@ let tomlContent
|
|||
let moduleName
|
||||
|
||||
try {
|
||||
tomlContentString = fs.readFileSync(path.join(process.cwd(), 'Cargo.toml'), 'utf-8')
|
||||
tomlContentString = fs.readFileSync(
|
||||
path.join(process.cwd(), 'Cargo.toml'),
|
||||
'utf-8',
|
||||
)
|
||||
} catch {
|
||||
throw new TypeError('Can not find Cargo.toml in process.cwd')
|
||||
}
|
||||
|
@ -60,7 +63,9 @@ const targetDir = argv.release ? 'release' : 'debug'
|
|||
|
||||
const platformName = argv.platform ? `.${platform}` : ''
|
||||
|
||||
let subcommand = argv._[0] || path.join('target', targetDir, `${moduleName}${platformName}.node`)
|
||||
let subcommand =
|
||||
argv._[0] ||
|
||||
path.join('target', targetDir, `${moduleName}${platformName}.node`)
|
||||
const parsedDist = path.parse(subcommand)
|
||||
|
||||
if (!parsedDist.name || parsedDist.name === '.') {
|
||||
|
@ -73,11 +78,13 @@ if (!parsedDist.ext) {
|
|||
|
||||
const pos = __dirname.indexOf('node_modules')
|
||||
|
||||
const dylibContent = fs.readFileSync(path.join(
|
||||
__dirname.substring(0, pos),
|
||||
'target',
|
||||
targetDir,
|
||||
`${dylibName}${libExt}`,
|
||||
))
|
||||
const dylibContent = fs.readFileSync(
|
||||
path.join(
|
||||
__dirname.substring(0, pos),
|
||||
'target',
|
||||
targetDir,
|
||||
`${dylibName}${libExt}`,
|
||||
),
|
||||
)
|
||||
|
||||
fs.writeFileSync(subcommand, dylibContent)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
const testModule = require(`./target/debug/test_module.node`)
|
||||
const testModule = require('./index.node')
|
||||
|
||||
function testSpawn() {
|
||||
console.log('=== Test spawning a future on libuv event loop')
|
||||
|
@ -9,19 +9,21 @@ function testThrow() {
|
|||
console.log('=== Test throwing from Rust')
|
||||
try {
|
||||
testModule.testThrow()
|
||||
console.error('Expected function to throw an error')
|
||||
process.exit(1)
|
||||
} catch (e) {
|
||||
return
|
||||
console.error(e)
|
||||
}
|
||||
console.error('Expected function to throw an error')
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
const future = testSpawn()
|
||||
|
||||
// https://github.com/nodejs/node/issues/29355
|
||||
setTimeout(() => {
|
||||
future.then(testThrow).catch((e) => {
|
||||
future
|
||||
.then((value) => {
|
||||
console.info(`${value} from napi`)
|
||||
testThrow()
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error(e)
|
||||
process.exit(1)
|
||||
})
|
||||
}, 1000)
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
"name": "test-module",
|
||||
"version": "1.0.0",
|
||||
"scripts": {
|
||||
"build": "cargo build && node ../scripts/napi.js",
|
||||
"build-release": "cargo build --release && node ../scripts/napi.js --release",
|
||||
"build": "cargo build && node ../scripts/napi.js ./index",
|
||||
"build-release": "cargo build --release && node ../scripts/napi.js --release ./index",
|
||||
"test": "node ./index.js"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,49 +9,36 @@ use napi::{Any, CallContext, Env, Error, Object, Result, Status, Value};
|
|||
|
||||
register_module!(test_module, init);
|
||||
|
||||
fn init<'env>(
|
||||
env: &'env Env,
|
||||
exports: &'env mut Value<'env, Object>,
|
||||
) -> Result<Option<Value<'env, Object>>> {
|
||||
fn init(env: &Env, exports: &mut Value<Object>) -> Result<Option<Value<Object>>> {
|
||||
exports.set_named_property("testSpawn", env.create_function("testSpawn", test_spawn)?)?;
|
||||
exports.set_named_property("testThrow", env.create_function("testThrow", test_throw)?)?;
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
#[js_function]
|
||||
fn test_spawn<'a>(ctx: CallContext<'a>) -> Result<Value<'a, Object>> {
|
||||
fn test_spawn(ctx: CallContext) -> Result<Value<Object>> {
|
||||
use futures::executor::ThreadPool;
|
||||
use futures::StreamExt;
|
||||
let env = ctx.env;
|
||||
let async_context = env.async_init(None, "test_spawn")?;
|
||||
let pool = ThreadPool::new().expect("Failed to build pool");
|
||||
let (promise, deferred) = env.create_promise()?;
|
||||
let (tx, rx) = futures::channel::mpsc::unbounded::<i32>();
|
||||
let fut_values = async move {
|
||||
let fut_tx_result = async move {
|
||||
(0..20).for_each(|v| {
|
||||
(0..200).for_each(|v| {
|
||||
tx.unbounded_send(v).expect("Failed to send");
|
||||
})
|
||||
};
|
||||
pool.spawn_ok(fut_tx_result);
|
||||
let fut_values = rx.map(|v| v * 2).collect::<Vec<i32>>();
|
||||
let results = fut_values.await;
|
||||
if !cfg!(windows) {
|
||||
println!("Collected result lenght {}", results.len());
|
||||
};
|
||||
async_context.enter(|env| {
|
||||
env
|
||||
.resolve_deferred(deferred, env.get_undefined().unwrap())
|
||||
.unwrap();
|
||||
});
|
||||
let fut = rx.map(|v| v * 2).collect::<Vec<i32>>();
|
||||
let results = fut.await;
|
||||
println!("Collected result lenght {}", results.len());
|
||||
Ok(results.len() as u32)
|
||||
};
|
||||
|
||||
env.create_executor().execute(fut_values);
|
||||
|
||||
Ok(promise)
|
||||
env.perform_async_operation(fut_values, |&mut env, len| env.create_uint32(len))
|
||||
}
|
||||
|
||||
#[js_function]
|
||||
fn test_throw<'a>(_ctx: CallContext<'a>) -> Result<Value<'a, Any>> {
|
||||
Err(Error::new(Status::GenericFailure))
|
||||
fn test_throw(_ctx: CallContext) -> Result<Value<Any>> {
|
||||
Err(Error::from_status(Status::GenericFailure))
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue