From 88e553e077e9de44cc50f73e86868571001665a3 Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Thu, 15 Apr 2021 05:37:12 -0500 Subject: [PATCH 01/19] fix: let Cmake choose the generator This lets CMake use the best generator for that system, which increases the portability of the library and removing the need for workarounds in different environments --- script/build.sh | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/script/build.sh b/script/build.sh index 046ddd48..fed81ea3 100755 --- a/script/build.sh +++ b/script/build.sh @@ -12,22 +12,10 @@ if [ -n "${WINDIR}" ]; then # Working directory is NAPI temporary build directory. PATH_PREFIX="${PWD}/libzmq" ARTIFACT="${PATH_PREFIX}/lib/libzmq.lib" - CMAKE_GENERATOR="Visual Studio 15 2017" - TOOLSET_VERSION="141" - - # In Travis CI, Node paths are: - # - C:\ProgramData\nvs\node\\x64\node.exe - # - C:\ProgramData\nvs\node\\x86\node.exe - if [[ "${NODE}" != *"x86"* ]]; then - # Target Windows x64 platform. - CMAKE_GENERATOR="${CMAKE_GENERATOR} Win64" - fi else # Working directory is project root. PATH_PREFIX="${PWD}/build/libzmq" ARTIFACT="${PATH_PREFIX}/lib/libzmq.a" - CMAKE_GENERATOR="Unix Makefiles" - export MACOSX_DEPLOYMENT_TARGET=10.9 fi @@ -57,7 +45,7 @@ else echo > "${SRC_DIR}/builds/cmake/Modules/ClangFormat.cmake" fi - cmake -G "${CMAKE_GENERATOR}" \ + cmake \ "${BUILD_OPTIONS}" \ -DCMAKE_INSTALL_PREFIX="${PATH_PREFIX}" \ -DCMAKE_INSTALL_LIBDIR=lib \ @@ -73,9 +61,10 @@ else --config Release \ --target install \ -- -verbosity:Minimal -maxcpucount - mv \ - "${PATH_PREFIX}/lib/libzmq-v${TOOLSET_VERSION}-mt-s-${ZMQ_VERSION//./_}.lib" \ - "${PATH_PREFIX}/lib/libzmq.lib" + + BuilFile=$(find $PATH_PREFIX/lib/*.lib -type f) + mv "$BuilFile" "${PATH_PREFIX}/lib/libzmq.lib" + else cmake \ --build .\ From 3c61feabb621bcc52f4d2c248ed4895ab64f2ed6 Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Thu, 15 Apr 2021 05:37:29 -0500 Subject: [PATCH 02/19] fix: fix building with VS2019 and VS2017 --- binding.gyp | 1 - 1 file changed, 1 deletion(-) diff --git a/binding.gyp b/binding.gyp index 93e0322e..4b3902d1 100644 --- a/binding.gyp +++ b/binding.gyp @@ -72,7 +72,6 @@ }], ['OS == "win"', { - 'msbuild_toolset': 'v141', 'libraries': [ '<(PRODUCT_DIR)/../libzmq/lib/libzmq', 'ws2_32.lib', From 22dee8f56ae7c87f812838f1acc975faeb2779b1 Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Tue, 6 Apr 2021 10:36:31 -0500 Subject: [PATCH 03/19] test: fix mocha config Replaces old mocha.opts with .mocharc.js. Now the mocha config is detected correctly. --- .mocharc.js | 9 +++++++++ test/mocha.opts | 5 ----- 2 files changed, 9 insertions(+), 5 deletions(-) create mode 100644 .mocharc.js delete mode 100644 test/mocha.opts diff --git a/.mocharc.js b/.mocharc.js new file mode 100644 index 00000000..4c0068d6 --- /dev/null +++ b/.mocharc.js @@ -0,0 +1,9 @@ +'use strict' + +module.exports = { + require: ['ts-node/register', 'choma'], + spec: ['test/unit/*-test.ts', 'test/unit/compat/*-test.{ts,js}'], + "expose-gc": true, + "experimental-worker": true, + recursive: true, +} diff --git a/test/mocha.opts b/test/mocha.opts deleted file mode 100644 index 6be1c57f..00000000 --- a/test/mocha.opts +++ /dev/null @@ -1,5 +0,0 @@ -test/unit/*-test.ts test/unit/compat/*-test.{ts,js} ---experimental-worker ---require ts-node/register ---require choma ---expose-gc From 0c61aa0beb21434ce294291cbc409742107bd2b0 Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Tue, 6 Apr 2021 10:46:26 -0500 Subject: [PATCH 04/19] fix: resolve always expects a value - pass undefined --- test/unit/socket-draft-dgram-test.ts | 2 +- test/unit/typings-compatibility-test.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/unit/socket-draft-dgram-test.ts b/test/unit/socket-draft-dgram-test.ts index 331e4d42..ce1a7848 100644 --- a/test/unit/socket-draft-dgram-test.ts +++ b/test/unit/socket-draft-dgram-test.ts @@ -41,7 +41,7 @@ if (zmq.capability.draft) { client.on("message", res => { received.push(res.toString()) client.close() - resolve() + resolve(undefined) }) client.send(msg, port, "localhost") diff --git a/test/unit/typings-compatibility-test.ts b/test/unit/typings-compatibility-test.ts index ae511e15..389440ae 100644 --- a/test/unit/typings-compatibility-test.ts +++ b/test/unit/typings-compatibility-test.ts @@ -101,7 +101,7 @@ async function run( if (error) { resolve(errorAsString ? stdout + "\n" + stderr : error) } else { - resolve() + resolve(undefined) } }) }) From 22d878a88ae93afebed5dcf63468de5137c5a130 Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Thu, 15 Apr 2021 05:20:51 -0500 Subject: [PATCH 05/19] fix: remove none-existing node-addon-api from package.json --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ef3e51e5..35c13823 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,7 @@ "fs-extra": "^8.1.0", "gunzip-maybe": "^1.4.1", "mocha": ">= 4.0", - "node-addon-api": "nodejs/node-addon-api", + "node-addon-api": "^3.1.0", "node-fetch": "^2.6.0", "prebuildify": "^3.0", "prettier": "^1.19.1", From b8d295d3f7db980c658b293be9cf4e05906b5d43 Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Tue, 6 Apr 2021 11:12:18 -0500 Subject: [PATCH 06/19] fix: add the required libs (es2018 and dom) to tsconfig --- tsconfig.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tsconfig.json b/tsconfig.json index f751d2ce..5b5085c3 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -8,6 +8,7 @@ "module": "commonjs", "types": ["node", "mocha"], "strict": true, - "strictPropertyInitialization": false + "strictPropertyInitialization": false, + "lib": ["es2018", "dom"] } } From 18307a5c0c2a6547b9f30a30ae82eab251c737f0 Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Thu, 8 Apr 2021 01:41:42 -0500 Subject: [PATCH 07/19] fix: update libzmq version --- script/build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/build.sh b/script/build.sh index fed81ea3..2a936e12 100755 --- a/script/build.sh +++ b/script/build.sh @@ -1,7 +1,7 @@ #!/bin/sh set -e -ZMQ_VERSION=${ZMQ_VERSION:-"4.3.2"} +ZMQ_VERSION=${ZMQ_VERSION:-"4.3.4"} SRC_URL="https://github.com/zeromq/libzmq/releases/download/v${ZMQ_VERSION}/zeromq-${ZMQ_VERSION}.tar.gz" SRC_DIR="zeromq-${ZMQ_VERSION}" From c7090c94b7ab953e505f2b11c0feac99c6ddb1bd Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Thu, 15 Apr 2021 05:29:42 -0500 Subject: [PATCH 08/19] ci: use Node 14 in Travis Node 13+ are able to prebuild without the v8 compression error --- .travis.yml | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/.travis.yml b/.travis.yml index cce3f192..21069467 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,52 +8,53 @@ jobs: ## TEST STAGE - os: linux - node_js: "10.2" + node_js: "14" env: ZMQ_DRAFT=true - os: linux - node_js: "10.16" + node_js: "14" env: ZMQ_DRAFT=true INCLUDE_COMPAT_TESTS=true - os: linux env: ALPINE_CHROOT=3.10 ZMQ_DRAFT=true INCLUDE_COMPAT_TESTS=true sudo: required + node_js: "14" - os: osx osx_image: xcode10 env: ZMQ_DRAFT=true - node_js: "10.16" + node_js: "14" - os: windows - node_js: "10.16" + node_js: "14" # https://travis-ci.community/t/build-doesnt-finish-after-completing-tests/288 env: ZMQ_DRAFT=true YARN_GPG=no - os: windows - node_js: "10.16/x86" + node_js: "14/x86" # https://travis-ci.community/t/build-doesnt-finish-after-completing-tests/288 env: ZMQ_DRAFT=true YARN_GPG=no # Test shared libraries on Linux and macOS. - os: linux - node_js: "10.16" + node_js: "14" env: ZMQ_SHARED=true addons: {apt: {packages: libzmq3-dev}} - os: osx osx_image: xcode10 - node_js: "10.16" + node_js: "14" env: ZMQ_SHARED=true addons: {homebrew: {packages: zeromq, update: true}} # Test older versions of ZMQ. - os: linux - node_js: "10.16" + node_js: "14" env: ZMQ_VERSION=4.2.4 # Test recent Node versions. - os: linux - node_js: "12" + node_js: "14" # Skip GC tests due to https://github.com/node-ffi-napi/weak-napi/issues/16 env: ZMQ_DRAFT=true SKIP_GC_TESTS=true INCLUDE_COMPAT_TESTS=true @@ -67,7 +68,7 @@ jobs: # This test ensures the delayed resolution of read/write promises is correct # by disabling immediate resolution (which happens 99% of the time) entirely. - os: linux - node_js: "10.16" + node_js: "14" env: ZMQ_NO_SYNC_RESOLVE=true ZMQ_DRAFT=true INCLUDE_COMPAT_TESTS=true NODE_NO_WARNINGS=1 ## PREBUILD STAGE @@ -75,7 +76,7 @@ jobs: - stage: prebuild os: linux env: ARCHIVE_SUFFIX=-x64 - node_js: "10.16" + node_js: "14" script: script/ci/prebuild.sh - stage: prebuild @@ -86,14 +87,14 @@ jobs: - stage: prebuild os: linux - node_js: "10.16" + node_js: "14" env: ARCH=arm TRIPLE=arm-linux-gnueabihf GCC=8 ARCHIVE_SUFFIX=-armv7 addons: {apt: {packages: [gcc-8-arm-linux-gnueabihf, g++-8-arm-linux-gnueabihf]}} script: script/ci/prebuild.sh - stage: prebuild os: linux - node_js: "10.16" + node_js: "14" env: ARCH=arm64 TRIPLE=aarch64-linux-gnu GCC=8 ARCHIVE_SUFFIX=-armv8 addons: {apt: {packages: [gcc-8-aarch64-linux-gnu, g++-8-aarch64-linux-gnu]}} script: script/ci/prebuild.sh @@ -101,19 +102,19 @@ jobs: - stage: prebuild os: osx osx_image: xcode10 - node_js: "10.16" + node_js: "14" script: script/ci/prebuild.sh - stage: prebuild os: windows - node_js: "10.16" + node_js: "14" # https://travis-ci.community/t/build-doesnt-finish-after-completing-tests/288 env: YARN_GPG=no ARCHIVE_SUFFIX=-x64 script: script/ci/prebuild.sh - stage: prebuild os: windows - node_js: "10.16/x86" + node_js: "14/x86" # https://travis-ci.community/t/build-doesnt-finish-after-completing-tests/288 env: YARN_GPG=no ARCHIVE_SUFFIX=-x86 script: script/ci/prebuild.sh @@ -122,7 +123,7 @@ jobs: - stage: publish os: linux - node_js: "10.16" + node_js: "14" env: IGNORE_SCRIPTS=true script: script/ci/package.sh From 520f4769b8160cbc86a5e56eb4c48c259e2e10f4 Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Tue, 6 Apr 2021 10:14:19 -0500 Subject: [PATCH 09/19] ci: use python 3 in Travis --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 21069467..1c8c48ad 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,8 @@ language: node_js cache: yarn dist: bionic +python: + - 3.6 jobs: include: From 629dfad041249b11cfb4b08933c74daac8f13ec2 Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Wed, 7 Apr 2021 20:48:44 -0500 Subject: [PATCH 10/19] chore: prevent minwindef.h from defining max macro in the debug build --- src/socket.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/socket.cc b/src/socket.cc index bafd86f2..77b54c99 100644 --- a/src/socket.cc +++ b/src/socket.cc @@ -1,4 +1,6 @@ /* Copyright (c) 2017-2019 Rolf Timmermans */ + +#define NOMINMAX // prevent minwindef.h from defining max macro in the debug build #include "socket.h" #include "context.h" #include "incoming_msg.h" From 9c79db2f33909f7287a6053ca788d9b1482b9337 Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Thu, 8 Apr 2021 02:03:38 -0500 Subject: [PATCH 11/19] chore: add BuildType env variable to allow debug builds --- binding.gyp | 2 +- script/build.sh | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/binding.gyp b/binding.gyp index 4b3902d1..30e1baef 100644 --- a/binding.gyp +++ b/binding.gyp @@ -16,7 +16,7 @@ 'action_name': 'build_libzmq', 'inputs': ['package.json'], 'outputs': ['libzmq/lib'], - 'action': ['sh', '<(PRODUCT_DIR)/../../script/build.sh'], + 'action': ['sh', '<(PRODUCT_DIR)/../../script/build.sh', '<(CONFIGURATION_NAME)'], }], }], ], diff --git a/script/build.sh b/script/build.sh index 2a936e12..3ad3a92d 100755 --- a/script/build.sh +++ b/script/build.sh @@ -58,7 +58,7 @@ else if [ -n "${WINDIR}" ]; then cmake \ --build . \ - --config Release \ + --config $1 \ --target install \ -- -verbosity:Minimal -maxcpucount @@ -68,7 +68,7 @@ else else cmake \ --build .\ - --config Release \ + --config $1 \ --target install \ -- -j5 fi From 0e0acbbdbe8b87b51f6ad0aebf3e840cf52e1830 Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Thu, 8 Apr 2021 02:32:15 -0500 Subject: [PATCH 12/19] chore: enable exceptions in debug builds --- binding.gyp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/binding.gyp b/binding.gyp index 30e1baef..a74b6d61 100644 --- a/binding.gyp +++ b/binding.gyp @@ -42,7 +42,6 @@ 'defines': [ 'NAPI_VERSION=3', - 'NAPI_DISABLE_CPP_EXCEPTIONS', 'ZMQ_STATIC', ], @@ -84,6 +83,7 @@ 'configurations': { 'Debug': { + 'defines': ['NAPI_CPP_EXCEPTIONS', 'DEBUG', '_DEBUG'], 'conditions': [ ['OS == "linux" or OS == "freebsd" or OS == "openbsd" or OS == "solaris"', { 'cflags_cc!': [ @@ -113,6 +113,7 @@ ['OS == "win"', { 'msvs_settings': { 'VCCLCompilerTool': { + 'ExceptionHandling': 2, # /EHsc # 0 - MultiThreaded (/MT) # 1 - MultiThreadedDebug (/MTd) # 2 - MultiThreadedDLL (/MD) @@ -120,14 +121,21 @@ 'RuntimeLibrary': 3, 'AdditionalOptions': [ '-std:c++17', + "/DEBUG", ], }, + 'VCLinkerTool': { + 'BasicRuntimeChecks': 3, # /RTC1 + }, }, }], ], }, 'Release': { + 'defines': [ + 'NAPI_DISABLE_CPP_EXCEPTIONS', + ], 'conditions': [ ['OS == "linux" or OS == "freebsd" or OS == "openbsd" or OS == "solaris"', { 'cflags_cc!': [ From dc17ddda6bcef07166750a62a5a28477563f56ca Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Thu, 8 Apr 2021 06:34:00 -0500 Subject: [PATCH 13/19] chore: add address sanitizer support for MSVC in the debug build --- binding.gyp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/binding.gyp b/binding.gyp index a74b6d61..0a63cdc2 100644 --- a/binding.gyp +++ b/binding.gyp @@ -122,6 +122,14 @@ 'AdditionalOptions': [ '-std:c++17', "/DEBUG", + + # Uncomment to enable address sanitizer + # Make sure to add the followings (or what your MSVC use) to the PATH and run `refreshenv`. + # # C:/Program Files (x86)/Microsoft Visual Studio/2019/Preview/VC/Tools/MSVC/14.29.29917/lib/x64/ + # # C:/Program Files (x86)/Microsoft Visual Studio/2019/Preview/VC/Tools/MSVC/14.29.29917/bin/Hostx64/x64/ + # "/fsanitize=address", + # "/Zi", + # "/INCREMENTAL:NO", ], }, 'VCLinkerTool': { From 2fb0d1ebad1033154348d4d47ff79d145be51b9f Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Thu, 15 Apr 2021 05:20:59 -0500 Subject: [PATCH 14/19] fix: update prebuildify --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 35c13823..17c76743 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "mocha": ">= 4.0", "node-addon-api": "^3.1.0", "node-fetch": "^2.6.0", - "prebuildify": "^3.0", + "prebuildify": "^4.1.2", "prettier": "^1.19.1", "semver": ">= 0", "tar-fs": "^2.0.0", From 47eaf2f59d50796600c32024cf3141bc519bc316 Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Thu, 15 Apr 2021 05:27:40 -0500 Subject: [PATCH 15/19] fix: prebuildify for both Node and Electron --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 17c76743..859760ea 100644 --- a/package.json +++ b/package.json @@ -74,7 +74,8 @@ "install": "node-gyp-build", "ci:compile": "tsc --project tsconfig-build.json && node script/ci/downlevel-dts.js", "ci:doc": "typedoc --out docs --name zeromq.js --excludeProtected --excludePrivate --excludeNotExported --excludeExternals --externalPattern 'src/+(draft|native|compat).ts' --tsconfig tsconfig-build.json --mode file", - "ci:prebuild": "prebuildify --napi --strip", + "ci:prebuild": "npm run prebuildify", + "prebuildify": "prebuildify --napi -t 12.0.0 -t electron@9.4.4 --strip", "dev:build": "rm -f vendor/* && touch vendor/.gitkeep && cp node_modules/node-addon-api/{*.h,LICENSE.md} vendor && prebuildify --napi --build-from-source --debug", "dev:test": "tsc --project tsconfig-build.json && node script/ci/downlevel-dts.js && mocha && script/format.sh && rm -f tmp/*", "dev:bench": "node --expose-gc test/bench" From 608a615aabcb0fd8ccdfb4bb650e19a55aa03e5f Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Thu, 8 Apr 2021 06:48:15 -0500 Subject: [PATCH 16/19] fix: include node-addon-api from the dependency and remove vendor folder --- binding.gyp | 1 + vendor/.gitkeep | 0 vendor/LICENSE.md | 13 - vendor/napi-inl.deprecated.h | 192 -- vendor/napi-inl.h | 4753 ---------------------------------- vendor/napi.h | 2318 ----------------- 6 files changed, 1 insertion(+), 7276 deletions(-) delete mode 100644 vendor/.gitkeep delete mode 100644 vendor/LICENSE.md delete mode 100644 vendor/napi-inl.deprecated.h delete mode 100644 vendor/napi-inl.h delete mode 100644 vendor/napi.h diff --git a/binding.gyp b/binding.gyp index 0a63cdc2..88f9012b 100644 --- a/binding.gyp +++ b/binding.gyp @@ -38,6 +38,7 @@ 'include_dirs': [ "vendor", '<(PRODUCT_DIR)/../libzmq/include', + "* - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/vendor/napi-inl.deprecated.h b/vendor/napi-inl.deprecated.h deleted file mode 100644 index f19aca76..00000000 --- a/vendor/napi-inl.deprecated.h +++ /dev/null @@ -1,192 +0,0 @@ -#ifndef SRC_NAPI_INL_DEPRECATED_H_ -#define SRC_NAPI_INL_DEPRECATED_H_ - -//////////////////////////////////////////////////////////////////////////////// -// PropertyDescriptor class -//////////////////////////////////////////////////////////////////////////////// - -template -inline PropertyDescriptor -PropertyDescriptor::Accessor(const char* utf8name, - Getter getter, - napi_property_attributes attributes, - void* /*data*/) { - typedef details::CallbackData CbData; - // TODO: Delete when the function is destroyed - auto callbackData = new CbData({ getter, nullptr }); - - return PropertyDescriptor({ - utf8name, - nullptr, - nullptr, - CbData::Wrapper, - nullptr, - nullptr, - attributes, - callbackData - }); -} - -template -inline PropertyDescriptor PropertyDescriptor::Accessor(const std::string& utf8name, - Getter getter, - napi_property_attributes attributes, - void* data) { - return Accessor(utf8name.c_str(), getter, attributes, data); -} - -template -inline PropertyDescriptor PropertyDescriptor::Accessor(napi_value name, - Getter getter, - napi_property_attributes attributes, - void* /*data*/) { - typedef details::CallbackData CbData; - // TODO: Delete when the function is destroyed - auto callbackData = new CbData({ getter, nullptr }); - - return PropertyDescriptor({ - nullptr, - name, - nullptr, - CbData::Wrapper, - nullptr, - nullptr, - attributes, - callbackData - }); -} - -template -inline PropertyDescriptor PropertyDescriptor::Accessor(Name name, - Getter getter, - napi_property_attributes attributes, - void* data) { - napi_value nameValue = name; - return PropertyDescriptor::Accessor(nameValue, getter, attributes, data); -} - -template -inline PropertyDescriptor PropertyDescriptor::Accessor(const char* utf8name, - Getter getter, - Setter setter, - napi_property_attributes attributes, - void* /*data*/) { - typedef details::AccessorCallbackData CbData; - // TODO: Delete when the function is destroyed - auto callbackData = new CbData({ getter, setter, nullptr }); - - return PropertyDescriptor({ - utf8name, - nullptr, - nullptr, - CbData::GetterWrapper, - CbData::SetterWrapper, - nullptr, - attributes, - callbackData - }); -} - -template -inline PropertyDescriptor PropertyDescriptor::Accessor(const std::string& utf8name, - Getter getter, - Setter setter, - napi_property_attributes attributes, - void* data) { - return Accessor(utf8name.c_str(), getter, setter, attributes, data); -} - -template -inline PropertyDescriptor PropertyDescriptor::Accessor(napi_value name, - Getter getter, - Setter setter, - napi_property_attributes attributes, - void* /*data*/) { - typedef details::AccessorCallbackData CbData; - // TODO: Delete when the function is destroyed - auto callbackData = new CbData({ getter, setter, nullptr }); - - return PropertyDescriptor({ - nullptr, - name, - nullptr, - CbData::GetterWrapper, - CbData::SetterWrapper, - nullptr, - attributes, - callbackData - }); -} - -template -inline PropertyDescriptor PropertyDescriptor::Accessor(Name name, - Getter getter, - Setter setter, - napi_property_attributes attributes, - void* data) { - napi_value nameValue = name; - return PropertyDescriptor::Accessor(nameValue, getter, setter, attributes, data); -} - -template -inline PropertyDescriptor PropertyDescriptor::Function(const char* utf8name, - Callable cb, - napi_property_attributes attributes, - void* /*data*/) { - typedef decltype(cb(CallbackInfo(nullptr, nullptr))) ReturnType; - typedef details::CallbackData CbData; - // TODO: Delete when the function is destroyed - auto callbackData = new CbData({ cb, nullptr }); - - return PropertyDescriptor({ - utf8name, - nullptr, - CbData::Wrapper, - nullptr, - nullptr, - nullptr, - attributes, - callbackData - }); -} - -template -inline PropertyDescriptor PropertyDescriptor::Function(const std::string& utf8name, - Callable cb, - napi_property_attributes attributes, - void* data) { - return Function(utf8name.c_str(), cb, attributes, data); -} - -template -inline PropertyDescriptor PropertyDescriptor::Function(napi_value name, - Callable cb, - napi_property_attributes attributes, - void* /*data*/) { - typedef decltype(cb(CallbackInfo(nullptr, nullptr))) ReturnType; - typedef details::CallbackData CbData; - // TODO: Delete when the function is destroyed - auto callbackData = new CbData({ cb, nullptr }); - - return PropertyDescriptor({ - nullptr, - name, - CbData::Wrapper, - nullptr, - nullptr, - nullptr, - attributes, - callbackData - }); -} - -template -inline PropertyDescriptor PropertyDescriptor::Function(Name name, - Callable cb, - napi_property_attributes attributes, - void* data) { - napi_value nameValue = name; - return PropertyDescriptor::Function(nameValue, cb, attributes, data); -} - -#endif // !SRC_NAPI_INL_DEPRECATED_H_ diff --git a/vendor/napi-inl.h b/vendor/napi-inl.h deleted file mode 100644 index bef889f9..00000000 --- a/vendor/napi-inl.h +++ /dev/null @@ -1,4753 +0,0 @@ -#ifndef SRC_NAPI_INL_H_ -#define SRC_NAPI_INL_H_ - -//////////////////////////////////////////////////////////////////////////////// -// N-API C++ Wrapper Classes -// -// Inline header-only implementations for "N-API" ABI-stable C APIs for Node.js. -//////////////////////////////////////////////////////////////////////////////// - -// Note: Do not include this file directly! Include "napi.h" instead. - -#include -#include -#include -#include - -namespace Napi { - -// Helpers to handle functions exposed from C++. -namespace details { - -// Attach a data item to an object and delete it when the object gets -// garbage-collected. -// TODO: Replace this code with `napi_add_finalizer()` whenever it becomes -// available on all supported versions of Node.js. -template -static inline napi_status AttachData(napi_env env, - napi_value obj, - FreeType* data, - napi_finalize finalizer = nullptr, - void* hint = nullptr) { - napi_status status; - if (finalizer == nullptr) { - finalizer = [](napi_env /*env*/, void* data, void* /*hint*/) { - delete static_cast(data); - }; - } -#if (NAPI_VERSION < 5) - napi_value symbol, external; - status = napi_create_symbol(env, nullptr, &symbol); - if (status == napi_ok) { - status = napi_create_external(env, - data, - finalizer, - hint, - &external); - if (status == napi_ok) { - napi_property_descriptor desc = { - nullptr, - symbol, - nullptr, - nullptr, - nullptr, - external, - napi_default, - nullptr - }; - status = napi_define_properties(env, obj, 1, &desc); - } - } -#else // NAPI_VERSION >= 5 - status = napi_add_finalizer(env, obj, data, finalizer, hint, nullptr); -#endif - return status; -} - -// For use in JS to C++ callback wrappers to catch any Napi::Error exceptions -// and rethrow them as JavaScript exceptions before returning from the callback. -template -inline napi_value WrapCallback(Callable callback) { -#ifdef NAPI_CPP_EXCEPTIONS - try { - return callback(); - } catch (const Error& e) { - e.ThrowAsJavaScriptException(); - return nullptr; - } -#else // NAPI_CPP_EXCEPTIONS - // When C++ exceptions are disabled, errors are immediately thrown as JS - // exceptions, so there is no need to catch and rethrow them here. - return callback(); -#endif // NAPI_CPP_EXCEPTIONS -} - -template -struct CallbackData { - static inline - napi_value Wrapper(napi_env env, napi_callback_info info) { - return details::WrapCallback([&] { - CallbackInfo callbackInfo(env, info); - CallbackData* callbackData = - static_cast(callbackInfo.Data()); - callbackInfo.SetData(callbackData->data); - return callbackData->callback(callbackInfo); - }); - } - - Callable callback; - void* data; -}; - -template -struct CallbackData { - static inline - napi_value Wrapper(napi_env env, napi_callback_info info) { - return details::WrapCallback([&] { - CallbackInfo callbackInfo(env, info); - CallbackData* callbackData = - static_cast(callbackInfo.Data()); - callbackInfo.SetData(callbackData->data); - callbackData->callback(callbackInfo); - return nullptr; - }); - } - - Callable callback; - void* data; -}; - -template -struct FinalizeData { - static inline - void Wrapper(napi_env env, void* data, void* finalizeHint) { - FinalizeData* finalizeData = static_cast(finalizeHint); - finalizeData->callback(Env(env), static_cast(data)); - delete finalizeData; - } - - static inline - void WrapperWithHint(napi_env env, void* data, void* finalizeHint) { - FinalizeData* finalizeData = static_cast(finalizeHint); - finalizeData->callback(Env(env), static_cast(data), finalizeData->hint); - delete finalizeData; - } - - Finalizer callback; - Hint* hint; -}; - -#if (NAPI_VERSION > 3) -template , - typename FinalizerDataType=void> -struct ThreadSafeFinalize { - static inline - void Wrapper(napi_env env, void* rawFinalizeData, void* /* rawContext */) { - if (rawFinalizeData == nullptr) - return; - - ThreadSafeFinalize* finalizeData = - static_cast(rawFinalizeData); - finalizeData->callback(Env(env)); - if (finalizeData->tsfn) { - *finalizeData->tsfn = nullptr; - } - delete finalizeData; - } - - static inline - void FinalizeWrapperWithData(napi_env env, - void* rawFinalizeData, - void* /* rawContext */) { - if (rawFinalizeData == nullptr) - return; - - ThreadSafeFinalize* finalizeData = - static_cast(rawFinalizeData); - finalizeData->callback(Env(env), finalizeData->data); - if (finalizeData->tsfn) { - *finalizeData->tsfn = nullptr; - } - delete finalizeData; - } - - static inline - void FinalizeWrapperWithContext(napi_env env, - void* rawFinalizeData, - void* rawContext) { - if (rawFinalizeData == nullptr) - return; - - ThreadSafeFinalize* finalizeData = - static_cast(rawFinalizeData); - finalizeData->callback(Env(env), static_cast(rawContext)); - if (finalizeData->tsfn) { - *finalizeData->tsfn = nullptr; - } - delete finalizeData; - } - - static inline - void FinalizeFinalizeWrapperWithDataAndContext(napi_env env, - void* rawFinalizeData, - void* rawContext) { - if (rawFinalizeData == nullptr) - return; - - ThreadSafeFinalize* finalizeData = - static_cast(rawFinalizeData); - finalizeData->callback(Env(env), finalizeData->data, - static_cast(rawContext)); - if (finalizeData->tsfn) { - *finalizeData->tsfn = nullptr; - } - delete finalizeData; - } - - FinalizerDataType* data; - Finalizer callback; - napi_threadsafe_function* tsfn; -}; -#endif - -template -struct AccessorCallbackData { - static inline - napi_value GetterWrapper(napi_env env, napi_callback_info info) { - return details::WrapCallback([&] { - CallbackInfo callbackInfo(env, info); - AccessorCallbackData* callbackData = - static_cast(callbackInfo.Data()); - callbackInfo.SetData(callbackData->data); - return callbackData->getterCallback(callbackInfo); - }); - } - - static inline - napi_value SetterWrapper(napi_env env, napi_callback_info info) { - return details::WrapCallback([&] { - CallbackInfo callbackInfo(env, info); - AccessorCallbackData* callbackData = - static_cast(callbackInfo.Data()); - callbackInfo.SetData(callbackData->data); - callbackData->setterCallback(callbackInfo); - return nullptr; - }); - } - - Getter getterCallback; - Setter setterCallback; - void* data; -}; - -} // namespace details - -#ifndef NODE_ADDON_API_DISABLE_DEPRECATED -# include "napi-inl.deprecated.h" -#endif // !NODE_ADDON_API_DISABLE_DEPRECATED - -//////////////////////////////////////////////////////////////////////////////// -// Module registration -//////////////////////////////////////////////////////////////////////////////// - -#define NODE_API_MODULE(modname, regfunc) \ - napi_value __napi_ ## regfunc(napi_env env, \ - napi_value exports) { \ - return Napi::RegisterModule(env, exports, regfunc); \ - } \ - NAPI_MODULE(modname, __napi_ ## regfunc) - -// Adapt the NAPI_MODULE registration function: -// - Wrap the arguments in NAPI wrappers. -// - Catch any NAPI errors and rethrow as JS exceptions. -inline napi_value RegisterModule(napi_env env, - napi_value exports, - ModuleRegisterCallback registerCallback) { - return details::WrapCallback([&] { - return napi_value(registerCallback(Napi::Env(env), - Napi::Object(env, exports))); - }); -} - -//////////////////////////////////////////////////////////////////////////////// -// Env class -//////////////////////////////////////////////////////////////////////////////// - -inline Env::Env(napi_env env) : _env(env) { -} - -inline Env::operator napi_env() const { - return _env; -} - -inline Object Env::Global() const { - napi_value value; - napi_status status = napi_get_global(*this, &value); - NAPI_THROW_IF_FAILED(*this, status, Object()); - return Object(*this, value); -} - -inline Value Env::Undefined() const { - napi_value value; - napi_status status = napi_get_undefined(*this, &value); - NAPI_THROW_IF_FAILED(*this, status, Value()); - return Value(*this, value); -} - -inline Value Env::Null() const { - napi_value value; - napi_status status = napi_get_null(*this, &value); - NAPI_THROW_IF_FAILED(*this, status, Value()); - return Value(*this, value); -} - -inline bool Env::IsExceptionPending() const { - bool result; - napi_status status = napi_is_exception_pending(_env, &result); - if (status != napi_ok) result = false; // Checking for a pending exception shouldn't throw. - return result; -} - -inline Error Env::GetAndClearPendingException() { - napi_value value; - napi_status status = napi_get_and_clear_last_exception(_env, &value); - if (status != napi_ok) { - // Don't throw another exception when failing to get the exception! - return Error(); - } - return Error(_env, value); -} - -inline Value Env::RunScript(const char* utf8script) { - String script = String::New(_env, utf8script); - return RunScript(script); -} - -inline Value Env::RunScript(const std::string& utf8script) { - return RunScript(utf8script.c_str()); -} - -inline Value Env::RunScript(String script) { - napi_value result; - napi_status status = napi_run_script(_env, script, &result); - NAPI_THROW_IF_FAILED(_env, status, Undefined()); - return Value(_env, result); -} - -//////////////////////////////////////////////////////////////////////////////// -// Value class -//////////////////////////////////////////////////////////////////////////////// - -inline Value::Value() : _env(nullptr), _value(nullptr) { -} - -inline Value::Value(napi_env env, napi_value value) : _env(env), _value(value) { -} - -inline Value::operator napi_value() const { - return _value; -} - -inline bool Value::operator ==(const Value& other) const { - return StrictEquals(other); -} - -inline bool Value::operator !=(const Value& other) const { - return !this->operator ==(other); -} - -inline bool Value::StrictEquals(const Value& other) const { - bool result; - napi_status status = napi_strict_equals(_env, *this, other, &result); - NAPI_THROW_IF_FAILED(_env, status, false); - return result; -} - -inline Napi::Env Value::Env() const { - return Napi::Env(_env); -} - -inline bool Value::IsEmpty() const { - return _value == nullptr; -} - -inline napi_valuetype Value::Type() const { - if (IsEmpty()) { - return napi_undefined; - } - - napi_valuetype type; - napi_status status = napi_typeof(_env, _value, &type); - NAPI_THROW_IF_FAILED(_env, status, napi_undefined); - return type; -} - -inline bool Value::IsUndefined() const { - return Type() == napi_undefined; -} - -inline bool Value::IsNull() const { - return Type() == napi_null; -} - -inline bool Value::IsBoolean() const { - return Type() == napi_boolean; -} - -inline bool Value::IsNumber() const { - return Type() == napi_number; -} - -// Currently experimental guard with the definition of NAPI_EXPERIMENTAL. -// Once it is no longer experimental guard with the NAPI_VERSION in which it is -// released instead. -#ifdef NAPI_EXPERIMENTAL -inline bool Value::IsBigInt() const { - return Type() == napi_bigint; -} -#endif // NAPI_EXPERIMENTAL - -#if (NAPI_VERSION > 4) -inline bool Value::IsDate() const { - if (IsEmpty()) { - return false; - } - - bool result; - napi_status status = napi_is_date(_env, _value, &result); - NAPI_THROW_IF_FAILED(_env, status, false); - return result; -} -#endif - -inline bool Value::IsString() const { - return Type() == napi_string; -} - -inline bool Value::IsSymbol() const { - return Type() == napi_symbol; -} - -inline bool Value::IsArray() const { - if (IsEmpty()) { - return false; - } - - bool result; - napi_status status = napi_is_array(_env, _value, &result); - NAPI_THROW_IF_FAILED(_env, status, false); - return result; -} - -inline bool Value::IsArrayBuffer() const { - if (IsEmpty()) { - return false; - } - - bool result; - napi_status status = napi_is_arraybuffer(_env, _value, &result); - NAPI_THROW_IF_FAILED(_env, status, false); - return result; -} - -inline bool Value::IsTypedArray() const { - if (IsEmpty()) { - return false; - } - - bool result; - napi_status status = napi_is_typedarray(_env, _value, &result); - NAPI_THROW_IF_FAILED(_env, status, false); - return result; -} - -inline bool Value::IsObject() const { - return Type() == napi_object || IsFunction(); -} - -inline bool Value::IsFunction() const { - return Type() == napi_function; -} - -inline bool Value::IsPromise() const { - if (IsEmpty()) { - return false; - } - - bool result; - napi_status status = napi_is_promise(_env, _value, &result); - NAPI_THROW_IF_FAILED(_env, status, false); - return result; -} - -inline bool Value::IsDataView() const { - if (IsEmpty()) { - return false; - } - - bool result; - napi_status status = napi_is_dataview(_env, _value, &result); - NAPI_THROW_IF_FAILED(_env, status, false); - return result; -} - -inline bool Value::IsBuffer() const { - if (IsEmpty()) { - return false; - } - - bool result; - napi_status status = napi_is_buffer(_env, _value, &result); - NAPI_THROW_IF_FAILED(_env, status, false); - return result; -} - -inline bool Value::IsExternal() const { - return Type() == napi_external; -} - -template -inline T Value::As() const { - return T(_env, _value); -} - -inline Boolean Value::ToBoolean() const { - napi_value result; - napi_status status = napi_coerce_to_bool(_env, _value, &result); - NAPI_THROW_IF_FAILED(_env, status, Boolean()); - return Boolean(_env, result); -} - -inline Number Value::ToNumber() const { - napi_value result; - napi_status status = napi_coerce_to_number(_env, _value, &result); - NAPI_THROW_IF_FAILED(_env, status, Number()); - return Number(_env, result); -} - -inline String Value::ToString() const { - napi_value result; - napi_status status = napi_coerce_to_string(_env, _value, &result); - NAPI_THROW_IF_FAILED(_env, status, String()); - return String(_env, result); -} - -inline Object Value::ToObject() const { - napi_value result; - napi_status status = napi_coerce_to_object(_env, _value, &result); - NAPI_THROW_IF_FAILED(_env, status, Object()); - return Object(_env, result); -} - -//////////////////////////////////////////////////////////////////////////////// -// Boolean class -//////////////////////////////////////////////////////////////////////////////// - -inline Boolean Boolean::New(napi_env env, bool val) { - napi_value value; - napi_status status = napi_get_boolean(env, val, &value); - NAPI_THROW_IF_FAILED(env, status, Boolean()); - return Boolean(env, value); -} - -inline Boolean::Boolean() : Napi::Value() { -} - -inline Boolean::Boolean(napi_env env, napi_value value) : Napi::Value(env, value) { -} - -inline Boolean::operator bool() const { - return Value(); -} - -inline bool Boolean::Value() const { - bool result; - napi_status status = napi_get_value_bool(_env, _value, &result); - NAPI_THROW_IF_FAILED(_env, status, false); - return result; -} - -//////////////////////////////////////////////////////////////////////////////// -// Number class -//////////////////////////////////////////////////////////////////////////////// - -inline Number Number::New(napi_env env, double val) { - napi_value value; - napi_status status = napi_create_double(env, val, &value); - NAPI_THROW_IF_FAILED(env, status, Number()); - return Number(env, value); -} - -inline Number::Number() : Value() { -} - -inline Number::Number(napi_env env, napi_value value) : Value(env, value) { -} - -inline Number::operator int32_t() const { - return Int32Value(); -} - -inline Number::operator uint32_t() const { - return Uint32Value(); -} - -inline Number::operator int64_t() const { - return Int64Value(); -} - -inline Number::operator float() const { - return FloatValue(); -} - -inline Number::operator double() const { - return DoubleValue(); -} - -inline int32_t Number::Int32Value() const { - int32_t result; - napi_status status = napi_get_value_int32(_env, _value, &result); - NAPI_THROW_IF_FAILED(_env, status, 0); - return result; -} - -inline uint32_t Number::Uint32Value() const { - uint32_t result; - napi_status status = napi_get_value_uint32(_env, _value, &result); - NAPI_THROW_IF_FAILED(_env, status, 0); - return result; -} - -inline int64_t Number::Int64Value() const { - int64_t result; - napi_status status = napi_get_value_int64(_env, _value, &result); - NAPI_THROW_IF_FAILED(_env, status, 0); - return result; -} - -inline float Number::FloatValue() const { - return static_cast(DoubleValue()); -} - -inline double Number::DoubleValue() const { - double result; - napi_status status = napi_get_value_double(_env, _value, &result); - NAPI_THROW_IF_FAILED(_env, status, 0); - return result; -} - -// Currently experimental guard with the definition of NAPI_EXPERIMENTAL. -// Once it is no longer experimental guard with the NAPI_VERSION in which it is -// released instead. -#ifdef NAPI_EXPERIMENTAL -//////////////////////////////////////////////////////////////////////////////// -// BigInt Class -//////////////////////////////////////////////////////////////////////////////// - -inline BigInt BigInt::New(napi_env env, int64_t val) { - napi_value value; - napi_status status = napi_create_bigint_int64(env, val, &value); - NAPI_THROW_IF_FAILED(env, status, BigInt()); - return BigInt(env, value); -} - -inline BigInt BigInt::New(napi_env env, uint64_t val) { - napi_value value; - napi_status status = napi_create_bigint_uint64(env, val, &value); - NAPI_THROW_IF_FAILED(env, status, BigInt()); - return BigInt(env, value); -} - -inline BigInt BigInt::New(napi_env env, int sign_bit, size_t word_count, const uint64_t* words) { - napi_value value; - napi_status status = napi_create_bigint_words(env, sign_bit, word_count, words, &value); - NAPI_THROW_IF_FAILED(env, status, BigInt()); - return BigInt(env, value); -} - -inline BigInt::BigInt() : Value() { -} - -inline BigInt::BigInt(napi_env env, napi_value value) : Value(env, value) { -} - -inline int64_t BigInt::Int64Value(bool* lossless) const { - int64_t result; - napi_status status = napi_get_value_bigint_int64( - _env, _value, &result, lossless); - NAPI_THROW_IF_FAILED(_env, status, 0); - return result; -} - -inline uint64_t BigInt::Uint64Value(bool* lossless) const { - uint64_t result; - napi_status status = napi_get_value_bigint_uint64( - _env, _value, &result, lossless); - NAPI_THROW_IF_FAILED(_env, status, 0); - return result; -} - -inline size_t BigInt::WordCount() const { - size_t word_count; - napi_status status = napi_get_value_bigint_words( - _env, _value, nullptr, &word_count, nullptr); - NAPI_THROW_IF_FAILED(_env, status, 0); - return word_count; -} - -inline void BigInt::ToWords(int* sign_bit, size_t* word_count, uint64_t* words) { - napi_status status = napi_get_value_bigint_words( - _env, _value, sign_bit, word_count, words); - NAPI_THROW_IF_FAILED_VOID(_env, status); -} -#endif // NAPI_EXPERIMENTAL - -#if (NAPI_VERSION > 4) -//////////////////////////////////////////////////////////////////////////////// -// Date Class -//////////////////////////////////////////////////////////////////////////////// - -inline Date Date::New(napi_env env, double val) { - napi_value value; - napi_status status = napi_create_date(env, val, &value); - NAPI_THROW_IF_FAILED(env, status, Date()); - return Date(env, value); -} - -inline Date::Date() : Value() { -} - -inline Date::Date(napi_env env, napi_value value) : Value(env, value) { -} - -inline Date::operator double() const { - return ValueOf(); -} - -inline double Date::ValueOf() const { - double result; - napi_status status = napi_get_date_value( - _env, _value, &result); - NAPI_THROW_IF_FAILED(_env, status, 0); - return result; -} -#endif - -//////////////////////////////////////////////////////////////////////////////// -// Name class -//////////////////////////////////////////////////////////////////////////////// - -inline Name::Name() : Value() { -} - -inline Name::Name(napi_env env, napi_value value) : Value(env, value) { -} - -//////////////////////////////////////////////////////////////////////////////// -// String class -//////////////////////////////////////////////////////////////////////////////// - -inline String String::New(napi_env env, const std::string& val) { - return String::New(env, val.c_str(), val.size()); -} - -inline String String::New(napi_env env, const std::u16string& val) { - return String::New(env, val.c_str(), val.size()); -} - -inline String String::New(napi_env env, const char* val) { - napi_value value; - napi_status status = napi_create_string_utf8(env, val, std::strlen(val), &value); - NAPI_THROW_IF_FAILED(env, status, String()); - return String(env, value); -} - -inline String String::New(napi_env env, const char16_t* val) { - napi_value value; - napi_status status = napi_create_string_utf16(env, val, std::u16string(val).size(), &value); - NAPI_THROW_IF_FAILED(env, status, String()); - return String(env, value); -} - -inline String String::New(napi_env env, const char* val, size_t length) { - napi_value value; - napi_status status = napi_create_string_utf8(env, val, length, &value); - NAPI_THROW_IF_FAILED(env, status, String()); - return String(env, value); -} - -inline String String::New(napi_env env, const char16_t* val, size_t length) { - napi_value value; - napi_status status = napi_create_string_utf16(env, val, length, &value); - NAPI_THROW_IF_FAILED(env, status, String()); - return String(env, value); -} - -inline String::String() : Name() { -} - -inline String::String(napi_env env, napi_value value) : Name(env, value) { -} - -inline String::operator std::string() const { - return Utf8Value(); -} - -inline String::operator std::u16string() const { - return Utf16Value(); -} - -inline std::string String::Utf8Value() const { - size_t length; - napi_status status = napi_get_value_string_utf8(_env, _value, nullptr, 0, &length); - NAPI_THROW_IF_FAILED(_env, status, ""); - - std::string value; - value.reserve(length + 1); - value.resize(length); - status = napi_get_value_string_utf8(_env, _value, &value[0], value.capacity(), nullptr); - NAPI_THROW_IF_FAILED(_env, status, ""); - return value; -} - -inline std::u16string String::Utf16Value() const { - size_t length; - napi_status status = napi_get_value_string_utf16(_env, _value, nullptr, 0, &length); - NAPI_THROW_IF_FAILED(_env, status, NAPI_WIDE_TEXT("")); - - std::u16string value; - value.reserve(length + 1); - value.resize(length); - status = napi_get_value_string_utf16(_env, _value, &value[0], value.capacity(), nullptr); - NAPI_THROW_IF_FAILED(_env, status, NAPI_WIDE_TEXT("")); - return value; -} - -//////////////////////////////////////////////////////////////////////////////// -// Symbol class -//////////////////////////////////////////////////////////////////////////////// - -inline Symbol Symbol::New(napi_env env, const char* description) { - napi_value descriptionValue = description != nullptr ? - String::New(env, description) : static_cast(nullptr); - return Symbol::New(env, descriptionValue); -} - -inline Symbol Symbol::New(napi_env env, const std::string& description) { - napi_value descriptionValue = String::New(env, description); - return Symbol::New(env, descriptionValue); -} - -inline Symbol Symbol::New(napi_env env, String description) { - napi_value descriptionValue = description; - return Symbol::New(env, descriptionValue); -} - -inline Symbol Symbol::New(napi_env env, napi_value description) { - napi_value value; - napi_status status = napi_create_symbol(env, description, &value); - NAPI_THROW_IF_FAILED(env, status, Symbol()); - return Symbol(env, value); -} - -inline Symbol Symbol::WellKnown(napi_env env, const std::string& name) { - return Napi::Env(env).Global().Get("Symbol").As().Get(name).As(); -} - -inline Symbol::Symbol() : Name() { -} - -inline Symbol::Symbol(napi_env env, napi_value value) : Name(env, value) { -} - -//////////////////////////////////////////////////////////////////////////////// -// Automagic value creation -//////////////////////////////////////////////////////////////////////////////// - -namespace details { -template -struct vf_number { - static Number From(napi_env env, T value) { - return Number::New(env, static_cast(value)); - } -}; - -template<> -struct vf_number { - static Boolean From(napi_env env, bool value) { - return Boolean::New(env, value); - } -}; - -struct vf_utf8_charp { - static String From(napi_env env, const char* value) { - return String::New(env, value); - } -}; - -struct vf_utf16_charp { - static String From(napi_env env, const char16_t* value) { - return String::New(env, value); - } -}; -struct vf_utf8_string { - static String From(napi_env env, const std::string& value) { - return String::New(env, value); - } -}; - -struct vf_utf16_string { - static String From(napi_env env, const std::u16string& value) { - return String::New(env, value); - } -}; - -template -struct vf_fallback { - static Value From(napi_env env, const T& value) { - return Value(env, value); - } -}; - -template struct disjunction : std::false_type {}; -template struct disjunction : B {}; -template -struct disjunction - : std::conditional>::type {}; - -template -struct can_make_string - : disjunction::type, - typename std::is_convertible::type, - typename std::is_convertible::type, - typename std::is_convertible::type> {}; -} - -template -Value Value::From(napi_env env, const T& value) { - using Helper = typename std::conditional< - std::is_integral::value || std::is_floating_point::value, - details::vf_number, - typename std::conditional< - details::can_make_string::value, - String, - details::vf_fallback - >::type - >::type; - return Helper::From(env, value); -} - -template -String String::From(napi_env env, const T& value) { - struct Dummy {}; - using Helper = typename std::conditional< - std::is_convertible::value, - details::vf_utf8_charp, - typename std::conditional< - std::is_convertible::value, - details::vf_utf16_charp, - typename std::conditional< - std::is_convertible::value, - details::vf_utf8_string, - typename std::conditional< - std::is_convertible::value, - details::vf_utf16_string, - Dummy - >::type - >::type - >::type - >::type; - return Helper::From(env, value); -} - -//////////////////////////////////////////////////////////////////////////////// -// Object class -//////////////////////////////////////////////////////////////////////////////// - -template -inline Object::PropertyLValue::operator Value() const { - return Object(_env, _object).Get(_key); -} - -template template -inline Object::PropertyLValue& Object::PropertyLValue::operator =(ValueType value) { - Object(_env, _object).Set(_key, value); - return *this; -} - -template -inline Object::PropertyLValue::PropertyLValue(Object object, Key key) - : _env(object.Env()), _object(object), _key(key) {} - -inline Object Object::New(napi_env env) { - napi_value value; - napi_status status = napi_create_object(env, &value); - NAPI_THROW_IF_FAILED(env, status, Object()); - return Object(env, value); -} - -inline Object::Object() : Value() { -} - -inline Object::Object(napi_env env, napi_value value) : Value(env, value) { -} - -inline Object::PropertyLValue Object::operator [](const char* utf8name) { - return PropertyLValue(*this, utf8name); -} - -inline Object::PropertyLValue Object::operator [](const std::string& utf8name) { - return PropertyLValue(*this, utf8name); -} - -inline Object::PropertyLValue Object::operator [](uint32_t index) { - return PropertyLValue(*this, index); -} - -inline Value Object::operator [](const char* utf8name) const { - return Get(utf8name); -} - -inline Value Object::operator [](const std::string& utf8name) const { - return Get(utf8name); -} - -inline Value Object::operator [](uint32_t index) const { - return Get(index); -} - -inline bool Object::Has(napi_value key) const { - bool result; - napi_status status = napi_has_property(_env, _value, key, &result); - NAPI_THROW_IF_FAILED(_env, status, false); - return result; -} - -inline bool Object::Has(Value key) const { - bool result; - napi_status status = napi_has_property(_env, _value, key, &result); - NAPI_THROW_IF_FAILED(_env, status, false); - return result; -} - -inline bool Object::Has(const char* utf8name) const { - bool result; - napi_status status = napi_has_named_property(_env, _value, utf8name, &result); - NAPI_THROW_IF_FAILED(_env, status, false); - return result; -} - -inline bool Object::Has(const std::string& utf8name) const { - return Has(utf8name.c_str()); -} - -inline bool Object::HasOwnProperty(napi_value key) const { - bool result; - napi_status status = napi_has_own_property(_env, _value, key, &result); - NAPI_THROW_IF_FAILED(_env, status, false); - return result; -} - -inline bool Object::HasOwnProperty(Value key) const { - bool result; - napi_status status = napi_has_own_property(_env, _value, key, &result); - NAPI_THROW_IF_FAILED(_env, status, false); - return result; -} - -inline bool Object::HasOwnProperty(const char* utf8name) const { - napi_value key; - napi_status status = napi_create_string_utf8(_env, utf8name, std::strlen(utf8name), &key); - NAPI_THROW_IF_FAILED(_env, status, false); - return HasOwnProperty(key); -} - -inline bool Object::HasOwnProperty(const std::string& utf8name) const { - return HasOwnProperty(utf8name.c_str()); -} - -inline Value Object::Get(napi_value key) const { - napi_value result; - napi_status status = napi_get_property(_env, _value, key, &result); - NAPI_THROW_IF_FAILED(_env, status, Value()); - return Value(_env, result); -} - -inline Value Object::Get(Value key) const { - napi_value result; - napi_status status = napi_get_property(_env, _value, key, &result); - NAPI_THROW_IF_FAILED(_env, status, Value()); - return Value(_env, result); -} - -inline Value Object::Get(const char* utf8name) const { - napi_value result; - napi_status status = napi_get_named_property(_env, _value, utf8name, &result); - NAPI_THROW_IF_FAILED(_env, status, Value()); - return Value(_env, result); -} - -inline Value Object::Get(const std::string& utf8name) const { - return Get(utf8name.c_str()); -} - -template -inline void Object::Set(napi_value key, const ValueType& value) { - napi_status status = - napi_set_property(_env, _value, key, Value::From(_env, value)); - NAPI_THROW_IF_FAILED_VOID(_env, status); -} - -template -inline void Object::Set(Value key, const ValueType& value) { - napi_status status = - napi_set_property(_env, _value, key, Value::From(_env, value)); - NAPI_THROW_IF_FAILED_VOID(_env, status); -} - -template -inline void Object::Set(const char* utf8name, const ValueType& value) { - napi_status status = - napi_set_named_property(_env, _value, utf8name, Value::From(_env, value)); - NAPI_THROW_IF_FAILED_VOID(_env, status); -} - -template -inline void Object::Set(const std::string& utf8name, const ValueType& value) { - Set(utf8name.c_str(), value); -} - -inline bool Object::Delete(napi_value key) { - bool result; - napi_status status = napi_delete_property(_env, _value, key, &result); - NAPI_THROW_IF_FAILED(_env, status, false); - return result; -} - -inline bool Object::Delete(Value key) { - bool result; - napi_status status = napi_delete_property(_env, _value, key, &result); - NAPI_THROW_IF_FAILED(_env, status, false); - return result; -} - -inline bool Object::Delete(const char* utf8name) { - return Delete(String::New(_env, utf8name)); -} - -inline bool Object::Delete(const std::string& utf8name) { - return Delete(String::New(_env, utf8name)); -} - -inline bool Object::Has(uint32_t index) const { - bool result; - napi_status status = napi_has_element(_env, _value, index, &result); - NAPI_THROW_IF_FAILED(_env, status, false); - return result; -} - -inline Value Object::Get(uint32_t index) const { - napi_value value; - napi_status status = napi_get_element(_env, _value, index, &value); - NAPI_THROW_IF_FAILED(_env, status, Value()); - return Value(_env, value); -} - -template -inline void Object::Set(uint32_t index, const ValueType& value) { - napi_status status = - napi_set_element(_env, _value, index, Value::From(_env, value)); - NAPI_THROW_IF_FAILED_VOID(_env, status); -} - -inline bool Object::Delete(uint32_t index) { - bool result; - napi_status status = napi_delete_element(_env, _value, index, &result); - NAPI_THROW_IF_FAILED(_env, status, false); - return result; -} - -inline Array Object::GetPropertyNames() const { - napi_value result; - napi_status status = napi_get_property_names(_env, _value, &result); - NAPI_THROW_IF_FAILED(_env, status, Array()); - return Array(_env, result); -} - -inline void Object::DefineProperty(const PropertyDescriptor& property) { - napi_status status = napi_define_properties(_env, _value, 1, - reinterpret_cast(&property)); - NAPI_THROW_IF_FAILED_VOID(_env, status); -} - -inline void Object::DefineProperties(const std::initializer_list& properties) { - napi_status status = napi_define_properties(_env, _value, properties.size(), - reinterpret_cast(properties.begin())); - NAPI_THROW_IF_FAILED_VOID(_env, status); -} - -inline void Object::DefineProperties(const std::vector& properties) { - napi_status status = napi_define_properties(_env, _value, properties.size(), - reinterpret_cast(properties.data())); - NAPI_THROW_IF_FAILED_VOID(_env, status); -} - -inline bool Object::InstanceOf(const Function& constructor) const { - bool result; - napi_status status = napi_instanceof(_env, _value, constructor, &result); - NAPI_THROW_IF_FAILED(_env, status, false); - return result; -} - -template -inline void Object::AddFinalizer(Finalizer finalizeCallback, T* data) { - details::FinalizeData* finalizeData = - new details::FinalizeData({ finalizeCallback, nullptr }); - napi_status status = - details::AttachData(_env, - *this, - data, - details::FinalizeData::Wrapper, - finalizeData); - if (status != napi_ok) { - delete finalizeData; - NAPI_THROW_IF_FAILED_VOID(_env, status); - } -} - -template -inline void Object::AddFinalizer(Finalizer finalizeCallback, - T* data, - Hint* finalizeHint) { - details::FinalizeData* finalizeData = - new details::FinalizeData({ finalizeCallback, finalizeHint }); - napi_status status = - details::AttachData(_env, - *this, - data, - details::FinalizeData::WrapperWithHint, - finalizeData); - if (status != napi_ok) { - delete finalizeData; - NAPI_THROW_IF_FAILED_VOID(_env, status); - } -} - -//////////////////////////////////////////////////////////////////////////////// -// External class -//////////////////////////////////////////////////////////////////////////////// - -template -inline External External::New(napi_env env, T* data) { - napi_value value; - napi_status status = napi_create_external(env, data, nullptr, nullptr, &value); - NAPI_THROW_IF_FAILED(env, status, External()); - return External(env, value); -} - -template -template -inline External External::New(napi_env env, - T* data, - Finalizer finalizeCallback) { - napi_value value; - details::FinalizeData* finalizeData = - new details::FinalizeData({ finalizeCallback, nullptr }); - napi_status status = napi_create_external( - env, - data, - details::FinalizeData::Wrapper, - finalizeData, - &value); - if (status != napi_ok) { - delete finalizeData; - NAPI_THROW_IF_FAILED(env, status, External()); - } - return External(env, value); -} - -template -template -inline External External::New(napi_env env, - T* data, - Finalizer finalizeCallback, - Hint* finalizeHint) { - napi_value value; - details::FinalizeData* finalizeData = - new details::FinalizeData({ finalizeCallback, finalizeHint }); - napi_status status = napi_create_external( - env, - data, - details::FinalizeData::WrapperWithHint, - finalizeData, - &value); - if (status != napi_ok) { - delete finalizeData; - NAPI_THROW_IF_FAILED(env, status, External()); - } - return External(env, value); -} - -template -inline External::External() : Value() { -} - -template -inline External::External(napi_env env, napi_value value) : Value(env, value) { -} - -template -inline T* External::Data() const { - void* data; - napi_status status = napi_get_value_external(_env, _value, &data); - NAPI_THROW_IF_FAILED(_env, status, nullptr); - return reinterpret_cast(data); -} - -//////////////////////////////////////////////////////////////////////////////// -// Array class -//////////////////////////////////////////////////////////////////////////////// - -inline Array Array::New(napi_env env) { - napi_value value; - napi_status status = napi_create_array(env, &value); - NAPI_THROW_IF_FAILED(env, status, Array()); - return Array(env, value); -} - -inline Array Array::New(napi_env env, size_t length) { - napi_value value; - napi_status status = napi_create_array_with_length(env, length, &value); - NAPI_THROW_IF_FAILED(env, status, Array()); - return Array(env, value); -} - -inline Array::Array() : Object() { -} - -inline Array::Array(napi_env env, napi_value value) : Object(env, value) { -} - -inline uint32_t Array::Length() const { - uint32_t result; - napi_status status = napi_get_array_length(_env, _value, &result); - NAPI_THROW_IF_FAILED(_env, status, 0); - return result; -} - -//////////////////////////////////////////////////////////////////////////////// -// ArrayBuffer class -//////////////////////////////////////////////////////////////////////////////// - -inline ArrayBuffer ArrayBuffer::New(napi_env env, size_t byteLength) { - napi_value value; - void* data; - napi_status status = napi_create_arraybuffer(env, byteLength, &data, &value); - NAPI_THROW_IF_FAILED(env, status, ArrayBuffer()); - - return ArrayBuffer(env, value); -} - -inline ArrayBuffer ArrayBuffer::New(napi_env env, - void* externalData, - size_t byteLength) { - napi_value value; - napi_status status = napi_create_external_arraybuffer( - env, externalData, byteLength, nullptr, nullptr, &value); - NAPI_THROW_IF_FAILED(env, status, ArrayBuffer()); - - return ArrayBuffer(env, value); -} - -template -inline ArrayBuffer ArrayBuffer::New(napi_env env, - void* externalData, - size_t byteLength, - Finalizer finalizeCallback) { - napi_value value; - details::FinalizeData* finalizeData = - new details::FinalizeData({ finalizeCallback, nullptr }); - napi_status status = napi_create_external_arraybuffer( - env, - externalData, - byteLength, - details::FinalizeData::Wrapper, - finalizeData, - &value); - if (status != napi_ok) { - delete finalizeData; - NAPI_THROW_IF_FAILED(env, status, ArrayBuffer()); - } - - return ArrayBuffer(env, value); -} - -template -inline ArrayBuffer ArrayBuffer::New(napi_env env, - void* externalData, - size_t byteLength, - Finalizer finalizeCallback, - Hint* finalizeHint) { - napi_value value; - details::FinalizeData* finalizeData = - new details::FinalizeData({ finalizeCallback, finalizeHint }); - napi_status status = napi_create_external_arraybuffer( - env, - externalData, - byteLength, - details::FinalizeData::WrapperWithHint, - finalizeData, - &value); - if (status != napi_ok) { - delete finalizeData; - NAPI_THROW_IF_FAILED(env, status, ArrayBuffer()); - } - - return ArrayBuffer(env, value); -} - -inline ArrayBuffer::ArrayBuffer() : Object() { -} - -inline ArrayBuffer::ArrayBuffer(napi_env env, napi_value value) - : Object(env, value) { -} - -inline void* ArrayBuffer::Data() { - void* data; - napi_status status = napi_get_arraybuffer_info(_env, _value, &data, nullptr); - NAPI_THROW_IF_FAILED(_env, status, nullptr); - return data; -} - -inline size_t ArrayBuffer::ByteLength() { - size_t length; - napi_status status = napi_get_arraybuffer_info(_env, _value, nullptr, &length); - NAPI_THROW_IF_FAILED(_env, status, 0); - return length; -} - -//////////////////////////////////////////////////////////////////////////////// -// DataView class -//////////////////////////////////////////////////////////////////////////////// -inline DataView DataView::New(napi_env env, - Napi::ArrayBuffer arrayBuffer) { - return New(env, arrayBuffer, 0, arrayBuffer.ByteLength()); -} - -inline DataView DataView::New(napi_env env, - Napi::ArrayBuffer arrayBuffer, - size_t byteOffset) { - if (byteOffset > arrayBuffer.ByteLength()) { - NAPI_THROW(RangeError::New(env, - "Start offset is outside the bounds of the buffer"), - DataView()); - } - return New(env, arrayBuffer, byteOffset, - arrayBuffer.ByteLength() - byteOffset); -} - -inline DataView DataView::New(napi_env env, - Napi::ArrayBuffer arrayBuffer, - size_t byteOffset, - size_t byteLength) { - if (byteOffset + byteLength > arrayBuffer.ByteLength()) { - NAPI_THROW(RangeError::New(env, "Invalid DataView length"), - DataView()); - } - napi_value value; - napi_status status = napi_create_dataview( - env, byteLength, arrayBuffer, byteOffset, &value); - NAPI_THROW_IF_FAILED(env, status, DataView()); - return DataView(env, value); -} - -inline DataView::DataView() : Object() { -} - -inline DataView::DataView(napi_env env, napi_value value) : Object(env, value) { - napi_status status = napi_get_dataview_info( - _env, - _value /* dataView */, - &_length /* byteLength */, - &_data /* data */, - nullptr /* arrayBuffer */, - nullptr /* byteOffset */); - NAPI_THROW_IF_FAILED_VOID(_env, status); -} - -inline Napi::ArrayBuffer DataView::ArrayBuffer() const { - napi_value arrayBuffer; - napi_status status = napi_get_dataview_info( - _env, - _value /* dataView */, - nullptr /* byteLength */, - nullptr /* data */, - &arrayBuffer /* arrayBuffer */, - nullptr /* byteOffset */); - NAPI_THROW_IF_FAILED(_env, status, Napi::ArrayBuffer()); - return Napi::ArrayBuffer(_env, arrayBuffer); -} - -inline size_t DataView::ByteOffset() const { - size_t byteOffset; - napi_status status = napi_get_dataview_info( - _env, - _value /* dataView */, - nullptr /* byteLength */, - nullptr /* data */, - nullptr /* arrayBuffer */, - &byteOffset /* byteOffset */); - NAPI_THROW_IF_FAILED(_env, status, 0); - return byteOffset; -} - -inline size_t DataView::ByteLength() const { - return _length; -} - -inline void* DataView::Data() const { - return _data; -} - -inline float DataView::GetFloat32(size_t byteOffset) const { - return ReadData(byteOffset); -} - -inline double DataView::GetFloat64(size_t byteOffset) const { - return ReadData(byteOffset); -} - -inline int8_t DataView::GetInt8(size_t byteOffset) const { - return ReadData(byteOffset); -} - -inline int16_t DataView::GetInt16(size_t byteOffset) const { - return ReadData(byteOffset); -} - -inline int32_t DataView::GetInt32(size_t byteOffset) const { - return ReadData(byteOffset); -} - -inline uint8_t DataView::GetUint8(size_t byteOffset) const { - return ReadData(byteOffset); -} - -inline uint16_t DataView::GetUint16(size_t byteOffset) const { - return ReadData(byteOffset); -} - -inline uint32_t DataView::GetUint32(size_t byteOffset) const { - return ReadData(byteOffset); -} - -inline void DataView::SetFloat32(size_t byteOffset, float value) const { - WriteData(byteOffset, value); -} - -inline void DataView::SetFloat64(size_t byteOffset, double value) const { - WriteData(byteOffset, value); -} - -inline void DataView::SetInt8(size_t byteOffset, int8_t value) const { - WriteData(byteOffset, value); -} - -inline void DataView::SetInt16(size_t byteOffset, int16_t value) const { - WriteData(byteOffset, value); -} - -inline void DataView::SetInt32(size_t byteOffset, int32_t value) const { - WriteData(byteOffset, value); -} - -inline void DataView::SetUint8(size_t byteOffset, uint8_t value) const { - WriteData(byteOffset, value); -} - -inline void DataView::SetUint16(size_t byteOffset, uint16_t value) const { - WriteData(byteOffset, value); -} - -inline void DataView::SetUint32(size_t byteOffset, uint32_t value) const { - WriteData(byteOffset, value); -} - -template -inline T DataView::ReadData(size_t byteOffset) const { - if (byteOffset + sizeof(T) > _length || - byteOffset + sizeof(T) < byteOffset) { // overflow - NAPI_THROW(RangeError::New(_env, - "Offset is outside the bounds of the DataView"), 0); - } - - return *reinterpret_cast(static_cast(_data) + byteOffset); -} - -template -inline void DataView::WriteData(size_t byteOffset, T value) const { - if (byteOffset + sizeof(T) > _length || - byteOffset + sizeof(T) < byteOffset) { // overflow - NAPI_THROW_VOID(RangeError::New(_env, - "Offset is outside the bounds of the DataView")); - } - - *reinterpret_cast(static_cast(_data) + byteOffset) = value; -} - -//////////////////////////////////////////////////////////////////////////////// -// TypedArray class -//////////////////////////////////////////////////////////////////////////////// - -inline TypedArray::TypedArray() - : Object(), _type(TypedArray::unknown_array_type), _length(0) { -} - -inline TypedArray::TypedArray(napi_env env, napi_value value) - : Object(env, value), _type(TypedArray::unknown_array_type), _length(0) { -} - -inline TypedArray::TypedArray(napi_env env, - napi_value value, - napi_typedarray_type type, - size_t length) - : Object(env, value), _type(type), _length(length) { -} - -inline napi_typedarray_type TypedArray::TypedArrayType() const { - if (_type == TypedArray::unknown_array_type) { - napi_status status = napi_get_typedarray_info(_env, _value, - &const_cast(this)->_type, &const_cast(this)->_length, - nullptr, nullptr, nullptr); - NAPI_THROW_IF_FAILED(_env, status, napi_int8_array); - } - - return _type; -} - -inline uint8_t TypedArray::ElementSize() const { - switch (TypedArrayType()) { - case napi_int8_array: - case napi_uint8_array: - case napi_uint8_clamped_array: - return 1; - case napi_int16_array: - case napi_uint16_array: - return 2; - case napi_int32_array: - case napi_uint32_array: - case napi_float32_array: - return 4; - case napi_float64_array: - return 8; - default: - return 0; - } -} - -inline size_t TypedArray::ElementLength() const { - if (_type == TypedArray::unknown_array_type) { - napi_status status = napi_get_typedarray_info(_env, _value, - &const_cast(this)->_type, &const_cast(this)->_length, - nullptr, nullptr, nullptr); - NAPI_THROW_IF_FAILED(_env, status, 0); - } - - return _length; -} - -inline size_t TypedArray::ByteOffset() const { - size_t byteOffset; - napi_status status = napi_get_typedarray_info( - _env, _value, nullptr, nullptr, nullptr, nullptr, &byteOffset); - NAPI_THROW_IF_FAILED(_env, status, 0); - return byteOffset; -} - -inline size_t TypedArray::ByteLength() const { - return ElementSize() * ElementLength(); -} - -inline Napi::ArrayBuffer TypedArray::ArrayBuffer() const { - napi_value arrayBuffer; - napi_status status = napi_get_typedarray_info( - _env, _value, nullptr, nullptr, nullptr, &arrayBuffer, nullptr); - NAPI_THROW_IF_FAILED(_env, status, Napi::ArrayBuffer()); - return Napi::ArrayBuffer(_env, arrayBuffer); -} - -//////////////////////////////////////////////////////////////////////////////// -// TypedArrayOf class -//////////////////////////////////////////////////////////////////////////////// - -template -inline TypedArrayOf TypedArrayOf::New(napi_env env, - size_t elementLength, - napi_typedarray_type type) { - Napi::ArrayBuffer arrayBuffer = Napi::ArrayBuffer::New(env, elementLength * sizeof (T)); - return New(env, elementLength, arrayBuffer, 0, type); -} - -template -inline TypedArrayOf TypedArrayOf::New(napi_env env, - size_t elementLength, - Napi::ArrayBuffer arrayBuffer, - size_t bufferOffset, - napi_typedarray_type type) { - napi_value value; - napi_status status = napi_create_typedarray( - env, type, elementLength, arrayBuffer, bufferOffset, &value); - NAPI_THROW_IF_FAILED(env, status, TypedArrayOf()); - - return TypedArrayOf( - env, value, type, elementLength, - reinterpret_cast(reinterpret_cast(arrayBuffer.Data()) + bufferOffset)); -} - -template -inline TypedArrayOf::TypedArrayOf() : TypedArray(), _data(nullptr) { -} - -template -inline TypedArrayOf::TypedArrayOf(napi_env env, napi_value value) - : TypedArray(env, value), _data(nullptr) { - napi_status status = napi_get_typedarray_info( - _env, _value, &_type, &_length, reinterpret_cast(&_data), nullptr, nullptr); - NAPI_THROW_IF_FAILED_VOID(_env, status); -} - -template -inline TypedArrayOf::TypedArrayOf(napi_env env, - napi_value value, - napi_typedarray_type type, - size_t length, - T* data) - : TypedArray(env, value, type, length), _data(data) { - if (!(type == TypedArrayTypeForPrimitiveType() || - (type == napi_uint8_clamped_array && std::is_same::value))) { - NAPI_THROW_VOID(TypeError::New(env, "Array type must match the template parameter. " - "(Uint8 arrays may optionally have the \"clamped\" array type.)")); - } -} - -template -inline T& TypedArrayOf::operator [](size_t index) { - return _data[index]; -} - -template -inline const T& TypedArrayOf::operator [](size_t index) const { - return _data[index]; -} - -template -inline T* TypedArrayOf::Data() { - return _data; -} - -template -inline const T* TypedArrayOf::Data() const { - return _data; -} - -//////////////////////////////////////////////////////////////////////////////// -// Function class -//////////////////////////////////////////////////////////////////////////////// - -template -static inline napi_status -CreateFunction(napi_env env, - const char* utf8name, - napi_callback cb, - CbData* data, - napi_value* result) { - napi_status status = - napi_create_function(env, utf8name, NAPI_AUTO_LENGTH, cb, data, result); - if (status == napi_ok) { - status = Napi::details::AttachData(env, *result, data); - } - - return status; -} - -template -inline Function Function::New(napi_env env, const char* utf8name, void* data) { - napi_value result = nullptr; - napi_status status = napi_create_function( - env, utf8name, NAPI_AUTO_LENGTH, - [](napi_env env, napi_callback_info info) { - CallbackInfo callbackInfo(env, info); - return details::WrapCallback([&] { - cb(callbackInfo); - return nullptr; - }); - }, data, &result); - NAPI_THROW_IF_FAILED(env, status, Function()); - return Function(env, result); -} - -template -inline Function Function::New(napi_env env, const char* utf8name, void* data) { - napi_value result = nullptr; - napi_status status = napi_create_function( - env, utf8name, NAPI_AUTO_LENGTH, - [](napi_env env, napi_callback_info info) { - CallbackInfo callbackInfo(env, info); - return details::WrapCallback([&] { - return cb(callbackInfo); - }); - }, data, &result); - NAPI_THROW_IF_FAILED(env, status, Function()); - return Function(env, result); -} - -template -inline Function Function::New(napi_env env, - const std::string& utf8name, - void* data) { - return Function::New(env, utf8name.c_str(), data); -} - -template -inline Function Function::New(napi_env env, - const std::string& utf8name, - void* data) { - return Function::New(env, utf8name.c_str(), data); -} - -template -inline Function Function::New(napi_env env, - Callable cb, - const char* utf8name, - void* data) { - typedef decltype(cb(CallbackInfo(nullptr, nullptr))) ReturnType; - typedef details::CallbackData CbData; - auto callbackData = new CbData({ cb, data }); - - napi_value value; - napi_status status = CreateFunction(env, - utf8name, - CbData::Wrapper, - callbackData, - &value); - if (status != napi_ok) { - delete callbackData; - NAPI_THROW_IF_FAILED(env, status, Function()); - } - - return Function(env, value); -} - -template -inline Function Function::New(napi_env env, - Callable cb, - const std::string& utf8name, - void* data) { - return New(env, cb, utf8name.c_str(), data); -} - -inline Function::Function() : Object() { -} - -inline Function::Function(napi_env env, napi_value value) : Object(env, value) { -} - -inline Value Function::operator ()(const std::initializer_list& args) const { - return Call(Env().Undefined(), args); -} - -inline Value Function::Call(const std::initializer_list& args) const { - return Call(Env().Undefined(), args); -} - -inline Value Function::Call(const std::vector& args) const { - return Call(Env().Undefined(), args); -} - -inline Value Function::Call(size_t argc, const napi_value* args) const { - return Call(Env().Undefined(), argc, args); -} - -inline Value Function::Call(napi_value recv, const std::initializer_list& args) const { - return Call(recv, args.size(), args.begin()); -} - -inline Value Function::Call(napi_value recv, const std::vector& args) const { - return Call(recv, args.size(), args.data()); -} - -inline Value Function::Call(napi_value recv, size_t argc, const napi_value* args) const { - napi_value result; - napi_status status = napi_call_function( - _env, recv, _value, argc, args, &result); - NAPI_THROW_IF_FAILED(_env, status, Value()); - return Value(_env, result); -} - -inline Value Function::MakeCallback( - napi_value recv, - const std::initializer_list& args, - napi_async_context context) const { - return MakeCallback(recv, args.size(), args.begin(), context); -} - -inline Value Function::MakeCallback( - napi_value recv, - const std::vector& args, - napi_async_context context) const { - return MakeCallback(recv, args.size(), args.data(), context); -} - -inline Value Function::MakeCallback( - napi_value recv, - size_t argc, - const napi_value* args, - napi_async_context context) const { - napi_value result; - napi_status status = napi_make_callback( - _env, context, recv, _value, argc, args, &result); - NAPI_THROW_IF_FAILED(_env, status, Value()); - return Value(_env, result); -} - -inline Object Function::New(const std::initializer_list& args) const { - return New(args.size(), args.begin()); -} - -inline Object Function::New(const std::vector& args) const { - return New(args.size(), args.data()); -} - -inline Object Function::New(size_t argc, const napi_value* args) const { - napi_value result; - napi_status status = napi_new_instance( - _env, _value, argc, args, &result); - NAPI_THROW_IF_FAILED(_env, status, Object()); - return Object(_env, result); -} - -//////////////////////////////////////////////////////////////////////////////// -// Promise class -//////////////////////////////////////////////////////////////////////////////// - -inline Promise::Deferred Promise::Deferred::New(napi_env env) { - return Promise::Deferred(env); -} - -inline Promise::Deferred::Deferred(napi_env env) : _env(env) { - napi_status status = napi_create_promise(_env, &_deferred, &_promise); - NAPI_THROW_IF_FAILED_VOID(_env, status); -} - -inline Promise Promise::Deferred::Promise() const { - return Napi::Promise(_env, _promise); -} - -inline Napi::Env Promise::Deferred::Env() const { - return Napi::Env(_env); -} - -inline void Promise::Deferred::Resolve(napi_value value) const { - napi_status status = napi_resolve_deferred(_env, _deferred, value); - NAPI_THROW_IF_FAILED_VOID(_env, status); -} - -inline void Promise::Deferred::Reject(napi_value value) const { - napi_status status = napi_reject_deferred(_env, _deferred, value); - NAPI_THROW_IF_FAILED_VOID(_env, status); -} - -inline Promise::Promise(napi_env env, napi_value value) : Object(env, value) { -} - -//////////////////////////////////////////////////////////////////////////////// -// Buffer class -//////////////////////////////////////////////////////////////////////////////// - -template -inline Buffer Buffer::New(napi_env env, size_t length) { - napi_value value; - void* data; - napi_status status = napi_create_buffer(env, length * sizeof (T), &data, &value); - NAPI_THROW_IF_FAILED(env, status, Buffer()); - return Buffer(env, value, length, static_cast(data)); -} - -template -inline Buffer Buffer::New(napi_env env, T* data, size_t length) { - napi_value value; - napi_status status = napi_create_external_buffer( - env, length * sizeof (T), data, nullptr, nullptr, &value); - NAPI_THROW_IF_FAILED(env, status, Buffer()); - return Buffer(env, value, length, data); -} - -template -template -inline Buffer Buffer::New(napi_env env, - T* data, - size_t length, - Finalizer finalizeCallback) { - napi_value value; - details::FinalizeData* finalizeData = - new details::FinalizeData({ finalizeCallback, nullptr }); - napi_status status = napi_create_external_buffer( - env, - length * sizeof (T), - data, - details::FinalizeData::Wrapper, - finalizeData, - &value); - if (status != napi_ok) { - delete finalizeData; - NAPI_THROW_IF_FAILED(env, status, Buffer()); - } - return Buffer(env, value, length, data); -} - -template -template -inline Buffer Buffer::New(napi_env env, - T* data, - size_t length, - Finalizer finalizeCallback, - Hint* finalizeHint) { - napi_value value; - details::FinalizeData* finalizeData = - new details::FinalizeData({ finalizeCallback, finalizeHint }); - napi_status status = napi_create_external_buffer( - env, - length * sizeof (T), - data, - details::FinalizeData::WrapperWithHint, - finalizeData, - &value); - if (status != napi_ok) { - delete finalizeData; - NAPI_THROW_IF_FAILED(env, status, Buffer()); - } - return Buffer(env, value, length, data); -} - -template -inline Buffer Buffer::Copy(napi_env env, const T* data, size_t length) { - napi_value value; - napi_status status = napi_create_buffer_copy( - env, length * sizeof (T), data, nullptr, &value); - NAPI_THROW_IF_FAILED(env, status, Buffer()); - return Buffer(env, value); -} - -template -inline Buffer::Buffer() : Uint8Array(), _length(0), _data(nullptr) { -} - -template -inline Buffer::Buffer(napi_env env, napi_value value) - : Uint8Array(env, value), _length(0), _data(nullptr) { -} - -template -inline Buffer::Buffer(napi_env env, napi_value value, size_t length, T* data) - : Uint8Array(env, value), _length(length), _data(data) { -} - -template -inline size_t Buffer::Length() const { - EnsureInfo(); - return _length; -} - -template -inline T* Buffer::Data() const { - EnsureInfo(); - return _data; -} - -template -inline void Buffer::EnsureInfo() const { - // The Buffer instance may have been constructed from a napi_value whose - // length/data are not yet known. Fetch and cache these values just once, - // since they can never change during the lifetime of the Buffer. - if (_data == nullptr) { - size_t byteLength; - void* voidData; - napi_status status = napi_get_buffer_info(_env, _value, &voidData, &byteLength); - NAPI_THROW_IF_FAILED_VOID(_env, status); - _length = byteLength / sizeof (T); - _data = static_cast(voidData); - } -} - -//////////////////////////////////////////////////////////////////////////////// -// Error class -//////////////////////////////////////////////////////////////////////////////// - -inline Error Error::New(napi_env env) { - napi_status status; - napi_value error = nullptr; - bool is_exception_pending; - const napi_extended_error_info* info; - - // We must retrieve the last error info before doing anything else, because - // doing anything else will replace the last error info. - status = napi_get_last_error_info(env, &info); - NAPI_FATAL_IF_FAILED(status, "Error::New", "napi_get_last_error_info"); - - status = napi_is_exception_pending(env, &is_exception_pending); - NAPI_FATAL_IF_FAILED(status, "Error::New", "napi_is_exception_pending"); - - // A pending exception takes precedence over any internal error status. - if (is_exception_pending) { - status = napi_get_and_clear_last_exception(env, &error); - NAPI_FATAL_IF_FAILED(status, "Error::New", "napi_get_and_clear_last_exception"); - } - else { - const char* error_message = info->error_message != nullptr ? - info->error_message : "Error in native callback"; - - napi_value message; - status = napi_create_string_utf8( - env, - error_message, - std::strlen(error_message), - &message); - NAPI_FATAL_IF_FAILED(status, "Error::New", "napi_create_string_utf8"); - - switch (info->error_code) { - case napi_object_expected: - case napi_string_expected: - case napi_boolean_expected: - case napi_number_expected: - status = napi_create_type_error(env, nullptr, message, &error); - break; - default: - status = napi_create_error(env, nullptr, message, &error); - break; - } - NAPI_FATAL_IF_FAILED(status, "Error::New", "napi_create_error"); - } - - return Error(env, error); -} - -inline Error Error::New(napi_env env, const char* message) { - return Error::New(env, message, std::strlen(message), napi_create_error); -} - -inline Error Error::New(napi_env env, const std::string& message) { - return Error::New(env, message.c_str(), message.size(), napi_create_error); -} - -inline NAPI_NO_RETURN void Error::Fatal(const char* location, const char* message) { - napi_fatal_error(location, NAPI_AUTO_LENGTH, message, NAPI_AUTO_LENGTH); -} - -inline Error::Error() : ObjectReference() { -} - -inline Error::Error(napi_env env, napi_value value) : ObjectReference(env, nullptr) { - if (value != nullptr) { - napi_status status = napi_create_reference(env, value, 1, &_ref); - - // Avoid infinite recursion in the failure case. - // Don't try to construct & throw another Error instance. - NAPI_FATAL_IF_FAILED(status, "Error::Error", "napi_create_reference"); - } -} - -inline Error::Error(Error&& other) : ObjectReference(std::move(other)) { -} - -inline Error& Error::operator =(Error&& other) { - static_cast*>(this)->operator=(std::move(other)); - return *this; -} - -inline Error::Error(const Error& other) : ObjectReference(other) { -} - -inline Error& Error::operator =(const Error& other) { - Reset(); - - _env = other.Env(); - HandleScope scope(_env); - - napi_value value = other.Value(); - if (value != nullptr) { - napi_status status = napi_create_reference(_env, value, 1, &_ref); - NAPI_THROW_IF_FAILED(_env, status, *this); - } - - return *this; -} - -inline const std::string& Error::Message() const NAPI_NOEXCEPT { - if (_message.size() == 0 && _env != nullptr) { -#ifdef NAPI_CPP_EXCEPTIONS - try { - _message = Get("message").As(); - } - catch (...) { - // Catch all errors here, to include e.g. a std::bad_alloc from - // the std::string::operator=, because this method may not throw. - } -#else // NAPI_CPP_EXCEPTIONS - _message = Get("message").As(); -#endif // NAPI_CPP_EXCEPTIONS - } - return _message; -} - -inline void Error::ThrowAsJavaScriptException() const { - HandleScope scope(_env); - if (!IsEmpty()) { - - // We intentionally don't use `NAPI_THROW_*` macros here to ensure - // that there is no possible recursion as `ThrowAsJavaScriptException` - // is part of `NAPI_THROW_*` macro definition for noexcept. - - napi_status status = napi_throw(_env, Value()); - -#ifdef NAPI_CPP_EXCEPTIONS - if (status != napi_ok) { - throw Error::New(_env); - } -#else // NAPI_CPP_EXCEPTIONS - NAPI_FATAL_IF_FAILED(status, "Error::ThrowAsJavaScriptException", "napi_throw"); -#endif // NAPI_CPP_EXCEPTIONS - } -} - -#ifdef NAPI_CPP_EXCEPTIONS - -inline const char* Error::what() const NAPI_NOEXCEPT { - return Message().c_str(); -} - -#endif // NAPI_CPP_EXCEPTIONS - -template -inline TError Error::New(napi_env env, - const char* message, - size_t length, - create_error_fn create_error) { - napi_value str; - napi_status status = napi_create_string_utf8(env, message, length, &str); - NAPI_THROW_IF_FAILED(env, status, TError()); - - napi_value error; - status = create_error(env, nullptr, str, &error); - NAPI_THROW_IF_FAILED(env, status, TError()); - - return TError(env, error); -} - -inline TypeError TypeError::New(napi_env env, const char* message) { - return Error::New(env, message, std::strlen(message), napi_create_type_error); -} - -inline TypeError TypeError::New(napi_env env, const std::string& message) { - return Error::New(env, message.c_str(), message.size(), napi_create_type_error); -} - -inline TypeError::TypeError() : Error() { -} - -inline TypeError::TypeError(napi_env env, napi_value value) : Error(env, value) { -} - -inline RangeError RangeError::New(napi_env env, const char* message) { - return Error::New(env, message, std::strlen(message), napi_create_range_error); -} - -inline RangeError RangeError::New(napi_env env, const std::string& message) { - return Error::New(env, message.c_str(), message.size(), napi_create_range_error); -} - -inline RangeError::RangeError() : Error() { -} - -inline RangeError::RangeError(napi_env env, napi_value value) : Error(env, value) { -} - -//////////////////////////////////////////////////////////////////////////////// -// Reference class -//////////////////////////////////////////////////////////////////////////////// - -template -inline Reference Reference::New(const T& value, uint32_t initialRefcount) { - napi_env env = value.Env(); - napi_value val = value; - - if (val == nullptr) { - return Reference(env, nullptr); - } - - napi_ref ref; - napi_status status = napi_create_reference(env, value, initialRefcount, &ref); - NAPI_THROW_IF_FAILED(env, status, Reference()); - - return Reference(env, ref); -} - - -template -inline Reference::Reference() : _env(nullptr), _ref(nullptr), _suppressDestruct(false) { -} - -template -inline Reference::Reference(napi_env env, napi_ref ref) - : _env(env), _ref(ref), _suppressDestruct(false) { -} - -template -inline Reference::~Reference() { - if (_ref != nullptr) { - if (!_suppressDestruct) { - napi_delete_reference(_env, _ref); - } - - _ref = nullptr; - } -} - -template -inline Reference::Reference(Reference&& other) - : _env(other._env), _ref(other._ref), _suppressDestruct(other._suppressDestruct) { - other._env = nullptr; - other._ref = nullptr; - other._suppressDestruct = false; -} - -template -inline Reference& Reference::operator =(Reference&& other) { - Reset(); - _env = other._env; - _ref = other._ref; - _suppressDestruct = other._suppressDestruct; - other._env = nullptr; - other._ref = nullptr; - other._suppressDestruct = false; - return *this; -} - -template -inline Reference::Reference(const Reference& other) - : _env(other._env), _ref(nullptr), _suppressDestruct(false) { - HandleScope scope(_env); - - napi_value value = other.Value(); - if (value != nullptr) { - // Copying is a limited scenario (currently only used for Error object) and always creates a - // strong reference to the given value even if the incoming reference is weak. - napi_status status = napi_create_reference(_env, value, 1, &_ref); - NAPI_FATAL_IF_FAILED(status, "Reference::Reference", "napi_create_reference"); - } -} - -template -inline Reference::operator napi_ref() const { - return _ref; -} - -template -inline bool Reference::operator ==(const Reference &other) const { - HandleScope scope(_env); - return this->Value().StrictEquals(other.Value()); -} - -template -inline bool Reference::operator !=(const Reference &other) const { - return !this->operator ==(other); -} - -template -inline Napi::Env Reference::Env() const { - return Napi::Env(_env); -} - -template -inline bool Reference::IsEmpty() const { - return _ref == nullptr; -} - -template -inline T Reference::Value() const { - if (_ref == nullptr) { - return T(_env, nullptr); - } - - napi_value value; - napi_status status = napi_get_reference_value(_env, _ref, &value); - NAPI_THROW_IF_FAILED(_env, status, T()); - return T(_env, value); -} - -template -inline uint32_t Reference::Ref() { - uint32_t result; - napi_status status = napi_reference_ref(_env, _ref, &result); - NAPI_THROW_IF_FAILED(_env, status, 1); - return result; -} - -template -inline uint32_t Reference::Unref() { - uint32_t result; - napi_status status = napi_reference_unref(_env, _ref, &result); - NAPI_THROW_IF_FAILED(_env, status, 1); - return result; -} - -template -inline void Reference::Reset() { - if (_ref != nullptr) { - napi_status status = napi_delete_reference(_env, _ref); - NAPI_THROW_IF_FAILED_VOID(_env, status); - _ref = nullptr; - } -} - -template -inline void Reference::Reset(const T& value, uint32_t refcount) { - Reset(); - _env = value.Env(); - - napi_value val = value; - if (val != nullptr) { - napi_status status = napi_create_reference(_env, value, refcount, &_ref); - NAPI_THROW_IF_FAILED_VOID(_env, status); - } -} - -template -inline void Reference::SuppressDestruct() { - _suppressDestruct = true; -} - -template -inline Reference Weak(T value) { - return Reference::New(value, 0); -} - -inline ObjectReference Weak(Object value) { - return Reference::New(value, 0); -} - -inline FunctionReference Weak(Function value) { - return Reference::New(value, 0); -} - -template -inline Reference Persistent(T value) { - return Reference::New(value, 1); -} - -inline ObjectReference Persistent(Object value) { - return Reference::New(value, 1); -} - -inline FunctionReference Persistent(Function value) { - return Reference::New(value, 1); -} - -//////////////////////////////////////////////////////////////////////////////// -// ObjectReference class -//////////////////////////////////////////////////////////////////////////////// - -inline ObjectReference::ObjectReference(): Reference() { -} - -inline ObjectReference::ObjectReference(napi_env env, napi_ref ref): Reference(env, ref) { -} - -inline ObjectReference::ObjectReference(Reference&& other) - : Reference(std::move(other)) { -} - -inline ObjectReference& ObjectReference::operator =(Reference&& other) { - static_cast*>(this)->operator=(std::move(other)); - return *this; -} - -inline ObjectReference::ObjectReference(ObjectReference&& other) - : Reference(std::move(other)) { -} - -inline ObjectReference& ObjectReference::operator =(ObjectReference&& other) { - static_cast*>(this)->operator=(std::move(other)); - return *this; -} - -inline ObjectReference::ObjectReference(const ObjectReference& other) - : Reference(other) { -} - -inline Napi::Value ObjectReference::Get(const char* utf8name) const { - EscapableHandleScope scope(_env); - return scope.Escape(Value().Get(utf8name)); -} - -inline Napi::Value ObjectReference::Get(const std::string& utf8name) const { - EscapableHandleScope scope(_env); - return scope.Escape(Value().Get(utf8name)); -} - -inline void ObjectReference::Set(const char* utf8name, napi_value value) { - HandleScope scope(_env); - Value().Set(utf8name, value); -} - -inline void ObjectReference::Set(const char* utf8name, Napi::Value value) { - HandleScope scope(_env); - Value().Set(utf8name, value); -} - -inline void ObjectReference::Set(const char* utf8name, const char* utf8value) { - HandleScope scope(_env); - Value().Set(utf8name, utf8value); -} - -inline void ObjectReference::Set(const char* utf8name, bool boolValue) { - HandleScope scope(_env); - Value().Set(utf8name, boolValue); -} - -inline void ObjectReference::Set(const char* utf8name, double numberValue) { - HandleScope scope(_env); - Value().Set(utf8name, numberValue); -} - -inline void ObjectReference::Set(const std::string& utf8name, napi_value value) { - HandleScope scope(_env); - Value().Set(utf8name, value); -} - -inline void ObjectReference::Set(const std::string& utf8name, Napi::Value value) { - HandleScope scope(_env); - Value().Set(utf8name, value); -} - -inline void ObjectReference::Set(const std::string& utf8name, std::string& utf8value) { - HandleScope scope(_env); - Value().Set(utf8name, utf8value); -} - -inline void ObjectReference::Set(const std::string& utf8name, bool boolValue) { - HandleScope scope(_env); - Value().Set(utf8name, boolValue); -} - -inline void ObjectReference::Set(const std::string& utf8name, double numberValue) { - HandleScope scope(_env); - Value().Set(utf8name, numberValue); -} - -inline Napi::Value ObjectReference::Get(uint32_t index) const { - EscapableHandleScope scope(_env); - return scope.Escape(Value().Get(index)); -} - -inline void ObjectReference::Set(uint32_t index, napi_value value) { - HandleScope scope(_env); - Value().Set(index, value); -} - -inline void ObjectReference::Set(uint32_t index, Napi::Value value) { - HandleScope scope(_env); - Value().Set(index, value); -} - -inline void ObjectReference::Set(uint32_t index, const char* utf8value) { - HandleScope scope(_env); - Value().Set(index, utf8value); -} - -inline void ObjectReference::Set(uint32_t index, const std::string& utf8value) { - HandleScope scope(_env); - Value().Set(index, utf8value); -} - -inline void ObjectReference::Set(uint32_t index, bool boolValue) { - HandleScope scope(_env); - Value().Set(index, boolValue); -} - -inline void ObjectReference::Set(uint32_t index, double numberValue) { - HandleScope scope(_env); - Value().Set(index, numberValue); -} - -//////////////////////////////////////////////////////////////////////////////// -// FunctionReference class -//////////////////////////////////////////////////////////////////////////////// - -inline FunctionReference::FunctionReference(): Reference() { -} - -inline FunctionReference::FunctionReference(napi_env env, napi_ref ref) - : Reference(env, ref) { -} - -inline FunctionReference::FunctionReference(Reference&& other) - : Reference(std::move(other)) { -} - -inline FunctionReference& FunctionReference::operator =(Reference&& other) { - static_cast*>(this)->operator=(std::move(other)); - return *this; -} - -inline FunctionReference::FunctionReference(FunctionReference&& other) - : Reference(std::move(other)) { -} - -inline FunctionReference& FunctionReference::operator =(FunctionReference&& other) { - static_cast*>(this)->operator=(std::move(other)); - return *this; -} - -inline Napi::Value FunctionReference::operator ()( - const std::initializer_list& args) const { - EscapableHandleScope scope(_env); - return scope.Escape(Value()(args)); -} - -inline Napi::Value FunctionReference::Call(const std::initializer_list& args) const { - EscapableHandleScope scope(_env); - Napi::Value result = Value().Call(args); - if (scope.Env().IsExceptionPending()) { - return Value(); - } - return scope.Escape(result); -} - -inline Napi::Value FunctionReference::Call(const std::vector& args) const { - EscapableHandleScope scope(_env); - Napi::Value result = Value().Call(args); - if (scope.Env().IsExceptionPending()) { - return Value(); - } - return scope.Escape(result); -} - -inline Napi::Value FunctionReference::Call( - napi_value recv, const std::initializer_list& args) const { - EscapableHandleScope scope(_env); - Napi::Value result = Value().Call(recv, args); - if (scope.Env().IsExceptionPending()) { - return Value(); - } - return scope.Escape(result); -} - -inline Napi::Value FunctionReference::Call( - napi_value recv, const std::vector& args) const { - EscapableHandleScope scope(_env); - Napi::Value result = Value().Call(recv, args); - if (scope.Env().IsExceptionPending()) { - return Value(); - } - return scope.Escape(result); -} - -inline Napi::Value FunctionReference::Call( - napi_value recv, size_t argc, const napi_value* args) const { - EscapableHandleScope scope(_env); - Napi::Value result = Value().Call(recv, argc, args); - if (scope.Env().IsExceptionPending()) { - return Value(); - } - return scope.Escape(result); -} - -inline Napi::Value FunctionReference::MakeCallback( - napi_value recv, - const std::initializer_list& args, - napi_async_context context) const { - EscapableHandleScope scope(_env); - Napi::Value result = Value().MakeCallback(recv, args, context); - if (scope.Env().IsExceptionPending()) { - return Value(); - } - return scope.Escape(result); -} - -inline Napi::Value FunctionReference::MakeCallback( - napi_value recv, - const std::vector& args, - napi_async_context context) const { - EscapableHandleScope scope(_env); - Napi::Value result = Value().MakeCallback(recv, args, context); - if (scope.Env().IsExceptionPending()) { - return Value(); - } - return scope.Escape(result); -} - -inline Napi::Value FunctionReference::MakeCallback( - napi_value recv, - size_t argc, - const napi_value* args, - napi_async_context context) const { - EscapableHandleScope scope(_env); - Napi::Value result = Value().MakeCallback(recv, argc, args, context); - if (scope.Env().IsExceptionPending()) { - return Value(); - } - return scope.Escape(result); -} - -inline Object FunctionReference::New(const std::initializer_list& args) const { - EscapableHandleScope scope(_env); - return scope.Escape(Value().New(args)).As(); -} - -inline Object FunctionReference::New(const std::vector& args) const { - EscapableHandleScope scope(_env); - return scope.Escape(Value().New(args)).As(); -} - -//////////////////////////////////////////////////////////////////////////////// -// CallbackInfo class -//////////////////////////////////////////////////////////////////////////////// - -inline CallbackInfo::CallbackInfo(napi_env env, napi_callback_info info) - : _env(env), _info(info), _this(nullptr), _dynamicArgs(nullptr), _data(nullptr) { - _argc = _staticArgCount; - _argv = _staticArgs; - napi_status status = napi_get_cb_info(env, info, &_argc, _argv, &_this, &_data); - NAPI_THROW_IF_FAILED_VOID(_env, status); - - if (_argc > _staticArgCount) { - // Use either a fixed-size array (on the stack) or a dynamically-allocated - // array (on the heap) depending on the number of args. - _dynamicArgs = new napi_value[_argc]; - _argv = _dynamicArgs; - - status = napi_get_cb_info(env, info, &_argc, _argv, nullptr, nullptr); - NAPI_THROW_IF_FAILED_VOID(_env, status); - } -} - -inline CallbackInfo::~CallbackInfo() { - if (_dynamicArgs != nullptr) { - delete[] _dynamicArgs; - } -} - -inline Value CallbackInfo::NewTarget() const { - napi_value newTarget; - napi_status status = napi_get_new_target(_env, _info, &newTarget); - NAPI_THROW_IF_FAILED(_env, status, Value()); - return Value(_env, newTarget); -} - -inline bool CallbackInfo::IsConstructCall() const { - return !NewTarget().IsEmpty(); -} - -inline Napi::Env CallbackInfo::Env() const { - return Napi::Env(_env); -} - -inline size_t CallbackInfo::Length() const { - return _argc; -} - -inline const Value CallbackInfo::operator [](size_t index) const { - return index < _argc ? Value(_env, _argv[index]) : Env().Undefined(); -} - -inline Value CallbackInfo::This() const { - if (_this == nullptr) { - return Env().Undefined(); - } - return Object(_env, _this); -} - -inline void* CallbackInfo::Data() const { - return _data; -} - -inline void CallbackInfo::SetData(void* data) { - _data = data; -} - -//////////////////////////////////////////////////////////////////////////////// -// PropertyDescriptor class -//////////////////////////////////////////////////////////////////////////////// - -template -PropertyDescriptor -PropertyDescriptor::Accessor(const char* utf8name, - napi_property_attributes attributes, - void* data) { - napi_property_descriptor desc = napi_property_descriptor(); - - desc.utf8name = utf8name; - desc.getter = &GetterCallbackWrapper; - desc.attributes = attributes; - desc.data = data; - - return desc; -} - -template -PropertyDescriptor -PropertyDescriptor::Accessor(const std::string& utf8name, - napi_property_attributes attributes, - void* data) { - return Accessor(utf8name.c_str(), attributes, data); -} - -template -PropertyDescriptor -PropertyDescriptor::Accessor(Name name, - napi_property_attributes attributes, - void* data) { - napi_property_descriptor desc = napi_property_descriptor(); - - desc.name = name; - desc.getter = &GetterCallbackWrapper; - desc.attributes = attributes; - desc.data = data; - - return desc; -} - -template < -typename PropertyDescriptor::GetterCallback Getter, -typename PropertyDescriptor::SetterCallback Setter> -PropertyDescriptor -PropertyDescriptor::Accessor(const char* utf8name, - napi_property_attributes attributes, - void* data) { - - napi_property_descriptor desc = napi_property_descriptor(); - - desc.utf8name = utf8name; - desc.getter = &GetterCallbackWrapper; - desc.setter = &SetterCallbackWrapper; - desc.attributes = attributes; - desc.data = data; - - return desc; -} - -template < -typename PropertyDescriptor::GetterCallback Getter, -typename PropertyDescriptor::SetterCallback Setter> -PropertyDescriptor -PropertyDescriptor::Accessor(const std::string& utf8name, - napi_property_attributes attributes, - void* data) { - return Accessor(utf8name.c_str(), attributes, data); -} - -template < -typename PropertyDescriptor::GetterCallback Getter, -typename PropertyDescriptor::SetterCallback Setter> -PropertyDescriptor -PropertyDescriptor::Accessor(Name name, - napi_property_attributes attributes, - void* data) { - napi_property_descriptor desc = napi_property_descriptor(); - - desc.name = name; - desc.getter = &GetterCallbackWrapper; - desc.setter = &SetterCallbackWrapper; - desc.attributes = attributes; - desc.data = data; - - return desc; -} - -template -napi_value -PropertyDescriptor::GetterCallbackWrapper(napi_env env, - napi_callback_info info) { - CallbackInfo cbInfo(env, info); - return Getter(cbInfo); -} - -template -napi_value -PropertyDescriptor::SetterCallbackWrapper(napi_env env, - napi_callback_info info) { - CallbackInfo cbInfo(env, info); - Setter(cbInfo); - return nullptr; -} - -template -inline PropertyDescriptor -PropertyDescriptor::Accessor(Napi::Env env, - Napi::Object object, - const char* utf8name, - Getter getter, - napi_property_attributes attributes, - void* data) { - typedef details::CallbackData CbData; - auto callbackData = new CbData({ getter, data }); - - napi_status status = AttachData(env, object, callbackData); - if (status != napi_ok) { - delete callbackData; - NAPI_THROW_IF_FAILED(env, status, napi_property_descriptor()); - } - - return PropertyDescriptor({ - utf8name, - nullptr, - nullptr, - CbData::Wrapper, - nullptr, - nullptr, - attributes, - callbackData - }); -} - -template -inline PropertyDescriptor PropertyDescriptor::Accessor(Napi::Env env, - Napi::Object object, - const std::string& utf8name, - Getter getter, - napi_property_attributes attributes, - void* data) { - return Accessor(env, object, utf8name.c_str(), getter, attributes, data); -} - -template -inline PropertyDescriptor PropertyDescriptor::Accessor(Napi::Env env, - Napi::Object object, - Name name, - Getter getter, - napi_property_attributes attributes, - void* data) { - typedef details::CallbackData CbData; - auto callbackData = new CbData({ getter, data }); - - napi_status status = AttachData(env, object, callbackData); - if (status != napi_ok) { - delete callbackData; - NAPI_THROW_IF_FAILED(env, status, napi_property_descriptor()); - } - - return PropertyDescriptor({ - nullptr, - name, - nullptr, - CbData::Wrapper, - nullptr, - nullptr, - attributes, - callbackData - }); -} - -template -inline PropertyDescriptor PropertyDescriptor::Accessor(Napi::Env env, - Napi::Object object, - const char* utf8name, - Getter getter, - Setter setter, - napi_property_attributes attributes, - void* data) { - typedef details::AccessorCallbackData CbData; - auto callbackData = new CbData({ getter, setter, data }); - - napi_status status = AttachData(env, object, callbackData); - if (status != napi_ok) { - delete callbackData; - NAPI_THROW_IF_FAILED(env, status, napi_property_descriptor()); - } - - return PropertyDescriptor({ - utf8name, - nullptr, - nullptr, - CbData::GetterWrapper, - CbData::SetterWrapper, - nullptr, - attributes, - callbackData - }); -} - -template -inline PropertyDescriptor PropertyDescriptor::Accessor(Napi::Env env, - Napi::Object object, - const std::string& utf8name, - Getter getter, - Setter setter, - napi_property_attributes attributes, - void* data) { - return Accessor(env, object, utf8name.c_str(), getter, setter, attributes, data); -} - -template -inline PropertyDescriptor PropertyDescriptor::Accessor(Napi::Env env, - Napi::Object object, - Name name, - Getter getter, - Setter setter, - napi_property_attributes attributes, - void* data) { - typedef details::AccessorCallbackData CbData; - auto callbackData = new CbData({ getter, setter, data }); - - napi_status status = AttachData(env, object, callbackData); - if (status != napi_ok) { - delete callbackData; - NAPI_THROW_IF_FAILED(env, status, napi_property_descriptor()); - } - - return PropertyDescriptor({ - nullptr, - name, - nullptr, - CbData::GetterWrapper, - CbData::SetterWrapper, - nullptr, - attributes, - callbackData - }); -} - -template -inline PropertyDescriptor PropertyDescriptor::Function(Napi::Env env, - Napi::Object /*object*/, - const char* utf8name, - Callable cb, - napi_property_attributes attributes, - void* data) { - return PropertyDescriptor({ - utf8name, - nullptr, - nullptr, - nullptr, - nullptr, - Napi::Function::New(env, cb, utf8name, data), - attributes, - nullptr - }); -} - -template -inline PropertyDescriptor PropertyDescriptor::Function(Napi::Env env, - Napi::Object object, - const std::string& utf8name, - Callable cb, - napi_property_attributes attributes, - void* data) { - return Function(env, object, utf8name.c_str(), cb, attributes, data); -} - -template -inline PropertyDescriptor PropertyDescriptor::Function(Napi::Env env, - Napi::Object /*object*/, - Name name, - Callable cb, - napi_property_attributes attributes, - void* data) { - return PropertyDescriptor({ - nullptr, - name, - nullptr, - nullptr, - nullptr, - Napi::Function::New(env, cb, nullptr, data), - attributes, - nullptr - }); -} - -inline PropertyDescriptor PropertyDescriptor::Value(const char* utf8name, - napi_value value, - napi_property_attributes attributes) { - return PropertyDescriptor({ - utf8name, nullptr, nullptr, nullptr, nullptr, value, attributes, nullptr - }); -} - -inline PropertyDescriptor PropertyDescriptor::Value(const std::string& utf8name, - napi_value value, - napi_property_attributes attributes) { - return Value(utf8name.c_str(), value, attributes); -} - -inline PropertyDescriptor PropertyDescriptor::Value(napi_value name, - napi_value value, - napi_property_attributes attributes) { - return PropertyDescriptor({ - nullptr, name, nullptr, nullptr, nullptr, value, attributes, nullptr - }); -} - -inline PropertyDescriptor PropertyDescriptor::Value(Name name, - Napi::Value value, - napi_property_attributes attributes) { - napi_value nameValue = name; - napi_value valueValue = value; - return PropertyDescriptor::Value(nameValue, valueValue, attributes); -} - -inline PropertyDescriptor::PropertyDescriptor(napi_property_descriptor desc) - : _desc(desc) { -} - -inline PropertyDescriptor::operator napi_property_descriptor&() { - return _desc; -} - -inline PropertyDescriptor::operator const napi_property_descriptor&() const { - return _desc; -} - -//////////////////////////////////////////////////////////////////////////////// -// ObjectWrap class -//////////////////////////////////////////////////////////////////////////////// - -template -inline ObjectWrap::ObjectWrap(const Napi::CallbackInfo& callbackInfo) { - napi_env env = callbackInfo.Env(); - napi_value wrapper = callbackInfo.This(); - napi_status status; - napi_ref ref; - T* instance = static_cast(this); - status = napi_wrap(env, wrapper, instance, FinalizeCallback, nullptr, &ref); - NAPI_THROW_IF_FAILED_VOID(env, status); - - Reference* instanceRef = instance; - *instanceRef = Reference(env, ref); -} - -template -inline ObjectWrap::~ObjectWrap() {} - -template -inline T* ObjectWrap::Unwrap(Object wrapper) { - T* unwrapped; - napi_status status = napi_unwrap(wrapper.Env(), wrapper, reinterpret_cast(&unwrapped)); - NAPI_THROW_IF_FAILED(wrapper.Env(), status, nullptr); - return unwrapped; -} - -template -inline Function -ObjectWrap::DefineClass(Napi::Env env, - const char* utf8name, - const size_t props_count, - const napi_property_descriptor* descriptors, - void* data) { - napi_status status; - std::vector props(props_count); - - // We copy the descriptors to a local array because before defining the class - // we must replace static method property descriptors with value property - // descriptors such that the value is a function-valued `napi_value` created - // with `CreateFunction()`. - // - // This replacement could be made for instance methods as well, but V8 aborts - // if we do that, because it expects methods defined on the prototype template - // to have `FunctionTemplate`s. - for (size_t index = 0; index < props_count; index++) { - props[index] = descriptors[index]; - napi_property_descriptor* prop = &props[index]; - if (prop->method == T::StaticMethodCallbackWrapper) { - status = CreateFunction(env, - utf8name, - prop->method, - static_cast(prop->data), - &(prop->value)); - NAPI_THROW_IF_FAILED(env, status, Function()); - prop->method = nullptr; - prop->data = nullptr; - } else if (prop->method == T::StaticVoidMethodCallbackWrapper) { - status = CreateFunction(env, - utf8name, - prop->method, - static_cast(prop->data), - &(prop->value)); - NAPI_THROW_IF_FAILED(env, status, Function()); - prop->method = nullptr; - prop->data = nullptr; - } - } - - napi_value value; - status = napi_define_class(env, - utf8name, - NAPI_AUTO_LENGTH, - T::ConstructorCallbackWrapper, - data, - props_count, - props.data(), - &value); - NAPI_THROW_IF_FAILED(env, status, Function()); - - // After defining the class we iterate once more over the property descriptors - // and attach the data associated with accessors and instance methods to the - // newly created JavaScript class. - for (size_t idx = 0; idx < props_count; idx++) { - const napi_property_descriptor* prop = &props[idx]; - - if (prop->getter == T::StaticGetterCallbackWrapper || - prop->setter == T::StaticSetterCallbackWrapper) { - status = Napi::details::AttachData(env, - value, - static_cast(prop->data)); - NAPI_THROW_IF_FAILED(env, status, Function()); - } else if (prop->getter == T::InstanceGetterCallbackWrapper || - prop->setter == T::InstanceSetterCallbackWrapper) { - status = Napi::details::AttachData(env, - value, - static_cast(prop->data)); - NAPI_THROW_IF_FAILED(env, status, Function()); - } else if (prop->method != nullptr && !(prop->attributes & napi_static)) { - if (prop->method == T::InstanceVoidMethodCallbackWrapper) { - status = Napi::details::AttachData(env, - value, - static_cast(prop->data)); - NAPI_THROW_IF_FAILED(env, status, Function()); - } else if (prop->method == T::InstanceMethodCallbackWrapper) { - status = Napi::details::AttachData(env, - value, - static_cast(prop->data)); - NAPI_THROW_IF_FAILED(env, status, Function()); - } - } - } - - return Function(env, value); -} - -template -inline Function ObjectWrap::DefineClass( - Napi::Env env, - const char* utf8name, - const std::initializer_list>& properties, - void* data) { - return DefineClass(env, - utf8name, - properties.size(), - reinterpret_cast(properties.begin()), - data); -} - -template -inline Function ObjectWrap::DefineClass( - Napi::Env env, - const char* utf8name, - const std::vector>& properties, - void* data) { - return DefineClass(env, - utf8name, - properties.size(), - reinterpret_cast(properties.data()), - data); -} - -template -inline ClassPropertyDescriptor ObjectWrap::StaticMethod( - const char* utf8name, - StaticVoidMethodCallback method, - napi_property_attributes attributes, - void* data) { - StaticVoidMethodCallbackData* callbackData = new StaticVoidMethodCallbackData({ method, data }); - - napi_property_descriptor desc = napi_property_descriptor(); - desc.utf8name = utf8name; - desc.method = T::StaticVoidMethodCallbackWrapper; - desc.data = callbackData; - desc.attributes = static_cast(attributes | napi_static); - return desc; -} - -template -inline ClassPropertyDescriptor ObjectWrap::StaticMethod( - const char* utf8name, - StaticMethodCallback method, - napi_property_attributes attributes, - void* data) { - StaticMethodCallbackData* callbackData = new StaticMethodCallbackData({ method, data }); - - napi_property_descriptor desc = napi_property_descriptor(); - desc.utf8name = utf8name; - desc.method = T::StaticMethodCallbackWrapper; - desc.data = callbackData; - desc.attributes = static_cast(attributes | napi_static); - return desc; -} - -template -inline ClassPropertyDescriptor ObjectWrap::StaticMethod( - Symbol name, - StaticVoidMethodCallback method, - napi_property_attributes attributes, - void* data) { - StaticVoidMethodCallbackData* callbackData = new StaticVoidMethodCallbackData({ method, data }); - - napi_property_descriptor desc = napi_property_descriptor(); - desc.name = name; - desc.method = T::StaticVoidMethodCallbackWrapper; - desc.data = callbackData; - desc.attributes = static_cast(attributes | napi_static); - return desc; -} - -template -inline ClassPropertyDescriptor ObjectWrap::StaticMethod( - Symbol name, - StaticMethodCallback method, - napi_property_attributes attributes, - void* data) { - StaticMethodCallbackData* callbackData = new StaticMethodCallbackData({ method, data }); - - napi_property_descriptor desc = napi_property_descriptor(); - desc.name = name; - desc.method = T::StaticMethodCallbackWrapper; - desc.data = callbackData; - desc.attributes = static_cast(attributes | napi_static); - return desc; -} - -template -template ::StaticVoidMethodCallback method> -inline ClassPropertyDescriptor ObjectWrap::StaticMethod( - const char* utf8name, - napi_property_attributes attributes, - void* data) { - napi_property_descriptor desc = napi_property_descriptor(); - desc.utf8name = utf8name; - desc.method = &ObjectWrap::WrappedMethod; - desc.data = data; - desc.attributes = static_cast(attributes | napi_static); - return desc; -} - -template -template ::StaticVoidMethodCallback method> -inline ClassPropertyDescriptor ObjectWrap::StaticMethod( - Symbol name, - napi_property_attributes attributes, - void* data) { - napi_property_descriptor desc = napi_property_descriptor(); - desc.name = name; - desc.method = &ObjectWrap::WrappedMethod; - desc.data = data; - desc.attributes = static_cast(attributes | napi_static); - return desc; -} - -template -template ::StaticMethodCallback method> -inline ClassPropertyDescriptor ObjectWrap::StaticMethod( - const char* utf8name, - napi_property_attributes attributes, - void* data) { - napi_property_descriptor desc = napi_property_descriptor(); - desc.utf8name = utf8name; - desc.method = &ObjectWrap::WrappedMethod; - desc.data = data; - desc.attributes = static_cast(attributes | napi_static); - return desc; -} - -template -template ::StaticMethodCallback method> -inline ClassPropertyDescriptor ObjectWrap::StaticMethod( - Symbol name, - napi_property_attributes attributes, - void* data) { - napi_property_descriptor desc = napi_property_descriptor(); - desc.name = name; - desc.method = &ObjectWrap::WrappedMethod; - desc.data = data; - desc.attributes = static_cast(attributes | napi_static); - return desc; -} - -template -inline ClassPropertyDescriptor ObjectWrap::StaticAccessor( - const char* utf8name, - StaticGetterCallback getter, - StaticSetterCallback setter, - napi_property_attributes attributes, - void* data) { - StaticAccessorCallbackData* callbackData = - new StaticAccessorCallbackData({ getter, setter, data }); - - napi_property_descriptor desc = napi_property_descriptor(); - desc.utf8name = utf8name; - desc.getter = getter != nullptr ? T::StaticGetterCallbackWrapper : nullptr; - desc.setter = setter != nullptr ? T::StaticSetterCallbackWrapper : nullptr; - desc.data = callbackData; - desc.attributes = static_cast(attributes | napi_static); - return desc; -} - -template -inline ClassPropertyDescriptor ObjectWrap::StaticAccessor( - Symbol name, - StaticGetterCallback getter, - StaticSetterCallback setter, - napi_property_attributes attributes, - void* data) { - StaticAccessorCallbackData* callbackData = - new StaticAccessorCallbackData({ getter, setter, data }); - - napi_property_descriptor desc = napi_property_descriptor(); - desc.name = name; - desc.getter = getter != nullptr ? T::StaticGetterCallbackWrapper : nullptr; - desc.setter = setter != nullptr ? T::StaticSetterCallbackWrapper : nullptr; - desc.data = callbackData; - desc.attributes = static_cast(attributes | napi_static); - return desc; -} - -template -template ::StaticGetterCallback getter, - typename ObjectWrap::StaticSetterCallback setter> -inline ClassPropertyDescriptor ObjectWrap::StaticAccessor( - const char* utf8name, - napi_property_attributes attributes, - void* data) { - napi_property_descriptor desc = napi_property_descriptor(); - desc.utf8name = utf8name; - desc.getter = This::WrapStaticGetter(This::StaticGetterTag()); - desc.setter = This::WrapStaticSetter(This::StaticSetterTag()); - desc.data = data; - desc.attributes = static_cast(attributes | napi_static); - return desc; -} - -template -template ::StaticGetterCallback getter, - typename ObjectWrap::StaticSetterCallback setter> -inline ClassPropertyDescriptor ObjectWrap::StaticAccessor( - Symbol name, - napi_property_attributes attributes, - void* data) { - napi_property_descriptor desc = napi_property_descriptor(); - desc.name = name; - desc.getter = This::WrapStaticGetter(This::StaticGetterTag()); - desc.setter = This::WrapStaticSetter(This::StaticSetterTag()); - desc.data = data; - desc.attributes = static_cast(attributes | napi_static); - return desc; -} - -template -inline ClassPropertyDescriptor ObjectWrap::InstanceMethod( - const char* utf8name, - InstanceVoidMethodCallback method, - napi_property_attributes attributes, - void* data) { - InstanceVoidMethodCallbackData* callbackData = - new InstanceVoidMethodCallbackData({ method, data}); - - napi_property_descriptor desc = napi_property_descriptor(); - desc.utf8name = utf8name; - desc.method = T::InstanceVoidMethodCallbackWrapper; - desc.data = callbackData; - desc.attributes = attributes; - return desc; -} - -template -inline ClassPropertyDescriptor ObjectWrap::InstanceMethod( - const char* utf8name, - InstanceMethodCallback method, - napi_property_attributes attributes, - void* data) { - InstanceMethodCallbackData* callbackData = new InstanceMethodCallbackData({ method, data }); - - napi_property_descriptor desc = napi_property_descriptor(); - desc.utf8name = utf8name; - desc.method = T::InstanceMethodCallbackWrapper; - desc.data = callbackData; - desc.attributes = attributes; - return desc; -} - -template -inline ClassPropertyDescriptor ObjectWrap::InstanceMethod( - Symbol name, - InstanceVoidMethodCallback method, - napi_property_attributes attributes, - void* data) { - InstanceVoidMethodCallbackData* callbackData = - new InstanceVoidMethodCallbackData({ method, data}); - - napi_property_descriptor desc = napi_property_descriptor(); - desc.name = name; - desc.method = T::InstanceVoidMethodCallbackWrapper; - desc.data = callbackData; - desc.attributes = attributes; - return desc; -} - -template -inline ClassPropertyDescriptor ObjectWrap::InstanceMethod( - Symbol name, - InstanceMethodCallback method, - napi_property_attributes attributes, - void* data) { - InstanceMethodCallbackData* callbackData = new InstanceMethodCallbackData({ method, data }); - - napi_property_descriptor desc = napi_property_descriptor(); - desc.name = name; - desc.method = T::InstanceMethodCallbackWrapper; - desc.data = callbackData; - desc.attributes = attributes; - return desc; -} - -template -template ::InstanceVoidMethodCallback method> -inline ClassPropertyDescriptor ObjectWrap::InstanceMethod( - const char* utf8name, - napi_property_attributes attributes, - void* data) { - napi_property_descriptor desc = napi_property_descriptor(); - desc.utf8name = utf8name; - desc.method = &ObjectWrap::WrappedMethod; - desc.data = data; - desc.attributes = attributes; - return desc; -} - -template -template ::InstanceMethodCallback method> -inline ClassPropertyDescriptor ObjectWrap::InstanceMethod( - const char* utf8name, - napi_property_attributes attributes, - void* data) { - napi_property_descriptor desc = napi_property_descriptor(); - desc.utf8name = utf8name; - desc.method = &ObjectWrap::WrappedMethod; - desc.data = data; - desc.attributes = attributes; - return desc; -} - -template -template ::InstanceVoidMethodCallback method> -inline ClassPropertyDescriptor ObjectWrap::InstanceMethod( - Symbol name, - napi_property_attributes attributes, - void* data) { - napi_property_descriptor desc = napi_property_descriptor(); - desc.name = name; - desc.method = &ObjectWrap::WrappedMethod; - desc.data = data; - desc.attributes = attributes; - return desc; -} - -template -template ::InstanceMethodCallback method> -inline ClassPropertyDescriptor ObjectWrap::InstanceMethod( - Symbol name, - napi_property_attributes attributes, - void* data) { - napi_property_descriptor desc = napi_property_descriptor(); - desc.name = name; - desc.method = &ObjectWrap::WrappedMethod; - desc.data = data; - desc.attributes = attributes; - return desc; -} - -template -inline ClassPropertyDescriptor ObjectWrap::InstanceAccessor( - const char* utf8name, - InstanceGetterCallback getter, - InstanceSetterCallback setter, - napi_property_attributes attributes, - void* data) { - InstanceAccessorCallbackData* callbackData = - new InstanceAccessorCallbackData({ getter, setter, data }); - - napi_property_descriptor desc = napi_property_descriptor(); - desc.utf8name = utf8name; - desc.getter = getter != nullptr ? T::InstanceGetterCallbackWrapper : nullptr; - desc.setter = setter != nullptr ? T::InstanceSetterCallbackWrapper : nullptr; - desc.data = callbackData; - desc.attributes = attributes; - return desc; -} - -template -inline ClassPropertyDescriptor ObjectWrap::InstanceAccessor( - Symbol name, - InstanceGetterCallback getter, - InstanceSetterCallback setter, - napi_property_attributes attributes, - void* data) { - InstanceAccessorCallbackData* callbackData = - new InstanceAccessorCallbackData({ getter, setter, data }); - - napi_property_descriptor desc = napi_property_descriptor(); - desc.name = name; - desc.getter = getter != nullptr ? T::InstanceGetterCallbackWrapper : nullptr; - desc.setter = setter != nullptr ? T::InstanceSetterCallbackWrapper : nullptr; - desc.data = callbackData; - desc.attributes = attributes; - return desc; -} - -template -template ::InstanceGetterCallback getter, - typename ObjectWrap::InstanceSetterCallback setter> -inline ClassPropertyDescriptor ObjectWrap::InstanceAccessor( - const char* utf8name, - napi_property_attributes attributes, - void* data) { - napi_property_descriptor desc = napi_property_descriptor(); - desc.utf8name = utf8name; - desc.getter = This::WrapGetter(This::GetterTag()); - desc.setter = This::WrapSetter(This::SetterTag()); - desc.data = data; - desc.attributes = attributes; - return desc; -} - -template -template ::InstanceGetterCallback getter, - typename ObjectWrap::InstanceSetterCallback setter> -inline ClassPropertyDescriptor ObjectWrap::InstanceAccessor( - Symbol name, - napi_property_attributes attributes, - void* data) { - napi_property_descriptor desc = napi_property_descriptor(); - desc.name = name; - desc.getter = This::WrapGetter(This::GetterTag()); - desc.setter = This::WrapSetter(This::SetterTag()); - desc.data = data; - desc.attributes = attributes; - return desc; -} - -template -inline ClassPropertyDescriptor ObjectWrap::StaticValue(const char* utf8name, - Napi::Value value, napi_property_attributes attributes) { - napi_property_descriptor desc = napi_property_descriptor(); - desc.utf8name = utf8name; - desc.value = value; - desc.attributes = static_cast(attributes | napi_static); - return desc; -} - -template -inline ClassPropertyDescriptor ObjectWrap::StaticValue(Symbol name, - Napi::Value value, napi_property_attributes attributes) { - napi_property_descriptor desc = napi_property_descriptor(); - desc.name = name; - desc.value = value; - desc.attributes = static_cast(attributes | napi_static); - return desc; -} - -template -inline ClassPropertyDescriptor ObjectWrap::InstanceValue( - const char* utf8name, - Napi::Value value, - napi_property_attributes attributes) { - napi_property_descriptor desc = napi_property_descriptor(); - desc.utf8name = utf8name; - desc.value = value; - desc.attributes = attributes; - return desc; -} - -template -inline ClassPropertyDescriptor ObjectWrap::InstanceValue( - Symbol name, - Napi::Value value, - napi_property_attributes attributes) { - napi_property_descriptor desc = napi_property_descriptor(); - desc.name = name; - desc.value = value; - desc.attributes = attributes; - return desc; -} - -template -inline void ObjectWrap::Finalize(Napi::Env /*env*/) {} - -template -inline napi_value ObjectWrap::ConstructorCallbackWrapper( - napi_env env, - napi_callback_info info) { - napi_value new_target; - napi_status status = napi_get_new_target(env, info, &new_target); - if (status != napi_ok) return nullptr; - - bool isConstructCall = (new_target != nullptr); - if (!isConstructCall) { - napi_throw_type_error(env, nullptr, "Class constructors cannot be invoked without 'new'"); - return nullptr; - } - - T* instance; - napi_value wrapper = details::WrapCallback([&] { - CallbackInfo callbackInfo(env, info); - instance = new T(callbackInfo); - return callbackInfo.This(); - }); - - return wrapper; -} - -template -inline napi_value ObjectWrap::StaticVoidMethodCallbackWrapper( - napi_env env, - napi_callback_info info) { - return details::WrapCallback([&] { - CallbackInfo callbackInfo(env, info); - StaticVoidMethodCallbackData* callbackData = - reinterpret_cast(callbackInfo.Data()); - callbackInfo.SetData(callbackData->data); - callbackData->callback(callbackInfo); - return nullptr; - }); -} - -template -inline napi_value ObjectWrap::StaticMethodCallbackWrapper( - napi_env env, - napi_callback_info info) { - return details::WrapCallback([&] { - CallbackInfo callbackInfo(env, info); - StaticMethodCallbackData* callbackData = - reinterpret_cast(callbackInfo.Data()); - callbackInfo.SetData(callbackData->data); - return callbackData->callback(callbackInfo); - }); -} - -template -inline napi_value ObjectWrap::StaticGetterCallbackWrapper( - napi_env env, - napi_callback_info info) { - return details::WrapCallback([&] { - CallbackInfo callbackInfo(env, info); - StaticAccessorCallbackData* callbackData = - reinterpret_cast(callbackInfo.Data()); - callbackInfo.SetData(callbackData->data); - return callbackData->getterCallback(callbackInfo); - }); -} - -template -inline napi_value ObjectWrap::StaticSetterCallbackWrapper( - napi_env env, - napi_callback_info info) { - return details::WrapCallback([&] { - CallbackInfo callbackInfo(env, info); - StaticAccessorCallbackData* callbackData = - reinterpret_cast(callbackInfo.Data()); - callbackInfo.SetData(callbackData->data); - callbackData->setterCallback(callbackInfo, callbackInfo[0]); - return nullptr; - }); -} - -template -inline napi_value ObjectWrap::InstanceVoidMethodCallbackWrapper( - napi_env env, - napi_callback_info info) { - return details::WrapCallback([&] { - CallbackInfo callbackInfo(env, info); - InstanceVoidMethodCallbackData* callbackData = - reinterpret_cast(callbackInfo.Data()); - callbackInfo.SetData(callbackData->data); - T* instance = Unwrap(callbackInfo.This().As()); - auto cb = callbackData->callback; - (instance->*cb)(callbackInfo); - return nullptr; - }); -} - -template -inline napi_value ObjectWrap::InstanceMethodCallbackWrapper( - napi_env env, - napi_callback_info info) { - return details::WrapCallback([&] { - CallbackInfo callbackInfo(env, info); - InstanceMethodCallbackData* callbackData = - reinterpret_cast(callbackInfo.Data()); - callbackInfo.SetData(callbackData->data); - T* instance = Unwrap(callbackInfo.This().As()); - auto cb = callbackData->callback; - return (instance->*cb)(callbackInfo); - }); -} - -template -inline napi_value ObjectWrap::InstanceGetterCallbackWrapper( - napi_env env, - napi_callback_info info) { - return details::WrapCallback([&] { - CallbackInfo callbackInfo(env, info); - InstanceAccessorCallbackData* callbackData = - reinterpret_cast(callbackInfo.Data()); - callbackInfo.SetData(callbackData->data); - T* instance = Unwrap(callbackInfo.This().As()); - auto cb = callbackData->getterCallback; - return (instance->*cb)(callbackInfo); - }); -} - -template -inline napi_value ObjectWrap::InstanceSetterCallbackWrapper( - napi_env env, - napi_callback_info info) { - return details::WrapCallback([&] { - CallbackInfo callbackInfo(env, info); - InstanceAccessorCallbackData* callbackData = - reinterpret_cast(callbackInfo.Data()); - callbackInfo.SetData(callbackData->data); - T* instance = Unwrap(callbackInfo.This().As()); - auto cb = callbackData->setterCallback; - (instance->*cb)(callbackInfo, callbackInfo[0]); - return nullptr; - }); -} - -template -inline void ObjectWrap::FinalizeCallback(napi_env env, void* data, void* /*hint*/) { - T* instance = reinterpret_cast(data); - instance->Finalize(Napi::Env(env)); - delete instance; -} - -template -template ::StaticVoidMethodCallback method> -inline napi_value ObjectWrap::WrappedMethod(napi_env env, napi_callback_info info) noexcept { - return details::WrapCallback([&] { - method(CallbackInfo(env, info)); - return nullptr; - }); -} - -template -template ::StaticMethodCallback method> -inline napi_value ObjectWrap::WrappedMethod(napi_env env, napi_callback_info info) noexcept { - return details::WrapCallback([&] { - return method(CallbackInfo(env, info)); - }); -} - -template -template ::InstanceVoidMethodCallback method> -inline napi_value ObjectWrap::WrappedMethod(napi_env env, napi_callback_info info) noexcept { - return details::WrapCallback([&] { - const CallbackInfo cbInfo(env, info); - T* instance = Unwrap(cbInfo.This().As()); - (instance->*method)(cbInfo); - return nullptr; - }); -} - -template -template ::InstanceMethodCallback method> -inline napi_value ObjectWrap::WrappedMethod(napi_env env, napi_callback_info info) noexcept { - return details::WrapCallback([&] { - const CallbackInfo cbInfo(env, info); - T* instance = Unwrap(cbInfo.This().As()); - return (instance->*method)(cbInfo); - }); -} - -template -template ::StaticSetterCallback method> -inline napi_value ObjectWrap::WrappedMethod(napi_env env, napi_callback_info info) noexcept { - return details::WrapCallback([&] { - const CallbackInfo cbInfo(env, info); - method(cbInfo, cbInfo[0]); - return nullptr; - }); -} - -template -template ::InstanceSetterCallback method> -inline napi_value ObjectWrap::WrappedMethod(napi_env env, napi_callback_info info) noexcept { - return details::WrapCallback([&] { - const CallbackInfo cbInfo(env, info); - T* instance = Unwrap(cbInfo.This().As()); - (instance->*method)(cbInfo, cbInfo[0]); - return nullptr; - }); -} - -//////////////////////////////////////////////////////////////////////////////// -// HandleScope class -//////////////////////////////////////////////////////////////////////////////// - -inline HandleScope::HandleScope(napi_env env, napi_handle_scope scope) - : _env(env), _scope(scope) { -} - -inline HandleScope::HandleScope(Napi::Env env) : _env(env) { - napi_status status = napi_open_handle_scope(_env, &_scope); - NAPI_THROW_IF_FAILED_VOID(_env, status); -} - -inline HandleScope::~HandleScope() { - napi_status status = napi_close_handle_scope(_env, _scope); - NAPI_FATAL_IF_FAILED(status, - "HandleScope::~HandleScope", - "napi_close_handle_scope"); -} - -inline HandleScope::operator napi_handle_scope() const { - return _scope; -} - -inline Napi::Env HandleScope::Env() const { - return Napi::Env(_env); -} - -//////////////////////////////////////////////////////////////////////////////// -// EscapableHandleScope class -//////////////////////////////////////////////////////////////////////////////// - -inline EscapableHandleScope::EscapableHandleScope( - napi_env env, napi_escapable_handle_scope scope) : _env(env), _scope(scope) { -} - -inline EscapableHandleScope::EscapableHandleScope(Napi::Env env) : _env(env) { - napi_status status = napi_open_escapable_handle_scope(_env, &_scope); - NAPI_THROW_IF_FAILED_VOID(_env, status); -} - -inline EscapableHandleScope::~EscapableHandleScope() { - napi_status status = napi_close_escapable_handle_scope(_env, _scope); - NAPI_FATAL_IF_FAILED(status, - "EscapableHandleScope::~EscapableHandleScope", - "napi_close_escapable_handle_scope"); -} - -inline EscapableHandleScope::operator napi_escapable_handle_scope() const { - return _scope; -} - -inline Napi::Env EscapableHandleScope::Env() const { - return Napi::Env(_env); -} - -inline Value EscapableHandleScope::Escape(napi_value escapee) { - napi_value result; - napi_status status = napi_escape_handle(_env, _scope, escapee, &result); - NAPI_THROW_IF_FAILED(_env, status, Value()); - return Value(_env, result); -} - - -#if (NAPI_VERSION > 2) -//////////////////////////////////////////////////////////////////////////////// -// CallbackScope class -//////////////////////////////////////////////////////////////////////////////// - -inline CallbackScope::CallbackScope( - napi_env env, napi_callback_scope scope) : _env(env), _scope(scope) { -} - -inline CallbackScope::CallbackScope(napi_env env, napi_async_context context) - : _env(env) { - napi_status status = napi_open_callback_scope( - _env, Object::New(env), context, &_scope); - NAPI_THROW_IF_FAILED_VOID(_env, status); -} - -inline CallbackScope::~CallbackScope() { - napi_status status = napi_close_callback_scope(_env, _scope); - NAPI_FATAL_IF_FAILED(status, - "CallbackScope::~CallbackScope", - "napi_close_callback_scope"); -} - -inline CallbackScope::operator napi_callback_scope() const { - return _scope; -} - -inline Napi::Env CallbackScope::Env() const { - return Napi::Env(_env); -} -#endif - -//////////////////////////////////////////////////////////////////////////////// -// AsyncContext class -//////////////////////////////////////////////////////////////////////////////// - -inline AsyncContext::AsyncContext(napi_env env, const char* resource_name) - : AsyncContext(env, resource_name, Object::New(env)) { -} - -inline AsyncContext::AsyncContext(napi_env env, - const char* resource_name, - const Object& resource) - : _env(env), - _context(nullptr) { - napi_value resource_id; - napi_status status = napi_create_string_utf8( - _env, resource_name, NAPI_AUTO_LENGTH, &resource_id); - NAPI_THROW_IF_FAILED_VOID(_env, status); - - status = napi_async_init(_env, resource, resource_id, &_context); - NAPI_THROW_IF_FAILED_VOID(_env, status); -} - -inline AsyncContext::~AsyncContext() { - if (_context != nullptr) { - napi_async_destroy(_env, _context); - _context = nullptr; - } -} - -inline AsyncContext::AsyncContext(AsyncContext&& other) { - _env = other._env; - other._env = nullptr; - _context = other._context; - other._context = nullptr; -} - -inline AsyncContext& AsyncContext::operator =(AsyncContext&& other) { - _env = other._env; - other._env = nullptr; - _context = other._context; - other._context = nullptr; - return *this; -} - -inline AsyncContext::operator napi_async_context() const { - return _context; -} - -inline Napi::Env AsyncContext::Env() const { - return Napi::Env(_env); -} - -//////////////////////////////////////////////////////////////////////////////// -// AsyncWorker class -//////////////////////////////////////////////////////////////////////////////// - -inline AsyncWorker::AsyncWorker(const Function& callback) - : AsyncWorker(callback, "generic") { -} - -inline AsyncWorker::AsyncWorker(const Function& callback, - const char* resource_name) - : AsyncWorker(callback, resource_name, Object::New(callback.Env())) { -} - -inline AsyncWorker::AsyncWorker(const Function& callback, - const char* resource_name, - const Object& resource) - : AsyncWorker(Object::New(callback.Env()), - callback, - resource_name, - resource) { -} - -inline AsyncWorker::AsyncWorker(const Object& receiver, - const Function& callback) - : AsyncWorker(receiver, callback, "generic") { -} - -inline AsyncWorker::AsyncWorker(const Object& receiver, - const Function& callback, - const char* resource_name) - : AsyncWorker(receiver, - callback, - resource_name, - Object::New(callback.Env())) { -} - -inline AsyncWorker::AsyncWorker(const Object& receiver, - const Function& callback, - const char* resource_name, - const Object& resource) - : _env(callback.Env()), - _receiver(Napi::Persistent(receiver)), - _callback(Napi::Persistent(callback)), - _suppress_destruct(false) { - napi_value resource_id; - napi_status status = napi_create_string_latin1( - _env, resource_name, NAPI_AUTO_LENGTH, &resource_id); - NAPI_THROW_IF_FAILED_VOID(_env, status); - - status = napi_create_async_work(_env, resource, resource_id, OnExecute, - OnWorkComplete, this, &_work); - NAPI_THROW_IF_FAILED_VOID(_env, status); -} - -inline AsyncWorker::AsyncWorker(Napi::Env env) - : AsyncWorker(env, "generic") { -} - -inline AsyncWorker::AsyncWorker(Napi::Env env, - const char* resource_name) - : AsyncWorker(env, resource_name, Object::New(env)) { -} - -inline AsyncWorker::AsyncWorker(Napi::Env env, - const char* resource_name, - const Object& resource) - : _env(env), - _receiver(), - _callback(), - _suppress_destruct(false) { - napi_value resource_id; - napi_status status = napi_create_string_latin1( - _env, resource_name, NAPI_AUTO_LENGTH, &resource_id); - NAPI_THROW_IF_FAILED_VOID(_env, status); - - status = napi_create_async_work(_env, resource, resource_id, OnExecute, - OnWorkComplete, this, &_work); - NAPI_THROW_IF_FAILED_VOID(_env, status); -} - -inline AsyncWorker::~AsyncWorker() { - if (_work != nullptr) { - napi_delete_async_work(_env, _work); - _work = nullptr; - } -} - -inline void AsyncWorker::Destroy() { - delete this; -} - -inline AsyncWorker::AsyncWorker(AsyncWorker&& other) { - _env = other._env; - other._env = nullptr; - _work = other._work; - other._work = nullptr; - _receiver = std::move(other._receiver); - _callback = std::move(other._callback); - _error = std::move(other._error); - _suppress_destruct = other._suppress_destruct; -} - -inline AsyncWorker& AsyncWorker::operator =(AsyncWorker&& other) { - _env = other._env; - other._env = nullptr; - _work = other._work; - other._work = nullptr; - _receiver = std::move(other._receiver); - _callback = std::move(other._callback); - _error = std::move(other._error); - _suppress_destruct = other._suppress_destruct; - return *this; -} - -inline AsyncWorker::operator napi_async_work() const { - return _work; -} - -inline Napi::Env AsyncWorker::Env() const { - return Napi::Env(_env); -} - -inline void AsyncWorker::Queue() { - napi_status status = napi_queue_async_work(_env, _work); - NAPI_THROW_IF_FAILED_VOID(_env, status); -} - -inline void AsyncWorker::Cancel() { - napi_status status = napi_cancel_async_work(_env, _work); - NAPI_THROW_IF_FAILED_VOID(_env, status); -} - -inline ObjectReference& AsyncWorker::Receiver() { - return _receiver; -} - -inline FunctionReference& AsyncWorker::Callback() { - return _callback; -} - -inline void AsyncWorker::SuppressDestruct() { - _suppress_destruct = true; -} - -inline void AsyncWorker::OnOK() { - if (!_callback.IsEmpty()) { - _callback.Call(_receiver.Value(), GetResult(_callback.Env())); - } -} - -inline void AsyncWorker::OnError(const Error& e) { - if (!_callback.IsEmpty()) { - _callback.Call(_receiver.Value(), std::initializer_list{ e.Value() }); - } -} - -inline void AsyncWorker::SetError(const std::string& error) { - _error = error; -} - -inline std::vector AsyncWorker::GetResult(Napi::Env /*env*/) { - return {}; -} -// The OnExecute method receives an napi_env argument. However, do NOT -// use it within this method, as it does not run on the main thread and must -// not run any method that would cause JavaScript to run. In practice, this -// means that almost any use of napi_env will be incorrect. -inline void AsyncWorker::OnExecute(napi_env /*DO_NOT_USE*/, void* this_pointer) { - AsyncWorker* self = static_cast(this_pointer); -#ifdef NAPI_CPP_EXCEPTIONS - try { - self->Execute(); - } catch (const std::exception& e) { - self->SetError(e.what()); - } -#else // NAPI_CPP_EXCEPTIONS - self->Execute(); -#endif // NAPI_CPP_EXCEPTIONS -} - -inline void AsyncWorker::OnWorkComplete( - napi_env /*env*/, napi_status status, void* this_pointer) { - AsyncWorker* self = static_cast(this_pointer); - if (status != napi_cancelled) { - HandleScope scope(self->_env); - details::WrapCallback([&] { - if (self->_error.size() == 0) { - self->OnOK(); - } - else { - self->OnError(Error::New(self->_env, self->_error)); - } - return nullptr; - }); - } - if (!self->_suppress_destruct) { - self->Destroy(); - } -} - -#if (NAPI_VERSION > 3) -//////////////////////////////////////////////////////////////////////////////// -// ThreadSafeFunction class -//////////////////////////////////////////////////////////////////////////////// - -// static -template -inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env, - const Function& callback, - ResourceString resourceName, - size_t maxQueueSize, - size_t initialThreadCount) { - return New(env, callback, Object(), resourceName, maxQueueSize, - initialThreadCount); -} - -// static -template -inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env, - const Function& callback, - ResourceString resourceName, - size_t maxQueueSize, - size_t initialThreadCount, - ContextType* context) { - return New(env, callback, Object(), resourceName, maxQueueSize, - initialThreadCount, context); -} - -// static -template -inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env, - const Function& callback, - ResourceString resourceName, - size_t maxQueueSize, - size_t initialThreadCount, - Finalizer finalizeCallback) { - return New(env, callback, Object(), resourceName, maxQueueSize, - initialThreadCount, finalizeCallback); -} - -// static -template -inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env, - const Function& callback, - ResourceString resourceName, - size_t maxQueueSize, - size_t initialThreadCount, - Finalizer finalizeCallback, - FinalizerDataType* data) { - return New(env, callback, Object(), resourceName, maxQueueSize, - initialThreadCount, finalizeCallback, data); -} - -// static -template -inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env, - const Function& callback, - ResourceString resourceName, - size_t maxQueueSize, - size_t initialThreadCount, - ContextType* context, - Finalizer finalizeCallback) { - return New(env, callback, Object(), resourceName, maxQueueSize, - initialThreadCount, context, finalizeCallback); -} - -// static -template -inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env, - const Function& callback, - ResourceString resourceName, - size_t maxQueueSize, - size_t initialThreadCount, - ContextType* context, - Finalizer finalizeCallback, - FinalizerDataType* data) { - return New(env, callback, Object(), resourceName, maxQueueSize, - initialThreadCount, context, finalizeCallback, data); -} - -// static -template -inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env, - const Function& callback, - const Object& resource, - ResourceString resourceName, - size_t maxQueueSize, - size_t initialThreadCount) { - return New(env, callback, resource, resourceName, maxQueueSize, - initialThreadCount, static_cast(nullptr) /* context */); -} - -// static -template -inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env, - const Function& callback, - const Object& resource, - ResourceString resourceName, - size_t maxQueueSize, - size_t initialThreadCount, - ContextType* context) { - return New(env, callback, resource, resourceName, maxQueueSize, - initialThreadCount, context, - [](Env, ContextType*) {} /* empty finalizer */); -} - -// static -template -inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env, - const Function& callback, - const Object& resource, - ResourceString resourceName, - size_t maxQueueSize, - size_t initialThreadCount, - Finalizer finalizeCallback) { - return New(env, callback, resource, resourceName, maxQueueSize, - initialThreadCount, static_cast(nullptr) /* context */, - finalizeCallback, static_cast(nullptr) /* data */, - details::ThreadSafeFinalize::Wrapper); -} - -// static -template -inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env, - const Function& callback, - const Object& resource, - ResourceString resourceName, - size_t maxQueueSize, - size_t initialThreadCount, - Finalizer finalizeCallback, - FinalizerDataType* data) { - return New(env, callback, resource, resourceName, maxQueueSize, - initialThreadCount, static_cast(nullptr) /* context */, - finalizeCallback, data, - details::ThreadSafeFinalize< - void, Finalizer, FinalizerDataType>::FinalizeWrapperWithData); -} - -// static -template -inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env, - const Function& callback, - const Object& resource, - ResourceString resourceName, - size_t maxQueueSize, - size_t initialThreadCount, - ContextType* context, - Finalizer finalizeCallback) { - return New(env, callback, resource, resourceName, maxQueueSize, - initialThreadCount, context, finalizeCallback, - static_cast(nullptr) /* data */, - details::ThreadSafeFinalize< - ContextType, Finalizer>::FinalizeWrapperWithContext); -} - -// static -template -inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env, - const Function& callback, - const Object& resource, - ResourceString resourceName, - size_t maxQueueSize, - size_t initialThreadCount, - ContextType* context, - Finalizer finalizeCallback, - FinalizerDataType* data) { - return New(env, callback, resource, resourceName, maxQueueSize, - initialThreadCount, context, finalizeCallback, data, - details::ThreadSafeFinalize::FinalizeFinalizeWrapperWithDataAndContext); -} - -inline ThreadSafeFunction::ThreadSafeFunction() - : _tsfn() { -} - -inline ThreadSafeFunction::ThreadSafeFunction( - napi_threadsafe_function tsfn) - : _tsfn(tsfn) { -} - -inline ThreadSafeFunction::operator napi_threadsafe_function() const { - return _tsfn; -} - -inline napi_status ThreadSafeFunction::BlockingCall() const { - return CallInternal(nullptr, napi_tsfn_blocking); -} - -template <> -inline napi_status ThreadSafeFunction::BlockingCall( - void* data) const { - return napi_call_threadsafe_function(_tsfn, data, napi_tsfn_blocking); -} - -template -inline napi_status ThreadSafeFunction::BlockingCall( - Callback callback) const { - return CallInternal(new CallbackWrapper(callback), napi_tsfn_blocking); -} - -template -inline napi_status ThreadSafeFunction::BlockingCall( - DataType* data, Callback callback) const { - auto wrapper = [data, callback](Env env, Function jsCallback) { - callback(env, jsCallback, data); - }; - return CallInternal(new CallbackWrapper(wrapper), napi_tsfn_blocking); -} - -inline napi_status ThreadSafeFunction::NonBlockingCall() const { - return CallInternal(nullptr, napi_tsfn_nonblocking); -} - -template <> -inline napi_status ThreadSafeFunction::NonBlockingCall( - void* data) const { - return napi_call_threadsafe_function(_tsfn, data, napi_tsfn_nonblocking); -} - -template -inline napi_status ThreadSafeFunction::NonBlockingCall( - Callback callback) const { - return CallInternal(new CallbackWrapper(callback), napi_tsfn_nonblocking); -} - -template -inline napi_status ThreadSafeFunction::NonBlockingCall( - DataType* data, Callback callback) const { - auto wrapper = [data, callback](Env env, Function jsCallback) { - callback(env, jsCallback, data); - }; - return CallInternal(new CallbackWrapper(wrapper), napi_tsfn_nonblocking); -} - -inline void ThreadSafeFunction::Ref(napi_env env) const { - if (_tsfn != nullptr) { - napi_status status = napi_ref_threadsafe_function(env, _tsfn); - NAPI_THROW_IF_FAILED_VOID(env, status); - } -} - -inline void ThreadSafeFunction::Unref(napi_env env) const { - if (_tsfn != nullptr) { - napi_status status = napi_unref_threadsafe_function(env, _tsfn); - NAPI_THROW_IF_FAILED_VOID(env, status); - } -} - -inline napi_status ThreadSafeFunction::Acquire() const { - return napi_acquire_threadsafe_function(_tsfn); -} - -inline napi_status ThreadSafeFunction::Release() { - return napi_release_threadsafe_function(_tsfn, napi_tsfn_release); -} - -inline napi_status ThreadSafeFunction::Abort() { - return napi_release_threadsafe_function(_tsfn, napi_tsfn_abort); -} - -inline ThreadSafeFunction::ConvertibleContext -ThreadSafeFunction::GetContext() const { - void* context; - napi_status status = napi_get_threadsafe_function_context(_tsfn, &context); - NAPI_FATAL_IF_FAILED(status, "ThreadSafeFunction::GetContext", "napi_get_threadsafe_function_context"); - return ConvertibleContext({ context }); -} - -// static -template -inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env, - const Function& callback, - const Object& resource, - ResourceString resourceName, - size_t maxQueueSize, - size_t initialThreadCount, - ContextType* context, - Finalizer finalizeCallback, - FinalizerDataType* data, - napi_finalize wrapper) { - static_assert(details::can_make_string::value - || std::is_convertible::value, - "Resource name should be convertible to the string type"); - - ThreadSafeFunction tsfn; - auto* finalizeData = new details::ThreadSafeFinalize({ data, finalizeCallback, &tsfn._tsfn }); - napi_status status = napi_create_threadsafe_function(env, callback, resource, - Value::From(env, resourceName), maxQueueSize, initialThreadCount, - finalizeData, wrapper, context, CallJS, &tsfn._tsfn); - if (status != napi_ok) { - delete finalizeData; - NAPI_THROW_IF_FAILED(env, status, ThreadSafeFunction()); - } - - return tsfn; -} - -inline napi_status ThreadSafeFunction::CallInternal( - CallbackWrapper* callbackWrapper, - napi_threadsafe_function_call_mode mode) const { - napi_status status = napi_call_threadsafe_function( - _tsfn, callbackWrapper, mode); - if (status != napi_ok && callbackWrapper != nullptr) { - delete callbackWrapper; - } - - return status; -} - -// static -inline void ThreadSafeFunction::CallJS(napi_env env, - napi_value jsCallback, - void* /* context */, - void* data) { - if (env == nullptr && jsCallback == nullptr) { - return; - } - - if (data != nullptr) { - auto* callbackWrapper = static_cast(data); - (*callbackWrapper)(env, Function(env, jsCallback)); - delete callbackWrapper; - } else if (jsCallback != nullptr) { - Function(env, jsCallback).Call({}); - } -} - -//////////////////////////////////////////////////////////////////////////////// -// Async Progress Worker class -//////////////////////////////////////////////////////////////////////////////// - -template -inline AsyncProgressWorker::AsyncProgressWorker(const Function& callback) - : AsyncProgressWorker(callback, "generic") { -} - -template -inline AsyncProgressWorker::AsyncProgressWorker(const Function& callback, - const char* resource_name) - : AsyncProgressWorker(callback, resource_name, Object::New(callback.Env())) { -} - -template -inline AsyncProgressWorker::AsyncProgressWorker(const Function& callback, - const char* resource_name, - const Object& resource) - : AsyncProgressWorker(Object::New(callback.Env()), - callback, - resource_name, - resource) { -} - -template -inline AsyncProgressWorker::AsyncProgressWorker(const Object& receiver, - const Function& callback) - : AsyncProgressWorker(receiver, callback, "generic") { -} - -template -inline AsyncProgressWorker::AsyncProgressWorker(const Object& receiver, - const Function& callback, - const char* resource_name) - : AsyncProgressWorker(receiver, - callback, - resource_name, - Object::New(callback.Env())) { -} - -template -inline AsyncProgressWorker::AsyncProgressWorker(const Object& receiver, - const Function& callback, - const char* resource_name, - const Object& resource) - : AsyncWorker(receiver, callback, resource_name, resource), - _asyncdata(nullptr), - _asyncsize(0) { - _tsfn = ThreadSafeFunction::New(callback.Env(), callback, resource_name, 1, 1); -} - -#if NAPI_VERSION > 4 -template -inline AsyncProgressWorker::AsyncProgressWorker(Napi::Env env) - : AsyncProgressWorker(env, "generic") { -} - -template -inline AsyncProgressWorker::AsyncProgressWorker(Napi::Env env, - const char* resource_name) - : AsyncProgressWorker(env, resource_name, Object::New(env)) { -} - -template -inline AsyncProgressWorker::AsyncProgressWorker(Napi::Env env, - const char* resource_name, - const Object& resource) - : AsyncWorker(env, resource_name, resource), - _asyncdata(nullptr), - _asyncsize(0) { - // TODO: Once the changes to make the callback optional for threadsafe - // functions are no longer optional we can remove the dummy Function here. - Function callback; - _tsfn = ThreadSafeFunction::New(env, callback, resource_name, 1, 1); -} -#endif - -template -inline AsyncProgressWorker::~AsyncProgressWorker() { - // Abort pending tsfn call. - // Don't send progress events after we've already completed. - _tsfn.Abort(); - { - std::lock_guard lock(_mutex); - _asyncdata = nullptr; - _asyncsize = 0; - } - _tsfn.Release(); -} - -template -inline void AsyncProgressWorker::Execute() { - ExecutionProgress progress(this); - Execute(progress); -} - -template -inline void AsyncProgressWorker::WorkProgress_(Napi::Env /* env */, Napi::Function /* jsCallback */, void* _data) { - AsyncProgressWorker* self = static_cast(_data); - - T* data; - size_t size; - { - std::lock_guard lock(self->_mutex); - data = self->_asyncdata; - size = self->_asyncsize; - self->_asyncdata = nullptr; - self->_asyncsize = 0; - } - - self->OnProgress(data, size); - delete[] data; -} - -template -inline void AsyncProgressWorker::SendProgress_(const T* data, size_t count) { - T* new_data = new T[count]; - std::copy(data, data + count, new_data); - - T* old_data; - { - std::lock_guard lock(_mutex); - old_data = _asyncdata; - _asyncdata = new_data; - _asyncsize = count; - } - _tsfn.NonBlockingCall(this, WorkProgress_); - - delete[] old_data; -} - -template -inline void AsyncProgressWorker::Signal() const { - _tsfn.NonBlockingCall(this, WorkProgress_); -} - -template -inline void AsyncProgressWorker::ExecutionProgress::Signal() const { - _worker->Signal(); -} - -template -inline void AsyncProgressWorker::ExecutionProgress::Send(const T* data, size_t count) const { - _worker->SendProgress_(data, count); -} - -#endif - -//////////////////////////////////////////////////////////////////////////////// -// Memory Management class -//////////////////////////////////////////////////////////////////////////////// - -inline int64_t MemoryManagement::AdjustExternalMemory(Env env, int64_t change_in_bytes) { - int64_t result; - napi_status status = napi_adjust_external_memory(env, change_in_bytes, &result); - NAPI_THROW_IF_FAILED(env, status, 0); - return result; -} - -//////////////////////////////////////////////////////////////////////////////// -// Version Management class -//////////////////////////////////////////////////////////////////////////////// - -inline uint32_t VersionManagement::GetNapiVersion(Env env) { - uint32_t result; - napi_status status = napi_get_version(env, &result); - NAPI_THROW_IF_FAILED(env, status, 0); - return result; -} - -inline const napi_node_version* VersionManagement::GetNodeVersion(Env env) { - const napi_node_version* result; - napi_status status = napi_get_node_version(env, &result); - NAPI_THROW_IF_FAILED(env, status, 0); - return result; -} - -} // namespace Napi - -#endif // SRC_NAPI_INL_H_ diff --git a/vendor/napi.h b/vendor/napi.h deleted file mode 100644 index 62198b1b..00000000 --- a/vendor/napi.h +++ /dev/null @@ -1,2318 +0,0 @@ -#ifndef SRC_NAPI_H_ -#define SRC_NAPI_H_ - -#include -#include -#include -#include -#include -#include -#include - -// VS2015 RTM has bugs with constexpr, so require min of VS2015 Update 3 (known good version) -#if !defined(_MSC_VER) || _MSC_FULL_VER >= 190024210 -#define NAPI_HAS_CONSTEXPR 1 -#endif - -// VS2013 does not support char16_t literal strings, so we'll work around it using wchar_t strings -// and casting them. This is safe as long as the character sizes are the same. -#if defined(_MSC_VER) && _MSC_VER <= 1800 -static_assert(sizeof(char16_t) == sizeof(wchar_t), "Size mismatch between char16_t and wchar_t"); -#define NAPI_WIDE_TEXT(x) reinterpret_cast(L ## x) -#else -#define NAPI_WIDE_TEXT(x) u ## x -#endif - -// If C++ exceptions are not explicitly enabled or disabled, enable them -// if exceptions were enabled in the compiler settings. -#if !defined(NAPI_CPP_EXCEPTIONS) && !defined(NAPI_DISABLE_CPP_EXCEPTIONS) - #if defined(_CPPUNWIND) || defined (__EXCEPTIONS) - #define NAPI_CPP_EXCEPTIONS - #else - #error Exception support not detected. \ - Define either NAPI_CPP_EXCEPTIONS or NAPI_DISABLE_CPP_EXCEPTIONS. - #endif -#endif - -#ifdef _NOEXCEPT - #define NAPI_NOEXCEPT _NOEXCEPT -#else - #define NAPI_NOEXCEPT noexcept -#endif - -#ifdef NAPI_CPP_EXCEPTIONS - -// When C++ exceptions are enabled, Errors are thrown directly. There is no need -// to return anything after the throw statements. The variadic parameter is an -// optional return value that is ignored. -// We need _VOID versions of the macros to avoid warnings resulting from -// leaving the NAPI_THROW_* `...` argument empty. - -#define NAPI_THROW(e, ...) throw e -#define NAPI_THROW_VOID(e) throw e - -#define NAPI_THROW_IF_FAILED(env, status, ...) \ - if ((status) != napi_ok) throw Napi::Error::New(env); - -#define NAPI_THROW_IF_FAILED_VOID(env, status) \ - if ((status) != napi_ok) throw Napi::Error::New(env); - -#else // NAPI_CPP_EXCEPTIONS - -// When C++ exceptions are disabled, Errors are thrown as JavaScript exceptions, -// which are pending until the callback returns to JS. The variadic parameter -// is an optional return value; usually it is an empty result. -// We need _VOID versions of the macros to avoid warnings resulting from -// leaving the NAPI_THROW_* `...` argument empty. - -#define NAPI_THROW(e, ...) \ - do { \ - (e).ThrowAsJavaScriptException(); \ - return __VA_ARGS__; \ - } while (0) - -#define NAPI_THROW_VOID(e) \ - do { \ - (e).ThrowAsJavaScriptException(); \ - return; \ - } while (0) - -#define NAPI_THROW_IF_FAILED(env, status, ...) \ - if ((status) != napi_ok) { \ - Napi::Error::New(env).ThrowAsJavaScriptException(); \ - return __VA_ARGS__; \ - } - -#define NAPI_THROW_IF_FAILED_VOID(env, status) \ - if ((status) != napi_ok) { \ - Napi::Error::New(env).ThrowAsJavaScriptException(); \ - return; \ - } - -#endif // NAPI_CPP_EXCEPTIONS - -#define NAPI_FATAL_IF_FAILED(status, location, message) \ - do { \ - if ((status) != napi_ok) { \ - Napi::Error::Fatal((location), (message)); \ - } \ - } while (0) - -//////////////////////////////////////////////////////////////////////////////// -/// N-API C++ Wrapper Classes -/// -/// These classes wrap the "N-API" ABI-stable C APIs for Node.js, providing a -/// C++ object model and C++ exception-handling semantics with low overhead. -/// The wrappers are all header-only so that they do not affect the ABI. -//////////////////////////////////////////////////////////////////////////////// -namespace Napi { - - // Forward declarations - class Env; - class Value; - class Boolean; - class Number; -// Currently experimental guard with the definition of NAPI_EXPERIMENTAL. -// Once it is no longer experimental guard with the NAPI_VERSION in which it is -// released instead. -#ifdef NAPI_EXPERIMENTAL - class BigInt; -#endif // NAPI_EXPERIMENTAL -#if (NAPI_VERSION > 4) - class Date; -#endif - class String; - class Object; - class Array; - class ArrayBuffer; - class Function; - template class Buffer; - class Error; - class PropertyDescriptor; - class CallbackInfo; - template class Reference; - class TypedArray; - template class TypedArrayOf; - - typedef TypedArrayOf Int8Array; ///< Typed-array of signed 8-bit integers - typedef TypedArrayOf Uint8Array; ///< Typed-array of unsigned 8-bit integers - typedef TypedArrayOf Int16Array; ///< Typed-array of signed 16-bit integers - typedef TypedArrayOf Uint16Array; ///< Typed-array of unsigned 16-bit integers - typedef TypedArrayOf Int32Array; ///< Typed-array of signed 32-bit integers - typedef TypedArrayOf Uint32Array; ///< Typed-array of unsigned 32-bit integers - typedef TypedArrayOf Float32Array; ///< Typed-array of 32-bit floating-point values - typedef TypedArrayOf Float64Array; ///< Typed-array of 64-bit floating-point values -// Currently experimental guard with the definition of NAPI_EXPERIMENTAL. -// Once it is no longer experimental guard with the NAPI_VERSION in which it is -// released instead. -#ifdef NAPI_EXPERIMENTAL - typedef TypedArrayOf BigInt64Array; ///< Typed array of signed 64-bit integers - typedef TypedArrayOf BigUint64Array; ///< Typed array of unsigned 64-bit integers -#endif // NAPI_EXPERIMENTAL - - /// Defines the signature of a N-API C++ module's registration callback (init) function. - typedef Object (*ModuleRegisterCallback)(Env env, Object exports); - - class MemoryManagement; - - /// Environment for N-API values and operations. - /// - /// All N-API values and operations must be associated with an environment. An environment - /// instance is always provided to callback functions; that environment must then be used for any - /// creation of N-API values or other N-API operations within the callback. (Many methods infer - /// the environment from the `this` instance that the method is called on.) - /// - /// In the future, multiple environments per process may be supported, although current - /// implementations only support one environment per process. - /// - /// In the V8 JavaScript engine, a N-API environment approximately corresponds to an Isolate. - class Env { - public: - Env(napi_env env); - - operator napi_env() const; - - Object Global() const; - Value Undefined() const; - Value Null() const; - - bool IsExceptionPending() const; - Error GetAndClearPendingException(); - - Value RunScript(const char* utf8script); - Value RunScript(const std::string& utf8script); - Value RunScript(String script); - - private: - napi_env _env; - }; - - /// A JavaScript value of unknown type. - /// - /// For type-specific operations, convert to one of the Value subclasses using a `To*` or `As()` - /// method. The `To*` methods do type coercion; the `As()` method does not. - /// - /// Napi::Value value = ... - /// if (!value.IsString()) throw Napi::TypeError::New(env, "Invalid arg..."); - /// Napi::String str = value.As(); // Cast to a string value - /// - /// Napi::Value anotherValue = ... - /// bool isTruthy = anotherValue.ToBoolean(); // Coerce to a boolean value - class Value { - public: - Value(); ///< Creates a new _empty_ Value instance. - Value(napi_env env, napi_value value); ///< Wraps a N-API value primitive. - - /// Creates a JS value from a C++ primitive. - /// - /// `value` may be any of: - /// - bool - /// - Any integer type - /// - Any floating point type - /// - const char* (encoded using UTF-8, null-terminated) - /// - const char16_t* (encoded using UTF-16-LE, null-terminated) - /// - std::string (encoded using UTF-8) - /// - std::u16string - /// - napi::Value - /// - napi_value - template - static Value From(napi_env env, const T& value); - - /// Converts to a N-API value primitive. - /// - /// If the instance is _empty_, this returns `nullptr`. - operator napi_value() const; - - /// Tests if this value strictly equals another value. - bool operator ==(const Value& other) const; - - /// Tests if this value does not strictly equal another value. - bool operator !=(const Value& other) const; - - /// Tests if this value strictly equals another value. - bool StrictEquals(const Value& other) const; - - /// Gets the environment the value is associated with. - Napi::Env Env() const; - - /// Checks if the value is empty (uninitialized). - /// - /// An empty value is invalid, and most attempts to perform an operation on an empty value - /// will result in an exception. Note an empty value is distinct from JavaScript `null` or - /// `undefined`, which are valid values. - /// - /// When C++ exceptions are disabled at compile time, a method with a `Value` return type may - /// return an empty value to indicate a pending exception. So when not using C++ exceptions, - /// callers should check whether the value is empty before attempting to use it. - bool IsEmpty() const; - - napi_valuetype Type() const; ///< Gets the type of the value. - - bool IsUndefined() const; ///< Tests if a value is an undefined JavaScript value. - bool IsNull() const; ///< Tests if a value is a null JavaScript value. - bool IsBoolean() const; ///< Tests if a value is a JavaScript boolean. - bool IsNumber() const; ///< Tests if a value is a JavaScript number. -// Currently experimental guard with the definition of NAPI_EXPERIMENTAL. -// Once it is no longer experimental guard with the NAPI_VERSION in which it is -// released instead. -#ifdef NAPI_EXPERIMENTAL - bool IsBigInt() const; ///< Tests if a value is a JavaScript bigint. -#endif // NAPI_EXPERIMENTAL -#if (NAPI_VERSION > 4) - bool IsDate() const; ///< Tests if a value is a JavaScript date. -#endif - bool IsString() const; ///< Tests if a value is a JavaScript string. - bool IsSymbol() const; ///< Tests if a value is a JavaScript symbol. - bool IsArray() const; ///< Tests if a value is a JavaScript array. - bool IsArrayBuffer() const; ///< Tests if a value is a JavaScript array buffer. - bool IsTypedArray() const; ///< Tests if a value is a JavaScript typed array. - bool IsObject() const; ///< Tests if a value is a JavaScript object. - bool IsFunction() const; ///< Tests if a value is a JavaScript function. - bool IsPromise() const; ///< Tests if a value is a JavaScript promise. - bool IsDataView() const; ///< Tests if a value is a JavaScript data view. - bool IsBuffer() const; ///< Tests if a value is a Node buffer. - bool IsExternal() const; ///< Tests if a value is a pointer to external data. - - /// Casts to another type of `Napi::Value`, when the actual type is known or assumed. - /// - /// This conversion does NOT coerce the type. Calling any methods inappropriate for the actual - /// value type will throw `Napi::Error`. - template T As() const; - - Boolean ToBoolean() const; ///< Coerces a value to a JavaScript boolean. - Number ToNumber() const; ///< Coerces a value to a JavaScript number. - String ToString() const; ///< Coerces a value to a JavaScript string. - Object ToObject() const; ///< Coerces a value to a JavaScript object. - - protected: - /// !cond INTERNAL - napi_env _env; - napi_value _value; - /// !endcond - }; - - /// A JavaScript boolean value. - class Boolean : public Value { - public: - static Boolean New( - napi_env env, ///< N-API environment - bool value ///< Boolean value - ); - - Boolean(); ///< Creates a new _empty_ Boolean instance. - Boolean(napi_env env, napi_value value); ///< Wraps a N-API value primitive. - - operator bool() const; ///< Converts a Boolean value to a boolean primitive. - bool Value() const; ///< Converts a Boolean value to a boolean primitive. - }; - - /// A JavaScript number value. - class Number : public Value { - public: - static Number New( - napi_env env, ///< N-API environment - double value ///< Number value - ); - - Number(); ///< Creates a new _empty_ Number instance. - Number(napi_env env, napi_value value); ///< Wraps a N-API value primitive. - - operator int32_t() const; ///< Converts a Number value to a 32-bit signed integer value. - operator uint32_t() const; ///< Converts a Number value to a 32-bit unsigned integer value. - operator int64_t() const; ///< Converts a Number value to a 64-bit signed integer value. - operator float() const; ///< Converts a Number value to a 32-bit floating-point value. - operator double() const; ///< Converts a Number value to a 64-bit floating-point value. - - int32_t Int32Value() const; ///< Converts a Number value to a 32-bit signed integer value. - uint32_t Uint32Value() const; ///< Converts a Number value to a 32-bit unsigned integer value. - int64_t Int64Value() const; ///< Converts a Number value to a 64-bit signed integer value. - float FloatValue() const; ///< Converts a Number value to a 32-bit floating-point value. - double DoubleValue() const; ///< Converts a Number value to a 64-bit floating-point value. - }; - -// Currently experimental guard with the definition of NAPI_EXPERIMENTAL. -// Once it is no longer experimental guard with the NAPI_VERSION in which it is -// released instead. -#ifdef NAPI_EXPERIMENTAL - /// A JavaScript bigint value. - class BigInt : public Value { - public: - static BigInt New( - napi_env env, ///< N-API environment - int64_t value ///< Number value - ); - static BigInt New( - napi_env env, ///< N-API environment - uint64_t value ///< Number value - ); - - /// Creates a new BigInt object using a specified sign bit and a - /// specified list of digits/words. - /// The resulting number is calculated as: - /// (-1)^sign_bit * (words[0] * (2^64)^0 + words[1] * (2^64)^1 + ...) - static BigInt New( - napi_env env, ///< N-API environment - int sign_bit, ///< Sign bit. 1 if negative. - size_t word_count, ///< Number of words in array - const uint64_t* words ///< Array of words - ); - - BigInt(); ///< Creates a new _empty_ BigInt instance. - BigInt(napi_env env, napi_value value); ///< Wraps a N-API value primitive. - - int64_t Int64Value(bool* lossless) const; ///< Converts a BigInt value to a 64-bit signed integer value. - uint64_t Uint64Value(bool* lossless) const; ///< Converts a BigInt value to a 64-bit unsigned integer value. - - size_t WordCount() const; ///< The number of 64-bit words needed to store the result of ToWords(). - - /// Writes the contents of this BigInt to a specified memory location. - /// `sign_bit` must be provided and will be set to 1 if this BigInt is negative. - /// `*word_count` has to be initialized to the length of the `words` array. - /// Upon return, it will be set to the actual number of words that would - /// be needed to store this BigInt (i.e. the return value of `WordCount()`). - void ToWords(int* sign_bit, size_t* word_count, uint64_t* words); - }; -#endif // NAPI_EXPERIMENTAL - -#if (NAPI_VERSION > 4) - /// A JavaScript date value. - class Date : public Value { - public: - /// Creates a new Date value from a double primitive. - static Date New( - napi_env env, ///< N-API environment - double value ///< Number value - ); - - Date(); ///< Creates a new _empty_ Date instance. - Date(napi_env env, napi_value value); ///< Wraps a N-API value primitive. - operator double() const; ///< Converts a Date value to double primitive - - double ValueOf() const; ///< Converts a Date value to a double primitive. - }; - #endif - - /// A JavaScript string or symbol value (that can be used as a property name). - class Name : public Value { - public: - Name(); ///< Creates a new _empty_ Name instance. - Name(napi_env env, napi_value value); ///< Wraps a N-API value primitive. - }; - - /// A JavaScript string value. - class String : public Name { - public: - /// Creates a new String value from a UTF-8 encoded C++ string. - static String New( - napi_env env, ///< N-API environment - const std::string& value ///< UTF-8 encoded C++ string - ); - - /// Creates a new String value from a UTF-16 encoded C++ string. - static String New( - napi_env env, ///< N-API environment - const std::u16string& value ///< UTF-16 encoded C++ string - ); - - /// Creates a new String value from a UTF-8 encoded C string. - static String New( - napi_env env, ///< N-API environment - const char* value ///< UTF-8 encoded null-terminated C string - ); - - /// Creates a new String value from a UTF-16 encoded C string. - static String New( - napi_env env, ///< N-API environment - const char16_t* value ///< UTF-16 encoded null-terminated C string - ); - - /// Creates a new String value from a UTF-8 encoded C string with specified length. - static String New( - napi_env env, ///< N-API environment - const char* value, ///< UTF-8 encoded C string (not necessarily null-terminated) - size_t length ///< length of the string in bytes - ); - - /// Creates a new String value from a UTF-16 encoded C string with specified length. - static String New( - napi_env env, ///< N-API environment - const char16_t* value, ///< UTF-16 encoded C string (not necessarily null-terminated) - size_t length ///< Length of the string in 2-byte code units - ); - - /// Creates a new String based on the original object's type. - /// - /// `value` may be any of: - /// - const char* (encoded using UTF-8, null-terminated) - /// - const char16_t* (encoded using UTF-16-LE, null-terminated) - /// - std::string (encoded using UTF-8) - /// - std::u16string - template - static String From(napi_env env, const T& value); - - String(); ///< Creates a new _empty_ String instance. - String(napi_env env, napi_value value); ///< Wraps a N-API value primitive. - - operator std::string() const; ///< Converts a String value to a UTF-8 encoded C++ string. - operator std::u16string() const; ///< Converts a String value to a UTF-16 encoded C++ string. - std::string Utf8Value() const; ///< Converts a String value to a UTF-8 encoded C++ string. - std::u16string Utf16Value() const; ///< Converts a String value to a UTF-16 encoded C++ string. - }; - - /// A JavaScript symbol value. - class Symbol : public Name { - public: - /// Creates a new Symbol value with an optional description. - static Symbol New( - napi_env env, ///< N-API environment - const char* description = nullptr ///< Optional UTF-8 encoded null-terminated C string - /// describing the symbol - ); - - /// Creates a new Symbol value with a description. - static Symbol New( - napi_env env, ///< N-API environment - const std::string& description ///< UTF-8 encoded C++ string describing the symbol - ); - - /// Creates a new Symbol value with a description. - static Symbol New( - napi_env env, ///< N-API environment - String description ///< String value describing the symbol - ); - - /// Creates a new Symbol value with a description. - static Symbol New( - napi_env env, ///< N-API environment - napi_value description ///< String value describing the symbol - ); - - /// Get a public Symbol (e.g. Symbol.iterator). - static Symbol WellKnown(napi_env, const std::string& name); - - Symbol(); ///< Creates a new _empty_ Symbol instance. - Symbol(napi_env env, napi_value value); ///< Wraps a N-API value primitive. - }; - - /// A JavaScript object value. - class Object : public Value { - public: - /// Enables property and element assignments using indexing syntax. - /// - /// Example: - /// - /// Napi::Value propertyValue = object1['A']; - /// object2['A'] = propertyValue; - /// Napi::Value elementValue = array[0]; - /// array[1] = elementValue; - template - class PropertyLValue { - public: - /// Converts an L-value to a value. - operator Value() const; - - /// Assigns a value to the property. The type of value can be - /// anything supported by `Object::Set`. - template - PropertyLValue& operator =(ValueType value); - - private: - PropertyLValue() = delete; - PropertyLValue(Object object, Key key); - napi_env _env; - napi_value _object; - Key _key; - - friend class Napi::Object; - }; - - /// Creates a new Object value. - static Object New( - napi_env env ///< N-API environment - ); - - Object(); ///< Creates a new _empty_ Object instance. - Object(napi_env env, napi_value value); ///< Wraps a N-API value primitive. - - /// Gets or sets a named property. - PropertyLValue operator []( - const char* utf8name ///< UTF-8 encoded null-terminated property name - ); - - /// Gets or sets a named property. - PropertyLValue operator []( - const std::string& utf8name ///< UTF-8 encoded property name - ); - - /// Gets or sets an indexed property or array element. - PropertyLValue operator []( - uint32_t index /// Property / element index - ); - - /// Gets a named property. - Value operator []( - const char* utf8name ///< UTF-8 encoded null-terminated property name - ) const; - - /// Gets a named property. - Value operator []( - const std::string& utf8name ///< UTF-8 encoded property name - ) const; - - /// Gets an indexed property or array element. - Value operator []( - uint32_t index ///< Property / element index - ) const; - - /// Checks whether a property is present. - bool Has( - napi_value key ///< Property key primitive - ) const; - - /// Checks whether a property is present. - bool Has( - Value key ///< Property key - ) const; - - /// Checks whether a named property is present. - bool Has( - const char* utf8name ///< UTF-8 encoded null-terminated property name - ) const; - - /// Checks whether a named property is present. - bool Has( - const std::string& utf8name ///< UTF-8 encoded property name - ) const; - - /// Checks whether a own property is present. - bool HasOwnProperty( - napi_value key ///< Property key primitive - ) const; - - /// Checks whether a own property is present. - bool HasOwnProperty( - Value key ///< Property key - ) const; - - /// Checks whether a own property is present. - bool HasOwnProperty( - const char* utf8name ///< UTF-8 encoded null-terminated property name - ) const; - - /// Checks whether a own property is present. - bool HasOwnProperty( - const std::string& utf8name ///< UTF-8 encoded property name - ) const; - - /// Gets a property. - Value Get( - napi_value key ///< Property key primitive - ) const; - - /// Gets a property. - Value Get( - Value key ///< Property key - ) const; - - /// Gets a named property. - Value Get( - const char* utf8name ///< UTF-8 encoded null-terminated property name - ) const; - - /// Gets a named property. - Value Get( - const std::string& utf8name ///< UTF-8 encoded property name - ) const; - - /// Sets a property. - template - void Set( - napi_value key, ///< Property key primitive - const ValueType& value ///< Property value primitive - ); - - /// Sets a property. - template - void Set( - Value key, ///< Property key - const ValueType& value ///< Property value - ); - - /// Sets a named property. - template - void Set( - const char* utf8name, ///< UTF-8 encoded null-terminated property name - const ValueType& value - ); - - /// Sets a named property. - template - void Set( - const std::string& utf8name, ///< UTF-8 encoded property name - const ValueType& value ///< Property value primitive - ); - - /// Delete property. - bool Delete( - napi_value key ///< Property key primitive - ); - - /// Delete property. - bool Delete( - Value key ///< Property key - ); - - /// Delete property. - bool Delete( - const char* utf8name ///< UTF-8 encoded null-terminated property name - ); - - /// Delete property. - bool Delete( - const std::string& utf8name ///< UTF-8 encoded property name - ); - - /// Checks whether an indexed property is present. - bool Has( - uint32_t index ///< Property / element index - ) const; - - /// Gets an indexed property or array element. - Value Get( - uint32_t index ///< Property / element index - ) const; - - /// Sets an indexed property or array element. - template - void Set( - uint32_t index, ///< Property / element index - const ValueType& value ///< Property value primitive - ); - - /// Deletes an indexed property or array element. - bool Delete( - uint32_t index ///< Property / element index - ); - - Array GetPropertyNames() const; ///< Get all property names - - /// Defines a property on the object. - void DefineProperty( - const PropertyDescriptor& property ///< Descriptor for the property to be defined - ); - - /// Defines properties on the object. - void DefineProperties( - const std::initializer_list& properties - ///< List of descriptors for the properties to be defined - ); - - /// Defines properties on the object. - void DefineProperties( - const std::vector& properties - ///< Vector of descriptors for the properties to be defined - ); - - /// Checks if an object is an instance created by a constructor function. - /// - /// This is equivalent to the JavaScript `instanceof` operator. - bool InstanceOf( - const Function& constructor ///< Constructor function - ) const; - - template - inline void AddFinalizer(Finalizer finalizeCallback, T* data); - - template - inline void AddFinalizer(Finalizer finalizeCallback, - T* data, - Hint* finalizeHint); - }; - - template - class External : public Value { - public: - static External New(napi_env env, T* data); - - // Finalizer must implement `void operator()(Env env, T* data)`. - template - static External New(napi_env env, - T* data, - Finalizer finalizeCallback); - // Finalizer must implement `void operator()(Env env, T* data, Hint* hint)`. - template - static External New(napi_env env, - T* data, - Finalizer finalizeCallback, - Hint* finalizeHint); - - External(); - External(napi_env env, napi_value value); - - T* Data() const; - }; - - class Array : public Object { - public: - static Array New(napi_env env); - static Array New(napi_env env, size_t length); - - Array(); - Array(napi_env env, napi_value value); - - uint32_t Length() const; - }; - - /// A JavaScript array buffer value. - class ArrayBuffer : public Object { - public: - /// Creates a new ArrayBuffer instance over a new automatically-allocated buffer. - static ArrayBuffer New( - napi_env env, ///< N-API environment - size_t byteLength ///< Length of the buffer to be allocated, in bytes - ); - - /// Creates a new ArrayBuffer instance, using an external buffer with specified byte length. - static ArrayBuffer New( - napi_env env, ///< N-API environment - void* externalData, ///< Pointer to the external buffer to be used by the array - size_t byteLength ///< Length of the external buffer to be used by the array, in bytes - ); - - /// Creates a new ArrayBuffer instance, using an external buffer with specified byte length. - template - static ArrayBuffer New( - napi_env env, ///< N-API environment - void* externalData, ///< Pointer to the external buffer to be used by the array - size_t byteLength, ///< Length of the external buffer to be used by the array, - /// in bytes - Finalizer finalizeCallback ///< Function to be called when the array buffer is destroyed; - /// must implement `void operator()(Env env, void* externalData)` - ); - - /// Creates a new ArrayBuffer instance, using an external buffer with specified byte length. - template - static ArrayBuffer New( - napi_env env, ///< N-API environment - void* externalData, ///< Pointer to the external buffer to be used by the array - size_t byteLength, ///< Length of the external buffer to be used by the array, - /// in bytes - Finalizer finalizeCallback, ///< Function to be called when the array buffer is destroyed; - /// must implement `void operator()(Env env, void* externalData, Hint* hint)` - Hint* finalizeHint ///< Hint (second parameter) to be passed to the finalize callback - ); - - ArrayBuffer(); ///< Creates a new _empty_ ArrayBuffer instance. - ArrayBuffer(napi_env env, napi_value value); ///< Wraps a N-API value primitive. - - void* Data(); ///< Gets a pointer to the data buffer. - size_t ByteLength(); ///< Gets the length of the array buffer in bytes. - }; - - /// A JavaScript typed-array value with unknown array type. - /// - /// For type-specific operations, cast to a `TypedArrayOf` instance using the `As()` - /// method: - /// - /// Napi::TypedArray array = ... - /// if (t.TypedArrayType() == napi_int32_array) { - /// Napi::Int32Array int32Array = t.As(); - /// } - class TypedArray : public Object { - public: - TypedArray(); ///< Creates a new _empty_ TypedArray instance. - TypedArray(napi_env env, napi_value value); ///< Wraps a N-API value primitive. - - napi_typedarray_type TypedArrayType() const; ///< Gets the type of this typed-array. - Napi::ArrayBuffer ArrayBuffer() const; ///< Gets the backing array buffer. - - uint8_t ElementSize() const; ///< Gets the size in bytes of one element in the array. - size_t ElementLength() const; ///< Gets the number of elements in the array. - size_t ByteOffset() const; ///< Gets the offset into the buffer where the array starts. - size_t ByteLength() const; ///< Gets the length of the array in bytes. - - protected: - /// !cond INTERNAL - napi_typedarray_type _type; - size_t _length; - - TypedArray(napi_env env, napi_value value, napi_typedarray_type type, size_t length); - - static const napi_typedarray_type unknown_array_type = static_cast(-1); - - template - static -#if defined(NAPI_HAS_CONSTEXPR) - constexpr -#endif - napi_typedarray_type TypedArrayTypeForPrimitiveType() { - return std::is_same::value ? napi_int8_array - : std::is_same::value ? napi_uint8_array - : std::is_same::value ? napi_int16_array - : std::is_same::value ? napi_uint16_array - : std::is_same::value ? napi_int32_array - : std::is_same::value ? napi_uint32_array - : std::is_same::value ? napi_float32_array - : std::is_same::value ? napi_float64_array -// Currently experimental guard with the definition of NAPI_EXPERIMENTAL. -// Once it is no longer experimental guard with the NAPI_VERSION in which it is -// released instead. -#ifdef NAPI_EXPERIMENTAL - : std::is_same::value ? napi_bigint64_array - : std::is_same::value ? napi_biguint64_array -#endif // NAPI_EXPERIMENTAL - : unknown_array_type; - } - /// !endcond - }; - - /// A JavaScript typed-array value with known array type. - /// - /// Note while it is possible to create and access Uint8 "clamped" arrays using this class, - /// the _clamping_ behavior is only applied in JavaScript. - template - class TypedArrayOf : public TypedArray { - public: - /// Creates a new TypedArray instance over a new automatically-allocated array buffer. - /// - /// The array type parameter can normally be omitted (because it is inferred from the template - /// parameter T), except when creating a "clamped" array: - /// - /// Uint8Array::New(env, length, napi_uint8_clamped_array) - static TypedArrayOf New( - napi_env env, ///< N-API environment - size_t elementLength, ///< Length of the created array, as a number of elements -#if defined(NAPI_HAS_CONSTEXPR) - napi_typedarray_type type = TypedArray::TypedArrayTypeForPrimitiveType() -#else - napi_typedarray_type type -#endif - ///< Type of array, if different from the default array type for the template parameter T. - ); - - /// Creates a new TypedArray instance over a provided array buffer. - /// - /// The array type parameter can normally be omitted (because it is inferred from the template - /// parameter T), except when creating a "clamped" array: - /// - /// Uint8Array::New(env, length, buffer, 0, napi_uint8_clamped_array) - static TypedArrayOf New( - napi_env env, ///< N-API environment - size_t elementLength, ///< Length of the created array, as a number of elements - Napi::ArrayBuffer arrayBuffer, ///< Backing array buffer instance to use - size_t bufferOffset, ///< Offset into the array buffer where the typed-array starts -#if defined(NAPI_HAS_CONSTEXPR) - napi_typedarray_type type = TypedArray::TypedArrayTypeForPrimitiveType() -#else - napi_typedarray_type type -#endif - ///< Type of array, if different from the default array type for the template parameter T. - ); - - TypedArrayOf(); ///< Creates a new _empty_ TypedArrayOf instance. - TypedArrayOf(napi_env env, napi_value value); ///< Wraps a N-API value primitive. - - T& operator [](size_t index); ///< Gets or sets an element in the array. - const T& operator [](size_t index) const; ///< Gets an element in the array. - - /// Gets a pointer to the array's backing buffer. - /// - /// This is not necessarily the same as the `ArrayBuffer::Data()` pointer, because the - /// typed-array may have a non-zero `ByteOffset()` into the `ArrayBuffer`. - T* Data(); - - /// Gets a pointer to the array's backing buffer. - /// - /// This is not necessarily the same as the `ArrayBuffer::Data()` pointer, because the - /// typed-array may have a non-zero `ByteOffset()` into the `ArrayBuffer`. - const T* Data() const; - - private: - T* _data; - - TypedArrayOf(napi_env env, - napi_value value, - napi_typedarray_type type, - size_t length, - T* data); - }; - - /// The DataView provides a low-level interface for reading/writing multiple - /// number types in an ArrayBuffer irrespective of the platform's endianness. - class DataView : public Object { - public: - static DataView New(napi_env env, - Napi::ArrayBuffer arrayBuffer); - static DataView New(napi_env env, - Napi::ArrayBuffer arrayBuffer, - size_t byteOffset); - static DataView New(napi_env env, - Napi::ArrayBuffer arrayBuffer, - size_t byteOffset, - size_t byteLength); - - DataView(); ///< Creates a new _empty_ DataView instance. - DataView(napi_env env, napi_value value); ///< Wraps a N-API value primitive. - - Napi::ArrayBuffer ArrayBuffer() const; ///< Gets the backing array buffer. - size_t ByteOffset() const; ///< Gets the offset into the buffer where the array starts. - size_t ByteLength() const; ///< Gets the length of the array in bytes. - - void* Data() const; - - float GetFloat32(size_t byteOffset) const; - double GetFloat64(size_t byteOffset) const; - int8_t GetInt8(size_t byteOffset) const; - int16_t GetInt16(size_t byteOffset) const; - int32_t GetInt32(size_t byteOffset) const; - uint8_t GetUint8(size_t byteOffset) const; - uint16_t GetUint16(size_t byteOffset) const; - uint32_t GetUint32(size_t byteOffset) const; - - void SetFloat32(size_t byteOffset, float value) const; - void SetFloat64(size_t byteOffset, double value) const; - void SetInt8(size_t byteOffset, int8_t value) const; - void SetInt16(size_t byteOffset, int16_t value) const; - void SetInt32(size_t byteOffset, int32_t value) const; - void SetUint8(size_t byteOffset, uint8_t value) const; - void SetUint16(size_t byteOffset, uint16_t value) const; - void SetUint32(size_t byteOffset, uint32_t value) const; - - private: - template - T ReadData(size_t byteOffset) const; - - template - void WriteData(size_t byteOffset, T value) const; - - void* _data; - size_t _length; - }; - - class Function : public Object { - public: - typedef void (*VoidCallback)(const CallbackInfo& info); - typedef Value (*Callback)(const CallbackInfo& info); - - template - static Function New(napi_env env, - const char* utf8name = nullptr, - void* data = nullptr); - - template - static Function New(napi_env env, - const char* utf8name = nullptr, - void* data = nullptr); - - template - static Function New(napi_env env, - const std::string& utf8name, - void* data = nullptr); - - template - static Function New(napi_env env, - const std::string& utf8name, - void* data = nullptr); - - /// Callable must implement operator() accepting a const CallbackInfo& - /// and return either void or Value. - template - static Function New(napi_env env, - Callable cb, - const char* utf8name = nullptr, - void* data = nullptr); - /// Callable must implement operator() accepting a const CallbackInfo& - /// and return either void or Value. - template - static Function New(napi_env env, - Callable cb, - const std::string& utf8name, - void* data = nullptr); - - Function(); - Function(napi_env env, napi_value value); - - Value operator ()(const std::initializer_list& args) const; - - Value Call(const std::initializer_list& args) const; - Value Call(const std::vector& args) const; - Value Call(size_t argc, const napi_value* args) const; - Value Call(napi_value recv, const std::initializer_list& args) const; - Value Call(napi_value recv, const std::vector& args) const; - Value Call(napi_value recv, size_t argc, const napi_value* args) const; - - Value MakeCallback(napi_value recv, - const std::initializer_list& args, - napi_async_context context = nullptr) const; - Value MakeCallback(napi_value recv, - const std::vector& args, - napi_async_context context = nullptr) const; - Value MakeCallback(napi_value recv, - size_t argc, - const napi_value* args, - napi_async_context context = nullptr) const; - - Object New(const std::initializer_list& args) const; - Object New(const std::vector& args) const; - Object New(size_t argc, const napi_value* args) const; - }; - - class Promise : public Object { - public: - class Deferred { - public: - static Deferred New(napi_env env); - Deferred(napi_env env); - - Napi::Promise Promise() const; - Napi::Env Env() const; - - void Resolve(napi_value value) const; - void Reject(napi_value value) const; - - private: - napi_env _env; - napi_deferred _deferred; - napi_value _promise; - }; - - Promise(napi_env env, napi_value value); - }; - - template - class Buffer : public Uint8Array { - public: - static Buffer New(napi_env env, size_t length); - static Buffer New(napi_env env, T* data, size_t length); - - // Finalizer must implement `void operator()(Env env, T* data)`. - template - static Buffer New(napi_env env, T* data, - size_t length, - Finalizer finalizeCallback); - // Finalizer must implement `void operator()(Env env, T* data, Hint* hint)`. - template - static Buffer New(napi_env env, T* data, - size_t length, - Finalizer finalizeCallback, - Hint* finalizeHint); - - static Buffer Copy(napi_env env, const T* data, size_t length); - - Buffer(); - Buffer(napi_env env, napi_value value); - size_t Length() const; - T* Data() const; - - private: - mutable size_t _length; - mutable T* _data; - - Buffer(napi_env env, napi_value value, size_t length, T* data); - void EnsureInfo() const; - }; - - /// Holds a counted reference to a value; initially a weak reference unless otherwise specified, - /// may be changed to/from a strong reference by adjusting the refcount. - /// - /// The referenced value is not immediately destroyed when the reference count is zero; it is - /// merely then eligible for garbage-collection if there are no other references to the value. - template - class Reference { - public: - static Reference New(const T& value, uint32_t initialRefcount = 0); - - Reference(); - Reference(napi_env env, napi_ref ref); - ~Reference(); - - // A reference can be moved but cannot be copied. - Reference(Reference&& other); - Reference& operator =(Reference&& other); - Reference& operator =(const Reference&) = delete; - - operator napi_ref() const; - bool operator ==(const Reference &other) const; - bool operator !=(const Reference &other) const; - - Napi::Env Env() const; - bool IsEmpty() const; - - // Note when getting the value of a Reference it is usually correct to do so - // within a HandleScope so that the value handle gets cleaned up efficiently. - T Value() const; - - uint32_t Ref(); - uint32_t Unref(); - void Reset(); - void Reset(const T& value, uint32_t refcount = 0); - - // Call this on a reference that is declared as static data, to prevent its destructor - // from running at program shutdown time, which would attempt to reset the reference when - // the environment is no longer valid. - void SuppressDestruct(); - - protected: - Reference(const Reference&); - - /// !cond INTERNAL - napi_env _env; - napi_ref _ref; - /// !endcond - - private: - bool _suppressDestruct; - }; - - class ObjectReference: public Reference { - public: - ObjectReference(); - ObjectReference(napi_env env, napi_ref ref); - - // A reference can be moved but cannot be copied. - ObjectReference(Reference&& other); - ObjectReference& operator =(Reference&& other); - ObjectReference(ObjectReference&& other); - ObjectReference& operator =(ObjectReference&& other); - ObjectReference& operator =(const ObjectReference&) = delete; - - Napi::Value Get(const char* utf8name) const; - Napi::Value Get(const std::string& utf8name) const; - void Set(const char* utf8name, napi_value value); - void Set(const char* utf8name, Napi::Value value); - void Set(const char* utf8name, const char* utf8value); - void Set(const char* utf8name, bool boolValue); - void Set(const char* utf8name, double numberValue); - void Set(const std::string& utf8name, napi_value value); - void Set(const std::string& utf8name, Napi::Value value); - void Set(const std::string& utf8name, std::string& utf8value); - void Set(const std::string& utf8name, bool boolValue); - void Set(const std::string& utf8name, double numberValue); - - Napi::Value Get(uint32_t index) const; - void Set(uint32_t index, const napi_value value); - void Set(uint32_t index, const Napi::Value value); - void Set(uint32_t index, const char* utf8value); - void Set(uint32_t index, const std::string& utf8value); - void Set(uint32_t index, bool boolValue); - void Set(uint32_t index, double numberValue); - - protected: - ObjectReference(const ObjectReference&); - }; - - class FunctionReference: public Reference { - public: - FunctionReference(); - FunctionReference(napi_env env, napi_ref ref); - - // A reference can be moved but cannot be copied. - FunctionReference(Reference&& other); - FunctionReference& operator =(Reference&& other); - FunctionReference(FunctionReference&& other); - FunctionReference& operator =(FunctionReference&& other); - FunctionReference(const FunctionReference&) = delete; - FunctionReference& operator =(const FunctionReference&) = delete; - - Napi::Value operator ()(const std::initializer_list& args) const; - - Napi::Value Call(const std::initializer_list& args) const; - Napi::Value Call(const std::vector& args) const; - Napi::Value Call(napi_value recv, const std::initializer_list& args) const; - Napi::Value Call(napi_value recv, const std::vector& args) const; - Napi::Value Call(napi_value recv, size_t argc, const napi_value* args) const; - - Napi::Value MakeCallback(napi_value recv, - const std::initializer_list& args, - napi_async_context context = nullptr) const; - Napi::Value MakeCallback(napi_value recv, - const std::vector& args, - napi_async_context context = nullptr) const; - Napi::Value MakeCallback(napi_value recv, - size_t argc, - const napi_value* args, - napi_async_context context = nullptr) const; - - Object New(const std::initializer_list& args) const; - Object New(const std::vector& args) const; - }; - - // Shortcuts to creating a new reference with inferred type and refcount = 0. - template Reference Weak(T value); - ObjectReference Weak(Object value); - FunctionReference Weak(Function value); - - // Shortcuts to creating a new reference with inferred type and refcount = 1. - template Reference Persistent(T value); - ObjectReference Persistent(Object value); - FunctionReference Persistent(Function value); - - /// A persistent reference to a JavaScript error object. Use of this class depends somewhat - /// on whether C++ exceptions are enabled at compile time. - /// - /// ### Handling Errors With C++ Exceptions - /// - /// If C++ exceptions are enabled, then the `Error` class extends `std::exception` and enables - /// integrated error-handling for C++ exceptions and JavaScript exceptions. - /// - /// If a N-API call fails without executing any JavaScript code (for example due to an invalid - /// argument), then the N-API wrapper automatically converts and throws the error as a C++ - /// exception of type `Napi::Error`. Or if a JavaScript function called by C++ code via N-API - /// throws a JavaScript exception, then the N-API wrapper automatically converts and throws it as - /// a C++ exception of type `Napi::Error`. - /// - /// If a C++ exception of type `Napi::Error` escapes from a N-API C++ callback, then the N-API - /// wrapper automatically converts and throws it as a JavaScript exception. Therefore, catching - /// a C++ exception of type `Napi::Error` prevents a JavaScript exception from being thrown. - /// - /// #### Example 1A - Throwing a C++ exception: - /// - /// Napi::Env env = ... - /// throw Napi::Error::New(env, "Example exception"); - /// - /// Following C++ statements will not be executed. The exception will bubble up as a C++ - /// exception of type `Napi::Error`, until it is either caught while still in C++, or else - /// automatically propataged as a JavaScript exception when the callback returns to JavaScript. - /// - /// #### Example 2A - Propagating a N-API C++ exception: - /// - /// Napi::Function jsFunctionThatThrows = someObj.As(); - /// Napi::Value result = jsFunctionThatThrows({ arg1, arg2 }); - /// - /// Following C++ statements will not be executed. The exception will bubble up as a C++ - /// exception of type `Napi::Error`, until it is either caught while still in C++, or else - /// automatically propagated as a JavaScript exception when the callback returns to JavaScript. - /// - /// #### Example 3A - Handling a N-API C++ exception: - /// - /// Napi::Function jsFunctionThatThrows = someObj.As(); - /// Napi::Value result; - /// try { - /// result = jsFunctionThatThrows({ arg1, arg2 }); - /// } catch (const Napi::Error& e) { - /// cerr << "Caught JavaScript exception: " + e.what(); - /// } - /// - /// Since the exception was caught here, it will not be propagated as a JavaScript exception. - /// - /// ### Handling Errors Without C++ Exceptions - /// - /// If C++ exceptions are disabled (by defining `NAPI_DISABLE_CPP_EXCEPTIONS`) then this class - /// does not extend `std::exception`, and APIs in the `Napi` namespace do not throw C++ - /// exceptions when they fail. Instead, they raise _pending_ JavaScript exceptions and - /// return _empty_ `Value`s. Calling code should check `Value::IsEmpty()` before attempting - /// to use a returned value, and may use methods on the `Env` class to check for, get, and - /// clear a pending JavaScript exception. If the pending exception is not cleared, it will - /// be thrown when the native callback returns to JavaScript. - /// - /// #### Example 1B - Throwing a JS exception - /// - /// Napi::Env env = ... - /// Napi::Error::New(env, "Example exception").ThrowAsJavaScriptException(); - /// return; - /// - /// After throwing a JS exception, the code should generally return immediately from the native - /// callback, after performing any necessary cleanup. - /// - /// #### Example 2B - Propagating a N-API JS exception: - /// - /// Napi::Function jsFunctionThatThrows = someObj.As(); - /// Napi::Value result = jsFunctionThatThrows({ arg1, arg2 }); - /// if (result.IsEmpty()) return; - /// - /// An empty value result from a N-API call indicates an error occurred, and a JavaScript - /// exception is pending. To let the exception propagate, the code should generally return - /// immediately from the native callback, after performing any necessary cleanup. - /// - /// #### Example 3B - Handling a N-API JS exception: - /// - /// Napi::Function jsFunctionThatThrows = someObj.As(); - /// Napi::Value result = jsFunctionThatThrows({ arg1, arg2 }); - /// if (result.IsEmpty()) { - /// Napi::Error e = env.GetAndClearPendingException(); - /// cerr << "Caught JavaScript exception: " + e.Message(); - /// } - /// - /// Since the exception was cleared here, it will not be propagated as a JavaScript exception - /// after the native callback returns. - class Error : public ObjectReference -#ifdef NAPI_CPP_EXCEPTIONS - , public std::exception -#endif // NAPI_CPP_EXCEPTIONS - { - public: - static Error New(napi_env env); - static Error New(napi_env env, const char* message); - static Error New(napi_env env, const std::string& message); - - static NAPI_NO_RETURN void Fatal(const char* location, const char* message); - - Error(); - Error(napi_env env, napi_value value); - - // An error can be moved or copied. - Error(Error&& other); - Error& operator =(Error&& other); - Error(const Error&); - Error& operator =(const Error&); - - const std::string& Message() const NAPI_NOEXCEPT; - void ThrowAsJavaScriptException() const; - -#ifdef NAPI_CPP_EXCEPTIONS - const char* what() const NAPI_NOEXCEPT override; -#endif // NAPI_CPP_EXCEPTIONS - - protected: - /// !cond INTERNAL - typedef napi_status (*create_error_fn)(napi_env envb, napi_value code, napi_value msg, napi_value* result); - - template - static TError New(napi_env env, - const char* message, - size_t length, - create_error_fn create_error); - /// !endcond - - private: - mutable std::string _message; - }; - - class TypeError : public Error { - public: - static TypeError New(napi_env env, const char* message); - static TypeError New(napi_env env, const std::string& message); - - TypeError(); - TypeError(napi_env env, napi_value value); - }; - - class RangeError : public Error { - public: - static RangeError New(napi_env env, const char* message); - static RangeError New(napi_env env, const std::string& message); - - RangeError(); - RangeError(napi_env env, napi_value value); - }; - - class CallbackInfo { - public: - CallbackInfo(napi_env env, napi_callback_info info); - ~CallbackInfo(); - - // Disallow copying to prevent multiple free of _dynamicArgs - CallbackInfo(CallbackInfo const &) = delete; - void operator=(CallbackInfo const &) = delete; - - Napi::Env Env() const; - Value NewTarget() const; - bool IsConstructCall() const; - size_t Length() const; - const Value operator [](size_t index) const; - Value This() const; - void* Data() const; - void SetData(void* data); - - private: - const size_t _staticArgCount = 6; - napi_env _env; - napi_callback_info _info; - napi_value _this; - size_t _argc; - napi_value* _argv; - napi_value _staticArgs[6]; - napi_value* _dynamicArgs; - void* _data; - }; - - class PropertyDescriptor { - public: - typedef Napi::Value (*GetterCallback)(const Napi::CallbackInfo& info); - typedef void (*SetterCallback)(const Napi::CallbackInfo& info); - -#ifndef NODE_ADDON_API_DISABLE_DEPRECATED - template - static PropertyDescriptor Accessor(const char* utf8name, - Getter getter, - napi_property_attributes attributes = napi_default, - void* data = nullptr); - template - static PropertyDescriptor Accessor(const std::string& utf8name, - Getter getter, - napi_property_attributes attributes = napi_default, - void* data = nullptr); - template - static PropertyDescriptor Accessor(napi_value name, - Getter getter, - napi_property_attributes attributes = napi_default, - void* data = nullptr); - template - static PropertyDescriptor Accessor(Name name, - Getter getter, - napi_property_attributes attributes = napi_default, - void* data = nullptr); - template - static PropertyDescriptor Accessor(const char* utf8name, - Getter getter, - Setter setter, - napi_property_attributes attributes = napi_default, - void* data = nullptr); - template - static PropertyDescriptor Accessor(const std::string& utf8name, - Getter getter, - Setter setter, - napi_property_attributes attributes = napi_default, - void* data = nullptr); - template - static PropertyDescriptor Accessor(napi_value name, - Getter getter, - Setter setter, - napi_property_attributes attributes = napi_default, - void* data = nullptr); - template - static PropertyDescriptor Accessor(Name name, - Getter getter, - Setter setter, - napi_property_attributes attributes = napi_default, - void* data = nullptr); - template - static PropertyDescriptor Function(const char* utf8name, - Callable cb, - napi_property_attributes attributes = napi_default, - void* data = nullptr); - template - static PropertyDescriptor Function(const std::string& utf8name, - Callable cb, - napi_property_attributes attributes = napi_default, - void* data = nullptr); - template - static PropertyDescriptor Function(napi_value name, - Callable cb, - napi_property_attributes attributes = napi_default, - void* data = nullptr); - template - static PropertyDescriptor Function(Name name, - Callable cb, - napi_property_attributes attributes = napi_default, - void* data = nullptr); -#endif // !NODE_ADDON_API_DISABLE_DEPRECATED - - template - static PropertyDescriptor Accessor(const char* utf8name, - napi_property_attributes attributes = napi_default, - void* data = nullptr); - - template - static PropertyDescriptor Accessor(const std::string& utf8name, - napi_property_attributes attributes = napi_default, - void* data = nullptr); - - template - static PropertyDescriptor Accessor(Name name, - napi_property_attributes attributes = napi_default, - void* data = nullptr); - - template - static PropertyDescriptor Accessor(const char* utf8name, - napi_property_attributes attributes = napi_default, - void* data = nullptr); - - template - static PropertyDescriptor Accessor(const std::string& utf8name, - napi_property_attributes attributes = napi_default, - void* data = nullptr); - - template - static PropertyDescriptor Accessor(Name name, - napi_property_attributes attributes = napi_default, - void* data = nullptr); - - template - static PropertyDescriptor Accessor(Napi::Env env, - Napi::Object object, - const char* utf8name, - Getter getter, - napi_property_attributes attributes = napi_default, - void* data = nullptr); - template - static PropertyDescriptor Accessor(Napi::Env env, - Napi::Object object, - const std::string& utf8name, - Getter getter, - napi_property_attributes attributes = napi_default, - void* data = nullptr); - template - static PropertyDescriptor Accessor(Napi::Env env, - Napi::Object object, - Name name, - Getter getter, - napi_property_attributes attributes = napi_default, - void* data = nullptr); - template - static PropertyDescriptor Accessor(Napi::Env env, - Napi::Object object, - const char* utf8name, - Getter getter, - Setter setter, - napi_property_attributes attributes = napi_default, - void* data = nullptr); - template - static PropertyDescriptor Accessor(Napi::Env env, - Napi::Object object, - const std::string& utf8name, - Getter getter, - Setter setter, - napi_property_attributes attributes = napi_default, - void* data = nullptr); - template - static PropertyDescriptor Accessor(Napi::Env env, - Napi::Object object, - Name name, - Getter getter, - Setter setter, - napi_property_attributes attributes = napi_default, - void* data = nullptr); - template - static PropertyDescriptor Function(Napi::Env env, - Napi::Object object, - const char* utf8name, - Callable cb, - napi_property_attributes attributes = napi_default, - void* data = nullptr); - template - static PropertyDescriptor Function(Napi::Env env, - Napi::Object object, - const std::string& utf8name, - Callable cb, - napi_property_attributes attributes = napi_default, - void* data = nullptr); - template - static PropertyDescriptor Function(Napi::Env env, - Napi::Object object, - Name name, - Callable cb, - napi_property_attributes attributes = napi_default, - void* data = nullptr); - static PropertyDescriptor Value(const char* utf8name, - napi_value value, - napi_property_attributes attributes = napi_default); - static PropertyDescriptor Value(const std::string& utf8name, - napi_value value, - napi_property_attributes attributes = napi_default); - static PropertyDescriptor Value(napi_value name, - napi_value value, - napi_property_attributes attributes = napi_default); - static PropertyDescriptor Value(Name name, - Napi::Value value, - napi_property_attributes attributes = napi_default); - - PropertyDescriptor(napi_property_descriptor desc); - - operator napi_property_descriptor&(); - operator const napi_property_descriptor&() const; - - private: - template - static napi_value GetterCallbackWrapper(napi_env env, napi_callback_info info); - template - static napi_value SetterCallbackWrapper(napi_env env, napi_callback_info info); - napi_property_descriptor _desc; - }; - - /// Property descriptor for use with `ObjectWrap::DefineClass()`. - /// - /// This is different from the standalone `PropertyDescriptor` because it is specific to each - /// `ObjectWrap` subclass. This prevents using descriptors from a different class when - /// defining a new class (preventing the callbacks from having incorrect `this` pointers). - template - class ClassPropertyDescriptor { - public: - ClassPropertyDescriptor(napi_property_descriptor desc) : _desc(desc) {} - - operator napi_property_descriptor&() { return _desc; } - operator const napi_property_descriptor&() const { return _desc; } - - private: - napi_property_descriptor _desc; - }; - - /// Base class to be extended by C++ classes exposed to JavaScript; each C++ class instance gets - /// "wrapped" by a JavaScript object that is managed by this class. - /// - /// At initialization time, the `DefineClass()` method must be used to - /// hook up the accessor and method callbacks. It takes a list of - /// property descriptors, which can be constructed via the various - /// static methods on the base class. - /// - /// #### Example: - /// - /// class Example: public Napi::ObjectWrap { - /// public: - /// static void Initialize(Napi::Env& env, Napi::Object& target) { - /// Napi::Function constructor = DefineClass(env, "Example", { - /// InstanceAccessor<&Example::GetSomething, &Example::SetSomething>("value"), - /// InstanceMethod<&Example::DoSomething>("doSomething"), - /// }); - /// target.Set("Example", constructor); - /// } - /// - /// Example(const Napi::CallbackInfo& info); // Constructor - /// Napi::Value GetSomething(const Napi::CallbackInfo& info); - /// void SetSomething(const Napi::CallbackInfo& info, const Napi::Value& value); - /// Napi::Value DoSomething(const Napi::CallbackInfo& info); - /// } - template - class ObjectWrap : public Reference { - public: - ObjectWrap(const CallbackInfo& callbackInfo); - virtual ~ObjectWrap(); - - static T* Unwrap(Object wrapper); - - // Methods exposed to JavaScript must conform to one of these callback signatures. - typedef void (*StaticVoidMethodCallback)(const CallbackInfo& info); - typedef Napi::Value (*StaticMethodCallback)(const CallbackInfo& info); - typedef Napi::Value (*StaticGetterCallback)(const CallbackInfo& info); - typedef void (*StaticSetterCallback)(const CallbackInfo& info, const Napi::Value& value); - typedef void (T::*InstanceVoidMethodCallback)(const CallbackInfo& info); - typedef Napi::Value (T::*InstanceMethodCallback)(const CallbackInfo& info); - typedef Napi::Value (T::*InstanceGetterCallback)(const CallbackInfo& info); - typedef void (T::*InstanceSetterCallback)(const CallbackInfo& info, const Napi::Value& value); - - typedef ClassPropertyDescriptor PropertyDescriptor; - - static Function DefineClass(Napi::Env env, - const char* utf8name, - const std::initializer_list& properties, - void* data = nullptr); - static Function DefineClass(Napi::Env env, - const char* utf8name, - const std::vector& properties, - void* data = nullptr); - static PropertyDescriptor StaticMethod(const char* utf8name, - StaticVoidMethodCallback method, - napi_property_attributes attributes = napi_default, - void* data = nullptr); - static PropertyDescriptor StaticMethod(const char* utf8name, - StaticMethodCallback method, - napi_property_attributes attributes = napi_default, - void* data = nullptr); - static PropertyDescriptor StaticMethod(Symbol name, - StaticVoidMethodCallback method, - napi_property_attributes attributes = napi_default, - void* data = nullptr); - static PropertyDescriptor StaticMethod(Symbol name, - StaticMethodCallback method, - napi_property_attributes attributes = napi_default, - void* data = nullptr); - template - static PropertyDescriptor StaticMethod(const char* utf8name, - napi_property_attributes attributes = napi_default, - void* data = nullptr); - template - static PropertyDescriptor StaticMethod(Symbol name, - napi_property_attributes attributes = napi_default, - void* data = nullptr); - template - static PropertyDescriptor StaticMethod(const char* utf8name, - napi_property_attributes attributes = napi_default, - void* data = nullptr); - template - static PropertyDescriptor StaticMethod(Symbol name, - napi_property_attributes attributes = napi_default, - void* data = nullptr); - static PropertyDescriptor StaticAccessor(const char* utf8name, - StaticGetterCallback getter, - StaticSetterCallback setter, - napi_property_attributes attributes = napi_default, - void* data = nullptr); - static PropertyDescriptor StaticAccessor(Symbol name, - StaticGetterCallback getter, - StaticSetterCallback setter, - napi_property_attributes attributes = napi_default, - void* data = nullptr); - template - static PropertyDescriptor StaticAccessor(const char* utf8name, - napi_property_attributes attributes = napi_default, - void* data = nullptr); - template - static PropertyDescriptor StaticAccessor(Symbol name, - napi_property_attributes attributes = napi_default, - void* data = nullptr); - static PropertyDescriptor InstanceMethod(const char* utf8name, - InstanceVoidMethodCallback method, - napi_property_attributes attributes = napi_default, - void* data = nullptr); - static PropertyDescriptor InstanceMethod(const char* utf8name, - InstanceMethodCallback method, - napi_property_attributes attributes = napi_default, - void* data = nullptr); - static PropertyDescriptor InstanceMethod(Symbol name, - InstanceVoidMethodCallback method, - napi_property_attributes attributes = napi_default, - void* data = nullptr); - static PropertyDescriptor InstanceMethod(Symbol name, - InstanceMethodCallback method, - napi_property_attributes attributes = napi_default, - void* data = nullptr); - template - static PropertyDescriptor InstanceMethod(const char* utf8name, - napi_property_attributes attributes = napi_default, - void* data = nullptr); - template - static PropertyDescriptor InstanceMethod(const char* utf8name, - napi_property_attributes attributes = napi_default, - void* data = nullptr); - template - static PropertyDescriptor InstanceMethod(Symbol name, - napi_property_attributes attributes = napi_default, - void* data = nullptr); - template - static PropertyDescriptor InstanceMethod(Symbol name, - napi_property_attributes attributes = napi_default, - void* data = nullptr); - static PropertyDescriptor InstanceAccessor(const char* utf8name, - InstanceGetterCallback getter, - InstanceSetterCallback setter, - napi_property_attributes attributes = napi_default, - void* data = nullptr); - static PropertyDescriptor InstanceAccessor(Symbol name, - InstanceGetterCallback getter, - InstanceSetterCallback setter, - napi_property_attributes attributes = napi_default, - void* data = nullptr); - template - static PropertyDescriptor InstanceAccessor(const char* utf8name, - napi_property_attributes attributes = napi_default, - void* data = nullptr); - template - static PropertyDescriptor InstanceAccessor(Symbol name, - napi_property_attributes attributes = napi_default, - void* data = nullptr); - static PropertyDescriptor StaticValue(const char* utf8name, - Napi::Value value, - napi_property_attributes attributes = napi_default); - static PropertyDescriptor StaticValue(Symbol name, - Napi::Value value, - napi_property_attributes attributes = napi_default); - static PropertyDescriptor InstanceValue(const char* utf8name, - Napi::Value value, - napi_property_attributes attributes = napi_default); - static PropertyDescriptor InstanceValue(Symbol name, - Napi::Value value, - napi_property_attributes attributes = napi_default); - virtual void Finalize(Napi::Env env); - - private: - using This = ObjectWrap; - - static napi_value ConstructorCallbackWrapper(napi_env env, napi_callback_info info); - static napi_value StaticVoidMethodCallbackWrapper(napi_env env, napi_callback_info info); - static napi_value StaticMethodCallbackWrapper(napi_env env, napi_callback_info info); - static napi_value StaticGetterCallbackWrapper(napi_env env, napi_callback_info info); - static napi_value StaticSetterCallbackWrapper(napi_env env, napi_callback_info info); - static napi_value InstanceVoidMethodCallbackWrapper(napi_env env, napi_callback_info info); - static napi_value InstanceMethodCallbackWrapper(napi_env env, napi_callback_info info); - static napi_value InstanceGetterCallbackWrapper(napi_env env, napi_callback_info info); - static napi_value InstanceSetterCallbackWrapper(napi_env env, napi_callback_info info); - static void FinalizeCallback(napi_env env, void* data, void* hint); - static Function DefineClass(Napi::Env env, - const char* utf8name, - const size_t props_count, - const napi_property_descriptor* props, - void* data = nullptr); - - template - struct MethodCallbackData { - TCallback callback; - void* data; - }; - typedef MethodCallbackData StaticVoidMethodCallbackData; - typedef MethodCallbackData StaticMethodCallbackData; - typedef MethodCallbackData InstanceVoidMethodCallbackData; - typedef MethodCallbackData InstanceMethodCallbackData; - - template - struct AccessorCallbackData { - TGetterCallback getterCallback; - TSetterCallback setterCallback; - void* data; - }; - typedef AccessorCallbackData - StaticAccessorCallbackData; - typedef AccessorCallbackData - InstanceAccessorCallbackData; - - template - static napi_value WrappedMethod(napi_env env, napi_callback_info info) noexcept; - - template - static napi_value WrappedMethod(napi_env env, napi_callback_info info) noexcept; - - template - static napi_value WrappedMethod(napi_env env, napi_callback_info info) noexcept; - - template - static napi_value WrappedMethod(napi_env env, napi_callback_info info) noexcept; - - template - static napi_value WrappedMethod(napi_env env, napi_callback_info info) noexcept; - - template - static napi_value WrappedMethod(napi_env env, napi_callback_info info) noexcept; - - template struct StaticGetterTag {}; - template struct StaticSetterTag {}; - template struct GetterTag {}; - template struct SetterTag {}; - - template - static napi_callback WrapStaticGetter(StaticGetterTag) noexcept { return &This::WrappedMethod; } - static napi_callback WrapStaticGetter(StaticGetterTag) noexcept { return nullptr; } - - template - static napi_callback WrapStaticSetter(StaticSetterTag) noexcept { return &This::WrappedMethod; } - static napi_callback WrapStaticSetter(StaticSetterTag) noexcept { return nullptr; } - - template - static napi_callback WrapGetter(GetterTag) noexcept { return &This::WrappedMethod; } - static napi_callback WrapGetter(GetterTag) noexcept { return nullptr; } - - template - static napi_callback WrapSetter(SetterTag) noexcept { return &This::WrappedMethod; } - static napi_callback WrapSetter(SetterTag) noexcept { return nullptr; } - }; - - class HandleScope { - public: - HandleScope(napi_env env, napi_handle_scope scope); - explicit HandleScope(Napi::Env env); - ~HandleScope(); - - // Disallow copying to prevent double close of napi_handle_scope - HandleScope(HandleScope const &) = delete; - void operator=(HandleScope const &) = delete; - - operator napi_handle_scope() const; - - Napi::Env Env() const; - - private: - napi_env _env; - napi_handle_scope _scope; - }; - - class EscapableHandleScope { - public: - EscapableHandleScope(napi_env env, napi_escapable_handle_scope scope); - explicit EscapableHandleScope(Napi::Env env); - ~EscapableHandleScope(); - - // Disallow copying to prevent double close of napi_escapable_handle_scope - EscapableHandleScope(EscapableHandleScope const &) = delete; - void operator=(EscapableHandleScope const &) = delete; - - operator napi_escapable_handle_scope() const; - - Napi::Env Env() const; - Value Escape(napi_value escapee); - - private: - napi_env _env; - napi_escapable_handle_scope _scope; - }; - -#if (NAPI_VERSION > 2) - class CallbackScope { - public: - CallbackScope(napi_env env, napi_callback_scope scope); - CallbackScope(napi_env env, napi_async_context context); - virtual ~CallbackScope(); - - // Disallow copying to prevent double close of napi_callback_scope - CallbackScope(CallbackScope const &) = delete; - void operator=(CallbackScope const &) = delete; - - operator napi_callback_scope() const; - - Napi::Env Env() const; - - private: - napi_env _env; - napi_callback_scope _scope; - }; -#endif - - class AsyncContext { - public: - explicit AsyncContext(napi_env env, const char* resource_name); - explicit AsyncContext(napi_env env, const char* resource_name, const Object& resource); - virtual ~AsyncContext(); - - AsyncContext(AsyncContext&& other); - AsyncContext& operator =(AsyncContext&& other); - AsyncContext(const AsyncContext&) = delete; - AsyncContext& operator =(const AsyncContext&) = delete; - - operator napi_async_context() const; - - Napi::Env Env() const; - - private: - napi_env _env; - napi_async_context _context; - }; - - class AsyncWorker { - public: - virtual ~AsyncWorker(); - - // An async worker can be moved but cannot be copied. - AsyncWorker(AsyncWorker&& other); - AsyncWorker& operator =(AsyncWorker&& other); - AsyncWorker(const AsyncWorker&) = delete; - AsyncWorker& operator =(const AsyncWorker&) = delete; - - operator napi_async_work() const; - - Napi::Env Env() const; - - void Queue(); - void Cancel(); - void SuppressDestruct(); - - ObjectReference& Receiver(); - FunctionReference& Callback(); - - protected: - explicit AsyncWorker(const Function& callback); - explicit AsyncWorker(const Function& callback, - const char* resource_name); - explicit AsyncWorker(const Function& callback, - const char* resource_name, - const Object& resource); - explicit AsyncWorker(const Object& receiver, - const Function& callback); - explicit AsyncWorker(const Object& receiver, - const Function& callback, - const char* resource_name); - explicit AsyncWorker(const Object& receiver, - const Function& callback, - const char* resource_name, - const Object& resource); - - explicit AsyncWorker(Napi::Env env); - explicit AsyncWorker(Napi::Env env, - const char* resource_name); - explicit AsyncWorker(Napi::Env env, - const char* resource_name, - const Object& resource); - - virtual void Execute() = 0; - virtual void OnOK(); - virtual void OnError(const Error& e); - virtual void Destroy(); - virtual std::vector GetResult(Napi::Env env); - - void SetError(const std::string& error); - - private: - static void OnExecute(napi_env env, void* this_pointer); - static void OnWorkComplete(napi_env env, - napi_status status, - void* this_pointer); - - napi_env _env; - napi_async_work _work; - ObjectReference _receiver; - FunctionReference _callback; - std::string _error; - bool _suppress_destruct; - }; - - #if (NAPI_VERSION > 3) - class ThreadSafeFunction { - public: - // This API may only be called from the main thread. - template - static ThreadSafeFunction New(napi_env env, - const Function& callback, - ResourceString resourceName, - size_t maxQueueSize, - size_t initialThreadCount); - - // This API may only be called from the main thread. - template - static ThreadSafeFunction New(napi_env env, - const Function& callback, - ResourceString resourceName, - size_t maxQueueSize, - size_t initialThreadCount, - ContextType* context); - - // This API may only be called from the main thread. - template - static ThreadSafeFunction New(napi_env env, - const Function& callback, - ResourceString resourceName, - size_t maxQueueSize, - size_t initialThreadCount, - Finalizer finalizeCallback); - - // This API may only be called from the main thread. - template - static ThreadSafeFunction New(napi_env env, - const Function& callback, - ResourceString resourceName, - size_t maxQueueSize, - size_t initialThreadCount, - Finalizer finalizeCallback, - FinalizerDataType* data); - - // This API may only be called from the main thread. - template - static ThreadSafeFunction New(napi_env env, - const Function& callback, - ResourceString resourceName, - size_t maxQueueSize, - size_t initialThreadCount, - ContextType* context, - Finalizer finalizeCallback); - - // This API may only be called from the main thread. - template - static ThreadSafeFunction New(napi_env env, - const Function& callback, - ResourceString resourceName, - size_t maxQueueSize, - size_t initialThreadCount, - ContextType* context, - Finalizer finalizeCallback, - FinalizerDataType* data); - - // This API may only be called from the main thread. - template - static ThreadSafeFunction New(napi_env env, - const Function& callback, - const Object& resource, - ResourceString resourceName, - size_t maxQueueSize, - size_t initialThreadCount); - - // This API may only be called from the main thread. - template - static ThreadSafeFunction New(napi_env env, - const Function& callback, - const Object& resource, - ResourceString resourceName, - size_t maxQueueSize, - size_t initialThreadCount, - ContextType* context); - - // This API may only be called from the main thread. - template - static ThreadSafeFunction New(napi_env env, - const Function& callback, - const Object& resource, - ResourceString resourceName, - size_t maxQueueSize, - size_t initialThreadCount, - Finalizer finalizeCallback); - - // This API may only be called from the main thread. - template - static ThreadSafeFunction New(napi_env env, - const Function& callback, - const Object& resource, - ResourceString resourceName, - size_t maxQueueSize, - size_t initialThreadCount, - Finalizer finalizeCallback, - FinalizerDataType* data); - - // This API may only be called from the main thread. - template - static ThreadSafeFunction New(napi_env env, - const Function& callback, - const Object& resource, - ResourceString resourceName, - size_t maxQueueSize, - size_t initialThreadCount, - ContextType* context, - Finalizer finalizeCallback); - - // This API may only be called from the main thread. - template - static ThreadSafeFunction New(napi_env env, - const Function& callback, - const Object& resource, - ResourceString resourceName, - size_t maxQueueSize, - size_t initialThreadCount, - ContextType* context, - Finalizer finalizeCallback, - FinalizerDataType* data); - - ThreadSafeFunction(); - ThreadSafeFunction(napi_threadsafe_function tsFunctionValue); - - operator napi_threadsafe_function() const; - - // This API may be called from any thread. - napi_status BlockingCall() const; - - // This API may be called from any thread. - template - napi_status BlockingCall(Callback callback) const; - - // This API may be called from any thread. - template - napi_status BlockingCall(DataType* data, Callback callback) const; - - // This API may be called from any thread. - napi_status NonBlockingCall() const; - - // This API may be called from any thread. - template - napi_status NonBlockingCall(Callback callback) const; - - // This API may be called from any thread. - template - napi_status NonBlockingCall(DataType* data, Callback callback) const; - - // This API may only be called from the main thread. - void Ref(napi_env env) const; - - // This API may only be called from the main thread. - void Unref(napi_env env) const; - - // This API may be called from any thread. - napi_status Acquire() const; - - // This API may be called from any thread. - napi_status Release(); - - // This API may be called from any thread. - napi_status Abort(); - - struct ConvertibleContext - { - template - operator T*() { return static_cast(context); } - void* context; - }; - - // This API may be called from any thread. - ConvertibleContext GetContext() const; - - private: - using CallbackWrapper = std::function; - - template - static ThreadSafeFunction New(napi_env env, - const Function& callback, - const Object& resource, - ResourceString resourceName, - size_t maxQueueSize, - size_t initialThreadCount, - ContextType* context, - Finalizer finalizeCallback, - FinalizerDataType* data, - napi_finalize wrapper); - - napi_status CallInternal(CallbackWrapper* callbackWrapper, - napi_threadsafe_function_call_mode mode) const; - - static void CallJS(napi_env env, - napi_value jsCallback, - void* context, - void* data); - - napi_threadsafe_function _tsfn; - }; - - template - class AsyncProgressWorker : public AsyncWorker { - public: - virtual ~AsyncProgressWorker(); - - class ExecutionProgress { - friend class AsyncProgressWorker; - public: - void Signal() const; - void Send(const T* data, size_t count) const; - private: - explicit ExecutionProgress(AsyncProgressWorker* worker) : _worker(worker) {} - AsyncProgressWorker* const _worker; - }; - - protected: - explicit AsyncProgressWorker(const Function& callback); - explicit AsyncProgressWorker(const Function& callback, - const char* resource_name); - explicit AsyncProgressWorker(const Function& callback, - const char* resource_name, - const Object& resource); - explicit AsyncProgressWorker(const Object& receiver, - const Function& callback); - explicit AsyncProgressWorker(const Object& receiver, - const Function& callback, - const char* resource_name); - explicit AsyncProgressWorker(const Object& receiver, - const Function& callback, - const char* resource_name, - const Object& resource); - -// Optional callback of Napi::ThreadSafeFunction only available after NAPI_VERSION 4. -// Refs: https://github.com/nodejs/node/pull/27791 -#if NAPI_VERSION > 4 - explicit AsyncProgressWorker(Napi::Env env); - explicit AsyncProgressWorker(Napi::Env env, - const char* resource_name); - explicit AsyncProgressWorker(Napi::Env env, - const char* resource_name, - const Object& resource); -#endif - - virtual void Execute(const ExecutionProgress& progress) = 0; - virtual void OnProgress(const T* data, size_t count) = 0; - - private: - static void WorkProgress_(Napi::Env env, Napi::Function jsCallback, void* data); - - void Execute() override; - void Signal() const; - void SendProgress_(const T* data, size_t count); - - std::mutex _mutex; - T* _asyncdata; - size_t _asyncsize; - ThreadSafeFunction _tsfn; - }; - #endif - - // Memory management. - class MemoryManagement { - public: - static int64_t AdjustExternalMemory(Env env, int64_t change_in_bytes); - }; - - // Version management - class VersionManagement { - public: - static uint32_t GetNapiVersion(Env env); - static const napi_node_version* GetNodeVersion(Env env); - }; - -} // namespace Napi - -// Inline implementations of all the above class methods are included here. -#include "napi-inl.h" - -#endif // SRC_NAPI_H_ From c85850676dcf508a0dd664e91299eb31572392db Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Tue, 13 Apr 2021 19:00:58 -0500 Subject: [PATCH 17/19] test: update weak-napi to help with gc detection There are no breaking changes: https://github.com/node-ffi-napi/weak-napi/compare/v1.0.3...v2.0.2 --- package.json | 3 ++- test/unit/socket-close-test.ts | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 859760ea..9392a93d 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "@types/mocha": ">= 5.2", "@types/node": ">= 8.0", "@types/semver": ">= 0", + "@types/weak-napi": "^2.0.0", "@typescript-eslint/eslint-plugin": "^2.9.0", "@typescript-eslint/parser": "^2.9.0", "benchmark": ">= 0", @@ -47,7 +48,7 @@ "ts-morph": "^7.0.0", "ts-node": ">= 7", "typescript": ">= 3.6", - "weak-napi": ">= 1.0" + "weak-napi": "^2.0.2" }, "engines": { "node": ">= 10.2" diff --git a/test/unit/socket-close-test.ts b/test/unit/socket-close-test.ts index 3a479d00..a9c33677 100644 --- a/test/unit/socket-close-test.ts +++ b/test/unit/socket-close-test.ts @@ -105,7 +105,7 @@ for (const proto of testProtos("tcp", "ipc", "inproc")) { if (process.env.SKIP_GC_TESTS) this.skip() this.slow(200) - const weak = require("weak-napi") + const weak = require("weak-napi") as typeof import("weak-napi") let released = false const task = async () => { @@ -135,7 +135,7 @@ for (const proto of testProtos("tcp", "ipc", "inproc")) { if (process.env.SKIP_GC_TESTS) this.skip() this.slow(200) - const weak = require("weak-napi") + const weak = require("weak-napi") as typeof import("weak-napi") let released = false const task = async () => { From be3eff2dad3c1a3a988b202590abe5fd92777b74 Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Thu, 15 Apr 2021 05:52:26 -0500 Subject: [PATCH 18/19] test: disable typeScript-compatibility for older than 3.4.x It is not the responsibility of Zeromq to be buildable on old TypeScript or fullfil technical debts that TypeScript doesn't comply to. --- test/unit/typings-compatibility-test.ts | 38 ++++--------------------- 1 file changed, 5 insertions(+), 33 deletions(-) diff --git a/test/unit/typings-compatibility-test.ts b/test/unit/typings-compatibility-test.ts index 389440ae..27119095 100644 --- a/test/unit/typings-compatibility-test.ts +++ b/test/unit/typings-compatibility-test.ts @@ -23,42 +23,14 @@ type TestDef = {version: string; minTarget: string; requiredLibs?: string[]} // NOTE tsc version 2.9.x (and lower) will not work with current typings! const tsVersions: TestDef[] = [ - // typescript 3.0.x - 3.4.x: + // typescript 3.0.x - 3.3.x: // must either have a target that supports AsyncIterators, // or include a typings library that supports AsyncIterator - { - version: "3.0.x", - minTarget: "es3", - requiredLibs: ["es2015", "ESNext.AsyncIterable"], - }, - { - version: "3.1.x", - minTarget: "es3", - requiredLibs: ["es2015", "ESNext.AsyncIterable"], - }, - { - version: "3.2.x", - minTarget: "es3", - requiredLibs: ["es2015", "ESNext.AsyncIterable"], - }, - { - version: "3.3.x", - minTarget: "es3", - requiredLibs: ["es2015", "ESNext.AsyncIterable"], - }, - { - version: "3.4.x", - minTarget: "es3", - requiredLibs: ["es2015", "ESNext.AsyncIterable"], - }, - {version: "3.0.x", minTarget: "esnext"}, - {version: "3.1.x", minTarget: "esnext"}, - {version: "3.2.x", minTarget: "esnext"}, - {version: "3.3.x", minTarget: "esnext"}, - {version: "3.4.x", minTarget: "esnext"}, - - // typescript 3.5.x - 3.7.x: + // TODO might support older TypeScript + + // typescript 3.4.x - 3.7.x: // these include typings for AsyncIterator by default + {version: "3.4.x", minTarget: "es3"}, {version: "3.5.x", minTarget: "es3"}, {version: "3.6.x", minTarget: "es3"}, {version: "3.7.x", minTarget: "es3"}, From 740b4dfd737ab798fb06bd0617952a73603c93f9 Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Sat, 17 Apr 2021 03:50:25 -0500 Subject: [PATCH 19/19] chore: parametrize sanitizer build --- binding.gyp | 57 ++++++++++++++++++++++++++++---------------- script/ci/install.sh | 4 ++++ 2 files changed, 41 insertions(+), 20 deletions(-) diff --git a/binding.gyp b/binding.gyp index 88f9012b..e3450169 100644 --- a/binding.gyp +++ b/binding.gyp @@ -113,29 +113,46 @@ ['OS == "win"', { 'msvs_settings': { - 'VCCLCompilerTool': { - 'ExceptionHandling': 2, # /EHsc - # 0 - MultiThreaded (/MT) - # 1 - MultiThreadedDebug (/MTd) - # 2 - MultiThreadedDLL (/MD) - # 3 - MultiThreadedDebugDLL (/MDd) - 'RuntimeLibrary': 3, - 'AdditionalOptions': [ - '-std:c++17', - "/DEBUG", - - # Uncomment to enable address sanitizer + 'conditions': [ + ['"<@(sanitizers)" != "true"', { + # without sanitizer + 'VCCLCompilerTool': { + 'ExceptionHandling': 2, # /EHsc + # 0 - MultiThreaded (/MT) + # 1 - MultiThreadedDebug (/MTd) + # 2 - MultiThreadedDLL (/MD) + # 3 - MultiThreadedDebugDLL (/MDd) + 'RuntimeLibrary': 3, + 'AdditionalOptions': [ + '-std:c++17', + "/DEBUG", + ], + }, + 'VCLinkerTool': { + 'BasicRuntimeChecks': 3, # /RTC1 + }, + }, { + # with sanitizer + # Build with `node-gyp rebuild --debug --sanitizers='true'` # Make sure to add the followings (or what your MSVC use) to the PATH and run `refreshenv`. # # C:/Program Files (x86)/Microsoft Visual Studio/2019/Preview/VC/Tools/MSVC/14.29.29917/lib/x64/ # # C:/Program Files (x86)/Microsoft Visual Studio/2019/Preview/VC/Tools/MSVC/14.29.29917/bin/Hostx64/x64/ - # "/fsanitize=address", - # "/Zi", - # "/INCREMENTAL:NO", - ], - }, - 'VCLinkerTool': { - 'BasicRuntimeChecks': 3, # /RTC1 - }, + 'VCCLCompilerTool': { + 'ExceptionHandling': 2, # /EHsc + 'RuntimeLibrary': 3, + "DebugInformationFormat": "ProgramDatabase", # /Zi + 'AdditionalOptions': [ + '-std:c++17', + "/DEBUG", + "/fsanitize=address", + ], + }, + 'VCLinkerTool': { + 'BasicRuntimeChecks': 0, # not supported with fsanitize + "LinkIncremental": "NO", # /INCREMENTAL:NO + }, + }], + ], }, }], ], diff --git a/script/ci/install.sh b/script/ci/install.sh index cfe89cfb..8a9c8711 100755 --- a/script/ci/install.sh +++ b/script/ci/install.sh @@ -29,6 +29,10 @@ if [ -n "${ZMQ_NO_SYNC_RESOLVE}" ]; then export npm_config_zmq_no_sync_resolve=true fi +if [ -n "${ZMQ_SANITIZERS}" ]; then + export npm_config_sanitizers=true +fi + export npm_config_build_from_source=true # Installing node-gyp globally facilitates calling it in various ways, not just