refactor(napi-sys): remove bindgen

This commit is contained in:
LongYinan 2020-11-10 11:09:25 +08:00
parent f376f3615c
commit fc0ec0b378
No known key found for this signature in database
GPG key ID: A3FFE134A3E20881
39 changed files with 1428 additions and 597 deletions

View file

@ -7,7 +7,7 @@ task:
DEBUG: 'napi:*' DEBUG: 'napi:*'
setup_script: setup_script:
- pkg update - pkg update
- pkg install -y -f curl node yarn npm libnghttp2 llvm - pkg install -y -f curl node yarn npm libnghttp2
- curl https://sh.rustup.rs -sSf --output rustup.sh - curl https://sh.rustup.rs -sSf --output rustup.sh
- sh rustup.sh -y --profile minimal --default-toolchain stable - sh rustup.sh -y --profile minimal --default-toolchain stable
- . $HOME/.cargo/env - . $HOME/.cargo/env

View file

@ -18,9 +18,10 @@ jobs:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Setup node - name: Setup node
uses: actions/setup-node@v1 uses: actions/setup-node@v2-beta
with: with:
node-version: 14 node-version: 14
check-latest: true
- name: Install - name: Install
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1

View file

@ -14,9 +14,10 @@ jobs:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Setup node - name: Setup node
uses: actions/setup-node@v1 uses: actions/setup-node@v2-beta
with: with:
node-version: 12 node-version: 14
check-latest: true
- name: Install - name: Install
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1

View file

@ -21,9 +21,10 @@ jobs:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Setup node - name: Setup node
uses: actions/setup-node@v1 uses: actions/setup-node@v2-beta
with: with:
node-version: 14 node-version: 14
check-latest: true
- name: Install - name: Install
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1

View file

@ -42,10 +42,6 @@ jobs:
run: | run: |
docker run --rm -v $(pwd)/.cargo:/root/.cargo -v $(pwd):/napi-rs -w /napi-rs builder cargo check -vvv docker run --rm -v $(pwd)/.cargo:/root/.cargo -v $(pwd):/napi-rs -w /napi-rs builder cargo check -vvv
- name: Run tests
run: |
docker run --rm -v $(pwd)/.cargo:/root/.cargo -v $(pwd):/napi-rs -w /napi-rs builder cargo test -p napi-sys --lib -- --nocapture
- name: Unit test - name: Unit test
run: | run: |
docker run --rm -v $(pwd)/.cargo:/root/.cargo -v $(pwd):/napi-rs -w /napi-rs builder sh -c "yarn build:test && yarn test" docker run --rm -v $(pwd)/.cargo:/root/.cargo -v $(pwd):/napi-rs -w /napi-rs builder sh -c "yarn build:test && yarn test"

View file

@ -69,16 +69,9 @@ jobs:
command: check command: check
args: --all --bins --examples --tests -vvv args: --all --bins --examples --tests -vvv
- name: Tests
uses: actions-rs/cargo@v1
timeout-minutes: 5
with:
command: test
args: -p napi-sys --lib -- --nocapture
- name: Unit tests - name: Unit tests
run: | run: |
yarn --cwd ./test_module --ignore-engines build yarn --cwd ./test_module --ignore-engines build-napi3
yarn --ignore-engines test yarn --ignore-engines test
env: env:
RUST_BACKTRACE: 1 RUST_BACKTRACE: 1

View file

@ -13,7 +13,7 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
node: ['10', '12', '14'] node: ['10', '12', '14', '15']
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 }}
@ -23,19 +23,10 @@ jobs:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Setup node - name: Setup node
uses: actions/setup-node@v1 uses: actions/setup-node@v2-beta
with: with:
node-version: ${{ matrix.node }} node-version: ${{ matrix.node }}
check-latest: true
- name: Install llvm
if: matrix.os == 'windows-latest'
run: choco install -y llvm
- name: Set llvm path
if: matrix.os == 'windows-latest'
uses: allenevans/set-env@v1.1.0
with:
LIBCLANG_PATH: 'C:\Program Files\LLVM\bin'
- name: Install - name: Install
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
@ -81,13 +72,6 @@ jobs:
command: check command: check
args: --all --bins --examples --tests -vvv args: --all --bins --examples --tests -vvv
- name: Tests
uses: actions-rs/cargo@v1
timeout-minutes: 5
with:
command: test
args: -p napi-sys --lib -- --nocapture
- name: Unit tests - name: Unit tests
run: | run: |
yarn build:test yarn build:test

View file

@ -17,17 +17,27 @@ jobs:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Setup node - name: Setup node
uses: actions/setup-node@v1 run: choco install nodejs-lts --x86 -y --force
with:
node-version: 14
- name: Install llvm - name: Set 32bit NodeJS path
run: choco install -y llvm run: |
echo "C:\\Program Files (x86)\\nodejs" >> $GITHUB_PATH
- name: Set llvm path
run: echo "LIBCLANG_PATH=C:\\Program Files\\LLVM\\bin" >> $GITHUB_ENV
shell: bash shell: bash
- name: Cache NPM dependencies
uses: actions/cache@v1
with:
path: node_modules
key: npm-cache-windows-i686-node@lts-${{ hashFiles('yarn.lock') }}
restore-keys: |
npm-cache-
- name: 'Install dependencies'
run: yarn install --frozen-lockfile --registry https://registry.npmjs.org
- name: 'Build TypeScript'
run: yarn build
- name: Install - name: Install
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
@ -47,13 +57,13 @@ jobs:
uses: actions/cache@v1 uses: actions/cache@v1
with: with:
path: ~/.cargo/registry path: ~/.cargo/registry
key: stable-${{ matrix.os }}-node@${{ matrix.node }}-cargo-registry-trimmed-${{ hashFiles('**/Cargo.lock') }} key: stable-windows-i686-node@lts-cargo-registry-trimmed-${{ hashFiles('**/Cargo.lock') }}
- name: Cache cargo index - name: Cache cargo index
uses: actions/cache@v1 uses: actions/cache@v1
with: with:
path: ~/.cargo/git path: ~/.cargo/git
key: stable-${{ matrix.os }}gnu-node@${{ matrix.node }}-cargo-index-trimmed-${{ hashFiles('**/Cargo.lock') }} key: stable-windows-i686-node@lts-cargo-index-trimmed-${{ hashFiles('**/Cargo.lock') }}
- name: Check build - name: Check build
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
@ -61,12 +71,12 @@ jobs:
command: check command: check
args: --all --bins --examples --tests --target i686-pc-windows-msvc -vvv args: --all --bins --examples --tests --target i686-pc-windows-msvc -vvv
- name: Tests - name: Build Tests
uses: actions-rs/cargo@v1 run: |
timeout-minutes: 5 yarn --cwd ./test_module build-i686
with: yarn test
command: test env:
args: -p napi-sys --lib --target i686-pc-windows-msvc -- --nocapture RUST_BACKTRACE: 1
- name: Clear the cargo caches - name: Clear the cargo caches
run: | run: |

View file

@ -28,9 +28,9 @@ A minimal library for building compiled `NodeJS` add-ons in `Rust`.
## NodeJS ## NodeJS
| Node10 | Node 12 | Node14 | | Node10 | Node 12 | Node14 | Node15 |
| ------ | ------- | ------ | | ------ | ------- | ------ | ------ |
| ✓ | ✓ | ✓ | | ✓ | ✓ | ✓ | ✓ |
This library depends on N-API and requires `Node@8.9` or later. This library depends on N-API and requires `Node@8.9` or later.

View file

@ -8,14 +8,8 @@ version = "0.1.0"
crate-type = ["cdylib"] crate-type = ["cdylib"]
[dependencies] [dependencies]
futures = "0.3" napi = {path = "../napi"}
napi = {path = "../napi", features = ["libuv", "tokio_rt", "serde-json", "latin1"]}
napi-derive = {path = "../napi-derive"} napi-derive = {path = "../napi-derive"}
serde = "1"
serde_bytes = "0.11"
serde_derive = "1"
serde_json = "1"
tokio = {version = "0.2", features = ["default", "fs"]}
[build-dependencies] [build-dependencies]
napi-build = {path = "../build"} napi-build = {path = "../build"}

View file

@ -1,40 +1,11 @@
cfg_if::cfg_if! { cfg_if::cfg_if! {
if #[cfg(windows)] { if #[cfg(windows)] {
mod windows; mod windows;
pub use windows::setup; pub use windows::setup;
} else if #[cfg(target_os = "macos")] { } else if #[cfg(target_os = "macos")] {
mod macos; mod macos;
pub use macos::setup; pub use macos::setup;
} else {
pub fn setup() {
setup_napi_feature();
}
}
}
use std::process::Command;
pub fn setup_napi_feature() {
let napi_version = String::from_utf8(
Command::new("node")
.args(&["-e", "console.log(process.versions.napi)"])
.output()
.unwrap()
.stdout,
)
.expect("Get NAPI version failed");
let napi_version_number = napi_version.trim().parse::<u32>().unwrap();
if napi_version_number < 2 {
panic!("current napi version is too low");
}
if napi_version_number == 2 {
println!("cargo:rustc-cfg=napi{}", napi_version_number);
} else { } else {
for version in 2..(napi_version_number + 1) { pub fn setup() { }
println!("cargo:rustc-cfg=napi{}", version);
}
} }
} }

View file

@ -1,8 +1,5 @@
use crate::*;
pub fn setup() { pub fn setup() {
println!("cargo:rustc-cdylib-link-arg=-Wl"); println!("cargo:rustc-cdylib-link-arg=-Wl");
println!("cargo:rustc-cdylib-link-arg=-undefined"); println!("cargo:rustc-cdylib-link-arg=-undefined");
println!("cargo:rustc-cdylib-link-arg=dynamic_lookup"); println!("cargo:rustc-cdylib-link-arg=dynamic_lookup");
setup_napi_feature();
} }

View file

@ -1,9 +1,9 @@
use crate::*;
use std::collections::hash_map::DefaultHasher; use std::collections::hash_map::DefaultHasher;
use std::fs::{metadata, write}; use std::fs::{metadata, write};
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use std::io::Read; use std::io::Read;
use std::path::PathBuf; use std::path::PathBuf;
use std::process::Command;
fn get_node_version() -> std::io::Result<String> { fn get_node_version() -> std::io::Result<String> {
let output = Command::new("node").arg("-v").output()?; let output = Command::new("node").arg("-v").output()?;
@ -51,16 +51,17 @@ pub fn setup() {
// See https://doc.rust-lang.org/reference/conditional-compilation.html#target_arch for rust env values. // See https://doc.rust-lang.org/reference/conditional-compilation.html#target_arch for rust env values.
// Nodejs appears to follow `process.arch`. // Nodejs appears to follow `process.arch`.
// See https://nodejs.org/docs/latest/api/process.html#process_process_arch for npm env values. // See https://nodejs.org/docs/latest/api/process.html#process_process_arch for npm env values.
// For windows, we only support `['ia32', 'x64', 'arm64']`
// https://github.com/nodejs/node-gyp/blob/master/lib/install.js#L301
let arch = std::env::var("CARGO_CFG_TARGET_ARCH") let arch = std::env::var("CARGO_CFG_TARGET_ARCH")
.map(|arch| match arch.as_str() { .map(|arch| match arch.as_str() {
"x86" => "x86", // TODO: x86 appears to also be called ia32 in npm_config_arch sometimes. What is the right value? "x86" => "x86",
"x86_64" => "x64", "x86_64" => "x64",
"mips" => "mips", // https://github.com/nodejs/node/issues/25998
"powerpc" => "ppc", // actually not supported for now
"powerpc64" => "ppc64", // because we can not get `node.lib` file for `aarch64` device
"arm" => "arm",
"aarch64" => "arm64", "aarch64" => "arm64",
arch => panic!("Unknown Architecture: {}", arch), arch => panic!("Unsupported CPU Architecture: {}", arch),
}) })
.expect("Failed to determine target arch"); .expect("Failed to determine target arch");
@ -106,6 +107,4 @@ pub fn setup() {
); );
println!("cargo:rustc-cdylib-link-arg=delayimp.lib"); println!("cargo:rustc-cdylib-link-arg=delayimp.lib");
println!("cargo:rustc-cdylib-link-arg=/DELAYLOAD:node.exe"); println!("cargo:rustc-cdylib-link-arg=/DELAYLOAD:node.exe");
setup_napi_feature();
} }

View file

@ -10,8 +10,15 @@ repository = "https://github.com/napi-rs/napi-rs"
version = "0.5.1" version = "0.5.1"
[features] [features]
default = ["napi3"] # for most NodeJS users
latin1 = ["encoding_rs"] latin1 = ["encoding_rs"]
libuv = ["futures"] napi1 = []
napi2 = ["napi1"]
napi3 = ["napi2", "napi-sys/napi3"]
napi4 = ["napi3", "napi-sys/napi4"]
napi5 = ["napi4", "napi-sys/napi5"]
napi6 = ["napi5", "napi-sys/napi6"]
napi7 = ["napi6", "napi-sys/napi7"]
serde-json = ["serde", "serde_json"] serde-json = ["serde", "serde_json"]
tokio_rt = ["futures", "tokio", "once_cell"] tokio_rt = ["futures", "tokio", "once_cell"]
@ -51,4 +58,3 @@ napi-build = {version = "0.2", path = "../build"}
[package.metadata.docs.rs] [package.metadata.docs.rs]
all-features = true all-features = true
rustc-args = ["--cfg", "napidocsrs"]

View file

@ -1,3 +0,0 @@
fn main() {
napi_build::setup_napi_feature();
}

View file

@ -5,30 +5,29 @@ use std::mem;
use std::os::raw::{c_char, c_void}; use std::os::raw::{c_char, c_void};
use std::ptr; use std::ptr;
use super::cleanup_env::{CleanupEnvHook, CleanupEnvHookData};
use crate::async_work::{self, AsyncWorkPromise}; use crate::async_work::{self, AsyncWorkPromise};
use crate::error::check_status; use crate::error::check_status;
use crate::js_values::*; use crate::js_values::*;
use crate::task::Task; use crate::task::Task;
use crate::{sys, Error, NodeVersion, Result, Status}; use crate::{sys, Error, NodeVersion, Result, Status};
#[cfg(feature = "napi3")]
use super::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(any(feature = "libuv", feature = "tokio_rt"), napi4))] #[cfg(all(feature = "tokio_rt", feature = "napi4"))]
use crate::promise; use crate::promise;
#[cfg(napi4)] #[cfg(feature = "napi4")]
use crate::threadsafe_function::{ThreadSafeCallContext, ThreadsafeFunction}; use crate::threadsafe_function::{ThreadSafeCallContext, ThreadsafeFunction};
#[cfg(all(feature = "tokio_rt", napi4))] #[cfg(all(feature = "tokio_rt", feature = "napi4"))]
use crate::tokio_rt::{get_tokio_sender, Message}; use crate::tokio_rt::{get_tokio_sender, Message};
#[cfg(all(feature = "libuv", napi4))]
use crate::uv;
#[cfg(all(feature = "serde-json"))] #[cfg(all(feature = "serde-json"))]
use serde::de::DeserializeOwned; use serde::de::DeserializeOwned;
#[cfg(all(feature = "serde-json"))] #[cfg(all(feature = "serde-json"))]
use serde::Serialize; use serde::Serialize;
#[cfg(all(feature = "libuv", napi4))] #[cfg(all(feature = "tokio_rt", feature = "napi4"))]
use std::future::Future; use std::future::Future;
#[cfg(all(feature = "tokio_rt", napi4))] #[cfg(all(feature = "tokio_rt", feature = "napi4"))]
use tokio::sync::mpsc::error::TrySendError; use tokio::sync::mpsc::error::TrySendError;
pub type Callback = extern "C" fn(sys::napi_env, sys::napi_callback_info) -> sys::napi_value; pub type Callback = extern "C" fn(sys::napi_env, sys::napi_callback_info) -> sys::napi_value;
@ -90,7 +89,7 @@ impl Env {
Ok(JsNumber::from_raw_unchecked(self.0, raw_value)) Ok(JsNumber::from_raw_unchecked(self.0, raw_value))
} }
#[cfg(napi6)] #[cfg(feature = "napi6")]
/// [n_api_napi_create_bigint_int64](https://nodejs.org/api/n-api.html#n_api_napi_create_bigint_int64) /// [n_api_napi_create_bigint_int64](https://nodejs.org/api/n-api.html#n_api_napi_create_bigint_int64)
pub fn create_bigint_from_i64(&self, value: i64) -> Result<JsBigint> { pub fn create_bigint_from_i64(&self, value: i64) -> Result<JsBigint> {
let mut raw_value = ptr::null_mut(); let mut raw_value = ptr::null_mut();
@ -98,14 +97,14 @@ impl Env {
Ok(JsBigint::from_raw_unchecked(self.0, raw_value, 1)) Ok(JsBigint::from_raw_unchecked(self.0, raw_value, 1))
} }
#[cfg(napi6)] #[cfg(feature = "napi6")]
pub fn create_bigint_from_u64(&self, value: u64) -> Result<JsBigint> { pub fn create_bigint_from_u64(&self, value: u64) -> Result<JsBigint> {
let mut raw_value = ptr::null_mut(); let mut raw_value = ptr::null_mut();
check_status(unsafe { sys::napi_create_bigint_uint64(self.0, value, &mut raw_value) })?; check_status(unsafe { sys::napi_create_bigint_uint64(self.0, value, &mut raw_value) })?;
Ok(JsBigint::from_raw_unchecked(self.0, raw_value, 1)) Ok(JsBigint::from_raw_unchecked(self.0, raw_value, 1))
} }
#[cfg(napi6)] #[cfg(feature = "napi6")]
pub fn create_bigint_from_i128(&self, value: i128) -> Result<JsBigint> { pub fn create_bigint_from_i128(&self, value: i128) -> Result<JsBigint> {
let mut raw_value = ptr::null_mut(); let mut raw_value = ptr::null_mut();
let sign_bit = if value > 0 { 0 } else { 1 }; let sign_bit = if value > 0 { 0 } else { 1 };
@ -116,7 +115,7 @@ impl Env {
Ok(JsBigint::from_raw_unchecked(self.0, raw_value, 1)) Ok(JsBigint::from_raw_unchecked(self.0, raw_value, 1))
} }
#[cfg(napi6)] #[cfg(feature = "napi6")]
pub fn create_bigint_from_u128(&self, value: u128) -> Result<JsBigint> { pub fn create_bigint_from_u128(&self, value: u128) -> Result<JsBigint> {
let mut raw_value = ptr::null_mut(); let mut raw_value = ptr::null_mut();
let words = &value as *const u128 as *const u64; let words = &value as *const u128 as *const u64;
@ -124,7 +123,7 @@ impl Env {
Ok(JsBigint::from_raw_unchecked(self.0, raw_value, 1)) Ok(JsBigint::from_raw_unchecked(self.0, raw_value, 1))
} }
#[cfg(napi6)] #[cfg(feature = "napi6")]
/// [n_api_napi_create_bigint_words](https://nodejs.org/api/n-api.html#n_api_napi_create_bigint_words) /// [n_api_napi_create_bigint_words](https://nodejs.org/api/n-api.html#n_api_napi_create_bigint_words)
/// The resulting BigInt will be negative when sign_bit is true. /// The resulting BigInt will be negative when sign_bit is true.
pub fn create_bigint_from_words(&self, sign_bit: bool, words: Vec<u64>) -> Result<JsBigint> { pub fn create_bigint_from_words(&self, sign_bit: bool, words: Vec<u64>) -> Result<JsBigint> {
@ -549,14 +548,14 @@ impl Env {
.map_err(|e| Error::new(Status::InvalidArg, format!("{}", e))) .map_err(|e| Error::new(Status::InvalidArg, format!("{}", e)))
} }
#[cfg(napi2)] #[cfg(feature = "napi2")]
pub fn get_uv_event_loop(&self) -> Result<*mut sys::uv_loop_s> { pub fn get_uv_event_loop(&self) -> Result<*mut sys::uv_loop_s> {
let mut uv_loop: *mut sys::uv_loop_s = ptr::null_mut(); let mut uv_loop: *mut sys::uv_loop_s = ptr::null_mut();
check_status(unsafe { sys::napi_get_uv_event_loop(self.0, &mut uv_loop) })?; check_status(unsafe { sys::napi_get_uv_event_loop(self.0, &mut uv_loop) })?;
Ok(uv_loop) Ok(uv_loop)
} }
#[cfg(napi3)] #[cfg(feature = "napi3")]
pub fn add_env_cleanup_hook<T, F>( pub fn add_env_cleanup_hook<T, F>(
&mut self, &mut self,
cleanup_data: T, cleanup_data: T,
@ -581,7 +580,7 @@ impl Env {
Ok(CleanupEnvHook(hook_ref)) Ok(CleanupEnvHook(hook_ref))
} }
#[cfg(napi3)] #[cfg(feature = "napi3")]
pub fn remove_env_cleanup_hook<T>(&mut self, hook: CleanupEnvHook<T>) -> Result<()> pub fn remove_env_cleanup_hook<T>(&mut self, hook: CleanupEnvHook<T>) -> Result<()>
where where
T: 'static, T: 'static,
@ -591,7 +590,7 @@ impl Env {
}) })
} }
#[cfg(napi4)] #[cfg(feature = "napi4")]
pub fn create_threadsafe_function< pub fn create_threadsafe_function<
T: Send, T: Send,
V: NapiValue, V: NapiValue,
@ -605,31 +604,7 @@ impl Env {
ThreadsafeFunction::create(self.0, func, max_queue_size, callback) ThreadsafeFunction::create(self.0, func, max_queue_size, callback)
} }
#[cfg(all(feature = "libuv", napi4))] #[cfg(all(feature = "tokio_rt", feature = "napi4"))]
pub fn execute<
T: 'static + Send,
V: 'static + NapiValue,
F: 'static + Future<Output = Result<T>>,
R: 'static + Send + Sync + FnOnce(&mut Env, T) -> Result<V>,
>(
&self,
deferred: F,
resolver: R,
) -> Result<JsObject> {
let mut raw_promise = ptr::null_mut();
let mut raw_deferred = ptr::null_mut();
check_status(unsafe { sys::napi_create_promise(self.0, &mut raw_deferred, &mut raw_promise) })?;
let event_loop = self.get_uv_event_loop()?;
let future_promise = promise::FuturePromise::create(self.0, raw_deferred, Box::from(resolver))?;
let future_to_execute = promise::resolve_from_future(future_promise.start()?, deferred);
uv::execute(event_loop, Box::pin(future_to_execute))?;
Ok(JsObject::from_raw_unchecked(self.0, raw_promise))
}
#[cfg(all(feature = "tokio_rt", napi4))]
pub fn execute_tokio_future< pub fn execute_tokio_future<
T: 'static + Send, T: 'static + Send,
V: 'static + NapiValue, V: 'static + NapiValue,
@ -664,7 +639,7 @@ impl Env {
Ok(JsObject::from_raw_unchecked(self.0, raw_promise)) Ok(JsObject::from_raw_unchecked(self.0, raw_promise))
} }
#[cfg(napi5)] #[cfg(feature = "napi5")]
pub fn create_date(&self, time: f64) -> Result<JsDate> { pub fn create_date(&self, time: f64) -> Result<JsDate> {
let mut js_value = ptr::null_mut(); let mut js_value = ptr::null_mut();
check_status(unsafe { sys::napi_create_date(self.0, time, &mut js_value) })?; check_status(unsafe { sys::napi_create_date(self.0, time, &mut js_value) })?;
@ -738,6 +713,11 @@ impl Env {
let version = unsafe { *result }; let version = unsafe { *result };
version.try_into() version.try_into()
} }
/// get raw env ptr
pub fn raw(&self) -> sys::napi_env {
self.0
}
} }
unsafe extern "C" fn drop_buffer(env: sys::napi_env, finalize_data: *mut c_void, len: *mut c_void) { unsafe extern "C" fn drop_buffer(env: sys::napi_env, finalize_data: *mut c_void, len: *mut c_void) {
@ -759,6 +739,7 @@ unsafe extern "C" fn raw_finalize<T>(
Box::from_raw(tagged_object); Box::from_raw(tagged_object);
} }
#[cfg(feature = "napi3")]
unsafe extern "C" fn cleanup_env<T: 'static>(hook_data: *mut c_void) { unsafe extern "C" fn cleanup_env<T: 'static>(hook_data: *mut c_void) {
let cleanup_env_hook = Box::from_raw(hook_data as *mut CleanupEnvHookData<T>); let cleanup_env_hook = Box::from_raw(hook_data as *mut CleanupEnvHookData<T>);
(cleanup_env_hook.hook)(cleanup_env_hook.data); (cleanup_env_hook.hook)(cleanup_env_hook.data);

View file

@ -7,7 +7,7 @@ use std::ptr;
use super::{Value, ValueType}; use super::{Value, ValueType};
use crate::error::check_status; use crate::error::check_status;
use crate::{sys, Error, JsUnknown, NapiValue, Ref, Result, Status}; use crate::{sys, Error, JsUnknown, NapiValue, Ref, Result};
#[repr(transparent)] #[repr(transparent)]
#[derive(Debug)] #[derive(Debug)]
@ -44,6 +44,7 @@ pub struct JsDataViewValue {
pub length: u64, pub length: u64,
} }
#[repr(u8)]
#[derive(Debug)] #[derive(Debug)]
pub enum TypedArrayType { pub enum TypedArrayType {
Int8, Int8,
@ -55,9 +56,9 @@ pub enum TypedArrayType {
Uint32, Uint32,
Float32, Float32,
Float64, Float64,
#[cfg(napi6)] #[cfg(feature = "napi6")]
BigInt64, BigInt64,
#[cfg(napi6)] #[cfg(feature = "napi6")]
BigUint64, BigUint64,
} }
@ -75,11 +76,10 @@ impl TryFrom<sys::napi_typedarray_type> for TypedArrayType {
sys::napi_typedarray_type::napi_uint32_array => Ok(Self::Uint32), sys::napi_typedarray_type::napi_uint32_array => Ok(Self::Uint32),
sys::napi_typedarray_type::napi_float32_array => Ok(Self::Float32), sys::napi_typedarray_type::napi_float32_array => Ok(Self::Float32),
sys::napi_typedarray_type::napi_float64_array => Ok(Self::Float64), sys::napi_typedarray_type::napi_float64_array => Ok(Self::Float64),
#[cfg(napi6)] #[cfg(feature = "napi6")]
sys::napi_typedarray_type::napi_bigint64_array => Ok(Self::BigInt64), sys::napi_typedarray_type::napi_bigint64_array => Ok(Self::BigInt64),
#[cfg(napi6)] #[cfg(feature = "napi6")]
sys::napi_typedarray_type::napi_biguint64_array => Ok(Self::BigUint64), sys::napi_typedarray_type::napi_biguint64_array => Ok(Self::BigUint64),
_ => Err(Error::from_status(Status::Unknown)),
} }
} }
} }
@ -96,21 +96,21 @@ impl From<TypedArrayType> for sys::napi_typedarray_type {
TypedArrayType::Uint32 => sys::napi_typedarray_type::napi_uint32_array, TypedArrayType::Uint32 => sys::napi_typedarray_type::napi_uint32_array,
TypedArrayType::Float32 => sys::napi_typedarray_type::napi_float32_array, TypedArrayType::Float32 => sys::napi_typedarray_type::napi_float32_array,
TypedArrayType::Float64 => sys::napi_typedarray_type::napi_float64_array, TypedArrayType::Float64 => sys::napi_typedarray_type::napi_float64_array,
#[cfg(napi6)] #[cfg(feature = "napi6")]
TypedArrayType::BigInt64 => sys::napi_typedarray_type::napi_bigint64_array, TypedArrayType::BigInt64 => sys::napi_typedarray_type::napi_bigint64_array,
#[cfg(napi6)] #[cfg(feature = "napi6")]
TypedArrayType::BigUint64 => sys::napi_typedarray_type::napi_biguint64_array, TypedArrayType::BigUint64 => sys::napi_typedarray_type::napi_biguint64_array,
} }
} }
} }
impl JsArrayBuffer { impl JsArrayBuffer {
#[cfg(napi7)] #[cfg(feature = "napi7")]
pub fn detach(self) -> Result<()> { pub fn detach(self) -> Result<()> {
check_status(unsafe { sys::napi_detach_arraybuffer(self.0.env, self.0.value) }) check_status(unsafe { sys::napi_detach_arraybuffer(self.0.env, self.0.value) })
} }
#[cfg(napi7)] #[cfg(feature = "napi7")]
pub fn is_detached(&self) -> Result<bool> { pub fn is_detached(&self) -> Result<bool> {
let mut is_detached = false; let mut is_detached = false;
check_status(unsafe { check_status(unsafe {

View file

@ -71,7 +71,7 @@ impl JsBigint {
} }
#[inline] #[inline]
#[cfg(napi5)] #[cfg(feature = "napi5")]
pub fn is_date(&self) -> Result<bool> { pub fn is_date(&self) -> Result<bool> {
let mut is_date = true; let mut is_date = true;
check_status(unsafe { sys::napi_is_date(self.raw.env, self.raw.value, &mut is_date) })?; check_status(unsafe { sys::napi_is_date(self.raw.env, self.raw.value, &mut is_date) })?;

View file

@ -4,7 +4,7 @@ use serde::de::Visitor;
use serde::de::{DeserializeSeed, EnumAccess, MapAccess, SeqAccess, Unexpected, VariantAccess}; use serde::de::{DeserializeSeed, EnumAccess, MapAccess, SeqAccess, Unexpected, VariantAccess};
use super::{type_of, NapiValue, Value, ValueType}; use super::{type_of, NapiValue, Value, ValueType};
#[cfg(napi6)] #[cfg(feature = "napi6")]
use crate::JsBigint; use crate::JsBigint;
use crate::{ use crate::{
Error, JsBoolean, JsBufferValue, JsNumber, JsObject, JsString, JsUnknown, Result, Status, Error, JsBoolean, JsBufferValue, JsNumber, JsObject, JsString, JsUnknown, Result, Status,
@ -52,7 +52,7 @@ impl<'x, 'de, 'env> serde::de::Deserializer<'x> for &'de mut De<'env> {
visitor.visit_map(&mut deserializer) visitor.visit_map(&mut deserializer)
} }
} }
#[cfg(napi6)] #[cfg(feature = "napi6")]
ValueType::Bigint => { ValueType::Bigint => {
let mut js_bigint = JsBigint::from_raw(self.0.env, self.0.value)?; let mut js_bigint = JsBigint::from_raw(self.0.env, self.0.value)?;
let (signed, v, _loss) = js_bigint.get_u128()?; let (signed, v, _loss) = js_bigint.get_u128()?;

View file

@ -11,11 +11,11 @@ mod de;
mod ser; mod ser;
mod arraybuffer; mod arraybuffer;
#[cfg(napi6)] #[cfg(feature = "napi6")]
mod bigint; mod bigint;
mod boolean; mod boolean;
mod buffer; mod buffer;
#[cfg(napi5)] #[cfg(feature = "napi5")]
mod date; mod date;
mod either; mod either;
mod escapable_handle_scope; mod escapable_handle_scope;
@ -32,11 +32,11 @@ mod value_ref;
mod value_type; mod value_type;
pub use arraybuffer::*; pub use arraybuffer::*;
#[cfg(napi6)] #[cfg(feature = "napi6")]
pub use bigint::JsBigint; pub use bigint::JsBigint;
pub use boolean::JsBoolean; pub use boolean::JsBoolean;
pub use buffer::*; pub use buffer::*;
#[cfg(napi5)] #[cfg(feature = "napi5")]
pub use date::*; pub use date::*;
#[cfg(feature = "serde-json")] #[cfg(feature = "serde-json")]
pub(crate) use de::De; pub(crate) use de::De;
@ -78,7 +78,7 @@ pub(crate) fn type_of(env: sys::napi_env, raw_value: sys::napi_value) -> Result<
unsafe { unsafe {
let mut value_type = sys::napi_valuetype::napi_undefined; let mut value_type = sys::napi_valuetype::napi_undefined;
check_status(sys::napi_typeof(env, raw_value, &mut value_type))?; check_status(sys::napi_typeof(env, raw_value, &mut value_type))?;
ValueType::try_from(value_type) Ok(ValueType::from(value_type))
} }
} }
@ -171,7 +171,7 @@ macro_rules! impl_js_value_methods {
} }
#[inline] #[inline]
#[cfg(napi5)] #[cfg(feature = "napi5")]
pub fn is_date(&self) -> Result<bool> { pub fn is_date(&self) -> Result<bool> {
let mut is_date = true; let mut is_date = true;
check_status(unsafe { sys::napi_is_date(self.0.env, self.0.value, &mut is_date) })?; check_status(unsafe { sys::napi_is_date(self.0.env, self.0.value, &mut is_date) })?;
@ -363,7 +363,7 @@ macro_rules! impl_object_methods {
/// https://nodejs.org/api/n-api.html#n_api_napi_get_all_property_names /// https://nodejs.org/api/n-api.html#n_api_napi_get_all_property_names
/// return `Array` of property names /// return `Array` of property names
#[cfg(napi6)] #[cfg(feature = "napi6")]
pub fn get_all_property_names( pub fn get_all_property_names(
&self, &self,
mode: KeyCollectionMode, mode: KeyCollectionMode,
@ -484,7 +484,7 @@ impl_js_value_methods!(JsNumber);
impl_js_value_methods!(JsString); impl_js_value_methods!(JsString);
impl_js_value_methods!(JsObject); impl_js_value_methods!(JsObject);
impl_js_value_methods!(JsGlobal); impl_js_value_methods!(JsGlobal);
#[cfg(napi5)] #[cfg(feature = "napi5")]
impl_js_value_methods!(JsDate); impl_js_value_methods!(JsDate);
impl_js_value_methods!(JsFunction); impl_js_value_methods!(JsFunction);
impl_js_value_methods!(JsExternal); impl_js_value_methods!(JsExternal);
@ -511,7 +511,7 @@ impl_napi_value_trait!(JsNumber, Number);
impl_napi_value_trait!(JsString, String); impl_napi_value_trait!(JsString, String);
impl_napi_value_trait!(JsObject, Object); impl_napi_value_trait!(JsObject, Object);
impl_napi_value_trait!(JsGlobal, Object); impl_napi_value_trait!(JsGlobal, Object);
#[cfg(napi5)] #[cfg(feature = "napi5")]
impl_napi_value_trait!(JsDate, Object); impl_napi_value_trait!(JsDate, Object);
impl_napi_value_trait!(JsTimeout, Object); impl_napi_value_trait!(JsTimeout, Object);
impl_napi_value_trait!(JsFunction, Function); impl_napi_value_trait!(JsFunction, Function);
@ -535,6 +535,7 @@ impl NapiValue for JsUnknown {
}) })
} }
/// get raw js value ptr
fn raw(&self) -> sys::napi_value { fn raw(&self) -> sys::napi_value {
self.0.value self.0.value
} }

View file

@ -1,20 +1,22 @@
use super::Value; use super::Value;
#[cfg(napi6)] #[cfg(feature = "napi6")]
use crate::sys; use crate::sys;
use crate::{Error, Result, Status}; #[cfg(feature = "napi6")]
use crate::{Error, Result};
#[cfg(feature = "napi6")]
use std::convert::TryFrom; use std::convert::TryFrom;
#[repr(transparent)] #[repr(transparent)]
#[derive(Debug)] #[derive(Debug)]
pub struct JsObject(pub(crate) Value); pub struct JsObject(pub(crate) Value);
#[cfg(napi6)] #[cfg(feature = "napi6")]
pub enum KeyCollectionMode { pub enum KeyCollectionMode {
IncludePrototypes, IncludePrototypes,
OwnOnly, OwnOnly,
} }
#[cfg(napi6)] #[cfg(feature = "napi6")]
impl TryFrom<sys::napi_key_collection_mode> for KeyCollectionMode { impl TryFrom<sys::napi_key_collection_mode> for KeyCollectionMode {
type Error = Error; type Error = Error;
@ -22,12 +24,11 @@ impl TryFrom<sys::napi_key_collection_mode> for KeyCollectionMode {
match value { match value {
sys::napi_key_collection_mode::napi_key_include_prototypes => Ok(Self::IncludePrototypes), sys::napi_key_collection_mode::napi_key_include_prototypes => Ok(Self::IncludePrototypes),
sys::napi_key_collection_mode::napi_key_own_only => Ok(Self::OwnOnly), sys::napi_key_collection_mode::napi_key_own_only => Ok(Self::OwnOnly),
_ => Err(Error::from_status(Status::Unknown)),
} }
} }
} }
#[cfg(napi6)] #[cfg(feature = "napi6")]
impl From<KeyCollectionMode> for sys::napi_key_collection_mode { impl From<KeyCollectionMode> for sys::napi_key_collection_mode {
fn from(value: KeyCollectionMode) -> Self { fn from(value: KeyCollectionMode) -> Self {
match value { match value {
@ -39,7 +40,7 @@ impl From<KeyCollectionMode> for sys::napi_key_collection_mode {
} }
} }
#[cfg(napi6)] #[cfg(feature = "napi6")]
pub enum KeyFilter { pub enum KeyFilter {
AllProperties, AllProperties,
Writable, Writable,
@ -49,7 +50,7 @@ pub enum KeyFilter {
SkipSymbols, SkipSymbols,
} }
#[cfg(napi6)] #[cfg(feature = "napi6")]
impl TryFrom<sys::napi_key_filter> for KeyFilter { impl TryFrom<sys::napi_key_filter> for KeyFilter {
type Error = Error; type Error = Error;
@ -61,12 +62,11 @@ impl TryFrom<sys::napi_key_filter> for KeyFilter {
sys::napi_key_filter::napi_key_configurable => Ok(Self::Configurable), sys::napi_key_filter::napi_key_configurable => Ok(Self::Configurable),
sys::napi_key_filter::napi_key_skip_strings => Ok(Self::SkipStrings), sys::napi_key_filter::napi_key_skip_strings => Ok(Self::SkipStrings),
sys::napi_key_filter::napi_key_skip_symbols => Ok(Self::SkipSymbols), sys::napi_key_filter::napi_key_skip_symbols => Ok(Self::SkipSymbols),
_ => Err(Error::from_status(Status::Unknown)),
} }
} }
} }
#[cfg(napi6)] #[cfg(feature = "napi6")]
impl From<KeyFilter> for sys::napi_key_filter { impl From<KeyFilter> for sys::napi_key_filter {
fn from(value: KeyFilter) -> Self { fn from(value: KeyFilter) -> Self {
match value { match value {
@ -80,13 +80,13 @@ impl From<KeyFilter> for sys::napi_key_filter {
} }
} }
#[cfg(napi6)] #[cfg(feature = "napi6")]
pub enum KeyConversion { pub enum KeyConversion {
KeepNumbers, KeepNumbers,
NumbersToStrings, NumbersToStrings,
} }
#[cfg(napi6)] #[cfg(feature = "napi6")]
impl TryFrom<sys::napi_key_conversion> for KeyConversion { impl TryFrom<sys::napi_key_conversion> for KeyConversion {
type Error = Error; type Error = Error;
@ -94,12 +94,11 @@ impl TryFrom<sys::napi_key_conversion> for KeyConversion {
match value { match value {
sys::napi_key_conversion::napi_key_keep_numbers => Ok(Self::KeepNumbers), sys::napi_key_conversion::napi_key_keep_numbers => Ok(Self::KeepNumbers),
sys::napi_key_conversion::napi_key_numbers_to_strings => Ok(Self::NumbersToStrings), sys::napi_key_conversion::napi_key_numbers_to_strings => Ok(Self::NumbersToStrings),
_ => Err(Error::from_status(Status::Unknown)),
} }
} }
} }
#[cfg(napi6)] #[cfg(feature = "napi6")]
impl From<KeyConversion> for sys::napi_key_conversion { impl From<KeyConversion> for sys::napi_key_conversion {
fn from(value: KeyConversion) -> Self { fn from(value: KeyConversion) -> Self {
match value { match value {

View file

@ -13,11 +13,11 @@ pub struct Property<'env> {
#[repr(u32)] #[repr(u32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum PropertyAttributes { pub enum PropertyAttributes {
Default = sys::napi_property_attributes::napi_default.0 as _, Default = sys::napi_property_attributes::napi_default as _,
Writable = sys::napi_property_attributes::napi_writable.0 as _, Writable = sys::napi_property_attributes::napi_writable as _,
Enumerable = sys::napi_property_attributes::napi_enumerable.0 as _, Enumerable = sys::napi_property_attributes::napi_enumerable as _,
Configurable = sys::napi_property_attributes::napi_configurable.0 as _, Configurable = sys::napi_property_attributes::napi_configurable as _,
Static = sys::napi_property_attributes::napi_static.0 as _, Static = sys::napi_property_attributes::napi_static as _,
} }
impl From<PropertyAttributes> for sys::napi_property_attributes { impl From<PropertyAttributes> for sys::napi_property_attributes {

View file

@ -1,5 +1,5 @@
use std::result::Result as StdResult; use std::result::Result as StdResult;
#[cfg(napi6)] #[cfg(feature = "napi6")]
use std::slice; use std::slice;
use serde::{ser, Serialize, Serializer}; use serde::{ser, Serialize, Serializer};
@ -92,13 +92,21 @@ impl<'env> Serializer for Ser<'env> {
self.0.create_uint32(v).map(|js_number| js_number.0) self.0.create_uint32(v).map(|js_number| js_number.0)
} }
#[cfg(all(any(napi2, napi3, napi4, napi5), not(napi6)))] #[cfg(all(
any(
feature = "napi2",
feature = "napi3",
feature = "napi4",
feature = "napi5"
),
not(feature = "napi6")
))]
#[inline] #[inline]
fn serialize_u64(self, v: u64) -> Result<Self::Ok> { fn serialize_u64(self, v: u64) -> Result<Self::Ok> {
self.0.create_int64(v as _).map(|js_number| js_number.0) self.0.create_int64(v as _).map(|js_number| js_number.0)
} }
#[cfg(napi6)] #[cfg(feature = "napi6")]
#[inline] #[inline]
fn serialize_u64(self, v: u64) -> Result<Self::Ok> { fn serialize_u64(self, v: u64) -> Result<Self::Ok> {
self self
@ -107,13 +115,21 @@ impl<'env> Serializer for Ser<'env> {
.map(|js_number| js_number.raw) .map(|js_number| js_number.raw)
} }
#[cfg(all(any(napi2, napi3, napi4, napi5), not(napi6)))] #[cfg(all(
any(
feature = "napi2",
feature = "napi3",
feature = "napi4",
feature = "napi5"
),
not(feature = "napi6")
))]
#[inline] #[inline]
fn serialize_u128(self, v: u128) -> Result<Self::Ok> { fn serialize_u128(self, v: u128) -> Result<Self::Ok> {
self.0.create_string(v.to_string().as_str()).map(|v| v.0) self.0.create_string(v.to_string().as_str()).map(|v| v.0)
} }
#[cfg(napi6)] #[cfg(feature = "napi6")]
#[inline] #[inline]
fn serialize_u128(self, v: u128) -> Result<Self::Ok> { fn serialize_u128(self, v: u128) -> Result<Self::Ok> {
let words_ref = &v as *const _; let words_ref = &v as *const _;
@ -124,13 +140,21 @@ impl<'env> Serializer for Ser<'env> {
.map(|v| v.raw) .map(|v| v.raw)
} }
#[cfg(all(any(napi2, napi3, napi4, napi5), not(napi6)))] #[cfg(all(
any(
feature = "napi2",
feature = "napi3",
feature = "napi4",
feature = "napi5"
),
not(feature = "napi6")
))]
#[inline] #[inline]
fn serialize_i128(self, v: i128) -> Result<Self::Ok> { fn serialize_i128(self, v: i128) -> Result<Self::Ok> {
self.0.create_string(v.to_string().as_str()).map(|v| v.0) self.0.create_string(v.to_string().as_str()).map(|v| v.0)
} }
#[cfg(napi6)] #[cfg(feature = "napi6")]
#[inline] #[inline]
fn serialize_i128(self, v: i128) -> Result<Self::Ok> { fn serialize_i128(self, v: i128) -> Result<Self::Ok> {
let words_ref = &(v as u128) as *const _; let words_ref = &(v as u128) as *const _;

View file

@ -1,11 +1,10 @@
use std::convert::TryFrom;
use std::convert::TryInto; use std::convert::TryInto;
use crate::{sys, Error, Result, Status}; use crate::{sys, Error, Result, Status};
#[repr(u8)]
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Ord, Eq, Hash)] #[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Ord, Eq, Hash)]
pub enum ValueType { pub enum ValueType {
Unknown = 100,
Undefined = 0, Undefined = 0,
Null = 1, Null = 1,
Boolean = 2, Boolean = 2,
@ -15,8 +14,9 @@ pub enum ValueType {
Object = 6, Object = 6,
Function = 7, Function = 7,
External = 8, External = 8,
#[cfg(napi6)] #[cfg(feature = "napi6")]
Bigint = 9, Bigint = 9,
Unknown = 255,
} }
impl TryInto<sys::napi_valuetype> for ValueType { impl TryInto<sys::napi_valuetype> for ValueType {
@ -25,7 +25,7 @@ impl TryInto<sys::napi_valuetype> for ValueType {
fn try_into(self) -> Result<sys::napi_valuetype> { fn try_into(self) -> Result<sys::napi_valuetype> {
match self { match self {
ValueType::Unknown => Err(Error::from_status(Status::Unknown)), ValueType::Unknown => Err(Error::from_status(Status::Unknown)),
#[cfg(napi6)] #[cfg(feature = "napi6")]
ValueType::Bigint => Ok(sys::napi_valuetype::napi_bigint), ValueType::Bigint => Ok(sys::napi_valuetype::napi_bigint),
ValueType::Boolean => Ok(sys::napi_valuetype::napi_boolean), ValueType::Boolean => Ok(sys::napi_valuetype::napi_boolean),
ValueType::External => Ok(sys::napi_valuetype::napi_external), ValueType::External => Ok(sys::napi_valuetype::napi_external),
@ -40,23 +40,20 @@ impl TryInto<sys::napi_valuetype> for ValueType {
} }
} }
impl TryFrom<sys::napi_valuetype> for ValueType { impl From<sys::napi_valuetype> for ValueType {
type Error = Error; fn from(value: sys::napi_valuetype) -> Self {
fn try_from(value: sys::napi_valuetype) -> Result<Self> {
match value { match value {
#[cfg(napi6)] #[cfg(feature = "napi6")]
sys::napi_valuetype::napi_bigint => Ok(ValueType::Bigint), sys::napi_valuetype::napi_bigint => ValueType::Bigint,
sys::napi_valuetype::napi_boolean => Ok(ValueType::Boolean), sys::napi_valuetype::napi_boolean => ValueType::Boolean,
sys::napi_valuetype::napi_external => Ok(ValueType::External), sys::napi_valuetype::napi_external => ValueType::External,
sys::napi_valuetype::napi_function => Ok(ValueType::Function), sys::napi_valuetype::napi_function => ValueType::Function,
sys::napi_valuetype::napi_null => Ok(ValueType::Null), sys::napi_valuetype::napi_null => ValueType::Null,
sys::napi_valuetype::napi_number => Ok(ValueType::Number), sys::napi_valuetype::napi_number => ValueType::Number,
sys::napi_valuetype::napi_object => Ok(ValueType::Object), sys::napi_valuetype::napi_object => ValueType::Object,
sys::napi_valuetype::napi_string => Ok(ValueType::String), sys::napi_valuetype::napi_string => ValueType::String,
sys::napi_valuetype::napi_symbol => Ok(ValueType::Symbol), sys::napi_valuetype::napi_symbol => ValueType::Symbol,
sys::napi_valuetype::napi_undefined => Ok(ValueType::Undefined), sys::napi_valuetype::napi_undefined => ValueType::Undefined,
_ => Err(Error::from_status(Status::Unknown)),
} }
} }
} }

View file

@ -92,23 +92,22 @@
mod async_work; mod async_work;
mod call_context; mod call_context;
#[cfg(feature = "napi3")]
mod cleanup_env; mod cleanup_env;
mod env; mod env;
mod error; mod error;
mod js_values; mod js_values;
mod module; mod module;
#[cfg(all(feature = "libuv", napi4))] #[cfg(all(feature = "tokio_rt", feature = "napi4"))]
mod promise; mod promise;
mod status; mod status;
mod task; mod task;
#[cfg(napi3)] #[cfg(feature = "napi3")]
pub use cleanup_env::CleanupEnvHook; pub use cleanup_env::CleanupEnvHook;
#[cfg(napi4)] #[cfg(feature = "napi4")]
pub mod threadsafe_function; pub mod threadsafe_function;
#[cfg(all(feature = "tokio_rt", napi4))] #[cfg(all(feature = "tokio_rt", feature = "napi4"))]
mod tokio_rt; mod tokio_rt;
#[cfg(all(feature = "libuv", napi4))]
mod uv;
mod version; mod version;
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
mod win_delay_load_hook; mod win_delay_load_hook;
@ -124,7 +123,7 @@ pub use status::Status;
pub use task::Task; pub use task::Task;
pub use version::NodeVersion; pub use version::NodeVersion;
#[cfg(all(feature = "tokio_rt", napi4))] #[cfg(all(feature = "tokio_rt", feature = "napi4"))]
pub use tokio_rt::shutdown as shutdown_tokio_rt; pub use tokio_rt::shutdown as shutdown_tokio_rt;
#[cfg(feature = "serde-json")] #[cfg(feature = "serde-json")]
@ -147,7 +146,7 @@ pub type ContextlessResult<T> = Result<Option<T>>;
macro_rules! register_module { macro_rules! register_module {
($module_name:ident, $init:ident) => { ($module_name:ident, $init:ident) => {
#[inline] #[inline]
#[cfg(all(feature = "tokio_rt", napi4))] #[cfg(all(feature = "tokio_rt", feature = "napi4"))]
fn check_status(code: $crate::sys::napi_status) -> Result<()> { fn check_status(code: $crate::sys::napi_status) -> Result<()> {
use $crate::{Error, Status}; use $crate::{Error, Status};
let status = Status::from(code); let status = Status::from(code);
@ -163,7 +162,7 @@ macro_rules! register_module {
use std::ptr; use std::ptr;
use $crate::{sys, Env, JsObject, NapiValue}; use $crate::{sys, Env, JsObject, NapiValue};
#[cfg(all(feature = "tokio_rt", napi4))] #[cfg(all(feature = "tokio_rt", feature = "napi4"))]
use $crate::shutdown_tokio_rt; use $crate::shutdown_tokio_rt;
#[no_mangle] #[no_mangle]
@ -175,11 +174,11 @@ macro_rules! register_module {
let mut exports: JsObject = JsObject::from_raw_unchecked(raw_env, raw_exports); let mut exports: JsObject = JsObject::from_raw_unchecked(raw_env, raw_exports);
let mut cjs_module = Module { env, exports }; let mut cjs_module = Module { env, exports };
let result = $init(&mut cjs_module); let result = $init(&mut cjs_module);
#[cfg(all(feature = "tokio_rt", napi4))] #[cfg(all(feature = "tokio_rt", feature = "napi4"))]
let hook_result = check_status(unsafe { let hook_result = check_status(unsafe {
sys::napi_add_env_cleanup_hook(raw_env, Some(shutdown_tokio_rt), ptr::null_mut()) sys::napi_add_env_cleanup_hook(raw_env, Some(shutdown_tokio_rt), ptr::null_mut())
}); });
#[cfg(not(all(feature = "tokio_rt", napi4)))] #[cfg(not(all(feature = "tokio_rt", feature = "napi4")))]
let hook_result = Ok(()); let hook_result = Ok(());
match hook_result.and_then(move |_| result) { match hook_result.and_then(move |_| result) {
Ok(_) => cjs_module.exports.raw(), Ok(_) => cjs_module.exports.raw(),

View file

@ -17,11 +17,11 @@ pub enum Status {
EscapeCalledTwice, EscapeCalledTwice,
HandleScopeMismatch, HandleScopeMismatch,
CallbackScopeMismatch, CallbackScopeMismatch,
#[cfg(napi4)] #[cfg(feature = "napi4")]
QueueFull, QueueFull,
#[cfg(napi4)] #[cfg(feature = "napi4")]
Closing, Closing,
#[cfg(napi6)] #[cfg(feature = "napi6")]
BigintExpected, BigintExpected,
Unknown, Unknown,
} }
@ -46,11 +46,11 @@ impl From<napi_status> for Status {
napi_status::napi_escape_called_twice => EscapeCalledTwice, napi_status::napi_escape_called_twice => EscapeCalledTwice,
napi_status::napi_handle_scope_mismatch => HandleScopeMismatch, napi_status::napi_handle_scope_mismatch => HandleScopeMismatch,
napi_status::napi_callback_scope_mismatch => CallbackScopeMismatch, napi_status::napi_callback_scope_mismatch => CallbackScopeMismatch,
#[cfg(napi4)] #[cfg(feature = "napi4")]
napi_status::napi_queue_full => QueueFull, napi_status::napi_queue_full => QueueFull,
#[cfg(napi4)] #[cfg(feature = "napi4")]
napi_status::napi_closing => Closing, napi_status::napi_closing => Closing,
#[cfg(napi6)] #[cfg(feature = "napi6")]
napi_status::napi_bigint_expected => BigintExpected, napi_status::napi_bigint_expected => BigintExpected,
_ => Unknown, _ => Unknown,
} }
@ -75,11 +75,11 @@ impl Into<self::napi_status> for Status {
Self::EscapeCalledTwice => napi_status::napi_escape_called_twice, Self::EscapeCalledTwice => napi_status::napi_escape_called_twice,
Self::HandleScopeMismatch => napi_status::napi_handle_scope_mismatch, Self::HandleScopeMismatch => napi_status::napi_handle_scope_mismatch,
Self::CallbackScopeMismatch => napi_status::napi_callback_scope_mismatch, Self::CallbackScopeMismatch => napi_status::napi_callback_scope_mismatch,
#[cfg(napi4)] #[cfg(feature = "napi4")]
Self::QueueFull => napi_status::napi_queue_full, Self::QueueFull => napi_status::napi_queue_full,
#[cfg(napi4)] #[cfg(feature = "napi4")]
Self::Closing => napi_status::napi_closing, Self::Closing => napi_status::napi_closing,
#[cfg(napi6)] #[cfg(feature = "napi6")]
Self::BigintExpected => napi_status::napi_bigint_expected, Self::BigintExpected => napi_status::napi_bigint_expected,
Self::Unknown => napi_status::napi_generic_failure, Self::Unknown => napi_status::napi_generic_failure,
} }

View file

@ -1,96 +0,0 @@
extern crate alloc;
use alloc::alloc::{alloc, Layout};
use futures::future::LocalBoxFuture;
use futures::task::{waker, ArcWake, Context, Poll};
use std::future::Future;
use std::os::raw::c_void;
use std::pin::Pin;
use std::sync::Arc;
use crate::{sys, Error, Result, Status};
struct Task<'a> {
future: LocalBoxFuture<'a, ()>,
context: Context<'a>,
}
struct UvWaker(*mut sys::uv_async_t);
unsafe impl Send for UvWaker {}
unsafe impl Sync for UvWaker {}
impl UvWaker {
fn new(event_loop: *mut sys::uv_loop_s) -> Result<UvWaker> {
let uv_async_t = unsafe { alloc(Layout::new::<sys::uv_async_t>()) as *mut sys::uv_async_t };
unsafe {
let status = sys::uv_async_init(event_loop, uv_async_t, Some(poll_future));
if status != 0 {
return Err(Error::new(
Status::Unknown,
"Non-zero status returned from uv_async_init".to_owned(),
));
}
};
Ok(UvWaker(uv_async_t))
}
#[inline]
fn assign_task(&self, mut task: Task) {
if !task.poll_future() {
let arc_task = Arc::new(task);
unsafe {
sys::uv_handle_set_data(
self.0 as *mut sys::uv_handle_t,
Arc::into_raw(arc_task) as *mut c_void,
)
};
} else {
unsafe { sys::uv_close(self.0 as *mut sys::uv_handle_t, None) };
};
}
}
impl ArcWake for UvWaker {
fn wake_by_ref(arc_self: &Arc<Self>) {
let status = unsafe { sys::uv_async_send(arc_self.0) };
assert!(status == 0, "wake_uv_async_by_ref failed");
}
}
#[inline]
pub fn execute(event_loop: *mut sys::uv_loop_s, future: LocalBoxFuture<()>) -> Result<()> {
let uv_waker = UvWaker::new(event_loop)?;
let arc_waker = Arc::new(uv_waker);
let waker_to_poll = Arc::clone(&arc_waker);
let waker = waker(arc_waker);
let context = Context::from_waker(&waker);
let task = Task { future, context };
waker_to_poll.assign_task(task);
Ok(())
}
impl<'a> Task<'a> {
fn poll_future(&mut self) -> bool {
let mut pinned = Pin::new(&mut self.future);
let fut_mut = pinned.as_mut();
match fut_mut.poll(&mut self.context) {
Poll::Ready(_) => true,
Poll::Pending => false,
}
}
}
unsafe extern "C" fn poll_future(handle: *mut sys::uv_async_t) {
let data_ptr = sys::uv_handle_get_data(handle as *mut sys::uv_handle_t) as *mut Task;
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, None);
} else {
Arc::into_raw(task);
};
} else {
Arc::into_raw(task);
}
}

View file

@ -10,14 +10,14 @@ readme = "README.md"
repository = "https://github.com/napi-rs/napi-rs" repository = "https://github.com/napi-rs/napi-rs"
version = "0.4.7" version = "0.4.7"
[target.'cfg(windows)'.build-dependencies] [features]
tar = "0.4" napi1 = []
napi2 = ["napi1"]
napi3 = ["napi2"]
napi4 = ["napi3"]
napi5 = ["napi4"]
napi6 = ["napi5"]
napi7 = ["napi6"]
[build-dependencies] [build-dependencies]
bindgen = {version = "0.55", default-features = false, features = ["logging", "runtime"]} napi-build = {version = "0.2", path = "../build"}
glob = "0.3"
regex = "1.3"
semver = "0.11"
[package.metadata.docs.rs]
rustc-args = ["--cfg", "napidocsrs"]

View file

@ -1,125 +0,0 @@
extern crate bindgen;
extern crate glob;
extern crate semver;
#[cfg(target_os = "windows")]
extern crate tar;
use glob::glob;
use std::env;
use std::path::PathBuf;
use std::process::Command;
#[cfg(not(any(target_os = "windows", napidocsrs)))]
const NODE_PRINT_EXEC_PATH: &'static str = "console.log(process.execPath)";
fn main() {
let node_full_version =
String::from_utf8(Command::new("node").arg("-v").output().unwrap().stdout).unwrap();
let node_version = semver::Version::parse(node_full_version.as_str().get(1..).unwrap()).unwrap();
let node_major_version = node_version.major;
println!("cargo:rerun-if-env-changed=NODE_INCLUDE_PATH");
for entry in glob("./src/**/*.*").unwrap() {
println!(
"cargo:rerun-if-changed={}",
entry.unwrap().to_str().unwrap()
);
}
if node_major_version < 8 && node_version.minor < 9 {
panic!("node version is too low")
}
let node_include_path_buf = find_node_include_path(node_full_version.trim_end());
let node_include_path = match env::var("NODE_INCLUDE_PATH") {
Ok(node_include_path) => node_include_path,
Err(_) => node_include_path_buf.to_str().unwrap().to_owned(),
};
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
let mut sys_bindings_path = PathBuf::from("src");
sys_bindings_path.push("bindings.h");
let mut bindgen_builder = bindgen::Builder::default()
.derive_default(true)
.header(sys_bindings_path.to_str().unwrap().to_owned())
.clang_arg(format!("-I{}", node_include_path))
.clang_arg("-target")
.clang_arg(env::var("TARGET").unwrap());
if let Ok(uv_include_path) = env::var("NAPI_RS_INCLUDE_PATH") {
bindgen_builder = bindgen_builder.clang_arg(format!("-I{}", uv_include_path));
}
if cfg!(target_os = "freebsd") {
bindgen_builder = bindgen_builder.clang_arg(format!(
"-I{}",
node_include_path_buf.parent().unwrap().to_str().unwrap()
));
}
bindgen_builder
.newtype_enum("(napi_|uv_).+")
.whitelist_function("(napi_|uv_|extras_).+")
.whitelist_type("(napi_|uv_|extras_).+")
.generate()
.expect("Unable to generate napi bindings")
.write_to_file(out_path.join("bindings.rs"))
.expect("Unable to write napi bindings");
}
#[cfg(all(target_os = "windows", not(napidocsrs)))]
fn find_node_include_path(node_full_version: &str) -> PathBuf {
let mut out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
out_path.push(format!("node-headers-{}.tar.gz", node_full_version));
let mut header_dist_path = PathBuf::from(&PathBuf::from(&out_path).parent().unwrap());
let unpack_path = PathBuf::from(&header_dist_path);
header_dist_path.push(format!("node-{}", node_full_version));
header_dist_path.push("include");
header_dist_path.push("node");
if !header_dist_path.exists() {
let script = r#"require('https').get(process.release.headersUrl, function (res) {
res.pipe(require('zlib').createUnzip()).pipe(process.stdout)
})"#;
let tar_binary = Command::new("node")
.arg("-e")
.arg(script)
.output()
.expect("Download headers file failed")
.stdout;
tar::Archive::new(tar_binary.as_slice())
.unpack(&unpack_path)
.expect("Unpack headers file failed");
};
header_dist_path
}
#[cfg(napidocsrs)]
fn find_node_include_path(_node_full_version: &str) -> PathBuf {
let mut current = env::current_dir().unwrap();
current.push(".node-headers");
current
}
#[cfg(not(any(target_os = "windows", napidocsrs)))]
fn find_node_include_path(_node_full_version: &str) -> PathBuf {
let node_exec_path = String::from_utf8(
Command::new("node")
.arg("-e")
.arg(NODE_PRINT_EXEC_PATH)
.output()
.unwrap()
.stdout,
)
.unwrap();
PathBuf::from(node_exec_path)
.parent()
.unwrap()
.parent()
.unwrap()
.join("include/node")
}

View file

@ -1,2 +0,0 @@
#include <node_api.h>
#include <uv.h>

File diff suppressed because it is too large Load diff

View file

@ -1,6 +0,0 @@
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(dead_code)]
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));

View file

@ -7,9 +7,13 @@ version = "0.1.0"
[lib] [lib]
crate-type = ["cdylib"] crate-type = ["cdylib"]
[features]
latest = ["napi/napi7"]
napi3 = ["napi/napi3"]
[dependencies] [dependencies]
futures = "0.3" futures = "0.3"
napi = {path = "../napi", features = ["libuv", "tokio_rt", "serde-json", "latin1"]} napi = {path = "../napi", features = ["tokio_rt", "serde-json", "latin1"]}
napi-derive = {path = "../napi-derive"} napi-derive = {path = "../napi-derive"}
serde = "1" serde = "1"
serde_bytes = "0.11" serde_bytes = "0.11"

View file

@ -1,45 +0,0 @@
import { readFileSync } from 'fs'
import { join, resolve } from 'path'
import test from 'ava'
import { napiVersion } from '../napi-version'
const bindings = require('../../index.node')
let threadMod: any
try {
threadMod = require('worker_threads')
} catch (err) {
//
}
const filepath = join(__dirname, './example.txt')
test('should execute future on libuv thread pool', async (t) => {
if (napiVersion < 4) {
t.is(bindings.uvReadFile, undefined)
return
}
const fileContent = await bindings.uvReadFile(filepath)
t.true(Buffer.isBuffer(fileContent))
t.deepEqual(readFileSync(filepath), fileContent)
})
if (threadMod && napiVersion >= 4) {
test('should execute future on libuv thread pool of "Worker"', async (t) => {
// Test in threads if current Node.js supports "worker_threads".`
const { Worker } = threadMod
const script = resolve(__dirname, './uv_worker.js')
const worker = new Worker(script)
const success = await new Promise((resolve) => {
worker.on('message', (success: boolean) => {
resolve(success)
})
})
t.is(success, true)
})
}

View file

@ -1,19 +0,0 @@
const { readFileSync } = require('fs')
const { join } = require('path')
const { isMainThread, parentPort } = require('worker_threads')
const bindings = require('../../index.node')
const filepath = join(__dirname, './example.txt')
if (!isMainThread) {
;(async () => {
const fileContent = await bindings.uvReadFile(filepath)
const success =
Buffer.isBuffer(fileContent) &&
readFileSync(filepath).toString('utf8') === fileContent.toString('utf8')
parentPort.postMessage(success)
})().catch((e) => {
throw e
})
}

View file

@ -2,9 +2,11 @@
"name": "test-module", "name": "test-module",
"version": "1.0.0", "version": "1.0.0",
"scripts": { "scripts": {
"build": "cargo build && node ../scripts/index.js build", "build": "cargo build --features \"latest\" && node ../scripts/index.js build",
"build-aarch64": "cargo build --target aarch64-unknown-linux-gnu && node ../scripts/index.js build --target-triple aarch64-unknown-linux-gnu", "build-napi3": "cargo build --features \"napi3\" && node ../scripts/index.js build",
"build-release": "cargo build --release && node ../scripts/index.js build --release", "build-aarch64": "cargo build --features \"latest\" --target aarch64-unknown-linux-gnu && node ../scripts/index.js build --target-triple aarch64-unknown-linux-gnu",
"build-i686": "cargo build --features \"latest\" --target i686-pc-windows-msvc && node ../scripts/index.js build --target-triple i686-pc-windows-msvc",
"build-release": "cargo build --features \"latest\" --release && node ../scripts/index.js build --release",
"test": "node ./index.js" "test": "node ./index.js"
} }
} }

View file

@ -7,17 +7,14 @@ extern crate serde_derive;
use napi::{Module, Result}; use napi::{Module, Result};
#[cfg(napi3)]
mod cleanup_env; mod cleanup_env;
#[cfg(napi4)] #[cfg(feature = "latest")]
mod libuv;
#[cfg(napi4)]
mod napi4; mod napi4;
#[cfg(napi5)] #[cfg(feature = "latest")]
mod napi5; mod napi5;
#[cfg(napi6)] #[cfg(feature = "latest")]
mod napi6; mod napi6;
#[cfg(napi4)] #[cfg(feature = "latest")]
mod tokio_rt; mod tokio_rt;
mod array; mod array;
@ -58,17 +55,14 @@ fn init(module: &mut Module) -> Result<()> {
env::register_js(module)?; env::register_js(module)?;
object::register_js(module)?; object::register_js(module)?;
global::register_js(module)?; global::register_js(module)?;
#[cfg(napi3)]
cleanup_env::register_js(module)?; cleanup_env::register_js(module)?;
#[cfg(napi4)] #[cfg(feature = "latest")]
napi4::register_js(module)?; napi4::register_js(module)?;
#[cfg(napi4)] #[cfg(feature = "latest")]
tokio_rt::register_js(module)?; tokio_rt::register_js(module)?;
#[cfg(napi4)] #[cfg(feature = "latest")]
libuv::read_file::register_js(module)?;
#[cfg(napi5)]
napi5::register_js(module)?; napi5::register_js(module)?;
#[cfg(napi6)] #[cfg(feature = "latest")]
napi6::register_js(module)?; napi6::register_js(module)?;
Ok(()) Ok(())
} }

View file

@ -1 +0,0 @@
pub mod read_file;

View file

@ -1,28 +0,0 @@
use std::fs;
use std::thread;
use futures::channel::oneshot;
use futures::prelude::*;
use napi::{CallContext, Error, JsObject, JsString, Module, Result, Status};
#[js_function(1)]
pub fn uv_read_file(ctx: CallContext) -> Result<JsObject> {
let path = ctx.get::<JsString>(0)?;
let (sender, receiver) = oneshot::channel();
let p = path.into_utf8()?.to_owned()?;
thread::spawn(|| {
let res = fs::read(p).map_err(|e| Error::new(Status::Unknown, format!("{}", e)));
sender.send(res).expect("Send data failed");
});
ctx.env.execute(
receiver
.map_err(|e| Error::new(Status::Unknown, format!("{}", e)))
.map(|x| x.and_then(|x| x)),
|&mut env, data| env.create_buffer_with_data(data).map(|v| v.into_raw()),
)
}
pub fn register_js(module: &mut Module) -> Result<()> {
module.create_named_method("uvReadFile", uv_read_file)?;
Ok(())
}