feat: export registers in wasm32 target (#1529)
This commit is contained in:
parent
5605bdf7fc
commit
550ef7c3cc
21 changed files with 278 additions and 131 deletions
27
.github/workflows/check-all-features.yml
vendored
27
.github/workflows/check-all-features.yml
vendored
|
@ -15,21 +15,11 @@ jobs:
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
features:
|
settings:
|
||||||
[
|
- features: 'napi1,napi2,napi3,napi4,napi5,napi6,napi7,napi8,experimental,async,chrono_date,latin1,full'
|
||||||
'napi3',
|
package: 'napi'
|
||||||
'napi4',
|
- features: 'compat-mode,strict,type-def,noop,full,default'
|
||||||
'napi5',
|
package: 'napi-derive'
|
||||||
'napi6',
|
|
||||||
'napi7',
|
|
||||||
'napi8',
|
|
||||||
'experimental',
|
|
||||||
'async',
|
|
||||||
'chrono_date',
|
|
||||||
'latin1',
|
|
||||||
'full',
|
|
||||||
]
|
|
||||||
|
|
||||||
name: stable - ubuntu-latest
|
name: stable - ubuntu-latest
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
@ -47,10 +37,7 @@ jobs:
|
||||||
path: |
|
path: |
|
||||||
~/.cargo/registry
|
~/.cargo/registry
|
||||||
~/.cargo/git
|
~/.cargo/git
|
||||||
key: stable-check-ubuntu-latest-cargo-cache-features-${{ matrix.features }}
|
key: stable-check-ubuntu-latest-cargo-cache-features-${{ matrix.settings.package }}-${{ matrix.features }}
|
||||||
|
|
||||||
- name: Check build
|
- name: Check build
|
||||||
uses: actions-rs/cargo@v1
|
run: cargo check -p ${{ matrix.settings.package }} -F ${{ matrix.settings.features }}
|
||||||
with:
|
|
||||||
command: check
|
|
||||||
args: -p napi --no-default-features --features ${{ matrix.features }}
|
|
||||||
|
|
|
@ -311,10 +311,6 @@ export class BuildCommand extends Command {
|
||||||
rustflags.push('-C link-arg=-s')
|
rustflags.push('-C link-arg=-s')
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rustflags.length > 0) {
|
|
||||||
additionalEnv['RUSTFLAGS'] = rustflags.join(' ')
|
|
||||||
}
|
|
||||||
|
|
||||||
let useZig = false
|
let useZig = false
|
||||||
if (this.useZig || isCrossForLinux || isCrossForMacOS) {
|
if (this.useZig || isCrossForLinux || isCrossForMacOS) {
|
||||||
try {
|
try {
|
||||||
|
@ -452,6 +448,22 @@ export class BuildCommand extends Command {
|
||||||
tsConstEnum: tsConstEnumFromConfig,
|
tsConstEnum: tsConstEnumFromConfig,
|
||||||
} = getNapiConfig(this.configFileName)
|
} = getNapiConfig(this.configFileName)
|
||||||
const tsConstEnum = this.constEnum ?? tsConstEnumFromConfig
|
const tsConstEnum = this.constEnum ?? tsConstEnumFromConfig
|
||||||
|
if (triple.platform === 'wasi') {
|
||||||
|
try {
|
||||||
|
const emnapiDir = require.resolve('emnapi')
|
||||||
|
const linkDir = join(emnapiDir, '..', 'lib', 'wasm32-wasi')
|
||||||
|
additionalEnv['EMNAPI_LINK_DIR'] = linkDir
|
||||||
|
rustflags.push('-Z wasi-exec-model=reactor')
|
||||||
|
} catch (e) {
|
||||||
|
const err = new Error(`Could not find emnapi, please install emnapi`)
|
||||||
|
err.cause = e
|
||||||
|
throw err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (rustflags.length > 0) {
|
||||||
|
additionalEnv['RUSTFLAGS'] = rustflags.join(' ')
|
||||||
|
}
|
||||||
|
|
||||||
let cargoArtifactName = this.cargoName
|
let cargoArtifactName = this.cargoName
|
||||||
if (!cargoArtifactName) {
|
if (!cargoArtifactName) {
|
||||||
if (this.bin) {
|
if (this.bin) {
|
||||||
|
@ -479,23 +491,30 @@ export class BuildCommand extends Command {
|
||||||
} else {
|
} else {
|
||||||
debug(`Dylib name: ${chalk.greenBright(cargoArtifactName)}`)
|
debug(`Dylib name: ${chalk.greenBright(cargoArtifactName)}`)
|
||||||
}
|
}
|
||||||
|
const cwdSha = createHash('sha256')
|
||||||
const intermediateTypeFile = join(
|
|
||||||
tmpdir(),
|
|
||||||
`${cargoArtifactName}-${createHash('sha256')
|
|
||||||
.update(process.cwd())
|
.update(process.cwd())
|
||||||
.digest('hex')
|
.digest('hex')
|
||||||
.substring(0, 8)}.napi_type_def.tmp`,
|
.substring(0, 8)
|
||||||
|
const intermediateTypeFile = join(
|
||||||
|
tmpdir(),
|
||||||
|
`${cargoArtifactName}-${cwdSha}.napi_type_def.tmp`,
|
||||||
|
)
|
||||||
|
const intermediateWasiRegisterFile = join(
|
||||||
|
tmpdir(),
|
||||||
|
`${cargoArtifactName}-${cwdSha}.napi_wasi_register.tmp`,
|
||||||
)
|
)
|
||||||
debug(`intermediate type def file: ${intermediateTypeFile}`)
|
debug(`intermediate type def file: ${intermediateTypeFile}`)
|
||||||
|
|
||||||
try {
|
const commandEnv = {
|
||||||
execSync(cargoCommand, {
|
|
||||||
env: {
|
|
||||||
...process.env,
|
...process.env,
|
||||||
...additionalEnv,
|
...additionalEnv,
|
||||||
TYPE_DEF_TMP_PATH: intermediateTypeFile,
|
TYPE_DEF_TMP_PATH: intermediateTypeFile,
|
||||||
},
|
WASI_REGISTER_TMP_PATH: intermediateWasiRegisterFile,
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
execSync(cargoCommand, {
|
||||||
|
env: commandEnv,
|
||||||
stdio: 'inherit',
|
stdio: 'inherit',
|
||||||
cwd,
|
cwd,
|
||||||
})
|
})
|
||||||
|
@ -606,18 +625,6 @@ export class BuildCommand extends Command {
|
||||||
this.dts ?? 'index.d.ts',
|
this.dts ?? 'index.d.ts',
|
||||||
)
|
)
|
||||||
|
|
||||||
if (this.pipe) {
|
|
||||||
const pipeCommand = `${this.pipe} ${dtsFilePath}`
|
|
||||||
console.info(`Run ${chalk.green(pipeCommand)}`)
|
|
||||||
try {
|
|
||||||
execSync(pipeCommand, { stdio: 'inherit', env: process.env })
|
|
||||||
} catch (e) {
|
|
||||||
console.warn(
|
|
||||||
chalk.bgYellowBright('Pipe the dts file to command failed'),
|
|
||||||
e,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const jsBindingFilePath =
|
const jsBindingFilePath =
|
||||||
this.jsBinding &&
|
this.jsBinding &&
|
||||||
this.jsBinding !== 'false' &&
|
this.jsBinding !== 'false' &&
|
||||||
|
@ -640,7 +647,7 @@ export class BuildCommand extends Command {
|
||||||
const pipeCommand = `${this.pipe} ${jsBindingFilePath}`
|
const pipeCommand = `${this.pipe} ${jsBindingFilePath}`
|
||||||
console.info(`Run ${chalk.green(pipeCommand)}`)
|
console.info(`Run ${chalk.green(pipeCommand)}`)
|
||||||
try {
|
try {
|
||||||
execSync(pipeCommand, { stdio: 'inherit', env: process.env })
|
execSync(pipeCommand, { stdio: 'inherit', env: commandEnv })
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.warn(
|
console.warn(
|
||||||
chalk.bgYellowBright('Pipe the js binding file to command failed'),
|
chalk.bgYellowBright('Pipe the js binding file to command failed'),
|
||||||
|
|
|
@ -1,7 +1,13 @@
|
||||||
export const createJsBinding = (
|
export const createJsBinding = (
|
||||||
localName: string,
|
localName: string,
|
||||||
pkgName: string,
|
pkgName: string,
|
||||||
) => `const { existsSync, readFileSync } = require('fs')
|
) => `/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
/* prettier-ignore */
|
||||||
|
|
||||||
|
/* auto-generated by NAPI-RS */
|
||||||
|
|
||||||
|
const { existsSync, readFileSync } = require('fs')
|
||||||
const { join } = require('path')
|
const { join } = require('path')
|
||||||
|
|
||||||
const { platform, arch } = process
|
const { platform, arch } = process
|
||||||
|
|
|
@ -10,10 +10,10 @@ import { debugFactory } from '../debug'
|
||||||
import { DefaultPlatforms } from '../parse-triple'
|
import { DefaultPlatforms } from '../parse-triple'
|
||||||
import { spawn } from '../spawn'
|
import { spawn } from '../spawn'
|
||||||
|
|
||||||
import { GitIgnore } from './.gitignore-template'
|
|
||||||
import { createCargoContent } from './cargo'
|
import { createCargoContent } from './cargo'
|
||||||
import { createCargoConfig } from './cargo-config'
|
import { createCargoConfig } from './cargo-config'
|
||||||
import { createGithubActionsCIYml } from './ci-yml'
|
import { createGithubActionsCIYml } from './ci-yml'
|
||||||
|
import { GitIgnore } from './gitignore-template'
|
||||||
import { LibRs } from './lib-rs'
|
import { LibRs } from './lib-rs'
|
||||||
import { NPMIgnoreFiles } from './npmignore'
|
import { NPMIgnoreFiles } from './npmignore'
|
||||||
import { createPackageJson } from './package'
|
import { createPackageJson } from './package'
|
||||||
|
|
|
@ -14,6 +14,7 @@ type NodeJSArch =
|
||||||
| 'x32'
|
| 'x32'
|
||||||
| 'x64'
|
| 'x64'
|
||||||
| 'universal'
|
| 'universal'
|
||||||
|
| 'wasm32'
|
||||||
|
|
||||||
const CpuToNodeArch: { [index: string]: NodeJSArch } = {
|
const CpuToNodeArch: { [index: string]: NodeJSArch } = {
|
||||||
x86_64: 'x64',
|
x86_64: 'x64',
|
||||||
|
@ -41,7 +42,7 @@ export const UniArchsByPlatform: Record<string, NodeJSArch[]> = {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PlatformDetail {
|
export interface PlatformDetail {
|
||||||
platform: NodeJS.Platform
|
platform: NodeJS.Platform | 'wasi'
|
||||||
platformArchABI: string
|
platformArchABI: string
|
||||||
arch: NodeJSArch
|
arch: NodeJSArch
|
||||||
raw: string
|
raw: string
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use std::sync::atomic::AtomicUsize;
|
||||||
|
|
||||||
use proc_macro2::{Ident, Span, TokenStream};
|
use proc_macro2::{Ident, Span, TokenStream};
|
||||||
|
|
||||||
use crate::BindgenResult;
|
use crate::BindgenResult;
|
||||||
|
@ -12,6 +14,12 @@ pub const PROPERTY_ATTRIBUTE_WRITABLE: i32 = 1 << 0;
|
||||||
pub const PROPERTY_ATTRIBUTE_ENUMERABLE: i32 = 1 << 1;
|
pub const PROPERTY_ATTRIBUTE_ENUMERABLE: i32 = 1 << 1;
|
||||||
pub const PROPERTY_ATTRIBUTE_CONFIGURABLE: i32 = 1 << 2;
|
pub const PROPERTY_ATTRIBUTE_CONFIGURABLE: i32 = 1 << 2;
|
||||||
|
|
||||||
|
static REGISTER_INDEX: AtomicUsize = AtomicUsize::new(0);
|
||||||
|
|
||||||
|
thread_local! {
|
||||||
|
pub static REGISTER_IDENTS: std::cell::RefCell<Vec<String>> = std::cell::RefCell::new(Vec::new());
|
||||||
|
}
|
||||||
|
|
||||||
pub trait TryToTokens {
|
pub trait TryToTokens {
|
||||||
fn try_to_tokens(&self, tokens: &mut TokenStream) -> BindgenResult<()>;
|
fn try_to_tokens(&self, tokens: &mut TokenStream) -> BindgenResult<()>;
|
||||||
|
|
||||||
|
@ -29,7 +37,11 @@ fn get_intermediate_ident(name: &str) -> Ident {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_register_ident(name: &str) -> Ident {
|
fn get_register_ident(name: &str) -> Ident {
|
||||||
let new_name = format!("__napi_register__{}", name);
|
let new_name = format!(
|
||||||
|
"__napi_register__{}_{}",
|
||||||
|
name,
|
||||||
|
REGISTER_INDEX.fetch_add(1, std::sync::atomic::Ordering::Relaxed)
|
||||||
|
);
|
||||||
Ident::new(&new_name, Span::call_site())
|
Ident::new(&new_name, Span::call_site())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,9 @@ impl NapiConst {
|
||||||
self.name.span(),
|
self.name.span(),
|
||||||
);
|
);
|
||||||
let js_mod_ident = js_mod_to_token_stream(self.js_mod.as_ref());
|
let js_mod_ident = js_mod_to_token_stream(self.js_mod.as_ref());
|
||||||
|
crate::codegen::REGISTER_IDENTS.with(|c| {
|
||||||
|
c.borrow_mut().push(register_name.to_string());
|
||||||
|
});
|
||||||
quote! {
|
quote! {
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
#[allow(clippy::all)]
|
#[allow(clippy::all)]
|
||||||
|
@ -38,11 +41,19 @@ impl NapiConst {
|
||||||
}
|
}
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
#[allow(clippy::all)]
|
#[allow(clippy::all)]
|
||||||
#[cfg(all(not(test), not(feature = "noop")))]
|
#[cfg(all(not(test), not(feature = "noop"), not(target_arch = "wasm32")))]
|
||||||
#[napi::bindgen_prelude::ctor]
|
#[napi::bindgen_prelude::ctor]
|
||||||
fn #register_name() {
|
fn #register_name() {
|
||||||
napi::bindgen_prelude::register_module_export(#js_mod_ident, #js_name_lit, #cb_name);
|
napi::bindgen_prelude::register_module_export(#js_mod_ident, #js_name_lit, #cb_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
#[allow(clippy::all)]
|
||||||
|
#[cfg(all(not(test), not(feature = "noop"), target_arch = "wasm32"))]
|
||||||
|
#[no_mangle]
|
||||||
|
unsafe extern "C" fn #register_name() {
|
||||||
|
napi::bindgen_prelude::register_module_export(#js_mod_ident, #js_name_lit, #cb_name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -130,6 +130,10 @@ impl NapiEnum {
|
||||||
|
|
||||||
let js_mod_ident = js_mod_to_token_stream(self.js_mod.as_ref());
|
let js_mod_ident = js_mod_to_token_stream(self.js_mod.as_ref());
|
||||||
|
|
||||||
|
crate::codegen::REGISTER_IDENTS.with(|c| {
|
||||||
|
c.borrow_mut().push(register_name.to_string());
|
||||||
|
});
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
#[allow(clippy::all)]
|
#[allow(clippy::all)]
|
||||||
|
@ -150,11 +154,18 @@ impl NapiEnum {
|
||||||
}
|
}
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
#[allow(clippy::all)]
|
#[allow(clippy::all)]
|
||||||
#[cfg(all(not(test), not(feature = "noop")))]
|
#[cfg(all(not(test), not(feature = "noop"), not(target_arch = "wasm32")))]
|
||||||
#[napi::bindgen_prelude::ctor]
|
#[napi::bindgen_prelude::ctor]
|
||||||
fn #register_name() {
|
fn #register_name() {
|
||||||
napi::bindgen_prelude::register_module_export(#js_mod_ident, #js_name_lit, #callback_name);
|
napi::bindgen_prelude::register_module_export(#js_mod_ident, #js_name_lit, #callback_name);
|
||||||
}
|
}
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
#[allow(clippy::all)]
|
||||||
|
#[cfg(all(not(test), not(feature = "noop"), target_arch = "wasm32"))]
|
||||||
|
#[no_mangle]
|
||||||
|
extern "C" fn #register_name() {
|
||||||
|
napi::bindgen_prelude::register_module_export(#js_mod_ident, #js_name_lit, #callback_name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -474,7 +474,7 @@ impl NapiFn {
|
||||||
match self.fn_self {
|
match self.fn_self {
|
||||||
Some(FnSelf::Value) => {
|
Some(FnSelf::Value) => {
|
||||||
// impossible, panic! in parser
|
// impossible, panic! in parser
|
||||||
unimplemented!();
|
unreachable!();
|
||||||
}
|
}
|
||||||
Some(FnSelf::Ref) | Some(FnSelf::MutRef) => quote! { this.#name },
|
Some(FnSelf::Ref) | Some(FnSelf::MutRef) => quote! { this.#name },
|
||||||
None => match &self.parent {
|
None => match &self.parent {
|
||||||
|
@ -552,11 +552,14 @@ impl NapiFn {
|
||||||
} else {
|
} else {
|
||||||
let name_str = self.name.to_string();
|
let name_str = self.name.to_string();
|
||||||
let js_name = format!("{}\0", &self.js_name);
|
let js_name = format!("{}\0", &self.js_name);
|
||||||
let name_len = js_name.len();
|
let name_len = self.js_name.len();
|
||||||
let module_register_name = get_register_ident(&name_str);
|
let module_register_name = get_register_ident(&name_str);
|
||||||
let intermediate_ident = get_intermediate_ident(&name_str);
|
let intermediate_ident = get_intermediate_ident(&name_str);
|
||||||
let js_mod_ident = js_mod_to_token_stream(self.js_mod.as_ref());
|
let js_mod_ident = js_mod_to_token_stream(self.js_mod.as_ref());
|
||||||
let cb_name = Ident::new(&format!("{}_js_function", name_str), Span::call_site());
|
let cb_name = Ident::new(&format!("{}_js_function", name_str), Span::call_site());
|
||||||
|
crate::codegen::REGISTER_IDENTS.with(|c| {
|
||||||
|
c.borrow_mut().push(module_register_name.to_string());
|
||||||
|
});
|
||||||
quote! {
|
quote! {
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
#[allow(clippy::all)]
|
#[allow(clippy::all)]
|
||||||
|
@ -566,7 +569,7 @@ impl NapiFn {
|
||||||
napi::bindgen_prelude::check_status!(
|
napi::bindgen_prelude::check_status!(
|
||||||
napi::bindgen_prelude::sys::napi_create_function(
|
napi::bindgen_prelude::sys::napi_create_function(
|
||||||
env,
|
env,
|
||||||
#js_name.as_ptr() as *const _,
|
#js_name.as_ptr().cast(),
|
||||||
#name_len,
|
#name_len,
|
||||||
Some(#intermediate_ident),
|
Some(#intermediate_ident),
|
||||||
std::ptr::null_mut(),
|
std::ptr::null_mut(),
|
||||||
|
@ -581,11 +584,19 @@ impl NapiFn {
|
||||||
|
|
||||||
#[allow(clippy::all)]
|
#[allow(clippy::all)]
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
#[cfg(all(not(test), not(feature = "noop")))]
|
#[cfg(all(not(test), not(feature = "noop"), not(target_arch = "wasm32")))]
|
||||||
#[napi::bindgen_prelude::ctor]
|
#[napi::bindgen_prelude::ctor]
|
||||||
fn #module_register_name() {
|
fn #module_register_name() {
|
||||||
napi::bindgen_prelude::register_module_export(#js_mod_ident, #js_name, #cb_name);
|
napi::bindgen_prelude::register_module_export(#js_mod_ident, #js_name, #cb_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::all)]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
#[cfg(all(not(test), not(feature = "noop"), target_arch = "wasm32"))]
|
||||||
|
#[no_mangle]
|
||||||
|
extern "C" fn #module_register_name() {
|
||||||
|
napi::bindgen_prelude::register_module_export(#js_mod_ident, #js_name, #cb_name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -760,14 +760,25 @@ impl NapiStruct {
|
||||||
props.push(prop);
|
props.push(prop);
|
||||||
}
|
}
|
||||||
let js_mod_ident = js_mod_to_token_stream(self.js_mod.as_ref());
|
let js_mod_ident = js_mod_to_token_stream(self.js_mod.as_ref());
|
||||||
|
crate::codegen::REGISTER_IDENTS.with(|c| {
|
||||||
|
c.borrow_mut().push(struct_register_name.to_string());
|
||||||
|
});
|
||||||
quote! {
|
quote! {
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
#[allow(clippy::all)]
|
#[allow(clippy::all)]
|
||||||
#[cfg(all(not(test), not(feature = "noop")))]
|
#[cfg(all(not(test), not(feature = "noop"), not(target_arch = "wasm32")))]
|
||||||
#[napi::bindgen_prelude::ctor]
|
#[napi::bindgen_prelude::ctor]
|
||||||
fn #struct_register_name() {
|
fn #struct_register_name() {
|
||||||
napi::__private::register_class(#name_str, #js_mod_ident, #js_name, vec![#(#props),*]);
|
napi::__private::register_class(#name_str, #js_mod_ident, #js_name, vec![#(#props),*]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
#[allow(clippy::all)]
|
||||||
|
#[cfg(all(not(test), not(feature = "noop"), target_arch = "wasm32"))]
|
||||||
|
#[no_mangle]
|
||||||
|
extern "C" fn #struct_register_name() {
|
||||||
|
napi::__private::register_class(#name_str, #js_mod_ident, #js_name, vec![#(#props),*]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -866,7 +877,11 @@ impl NapiImpl {
|
||||||
let mut props: Vec<_> = props.into_iter().collect();
|
let mut props: Vec<_> = props.into_iter().collect();
|
||||||
props.sort_by_key(|(_, prop)| prop.to_string());
|
props.sort_by_key(|(_, prop)| prop.to_string());
|
||||||
let props = props.into_iter().map(|(_, prop)| prop);
|
let props = props.into_iter().map(|(_, prop)| prop);
|
||||||
|
let props_wasm = props.clone();
|
||||||
let js_mod_ident = js_mod_to_token_stream(self.js_mod.as_ref());
|
let js_mod_ident = js_mod_to_token_stream(self.js_mod.as_ref());
|
||||||
|
crate::codegen::REGISTER_IDENTS.with(|c| {
|
||||||
|
c.borrow_mut().push(register_name.to_string());
|
||||||
|
});
|
||||||
Ok(quote! {
|
Ok(quote! {
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
#[allow(clippy::all)]
|
#[allow(clippy::all)]
|
||||||
|
@ -874,11 +889,17 @@ impl NapiImpl {
|
||||||
use super::*;
|
use super::*;
|
||||||
#(#methods)*
|
#(#methods)*
|
||||||
|
|
||||||
#[cfg(all(not(test), not(feature = "noop")))]
|
#[cfg(all(not(test), not(feature = "noop"), not(target_arch = "wasm32")))]
|
||||||
#[napi::bindgen_prelude::ctor]
|
#[napi::bindgen_prelude::ctor]
|
||||||
fn #register_name() {
|
fn #register_name() {
|
||||||
napi::__private::register_class(#name_str, #js_mod_ident, #js_name, vec![#(#props),*]);
|
napi::__private::register_class(#name_str, #js_mod_ident, #js_name, vec![#(#props),*]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(all(not(test), not(feature = "noop"), target_arch = "wasm32"))]
|
||||||
|
#[no_mangle]
|
||||||
|
extern "C" fn #register_name() {
|
||||||
|
napi::__private::register_class(#name_str, #js_mod_ident, #js_name, vec![#(#props_wasm),*]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,16 +11,20 @@ extern crate quote;
|
||||||
|
|
||||||
#[cfg(not(feature = "noop"))]
|
#[cfg(not(feature = "noop"))]
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
#[cfg(not(feature = "noop"))]
|
||||||
|
use std::fs;
|
||||||
|
#[cfg(not(feature = "noop"))]
|
||||||
|
use std::io::Write;
|
||||||
#[cfg(all(feature = "type-def", not(feature = "noop")))]
|
#[cfg(all(feature = "type-def", not(feature = "noop")))]
|
||||||
use std::{
|
use std::io::{BufWriter, Result as IOResult};
|
||||||
fs,
|
#[cfg(not(feature = "noop"))]
|
||||||
io::{BufWriter, Result as IOResult, Write},
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
};
|
|
||||||
|
|
||||||
use napi_derive_backend::BindgenResult;
|
use napi_derive_backend::BindgenResult;
|
||||||
#[cfg(not(feature = "noop"))]
|
#[cfg(not(feature = "noop"))]
|
||||||
use napi_derive_backend::TryToTokens;
|
use napi_derive_backend::TryToTokens;
|
||||||
|
#[cfg(not(feature = "noop"))]
|
||||||
|
use napi_derive_backend::REGISTER_IDENTS;
|
||||||
#[cfg(all(feature = "type-def", not(feature = "noop")))]
|
#[cfg(all(feature = "type-def", not(feature = "noop")))]
|
||||||
use napi_derive_backend::{ToTypeDef, TypeDef};
|
use napi_derive_backend::{ToTypeDef, TypeDef};
|
||||||
#[cfg(not(feature = "noop"))]
|
#[cfg(not(feature = "noop"))]
|
||||||
|
@ -36,6 +40,7 @@ use syn::Item;
|
||||||
#[cfg(feature = "compat-mode")]
|
#[cfg(feature = "compat-mode")]
|
||||||
use syn::{fold::Fold, parse_macro_input, ItemFn};
|
use syn::{fold::Fold, parse_macro_input, ItemFn};
|
||||||
|
|
||||||
|
#[cfg(not(feature = "noop"))]
|
||||||
/// a flag indicate whether or never at least one `napi` macro has been expanded.
|
/// a flag indicate whether or never at least one `napi` macro has been expanded.
|
||||||
/// ```ignore
|
/// ```ignore
|
||||||
/// if BUILT_FLAG
|
/// if BUILT_FLAG
|
||||||
|
@ -64,8 +69,18 @@ pub fn napi(attr: RawStream, input: RawStream) -> RawStream {
|
||||||
#[cfg(feature = "type-def")]
|
#[cfg(feature = "type-def")]
|
||||||
if let Ok(type_def_file) = env::var("TYPE_DEF_TMP_PATH") {
|
if let Ok(type_def_file) = env::var("TYPE_DEF_TMP_PATH") {
|
||||||
if let Err(_e) = fs::remove_file(type_def_file) {
|
if let Err(_e) = fs::remove_file(type_def_file) {
|
||||||
// should only input in debug mode
|
#[cfg(debug_assertions)]
|
||||||
// println!("Failed to manipulate type def file: {:?}", e);
|
{
|
||||||
|
println!("Failed to manipulate type def file: {:?}", _e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Ok(wasi_register_file) = env::var("WASI_REGISTER_TMP_PATH") {
|
||||||
|
if let Err(_e) = fs::remove_file(wasi_register_file) {
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
{
|
||||||
|
println!("Failed to manipulate wasi register file: {:?}", _e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -75,6 +90,15 @@ pub fn napi(attr: RawStream, input: RawStream) -> RawStream {
|
||||||
if env::var("DEBUG_GENERATED_CODE").is_ok() {
|
if env::var("DEBUG_GENERATED_CODE").is_ok() {
|
||||||
println!("{}", tokens);
|
println!("{}", tokens);
|
||||||
}
|
}
|
||||||
|
REGISTER_IDENTS.with(|idents| {
|
||||||
|
if let Ok(wasi_register_file) = env::var("WASI_REGISTER_TMP_PATH") {
|
||||||
|
let mut file =
|
||||||
|
fs::File::create(wasi_register_file).expect("Create wasi register file failed");
|
||||||
|
file
|
||||||
|
.write_all(format!("{:?}", idents.borrow()).as_bytes())
|
||||||
|
.expect("Write wasi register file failed");
|
||||||
|
}
|
||||||
|
});
|
||||||
tokens.into()
|
tokens.into()
|
||||||
}
|
}
|
||||||
Err(diagnostic) => {
|
Err(diagnostic) => {
|
||||||
|
@ -338,7 +362,7 @@ pub fn module_exports(_attr: RawStream, input: RawStream) -> RawStream {
|
||||||
};
|
};
|
||||||
|
|
||||||
let register = quote! {
|
let register = quote! {
|
||||||
#[napi::bindgen_prelude::ctor]
|
#[cfg_attr(not(target_arch = "wasm32"), napi::bindgen_prelude::ctor)]
|
||||||
fn __napi__explicit_module_register() {
|
fn __napi__explicit_module_register() {
|
||||||
unsafe fn register(raw_env: napi::sys::napi_env, raw_exports: napi::sys::napi_value) -> napi::Result<()> {
|
unsafe fn register(raw_env: napi::sys::napi_env, raw_exports: napi::sys::napi_value) -> napi::Result<()> {
|
||||||
use napi::{Env, JsObject, NapiValue};
|
use napi::{Env, JsObject, NapiValue};
|
||||||
|
|
|
@ -69,10 +69,16 @@ version = "0.8"
|
||||||
optional = true
|
optional = true
|
||||||
version = "0.4"
|
version = "0.4"
|
||||||
|
|
||||||
[dependencies.tokio]
|
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||||
features = ["rt", "rt-multi-thread", "sync"]
|
tokio = { version = "1", optional = true, features = ["rt", "sync"] }
|
||||||
optional = true
|
napi-derive = { path = "../macro", version = "2.10.1", default-features = false }
|
||||||
version = "1"
|
|
||||||
|
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||||
|
tokio = { version = "1", optional = true, features = [
|
||||||
|
"rt",
|
||||||
|
"rt-multi-thread",
|
||||||
|
"sync",
|
||||||
|
] }
|
||||||
|
|
||||||
[dependencies.serde]
|
[dependencies.serde]
|
||||||
optional = true
|
optional = true
|
||||||
|
|
|
@ -77,7 +77,7 @@ pub fn run<T: Task>(
|
||||||
complete::<T>
|
complete::<T>
|
||||||
as unsafe extern "C" fn(env: sys::napi_env, status: sys::napi_status, data: *mut c_void),
|
as unsafe extern "C" fn(env: sys::napi_env, status: sys::napi_status, data: *mut c_void),
|
||||||
),
|
),
|
||||||
result as *mut _ as *mut c_void,
|
(result as *mut AsyncWork<T>).cast(),
|
||||||
&mut result.napi_async_work,
|
&mut result.napi_async_work,
|
||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
|
@ -91,10 +91,8 @@ pub fn run<T: Task>(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::non_send_fields_in_send_ty)]
|
unsafe impl<T: Task + Send> Send for AsyncWork<T> {}
|
||||||
unsafe impl<T: Task> Send for AsyncWork<T> {}
|
unsafe impl<T: Task + Sync> Sync for AsyncWork<T> {}
|
||||||
|
|
||||||
unsafe impl<T: Task> Sync for AsyncWork<T> {}
|
|
||||||
|
|
||||||
/// env here is the same with the one in `CallContext`.
|
/// env here is the same with the one in `CallContext`.
|
||||||
/// So it actually could do nothing here, because `execute` function is called in the other thread mostly.
|
/// So it actually could do nothing here, because `execute` function is called in the other thread mostly.
|
||||||
|
|
|
@ -7,7 +7,7 @@ use std::sync::{
|
||||||
Arc,
|
Arc,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "napi4")]
|
#[cfg(all(feature = "napi4", not(target_arch = "wasm32")))]
|
||||||
use crate::bindgen_prelude::{CUSTOM_GC_TSFN, CUSTOM_GC_TSFN_CLOSED, MAIN_THREAD_ID};
|
use crate::bindgen_prelude::{CUSTOM_GC_TSFN, CUSTOM_GC_TSFN_CLOSED, MAIN_THREAD_ID};
|
||||||
pub use crate::js_values::TypedArrayType;
|
pub use crate::js_values::TypedArrayType;
|
||||||
use crate::{check_status, sys, Error, Result, Status};
|
use crate::{check_status, sys, Error, Result, Status};
|
||||||
|
@ -66,7 +66,7 @@ macro_rules! impl_typed_array {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
if Arc::strong_count(&self.drop_in_vm) == 1 {
|
if Arc::strong_count(&self.drop_in_vm) == 1 {
|
||||||
if let Some((ref_, env)) = self.raw {
|
if let Some((ref_, env)) = self.raw {
|
||||||
#[cfg(feature = "napi4")]
|
#[cfg(all(feature = "napi4", not(target_arch = "wasm32")))]
|
||||||
{
|
{
|
||||||
if CUSTOM_GC_TSFN_CLOSED.load(std::sync::atomic::Ordering::SeqCst) {
|
if CUSTOM_GC_TSFN_CLOSED.load(std::sync::atomic::Ordering::SeqCst) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -9,7 +9,7 @@ use std::sync::Arc;
|
||||||
#[cfg(all(debug_assertions, not(windows)))]
|
#[cfg(all(debug_assertions, not(windows)))]
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
|
|
||||||
#[cfg(feature = "napi4")]
|
#[cfg(all(feature = "napi4", not(target_arch = "wasm32")))]
|
||||||
use crate::bindgen_prelude::{CUSTOM_GC_TSFN, CUSTOM_GC_TSFN_CLOSED, MAIN_THREAD_ID};
|
use crate::bindgen_prelude::{CUSTOM_GC_TSFN, CUSTOM_GC_TSFN_CLOSED, MAIN_THREAD_ID};
|
||||||
use crate::{bindgen_prelude::*, check_status, sys, Result, ValueType};
|
use crate::{bindgen_prelude::*, check_status, sys, Result, ValueType};
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ impl Drop for Buffer {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
if Arc::strong_count(&self.ref_count) == 1 {
|
if Arc::strong_count(&self.ref_count) == 1 {
|
||||||
if let Some((ref_, env)) = self.raw {
|
if let Some((ref_, env)) = self.raw {
|
||||||
#[cfg(feature = "napi4")]
|
#[cfg(all(feature = "napi4", not(target_arch = "wasm32")))]
|
||||||
{
|
{
|
||||||
if CUSTOM_GC_TSFN_CLOSED.load(std::sync::atomic::Ordering::SeqCst) {
|
if CUSTOM_GC_TSFN_CLOSED.load(std::sync::atomic::Ordering::SeqCst) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -1,30 +1,33 @@
|
||||||
use std::ffi::CStr;
|
use std::ffi::{c_void, CStr};
|
||||||
use std::future;
|
use std::future;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use std::sync::{
|
use std::sync::{
|
||||||
atomic::{AtomicBool, Ordering},
|
atomic::{AtomicBool, AtomicPtr, Ordering},
|
||||||
Arc,
|
Arc,
|
||||||
};
|
};
|
||||||
use std::task::{Context, Poll};
|
use std::task::{Context, Poll, Waker};
|
||||||
|
|
||||||
use tokio::sync::oneshot::{channel, Receiver, Sender};
|
use crate::{check_status, sys, Error, JsUnknown, NapiValue, Result};
|
||||||
|
|
||||||
use crate::{check_status, sys, Error, JsUnknown, NapiValue, Result, Status};
|
|
||||||
|
|
||||||
use super::{FromNapiValue, TypeName, ValidateNapiValue};
|
use super::{FromNapiValue, TypeName, ValidateNapiValue};
|
||||||
|
|
||||||
pub struct Promise<T: FromNapiValue> {
|
struct PromiseInner<T: FromNapiValue> {
|
||||||
value: Pin<Box<Receiver<*mut Result<T>>>>,
|
value: AtomicPtr<Result<T>>,
|
||||||
aborted: Arc<AtomicBool>,
|
waker: AtomicPtr<Waker>,
|
||||||
|
aborted: AtomicBool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: FromNapiValue> Drop for Promise<T> {
|
impl<T: FromNapiValue> Drop for PromiseInner<T> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
self.aborted.store(true, Ordering::SeqCst);
|
self.aborted.store(true, Ordering::SeqCst);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct Promise<T: FromNapiValue> {
|
||||||
|
inner: Arc<PromiseInner<T>>,
|
||||||
|
}
|
||||||
|
|
||||||
impl<T: FromNapiValue> TypeName for Promise<T> {
|
impl<T: FromNapiValue> TypeName for Promise<T> {
|
||||||
fn type_name() -> &'static str {
|
fn type_name() -> &'static str {
|
||||||
"Promise"
|
"Promise"
|
||||||
|
@ -100,9 +103,13 @@ impl<T: FromNapiValue> FromNapiValue for Promise<T> {
|
||||||
)?;
|
)?;
|
||||||
let mut promise_after_then = ptr::null_mut();
|
let mut promise_after_then = ptr::null_mut();
|
||||||
let mut then_js_cb = ptr::null_mut();
|
let mut then_js_cb = ptr::null_mut();
|
||||||
let (tx, rx) = channel();
|
let promise_inner = PromiseInner {
|
||||||
let aborted = Arc::new(AtomicBool::new(false));
|
value: AtomicPtr::new(ptr::null_mut()),
|
||||||
let tx_ptr = Box::into_raw(Box::new((tx, aborted.clone())));
|
waker: AtomicPtr::new(ptr::null_mut()),
|
||||||
|
aborted: AtomicBool::new(false),
|
||||||
|
};
|
||||||
|
let shared_inner = Arc::new(promise_inner);
|
||||||
|
let context_ptr = Arc::into_raw(shared_inner.clone());
|
||||||
check_status!(
|
check_status!(
|
||||||
unsafe {
|
unsafe {
|
||||||
sys::napi_create_function(
|
sys::napi_create_function(
|
||||||
|
@ -110,7 +117,7 @@ impl<T: FromNapiValue> FromNapiValue for Promise<T> {
|
||||||
then_c_string.as_ptr(),
|
then_c_string.as_ptr(),
|
||||||
4,
|
4,
|
||||||
Some(then_callback::<T>),
|
Some(then_callback::<T>),
|
||||||
tx_ptr.cast(),
|
context_ptr as *mut c_void,
|
||||||
&mut then_js_cb,
|
&mut then_js_cb,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
@ -145,7 +152,7 @@ impl<T: FromNapiValue> FromNapiValue for Promise<T> {
|
||||||
catch_c_string.as_ptr(),
|
catch_c_string.as_ptr(),
|
||||||
5,
|
5,
|
||||||
Some(catch_callback::<T>),
|
Some(catch_callback::<T>),
|
||||||
tx_ptr.cast(),
|
context_ptr as *mut c_void,
|
||||||
&mut catch_js_cb,
|
&mut catch_js_cb,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
@ -165,8 +172,7 @@ impl<T: FromNapiValue> FromNapiValue for Promise<T> {
|
||||||
"Failed to call catch method"
|
"Failed to call catch method"
|
||||||
)?;
|
)?;
|
||||||
Ok(Promise {
|
Ok(Promise {
|
||||||
value: Box::pin(rx),
|
inner: shared_inner,
|
||||||
aborted,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -174,13 +180,19 @@ impl<T: FromNapiValue> FromNapiValue for Promise<T> {
|
||||||
impl<T: FromNapiValue> future::Future for Promise<T> {
|
impl<T: FromNapiValue> future::Future for Promise<T> {
|
||||||
type Output = Result<T>;
|
type Output = Result<T>;
|
||||||
|
|
||||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
match self.value.as_mut().poll(cx) {
|
if self.inner.value.load(Ordering::Relaxed).is_null() {
|
||||||
Poll::Pending => Poll::Pending,
|
if self.inner.waker.load(Ordering::Acquire).is_null() {
|
||||||
Poll::Ready(v) => Poll::Ready(
|
self.inner.waker.store(
|
||||||
v.map_err(|e| Error::new(Status::GenericFailure, format!("{}", e)))
|
Box::into_raw(Box::new(cx.waker().clone())),
|
||||||
.and_then(|v| unsafe { *Box::from_raw(v) }.map_err(Error::from)),
|
Ordering::Release,
|
||||||
),
|
);
|
||||||
|
}
|
||||||
|
Poll::Pending
|
||||||
|
} else {
|
||||||
|
Poll::Ready(
|
||||||
|
unsafe { Box::from_raw(self.inner.value.load(Ordering::Relaxed)) }.map_err(Error::from),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -206,15 +218,20 @@ unsafe extern "C" fn then_callback<T: FromNapiValue>(
|
||||||
get_cb_status == sys::Status::napi_ok,
|
get_cb_status == sys::Status::napi_ok,
|
||||||
"Get callback info from Promise::then failed"
|
"Get callback info from Promise::then failed"
|
||||||
);
|
);
|
||||||
let (sender, aborted) =
|
let PromiseInner {
|
||||||
*unsafe { Box::from_raw(data as *mut (Sender<*mut Result<T>>, Arc<AtomicBool>)) };
|
value,
|
||||||
|
waker,
|
||||||
|
aborted,
|
||||||
|
} = &*unsafe { Arc::from_raw(data as *mut PromiseInner<T>) };
|
||||||
if aborted.load(Ordering::SeqCst) {
|
if aborted.load(Ordering::SeqCst) {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
let resolve_value_t = Box::new(unsafe { T::from_napi_value(env, resolved_value[0]) });
|
let resolve_value_t = Box::new(unsafe { T::from_napi_value(env, resolved_value[0]) });
|
||||||
sender
|
value.store(Box::into_raw(resolve_value_t), Ordering::Relaxed);
|
||||||
.send(Box::into_raw(resolve_value_t))
|
let waker = waker.load(Ordering::Acquire);
|
||||||
.expect("Send Promise resolved value error");
|
if !waker.is_null() {
|
||||||
|
unsafe { Box::from_raw(waker) }.wake();
|
||||||
|
}
|
||||||
this
|
this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -241,15 +258,23 @@ unsafe extern "C" fn catch_callback<T: FromNapiValue>(
|
||||||
"Get callback info from Promise::catch failed"
|
"Get callback info from Promise::catch failed"
|
||||||
);
|
);
|
||||||
let rejected_value = rejected_value[0];
|
let rejected_value = rejected_value[0];
|
||||||
let (sender, aborted) =
|
let PromiseInner {
|
||||||
*unsafe { Box::from_raw(data as *mut (Sender<*mut Result<T>>, Arc<AtomicBool>)) };
|
value,
|
||||||
|
waker,
|
||||||
|
aborted,
|
||||||
|
} = &*unsafe { Arc::from_raw(data as *mut PromiseInner<T>) };
|
||||||
if aborted.load(Ordering::SeqCst) {
|
if aborted.load(Ordering::SeqCst) {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
sender
|
value.store(
|
||||||
.send(Box::into_raw(Box::new(Err(Error::from(unsafe {
|
Box::into_raw(Box::new(Err(Error::from(unsafe {
|
||||||
JsUnknown::from_raw_unchecked(env, rejected_value)
|
JsUnknown::from_raw_unchecked(env, rejected_value)
|
||||||
})))))
|
})))),
|
||||||
.expect("Send Promise resolved value error");
|
Ordering::Relaxed,
|
||||||
|
);
|
||||||
|
let waker = waker.load(Ordering::Acquire);
|
||||||
|
if !waker.is_null() {
|
||||||
|
unsafe { Box::from_raw(waker) }.wake();
|
||||||
|
}
|
||||||
this
|
this
|
||||||
}
|
}
|
||||||
|
|
|
@ -117,14 +117,14 @@ static IS_FIRST_MODULE: AtomicBool = AtomicBool::new(true);
|
||||||
static FIRST_MODULE_REGISTERED: AtomicBool = AtomicBool::new(false);
|
static FIRST_MODULE_REGISTERED: AtomicBool = AtomicBool::new(false);
|
||||||
static REGISTERED_CLASSES: Lazy<RegisteredClassesMap> = Lazy::new(Default::default);
|
static REGISTERED_CLASSES: Lazy<RegisteredClassesMap> = Lazy::new(Default::default);
|
||||||
static FN_REGISTER_MAP: Lazy<FnRegisterMap> = Lazy::new(Default::default);
|
static FN_REGISTER_MAP: Lazy<FnRegisterMap> = Lazy::new(Default::default);
|
||||||
#[cfg(feature = "napi4")]
|
#[cfg(all(feature = "napi4", not(target_arch = "wasm32")))]
|
||||||
pub(crate) static CUSTOM_GC_TSFN: AtomicPtr<sys::napi_threadsafe_function__> =
|
pub(crate) static CUSTOM_GC_TSFN: AtomicPtr<sys::napi_threadsafe_function__> =
|
||||||
AtomicPtr::new(ptr::null_mut());
|
AtomicPtr::new(ptr::null_mut());
|
||||||
#[cfg(feature = "napi4")]
|
#[cfg(all(feature = "napi4", not(target_arch = "wasm32")))]
|
||||||
// CustomGC ThreadsafeFunction may be deleted during the process exit.
|
// CustomGC ThreadsafeFunction may be deleted during the process exit.
|
||||||
// And there may still some Buffer alive after that.
|
// And there may still some Buffer alive after that.
|
||||||
pub(crate) static CUSTOM_GC_TSFN_CLOSED: AtomicBool = AtomicBool::new(false);
|
pub(crate) static CUSTOM_GC_TSFN_CLOSED: AtomicBool = AtomicBool::new(false);
|
||||||
#[cfg(feature = "napi4")]
|
#[cfg(all(feature = "napi4", not(target_arch = "wasm32")))]
|
||||||
pub(crate) static MAIN_THREAD_ID: once_cell::sync::OnceCell<ThreadId> =
|
pub(crate) static MAIN_THREAD_ID: once_cell::sync::OnceCell<ThreadId> =
|
||||||
once_cell::sync::OnceCell::new();
|
once_cell::sync::OnceCell::new();
|
||||||
|
|
||||||
|
@ -288,6 +288,15 @@ fn load_host() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "wasm32")]
|
||||||
|
#[no_mangle]
|
||||||
|
unsafe extern "C" fn napi_register_wasm_v1(
|
||||||
|
env: sys::napi_env,
|
||||||
|
exports: sys::napi_value,
|
||||||
|
) -> sys::napi_value {
|
||||||
|
unsafe { napi_register_module_v1(env, exports) }
|
||||||
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
unsafe extern "C" fn napi_register_module_v1(
|
unsafe extern "C" fn napi_register_module_v1(
|
||||||
env: sys::napi_env,
|
env: sys::napi_env,
|
||||||
|
@ -488,7 +497,7 @@ unsafe extern "C" fn napi_register_module_v1(
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#[cfg(feature = "napi4")]
|
#[cfg(all(feature = "napi4", not(target_arch = "wasm32")))]
|
||||||
create_custom_gc(env);
|
create_custom_gc(env);
|
||||||
FIRST_MODULE_REGISTERED.store(true, Ordering::SeqCst);
|
FIRST_MODULE_REGISTERED.store(true, Ordering::SeqCst);
|
||||||
exports
|
exports
|
||||||
|
@ -511,7 +520,7 @@ pub(crate) unsafe extern "C" fn noop(
|
||||||
ptr::null_mut()
|
ptr::null_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "napi4")]
|
#[cfg(all(feature = "napi4", not(target_arch = "wasm32")))]
|
||||||
fn create_custom_gc(env: sys::napi_env) {
|
fn create_custom_gc(env: sys::napi_env) {
|
||||||
use std::os::raw::c_char;
|
use std::os::raw::c_char;
|
||||||
|
|
||||||
|
@ -572,13 +581,13 @@ fn create_custom_gc(env: sys::napi_env) {
|
||||||
MAIN_THREAD_ID.get_or_init(|| std::thread::current().id());
|
MAIN_THREAD_ID.get_or_init(|| std::thread::current().id());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "napi4")]
|
#[cfg(all(feature = "napi4", not(target_arch = "wasm32")))]
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
unsafe extern "C" fn empty(env: sys::napi_env, info: sys::napi_callback_info) -> sys::napi_value {
|
unsafe extern "C" fn empty(env: sys::napi_env, info: sys::napi_callback_info) -> sys::napi_value {
|
||||||
ptr::null_mut()
|
ptr::null_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "napi4")]
|
#[cfg(all(feature = "napi4", not(target_arch = "wasm32")))]
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
unsafe extern "C" fn custom_gc_finalize(
|
unsafe extern "C" fn custom_gc_finalize(
|
||||||
env: sys::napi_env,
|
env: sys::napi_env,
|
||||||
|
@ -588,7 +597,7 @@ unsafe extern "C" fn custom_gc_finalize(
|
||||||
CUSTOM_GC_TSFN_CLOSED.store(true, Ordering::SeqCst);
|
CUSTOM_GC_TSFN_CLOSED.store(true, Ordering::SeqCst);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "napi4")]
|
#[cfg(all(feature = "napi4", not(target_arch = "wasm32")))]
|
||||||
// recycle the ArrayBuffer/Buffer Reference if the ArrayBuffer/Buffer is not dropped on the main thread
|
// recycle the ArrayBuffer/Buffer Reference if the ArrayBuffer/Buffer is not dropped on the main thread
|
||||||
extern "C" fn custom_gc(
|
extern "C" fn custom_gc(
|
||||||
env: sys::napi_env,
|
env: sys::napi_env,
|
||||||
|
|
|
@ -567,7 +567,7 @@ impl Env {
|
||||||
pub fn create_function_from_closure<R, F>(&self, name: &str, callback: F) -> Result<JsFunction>
|
pub fn create_function_from_closure<R, F>(&self, name: &str, callback: F) -> Result<JsFunction>
|
||||||
where
|
where
|
||||||
F: 'static + Fn(crate::CallContext<'_>) -> Result<R>,
|
F: 'static + Fn(crate::CallContext<'_>) -> Result<R>,
|
||||||
R: NapiRaw,
|
R: ToNapiValue,
|
||||||
{
|
{
|
||||||
use crate::CallContext;
|
use crate::CallContext;
|
||||||
let boxed_callback = Box::new(callback);
|
let boxed_callback = Box::new(callback);
|
||||||
|
@ -582,7 +582,7 @@ impl Env {
|
||||||
name.as_ptr(),
|
name.as_ptr(),
|
||||||
len,
|
len,
|
||||||
Some({
|
Some({
|
||||||
unsafe extern "C" fn trampoline<R: NapiRaw, F: Fn(CallContext<'_>) -> Result<R>>(
|
unsafe extern "C" fn trampoline<R: ToNapiValue, F: Fn(CallContext<'_>) -> Result<R>>(
|
||||||
raw_env: sys::napi_env,
|
raw_env: sys::napi_env,
|
||||||
cb_info: sys::napi_callback_info,
|
cb_info: sys::napi_callback_info,
|
||||||
) -> sys::napi_value {
|
) -> sys::napi_value {
|
||||||
|
@ -636,7 +636,8 @@ impl Env {
|
||||||
};
|
};
|
||||||
let env = &mut unsafe { Env::from_raw(raw_env) };
|
let env = &mut unsafe { Env::from_raw(raw_env) };
|
||||||
let ctx = CallContext::new(env, cb_info, raw_this, raw_args, raw_args.len());
|
let ctx = CallContext::new(env, cb_info, raw_this, raw_args, raw_args.len());
|
||||||
closure(ctx).map(|ret: R| unsafe { ret.raw() })
|
closure(ctx)
|
||||||
|
.and_then(|ret: R| unsafe { <R as ToNapiValue>::to_napi_value(env.0, ret) })
|
||||||
}))
|
}))
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
Error::from_reason(format!(
|
Error::from_reason(format!(
|
||||||
|
|
|
@ -674,7 +674,7 @@ unsafe extern "C" fn call_js_cb<T: 'static, V: ToNapiValue, R, ES>(
|
||||||
let message_length = message.len();
|
let message_length = message.len();
|
||||||
unsafe {
|
unsafe {
|
||||||
sys::napi_fatal_error(
|
sys::napi_fatal_error(
|
||||||
"threadsafe_function.rs:573\0".as_ptr().cast(),
|
"threadsafe_function.rs:642\0".as_ptr().cast(),
|
||||||
26,
|
26,
|
||||||
CString::new(message).unwrap().into_raw(),
|
CString::new(message).unwrap().into_raw(),
|
||||||
message_length,
|
message_length,
|
||||||
|
|
|
@ -6,8 +6,19 @@ use tokio::runtime::Runtime;
|
||||||
use crate::{sys, JsDeferred, JsUnknown, NapiValue, Result};
|
use crate::{sys, JsDeferred, JsUnknown, NapiValue, Result};
|
||||||
|
|
||||||
pub(crate) static mut RT: Lazy<Option<Runtime>> = Lazy::new(|| {
|
pub(crate) static mut RT: Lazy<Option<Runtime>> = Lazy::new(|| {
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
{
|
||||||
let runtime = tokio::runtime::Runtime::new().expect("Create tokio runtime failed");
|
let runtime = tokio::runtime::Runtime::new().expect("Create tokio runtime failed");
|
||||||
Some(runtime)
|
Some(runtime)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "wasm32")]
|
||||||
|
{
|
||||||
|
tokio::runtime::Builder::new_current_thread()
|
||||||
|
.enable_all()
|
||||||
|
.build()
|
||||||
|
.ok()
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
|
@ -74,14 +85,20 @@ pub fn execute_tokio_future<
|
||||||
) -> Result<sys::napi_value> {
|
) -> Result<sys::napi_value> {
|
||||||
let (deferred, promise) = JsDeferred::new(env)?;
|
let (deferred, promise) = JsDeferred::new(env)?;
|
||||||
|
|
||||||
spawn(async move {
|
let inner = async move {
|
||||||
match fut.await {
|
match fut.await {
|
||||||
Ok(v) => deferred.resolve(|env| {
|
Ok(v) => deferred.resolve(|env| {
|
||||||
resolver(env.raw(), v).map(|v| unsafe { JsUnknown::from_raw_unchecked(env.raw(), v) })
|
resolver(env.raw(), v).map(|v| unsafe { JsUnknown::from_raw_unchecked(env.raw(), v) })
|
||||||
}),
|
}),
|
||||||
Err(e) => deferred.reject(e),
|
Err(e) => deferred.reject(e),
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
spawn(inner);
|
||||||
|
|
||||||
|
#[cfg(target_arch = "wasm32")]
|
||||||
|
block_on(inner);
|
||||||
|
|
||||||
Ok(promise.0.value)
|
Ok(promise.0.value)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue