diff --git a/.github/jobs/ios.yml b/.github/jobs/ios.yml index 46c216124..8ae6527fe 100644 --- a/.github/jobs/ios.yml +++ b/.github/jobs/ios.yml @@ -27,7 +27,7 @@ jobs: - script: | mkdir buildiOS cd buildiOS - cmake .. -G Xcode -DCMAKE_TOOLCHAIN_FILE=../Dependencies/ios-cmake/ios.toolchain.cmake -DPLATFORM=OS64COMBINED -DENABLE_ARC=0 -DDEPLOYMENT_TARGET=${{ parameters.deploymentTarget }} -DENABLE_GLSLANG_BINARIES=OFF -DSPIRV_CROSS_CLI=OFF -DCMAKE_UNITY_BUILD=${UNITY_BUILD} + cmake .. -G Xcode -D IOS=ON -D DEPLOYMENT_TARGET=${{ parameters.deploymentTarget }} -D CMAKE_UNITY_BUILD=${UNITY_BUILD} displayName: 'Generate iOS solution' - task: Xcode@5 diff --git a/.github/jobs/linux.yml b/.github/jobs/linux.yml index eea29ef43..6f8026840 100644 --- a/.github/jobs/linux.yml +++ b/.github/jobs/linux.yml @@ -32,7 +32,7 @@ jobs: - script: | mkdir build cd build - cmake .. -GNinja -DJSCORE_LIBRARY=/usr/lib/x86_64-linux-gnu/libjavascriptcoregtk-4.0.so -DNAPI_JAVASCRIPT_ENGINE=${{ parameters.JSEngine }} -DCMAKE_BUILD_TYPE=RelWithDebInfo -DBGFX_CONFIG_DEBUG=ON -DCMAKE_UNITY_BUILD=${UNITY_BUILD} + cmake .. -G Ninja -D JAVASCRIPTCORE_LIBRARY=/usr/lib/x86_64-linux-gnu/libjavascriptcoregtk-4.0.so -D NAPI_JAVASCRIPT_ENGINE=${{ parameters.JSEngine }} -D CMAKE_BUILD_TYPE=RelWithDebInfo -D BGFX_CONFIG_DEBUG=ON -D CMAKE_UNITY_BUILD=${UNITY_BUILD} ninja displayName: 'Build X11' diff --git a/.github/jobs/macos.yml b/.github/jobs/macos.yml index 09b1f0c1b..10aa0bf94 100644 --- a/.github/jobs/macos.yml +++ b/.github/jobs/macos.yml @@ -26,7 +26,7 @@ jobs: - script: | mkdir buildmacOS cd buildmacOS - cmake .. -GXcode -DCMAKE_UNITY_BUILD=${UNITY_BUILD} + cmake .. -G Xcode -D CMAKE_UNITY_BUILD=${UNITY_BUILD} displayName: 'Generate macOS solution' - task: Xcode@5 diff --git a/.github/jobs/uwp.yml b/.github/jobs/uwp.yml index a3b09c146..07455999f 100644 --- a/.github/jobs/uwp.yml +++ b/.github/jobs/uwp.yml @@ -34,7 +34,7 @@ jobs: - script: | mkdir build${{ variables.solutionName }} cd build${{ variables.solutionName }} - cmake .. -DCMAKE_SYSTEM_NAME=WindowsStore -DCMAKE_SYSTEM_VERSION=10.0 ${{ variables.jsEngineDefine }} -A ${{ parameters.platform }} -DCMAKE_UNITY_BUILD=${UNITY_BUILD} + cmake .. -D CMAKE_SYSTEM_NAME=WindowsStore -D CMAKE_SYSTEM_VERSION=10.0 ${{ variables.jsEngineDefine }} -A ${{ parameters.platform }} -D CMAKE_UNITY_BUILD=${UNITY_BUILD} displayName: 'Generate ${{ variables.solutionName }} solution' - task: VSBuild@1 diff --git a/.github/jobs/win32.yml b/.github/jobs/win32.yml index 48ca563ad..d43ab8fda 100644 --- a/.github/jobs/win32.yml +++ b/.github/jobs/win32.yml @@ -37,7 +37,7 @@ jobs: - script: | mkdir build${{ variables.solutionName }} cd build${{ variables.solutionName }} - cmake -A ${{ parameters.platform }} ${{ variables.jsEngineDefine }} -DBGFX_CONFIG_DEBUG=ON -DGRAPHICS_API=${{ parameters.graphics_api }} -DCMAKE_UNITY_BUILD=${UNITY_BUILD} .. + cmake -A ${{ parameters.platform }} ${{ variables.jsEngineDefine }} -D BGFX_CONFIG_DEBUG=ON -D GRAPHICS_API=${{ parameters.graphics_api }} -D CMAKE_UNITY_BUILD=${UNITY_BUILD} .. displayName: 'Generate ${{ variables.solutionName }} solution' - task: MSBuild@1 diff --git a/.gitmodules b/.gitmodules index 2ca642e60..078d99025 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,9 +1,6 @@ [submodule "base-n"] path = Dependencies/base-n url = https://github.com/azawadzki/base-n -[submodule "arcana.cpp"] - path = Dependencies/arcana.cpp - url = https://github.com/microsoft/arcana.cpp [submodule "glslang"] path = Dependencies/glslang url = https://github.com/KhronosGroup/glslang @@ -13,9 +10,6 @@ [submodule "bgfx.cmake"] path = Dependencies/bgfx.cmake url = https://github.com/BabylonJS/bgfx.cmake -[submodule "Dependencies/ios-cmake"] - path = Dependencies/ios-cmake - url = https://github.com/leetal/ios-cmake.git [submodule "Dependencies/xr/Dependencies/OpenXR-SDK"] path = Dependencies/xr/Dependencies/OpenXR-SDK url = https://github.com/KhronosGroup/OpenXR-SDK diff --git a/Apps/CMakeLists.txt b/Apps/CMakeLists.txt index 96ae9a86a..52a0a38ca 100644 --- a/Apps/CMakeLists.txt +++ b/Apps/CMakeLists.txt @@ -7,4 +7,4 @@ if((WIN32 AND NOT WINDOWS_STORE) OR (APPLE AND NOT IOS) OR (UNIX AND NOT ANDROID endif() # NPM install -npm(install) +npm(install ${CMAKE_CURRENT_SOURCE_DIR} "Apps module") diff --git a/Apps/Playground/Android/app/CMakeLists.txt b/Apps/Playground/Android/app/CMakeLists.txt index 2520c9d08..b49da5a03 100644 --- a/Apps/Playground/Android/app/CMakeLists.txt +++ b/Apps/Playground/Android/app/CMakeLists.txt @@ -56,7 +56,6 @@ target_link_libraries(BabylonNativeJNI AppRuntime Canvas Console - ChromeDevTools GraphicsDevice NativeCamera NativeEngine diff --git a/Apps/Playground/Android/app/src/main/cpp/BabylonNativeJNI.cpp b/Apps/Playground/Android/app/src/main/cpp/BabylonNativeJNI.cpp index 97cf4b189..ecc89ba7d 100644 --- a/Apps/Playground/Android/app/src/main/cpp/BabylonNativeJNI.cpp +++ b/Apps/Playground/Android/app/src/main/cpp/BabylonNativeJNI.cpp @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include @@ -29,7 +28,6 @@ namespace std::optional device{}; std::optional deviceUpdate{}; std::optional runtime{}; - std::optional chromeDevTools{}; std::optional nativeXr{}; Babylon::Plugins::NativeInput* nativeInput{}; std::optional nativeCanvas{}; @@ -58,7 +56,6 @@ extern "C" scriptLoader.reset(); nativeInput = {}; - chromeDevTools.reset(); nativeXr.reset(); scriptLoader.reset(); runtime.reset(); @@ -126,12 +123,6 @@ extern "C" Babylon::Polyfills::XMLHttpRequest::Initialize(env); nativeCanvas.emplace(Babylon::Polyfills::Canvas::Initialize(env)); - - chromeDevTools.emplace(Babylon::Plugins::ChromeDevTools::Initialize(env)); - if (chromeDevTools->SupportsInspector()) - { - chromeDevTools->StartInspector(5643, "BabylonNative Playground"); - } }); scriptLoader.emplace(*runtime); diff --git a/Apps/Playground/CMakeLists.txt b/Apps/Playground/CMakeLists.txt index 961775173..12149838e 100644 --- a/Apps/Playground/CMakeLists.txt +++ b/Apps/Playground/CMakeLists.txt @@ -22,7 +22,7 @@ set(SCRIPTS "Scripts/config.json") if(APPLE) - find_library(JSCORE_LIBRARY JavaScriptCore) + find_library(JAVASCRIPTCORE_LIBRARY JavaScriptCore) if(IOS) set(PLIST_FILE "${CMAKE_CURRENT_LIST_DIR}/iOS/Info.plist") @@ -54,7 +54,7 @@ if(APPLE) set_source_files_properties(${REFERENCE_IMAGES} PROPERTIES MACOSX_PACKAGE_LOCATION "Resources/ReferenceImages") endif() set(ADDITIONAL_LIBRARIES ${ADDITIONAL_LIBRARIES} - PRIVATE ${JSCORE_LIBRARY} + PRIVATE ${JAVASCRIPTCORE_LIBRARY} PRIVATE NativeCamera) set(RESOURCE_FILES ${STORYBOARD}) elseif(UNIX) @@ -115,7 +115,6 @@ target_include_directories(Playground PRIVATE "Source" ".") target_link_to_dependencies(Playground PRIVATE AppRuntime PRIVATE Canvas - PRIVATE ChromeDevTools PRIVATE Console PRIVATE GraphicsDevice PRIVATE NativeCapture @@ -129,10 +128,10 @@ target_link_to_dependencies(Playground ${ADDITIONAL_LIBRARIES} ${BABYLON_NATIVE_PLAYGROUND_EXTENSION_LIBRARIES}) -if(WIN32) - target_link_to_dependencies(Playground - PRIVATE "shlwapi.lib") -endif() +# See https://gitlab.kitware.com/cmake/cmake/-/issues/23543 +# If we can set minimum required to 3.26+, then we can use the `copy -t` syntax instead. +add_custom_command(TARGET Playground POST_BUILD + COMMAND ${CMAKE_COMMAND} -E $>,copy,true> $ $) if (UNIX AND NOT APPLE AND NOT ANDROID) # Ubuntu mixes old experimental header and new runtime libraries @@ -176,6 +175,7 @@ if(APPLE) RESOURCE "${RESOURCE_FILES}" FOLDER "Playground") endif() + set_property(TARGET Playground PROPERTY UNITY_BUILD false) endif() if(WINDOWS_STORE) diff --git a/Apps/Playground/UWP/App.cpp b/Apps/Playground/UWP/App.cpp index e55e8c788..c5dfbdba5 100644 --- a/Apps/Playground/UWP/App.cpp +++ b/Apps/Playground/UWP/App.cpp @@ -172,7 +172,6 @@ void App::Uninitialize() } m_nativeInput = {}; - m_chromeDevTools.reset(); m_nativeCanvas.reset(); m_runtime.reset(); m_update.reset(); @@ -398,12 +397,6 @@ void App::RestartRuntime(Windows::Foundation::Rect bounds) Babylon::Plugins::NativeXr::Initialize(env); m_nativeInput = &Babylon::Plugins::NativeInput::CreateForJavaScript(env); - - m_chromeDevTools.emplace(Babylon::Plugins::ChromeDevTools::Initialize(env)); - if (m_chromeDevTools->SupportsInspector()) - { - m_chromeDevTools->StartInspector(5643, "BabylonNative Playground"); - } }); Babylon::ScriptLoader loader{*m_runtime}; diff --git a/Apps/Playground/UWP/App.h b/Apps/Playground/UWP/App.h index 26ba3a571..b48258be3 100644 --- a/Apps/Playground/UWP/App.h +++ b/Apps/Playground/UWP/App.h @@ -3,7 +3,6 @@ #include #include #include -#include #include #include @@ -48,7 +47,6 @@ ref class App sealed : public Windows::ApplicationModel::Core::IFrameworkView std::optional m_update{}; std::optional m_runtime{}; std::optional m_nativeCanvas{}; - std::optional m_chromeDevTools{}; Babylon::Plugins::NativeInput* m_nativeInput{}; Windows::Foundation::Collections::IVectorView^ m_files; diff --git a/Apps/Playground/Win32/App.cpp b/Apps/Playground/Win32/App.cpp index 3ca1ba7be..e728544e9 100644 --- a/Apps/Playground/Win32/App.cpp +++ b/Apps/Playground/Win32/App.cpp @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include @@ -36,7 +35,6 @@ std::optional runtime{}; std::optional device{}; std::optional update{}; Babylon::Plugins::NativeInput* nativeInput{}; -std::optional chromeDevTools{}; std::optional nativeCanvas{}; bool minimized{false}; int buttonRefCount{0}; @@ -92,7 +90,6 @@ namespace } nativeCanvas.reset(); - chromeDevTools.reset(); nativeInput = {}; runtime.reset(); update.reset(); @@ -154,11 +151,6 @@ namespace nativeInput = &Babylon::Plugins::NativeInput::CreateForJavaScript(env); - chromeDevTools.emplace(Babylon::Plugins::ChromeDevTools::Initialize(env)); - if (chromeDevTools->SupportsInspector()) - { - chromeDevTools->StartInspector(5643, "BabylonNative Playground"); - } Babylon::Plugins::TestUtils::Initialize(env, hWnd); }); diff --git a/Apps/UnitTests/CMakeLists.txt b/Apps/UnitTests/CMakeLists.txt index 163939e95..95b502a2a 100644 --- a/Apps/UnitTests/CMakeLists.txt +++ b/Apps/UnitTests/CMakeLists.txt @@ -18,8 +18,8 @@ set(HEADERS "Shared/Tests.h") if(APPLE) - find_library(JSCORE_LIBRARY JavaScriptCore) - set(ADDITIONAL_LIBRARIES PRIVATE ${JSCORE_LIBRARY}) + find_library(JAVASCRIPTCORE_LIBRARY JavaScriptCore) + set(ADDITIONAL_LIBRARIES PRIVATE ${JAVASCRIPTCORE_LIBRARY}) set(TEST_APP "Apple/App.mm") elseif(UNIX AND NOT ANDROID) set(TEST_APP "X11/App.cpp") @@ -28,6 +28,7 @@ elseif(WIN32) endif() add_executable(UnitTests ${LOCAL_SCRIPTS} ${NPM_SCRIPTS} ${TEST_APP} ${HEADERS}) +set_property(TARGET UnitTests PROPERTY UNITY_BUILD false) target_link_to_dependencies(UnitTests PRIVATE AppRuntime @@ -43,6 +44,11 @@ target_link_to_dependencies(UnitTests add_test(NAME UnitTests COMMAND UnitTests) +# See https://gitlab.kitware.com/cmake/cmake/-/issues/23543 +# If we can set minimum required to 3.26+, then we can use the `copy -t` syntax instead. +add_custom_command(TARGET UnitTests POST_BUILD + COMMAND ${CMAKE_COMMAND} -E $>,copy,true> $ $) + foreach(SCRIPT ${LOCAL_SCRIPTS} ${NPM_SCRIPTS}) get_filename_component(SCRIPT_NAME "${SCRIPT}" NAME) add_custom_command( diff --git a/Apps/UnitTests/Scripts/tests.js b/Apps/UnitTests/Scripts/tests.js index dd11ef113..b330c3735 100644 --- a/Apps/UnitTests/Scripts/tests.js +++ b/Apps/UnitTests/Scripts/tests.js @@ -17,74 +17,8 @@ function BabylonReporter(runner) { mocha.setup({ ui: "bdd", reporter: BabylonReporter }); -function createRequest(method, url) { - return new Promise((resolve, reject) => { - const xhr = new XMLHttpRequest(); - xhr.open(method, url); - xhr.addEventListener("loadend", () => resolve(xhr)); - xhr.send(); - }); -} - const expect = chai.expect; -describe("XMLHTTPRequest", function () { - this.timeout(0); - it("should have readyState=4 when load ends", async function () { - const xhr = await createRequest("GET", "https://github.com/"); - expect(xhr.readyState).to.equal(4); - }); - it("should have status=200 for a file that exists", async function () { - const xhr = await createRequest("GET", "https://github.com/"); - expect(xhr.status).to.equal(200); - }); - it("should load URLs with escaped unicode characters", async function () { - const xhr = await createRequest("GET", "https://raw.githubusercontent.com/BabylonJS/Assets/master/meshes/%CF%83%CF%84%CF%81%CE%BF%CE%B3%CE%B3%CF%85%CE%BB%CE%B5%CE%BC%CE%AD%CE%BD%CE%BF%CF%82%20%25%20%CE%BA%CF%8D%CE%B2%CE%BF%CF%82.glb"); - expect(xhr.status).to.equal(200); - }); - it("should load URLs with unescaped unicode characters", async function () { - const xhr = await createRequest("GET", "https://raw.githubusercontent.com/BabylonJS/Assets/master/meshes/στρογγυλεμένος%20%25%20κύβος.glb"); - expect(xhr.status).to.equal(200); - }); - it("should load URLs with unescaped unicode characters and spaces", async function () { - const xhr = await createRequest("GET", "https://raw.githubusercontent.com/BabylonJS/Assets/master/meshes/στρογγυλεμένος %25 κύβος.glb"); - expect(xhr.status).to.equal(200); - }); - it("should have status=404 for a file that does not exist", async function () { - const xhr = await createRequest("GET", "https://github.com/babylonJS/BabylonNative404"); - expect(xhr.status).to.equal(404); - }); - it("should throw something when opening //", async function () { - function openDoubleSlash() { - const xhr = new XMLHttpRequest(); - xhr.open("GET", "//"); - xhr.send(); - } - expect(openDoubleSlash).to.throw(); - }); - it("should throw something when opening a url with no scheme", function () { - function openNoProtocol() { - const xhr = new XMLHttpRequest(); - xhr.open("GET", "noscheme.glb"); - xhr.send(); - } - expect(openNoProtocol).to.throw(); - }); - it("should throw something when sending before opening", function () { - function sendWithoutOpening() { - const xhr = new XMLHttpRequest(); - xhr.send(); - } - expect(sendWithoutOpening).to.throw(); - }); - it("should open a local file", async function () { - const xhr = await createRequest("GET", "app:///Scripts/tests.js"); - expect(xhr).to.have.property('readyState', 4); - expect(xhr).to.have.property('status', 200); - expect(xhr).to.have.property('responseText').with.lengthOf.above(0); - }); -}); - describe("RequestFile", function () { this.timeout(0); it("should throw when requesting a URL with no protocol", function () { diff --git a/BUILDING.md b/BUILDING.md index 7f494e21b..e1c45f6d2 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -260,7 +260,7 @@ sudo apt-get install libjavascriptcoregtk-4.0-dev Then, run cmake targetting a Ninja make file: ``` -cmake -G Ninja -D JSCORE_LIBRARY=/usr/lib/x86_64-linux-gnu/libjavascriptcoregtk-4.0.so -D NAPI_JAVASCRIPT_ENGINE=JavaScriptCore +cmake -G Ninja -D JAVASCRIPTCORE_LIBRARY=/usr/lib/x86_64-linux-gnu/libjavascriptcoregtk-4.0.so -D NAPI_JAVASCRIPT_ENGINE=JavaScriptCore ``` ### V8 diff --git a/CMakeLists.txt b/CMakeLists.txt index b05e5e635..ad3b0a168 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,12 +5,19 @@ set_property(GLOBAL PROPERTY USE_FOLDERS ON) # CMakeExtensions include(FetchContent) FetchContent_Declare(cmake-extensions - GIT_REPOSITORY https://github.com/BabylonJS/CMakeExtensions.git - GIT_TAG 17baf9e349afea90677e69cdd273d773c894f7b5) + GIT_REPOSITORY https://github.com/BabylonJS/CMakeExtensions.git + GIT_TAG 7bdd0664181ce3d90dc94474464cea9b25b22db7) message(STATUS "Fetching cmake-extensions") FetchContent_MakeAvailable(cmake-extensions) message(STATUS "Fetching cmake-extensions - done") +# JSRuntime Host +FetchContent_Declare(jsruntimehost + GIT_REPOSITORY https://github.com/BabylonJS/JsRuntimeHost.git + GIT_TAG 7d4c1966b54dca290be44646998cbeec431fca50) +set(JSRUNTIMEHOST_TESTS OFF) +FetchContent_MakeAvailable(jsruntimehost) + project(BabylonNative) # -------------------------------------------------- @@ -20,13 +27,9 @@ option(BABYLON_NATIVE_BUILD_APPS "Build Babylon Native apps." ON) option(BABYLON_NATIVE_INSTALL "Include the install target." ON) ## Core -option(BABYLON_NATIVE_CORE_JSRUNTIME "Include Babylon Native Core JsRuntime" ON) -option(BABYLON_NATIVE_CORE_APPRUNTIME "Include Babylon Native Core AppRuntime" ON) -option(BABYLON_NATIVE_CORE_SCRIPTLOADER "Include Babylon Native Core ScriptLoader" ON) option(BABYLON_NATIVE_CORE_GRAPHICS "Include Babylon Native Core Graphics" ON) ## Plugins -option(BABYLON_NATIVE_PLUGIN_CHROMEDEVTOOLS "Include Babylon Native Plugin ChromeDevTools." ON) option(BABYLON_NATIVE_PLUGIN_EXTERNALTEXTURE "Include Babylon Native Plugin ExternalTexture." ON) option(BABYLON_NATIVE_PLUGIN_NATIVECAMERA "Include Babylon Native Plugin NativeCamera." ON) option(BABYLON_NATIVE_PLUGIN_NATIVECAPTURE "Include Babylon Native Plugin NativeCapture." ON) @@ -38,9 +41,7 @@ option(BABYLON_NATIVE_PLUGIN_TESTUTILS "Include Babylon Native Plugin TestUtils. option(BABYLON_NATIVE_PLUGIN_NATIVEXR "Include Babylon Native Plugin XR." ON) ## Polyfills -option(BABYLON_NATIVE_POLYFILL_CONSOLE "Include Babylon Native Polyfill Console." ON) option(BABYLON_NATIVE_POLYFILL_WINDOW "Include Babylon Native Polyfill Window." ON) -option(BABYLON_NATIVE_POLYFILL_XMLHTTPREQUEST "Include Babylon Native Polyfill XMLHttpRequest." ON) option(BABYLON_NATIVE_POLYFILL_CANVAS "Include Babylon Native Polyfill Canvas." ON) # -------------------------------------------------- @@ -90,6 +91,8 @@ endif() if(APPLE) set(BABYLON_NATIVE_PLATFORM_IMPL_EXT "mm") + set_property(TARGET JsRuntime PROPERTY UNITY_BUILD false) + set_property(TARGET AppRuntime PROPERTY UNITY_BUILD false) else() set(BABYLON_NATIVE_PLATFORM_IMPL_EXT "cpp") endif() diff --git a/Core/AppRuntime/CMakeLists.txt b/Core/AppRuntime/CMakeLists.txt deleted file mode 100644 index 400783488..000000000 --- a/Core/AppRuntime/CMakeLists.txt +++ /dev/null @@ -1,34 +0,0 @@ -set(SOURCES - "Include/Babylon/Dispatchable.h" - "Include/Babylon/AppRuntime.h" - "Source/AppRuntime.cpp" - "Source/AppRuntime_${NAPI_JAVASCRIPT_ENGINE}.cpp" - "Source/AppRuntime_${BABYLON_NATIVE_PLATFORM}.${BABYLON_NATIVE_PLATFORM_IMPL_EXT}" - "Source/WorkQueue.cpp" - "Source/WorkQueue.h") - -add_library(AppRuntime ${SOURCES}) -warnings_as_errors(AppRuntime) - -target_include_directories(AppRuntime - PRIVATE "Include/Babylon" - INTERFACE "Include") - -if(UNIX AND NOT APPLE AND NOT ANDROID) - target_include_directories(AppRuntime INTERFACE "/usr/include/webkitgtk-4.0/") -endif() - -if(APPLE) - set_property(TARGET AppRuntime PROPERTY UNITY_BUILD false) -endif() - -target_link_to_dependencies(AppRuntime - PRIVATE arcana - PRIVATE JsRuntime) - -target_compile_definitions(AppRuntime - PRIVATE NOMINMAX) - -set_property(TARGET AppRuntime PROPERTY FOLDER Core) -source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${SOURCES}) - diff --git a/Core/AppRuntime/Include/Babylon/AppRuntime.h b/Core/AppRuntime/Include/Babylon/AppRuntime.h deleted file mode 100644 index 70ddd5921..000000000 --- a/Core/AppRuntime/Include/Babylon/AppRuntime.h +++ /dev/null @@ -1,50 +0,0 @@ -#pragma once - -#include "Dispatchable.h" -#include - -#include -#include -#include - -namespace Babylon -{ - class WorkQueue; - - class AppRuntime final - { - public: - AppRuntime(); - AppRuntime(std::function unhandledExceptionHandler); - ~AppRuntime(); - - void Suspend(); - void Resume(); - - void Dispatch(Dispatchable callback); - - private: - // These three methods are the mechanism by which platform- and JavaScript-specific - // code can be "injected" into the execution of the JavaScript thread. These three - // functions are implemented in separate files, thus allowing implementations to be - // mixed and matched by the build system based on the platform and JavaScript engine - // being targeted, without resorting to virtuality. An important nuance of these - // functions is that they are all intended to call each other: RunPlatformTier MUST - // call RunEnvironmentTier, which MUST create the initial Napi::Env and pass it to - // Run. This arrangement allows not only for an arbitrary assemblage of platforms, - // but it also allows us to respect the requirement by certain platforms (notably V8) - // that certain program state be allocated and stored only on the stack. - void RunPlatformTier(); - void RunEnvironmentTier(const char* executablePath = "."); - void Run(Napi::Env); - - // This method is called from Dispatch to allow platform-specific code to add - // extra logic around the invocation of a dispatched callback. - void Execute(Dispatchable callback); - - static void DefaultUnhandledExceptionHandler(const std::exception& error); - - std::unique_ptr m_workQueue{}; - std::function m_unhandledExceptionHandler{}; - }; -} diff --git a/Core/AppRuntime/Include/Babylon/Dispatchable.h b/Core/AppRuntime/Include/Babylon/Dispatchable.h deleted file mode 100644 index f2adca5d6..000000000 --- a/Core/AppRuntime/Include/Babylon/Dispatchable.h +++ /dev/null @@ -1,71 +0,0 @@ -#pragma once - -#include -#include - -namespace Babylon -{ - namespace Internal - { - template - class DispatchableImplBase; - - template - class DispatchableImplBase - { - public: - virtual ~DispatchableImplBase() - { - } - - virtual ReturnT operator()(ArgsT... args) = 0; - }; - - template - class DispatchableImpl; - - template - class DispatchableImpl : public DispatchableImplBase - { - public: - DispatchableImpl(DispatchableImpl&& other) = default; - - DispatchableImpl(CallableT&& callable) - : m_callable{std::forward(callable)} - { - } - - ReturnT operator()(ArgsT... args) override - { - return m_callable(args...); - } - - private: - CallableT m_callable; - }; - } - - template - class Dispatchable - { - public: - Dispatchable() = default; - Dispatchable(const Dispatchable&) = delete; - Dispatchable(Dispatchable&&) noexcept = default; - - template - Dispatchable(CallableT&& callable) - : m_impl{std::make_unique>(std::forward(callable))} - { - } - - template - void operator()(ArgsT... args) - { - (*m_impl)(args...); - } - - private: - std::unique_ptr> m_impl{}; - }; -} diff --git a/Core/AppRuntime/Source/AppRuntime.cpp b/Core/AppRuntime/Source/AppRuntime.cpp deleted file mode 100644 index 42bf8fce3..000000000 --- a/Core/AppRuntime/Source/AppRuntime.cpp +++ /dev/null @@ -1,59 +0,0 @@ -#include "AppRuntime.h" -#include "WorkQueue.h" -#include - -namespace Babylon -{ - AppRuntime::AppRuntime() - : AppRuntime{DefaultUnhandledExceptionHandler} - { - } - - AppRuntime::AppRuntime(std::function unhandledExceptionHandler) - : m_workQueue{std::make_unique([this] { RunPlatformTier(); })} - , m_unhandledExceptionHandler{unhandledExceptionHandler} - { - Dispatch([this](Napi::Env env) { - JsRuntime::CreateForJavaScript(env, [this](auto func) { Dispatch(std::move(func)); }); - }); - } - - AppRuntime::~AppRuntime() - { - } - - void AppRuntime::Run(Napi::Env env) - { - m_workQueue->Run(env); - } - - void AppRuntime::Suspend() - { - m_workQueue->Suspend(); - } - - void AppRuntime::Resume() - { - m_workQueue->Resume(); - } - - void AppRuntime::Dispatch(Dispatchable func) - { - m_workQueue->Append([this, func{std::move(func)}](Napi::Env env) mutable { - Execute([this, env, func{std::move(func)}]() mutable { - try - { - func(env); - } - catch (const std::exception& error) - { - m_unhandledExceptionHandler(error); - } - catch (...) - { - std::abort(); - } - }); - }); - } -} diff --git a/Core/AppRuntime/Source/AppRuntime_Android.cpp b/Core/AppRuntime/Source/AppRuntime_Android.cpp deleted file mode 100644 index a87db5681..000000000 --- a/Core/AppRuntime/Source/AppRuntime_Android.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "AppRuntime.h" -#include -#include -#include - -namespace Babylon -{ - void AppRuntime::RunPlatformTier() - { - RunEnvironmentTier(); - } - - void AppRuntime::DefaultUnhandledExceptionHandler(const std::exception& error) - { - std::stringstream ss{}; - ss << "Uncaught Error: " << error.what() << std::endl; - __android_log_write(ANDROID_LOG_ERROR, "BabylonNative", ss.str().data()); - } - - void AppRuntime::Execute(Dispatchable callback) - { - callback(); - } -} diff --git a/Core/AppRuntime/Source/AppRuntime_Chakra.cpp b/Core/AppRuntime/Source/AppRuntime_Chakra.cpp deleted file mode 100644 index 4484070c0..000000000 --- a/Core/AppRuntime/Source/AppRuntime_Chakra.cpp +++ /dev/null @@ -1,73 +0,0 @@ -#include "AppRuntime.h" - -#include - -#include - -#include -#include - -namespace Babylon -{ - namespace - { - void ThrowIfFailed(JsErrorCode errorCode) - { - if (errorCode != JsErrorCode::JsNoError) - { - throw std::exception(); - } - } - } - - void AppRuntime::RunEnvironmentTier(const char*) - { - using DispatchFunction = std::function)>; - DispatchFunction dispatchFunction = - [this](std::function action) { - Dispatch([action = std::move(action)](Napi::Env) { - action(); - }); - }; - - JsRuntimeHandle jsRuntime; - ThrowIfFailed(JsCreateRuntime(JsRuntimeAttributeNone, nullptr, &jsRuntime)); - JsContextRef context; - ThrowIfFailed(JsCreateContext(jsRuntime, &context)); - ThrowIfFailed(JsSetCurrentContext(context)); - ThrowIfFailed(JsSetPromiseContinuationCallback( - [](JsValueRef task, void* callbackState) { - ThrowIfFailed(JsAddRef(task, nullptr)); - auto* dispatch = reinterpret_cast(callbackState); - dispatch->operator()([task]() { - JsValueRef undefined; - ThrowIfFailed(JsGetUndefinedValue(&undefined)); - ThrowIfFailed(JsCallFunction(task, &undefined, 1, nullptr)); - ThrowIfFailed(JsRelease(task, nullptr)); - }); - }, - &dispatchFunction)); - ThrowIfFailed(JsProjectWinRTNamespace(L"Windows")); - -#if defined(_DEBUG) - // Put Chakra in debug mode. - { - auto result = JsStartDebugging(); - if (result != JsErrorCode::JsNoError) - { - OutputDebugStringW(L"Failed to initialize JavaScript debugging support.\n"); - } - } -#endif - - Napi::Env env = Napi::Attach(); - - Run(env); - - ThrowIfFailed(JsSetCurrentContext(JS_INVALID_REFERENCE)); - ThrowIfFailed(JsDisposeRuntime(jsRuntime)); - - // Detach must come after JsDisposeRuntime since it triggers finalizers which require env. - Napi::Detach(env); - } -} diff --git a/Core/AppRuntime/Source/AppRuntime_JSI.cpp b/Core/AppRuntime/Source/AppRuntime_JSI.cpp deleted file mode 100644 index 2b94fcd19..000000000 --- a/Core/AppRuntime/Source/AppRuntime_JSI.cpp +++ /dev/null @@ -1,52 +0,0 @@ -#include "AppRuntime.h" -#include "WorkQueue.h" - -#include - -#include -#include - -namespace -{ - class TaskRunnerAdapter : public v8runtime::JSITaskRunner - { - public: - TaskRunnerAdapter(Babylon::WorkQueue& workQueue) - : m_workQueue(workQueue) - { - } - - void postTask(std::unique_ptr task) override - { - std::shared_ptr shared_task(task.release()); - m_workQueue.Append([shared_task2 = std::move(shared_task)](Napi::Env) { - shared_task2->run(); - }); - } - - private: - TaskRunnerAdapter(const TaskRunnerAdapter&) = delete; - TaskRunnerAdapter& operator=(const TaskRunnerAdapter&) = delete; - - Babylon::WorkQueue& m_workQueue; - }; -} - -namespace Babylon -{ - void AppRuntime::RunEnvironmentTier(const char*) - { - v8runtime::V8RuntimeArgs args{}; - args.inspectorPort = 5643; - args.foreground_task_runner = std::make_shared(*m_workQueue); - - const auto runtime{v8runtime::makeV8Runtime(std::move(args))}; - const auto env{Napi::Attach(*runtime)}; - Dispatch([&runtime](Napi::Env env) { - JsRuntime::NativeObject::GetFromJavaScript(env) - .Set("_JSIRuntime", Napi::External::New(env, runtime.get())); - }); - Run(env); - Napi::Detach(env); - } -} diff --git a/Core/AppRuntime/Source/AppRuntime_JavaScriptCore.cpp b/Core/AppRuntime/Source/AppRuntime_JavaScriptCore.cpp deleted file mode 100644 index bcc224d29..000000000 --- a/Core/AppRuntime/Source/AppRuntime_JavaScriptCore.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "AppRuntime.h" - -#include -#include - -namespace Babylon -{ - void AppRuntime::RunEnvironmentTier(const char*) - { - auto globalContext = JSGlobalContextCreateInGroup(nullptr, nullptr); - Napi::Env env = Napi::Attach(globalContext); - - Run(env); - - JSGlobalContextRelease(globalContext); - - // Detach must come after JSGlobalContextRelease since it triggers finalizers which require env. - Napi::Detach(env); - } -} diff --git a/Core/AppRuntime/Source/AppRuntime_Unix.cpp b/Core/AppRuntime/Source/AppRuntime_Unix.cpp deleted file mode 100644 index 69585c398..000000000 --- a/Core/AppRuntime/Source/AppRuntime_Unix.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include "WorkQueue.h" -#include "AppRuntime.h" -#include -#include - -namespace Babylon -{ - void AppRuntime::RunPlatformTier() - { - RunEnvironmentTier(); - } - - void AppRuntime::DefaultUnhandledExceptionHandler(const std::exception& error) - { - std::cerr << "Uncaught Error: " << error.what() << std::endl; - } - - void AppRuntime::Execute(Dispatchable callback) - { - callback(); - } -} diff --git a/Core/AppRuntime/Source/AppRuntime_V8.cpp b/Core/AppRuntime/Source/AppRuntime_V8.cpp deleted file mode 100644 index a08abdeff..000000000 --- a/Core/AppRuntime/Source/AppRuntime_V8.cpp +++ /dev/null @@ -1,95 +0,0 @@ -#include "AppRuntime.h" - -#include - -#if defined(_MSC_VER) -#pragma warning(disable : 4100 4267 4127) -#endif -#if defined(__clang__) -#pragma clang diagnostic ignored "-Wunused-parameter" -#endif -#if defined(__GNUC__) -#pragma GCC diagnostic ignored "-Wunused-parameter" -#endif -#include -#include - -namespace Babylon -{ - namespace - { - class Module final - { - public: - Module(const char* executablePath) - { - v8::V8::InitializeICUDefaultLocation(executablePath); - v8::V8::InitializeExternalStartupData(executablePath); - m_platform = v8::platform::NewDefaultPlatform(); - v8::V8::InitializePlatform(m_platform.get()); - v8::V8::Initialize(); - } - - ~Module() - { - v8::V8::Dispose(); - v8::V8::ShutdownPlatform(); - } - - static Module& Instance() - { - return *s_module; - } - - static void Initialize(const char* executablePath) - { - if (s_module == nullptr) - { - s_module = std::make_unique(executablePath); - } - } - - void AddPlatformToJavaScript(Napi::Env env) - { - JsRuntime::NativeObject::GetFromJavaScript(env) - .Set("_V8Platform", Napi::External::New(env, m_platform.get())); - } - - private: - std::unique_ptr m_platform; - - static std::unique_ptr s_module; - }; - - std::unique_ptr Module::s_module; - } - - void AppRuntime::RunEnvironmentTier(const char* executablePath) - { - // Create the isolate. - Module::Initialize(executablePath); - v8::Isolate::CreateParams create_params; - create_params.array_buffer_allocator = v8::ArrayBuffer::Allocator::NewDefaultAllocator(); - v8::Isolate* isolate = v8::Isolate::New(create_params); - - // Use the isolate within a scope. - { - v8::Isolate::Scope isolate_scope{isolate}; - v8::HandleScope isolate_handle_scope{isolate}; - v8::Local context = v8::Context::New(isolate); - v8::Context::Scope context_scope{context}; - - Napi::Env env = Napi::Attach(context); - Dispatch([](Napi::Env env) { - Module::Instance().AddPlatformToJavaScript(env); - }); - Run(env); - Napi::Detach(env); - } - - // Destroy the isolate. - // todo : GetArrayBufferAllocator not available? - // delete isolate->GetArrayBufferAllocator(); - isolate->Dispose(); - } -} diff --git a/Core/AppRuntime/Source/AppRuntime_Win32.cpp b/Core/AppRuntime/Source/AppRuntime_Win32.cpp deleted file mode 100644 index baf89300d..000000000 --- a/Core/AppRuntime/Source/AppRuntime_Win32.cpp +++ /dev/null @@ -1,43 +0,0 @@ -#include "AppRuntime.h" - -#include -#include - -#include -#include -#include -#include - -namespace Babylon -{ - namespace - { - constexpr size_t FILENAME_BUFFER_SIZE = 1024; - } - - void AppRuntime::RunPlatformTier() - { - HRESULT hr = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); - assert(SUCCEEDED(hr)); - _CRT_UNUSED(hr); - auto coInitScopeGuard = gsl::finally([] { CoUninitialize(); }); - - char filename[FILENAME_BUFFER_SIZE]; - auto result = GetModuleFileNameA(nullptr, filename, static_cast(std::size(filename))); - assert(result != 0); - (void)result; - RunEnvironmentTier(filename); - } - - void AppRuntime::DefaultUnhandledExceptionHandler(const std::exception& error) - { - std::stringstream ss{}; - ss << "Uncaught Error: " << error.what() << std::endl; - OutputDebugStringA(ss.str().data()); - } - - void AppRuntime::Execute(Dispatchable callback) - { - callback(); - } -} diff --git a/Core/AppRuntime/Source/AppRuntime_WinRT.cpp b/Core/AppRuntime/Source/AppRuntime_WinRT.cpp deleted file mode 100644 index 2a1a3f586..000000000 --- a/Core/AppRuntime/Source/AppRuntime_WinRT.cpp +++ /dev/null @@ -1,26 +0,0 @@ -#include "AppRuntime.h" - -#include - -#include -#include - -namespace Babylon -{ - void AppRuntime::RunPlatformTier() - { - RunEnvironmentTier(); - } - - void AppRuntime::DefaultUnhandledExceptionHandler(const std::exception& error) - { - std::stringstream ss{}; - ss << "Uncaught Error: " << error.what() << std::endl; - OutputDebugStringA(ss.str().data()); - } - - void AppRuntime::Execute(Dispatchable callback) - { - callback(); - } -} diff --git a/Core/AppRuntime/Source/AppRuntime_iOS.mm b/Core/AppRuntime/Source/AppRuntime_iOS.mm deleted file mode 100644 index e1528cf8e..000000000 --- a/Core/AppRuntime/Source/AppRuntime_iOS.mm +++ /dev/null @@ -1,25 +0,0 @@ -#include "AppRuntime.h" -#include - -#import - -namespace Babylon -{ - void AppRuntime::RunPlatformTier() - { - RunEnvironmentTier(); - } - - void AppRuntime::DefaultUnhandledExceptionHandler(const std::exception& error) - { - NSLog(@"Uncaught Error: %s", error.what()); - } - - void AppRuntime::Execute(Dispatchable callback) - { - @autoreleasepool - { - callback(); - } - } -} diff --git a/Core/AppRuntime/Source/AppRuntime_macOS.mm b/Core/AppRuntime/Source/AppRuntime_macOS.mm deleted file mode 100644 index e1528cf8e..000000000 --- a/Core/AppRuntime/Source/AppRuntime_macOS.mm +++ /dev/null @@ -1,25 +0,0 @@ -#include "AppRuntime.h" -#include - -#import - -namespace Babylon -{ - void AppRuntime::RunPlatformTier() - { - RunEnvironmentTier(); - } - - void AppRuntime::DefaultUnhandledExceptionHandler(const std::exception& error) - { - NSLog(@"Uncaught Error: %s", error.what()); - } - - void AppRuntime::Execute(Dispatchable callback) - { - @autoreleasepool - { - callback(); - } - } -} diff --git a/Core/AppRuntime/Source/WorkQueue.cpp b/Core/AppRuntime/Source/WorkQueue.cpp deleted file mode 100644 index 4c1c5f21a..000000000 --- a/Core/AppRuntime/Source/WorkQueue.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#include "WorkQueue.h" - -namespace Babylon -{ - WorkQueue::WorkQueue(std::function threadProcedure) - : m_thread{std::move(threadProcedure)} - { - } - - WorkQueue::~WorkQueue() - { - if (m_suspensionLock.has_value()) - { - Resume(); - } - - m_cancelSource.cancel(); - m_dispatcher.cancelled(); - - m_thread.join(); - } - - void WorkQueue::Suspend() - { - auto suspensionMutex = std::make_shared(); - m_suspensionLock.emplace(*suspensionMutex); - Append([suspensionMutex{std::move(suspensionMutex)}](Napi::Env) { - std::scoped_lock lock{*suspensionMutex}; - }); - } - - void WorkQueue::Resume() - { - m_suspensionLock.reset(); - } - - void WorkQueue::Run(Napi::Env env) - { - m_env = std::make_optional(env); - m_dispatcher.set_affinity(std::this_thread::get_id()); - - while (!m_cancelSource.cancelled()) - { - m_dispatcher.blocking_tick(m_cancelSource); - } - - m_dispatcher.clear(); - } -} diff --git a/Core/AppRuntime/Source/WorkQueue.h b/Core/AppRuntime/Source/WorkQueue.h deleted file mode 100644 index a9b8fada8..000000000 --- a/Core/AppRuntime/Source/WorkQueue.h +++ /dev/null @@ -1,54 +0,0 @@ -#pragma once - -#include -#include -#include - -#include -#include -#include - -namespace Babylon -{ - class WorkQueue - { - public: - WorkQueue(std::function threadProcedure); - ~WorkQueue(); - - template - void Append(CallableT callable) - { - // Manual dispatcher queueing requires a copyable CallableT, we use a shared pointer trick to make a - // copyable callable if necessary. - if constexpr (std::is_copy_constructible::value) - { - m_dispatcher.queue([this, callable = std::move(callable)]() { Invoke(callable); }); - } - else - { - m_dispatcher.queue([this, callablePtr = std::make_shared(std::move(callable))]() { Invoke(*callablePtr); }); - } - } - - void Suspend(); - void Resume(); - void Run(Napi::Env); - - private: - template - void Invoke(CallableT& callable) - { - callable(m_env.value()); - } - - std::optional m_env{}; - - std::optional> m_suspensionLock{}; - - arcana::cancellation_source m_cancelSource{}; - arcana::manual_dispatcher<128> m_dispatcher{}; - - std::thread m_thread; - }; -} diff --git a/Core/CMakeLists.txt b/Core/CMakeLists.txt index fe14949e2..a1d865681 100644 --- a/Core/CMakeLists.txt +++ b/Core/CMakeLists.txt @@ -1,10 +1 @@ -add_subdirectory(JsRuntime) add_subdirectory(Graphics) - -if(BABYLON_NATIVE_CORE_APPRUNTIME) - add_subdirectory(AppRuntime) -endif() - -if(BABYLON_NATIVE_CORE_SCRIPTLOADER) - add_subdirectory(ScriptLoader) -endif() diff --git a/Core/JsRuntime/CMakeLists.txt b/Core/JsRuntime/CMakeLists.txt deleted file mode 100644 index d8f2e03e0..000000000 --- a/Core/JsRuntime/CMakeLists.txt +++ /dev/null @@ -1,22 +0,0 @@ -set(SOURCES - "Include/Babylon/JsRuntime.h" - "InternalInclude/Babylon/JsRuntimeScheduler.h" - "Source/JsRuntime.cpp") - -add_library(JsRuntime ${SOURCES}) -warnings_as_errors(JsRuntime) - -target_include_directories(JsRuntime PUBLIC "Include") - -target_link_to_dependencies(JsRuntime - PUBLIC napi - PRIVATE arcana) - -set_property(TARGET JsRuntime PROPERTY FOLDER Core) -source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${SOURCES}) - -add_library(JsRuntimeInternal INTERFACE) -target_include_directories(JsRuntimeInternal INTERFACE "InternalInclude") -target_link_to_dependencies(JsRuntimeInternal - INTERFACE JsRuntime - INTERFACE arcana) diff --git a/Core/JsRuntime/Include/Babylon/JsRuntime.h b/Core/JsRuntime/Include/Babylon/JsRuntime.h deleted file mode 100644 index afa288454..000000000 --- a/Core/JsRuntime/Include/Babylon/JsRuntime.h +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once - -#include - -#include -#include - -namespace Babylon -{ - class JsRuntime - { - public: - class NativeObject - { - friend class JsRuntime; - static constexpr auto JS_NATIVE_NAME = "_native"; - - public: - static Napi::Object GetFromJavaScript(Napi::Env env) - { - return env.Global().Get(JS_NATIVE_NAME).As(); - } - }; - - struct InternalState; - friend struct InternalState; - - // Any JavaScript errors that occur will bubble up as a Napi::Error C++ exception. - // JsRuntime expects the provided dispatch function to handle this exception, - // such as with a try/catch and logging the exception message. - using DispatchFunctionT = std::function)>; - - // Note: It is the contract of JsRuntime that its dispatch function must be usable - // at the moment of construction. JsRuntime cannot be built with dispatch function - // that captures a reference to a not-yet-completed object that will be completed - // later -- an instance of an inheriting type, for example. The dispatch function - // must be safely callable as soon as it is passed to the JsRuntime constructor. - static JsRuntime& CreateForJavaScript(Napi::Env, DispatchFunctionT); - static JsRuntime& GetFromJavaScript(Napi::Env); - void Dispatch(std::function); - - protected: - JsRuntime(const JsRuntime&) = delete; - JsRuntime& operator=(const JsRuntime&) = delete; - - private: - JsRuntime(Napi::Env, DispatchFunctionT); - - DispatchFunctionT m_dispatchFunction{}; - }; -} diff --git a/Core/JsRuntime/InternalInclude/Babylon/JsRuntimeScheduler.h b/Core/JsRuntime/InternalInclude/Babylon/JsRuntimeScheduler.h deleted file mode 100644 index 4f1929203..000000000 --- a/Core/JsRuntime/InternalInclude/Babylon/JsRuntimeScheduler.h +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once - -#include - -namespace Babylon -{ - /** - * Scheduler that invokes continuations via JsRuntime::Dispatch. - * Intended to be consumed by arcana.cpp tasks. - */ - class JsRuntimeScheduler - { - public: - explicit JsRuntimeScheduler(JsRuntime& runtime) - : m_runtime{runtime} - { - } - - template - void operator()(CallableT&& callable) const - { - m_runtime.Dispatch([callable{std::forward(callable)}](Napi::Env) { - callable(); - }); - } - - private: - JsRuntime& m_runtime; - }; -} diff --git a/Core/JsRuntime/Source/JsRuntime.cpp b/Core/JsRuntime/Source/JsRuntime.cpp deleted file mode 100644 index 9e8f4c1a6..000000000 --- a/Core/JsRuntime/Source/JsRuntime.cpp +++ /dev/null @@ -1,58 +0,0 @@ -#include - -namespace Babylon -{ - namespace - { - static constexpr auto JS_RUNTIME_NAME = "runtime"; - static constexpr auto JS_WINDOW_NAME = "window"; - } - - JsRuntime::JsRuntime(Napi::Env env, DispatchFunctionT dispatchFunction) - : m_dispatchFunction{std::move(dispatchFunction)} - { - auto global = env.Global(); - - if (global.Get(JS_WINDOW_NAME).IsUndefined()) - { - global.Set(JS_WINDOW_NAME, global); - } - - auto jsNative = Napi::Object::New(env); - env.Global().Set(NativeObject::JS_NATIVE_NAME, jsNative); - - Napi::Value jsRuntime = Napi::External::New(env, this, [](Napi::Env, JsRuntime* runtime) { delete runtime; }); - jsNative.Set(JS_RUNTIME_NAME, jsRuntime); - } - - JsRuntime& JsRuntime::CreateForJavaScript(Napi::Env env, DispatchFunctionT dispatchFunction) - { - auto* runtime = new JsRuntime(env, std::move(dispatchFunction)); - return *runtime; - } - - JsRuntime& JsRuntime::GetFromJavaScript(Napi::Env env) - { - return *NativeObject::GetFromJavaScript(env) - .As() - .Get(JS_RUNTIME_NAME) - .As>() - .Data(); - } - - void JsRuntime::Dispatch(std::function function) - { - m_dispatchFunction([function = std::move(function)](Napi::Env env) { - function(env); - - // The environment will be in a pending exceptional state if - // Napi::Error::ThrowAsJavaScriptException is invoked within the - // previous function. Throw and clear the pending exception here to - // bubble up the exception to the the dispatcher. - if (env.IsExceptionPending()) - { - throw env.GetAndClearPendingException(); - } - }); - } -} diff --git a/Core/ScriptLoader/CMakeLists.txt b/Core/ScriptLoader/CMakeLists.txt deleted file mode 100644 index 7cc11465e..000000000 --- a/Core/ScriptLoader/CMakeLists.txt +++ /dev/null @@ -1,16 +0,0 @@ -set(SOURCES - "Include/Babylon/ScriptLoader.h" - "Source/ScriptLoader.cpp") - -add_library(ScriptLoader ${SOURCES}) -warnings_as_errors(ScriptLoader) - -target_include_directories(ScriptLoader PUBLIC "Include") - -target_link_to_dependencies(ScriptLoader - PUBLIC napi - PRIVATE arcana - PRIVATE UrlLib) - -set_property(TARGET ScriptLoader PROPERTY FOLDER Core) -source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${SOURCES}) diff --git a/Core/ScriptLoader/Include/Babylon/ScriptLoader.h b/Core/ScriptLoader/Include/Babylon/ScriptLoader.h deleted file mode 100644 index 3001fa43b..000000000 --- a/Core/ScriptLoader/Include/Babylon/ScriptLoader.h +++ /dev/null @@ -1,38 +0,0 @@ -#pragma once - -#include - -#include -#include -#include - -namespace Babylon -{ - class ScriptLoader - { - public: - using DispatchFunctionT = std::function)>; - - ScriptLoader(DispatchFunctionT dispatchFunction); - - template - ScriptLoader(T& dispatcher) - : ScriptLoader([&dispatcher](auto func) { dispatcher.Dispatch(std::move(func)); }) - { - } - - ~ScriptLoader(); - - // Move semantics - ScriptLoader(ScriptLoader&&) noexcept; - ScriptLoader& operator=(ScriptLoader&&) noexcept; - - void LoadScript(std::string url); - void Eval(std::string source, std::string url); - void Dispatch(std::function callback); - - private: - class Impl; - std::unique_ptr m_impl{}; - }; -} diff --git a/Core/ScriptLoader/Source/ScriptLoader.cpp b/Core/ScriptLoader/Source/ScriptLoader.cpp deleted file mode 100644 index aaf131b6e..000000000 --- a/Core/ScriptLoader/Source/ScriptLoader.cpp +++ /dev/null @@ -1,89 +0,0 @@ -#include -#include -#include - -namespace Babylon -{ - class ScriptLoader::Impl - { - public: - Impl(DispatchFunctionT dispatchFunction) - : m_dispatchFunction{dispatchFunction} - , m_task{arcana::task_from_result()} - { - } - - void LoadScript(std::string url) - { - UrlLib::UrlRequest request; - request.Open(UrlLib::UrlMethod::Get, url); - request.ResponseType(UrlLib::UrlResponseType::String); - m_task = arcana::when_all(m_task, request.SendAsync()).then(arcana::inline_scheduler, arcana::cancellation::none(), [dispatchFunction = m_dispatchFunction, request = std::move(request), url = std::move(url)](auto) mutable { - arcana::task_completion_source taskCompletionSource{}; - dispatchFunction([taskCompletionSource, request = std::move(request), url = std::move(url)](Napi::Env env) mutable { - Napi::Eval(env, request.ResponseString().data(), url.data()); - taskCompletionSource.complete(); - }); - return taskCompletionSource.as_task(); - }); - } - - void Eval(std::string source, std::string url) - { - m_task = m_task.then(arcana::inline_scheduler, arcana::cancellation::none(), - [dispatchFunction = m_dispatchFunction, source = std::move(source), url = std::move(url)](auto) mutable { - arcana::task_completion_source taskCompletionSource{}; - dispatchFunction([taskCompletionSource, source = std::move(source), url = std::move(url)](Napi::Env env) mutable { - Napi::Eval(env, source.data(), url.data()); - taskCompletionSource.complete(); - }); - return taskCompletionSource.as_task(); - }); - } - - void Dispatch(std::function callback) - { - m_task = m_task.then(arcana::inline_scheduler, arcana::cancellation::none(), - [dispatchFunction = m_dispatchFunction, callback = std::move(callback)](auto) mutable { - arcana::task_completion_source taskCompletionSource{}; - dispatchFunction([taskCompletionSource, callback = std::move(callback)](Napi::Env env) mutable { - callback(env); - taskCompletionSource.complete(); - }); - return taskCompletionSource.as_task(); - }); - } - - private: - DispatchFunctionT m_dispatchFunction{}; - arcana::task m_task{}; - }; - - ScriptLoader::ScriptLoader(DispatchFunctionT dispatchFunction) - : m_impl{std::make_unique(std::move(dispatchFunction))} - { - } - - ScriptLoader::~ScriptLoader() - { - } - - // Move semantics - ScriptLoader::ScriptLoader(ScriptLoader&&) noexcept = default; - ScriptLoader& ScriptLoader::operator=(ScriptLoader&&) noexcept = default; - - void ScriptLoader::LoadScript(std::string url) - { - m_impl->LoadScript(std::move(url)); - } - - void ScriptLoader::Eval(std::string source, std::string url) - { - m_impl->Eval(std::move(source), std::move(url)); - } - - void ScriptLoader::Dispatch(std::function callback) - { - m_impl->Dispatch(std::move(callback)); - } -} diff --git a/Dependencies/AndroidExtensions/CMakeLists.txt b/Dependencies/AndroidExtensions/CMakeLists.txt deleted file mode 100644 index ca9dc8313..000000000 --- a/Dependencies/AndroidExtensions/CMakeLists.txt +++ /dev/null @@ -1,17 +0,0 @@ -set(SOURCES - "Include/AndroidExtensions/Globals.h" - "Include/AndroidExtensions/JavaWrappers.h" - "Include/AndroidExtensions/OpenGLHelpers.h" - "Include/AndroidExtensions/Permissions.h" - "Source/Globals.cpp" - "Source/JavaWrappers.cpp" - "Source/OpenGLHelpers.cpp" - "Source/Permissions.cpp") - -add_library(AndroidExtensions ${SOURCES}) -warnings_as_errors(AndroidExtensions) - -target_link_to_dependencies(AndroidExtensions - PUBLIC arcana) - -target_include_directories(AndroidExtensions PUBLIC "Include") diff --git a/Dependencies/AndroidExtensions/Include/AndroidExtensions/Globals.h b/Dependencies/AndroidExtensions/Include/AndroidExtensions/Globals.h deleted file mode 100644 index 767fd7f80..000000000 --- a/Dependencies/AndroidExtensions/Include/AndroidExtensions/Globals.h +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once - -#include -#include -#include "JavaWrappers.h" - -namespace android::global -{ - void Initialize(JavaVM* javaVM, jobject appContext); - - JNIEnv* GetEnvForCurrentThread(); - - android::content::Context GetAppContext(); - - android::app::Activity GetCurrentActivity(); - void SetCurrentActivity(jobject currentActivity); - using AppStateChangedCallback = std::function; - using AppStateChangedCallbackTicket = arcana::ticketed_collection::ticket; - - void Pause(); - AppStateChangedCallbackTicket AddPauseCallback(std::function&&); - - void Resume(); - AppStateChangedCallbackTicket AddResumeCallback(std::function&&); - - using RequestPermissionsResultCallback = std::function&, const std::vector&)>; - using RequestPermissionsResultCallbackTicket = arcana::ticketed_collection::ticket; - - void RequestPermissionsResult(int32_t, const std::vector&, const std::vector&); - RequestPermissionsResultCallbackTicket AddRequestPermissionsResultCallback(RequestPermissionsResultCallback&&); -} diff --git a/Dependencies/AndroidExtensions/Include/AndroidExtensions/JavaWrappers.h b/Dependencies/AndroidExtensions/Include/AndroidExtensions/JavaWrappers.h deleted file mode 100644 index 27aba4867..000000000 --- a/Dependencies/AndroidExtensions/Include/AndroidExtensions/JavaWrappers.h +++ /dev/null @@ -1,362 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include - -// -------------------- -// Forward Declarations -// -------------------- - -namespace java::lang -{ - class ByteArray; - class Object; - class String; - class Throwable; -} - -namespace java::io -{ - class ByteArrayOutputStream; - class InputStream; -} - -namespace java::net -{ - class HttpURLConnection; - class URL; - class URLConnection; -} - -namespace android -{ - class ManifestPermission; -} - -namespace android::app -{ - class Activity; -} - -namespace android::content -{ - class Context; -} - -namespace android::content::res -{ - class AssetManager; - class Resources; - class Configuration; -} - -namespace android::net -{ - class Uri; -} - -// ------------ -// Declarations -// ------------ - -namespace java::lang -{ - class ByteArray - { - public: - ByteArray(int size); - ByteArray(jbyteArray byteArray); - - operator jbyteArray() const; - - operator std::vector() const; - - protected: - JNIEnv* m_env; - jbyteArray m_byteArray; - }; - - class Class final - { - public: - Class(const char* className); - Class(const jclass classObj); - ~Class(); - - Class(const Class&); - Class& operator=(const Class&); - - Class(Class&&); - Class& operator=(Class&&); - - operator jclass() const; - - bool IsAssignableFrom(Class otherClass); - - private: - jclass JClass() const; - void JClass(jclass classObj); - - JNIEnv* m_env; - jclass m_class; - }; - - class Object - { - public: - operator jobject() const; - Class GetClass(); - ~Object(); - - protected: - Object(const char* className); - Object(jobject object); - - Object(const Object&); - Object& operator=(const Object&); - - Object(Object&&); - Object& operator=(Object&&); - - jobject JObject() const; - void JObject(jobject object); - - JNIEnv* m_env; - Class m_class; - - private: - jobject m_object; - - }; - - class String - { - public: - String(jstring string); - String(const char* string); - - operator jstring() const; - - operator std::string() const; - - protected: - JNIEnv* m_env; - jstring m_string; - }; - - class Throwable : public Object, public std::exception - { - public: - Throwable(jthrowable throwable); - ~Throwable(); - - String GetMessage() const; - - const char* what() const noexcept override; - - private: - jobject m_throwableRef; - std::string m_message; - }; -} - -namespace java::io -{ - class ByteArrayOutputStream : public lang::Object - { - public: - ByteArrayOutputStream(); - ByteArrayOutputStream(int size); - ByteArrayOutputStream(jobject object); - - void Write(lang::ByteArray b, int off, int len); - - lang::ByteArray ToByteArray() const; - - lang::String ToString(const char* charsetName) const; - }; - - class InputStream : public lang::Object - { - public: - InputStream(jobject object); - - int Read(lang::ByteArray byteArray) const; - }; -} - -namespace java::net -{ - class HttpURLConnection : public lang::Object - { - public: - static lang::Class Class(); - - HttpURLConnection(jobject object); - - int GetResponseCode() const; - }; - - class URL : public lang::Object - { - public: - URL(jobject object); - URL(lang::String url); - - URLConnection OpenConnection(); - - lang::String ToString(); - }; - - class URLConnection : public lang::Object - { - public: - URLConnection(jobject object); - - void Connect(); - - URL GetURL() const; - - int GetContentLength() const; - - lang::String GetHeaderField(int n) const; - - lang::String GetHeaderFieldKey(int n) const; - - io::InputStream GetInputStream() const; - - explicit operator HttpURLConnection() const; - }; -} - -namespace android -{ - class ManifestPermission - { - public: - static jstring CAMERA(); - - private: - static jstring getPermissionName(const char* permissionName); - }; -} - -namespace android::app -{ - class Activity : public java::lang::Object - { - public: - Activity(jobject object); - - void requestPermissions(jstring systemPermissionName, int permissionRequestID); - }; -} - -namespace android::content -{ - class Context : public java::lang::Object - { - public: - Context(jobject object); - - Context getApplicationContext(); - - res::AssetManager getAssets() const; - - res::Resources getResources(); - - template - ServiceT getSystemService() - { - return {getSystemService(ServiceT::ServiceName)}; - }; - - jobject getSystemService(const char* serviceName); - - bool checkSelfPermission(jstring systemPermissionName); - }; -} - -namespace android::content::res -{ - class AssetManager : public java::lang::Object - { - public: - AssetManager(jobject object); - - operator AAssetManager*() const; - }; - - class Resources : public java::lang::Object - { - public: - Resources(jobject object); - - Configuration getConfiguration(); - }; - - class Configuration : public java::lang::Object - { - public: - Configuration(jobject object); - - int getDensityDpi(); - }; -} - -namespace android::graphics -{ - class SurfaceTexture : public java::lang::Object - { - public: - SurfaceTexture(); - void InitWithTexture(int texture); - void updateTexImage() const; - void setDefaultBufferSize(int width, int height); - }; -} - -namespace android::view -{ - class Display : public java::lang::Object - { - public: - Display(jobject object); - - int getRotation(); - }; - - class WindowManager : public java::lang::Object - { - public: - static constexpr const char* ServiceName{"window"}; - WindowManager(jobject object); - - Display getDefaultDisplay(); - }; - - class Surface : public java::lang::Object - { - public: - Surface(android::graphics::SurfaceTexture& surfaceTexture); - }; -} - -namespace android::net -{ - class Uri : public java::lang::Object - { - public: - Uri(jobject object); - - java::lang::String getScheme() const; - - java::lang::String getPath() const; - - static Uri Parse(java::lang::String uriString); - }; -} diff --git a/Dependencies/AndroidExtensions/Include/AndroidExtensions/OpenGLHelpers.h b/Dependencies/AndroidExtensions/Include/AndroidExtensions/OpenGLHelpers.h deleted file mode 100644 index 7c54bd5b9..000000000 --- a/Dependencies/AndroidExtensions/Include/AndroidExtensions/OpenGLHelpers.h +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace android::OpenGLHelpers -{ - constexpr GLint GetTextureUnit(GLenum texture) - { - return texture - GL_TEXTURE0; - } - - GLuint CreateShaderProgram(const char* vertShaderSource, const char* fragShaderSource); - - namespace GLTransactions - { - inline auto MakeCurrent(EGLDisplay display, EGLSurface drawSurface, EGLSurface readSurface, EGLContext context) - { - EGLDisplay previousDisplay{ eglGetDisplay(EGL_DEFAULT_DISPLAY) }; - EGLSurface previousDrawSurface{ eglGetCurrentSurface(EGL_DRAW) }; - EGLSurface previousReadSurface{ eglGetCurrentSurface(EGL_READ) }; - EGLContext previousContext{ eglGetCurrentContext() }; - eglMakeCurrent(display, drawSurface, readSurface, context); - return gsl::finally([previousDisplay, previousDrawSurface, previousReadSurface, previousContext]() { eglMakeCurrent(previousDisplay, previousDrawSurface, previousReadSurface, previousContext); }); - } - - inline auto SetStencil(uint8_t mask) - { - GLint previousStencilMask{}; - glGetIntegerv(GL_STENCIL_WRITEMASK, &previousStencilMask); - glStencilMask(mask); - return gsl::finally([previousStencilMask]() { glStencilMask(previousStencilMask); }); - } - } -} \ No newline at end of file diff --git a/Dependencies/AndroidExtensions/Include/AndroidExtensions/Permissions.h b/Dependencies/AndroidExtensions/Include/AndroidExtensions/Permissions.h deleted file mode 100644 index 21ab12dea..000000000 --- a/Dependencies/AndroidExtensions/Include/AndroidExtensions/Permissions.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once - -#include - -namespace android::Permissions -{ - arcana::task CheckCameraPermissionAsync(); -} \ No newline at end of file diff --git a/Dependencies/AndroidExtensions/Source/Globals.cpp b/Dependencies/AndroidExtensions/Source/Globals.cpp deleted file mode 100644 index 2a6aade42..000000000 --- a/Dependencies/AndroidExtensions/Source/Globals.cpp +++ /dev/null @@ -1,130 +0,0 @@ -#include -#include - -namespace android::global -{ - namespace - { - JavaVM* g_javaVM{}; - jobject g_appContext{}; - jobject g_currentActivity{}; - - thread_local struct Env final - { - ~Env() - { - if (m_attached) - { - g_javaVM->DetachCurrentThread(); - } - } - - bool m_attached{}; - } g_env{}; - - template - class Event final - { - public: - using Handler = std::function; - using Ticket = typename arcana::ticketed_collection::ticket; - Ticket AddHandler(Handler&& handler) - { - std::lock_guard guard{m_mutex}; - return m_handlers.insert(handler, m_mutex); - } - - void Fire(Args ... args) - { - std::lock_guard guard{m_mutex}; - for (auto& handler : m_handlers) - { - handler(args ...); - } - } - - private: - std::recursive_mutex m_mutex{}; - arcana::ticketed_collection m_handlers{}; - }; - - using AppStateChangedEvent = Event<>; - AppStateChangedEvent g_pauseEvent{}; - AppStateChangedEvent g_resumeEvent{}; - - using RequestPermissionsResultEvent = Event&, const std::vector&>; - RequestPermissionsResultEvent g_requestPermissionsResultEvent{}; - } - - void Initialize(JavaVM* javaVM, jobject context) - { - g_javaVM = javaVM; - g_appContext = GetEnvForCurrentThread()->NewGlobalRef(android::content::Context{context}.getApplicationContext()); - } - - JNIEnv* GetEnvForCurrentThread() - { - JNIEnv* env{}; - - if (g_javaVM->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6) == JNI_EDETACHED) - { - if (g_javaVM->AttachCurrentThread(&env, nullptr) != 0) { - throw std::runtime_error("Failed to attach JavaScript thread to Java VM"); - } - - g_env.m_attached = true; - } - - return env; - } - - android::content::Context GetAppContext() - { - return {g_appContext}; - } - - android::app::Activity GetCurrentActivity() - { - return {g_currentActivity}; - } - - void SetCurrentActivity(jobject currentActivity) - { - if (g_currentActivity) - { - GetEnvForCurrentThread()->DeleteGlobalRef(g_currentActivity); - } - - g_currentActivity = GetEnvForCurrentThread()->NewGlobalRef(currentActivity); - } - - void Pause() - { - g_pauseEvent.Fire(); - } - - AppStateChangedEvent::Ticket AddPauseCallback(AppStateChangedEvent::Handler&& onPause) - { - return g_pauseEvent.AddHandler(std::move(onPause)); - } - - void Resume() - { - g_resumeEvent.Fire(); - } - - AppStateChangedEvent::Ticket AddResumeCallback(AppStateChangedEvent::Handler&& onResume) - { - return g_resumeEvent.AddHandler(std::move(onResume)); - } - - void RequestPermissionsResult(int32_t requestCode, const std::vector& permissions, const std::vector& grantResults) - { - g_requestPermissionsResultEvent.Fire(requestCode, permissions, grantResults); - } - - RequestPermissionsResultEvent::Ticket AddRequestPermissionsResultCallback(RequestPermissionsResultEvent::Handler&& onAddRequestPermissionsResult) - { - return g_requestPermissionsResultEvent.AddHandler(std::move(onAddRequestPermissionsResult)); - } -} diff --git a/Dependencies/AndroidExtensions/Source/JavaWrappers.cpp b/Dependencies/AndroidExtensions/Source/JavaWrappers.cpp deleted file mode 100644 index 99ace57b1..000000000 --- a/Dependencies/AndroidExtensions/Source/JavaWrappers.cpp +++ /dev/null @@ -1,613 +0,0 @@ -#include -#include -#include -#include -#include -#include - -using namespace android::global; - -namespace -{ - void ThrowIfFaulted(JNIEnv* env) - { - if (env->ExceptionCheck()) - { - auto jthrowable{env->ExceptionOccurred()}; - env->ExceptionClear(); - throw java::lang::Throwable{jthrowable}; - } - } -} - -namespace java::lang -{ - ByteArray::ByteArray(int size) - : m_env{GetEnvForCurrentThread()} - , m_byteArray{m_env->NewByteArray(size)} - { - } - - ByteArray::ByteArray(jbyteArray byteArray) - : m_env{GetEnvForCurrentThread()} - , m_byteArray{byteArray} - { - } - - ByteArray::operator jbyteArray() const - { - return m_byteArray; - } - - ByteArray::operator std::vector() const - { - std::vector result{static_cast(m_env->GetArrayLength(m_byteArray))}; - std::memcpy(result.data(), m_env->GetByteArrayElements(m_byteArray, nullptr), result.size()); - return result; - } - - Class::Class(const char* className) - : m_env{GetEnvForCurrentThread()} - , m_class{static_cast(m_env->NewGlobalRef(m_env->FindClass(className)))} - { - } - - Class::Class(const jclass classObj) - : m_env{GetEnvForCurrentThread()} - , m_class{static_cast(m_env->NewGlobalRef(classObj))} - { - } - - Class::~Class() - { - JClass(nullptr); - } - - Class::Class(const Class& other) - : Class(other.m_class) - { - } - - Class& Class::operator=(const Class& other) - { - if (this != &other) - { - // Clear out the jclass using the current environment before updating to the - // other Class's environment and jclass. The jclass should be used in conjunction - // with the environment it was created in. - JClass(nullptr); - m_env = other.m_env; - JClass(other.JClass()); - } - - return *this; - } - - Class::Class(Class&& other) - : m_env{other.m_env} - , m_class{other.m_class} - { - other.m_class = nullptr; - other.m_env = nullptr; - } - - Class& Class::operator=(Class&& other) - { - m_env = other.m_env; - m_class = other.m_class; - other.m_class = nullptr; - other.m_env = nullptr; - - return *this; - } - - Class::operator jclass() const - { - return m_class; - }; - - bool Class::IsAssignableFrom(Class otherClass) - { - return m_env->IsAssignableFrom(m_class, otherClass.m_class); - }; - - jclass Class::JClass() const - { - return m_class; - } - - void Class::JClass(jclass classObj) - { - if (m_class) { - m_env->DeleteGlobalRef(m_class); - } - - m_class = classObj; - - if (m_class) - { - m_class = static_cast(m_env->NewGlobalRef(classObj)); - } - } - - Object::operator jobject() const - { - return m_object; - } - - Object::Object(const char* className) - : m_env{GetEnvForCurrentThread()} - , m_class{m_env->FindClass(className)} - , m_object{nullptr} - { - } - - Object::Object(jobject object) - : m_env{GetEnvForCurrentThread()} - , m_class{m_env->GetObjectClass(object)} - , m_object{m_env->NewGlobalRef(object)} - { - } - - Object::~Object() - { - JObject(nullptr); - } - - Object::Object(const Object& other) - : Object(other.m_object) - { - } - - Object& Object::operator=(const Object& other) - { - if (this != &other) - { - // Clear out the jobject using the current environment before updating to the - // other Object's environment and jobject. The jobject should be used in conjunction - // with the environment it was created in. - JObject(nullptr); - m_env = other.m_env; - m_class = other.m_class; - JObject(other.m_object); - } - - return *this; - } - - Object::Object(Object&& other) - : m_env{other.m_env} - , m_class{std::move(other.m_class)} - , m_object{other.m_object} - { - other.m_object = nullptr; - other.m_env = nullptr; - } - - Object& Object::operator=(Object&& other) - { - m_env = other.m_env; - m_class = std::move(other.m_class); - m_object = other.m_object; - other.m_object = nullptr; - other.m_env = nullptr; - - return *this; - } - - jobject Object::JObject() const - { - return m_object; - } - - void Object::JObject(jobject object) - { - if (m_object) - { - m_env->DeleteGlobalRef(m_object); - } - - m_object = object; - - if (m_object) - { - m_object = m_env->NewGlobalRef(object); - } - } - - Class Object::GetClass() - { - return m_class; - } - - String::String(jstring string) - : m_env{GetEnvForCurrentThread()} - , m_string{string} - { - } - - String::String(const char* string) - : m_env{GetEnvForCurrentThread()} - , m_string{m_env->NewStringUTF(string)} - { - } - - String::operator jstring() const - { - return m_string; - } - - String::operator std::string() const - { - if (m_string == nullptr) - { - // Java strings can be null, but an std::string cannot be null. - // If there is a possibility that the underlying Java string is null, you should test for that using (jstring != nullptr) before trying to implicitly convert. - throw std::runtime_error("Tried to implicitly convert null Java String to C++ String"); - } - const char* buffer{m_env->GetStringUTFChars(m_string, nullptr)}; - std::string str{buffer}; - m_env->ReleaseStringUTFChars(m_string, buffer); - return str; - } - - Throwable::Throwable(jthrowable throwable) - : Object{throwable} - , m_throwableRef{m_env->NewGlobalRef(throwable)} - , m_message{GetMessage()} - { - } - - Throwable::~Throwable() - { - m_env->DeleteGlobalRef(m_throwableRef); - } - - String Throwable::GetMessage() const - { - return {(jstring)m_env->CallObjectMethod(JObject(), m_env->GetMethodID(m_class, "getMessage", "()Ljava/lang/String;"))}; - } - - const char* Throwable::what() const noexcept - { - return m_message.c_str(); - } -} - -namespace java::io -{ - ByteArrayOutputStream::ByteArrayOutputStream() - : Object{"java/io/ByteArrayOutputStream"} - { - JObject(m_env->NewObject(m_class, m_env->GetMethodID(m_class, "", "()V"))); - } - - ByteArrayOutputStream::ByteArrayOutputStream(int size) - : Object{"java/io/ByteArrayOutputStream"} - { - JObject(m_env->NewObject(m_class, m_env->GetMethodID(m_class, "", "(I)V"), size)); - } - - ByteArrayOutputStream::ByteArrayOutputStream(jobject object) - : Object{object} - { - } - - void ByteArrayOutputStream::Write(lang::ByteArray b, int off, int len) - { - m_env->CallVoidMethod(JObject(), m_env->GetMethodID(m_class, "write", "([BII)V"), (jbyteArray)b, off, len); - } - - lang::ByteArray ByteArrayOutputStream::ToByteArray() const - { - return {(jbyteArray)m_env->CallObjectMethod(JObject(), m_env->GetMethodID(m_class, "toByteArray", "()[B"))}; - } - - lang::String ByteArrayOutputStream::ToString(const char* charsetName) const - { - jmethodID method{m_env->GetMethodID(m_class, "toString", "(Ljava/lang/String;)Ljava/lang/String;")}; - return {(jstring)m_env->CallObjectMethod(JObject(), method, m_env->NewStringUTF(charsetName))}; - } - - InputStream::InputStream(jobject object) - : Object{object} - { - } - - int InputStream::Read(lang::ByteArray byteArray) const - { - return m_env->CallIntMethod(JObject(), m_env->GetMethodID(m_class, "read", "([B)I"), (jbyteArray)byteArray); - } -} - -namespace java::net -{ - HttpURLConnection::HttpURLConnection(jobject object) - : Object{object} - { - } - - lang::Class HttpURLConnection::Class() - { - return {"java/net/HttpURLConnection"}; - } - - int HttpURLConnection::GetResponseCode() const - { - auto responseCode = m_env->CallIntMethod(JObject(), m_env->GetMethodID(m_class, "getResponseCode", "()I")); - ThrowIfFaulted(m_env); - return responseCode; - } - - URL::URL(lang::String url) - : Object{"java/net/URL"} - { - JObject(m_env->NewObject(m_class, m_env->GetMethodID(m_class, "", "(Ljava/lang/String;)V"), (jstring)url)); - ThrowIfFaulted(m_env); - } - - URL::URL(jobject object) - : Object{object} - { - } - - URLConnection URL::OpenConnection() - { - auto urlConnection{m_env->CallObjectMethod(JObject(), m_env->GetMethodID(m_class, "openConnection", "()Ljava/net/URLConnection;"))}; - ThrowIfFaulted(m_env); - return {urlConnection}; - } - - lang::String URL::ToString() - { - auto string{(jstring)m_env->CallObjectMethod(JObject(), m_env->GetMethodID(m_class, "toString", "()Ljava/lang/String;"))}; - ThrowIfFaulted((m_env)); - return {string}; - } - - URLConnection::URLConnection(jobject object) - : Object{object} - { - } - - void URLConnection::Connect() - { - m_env->CallVoidMethod(JObject(), m_env->GetMethodID(m_class, "connect", "()V")); - ThrowIfFaulted(m_env); - } - - URL URLConnection::GetURL() const - { - auto url{m_env->CallObjectMethod(JObject(), m_env->GetMethodID(m_class, "getURL", "()Ljava/net/URL;"))}; - ThrowIfFaulted(m_env); - return {url}; - } - - int URLConnection::GetContentLength() const - { - auto contentLength{m_env->CallIntMethod(JObject(), m_env->GetMethodID(m_class, "getContentLength", "()I"))}; - ThrowIfFaulted(m_env); - return contentLength; - } - - io::InputStream URLConnection::GetInputStream() const - { - auto inputStream{m_env->CallObjectMethod(JObject(), m_env->GetMethodID(m_class, "getInputStream", "()Ljava/io/InputStream;"))}; - ThrowIfFaulted(m_env); - return {inputStream}; - } - - lang::String URLConnection::GetHeaderField(int n) const - { - auto result{(jstring)m_env->CallObjectMethod(JObject(), m_env->GetMethodID(m_class, "getHeaderField", "(I)Ljava/lang/String;"), n)}; - ThrowIfFaulted(m_env); - return {result}; - } - - lang::String URLConnection::GetHeaderFieldKey(int n) const - { - auto result{(jstring)m_env->CallObjectMethod(JObject(), m_env->GetMethodID(m_class, "getHeaderFieldKey", "(I)Ljava/lang/String;"), n)}; - ThrowIfFaulted(m_env); - return {result}; - } - - URLConnection::operator HttpURLConnection() const - { - return {JObject()}; - } -} - -namespace android -{ - jstring ManifestPermission::CAMERA() - { - return getPermissionName("CAMERA"); - } - - jstring ManifestPermission::getPermissionName(const char* permissionName) - { - JNIEnv* env{GetEnvForCurrentThread()}; - jclass cls{env->FindClass("android/Manifest$permission")}; - jfieldID permId{env->GetStaticFieldID(cls, permissionName, "Ljava/lang/String;")}; - return (jstring)env->GetStaticObjectField(cls, permId); - } -} - -namespace android::app -{ - Activity::Activity(jobject object) - : Object{object} - { - } - - void Activity::requestPermissions(jstring systemPermissionName, int permissionRequestID) - { - jobjectArray permissionArray{m_env->NewObjectArray( - 1, - m_env->FindClass("java/lang/String"), - systemPermissionName)}; - m_env->CallVoidMethod(JObject(), m_env->GetMethodID(m_class, "requestPermissions", "([Ljava/lang/String;I)V"), permissionArray, permissionRequestID); - m_env->DeleteLocalRef(permissionArray); - } -} - -namespace android::content -{ - Context::Context(jobject object) - : Object{object} - { - } - - Context Context::getApplicationContext() - { - return {m_env->CallObjectMethod(JObject(), m_env->GetMethodID(m_class, "getApplicationContext", "()Landroid/content/Context;"))}; - } - - res::AssetManager Context::getAssets() const - { - return {m_env->CallObjectMethod(JObject(), m_env->GetMethodID(m_class, "getAssets", "()Landroid/content/res/AssetManager;"))}; - } - - jobject Context::getSystemService(const char* serviceName) - { - return m_env->CallObjectMethod(JObject(), m_env->GetMethodID(m_class, "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;"), m_env->NewStringUTF(serviceName)); - } - - res::Resources Context::getResources() { - return {m_env->CallObjectMethod(JObject(), m_env->GetMethodID(m_class, "getResources", "()Landroid/content/res/Resources;"))}; - } - - bool Context::checkSelfPermission(jstring systemPermissionName) - { - // Get the package manager, and get the value that represents a successful permission grant. - jclass packageManager{m_env->FindClass("android/content/pm/PackageManager")}; - jfieldID permissionGrantedId{m_env->GetStaticFieldID(packageManager, "PERMISSION_GRANTED", "I")}; - jint permissionGrantedValue{m_env->GetStaticIntField(packageManager, permissionGrantedId)}; - - // Perform the actual permission check by checking against the android context object. - jint permissionCheckResult{m_env->CallIntMethod(JObject(), m_env->GetMethodID(m_class, "checkSelfPermission", "(Ljava/lang/String;)I"), systemPermissionName)}; - ThrowIfFaulted(m_env); - return permissionGrantedValue == permissionCheckResult; - } -} - -namespace android::content::res -{ - AssetManager::AssetManager(jobject object) - : Object(object) - { - } - - AssetManager::operator AAssetManager*() const - { - return AAssetManager_fromJava(m_env, JObject()); - } - - Configuration::Configuration(jobject object) - : Object(object) - { - } - - int Configuration::getDensityDpi() - { - return m_env->GetIntField(JObject(), m_env->GetFieldID(m_class, "densityDpi", "I")); - } - - Resources::Resources(jobject object) - : Object(object) - { - } - - Configuration Resources::getConfiguration() - { - return {m_env->CallObjectMethod(JObject(), m_env->GetMethodID(m_class, "getConfiguration", "()Landroid/content/res/Configuration;"))}; - } -} - -namespace android::view -{ - Display::Display(jobject object) - : Object(object) - { - } - - int Display::getRotation() - { - return m_env->CallIntMethod(JObject(), m_env->GetMethodID(m_class, "getRotation", "()I")); - } - - WindowManager::WindowManager(jobject object) - : Object(object) - { - } - - Display WindowManager::getDefaultDisplay() - { - return {m_env->CallObjectMethod(JObject(), m_env->GetMethodID(m_class, "getDefaultDisplay", "()Landroid/view/Display;"))}; - } - - Surface::Surface(android::graphics::SurfaceTexture& surfaceTexture) - : Object("android/view/Surface") - { - JObject(m_env->NewObject(m_class, m_env->GetMethodID(m_class, "", "(Landroid/graphics/SurfaceTexture;)V"), (jobject)surfaceTexture)); - } -} - -namespace android::net -{ - Uri::Uri(jobject object) - : Object{object} - { - } - - java::lang::String Uri::getScheme() const - { - auto scheme{(jstring)m_env->CallObjectMethod(JObject(), m_env->GetMethodID(m_class, "getScheme", "()Ljava/lang/String;"))}; - ThrowIfFaulted(m_env); - return {scheme}; - } - - java::lang::String Uri::getPath() const - { - auto path{(jstring)m_env->CallObjectMethod(JObject(), m_env->GetMethodID(m_class, "getPath", "()Ljava/lang/String;"))}; - ThrowIfFaulted(m_env); - return {path}; - } - - Uri Uri::Parse(java::lang::String uriString) - { - JNIEnv* env{GetEnvForCurrentThread()}; - jclass cls{env->FindClass("android/net/Uri")}; - auto uri{env->CallStaticObjectMethod(cls, env->GetStaticMethodID(cls, "parse", "(Ljava/lang/String;)Landroid/net/Uri;"), (jstring)uriString)}; - ThrowIfFaulted(env); - return {uri}; - } -} - -namespace android::graphics -{ - SurfaceTexture::SurfaceTexture() - : Object("android/graphics/SurfaceTexture") - { - } - - void SurfaceTexture::InitWithTexture(int texture) - { - JObject(m_env->NewObject(m_class, m_env->GetMethodID(m_class, "", "(I)V"), texture)); - } - - void SurfaceTexture::updateTexImage() const - { - if (JObject()) { - m_env->CallVoidMethod(JObject(), m_env->GetMethodID(m_class, "updateTexImage", "()V")); - } - } - - void SurfaceTexture::setDefaultBufferSize(int width, int height) - { - if (JObject()) { - m_env->CallVoidMethod(JObject(), m_env->GetMethodID(m_class, "setDefaultBufferSize", "(II)V"), width, height); - } - } - -} \ No newline at end of file diff --git a/Dependencies/AndroidExtensions/Source/OpenGLHelpers.cpp b/Dependencies/AndroidExtensions/Source/OpenGLHelpers.cpp deleted file mode 100644 index fd7ede562..000000000 --- a/Dependencies/AndroidExtensions/Source/OpenGLHelpers.cpp +++ /dev/null @@ -1,79 +0,0 @@ -#include - -namespace android::OpenGLHelpers -{ - GLuint LoadShader(GLenum shader_type, const char* shader_source) - { - GLuint shader{ glCreateShader(shader_type) }; - if (!shader) - { - throw std::runtime_error{"Failed to create shader"}; - } - - glShaderSource(shader, 1, &shader_source, nullptr); - glCompileShader(shader); - GLint compileStatus{ GL_FALSE }; - glGetShaderiv(shader, GL_COMPILE_STATUS, &compileStatus); - - if (compileStatus != GL_TRUE) - { - GLint infoLogLength{}; - - glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLength); - if (!infoLogLength) - { - throw std::runtime_error{"Unknown error compiling shader"}; - } - - std::string infoLog; - infoLog.resize(static_cast(infoLogLength)); - glGetShaderInfoLog(shader, infoLogLength, nullptr, infoLog.data()); - glDeleteShader(shader); - throw std::runtime_error("Error compiling shader: " + infoLog); - } - - return shader; - } - - GLuint CreateShaderProgram(const char* vertShaderSource, const char* fragShaderSource) - { - GLuint vertShader{ LoadShader(GL_VERTEX_SHADER, vertShaderSource) }; - GLuint fragShader{ LoadShader(GL_FRAGMENT_SHADER, fragShaderSource) }; - - GLuint program{ glCreateProgram() }; - if (!program) - { - throw std::runtime_error{"Failed to create shader program"}; - } - - glAttachShader(program, vertShader); - glAttachShader(program, fragShader); - - glLinkProgram(program); - GLint linkStatus{ GL_FALSE }; - glGetProgramiv(program, GL_LINK_STATUS, &linkStatus); - - glDetachShader(program, vertShader); - glDeleteShader(vertShader); - glDetachShader(program, fragShader); - glDeleteShader(fragShader); - - if (linkStatus != GL_TRUE) - { - GLint infoLogLength{}; - glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLogLength); - if (!infoLogLength) - { - throw std::runtime_error{"Unknown error linking shader program"}; - } - - std::string infoLog; - infoLog.resize(static_cast(infoLogLength)); - glGetProgramInfoLog(program, infoLogLength, nullptr, infoLog.data()); - glDeleteProgram(program); - throw std::runtime_error("Error linking shader program: " + infoLog); - } - - return program; - } -} \ No newline at end of file diff --git a/Dependencies/AndroidExtensions/Source/Permissions.cpp b/Dependencies/AndroidExtensions/Source/Permissions.cpp deleted file mode 100644 index 72cc97a83..000000000 --- a/Dependencies/AndroidExtensions/Source/Permissions.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include -#include - -using namespace android; -using namespace android::global; - -namespace android::Permissions -{ - // Permission request ID used to uniquely identify our request in the callback when calling requestPermissions. - const int PERMISSION_REQUEST_ID{ 8435 }; - - arcana::task CheckCameraPermissionAsync() - { - auto task{ arcana::task_from_result() }; - - // Check if permissions are already granted. - if (!GetAppContext().checkSelfPermission(ManifestPermission::CAMERA())) - { - // Register for the permission callback request. - arcana::task_completion_source permissionTcs; - auto permissionTicket - { - AddRequestPermissionsResultCallback( - [permissionTcs](int32_t requestCode, const std::vector& /*permissionList*/, const std::vector& results) mutable - { - // Check if this is our permission request ID. - if (requestCode == PERMISSION_REQUEST_ID) - { - // If the permission is found and granted complete the task. - if (results[0] == 0 /* PackageManager.PERMISSION_GRANTED */) - { - permissionTcs.complete(); - return; - } - - // Permission was denied. Complete the task with an error. - permissionTcs.complete(arcana::make_unexpected(make_exception_ptr(std::runtime_error{"Camera permission not acquired successfully"}))); - } - }) - }; - - // Kick off the permission check request, and set the task for our caller to wait on. - GetCurrentActivity().requestPermissions(ManifestPermission::CAMERA(), PERMISSION_REQUEST_ID); - task = permissionTcs.as_task().then(arcana::inline_scheduler, arcana::cancellation::none(), [ticket{ std::move(permissionTicket) }](){ - return; - }); - } - - return task; - } -} \ No newline at end of file diff --git a/Dependencies/CMakeLists.txt b/Dependencies/CMakeLists.txt index 9745d4b21..44b69df16 100644 --- a/Dependencies/CMakeLists.txt +++ b/Dependencies/CMakeLists.txt @@ -1,14 +1,3 @@ -# -------------------------------- arcana -------------------------------- -# Dependencies: GSL -add_subdirectory(arcana.cpp) -if(WIN32) - set_property(TARGET arcana PROPERTY FOLDER Dependencies) -endif() - -# -------------------------------- GSL ----------------------------------- -# Dependencies: none -add_subdirectory(arcana.cpp/Source/Submodules/GSL) - # -------------------------------- base-n -------------------------------- # Dependencies: none add_library(base-n INTERFACE) @@ -96,14 +85,6 @@ disable_warnings(OSDependent) disable_warnings(MachineIndependent) disable_warnings(SPIRV) -# -------------------------------- ios-cmake -------------------------------- -# Nothing to do here. - -# -------------------------------- napi -------------------------------- -# Dependencies: none -add_subdirectory(napi) -set_property(TARGET napi PROPERTY FOLDER Dependencies) - # -------------------------------- SPIRV-Cross -------------------------------- # Dependencies: none set(SPIRV_CROSS_CLI OFF CACHE BOOL "") @@ -148,31 +129,11 @@ if(BABYLON_NATIVE_PLUGIN_NATIVEXR AND (WIN32 OR ANDROID OR IOS)) endif() endif() -# -------------------------------- AndroidExtensions -------------------------------- -# Dependencies: none -if(ANDROID) - add_subdirectory(AndroidExtensions) -endif() - -# -------------------------------- UrlLib -------------------------------- -# Dependencies: arcana, AndroidExtensions -if(BABYLON_NATIVE_POLYFILL_XMLHTTPREQUEST) - add_subdirectory(UrlLib) - set_property(TARGET UrlLib PROPERTY FOLDER Dependencies) -endif() - -# --------------------------- v8inspector --------------------------- -# Dependencies: none -# Currently only supported on Win32 x86/x64 and Android -if(NAPI_JAVASCRIPT_ENGINE STREQUAL "V8" AND ((WIN32 AND NOT (WINDOWS_STORE OR CMAKE_GENERATOR_PLATFORM_UPPER MATCHES "ARM.*")) OR ANDROID)) - add_subdirectory(v8inspector) - set_property(TARGET v8inspector PROPERTY FOLDER Dependencies) - set_property(TARGET v8inspector PROPERTY UNITY_BUILD false) - set_property(TARGET llhttp PROPERTY UNITY_BUILD false) -endif() - # --------------------------- WindowsAppSDK --------------------------- # Dependencies: none if(WINDOWS_STORE) add_subdirectory(WindowsAppSDK) endif() + +# --------------------------- NAPI Extensions --------------------------- +add_subdirectory(napi-extensions) diff --git a/Dependencies/UrlLib/CMakeLists.txt b/Dependencies/UrlLib/CMakeLists.txt deleted file mode 100644 index 512a757bc..000000000 --- a/Dependencies/UrlLib/CMakeLists.txt +++ /dev/null @@ -1,47 +0,0 @@ -if(ANDROID) - set(ADDITIONAL_SOURCES - "Source/UrlRequest_Android.cpp") - set(ADDITIONAL_LIBRARIES - PRIVATE AndroidExtensions) -elseif(APPLE) - set(ADDITIONAL_SOURCES - "Source/UrlRequest_Apple.mm") -elseif(UNIX) - set(ADDITIONAL_SOURCES - "Source/UrlRequest_Unix.cpp") - set(ADDITIONAL_LIBRARIES - PRIVATE curl) -elseif(WIN32) - set(ADDITIONAL_SOURCES - "Source/UrlRequest_Windows.cpp") - if(NOT WINDOWS_STORE) - set(ADDITIONAL_LIBRARIES - PUBLIC onecoreuap.lib) - endif() -else() - message(FATAL_ERROR "Unrecognized platform: ${CMAKE_SYSTEM_NAME}") -endif() - -set(SOURCES - "Include/UrlLib/UrlLib.h" - "Source/UrlRequest_Base.h" - "Source/UrlRequest_Shared.h" - ${ADDITIONAL_SOURCES}) - -add_library(UrlLib ${SOURCES}) -warnings_as_errors(UrlLib) - -target_include_directories(UrlLib PUBLIC "Include") -target_include_directories(UrlLib PRIVATE "Source") - -target_link_libraries(UrlLib - PUBLIC arcana - ${ADDITIONAL_LIBRARIES}) - -if(APPLE) - set_target_properties(UrlLib PROPERTIES - XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_ARC YES) - set_property(TARGET UrlLib PROPERTY UNITY_BUILD false) -endif() - -source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${SOURCES}) diff --git a/Dependencies/UrlLib/Include/UrlLib/UrlLib.h b/Dependencies/UrlLib/Include/UrlLib/UrlLib.h deleted file mode 100644 index c10adb85c..000000000 --- a/Dependencies/UrlLib/Include/UrlLib/UrlLib.h +++ /dev/null @@ -1,68 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -namespace UrlLib -{ - enum class UrlStatusCode - { - None = 0, - Ok = 200, - }; - - enum class UrlMethod - { - Get, - }; - - enum class UrlResponseType - { - String, - Buffer, - }; - - class UrlRequest final - { - public: - UrlRequest(); - ~UrlRequest(); - - // Copy semantics - UrlRequest(const UrlRequest&); - UrlRequest& operator=(const UrlRequest&); - - // Move semantics - UrlRequest(UrlRequest&&) noexcept; - UrlRequest& operator=(UrlRequest&&) noexcept; - - void Abort(); - - void Open(UrlMethod method, const std::string& url); - - UrlResponseType ResponseType() const; - - void ResponseType(UrlResponseType value); - - arcana::task SendAsync(); - - UrlStatusCode StatusCode() const; - - std::string_view ResponseUrl() const; - - std::string_view ResponseString() const; - - gsl::span ResponseBuffer() const; - - std::optional GetResponseHeader(const std::string& headerName) const; - - private: - class Impl; - class ImplBase; - - std::shared_ptr m_impl{}; - }; -} diff --git a/Dependencies/UrlLib/Source/UrlRequest_Android.cpp b/Dependencies/UrlLib/Source/UrlRequest_Android.cpp deleted file mode 100644 index bc0f7a50b..000000000 --- a/Dependencies/UrlLib/Source/UrlRequest_Android.cpp +++ /dev/null @@ -1,178 +0,0 @@ -#include "UrlRequest_Base.h" - -#include -#include -#include -#include - -using namespace android::global; -using namespace android::net; -using namespace java::lang; -using namespace java::io; -using namespace java::net; - -namespace UrlLib -{ - namespace - { - template void LoadAsset(AAssetManager* assetManager, const char* url, T& data) - { - AAsset* asset = AAssetManager_open(assetManager, url, AASSET_MODE_UNKNOWN); - if (asset == nullptr) - { - throw std::runtime_error("Failed to open asset"); - } - - data.resize(AAsset_getLength64(asset)); - AAsset_read(asset, data.data(), data.size()); - AAsset_close(asset); - } - } - - class UrlRequest::Impl : public ImplBase - { - public: - void Open(UrlMethod method, const std::string& url) - { - m_method = method; - Uri uri{Uri::Parse(url.data())}; - // If the URL string doesn't contain a scheme, the URI object's scheme will be null. We throw in this case - // The path is never null, even if it's empty it will be an empty string - if ((jstring)uri.getScheme() == nullptr) - { - throw std::runtime_error("Cannot parse a URI without a scheme"); - } - if ((std::string)uri.getScheme() == "app") - { - m_schemeIsApp = true; - m_appPathOrUrl = uri.getPath(); - } - else - { - // Platform API can handle both http:// and file:// schemes - m_schemeIsApp = false; - m_appPathOrUrl = std::move(url); - } - } - - arcana::task SendAsync() - { - return arcana::make_task(arcana::threadpool_scheduler, m_cancellationSource, [this]() - { - try - { - if (m_schemeIsApp) - { - std::string path{m_appPathOrUrl.substr(1)}; - AAssetManager* assetsManager{GetAppContext().getAssets()}; - - switch (m_responseType) - { - case UrlResponseType::String: - { - LoadAsset(assetsManager, path.data(), m_responseString); - break; - } - case UrlResponseType::Buffer: - { - LoadAsset(assetsManager, path.data(), m_responseBuffer); - break; - } - default: - { - throw std::runtime_error{"Invalid response type"}; - } - } - - m_statusCode = UrlStatusCode::Ok; - } - else - { - URL url{m_appPathOrUrl.data()}; - - URLConnection connection{url.OpenConnection()}; - connection.Connect(); - - if (connection.GetClass().IsAssignableFrom(HttpURLConnection::Class())) - { - m_statusCode = static_cast(((HttpURLConnection)connection).GetResponseCode()); - } - else - { - m_statusCode = UrlStatusCode::Ok; - } - - for (int n = 0;; ++n) - { - String key = connection.GetHeaderFieldKey(n); - String value = connection.GetHeaderField(n); - if ((jstring)key == nullptr || (jstring)value == nullptr) - { - break; - } - - std::string lowerCaseKey = key; - ToLower(lowerCaseKey); - - m_headers.insert({lowerCaseKey, value}); - } - - int contentLength = connection.GetContentLength(); - if (contentLength < 0) - { - contentLength = 0; - } - - InputStream inputStream{connection.GetInputStream()}; - ByteArrayOutputStream byteArrayOutputStream{contentLength}; - - ByteArray byteArray{4096}; - int bytesRead{}; - while ((bytesRead = inputStream.Read(byteArray)) != -1) - { - byteArrayOutputStream.Write(byteArray, 0, bytesRead); - } - - switch (m_responseType) - { - case UrlResponseType::String: - { - // TODO: use the charset from the content type? - m_responseString = byteArrayOutputStream.ToString("UTF-8"); - break; - } - case UrlResponseType::Buffer: - { - m_responseBuffer = byteArrayOutputStream.ToByteArray(); - break; - } - default: - { - throw std::runtime_error{"Invalid response type"}; - } - } - - // Must happen after getting the content to get the redirected URL. - m_responseUrl = connection.GetURL().ToString(); - } - } - catch (const Throwable&) - { - // Catch Java exceptions, but retain the default status code of 0 to indicate a client side error. - } - }); - } - - gsl::span ResponseBuffer() const - { - return m_responseBuffer; - } - - private: - bool m_schemeIsApp{}; - std::string m_appPathOrUrl{}; - std::vector m_responseBuffer{}; - }; -} - -#include "UrlRequest_Shared.h" diff --git a/Dependencies/UrlLib/Source/UrlRequest_Apple.mm b/Dependencies/UrlLib/Source/UrlRequest_Apple.mm deleted file mode 100644 index d351b481c..000000000 --- a/Dependencies/UrlLib/Source/UrlRequest_Apple.mm +++ /dev/null @@ -1,129 +0,0 @@ -#if !__has_feature(objc_arc) -#error "ARC is off" -#endif - -#include "UrlRequest_Base.h" - -#import - -namespace -{ - auto URLAllowedCharacterSet = []() - { - NSRange range; - range.location = 0x21; - range.length = 0x7e - range.location + 1; - return [NSCharacterSet characterSetWithRange:range]; - }(); -} - -namespace UrlLib -{ - class UrlRequest::Impl : public ImplBase - { - public: - void Open(UrlMethod method, const std::string& url) - { - m_method = method; - m_url = [NSURL URLWithString:[[NSString stringWithUTF8String:url.data()] stringByAddingPercentEncodingWithAllowedCharacters:URLAllowedCharacterSet]]; - if (!m_url || !m_url.scheme) - { - throw std::runtime_error{"URL does not have a valid scheme"}; - } - NSString* scheme{m_url.scheme}; - if ([scheme isEqual:@"app"]) - { - NSString* path = [[NSBundle mainBundle] pathForResource:[m_url.path substringFromIndex:1] ofType:nil]; - if (path == nil) - { - throw std::runtime_error{"No file exists at local path"}; - } - m_url = [NSURL fileURLWithPath:path]; - } - } - - arcana::task SendAsync() - { - if (m_url == nil) - { - // Complete the task, but retain the default status code of 0 to indicate a client side error. - return arcana::task_from_result(); - } - NSURLSession* session{[NSURLSession sharedSession]}; - NSURLRequest* request{[NSURLRequest requestWithURL:m_url]}; - - __block arcana::task_completion_source taskCompletionSource{}; - - id completionHandler{^(NSData* data, NSURLResponse* response, NSError* error) - { - if (error != nil) - { - // Complete the task, but retain the default status code of 0 to indicate a client side error. - // TODO: Consider logging or otherwise exposing the error message in some way via: [[error localizedDescription] UTF8String] - taskCompletionSource.complete(); - return; - } - - if ([response class] == [NSHTTPURLResponse class]) - { - NSHTTPURLResponse* httpResponse{(NSHTTPURLResponse*)response}; - m_statusCode = static_cast(httpResponse.statusCode); - - for (id key in httpResponse.allHeaderFields) - { - id value = [httpResponse.allHeaderFields objectForKey:key]; - m_headers.insert({ToLower([key UTF8String]), [value UTF8String]}); - } - } - else - { - m_statusCode = UrlStatusCode::Ok; - } - - if (data != nil) - { - switch (m_responseType) - { - case UrlResponseType::String: - { - m_responseString = std::string{static_cast(data.bytes), data.length}; - break; - } - case UrlResponseType::Buffer: - { - m_responseBuffer = data; - break; - } - default: - { - taskCompletionSource.complete(arcana::make_unexpected(std::make_exception_ptr(std::runtime_error{"Invalid response type"}))); - } - } - } - - taskCompletionSource.complete(); - }}; - - NSURLSessionDataTask* task{[session dataTaskWithRequest:request completionHandler:completionHandler]}; - [task resume]; - - return taskCompletionSource.as_task(); - } - - gsl::span ResponseBuffer() const - { - if (m_responseBuffer) - { - return {reinterpret_cast(m_responseBuffer.bytes), m_responseBuffer.length}; - } - - return {}; - } - - private: - NSURL* m_url{}; - NSData* m_responseBuffer{}; - }; -} - -#include "UrlRequest_Shared.h" diff --git a/Dependencies/UrlLib/Source/UrlRequest_Base.h b/Dependencies/UrlLib/Source/UrlRequest_Base.h deleted file mode 100644 index 703b705f8..000000000 --- a/Dependencies/UrlLib/Source/UrlRequest_Base.h +++ /dev/null @@ -1,81 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -namespace UrlLib -{ - class UrlRequest::ImplBase - { - public: - ~ImplBase() - { - Abort(); - } - - void Abort() - { - m_cancellationSource.cancel(); - } - - UrlResponseType ResponseType() const - { - return m_responseType; - } - - void ResponseType(UrlResponseType value) - { - m_responseType = value; - } - - UrlStatusCode StatusCode() const - { - return m_statusCode; - } - - std::string_view ResponseUrl() - { - return m_responseUrl; - } - - std::string_view ResponseString() - { - return m_responseString; - } - - std::optional GetResponseHeader(const std::string& headerName) const - { - const auto it = m_headers.find(ToLower(headerName.data())); - if (it == m_headers.end()) - { - return {}; - } - - return it->second; - } - - protected: - static std::string ToLower(const char* str) - { - std::string s{str}; - std::transform(s.cbegin(), s.cend(), s.begin(), [](auto c) { return static_cast(std::tolower(c)); }); - return s; - } - - static void ToLower(std::string& s) - { - std::transform(s.cbegin(), s.cend(), s.begin(), [](auto c) { return static_cast(std::tolower(c)); }); - } - - arcana::cancellation_source m_cancellationSource{}; - UrlResponseType m_responseType{UrlResponseType::String}; - UrlMethod m_method{UrlMethod::Get}; - UrlStatusCode m_statusCode{UrlStatusCode::None}; - std::string m_responseUrl{}; - std::string m_responseString{}; - std::unordered_map m_headers; - }; -} diff --git a/Dependencies/UrlLib/Source/UrlRequest_Shared.h b/Dependencies/UrlLib/Source/UrlRequest_Shared.h deleted file mode 100644 index d3e9652f1..000000000 --- a/Dependencies/UrlLib/Source/UrlRequest_Shared.h +++ /dev/null @@ -1,69 +0,0 @@ -// Shared pimpl code (not an actual header) - -namespace UrlLib -{ - UrlRequest::UrlRequest() - : m_impl{std::make_unique()} - { - } - - UrlRequest::~UrlRequest() = default; - - // Copy semantics - UrlRequest::UrlRequest(const UrlRequest&) = default; - UrlRequest& UrlRequest::operator=(const UrlRequest&) = default; - - // Move semantics - UrlRequest::UrlRequest(UrlRequest&&) noexcept = default; - UrlRequest& UrlRequest::operator=(UrlRequest&&) noexcept = default; - - void UrlRequest::Abort() - { - m_impl->Abort(); - } - - void UrlRequest::Open(UrlMethod method, const std::string& url) - { - m_impl->Open(method, url); - } - - UrlResponseType UrlRequest::ResponseType() const - { - return m_impl->ResponseType(); - } - - void UrlRequest::ResponseType(UrlResponseType value) - { - m_impl->ResponseType(value); - } - - arcana::task UrlRequest::SendAsync() - { - return m_impl->SendAsync(); - } - - UrlStatusCode UrlRequest::StatusCode() const - { - return m_impl->StatusCode(); - } - - std::string_view UrlRequest::ResponseUrl() const - { - return m_impl->ResponseUrl(); - } - - std::string_view UrlRequest::ResponseString() const - { - return m_impl->ResponseString(); - } - - gsl::span UrlRequest::ResponseBuffer() const - { - return m_impl->ResponseBuffer(); - } - - std::optional UrlRequest::GetResponseHeader(const std::string& headerName) const - { - return m_impl->GetResponseHeader(headerName); - } -} diff --git a/Dependencies/UrlLib/Source/UrlRequest_Unix.cpp b/Dependencies/UrlLib/Source/UrlRequest_Unix.cpp deleted file mode 100644 index f99fbf87a..000000000 --- a/Dependencies/UrlLib/Source/UrlRequest_Unix.cpp +++ /dev/null @@ -1,249 +0,0 @@ -#include "UrlRequest_Base.h" - -#include -#include -#include -#include -#include - -namespace -{ - void curl_check(CURLcode code) - { - if (code != CURLE_OK) - { - throw std::runtime_error{(std::stringstream{} << "CURL call failed with code (" << code << ")").str()}; - } - } - - void curl_check(CURLUcode code) - { - if (code != CURLUE_OK) - { - throw std::runtime_error{(std::stringstream{} << "CURLU call failed with code (" << code << ")").str()}; - } - } -} - -namespace UrlLib -{ - class UrlRequest::Impl : public ImplBase - { - public: - ~Impl() - { - Cleanup(); - } - - void Open(UrlMethod method, const std::string& url) - { - Cleanup(); - - m_method = method; - - m_curl = curl_easy_init(); - if (m_curl) - { - m_curlu = curl_url(); - if (!m_curlu) - { - throw std::runtime_error{"Out of memory"}; - } - - CURLUcode rc = curl_url_set(m_curlu, CURLUPART_URL, url.data(), CURLU_URLENCODE | CURLU_NON_SUPPORT_SCHEME); - if (rc != CURLUE_OK) - { - throw std::runtime_error{"Unable to build URL"}; - } - - char* scheme{}; - auto schemeScope = gsl::finally([&scheme] { curl_free(scheme); }); - if (curl_url_get(m_curlu, CURLUPART_SCHEME, &scheme, 0) == CURLUE_OK) - { - if (std::strcmp(scheme, "app") == 0) - { - curl_check(curl_url_set(m_curlu, CURLUPART_SCHEME, "file", 0)); - - char exe[1024]; - int ret = readlink("/proc/self/exe", exe, std::size(exe) - 1); - if (ret == -1) - { - throw std::runtime_error{"Unable to get executable location"}; - } - exe[ret] = 0; - - char* host{}; - auto hostScope = gsl::finally([&host] { curl_free(host); }); - curl_check(curl_url_get(m_curlu, CURLUPART_HOST, &host, 0)); - - char* path{}; - auto pathScope = gsl::finally([&path] { curl_free(path); }); - curl_check(curl_url_get(m_curlu, CURLUPART_PATH, &path, 0)); - - auto newPath = std::filesystem::path{exe}.parent_path() / host / (path + 1); - curl_check(curl_url_set(m_curlu, CURLUPART_PATH, newPath.generic_u8string().data(), 0)); - - m_file = true; - } - else if (std::strcmp(scheme, "file") == 0) - { - m_file = true; - } - } - - curl_check(curl_easy_setopt(m_curl, CURLOPT_CURLU, m_curlu)); - curl_check(curl_easy_setopt(m_curl, CURLOPT_HEADERDATA, this)); - curl_check(curl_easy_setopt(m_curl, CURLOPT_HEADERFUNCTION, HeaderCallback)); - curl_check(curl_easy_setopt(m_curl, CURLOPT_FOLLOWLOCATION, 1L)); - } - } - - arcana::task SendAsync() - { - switch (m_responseType) - { - case UrlResponseType::String: - { - return PerformAsync(m_responseString); - } - case UrlResponseType::Buffer: - { - return PerformAsync(m_responseBuffer); - } - } - - throw std::runtime_error{"Invalid response type"}; - } - - gsl::span ResponseBuffer() const - { - return m_responseBuffer; - } - - private: - void Cleanup() - { - if (m_thread.has_value()) - { - m_thread->join(); - m_thread = {}; - } - - if (m_curlu) - { - curl_url_cleanup(m_curlu); - m_curlu = nullptr; - } - - if (m_curl) - { - curl_easy_cleanup(m_curl); - m_curl = nullptr; - } - } - - - static void Append(std::string& string, char* buffer, size_t nitems) - { - string.insert(string.end(), buffer, buffer + nitems); - } - - static void Append(std::vector& byteVector, char* buffer, size_t nitems) - { - auto bytes = reinterpret_cast(buffer); - byteVector.insert(byteVector.end(), bytes, bytes + nitems); - } - - template - arcana::task PerformAsync(DataT& data) - { - data.clear(); - - curl_write_callback callback = [](char* buffer, size_t /*size*/, size_t nitems, void* userData) { - auto& data = *static_cast(userData); - Append(data, buffer, nitems); - return nitems; - }; - - curl_check(curl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, callback)); - curl_check(curl_easy_setopt(m_curl, CURLOPT_WRITEDATA, &data)); - - arcana::task_completion_source taskCompletionSource{}; - - m_thread.emplace([this, taskCompletionSource]() mutable - { - curl_check(curl_easy_perform(m_curl)); - - long codep{}; - curl_check(curl_easy_getinfo(m_curl, CURLINFO_RESPONSE_CODE, &codep)); - if (codep == 0 && m_file) - { - // File scheme always returns 0 - m_statusCode = UrlStatusCode::Ok; - } - else - { - m_statusCode = static_cast(codep); - } - - taskCompletionSource.complete(); - }); - - return taskCompletionSource.as_task(); - } - - static size_t HeaderCallback(char* buffer, size_t size, size_t nitems, void* userdata) - { - if (nitems > 0) - { - char* bufferEnd = buffer + nitems; - - char* keyStart = buffer; - char* keyEnd = keyStart; - for (; keyEnd < bufferEnd; ++keyEnd) - { - if (*keyEnd == ':') - { - break; - } - } - - if (keyEnd != bufferEnd) - { - char* valueStart = keyEnd + 1; - for (; valueStart < bufferEnd; ++valueStart) - { - if (*valueStart != ' ') - { - break; - } - } - - char* valueEnd = bufferEnd; - for (; valueEnd - 1 >= valueStart; --valueEnd) - { - auto ch = *(valueEnd - 1); - if (ch != '\r' && ch != '\n' && ch != ' ') - { - break; - } - } - - std::string key{keyStart, keyEnd}; - std::string value{valueStart, valueEnd}; - static_cast(userdata)->m_headers.insert({std::move(key), std::move(value)}); - } - } - - return nitems * size; - } - - std::vector m_responseBuffer{}; - CURL* m_curl{}; - CURLU* m_curlu{}; - bool m_file{}; - std::optional m_thread{}; - }; -} - -#include "UrlRequest_Shared.h" diff --git a/Dependencies/UrlLib/Source/UrlRequest_Windows.cpp b/Dependencies/UrlLib/Source/UrlRequest_Windows.cpp deleted file mode 100644 index 080029473..000000000 --- a/Dependencies/UrlLib/Source/UrlRequest_Windows.cpp +++ /dev/null @@ -1,184 +0,0 @@ -#include "UrlRequest_Base.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace UrlLib -{ - using namespace winrt::Windows; - - namespace - { - Web::Http::HttpMethod ConvertHttpMethod(UrlMethod method) - { - switch (method) - { - case UrlMethod::Get: - return Web::Http::HttpMethod::Get(); - default: - throw std::runtime_error("Unsupported method"); - } - } - - winrt::hstring GetInstalledLocation() - { -#ifdef WIN32 - WCHAR modulePath[4096]; - DWORD result{::GetModuleFileNameW(nullptr, modulePath, ARRAYSIZE(modulePath))}; - winrt::check_bool(result != 0 && result != std::size(modulePath)); - winrt::check_hresult(PathCchRemoveFileSpec(modulePath, ARRAYSIZE(modulePath))); - return modulePath; -#else - return ApplicationModel::Package::Current().InstalledLocation().Path; -#endif - } - - std::wstring GetLocalPath(Foundation::Uri url) - { - std::wstring path{std::wstring_view{Foundation::Uri::UnescapeComponent(url.Path())}.substr(1)}; - std::replace(path.begin(), path.end(), '/', '\\'); - return std::move(path); - } - } - - class UrlRequest::Impl : public ImplBase - { - public: - void Open(UrlMethod method, const std::string& url) - { - m_method = method; - m_uri = Foundation::Uri{winrt::to_hstring(url)}; - } - - arcana::task SendAsync() - { - try - { - if (m_uri.SchemeName() == L"app") - { - return arcana::create_task(Storage::StorageFolder::GetFolderFromPathAsync(GetInstalledLocation())) - .then(arcana::inline_scheduler, m_cancellationSource, [this, m_uri{m_uri}](Storage::StorageFolder folder) { - return arcana::create_task(folder.GetFileAsync(GetLocalPath(m_uri))); - }) - .then(arcana::inline_scheduler, m_cancellationSource, [this](Storage::StorageFile file) { - return LoadFileAsync(file); - }); - } - else if (m_uri.SchemeName() == L"file") - { - return arcana::create_task(Storage::StorageFile::GetFileFromPathAsync(GetLocalPath(m_uri))) - .then(arcana::inline_scheduler, m_cancellationSource, [this](Storage::StorageFile file) { - return LoadFileAsync(file); - }); - } - else - { - Web::Http::HttpRequestMessage requestMessage; - requestMessage.RequestUri(m_uri); - requestMessage.Method(ConvertHttpMethod(m_method)); - - Web::Http::HttpClient client; - return arcana::create_task(client.SendRequestAsync(requestMessage)) - .then(arcana::inline_scheduler, m_cancellationSource, [this](Web::Http::HttpResponseMessage responseMessage) - { - m_statusCode = static_cast(responseMessage.StatusCode()); - if (!responseMessage.IsSuccessStatusCode()) - { - return arcana::task_from_result(); - } - - m_responseUrl = winrt::to_string(responseMessage.RequestMessage().RequestUri().RawUri()); - - for (auto&& iter : responseMessage.Headers()) - { - m_headers.insert(std::make_pair(winrt::to_string(iter.Key()), winrt::to_string(iter.Value()))); - } - - switch (m_responseType) - { - case UrlResponseType::String: - { - return arcana::create_task(responseMessage.Content().ReadAsStringAsync()) - .then(arcana::inline_scheduler, m_cancellationSource, [this](winrt::hstring string) - { - m_responseString = winrt::to_string(string); - m_statusCode = UrlStatusCode::Ok; - }); - } - case UrlResponseType::Buffer: - { - return arcana::create_task(responseMessage.Content().ReadAsBufferAsync()) - .then(arcana::inline_scheduler, m_cancellationSource, [this](Storage::Streams::IBuffer buffer) - { - m_responseBuffer = std::move(buffer); - m_statusCode = UrlStatusCode::Ok; - }); - } - default: - { - throw std::runtime_error{"Invalid response type"}; - } - } - }); - } - } - catch (winrt::hresult_error) - { - // Catch WinRT exceptions, but retain the default status code of 0 to indicate a client side error. - return arcana::task_from_result(); - } - } - - gsl::span ResponseBuffer() const - { - if (!m_responseBuffer) - { - return {}; - } - - std::byte* bytes; - auto bufferByteAccess = m_responseBuffer.as<::Windows::Storage::Streams::IBufferByteAccess>(); - winrt::check_hresult(bufferByteAccess->Buffer(reinterpret_cast(&bytes))); - return {bytes, gsl::narrow_cast(m_responseBuffer.Length())}; - } - - private: - arcana::task LoadFileAsync(Storage::StorageFile file) - { - switch (m_responseType) - { - case UrlResponseType::String: - { - return arcana::create_task(Storage::FileIO::ReadTextAsync(file)) - .then(arcana::inline_scheduler, m_cancellationSource, [this](winrt::hstring text) { - m_responseString = winrt::to_string(text); - m_statusCode = UrlStatusCode::Ok; - }); - } - case UrlResponseType::Buffer: - { - return arcana::create_task(Storage::FileIO::ReadBufferAsync(file)) - .then(arcana::inline_scheduler, m_cancellationSource, [this](Storage::Streams::IBuffer buffer) { - m_responseBuffer = std::move(buffer); - m_statusCode = UrlStatusCode::Ok; - }); - } - default: - { - throw std::runtime_error{"Invalid response type"}; - } - } - } - - Foundation::Uri m_uri{nullptr}; - Storage::Streams::IBuffer m_responseBuffer{}; - }; -} - -#include "UrlRequest_Shared.h" diff --git a/Dependencies/arcana.cpp b/Dependencies/arcana.cpp deleted file mode 160000 index 74b539f47..000000000 --- a/Dependencies/arcana.cpp +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 74b539f474a7a85c2be8f7b3b8ac8303ce176cb4 diff --git a/Dependencies/ios-cmake b/Dependencies/ios-cmake deleted file mode 160000 index 87c2d9f35..000000000 --- a/Dependencies/ios-cmake +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 87c2d9f351250b5eeaccbdc3303ff19311bd83b0 diff --git a/Dependencies/napi/napi-extensions/CMakeLists.txt b/Dependencies/napi-extensions/CMakeLists.txt similarity index 100% rename from Dependencies/napi/napi-extensions/CMakeLists.txt rename to Dependencies/napi-extensions/CMakeLists.txt diff --git a/Dependencies/napi/napi-extensions/include/napi/napi_pointer.h b/Dependencies/napi-extensions/include/napi/napi_pointer.h similarity index 100% rename from Dependencies/napi/napi-extensions/include/napi/napi_pointer.h rename to Dependencies/napi-extensions/include/napi/napi_pointer.h diff --git a/Dependencies/napi/CMakeLists.txt b/Dependencies/napi/CMakeLists.txt deleted file mode 100644 index 97667b4a8..000000000 --- a/Dependencies/napi/CMakeLists.txt +++ /dev/null @@ -1,32 +0,0 @@ -cmake_minimum_required(VERSION 3.12) - -project(napi) - -# Set per-platform defaults if no JS engine is set. -if (WIN32) - set(NAPI_JAVASCRIPT_ENGINE "Chakra" CACHE STRING "JavaScript engine for N-API.") -elseif (ANDROID) - # engine is selected in native build cmakelists.txt -elseif (APPLE) - set(NAPI_JAVASCRIPT_ENGINE "JavaScriptCore" CACHE STRING "JavaScript engine for N-API.") -elseif (UNIX) - set(NAPI_JAVASCRIPT_ENGINE "V8" CACHE STRING "JavaScript engine for N-API.") -else() - message(FATAL_ERROR "Unable to select N-API JavaScript engine for platform.") -endif() - -# Check that the requested JavaScript engine is supported. -set(SUPPORTED_JAVASCRIPT_ENGINES "Chakra" "V8" "JavaScriptCore" "JSI") -if(NOT NAPI_JAVASCRIPT_ENGINE IN_LIST SUPPORTED_JAVASCRIPT_ENGINES) - message(FATAL_ERROR "Unsupported engine: ${NAPI_JAVASCRIPT_ENGINE}") -endif() - -if(NAPI_JAVASCRIPT_ENGINE STREQUAL "JSI") - add_subdirectory(napi-jsi) -else() - add_subdirectory(napi-direct) -endif() - -add_subdirectory(napi-extensions) - -add_on_linked_as_dependency_cmake_file(napi "${CMAKE_CURRENT_SOURCE_DIR}/OnLinkedAsDependency.cmake") \ No newline at end of file diff --git a/Dependencies/napi/OnLinkedAsDependency.cmake b/Dependencies/napi/OnLinkedAsDependency.cmake deleted file mode 100644 index 497402d6a..000000000 --- a/Dependencies/napi/OnLinkedAsDependency.cmake +++ /dev/null @@ -1,31 +0,0 @@ -# Callback to perform custom behavior -- in this case, copying runtime output artifacts like DLLs -- when -# linked from an executable target as a library. -function(on_linked_as_dependency target) - # Propagate this file to the target so that it will be transitively available to targets that - # link to that one, too. - propagate_on_linked_as_dependency_cmake_file(napi ${target}) - if (DEFINED NAPI_JAVASCRIPT_RUNTIME_OUTPUT_ARTIFACTS) - # We only need to actually copy files if we're being linked from an executable. - get_target_property(type ${target} TYPE) - if(${type} STREQUAL "EXECUTABLE") - if (WINDOWS_STORE) - # WINDOWS_STORE allows us to use the VS_DEPLOYMENT_CONTENT property. - target_sources(${target} PRIVATE ${NAPI_JAVASCRIPT_RUNTIME_OUTPUT_ARTIFACTS}) - - if ((DEFINED NAPI_JAVASCRIPT_RUNTIME_OUTPUT_ARTIFACTS_DEBUG) AND (DEFINED NAPI_JAVASCRIPT_RUNTIME_OUTPUT_ARTIFACTS_RELEASE)) - set_property(SOURCE ${NAPI_JAVASCRIPT_RUNTIME_OUTPUT_ARTIFACTS_DEBUG} PROPERTY VS_DEPLOYMENT_CONTENT $) - set_property(SOURCE ${NAPI_JAVASCRIPT_RUNTIME_OUTPUT_ARTIFACTS_RELEASE} PROPERTY VS_DEPLOYMENT_CONTENT $>) - else() - set_property(SOURCE ${NAPI_JAVASCRIPT_RUNTIME_OUTPUT_ARTIFACTS} PROPERTY VS_DEPLOYMENT_CONTENT 1) - endif() - - set_property(SOURCE ${NAPI_JAVASCRIPT_RUNTIME_OUTPUT_ARTIFACTS} PROPERTY VS_DEPLOYMENT_LOCATION ".") - else() - # Without the VS_DEPLOYMENT_CONTENT property, create custom rules to copy the artifacts. - foreach(artifact ${NAPI_JAVASCRIPT_RUNTIME_OUTPUT_ARTIFACTS}) - add_custom_command(TARGET ${target} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different ${artifact} $) - endforeach() - endif() - endif() - endif() -endfunction() \ No newline at end of file diff --git a/Dependencies/napi/napi-direct/CMakeLists.txt b/Dependencies/napi/napi-direct/CMakeLists.txt deleted file mode 100644 index 978b7a12a..000000000 --- a/Dependencies/napi/napi-direct/CMakeLists.txt +++ /dev/null @@ -1,88 +0,0 @@ -STRING(TOLOWER ${NAPI_JAVASCRIPT_ENGINE} ENGINE_FILE_POSTFIX) - -set(SOURCES - "include/napi/env.h" - "include/napi/js_native_api.h" - "include/napi/js_native_api_types.h" - "include/napi/napi.h" - "include/napi/napi-inl.h" - "source/env.cc" - "source/env_${ENGINE_FILE_POSTFIX}.cc" - "source/js_native_api_${ENGINE_FILE_POSTFIX}.cc" - "source/js_native_api_${ENGINE_FILE_POSTFIX}.h" - "source/js_native_api_${ENGINE_FILE_POSTFIX}_internals.h") - -add_library(napi ${SOURCES}) - -target_compile_definitions(napi PRIVATE NOMINMAX) -target_compile_definitions(napi PRIVATE _CRT_SECURE_NO_WARNINGS) - -target_compile_definitions(napi PUBLIC NODE_ADDON_API_DISABLE_DEPRECATED) -target_compile_definitions(napi PUBLIC NODE_ADDON_API_DISABLE_NODE_SPECIFIC) - -if(NAPI_JAVASCRIPT_ENGINE STREQUAL "Chakra") - target_compile_definitions(napi PUBLIC USE_EDGEMODE_JSRT) -endif() - -target_include_directories(napi PUBLIC "include") - -# Install v8 SDK from NuGet -function (install_v8_nuget V8_VERSION ARCH) - download_nuget() - set(V8_PACKAGE_PATH "${NUGET_PATH}/packages/v8-v142-${ARCH}.${V8_VERSION}") - set(V8_REDIST_PACKAGE_PATH "${NUGET_PATH}/packages/v8.redist-v142-${ARCH}.${V8_VERSION}") - - add_library(v8_libbase SHARED IMPORTED) - set_target_properties(v8_libbase PROPERTIES IMPORTED_IMPLIB "${V8_PACKAGE_PATH}/lib/Release/v8_libbase.dll.lib") - add_library(v8_libplatform SHARED IMPORTED) - set_target_properties(v8_libplatform PROPERTIES IMPORTED_IMPLIB "${V8_PACKAGE_PATH}/lib/Release/v8_libplatform.dll.lib") - add_library(v8 SHARED IMPORTED) - set_target_properties(v8 PROPERTIES IMPORTED_IMPLIB "${V8_PACKAGE_PATH}/lib/Release/v8.dll.lib") - target_link_libraries(v8 INTERFACE v8_libbase INTERFACE v8_libplatform) - target_include_directories(v8 INTERFACE "${V8_PACKAGE_PATH}/include") - - set(NAPI_JAVASCRIPT_RUNTIME_OUTPUT_ARTIFACTS - "${V8_REDIST_PACKAGE_PATH}/lib/Release/icudtl.dat" - "${V8_REDIST_PACKAGE_PATH}/lib/Release/icui18n.dll" - "${V8_REDIST_PACKAGE_PATH}/lib/Release/icuuc.dll" - "${V8_REDIST_PACKAGE_PATH}/lib/Release/v8.dll" - "${V8_REDIST_PACKAGE_PATH}/lib/Release/v8_libbase.dll" - "${V8_REDIST_PACKAGE_PATH}/lib/Release/v8_libplatform.dll" - "${V8_REDIST_PACKAGE_PATH}/lib/Release/zlib.dll" - CACHE STRING "N-API runtime output artifacts") -endfunction() - -if(NOT TARGET javascript_engine) - add_library(javascript_engine INTERFACE) - if(NAPI_JAVASCRIPT_ENGINE STREQUAL "V8") - if(WIN32) - set_cpu_platform_arch() - set(V8_VERSION "8.4.371.15") - install_v8_nuget(${V8_VERSION} ${CPU_ARCH}) - target_link_to_dependencies(javascript_engine INTERFACE v8) - - if (CPU_ARCH STREQUAL "x64") - # Enable V8 Pointer Compression - # https://v8.dev/blog/pointer-compression - # https://stackoverflow.com/q/62921373 - target_compile_definitions(javascript_engine INTERFACE V8_COMPRESS_POINTERS) - endif() - elseif(UNIX AND NOT ANDROID AND NOT APPLE) - target_include_directories(napi PUBLIC "/usr/include/v8") - find_library(V8_LIBRARY v8) - target_link_to_dependencies(javascript_engine INTERFACE ${V8_LIBRARY}) - endif() - elseif(NAPI_JAVASCRIPT_ENGINE STREQUAL "Chakra") - target_link_to_dependencies(javascript_engine INTERFACE "chakrart.lib") - - elseif(NAPI_JAVASCRIPT_ENGINE STREQUAL "JavaScriptCore") - if(UNIX AND NOT ANDROID AND NOT APPLE) - target_include_directories(napi PUBLIC "/usr/include/webkitgtk-4.0") - find_library(JSCORE_LIBRARY JavaScriptCore) - target_link_to_dependencies(javascript_engine INTERFACE ${JSCORE_LIBRARY}) - endif() - endif() -endif() -target_link_to_dependencies(napi PUBLIC javascript_engine) - -source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${SOURCES}) diff --git a/Dependencies/napi/napi-direct/include/napi/env.h b/Dependencies/napi/napi-direct/include/napi/env.h deleted file mode 100644 index c138a96ec..000000000 --- a/Dependencies/napi/napi-direct/include/napi/env.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -#include "napi.h" - -namespace Napi -{ - template Napi::Env Attach(Ts... args); - - void Detach(Napi::Env); - - Napi::Value Eval(Napi::Env env, const char* source, const char* sourceUrl); - - template T GetContext(Napi::Env env); -} diff --git a/Dependencies/napi/napi-direct/include/napi/js_native_api.h b/Dependencies/napi/napi-direct/include/napi/js_native_api.h deleted file mode 100644 index 632ee9f42..000000000 --- a/Dependencies/napi/napi-direct/include/napi/js_native_api.h +++ /dev/null @@ -1,486 +0,0 @@ -#ifndef SRC_JS_NATIVE_API_H_ -#define SRC_JS_NATIVE_API_H_ - -#include -#include -#include "js_native_api_types.h" - -#ifndef NAPI_VERSION -#ifdef NAPI_EXPERIMENTAL -// Use INT_MAX, this should only be consumed by the pre-processor anyway. -#define NAPI_VERSION 2147483647 -#else -// The baseline version for N-API -#define NAPI_VERSION 3 -#endif -#endif - -// If you need __declspec(dllimport), either include instead, or -// define NAPI_EXTERN as __declspec(dllimport) on the compiler's command line. -#ifndef NAPI_EXTERN - #ifdef _WIN32 - #define NAPI_EXTERN __declspec(dllexport) - #else - #define NAPI_EXTERN /* nothing */ - #endif -#endif - -#define NAPI_AUTO_LENGTH SIZE_MAX - -#ifdef __cplusplus -#define EXTERN_C_START extern "C" { -#define EXTERN_C_END } -#else -#define EXTERN_C_START -#define EXTERN_C_END -#endif - -EXTERN_C_START - -NAPI_EXTERN napi_status -napi_get_last_error_info(napi_env env, - const napi_extended_error_info** result); - -// Getters for defined singletons -NAPI_EXTERN napi_status napi_get_undefined(napi_env env, napi_value* result); -NAPI_EXTERN napi_status napi_get_null(napi_env env, napi_value* result); -NAPI_EXTERN napi_status napi_get_global(napi_env env, napi_value* result); -NAPI_EXTERN napi_status napi_get_boolean(napi_env env, - bool value, - napi_value* result); - -// Methods to create Primitive types/Objects -NAPI_EXTERN napi_status napi_create_object(napi_env env, napi_value* result); -NAPI_EXTERN napi_status napi_create_array(napi_env env, napi_value* result); -NAPI_EXTERN napi_status napi_create_array_with_length(napi_env env, - size_t length, - napi_value* result); -NAPI_EXTERN napi_status napi_create_double(napi_env env, - double value, - napi_value* result); -NAPI_EXTERN napi_status napi_create_int32(napi_env env, - int32_t value, - napi_value* result); -NAPI_EXTERN napi_status napi_create_uint32(napi_env env, - uint32_t value, - napi_value* result); -NAPI_EXTERN napi_status napi_create_int64(napi_env env, - int64_t value, - napi_value* result); -NAPI_EXTERN napi_status napi_create_string_latin1(napi_env env, - const char* str, - size_t length, - napi_value* result); -NAPI_EXTERN napi_status napi_create_string_utf8(napi_env env, - const char* str, - size_t length, - napi_value* result); -NAPI_EXTERN napi_status napi_create_string_utf16(napi_env env, - const char16_t* str, - size_t length, - napi_value* result); -NAPI_EXTERN napi_status napi_create_symbol(napi_env env, - napi_value description, - napi_value* result); -NAPI_EXTERN napi_status napi_create_function(napi_env env, - const char* utf8name, - size_t length, - napi_callback cb, - void* data, - napi_value* result); -NAPI_EXTERN napi_status napi_create_error(napi_env env, - napi_value code, - napi_value msg, - napi_value* result); -NAPI_EXTERN napi_status napi_create_type_error(napi_env env, - napi_value code, - napi_value msg, - napi_value* result); -NAPI_EXTERN napi_status napi_create_range_error(napi_env env, - napi_value code, - napi_value msg, - napi_value* result); - -// Methods to get the native napi_value from Primitive type -NAPI_EXTERN napi_status napi_typeof(napi_env env, - napi_value value, - napi_valuetype* result); -NAPI_EXTERN napi_status napi_get_value_double(napi_env env, - napi_value value, - double* result); -NAPI_EXTERN napi_status napi_get_value_int32(napi_env env, - napi_value value, - int32_t* result); -NAPI_EXTERN napi_status napi_get_value_uint32(napi_env env, - napi_value value, - uint32_t* result); -NAPI_EXTERN napi_status napi_get_value_int64(napi_env env, - napi_value value, - int64_t* result); -NAPI_EXTERN napi_status napi_get_value_bool(napi_env env, - napi_value value, - bool* result); - -// Copies LATIN-1 encoded bytes from a string into a buffer. -NAPI_EXTERN napi_status napi_get_value_string_latin1(napi_env env, - napi_value value, - char* buf, - size_t bufsize, - size_t* result); - -// Copies UTF-8 encoded bytes from a string into a buffer. -NAPI_EXTERN napi_status napi_get_value_string_utf8(napi_env env, - napi_value value, - char* buf, - size_t bufsize, - size_t* result); - -// Copies UTF-16 encoded bytes from a string into a buffer. -NAPI_EXTERN napi_status napi_get_value_string_utf16(napi_env env, - napi_value value, - char16_t* buf, - size_t bufsize, - size_t* result); - -// Methods to coerce values -// These APIs may execute user scripts -NAPI_EXTERN napi_status napi_coerce_to_bool(napi_env env, - napi_value value, - napi_value* result); -NAPI_EXTERN napi_status napi_coerce_to_number(napi_env env, - napi_value value, - napi_value* result); -NAPI_EXTERN napi_status napi_coerce_to_object(napi_env env, - napi_value value, - napi_value* result); -NAPI_EXTERN napi_status napi_coerce_to_string(napi_env env, - napi_value value, - napi_value* result); - -// Methods to work with Objects -NAPI_EXTERN napi_status napi_get_prototype(napi_env env, - napi_value object, - napi_value* result); -NAPI_EXTERN napi_status napi_get_property_names(napi_env env, - napi_value object, - napi_value* result); -NAPI_EXTERN napi_status napi_set_property(napi_env env, - napi_value object, - napi_value key, - napi_value value); -NAPI_EXTERN napi_status napi_has_property(napi_env env, - napi_value object, - napi_value key, - bool* result); -NAPI_EXTERN napi_status napi_get_property(napi_env env, - napi_value object, - napi_value key, - napi_value* result); -NAPI_EXTERN napi_status napi_delete_property(napi_env env, - napi_value object, - napi_value key, - bool* result); -NAPI_EXTERN napi_status napi_has_own_property(napi_env env, - napi_value object, - napi_value key, - bool* result); -NAPI_EXTERN napi_status napi_set_named_property(napi_env env, - napi_value object, - const char* utf8name, - napi_value value); -NAPI_EXTERN napi_status napi_has_named_property(napi_env env, - napi_value object, - const char* utf8name, - bool* result); -NAPI_EXTERN napi_status napi_get_named_property(napi_env env, - napi_value object, - const char* utf8name, - napi_value* result); -NAPI_EXTERN napi_status napi_set_element(napi_env env, - napi_value object, - uint32_t index, - napi_value value); -NAPI_EXTERN napi_status napi_has_element(napi_env env, - napi_value object, - uint32_t index, - bool* result); -NAPI_EXTERN napi_status napi_get_element(napi_env env, - napi_value object, - uint32_t index, - napi_value* result); -NAPI_EXTERN napi_status napi_delete_element(napi_env env, - napi_value object, - uint32_t index, - bool* result); -NAPI_EXTERN napi_status -napi_define_properties(napi_env env, - napi_value object, - size_t property_count, - const napi_property_descriptor* properties); - -// Methods to work with Arrays -NAPI_EXTERN napi_status napi_is_array(napi_env env, - napi_value value, - bool* result); -NAPI_EXTERN napi_status napi_get_array_length(napi_env env, - napi_value value, - uint32_t* result); - -// Methods to compare values -NAPI_EXTERN napi_status napi_strict_equals(napi_env env, - napi_value lhs, - napi_value rhs, - bool* result); - -// Methods to work with Functions -NAPI_EXTERN napi_status napi_call_function(napi_env env, - napi_value recv, - napi_value func, - size_t argc, - const napi_value* argv, - napi_value* result); -NAPI_EXTERN napi_status napi_new_instance(napi_env env, - napi_value constructor, - size_t argc, - const napi_value* argv, - napi_value* result); -NAPI_EXTERN napi_status napi_instanceof(napi_env env, - napi_value object, - napi_value constructor, - bool* result); - -// Methods to work with napi_callbacks - -// Gets all callback info in a single call. (Ugly, but faster.) -NAPI_EXTERN napi_status napi_get_cb_info( - napi_env env, // [in] NAPI environment handle - napi_callback_info cbinfo, // [in] Opaque callback-info handle - size_t* argc, // [in-out] Specifies the size of the provided argv array - // and receives the actual count of args. - napi_value* argv, // [out] Array of values - napi_value* this_arg, // [out] Receives the JS 'this' arg for the call - void** data); // [out] Receives the data pointer for the callback. - -NAPI_EXTERN napi_status napi_get_new_target(napi_env env, - napi_callback_info cbinfo, - napi_value* result); -NAPI_EXTERN napi_status -napi_define_class(napi_env env, - const char* utf8name, - size_t length, - napi_callback constructor, - void* data, - size_t property_count, - const napi_property_descriptor* properties, - napi_value* result); - -// Methods to work with external data objects -NAPI_EXTERN napi_status napi_wrap(napi_env env, - napi_value js_object, - void* native_object, - napi_finalize finalize_cb, - void* finalize_hint, - napi_ref* result); -NAPI_EXTERN napi_status napi_unwrap(napi_env env, - napi_value js_object, - void** result); -NAPI_EXTERN napi_status napi_remove_wrap(napi_env env, - napi_value js_object, - void** result); -NAPI_EXTERN napi_status napi_create_external(napi_env env, - void* data, - napi_finalize finalize_cb, - void* finalize_hint, - napi_value* result); -NAPI_EXTERN napi_status napi_get_value_external(napi_env env, - napi_value value, - void** result); - -// Methods to control object lifespan - -// Set initial_refcount to 0 for a weak reference, >0 for a strong reference. -NAPI_EXTERN napi_status napi_create_reference(napi_env env, - napi_value value, - uint32_t initial_refcount, - napi_ref* result); - -// Deletes a reference. The referenced value is released, and may -// be GC'd unless there are other references to it. -NAPI_EXTERN napi_status napi_delete_reference(napi_env env, napi_ref ref); - -// Increments the reference count, optionally returning the resulting count. -// After this call the reference will be a strong reference because its -// refcount is >0, and the referenced object is effectively "pinned". -// Calling this when the refcount is 0 and the object is unavailable -// results in an error. -NAPI_EXTERN napi_status napi_reference_ref(napi_env env, - napi_ref ref, - uint32_t* result); - -// Decrements the reference count, optionally returning the resulting count. -// If the result is 0 the reference is now weak and the object may be GC'd -// at any time if there are no other references. Calling this when the -// refcount is already 0 results in an error. -NAPI_EXTERN napi_status napi_reference_unref(napi_env env, - napi_ref ref, - uint32_t* result); - -// Attempts to get a referenced value. If the reference is weak, -// the value might no longer be available, in that case the call -// is still successful but the result is NULL. -NAPI_EXTERN napi_status napi_get_reference_value(napi_env env, - napi_ref ref, - napi_value* result); - -NAPI_EXTERN napi_status napi_open_handle_scope(napi_env env, - napi_handle_scope* result); -NAPI_EXTERN napi_status napi_close_handle_scope(napi_env env, - napi_handle_scope scope); -NAPI_EXTERN napi_status -napi_open_escapable_handle_scope(napi_env env, - napi_escapable_handle_scope* result); -NAPI_EXTERN napi_status -napi_close_escapable_handle_scope(napi_env env, - napi_escapable_handle_scope scope); - -NAPI_EXTERN napi_status napi_escape_handle(napi_env env, - napi_escapable_handle_scope scope, - napi_value escapee, - napi_value* result); - -// Methods to support error handling -NAPI_EXTERN napi_status napi_throw(napi_env env, napi_value error); -NAPI_EXTERN napi_status napi_throw_error(napi_env env, - const char* code, - const char* msg); -NAPI_EXTERN napi_status napi_throw_type_error(napi_env env, - const char* code, - const char* msg); -NAPI_EXTERN napi_status napi_throw_range_error(napi_env env, - const char* code, - const char* msg); -NAPI_EXTERN napi_status napi_is_error(napi_env env, - napi_value value, - bool* result); - -// Methods to support catching exceptions -NAPI_EXTERN napi_status napi_is_exception_pending(napi_env env, bool* result); -NAPI_EXTERN napi_status napi_get_and_clear_last_exception(napi_env env, - napi_value* result); - -// Methods to work with array buffers and typed arrays -NAPI_EXTERN napi_status napi_is_arraybuffer(napi_env env, - napi_value value, - bool* result); -NAPI_EXTERN napi_status napi_create_arraybuffer(napi_env env, - size_t byte_length, - void** data, - napi_value* result); -NAPI_EXTERN napi_status -napi_create_external_arraybuffer(napi_env env, - void* external_data, - size_t byte_length, - napi_finalize finalize_cb, - void* finalize_hint, - napi_value* result); -NAPI_EXTERN napi_status napi_get_arraybuffer_info(napi_env env, - napi_value arraybuffer, - void** data, - size_t* byte_length); -NAPI_EXTERN napi_status napi_is_typedarray(napi_env env, - napi_value value, - bool* result); -NAPI_EXTERN napi_status napi_create_typedarray(napi_env env, - napi_typedarray_type type, - size_t length, - napi_value arraybuffer, - size_t byte_offset, - napi_value* result); -NAPI_EXTERN napi_status napi_get_typedarray_info(napi_env env, - napi_value typedarray, - napi_typedarray_type* type, - size_t* length, - void** data, - napi_value* arraybuffer, - size_t* byte_offset); - -NAPI_EXTERN napi_status napi_create_dataview(napi_env env, - size_t length, - napi_value arraybuffer, - size_t byte_offset, - napi_value* result); -NAPI_EXTERN napi_status napi_is_dataview(napi_env env, - napi_value value, - bool* result); -NAPI_EXTERN napi_status napi_get_dataview_info(napi_env env, - napi_value dataview, - size_t* bytelength, - void** data, - napi_value* arraybuffer, - size_t* byte_offset); - -// version management -NAPI_EXTERN napi_status napi_get_version(napi_env env, uint32_t* result); - -// Promises -NAPI_EXTERN napi_status napi_create_promise(napi_env env, - napi_deferred* deferred, - napi_value* promise); -NAPI_EXTERN napi_status napi_resolve_deferred(napi_env env, - napi_deferred deferred, - napi_value resolution); -NAPI_EXTERN napi_status napi_reject_deferred(napi_env env, - napi_deferred deferred, - napi_value rejection); -NAPI_EXTERN napi_status napi_is_promise(napi_env env, - napi_value promise, - bool* is_promise); - -// Running a script -NAPI_EXTERN napi_status napi_run_script(napi_env env, - napi_value script, - const char* source_url, - napi_value* result); - -// Memory management -NAPI_EXTERN napi_status napi_adjust_external_memory(napi_env env, - int64_t change_in_bytes, - int64_t* adjusted_value); - -#ifdef NAPI_EXPERIMENTAL - -NAPI_EXTERN napi_status napi_create_bigint_int64(napi_env env, - int64_t value, - napi_value* result); -NAPI_EXTERN napi_status napi_create_bigint_uint64(napi_env env, - uint64_t value, - napi_value* result); -NAPI_EXTERN napi_status napi_create_bigint_words(napi_env env, - int sign_bit, - size_t word_count, - const uint64_t* words, - napi_value* result); -NAPI_EXTERN napi_status napi_get_value_bigint_int64(napi_env env, - napi_value value, - int64_t* result, - bool* lossless); -NAPI_EXTERN napi_status napi_get_value_bigint_uint64(napi_env env, - napi_value value, - uint64_t* result, - bool* lossless); -NAPI_EXTERN napi_status napi_get_value_bigint_words(napi_env env, - napi_value value, - int* sign_bit, - size_t* word_count, - uint64_t* words); -NAPI_EXTERN napi_status napi_add_finalizer(napi_env env, - napi_value js_object, - void* native_object, - napi_finalize finalize_cb, - void* finalize_hint, - napi_ref* result); -#endif // NAPI_EXPERIMENTAL - -EXTERN_C_END - -#endif // SRC_JS_NATIVE_API_H_ diff --git a/Dependencies/napi/napi-direct/include/napi/js_native_api_types.h b/Dependencies/napi/napi-direct/include/napi/js_native_api_types.h deleted file mode 100644 index d49dac006..000000000 --- a/Dependencies/napi/napi-direct/include/napi/js_native_api_types.h +++ /dev/null @@ -1,117 +0,0 @@ -#ifndef SRC_JS_NATIVE_API_TYPES_H_ -#define SRC_JS_NATIVE_API_TYPES_H_ - -// This file needs to be compatible with C compilers. -// This is a public include file, and these includes have essentially -// became part of it's API. -#include // NOLINT(modernize-deprecated-headers) -#include // NOLINT(modernize-deprecated-headers) - -#if !defined __cplusplus || (defined(_MSC_VER) && _MSC_VER < 1900) - typedef uint16_t char16_t; -#endif - -// JSVM API types are all opaque pointers for ABI stability -// typedef undefined structs instead of void* for compile time type safety -typedef struct napi_env__* napi_env; -typedef struct napi_value__* napi_value; -typedef struct napi_ref__* napi_ref; -typedef struct napi_handle_scope__* napi_handle_scope; -typedef struct napi_escapable_handle_scope__* napi_escapable_handle_scope; -typedef struct napi_callback_info__* napi_callback_info; -typedef struct napi_deferred__* napi_deferred; - -typedef enum { - napi_default = 0, - napi_writable = 1 << 0, - napi_enumerable = 1 << 1, - napi_configurable = 1 << 2, - // Used with napi_define_class to distinguish static properties - // from instance properties. Ignored by napi_define_properties. - napi_static = 1 << 10, -} napi_property_attributes; - -typedef enum { - // ES6 types (corresponds to typeof) - napi_undefined, - napi_null, - napi_boolean, - napi_number, - napi_string, - napi_symbol, - napi_object, - napi_function, - napi_external, - napi_bigint, -} napi_valuetype; - -typedef enum { - napi_int8_array, - napi_uint8_array, - napi_uint8_clamped_array, - napi_int16_array, - napi_uint16_array, - napi_int32_array, - napi_uint32_array, - napi_float32_array, - napi_float64_array, - napi_bigint64_array, - napi_biguint64_array, -} napi_typedarray_type; - -typedef enum { - napi_ok, - napi_invalid_arg, - napi_object_expected, - napi_string_expected, - napi_name_expected, - napi_function_expected, - napi_number_expected, - napi_boolean_expected, - napi_array_expected, - napi_generic_failure, - napi_pending_exception, - napi_cancelled, - napi_escape_called_twice, - napi_handle_scope_mismatch, - napi_callback_scope_mismatch, - napi_queue_full, - napi_closing, - napi_bigint_expected, - napi_date_expected, - napi_arraybuffer_expected, - napi_detachable_arraybuffer_expected, -} napi_status; -// Note: when adding a new enum value to `napi_status`, please also update -// `const int last_status` in `napi_get_last_error_info()' definition, -// in file js_native_api_v8.cc. Please also update the definition of -// `napi_status` in doc/api/n-api.md to reflect the newly added value(s). - -typedef napi_value (*napi_callback)(napi_env env, - napi_callback_info info); -typedef void (*napi_finalize)(napi_env env, - void* finalize_data, - void* finalize_hint); - -typedef struct { - // One of utf8name or name should be NULL. - const char* utf8name; - napi_value name; - - napi_callback method; - napi_callback getter; - napi_callback setter; - napi_value value; - - napi_property_attributes attributes; - void* data; -} napi_property_descriptor; - -typedef struct { - const char* error_message; - void* engine_reserved; - uint32_t engine_error_code; - napi_status error_code; -} napi_extended_error_info; - -#endif // SRC_JS_NATIVE_API_TYPES_H_ diff --git a/Dependencies/napi/napi-direct/include/napi/napi-inl.h b/Dependencies/napi/napi-direct/include/napi/napi-inl.h deleted file mode 100644 index bb5415171..000000000 --- a/Dependencies/napi/napi-direct/include/napi/napi-inl.h +++ /dev/null @@ -1,4194 +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 - -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_value symbol, external; - napi_status status = napi_create_symbol(env, nullptr, &symbol); - if (status == napi_ok) { - status = napi_create_external(env, - data, - [](napi_env /*env*/, void* data, void* /*hint*/) { - delete static_cast(data); - }, - nullptr, - &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); - } - } - 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); -} - -//////////////////////////////////////////////////////////////////////////////// -// 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 version of NAPI_VERSION that it is -// released in once it is no longer experimental -#if (NAPI_VERSION > 2147483646) -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; -} -#ifndef NODE_ADDON_API_DISABLE_NODE_SPECIFIC -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; -} -#endif // NODE_ADDON_API_DISABLE_NODE_SPECIFIC - -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 version of NAPI_VERSION that it is -// released in once it is no longer experimental -#if (NAPI_VERSION > 2147483646) -//////////////////////////////////////////////////////////////////////////////// -// 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; -} - -//////////////////////////////////////////////////////////////////////////////// -// 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({ std::move(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, data, byteLength); -} - -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, externalData, byteLength); -} - -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, externalData, byteLength); -} - -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, externalData, byteLength); -} - -inline ArrayBuffer::ArrayBuffer() : Object(), _data(nullptr), _length(0) { -} - -inline ArrayBuffer::ArrayBuffer(napi_env env, napi_value value) - : Object(env, value), _data(nullptr), _length(0) { -} - -inline ArrayBuffer::ArrayBuffer(napi_env env, napi_value value, void* data, size_t length) - : Object(env, value), _data(data), _length(length) { -} - -inline void* ArrayBuffer::Data() const { - EnsureInfo(); - return _data; -} - -inline size_t ArrayBuffer::ByteLength() const { - EnsureInfo(); - return _length; -} - -inline void ArrayBuffer::EnsureInfo() const { - // The ArrayBuffer 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 ArrayBuffer. - if (_data == nullptr) { - napi_status status = napi_get_arraybuffer_info(_env, _value, &_data, &_length); - NAPI_THROW_IF_FAILED_VOID(_env, status); - } -} - -//////////////////////////////////////////////////////////////////////////////// -// 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, - 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(size_t argc, const 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 Value* args) const { - const size_t stackArgsCount = 6; - napi_value stackArgs[stackArgsCount]; - std::vector heapArgs; - napi_value* argv; - if (argc <= stackArgsCount) { - argv = stackArgs; - } else { - heapArgs.resize(argc); - argv = heapArgs.data(); - } - - for (size_t index = 0; index < argc; index++) { - argv[index] = static_cast(args[index]); - } - - return Call(recv, argc, argv); -} - -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); -} - -#ifndef NODE_ADDON_API_DISABLE_NODE_SPECIFIC -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); -} -#endif // NODE_ADDON_API_DISABLE_NODE_SPECIFIC - -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) { -} - -#ifndef NODE_ADDON_API_DISABLE_NODE_SPECIFIC -//////////////////////////////////////////////////////////////////////////////// -// 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); - } -} -#endif // NODE_ADDON_API_DISABLE_NODE_SPECIFIC - -//////////////////////////////////////////////////////////////////////////////// -// Error class -//////////////////////////////////////////////////////////////////////////////// - -inline Error Error::New(napi_env env) { - napi_status status; - napi_value error = nullptr; - - const napi_extended_error_info* info; - status = napi_get_last_error_info(env, &info); - NAPI_FATAL_IF_FAILED(status, "Error::New", "napi_get_last_error_info"); - - if (info->error_code == napi_pending_exception) { - 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"; - - bool isExceptionPending; - status = napi_is_exception_pending(env, &isExceptionPending); - NAPI_FATAL_IF_FAILED(status, "Error::New", "napi_is_exception_pending"); - - if (isExceptionPending) { - status = napi_get_and_clear_last_exception(env, &error); - NAPI_FATAL_IF_FAILED(status, "Error::New", "napi_get_and_clear_last_exception"); - } - - 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); -} - -#ifdef NAPI_CPP_EXCEPTIONS - -inline Error Error::New(napi_env env, const std::exception& exception) { - return Error::New(env, exception.what()); -} - -inline Error Error::New(napi_env env, const std::exception_ptr& exception_ptr) { - try { - std::rethrow_exception(exception_ptr); - } catch (const std::exception& exception) { - return Error::New(env, exception); - } -} - -#endif // NAPI_CPP_EXCEPTIONS - -inline NAPI_NO_RETURN void Error::Fatal(const char* location, const char* message) { - throw std::runtime_error(std::string{location} + ": " + message); -} - -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 =(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); -} - -#ifndef NODE_ADDON_API_DISABLE_NODE_SPECIFIC -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); -} -#endif // NODE_ADDON_API_DISABLE_NODE_SPECIFIC - -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 -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 -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 -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 -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 -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; -} - -//////////////////////////////////////////////////////////////////////////////// -// 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_close_handle_scope(_env, _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_close_escapable_handle_scope(_env, _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); -} - -#ifndef NODE_ADDON_API_DISABLE_NODE_SPECIFIC -#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_close_callback_scope(_env, _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; -} - -//////////////////////////////////////////////////////////////////////////////// -// 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(new napi_threadsafe_function(nullptr), _d) { -} - -inline ThreadSafeFunction::ThreadSafeFunction( - napi_threadsafe_function tsfn) - : _tsfn(new napi_threadsafe_function(tsfn), _d) { -} - -inline ThreadSafeFunction::ThreadSafeFunction(ThreadSafeFunction&& other) - : _tsfn(std::move(other._tsfn)) { - other._tsfn.reset(); -} - -inline ThreadSafeFunction& ThreadSafeFunction::operator =( - ThreadSafeFunction&& other) { - if (*_tsfn != nullptr) { - Error::Fatal("ThreadSafeFunction::operator =", - "You cannot assign a new TSFN because existing one is still alive."); - return *this; - } - _tsfn = std::move(other._tsfn); - other._tsfn.reset(); - return *this; -} - -inline napi_status ThreadSafeFunction::BlockingCall() const { - return CallInternal(nullptr, 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( - 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 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_get_threadsafe_function_context(*_tsfn, &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.get() }); - napi_status status = napi_create_threadsafe_function(env, callback, resource, - Value::From(env, resourceName), maxQueueSize, initialThreadCount, - finalizeData, wrapper, context, CallJS, tsfn._tsfn.get()); - 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({}); - } -} -#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; -} -#endif // NODE_ADDON_API_DISABLE_NODE_SPECIFIC - -} // namespace Napi - -#endif // SRC_NAPI_INL_H_ diff --git a/Dependencies/napi/napi-direct/include/napi/napi.h b/Dependencies/napi/napi-direct/include/napi/napi.h deleted file mode 100644 index 3ca99da91..000000000 --- a/Dependencies/napi/napi-direct/include/napi/napi.h +++ /dev/null @@ -1,2110 +0,0 @@ -#ifndef SRC_NAPI_H_ -#define SRC_NAPI_H_ - -#ifdef NODE_ADDON_API_DISABLE_NODE_SPECIFIC -#define NAPI_NO_RETURN -#endif - -#ifndef NODE_ADDON_API_DISABLE_NODE_SPECIFIC -#include -#else -#include "js_native_api.h" -#endif - -#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 version of NAPI_VERSION that it is -// released in once it is no longer experimental -#if (NAPI_VERSION > 2147483646) - class BigInt; -#endif // NAPI_EXPERIMENTAL -#if (NAPI_VERSION > 4) - class Date; -#endif - class String; - class Object; - class Array; - 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 version of NAPI_VERSION that it is -// released in once it is no longer experimental -#if (NAPI_VERSION > 2147483646) - 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(); - - 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 version of NAPI_VERSION that it is -// released in once it is no longer experimental -#if (NAPI_VERSION > 2147483646) - 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 version of NAPI_VERSION that it is -// released in once it is no longer experimental -#if (NAPI_VERSION > 2147483646) - /// 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 - 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() const; ///< Gets a pointer to the data buffer. - size_t ByteLength() const; ///< Gets the length of the array buffer in bytes. - - private: - mutable void* _data; - mutable size_t _length; - - ArrayBuffer(napi_env env, napi_value value, void* data, size_t length); - void EnsureInfo() const; - }; - - /// 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 version of NAPI_VERSION that it is -// released in once it is no longer experimental -#if (NAPI_VERSION > 2147483646) - : 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: - /// 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(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 Call(napi_value recv, size_t argc, const napi_value* args) const; - -#ifndef NODE_ADDON_API_DISABLE_NODE_SPECIFIC - 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; -#endif // NODE_ADDON_API_DISABLE_NODE_SPECIFIC - - 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); - }; - -#ifndef NODE_ADDON_API_DISABLE_NODE_SPECIFIC - 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; - }; -#endif // NODE_ADDON_API_DISABLE_NODE_SPECIFIC - - /// 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 =(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 =(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 =(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; - -#ifndef NODE_ADDON_API_DISABLE_NODE_SPECIFIC - 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; -#endif // NODE_ADDON_API_DISABLE_NODE_SPECIFIC - - 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); - -#ifdef NAPI_CPP_EXCEPTIONS - static Error New(napi_env env, const std::exception& exception); - static Error New(napi_env env, const std::exception_ptr& exception_ptr); -#endif // NAPI_CPP_EXCEPTIONS - - 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 =(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: -#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(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: - 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("value", &Example::GetSomething, &Example::SetSomething), - /// InstanceMethod("doSomething", &Example::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); - 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); - 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); - 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); - 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: - 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; - }; - - class HandleScope { - public: - HandleScope(napi_env env, napi_handle_scope scope); - explicit HandleScope(Napi::Env env); - ~HandleScope(); - - 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(); - - operator napi_escapable_handle_scope() const; - - Napi::Env Env() const; - Value Escape(napi_value escapee); - - private: - napi_env _env; - napi_escapable_handle_scope _scope; - }; - -#ifndef NODE_ADDON_API_DISABLE_NODE_SPECIFIC -#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(); - - 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 =(AsyncContext&) = delete; - - operator napi_async_context() 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 =(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; - }; -#endif // NODE_ADDON_API_DISABLE_NODE_SPECIFIC - - #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); - - ThreadSafeFunction(ThreadSafeFunction&& other); - ThreadSafeFunction& operator=(ThreadSafeFunction&& other); - - // 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 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); - struct Deleter { - // napi_threadsafe_function is managed by Node.js, leave it alone. - void operator()(napi_threadsafe_function*) const {}; - }; - - std::unique_ptr _tsfn; - Deleter _d; - }; - #endif - -#ifndef NODE_ADDON_API_DISABLE_NODE_SPECIFIC - // 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); - }; -#endif // NODE_ADDON_API_DISABLE_NODE_SPECIFIC - -} // namespace Napi - -// Inline implementations of all the above class methods are included here. -#include "napi-inl.h" - -#endif // SRC_NAPI_H_ diff --git a/Dependencies/napi/napi-direct/nuget.config b/Dependencies/napi/napi-direct/nuget.config deleted file mode 100644 index db7d8b6cc..000000000 --- a/Dependencies/napi/napi-direct/nuget.config +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - diff --git a/Dependencies/napi/napi-direct/packages.config b/Dependencies/napi/napi-direct/packages.config deleted file mode 100644 index 236d8f7af..000000000 --- a/Dependencies/napi/napi-direct/packages.config +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/Dependencies/napi/napi-direct/source/env.cc b/Dependencies/napi/napi-direct/source/env.cc deleted file mode 100644 index 8e35c8f26..000000000 --- a/Dependencies/napi/napi-direct/source/env.cc +++ /dev/null @@ -1,11 +0,0 @@ -#include - -namespace Napi -{ - Napi::Value Eval(Napi::Env env, const char* source, const char* sourceUrl) - { - napi_value result; - NAPI_THROW_IF_FAILED(env, napi_run_script(env, Napi::String::New(env, source), sourceUrl, &result)); - return{ env, result }; - } -} diff --git a/Dependencies/napi/napi-direct/source/env_chakra.cc b/Dependencies/napi/napi-direct/source/env_chakra.cc deleted file mode 100644 index 8436e9bb7..000000000 --- a/Dependencies/napi/napi-direct/source/env_chakra.cc +++ /dev/null @@ -1,43 +0,0 @@ -#include -#include "js_native_api_chakra.h" -#include -#include - -namespace -{ - void ThrowIfFailed(JsErrorCode errorCode) - { - if (errorCode != JsErrorCode::JsNoError) - { - throw std::exception(); - } - } -} - -namespace Napi -{ - template<> - Env Attach<>() - { - napi_env env_ptr{new napi_env__}; - - JsValueRef global; - ThrowIfFailed(JsGetGlobalObject(&global)); - JsPropertyIdRef propertyId; - ThrowIfFailed(JsGetPropertyIdFromName(L"Object", &propertyId)); - JsValueRef object; - ThrowIfFailed(JsGetProperty(global, propertyId, &object)); - JsValueRef prototype; - ThrowIfFailed(JsGetPrototype(object, &prototype)); - ThrowIfFailed(JsGetPropertyIdFromName(L"hasOwnProperty", &propertyId)); - ThrowIfFailed(JsGetProperty(prototype, propertyId, &env_ptr->has_own_property_function)); - - return {env_ptr}; - } - - void Detach(Env env) - { - napi_env env_ptr{env}; - delete env_ptr; - } -} diff --git a/Dependencies/napi/napi-direct/source/env_javascriptcore.cc b/Dependencies/napi/napi-direct/source/env_javascriptcore.cc deleted file mode 100644 index 118a41ed1..000000000 --- a/Dependencies/napi/napi-direct/source/env_javascriptcore.cc +++ /dev/null @@ -1,26 +0,0 @@ -#include -#include -#include "JavaScriptCore/JavaScript.h" -#include "js_native_api_javascriptcore.h" - -namespace Napi -{ - template<> - Napi::Env Attach(JSGlobalContextRef context) - { - napi_env env_ptr{new napi_env__{context}}; - return {env_ptr}; - } - - void Detach(Napi::Env env) - { - napi_env env_ptr{env}; - delete env_ptr; - } - - template<> JSGlobalContextRef GetContext(Napi::Env env) - { - napi_env env_ptr{env}; - return env_ptr->context; - } -} diff --git a/Dependencies/napi/napi-direct/source/env_v8.cc b/Dependencies/napi/napi-direct/source/env_v8.cc deleted file mode 100644 index cf6bcb4ab..000000000 --- a/Dependencies/napi/napi-direct/source/env_v8.cc +++ /dev/null @@ -1,25 +0,0 @@ -#include -#include -#include "js_native_api_v8.h" -#include - -namespace Napi -{ - template<> - Env Attach>(v8::Local isolate) - { - return {new napi_env__(isolate)}; - } - - template<> - v8::Local GetContext(Env env) - { - return ((napi_env)env)->context(); - } - - void Detach(Env env) - { - napi_env env_ptr{env}; - delete env_ptr; - } -} diff --git a/Dependencies/napi/napi-direct/source/js_native_api_chakra.cc b/Dependencies/napi/napi-direct/source/js_native_api_chakra.cc deleted file mode 100644 index 8824140db..000000000 --- a/Dependencies/napi/napi-direct/source/js_native_api_chakra.cc +++ /dev/null @@ -1,2424 +0,0 @@ -#include "js_native_api_chakra.h" -#include -#include -#include -#include -#include -#include -#include - -namespace { -constexpr UINT CP_LATIN1 = 28591; - -std::wstring NarrowToWide(std::string_view value, UINT codePage = CP_UTF8) { - if (value.size() == 0) { - return {}; - } - - int requiredSize = ::MultiByteToWideChar(codePage, 0, value.data(), static_cast(value.size()), nullptr, 0); - assert(requiredSize != 0); - std::wstring wstr(requiredSize, 0); - int result = ::MultiByteToWideChar(codePage, 0, value.data(), static_cast(value.size()), &wstr[0], requiredSize); - assert(result != 0); - return std::move(wstr); -} - -JsErrorCode JsCreateString(_In_ const char* content, _In_ size_t length, _Out_ JsValueRef* value) { - auto str = (length == NAPI_AUTO_LENGTH ? NarrowToWide({ content }) : NarrowToWide({ content, length })); - return JsPointerToString(str.data(), str.size(), value); -} - -JsErrorCode JsCopyString(_In_ JsValueRef value, _Out_opt_ char* buffer, _In_ size_t bufferSize, _Out_opt_ size_t* length, UINT codePage = CP_UTF8) { - const wchar_t* stringValue; - size_t stringLength; - CHECK_JSRT_ERROR_CODE(JsStringToPointer(value, &stringValue, &stringLength)); - - int result = ::WideCharToMultiByte(codePage, 0, stringValue, static_cast(stringLength), buffer, static_cast(bufferSize), nullptr, nullptr); - assert(result != 0 || stringLength == 0); - if (length != nullptr) { - *length = result; - } - - return JsErrorCode::JsNoError; -} - -JsErrorCode JsCopyStringUtf16(_In_ JsValueRef value, _Out_opt_ char16_t* buffer, _In_ size_t bufferSize, _Out_opt_ size_t* length) { - const wchar_t* stringValue; - size_t stringLength; - CHECK_JSRT_ERROR_CODE(JsStringToPointer(value, &stringValue, &stringLength)); - - if (length != nullptr) { - *length = stringLength; - } - - if (buffer != nullptr) { - static_assert(sizeof(char16_t) == sizeof(wchar_t)); - memcpy_s(buffer, bufferSize, stringValue, stringLength * sizeof(wchar_t)); - } - - return JsErrorCode::JsNoError; -} - -JsErrorCode JsCreatePropertyId(_In_z_ const char* name, _In_ size_t length, _Out_ JsPropertyIdRef* propertyId) { - auto str = (length == NAPI_AUTO_LENGTH ? NarrowToWide({ name }) : NarrowToWide({ name, length })); - return JsGetPropertyIdFromName(str.data(), propertyId); -} - -JsErrorCode JsCreatePromise(JsValueRef* promise, JsValueRef* resolve, JsValueRef* reject) { - JsValueRef global{}; - CHECK_JSRT_ERROR_CODE(JsGetGlobalObject(&global)); - - JsPropertyIdRef promiseConstructorId{}; - CHECK_JSRT_ERROR_CODE(JsGetPropertyIdFromName(L"Promise", &promiseConstructorId)); - - JsValueRef promiseConstructor{}; - CHECK_JSRT_ERROR_CODE(JsGetProperty(global, promiseConstructorId, &promiseConstructor)); - - struct CallbackStruct { - static JsValueRef CALLBACK Callback(JsValueRef callee, bool isConstructCall, JsValueRef* arguments, unsigned short argumentCount, void* callbackState) { - return (reinterpret_cast(callbackState))->Callback(callee, isConstructCall, arguments, argumentCount); - } - - JsValueRef Callback(JsValueRef callee, bool isConstructCall, JsValueRef* arguments, unsigned short argumentCount) { - *resolve = arguments[1]; - *reject = arguments[2]; - - return JS_INVALID_REFERENCE; - } - - JsValueRef* resolve{}; - JsValueRef* reject{}; - } cbs{ resolve, reject }; - - JsValueRef callbackFunction{}; - CHECK_JSRT_ERROR_CODE(JsCreateFunction(&CallbackStruct::Callback, &cbs, &callbackFunction)); - - JsValueRef args[2]; - CHECK_JSRT_ERROR_CODE(JsGetUndefinedValue(&args[0])); - args[1] = callbackFunction; - CHECK_JSRT_ERROR_CODE(JsConstructObject(promiseConstructor, args, 2, promise)); - - return JsErrorCode::JsNoError; -} - -// Callback Info struct as per JSRT native function. -struct CallbackInfo { - napi_value newTarget; - napi_value thisArg; - napi_value* argv; - void* data; - uint16_t argc; - bool isConstructCall; -}; - -// Adapter for JSRT external data + finalize callback. -class ExternalData { - public: - ExternalData(napi_env env, void* data, napi_finalize finalize_cb, void* hint) - : _env(env) - , _data(data) - , _cb(finalize_cb) - , _hint(hint) { - } - - void* Data() { - return _data; - } - - // JsFinalizeCallback - static void CALLBACK Finalize(void* callbackState) { - ExternalData* externalData = - reinterpret_cast(callbackState); - if (externalData != nullptr) { - if (externalData->_cb != nullptr) { - externalData->_cb( - externalData->_env, externalData->_data, externalData->_hint); - } - - delete externalData; - } - } - - private: - napi_env _env; - void* _data; - napi_finalize _cb; - void* _hint; -}; - -// Adapter for JSRT external callback + callback data. -class ExternalCallback { - public: - ExternalCallback(napi_env env, napi_callback cb, void* data) - : _env(env), _cb(cb), _data(data) { - } - - // JsNativeFunction - static JsValueRef CALLBACK Callback(JsValueRef callee, bool isConstructCall, JsValueRef* arguments, unsigned short argumentCount, void* callbackState) { - ExternalCallback* externalCallback = - reinterpret_cast(callbackState); - - // Make sure any errors encountered last time we were in N-API are gone. - napi_clear_last_error(externalCallback->_env); - - CallbackInfo cbInfo; - cbInfo.thisArg = reinterpret_cast(arguments[0]); - cbInfo.newTarget = reinterpret_cast(externalCallback->newTarget); - cbInfo.isConstructCall = isConstructCall; - cbInfo.argc = argumentCount - 1; - cbInfo.argv = reinterpret_cast(arguments + 1); - cbInfo.data = externalCallback->_data; - - napi_value result = externalCallback->_cb( - externalCallback->_env, reinterpret_cast(&cbInfo)); - return reinterpret_cast(result); - } - - // JsObjectBeforeCollectCallback - static void CALLBACK Finalize(JsRef ref, void* callbackState) { - ExternalCallback* externalCallback = - reinterpret_cast(callbackState); - delete externalCallback; - } - - // Value for 'new.target' - JsValueRef newTarget; - - private: - napi_env _env; - napi_callback _cb; - void* _data; -}; - -JsErrorCode JsPropertyIdFromKey(JsValueRef key, JsPropertyIdRef* propertyId) { - JsValueType keyType; - CHECK_JSRT_ERROR_CODE(JsGetValueType(key, &keyType)); - - if (keyType == JsString) { - const wchar_t* stringValue; - size_t stringLength; - CHECK_JSRT_ERROR_CODE(JsStringToPointer(key, &stringValue, &stringLength)); - CHECK_JSRT_ERROR_CODE(JsGetPropertyIdFromName(stringValue, propertyId)); - } else if (keyType == JsSymbol) { - CHECK_JSRT_ERROR_CODE(JsGetPropertyIdFromSymbol(key, propertyId)); - } else { - return JsErrorCode::JsErrorInvalidArgument; - } - return JsErrorCode::JsNoError; -} - -JsErrorCode JsPropertyIdFromPropertyDescriptor(const napi_property_descriptor* p, JsPropertyIdRef* propertyId) { - if (p->utf8name != nullptr) { - return JsCreatePropertyId(p->utf8name, strlen(p->utf8name), propertyId); - } else { - return JsPropertyIdFromKey(p->name, propertyId); - } -} - -JsErrorCode JsNameValueFromPropertyDescriptor(const napi_property_descriptor* p, napi_value* name) { - if (p->utf8name != nullptr) { - return JsCreateString( - p->utf8name, - NAPI_AUTO_LENGTH, - reinterpret_cast(name)); - } else { - *name = p->name; - return JsErrorCode::JsNoError; - } -} - -inline napi_status FindWrapper(napi_env env, JsValueRef obj, JsValueRef* wrapper, JsValueRef* parent = nullptr) { - // Search the object's prototype chain for the wrapper with external data. - // Usually the wrapper would be the first in the chain, but it is OK for - // other objects to be inserted in the prototype chain. - JsValueRef candidate = obj; - JsValueRef current = JS_INVALID_REFERENCE; - bool hasExternalData = false; - - JsValueRef nullValue = JS_INVALID_REFERENCE; - CHECK_JSRT(env, JsGetNullValue(&nullValue)); - - do { - current = candidate; - - CHECK_JSRT(env, JsGetPrototype(current, &candidate)); - if (candidate == JS_INVALID_REFERENCE || candidate == nullValue) { - if (parent != nullptr) { - *parent = JS_INVALID_REFERENCE; - } - - *wrapper = JS_INVALID_REFERENCE; - return napi_ok; - } - - CHECK_JSRT(env, JsHasExternalData(candidate, &hasExternalData)); - } while (!hasExternalData); - - if (parent != nullptr) { - *parent = current; - } - - *wrapper = candidate; - - return napi_ok; -} - -inline napi_status Unwrap(napi_env env, JsValueRef obj, ExternalData** externalData, JsValueRef* wrapper = nullptr, JsValueRef* parent = nullptr) { - JsValueRef candidate = JS_INVALID_REFERENCE; - JsValueRef candidateParent = JS_INVALID_REFERENCE; - CHECK_NAPI(FindWrapper(env, obj, &candidate, &candidateParent)); - RETURN_STATUS_IF_FALSE(env, candidate != JS_INVALID_REFERENCE, napi_invalid_arg); - - CHECK_JSRT(env, JsGetExternalData(candidate, - reinterpret_cast(externalData))); - - if (wrapper != nullptr) { - *wrapper = candidate; - } - - if (parent != nullptr) { - *parent = candidateParent; - } - - return napi_ok; -} - -static napi_status SetErrorCode(napi_env env, JsValueRef error, napi_value code, const char* codeString) { - if ((code != nullptr) || (codeString != nullptr)) { - JsValueRef codeValue = reinterpret_cast(code); - if (codeValue != JS_INVALID_REFERENCE) { - JsValueType valueType = JsUndefined; - CHECK_JSRT(env, JsGetValueType(codeValue, &valueType)); - RETURN_STATUS_IF_FALSE(env, valueType == JsString, napi_string_expected); - } else { - CHECK_JSRT(env, JsCreateString(codeString, NAPI_AUTO_LENGTH, &codeValue)); - } - - JsPropertyIdRef codePropId = JS_INVALID_REFERENCE; - CHECK_JSRT(env, JsCreatePropertyId(STR_AND_LENGTH("code"), &codePropId)); - - CHECK_JSRT(env, JsSetProperty(error, codePropId, codeValue, true)); - - JsValueRef nameArray = JS_INVALID_REFERENCE; - CHECK_JSRT(env, JsCreateArray(0, &nameArray)); - - JsPropertyIdRef pushPropId = JS_INVALID_REFERENCE; - CHECK_JSRT(env, JsCreatePropertyId(STR_AND_LENGTH("push"), &pushPropId)); - - JsValueRef pushFunction = JS_INVALID_REFERENCE; - CHECK_JSRT(env, JsGetProperty(nameArray, pushPropId, &pushFunction)); - - JsPropertyIdRef namePropId = JS_INVALID_REFERENCE; - CHECK_JSRT(env, JsCreatePropertyId(STR_AND_LENGTH("name"), &namePropId)); - - bool hasProp = false; - CHECK_JSRT(env, JsHasProperty(error, namePropId, &hasProp)); - - JsValueRef nameValue = JS_INVALID_REFERENCE; - std::array args = { nameArray, JS_INVALID_REFERENCE }; - - if (hasProp) { - CHECK_JSRT(env, JsGetProperty(error, namePropId, &nameValue)); - - args[1] = nameValue; - CHECK_JSRT(env, - JsCallFunction(pushFunction, - args.data(), - static_cast(args.size()), - nullptr)); - } - - const char* openBracket = " ["; - JsValueRef openBracketValue = JS_INVALID_REFERENCE; - CHECK_JSRT(env, JsCreateString(openBracket, NAPI_AUTO_LENGTH, &openBracketValue)); - - args[1] = openBracketValue; - CHECK_JSRT(env, JsCallFunction(pushFunction, args.data(), static_cast(args.size()), nullptr)); - - args[1] = codeValue; - CHECK_JSRT(env, JsCallFunction(pushFunction, args.data(), static_cast(args.size()), nullptr)); - - const char* closeBracket = "]"; - JsValueRef closeBracketValue = JS_INVALID_REFERENCE; - CHECK_JSRT(env, JsCreateString(closeBracket, NAPI_AUTO_LENGTH, &closeBracketValue)); - - args[1] = closeBracketValue; - CHECK_JSRT(env, JsCallFunction(pushFunction, args.data(), static_cast(args.size()), nullptr)); - - JsValueRef emptyValue = JS_INVALID_REFERENCE; - CHECK_JSRT(env, JsCreateString("", 0, &emptyValue)); - - const char* joinPropIdName = "join"; - JsPropertyIdRef joinPropId = JS_INVALID_REFERENCE; - CHECK_JSRT(env, JsCreatePropertyId(joinPropIdName, - strlen(joinPropIdName), - &joinPropId)); - - JsValueRef joinFunction = JS_INVALID_REFERENCE; - CHECK_JSRT(env, JsGetProperty(nameArray, joinPropId, &joinFunction)); - - args[1] = emptyValue; - CHECK_JSRT(env, - JsCallFunction(joinFunction, - args.data(), - static_cast(args.size()), - &nameValue)); - - CHECK_JSRT(env, JsSetProperty(error, namePropId, nameValue, true)); - } - return napi_ok; -} - -napi_status ConcludeDeferred(napi_env env, napi_deferred deferred, const char* property, napi_value result) { - // We do not check if property is OK, because that's not coming from outside. - CHECK_ENV(env); - CHECK_ARG(env, deferred); - CHECK_ARG(env, result); - - napi_value container, resolver, js_null; - napi_ref ref = reinterpret_cast(deferred); - - CHECK_NAPI(napi_get_reference_value(env, ref, &container)); - CHECK_NAPI(napi_get_named_property(env, container, property, &resolver)); - CHECK_NAPI(napi_get_null(env, &js_null)); - CHECK_NAPI(napi_call_function(env, js_null, resolver, 1, &result, nullptr)); - CHECK_NAPI(napi_delete_reference(env, ref)); - - return napi_ok; -} - -napi_status CreatePropertyFunction(napi_env env, - napi_value property_name, - napi_callback cb, - void* callback_data, - napi_value* result) { - CHECK_ARG(env, result); - - ExternalCallback* externalCallback = - new ExternalCallback(env, cb, callback_data); - if (externalCallback == nullptr) { - return napi_set_last_error(env, napi_generic_failure); - } - - napi_valuetype nameType; - CHECK_NAPI(napi_typeof(env, property_name, &nameType)); - - JsValueRef function; - JsValueRef name = JS_INVALID_REFERENCE; - if (nameType == napi_string) { - name = property_name; - } - - CHECK_JSRT(env, JsCreateNamedFunction( - name, - ExternalCallback::Callback, - externalCallback, - &function)); - - externalCallback->newTarget = function; - - CHECK_JSRT(env, JsSetObjectBeforeCollectCallback( - function, externalCallback, ExternalCallback::Finalize)); - - *result = reinterpret_cast(function); - return napi_ok; -} - -struct RefInfo -{ - JsValueRef value; - uint32_t count; -}; - -struct DataViewInfo { - JsValueRef dataView; - JsValueRef arrayBuffer; - size_t byteOffset; - size_t byteLength; - - static void CALLBACK Finalize(_In_opt_ void* data) { - delete reinterpret_cast(data); - } -}; - -} // end anonymous namespace - -// Warning: Keep in-sync with napi_status enum -static const char* error_messages[] = { - nullptr, - "Invalid argument", - "An object was expected", - "A string was expected", - "A string or symbol was expected", - "A function was expected", - "A number was expected", - "A boolean was expected", - "An array was expected", - "Unknown failure", - "An exception is pending", - "The async work item was cancelled", - "napi_escape_handle already called on scope", - "Invalid handle scope usage", - "Invalid callback scope usage", - "Thread-safe function queue is full", - "Thread-safe function handle is closing", - "A bigint was expected", -}; - -napi_status napi_get_last_error_info(napi_env env, - const napi_extended_error_info** result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - - // you must update this assert to reference the last message - // in the napi_status enum each time a new error message is added. - // We don't have a napi_status_last as this would result in an ABI - // change each time a message was added. - static_assert( - std::size(error_messages) == napi_bigint_expected + 1, - "Count of error messages must match count of error values"); - assert(env->last_error.error_code <= napi_callback_scope_mismatch); - - // Wait until someone requests the last error information to fetch the error - // message string - env->last_error.error_message = - error_messages[env->last_error.error_code]; - - *result = &env->last_error; - return napi_ok; -} - -napi_status napi_create_function(napi_env env, - const char* utf8name, - size_t length, - napi_callback cb, - void* callback_data, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - - ExternalCallback* externalCallback = - new ExternalCallback(env, cb, callback_data); - if (externalCallback == nullptr) { - return napi_set_last_error(env, napi_generic_failure); - } - - JsValueRef function; - JsValueRef name = JS_INVALID_REFERENCE; - if (utf8name != nullptr) { - CHECK_JSRT(env, JsCreateString( - utf8name, - length, - &name)); - } - - CHECK_JSRT(env, JsCreateNamedFunction( - name, - ExternalCallback::Callback, - externalCallback, - &function)); - - externalCallback->newTarget = function; - - CHECK_JSRT(env, JsSetObjectBeforeCollectCallback( - function, externalCallback, ExternalCallback::Finalize)); - - *result = reinterpret_cast(function); - return napi_ok; -} - -napi_status napi_define_class(napi_env env, - const char* utf8name, - size_t length, - napi_callback cb, - void* data, - size_t property_count, - const napi_property_descriptor* properties, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - - napi_value namestring; - CHECK_NAPI(napi_create_string_utf8(env, utf8name, length, &namestring)); - - ExternalCallback* externalCallback = - new ExternalCallback(env, cb, data); - if (externalCallback == nullptr) { - return napi_set_last_error(env, napi_generic_failure); - } - - JsValueRef constructor; - CHECK_JSRT(env, JsCreateNamedFunction( - namestring, - ExternalCallback::Callback, - externalCallback, - &constructor)); - - externalCallback->newTarget = constructor; - - CHECK_JSRT(env, JsSetObjectBeforeCollectCallback( - constructor, externalCallback, ExternalCallback::Finalize)); - - JsPropertyIdRef pid = nullptr; - JsValueRef prototype = nullptr; - CHECK_JSRT(env, JsCreatePropertyId(STR_AND_LENGTH("prototype"), &pid)); - CHECK_JSRT(env, JsGetProperty(constructor, pid, &prototype)); - - CHECK_JSRT(env, JsCreatePropertyId(STR_AND_LENGTH("constructor"), &pid)); - CHECK_JSRT(env, JsSetProperty(prototype, pid, constructor, false)); - - int instancePropertyCount = 0; - int staticPropertyCount = 0; - for (size_t i = 0; i < property_count; i++) { - if ((properties[i].attributes & napi_static) != 0) { - staticPropertyCount++; - } else { - instancePropertyCount++; - } - } - - std::vector staticDescriptors; - std::vector instanceDescriptors; - staticDescriptors.reserve(staticPropertyCount); - instanceDescriptors.reserve(instancePropertyCount); - - for (size_t i = 0; i < property_count; i++) { - if ((properties[i].attributes & napi_static) != 0) { - staticDescriptors.push_back(properties[i]); - } else { - instanceDescriptors.push_back(properties[i]); - } - } - - if (staticPropertyCount > 0) { - CHECK_NAPI(napi_define_properties(env, - reinterpret_cast(constructor), - staticDescriptors.size(), - staticDescriptors.data())); - } - - if (instancePropertyCount > 0) { - CHECK_NAPI(napi_define_properties(env, - reinterpret_cast(prototype), - instanceDescriptors.size(), - instanceDescriptors.data())); - } - - *result = reinterpret_cast(constructor); - return napi_ok; -} - -napi_status napi_get_property_names(napi_env env, - napi_value object, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - JsValueRef obj = reinterpret_cast(object); - JsValueRef propertyNames; - CHECK_JSRT(env, JsGetOwnPropertyNames(obj, &propertyNames)); - *result = reinterpret_cast(propertyNames); - return napi_ok; -} - -napi_status napi_set_property(napi_env env, - napi_value object, - napi_value key, - napi_value value) { - CHECK_ENV(env); - CHECK_ARG(env, key); - CHECK_ARG(env, value); - JsValueRef obj = reinterpret_cast(object); - JsPropertyIdRef propertyId; - CHECK_JSRT(env, JsPropertyIdFromKey(key, &propertyId)); - JsValueRef js_value = reinterpret_cast(value); - CHECK_JSRT(env, JsSetProperty(obj, propertyId, js_value, true)); - return napi_ok; -} - -napi_status napi_has_property(napi_env env, - napi_value object, - napi_value key, - bool* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - CHECK_ARG(env, key); - JsPropertyIdRef propertyId; - CHECK_JSRT(env, JsPropertyIdFromKey(key, &propertyId)); - JsValueRef obj = reinterpret_cast(object); - CHECK_JSRT(env, JsHasProperty(obj, propertyId, result)); - return napi_ok; -} - -napi_status napi_get_property(napi_env env, - napi_value object, - napi_value key, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, key); - CHECK_ARG(env, result); - JsValueRef obj = reinterpret_cast(object); - JsPropertyIdRef propertyId; - CHECK_JSRT(env, JsPropertyIdFromKey(key, &propertyId)); - CHECK_JSRT(env, JsGetProperty(obj, propertyId, reinterpret_cast(result))); - return napi_ok; -} - -napi_status napi_delete_property(napi_env env, - napi_value object, - napi_value key, - bool* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - *result = false; - - JsValueRef obj = reinterpret_cast(object); - JsPropertyIdRef propertyId; - JsValueRef deletePropertyResult; - CHECK_JSRT(env, JsPropertyIdFromKey(key, &propertyId)); - CHECK_JSRT(env, JsDeleteProperty(obj, propertyId, false /* isStrictMode */, &deletePropertyResult)); - CHECK_JSRT(env, JsBooleanToBool(deletePropertyResult, result)); - - return napi_ok; -} - -NAPI_EXTERN napi_status napi_has_own_property(napi_env env, - napi_value object, - napi_value key, - bool* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - JsValueRef hasOwnPropertyResult; - std::array hasOwnPropertyFuncArgs{ object, key }; - CHECK_JSRT(env, JsCallFunction(env->has_own_property_function, hasOwnPropertyFuncArgs.data(), static_cast(hasOwnPropertyFuncArgs.size()), &hasOwnPropertyResult)); - CHECK_JSRT(env, JsBooleanToBool(hasOwnPropertyResult, result)); - return napi_ok; -} - -napi_status napi_set_named_property(napi_env env, - napi_value object, - const char* utf8name, - napi_value value) { - CHECK_ENV(env); - CHECK_ARG(env, value); - JsValueRef obj = reinterpret_cast(object); - JsPropertyIdRef propertyId; - CHECK_JSRT(env, JsCreatePropertyId(utf8name, NAPI_AUTO_LENGTH, &propertyId)); - JsValueRef js_value = reinterpret_cast(value); - CHECK_JSRT(env, JsSetProperty(obj, propertyId, js_value, true)); - return napi_ok; -} - -napi_status napi_has_named_property(napi_env env, - napi_value object, - const char* utf8name, - bool* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - JsPropertyIdRef propertyId; - CHECK_JSRT(env, JsCreatePropertyId(utf8name, strlen(utf8name), &propertyId)); - JsValueRef obj = reinterpret_cast(object); - CHECK_JSRT(env, JsHasProperty(obj, propertyId, result)); - return napi_ok; -} - -napi_status napi_get_named_property(napi_env env, - napi_value object, - const char* utf8name, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - JsValueRef obj = reinterpret_cast(object); - JsPropertyIdRef propertyId; - CHECK_JSRT(env, JsCreatePropertyId(utf8name, strlen(utf8name), &propertyId)); - CHECK_JSRT(env, - JsGetProperty(obj, propertyId, reinterpret_cast(result))); - return napi_ok; -} - -napi_status napi_set_element(napi_env env, - napi_value object, - uint32_t index, - napi_value value) { - CHECK_ENV(env); - CHECK_ARG(env, value); - JsValueRef jsIndex = nullptr; - CHECK_JSRT(env, JsIntToNumber(index, &jsIndex)); - JsValueRef obj = reinterpret_cast(object); - JsValueRef jsValue = reinterpret_cast(value); - CHECK_JSRT(env, JsSetIndexedProperty(obj, jsIndex, jsValue)); - return napi_ok; -} - -napi_status napi_has_element(napi_env env, - napi_value object, - uint32_t i, - bool* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - JsValueRef index = nullptr; - CHECK_JSRT(env, JsIntToNumber(i, &index)); - JsValueRef obj = reinterpret_cast(object); - CHECK_JSRT(env, JsHasIndexedProperty(obj, index, result)); - return napi_ok; -} - -napi_status napi_get_element(napi_env env, - napi_value object, - uint32_t i, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - JsValueRef index = nullptr; - JsValueRef obj = reinterpret_cast(object); - CHECK_JSRT(env, JsIntToNumber(i, &index)); - CHECK_JSRT(env, - JsGetIndexedProperty(obj, index, reinterpret_cast(result))); - return napi_ok; -} - -napi_status napi_delete_element(napi_env env, - napi_value object, - uint32_t index, - bool* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - JsValueRef indexValue = nullptr; - JsValueRef obj = reinterpret_cast(object); - CHECK_JSRT(env, JsIntToNumber(index, &indexValue)); - CHECK_JSRT(env, JsDeleteIndexedProperty(obj, indexValue)); - *result = true; - return napi_ok; -} - -napi_status napi_define_properties(napi_env env, - napi_value object, - size_t property_count, - const napi_property_descriptor* properties) { - CHECK_ENV(env); - if (property_count > 0) { - CHECK_ARG(env, properties); - } - - JsPropertyIdRef configurableProperty; - CHECK_JSRT(env, JsCreatePropertyId(STR_AND_LENGTH("configurable"), - &configurableProperty)); - - JsPropertyIdRef enumerableProperty; - CHECK_JSRT(env, JsCreatePropertyId(STR_AND_LENGTH("enumerable"), - &enumerableProperty)); - - for (size_t i = 0; i < property_count; i++) { - const napi_property_descriptor* p = properties + i; - - JsValueRef descriptor; - CHECK_JSRT(env, JsCreateObject(&descriptor)); - - JsValueRef configurable; - CHECK_JSRT(env, JsBoolToBoolean((p->attributes & napi_configurable), &configurable)); - CHECK_JSRT(env, JsSetProperty(descriptor, configurableProperty, configurable, true)); - - JsValueRef enumerable; - CHECK_JSRT(env, JsBoolToBoolean((p->attributes & napi_enumerable), &enumerable)); - CHECK_JSRT(env, JsSetProperty(descriptor, enumerableProperty, enumerable, true)); - - if (p->getter != nullptr || p->setter != nullptr) { - napi_value property_name; - CHECK_JSRT(env, - JsNameValueFromPropertyDescriptor(p, &property_name)); - - if (p->getter != nullptr) { - JsPropertyIdRef getProperty; - CHECK_JSRT(env, JsCreatePropertyId(STR_AND_LENGTH("get"), &getProperty)); - JsValueRef getter; - CHECK_NAPI(CreatePropertyFunction(env, property_name, - p->getter, p->data, reinterpret_cast(&getter))); - CHECK_JSRT(env, JsSetProperty(descriptor, getProperty, getter, true)); - } - - if (p->setter != nullptr) { - JsPropertyIdRef setProperty; - CHECK_JSRT(env, JsCreatePropertyId(STR_AND_LENGTH("set"), &setProperty)); - JsValueRef setter; - CHECK_NAPI(CreatePropertyFunction(env, property_name, - p->setter, p->data, reinterpret_cast(&setter))); - CHECK_JSRT(env, JsSetProperty(descriptor, setProperty, setter, true)); - } - } else if (p->method != nullptr) { - napi_value property_name; - CHECK_JSRT(env, - JsNameValueFromPropertyDescriptor(p, &property_name)); - - JsPropertyIdRef valueProperty; - CHECK_JSRT(env, JsCreatePropertyId(STR_AND_LENGTH("value"), &valueProperty)); - JsValueRef method; - CHECK_NAPI(CreatePropertyFunction(env, property_name, - p->method, p->data, reinterpret_cast(&method))); - CHECK_JSRT(env, JsSetProperty(descriptor, valueProperty, method, true)); - } else { - RETURN_STATUS_IF_FALSE(env, p->value != nullptr, napi_invalid_arg); - - JsPropertyIdRef writableProperty; - CHECK_JSRT(env, JsCreatePropertyId(STR_AND_LENGTH("writable"), - &writableProperty)); - JsValueRef writable; - CHECK_JSRT(env, JsBoolToBoolean((p->attributes & napi_writable), &writable)); - CHECK_JSRT(env, JsSetProperty(descriptor, writableProperty, writable, true)); - - JsPropertyIdRef valueProperty; - CHECK_JSRT(env, JsCreatePropertyId(STR_AND_LENGTH("value"), &valueProperty)); - CHECK_JSRT(env, JsSetProperty(descriptor, valueProperty, - reinterpret_cast(p->value), true)); - } - - JsPropertyIdRef nameProperty; - CHECK_JSRT(env, JsPropertyIdFromPropertyDescriptor(p, &nameProperty)); - bool result; - CHECK_JSRT(env, JsDefineProperty( - reinterpret_cast(object), - reinterpret_cast(nameProperty), - reinterpret_cast(descriptor), - &result)); - } - - return napi_ok; -} - -napi_status napi_is_array(napi_env env, napi_value value, bool* result) { - CHECK_ENV(env); - CHECK_ARG(env, value); - CHECK_ARG(env, result); - JsValueRef jsValue = reinterpret_cast(value); - JsValueType type = JsUndefined; - CHECK_JSRT(env, JsGetValueType(jsValue, &type)); - *result = (type == JsArray); - return napi_ok; -} - -napi_status napi_get_array_length(napi_env env, - napi_value value, - uint32_t* result) { - CHECK_ENV(env); - CHECK_ARG(env, value); - CHECK_ARG(env, result); - JsPropertyIdRef propertyIdRef; - CHECK_JSRT(env, JsCreatePropertyId(STR_AND_LENGTH("length"), &propertyIdRef)); - JsValueRef lengthRef; - JsValueRef arrayRef = reinterpret_cast(value); - CHECK_JSRT(env, JsGetProperty(arrayRef, propertyIdRef, &lengthRef)); - double sizeInDouble; - CHECK_JSRT(env, JsNumberToDouble(lengthRef, &sizeInDouble)); - *result = static_cast(sizeInDouble); - return napi_ok; -} - -napi_status napi_strict_equals(napi_env env, - napi_value lhs, - napi_value rhs, - bool* result) { - CHECK_ENV(env); - CHECK_ARG(env, lhs); - CHECK_ARG(env, rhs); - CHECK_ARG(env, result); - JsValueRef object1 = reinterpret_cast(lhs); - JsValueRef object2 = reinterpret_cast(rhs); - CHECK_JSRT(env, JsStrictEquals(object1, object2, result)); - return napi_ok; -} - -napi_status napi_get_prototype(napi_env env, - napi_value object, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - JsValueRef obj = reinterpret_cast(object); - CHECK_JSRT(env, JsGetPrototype(obj, reinterpret_cast(result))); - return napi_ok; -} - -napi_status napi_create_object(napi_env env, napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - CHECK_JSRT(env, JsCreateObject(reinterpret_cast(result))); - return napi_ok; -} - -napi_status napi_create_array(napi_env env, napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - unsigned int length = 0; - CHECK_JSRT(env, JsCreateArray(length, reinterpret_cast(result))); - return napi_ok; -} - -napi_status napi_create_array_with_length(napi_env env, - size_t length, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - CHECK_JSRT(env, JsCreateArray(static_cast(length), reinterpret_cast(result))); - return napi_ok; -} - -napi_status napi_create_string_latin1(napi_env env, - const char* str, - size_t length, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - std::wstring wstr = NarrowToWide({ str, length }, CP_LATIN1); - CHECK_JSRT(env, JsPointerToString( - wstr.data(), - wstr.size(), - reinterpret_cast(result))); - return napi_ok; -} - -napi_status napi_create_string_utf8(napi_env env, - const char* str, - size_t length, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - CHECK_JSRT(env, JsCreateString( - str, - length, - reinterpret_cast(result))); - return napi_ok; -} - -napi_status napi_create_string_utf16(napi_env env, - const char16_t* str, - size_t length, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - static_assert(sizeof(char16_t) == sizeof(wchar_t)); - CHECK_JSRT(env, JsPointerToString( - reinterpret_cast(str), - length, - reinterpret_cast(result))); - return napi_ok; -} - -napi_status napi_create_double(napi_env env, - double value, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - CHECK_JSRT(env, JsDoubleToNumber(value, reinterpret_cast(result))); - return napi_ok; -} - -napi_status napi_create_int32(napi_env env, - int32_t value, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - CHECK_JSRT(env, JsIntToNumber(value, reinterpret_cast(result))); - return napi_ok; -} - -napi_status napi_create_uint32(napi_env env, - uint32_t value, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - CHECK_JSRT(env, JsDoubleToNumber(static_cast(value), - reinterpret_cast(result))); - return napi_ok; -} - -napi_status napi_create_int64(napi_env env, - int64_t value, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - CHECK_JSRT(env, JsDoubleToNumber(static_cast(value), - reinterpret_cast(result))); - return napi_ok; -} - -napi_status napi_get_boolean(napi_env env, bool value, napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - CHECK_JSRT(env, JsBoolToBoolean(value, reinterpret_cast(result))); - return napi_ok; -} - -napi_status napi_create_symbol(napi_env env, - napi_value description, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - JsValueRef js_description = reinterpret_cast(description); - CHECK_JSRT(env, - JsCreateSymbol(js_description, reinterpret_cast(result))); - return napi_ok; -} - -napi_status napi_create_error(napi_env env, - napi_value code, - napi_value msg, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, msg); - CHECK_ARG(env, result); - JsValueRef message = reinterpret_cast(msg); - - JsValueRef error = JS_INVALID_REFERENCE; - CHECK_JSRT(env, JsCreateError(message, &error)); - CHECK_NAPI(SetErrorCode(env, error, code, nullptr)); - - *result = reinterpret_cast(error); - return napi_ok; -} - -napi_status napi_create_type_error(napi_env env, - napi_value code, - napi_value msg, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, msg); - CHECK_ARG(env, result); - JsValueRef message = reinterpret_cast(msg); - - JsValueRef error = JS_INVALID_REFERENCE; - CHECK_JSRT(env, JsCreateTypeError(message, &error)); - CHECK_NAPI(SetErrorCode(env, error, code, nullptr)); - - *result = reinterpret_cast(error); - return napi_ok; -} - -napi_status napi_create_range_error(napi_env env, - napi_value code, - napi_value msg, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, msg); - CHECK_ARG(env, result); - JsValueRef message = reinterpret_cast(msg); - - JsValueRef error = JS_INVALID_REFERENCE; - CHECK_JSRT(env, - JsCreateRangeError(message, &error)); - CHECK_NAPI(SetErrorCode(env, error, code, nullptr)); - - *result = reinterpret_cast(error); - return napi_ok; -} - -napi_status napi_typeof(napi_env env, napi_value value, napi_valuetype* result) { - CHECK_ENV(env); - CHECK_ARG(env, value); - CHECK_ARG(env, result); - JsValueRef jsValue = reinterpret_cast(value); - JsValueType valueType = JsUndefined; - CHECK_JSRT(env, JsGetValueType(jsValue, &valueType)); - - switch (valueType) { - case JsUndefined: *result = napi_undefined; break; - case JsNull: *result = napi_null; break; - case JsNumber: *result = napi_number; break; - case JsString: *result = napi_string; break; - case JsBoolean: *result = napi_boolean; break; - case JsFunction: *result = napi_function; break; - case JsSymbol: *result = napi_symbol; break; - case JsError: *result = napi_object; break; - - default: - bool hasExternalData; - if (JsHasExternalData(jsValue, &hasExternalData) != JsNoError) { - hasExternalData = false; - } - - *result = hasExternalData ? napi_external : napi_object; - break; - } - return napi_ok; -} - -napi_status napi_get_undefined(napi_env env, napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - CHECK_JSRT(env, JsGetUndefinedValue(reinterpret_cast(result))); - return napi_ok; -} - -napi_status napi_get_null(napi_env env, napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - CHECK_JSRT(env, JsGetNullValue(reinterpret_cast(result))); - return napi_ok; -} - -napi_status napi_get_cb_info(napi_env env, // [in] NAPI environment handle - napi_callback_info cbinfo, // [in] Opaque callback-info handle - size_t* argc, // [in-out] Specifies the size of the provided argv array - // and receives the actual count of args. - napi_value* argv, // [out] Array of values - napi_value* this_arg, // [out] Receives the JS 'this' arg for the call - void** data) { // [out] Receives the data pointer for the callback. - CHECK_ENV(env); - CHECK_ARG(env, cbinfo); - const CallbackInfo* info = reinterpret_cast(cbinfo); - - if (argv != nullptr) { - CHECK_ARG(env, argc); - - size_t i = 0; - size_t min = std::min(*argc, static_cast(info->argc)); - - for (; i < min; i++) { - argv[i] = info->argv[i]; - } - - if (i < *argc) { - napi_value undefined; - CHECK_JSRT(env, - JsGetUndefinedValue(reinterpret_cast(&undefined))); - for (; i < *argc; i++) { - argv[i] = undefined; - } - } - } - - if (argc != nullptr) { - *argc = info->argc; - } - - if (this_arg != nullptr) { - *this_arg = info->thisArg; - } - - if (data != nullptr) { - *data = info->data; - } - - return napi_ok; -} - -napi_status napi_get_new_target(napi_env env, - napi_callback_info cbinfo, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, cbinfo); - CHECK_ARG(env, result); - - const CallbackInfo* info = reinterpret_cast(cbinfo); - if (info->isConstructCall) { - *result = info->newTarget; - } else { - *result = nullptr; - } - - return napi_ok; -} - -napi_status napi_call_function(napi_env env, - napi_value recv, - napi_value func, - size_t argc, - const napi_value* argv, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, recv); - if (argc > 0) { - CHECK_ARG(env, argv); - } - - JsValueRef object = reinterpret_cast(recv); - JsValueRef function = reinterpret_cast(func); - std::vector args(argc + 1); - args[0] = object; - for (size_t i = 0; i < argc; i++) { - args[i + 1] = reinterpret_cast(argv[i]); - } - JsValueRef returnValue; - CHECK_JSRT(env, JsCallFunction( - function, - args.data(), - static_cast(argc + 1), - &returnValue)); - if (result != nullptr) { - *result = reinterpret_cast(returnValue); - } - return napi_ok; -} - -napi_status napi_get_global(napi_env env, napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - CHECK_JSRT(env, JsGetGlobalObject(reinterpret_cast(result))); - return napi_ok; -} - -napi_status napi_throw(napi_env env, napi_value error) { - CHECK_ENV(env); - JsValueRef exception = reinterpret_cast(error); - CHECK_JSRT(env, JsSetException(exception)); - return napi_ok; -} - -napi_status napi_throw_error(napi_env env, - const char* code, - const char* msg) { - CHECK_ENV(env); - JsValueRef strRef; - JsValueRef exception; - size_t length = strlen(msg); - CHECK_JSRT(env, JsCreateString(msg, length, &strRef)); - CHECK_JSRT(env, JsCreateError(strRef, &exception)); - CHECK_NAPI(SetErrorCode(env, exception, nullptr, code)); - CHECK_JSRT(env, JsSetException(exception)); - return napi_ok; -} - -napi_status napi_throw_type_error(napi_env env, - const char* code, - const char* msg) { - CHECK_ENV(env); - JsValueRef strRef; - JsValueRef exception; - size_t length = strlen(msg); - CHECK_JSRT(env, JsCreateString(msg, length, &strRef)); - CHECK_JSRT(env, JsCreateTypeError(strRef, &exception)); - CHECK_NAPI(SetErrorCode(env, exception, nullptr, code)); - CHECK_JSRT(env, JsSetException(exception)); - return napi_ok; -} - -napi_status napi_throw_range_error(napi_env env, - const char* code, - const char* msg) { - CHECK_ENV(env); - JsValueRef strRef; - JsValueRef exception; - size_t length = strlen(msg); - CHECK_JSRT(env, JsCreateString(msg, length, &strRef)); - CHECK_JSRT(env, JsCreateRangeError(strRef, &exception)); - CHECK_NAPI(SetErrorCode(env, exception, nullptr, code)); - CHECK_JSRT(env, JsSetException(exception)); - return napi_ok; -} - -napi_status napi_is_error(napi_env env, napi_value value, bool* result) { - CHECK_ENV(env); - CHECK_ARG(env, value); - CHECK_ARG(env, result); - JsValueType valueType; - CHECK_JSRT(env, JsGetValueType(value, &valueType)); - *result = (valueType == JsError); - return napi_ok; -} - -napi_status napi_get_value_double(napi_env env, napi_value value, double* result) { - CHECK_ENV(env); - CHECK_ARG(env, value); - CHECK_ARG(env, result); - JsValueRef jsValue = reinterpret_cast(value); - CHECK_JSRT_EXPECTED(env, JsNumberToDouble(jsValue, result), napi_number_expected); - return napi_ok; -} - -napi_status napi_get_value_int32(napi_env env, napi_value v, int32_t* result) { - CHECK_ENV(env); - CHECK_ARG(env, v); - CHECK_ARG(env, result); - JsValueRef value = reinterpret_cast(v); - int valueInt; - CHECK_JSRT_EXPECTED(env, JsNumberToInt(value, &valueInt), napi_number_expected); - *result = static_cast(valueInt); - return napi_ok; -} - -napi_status napi_get_value_uint32(napi_env env, napi_value value, uint32_t* result) { - CHECK_ENV(env); - CHECK_ARG(env, value); - CHECK_ARG(env, result); - JsValueRef jsValue = reinterpret_cast(value); - int valueInt; - CHECK_JSRT_EXPECTED(env, JsNumberToInt(jsValue, &valueInt), napi_number_expected); - *result = static_cast(valueInt); - return napi_ok; -} - -napi_status napi_get_value_int64(napi_env env, napi_value value, int64_t* result) { - CHECK_ENV(env); - CHECK_ARG(env, value); - CHECK_ARG(env, result); - - JsValueRef jsValue = reinterpret_cast(value); - - double valueDouble; - CHECK_JSRT_EXPECTED(env, JsNumberToDouble(jsValue, &valueDouble), - napi_number_expected); - - if (std::isfinite(valueDouble)) { - *result = static_cast(valueDouble); - } else { - *result = 0; - } - - return napi_ok; -} - -napi_status napi_get_value_bool(napi_env env, napi_value value, bool* result) { - CHECK_ENV(env); - CHECK_ARG(env, value); - CHECK_ARG(env, result); - JsValueRef jsValue = reinterpret_cast(value); - CHECK_JSRT_EXPECTED(env, JsBooleanToBool(jsValue, result), napi_boolean_expected); - return napi_ok; -} - -// Copies a JavaScript string into a LATIN-1 string buffer. The result is the -// number of bytes (excluding the null terminator) copied into buf. -// A sufficient buffer size should be greater than the length of string, -// reserving space for null terminator. -// If bufsize is insufficient, the string will be truncated and null terminated. -// If buf is NULL, this method returns the length of the string (in bytes) -// via the result parameter. -// The result argument is optional unless buf is NULL. -napi_status napi_get_value_string_latin1(napi_env env, - napi_value value, - char* buf, - size_t bufsize, - size_t* result) { - CHECK_ENV(env); - CHECK_ARG(env, value); - - JsValueRef jsValue = reinterpret_cast(value); - - if (!buf) { - CHECK_ARG(env, result); - CHECK_JSRT_EXPECTED(env, - JsCopyString(jsValue, nullptr, 0, result, CP_LATIN1), - napi_string_expected); - } else { - size_t count = 0; - CHECK_JSRT_EXPECTED(env, - JsCopyString(jsValue, nullptr, 0, &count), - napi_string_expected); - - if (bufsize <= count) { - // if bufsize == count there is no space for null terminator - // Slow path: must implement truncation here. - char* fullBuffer = static_cast(malloc(count)); - //CHAKRA_VERIFY(fullBuffer != nullptr); - - CHECK_JSRT_EXPECTED(env, - JsCopyString(jsValue, fullBuffer, count, nullptr), - napi_string_expected); - memmove(buf, fullBuffer, sizeof(char) * bufsize); - free(fullBuffer); - - // Truncate string to the start of the last codepoint - if (bufsize > 0 && - (((buf[bufsize-1] & 0x80) == 0) - || UTF8_MULTIBYTE_START(buf[bufsize-1])) - ) { - // Last byte is a single byte codepoint or - // starts a multibyte codepoint - bufsize -= 1; - } else if (bufsize > 1 && UTF8_MULTIBYTE_START(buf[bufsize-2])) { - // Second last byte starts a multibyte codepoint, - bufsize -= 2; - } else if (bufsize > 2 && UTF8_MULTIBYTE_START(buf[bufsize-3])) { - // Third last byte starts a multibyte codepoint - bufsize -= 3; - } else if (bufsize > 3 && UTF8_MULTIBYTE_START(buf[bufsize-4])) { - // Fourth last byte starts a multibyte codepoint - bufsize -= 4; - } - - buf[bufsize] = '\0'; - - if (result) { - *result = bufsize; - } - - return napi_ok; - } - - // Fastpath, result fits in the buffer - CHECK_JSRT_EXPECTED(env, - JsCopyString(jsValue, buf, bufsize-1, &count), - napi_string_expected); - - buf[count] = 0; - - if (result != nullptr) { - *result = count; - } - } - - return napi_ok; -} - -// Copies a JavaScript string into a UTF-8 string buffer. The result is the -// number of bytes (excluding the null terminator) copied into buf. -// A sufficient buffer size should be greater than the length of string, -// reserving space for null terminator. -// If bufsize is insufficient, the string will be truncated and null terminated. -// If buf is NULL, this method returns the length of the string (in bytes) -// via the result parameter. -// The result argument is optional unless buf is NULL. -napi_status napi_get_value_string_utf8(napi_env env, - napi_value value, - char* buf, - size_t bufsize, - size_t* result) { - CHECK_ENV(env); - CHECK_ARG(env, value); - - JsValueRef jsValue = reinterpret_cast(value); - - if (!buf) { - CHECK_ARG(env, result); - CHECK_JSRT_EXPECTED(env, - JsCopyString(jsValue, nullptr, 0, result), - napi_string_expected); - } else { - size_t count = 0; - CHECK_JSRT_EXPECTED(env, - JsCopyString(jsValue, nullptr, 0, &count), - napi_string_expected); - - if (bufsize <= count) { - // if bufsize == count there is no space for null terminator - // Slow path: must implement truncation here. - char* fullBuffer = static_cast(malloc(count)); - //CHAKRA_VERIFY(fullBuffer != nullptr); - - CHECK_JSRT_EXPECTED(env, - JsCopyString(jsValue, fullBuffer, count, nullptr), - napi_string_expected); - memmove(buf, fullBuffer, sizeof(char) * bufsize); - free(fullBuffer); - - // Truncate string to the start of the last codepoint - if (bufsize > 0 && - (((buf[bufsize-1] & 0x80) == 0) - || UTF8_MULTIBYTE_START(buf[bufsize-1])) - ) { - // Last byte is a single byte codepoint or - // starts a multibyte codepoint - bufsize -= 1; - } else if (bufsize > 1 && UTF8_MULTIBYTE_START(buf[bufsize-2])) { - // Second last byte starts a multibyte codepoint, - bufsize -= 2; - } else if (bufsize > 2 && UTF8_MULTIBYTE_START(buf[bufsize-3])) { - // Third last byte starts a multibyte codepoint - bufsize -= 3; - } else if (bufsize > 3 && UTF8_MULTIBYTE_START(buf[bufsize-4])) { - // Fourth last byte starts a multibyte codepoint - bufsize -= 4; - } - - buf[bufsize] = '\0'; - - if (result) { - *result = bufsize; - } - - return napi_ok; - } - - // Fastpath, result fits in the buffer - CHECK_JSRT_EXPECTED(env, - JsCopyString(jsValue, buf, bufsize-1, &count), - napi_string_expected); - - buf[count] = 0; - - if (result != nullptr) { - *result = count; - } - } - - return napi_ok; -} - -// Copies a JavaScript string into a UTF-16 string buffer. The result is the -// number of 2-byte code units (excluding the null terminator) copied into buf. -// A sufficient buffer size should be greater than the length of string, -// reserving space for null terminator. -// If bufsize is insufficient, the string will be truncated and null terminated. -// If buf is NULL, this method returns the length of the string (in 2-byte -// code units) via the result parameter. -// The result argument is optional unless buf is NULL. -napi_status napi_get_value_string_utf16(napi_env env, - napi_value value, - char16_t* buf, - size_t bufsize, - size_t* result) { - CHECK_ENV(env); - CHECK_ARG(env, value); - - JsValueRef jsValue = reinterpret_cast(value); - - if (!buf) { - CHECK_ARG(env, result); - - CHECK_JSRT_EXPECTED(env, - JsCopyStringUtf16(jsValue, nullptr, 0, result), - napi_string_expected); - } else { - size_t copied = 0; - CHECK_JSRT_EXPECTED(env, - JsCopyStringUtf16( - jsValue, - buf, - bufsize - 1, - &copied), - napi_string_expected); - - if (copied < bufsize - 1) { - buf[copied] = 0; - } else { - buf[bufsize - 1] = 0; - } - - if (result != nullptr) { - *result = copied; - } - } - - return napi_ok; -} - -napi_status napi_coerce_to_bool(napi_env env, - napi_value v, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - JsValueRef value = reinterpret_cast(v); - CHECK_JSRT(env, - JsConvertValueToBoolean(value, reinterpret_cast(result))); - return napi_ok; -} - -napi_status napi_coerce_to_number(napi_env env, - napi_value value, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, value); - CHECK_ARG(env, result); - JsValueRef jsValue = reinterpret_cast(value); - CHECK_JSRT(env, - JsConvertValueToNumber(jsValue, reinterpret_cast(result))); - return napi_ok; -} - -napi_status napi_coerce_to_object(napi_env env, - napi_value value, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, value); - CHECK_ARG(env, result); - JsValueRef jsValue = reinterpret_cast(value); - CHECK_JSRT(env, - JsConvertValueToObject(jsValue, reinterpret_cast(result))); - return napi_ok; -} - -napi_status napi_coerce_to_string(napi_env env, - napi_value value, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, value); - CHECK_ARG(env, result); - JsValueRef jsValue = reinterpret_cast(value); - CHECK_JSRT(env, - JsConvertValueToString(jsValue, reinterpret_cast(result))); - return napi_ok; -} - -napi_status napi_wrap(napi_env env, - napi_value js_object, - void* native_object, - napi_finalize finalize_cb, - void* finalize_hint, - napi_ref* result) { - CHECK_ENV(env); - CHECK_ARG(env, js_object); - - JsValueRef value = reinterpret_cast(js_object); - - JsValueRef wrapper = JS_INVALID_REFERENCE; - CHECK_NAPI(FindWrapper(env, value, &wrapper)); - RETURN_STATUS_IF_FALSE(env, wrapper == JS_INVALID_REFERENCE, napi_invalid_arg); - - ExternalData* externalData = new ExternalData( - env, native_object, finalize_cb, finalize_hint); - if (externalData == nullptr) return napi_set_last_error(env, napi_generic_failure); - - // Create an external object that will hold the external data pointer. - JsValueRef external = JS_INVALID_REFERENCE; - CHECK_JSRT(env, JsCreateExternalObject( - externalData, ExternalData::Finalize, &external)); - - // Insert the external object into the value's prototype chain. - JsValueRef valuePrototype = JS_INVALID_REFERENCE; - CHECK_JSRT(env, JsGetPrototype(value, &valuePrototype)); - CHECK_JSRT(env, JsSetPrototype(external, valuePrototype)); - CHECK_JSRT(env, JsSetPrototype(value, external)); - - if (result != nullptr) { - CHECK_NAPI(napi_create_reference(env, js_object, 0, result)); - } - - return napi_ok; -} - -napi_status napi_unwrap(napi_env env, napi_value js_object, void** result) { - CHECK_ENV(env); - CHECK_ARG(env, js_object); - - JsValueRef value = reinterpret_cast(js_object); - - ExternalData* externalData = nullptr; - CHECK_NAPI(Unwrap(env, value, &externalData)); - - *result = (externalData != nullptr ? externalData->Data() : nullptr); - - return napi_ok; -} - -napi_status napi_remove_wrap(napi_env env, napi_value js_object, void** result) { - CHECK_ENV(env); - CHECK_ARG(env, js_object); - - JsValueRef value = reinterpret_cast(js_object); - - ExternalData* externalData = nullptr; - JsValueRef parent = JS_INVALID_REFERENCE; - JsValueRef wrapper = JS_INVALID_REFERENCE; - CHECK_NAPI(Unwrap(env, value, &externalData, &wrapper, &parent)); - RETURN_STATUS_IF_FALSE(env, parent != JS_INVALID_REFERENCE, napi_invalid_arg); - RETURN_STATUS_IF_FALSE(env, wrapper != JS_INVALID_REFERENCE, napi_invalid_arg); - - // Remove the external from the prototype chain - JsValueRef wrapperProto = JS_INVALID_REFERENCE; - CHECK_JSRT(env, JsGetPrototype(wrapper, &wrapperProto)); - CHECK_JSRT(env, JsSetPrototype(parent, wrapperProto)); - - // Clear the external data from the object - CHECK_JSRT(env, JsSetExternalData(wrapper, nullptr)); - - if (externalData != nullptr) { - *result = externalData->Data(); - delete externalData; - } else { - *result = nullptr; - } - - return napi_ok; -} - -napi_status napi_create_external(napi_env env, - void* data, - napi_finalize finalize_cb, - void* finalize_hint, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - - ExternalData* externalData = new ExternalData( - env, data, finalize_cb, finalize_hint); - if (externalData == nullptr) return napi_set_last_error(env, napi_generic_failure); - - CHECK_JSRT(env, JsCreateExternalObject( - externalData, - ExternalData::Finalize, - reinterpret_cast(result))); - - return napi_ok; -} - -napi_status napi_get_value_external(napi_env env, napi_value value, void** result) { - CHECK_ENV(env); - CHECK_ARG(env, value); - CHECK_ARG(env, result); - - ExternalData* externalData; - CHECK_JSRT(env, JsGetExternalData( - reinterpret_cast(value), - reinterpret_cast(&externalData))); - - *result = (externalData != nullptr ? externalData->Data() : nullptr); - - return napi_ok; -} - -// Set initial_refcount to 0 for a weak reference, >0 for a strong reference. -napi_status napi_create_reference(napi_env env, - napi_value value, - uint32_t initial_refcount, - napi_ref* result) { - CHECK_ENV(env); - CHECK_ARG(env, value); - CHECK_ARG(env, result); - - auto jsValue = reinterpret_cast(value); - auto info = new RefInfo{ reinterpret_cast(value), initial_refcount }; - if (info == nullptr) { - return napi_set_last_error(env, napi_generic_failure); - } - - if (info->count != 0) - { - CHECK_JSRT(env, JsAddRef(jsValue, nullptr)); - } - - *result = reinterpret_cast(info); - return napi_ok; -} - -// Deletes a reference. The referenced value is released, and may be GC'd -// unless there are other references to it. -napi_status napi_delete_reference(napi_env env, napi_ref ref) { - CHECK_ENV(env); - CHECK_ARG(env, ref); - - auto info = reinterpret_cast(ref); - - if (info->count != 0) { - CHECK_JSRT(env, JsRelease(info->value, nullptr)); - } - - delete info; - - return napi_ok; -} - -// Increments the reference count, optionally returning the resulting count. -// After this call the reference will be a strong reference because its refcount -// is >0, and the referenced object is effectively "pinned". Calling this when -// the refcount is 0 and the target is unavailable results in an error. -napi_status napi_reference_ref(napi_env env, napi_ref ref, uint32_t* result) { - CHECK_ENV(env); - CHECK_ARG(env, ref); - auto info = reinterpret_cast(ref); - if (info->count++ == 0) { - CHECK_JSRT(env, JsAddRef(info->value, nullptr)); - } - if (result != nullptr) { - *result = info->count; - } - return napi_ok; -} - -// Decrements the reference count, optionally returning the resulting count. -// If the result is 0 the reference is now weak and the object may be GC'd at -// any time if there are no other references. Calling this when the refcount -// is already 0 results in an error. -napi_status napi_reference_unref(napi_env env, napi_ref ref, uint32_t* result) { - CHECK_ENV(env); - CHECK_ARG(env, ref); - auto info = reinterpret_cast(ref); - if (--info->count == 0) { - CHECK_JSRT(env, JsRelease(info->value, nullptr)); - } - if (result != nullptr) { - *result = info->count; - } - return napi_ok; -} - -// Attempts to get a referenced value. If the reference is weak, the value -// might no longer be available, in that case the call is still successful but -// the result is NULL. -napi_status napi_get_reference_value(napi_env env, - napi_ref ref, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, ref); - CHECK_ARG(env, result); - auto info = reinterpret_cast(ref); - if (info->count == 0) { - *result = nullptr; - } else { - *result = reinterpret_cast(info->value); - } - return napi_ok; -} - -// Stub implementation of handle scope apis for JSRT. -napi_status napi_open_handle_scope(napi_env env, napi_handle_scope* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - *result = reinterpret_cast(1); - return napi_ok; -} - -// Stub implementation of handle scope apis for JSRT. -napi_status napi_close_handle_scope(napi_env env, napi_handle_scope scope) { - CHECK_ENV(env); - CHECK_ARG(env, scope); - return napi_ok; -} - -// Stub implementation of handle scope apis for JSRT. -napi_status napi_open_escapable_handle_scope( - napi_env env, - napi_escapable_handle_scope* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - *result = reinterpret_cast(1); - return napi_ok; -} - -// Stub implementation of handle scope apis for JSRT. -napi_status napi_close_escapable_handle_scope( - napi_env env, - napi_escapable_handle_scope scope) { - CHECK_ENV(env); - CHECK_ARG(env, scope); - return napi_ok; -} - -// Stub implementation of handle scope apis for JSRT. -// This one will return escapee value as this is called from leveldown db. -napi_status napi_escape_handle(napi_env env, - napi_escapable_handle_scope scope, - napi_value escapee, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, scope); - CHECK_ARG(env, escapee); - CHECK_ARG(env, result); - *result = escapee; - return napi_ok; -} - -napi_status napi_new_instance(napi_env env, - napi_value constructor, - size_t argc, - const napi_value* argv, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, constructor); - if (argc > 0) { - CHECK_ARG(env, argv); - } - CHECK_ARG(env, result); - JsValueRef function = reinterpret_cast(constructor); - std::vector args(argc + 1); - CHECK_JSRT(env, JsGetUndefinedValue(&args[0])); - for (size_t i = 0; i < argc; i++) { - args[i + 1] = reinterpret_cast(argv[i]); - } - CHECK_JSRT(env, JsConstructObject( - function, - args.data(), - static_cast(argc + 1), - reinterpret_cast(result))); - return napi_ok; -} - -napi_status napi_instanceof(napi_env env, - napi_value object, - napi_value c, - bool* result) { - CHECK_ENV(env); - CHECK_ARG(env, object); - CHECK_ARG(env, result); - JsValueRef obj = reinterpret_cast(object); - JsValueRef constructor = reinterpret_cast(c); - - // FIXME: Remove this type check when we switch to a version of Chakracore - // where passing an integer into JsInstanceOf as the constructor parameter - // does not cause a segfault. The need for this if-statement is removed in at - // least Chakracore 1.4.0, but maybe in an earlier version too. - napi_valuetype valuetype; - CHECK_NAPI(napi_typeof(env, c, &valuetype)); - if (valuetype != napi_function) { - napi_throw_type_error(env, - "ERR_NAPI_CONS_FUNCTION", - "constructor must be a function"); - - return napi_set_last_error(env, napi_invalid_arg); - } - - CHECK_JSRT(env, JsInstanceOf(obj, constructor, result)); - return napi_ok; -} - -napi_status napi_is_exception_pending(napi_env env, bool* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - CHECK_JSRT(env, JsHasException(result)); - return napi_ok; -} - -napi_status napi_get_and_clear_last_exception(napi_env env, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - - bool hasException; - CHECK_JSRT(env, JsHasException(&hasException)); - if (hasException) { - CHECK_JSRT(env, JsGetAndClearException(reinterpret_cast(result))); - } else { - CHECK_NAPI(napi_get_undefined(env, result)); - } - - return napi_ok; -} - -napi_status napi_is_arraybuffer(napi_env env, napi_value value, bool* result) { - CHECK_ENV(env); - CHECK_ARG(env, value); - CHECK_ARG(env, result); - - JsValueRef jsValue = reinterpret_cast(value); - JsValueType valueType; - CHECK_JSRT(env, JsGetValueType(jsValue, &valueType)); - - *result = (valueType == JsArrayBuffer); - return napi_ok; -} - -napi_status napi_create_arraybuffer(napi_env env, - size_t byte_length, - void** data, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - - JsValueRef arrayBuffer; - CHECK_JSRT(env, - JsCreateArrayBuffer(static_cast(byte_length), &arrayBuffer)); - - if (data != nullptr) { - CHECK_JSRT(env, JsGetArrayBufferStorage( - arrayBuffer, - reinterpret_cast(data), - reinterpret_cast(&byte_length))); - } - - *result = reinterpret_cast(arrayBuffer); - return napi_ok; -} - -napi_status napi_create_external_arraybuffer(napi_env env, - void* external_data, - size_t byte_length, - napi_finalize finalize_cb, - void* finalize_hint, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - - ExternalData* externalData = new ExternalData( - env, external_data, finalize_cb, finalize_hint); - if (externalData == nullptr) return napi_set_last_error(env, napi_generic_failure); - - JsValueRef arrayBuffer; - CHECK_JSRT(env, JsCreateExternalArrayBuffer( - external_data, - static_cast(byte_length), - ExternalData::Finalize, - externalData, - &arrayBuffer)); - - *result = reinterpret_cast(arrayBuffer); - return napi_ok; -} - -napi_status napi_get_arraybuffer_info(napi_env env, - napi_value arraybuffer, - void** data, - size_t* byte_length) { - CHECK_ENV(env); - CHECK_ARG(env, arraybuffer); - - BYTE* storageData; - unsigned int storageLength; - CHECK_JSRT(env, JsGetArrayBufferStorage( - reinterpret_cast(arraybuffer), - &storageData, - &storageLength)); - - if (data != nullptr) { - *data = reinterpret_cast(storageData); - } - - if (byte_length != nullptr) { - *byte_length = static_cast(storageLength); - } - - return napi_ok; -} - -napi_status napi_is_typedarray(napi_env env, napi_value value, bool* result) { - CHECK_ENV(env); - CHECK_ARG(env, value); - CHECK_ARG(env, result); - - JsValueRef jsValue = reinterpret_cast(value); - JsValueType valueType; - CHECK_JSRT(env, JsGetValueType(jsValue, &valueType)); - - *result = (valueType == JsTypedArray); - return napi_ok; -} - -napi_status napi_create_typedarray(napi_env env, - napi_typedarray_type type, - size_t length, - napi_value arraybuffer, - size_t byte_offset, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, arraybuffer); - CHECK_ARG(env, result); - - JsTypedArrayType jsType; - switch (type) { - case napi_int8_array: - jsType = JsArrayTypeInt8; - break; - case napi_uint8_array: - jsType = JsArrayTypeUint8; - break; - case napi_uint8_clamped_array: - jsType = JsArrayTypeUint8Clamped; - break; - case napi_int16_array: - jsType = JsArrayTypeInt16; - break; - case napi_uint16_array: - jsType = JsArrayTypeUint16; - break; - case napi_int32_array: - jsType = JsArrayTypeInt32; - break; - case napi_uint32_array: - jsType = JsArrayTypeUint32; - break; - case napi_float32_array: - jsType = JsArrayTypeFloat32; - break; - case napi_float64_array: - jsType = JsArrayTypeFloat64; - break; - default: - return napi_set_last_error(env, napi_invalid_arg); - } - - JsValueRef jsArrayBuffer = reinterpret_cast(arraybuffer); - - CHECK_JSRT(env, JsCreateTypedArray( - jsType, - jsArrayBuffer, - static_cast(byte_offset), - static_cast(length), - reinterpret_cast(result))); - - return napi_ok; -} - -napi_status napi_get_typedarray_info(napi_env env, - napi_value typedarray, - napi_typedarray_type* type, - size_t* length, - void** data, - napi_value* arraybuffer, - size_t* byte_offset) { - CHECK_ENV(env); - CHECK_ARG(env, typedarray); - - JsTypedArrayType jsType; - JsValueRef jsArrayBuffer; - unsigned int byteOffset; - unsigned int byteLength; - BYTE* bufferData; - unsigned int bufferLength; - int elementSize; - - CHECK_JSRT(env, JsGetTypedArrayInfo( - reinterpret_cast(typedarray), - &jsType, - &jsArrayBuffer, - &byteOffset, - &byteLength)); - - CHECK_JSRT(env, JsGetTypedArrayStorage( - reinterpret_cast(typedarray), - &bufferData, - &bufferLength, - &jsType, - &elementSize)); - - if (type != nullptr) { - switch (jsType) { - case JsArrayTypeInt8: - *type = napi_int8_array; - break; - case JsArrayTypeUint8: - *type = napi_uint8_array; - break; - case JsArrayTypeUint8Clamped: - *type = napi_uint8_clamped_array; - break; - case JsArrayTypeInt16: - *type = napi_int16_array; - break; - case JsArrayTypeUint16: - *type = napi_uint16_array; - break; - case JsArrayTypeInt32: - *type = napi_int32_array; - break; - case JsArrayTypeUint32: - *type = napi_uint32_array; - break; - case JsArrayTypeFloat32: - *type = napi_float32_array; - break; - case JsArrayTypeFloat64: - *type = napi_float64_array; - break; - default: - return napi_set_last_error(env, napi_generic_failure); - } - } - - if (length != nullptr) { - *length = static_cast(byteLength / elementSize); - } - - if (data != nullptr) { - *data = static_cast(bufferData); - } - - if (arraybuffer != nullptr) { - *arraybuffer = reinterpret_cast(jsArrayBuffer); - } - - if (byte_offset != nullptr) { - *byte_offset = static_cast(byteOffset); - } - - return napi_ok; -} - -napi_status napi_create_dataview(napi_env env, - size_t byte_length, - napi_value arraybuffer, - size_t byte_offset, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, arraybuffer); - CHECK_ARG(env, result); - - JsValueRef jsArrayBuffer = reinterpret_cast(arraybuffer); - - BYTE* unused = nullptr; - unsigned int bufferLength = 0; - - CHECK_JSRT(env, JsGetArrayBufferStorage( - jsArrayBuffer, - &unused, - &bufferLength)); - - if (byte_length + byte_offset > bufferLength) { - napi_throw_range_error( - env, - "ERR_NAPI_INVALID_DATAVIEW_ARGS", - "byte_offset + byte_length should be less than or " - "equal to the size in bytes of the array passed in"); - return napi_set_last_error(env, napi_pending_exception); - } - - JsValueRef jsDataView; - CHECK_JSRT(env, JsCreateDataView( - jsArrayBuffer, - static_cast(byte_offset), - static_cast(byte_length), - &jsDataView)); - - auto dataViewInfo = new DataViewInfo{ jsDataView, jsArrayBuffer, byte_offset, byte_length }; - CHECK_JSRT(env, JsCreateExternalObject(dataViewInfo, DataViewInfo::Finalize, reinterpret_cast(result))); - - return napi_ok; -} - -napi_status napi_is_dataview(napi_env env, napi_value value, bool* result) { - CHECK_ENV(env); - CHECK_ARG(env, value); - CHECK_ARG(env, result); - - JsValueRef jsValue = reinterpret_cast(value); - JsValueType valueType; - CHECK_JSRT(env, JsGetValueType(jsValue, &valueType)); - - *result = (valueType == JsDataView); - return napi_ok; -} - -napi_status napi_get_dataview_info(napi_env env, - napi_value dataview, - size_t* byte_length, - void** data, - napi_value* arraybuffer, - size_t* byte_offset) { - CHECK_ENV(env); - CHECK_ARG(env, dataview); - - BYTE* bufferData = nullptr; - unsigned int bufferLength = 0; - - JsValueRef jsExternalObject = reinterpret_cast(dataview); - - DataViewInfo* dataViewInfo; - CHECK_JSRT(env, JsGetExternalData( - jsExternalObject, - reinterpret_cast(&dataViewInfo))); - - CHECK_JSRT(env, JsGetDataViewStorage( - dataViewInfo->dataView, - &bufferData, - &bufferLength)); - - if (byte_length != nullptr) { - *byte_length = dataViewInfo->byteLength; - } - - if (data != nullptr) { - *data = static_cast(bufferData); - } - - if (arraybuffer != nullptr) { - *arraybuffer = reinterpret_cast(dataViewInfo->arrayBuffer); - } - - if (byte_offset != nullptr) { - *byte_offset = dataViewInfo->byteOffset; - } - - return napi_ok; -} - -napi_status napi_get_version(napi_env env, uint32_t* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - *result = NAPI_VERSION; - return napi_ok; -} - -napi_status napi_create_promise(napi_env env, - napi_deferred* deferred, - napi_value* promise) { - CHECK_ARG(env, deferred); - CHECK_ARG(env, promise); - - JsValueRef js_promise, resolve, reject, container; - napi_ref ref; - napi_value js_deferred; - - CHECK_JSRT(env, JsCreatePromise(&js_promise, &resolve, &reject)); - - CHECK_JSRT(env, JsCreateObject(&container)); - js_deferred = reinterpret_cast(container); - - CHECK_NAPI(napi_set_named_property(env, js_deferred, "resolve", - reinterpret_cast(resolve))); - CHECK_NAPI(napi_set_named_property(env, js_deferred, "reject", - reinterpret_cast(reject))); - - CHECK_NAPI(napi_create_reference(env, js_deferred, 1, &ref)); - - *deferred = reinterpret_cast(ref); - *promise = reinterpret_cast(js_promise); - - return napi_ok; -} - -napi_status napi_resolve_deferred(napi_env env, - napi_deferred deferred, - napi_value resolution) { - return ConcludeDeferred(env, deferred, "resolve", resolution); -} - -napi_status napi_reject_deferred(napi_env env, - napi_deferred deferred, - napi_value rejection) { - return ConcludeDeferred(env, deferred, "reject", rejection); -} - -napi_status napi_is_promise(napi_env env, - napi_value promise, - bool* is_promise) { - CHECK_ENV(env); - CHECK_ARG(env, promise); - CHECK_ARG(env, is_promise); - - napi_value global, promise_ctor; - - CHECK_NAPI(napi_get_global(env, &global)); - CHECK_NAPI(napi_get_named_property(env, global, "Promise", &promise_ctor)); - CHECK_NAPI(napi_instanceof(env, promise, promise_ctor, is_promise)); - - return napi_ok; -} - -napi_status napi_run_script(napi_env env, - napi_value script, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, script); - CHECK_ARG(env, result); - - JsValueRef scriptVar = reinterpret_cast(script); - - const wchar_t* scriptStr; - size_t scriptStrLen; - CHECK_JSRT(env, JsStringToPointer(scriptVar, &scriptStr, &scriptStrLen)); - CHECK_JSRT_EXPECTED(env, JsRunScript(scriptStr, ++env->source_context, L"Unknown", reinterpret_cast(result)), napi_string_expected); - - return napi_ok; -} - -napi_status napi_run_script(napi_env env, - napi_value script, - const char* source_url, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, script); - CHECK_ARG(env, result); - JsValueRef scriptVar = reinterpret_cast(script); - - const wchar_t* scriptStr; - size_t scriptStrLen; - CHECK_JSRT(env, JsStringToPointer(scriptVar, &scriptStr, &scriptStrLen)); - CHECK_JSRT_EXPECTED(env, JsRunScript(scriptStr, ++env->source_context, NarrowToWide({ source_url }).data(), reinterpret_cast(result)), napi_string_expected); - - return napi_ok; -} - -napi_status napi_add_finalizer(napi_env env, - napi_value js_object, - void* native_object, - napi_finalize finalize_cb, - void* finalize_hint, - napi_ref* result) { - throw std::runtime_error("not impl"); -} - -napi_status napi_adjust_external_memory(napi_env env, - int64_t change_in_bytes, - int64_t* adjusted_value) { - CHECK_ENV(env); - CHECK_ARG(env, adjusted_value); - - // TODO(jackhorton): Determine if Chakra needs or is able to do anything here - // For now, we can lie and say that we always adjusted more memory - *adjusted_value = change_in_bytes; - - return napi_ok; -} diff --git a/Dependencies/napi/napi-direct/source/js_native_api_chakra.h b/Dependencies/napi/napi-direct/source/js_native_api_chakra.h deleted file mode 100644 index b884b4d02..000000000 --- a/Dependencies/napi/napi-direct/source/js_native_api_chakra.h +++ /dev/null @@ -1,98 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -struct napi_env__ { - JsSourceContext source_context = JS_SOURCE_CONTEXT_NONE; - napi_extended_error_info last_error{ nullptr, nullptr, 0, napi_ok }; - JsValueRef has_own_property_function = JS_INVALID_REFERENCE; - - const std::thread::id thread_id{std::this_thread::get_id()}; -}; - -#define RETURN_STATUS_IF_FALSE(env, condition, status) \ - do { \ - if (!(condition)) { \ - return napi_set_last_error((env), (status)); \ - } \ - } while (0) - -#define CHECK_ENV(env) \ - do { \ - if ((env) == nullptr) { \ - return napi_invalid_arg; \ - } \ - assert(env->thread_id == std::this_thread::get_id()); \ - } while (0) - -#define CHECK_ARG(env, arg) \ - RETURN_STATUS_IF_FALSE((env), ((arg) != nullptr), napi_invalid_arg) - -#define CHECK_JSRT(env, expr) \ - do { \ - JsErrorCode err = (expr); \ - if (err != JsNoError) return napi_set_last_error(env, err); \ - } while (0) - -#define CHECK_JSRT_EXPECTED(env, expr, expected) \ - do { \ - JsErrorCode err = (expr); \ - if (err == JsErrorInvalidArgument) \ - return napi_set_last_error(env, expected); \ - if (err != JsNoError) return napi_set_last_error(env, err); \ - } while (0) - -#define CHECK_JSRT_ERROR_CODE(operation) \ - do { \ - auto result = operation; \ - if (result != JsErrorCode::JsNoError) return result; \ - } while (0) - -// This does not call napi_set_last_error because the expression -// is assumed to be a NAPI function call that already did. -#define CHECK_NAPI(expr) \ - do { \ - napi_status status = (expr); \ - if (status != napi_ok) return status; \ - } while (0) - -// utf8 multibyte codepoint start check -#define UTF8_MULTIBYTE_START(c) (((c) & 0xC0) == 0xC0) - -#define STR_AND_LENGTH(str) str, sizeof(str) - 1 - -static void napi_clear_last_error(napi_env env) { - env->last_error.error_code = napi_ok; - env->last_error.engine_error_code = 0; - env->last_error.engine_reserved = nullptr; -} - -static napi_status napi_set_last_error(napi_env env, napi_status error_code, uint32_t engine_error_code = 0, void* engine_reserved = nullptr) { - env->last_error.error_code = error_code; - env->last_error.engine_error_code = engine_error_code; - env->last_error.engine_reserved = engine_reserved; - - return error_code; -} - -static napi_status napi_set_last_error(napi_env env, JsErrorCode jsError, void* engine_reserved = nullptr) { - napi_status status; - switch (jsError) { - case JsNoError: status = napi_ok; break; - case JsErrorNullArgument: - case JsErrorInvalidArgument: status = napi_invalid_arg; break; - case JsErrorPropertyNotString: status = napi_string_expected; break; - case JsErrorArgumentNotObject: status = napi_object_expected; break; - case JsErrorScriptException: - case JsErrorInExceptionState: status = napi_pending_exception; break; - default: status = napi_generic_failure; break; - } - - env->last_error.error_code = status; - env->last_error.engine_error_code = jsError; - env->last_error.engine_reserved = engine_reserved; - return status; -} diff --git a/Dependencies/napi/napi-direct/source/js_native_api_chakra_internals.h b/Dependencies/napi/napi-direct/source/js_native_api_chakra_internals.h deleted file mode 100644 index 6f70f09be..000000000 --- a/Dependencies/napi/napi-direct/source/js_native_api_chakra_internals.h +++ /dev/null @@ -1 +0,0 @@ -#pragma once diff --git a/Dependencies/napi/napi-direct/source/js_native_api_javascriptcore.cc b/Dependencies/napi/napi-direct/source/js_native_api_javascriptcore.cc deleted file mode 100644 index 6f0549797..000000000 --- a/Dependencies/napi/napi-direct/source/js_native_api_javascriptcore.cc +++ /dev/null @@ -1,2456 +0,0 @@ -#include "js_native_api_javascriptcore.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct napi_callback_info__ { - napi_value newTarget; - napi_value thisArg; - napi_value* argv; - void* data; - uint16_t argc; -}; - -namespace { - class JSString { - public: - JSString(const JSString&) = delete; - - JSString(JSString&& other) { - _string = other._string; - other._string = nullptr; - } - - JSString(const char* string, size_t length = NAPI_AUTO_LENGTH) - : _string{CreateUTF8(string, length)} { - } - - JSString(const JSChar* string, size_t length = NAPI_AUTO_LENGTH) - : _string{JSStringCreateWithCharacters(string, length == NAPI_AUTO_LENGTH ? std::char_traits::length(string) : length)} { - } - - ~JSString() { - if (_string != nullptr) { - JSStringRelease(_string); - } - } - - static JSString Attach(JSStringRef string) { - return {string}; - } - - operator JSStringRef() const { - return _string; - } - - size_t Length() const { - return JSStringGetLength(_string); - } - - size_t LengthUTF8() const { - std::vector buffer(JSStringGetMaximumUTF8CStringSize(_string)); - return JSStringGetUTF8CString(_string, buffer.data(), buffer.size()) - 1; - } - - size_t LengthLatin1() const { - // Latin1 has the same length as Unicode. - return JSStringGetLength(_string); - } - - void CopyTo(JSChar* buf, size_t bufsize, size_t* result) const { - size_t length{JSStringGetLength(_string)}; - const JSChar* chars{JSStringGetCharactersPtr(_string)}; - size_t size{std::min(length, bufsize - 1)}; - std::memcpy(buf, chars, size); - buf[size] = 0; - if (result != nullptr) { - *result = size; - } - } - - void CopyToUTF8(char* buf, size_t bufsize, size_t* result) const { - size_t size{JSStringGetUTF8CString(_string, buf, bufsize)}; - if (result != nullptr) { - // JSStringGetUTF8CString returns size with null terminator. - *result = size - 1; - } - } - - void CopyToLatin1(char* buf, size_t bufsize, size_t* result) const { - size_t length{JSStringGetLength(_string)}; - const JSChar* chars{JSStringGetCharactersPtr(_string)}; - size_t size{std::min(length, bufsize - 1)}; - for (int i = 0; i < size; ++i) { - const JSChar ch{chars[i]}; - buf[i] = (ch < 256) ? ch : '?'; - } - if (result != nullptr) { - *result = size; - } - } - - private: - static JSStringRef CreateUTF8(const char* string, size_t length) { - if (length == NAPI_AUTO_LENGTH) { - return JSStringCreateWithUTF8CString(string); - } - - std::u16string u16str{std::wstring_convert< - std::codecvt_utf8_utf16, char16_t>{}.from_bytes(string, string + length)}; - return JSStringCreateWithCharacters(reinterpret_cast(u16str.data()), u16str.size()); - } - - JSString(JSStringRef string) - : _string{string} { - } - - JSStringRef _string; - }; - - JSValueRef ToJSValue(const napi_value value) { - return reinterpret_cast(value); - } - - const JSValueRef* ToJSValues(const napi_value* values) { - return reinterpret_cast(values); - } - - JSObjectRef ToJSObject(napi_env env, const napi_value value) { - assert(value == nullptr || JSValueIsObject(env->context, reinterpret_cast(value))); - return reinterpret_cast(value); - } - - JSString ToJSString(napi_env env, napi_value value, JSValueRef* exception) { - return JSString::Attach(JSValueToStringCopy(env->context, ToJSValue(value), exception)); - } - - napi_value ToNapi(const JSValueRef value) { - return reinterpret_cast(const_cast(value)); - } - - napi_value* ToNapi(const JSValueRef* values) { - return reinterpret_cast(const_cast(values)); - } - - napi_status napi_clear_last_error(napi_env env) { - env->last_error.error_code = napi_ok; - env->last_error.engine_error_code = 0; - env->last_error.engine_reserved = nullptr; - return napi_ok; - } - - napi_status napi_set_last_error(napi_env env, napi_status error_code, uint32_t engine_error_code = 0, void* engine_reserved = nullptr) { - env->last_error.error_code = error_code; - env->last_error.engine_error_code = engine_error_code; - env->last_error.engine_reserved = engine_reserved; - return error_code; - } - - napi_status napi_set_exception(napi_env env, JSValueRef exception) { - env->last_exception = exception; - return napi_set_last_error(env, napi_pending_exception); - } - - napi_status napi_set_error_code(napi_env env, - napi_value error, - napi_value code, - const char* code_cstring) { - napi_value code_value{code}; - if (code_value == nullptr) { - code_value = ToNapi(JSValueMakeString(env->context, JSString(code_cstring))); - } else { - RETURN_STATUS_IF_FALSE(env, JSValueIsString(env->context, ToJSValue(code_value)), napi_string_expected); - } - - CHECK_NAPI(napi_set_named_property(env, error, "code", code_value)); - return napi_ok; - } - - enum class NativeType { - Constructor, - External, - Function, - Reference, - Wrapper, - }; - - class NativeInfo { - public: - NativeType Type() const { - return _type; - } - - template - static T* Get(JSObjectRef obj) { - return reinterpret_cast(JSObjectGetPrivate(obj)); - } - - template - static T* FindInPrototypeChain(JSContextRef ctx, JSObjectRef obj) { - while (true) { - JSValueRef exception{}; - JSObjectRef prototype = JSValueToObject(ctx, JSObjectGetPrototype(ctx, obj), &exception); - if (exception != nullptr) { - return nullptr; - } - - NativeInfo* info = Get(prototype); - if (info != nullptr && info->Type() == T::StaticType) { - return reinterpret_cast(info); - } - - obj = prototype; - } - } - - protected: - NativeInfo(NativeType type) - : _type{type} { - } - - private: - NativeType _type; - }; - - class ConstructorInfo : public NativeInfo { - public: - static const NativeType StaticType = NativeType::Constructor; - - static napi_status Create(napi_env env, - const char* utf8name, - size_t length, - napi_callback cb, - void* data, - napi_value* result) { - ConstructorInfo* info{new ConstructorInfo(env, utf8name, length, cb, data)}; - if (info == nullptr) { - return napi_set_last_error(env, napi_generic_failure); - } - - JSObjectRef constructor{JSObjectMakeConstructor(env->context, nullptr, CallAsConstructor)}; - JSObjectRef prototype{JSObjectMake(env->context, info->_class, info)}; - JSObjectSetPrototype(env->context, prototype, JSObjectGetPrototype(env->context, constructor)); - JSObjectSetPrototype(env->context, constructor, prototype); - - JSValueRef exception{}; - JSObjectSetProperty(env->context, prototype, JSString("constructor"), constructor, - kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, &exception); - CHECK_JSC(env, exception); - - *result = ToNapi(constructor); - return napi_ok; - } - - private: - ConstructorInfo(napi_env env, const char* name, size_t length, napi_callback cb, void* data) - : NativeInfo{NativeType::Constructor} - , _env{env} - , _name{name, (length == NAPI_AUTO_LENGTH ? std::strlen(name) : length)} - , _cb{cb} - , _data{data} { - JSClassDefinition classDefinition{kJSClassDefinitionEmpty}; - classDefinition.className = _name.data(); - classDefinition.finalize = Finalize; - _class = JSClassCreate(&classDefinition); - } - - ~ConstructorInfo() { - JSClassRelease(_class); - } - - // JSObjectCallAsConstructorCallback - static JSObjectRef CallAsConstructor(JSContextRef ctx, - JSObjectRef constructor, - size_t argumentCount, - const JSValueRef arguments[], - JSValueRef* exception) { - ConstructorInfo* info = NativeInfo::FindInPrototypeChain(ctx, constructor); - - // Make sure any errors encountered last time we were in N-API are gone. - napi_clear_last_error(info->_env); - - JSObjectRef instance{JSObjectMake(ctx, nullptr, nullptr)}; - JSObjectSetPrototype(ctx, instance, JSObjectGetPrototype(ctx, constructor)); - - napi_callback_info__ cbinfo{}; - cbinfo.thisArg = ToNapi(instance); - cbinfo.newTarget = ToNapi(constructor); - cbinfo.argc = argumentCount; - cbinfo.argv = ToNapi(arguments); - cbinfo.data = info->_data; - - napi_value result = info->_cb(info->_env, &cbinfo); - - if (info->_env->last_exception != nullptr) { - *exception = info->_env->last_exception; - info->_env->last_exception = nullptr; - } - - return ToJSObject(info->_env, result); - } - - // JSObjectFinalizeCallback - static void Finalize(JSObjectRef object) { - ConstructorInfo* info = NativeInfo::Get(object); - assert(info->Type() == NativeType::Constructor); - delete info; - } - - private: - napi_env _env; - std::string _name; - napi_callback _cb; - void* _data; - JSClassRef _class; - }; - - class FunctionInfo : public NativeInfo { - public: - static const NativeType StaticType = NativeType::Function; - - static napi_status Create(napi_env env, - const char* utf8name, - size_t length, - napi_callback cb, - void* data, - napi_value* result) { - FunctionInfo* info{new FunctionInfo(env, cb, data)}; - if (info == nullptr) { - return napi_set_last_error(env, napi_generic_failure); - } - - JSObjectRef function{JSObjectMakeFunctionWithCallback(env->context, JSString(utf8name), CallAsFunction)}; - JSObjectRef prototype{JSObjectMake(env->context, info->_class, info)}; - JSObjectSetPrototype(env->context, prototype, JSObjectGetPrototype(env->context, function)); - JSObjectSetPrototype(env->context, function, prototype); - - *result = ToNapi(function); - return napi_ok; - } - - private: - FunctionInfo(napi_env env, napi_callback cb, void* data) - : NativeInfo{NativeType::Function} - , _env{env} - , _cb{cb} - , _data{data} { - JSClassDefinition definition{kJSClassDefinitionEmpty}; - definition.className = "Native"; - definition.finalize = Finalize; - _class = JSClassCreate(&definition); - } - - ~FunctionInfo() { - JSClassRelease(_class); - } - - // JSObjectCallAsFunctionCallback - static JSValueRef CallAsFunction(JSContextRef ctx, - JSObjectRef function, - JSObjectRef thisObject, - size_t argumentCount, - const JSValueRef arguments[], - JSValueRef* exception) { - FunctionInfo* info = NativeInfo::FindInPrototypeChain(ctx, function); - - // Make sure any errors encountered last time we were in N-API are gone. - napi_clear_last_error(info->_env); - - napi_callback_info__ cbinfo{}; - cbinfo.thisArg = ToNapi(thisObject); - cbinfo.newTarget = nullptr; - cbinfo.argc = argumentCount; - cbinfo.argv = ToNapi(arguments); - cbinfo.data = info->_data; - - napi_value result = info->_cb(info->_env, &cbinfo); - - if (info->_env->last_exception != nullptr) { - *exception = info->_env->last_exception; - info->_env->last_exception = nullptr; - } - - return ToJSValue(result); - } - - // JSObjectFinalizeCallback - static void Finalize(JSObjectRef object) { - FunctionInfo* info = NativeInfo::Get(object); - assert(info->Type() == NativeType::Function); - delete info; - } - - napi_env _env; - napi_callback _cb; - void* _data; - JSClassRef _class; - }; - - template - class BaseInfoT : public NativeInfo { - public: - static const NativeType StaticType = TType; - - ~BaseInfoT() { - JSClassRelease(_class); - } - - napi_env Env() const { - return _env; - } - - void Data(void* value) { - _data = value; - } - - void* Data() const { - return _data; - } - - using FinalizerT = std::function; - void AddFinalizer(FinalizerT finalizer) { - _finalizers.push_back(finalizer); - } - - protected: - BaseInfoT(napi_env env, const char* className) - : NativeInfo{TType} - , _env{env} { - JSClassDefinition definition{kJSClassDefinitionEmpty}; - definition.className = className; - definition.finalize = Finalize; - _class = JSClassCreate(&definition); - } - - // JSObjectFinalizeCallback - static void Finalize(JSObjectRef object) { - T* info = Get(object); - assert(info->Type() == TType); - for (const FinalizerT& finalizer : info->_finalizers) { - finalizer(info); - } - delete info; - } - - napi_env _env; - void* _data{}; - std::vector _finalizers{}; - JSClassRef _class{}; - }; - - class ExternalInfo: public BaseInfoT { - public: - static napi_status Create(napi_env env, - void* data, - napi_finalize finalize_cb, - void* finalize_hint, - napi_value* result) { - ExternalInfo* info = new ExternalInfo(env); - if (info == nullptr) { - return napi_set_last_error(env, napi_generic_failure); - } - - info->Data(data); - - if (finalize_cb != nullptr) { - info->AddFinalizer([finalize_cb, finalize_hint](ExternalInfo* info) { - finalize_cb(info->Env(), info->Data(), finalize_hint); - }); - } - - *result = ToNapi(JSObjectMake(env->context, info->_class, info)); - return napi_ok; - } - - private: - ExternalInfo(napi_env env) - : BaseInfoT{env, "Native (External)"} { - } - }; - - class ReferenceInfo : public BaseInfoT { - public: - static napi_status Initialize(napi_env env, napi_value object, FinalizerT finalizer) { - ReferenceInfo* info = new ReferenceInfo(env); - if (info == nullptr) { - return napi_set_last_error(env, napi_generic_failure); - } - - JSObjectRef prototype{JSObjectMake(env->context, info->_class, info)}; - JSObjectSetPrototype(env->context, prototype, JSObjectGetPrototype(env->context, ToJSObject(env, object))); - JSObjectSetPrototype(env->context, ToJSObject(env, object), prototype); - - info->AddFinalizer(finalizer); - return napi_ok; - } - - private: - ReferenceInfo(napi_env env) - : BaseInfoT{env, "Native (Reference)"} { - } - }; - - class WrapperInfo : public BaseInfoT { - public: - static napi_status Wrap(napi_env env, napi_value object, WrapperInfo** result) { - WrapperInfo* info{}; - CHECK_NAPI(Unwrap(env, object, &info)); - if (info == nullptr) { - info = new WrapperInfo(env); - if (info == nullptr) { - return napi_set_last_error(env, napi_generic_failure); - } - - JSObjectRef prototype{JSObjectMake(env->context, info->_class, info)}; - JSObjectSetPrototype(env->context, prototype, JSObjectGetPrototype(env->context, ToJSObject(env, object))); - JSObjectSetPrototype(env->context, ToJSObject(env, object), prototype); - } - - *result = info; - return napi_ok; - } - - static napi_status Unwrap(napi_env env, napi_value object, WrapperInfo** result) { - *result = NativeInfo::FindInPrototypeChain(env->context, ToJSObject(env, object)); - return napi_ok; - } - - private: - WrapperInfo(napi_env env) - : BaseInfoT{env, "Native (Wrapper)"} { - } - }; - - class ExternalArrayBufferInfo { - public: - static napi_status Create(napi_env env, - void* external_data, - size_t byte_length, - napi_finalize finalize_cb, - void* finalize_hint, - napi_value* result) { - ExternalArrayBufferInfo* info{new ExternalArrayBufferInfo(env, finalize_cb, finalize_hint)}; - if (info == nullptr) { - return napi_set_last_error(env, napi_generic_failure); - } - - JSValueRef exception{}; - *result = ToNapi(JSObjectMakeArrayBufferWithBytesNoCopy( - env->context, - external_data, - byte_length, - BytesDeallocator, - info, - &exception)); - CHECK_JSC(env, exception); - - return napi_ok; - } - - private: - ExternalArrayBufferInfo(napi_env env, napi_finalize finalize_cb, void* hint) - : _env{env} - , _cb{finalize_cb} - , _hint{hint} { - } - - // JSTypedArrayBytesDeallocator - static void BytesDeallocator(void* bytes, void* deallocatorContext) { - ExternalArrayBufferInfo* info{reinterpret_cast(deallocatorContext)}; - if (info->_cb != nullptr) { - info->_cb(info->_env, bytes, info->_hint); - } - delete info; - } - - napi_env _env; - napi_finalize _cb; - void* _hint; - }; -} - -struct napi_ref__ { - napi_ref__(napi_value value, uint32_t count) - : _value{value} - , _count{count} { - } - - napi_status init(napi_env env) { - // track the ref values to support weak refs - auto pair{env->active_ref_values.insert(_value)}; - if (pair.second) { - CHECK_NAPI(ReferenceInfo::Initialize(env, _value, [value = _value](ReferenceInfo* info) { - info->Env()->active_ref_values.erase(value); - })); - } - - if (_count != 0) { - protect(env); - } - - return napi_ok; - } - - void deinit(napi_env env) { - if (_count != 0) { - unprotect(env); - } - - _value = nullptr; - _count = 0; - } - - void ref(napi_env env) { - if (_count++ == 0) { - protect(env); - } - } - - void unref(napi_env env) { - if (--_count == 0) { - unprotect(env); - } - } - - uint32_t count() const { - return _count; - } - - napi_value value(napi_env env) const { - if (env->active_ref_values.find(_value) == env->active_ref_values.end()) { - return nullptr; - } - - return _value; - } - - private: - void protect(napi_env env) { - _iter = env->strong_refs.insert(env->strong_refs.end(), this); - JSValueProtect(env->context, ToJSValue(_value)); - } - - void unprotect(napi_env env) { - env->strong_refs.erase(_iter); - JSValueUnprotect(env->context, ToJSValue(_value)); - } - - napi_value _value{}; - uint32_t _count{}; - std::list::iterator _iter{}; -}; - -void napi_env__::deinit_refs() { - while (!strong_refs.empty()) { - napi_ref ref{strong_refs.front()}; - ref->deinit(this); - } -} - -// Warning: Keep in-sync with napi_status enum -static const char* error_messages[] = { - nullptr, - "Invalid argument", - "An object was expected", - "A string was expected", - "A string or symbol was expected", - "A function was expected", - "A number was expected", - "A boolean was expected", - "An array was expected", - "Unknown failure", - "An exception is pending", - "The async work item was cancelled", - "napi_escape_handle already called on scope", - "Invalid handle scope usage", - "Invalid callback scope usage", - "Thread-safe function queue is full", - "Thread-safe function handle is closing", - "A bigint was expected", -}; - -napi_status napi_get_last_error_info(napi_env env, - const napi_extended_error_info** result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - - // you must update this assert to reference the last message - // in the napi_status enum each time a new error message is added. - // We don't have a napi_status_last as this would result in an ABI - // change each time a message was added. - static_assert( - std::size(error_messages) == napi_bigint_expected + 1, - "Count of error messages must match count of error values"); - assert(env->last_error.error_code <= napi_callback_scope_mismatch); - - // Wait until someone requests the last error information to fetch the error - // message string - env->last_error.error_message = - error_messages[env->last_error.error_code]; - - *result = &env->last_error; - return napi_ok; -} - -napi_status napi_create_function(napi_env env, - const char* utf8name, - size_t length, - napi_callback cb, - void* callback_data, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - - CHECK_NAPI(FunctionInfo::Create(env, utf8name, length, cb, callback_data, result)); - return napi_ok; -} - -napi_status napi_define_class(napi_env env, - const char* utf8name, - size_t length, - napi_callback cb, - void* data, - size_t property_count, - const napi_property_descriptor* properties, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - - napi_value constructor{}; - CHECK_NAPI(ConstructorInfo::Create(env, utf8name, length, cb, data, &constructor)); - - int instancePropertyCount{0}; - int staticPropertyCount{0}; - for (size_t i = 0; i < property_count; i++) { - if ((properties[i].attributes & napi_static) != 0) { - staticPropertyCount++; - } else { - instancePropertyCount++; - } - } - - std::vector staticDescriptors{}; - std::vector instanceDescriptors{}; - staticDescriptors.reserve(staticPropertyCount); - instanceDescriptors.reserve(instancePropertyCount); - - for (size_t i = 0; i < property_count; i++) { - if ((properties[i].attributes & napi_static) != 0) { - staticDescriptors.push_back(properties[i]); - } else { - instanceDescriptors.push_back(properties[i]); - } - } - - if (staticPropertyCount > 0) { - CHECK_NAPI(napi_define_properties(env, - constructor, - staticDescriptors.size(), - staticDescriptors.data())); - } - - if (instancePropertyCount > 0) { - napi_value prototype{}; - CHECK_NAPI(napi_get_prototype(env, constructor, &prototype)); - - CHECK_NAPI(napi_define_properties(env, - prototype, - instanceDescriptors.size(), - instanceDescriptors.data())); - } - - *result = constructor; - return napi_ok; -} - -napi_status napi_get_property_names(napi_env env, - napi_value object, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - - napi_value global{}, object_ctor{}, function{}; - CHECK_NAPI(napi_get_global(env, &global)); - CHECK_NAPI(napi_get_named_property(env, global, "Object", &object_ctor)); - CHECK_NAPI(napi_get_named_property(env, object_ctor, "getOwnPropertyNames", &function)); - CHECK_NAPI(napi_call_function(env, object_ctor, function, 0, nullptr, result)); - - return napi_ok; -} - -napi_status napi_set_property(napi_env env, - napi_value object, - napi_value key, - napi_value value) { - CHECK_ENV(env); - CHECK_ARG(env, key); - CHECK_ARG(env, value); - - JSValueRef exception{}; - JSString key_str{ToJSString(env, key, &exception)}; - CHECK_JSC(env, exception); - - JSObjectSetProperty( - env->context, - ToJSObject(env, object), - key_str, - ToJSValue(value), - kJSPropertyAttributeNone, - &exception); - CHECK_JSC(env, exception); - - return napi_ok; -} - -napi_status napi_has_property(napi_env env, - napi_value object, - napi_value key, - bool* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - CHECK_ARG(env, key); - - JSValueRef exception{}; - JSString key_str{ToJSString(env, key, &exception)}; - CHECK_JSC(env, exception); - - *result = JSObjectHasProperty( - env->context, - ToJSObject(env, object), - key_str); - return napi_ok; -} - -napi_status napi_get_property(napi_env env, - napi_value object, - napi_value key, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, key); - CHECK_ARG(env, result); - - JSValueRef exception{}; - JSString key_str{ToJSString(env, key, &exception)}; - CHECK_JSC(env, exception); - - *result = ToNapi(JSObjectGetProperty( - env->context, - ToJSObject(env, object), - key_str, - &exception)); - CHECK_JSC(env, exception); - - return napi_ok; -} - -napi_status napi_delete_property(napi_env env, - napi_value object, - napi_value key, - bool* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - - JSValueRef exception{}; - JSString key_str{ToJSString(env, key, &exception)}; - CHECK_JSC(env, exception); - - *result = JSObjectDeleteProperty( - env->context, - ToJSObject(env, object), - key_str, - &exception); - CHECK_JSC(env, exception); - - return napi_ok; -} - -NAPI_EXTERN napi_status napi_has_own_property(napi_env env, - napi_value object, - napi_value key, - bool* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - - napi_value global{}, object_ctor{}, function{}, value{}; - CHECK_NAPI(napi_get_global(env, &global)); - CHECK_NAPI(napi_get_named_property(env, global, "Object", &object_ctor)); - CHECK_NAPI(napi_get_named_property(env, object_ctor, "hasOwnProperty", &function)); - CHECK_NAPI(napi_call_function(env, object_ctor, function, 0, nullptr, &value)); - *result = JSValueToBoolean(env->context, ToJSValue(value)); - - return napi_ok; -} - -napi_status napi_set_named_property(napi_env env, - napi_value object, - const char* utf8name, - napi_value value) { - CHECK_ENV(env); - CHECK_ARG(env, value); - - JSValueRef exception{}; - JSObjectSetProperty( - env->context, - ToJSObject(env, object), - JSString(utf8name), - ToJSValue(value), - kJSPropertyAttributeNone, - &exception); - CHECK_JSC(env, exception); - - return napi_ok; -} - -napi_status napi_has_named_property(napi_env env, - napi_value object, - const char* utf8name, - bool* result) { - CHECK_ENV(env); - CHECK_ARG(env, object); - - *result = JSObjectHasProperty( - env->context, - ToJSObject(env, object), - JSString(utf8name)); - - return napi_ok; -} - -napi_status napi_get_named_property(napi_env env, - napi_value object, - const char* utf8name, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, object); - - JSValueRef exception{}; - *result = ToNapi(JSObjectGetProperty( - env->context, - ToJSObject(env, object), - JSString(utf8name), - &exception)); - CHECK_JSC(env, exception); - - return napi_ok; -} - -napi_status napi_set_element(napi_env env, - napi_value object, - uint32_t index, - napi_value value) { - CHECK_ENV(env); - CHECK_ARG(env, value); - - JSValueRef exception{}; - JSObjectSetPropertyAtIndex( - env->context, - ToJSObject(env, object), - index, - ToJSValue(value), - &exception); - CHECK_JSC(env, exception); - - return napi_ok; -} - -napi_status napi_has_element(napi_env env, - napi_value object, - uint32_t index, - bool* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - - JSValueRef exception{}; - JSValueRef value{JSObjectGetPropertyAtIndex( - env->context, - ToJSObject(env, object), - index, - &exception)}; - CHECK_JSC(env, exception); - - *result = !JSValueIsUndefined(env->context, value); - return napi_ok; -} - -napi_status napi_get_element(napi_env env, - napi_value object, - uint32_t index, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - - JSValueRef exception{}; - *result = ToNapi(JSObjectGetPropertyAtIndex( - env->context, - ToJSObject(env, object), - index, - &exception)); - CHECK_JSC(env, exception); - - return napi_ok; -} - -napi_status napi_delete_element(napi_env env, - napi_value object, - uint32_t index, - bool* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - - napi_value index_value{ToNapi(JSValueMakeNumber(env->context, index))}; - - JSValueRef exception{}; - JSString index_str{ToJSString(env, index_value, &exception)}; - CHECK_JSC(env, exception); - - *result = JSObjectDeleteProperty( - env->context, - ToJSObject(env, object), - index_str, - &exception); - CHECK_JSC(env, exception); - - return napi_ok; -} - -napi_status napi_define_properties(napi_env env, - napi_value object, - size_t property_count, - const napi_property_descriptor* properties) { - CHECK_ENV(env); - if (property_count > 0) { - CHECK_ARG(env, properties); - } - - for (size_t i = 0; i < property_count; i++) { - const napi_property_descriptor* p{properties + i}; - - napi_value descriptor{}; - CHECK_NAPI(napi_create_object(env, &descriptor)); - - napi_value configurable{}; - CHECK_NAPI(napi_get_boolean(env, (p->attributes & napi_configurable), &configurable)); - CHECK_NAPI(napi_set_named_property(env, descriptor, "configurable", configurable)); - - napi_value enumerable{}; - CHECK_NAPI(napi_get_boolean(env, (p->attributes & napi_configurable), &enumerable)); - CHECK_NAPI(napi_set_named_property(env, descriptor, "enumerable", enumerable)); - - if (p->getter != nullptr || p->setter != nullptr) { - if (p->getter != nullptr) { - napi_value getter{}; - CHECK_NAPI(napi_create_function(env, p->utf8name, NAPI_AUTO_LENGTH, p->getter, p->data, &getter)); - CHECK_NAPI(napi_set_named_property(env, descriptor, "get", getter)); - } - if (p->setter != nullptr) { - napi_value setter{}; - CHECK_NAPI(napi_create_function(env, p->utf8name, NAPI_AUTO_LENGTH, p->setter, p->data, &setter)); - CHECK_NAPI(napi_set_named_property(env, descriptor, "set", setter)); - } - } else if (p->method != nullptr) { - napi_value method{}; - CHECK_NAPI(napi_create_function(env, p->utf8name, NAPI_AUTO_LENGTH, p->method, p->data, &method)); - CHECK_NAPI(napi_set_named_property(env, descriptor, "value", method)); - } else { - RETURN_STATUS_IF_FALSE(env, p->value != nullptr, napi_invalid_arg); - - napi_value writable{}; - CHECK_NAPI(napi_get_boolean(env, (p->attributes & napi_writable), &writable)); - CHECK_NAPI(napi_set_named_property(env, descriptor, "writable", writable)); - - CHECK_NAPI(napi_set_named_property(env, descriptor, "value", p->value)); - } - - napi_value propertyName{}; - if (p->utf8name == nullptr) { - propertyName = p->name; - } else { - CHECK_NAPI(napi_create_string_utf8(env, p->utf8name, NAPI_AUTO_LENGTH, &propertyName)); - } - - napi_value global{}, object_ctor{}, function{}; - CHECK_NAPI(napi_get_global(env, &global)); - CHECK_NAPI(napi_get_named_property(env, global, "Object", &object_ctor)); - CHECK_NAPI(napi_get_named_property(env, object_ctor, "defineProperty", &function)); - - napi_value args[] = { object, propertyName, descriptor }; - CHECK_NAPI(napi_call_function(env, object_ctor, function, 3, args, nullptr)); - } - - return napi_ok; -} - -napi_status napi_is_array(napi_env env, napi_value value, bool* result) { - CHECK_ENV(env); - CHECK_ARG(env, value); - CHECK_ARG(env, result); - - *result = JSValueIsArray( - env->context, - ToJSValue(value)); - return napi_ok; -} - -napi_status napi_get_array_length(napi_env env, - napi_value value, - uint32_t* result) { - CHECK_ENV(env); - CHECK_ARG(env, value); - CHECK_ARG(env, result); - - JSValueRef exception{}; - JSValueRef length = JSObjectGetProperty( - env->context, - ToJSObject(env, value), - JSString("length"), - &exception); - CHECK_JSC(env, exception); - - *result = static_cast(JSValueToNumber(env->context, length, &exception)); - CHECK_JSC(env, exception); - - return napi_ok; -} - -napi_status napi_strict_equals(napi_env env, - napi_value lhs, - napi_value rhs, - bool* result) { - CHECK_ENV(env); - CHECK_ARG(env, lhs); - CHECK_ARG(env, rhs); - CHECK_ARG(env, result); - *result = JSValueIsStrictEqual( - env->context, - ToJSValue(lhs), - ToJSValue(rhs)); - return napi_ok; -} - -napi_status napi_get_prototype(napi_env env, - napi_value object, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - - JSValueRef exception{}; - JSObjectRef prototype{JSValueToObject(env->context, JSObjectGetPrototype(env->context, ToJSObject(env, object)), &exception)}; - CHECK_JSC(env, exception); - - *result = ToNapi(prototype); - return napi_ok; -} - -napi_status napi_create_object(napi_env env, napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - *result = ToNapi(JSObjectMake(env->context, nullptr, nullptr)); - return napi_ok; -} - -napi_status napi_create_array(napi_env env, napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - - JSValueRef exception{}; - *result = ToNapi(JSObjectMakeArray(env->context, 0, nullptr, &exception)); - CHECK_JSC(env, exception); - - return napi_ok; -} - -napi_status napi_create_array_with_length(napi_env env, - size_t length, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - - JSValueRef exception{}; - JSObjectRef array = JSObjectMakeArray( - env->context, - 0, - nullptr, - &exception); - CHECK_JSC(env, exception); - - JSObjectSetProperty( - env->context, - array, - JSString("length"), - JSValueMakeNumber(env->context, static_cast(length)), - kJSPropertyAttributeNone, - &exception); - CHECK_JSC(env, exception); - - *result = ToNapi(array); - return napi_ok; -} - -napi_status napi_create_string_latin1(napi_env env, - const char* str, - size_t length, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - *result = ToNapi(JSValueMakeString( - env->context, - JSString(str, length))); - return napi_ok; -} - -napi_status napi_create_string_utf8(napi_env env, - const char* str, - size_t length, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - *result = ToNapi(JSValueMakeString( - env->context, - JSString(str, length))); - return napi_ok; -} - -napi_status napi_create_string_utf16(napi_env env, - const char16_t* str, - size_t length, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - static_assert(sizeof(char16_t) == sizeof(JSChar)); - *result = ToNapi(JSValueMakeString( - env->context, - JSString(reinterpret_cast(str), length))); - return napi_ok; -} - -napi_status napi_create_double(napi_env env, - double value, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - *result = ToNapi(JSValueMakeNumber(env->context, value)); - return napi_ok; -} - -napi_status napi_create_int32(napi_env env, - int32_t value, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - *result = ToNapi(JSValueMakeNumber(env->context, static_cast(value))); - return napi_ok; -} - -napi_status napi_create_uint32(napi_env env, - uint32_t value, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - *result = ToNapi(JSValueMakeNumber(env->context, static_cast(value))); - return napi_ok; -} - -napi_status napi_create_int64(napi_env env, - int64_t value, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - *result = ToNapi(JSValueMakeNumber(env->context, static_cast(value))); - return napi_ok; -} - -napi_status napi_get_boolean(napi_env env, bool value, napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - *result = ToNapi(JSValueMakeBoolean(env->context, value)); - return napi_ok; -} - -napi_status napi_create_symbol(napi_env env, - napi_value description, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - - napi_value global{}, symbol_func{}; - CHECK_NAPI(napi_get_global(env, &global)); - CHECK_NAPI(napi_get_named_property(env, global, "Symbol", &symbol_func)); - CHECK_NAPI(napi_call_function(env, global, symbol_func, 1, &description, result)); - return napi_ok; -} - -napi_status napi_create_error(napi_env env, - napi_value code, - napi_value msg, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, msg); - CHECK_ARG(env, result); - - JSValueRef exception{}; - JSValueRef args[] = { ToJSValue(msg) }; - napi_value error = ToNapi(JSObjectMakeError(env->context, 1, args, &exception)); - CHECK_JSC(env, exception); - - CHECK_NAPI(napi_set_error_code(env, error, code, nullptr)); - - *result = error; - return napi_ok; -} - -napi_status napi_create_type_error(napi_env env, - napi_value code, - napi_value msg, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, msg); - CHECK_ARG(env, result); - - napi_value global{}, error_ctor{}, error{}; - CHECK_NAPI(napi_get_global(env, &global)); - CHECK_NAPI(napi_get_named_property(env, global, "TypeError", &error_ctor)); - CHECK_NAPI(napi_new_instance(env, error_ctor, 1, &msg, &error)); - CHECK_NAPI(napi_set_error_code(env, error, code, nullptr)); - - *result = error; - return napi_ok; -} - -napi_status napi_create_range_error(napi_env env, - napi_value code, - napi_value msg, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, msg); - CHECK_ARG(env, result); - - napi_value global{}, error_ctor{}, error{}; - CHECK_NAPI(napi_get_global(env, &global)); - CHECK_NAPI(napi_get_named_property(env, global, "RangeError", &error_ctor)); - CHECK_NAPI(napi_new_instance(env, error_ctor, 1, &msg, &error)); - CHECK_NAPI(napi_set_error_code(env, error, code, nullptr)); - - *result = error; - return napi_ok; -} - -napi_status napi_typeof(napi_env env, napi_value value, napi_valuetype* result) { - CHECK_ENV(env); - CHECK_ARG(env, value); - CHECK_ARG(env, result); - - // JSC does not support BigInt - JSType valueType = JSValueGetType(env->context, ToJSValue(value)); - switch (valueType) { - case kJSTypeUndefined: *result = napi_undefined; break; - case kJSTypeNull: *result = napi_null; break; - case kJSTypeBoolean: *result = napi_boolean; break; - case kJSTypeNumber: *result = napi_number; break; - case kJSTypeString: *result = napi_string; break; - case kJSTypeSymbol: *result = napi_symbol; break; - default: - JSObjectRef object{ToJSObject(env, value)}; - if (JSObjectIsFunction(env->context, object)) { - *result = napi_function; - } else { - NativeInfo* info = NativeInfo::Get(object); - if (info != nullptr && info->Type() == NativeType::External) { - *result = napi_external; - } else { - *result = napi_object; - } - } - break; - } - - return napi_ok; -} - -napi_status napi_get_undefined(napi_env env, napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - *result = ToNapi(JSValueMakeUndefined(env->context)); - return napi_ok; -} - -napi_status napi_get_null(napi_env env, napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - *result = ToNapi(JSValueMakeNull(env->context)); - return napi_ok; -} - -napi_status napi_get_cb_info(napi_env env, // [in] NAPI environment handle - napi_callback_info cbinfo, // [in] Opaque callback-info handle - size_t* argc, // [in-out] Specifies the size of the provided argv array - // and receives the actual count of args. - napi_value* argv, // [out] Array of values - napi_value* this_arg, // [out] Receives the JS 'this' arg for the call - void** data) { // [out] Receives the data pointer for the callback. - CHECK_ENV(env); - CHECK_ARG(env, cbinfo); - - if (argv != nullptr) { - CHECK_ARG(env, argc); - - size_t i{0}; - size_t min{std::min(*argc, static_cast(cbinfo->argc))}; - - for (; i < min; i++) { - argv[i] = cbinfo->argv[i]; - } - - if (i < *argc) { - for (; i < *argc; i++) { - argv[i] = ToNapi(JSValueMakeUndefined(env->context)); - } - } - } - - if (argc != nullptr) { - *argc = cbinfo->argc; - } - - if (this_arg != nullptr) { - *this_arg = cbinfo->thisArg; - } - - if (data != nullptr) { - *data = cbinfo->data; - } - - return napi_ok; -} - -napi_status napi_get_new_target(napi_env env, - napi_callback_info cbinfo, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, cbinfo); - CHECK_ARG(env, result); - - *result = cbinfo->newTarget; - return napi_ok; -} - -napi_status napi_call_function(napi_env env, - napi_value recv, - napi_value func, - size_t argc, - const napi_value* argv, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, recv); - if (argc > 0) { - CHECK_ARG(env, argv); - } - - JSValueRef exception{}; - JSValueRef return_value{JSObjectCallAsFunction( - env->context, - ToJSObject(env, func), - JSValueIsUndefined(env->context, ToJSValue(recv)) ? nullptr : ToJSObject(env, recv), - argc, - ToJSValues(argv), - &exception)}; - CHECK_JSC(env, exception); - - if (result != nullptr) { - *result = ToNapi(return_value); - } - - return napi_ok; -} - -napi_status napi_get_global(napi_env env, napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - *result = ToNapi(JSContextGetGlobalObject(env->context)); - return napi_ok; -} - -napi_status napi_throw(napi_env env, napi_value error) { - CHECK_ENV(env); - napi_status status{napi_set_exception(env, ToJSValue(error))}; - assert(status == napi_pending_exception); - return napi_ok; -} - -napi_status napi_throw_error(napi_env env, - const char* code, - const char* msg) { - CHECK_ENV(env); - napi_value code_value{ToNapi(JSValueMakeString(env->context, JSString(code)))}; - napi_value msg_value{ToNapi(JSValueMakeString(env->context, JSString(msg)))}; - napi_value error{}; - CHECK_NAPI(napi_create_error(env, code_value, msg_value, &error)); - return napi_throw(env, error); -} - -napi_status napi_throw_type_error(napi_env env, - const char* code, - const char* msg) { - CHECK_ENV(env); - napi_value code_value{ToNapi(JSValueMakeString(env->context, JSString(code)))}; - napi_value msg_value{ToNapi(JSValueMakeString(env->context, JSString(msg)))}; - napi_value error{}; - CHECK_NAPI(napi_create_type_error(env, code_value, msg_value, &error)); - return napi_throw(env, error); -} - -napi_status napi_throw_range_error(napi_env env, - const char* code, - const char* msg) { - CHECK_ENV(env); - napi_value code_value{ToNapi(JSValueMakeString(env->context, JSString(code)))}; - napi_value msg_value{ToNapi(JSValueMakeString(env->context, JSString(msg)))}; - napi_value error{}; - CHECK_NAPI(napi_create_range_error(env, code_value, msg_value, &error)); - return napi_throw(env, error); -} - -napi_status napi_is_error(napi_env env, napi_value value, bool* result) { - CHECK_ENV(env); - CHECK_ARG(env, value); - CHECK_ARG(env, result); - - napi_value global{}, error_ctor{}; - CHECK_NAPI(napi_get_global(env, &global)); - CHECK_NAPI(napi_get_named_property(env, global, "Error", &error_ctor)); - CHECK_NAPI(napi_instanceof(env, value, error_ctor, result)); - - return napi_ok; -} - -napi_status napi_get_value_double(napi_env env, napi_value value, double* result) { - CHECK_ENV(env); - CHECK_ARG(env, value); - CHECK_ARG(env, result); - - JSValueRef exception{}; - *result = JSValueToNumber(env->context, ToJSValue(value), &exception); - CHECK_JSC(env, exception); - - return napi_ok; -} - -napi_status napi_get_value_int32(napi_env env, napi_value value, int32_t* result) { - CHECK_ENV(env); - CHECK_ARG(env, value); - CHECK_ARG(env, result); - - JSValueRef exception{}; - *result = static_cast(JSValueToNumber(env->context, ToJSValue(value), &exception)); - CHECK_JSC(env, exception); - - return napi_ok; -} - -napi_status napi_get_value_uint32(napi_env env, napi_value value, uint32_t* result) { - CHECK_ENV(env); - CHECK_ARG(env, value); - CHECK_ARG(env, result); - - JSValueRef exception{}; - *result = static_cast(JSValueToNumber(env->context, ToJSValue(value), &exception)); - CHECK_JSC(env, exception); - - return napi_ok; -} - -napi_status napi_get_value_int64(napi_env env, napi_value value, int64_t* result) { - CHECK_ENV(env); - CHECK_ARG(env, value); - CHECK_ARG(env, result); - - JSValueRef exception{}; - double number = JSValueToNumber(env->context, ToJSValue(value), &exception); - CHECK_JSC(env, exception); - - if (std::isfinite(number)) { - *result = static_cast(number); - } else { - *result = 0; - } - - return napi_ok; -} - -napi_status napi_get_value_bool(napi_env env, napi_value value, bool* result) { - CHECK_ENV(env); - CHECK_ARG(env, value); - CHECK_ARG(env, result); - *result = JSValueToBoolean(env->context, ToJSValue(value)); - return napi_ok; -} - -// Copies a JavaScript string into a LATIN-1 string buffer. The result is the -// number of bytes (excluding the null terminator) copied into buf. -// A sufficient buffer size should be greater than the length of string, -// reserving space for null terminator. -// If bufsize is insufficient, the string will be truncated and null terminated. -// If buf is NULL, this method returns the length of the string (in bytes) -// via the result parameter. -// The result argument is optional unless buf is NULL. -napi_status napi_get_value_string_latin1(napi_env env, - napi_value value, - char* buf, - size_t bufsize, - size_t* result) { - CHECK_ENV(env); - CHECK_ARG(env, value); - - JSValueRef exception{}; - JSString string{ToJSString(env, value, &exception)}; - CHECK_JSC(env, exception); - - if (buf == nullptr) { - *result = string.LengthLatin1(); - } else { - string.CopyToLatin1(buf, bufsize, result); - } - - return napi_ok; -} - -// Copies a JavaScript string into a UTF-8 string buffer. The result is the -// number of bytes (excluding the null terminator) copied into buf. -// A sufficient buffer size should be greater than the length of string, -// reserving space for null terminator. -// If bufsize is insufficient, the string will be truncated and null terminated. -// If buf is NULL, this method returns the length of the string (in bytes) -// via the result parameter. -// The result argument is optional unless buf is NULL. -napi_status napi_get_value_string_utf8(napi_env env, - napi_value value, - char* buf, - size_t bufsize, - size_t* result) { - CHECK_ENV(env); - CHECK_ARG(env, value); - - JSValueRef exception{}; - JSString string{ToJSString(env, value, &exception)}; - CHECK_JSC(env, exception); - - if (buf == nullptr) { - *result = string.LengthUTF8(); - } else { - string.CopyToUTF8(buf, bufsize, result); - } - - return napi_ok; -} - -// Copies a JavaScript string into a UTF-16 string buffer. The result is the -// number of 2-byte code units (excluding the null terminator) copied into buf. -// A sufficient buffer size should be greater than the length of string, -// reserving space for null terminator. -// If bufsize is insufficient, the string will be truncated and null terminated. -// If buf is NULL, this method returns the length of the string (in 2-byte -// code units) via the result parameter. -// The result argument is optional unless buf is NULL. -napi_status napi_get_value_string_utf16(napi_env env, - napi_value value, - char16_t* buf, - size_t bufsize, - size_t* result) { - CHECK_ENV(env); - CHECK_ARG(env, value); - - JSValueRef exception{}; - JSString string{ToJSString(env, value, &exception)}; - CHECK_JSC(env, exception); - - if (buf == nullptr) { - *result = string.Length(); - } else { - static_assert(sizeof(char16_t) == sizeof(JSChar)); - string.CopyTo(reinterpret_cast(buf), bufsize, result); - } - - return napi_ok; -} - -napi_status napi_coerce_to_bool(napi_env env, - napi_value value, - napi_value* result) { - CHECK_ARG(env, result); - *result = ToNapi(JSValueMakeBoolean(env->context, - JSValueToBoolean(env->context, ToJSValue(value)))); - return napi_ok; -} - -napi_status napi_coerce_to_number(napi_env env, - napi_value value, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, value); - CHECK_ARG(env, result); - - JSValueRef exception{}; - double number{JSValueToNumber(env->context, ToJSValue(value), &exception)}; - CHECK_JSC(env, exception); - - *result = ToNapi(JSValueMakeNumber(env->context, number)); - return napi_ok; -} - -napi_status napi_coerce_to_object(napi_env env, - napi_value value, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, value); - CHECK_ARG(env, result); - - JSValueRef exception{}; - *result = ToNapi(JSValueToObject(env->context, ToJSValue(value), &exception)); - CHECK_JSC(env, exception); - - return napi_ok; -} - -napi_status napi_coerce_to_string(napi_env env, - napi_value value, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, value); - CHECK_ARG(env, result); - - JSValueRef exception{}; - JSString string{ToJSString(env, value, &exception)}; - CHECK_JSC(env, exception); - - *result = ToNapi(JSValueMakeString(env->context, string)); - return napi_ok; -} - -napi_status napi_wrap(napi_env env, - napi_value js_object, - void* native_object, - napi_finalize finalize_cb, - void* finalize_hint, - napi_ref* result) { - CHECK_ENV(env); - CHECK_ARG(env, js_object); - if (result != nullptr) { - CHECK_ARG(env, finalize_cb); - } - - WrapperInfo* info{}; - CHECK_NAPI(WrapperInfo::Wrap(env, js_object, &info)); - RETURN_STATUS_IF_FALSE(env, info->Data() == nullptr, napi_invalid_arg); - - info->Data(native_object); - - if (finalize_cb != nullptr) { - info->AddFinalizer([finalize_cb, finalize_hint](WrapperInfo* info) { - finalize_cb(info->Env(), info->Data(), finalize_hint); - }); - } - - if (result != nullptr) { - CHECK_NAPI(napi_create_reference(env, js_object, 0, result)); - } - - return napi_ok; -} - -napi_status napi_unwrap(napi_env env, napi_value js_object, void** result) { - CHECK_ENV(env); - CHECK_ARG(env, js_object); - - WrapperInfo* info{}; - CHECK_NAPI(WrapperInfo::Unwrap(env, js_object, &info)); - RETURN_STATUS_IF_FALSE(env, info != nullptr && info->Data() != nullptr, napi_invalid_arg); - - *result = info->Data(); - return napi_ok; -} - -napi_status napi_remove_wrap(napi_env env, napi_value js_object, void** result) { - CHECK_ENV(env); - CHECK_ARG(env, js_object); - - // Once an object is wrapped, it stays wrapped in order to support finalizer callbacks. - - WrapperInfo* info{}; - CHECK_NAPI(WrapperInfo::Unwrap(env, js_object, &info)); - RETURN_STATUS_IF_FALSE(env, info != nullptr && info->Data() != nullptr, napi_invalid_arg); - info->Data(nullptr); - - *result = info->Data(); - return napi_ok; -} - -napi_status napi_create_external(napi_env env, - void* data, - napi_finalize finalize_cb, - void* finalize_hint, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - - CHECK_NAPI(ExternalInfo::Create(env, data, finalize_cb, finalize_hint, result)); - return napi_ok; -} - -napi_status napi_get_value_external(napi_env env, napi_value value, void** result) { - CHECK_ENV(env); - CHECK_ARG(env, value); - CHECK_ARG(env, result); - - ExternalInfo* info = NativeInfo::Get(ToJSObject(env, value)); - *result = (info != nullptr && info->Type() == NativeType::External) ? info->Data() : nullptr; - return napi_ok; -} - -// Set initial_refcount to 0 for a weak reference, >0 for a strong reference. -napi_status napi_create_reference(napi_env env, - napi_value value, - uint32_t initial_refcount, - napi_ref* result) { - CHECK_ENV(env); - CHECK_ARG(env, value); - CHECK_ARG(env, result); - - napi_ref__* ref{new napi_ref__{value, initial_refcount}}; - if (ref == nullptr) { - return napi_set_last_error(env, napi_generic_failure); - } - - ref->init(env); - *result = ref; - - return napi_ok; -} - -// Deletes a reference. The referenced value is released, and may be GC'd -// unless there are other references to it. -napi_status napi_delete_reference(napi_env env, napi_ref ref) { - CHECK_ENV(env); - CHECK_ARG(env, ref); - - ref->deinit(env); - delete ref; - - return napi_ok; -} - -// Increments the reference count, optionally returning the resulting count. -// After this call the reference will be a strong reference because its refcount -// is >0, and the referenced object is effectively "pinned". Calling this when -// the refcount is 0 and the target is unavailable results in an error. -napi_status napi_reference_ref(napi_env env, napi_ref ref, uint32_t* result) { - CHECK_ENV(env); - CHECK_ARG(env, ref); - - ref->ref(env); - if (result != nullptr) { - *result = ref->count(); - } - - return napi_ok; -} - -// Decrements the reference count, optionally returning the resulting count. -// If the result is 0 the reference is now weak and the object may be GC'd at -// any time if there are no other references. Calling this when the refcount -// is already 0 results in an error. -napi_status napi_reference_unref(napi_env env, napi_ref ref, uint32_t* result) { - CHECK_ENV(env); - CHECK_ARG(env, ref); - - ref->unref(env); - if (result != nullptr) { - *result = ref->count(); - } - - return napi_ok; -} - -// Attempts to get a referenced value. If the reference is weak, the value -// might no longer be available, in that case the call is still successful but -// the result is NULL. -napi_status napi_get_reference_value(napi_env env, - napi_ref ref, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, ref); - CHECK_ARG(env, result); - - *result = ref->value(env); - return napi_ok; -} - -// Stub implementation of handle scope apis for JSC. -napi_status napi_open_handle_scope(napi_env env, - napi_handle_scope* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - *result = reinterpret_cast(1); - return napi_ok; -} - -// Stub implementation of handle scope apis for JSC. -napi_status napi_close_handle_scope(napi_env env, - napi_handle_scope scope) { - CHECK_ENV(env); - CHECK_ARG(env, scope); - return napi_ok; -} - -// Stub implementation of handle scope apis for JSC. -napi_status napi_open_escapable_handle_scope(napi_env env, - napi_escapable_handle_scope* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - *result = reinterpret_cast(1); - return napi_ok; -} - -// Stub implementation of handle scope apis for JSC. -napi_status napi_close_escapable_handle_scope(napi_env env, - napi_escapable_handle_scope scope) { - CHECK_ENV(env); - CHECK_ARG(env, scope); - return napi_ok; -} - -// Stub implementation of handle scope apis for JSC. -// This one will return escapee value as this is called from leveldown db. -napi_status napi_escape_handle(napi_env env, - napi_escapable_handle_scope scope, - napi_value escapee, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, scope); - CHECK_ARG(env, escapee); - CHECK_ARG(env, result); - *result = escapee; - return napi_ok; -} - -napi_status napi_new_instance(napi_env env, - napi_value constructor, - size_t argc, - const napi_value* argv, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, constructor); - if (argc > 0) { - CHECK_ARG(env, argv); - } - CHECK_ARG(env, result); - - JSValueRef exception{}; - *result = ToNapi(JSObjectCallAsConstructor( - env->context, - ToJSObject(env, constructor), - argc, - ToJSValues(argv), - &exception)); - CHECK_JSC(env, exception); - - return napi_ok; -} - -napi_status napi_instanceof(napi_env env, - napi_value object, - napi_value constructor, - bool* result) { - CHECK_ENV(env); - CHECK_ARG(env, object); - CHECK_ARG(env, result); - - JSValueRef exception{}; - *result = JSValueIsInstanceOfConstructor( - env->context, - ToJSValue(object), - ToJSObject(env, constructor), - &exception); - CHECK_JSC(env, exception); - - return napi_ok; -} - -napi_status napi_is_exception_pending(napi_env env, bool* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - - *result = (env->last_exception != nullptr); - return napi_ok; -} - -napi_status napi_get_and_clear_last_exception(napi_env env, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - - if (env->last_exception == nullptr) { - return napi_get_undefined(env, result); - } else { - *result = ToNapi(env->last_exception); - env->last_exception = nullptr; - } - - return napi_clear_last_error(env); -} - -napi_status napi_is_arraybuffer(napi_env env, napi_value value, bool* result) { - CHECK_ENV(env); - CHECK_ARG(env, value); - CHECK_ARG(env, result); - - JSValueRef exception{}; - JSTypedArrayType type{JSValueGetTypedArrayType(env->context, ToJSValue(value), &exception)}; - CHECK_JSC(env, exception); - - *result = (type == kJSTypedArrayTypeArrayBuffer); - return napi_ok; -} - -napi_status napi_create_arraybuffer(napi_env env, - size_t byte_length, - void** data, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - - *data = malloc(byte_length); - JSValueRef exception{}; - *result = ToNapi(JSObjectMakeArrayBufferWithBytesNoCopy( - env->context, - *data, - byte_length, - [](void* bytes, void* deallocatorContext) { - free(bytes); - }, - nullptr, - &exception)); - CHECK_JSC(env, exception); - - return napi_ok; -} - -napi_status napi_create_external_arraybuffer(napi_env env, - void* external_data, - size_t byte_length, - napi_finalize finalize_cb, - void* finalize_hint, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - - CHECK_NAPI(ExternalArrayBufferInfo::Create(env, external_data, byte_length, finalize_cb, finalize_hint, result)); - return napi_ok; -} - -napi_status napi_get_arraybuffer_info(napi_env env, - napi_value arraybuffer, - void** data, - size_t* byte_length) { - CHECK_ENV(env); - CHECK_ARG(env, arraybuffer); - - JSValueRef exception{}; - - if (data != nullptr) { - *data = JSObjectGetArrayBufferBytesPtr(env->context, ToJSObject(env, arraybuffer), &exception); - CHECK_JSC(env, exception); - } - - if (byte_length != nullptr) { - *byte_length = JSObjectGetArrayBufferByteLength(env->context, ToJSObject(env, arraybuffer), &exception); - CHECK_JSC(env, exception); - } - - return napi_ok; -} - -napi_status napi_is_typedarray(napi_env env, napi_value value, bool* result) { - CHECK_ENV(env); - CHECK_ARG(env, value); - CHECK_ARG(env, result); - - JSValueRef exception{}; - JSTypedArrayType type{JSValueGetTypedArrayType(env->context, ToJSValue(value), &exception)}; - CHECK_JSC(env, exception); - - *result = (type != kJSTypedArrayTypeNone && type != kJSTypedArrayTypeArrayBuffer); - return napi_ok; -} - -napi_status napi_create_typedarray(napi_env env, - napi_typedarray_type type, - size_t length, - napi_value arraybuffer, - size_t byte_offset, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, arraybuffer); - CHECK_ARG(env, result); - - JSTypedArrayType jsType{}; - switch (type) { - case napi_int8_array: - jsType = kJSTypedArrayTypeInt8Array; - break; - case napi_uint8_array: - jsType = kJSTypedArrayTypeUint8Array; - break; - case napi_uint8_clamped_array: - jsType = kJSTypedArrayTypeUint8ClampedArray; - break; - case napi_int16_array: - jsType = kJSTypedArrayTypeInt16Array; - break; - case napi_uint16_array: - jsType = kJSTypedArrayTypeUint16Array; - break; - case napi_int32_array: - jsType = kJSTypedArrayTypeInt32Array; - break; - case napi_uint32_array: - jsType = kJSTypedArrayTypeUint32Array; - break; - case napi_float32_array: - jsType = kJSTypedArrayTypeFloat32Array; - break; - case napi_float64_array: - jsType = kJSTypedArrayTypeFloat64Array; - break; - default: - return napi_set_last_error(env, napi_invalid_arg); - } - - JSValueRef exception{}; - *result = ToNapi(JSObjectMakeTypedArrayWithArrayBufferAndOffset( - env->context, - jsType, - ToJSObject(env, arraybuffer), - byte_offset, - length, - &exception)); - CHECK_JSC(env, exception); - - return napi_ok; -} - -napi_status napi_get_typedarray_info(napi_env env, - napi_value typedarray, - napi_typedarray_type* type, - size_t* length, - void** data, - napi_value* arraybuffer, - size_t* byte_offset) { - CHECK_ENV(env); - CHECK_ARG(env, typedarray); - - JSValueRef exception{}; - - JSObjectRef object{ToJSObject(env, typedarray)}; - - if (type != nullptr) { - JSTypedArrayType typedArrayType{JSValueGetTypedArrayType(env->context, object, &exception)}; - CHECK_JSC(env, exception); - - switch (typedArrayType) { - case kJSTypedArrayTypeInt8Array: - *type = napi_int8_array; - break; - case kJSTypedArrayTypeUint8Array: - *type = napi_uint8_array; - break; - case kJSTypedArrayTypeUint8ClampedArray: - *type = napi_uint8_clamped_array; - break; - case kJSTypedArrayTypeInt16Array: - *type = napi_int16_array; - break; - case kJSTypedArrayTypeUint16Array: - *type = napi_uint16_array; - break; - case kJSTypedArrayTypeInt32Array: - *type = napi_int32_array; - break; - case kJSTypedArrayTypeUint32Array: - *type = napi_uint32_array; - break; - case kJSTypedArrayTypeFloat32Array: - *type = napi_float32_array; - break; - case kJSTypedArrayTypeFloat64Array: - *type = napi_float64_array; - break; - default: - return napi_set_last_error(env, napi_generic_failure); - } - } - - if (length != nullptr) { - *length = JSObjectGetTypedArrayLength(env->context, object, &exception); - CHECK_JSC(env, exception); - } - - if (data != nullptr || byte_offset != nullptr) { - size_t data_byte_offset{JSObjectGetTypedArrayByteOffset(env->context, object, &exception)}; - CHECK_JSC(env, exception); - - if (data != nullptr) { - *data = static_cast(JSObjectGetTypedArrayBytesPtr(env->context, object, &exception)) + data_byte_offset; - CHECK_JSC(env, exception); - } - - if (byte_offset != nullptr) { - *byte_offset = data_byte_offset; - } - } - - if (arraybuffer != nullptr) { - *arraybuffer = ToNapi(JSObjectGetTypedArrayBuffer(env->context, object, &exception)); - CHECK_JSC(env, exception); - } - - return napi_ok; -} - -napi_status napi_create_dataview(napi_env env, - size_t byte_length, - napi_value arraybuffer, - size_t byte_offset, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, arraybuffer); - CHECK_ARG(env, result); - - napi_value global{}, dataview_ctor{}; - CHECK_NAPI(napi_get_global(env, &global)); - CHECK_NAPI(napi_get_named_property(env, global, "DataView", &dataview_ctor)); - - napi_value byte_offset_value{}, byte_length_value{}; - napi_create_double(env, static_cast(byte_offset), &byte_offset_value); - napi_create_double(env, static_cast(byte_length), &byte_length_value); - napi_value args[] = { arraybuffer, byte_offset_value, byte_length_value }; - CHECK_NAPI(napi_new_instance(env, dataview_ctor, 3, args, result)); - - return napi_ok; -} - -napi_status napi_is_dataview(napi_env env, napi_value value, bool* result) { - CHECK_ENV(env); - CHECK_ARG(env, value); - CHECK_ARG(env, result); - - napi_value global{}, dataview_ctor{}; - CHECK_NAPI(napi_get_global(env, &global)); - CHECK_NAPI(napi_get_named_property(env, global, "DataView", &dataview_ctor)); - CHECK_NAPI(napi_instanceof(env, value, dataview_ctor, result)); - - return napi_ok; -} - -napi_status napi_get_dataview_info(napi_env env, - napi_value dataview, - size_t* byte_length, - void** data, - napi_value* arraybuffer, - size_t* byte_offset) { - CHECK_ENV(env); - CHECK_ARG(env, dataview); - - if (byte_length != nullptr) { - napi_value value{}; - double doubleValue{}; - CHECK_NAPI(napi_get_named_property(env, dataview, "byteLength", &value)); - CHECK_NAPI(napi_get_value_double(env, value, &doubleValue)); - *byte_length = static_cast(doubleValue); - } - - if (data != nullptr) { - napi_value value{}; - CHECK_NAPI(napi_get_named_property(env, dataview, "buffer", &value)); - CHECK_NAPI(napi_get_arraybuffer_info(env, value, data, nullptr)); - } - - if (arraybuffer != nullptr) { - CHECK_NAPI(napi_get_named_property(env, dataview, "buffer", arraybuffer)); - } - - if (byte_offset != nullptr) { - napi_value value{}; - double doubleValue{}; - CHECK_NAPI(napi_get_named_property(env, dataview, "byteOffset", &value)); - CHECK_NAPI(napi_get_value_double(env, value, &doubleValue)); - *byte_offset = static_cast(doubleValue); - } - - return napi_ok; -} - -napi_status napi_get_version(napi_env env, uint32_t* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - *result = NAPI_VERSION; - return napi_ok; -} - -napi_status napi_create_promise(napi_env env, - napi_deferred* deferred, - napi_value* promise) { - CHECK_ENV(env); - CHECK_ARG(env, deferred); - CHECK_ARG(env, promise); - - napi_value global{}, promise_ctor{}; - CHECK_NAPI(napi_get_global(env, &global)); - CHECK_NAPI(napi_get_named_property(env, global, "Promise", &promise_ctor)); - - struct Wrapper { - napi_value resolve{}; - napi_value reject{}; - - static napi_value Callback(napi_env env, napi_callback_info cbinfo) { - Wrapper* wrapper = reinterpret_cast(cbinfo->data); - wrapper->resolve = cbinfo->argv[0]; - wrapper->reject = cbinfo->argv[1]; - return nullptr; - } - } wrapper; - - napi_value executor{}; - CHECK_NAPI(napi_create_function(env, "executor", NAPI_AUTO_LENGTH, Wrapper::Callback, &wrapper, &executor)); - CHECK_NAPI(napi_new_instance(env, promise_ctor, 1, &executor, promise)); - - napi_value deferred_value{}; - CHECK_NAPI(napi_create_object(env, &deferred_value)); - CHECK_NAPI(napi_set_named_property(env, deferred_value, "resolve", wrapper.resolve)); - CHECK_NAPI(napi_set_named_property(env, deferred_value, "reject", wrapper.reject)); - - napi_ref deferred_ref{}; - CHECK_NAPI(napi_create_reference(env, deferred_value, 1, &deferred_ref)); - *deferred = reinterpret_cast(deferred_ref); - - return napi_ok; -} - -napi_status napi_resolve_deferred(napi_env env, - napi_deferred deferred, - napi_value resolution) { - CHECK_ENV(env); - CHECK_ARG(env, deferred); - - napi_ref deferred_ref{reinterpret_cast(deferred)}; - napi_value undefined{}, deferred_value{}, resolve{}; - CHECK_NAPI(napi_get_undefined(env, &undefined)); - CHECK_NAPI(napi_get_reference_value(env, deferred_ref, &deferred_value)); - CHECK_NAPI(napi_get_named_property(env, deferred_value, "resolve", &resolve)); - CHECK_NAPI(napi_call_function(env, undefined, resolve, 1, &resolution, nullptr)); - CHECK_NAPI(napi_delete_reference(env, deferred_ref)); - - return napi_ok; -} - -napi_status napi_reject_deferred(napi_env env, - napi_deferred deferred, - napi_value rejection) { - CHECK_ENV(env); - CHECK_ARG(env, deferred); - - napi_ref deferred_ref{reinterpret_cast(deferred)}; - napi_value undefined{}, deferred_value{}, reject{}; - CHECK_NAPI(napi_get_undefined(env, &undefined)); - CHECK_NAPI(napi_get_reference_value(env, deferred_ref, &deferred_value)); - CHECK_NAPI(napi_get_named_property(env, deferred_value, "reject", &reject)); - CHECK_NAPI(napi_call_function(env, undefined, reject, 1, &rejection, nullptr)); - CHECK_NAPI(napi_delete_reference(env, deferred_ref)); - - return napi_ok; -} - -napi_status napi_is_promise(napi_env env, - napi_value promise, - bool* is_promise) { - CHECK_ENV(env); - CHECK_ARG(env, promise); - CHECK_ARG(env, is_promise); - - napi_value global{}, promise_ctor{}; - CHECK_NAPI(napi_get_global(env, &global)); - CHECK_NAPI(napi_get_named_property(env, global, "Promise", &promise_ctor)); - CHECK_NAPI(napi_instanceof(env, promise, promise_ctor, is_promise)); - - return napi_ok; -} - -napi_status napi_run_script(napi_env env, - napi_value script, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, script); - CHECK_ARG(env, result); - - JSValueRef exception{}; - - JSString script_str{ToJSString(env, script, &exception)}; - CHECK_JSC(env, exception); - - *result = ToNapi(JSEvaluateScript( - env->context, script_str, nullptr, nullptr, 0, &exception)); - CHECK_JSC(env, exception); - - return napi_ok; -} - -napi_status napi_run_script(napi_env env, - napi_value script, - const char* source_url, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, script); - CHECK_ARG(env, result); - - JSValueRef exception{}; - - JSString script_str{ToJSString(env, script, &exception)}; - CHECK_JSC(env, exception); - - JSValueRef return_value{JSEvaluateScript( - env->context, script_str, nullptr, JSString(source_url), 0, &exception)}; - CHECK_JSC(env, exception); - - if (result != nullptr) { - *result = ToNapi(return_value); - } - - return napi_ok; -} - -napi_status napi_add_finalizer(napi_env env, - napi_value js_object, - void* native_object, - napi_finalize finalize_cb, - void* finalize_hint, - napi_ref* result) { - throw std::runtime_error("not impl"); -} - -napi_status napi_adjust_external_memory(napi_env env, - int64_t change_in_bytes, - int64_t* adjusted_value) { - CHECK_ENV(env); - CHECK_ARG(env, adjusted_value); - - // TODO: Determine if JSC needs or is able to do anything here - // For now, we can lie and say that we always adjusted more memory - *adjusted_value = change_in_bytes; - - return napi_ok; -} diff --git a/Dependencies/napi/napi-direct/source/js_native_api_javascriptcore.h b/Dependencies/napi/napi-direct/source/js_native_api_javascriptcore.h deleted file mode 100644 index 8dc1048ed..000000000 --- a/Dependencies/napi/napi-direct/source/js_native_api_javascriptcore.h +++ /dev/null @@ -1,64 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include - -struct napi_env__ { - JSGlobalContextRef context{}; - JSValueRef last_exception{}; - napi_extended_error_info last_error{nullptr, nullptr, 0, napi_ok}; - std::unordered_set active_ref_values{}; - std::list strong_refs{}; - - const std::thread::id thread_id{std::this_thread::get_id()}; - - napi_env__(JSGlobalContextRef context) : context{context} { - JSGlobalContextRetain(context); - } - - ~napi_env__() { - deinit_refs(); - JSGlobalContextRelease(context); - } - - private: - void deinit_refs(); -}; - -#define RETURN_STATUS_IF_FALSE(env, condition, status) \ - do { \ - if (!(condition)) { \ - return napi_set_last_error((env), (status)); \ - } \ - } while (0) - -#define CHECK_ENV(env) \ - do { \ - if ((env) == nullptr) { \ - return napi_invalid_arg; \ - } \ - assert(env->thread_id == std::this_thread::get_id()); \ - } while (0) - -#define CHECK_ARG(env, arg) \ - RETURN_STATUS_IF_FALSE((env), ((arg) != nullptr), napi_invalid_arg) - -#define CHECK_JSC(env, exception) \ - do { \ - if ((exception) != nullptr) { \ - return napi_set_exception(env, exception); \ - } \ - } while (0) - -// This does not call napi_set_last_error because the expression -// is assumed to be a NAPI function call that already did. -#define CHECK_NAPI(expr) \ - do { \ - napi_status status = (expr); \ - if (status != napi_ok) return status; \ - } while (0) diff --git a/Dependencies/napi/napi-direct/source/js_native_api_javascriptcore_internals.h b/Dependencies/napi/napi-direct/source/js_native_api_javascriptcore_internals.h deleted file mode 100644 index 6f70f09be..000000000 --- a/Dependencies/napi/napi-direct/source/js_native_api_javascriptcore_internals.h +++ /dev/null @@ -1 +0,0 @@ -#pragma once diff --git a/Dependencies/napi/napi-direct/source/js_native_api_v8.cc b/Dependencies/napi/napi-direct/source/js_native_api_v8.cc deleted file mode 100644 index 9834e07bb..000000000 --- a/Dependencies/napi/napi-direct/source/js_native_api_v8.cc +++ /dev/null @@ -1,3051 +0,0 @@ -#include // INT_MAX -#include -#include -#include -#define NAPI_EXPERIMENTAL -#include "js_native_api_v8.h" -#include - -#define CHECK_MAYBE_NOTHING(env, maybe, status) \ - RETURN_STATUS_IF_FALSE((env), !((maybe).IsNothing()), (status)) - -#define CHECK_TO_NUMBER(env, context, result, src) \ - CHECK_TO_TYPE((env), Number, (context), (result), (src), napi_number_expected) - -// n-api defines NAPI_AUTO_LENGHTH as the indicator that a string -// is null terminated. For V8 the equivalent is -1. The assert -// validates that our cast of NAPI_AUTO_LENGTH results in -1 as -// needed by V8. -#define CHECK_NEW_FROM_UTF8_LEN(env, result, str, len) \ - do { \ - static_assert(static_cast(NAPI_AUTO_LENGTH) == -1, \ - "Casting NAPI_AUTO_LENGTH to int must result in -1"); \ - RETURN_STATUS_IF_FALSE((env), \ - (len == NAPI_AUTO_LENGTH) || len <= INT_MAX, \ - napi_invalid_arg); \ - RETURN_STATUS_IF_FALSE((env), \ - (str) != nullptr, \ - napi_invalid_arg); \ - auto str_maybe = v8::String::NewFromUtf8( \ - (env)->isolate, (str), v8::NewStringType::kInternalized, \ - static_cast(len)); \ - CHECK_MAYBE_EMPTY((env), str_maybe, napi_generic_failure); \ - (result) = str_maybe.ToLocalChecked(); \ - } while (0) - -#define CHECK_NEW_FROM_UTF8(env, result, str) \ - CHECK_NEW_FROM_UTF8_LEN((env), (result), (str), NAPI_AUTO_LENGTH) - -#define CREATE_TYPED_ARRAY( \ - env, type, size_of_element, buffer, byte_offset, length, out) \ - do { \ - if ((size_of_element) > 1) { \ - THROW_RANGE_ERROR_IF_FALSE( \ - (env), (byte_offset) % (size_of_element) == 0, \ - "ERR_NAPI_INVALID_TYPEDARRAY_ALIGNMENT", \ - "start offset of "#type" should be a multiple of "#size_of_element); \ - } \ - THROW_RANGE_ERROR_IF_FALSE((env), (length) * (size_of_element) + \ - (byte_offset) <= buffer->ByteLength(), \ - "ERR_NAPI_INVALID_TYPEDARRAY_LENGTH", \ - "Invalid typed array length"); \ - (out) = v8::type::New((buffer), (byte_offset), (length)); \ - } while (0) - -#ifndef __clang__ -#pragma warning(disable: 4100 4267) -#endif - -namespace v8impl { - -namespace { - -inline static napi_status -V8NameFromPropertyDescriptor(napi_env env, - const napi_property_descriptor* p, - v8::Local* result) { - if (p->utf8name != nullptr) { - CHECK_NEW_FROM_UTF8(env, *result, p->utf8name); - } else { - v8::Local property_value = - v8impl::V8LocalValueFromJsValue(p->name); - - RETURN_STATUS_IF_FALSE(env, property_value->IsName(), napi_name_expected); - *result = property_value.As(); - } - - return napi_ok; -} - -// convert from n-api property attributes to v8::PropertyAttribute -inline static v8::PropertyAttribute V8PropertyAttributesFromDescriptor( - const napi_property_descriptor* descriptor) { - unsigned int attribute_flags = v8::PropertyAttribute::None; - - // The napi_writable attribute is ignored for accessor descriptors, but - // V8 would throw `TypeError`s on assignment with nonexistence of a setter. - if ((descriptor->getter == nullptr && descriptor->setter == nullptr) && - (descriptor->attributes & napi_writable) == 0) { - attribute_flags |= v8::PropertyAttribute::ReadOnly; - } - - if ((descriptor->attributes & napi_enumerable) == 0) { - attribute_flags |= v8::PropertyAttribute::DontEnum; - } - if ((descriptor->attributes & napi_configurable) == 0) { - attribute_flags |= v8::PropertyAttribute::DontDelete; - } - - return static_cast(attribute_flags); -} - -inline static napi_deferred -JsDeferredFromNodePersistent(v8impl::Persistent* local) { - return reinterpret_cast(local); -} - -inline static v8impl::Persistent* -NodePersistentFromJsDeferred(napi_deferred local) { - return reinterpret_cast*>(local); -} - -class HandleScopeWrapper { - public: - explicit HandleScopeWrapper(v8::Isolate* isolate) : scope(isolate) {} - - private: - v8::HandleScope scope; -}; - -// In node v0.10 version of v8, there is no EscapableHandleScope and the -// node v0.10 port use HandleScope::Close(Local v) to mimic the behavior -// of a EscapableHandleScope::Escape(Local v), but it is not the same -// semantics. This is an example of where the api abstraction fail to work -// across different versions. -class EscapableHandleScopeWrapper { - public: - explicit EscapableHandleScopeWrapper(v8::Isolate* isolate) - : scope(isolate), escape_called_(false) {} - bool escape_called() const { - return escape_called_; - } - template - v8::Local Escape(v8::Local handle) { - escape_called_ = true; - return scope.Escape(handle); - } - - private: - v8::EscapableHandleScope scope; - bool escape_called_; -}; - -inline static napi_handle_scope -JsHandleScopeFromV8HandleScope(HandleScopeWrapper* s) { - return reinterpret_cast(s); -} - -inline static HandleScopeWrapper* -V8HandleScopeFromJsHandleScope(napi_handle_scope s) { - return reinterpret_cast(s); -} - -inline static napi_escapable_handle_scope -JsEscapableHandleScopeFromV8EscapableHandleScope( - EscapableHandleScopeWrapper* s) { - return reinterpret_cast(s); -} - -inline static EscapableHandleScopeWrapper* -V8EscapableHandleScopeFromJsEscapableHandleScope( - napi_escapable_handle_scope s) { - return reinterpret_cast(s); -} - -inline static napi_status ConcludeDeferred(napi_env env, - napi_deferred deferred, - napi_value result, - bool is_resolved) { - NAPI_PREAMBLE(env); - CHECK_ARG(env, result); - - v8::Local context = env->isolate->GetCurrentContext(); - v8impl::Persistent* deferred_ref = - NodePersistentFromJsDeferred(deferred); - v8::Local v8_deferred = - v8::Local::New(env->isolate, *deferred_ref); - - auto v8_resolver = v8::Local::Cast(v8_deferred); - - v8::Maybe success = is_resolved ? - v8_resolver->Resolve(context, v8impl::V8LocalValueFromJsValue(result)) : - v8_resolver->Reject(context, v8impl::V8LocalValueFromJsValue(result)); - - delete deferred_ref; - - RETURN_STATUS_IF_FALSE(env, success.FromMaybe(false), napi_generic_failure); - - return GET_RETURN_STATUS(env); -} - -// Wrapper around v8impl::Persistent that implements reference counting. -class Reference : private Finalizer, RefTracker { - private: - Reference(napi_env env, - v8::Local value, - uint32_t initial_refcount, - bool delete_self, - napi_finalize finalize_callback, - void* finalize_data, - void* finalize_hint) - : Finalizer(env, finalize_callback, finalize_data, finalize_hint), - _persistent(env->isolate, value), - _refcount(initial_refcount), - _delete_self(delete_self) { - if (initial_refcount == 0) { - _persistent.SetWeak( - this, FinalizeCallback, v8::WeakCallbackType::kParameter); - } - Link(finalize_callback == nullptr - ? &env->reflist - : &env->finalizing_reflist); - } - - public: - void* Data() { - return _finalize_data; - } - - static Reference* New(napi_env env, - v8::Local value, - uint32_t initial_refcount, - bool delete_self, - napi_finalize finalize_callback = nullptr, - void* finalize_data = nullptr, - void* finalize_hint = nullptr) { - return new Reference(env, - value, - initial_refcount, - delete_self, - finalize_callback, - finalize_data, - finalize_hint); - } - - // Delete is called in 2 ways. Either from the finalizer or - // from one of Unwrap or napi_delete_reference. - // - // When it is called from Unwrap or napi_delete_reference we only - // want to do the delete if the finalizer has already run or - // cannot have been queued to run (ie the reference count is > 0), - // otherwise we may crash when the finalizer does run. - // If the finalizer may have been queued and has not already run - // delay the delete until the finalizer runs by not doing the delete - // and setting _delete_self to true so that the finalizer will - // delete it when it runs. - // - // The second way this is called is from - // the finalizer and _delete_self is set. In this case we - // know we need to do the deletion so just do it. - static void Delete(Reference* reference) { - reference->Unlink(); - if ((reference->RefCount() != 0) || - (reference->_delete_self) || - (reference->_finalize_ran)) { - delete reference; - } else { - // defer until finalizer runs as - // it may alread be queued - reference->_delete_self = true; - } - } - - uint32_t Ref() { - if (++_refcount == 1) { - _persistent.ClearWeak(); - } - - return _refcount; - } - - uint32_t Unref() { - if (_refcount == 0) { - return 0; - } - if (--_refcount == 0) { - _persistent.SetWeak( - this, FinalizeCallback, v8::WeakCallbackType::kParameter); - } - - return _refcount; - } - - uint32_t RefCount() { - return _refcount; - } - - v8::Local Get() { - if (_persistent.IsEmpty()) { - return v8::Local(); - } else { - return v8::Local::New(_env->isolate, _persistent); - } - } - - private: - void Finalize(bool is_env_teardown = false) override { - if (_finalize_callback != nullptr) { - _env->CallIntoModuleThrow([&](napi_env env) { - _finalize_callback( - env, - _finalize_data, - _finalize_hint); - }); - } - - // this is safe because if a request to delete the reference - // is made in the finalize_callback it will defer deletion - // to this block and set _delete_self to true - if (_delete_self || is_env_teardown) { - Delete(this); - } else { - _finalize_ran = true; - } - } - - // The N-API finalizer callback may make calls into the engine. V8's heap is - // not in a consistent state during the weak callback, and therefore it does - // not support calls back into it. However, it provides a mechanism for adding - // a finalizer which may make calls back into the engine by allowing us to - // attach such a second-pass finalizer from the first pass finalizer. Thus, - // we do that here to ensure that the N-API finalizer callback is free to call - // into the engine. - static void FinalizeCallback(const v8::WeakCallbackInfo& data) { - Reference* reference = data.GetParameter(); - - // The reference must be reset during the first pass. - reference->_persistent.Reset(); - - data.SetSecondPassCallback(SecondPassCallback); - } - - static void SecondPassCallback(const v8::WeakCallbackInfo& data) { - data.GetParameter()->Finalize(); - } - - v8impl::Persistent _persistent; - uint32_t _refcount; - bool _delete_self; -}; - -enum UnwrapAction { - KeepWrap, - RemoveWrap -}; - -inline static napi_status Unwrap(napi_env env, - napi_value js_object, - void** result, - UnwrapAction action) { - NAPI_PREAMBLE(env); - CHECK_ARG(env, js_object); - if (action == KeepWrap) { - CHECK_ARG(env, result); - } - - v8::Isolate* isolate = env->isolate; - v8::Local context = isolate->GetCurrentContext(); - - v8::Local value = v8impl::V8LocalValueFromJsValue(js_object); - RETURN_STATUS_IF_FALSE(env, value->IsObject(), napi_invalid_arg); - v8::Local obj = value.As(); - - auto val = obj->GetInternalField(0); - RETURN_STATUS_IF_FALSE(env, val->IsExternal(), napi_invalid_arg); - Reference* reference = - static_cast(val.As()->Value()); - - if (result) { - *result = reference->Data(); - } - - if (action == RemoveWrap) { - obj->SetInternalField(0, v8::Undefined(env->isolate)); - Reference::Delete(reference); - } - - return GET_RETURN_STATUS(env); -} - -//=== Function napi_callback wrapper ================================= - -// Use this data structure to associate callback data with each N-API function -// exposed to JavaScript. The structure is stored in a v8::External which gets -// passed into our callback wrapper. This reduces the performance impact of -// calling through N-API. -// Ref: benchmark/misc/function_call -// Discussion (incl. perf. data): https://github.com/nodejs/node/pull/21072 -struct CallbackBundle { - napi_env env; // Necessary to invoke C++ NAPI callback - void* cb_data; // The user provided callback data - napi_callback function_or_getter; - napi_callback setter; -}; - -// Base class extended by classes that wrap V8 function and property callback -// info. -class CallbackWrapper { - public: - CallbackWrapper(napi_value this_arg, size_t args_length, void* data) - : _this(this_arg), _args_length(args_length), _data(data) {} - - virtual napi_value GetNewTarget() = 0; - virtual void Args(napi_value* buffer, size_t bufferlength) = 0; - virtual void SetReturnValue(napi_value value) = 0; - - napi_value This() { return _this; } - - size_t ArgsLength() { return _args_length; } - - void* Data() { return _data; } - - protected: - const napi_value _this; - const size_t _args_length; - void* _data; -}; - -template -class CallbackWrapperBase : public CallbackWrapper { - public: - CallbackWrapperBase(const Info& cbinfo, const size_t args_length) - : CallbackWrapper(JsValueFromV8LocalValue(cbinfo.This()), - args_length, - nullptr), - _cbinfo(cbinfo) { - _bundle = reinterpret_cast( - v8::Local::Cast(cbinfo.Data())->Value()); - _data = _bundle->cb_data; - } - - napi_value GetNewTarget() override { return nullptr; } - - protected: - void InvokeCallback() { - napi_callback_info cbinfo_wrapper = reinterpret_cast( - static_cast(this)); - - // All other pointers we need are stored in `_bundle` - napi_env env = _bundle->env; - napi_callback cb = _bundle->*FunctionField; - - napi_value result; - env->CallIntoModuleThrow([&](napi_env env) { - result = cb(env, cbinfo_wrapper); - }); - - if (result != nullptr) { - this->SetReturnValue(result); - } - } - - const Info& _cbinfo; - CallbackBundle* _bundle; -}; - -class FunctionCallbackWrapper - : public CallbackWrapperBase, - &CallbackBundle::function_or_getter> { - public: - static void Invoke(const v8::FunctionCallbackInfo& info) { - FunctionCallbackWrapper cbwrapper(info); - cbwrapper.InvokeCallback(); - } - - explicit FunctionCallbackWrapper( - const v8::FunctionCallbackInfo& cbinfo) - : CallbackWrapperBase(cbinfo, cbinfo.Length()) {} - - napi_value GetNewTarget() override { - if (_cbinfo.IsConstructCall()) { - return v8impl::JsValueFromV8LocalValue(_cbinfo.NewTarget()); - } else { - return nullptr; - } - } - - /*virtual*/ - void Args(napi_value* buffer, size_t buffer_length) override { - size_t i = 0; - size_t min = std::min(buffer_length, _args_length); - - for (; i < min; i += 1) { - buffer[i] = v8impl::JsValueFromV8LocalValue(_cbinfo[i]); - } - - if (i < buffer_length) { - napi_value undefined = - v8impl::JsValueFromV8LocalValue(v8::Undefined(_cbinfo.GetIsolate())); - for (; i < buffer_length; i += 1) { - buffer[i] = undefined; - } - } - } - - /*virtual*/ - void SetReturnValue(napi_value value) override { - v8::Local val = v8impl::V8LocalValueFromJsValue(value); - _cbinfo.GetReturnValue().Set(val); - } -}; - -class GetterCallbackWrapper - : public CallbackWrapperBase, - &CallbackBundle::function_or_getter> { - public: - static void Invoke(v8::Local property, - const v8::PropertyCallbackInfo& info) { - GetterCallbackWrapper cbwrapper(info); - cbwrapper.InvokeCallback(); - } - - explicit GetterCallbackWrapper( - const v8::PropertyCallbackInfo& cbinfo) - : CallbackWrapperBase(cbinfo, 0) {} - - /*virtual*/ - void Args(napi_value* buffer, size_t buffer_length) override { - if (buffer_length > 0) { - napi_value undefined = - v8impl::JsValueFromV8LocalValue(v8::Undefined(_cbinfo.GetIsolate())); - for (size_t i = 0; i < buffer_length; i += 1) { - buffer[i] = undefined; - } - } - } - - /*virtual*/ - void SetReturnValue(napi_value value) override { - v8::Local val = v8impl::V8LocalValueFromJsValue(value); - _cbinfo.GetReturnValue().Set(val); - } -}; - -class SetterCallbackWrapper - : public CallbackWrapperBase, - &CallbackBundle::setter> { - public: - static void Invoke(v8::Local property, - v8::Local value, - const v8::PropertyCallbackInfo& info) { - SetterCallbackWrapper cbwrapper(info, value); - cbwrapper.InvokeCallback(); - } - - SetterCallbackWrapper(const v8::PropertyCallbackInfo& cbinfo, - const v8::Local& value) - : CallbackWrapperBase(cbinfo, 1), _value(value) {} - - /*virtual*/ - void Args(napi_value* buffer, size_t buffer_length) override { - if (buffer_length > 0) { - buffer[0] = v8impl::JsValueFromV8LocalValue(_value); - - if (buffer_length > 1) { - napi_value undefined = v8impl::JsValueFromV8LocalValue( - v8::Undefined(_cbinfo.GetIsolate())); - for (size_t i = 1; i < buffer_length; i += 1) { - buffer[i] = undefined; - } - } - } - } - - /*virtual*/ - void SetReturnValue(napi_value value) override { - // Ignore any value returned from a setter callback. - } - - private: - const v8::Local& _value; -}; - -static void DeleteCallbackBundle(napi_env env, void* data, void* hint) { - CallbackBundle* bundle = static_cast(data); - delete bundle; -} - -// Creates an object to be made available to the static function callback -// wrapper, used to retrieve the native callback function and data pointer. -static -v8::Local CreateFunctionCallbackData(napi_env env, - napi_callback cb, - void* data) { - CallbackBundle* bundle = new CallbackBundle(); - bundle->function_or_getter = cb; - bundle->cb_data = data; - bundle->env = env; - v8::Local cbdata = v8::External::New(env->isolate, bundle); - Reference::New(env, cbdata, 0, true, DeleteCallbackBundle, bundle, nullptr); - - return cbdata; -} - -enum WrapType { - retrievable, - anonymous -}; - -template -inline napi_status Wrap(napi_env env, - napi_value js_object, - void* native_object, - napi_finalize finalize_cb, - void* finalize_hint, - napi_ref* result) { - NAPI_PREAMBLE(env); - CHECK_ARG(env, js_object); - - v8::Local context = env->context(); - - v8::Local value = v8impl::V8LocalValueFromJsValue(js_object); - RETURN_STATUS_IF_FALSE(env, value->IsObject(), napi_invalid_arg); - v8::Local obj = value.As(); - - if (wrap_type == retrievable) { - // If we've already wrapped this object, we error out. - RETURN_STATUS_IF_FALSE(env, - obj->GetInternalField(0)->IsUndefined(), - napi_invalid_arg); - } else if (wrap_type == anonymous) { - // If no finalize callback is provided, we error out. - CHECK_ARG(env, finalize_cb); - } - - v8impl::Reference* reference = nullptr; - if (result != nullptr) { - // The returned reference should be deleted via napi_delete_reference() - // ONLY in response to the finalize callback invocation. (If it is deleted - // before then, then the finalize callback will never be invoked.) - // Therefore a finalize callback is required when returning a reference. - CHECK_ARG(env, finalize_cb); - reference = v8impl::Reference::New( - env, obj, 0, false, finalize_cb, native_object, finalize_hint); - *result = reinterpret_cast(reference); - } else { - // Create a self-deleting reference. - reference = v8impl::Reference::New(env, obj, 0, true, finalize_cb, - native_object, finalize_cb == nullptr ? nullptr : finalize_hint); - } - - if (wrap_type == retrievable) { - obj->SetInternalField(0, v8::External::New(env->isolate, reference)); - } - - return GET_RETURN_STATUS(env); -} - -} // end of anonymous namespace - -} // end of namespace v8impl - -// Warning: Keep in-sync with napi_status enum -static -const char* error_messages[] = {nullptr, - "Invalid argument", - "An object was expected", - "A string was expected", - "A string or symbol was expected", - "A function was expected", - "A number was expected", - "A boolean was expected", - "An array was expected", - "Unknown failure", - "An exception is pending", - "The async work item was cancelled", - "napi_escape_handle already called on scope", - "Invalid handle scope usage", - "Invalid callback scope usage", - "Thread-safe function queue is full", - "Thread-safe function handle is closing", - "A bigint was expected", - "A date was expected", - "An arraybuffer was expected", - "A detachable arraybuffer was expected", -}; - -napi_status napi_get_last_error_info(napi_env env, - const napi_extended_error_info** result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - - // The value of the constant below must be updated to reference the last - // message in the `napi_status` enum each time a new error message is added. - // We don't have a napi_status_last as this would result in an ABI - // change each time a message was added. - const int last_status = napi_detachable_arraybuffer_expected; - - static_assert( - NAPI_ARRAYSIZE(error_messages) == last_status + 1, - "Count of error messages must match count of error values"); - CHECK_LE(env->last_error.error_code, last_status); - - // Wait until someone requests the last error information to fetch the error - // message string - env->last_error.error_message = - error_messages[env->last_error.error_code]; - - *result = &(env->last_error); - return napi_ok; -} - -napi_status napi_create_function(napi_env env, - const char* utf8name, - size_t length, - napi_callback cb, - void* callback_data, - napi_value* result) { - NAPI_PREAMBLE(env); - CHECK_ARG(env, result); - CHECK_ARG(env, cb); - - v8::Isolate* isolate = env->isolate; - v8::Local return_value; - v8::EscapableHandleScope scope(isolate); - v8::Local cbdata = - v8impl::CreateFunctionCallbackData(env, cb, callback_data); - - RETURN_STATUS_IF_FALSE(env, !cbdata.IsEmpty(), napi_generic_failure); - - v8::Local context = env->context(); - v8::MaybeLocal maybe_function = - v8::Function::New(context, - v8impl::FunctionCallbackWrapper::Invoke, - cbdata); - CHECK_MAYBE_EMPTY(env, maybe_function, napi_generic_failure); - - return_value = scope.Escape(maybe_function.ToLocalChecked()); - - if (utf8name != nullptr) { - v8::Local name_string; - CHECK_NEW_FROM_UTF8_LEN(env, name_string, utf8name, length); - return_value->SetName(name_string); - } - - *result = v8impl::JsValueFromV8LocalValue(return_value); - - return GET_RETURN_STATUS(env); -} - -napi_status napi_define_class(napi_env env, - const char* utf8name, - size_t length, - napi_callback constructor, - void* callback_data, - size_t property_count, - const napi_property_descriptor* properties, - napi_value* result) { - NAPI_PREAMBLE(env); - CHECK_ARG(env, result); - CHECK_ARG(env, constructor); - - if (property_count > 0) { - CHECK_ARG(env, properties); - } - - v8::Isolate* isolate = env->isolate; - - v8::EscapableHandleScope scope(isolate); - v8::Local cbdata = - v8impl::CreateFunctionCallbackData(env, constructor, callback_data); - - RETURN_STATUS_IF_FALSE(env, !cbdata.IsEmpty(), napi_generic_failure); - - v8::Local tpl = v8::FunctionTemplate::New( - isolate, v8impl::FunctionCallbackWrapper::Invoke, cbdata); - - tpl->InstanceTemplate()->SetInternalFieldCount(1); - - v8::Local name_string; - CHECK_NEW_FROM_UTF8_LEN(env, name_string, utf8name, length); - tpl->SetClassName(name_string); - - size_t static_property_count = 0; - for (size_t i = 0; i < property_count; i++) { - const napi_property_descriptor* p = properties + i; - - if ((p->attributes & napi_static) != 0) { - // Static properties are handled separately below. - static_property_count++; - continue; - } - - v8::Local property_name; - napi_status status = - v8impl::V8NameFromPropertyDescriptor(env, p, &property_name); - - if (status != napi_ok) { - return napi_set_last_error(env, status); - } - - v8::PropertyAttribute attributes = - v8impl::V8PropertyAttributesFromDescriptor(p); - - // This code is similar to that in napi_define_properties(); the - // difference is it applies to a template instead of an object, - // and preferred PropertyAttribute for lack of PropertyDescriptor - // support on ObjectTemplate. - if (p->getter != nullptr || p->setter != nullptr) { - v8::Local getter_tpl; - v8::Local setter_tpl; - if (p->getter != nullptr) { - v8::Local getter_data = - v8impl::CreateFunctionCallbackData(env, p->getter, p->data); - - getter_tpl = v8::FunctionTemplate::New( - isolate, v8impl::FunctionCallbackWrapper::Invoke, getter_data); - } - if (p->setter != nullptr) { - v8::Local setter_data = - v8impl::CreateFunctionCallbackData(env, p->setter, p->data); - - setter_tpl = v8::FunctionTemplate::New( - isolate, v8impl::FunctionCallbackWrapper::Invoke, setter_data); - } - - tpl->PrototypeTemplate()->SetAccessorProperty( - property_name, - getter_tpl, - setter_tpl, - attributes, - v8::AccessControl::DEFAULT); - } else if (p->method != nullptr) { - v8::Local cbdata = - v8impl::CreateFunctionCallbackData(env, p->method, p->data); - - RETURN_STATUS_IF_FALSE(env, !cbdata.IsEmpty(), napi_generic_failure); - - v8::Local t = - v8::FunctionTemplate::New(isolate, - v8impl::FunctionCallbackWrapper::Invoke, - cbdata, - v8::Signature::New(isolate, tpl)); - - tpl->PrototypeTemplate()->Set(property_name, t, attributes); - } else { - v8::Local value = v8impl::V8LocalValueFromJsValue(p->value); - tpl->PrototypeTemplate()->Set(property_name, value, attributes); - } - } - - v8::Local context = env->context(); - *result = v8impl::JsValueFromV8LocalValue( - scope.Escape(tpl->GetFunction(context).ToLocalChecked())); - - if (static_property_count > 0) { - std::vector static_descriptors; - static_descriptors.reserve(static_property_count); - - for (size_t i = 0; i < property_count; i++) { - const napi_property_descriptor* p = properties + i; - if ((p->attributes & napi_static) != 0) { - static_descriptors.push_back(*p); - } - } - - napi_status status = - napi_define_properties(env, - *result, - static_descriptors.size(), - static_descriptors.data()); - if (status != napi_ok) return status; - } - - return GET_RETURN_STATUS(env); -} - -napi_status napi_get_property_names(napi_env env, - napi_value object, - napi_value* result) { - NAPI_PREAMBLE(env); - CHECK_ARG(env, result); - - v8::Local context = env->context(); - v8::Local obj; - CHECK_TO_OBJECT(env, context, obj, object); - - v8::MaybeLocal maybe_propertynames = obj->GetPropertyNames( - context, - v8::KeyCollectionMode::kIncludePrototypes, - static_cast( - v8::PropertyFilter::ONLY_ENUMERABLE | - v8::PropertyFilter::SKIP_SYMBOLS), - v8::IndexFilter::kIncludeIndices, - v8::KeyConversionMode::kConvertToString); - - CHECK_MAYBE_EMPTY(env, maybe_propertynames, napi_generic_failure); - - *result = v8impl::JsValueFromV8LocalValue( - maybe_propertynames.ToLocalChecked()); - return GET_RETURN_STATUS(env); -} - -napi_status napi_set_property(napi_env env, - napi_value object, - napi_value key, - napi_value value) { - NAPI_PREAMBLE(env); - CHECK_ARG(env, key); - CHECK_ARG(env, value); - - v8::Local context = env->context(); - v8::Local obj; - - CHECK_TO_OBJECT(env, context, obj, object); - - v8::Local k = v8impl::V8LocalValueFromJsValue(key); - v8::Local val = v8impl::V8LocalValueFromJsValue(value); - - v8::Maybe set_maybe = obj->Set(context, k, val); - - RETURN_STATUS_IF_FALSE(env, set_maybe.FromMaybe(false), napi_generic_failure); - return GET_RETURN_STATUS(env); -} - -napi_status napi_has_property(napi_env env, - napi_value object, - napi_value key, - bool* result) { - NAPI_PREAMBLE(env); - CHECK_ARG(env, result); - CHECK_ARG(env, key); - - v8::Local context = env->context(); - v8::Local obj; - - CHECK_TO_OBJECT(env, context, obj, object); - - v8::Local k = v8impl::V8LocalValueFromJsValue(key); - v8::Maybe has_maybe = obj->Has(context, k); - - CHECK_MAYBE_NOTHING(env, has_maybe, napi_generic_failure); - - *result = has_maybe.FromMaybe(false); - return GET_RETURN_STATUS(env); -} - -napi_status napi_get_property(napi_env env, - napi_value object, - napi_value key, - napi_value* result) { - NAPI_PREAMBLE(env); - CHECK_ARG(env, key); - CHECK_ARG(env, result); - - v8::Local context = env->context(); - v8::Local k = v8impl::V8LocalValueFromJsValue(key); - v8::Local obj; - - CHECK_TO_OBJECT(env, context, obj, object); - - auto get_maybe = obj->Get(context, k); - - CHECK_MAYBE_EMPTY(env, get_maybe, napi_generic_failure); - - v8::Local val = get_maybe.ToLocalChecked(); - *result = v8impl::JsValueFromV8LocalValue(val); - return GET_RETURN_STATUS(env); -} - -napi_status napi_delete_property(napi_env env, - napi_value object, - napi_value key, - bool* result) { - NAPI_PREAMBLE(env); - CHECK_ARG(env, key); - - v8::Local context = env->context(); - v8::Local k = v8impl::V8LocalValueFromJsValue(key); - v8::Local obj; - - CHECK_TO_OBJECT(env, context, obj, object); - v8::Maybe delete_maybe = obj->Delete(context, k); - CHECK_MAYBE_NOTHING(env, delete_maybe, napi_generic_failure); - - if (result != nullptr) - *result = delete_maybe.FromMaybe(false); - - return GET_RETURN_STATUS(env); -} - -napi_status napi_has_own_property(napi_env env, - napi_value object, - napi_value key, - bool* result) { - NAPI_PREAMBLE(env); - CHECK_ARG(env, key); - - v8::Local context = env->context(); - v8::Local obj; - - CHECK_TO_OBJECT(env, context, obj, object); - v8::Local k = v8impl::V8LocalValueFromJsValue(key); - RETURN_STATUS_IF_FALSE(env, k->IsName(), napi_name_expected); - v8::Maybe has_maybe = obj->HasOwnProperty(context, k.As()); - CHECK_MAYBE_NOTHING(env, has_maybe, napi_generic_failure); - *result = has_maybe.FromMaybe(false); - - return GET_RETURN_STATUS(env); -} - -napi_status napi_set_named_property(napi_env env, - napi_value object, - const char* utf8name, - napi_value value) { - NAPI_PREAMBLE(env); - CHECK_ARG(env, value); - - v8::Local context = env->context(); - v8::Local obj; - - CHECK_TO_OBJECT(env, context, obj, object); - - v8::Local key; - CHECK_NEW_FROM_UTF8(env, key, utf8name); - - v8::Local val = v8impl::V8LocalValueFromJsValue(value); - - v8::Maybe set_maybe = obj->Set(context, key, val); - - RETURN_STATUS_IF_FALSE(env, set_maybe.FromMaybe(false), napi_generic_failure); - return GET_RETURN_STATUS(env); -} - -napi_status napi_has_named_property(napi_env env, - napi_value object, - const char* utf8name, - bool* result) { - NAPI_PREAMBLE(env); - CHECK_ARG(env, result); - - v8::Local context = env->context(); - v8::Local obj; - - CHECK_TO_OBJECT(env, context, obj, object); - - v8::Local key; - CHECK_NEW_FROM_UTF8(env, key, utf8name); - - v8::Maybe has_maybe = obj->Has(context, key); - - CHECK_MAYBE_NOTHING(env, has_maybe, napi_generic_failure); - - *result = has_maybe.FromMaybe(false); - return GET_RETURN_STATUS(env); -} - -napi_status napi_get_named_property(napi_env env, - napi_value object, - const char* utf8name, - napi_value* result) { - NAPI_PREAMBLE(env); - CHECK_ARG(env, result); - - v8::Local context = env->context(); - - v8::Local key; - CHECK_NEW_FROM_UTF8(env, key, utf8name); - - v8::Local obj; - - CHECK_TO_OBJECT(env, context, obj, object); - - auto get_maybe = obj->Get(context, key); - - CHECK_MAYBE_EMPTY(env, get_maybe, napi_generic_failure); - - v8::Local val = get_maybe.ToLocalChecked(); - *result = v8impl::JsValueFromV8LocalValue(val); - return GET_RETURN_STATUS(env); -} - -napi_status napi_set_element(napi_env env, - napi_value object, - uint32_t index, - napi_value value) { - NAPI_PREAMBLE(env); - CHECK_ARG(env, value); - - v8::Local context = env->context(); - v8::Local obj; - - CHECK_TO_OBJECT(env, context, obj, object); - - v8::Local val = v8impl::V8LocalValueFromJsValue(value); - auto set_maybe = obj->Set(context, index, val); - - RETURN_STATUS_IF_FALSE(env, set_maybe.FromMaybe(false), napi_generic_failure); - - return GET_RETURN_STATUS(env); -} - -napi_status napi_has_element(napi_env env, - napi_value object, - uint32_t index, - bool* result) { - NAPI_PREAMBLE(env); - CHECK_ARG(env, result); - - v8::Local context = env->context(); - v8::Local obj; - - CHECK_TO_OBJECT(env, context, obj, object); - - v8::Maybe has_maybe = obj->Has(context, index); - - CHECK_MAYBE_NOTHING(env, has_maybe, napi_generic_failure); - - *result = has_maybe.FromMaybe(false); - return GET_RETURN_STATUS(env); -} - -napi_status napi_get_element(napi_env env, - napi_value object, - uint32_t index, - napi_value* result) { - NAPI_PREAMBLE(env); - CHECK_ARG(env, result); - - v8::Local context = env->context(); - v8::Local obj; - - CHECK_TO_OBJECT(env, context, obj, object); - - auto get_maybe = obj->Get(context, index); - - CHECK_MAYBE_EMPTY(env, get_maybe, napi_generic_failure); - - *result = v8impl::JsValueFromV8LocalValue(get_maybe.ToLocalChecked()); - return GET_RETURN_STATUS(env); -} - -napi_status napi_delete_element(napi_env env, - napi_value object, - uint32_t index, - bool* result) { - NAPI_PREAMBLE(env); - - v8::Local context = env->context(); - v8::Local obj; - - CHECK_TO_OBJECT(env, context, obj, object); - v8::Maybe delete_maybe = obj->Delete(context, index); - CHECK_MAYBE_NOTHING(env, delete_maybe, napi_generic_failure); - - if (result != nullptr) - *result = delete_maybe.FromMaybe(false); - - return GET_RETURN_STATUS(env); -} - -napi_status napi_define_properties(napi_env env, - napi_value object, - size_t property_count, - const napi_property_descriptor* properties) { - NAPI_PREAMBLE(env); - if (property_count > 0) { - CHECK_ARG(env, properties); - } - - v8::Local context = env->context(); - - v8::Local obj; - CHECK_TO_OBJECT(env, context, obj, object); - - for (size_t i = 0; i < property_count; i++) { - const napi_property_descriptor* p = &properties[i]; - - v8::Local property_name; - napi_status status = - v8impl::V8NameFromPropertyDescriptor(env, p, &property_name); - - if (status != napi_ok) { - return napi_set_last_error(env, status); - } - - if (p->getter != nullptr || p->setter != nullptr) { - v8::Local local_getter; - v8::Local local_setter; - - if (p->getter != nullptr) { - v8::Local getter_data = - v8impl::CreateFunctionCallbackData(env, p->getter, p->data); - CHECK_MAYBE_EMPTY(env, getter_data, napi_generic_failure); - - v8::MaybeLocal maybe_getter = - v8::Function::New(context, - v8impl::FunctionCallbackWrapper::Invoke, - getter_data); - CHECK_MAYBE_EMPTY(env, maybe_getter, napi_generic_failure); - - local_getter = maybe_getter.ToLocalChecked(); - } - if (p->setter != nullptr) { - v8::Local setter_data = - v8impl::CreateFunctionCallbackData(env, p->setter, p->data); - CHECK_MAYBE_EMPTY(env, setter_data, napi_generic_failure); - - v8::MaybeLocal maybe_setter = - v8::Function::New(context, - v8impl::FunctionCallbackWrapper::Invoke, - setter_data); - CHECK_MAYBE_EMPTY(env, maybe_setter, napi_generic_failure); - local_setter = maybe_setter.ToLocalChecked(); - } - - v8::PropertyDescriptor descriptor(local_getter, local_setter); - descriptor.set_enumerable((p->attributes & napi_enumerable) != 0); - descriptor.set_configurable((p->attributes & napi_configurable) != 0); - - auto define_maybe = obj->DefineProperty(context, - property_name, - descriptor); - - if (!define_maybe.FromMaybe(false)) { - return napi_set_last_error(env, napi_invalid_arg); - } - } else if (p->method != nullptr) { - v8::Local cbdata = - v8impl::CreateFunctionCallbackData(env, p->method, p->data); - - CHECK_MAYBE_EMPTY(env, cbdata, napi_generic_failure); - - v8::MaybeLocal maybe_fn = - v8::Function::New(context, - v8impl::FunctionCallbackWrapper::Invoke, - cbdata); - - CHECK_MAYBE_EMPTY(env, maybe_fn, napi_generic_failure); - - v8::PropertyDescriptor descriptor(maybe_fn.ToLocalChecked(), - (p->attributes & napi_writable) != 0); - descriptor.set_enumerable((p->attributes & napi_enumerable) != 0); - descriptor.set_configurable((p->attributes & napi_configurable) != 0); - - auto define_maybe = obj->DefineProperty(context, - property_name, - descriptor); - - if (!define_maybe.FromMaybe(false)) { - return napi_set_last_error(env, napi_generic_failure); - } - } else { - v8::Local value = v8impl::V8LocalValueFromJsValue(p->value); - - v8::PropertyDescriptor descriptor(value, - (p->attributes & napi_writable) != 0); - descriptor.set_enumerable((p->attributes & napi_enumerable) != 0); - descriptor.set_configurable((p->attributes & napi_configurable) != 0); - - auto define_maybe = - obj->DefineProperty(context, property_name, descriptor); - - if (!define_maybe.FromMaybe(false)) { - return napi_set_last_error(env, napi_invalid_arg); - } - } - } - - return GET_RETURN_STATUS(env); -} - -napi_status napi_is_array(napi_env env, napi_value value, bool* result) { - CHECK_ENV(env); - CHECK_ARG(env, value); - CHECK_ARG(env, result); - - v8::Local val = v8impl::V8LocalValueFromJsValue(value); - - *result = val->IsArray(); - return napi_clear_last_error(env); -} - -napi_status napi_get_array_length(napi_env env, - napi_value value, - uint32_t* result) { - NAPI_PREAMBLE(env); - CHECK_ARG(env, value); - CHECK_ARG(env, result); - - v8::Local val = v8impl::V8LocalValueFromJsValue(value); - RETURN_STATUS_IF_FALSE(env, val->IsArray(), napi_array_expected); - - v8::Local arr = val.As(); - *result = arr->Length(); - - return GET_RETURN_STATUS(env); -} - -napi_status napi_strict_equals(napi_env env, - napi_value lhs, - napi_value rhs, - bool* result) { - NAPI_PREAMBLE(env); - CHECK_ARG(env, lhs); - CHECK_ARG(env, rhs); - CHECK_ARG(env, result); - - v8::Local a = v8impl::V8LocalValueFromJsValue(lhs); - v8::Local b = v8impl::V8LocalValueFromJsValue(rhs); - - *result = a->StrictEquals(b); - return GET_RETURN_STATUS(env); -} - -napi_status napi_get_prototype(napi_env env, - napi_value object, - napi_value* result) { - NAPI_PREAMBLE(env); - CHECK_ARG(env, result); - - v8::Local context = env->context(); - - v8::Local obj; - CHECK_TO_OBJECT(env, context, obj, object); - - v8::Local val = obj->GetPrototype(); - *result = v8impl::JsValueFromV8LocalValue(val); - return GET_RETURN_STATUS(env); -} - -napi_status napi_create_object(napi_env env, napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - - *result = v8impl::JsValueFromV8LocalValue( - v8::Object::New(env->isolate)); - - return napi_clear_last_error(env); -} - -napi_status napi_create_array(napi_env env, napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - - *result = v8impl::JsValueFromV8LocalValue( - v8::Array::New(env->isolate)); - - return napi_clear_last_error(env); -} - -napi_status napi_create_array_with_length(napi_env env, - size_t length, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - - *result = v8impl::JsValueFromV8LocalValue( - v8::Array::New(env->isolate, length)); - - return napi_clear_last_error(env); -} - -napi_status napi_create_string_latin1(napi_env env, - const char* str, - size_t length, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - RETURN_STATUS_IF_FALSE(env, - (length == NAPI_AUTO_LENGTH) || length <= INT_MAX, - napi_invalid_arg); - - auto isolate = env->isolate; - auto str_maybe = - v8::String::NewFromOneByte(isolate, - reinterpret_cast(str), - v8::NewStringType::kNormal, - length); - CHECK_MAYBE_EMPTY(env, str_maybe, napi_generic_failure); - - *result = v8impl::JsValueFromV8LocalValue(str_maybe.ToLocalChecked()); - return napi_clear_last_error(env); -} - -napi_status napi_create_string_utf8(napi_env env, - const char* str, - size_t length, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - RETURN_STATUS_IF_FALSE(env, - (length == NAPI_AUTO_LENGTH) || length <= INT_MAX, - napi_invalid_arg); - - auto isolate = env->isolate; - auto str_maybe = - v8::String::NewFromUtf8(isolate, - str, - v8::NewStringType::kNormal, - static_cast(length)); - CHECK_MAYBE_EMPTY(env, str_maybe, napi_generic_failure); - *result = v8impl::JsValueFromV8LocalValue(str_maybe.ToLocalChecked()); - return napi_clear_last_error(env); -} - -napi_status napi_create_string_utf16(napi_env env, - const char16_t* str, - size_t length, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - RETURN_STATUS_IF_FALSE(env, - (length == NAPI_AUTO_LENGTH) || length <= INT_MAX, - napi_invalid_arg); - - auto isolate = env->isolate; - auto str_maybe = - v8::String::NewFromTwoByte(isolate, - reinterpret_cast(str), - v8::NewStringType::kNormal, - length); - CHECK_MAYBE_EMPTY(env, str_maybe, napi_generic_failure); - - *result = v8impl::JsValueFromV8LocalValue(str_maybe.ToLocalChecked()); - return napi_clear_last_error(env); -} - -napi_status napi_create_double(napi_env env, - double value, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - - *result = v8impl::JsValueFromV8LocalValue( - v8::Number::New(env->isolate, value)); - - return napi_clear_last_error(env); -} - -napi_status napi_create_int32(napi_env env, - int32_t value, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - - *result = v8impl::JsValueFromV8LocalValue( - v8::Integer::New(env->isolate, value)); - - return napi_clear_last_error(env); -} - -napi_status napi_create_uint32(napi_env env, - uint32_t value, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - - *result = v8impl::JsValueFromV8LocalValue( - v8::Integer::NewFromUnsigned(env->isolate, value)); - - return napi_clear_last_error(env); -} - -napi_status napi_create_int64(napi_env env, - int64_t value, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - - *result = v8impl::JsValueFromV8LocalValue( - v8::Number::New(env->isolate, static_cast(value))); - - return napi_clear_last_error(env); -} - -napi_status napi_create_bigint_int64(napi_env env, - int64_t value, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - - *result = v8impl::JsValueFromV8LocalValue( - v8::BigInt::New(env->isolate, value)); - - return napi_clear_last_error(env); -} - -napi_status napi_create_bigint_uint64(napi_env env, - uint64_t value, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - - *result = v8impl::JsValueFromV8LocalValue( - v8::BigInt::NewFromUnsigned(env->isolate, value)); - - return napi_clear_last_error(env); -} - -napi_status napi_create_bigint_words(napi_env env, - int sign_bit, - size_t word_count, - const uint64_t* words, - napi_value* result) { - NAPI_PREAMBLE(env); - CHECK_ARG(env, words); - CHECK_ARG(env, result); - - v8::Local context = env->context(); - - if (word_count > INT_MAX) { - napi_throw_range_error(env, nullptr, "Maximum BigInt size exceeded"); - return napi_set_last_error(env, napi_pending_exception); - } - - v8::MaybeLocal b = v8::BigInt::NewFromWords( - context, sign_bit, word_count, words); - - if (try_catch.HasCaught()) { - return napi_set_last_error(env, napi_pending_exception); - } else { - CHECK_MAYBE_EMPTY(env, b, napi_generic_failure); - *result = v8impl::JsValueFromV8LocalValue(b.ToLocalChecked()); - return napi_clear_last_error(env); - } -} - -napi_status napi_get_boolean(napi_env env, bool value, napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - - v8::Isolate* isolate = env->isolate; - - if (value) { - *result = v8impl::JsValueFromV8LocalValue(v8::True(isolate)); - } else { - *result = v8impl::JsValueFromV8LocalValue(v8::False(isolate)); - } - - return napi_clear_last_error(env); -} - -napi_status napi_create_symbol(napi_env env, - napi_value description, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - - v8::Isolate* isolate = env->isolate; - - if (description == nullptr) { - *result = v8impl::JsValueFromV8LocalValue(v8::Symbol::New(isolate)); - } else { - v8::Local desc = v8impl::V8LocalValueFromJsValue(description); - RETURN_STATUS_IF_FALSE(env, desc->IsString(), napi_string_expected); - - *result = v8impl::JsValueFromV8LocalValue( - v8::Symbol::New(isolate, desc.As())); - } - - return napi_clear_last_error(env); -} - -static inline napi_status set_error_code(napi_env env, - v8::Local error, - napi_value code, - const char* code_cstring) { - if ((code != nullptr) || (code_cstring != nullptr)) { - v8::Local context = env->context(); - v8::Local err_object = error.As(); - - v8::Local code_value = v8impl::V8LocalValueFromJsValue(code); - if (code != nullptr) { - code_value = v8impl::V8LocalValueFromJsValue(code); - RETURN_STATUS_IF_FALSE(env, code_value->IsString(), napi_string_expected); - } else { - CHECK_NEW_FROM_UTF8(env, code_value, code_cstring); - } - - v8::Local code_key; - CHECK_NEW_FROM_UTF8(env, code_key, "code"); - - v8::Maybe set_maybe = err_object->Set(context, code_key, code_value); - RETURN_STATUS_IF_FALSE(env, - set_maybe.FromMaybe(false), - napi_generic_failure); - } - return napi_ok; -} - -napi_status napi_create_error(napi_env env, - napi_value code, - napi_value msg, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, msg); - CHECK_ARG(env, result); - - v8::Local message_value = v8impl::V8LocalValueFromJsValue(msg); - RETURN_STATUS_IF_FALSE(env, message_value->IsString(), napi_string_expected); - - v8::Local error_obj = - v8::Exception::Error(message_value.As()); - napi_status status = set_error_code(env, error_obj, code, nullptr); - if (status != napi_ok) return status; - - *result = v8impl::JsValueFromV8LocalValue(error_obj); - - return napi_clear_last_error(env); -} - -napi_status napi_create_type_error(napi_env env, - napi_value code, - napi_value msg, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, msg); - CHECK_ARG(env, result); - - v8::Local message_value = v8impl::V8LocalValueFromJsValue(msg); - RETURN_STATUS_IF_FALSE(env, message_value->IsString(), napi_string_expected); - - v8::Local error_obj = - v8::Exception::TypeError(message_value.As()); - napi_status status = set_error_code(env, error_obj, code, nullptr); - if (status != napi_ok) return status; - - *result = v8impl::JsValueFromV8LocalValue(error_obj); - - return napi_clear_last_error(env); -} - -napi_status napi_create_range_error(napi_env env, - napi_value code, - napi_value msg, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, msg); - CHECK_ARG(env, result); - - v8::Local message_value = v8impl::V8LocalValueFromJsValue(msg); - RETURN_STATUS_IF_FALSE(env, message_value->IsString(), napi_string_expected); - - v8::Local error_obj = - v8::Exception::RangeError(message_value.As()); - napi_status status = set_error_code(env, error_obj, code, nullptr); - if (status != napi_ok) return status; - - *result = v8impl::JsValueFromV8LocalValue(error_obj); - - return napi_clear_last_error(env); -} - -napi_status napi_typeof(napi_env env, - napi_value value, - napi_valuetype* result) { - // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw - // JS exceptions. - CHECK_ENV(env); - CHECK_ARG(env, value); - CHECK_ARG(env, result); - - v8::Local v = v8impl::V8LocalValueFromJsValue(value); - - if (v->IsNumber()) { - *result = napi_number; - } else if (v->IsBigInt()) { - *result = napi_bigint; - } else if (v->IsString()) { - *result = napi_string; - } else if (v->IsFunction()) { - // This test has to come before IsObject because IsFunction - // implies IsObject - *result = napi_function; - } else if (v->IsExternal()) { - // This test has to come before IsObject because IsExternal - // implies IsObject - *result = napi_external; - } else if (v->IsObject()) { - *result = napi_object; - } else if (v->IsBoolean()) { - *result = napi_boolean; - } else if (v->IsUndefined()) { - *result = napi_undefined; - } else if (v->IsSymbol()) { - *result = napi_symbol; - } else if (v->IsNull()) { - *result = napi_null; - } else { - // Should not get here unless V8 has added some new kind of value. - return napi_set_last_error(env, napi_invalid_arg); - } - - return napi_clear_last_error(env); -} - -napi_status napi_get_undefined(napi_env env, napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - - *result = v8impl::JsValueFromV8LocalValue( - v8::Undefined(env->isolate)); - - return napi_clear_last_error(env); -} - -napi_status napi_get_null(napi_env env, napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - - *result = v8impl::JsValueFromV8LocalValue( - v8::Null(env->isolate)); - - return napi_clear_last_error(env); -} - -// Gets all callback info in a single call. (Ugly, but faster.) -napi_status napi_get_cb_info( - napi_env env, // [in] NAPI environment handle - napi_callback_info cbinfo, // [in] Opaque callback-info handle - size_t* argc, // [in-out] Specifies the size of the provided argv array - // and receives the actual count of args. - napi_value* argv, // [out] Array of values - napi_value* this_arg, // [out] Receives the JS 'this' arg for the call - void** data) { // [out] Receives the data pointer for the callback. - CHECK_ENV(env); - CHECK_ARG(env, cbinfo); - - v8impl::CallbackWrapper* info = - reinterpret_cast(cbinfo); - - if (argv != nullptr) { - CHECK_ARG(env, argc); - info->Args(argv, *argc); - } - if (argc != nullptr) { - *argc = info->ArgsLength(); - } - if (this_arg != nullptr) { - *this_arg = info->This(); - } - if (data != nullptr) { - *data = info->Data(); - } - - return napi_clear_last_error(env); -} - -napi_status napi_get_new_target(napi_env env, - napi_callback_info cbinfo, - napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, cbinfo); - CHECK_ARG(env, result); - - v8impl::CallbackWrapper* info = - reinterpret_cast(cbinfo); - - *result = info->GetNewTarget(); - return napi_clear_last_error(env); -} - -napi_status napi_call_function(napi_env env, - napi_value recv, - napi_value func, - size_t argc, - const napi_value* argv, - napi_value* result) { - NAPI_PREAMBLE(env); - CHECK_ARG(env, recv); - if (argc > 0) { - CHECK_ARG(env, argv); - } - - v8::Local context = env->context(); - - v8::Local v8recv = v8impl::V8LocalValueFromJsValue(recv); - - v8::Local v8func; - CHECK_TO_FUNCTION(env, v8func, func); - - auto maybe = v8func->Call(context, v8recv, argc, - reinterpret_cast*>(const_cast(argv))); - - if (try_catch.HasCaught()) { - return napi_set_last_error(env, napi_pending_exception); - } else { - if (result != nullptr) { - CHECK_MAYBE_EMPTY(env, maybe, napi_generic_failure); - *result = v8impl::JsValueFromV8LocalValue(maybe.ToLocalChecked()); - } - return napi_clear_last_error(env); - } -} - -napi_status napi_get_global(napi_env env, napi_value* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - - *result = v8impl::JsValueFromV8LocalValue(env->context()->Global()); - - return napi_clear_last_error(env); -} - -napi_status napi_throw(napi_env env, napi_value error) { - NAPI_PREAMBLE(env); - CHECK_ARG(env, error); - - v8::Isolate* isolate = env->isolate; - - isolate->ThrowException(v8impl::V8LocalValueFromJsValue(error)); - // any VM calls after this point and before returning - // to the javascript invoker will fail - return napi_clear_last_error(env); -} - -napi_status napi_throw_error(napi_env env, - const char* code, - const char* msg) { - NAPI_PREAMBLE(env); - - v8::Isolate* isolate = env->isolate; - v8::Local str; - CHECK_NEW_FROM_UTF8(env, str, msg); - - v8::Local error_obj = v8::Exception::Error(str); - napi_status status = set_error_code(env, error_obj, nullptr, code); - if (status != napi_ok) return status; - - isolate->ThrowException(error_obj); - // any VM calls after this point and before returning - // to the javascript invoker will fail - return napi_clear_last_error(env); -} - -napi_status napi_throw_type_error(napi_env env, - const char* code, - const char* msg) { - NAPI_PREAMBLE(env); - - v8::Isolate* isolate = env->isolate; - v8::Local str; - CHECK_NEW_FROM_UTF8(env, str, msg); - - v8::Local error_obj = v8::Exception::TypeError(str); - napi_status status = set_error_code(env, error_obj, nullptr, code); - if (status != napi_ok) return status; - - isolate->ThrowException(error_obj); - // any VM calls after this point and before returning - // to the javascript invoker will fail - return napi_clear_last_error(env); -} - -napi_status napi_throw_range_error(napi_env env, - const char* code, - const char* msg) { - NAPI_PREAMBLE(env); - - v8::Isolate* isolate = env->isolate; - v8::Local str; - CHECK_NEW_FROM_UTF8(env, str, msg); - - v8::Local error_obj = v8::Exception::RangeError(str); - napi_status status = set_error_code(env, error_obj, nullptr, code); - if (status != napi_ok) return status; - - isolate->ThrowException(error_obj); - // any VM calls after this point and before returning - // to the javascript invoker will fail - return napi_clear_last_error(env); -} - -napi_status napi_is_error(napi_env env, napi_value value, bool* result) { - // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot - // throw JS exceptions. - CHECK_ENV(env); - CHECK_ARG(env, value); - CHECK_ARG(env, result); - - v8::Local val = v8impl::V8LocalValueFromJsValue(value); - *result = val->IsNativeError(); - - return napi_clear_last_error(env); -} - -napi_status napi_get_value_double(napi_env env, - napi_value value, - double* result) { - // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw - // JS exceptions. - CHECK_ENV(env); - CHECK_ARG(env, value); - CHECK_ARG(env, result); - - v8::Local val = v8impl::V8LocalValueFromJsValue(value); - RETURN_STATUS_IF_FALSE(env, val->IsNumber(), napi_number_expected); - - *result = val.As()->Value(); - - return napi_clear_last_error(env); -} - -napi_status napi_get_value_int32(napi_env env, - napi_value value, - int32_t* result) { - // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw - // JS exceptions. - CHECK_ENV(env); - CHECK_ARG(env, value); - CHECK_ARG(env, result); - - v8::Local val = v8impl::V8LocalValueFromJsValue(value); - - if (val->IsInt32()) { - *result = val.As()->Value(); - } else { - RETURN_STATUS_IF_FALSE(env, val->IsNumber(), napi_number_expected); - - // Empty context: https://github.com/nodejs/node/issues/14379 - v8::Local context; - *result = val->Int32Value(context).FromJust(); - } - - return napi_clear_last_error(env); -} - -napi_status napi_get_value_uint32(napi_env env, - napi_value value, - uint32_t* result) { - // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw - // JS exceptions. - CHECK_ENV(env); - CHECK_ARG(env, value); - CHECK_ARG(env, result); - - v8::Local val = v8impl::V8LocalValueFromJsValue(value); - - if (val->IsUint32()) { - *result = val.As()->Value(); - } else { - RETURN_STATUS_IF_FALSE(env, val->IsNumber(), napi_number_expected); - - // Empty context: https://github.com/nodejs/node/issues/14379 - v8::Local context; - *result = val->Uint32Value(context).FromJust(); - } - - return napi_clear_last_error(env); -} - -napi_status napi_get_value_int64(napi_env env, - napi_value value, - int64_t* result) { - // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw - // JS exceptions. - CHECK_ENV(env); - CHECK_ARG(env, value); - CHECK_ARG(env, result); - - v8::Local val = v8impl::V8LocalValueFromJsValue(value); - - // This is still a fast path very likely to be taken. - if (val->IsInt32()) { - *result = val.As()->Value(); - return napi_clear_last_error(env); - } - - RETURN_STATUS_IF_FALSE(env, val->IsNumber(), napi_number_expected); - - // v8::Value::IntegerValue() converts NaN, +Inf, and -Inf to INT64_MIN, - // inconsistent with v8::Value::Int32Value() which converts those values to 0. - // Special-case all non-finite values to match that behavior. - double doubleValue = val.As()->Value(); - if (std::isfinite(doubleValue)) { - // Empty context: https://github.com/nodejs/node/issues/14379 - v8::Local context; - *result = val->IntegerValue(context).FromJust(); - } else { - *result = 0; - } - - return napi_clear_last_error(env); -} - -napi_status napi_get_value_bigint_int64(napi_env env, - napi_value value, - int64_t* result, - bool* lossless) { - CHECK_ENV(env); - CHECK_ARG(env, value); - CHECK_ARG(env, result); - CHECK_ARG(env, lossless); - - v8::Local val = v8impl::V8LocalValueFromJsValue(value); - - RETURN_STATUS_IF_FALSE(env, val->IsBigInt(), napi_bigint_expected); - - *result = val.As()->Int64Value(lossless); - - return napi_clear_last_error(env); -} - -napi_status napi_get_value_bigint_uint64(napi_env env, - napi_value value, - uint64_t* result, - bool* lossless) { - CHECK_ENV(env); - CHECK_ARG(env, value); - CHECK_ARG(env, result); - CHECK_ARG(env, lossless); - - v8::Local val = v8impl::V8LocalValueFromJsValue(value); - - RETURN_STATUS_IF_FALSE(env, val->IsBigInt(), napi_bigint_expected); - - *result = val.As()->Uint64Value(lossless); - - return napi_clear_last_error(env); -} - -napi_status napi_get_value_bigint_words(napi_env env, - napi_value value, - int* sign_bit, - size_t* word_count, - uint64_t* words) { - CHECK_ENV(env); - CHECK_ARG(env, value); - CHECK_ARG(env, word_count); - - v8::Local val = v8impl::V8LocalValueFromJsValue(value); - - RETURN_STATUS_IF_FALSE(env, val->IsBigInt(), napi_bigint_expected); - - v8::Local big = val.As(); - - int word_count_int = *word_count; - - if (sign_bit == nullptr && words == nullptr) { - word_count_int = big->WordCount(); - } else { - CHECK_ARG(env, sign_bit); - CHECK_ARG(env, words); - big->ToWordsArray(sign_bit, &word_count_int, words); - } - - *word_count = word_count_int; - - return napi_clear_last_error(env); -} - -napi_status napi_get_value_bool(napi_env env, napi_value value, bool* result) { - // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw - // JS exceptions. - CHECK_ENV(env); - CHECK_ARG(env, value); - CHECK_ARG(env, result); - - v8::Local val = v8impl::V8LocalValueFromJsValue(value); - RETURN_STATUS_IF_FALSE(env, val->IsBoolean(), napi_boolean_expected); - - *result = val.As()->Value(); - - return napi_clear_last_error(env); -} - -// Copies a JavaScript string into a LATIN-1 string buffer. The result is the -// number of bytes (excluding the null terminator) copied into buf. -// A sufficient buffer size should be greater than the length of string, -// reserving space for null terminator. -// If bufsize is insufficient, the string will be truncated and null terminated. -// If buf is NULL, this method returns the length of the string (in bytes) -// via the result parameter. -// The result argument is optional unless buf is NULL. -napi_status napi_get_value_string_latin1(napi_env env, - napi_value value, - char* buf, - size_t bufsize, - size_t* result) { - CHECK_ENV(env); - CHECK_ARG(env, value); - - v8::Local val = v8impl::V8LocalValueFromJsValue(value); - RETURN_STATUS_IF_FALSE(env, val->IsString(), napi_string_expected); - - if (!buf) { - CHECK_ARG(env, result); - *result = val.As()->Length(); - } else { - int copied = - val.As()->WriteOneByte(env->isolate, - reinterpret_cast(buf), - 0, - bufsize - 1, - v8::String::NO_NULL_TERMINATION); - - buf[copied] = '\0'; - if (result != nullptr) { - *result = copied; - } - } - - return napi_clear_last_error(env); -} - -// Copies a JavaScript string into a UTF-8 string buffer. The result is the -// number of bytes (excluding the null terminator) copied into buf. -// A sufficient buffer size should be greater than the length of string, -// reserving space for null terminator. -// If bufsize is insufficient, the string will be truncated and null terminated. -// If buf is NULL, this method returns the length of the string (in bytes) -// via the result parameter. -// The result argument is optional unless buf is NULL. -napi_status napi_get_value_string_utf8(napi_env env, - napi_value value, - char* buf, - size_t bufsize, - size_t* result) { - CHECK_ENV(env); - CHECK_ARG(env, value); - - v8::Local val = v8impl::V8LocalValueFromJsValue(value); - RETURN_STATUS_IF_FALSE(env, val->IsString(), napi_string_expected); - - if (!buf) { - CHECK_ARG(env, result); - *result = val.As()->Utf8Length(env->isolate); - } else { - int copied = val.As()->WriteUtf8( - env->isolate, - buf, - bufsize - 1, - nullptr, - v8::String::REPLACE_INVALID_UTF8 | v8::String::NO_NULL_TERMINATION); - - buf[copied] = '\0'; - if (result != nullptr) { - *result = copied; - } - } - - return napi_clear_last_error(env); -} - -// Copies a JavaScript string into a UTF-16 string buffer. The result is the -// number of 2-byte code units (excluding the null terminator) copied into buf. -// A sufficient buffer size should be greater than the length of string, -// reserving space for null terminator. -// If bufsize is insufficient, the string will be truncated and null terminated. -// If buf is NULL, this method returns the length of the string (in 2-byte -// code units) via the result parameter. -// The result argument is optional unless buf is NULL. -napi_status napi_get_value_string_utf16(napi_env env, - napi_value value, - char16_t* buf, - size_t bufsize, - size_t* result) { - CHECK_ENV(env); - CHECK_ARG(env, value); - - v8::Local val = v8impl::V8LocalValueFromJsValue(value); - RETURN_STATUS_IF_FALSE(env, val->IsString(), napi_string_expected); - - if (!buf) { - CHECK_ARG(env, result); - // V8 assumes UTF-16 length is the same as the number of characters. - *result = val.As()->Length(); - } else { - int copied = val.As()->Write(env->isolate, - reinterpret_cast(buf), - 0, - bufsize - 1, - v8::String::NO_NULL_TERMINATION); - - buf[copied] = '\0'; - if (result != nullptr) { - *result = copied; - } - } - - return napi_clear_last_error(env); -} - -napi_status napi_coerce_to_bool(napi_env env, - napi_value value, - napi_value* result) { - NAPI_PREAMBLE(env); - CHECK_ARG(env, value); - CHECK_ARG(env, result); - - v8::Isolate* isolate = env->isolate; - v8::Local b = - v8impl::V8LocalValueFromJsValue(value)->ToBoolean(isolate); - *result = v8impl::JsValueFromV8LocalValue(b); - return GET_RETURN_STATUS(env); -} - -#define GEN_COERCE_FUNCTION(UpperCaseName, MixedCaseName, LowerCaseName) \ - napi_status napi_coerce_to_##LowerCaseName(napi_env env, \ - napi_value value, \ - napi_value* result) { \ - NAPI_PREAMBLE(env); \ - CHECK_ARG(env, value); \ - CHECK_ARG(env, result); \ - \ - v8::Local context = env->context(); \ - v8::Local str; \ - \ - CHECK_TO_##UpperCaseName(env, context, str, value); \ - \ - *result = v8impl::JsValueFromV8LocalValue(str); \ - return GET_RETURN_STATUS(env); \ - } - -GEN_COERCE_FUNCTION(NUMBER, Number, number) -GEN_COERCE_FUNCTION(OBJECT, Object, object) -GEN_COERCE_FUNCTION(STRING, String, string) - -#undef GEN_COERCE_FUNCTION - -napi_status napi_wrap(napi_env env, - napi_value js_object, - void* native_object, - napi_finalize finalize_cb, - void* finalize_hint, - napi_ref* result) { - return v8impl::Wrap(env, - js_object, - native_object, - finalize_cb, - finalize_hint, - result); -} - -napi_status napi_unwrap(napi_env env, napi_value obj, void** result) { - return v8impl::Unwrap(env, obj, result, v8impl::KeepWrap); -} - -napi_status napi_remove_wrap(napi_env env, napi_value obj, void** result) { - return v8impl::Unwrap(env, obj, result, v8impl::RemoveWrap); -} - -napi_status napi_create_external(napi_env env, - void* data, - napi_finalize finalize_cb, - void* finalize_hint, - napi_value* result) { - NAPI_PREAMBLE(env); - CHECK_ARG(env, result); - - v8::Isolate* isolate = env->isolate; - - v8::Local external_value = v8::External::New(isolate, data); - - // The Reference object will delete itself after invoking the finalizer - // callback. - v8impl::Reference::New(env, - external_value, - 0, - true, - finalize_cb, - data, - finalize_hint); - - *result = v8impl::JsValueFromV8LocalValue(external_value); - - return napi_clear_last_error(env); -} - -napi_status napi_get_value_external(napi_env env, - napi_value value, - void** result) { - CHECK_ENV(env); - CHECK_ARG(env, value); - CHECK_ARG(env, result); - - v8::Local val = v8impl::V8LocalValueFromJsValue(value); - RETURN_STATUS_IF_FALSE(env, val->IsExternal(), napi_invalid_arg); - - v8::Local external_value = val.As(); - *result = external_value->Value(); - - return napi_clear_last_error(env); -} - -// Set initial_refcount to 0 for a weak reference, >0 for a strong reference. -napi_status napi_create_reference(napi_env env, - napi_value value, - uint32_t initial_refcount, - napi_ref* result) { - // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw - // JS exceptions. - CHECK_ENV(env); - CHECK_ARG(env, value); - CHECK_ARG(env, result); - - v8::Local v8_value = v8impl::V8LocalValueFromJsValue(value); - - if (!(v8_value->IsObject() || v8_value->IsFunction())) { - return napi_set_last_error(env, napi_object_expected); - } - - v8impl::Reference* reference = - v8impl::Reference::New(env, v8_value, initial_refcount, false); - - *result = reinterpret_cast(reference); - return napi_clear_last_error(env); -} - -// Deletes a reference. The referenced value is released, and may be GC'd unless -// there are other references to it. -napi_status napi_delete_reference(napi_env env, napi_ref ref) { - // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw - // JS exceptions. - CHECK_ENV(env); - CHECK_ARG(env, ref); - - v8impl::Reference::Delete(reinterpret_cast(ref)); - - return napi_clear_last_error(env); -} - -// Increments the reference count, optionally returning the resulting count. -// After this call the reference will be a strong reference because its -// refcount is >0, and the referenced object is effectively "pinned". -// Calling this when the refcount is 0 and the object is unavailable -// results in an error. -napi_status napi_reference_ref(napi_env env, napi_ref ref, uint32_t* result) { - // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw - // JS exceptions. - CHECK_ENV(env); - CHECK_ARG(env, ref); - - v8impl::Reference* reference = reinterpret_cast(ref); - uint32_t count = reference->Ref(); - - if (result != nullptr) { - *result = count; - } - - return napi_clear_last_error(env); -} - -// Decrements the reference count, optionally returning the resulting count. If -// the result is 0 the reference is now weak and the object may be GC'd at any -// time if there are no other references. Calling this when the refcount is -// already 0 results in an error. -napi_status napi_reference_unref(napi_env env, napi_ref ref, uint32_t* result) { - // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw - // JS exceptions. - CHECK_ENV(env); - CHECK_ARG(env, ref); - - v8impl::Reference* reference = reinterpret_cast(ref); - - if (reference->RefCount() == 0) { - return napi_set_last_error(env, napi_generic_failure); - } - - uint32_t count = reference->Unref(); - - if (result != nullptr) { - *result = count; - } - - return napi_clear_last_error(env); -} - -// Attempts to get a referenced value. If the reference is weak, the value might -// no longer be available, in that case the call is still successful but the -// result is NULL. -napi_status napi_get_reference_value(napi_env env, - napi_ref ref, - napi_value* result) { - // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw - // JS exceptions. - CHECK_ENV(env); - CHECK_ARG(env, ref); - CHECK_ARG(env, result); - - v8impl::Reference* reference = reinterpret_cast(ref); - *result = v8impl::JsValueFromV8LocalValue(reference->Get()); - - return napi_clear_last_error(env); -} - -napi_status napi_open_handle_scope(napi_env env, napi_handle_scope* result) { - // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw - // JS exceptions. - CHECK_ENV(env); - CHECK_ARG(env, result); - - *result = v8impl::JsHandleScopeFromV8HandleScope( - new v8impl::HandleScopeWrapper(env->isolate)); - env->open_handle_scopes++; - return napi_clear_last_error(env); -} - -napi_status napi_close_handle_scope(napi_env env, napi_handle_scope scope) { - // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw - // JS exceptions. - CHECK_ENV(env); - CHECK_ARG(env, scope); - if (env->open_handle_scopes == 0) { - return napi_handle_scope_mismatch; - } - - env->open_handle_scopes--; - delete v8impl::V8HandleScopeFromJsHandleScope(scope); - return napi_clear_last_error(env); -} - -napi_status napi_open_escapable_handle_scope( - napi_env env, - napi_escapable_handle_scope* result) { - // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw - // JS exceptions. - CHECK_ENV(env); - CHECK_ARG(env, result); - - *result = v8impl::JsEscapableHandleScopeFromV8EscapableHandleScope( - new v8impl::EscapableHandleScopeWrapper(env->isolate)); - env->open_handle_scopes++; - return napi_clear_last_error(env); -} - -napi_status napi_close_escapable_handle_scope( - napi_env env, - napi_escapable_handle_scope scope) { - // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw - // JS exceptions. - CHECK_ENV(env); - CHECK_ARG(env, scope); - if (env->open_handle_scopes == 0) { - return napi_handle_scope_mismatch; - } - - delete v8impl::V8EscapableHandleScopeFromJsEscapableHandleScope(scope); - env->open_handle_scopes--; - return napi_clear_last_error(env); -} - -napi_status napi_escape_handle(napi_env env, - napi_escapable_handle_scope scope, - napi_value escapee, - napi_value* result) { - // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw - // JS exceptions. - CHECK_ENV(env); - CHECK_ARG(env, scope); - CHECK_ARG(env, escapee); - CHECK_ARG(env, result); - - v8impl::EscapableHandleScopeWrapper* s = - v8impl::V8EscapableHandleScopeFromJsEscapableHandleScope(scope); - if (!s->escape_called()) { - *result = v8impl::JsValueFromV8LocalValue( - s->Escape(v8impl::V8LocalValueFromJsValue(escapee))); - return napi_clear_last_error(env); - } - return napi_set_last_error(env, napi_escape_called_twice); -} - -napi_status napi_new_instance(napi_env env, - napi_value constructor, - size_t argc, - const napi_value* argv, - napi_value* result) { - NAPI_PREAMBLE(env); - CHECK_ARG(env, constructor); - if (argc > 0) { - CHECK_ARG(env, argv); - } - CHECK_ARG(env, result); - - v8::Local context = env->context(); - - v8::Local ctor; - CHECK_TO_FUNCTION(env, ctor, constructor); - - auto maybe = ctor->NewInstance(context, argc, - reinterpret_cast*>(const_cast(argv))); - - CHECK_MAYBE_EMPTY(env, maybe, napi_generic_failure); - - *result = v8impl::JsValueFromV8LocalValue(maybe.ToLocalChecked()); - return GET_RETURN_STATUS(env); -} - -napi_status napi_instanceof(napi_env env, - napi_value object, - napi_value constructor, - bool* result) { - NAPI_PREAMBLE(env); - CHECK_ARG(env, object); - CHECK_ARG(env, result); - - *result = false; - - v8::Local ctor; - v8::Local context = env->context(); - - CHECK_TO_OBJECT(env, context, ctor, constructor); - - if (!ctor->IsFunction()) { - napi_throw_type_error(env, - "ERR_NAPI_CONS_FUNCTION", - "Constructor must be a function"); - - return napi_set_last_error(env, napi_function_expected); - } - - napi_status status = napi_generic_failure; - - v8::Local val = v8impl::V8LocalValueFromJsValue(object); - auto maybe_result = val->InstanceOf(context, ctor); - CHECK_MAYBE_NOTHING(env, maybe_result, status); - *result = maybe_result.FromJust(); - return GET_RETURN_STATUS(env); -} - -// Methods to support catching exceptions -napi_status napi_is_exception_pending(napi_env env, bool* result) { - // NAPI_PREAMBLE is not used here: this function must execute when there is a - // pending exception. - CHECK_ENV(env); - CHECK_ARG(env, result); - - *result = !env->last_exception.IsEmpty(); - return napi_clear_last_error(env); -} - -napi_status napi_get_and_clear_last_exception(napi_env env, - napi_value* result) { - // NAPI_PREAMBLE is not used here: this function must execute when there is a - // pending exception. - CHECK_ENV(env); - CHECK_ARG(env, result); - - if (env->last_exception.IsEmpty()) { - return napi_get_undefined(env, result); - } else { - *result = v8impl::JsValueFromV8LocalValue( - v8::Local::New(env->isolate, env->last_exception)); - env->last_exception.Reset(); - } - - return napi_clear_last_error(env); -} - -napi_status napi_is_arraybuffer(napi_env env, napi_value value, bool* result) { - CHECK_ENV(env); - CHECK_ARG(env, value); - CHECK_ARG(env, result); - - v8::Local val = v8impl::V8LocalValueFromJsValue(value); - *result = val->IsArrayBuffer(); - - return napi_clear_last_error(env); -} - -napi_status napi_create_arraybuffer(napi_env env, - size_t byte_length, - void** data, - napi_value* result) { - NAPI_PREAMBLE(env); - CHECK_ARG(env, result); - - v8::Isolate* isolate = env->isolate; - v8::Local buffer = - v8::ArrayBuffer::New(isolate, byte_length); - - // Optionally return a pointer to the buffer's data, to avoid another call to - // retrieve it. - if (data != nullptr) { - *data = buffer->GetContents().Data(); - } - - *result = v8impl::JsValueFromV8LocalValue(buffer); - return GET_RETURN_STATUS(env); -} - -napi_status napi_create_external_arraybuffer(napi_env env, - void* external_data, - size_t byte_length, - napi_finalize finalize_cb, - void* finalize_hint, - napi_value* result) { - NAPI_PREAMBLE(env); - CHECK_ARG(env, result); - - v8::Isolate* isolate = env->isolate; - v8::Local buffer = - v8::ArrayBuffer::New(isolate, external_data, byte_length); - - if (finalize_cb != nullptr) { - // Create a self-deleting weak reference that invokes the finalizer - // callback. - v8impl::Reference::New(env, - buffer, - 0, - true, - finalize_cb, - external_data, - finalize_hint); - } - - *result = v8impl::JsValueFromV8LocalValue(buffer); - return GET_RETURN_STATUS(env); -} - -napi_status napi_get_arraybuffer_info(napi_env env, - napi_value arraybuffer, - void** data, - size_t* byte_length) { - CHECK_ENV(env); - CHECK_ARG(env, arraybuffer); - - v8::Local value = v8impl::V8LocalValueFromJsValue(arraybuffer); - RETURN_STATUS_IF_FALSE(env, value->IsArrayBuffer(), napi_invalid_arg); - - v8::ArrayBuffer::Contents contents = - value.As()->GetContents(); - - if (data != nullptr) { - *data = contents.Data(); - } - - if (byte_length != nullptr) { - *byte_length = contents.ByteLength(); - } - - return napi_clear_last_error(env); -} - -napi_status napi_is_typedarray(napi_env env, napi_value value, bool* result) { - CHECK_ENV(env); - CHECK_ARG(env, value); - CHECK_ARG(env, result); - - v8::Local val = v8impl::V8LocalValueFromJsValue(value); - *result = val->IsTypedArray(); - - return napi_clear_last_error(env); -} - -napi_status napi_create_typedarray(napi_env env, - napi_typedarray_type type, - size_t length, - napi_value arraybuffer, - size_t byte_offset, - napi_value* result) { - NAPI_PREAMBLE(env); - CHECK_ARG(env, arraybuffer); - CHECK_ARG(env, result); - - v8::Local value = v8impl::V8LocalValueFromJsValue(arraybuffer); - RETURN_STATUS_IF_FALSE(env, value->IsArrayBuffer(), napi_invalid_arg); - - v8::Local buffer = value.As(); - v8::Local typedArray; - - switch (type) { - case napi_int8_array: - CREATE_TYPED_ARRAY( - env, Int8Array, 1, buffer, byte_offset, length, typedArray); - break; - case napi_uint8_array: - CREATE_TYPED_ARRAY( - env, Uint8Array, 1, buffer, byte_offset, length, typedArray); - break; - case napi_uint8_clamped_array: - CREATE_TYPED_ARRAY( - env, Uint8ClampedArray, 1, buffer, byte_offset, length, typedArray); - break; - case napi_int16_array: - CREATE_TYPED_ARRAY( - env, Int16Array, 2, buffer, byte_offset, length, typedArray); - break; - case napi_uint16_array: - CREATE_TYPED_ARRAY( - env, Uint16Array, 2, buffer, byte_offset, length, typedArray); - break; - case napi_int32_array: - CREATE_TYPED_ARRAY( - env, Int32Array, 4, buffer, byte_offset, length, typedArray); - break; - case napi_uint32_array: - CREATE_TYPED_ARRAY( - env, Uint32Array, 4, buffer, byte_offset, length, typedArray); - break; - case napi_float32_array: - CREATE_TYPED_ARRAY( - env, Float32Array, 4, buffer, byte_offset, length, typedArray); - break; - case napi_float64_array: - CREATE_TYPED_ARRAY( - env, Float64Array, 8, buffer, byte_offset, length, typedArray); - break; - case napi_bigint64_array: - CREATE_TYPED_ARRAY( - env, BigInt64Array, 8, buffer, byte_offset, length, typedArray); - break; - case napi_biguint64_array: - CREATE_TYPED_ARRAY( - env, BigUint64Array, 8, buffer, byte_offset, length, typedArray); - break; - default: - return napi_set_last_error(env, napi_invalid_arg); - } - - *result = v8impl::JsValueFromV8LocalValue(typedArray); - return GET_RETURN_STATUS(env); -} - -napi_status napi_get_typedarray_info(napi_env env, - napi_value typedarray, - napi_typedarray_type* type, - size_t* length, - void** data, - napi_value* arraybuffer, - size_t* byte_offset) { - CHECK_ENV(env); - CHECK_ARG(env, typedarray); - - v8::Local value = v8impl::V8LocalValueFromJsValue(typedarray); - RETURN_STATUS_IF_FALSE(env, value->IsTypedArray(), napi_invalid_arg); - - v8::Local array = value.As(); - - if (type != nullptr) { - if (value->IsInt8Array()) { - *type = napi_int8_array; - } else if (value->IsUint8Array()) { - *type = napi_uint8_array; - } else if (value->IsUint8ClampedArray()) { - *type = napi_uint8_clamped_array; - } else if (value->IsInt16Array()) { - *type = napi_int16_array; - } else if (value->IsUint16Array()) { - *type = napi_uint16_array; - } else if (value->IsInt32Array()) { - *type = napi_int32_array; - } else if (value->IsUint32Array()) { - *type = napi_uint32_array; - } else if (value->IsFloat32Array()) { - *type = napi_float32_array; - } else if (value->IsFloat64Array()) { - *type = napi_float64_array; - } else if (value->IsBigInt64Array()) { - *type = napi_bigint64_array; - } else if (value->IsBigUint64Array()) { - *type = napi_biguint64_array; - } - } - - if (length != nullptr) { - *length = array->Length(); - } - - v8::Local buffer = array->Buffer(); - if (data != nullptr) { - *data = static_cast(buffer->GetContents().Data()) + - array->ByteOffset(); - } - - if (arraybuffer != nullptr) { - *arraybuffer = v8impl::JsValueFromV8LocalValue(buffer); - } - - if (byte_offset != nullptr) { - *byte_offset = array->ByteOffset(); - } - - return napi_clear_last_error(env); -} - -napi_status napi_create_dataview(napi_env env, - size_t byte_length, - napi_value arraybuffer, - size_t byte_offset, - napi_value* result) { - NAPI_PREAMBLE(env); - CHECK_ARG(env, arraybuffer); - CHECK_ARG(env, result); - - v8::Local value = v8impl::V8LocalValueFromJsValue(arraybuffer); - RETURN_STATUS_IF_FALSE(env, value->IsArrayBuffer(), napi_invalid_arg); - - v8::Local buffer = value.As(); - if (byte_length + byte_offset > buffer->ByteLength()) { - napi_throw_range_error( - env, - "ERR_NAPI_INVALID_DATAVIEW_ARGS", - "byte_offset + byte_length should be less than or " - "equal to the size in bytes of the array passed in"); - return napi_set_last_error(env, napi_pending_exception); - } - v8::Local DataView = v8::DataView::New(buffer, byte_offset, - byte_length); - - *result = v8impl::JsValueFromV8LocalValue(DataView); - return GET_RETURN_STATUS(env); -} - -napi_status napi_is_dataview(napi_env env, napi_value value, bool* result) { - CHECK_ENV(env); - CHECK_ARG(env, value); - CHECK_ARG(env, result); - - v8::Local val = v8impl::V8LocalValueFromJsValue(value); - *result = val->IsDataView(); - - return napi_clear_last_error(env); -} - -napi_status napi_get_dataview_info(napi_env env, - napi_value dataview, - size_t* byte_length, - void** data, - napi_value* arraybuffer, - size_t* byte_offset) { - CHECK_ENV(env); - CHECK_ARG(env, dataview); - - v8::Local value = v8impl::V8LocalValueFromJsValue(dataview); - RETURN_STATUS_IF_FALSE(env, value->IsDataView(), napi_invalid_arg); - - v8::Local array = value.As(); - - if (byte_length != nullptr) { - *byte_length = array->ByteLength(); - } - - v8::Local buffer = array->Buffer(); - if (data != nullptr) { - *data = static_cast(buffer->GetContents().Data()) + - array->ByteOffset(); - } - - if (arraybuffer != nullptr) { - *arraybuffer = v8impl::JsValueFromV8LocalValue(buffer); - } - - if (byte_offset != nullptr) { - *byte_offset = array->ByteOffset(); - } - - return napi_clear_last_error(env); -} - -napi_status napi_get_version(napi_env env, uint32_t* result) { - CHECK_ENV(env); - CHECK_ARG(env, result); - *result = NAPI_VERSION; - return napi_clear_last_error(env); -} - -napi_status napi_create_promise(napi_env env, - napi_deferred* deferred, - napi_value* promise) { - NAPI_PREAMBLE(env); - CHECK_ARG(env, deferred); - CHECK_ARG(env, promise); - - auto maybe = v8::Promise::Resolver::New(env->context()); - CHECK_MAYBE_EMPTY(env, maybe, napi_generic_failure); - - auto v8_resolver = maybe.ToLocalChecked(); - auto v8_deferred = new v8impl::Persistent(); - v8_deferred->Reset(env->isolate, v8_resolver); - - *deferred = v8impl::JsDeferredFromNodePersistent(v8_deferred); - *promise = v8impl::JsValueFromV8LocalValue(v8_resolver->GetPromise()); - return GET_RETURN_STATUS(env); -} - -napi_status napi_resolve_deferred(napi_env env, - napi_deferred deferred, - napi_value resolution) { - return v8impl::ConcludeDeferred(env, deferred, resolution, true); -} - -napi_status napi_reject_deferred(napi_env env, - napi_deferred deferred, - napi_value resolution) { - return v8impl::ConcludeDeferred(env, deferred, resolution, false); -} - -napi_status napi_is_promise(napi_env env, - napi_value promise, - bool* is_promise) { - CHECK_ENV(env); - CHECK_ARG(env, promise); - CHECK_ARG(env, is_promise); - - *is_promise = v8impl::V8LocalValueFromJsValue(promise)->IsPromise(); - - return napi_clear_last_error(env); -} - -napi_status napi_create_date(napi_env env, - double time, - napi_value* result) { - NAPI_PREAMBLE(env); - CHECK_ARG(env, result); - - v8::MaybeLocal maybe_date = v8::Date::New(env->context(), time); - CHECK_MAYBE_EMPTY(env, maybe_date, napi_generic_failure); - - *result = v8impl::JsValueFromV8LocalValue(maybe_date.ToLocalChecked()); - - return GET_RETURN_STATUS(env); -} - -napi_status napi_is_date(napi_env env, - napi_value value, - bool* is_date) { - CHECK_ENV(env); - CHECK_ARG(env, value); - CHECK_ARG(env, is_date); - - *is_date = v8impl::V8LocalValueFromJsValue(value)->IsDate(); - - return napi_clear_last_error(env); -} - -napi_status napi_get_date_value(napi_env env, - napi_value value, - double* result) { - NAPI_PREAMBLE(env); - CHECK_ARG(env, value); - CHECK_ARG(env, result); - - v8::Local val = v8impl::V8LocalValueFromJsValue(value); - RETURN_STATUS_IF_FALSE(env, val->IsDate(), napi_date_expected); - - v8::Local date = val.As(); - *result = date->ValueOf(); - - return GET_RETURN_STATUS(env); -} - -napi_status napi_run_script(napi_env env, - napi_value script, - napi_value* result) { - NAPI_PREAMBLE(env); - CHECK_ARG(env, script); - CHECK_ARG(env, result); - - v8::Local v8_script = v8impl::V8LocalValueFromJsValue(script); - - if (!v8_script->IsString()) { - return napi_set_last_error(env, napi_string_expected); - } - - v8::Local context = env->context(); - - auto maybe_script = v8::Script::Compile(context, - v8::Local::Cast(v8_script)); - - if (!maybe_script.IsEmpty()) { - auto script_result = - maybe_script.ToLocalChecked()->Run(context); - if (!script_result.IsEmpty()) { - *result = v8impl::JsValueFromV8LocalValue( - script_result.ToLocalChecked()); - } - } - - return GET_RETURN_STATUS(env); -} - -napi_status napi_run_script(napi_env env, - napi_value script, - const char* source_url, - napi_value* result) { - // Append the source URL so V8 can locate the file. - std::ostringstream source_url_comment; - source_url_comment << std::endl << "//# sourceURL=" << source_url << std::endl; - const auto source_url_comment_str = source_url_comment.str(); - - const auto v8_script_string = v8::Local::Cast(v8impl::V8LocalValueFromJsValue(script)); - const auto source_with_comment = v8::String::Concat(env->isolate, v8_script_string, OneByteString(env->isolate, source_url_comment_str.c_str(), source_url_comment_str.size())); - - return napi_run_script(env, v8impl::JsValueFromV8LocalValue(source_with_comment), result); -} - -napi_status napi_add_finalizer(napi_env env, - napi_value js_object, - void* native_object, - napi_finalize finalize_cb, - void* finalize_hint, - napi_ref* result) { - return v8impl::Wrap(env, - js_object, - native_object, - finalize_cb, - finalize_hint, - result); -} - -napi_status napi_adjust_external_memory(napi_env env, - int64_t change_in_bytes, - int64_t* adjusted_value) { - CHECK_ENV(env); - CHECK_ARG(env, adjusted_value); - - *adjusted_value = env->isolate->AdjustAmountOfExternalAllocatedMemory( - change_in_bytes); - - return napi_clear_last_error(env); -} - -napi_status napi_set_instance_data(napi_env env, - void* data, - napi_finalize finalize_cb, - void* finalize_hint) { - CHECK_ENV(env); - - env->instance_data.data = data; - env->instance_data.finalize_cb = finalize_cb; - env->instance_data.hint = finalize_hint; - - return napi_clear_last_error(env); -} - -napi_status napi_get_instance_data(napi_env env, - void** data) { - CHECK_ENV(env); - CHECK_ARG(env, data); - - *data = env->instance_data.data; - - return napi_clear_last_error(env); -} - -napi_status napi_detach_arraybuffer(napi_env env, napi_value arraybuffer) { - CHECK_ENV(env); - CHECK_ARG(env, arraybuffer); - - v8::Local value = v8impl::V8LocalValueFromJsValue(arraybuffer); - RETURN_STATUS_IF_FALSE( - env, value->IsArrayBuffer(), napi_arraybuffer_expected); - - v8::Local it = value.As(); - RETURN_STATUS_IF_FALSE( - env, it->IsExternal(), napi_detachable_arraybuffer_expected); -#if V8_MAJOR_VERSION > 7 || (V8_MAJOR_VERSION == 7 && V8_MINOR_VERSION >= 4) - RETURN_STATUS_IF_FALSE( - env, it->IsDetachable(), napi_detachable_arraybuffer_expected); - - it->Detach(); -#else - RETURN_STATUS_IF_FALSE( - env, it->IsNeuterable(), napi_detachable_arraybuffer_expected); - - it->Neuter(); -#endif - return napi_clear_last_error(env); -} diff --git a/Dependencies/napi/napi-direct/source/js_native_api_v8.h b/Dependencies/napi/napi-direct/source/js_native_api_v8.h deleted file mode 100644 index 14ce76f8d..000000000 --- a/Dependencies/napi/napi-direct/source/js_native_api_v8.h +++ /dev/null @@ -1,241 +0,0 @@ -#ifndef SRC_JS_NATIVE_API_V8_H_ -#define SRC_JS_NATIVE_API_V8_H_ - -// This file needs to be compatible with C compilers. -#include // NOLINT(modernize-deprecated-headers) -#include -#include "js_native_api_v8_internals.h" -#include -#include - -static napi_status napi_clear_last_error(napi_env env); - -struct napi_env__ { - explicit napi_env__(v8::Local context) - : isolate(context->GetIsolate()), - context_persistent(isolate, context) { - CHECK_EQ(isolate, context->GetIsolate()); - } - virtual ~napi_env__() { - // First we must finalize those references that have `napi_finalizer` - // callbacks. The reason is that addons might store other references which - // they delete during their `napi_finalizer` callbacks. If we deleted such - // references here first, they would be doubly deleted when the - // `napi_finalizer` deleted them subsequently. - v8impl::RefTracker::FinalizeAll(&finalizing_reflist); - v8impl::RefTracker::FinalizeAll(&reflist); - if (instance_data.finalize_cb != nullptr) { - CallIntoModuleThrow([&](napi_env env) { - instance_data.finalize_cb(env, instance_data.data, instance_data.hint); - }); - } - } - v8::Isolate* const isolate; // Shortcut for context()->GetIsolate() - v8impl::Persistent context_persistent; - - inline v8::Local context() const { - return v8impl::PersistentToLocal::Strong(context_persistent); - } - - inline void Ref() { refs++; } - inline void Unref() { if ( --refs == 0) delete this; } - - virtual bool can_call_into_js() const { return true; } - - template - void CallIntoModule(T&& call, U&& handle_exception) { - int open_handle_scopes_before = open_handle_scopes; - int open_callback_scopes_before = open_callback_scopes; - napi_clear_last_error(this); - call(this); - CHECK_EQ(open_handle_scopes, open_handle_scopes_before); - CHECK_EQ(open_callback_scopes, open_callback_scopes_before); - if (!last_exception.IsEmpty()) { - handle_exception(this, last_exception.Get(this->isolate)); - last_exception.Reset(); - } - } - - template - void CallIntoModuleThrow(T&& call) { - CallIntoModule(call, [&](napi_env env, v8::Local value) { - env->isolate->ThrowException(value); - }); - } - - v8impl::Persistent last_exception; - - // We store references in two different lists, depending on whether they have - // `napi_finalizer` callbacks, because we must first finalize the ones that - // have such a callback. See `~napi_env__()` above for details. - v8impl::RefTracker::RefList reflist; - v8impl::RefTracker::RefList finalizing_reflist; - napi_extended_error_info last_error; - int open_handle_scopes = 0; - int open_callback_scopes = 0; - int refs = 1; - struct { - void* data = nullptr; - void* hint = nullptr; - napi_finalize finalize_cb = nullptr; - } instance_data; - - const std::thread::id thread_id{std::this_thread::get_id()}; -}; - -static inline napi_status napi_clear_last_error(napi_env env) { - env->last_error.error_code = napi_ok; - - // TODO(boingoing): Should this be a callback? - env->last_error.engine_error_code = 0; - env->last_error.engine_reserved = nullptr; - return napi_ok; -} - -static inline -napi_status napi_set_last_error(napi_env env, napi_status error_code, - uint32_t engine_error_code = 0, - void* engine_reserved = nullptr) { - env->last_error.error_code = error_code; - env->last_error.engine_error_code = engine_error_code; - env->last_error.engine_reserved = engine_reserved; - return error_code; -} - -#define RETURN_STATUS_IF_FALSE(env, condition, status) \ - do { \ - if (!(condition)) { \ - return napi_set_last_error((env), (status)); \ - } \ - } while (0) - -#define CHECK_ENV(env) \ - do { \ - if ((env) == nullptr) { \ - return napi_invalid_arg; \ - } \ - assert(env->thread_id == std::this_thread::get_id()); \ - } while (0) - -#define CHECK_ARG(env, arg) \ - RETURN_STATUS_IF_FALSE((env), ((arg) != nullptr), napi_invalid_arg) - -#define CHECK_MAYBE_EMPTY(env, maybe, status) \ - RETURN_STATUS_IF_FALSE((env), !((maybe).IsEmpty()), (status)) - -// NAPI_PREAMBLE is not wrapped in do..while: try_catch must have function scope -#define NAPI_PREAMBLE(env) \ - CHECK_ENV((env)); \ - RETURN_STATUS_IF_FALSE((env), \ - (env)->last_exception.IsEmpty() && (env)->can_call_into_js(), \ - napi_pending_exception); \ - napi_clear_last_error((env)); \ - v8impl::TryCatch try_catch((env)) - -#define CHECK_TO_TYPE(env, type, context, result, src, status) \ - do { \ - CHECK_ARG((env), (src)); \ - auto maybe = v8impl::V8LocalValueFromJsValue((src))->To##type((context)); \ - CHECK_MAYBE_EMPTY((env), maybe, (status)); \ - (result) = maybe.ToLocalChecked(); \ - } while (0) - -#define CHECK_TO_FUNCTION(env, result, src) \ - do { \ - CHECK_ARG((env), (src)); \ - v8::Local v8value = v8impl::V8LocalValueFromJsValue((src)); \ - RETURN_STATUS_IF_FALSE((env), v8value->IsFunction(), napi_invalid_arg); \ - (result) = v8value.As(); \ - } while (0) - -#define CHECK_TO_OBJECT(env, context, result, src) \ - CHECK_TO_TYPE((env), Object, (context), (result), (src), napi_object_expected) - -#define CHECK_TO_STRING(env, context, result, src) \ - CHECK_TO_TYPE((env), String, (context), (result), (src), napi_string_expected) - -#define GET_RETURN_STATUS(env) \ - (!try_catch.HasCaught() ? napi_ok \ - : napi_set_last_error((env), napi_pending_exception)) - -#define THROW_RANGE_ERROR_IF_FALSE(env, condition, error, message) \ - do { \ - if (!(condition)) { \ - napi_throw_range_error((env), (error), (message)); \ - return napi_set_last_error((env), napi_generic_failure); \ - } \ - } while (0) - -namespace v8impl { - -//=== Conversion between V8 Handles and napi_value ======================== - -// This asserts v8::Local<> will always be implemented with a single -// pointer field so that we can pass it around as a void*. -static_assert(sizeof(v8::Local) == sizeof(napi_value), - "Cannot convert between v8::Local and napi_value"); - -inline napi_value JsValueFromV8LocalValue(v8::Local local) { - return reinterpret_cast(*local); -} - -inline v8::Local V8LocalValueFromJsValue(napi_value v) { - v8::Local local; - memcpy(static_cast(&local), &v, sizeof(v)); - return local; -} - -// Adapter for napi_finalize callbacks. -class Finalizer { - protected: - Finalizer(napi_env env, - napi_finalize finalize_callback, - void* finalize_data, - void* finalize_hint) - : _env(env), - _finalize_callback(finalize_callback), - _finalize_data(finalize_data), - _finalize_hint(finalize_hint) { - } - - ~Finalizer() = default; - - public: - static Finalizer* New(napi_env env, - napi_finalize finalize_callback = nullptr, - void* finalize_data = nullptr, - void* finalize_hint = nullptr) { - return new Finalizer( - env, finalize_callback, finalize_data, finalize_hint); - } - - static void Delete(Finalizer* finalizer) { - delete finalizer; - } - - protected: - napi_env _env; - napi_finalize _finalize_callback; - void* _finalize_data; - void* _finalize_hint; - bool _finalize_ran = false; -}; - -class TryCatch : public v8::TryCatch { - public: - explicit TryCatch(napi_env env) - : v8::TryCatch(env->isolate), _env(env) {} - - ~TryCatch() { - if (HasCaught()) { - _env->last_exception.Reset(_env->isolate, Exception()); - } - } - - private: - napi_env _env; -}; - -} // end of namespace v8impl - -#endif // SRC_JS_NATIVE_API_V8_H_ diff --git a/Dependencies/napi/napi-direct/source/js_native_api_v8_internals.h b/Dependencies/napi/napi-direct/source/js_native_api_v8_internals.h deleted file mode 100644 index 0836f560d..000000000 --- a/Dependencies/napi/napi-direct/source/js_native_api_v8_internals.h +++ /dev/null @@ -1,88 +0,0 @@ -#ifndef SRC_JS_NATIVE_API_V8_INTERNALS_H_ -#define SRC_JS_NATIVE_API_V8_INTERNALS_H_ - -#include -#include - -#define NAPI_ARRAYSIZE(array) \ - (sizeof(array) / sizeof(array[0])) - -inline v8::Local OneByteString(v8::Isolate* isolate, - const char* data, - int length) { - return v8::String::NewFromOneByte(isolate, - reinterpret_cast(data), - v8::NewStringType::kNormal, - length).ToLocalChecked(); -} - -#define NAPI_FIXED_ONE_BYTE_STRING(isolate, string) \ - OneByteString((isolate), (string), sizeof(string) - 1) - -namespace v8impl { -class RefTracker { -public: - RefTracker() {} - virtual ~RefTracker() {} - virtual void Finalize(bool isEnvTeardown) {} - - typedef RefTracker RefList; - - inline void Link(RefList* list) { - prev_ = list; - next_ = list->next_; - if (next_ != nullptr) { - next_->prev_ = this; - } - list->next_ = this; - } - - inline void Unlink() { - if (prev_ != nullptr) { - prev_->next_ = next_; - } - if (next_ != nullptr) { - next_->prev_ = prev_; - } - prev_ = nullptr; - next_ = nullptr; - } - - static void FinalizeAll(RefList* list) { - while (list->next_ != nullptr) { - list->next_->Finalize(true); - } - } - -private: - RefList* next_ = nullptr; - RefList* prev_ = nullptr; -}; - -template -using Persistent = v8::Persistent; - -class PersistentToLocal { -public: - template - static inline v8::Local Strong( - const Persistent& persistent) { - return *reinterpret_cast*>( - const_cast*>(&persistent)); - } -}; -} // end of namespace v8impl - -#ifndef CHECK -#define CHECK(expr) assert(expr) -#endif - -#ifndef CHECK_EQ -#define CHECK_EQ(a, b) CHECK((a) == (b)) -#endif - -#ifndef CHECK_LE -#define CHECK_LE(a, b) CHECK((a) <= (b)) -#endif - -#endif // SRC_JS_NATIVE_API_V8_INTERNALS_H_ diff --git a/Dependencies/napi/napi-jsi/CMakeLists.txt b/Dependencies/napi/napi-jsi/CMakeLists.txt deleted file mode 100644 index 41ca27a2b..000000000 --- a/Dependencies/napi/napi-jsi/CMakeLists.txt +++ /dev/null @@ -1,64 +0,0 @@ -set(SOURCES - "include/napi/env.h" - "include/napi/napi.h" - "include/napi/napi-inl.h" - "source/env.cc") - -add_library(napi ${SOURCES}) - -if(NOT TARGET jsi) - if(WIN32) - download_nuget() - set_cpu_platform_arch() - set(V8JSI_VERSION "0.64.33") - if (WINDOWS_STORE) - set(V8JSI_PACKAGE_PATH "${NUGET_PATH}/packages/ReactNative.V8Jsi.Windows.UWP.${V8JSI_VERSION}") - set(PLATFORM_FOLDER "uwp") - else() - set(V8JSI_PACKAGE_PATH "${NUGET_PATH}/packages/ReactNative.V8Jsi.Windows.${V8JSI_VERSION}") - set(PLATFORM_FOLDER "win32") - endif() - - # TODO: Pull in v8jsi symbols once they're packaged with the debug build. - set(V8JSI_LIB_PATH_DEBUG "${V8JSI_PACKAGE_PATH}/lib/${PLATFORM_FOLDER}/Debug/${CPU_ARCH}/v8jsi.dll.lib") - set(V8JSI_LIB_PATH_RELEASE "${V8JSI_PACKAGE_PATH}/lib/${PLATFORM_FOLDER}/Release/${CPU_ARCH}/v8jsi.dll.lib") - set(V8JSI_DLL_PATH "${V8JSI_PACKAGE_PATH}/lib/${PLATFORM_FOLDER}/$,Debug,Release>/${CPU_ARCH}/v8jsi.dll") - set(V8JSI_DLL_PATH_DEBUG "${V8JSI_PACKAGE_PATH}/lib/${PLATFORM_FOLDER}/Debug/${CPU_ARCH}/v8jsi.dll") - set(V8JSI_DLL_PATH_RELEASE "${V8JSI_PACKAGE_PATH}/lib/${PLATFORM_FOLDER}/Release/${CPU_ARCH}/v8jsi.dll") - - add_library(v8jsi SHARED IMPORTED) - set_target_properties(v8jsi PROPERTIES - IMPORTED_IMPLIB_DEBUG ${V8JSI_LIB_PATH_DEBUG} - IMPORTED_IMPLIB_RELEASE ${V8JSI_LIB_PATH_RELEASE} - IMPORTED_IMPLIB_MINSIZEREL ${V8JSI_LIB_PATH_RELEASE} - IMPORTED_IMPLIB_RELWITHDEBINFO ${V8JSI_LIB_PATH_RELEASE}) - - target_include_directories(v8jsi INTERFACE "${V8JSI_PACKAGE_PATH}/build/native/include") - target_include_directories(v8jsi INTERFACE "${V8JSI_PACKAGE_PATH}/build/native/jsi") - set(NAPI_JAVASCRIPT_RUNTIME_OUTPUT_ARTIFACTS_DEBUG ${V8JSI_DLL_PATH_DEBUG} CACHE STRING "N-API runtime output artifacts (debug)") - set(NAPI_JAVASCRIPT_RUNTIME_OUTPUT_ARTIFACTS_RELEASE ${V8JSI_DLL_PATH_RELEASE} CACHE STRING "N-API runtime output artifacts (release)") - set(NAPI_JAVASCRIPT_RUNTIME_OUTPUT_ARTIFACTS ${V8JSI_DLL_PATH} CACHE STRING "N-API runtime output artifacts") - target_compile_definitions(v8jsi INTERFACE V8JSI_ENABLE_INSPECTOR) - - add_library(jsi "${V8JSI_PACKAGE_PATH}/build/native/jsi/jsi/jsi.cpp") - target_include_directories(jsi - PUBLIC "${V8JSI_PACKAGE_PATH}/build/native/include" - PUBLIC "${V8JSI_PACKAGE_PATH}/build/native/jsi") - target_link_libraries(jsi PUBLIC v8jsi) - set_property(TARGET jsi PROPERTY FOLDER Dependencies) - else() - message(FATAL_ERROR "jsi target is required") - endif() -endif() - -target_include_directories(napi - PUBLIC "include") - -target_link_to_dependencies(napi - PUBLIC jsi) - -if(WIN32) - target_compile_definitions(napi PUBLIC _SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING) -endif() - -source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${SOURCES}) diff --git a/Dependencies/napi/napi-jsi/include/napi/env.h b/Dependencies/napi/napi-jsi/include/napi/env.h deleted file mode 100644 index c138a96ec..000000000 --- a/Dependencies/napi/napi-jsi/include/napi/env.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -#include "napi.h" - -namespace Napi -{ - template Napi::Env Attach(Ts... args); - - void Detach(Napi::Env); - - Napi::Value Eval(Napi::Env env, const char* source, const char* sourceUrl); - - template T GetContext(Napi::Env env); -} diff --git a/Dependencies/napi/napi-jsi/include/napi/napi-inl.h b/Dependencies/napi/napi-jsi/include/napi/napi-inl.h deleted file mode 100644 index d2bec9070..000000000 --- a/Dependencies/napi/napi-jsi/include/napi/napi-inl.h +++ /dev/null @@ -1,2601 +0,0 @@ -#include -#include -#include -#include - -namespace Napi { - -namespace details { - template - class External : public jsi::HostObject { - public: - External(napi_env env, T* data) - : _env{env}, _data{data} { - } - - T* Data() const { - return _data; - } - - protected: - napi_env _env; - T* _data; - }; - - template - class ExternalWithFinalizer : public External { - public: - ExternalWithFinalizer(napi_env env, T* data, Finalizer finalizer) - : External{env, data}, _finalizer{std::move(finalizer)} { - } - - ~ExternalWithFinalizer() { - _finalizer(this->_env, this->_data); - } - - private: - Finalizer _finalizer; - }; - - template - class ExternalWithFinalizerAndHint : public External { - public: - ExternalWithFinalizerAndHint(napi_env env, T* data, Finalizer finalizer, Hint* hint) - : External{env, data}, _finalizer{std::move(finalizer)}, _hint{hint} { - } - - ~ExternalWithFinalizerAndHint() { - _finalizer(this->_env, this->_data, _hint); - } - - private: - Finalizer _finalizer; - Hint* _hint; - }; -} // details - -//////////////////////////////////////////////////////////////////////////////// -// Env class -//////////////////////////////////////////////////////////////////////////////// - -inline Env::Env(napi_env env) : _env{env} { -} - -inline Env::operator napi_env() const { - return _env; -} - -inline Object Env::Global() const { - return {_env, _env->rt.global()}; -} - -inline Value Env::Undefined() const { - return {_env, jsi::Value::undefined()}; -} - -inline Value Env::Null() const { - return {_env, jsi::Value::null()}; -} - -inline bool Env::IsExceptionPending() const { - return !_env->last_exception.isUndefined(); -} - -inline Error Env::GetAndClearPendingException() { - if (_env->last_exception.isUndefined()) { - return {}; - } - - auto last_exception = std::move(_env->last_exception); - return {_env, last_exception.asObject(_env->rt)}; -} - -//////////////////////////////////////////////////////////////////////////////// -// Value class -//////////////////////////////////////////////////////////////////////////////// - -inline Value::Value() - : _env{nullptr}, _value{} { -} - -inline Value::Value(napi_env env, jsi::Value value) - : _env{env}, _value{std::move(value)} { -} - -inline Value::operator jsi::Value&&() && { - return std::move(_value); -} - -inline Value::Value(const Value& other) - : _env{other._env}, _value{_env == nullptr ? jsi::Value{} : jsi::Value{_env->rt, other._value}} { -} - -inline Value& Value::operator =(const Value& other){ - _env = other._env; - _value = {_env->rt, other._value}; - return *this; -} - -inline Value::operator jsi::Value&() & { - return _value; -} - -inline Value::operator const jsi::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 { - return jsi::Value::strictEquals(_env->rt, _value, other._value); -} - -inline Napi::Env Value::Env() const { - return {_env}; -} - -inline bool Value::IsEmpty() const { - return _env == nullptr; -} - -inline napi_valuetype Value::Type() const { - if (_value.isUndefined()) { - return napi_undefined; - } else if (_value.isNull()) { - return napi_null; - } else if (_value.isBool()) { - return napi_boolean; - } else if (_value.isNumber()) { - return napi_number; - } else if (_value.isString()) { - return napi_string; - } else if (_value.isSymbol()) { - return napi_symbol; - } else if (_value.isObject()) { - auto object{_value.getObject(_env->rt)}; - if (object.isFunction(_env->rt)) { - return napi_function; - } else if (object.isHostObject(_env->rt)) { - return napi_external; - } - return napi_object; - } - - abort(); -} - -inline bool Value::IsUndefined() const { - return _value.isUndefined(); -} - -inline bool Value::IsNull() const { - return _value.isNull(); -} - -inline bool Value::IsBoolean() const { - return _value.isBool(); -} - -inline bool Value::IsNumber() const { - return _value.isNumber(); -} - -inline bool Value::IsString() const { - return _value.isString(); -} - -inline bool Value::IsSymbol() const { - return _value.isSymbol(); -} - -inline bool Value::IsArray() const { - if (!_value.isObject()) { - return false; - } - - auto object{_value.getObject(_env->rt)}; - return object.isArray(_env->rt); -} - -inline bool Value::IsArrayBuffer() const { - if (!_value.isObject()) { - return false; - } - - auto object{_value.getObject(_env->rt)}; - return object.isArrayBuffer(_env->rt); -} - -inline bool Value::IsTypedArray() const { - throw std::runtime_error{"TODO"}; -} - -inline bool Value::IsObject() const { - return _value.isObject(); -} - -inline bool Value::IsFunction() const { - return _value.isObject() && _value.getObject(_env->rt).isFunction(_env->rt); -} - -inline bool Value::IsPromise() const { - throw std::runtime_error{"TODO"}; -} - -inline bool Value::IsDataView() const { - throw std::runtime_error{"TODO"}; -} - -inline bool Value::IsExternal() const { - return _value.isObject() && _value.getObject(_env->rt).isHostObject(_env->rt); -} - -template -inline T Value::As() const { - return T(_env, jsi::Value{_env->rt, _value}); -} - -inline Boolean Value::ToBoolean() const { - return {_env, _env->boolean_func.call(_env->rt, _value)}; -} - -inline Number Value::ToNumber() const { - return {_env, _env->number_func.call(_env->rt, _value)}; -} - -inline String Value::ToString() const { - return {_env, {_env->rt, _value.toString(_env->rt)}}; -} - -inline Object Value::ToObject() const { - return {_env, _value.getObject(_env->rt)}; -} - -//////////////////////////////////////////////////////////////////////////////// -// Boolean class -//////////////////////////////////////////////////////////////////////////////// - -inline Boolean::Boolean() { -} - -inline Boolean Boolean::New(napi_env env, bool val) { - return Boolean(env, {val}); -} - -inline Boolean::Boolean(napi_env env, jsi::Value value) - : Napi::Value(env, std::move(value)) { -} - -inline Boolean::operator bool() const { - return Value(); -} - -inline bool Boolean::Value() const { - return _value.getBool(); -} - -//////////////////////////////////////////////////////////////////////////////// -// Number class -//////////////////////////////////////////////////////////////////////////////// - -inline Number::Number() { -} - -inline Number Number::New(napi_env env, double val) { - return Number(env, {env->rt, jsi::Value(val)}); -} - -inline Number::Number(napi_env env, jsi::Value value) - : Value(env, std::move(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 { - NAPI_TRY() - return static_cast(_value.asNumber()); - NAPI_CATCH() -} - -inline uint32_t Number::Uint32Value() const { - NAPI_TRY() - return static_cast(_value.asNumber()); - NAPI_CATCH() -} - -inline int64_t Number::Int64Value() const { - NAPI_TRY() - return static_cast(_value.asNumber()); - NAPI_CATCH() -} - -inline float Number::FloatValue() const { - NAPI_TRY() - return static_cast(_value.asNumber()); - NAPI_CATCH() -} - -inline double Number::DoubleValue() const { - NAPI_TRY() - return _value.asNumber(); - NAPI_CATCH() -} - -//////////////////////////////////////////////////////////////////////////////// -// Name class -//////////////////////////////////////////////////////////////////////////////// - -inline Name::Name(napi_env env, jsi::Value value) - : Value(env, std::move(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) { - return {env, {env->rt, jsi::String::createFromUtf8(env->rt, reinterpret_cast(val), std::strlen(val))}}; -} - -inline String String::New(napi_env env, const char16_t* val) { - std::string u8{std::wstring_convert, char16_t>{}.to_bytes(val)}; - return {env, {env->rt, jsi::String::createFromUtf8(env->rt, u8)}}; -} - -inline String String::New(napi_env env, const char* val, size_t length) { - return {env, {env->rt, jsi::String::createFromUtf8(env->rt, reinterpret_cast(val), length)}}; -} - -inline String String::New(napi_env env, const char16_t* val, size_t length) { - std::string u8{std::wstring_convert, char16_t>{}.to_bytes(val, val + length)}; - return {env, {env->rt, jsi::String::createFromUtf8(env->rt, u8)}}; -} - -inline String::String(napi_env env, jsi::Value value) - : Name(env, std::move(value)) { -} - -inline String::operator std::string() const { - return Utf8Value(); -} - -inline String::operator std::u16string() const { - return Utf16Value(); -} - -inline std::string String::Utf8Value() const { - return _value.getString(_env->rt).utf8(_env->rt); -} - -inline std::u16string String::Utf16Value() const { - throw std::runtime_error("TODO"); -} - -//////////////////////////////////////////////////////////////////////////////// -// Symbol class -//////////////////////////////////////////////////////////////////////////////// - -inline Symbol Symbol::New(napi_env env, const char* description) { - (void)env; - (void)description; - throw std::runtime_error("TODO"); -} - -inline Symbol Symbol::New(napi_env env, const std::string& description) { - (void)env; - (void)description; - throw std::runtime_error("TODO"); -} - -inline Symbol Symbol::New(napi_env env, String description) { - (void)env; - (void)description; - throw std::runtime_error("TODO"); -} - -inline Symbol Symbol::New(napi_env env, jsi::Value description) { - (void)env; - (void)description; - throw std::runtime_error("TODO"); -} - -inline Symbol Symbol::WellKnown(napi_env env, const std::string& name) { - // TODO: can be optimized - return Napi::Env(env).Global().Get("Symbol").As().Get(name).As(); -} - -inline Symbol::Symbol(napi_env env, jsi::Value value) - : Name(env, std::move(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); - } -}; - -// TODO: this can probably be folded into the Helper/disjunction -template -struct vf_fallback { - static Value From(napi_env, const T& value) { - return value; - } -}; - -template <> -struct vf_fallback { - static Value From(napi_env env, const jsi::Value& value) { - return {env, {env->rt, 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.Get(_key); -} - -template template -inline Object::PropertyLValue& Object::PropertyLValue::operator =(ValueType value) { - _object.Set(_key, value); - return *this; -} - -template -inline Object::PropertyLValue::PropertyLValue(Object& object, Key key) - : _object{object}, _key{key} { -} - -inline Object::Object() { -} - -inline Object::Object(napi_env env, jsi::Value value) - : Value{env, std::move(value)}, _object{_value.getObject(env->rt)} { -} - -inline Object::operator jsi::Object&&() && { - return std::move(*_object); -} - -inline Object::Object(const Object& other) - : Object{other._env, {other._env->rt, other._value}} { -} - -inline Object& Object::operator =(const Object& other){ - Value::operator =(other); - _object = _value.getObject(_env->rt); - return *this; -} - -inline Object::operator jsi::Object&() & { - return *_object; -} - -inline Object::operator const jsi::Object&() const & { - return *_object; -} - -inline Object Object::New(napi_env env) { - return {env, jsi::Object{env->rt}}; -} - -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(const char* utf8name) const { - return _object->hasProperty(_env->rt, utf8name); -} - -inline bool Object::Has(const std::string& utf8name) const { - return Has(utf8name.c_str()); -} - -inline bool Object::HasOwnProperty(const char* utf8name) const { - (void)utf8name; - throw std::runtime_error("TODO"); -} - -inline bool Object::HasOwnProperty(const std::string& utf8name) const { - return HasOwnProperty(utf8name.c_str()); -} - -inline Value Object::Get(Napi::Value key) const { - if (key.IsString()) { - return Get(key.As().Utf8Value()); - } else { - throw std::runtime_error("TODO"); - } -} - -inline Value Object::Get(const char* utf8name) const { - return {_env, _object->getProperty(_env->rt, utf8name)}; -} - -inline Value Object::Get(const std::string& utf8name) const { - return Get(utf8name.c_str()); -} - -template -inline void Object::Set(const char* utf8name, const ValueType& value) { - _object->setProperty(_env->rt, utf8name, static_cast(Value::From(_env, value))); -} - -template -inline void Object::Set(const std::string& utf8name, const ValueType& value) { - Set(utf8name.c_str(), value); -} - -inline bool Object::Delete(const char* utf8name) { - (void)utf8name; - throw std::runtime_error("TODO"); -} - -inline bool Object::Delete(const std::string& utf8name) { - return Delete(utf8name.c_str()); -} - -inline bool Object::Has(uint32_t index) const { - (void)index; - throw std::runtime_error{"TODO"}; -} - -inline Value Object::Get(uint32_t index) const { - // TODO: does this need to work for non-array objects? - return {_env, _object->getArray(_env->rt).getValueAtIndex(_env->rt, static_cast(index))}; -} - -template -inline void Object::Set(uint32_t index, const ValueType& value) { - // TODO: does this need to work for non-array objects? - jsi::Array arrObj = _object->getArray(_env->rt); - if (arrObj.length(_env->rt) <= index) { - _object->setProperty(_env->rt, "length", static_cast(index + 1)); - } - - arrObj.setValueAtIndex(_env->rt, static_cast(index), static_cast(Value::From(_env, value))); -} - -inline bool Object::Delete(uint32_t index) { - (void)index; - throw std::runtime_error{"TODO"}; -} - -inline Array Object::GetPropertyNames() const { - throw std::runtime_error{"TODO"}; -} - -// TODO: not implemented -//inline void Object::DefineProperty(const PropertyDescriptor& property) { -// throw std::runtime_error{"TODO"}; -//} -// -//inline void Object::DefineProperties(const std::initializer_list& properties) { -// throw std::runtime_error{"TODO"}; -//} -// -//inline void Object::DefineProperties(const std::vector& properties) { -// throw std::runtime_error{"TODO"}; -//} - -inline bool Object::InstanceOf(const Function& constructor) const { - // REVIEW: why is jsi::Object::instanceOf not a const function? - return const_cast(*_object).instanceOf(_env->rt, constructor); -} - -//////////////////////////////////////////////////////////////////////////////// -// External class -//////////////////////////////////////////////////////////////////////////////// - -template -inline External External::New(napi_env env, T* data) { - return {env, jsi::Object::createFromHostObject(env->rt, std::make_shared>(env, data))}; -} - -template -template -inline External External::New(napi_env env, - T* data, - Finalizer finalizeCallback) { - return {env, jsi::Object::createFromHostObject(env->rt, std::make_shared>(env, data, std::move(finalizeCallback)))}; -} - -template -template -inline External External::New(napi_env env, - T* data, - Finalizer finalizeCallback, - Hint* finalizeHint) { - return {env, jsi::Object::createFromHostObject(env->rt, std::make_shared>(env, data, std::move(finalizeCallback), finalizeHint))}; -} - -template -inline External::External(napi_env env, jsi::Value value) - : Value(env, std::move(value)) { -} - -template -inline T* External::Data() const { - return _value.getObject(_env->rt).template getHostObject>(_env->rt)->Data(); -} - -//////////////////////////////////////////////////////////////////////////////// -// Array class -//////////////////////////////////////////////////////////////////////////////// - -inline Array Array::New(napi_env env) { - return New(env, 0); -} - -inline Array Array::New(napi_env env, size_t length) { - return {env, jsi::Array{env->rt, length}}; -} - -inline Array::Array() { -} - -inline Array::Array(napi_env env, jsi::Value value) - : Object{env, std::move(value)}, _array{_object->getArray(env->rt)} { -} - -inline Array::operator jsi::Array&&() && { - return std::move(*_array); -} - -inline Array::Array(const Array& other) - : Array{other._env, {other._env->rt, other._value}} { -} - -inline Array& Array::operator =(const Array& other){ - Object::operator =(other); - _array = _object->getArray(_env->rt); - return *this; -} - -inline Array::operator jsi::Array&() & { - return *_array; -} - -inline Array::operator const jsi::Array&() const & { - return *_array; -} - -inline uint32_t Array::Length() const { - return static_cast(_array->length(_env->rt)); -} - -//////////////////////////////////////////////////////////////////////////////// -// ArrayBuffer class -//////////////////////////////////////////////////////////////////////////////// - -inline ArrayBuffer ArrayBuffer::New(napi_env env, size_t byteLength) { - jsi::Value value{env->array_buffer_ctor.callAsConstructor(env->rt, static_cast(byteLength))}; - jsi::ArrayBuffer arrayBuffer{value.getObject(env->rt).getArrayBuffer(env->rt)}; - return {env, std::move(value)}; -} - -inline ArrayBuffer ArrayBuffer::New(napi_env env, - void* externalData, - size_t byteLength) { - return {env, FromExternal(env, externalData, byteLength)}; -} - -template -inline ArrayBuffer ArrayBuffer::New(napi_env env, - void* externalData, - size_t byteLength, - Finalizer finalizeCallback) { - jsi::ArrayBuffer arrayBuffer{ FromExternal(env, externalData, byteLength) }; - arrayBuffer.setProperty(env->rt, env->native_name, jsi::Object::createFromHostObject(env->rt, std::make_shared>(env, externalData, std::forward(finalizeCallback)))); - return {env, std::move(arrayBuffer)}; -} - -template -inline ArrayBuffer ArrayBuffer::New(napi_env env, - void* externalData, - size_t byteLength, - Finalizer finalizeCallback, - Hint* finalizeHint) { - jsi::ArrayBuffer arrayBuffer{ FromExternal(env, externalData, byteLength) }; - arrayBuffer.setProperty(env->rt, env->native_name, std::make_shared>(env, externalData, std::forward(finalizeCallback), finalizeHint)); - return {env, std::move(arrayBuffer)}; -} - -inline ArrayBuffer::ArrayBuffer() { -} - -inline ArrayBuffer::ArrayBuffer(napi_env env, jsi::Value value) - : Object{env, std::move(value)}, _arrayBuffer{_object->getArrayBuffer(env->rt)} { -} - -inline ArrayBuffer::operator jsi::ArrayBuffer&&() && { - return std::move(*_arrayBuffer); -} - -inline ArrayBuffer::ArrayBuffer(const ArrayBuffer& other) - : ArrayBuffer{other._env, {other._env->rt, other._value}} { -} - -inline ArrayBuffer& ArrayBuffer::operator =(const ArrayBuffer& other){ - Object::operator =(other); - _arrayBuffer = _object->getArrayBuffer(_env->rt); - return *this; -} - -inline ArrayBuffer::operator jsi::ArrayBuffer&() & { - return *_arrayBuffer; -} - -inline ArrayBuffer::operator const jsi::ArrayBuffer&() const & { - return *_arrayBuffer; -} - -inline void* ArrayBuffer::Data() const { - return const_cast(*_arrayBuffer).data(_env->rt); -} - -inline size_t ArrayBuffer::ByteLength() const { - return _arrayBuffer->length(_env->rt); -} - -inline jsi::ArrayBuffer ArrayBuffer::FromExternal(napi_env env, void* externalData, size_t byteLength) { - // must copy since jsi does not support array buffers with external data - jsi::Value value{ env->array_buffer_ctor.callAsConstructor(env->rt, static_cast(byteLength)) }; - jsi::ArrayBuffer arrayBuffer{ value.getObject(env->rt).getArrayBuffer(env->rt) }; - std::memcpy(arrayBuffer.data(env->rt), externalData, byteLength); - return arrayBuffer; -} - -//////////////////////////////////////////////////////////////////////////////// -// 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) { - (void)env; - (void)arrayBuffer; - (void)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); - throw std::runtime_error{"TODO"}; -} - -inline DataView DataView::New(napi_env env, - Napi::ArrayBuffer arrayBuffer, - size_t byteOffset, - size_t byteLength) { - (void)env; - (void)arrayBuffer; - (void)byteOffset; - (void)byteLength; - //if (byteOffset + byteLength > arrayBuffer.ByteLength()) { - // NAPI_THROW(RangeError::New(env, "Invalid DataView length"), - // DataView()); - //} - //jsi::Value value; - //napi_status status = napi_create_dataview( - // rt, byteLength, arrayBuffer, byteOffset, &value); - //NAPI_THROW_IF_FAILED(env, status, DataView()); - //return DataView(env, value); - throw std::runtime_error{"TODO"}; -} - -inline DataView::DataView(napi_env env, jsi::Value value) - : Object{env, std::move(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); - throw std::runtime_error{"TODO"}; -} - -inline Napi::ArrayBuffer DataView::ArrayBuffer() const { - //jsi::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); - throw std::runtime_error{"TODO"}; -} - -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; - throw std::runtime_error{"TODO"}; -} - -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 { - (void)byteOffset; - //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); - throw std::runtime_error{"TODO"}; -} - -template -inline void DataView::WriteData(size_t byteOffset, T value) const { - (void)byteOffset; - (void)value; - //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; - throw std::runtime_error{"TODO"}; -} - -//////////////////////////////////////////////////////////////////////////////// -// TypedArray class -//////////////////////////////////////////////////////////////////////////////// - -// JSI does not support typed array directly and thus this implementation is -// suboptimal. See https://github.com/facebook/hermes/issues/182. - -inline TypedArray::TypedArray() { -} - -inline TypedArray::TypedArray(napi_env env, jsi::Value value) - : Object{env, std::move(value)}, _type{TypedArray::unknown_array_type}, _length{0} { -} - -inline TypedArray::TypedArray(napi_env env, jsi::Value value, napi_typedarray_type type, size_t length) - : Object(env, std::move(value)), _type(type), _length(length) { -} - -inline napi_typedarray_type TypedArray::TypedArrayType() const { - if (_type == TypedArray::unknown_array_type) { - GetTypedArrayInfo(_env, *_object, &_type, &_length); - } - - 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) { - GetTypedArrayInfo(_env, *_object, &_type, &_length); - } - - return _length; -} - -inline size_t TypedArray::ByteOffset() const { - return static_cast(_object->getProperty(_env->rt, "byteOffset").asNumber()); -} - -inline size_t TypedArray::ByteLength() const { - return ElementSize() * ElementLength(); -} - -inline Napi::ArrayBuffer TypedArray::ArrayBuffer() const { - return {_env, _object->getPropertyAsObject(_env->rt, "buffer").getArrayBuffer(_env->rt)}; -} - -inline void TypedArray::GetTypedArrayInfo(napi_env env, - const jsi::Object& object, - napi_typedarray_type* type, - size_t* length) { - if (type != nullptr) { - std::string name{object.getPropertyAsObject(env->rt, "constructor").getProperty(env->rt, "name").getString(env->rt).utf8(env->rt)}; - if (name == "Int8Array") { - *type = napi_int8_array; - } else if (name == "Uint8Array") { - *type = napi_uint8_array; - } else if (name == "Uint8ClampedArray") { - *type = napi_uint8_clamped_array; - } else if (name == "Int16Array") { - *type = napi_int16_array; - } else if (name == "Uint16Array") { - *type = napi_uint16_array; - } else if (name == "Int32Array") { - *type = napi_int32_array; - } else if (name == "Uint32Array") { - *type = napi_uint32_array; - } else if (name == "Float32Array") { - *type = napi_float32_array; - } else if (name == "Float64Array") { - *type = napi_float64_array; - } else { - *type = TypedArray::unknown_array_type; - } - } - - if (length != nullptr) { - *length = static_cast(object.getProperty(env->rt, "length").asNumber()); - } -} - - -//////////////////////////////////////////////////////////////////////////////// -// TypedArrayOf class -//////////////////////////////////////////////////////////////////////////////// - -template -inline TypedArrayOf TypedArrayOf::New(napi_env env, - size_t elementLength, - napi_typedarray_type type) { - jsi::Function& ctor{ env->typed_array_ctor[type] }; - jsi::Value value{ctor.callAsConstructor(env->rt, static_cast(elementLength))}; - return {env, std::move(value)}; -} - -template -inline TypedArrayOf TypedArrayOf::New(napi_env env, - size_t elementLength, - Napi::ArrayBuffer arrayBuffer, - size_t bufferOffset, - napi_typedarray_type type) { - jsi::Function& ctor{env->typed_array_ctor[type]}; - jsi::Value value{ctor.callAsConstructor(env->rt, static_cast(arrayBuffer), static_cast(bufferOffset), static_cast(elementLength))}; - return {env, std::move(value), type, elementLength, reinterpret_cast(reinterpret_cast(arrayBuffer.Data()) + bufferOffset)}; -} - -template -inline TypedArrayOf::TypedArrayOf() { -} - -template -inline TypedArrayOf::TypedArrayOf(napi_env env, jsi::Value value) - : TypedArray{env, std::move(value)}, _data{reinterpret_cast(jsi::ArrayBuffer{_object->getPropertyAsObject(env->rt, "buffer").getArrayBuffer(env->rt)}.data(env->rt) + ByteOffset())} { -} - -template -inline TypedArrayOf::TypedArrayOf(napi_env env, - jsi::Value value, - napi_typedarray_type type, - size_t length, - T* data) - : TypedArray{env, std::move(value), type, length}, _data{data} { - // TODO - //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 -//////////////////////////////////////////////////////////////////////////////// - -namespace details -{ - template - struct Function { - static inline jsi::Value Callback(napi_env env, const jsi::Value& thisVal, const jsi::Value* args, size_t count, void* data, Callable cb) { - CallbackInfo callbackInfo{env, thisVal, args, count, {}, data}; - return {env->rt, cb(callbackInfo)}; - } - }; - - template - struct Function { - static inline jsi::Value Callback(napi_env env, const jsi::Value& thisVal, const jsi::Value* args, size_t count, void* data, Callable cb) { - CallbackInfo callbackInfo{env, thisVal, args, count, {}, data}; - cb(callbackInfo); - return {}; - } - }; -} - -template -inline Function Function::New(napi_env env, - Callable cb, - const char* utf8name, - void* data) { - auto function{jsi::Function::createFromHostFunction(env->rt, jsi::PropNameID::forUtf8(env->rt, utf8name), 0, - [env, cb{std::move(cb)}, data](jsi::Runtime&, const jsi::Value& thisVal, const jsi::Value* args, size_t count) -> jsi::Value { - typedef decltype(cb(CallbackInfo({}, {}, {}, {}, {}, {}))) ReturnType; - return details::Function::Callback(env, thisVal, args, count, data, cb); - })}; - - return {env, std::move(function)}; -} - -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() { -} - -inline Function::Function(napi_env env, jsi::Value value) - : Object{env, std::move(value)}, _function{_object->getFunction(env->rt)} { -} - -inline Function::operator jsi::Function&&() && { - return std::move(*_function); -} - -inline Function::Function(const Function& other) - : Function{other._env, {other._env->rt, other._value}} { -} - -inline Function& Function::operator =(const Function& other){ - Object::operator =(other); - _function = _object->getFunction(_env->rt); - return *this; -} - -inline Function::operator jsi::Function&() & { - return *_function; -} - -inline Function::operator const jsi::Function&() const & { - return *_function; -} - -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 Value* args) const { - return Call(Env().Undefined(), argc, args); -} - -inline Value Function::Call(const Value& recv, const std::initializer_list& args) const { - return Call(recv, args.size(), args.begin()); -} - -inline Value Function::Call(const Value& recv, const std::vector& args) const { - return Call(recv, args.size(), args.data()); -} - -inline Value Function::Call(const Value& recv, size_t argc, const Value* args) const { - NAPI_TRY() - - jsi::Value stackArgs[6]; - std::vector heapArgs; - jsi::Value* argv; - if (argc <= std::size(stackArgs)) { - argv = stackArgs; - } else { - heapArgs.resize(argc); - argv = heapArgs.data(); - } - - for (size_t i = 0; i < argc; ++i) { - argv[i] = {_env->rt, args[i]}; - } - - jsi::Value result{ - recv.IsUndefined() - ? _function->call(_env->rt, static_cast(argv), argc) - : _function->callWithThis(_env->rt, static_cast(recv.ToObject()), static_cast(argv), argc)}; - - return {_env, std::move(result)}; - - NAPI_CATCH() -} - -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 Value* args) const { - NAPI_TRY() - - jsi::Value stackArgs[6]; - std::vector heapArgs; - jsi::Value* argv; - if (argc <= std::size(stackArgs)) { - argv = stackArgs; - } else { - heapArgs.resize(argc); - argv = heapArgs.data(); - } - - for (size_t i = 0; i < argc; ++i) { - argv[i] = {_env->rt, args[i]}; - } - - jsi::Value instance{_function->callAsConstructor( - _env->rt, static_cast(argv), argc)}; - - return {_env, std::move(instance)}; - - NAPI_CATCH() -} - -//////////////////////////////////////////////////////////////////////////////// -// Promise class -//////////////////////////////////////////////////////////////////////////////// - -inline Promise::Deferred Promise::Deferred::New(napi_env env) { - return {env}; -} - -inline Promise::Deferred::Deferred(napi_env env) - : _env{env} { - jsi::Function executor{jsi::Function::createFromHostFunction(env->rt, jsi::PropNameID::forAscii(env->rt, "executor"), 0, - [this](jsi::Runtime& rt, const jsi::Value&, const jsi::Value* args, size_t) -> jsi::Value { - _resolve = args[0].asObject(rt).asFunction(rt); - _reject = args[1].asObject(rt).asFunction(rt); - return {}; - })}; - - _promise = env->promise_ctor.callAsConstructor(env->rt, executor); -} - -inline Promise::Deferred::Deferred(const Deferred& other) - : _env{other._env} - , _promise{_env->rt, other._promise} - , _resolve{jsi::Value{_env->rt, *other._resolve}.asObject(_env->rt).asFunction(_env->rt)} - , _reject{jsi::Value{_env->rt, *other._reject}.asObject(_env->rt).asFunction(_env->rt)} { -} - -inline Promise::Deferred& Promise::Deferred::operator =(const Deferred& other) { - _env = other._env; - _promise = {_env->rt, other._promise}; - _resolve = jsi::Value{_env->rt, *other._resolve}.asObject(_env->rt).asFunction(_env->rt); - _reject = jsi::Value{_env->rt, *other._reject}.asObject(_env->rt).asFunction(_env->rt); - return *this; -} - -inline Promise Promise::Deferred::Promise() const { - return {_env, {_env->rt, _promise}}; -} - -inline Napi::Env Promise::Deferred::Env() const { - return {_env}; -} - -inline void Promise::Deferred::Resolve(const jsi::Value& value) const { - _resolve->call(_env->rt, value); -} - -inline void Promise::Deferred::Reject(const jsi::Value& value) const { - _reject->call(_env->rt, value); -} - -inline Promise::Promise(napi_env env, jsi::Value value) - : Object(env, std::move(value)) { -} - -//////////////////////////////////////////////////////////////////////////////// -// Error class -//////////////////////////////////////////////////////////////////////////////// - -inline Error Error::New(napi_env env, const char* message) { - return Error::New(env, message, "Error"); -} - -inline Error Error::New(napi_env env, const std::string& message) { - return Error::New(env, message, "Error"); -} - -inline Error Error::New(napi_env env, const std::exception& exception) { - return Error::New(env, exception.what()); -} - -inline Error Error::New(napi_env env, const std::exception_ptr& exception_ptr) { - try { - std::rethrow_exception(exception_ptr); - } catch (const std::exception& exception) { - return Error::New(env, exception); - } -} - -inline void Error::Fatal(const char* location, const char* message) { - throw std::runtime_error{std::string{location} + ": " + message}; -} - -inline Error::Error() : ObjectReference() { -} - -inline Error::Error(napi_env env, jsi::Object object) - : ObjectReference{env, std::move(object)} { -} - -inline Error::Error(Error&& other) : ObjectReference(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 =(Error& other) { - _env = other.Env(); - _object = other._object; - _refcount = 1; - return *this; -} - -inline const std::string& Error::Message() const { - if (_message.empty()) { - _message = Get("message").As(); - } - return _message; -} - -inline void Error::ThrowAsJavaScriptException() const { - if (!IsEmpty()) { - _env->last_exception = {_env->rt, static_cast(Value())}; - } -} - -inline const char* Error::what() const noexcept { - return Message().c_str(); -} - -template -inline TError Error::New(napi_env env, TMessage message, const char* constructor) { - auto ctor{env->rt.global().getPropertyAsFunction(env->rt, constructor)}; - auto msg{jsi::String::createFromAscii(env->rt, message)}; - return {env, ctor.callAsConstructor(env->rt, msg).asObject(env->rt)}; -} - -inline TypeError TypeError::New(napi_env env, const char* message) { - return Error::New(env, message, "TypeError"); -} - -inline TypeError TypeError::New(napi_env env, const std::string& message) { - return Error::New(env, message, "TypeError"); -} - -inline TypeError::TypeError(napi_env env, jsi::Object object) - : Error{env, std::move(object)} { -} - -inline RangeError RangeError::New(napi_env env, const char* message) { - return Error::New(env, message, "RangeError"); -} - -inline RangeError RangeError::New(napi_env env, const std::string& message) { - return Error::New(env, message, "RangeError"); -} - -inline RangeError::RangeError(napi_env env, jsi::Object object) - : Error{env, std::move(object)} { -} - -//////////////////////////////////////////////////////////////////////////////// -// Reference class -//////////////////////////////////////////////////////////////////////////////// - -template -inline Reference Reference::New(const T& object, uint32_t initialRefcount) { - Reference ref{object.Env(), object}; - ref._refcount = initialRefcount; - return std::move(ref); -} - -template -inline Reference::Reference() - : _env{nullptr}, _object{}, _refcount{0} { -} - -template -inline Reference::Reference(napi_env env, T object) - : _env{env}, _object{std::move(object)}, _refcount{0} { -} - -template -inline Reference::Reference(Reference&& other) - : _env{other._env}, _object{std::move(other._object)}, _refcount{other._refcount} { - other._env = nullptr; - other._refcount = 0; -} - -template -inline Reference::Reference(const Reference& other) - : _env{other._env}, _object{other._object}, _refcount{1} { - // Copying is a limited scenario (currently only used for Error object). -} - -template -inline Reference& Reference::operator =(Reference&& other) { - Reset(); - _env = other._env; - _object = std::move(other._object); - other._env = nullptr; - return *this; -} - -template -inline bool Reference::operator ==(const Reference &other) const { - HandleScope scope{_env}; - return Value().StrictEquals(other.Value()); -} - -template -inline bool Reference::operator !=(const Reference &other) const { - return !this->operator ==(other); -} - -template -inline Reference::operator bool() const { - return _env != nullptr; -} - -template -inline Napi::Env Reference::Env() const { - return {_env}; -} - -template -inline bool Reference::IsEmpty() const { - return _env == nullptr; -} - -template -inline const T& Reference::Value() const { - return _object; -} - -template -inline T& Reference::Value() { - return _object; -} - -template -inline uint32_t Reference::Ref() { - return ++_refcount; -} - -template -inline uint32_t Reference::Unref() { - return --_refcount; -} - -template -inline void Reference::Reset() { - _env = {}; - _object = {}; - _refcount = 0; -} - -template -inline void Reference::Reset(const T& value, uint32_t refcount) { - _object = value; - _refcount = refcount; -} - -template -inline void Reference::SuppressDestruct() { - // no-op -} - -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() { -} - -inline ObjectReference::ObjectReference(napi_env env, jsi::Object object) - : Reference{env, {env, std::move(object)}} { -} - -inline ObjectReference::ObjectReference(Reference&& other) - : Reference(other) { -} - -inline ObjectReference& ObjectReference::operator =(Reference&& other) { - static_cast*>(this)->operator=(std::move(other)); - return *this; -} - -inline ObjectReference::ObjectReference(ObjectReference&& other) - : Reference(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 { - return Value().Get(utf8name); -} - -inline Napi::Value ObjectReference::Get(const std::string& utf8name) const { - return Value().Get(utf8name); -} - -inline void ObjectReference::Set(const char* utf8name, Napi::Value value) { - Value().Set(utf8name, value); -} - -inline void ObjectReference::Set(const char* utf8name, const char* utf8value) { - Value().Set(utf8name, utf8value); -} - -inline void ObjectReference::Set(const char* utf8name, bool boolValue) { - Value().Set(utf8name, boolValue); -} - -inline void ObjectReference::Set(const char* utf8name, double numberValue) { - Value().Set(utf8name, numberValue); -} - -inline void ObjectReference::Set(const std::string& utf8name, Napi::Value value) { - Value().Set(utf8name, value); -} - -inline void ObjectReference::Set(const std::string& utf8name, std::string& utf8value) { - Value().Set(utf8name, utf8value); -} - -inline void ObjectReference::Set(const std::string& utf8name, bool boolValue) { - Value().Set(utf8name, boolValue); -} - -inline void ObjectReference::Set(const std::string& utf8name, double numberValue) { - Value().Set(utf8name, numberValue); -} - -inline Napi::Value ObjectReference::Get(uint32_t index) const { - return Value().Get(index); -} - -inline void ObjectReference::Set(uint32_t index, Napi::Value value) { - Value().Set(index, value); -} - -inline void ObjectReference::Set(uint32_t index, const char* utf8value) { - Value().Set(index, utf8value); -} - -inline void ObjectReference::Set(uint32_t index, const std::string& utf8value) { - Value().Set(index, utf8value); -} - -inline void ObjectReference::Set(uint32_t index, bool boolValue) { - Value().Set(index, boolValue); -} - -inline void ObjectReference::Set(uint32_t index, double numberValue) { - Value().Set(index, numberValue); -} - -//////////////////////////////////////////////////////////////////////////////// -// FunctionReference class -//////////////////////////////////////////////////////////////////////////////// - -inline FunctionReference::FunctionReference() { -} - -inline FunctionReference::FunctionReference(napi_env env, jsi::Function function) - : Reference{env, {env, std::move(function)}} { -} - -inline FunctionReference::FunctionReference(Reference&& other) - : Reference(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 { - return Value().Call(args); -} - -inline Napi::Value FunctionReference::Call(const std::initializer_list& args) const { - return Value().Call(args); -} - -inline Napi::Value FunctionReference::Call(const std::vector& args) const { - return Value().Call(args); -} - -inline Napi::Value FunctionReference::Call( - const Napi::Value& recv, const std::initializer_list& args) const { - return Value().Call(recv, args); -} - -inline Napi::Value FunctionReference::Call( - const Napi::Value& recv, const std::vector& args) const { - return Value().Call(recv, args); -} - -inline Napi::Value FunctionReference::Call( - const Napi::Value& recv, size_t argc, const Napi::Value* args) const { - return Value().Call(recv, argc, args); -} - -inline Object FunctionReference::New(const std::initializer_list& args) const { - return Value().New(args); -} - -inline Object FunctionReference::New(const std::vector& args) const { - return Value().New(args); -} - -//////////////////////////////////////////////////////////////////////////////// -// CallbackInfo class -//////////////////////////////////////////////////////////////////////////////// - -inline CallbackInfo::CallbackInfo(napi_env env, const jsi::Value& thisVal, const jsi::Value* args, size_t argc, const jsi::Value& newTarget, void* data) - : _env{env}, _this{_env->rt, thisVal}, _argc{argc}, _dynamicArgs{nullptr}, _newTarget{_env->rt, newTarget}, _data{data} { - if (_argc <= std::size(_staticArgs)) { - _argv = _staticArgs; - } else { - _dynamicArgs = new jsi::Value[_argc]; - _argv = _dynamicArgs; - } - - for (size_t i = 0; i < _argc; ++i) { - _argv[i] = {_env->rt, args[i]}; - } -} - -inline CallbackInfo::~CallbackInfo() { - if (_dynamicArgs != nullptr) { - delete[] _dynamicArgs; - } -} - -inline Value CallbackInfo::NewTarget() const { - return {_env, jsi::Value{_env->rt, _newTarget}}; -} - -inline bool CallbackInfo::IsConstructCall() const { - return !NewTarget().IsUndefined(); -} - -inline Napi::Env CallbackInfo::Env() const { - return {_env}; -} - -inline size_t CallbackInfo::Length() const { - return _argc; -} - -inline const Value CallbackInfo::operator [](size_t index) const { - return index < _argc ? Value{_env, {_env->rt, _argv[index]}} : Env().Undefined(); -} - -inline Value CallbackInfo::This() const { - return {_env, {_env->rt, _this}}; -} - -inline void* CallbackInfo::Data() const { - return _data; -} - -inline void CallbackInfo::SetData(void* data) { - _data = data; -} - -//////////////////////////////////////////////////////////////////////////////// -// PropertyDescriptor class -//////////////////////////////////////////////////////////////////////////////// - -//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 -// //}); -// throw std::runtime_error{"TODO"}; -//} -// -//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 -// //}); -// throw std::runtime_error{"TODO"}; -//} -// -//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 -// //}); -// throw std::runtime_error{"TODO"}; -//} -// -//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 -// //}); -// throw std::runtime_error{"TODO"}; -//} -// -//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, -// jsi::Value value, -// napi_property_attributes attributes) { -// //return PropertyDescriptor({ -// // utf8name, {}, nullptr, nullptr, nullptr, value, attributes, nullptr -// //}); -// throw std::runtime_error{"TODO"}; -//} -// -//inline PropertyDescriptor PropertyDescriptor::Value(const std::string& utf8name, -// jsi::Value value, -// napi_property_attributes attributes) { -// return Value(utf8name.c_str(), std::move(value), attributes); -//} -// -//inline PropertyDescriptor PropertyDescriptor::Value(jsi::Value name, -// jsi::Value value, -// napi_property_attributes attributes) { -// //return PropertyDescriptor({ -// // nullptr, name, nullptr, nullptr, nullptr, value, attributes, nullptr -// //}); -// throw std::runtime_error{"TODO"}; -//} -// -//inline PropertyDescriptor PropertyDescriptor::Value(Name name, -// Napi::Value value, -// napi_property_attributes attributes) { -// //return PropertyDescriptor::Value(jsi::Value{name}, jsi::Value{value}, attributes); -// throw std::runtime_error{"TODO"}; -//} -// -//inline PropertyDescriptor::PropertyDescriptor(napi_property_descriptor desc) -// /*: _desc(desc)*/ { -// throw std::runtime_error{"TODO"}; -//} -// -//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) - : _env{callbackInfo.Env()} { - //: Reference(callbackInfo.Env(), {}) { - //napi_env env = callbackInfo.Env(); - //jsi::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); - //throw std::runtime_error{"TODO"}; -} - -template -inline ObjectWrap::~ObjectWrap() {} - -template -Napi::Env ObjectWrap::Env() const { - return {_env}; -} - -template -inline T* ObjectWrap::Unwrap(napi_env env, const jsi::Object& wrapper) { - auto native{wrapper.getProperty(env->rt, env->native_name)}; - return native.isUndefined() ? nullptr : native.getObject(env->rt).getHostObject(env->rt).get(); -} - -template -inline T* ObjectWrap::Unwrap(Object wrapper) { - return Unwrap(wrapper.Env(), wrapper); -} - -template -inline Function -ObjectWrap::DefineClass(napi_env env, - const char* utf8name, - const size_t props_count, - const PropertyDescriptor* descriptors, - void* data) { - jsi::Runtime& rt{env->rt}; - - // TODO: Cache this somewhere? - auto constructorFactoryCode{std::make_shared("(function(constructor) { return function() { return constructor.apply(this, arguments); }; })")}; - auto createConstructor{rt.evaluateJavaScript(std::move(constructorFactoryCode), "").asObject(rt).asFunction(rt)}; - - auto newTarget{std::make_shared()}; - - jsi::Function constructor{createConstructor.call(rt, - jsi::Function::createFromHostFunction(rt, jsi::PropNameID::forUtf8(rt, utf8name), 0, - [env, newTarget, data](jsi::Runtime& rt, const jsi::Value& thisVal, const jsi::Value* args, size_t count) -> jsi::Value { - CallbackInfo callbackInfo{env, thisVal, args, count, *newTarget, data}; - // TODO: use prototype to wrap object? - thisVal.getObject(rt).setProperty(rt, env->native_name, jsi::Object::createFromHostObject(rt, std::make_shared(callbackInfo))); - return {}; - })).getObject(rt).getFunction(rt)}; - - *newTarget = {rt, static_cast(constructor)}; - - jsi::Object prototype{constructor.getProperty(rt, "prototype").getObject(rt)}; - - for (size_t i = 0; i < props_count; ++i) { - const PropertyDescriptor& p{descriptors[i]}; - jsi::PropNameID name{jsi::PropNameID::forUtf8(rt, p.utf8name)}; - jsi::Object descriptor{rt}; - descriptor.setProperty(rt, "configurable", jsi::Value{(p.attributes & napi_configurable) != 0}); - descriptor.setProperty(rt, "enumerable", jsi::Value{(p.attributes & napi_enumerable) != 0}); - - jsi::Object& owner = (p.staticVoidMethod || p.staticMethod || p.staticGetter || p.staticSetter || !p.staticValue.IsEmpty()) ? - constructor : - prototype; - - if (p.staticVoidMethod != nullptr) { - descriptor.setProperty(rt, "value", jsi::Function::createFromHostFunction(rt, name, 0, - [env, method{p.staticVoidMethod}, data{p.data}](jsi::Runtime& /*rt*/, const jsi::Value& thisVal, const jsi::Value* args, size_t count) -> jsi::Value { - (*method)({env, thisVal, args, count, nullptr, data}); - return {}; - })); - } else if (p.staticMethod != nullptr) { - descriptor.setProperty(rt, "value", jsi::Function::createFromHostFunction(rt, name, 0, - [env, method{p.staticMethod}, data{p.data}](jsi::Runtime& rt, const jsi::Value& thisVal, const jsi::Value* args, size_t count) -> jsi::Value { - return {rt, (*method)({env, thisVal, args, count, nullptr, data})}; - })); - } else if (p.staticGetter != nullptr || p.staticSetter != nullptr) { - if (p.staticGetter != nullptr) - { - descriptor.setProperty(rt, "get", jsi::Function::createFromHostFunction(rt, name, 0, - [env, getter{p.staticGetter}, data{p.data}](jsi::Runtime& rt, const jsi::Value& thisVal, const jsi::Value* args, size_t count)-> jsi::Value { - return {rt, (*getter)({env, thisVal, args, count, nullptr, data})}; - })); - } - if (p.staticSetter != nullptr) { - descriptor.setProperty(rt, "set", jsi::Function::createFromHostFunction(rt, name, 0, - [env, setter{p.staticSetter}, data{p.data}](jsi::Runtime& rt, const jsi::Value& thisVal, const jsi::Value* args, size_t count)-> jsi::Value { - (*setter)({env, thisVal, args, count, nullptr, data}, {env, {rt, args[0]}}); - return {}; - })); - } - } else if (!p.staticValue.IsEmpty()) { - descriptor.setProperty(rt, "writable", jsi::Value{(p.attributes & napi_writable) != 0}); - descriptor.setProperty(rt, "value", static_cast(p.staticValue)); - } else if (p.instanceVoidMethod != nullptr) { - descriptor.setProperty(rt, "value", jsi::Function::createFromHostFunction(rt, name, 0, - [env, method{p.instanceVoidMethod}, data{p.data}](jsi::Runtime& rt, const jsi::Value& thisVal, const jsi::Value* args, size_t count) -> jsi::Value { - T* nativeObject{Unwrap(env, thisVal.getObject(rt))}; - (nativeObject->*method)({env, thisVal, args, count, nullptr, data}); - return {}; - })); - } else if (p.instanceMethod != nullptr) { - descriptor.setProperty(rt, "value", jsi::Function::createFromHostFunction(rt, name, 0, - [env, method{p.instanceMethod}, data{p.data}](jsi::Runtime& rt, const jsi::Value& thisVal, const jsi::Value* args, size_t count) -> jsi::Value { - T* nativeObject{Unwrap(env, thisVal.getObject(rt))}; - return {rt, (nativeObject->*method)({env, thisVal, args, count, nullptr, data})}; - })); - } else if (p.instanceGetter != nullptr || p.instanceSetter != nullptr) { - if (p.instanceGetter != nullptr) { - descriptor.setProperty(rt, "get", jsi::Function::createFromHostFunction(rt, name, 0, - [env, getter{p.instanceGetter}, data{p.data}](jsi::Runtime& rt, const jsi::Value& thisVal, const jsi::Value* args, size_t count) -> jsi::Value { - T* nativeObject{Unwrap(env, thisVal.getObject(rt))}; - return {rt, (nativeObject->*getter)({env, thisVal, args, count, nullptr, data})}; - })); - } - if (p.instanceSetter != nullptr) { - descriptor.setProperty(rt, "set", jsi::Function::createFromHostFunction(rt, name, 0, - [env, setter{p.instanceSetter}, data{p.data}](jsi::Runtime& rt, const jsi::Value& thisVal, const jsi::Value* args, size_t count) -> jsi::Value { - T* nativeObject{Unwrap(env, thisVal.getObject(rt))}; - (nativeObject->*setter)({env, thisVal, args, count, nullptr, data}, {env, {rt, args[0]}}); - return {}; - })); - } - } else if (!p.instanceValue.IsEmpty()) { - descriptor.setProperty(rt, "writable", jsi::Value{(p.attributes & napi_writable) != 0}); - descriptor.setProperty(rt, "value", static_cast(p.instanceValue)); - } - - jsi::Object object{rt.global().getPropertyAsObject(rt, "Object")}; - jsi::Function defineProperty{object.getPropertyAsFunction(rt, "defineProperty")}; - defineProperty.callWithThis(rt, object, owner, p.utf8name, descriptor); - } - - return {env, std::move(constructor)}; -} - -template -inline Function ObjectWrap::DefineClass( - napi_env env, - const char* utf8name, - const std::initializer_list& properties, - void* data) { - return DefineClass(env, - utf8name, - properties.size(), - 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(), - properties.data(), - data); -} - -template -inline typename ObjectWrap::PropertyDescriptor ObjectWrap::StaticMethod( - const char* utf8name, - StaticVoidMethodCallback method, - napi_property_attributes attributes, - void* data) { - StaticVoidMethodCallbackData* callbackData = new StaticVoidMethodCallbackData({ method, data }); - - PropertyDescriptor desc{}; - desc.utf8name = utf8name; - desc.staticVoidMethod = method; - desc.data = callbackData; - desc.attributes = attributes; - return desc; -} - -template -inline typename ObjectWrap::PropertyDescriptor ObjectWrap::StaticMethod( - const char* utf8name, - StaticMethodCallback method, - napi_property_attributes attributes, - void* data) { - StaticMethodCallbackData* callbackData = new StaticMethodCallbackData({ method, data }); - - PropertyDescriptor desc{}; - desc.utf8name = utf8name; - desc.staticMethod = method; - desc.data = callbackData; - desc.attributes = attributes; - return desc; -} - -template -inline typename ObjectWrap::PropertyDescriptor ObjectWrap::StaticMethod( - Symbol name, - StaticVoidMethodCallback method, - napi_property_attributes attributes, - void* data) { - StaticVoidMethodCallbackData* callbackData = new StaticVoidMethodCallbackData({ method, data }); - - PropertyDescriptor desc{}; - desc.name = name; - desc.staticVoidMethod = method; - desc.data = callbackData; - desc.attributes = attributes; - return desc; -} - -template -inline typename ObjectWrap::PropertyDescriptor ObjectWrap::StaticMethod( - Symbol name, - StaticMethodCallback method, - napi_property_attributes attributes, - void* data) { - StaticMethodCallbackData* callbackData = new StaticMethodCallbackData({ method, data }); - - PropertyDescriptor desc{}; - desc.name = name; - desc.staticMethod = method; - desc.data = callbackData; - desc.attributes = attributes; - return desc; -} - -template -inline typename ObjectWrap::PropertyDescriptor ObjectWrap::StaticAccessor( - const char* utf8name, - StaticGetterCallback getter, - StaticSetterCallback setter, - napi_property_attributes attributes, - void* data) { - PropertyDescriptor desc{}; - desc.utf8name = utf8name; - desc.staticGetter = getter; - desc.staticSetter = setter; - desc.attributes = attributes; - desc.data = data; - return desc; -} - -template -inline typename ObjectWrap::PropertyDescriptor ObjectWrap::StaticAccessor( - Symbol name, - StaticGetterCallback getter, - StaticSetterCallback setter, - napi_property_attributes attributes, - void* data) { - StaticAccessorCallbackData* callbackData = - new StaticAccessorCallbackData({ getter, setter, data }); - - PropertyDescriptor desc{}; - desc.name = name; - desc.staticGetter = getter != nullptr ? getter : nullptr; - desc.staticSetter = setter != nullptr ? setter : nullptr; - desc.data = callbackData; - desc.attributes = attributes; - return desc; -} - -template -inline typename ObjectWrap::PropertyDescriptor ObjectWrap::InstanceMethod( - const char* utf8name, - InstanceVoidMethodCallback method, - napi_property_attributes attributes, - void* data) { - PropertyDescriptor desc{}; - desc.utf8name = utf8name; - desc.instanceVoidMethod = method; - desc.attributes = attributes; - desc.data = data; - return desc; -} - -template -inline typename ObjectWrap::PropertyDescriptor ObjectWrap::InstanceMethod( - const char* utf8name, - InstanceMethodCallback method, - napi_property_attributes attributes, - void* data) { - PropertyDescriptor desc{}; - desc.utf8name = utf8name; - desc.instanceMethod = method; - desc.attributes = attributes; - desc.data = data; - return desc; -} - -template -inline typename ObjectWrap::PropertyDescriptor ObjectWrap::InstanceMethod( - Symbol name, - InstanceVoidMethodCallback method, - napi_property_attributes attributes, - void* data) { - InstanceVoidMethodCallbackData* callbackData = - new InstanceVoidMethodCallbackData({ method, data}); - - PropertyDescriptor desc{}; - desc.name = name; - desc.instanceVoidMethod = method; - desc.data = data; - desc.attributes = attributes; - return desc; -} - -template -inline typename ObjectWrap::PropertyDescriptor ObjectWrap::InstanceMethod( - Symbol name, - InstanceMethodCallback method, - napi_property_attributes attributes, - void* data) { - InstanceMethodCallbackData* callbackData = new InstanceMethodCallbackData({ method, data }); - - PropertyDescriptor desc{}; - desc.name = name; - desc.instanceMethod = method; - desc.data = callbackData; - desc.attributes = attributes; - return desc; -} - -template -inline typename ObjectWrap::PropertyDescriptor ObjectWrap::InstanceAccessor( - const char* utf8name, - InstanceGetterCallback getter, - InstanceSetterCallback setter, - napi_property_attributes attributes, - void* data) { - PropertyDescriptor desc{}; - desc.utf8name = utf8name; - desc.instanceGetter = getter; - desc.instanceSetter = setter; - desc.attributes = attributes; - desc.data = data; - return desc; -} - -template -inline typename ObjectWrap::PropertyDescriptor ObjectWrap::InstanceAccessor( - Symbol name, - InstanceGetterCallback getter, - InstanceSetterCallback setter, - napi_property_attributes attributes, - void* data) { - InstanceAccessorCallbackData* callbackData = - new InstanceAccessorCallbackData({ getter, setter, data }); - - PropertyDescriptor desc{}; - desc.name = name; - desc.instanceGetter = getter != nullptr ? getter : nullptr; - desc.instanceSetter = setter != nullptr ? setter : nullptr; - desc.data = callbackData; - desc.attributes = attributes; - return desc; -} - -template -inline typename ObjectWrap::PropertyDescriptor ObjectWrap::StaticValue(const char* utf8name, - Napi::Value value, napi_property_attributes attributes) { - PropertyDescriptor desc{}; - desc.utf8name = utf8name; - desc.staticValue = std::move(value); - desc.attributes = attributes; - return desc; -} - -template -inline typename ObjectWrap::PropertyDescriptor ObjectWrap::StaticValue(Symbol name, - Napi::Value value, napi_property_attributes attributes) { - PropertyDescriptor desc{}; - desc.name = name; - desc.value = value; - desc.attributes = attributes; - return desc; -} - -template -inline typename ObjectWrap::PropertyDescriptor ObjectWrap::InstanceValue( - const char* utf8name, - Napi::Value value, - napi_property_attributes attributes) { - PropertyDescriptor desc{}; - desc.utf8name = utf8name; - desc.instanceValue = std::move(value); - desc.attributes = attributes; - return desc; -} - -template -inline typename ObjectWrap::PropertyDescriptor ObjectWrap::InstanceValue( - Symbol name, - Napi::Value value, - napi_property_attributes attributes) { - PropertyDescriptor desc{}; - desc.name = name; - desc.value = value; - desc.attributes = attributes; - return desc; -} - -template -inline void ObjectWrap::Finalize(napi_env /*env*/) {} - -//////////////////////////////////////////////////////////////////////////////// -// HandleScope class -//////////////////////////////////////////////////////////////////////////////// - -inline HandleScope::HandleScope(napi_env env) : _env{env} { - // no-op -} - -inline HandleScope::~HandleScope() { - // no-op -} - -inline Napi::Env HandleScope::Env() const { - return {_env}; -} - -//////////////////////////////////////////////////////////////////////////////// -// EscapableHandleScope class -//////////////////////////////////////////////////////////////////////////////// - -inline EscapableHandleScope::EscapableHandleScope(napi_env env) : _env{env} { - // no-op -} - -inline EscapableHandleScope::~EscapableHandleScope() { - // no-op -} - -inline Napi::Env EscapableHandleScope::Env() const { - return {_env}; -} - -inline Value EscapableHandleScope::Escape(jsi::Value escapee) { - // no-op - return {_env, std::move(escapee)}; -} - -} // namespace Napi diff --git a/Dependencies/napi/napi-jsi/include/napi/napi.h b/Dependencies/napi/napi-jsi/include/napi/napi.h deleted file mode 100644 index 9e6c139a5..000000000 --- a/Dependencies/napi/napi-jsi/include/napi/napi.h +++ /dev/null @@ -1,1493 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include - -// Copied from js_native_api_types.h (https://git.io/J8aI5) -typedef enum { - napi_default = 0, - napi_writable = 1 << 0, - napi_enumerable = 1 << 1, - napi_configurable = 1 << 2, -} napi_property_attributes; - -typedef enum { - // ES6 types (corresponds to typeof) - napi_undefined, - napi_null, - napi_boolean, - napi_number, - napi_string, - napi_symbol, - napi_object, - napi_function, - napi_external, -} napi_valuetype; - -typedef enum { - napi_int8_array, - napi_uint8_array, - napi_uint8_clamped_array, - napi_int16_array, - napi_uint16_array, - napi_int32_array, - napi_uint32_array, - napi_float32_array, - napi_float64_array, - // JSI doesn't support bigint. - // napi_bigint64_array, - // napi_biguint64_array, -} napi_typedarray_type; - -struct napi_env__ { - napi_env__(facebook::jsi::Runtime& rt) - : rt{rt} - , native_name{facebook::jsi::PropNameID::forAscii(rt, "__native__")} - , array_buffer_ctor{rt.global().getPropertyAsFunction(rt, "ArrayBuffer")} - , promise_ctor{rt.global().getPropertyAsFunction(rt, "Promise")} - , typed_array_ctor{ - rt.global().getPropertyAsFunction(rt, "Int8Array"), - rt.global().getPropertyAsFunction(rt, "Uint8Array"), - rt.global().getPropertyAsFunction(rt, "Uint8ClampedArray"), - rt.global().getPropertyAsFunction(rt, "Int16Array"), - rt.global().getPropertyAsFunction(rt, "Uint16Array"), - rt.global().getPropertyAsFunction(rt, "Int32Array"), - rt.global().getPropertyAsFunction(rt, "Uint32Array"), - rt.global().getPropertyAsFunction(rt, "Float32Array"), - rt.global().getPropertyAsFunction(rt, "Float64Array")} - , boolean_func{rt.global().getPropertyAsFunction(rt, "Boolean")} - , number_func{rt.global().getPropertyAsFunction(rt, "Number")} { - } - - facebook::jsi::Runtime& rt; - - facebook::jsi::PropNameID native_name; - facebook::jsi::Function array_buffer_ctor; - facebook::jsi::Function promise_ctor; - facebook::jsi::Function typed_array_ctor[9]; - facebook::jsi::Function boolean_func; - facebook::jsi::Function number_func; - - facebook::jsi::Value last_exception; -}; - -using napi_env = napi_env__*; - -#ifdef NAPI_DISABLE_CPP_EXCEPTIONS - #error Exceptions cannot be disabled for NAPI/JSI -#endif - -#define NAPI_TRY() \ - try { - -#define NAPI_CATCH() \ - } catch (const std::exception& exception) { \ - throw Error::New(_env, exception); \ - } - -//////////////////////////////////////////////////////////////////////////////// -/// 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 { - - using namespace facebook; - - // Forward declarations - class Env; - class Value; - class Boolean; - class Number; - class String; - class Object; - class Array; - class Function; - 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 - - /// 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(); - - 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, jsi::Value value); ///< Wraps a N-API value primitive. - - // Move semantics - Value(Value&&) = default; - Value& operator =(Value&&) = default; - operator jsi::Value&&() &&; - - // Copy semantics - Value(const Value& other); - Value& operator =(const Value& other); - operator jsi::Value&() &; - operator const jsi::Value&() const &; - - /// 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 - /// - jsi::Value - template - static Value From(napi_env env, const T& value); - - /// 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. - 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 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; - jsi::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, jsi::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, jsi::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. - }; - - /// 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, jsi::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, jsi::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 - jsi::Value description ///< String value describing the symbol - ); - - /// Get a public Symbol (e.g. Symbol.iterator). - static Symbol WellKnown(napi_env env, const std::string& name); - - Symbol(); ///< Creates a new _empty_ Symbol instance. - Symbol(napi_env env, jsi::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); - Object& _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, jsi::Value value); ///< Wraps a N-API value primitive. - - // Move semantics - Object(Object&&) = default; - Object& operator =(Object&&) = default; - operator jsi::Object&&() &&; - - // Copy semantics - Object(const Object& other); - Object& operator =(const Object& other); - operator jsi::Object&() &; - operator const jsi::Object&() const &; - - /// 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( - 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( - 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( - 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( - 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( - 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; - - protected: - std::optional _object; - }; - - 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, jsi::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, jsi::Value value); - - // Move semantics - Array(Array&&) = default; - Array& operator =(Array&&) = default; - operator jsi::Array&&() &&; - - // Copy semantics - Array(const Array& other); - Array& operator =(const Array& other); - operator jsi::Array&() &; - operator const jsi::Array&() const &; - - uint32_t Length() const; - - private: - std::optional _array; - }; - - /// 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, jsi::Value value); ///< Wraps a N-API value primitive. - - // Move semantics - ArrayBuffer(ArrayBuffer&&) = default; - ArrayBuffer& operator =(ArrayBuffer&&) = default; - operator jsi::ArrayBuffer&&() &&; - - // Copy semantics - ArrayBuffer(const ArrayBuffer& other); - ArrayBuffer& operator =(const ArrayBuffer& other); - operator jsi::ArrayBuffer&() &; - operator const jsi::ArrayBuffer&() const &; - - void* Data() const; ///< Gets a pointer to the data buffer. - size_t ByteLength() const; ///< Gets the length of the array buffer in bytes. - - private: - static jsi::ArrayBuffer FromExternal(napi_env env, void* externalData, size_t byteLength); - - std::optional _arrayBuffer; - }; - - /// 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, jsi::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 - TypedArray(napi_env env, jsi::Value value, napi_typedarray_type type, size_t length); - - mutable napi_typedarray_type _type; - mutable size_t _length; - - static const napi_typedarray_type unknown_array_type = static_cast(-1); - - template - static - constexpr 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 - : unknown_array_type; - } - - static void GetTypedArrayInfo(napi_env env, - const jsi::Object& typedArray, - napi_typedarray_type* type, - size_t* length); - /// !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 - napi_typedarray_type type = TypedArray::TypedArrayTypeForPrimitiveType() ///< 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 - napi_typedarray_type type = TypedArray::TypedArrayTypeForPrimitiveType() ///< 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, jsi::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, - jsi::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(napi_env env, jsi::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: - /// 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, jsi::Value value); - - // Move semantics - Function(Function&&) = default; - Function& operator =(Function&&) = default; - operator jsi::Function&&() &&; - - // Copy semantics - Function(const Function& other); - Function& operator =(const Function& other); - operator jsi::Function&() &; - operator const jsi::Function&() const &; - - 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 Value* args) const; - Value Call(const Value& recv, const std::initializer_list& args) const; - Value Call(const Value& recv, const std::vector& args) const; - Value Call(const Value& recv, size_t argc, const Value* args) const; - - Object New(const std::initializer_list& args) const; - Object New(const std::vector& args) const; - Object New(size_t argc, const Value* args) const; - - private: - std::optional _function; - }; - - class Promise : public Object { - public: - class Deferred { - public: - static Deferred New(napi_env env); - Deferred(napi_env env); - - // Move semantics - Deferred(Deferred&&) = default; - Deferred& operator =(Deferred&&) = default; - - // Copy semantics - Deferred(const Deferred& other); - Deferred& operator =(const Deferred& other); - - Napi::Promise Promise() const; - Napi::Env Env() const; - - void Resolve(const jsi::Value& value) const; - void Reject(const jsi::Value& value) const; - - private: - napi_env _env; - jsi::Value _promise; - std::optional _resolve; - std::optional _reject; - }; - - Promise(napi_env env, jsi::Value value); - }; - - /// 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. - /// - /// NOTE: This class is implemented as a no-op for JSI. - template - class Reference { - public: - static Reference New(const T& object, uint32_t initialRefcount = 0); - - Reference(); - Reference(napi_env env, T object); - - // A reference can be moved but cannot be copied. - Reference(Reference&& other); - Reference& operator =(Reference&& other); - - bool operator ==(const Reference &other) const; - bool operator !=(const Reference &other) const; - operator bool() 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. - const T& Value() const; - T& Value(); - - 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. - // NOTE: This is no-op for JSI. - void SuppressDestruct(); - - protected: - Reference(const Reference&); - - /// !cond INTERNAL - napi_env _env; - T _object; - uint32_t _refcount; - /// !endcond - }; - - class ObjectReference : public Reference { - public: - ObjectReference(); - ObjectReference(napi_env env, jsi::Object object); - - // A reference can be moved but cannot be copied. - ObjectReference(Reference&& other); - ObjectReference& operator =(Reference&& other); - ObjectReference(ObjectReference&& other); - ObjectReference& operator =(ObjectReference&& other); - - 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, 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, 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 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, jsi::Function function); - - // A reference can be moved but cannot be copied. - FunctionReference(Reference&& other); - FunctionReference& operator =(Reference&& other); - FunctionReference(FunctionReference&& other); - FunctionReference& operator =(FunctionReference&& other); - - 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(const Napi::Value& recv, const std::initializer_list& args) const; - Napi::Value Call(const Napi::Value& recv, const std::vector& args) const; - Napi::Value Call(const Napi::Value& recv, size_t argc, const Napi::Value* args) 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. - class Error : public ObjectReference, public std::exception - { - public: - static Error New(napi_env env, const char* message); - static Error New(napi_env env, const std::string& message); - - static Error New(napi_env env, const std::exception& exception); - static Error New(napi_env env, const std::exception_ptr& exception_ptr); - - static void Fatal(const char* location, const char* message); - - Error(); - Error(napi_env env, jsi::Object object); - - // An error can be moved or copied. - Error(Error&& other); - Error& operator =(Error&& other); - Error(const Error&); - Error& operator =(Error&); - - const std::string& Message() const; - void ThrowAsJavaScriptException() const; - - const char* what() const noexcept override; - - protected: - /// !cond INTERNAL - template - static TError New(napi_env env, TMessage message, const char* constructor); - /// !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, jsi::Object object); - }; - - 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, jsi::Object object); - }; - - class CallbackInfo { - public: - CallbackInfo(napi_env env, const jsi::Value& thisVal, const jsi::Value* args, size_t argc, const jsi::Value& newTarget, void* data); - ~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: - napi_env _env; - jsi::Value _this; - size_t _argc; - jsi::Value* _argv; - jsi::Value _staticArgs[6]; - jsi::Value* _dynamicArgs; - jsi::Value _newTarget; - void* _data; - }; - - // TODO: not implemented - //class PropertyDescriptor { - //public: - // 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, - // jsi::Value value, - // napi_property_attributes attributes = napi_default); - // static PropertyDescriptor Value(const std::string& utf8name, - // jsi::Value value, - // napi_property_attributes attributes = napi_default); - // static PropertyDescriptor Value(jsi::Value name, - // jsi::Value value, - // napi_property_attributes attributes = napi_default); - // static PropertyDescriptor Value(Name name, - // Napi::Value value, - // napi_property_attributes attributes = napi_default); - //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("value", &Example::GetSomething, &Example::SetSomething), - /// InstanceMethod("doSomething", &Example::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 jsi::HostObject { - public: - ObjectWrap(const CallbackInfo& callbackInfo); - virtual ~ObjectWrap(); - - Napi::Env Env() const; - - 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); - - class PropertyDescriptor { - friend ObjectWrap; - - const char* utf8name; - StaticVoidMethodCallback staticVoidMethod; - StaticMethodCallback staticMethod; - StaticGetterCallback staticGetter; - StaticSetterCallback staticSetter; - Napi::Value staticValue; - InstanceVoidMethodCallback instanceVoidMethod; - InstanceMethodCallback instanceMethod; - InstanceGetterCallback instanceGetter; - InstanceSetterCallback instanceSetter; - Napi::Value instanceValue; - napi_property_attributes attributes; - void* data; - }; - - 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); - 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); - 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); - 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); - 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: - static Function DefineClass(napi_env env, - const char* utf8name, - const size_t props_count, - const PropertyDescriptor* props, - void* data = nullptr); - - static T* Unwrap(napi_env env, const jsi::Object& object); - - 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; - - napi_env _env; - }; - - // No-op stub class - class HandleScope { - public: - explicit HandleScope(napi_env env); - ~HandleScope(); - - Napi::Env Env() const; - - private: - napi_env _env; - }; - - // No-op stub class - class EscapableHandleScope { - public: - explicit EscapableHandleScope(napi_env env); - ~EscapableHandleScope(); - - Napi::Env Env() const; - Value Escape(jsi::Value escapee); - - private: - napi_env _env; - }; -} // namespace Napi - -// Inline implementations of all the above class methods are included here. -#include "napi-inl.h" diff --git a/Dependencies/napi/napi-jsi/nuget.config b/Dependencies/napi/napi-jsi/nuget.config deleted file mode 100644 index c681fdbd5..000000000 --- a/Dependencies/napi/napi-jsi/nuget.config +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - diff --git a/Dependencies/napi/napi-jsi/packages.config b/Dependencies/napi/napi-jsi/packages.config deleted file mode 100644 index 7832d415a..000000000 --- a/Dependencies/napi/napi-jsi/packages.config +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/Dependencies/napi/napi-jsi/source/env.cc b/Dependencies/napi/napi-jsi/source/env.cc deleted file mode 100644 index a391fc0ae..000000000 --- a/Dependencies/napi/napi-jsi/source/env.cc +++ /dev/null @@ -1,23 +0,0 @@ -#include - -namespace Napi -{ - template<> - Env Attach<>(facebook::jsi::Runtime& rt) - { - napi_env__* env_ptr{new napi_env__{rt}}; - return {env_ptr}; - } - - void Detach(Env env) - { - napi_env__* env_ptr{env}; - delete env_ptr; - } - - Napi::Value Eval(Napi::Env env, const char* string, const char* sourceUrl) - { - napi_env__* env_ptr{env}; - return {env_ptr, env_ptr->rt.evaluateJavaScript(std::make_shared(string), sourceUrl)}; - } -} diff --git a/Dependencies/v8inspector/CMakeLists.txt b/Dependencies/v8inspector/CMakeLists.txt deleted file mode 100644 index c1ce9fd9f..000000000 --- a/Dependencies/v8inspector/CMakeLists.txt +++ /dev/null @@ -1,89 +0,0 @@ -# ------------------------------- asio ------------------------------- -add_library(asio INTERFACE) -target_include_directories(asio INTERFACE "Dependencies/asio/asio/include") - -# ------------------------------ llhttp ------------------------------ -# Install node to use npm -set(NODE_VERSION "v14.15.5") -set_cpu_platform_arch() -set(NODE_DIST "node-${NODE_VERSION}-${PLATFORM_ARCH}-${CPU_ARCH}") -set(NODE_PATH "${CMAKE_BINARY_DIR}/node") - -if (PLATFORM_ARCH STREQUAL "darwin" OR PLATFORM_ARCH STREQUAL "linux") - set(ARCHIVE_EXT "tar.gz") - set(NPM_CMD "${NODE_PATH}/${NODE_DIST}/bin/npm") -else() - set(ARCHIVE_EXT "zip") - set(NPM_CMD "${NODE_PATH}/${NODE_DIST}/npm.cmd") -endif() - -set(NODE_ARCHIVE "${NODE_PATH}/node.${ARCHIVE_EXT}") - -if(NOT EXISTS ${NPM_CMD}) - message(STATUS "Downloading https://nodejs.org/dist/${NODE_VERSION}/${NODE_DIST}.${ARCHIVE_EXT}") - file(DOWNLOAD "https://nodejs.org/dist/${NODE_VERSION}/${NODE_DIST}.${ARCHIVE_EXT}" ${NODE_ARCHIVE}) - file(ARCHIVE_EXTRACT INPUT ${NODE_ARCHIVE} DESTINATION ${NODE_PATH}) - file(REMOVE ${NODE_ARCHIVE}) -endif() - -set(LLHTTP_DIR "${CMAKE_CURRENT_SOURCE_DIR}/Dependencies/llhttp") - -if (NOT EXISTS "${LLHTTP_DIR}/build") - message(STATUS "Generating llhttp library") - # Allow npm to use a relative-path installation of node - execute_process(COMMAND ${NPM_CMD} config set "scripts-prepend-node-path" true WORKING_DIRECTORY ${LLHTTP_DIR}) - - # Download npm dependencies, if necessary - if (NOT EXISTS "${LLHTTP_DIR}/node_modules") - message(STATUS "Downloading npm dependencies...") - execute_process(COMMAND ${NPM_CMD} ci WORKING_DIRECTORY ${LLHTTP_DIR} OUTPUT_QUIET ERROR_VARIABLE NPM_CI_ERROR) - endif() - - # Generate the library - message(STATUS "Running generation script...") - execute_process(COMMAND ${NPM_CMD} run build WORKING_DIRECTORY ${LLHTTP_DIR} ERROR_VARIABLE NPM_RUN_BUILD_ERROR) - - if (NOT ${NPM_RUN_BUILD_ERROR} STREQUAL "") - message(FATAL_ERROR "Problem with llhttp generation:\n${NPM_CI_ERROR}\n${NPM_RUN_BUILD_ERROR}") - endif() - message(STATUS "llhttp library generation done") -endif() - -set(LLHTTP_SOURCES - "Dependencies/llhttp/build/c/llhttp.c" - "Dependencies/llhttp/src/native/api.c" - "Dependencies/llhttp/src/native/http.c") -add_library(llhttp ${LLHTTP_SOURCES}) -target_include_directories(llhttp PUBLIC "Dependencies/llhttp/build") -target_include_directories(llhttp PUBLIC "Dependencies/llhttp/src/native") -source_group(TREE ${LLHTTP_DIR} FILES ${LLHTTP_SOURCES}) -set_property(TARGET llhttp PROPERTY FOLDER Dependencies) - -# --------------------------- v8 inspector --------------------------- -set(SOURCES - "Include/V8Inc.h" - "Include/V8InspectorAgent.h" - "Source/V8InspectorAgent.cpp" - "Source/V8InspectorSocket.h" - "Source/V8InspectorSocket.cpp" - "Source/V8InspectorSocketServer.h" - "Source/V8InspectorSocketServer.cpp" - "Source/V8InspectorTCP.h" - "Source/V8InspectorTCP.cpp" - "Source/V8InspectorUtils.h" - "Source/V8InspectorUtils.cpp") - -add_library(v8inspector ${SOURCES}) -warnings_as_errors(v8inspector) - -target_include_directories(v8inspector PUBLIC "Include") -target_include_directories(v8inspector PRIVATE "Source") - -target_compile_definitions(v8inspector PRIVATE ASIO_STANDALONE) - -source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${SOURCES}) - -target_link_to_dependencies(v8inspector PRIVATE asio) -target_link_to_dependencies(v8inspector PRIVATE llhttp) -target_link_to_dependencies(v8inspector PRIVATE javascript_engine) -disable_warnings(v8inspector) \ No newline at end of file diff --git a/Dependencies/v8inspector/Dependencies/asio b/Dependencies/v8inspector/Dependencies/asio deleted file mode 160000 index be7badc31..000000000 --- a/Dependencies/v8inspector/Dependencies/asio +++ /dev/null @@ -1 +0,0 @@ -Subproject commit be7badc31abcc395cf868de6a1e240c2350bdbf2 diff --git a/Dependencies/v8inspector/Dependencies/llhttp b/Dependencies/v8inspector/Dependencies/llhttp deleted file mode 160000 index 242cfd4eb..000000000 --- a/Dependencies/v8inspector/Dependencies/llhttp +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 242cfd4ebc2b57dd84904cb67b617bf4a6b6fa93 diff --git a/Dependencies/v8inspector/Include/V8Inc.h b/Dependencies/v8inspector/Include/V8Inc.h deleted file mode 100644 index 851ab3373..000000000 --- a/Dependencies/v8inspector/Include/V8Inc.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -#ifndef __clang__ -#pragma warning(push) -#pragma warning(disable: 4100 4267 4127) -#endif - -#include -#include -#include - -#ifndef __clang__ -#pragma warning(pop) -#endif \ No newline at end of file diff --git a/Dependencies/v8inspector/Include/V8InspectorAgent.h b/Dependencies/v8inspector/Include/V8InspectorAgent.h deleted file mode 100644 index 23ae0ac08..000000000 --- a/Dependencies/v8inspector/Include/V8InspectorAgent.h +++ /dev/null @@ -1,42 +0,0 @@ - -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. -// This code is based on the old node inspector implementation. See NOTICE.md for Node.js' project license details -#pragma once - -#include - -#include "V8Inc.h" - -namespace Babylon -{ - class AgentImpl; - - class V8InspectorAgent { - public: - // TODO :: safe access to platform - // Note :: Currently we do support one platform/isolate/context per agent.. - // This is enough for our scenarios. - explicit V8InspectorAgent( - v8::Platform& platform, - v8::Isolate* isolate, - v8::Local context, - const char* context_name); - ~V8InspectorAgent(); - - void waitForDebugger(); - - void start(const unsigned short port, const std::string& appName); - void stop(); - - bool IsStarted(); - bool IsConnected(); - void WaitForDisconnect(); - void FatalException( - v8::Local error, - v8::Local message); - - private: - std::shared_ptr impl; - }; -} \ No newline at end of file diff --git a/Dependencies/v8inspector/Source/V8InspectorAgent.cpp b/Dependencies/v8inspector/Source/V8InspectorAgent.cpp deleted file mode 100644 index 51653be1d..000000000 --- a/Dependencies/v8inspector/Source/V8InspectorAgent.cpp +++ /dev/null @@ -1,761 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. -// This code is based on the old node inspector implementation. See NOTICE.md for Node.js' project license details -#include -#include "V8InspectorSocketServer.h" -#include "V8InspectorUtils.h" - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace Babylon -{ - const char TAG_CONNECT[] = "#connect"; - const char TAG_DISCONNECT[] = "#disconnect"; - - std::string GetProcessTitle() - { - return "BabylonNative"; - } - - class V8NodeInspector; - - class AgentImpl : public std::enable_shared_from_this - { - public: - explicit AgentImpl( - v8::Platform& platform, - v8::Isolate* isolate, - v8::Local context, - const char* context_name); - ~AgentImpl(); - - void Start(const unsigned short port, const std::string& appName); - void Stop(); - - void waitForDebugger(); - - bool IsStarted(); - bool IsConnected(); - void WaitForDisconnect(); - - void FatalException( - v8::Local error, - v8::Local message); - - void PostIncomingMessage(int session_id, const std::string& message); - void ResumeStartup() {} - - private: - using MessageQueue = - std::vector>>; - enum class State - { - kNew, - kAccepting, - kConnected, - kDone, - kError - }; - - static void ThreadCbIO(void* agent); - static void WriteCbIO(/*uv_async_t* async*/); - - void InstallInspectorOnProcess(); - - void SetConnected(bool connected); - void DispatchMessages(); - void Write( - int session_id, - std::unique_ptr message); - bool AppendMessage( - MessageQueue* vector, - int session_id, - std::unique_ptr buffer); - void SwapBehindLock(MessageQueue* vector1, MessageQueue* vector2); - void WaitForFrontendMessage(); - void NotifyMessageReceived(); - State ToState(State state); - - std::mutex incoming_message_cond_m_; - std::condition_variable incoming_message_cond_; - - std::mutex state_m; - - unsigned short port_; - bool wait_; - bool shutting_down_; - State state_; - - bool waiting_for_frontend_ = true; - - std::unique_ptr inspector_; - v8::Isolate* isolate_; - MessageQueue incoming_message_queue_; - MessageQueue outgoing_message_queue_; - bool dispatching_messages_; - int session_id_; - std::unique_ptr server_; - - std::string script_name_; - - v8::Platform& platform_; - - friend class ChannelImpl; - friend class DispatchOnInspectorBackendTask; - friend class SetConnectedTask; - friend class V8NodeInspector; - friend void InterruptCallback(v8::Isolate*, void* agent); - - public: - }; - - void InterruptCallback(v8::Isolate*, void* agent) - { - static_cast(agent)->DispatchMessages(); - } - - class DispatchOnInspectorBackendTask : public v8::Task - { - public: - explicit DispatchOnInspectorBackendTask(AgentImpl& agent) - : agent_(agent) - { - } - - void Run() override - { - agent_.DispatchMessages(); - } - - private: - AgentImpl& agent_; - }; - - class ChannelImpl final : public v8_inspector::V8Inspector::Channel - { - public: - explicit ChannelImpl(AgentImpl& agent) - : agent_(agent) - { - } - virtual ~ChannelImpl() {} - - private: - void sendResponse( - int /*callId*/, - std::unique_ptr message) override - { - sendMessageToFrontend(std::move(message)); - } - - void sendNotification( - std::unique_ptr message) override - { - sendMessageToFrontend(std::move(message)); - } - - void flushProtocolNotifications() override {} - - void sendMessageToFrontend( - std::unique_ptr message) - { - agent_.Write(agent_.session_id_, std::move(message)); - } - - AgentImpl& agent_; - }; - - using V8Inspector = v8_inspector::V8Inspector; - - class V8NodeInspector : public v8_inspector::V8InspectorClient - { - public: - V8NodeInspector(AgentImpl& agent) - : agent_(agent) - , waiting_for_resume_(false) - , running_nested_loop_(false) - , inspector_(V8Inspector::create(agent.isolate_, this)) - { - } - - void setupContext( - v8::Local context, - const char* context_name /*must be null terminated*/) - { - std::unique_ptr name_buffer = utils::Utf8ToStringView(context_name); - v8_inspector::V8ContextInfo info(context, 1, name_buffer->string()); - - std::unique_ptr aux_data_buffer = utils::Utf8ToStringView("{\"isDefault\":true}"); - info.auxData = aux_data_buffer->string(); - - inspector_->contextCreated(info); - } - - void runMessageLoopOnPause(int /*context_group_id*/) override - { - waiting_for_resume_ = true; - if (running_nested_loop_) - return; - running_nested_loop_ = true; - while (waiting_for_resume_) - { - agent_.WaitForFrontendMessage(); - agent_.DispatchMessages(); - } - waiting_for_resume_ = false; - running_nested_loop_ = false; - } - - double currentTimeMS() override - { - auto duration = std::chrono::system_clock::now().time_since_epoch(); - return static_cast(std::chrono::duration_cast(duration) - .count()); - } - - void quitMessageLoopOnPause() override - { - waiting_for_resume_ = false; - } - - void connectFrontend() - { - session_ = inspector_->connect( - 1, new ChannelImpl(agent_), v8_inspector::StringView()); - } - - void disconnectFrontend() - { - session_.reset(); - } - - void dispatchMessageFromFrontend(const v8_inspector::StringView& message) - { - std::string messagestr = utils::StringViewToUtf8(message); - - if (agent_.waiting_for_frontend_) - agent_.waiting_for_frontend_ = - messagestr.find("Runtime.runIfWaitingForDebugger") != - std::string::npos; - - session_->dispatchProtocolMessage(message); - } - - v8::Local ensureDefaultContextInGroup( - int /*contextGroupId*/) override - { - return v8::Isolate::GetCurrent()->GetCurrentContext(); - } - - V8Inspector* inspector() - { - return inspector_.get(); - } - - bool isWaitingForResume() - { - return waiting_for_resume_; - } - - std::unique_ptr session_; - - private: - AgentImpl& agent_; - v8::Platform* platform_; - std::atomic waiting_for_resume_{false}; - bool running_nested_loop_; - std::unique_ptr inspector_; - }; - - AgentImpl::AgentImpl( - v8::Platform& platform, - v8::Isolate* isolate, - v8::Local context, - const char* context_name) - : platform_(platform) - , isolate_(isolate) - , wait_(false) - , shutting_down_(false) - , state_(State::kNew) - , inspector_(nullptr) - , dispatching_messages_(false) - , session_id_(0) - , server_(nullptr) - { - inspector_ = std::make_unique(*this); - inspector_->setupContext(context, context_name); - } - - AgentImpl::~AgentImpl() {} - - void InspectorConsoleCall(const v8::FunctionCallbackInfo& info) - { - v8::Isolate* isolate = info.GetIsolate(); - v8::Local context = isolate->GetCurrentContext(); - - v8::Local args = info.Data().As(); - CHECK_EQ(args->Length(), 3); - - v8::Local inspector_method = - args->Get(context, 0).ToLocalChecked(); - CHECK(inspector_method->IsFunction()); - v8::Local node_method = args->Get(context, 1).ToLocalChecked(); - CHECK(node_method->IsFunction()); - v8::Local config_value = args->Get(context, 2).ToLocalChecked(); - CHECK(config_value->IsObject()); - v8::Local config_object = config_value.As(); - - std::vector> call_args(info.Length()); - for (int i = 0; i < info.Length(); ++i) - { - call_args[i] = info[i]; - } - - v8::Local in_call_key = utils::OneByteString(isolate, "in_call"); - bool in_call = config_object->Has(context, in_call_key).FromMaybe(false); - if (!in_call) - { - CHECK( - config_object->Set(context, in_call_key, v8::True(isolate)).FromJust()); - CHECK( - !inspector_method.As() - ->Call(context, info.Holder(), static_cast(call_args.size()), call_args.data()) - .IsEmpty()); - } - - v8::TryCatch try_catch(info.GetIsolate()); - static_cast(node_method.As()->Call( - context, info.Holder(), static_cast(call_args.size()), call_args.data())); - CHECK(config_object->Delete(context, in_call_key).FromJust()); - if (try_catch.HasCaught()) - try_catch.ReThrow(); - } - - void InspectorWrapConsoleCall(const v8::FunctionCallbackInfo& args) - { - - v8::Local array = - v8::Array::New(v8::Isolate::GetCurrent(), args.Length()); - CHECK(array->Set(v8::Isolate::GetCurrent()->GetCurrentContext(), 0, args[0]) - .FromJust()); - CHECK(array->Set(v8::Isolate::GetCurrent()->GetCurrentContext(), 1, args[1]) - .FromJust()); - CHECK(array->Set(v8::Isolate::GetCurrent()->GetCurrentContext(), 2, args[2]) - .FromJust()); - args.GetReturnValue().Set(v8::Function::New( - v8::Isolate::GetCurrent()->GetCurrentContext(), - InspectorConsoleCall, - array) - .ToLocalChecked()); - } - - void AgentImpl::Start(const unsigned short port, const std::string& appName) - { - this->port_ = port; - this->script_name_ = appName; - - auto self(shared_from_this()); - std::thread([this, self]() { - auto delegate = std::make_unique(*this, "", script_name_, wait_); - server_ = std::make_unique(std::move(delegate), port_); - - state_ = State::kAccepting; - - // This loops - if (!server_->Start()) - { - std::abort(); - } - - server_->Stop(); - - server_.reset(); - }) - .detach(); - } - - void AgentImpl::waitForDebugger() - { - WaitForFrontendMessage(); - - if (state_ == State::kError) - { - Stop(); - } - state_ = State::kAccepting; - - while (waiting_for_frontend_) - DispatchMessages(); - - std::string reasonstr("Break on start"); - v8_inspector::StringView reason( - reinterpret_cast(reasonstr.c_str()), reasonstr.size()), - details( - reinterpret_cast(reasonstr.c_str()), - reasonstr.size()); - inspector_->session_->schedulePauseOnNextStatement(reason, details); - } - - void AgentImpl::Stop() - { - if (server_) - { - server_->Stop(); - inspector_.reset(); - server_.reset(); - } - } - - bool AgentImpl::IsConnected() - { - return server_ && server_->IsConnected(); - } - - bool AgentImpl::IsStarted() - { - return !!server_; - } - - void AgentImpl::WaitForDisconnect() - { - if (state_ == State::kConnected) - { - shutting_down_ = true; - // Gives a signal to stop accepting new connections - // TODO(eugeneo): Introduce an API with explicit request names. - Write(0, v8_inspector::StringBuffer::create((v8_inspector::StringView()))); - fprintf(stderr, "Waiting for the debugger to disconnect...\n"); - fflush(stderr); - inspector_->runMessageLoopOnPause(0); - } - } - - std::unique_ptr ToProtocolString( - v8::Local value) - { - if (value.IsEmpty() || value->IsNull() || value->IsUndefined() || - !value->IsString()) - { - return v8_inspector::StringBuffer::create(v8_inspector::StringView()); - } - v8::Local string_value = v8::Local::Cast(value); - int len = string_value->Length(); - std::basic_string buffer(len, '\0'); - string_value->Write(v8::Isolate::GetCurrent(), &buffer[0], 0, len); - return v8_inspector::StringBuffer::create( - v8_inspector::StringView(buffer.data(), len)); - } - - void AgentImpl::FatalException( - v8::Local error, - v8::Local message) - { - if (!IsStarted()) - return; - v8::Local context = - v8::Isolate::GetCurrent()->GetCurrentContext(); - - int script_id = static_cast(message->GetScriptOrigin().ScriptID()->Value()); - - v8::Local stack_trace = message->GetStackTrace(); - - if (!stack_trace.IsEmpty() && stack_trace->GetFrameCount() > 0 && - script_id == - stack_trace->GetFrame(v8::Isolate::GetCurrent(), 0)->GetScriptId()) - { - script_id = 0; - } - - const uint8_t DETAILS[] = "Uncaught"; - - inspector_->inspector()->exceptionThrown( - context, - v8_inspector::StringView(DETAILS, sizeof(DETAILS) - 1), - error, - ToProtocolString(message->Get())->string(), - ToProtocolString(message->GetScriptResourceName())->string(), - message->GetLineNumber(context).FromMaybe(0), - message->GetStartColumn(context).FromMaybe(0), - inspector_->inspector()->createStackTrace(stack_trace), - script_id); - WaitForDisconnect(); - } - - bool AgentImpl::AppendMessage( - MessageQueue* queue, - int session_id, - std::unique_ptr buffer) - { - std::unique_lock lock(state_m); - bool trigger_pumping = queue->empty(); - queue->push_back(std::make_pair(session_id, std::move(buffer))); - return trigger_pumping; - } - - void AgentImpl::SwapBehindLock(MessageQueue* vector1, MessageQueue* vector2) - { - std::unique_lock lock(state_m); - vector1->swap(*vector2); - } - - void AgentImpl::PostIncomingMessage( - int session_id, - const std::string& message) - { - if (AppendMessage(&incoming_message_queue_, session_id, utils::Utf8ToStringView(message))) - { - std::shared_ptr foregroundTaskRunner; - -#ifdef USE_DEFAULT_PLATFORM - // Need to get the foreground runner from the isolate data slot - v8runtime::IsolateData* isolate_data = reinterpret_cast(isolate_->GetData(v8runtime::ISOLATE_DATA_SLOT)); - foregroundTaskRunner = isolate_data->foreground_task_runner_; -#else - foregroundTaskRunner = platform_.GetForegroundTaskRunner(isolate_); -#endif - foregroundTaskRunner->PostTask(std::make_unique(*this)); - isolate_->RequestInterrupt(InterruptCallback, this); - } - NotifyMessageReceived(); - } - - void AgentImpl::WaitForFrontendMessage() - { - std::unique_lock lock(incoming_message_cond_m_); - if (incoming_message_queue_.empty()) - incoming_message_cond_.wait( - lock, [this] { return !incoming_message_queue_.empty(); }); - } - - void AgentImpl::NotifyMessageReceived() - { - incoming_message_cond_.notify_all(); - } - - void AgentImpl::DispatchMessages() - { - // This function can be reentered if there was an incoming message while - // V8 was processing another inspector request (e.g. if the user is - // evaluating a long-running JS code snippet). This can happen only at - // specific points (e.g. the lines that call inspector_ methods) - if (dispatching_messages_) - return; - dispatching_messages_ = true; - MessageQueue tasks; - do - { - tasks.clear(); - SwapBehindLock(&incoming_message_queue_, &tasks); - for (const MessageQueue::value_type& pair : tasks) - { - v8_inspector::StringView message = pair.second->string(); - std::string tag; - if (message.length() == sizeof(TAG_CONNECT) - 1 || - message.length() == sizeof(TAG_DISCONNECT) - 1) - { - tag = utils::StringViewToUtf8(message); - } - - if (tag == TAG_CONNECT) - { - CHECK_EQ(State::kAccepting, state_); - session_id_ = pair.first; - state_ = State::kConnected; - inspector_->connectFrontend(); - } - else if (tag == TAG_DISCONNECT) - { - CHECK_EQ(State::kConnected, state_); - if (shutting_down_) - { - state_ = State::kDone; - } - else - { - state_ = State::kAccepting; - } - - inspector_->quitMessageLoopOnPause(); - inspector_->disconnectFrontend(); - } - else if (inspector_) - { - inspector_->dispatchMessageFromFrontend(message); - } - else - { -#ifdef WIN32 - OutputDebugStringW(L"Warning: V8 inspector message dropped - "); - if (message.is8Bit()) - { - OutputDebugStringA(reinterpret_cast(message.characters8())); - } - else - { - OutputDebugStringW(reinterpret_cast(message.characters16())); - } - OutputDebugStringW(L"\n"); -#endif - } - } - } while (!tasks.empty()); - dispatching_messages_ = false; - } - - void AgentImpl::Write( - int session_id, - std::unique_ptr inspector_message) - { - AppendMessage( - &outgoing_message_queue_, session_id, std::move(inspector_message)); - - MessageQueue outgoing_messages; - SwapBehindLock(&outgoing_message_queue_, &outgoing_messages); - for (const MessageQueue::value_type& outgoing : outgoing_messages) - { - v8_inspector::StringView view = outgoing.second->string(); - assert(server_); - if (server_) - { - if (view.length() == 0) - { - server_->Stop(); - } - else - { - server_->Send( - outgoing.first, utils::StringViewToUtf8(outgoing.second->string())); - } - } - } - } - - // Exported class Agent - V8InspectorAgent::V8InspectorAgent( - v8::Platform& platform, - v8::Isolate* isolate, - v8::Local context, - const char* context_name) - : impl(std::make_shared(platform, isolate, context, context_name)) - { - } - - V8InspectorAgent::~V8InspectorAgent() - { - } - - void V8InspectorAgent::waitForDebugger() - { - impl->waitForDebugger(); - } - - void V8InspectorAgent::stop() - { - impl->Stop(); - } - - void V8InspectorAgent::start(const unsigned short port, const std::string& appName) - { - impl->Start(port, appName); - } - - bool V8InspectorAgent::IsStarted() - { - return impl->IsStarted(); - } - - bool V8InspectorAgent::IsConnected() - { - return impl->IsConnected(); - } - - void V8InspectorAgent::WaitForDisconnect() - { - impl->WaitForDisconnect(); - } - - void V8InspectorAgent::FatalException( - v8::Local error, - v8::Local message) - { - impl->FatalException(error, message); - } - - InspectorAgentDelegate::InspectorAgentDelegate( - AgentImpl& agent, - const std::string& script_path, - const std::string& script_name, - bool wait) - : agent_(agent) - , connected_(false) - , session_id_(0) - , script_name_(script_name) - , script_path_(script_path) - , target_id_(utils::GenerateUniqueID()) - , waiting_(wait) - { - } - - void InspectorAgentDelegate::StartSession( - int session_id, - const std::string& /*target_id*/) - { - connected_ = true; - agent_.PostIncomingMessage(session_id, TAG_CONNECT); - } - - void InspectorAgentDelegate::MessageReceived( - int session_id, - const std::string& message) - { - // TODO(pfeldman): Instead of blocking execution while debugger - // engages, node should wait for the run callback from the remote client - // and initiate its startup. This is a change to node.cc that should be - // upstreamed separately. - if (waiting_) - { - if (message.find("\"Runtime.runIfWaitingForDebugger\"") != - std::string::npos) - { - waiting_ = false; - agent_.ResumeStartup(); - } - } - agent_.PostIncomingMessage(session_id, message); - } - - void InspectorAgentDelegate::EndSession(int session_id) - { - connected_ = false; - agent_.PostIncomingMessage(session_id, TAG_DISCONNECT); - } - - std::vector InspectorAgentDelegate::GetTargetIds() - { - return {target_id_}; - } - - std::string InspectorAgentDelegate::GetTargetTitle(const std::string& /*id*/) - { - return script_name_.empty() ? GetProcessTitle() : script_name_; - } - - std::string InspectorAgentDelegate::GetTargetUrl(const std::string& /*id*/) - { - return "file://" + script_path_; - } - -} // namespace inspector \ No newline at end of file diff --git a/Dependencies/v8inspector/Source/V8InspectorClient.cpp b/Dependencies/v8inspector/Source/V8InspectorClient.cpp deleted file mode 100644 index 3efdc3894..000000000 --- a/Dependencies/v8inspector/Source/V8InspectorClient.cpp +++ /dev/null @@ -1,82 +0,0 @@ -#include "V8InspectorClient.h" -#include "V8InspectorUtils.h" - -#include - -namespace Babylon -{ - V8NodeInspector::V8NodeInspector(AgentImpl& agent) - : agent_(agent) - , waiting_for_resume_(false) - , running_nested_loop_(false) - , inspector_(v8_inspector::V8Inspector::create(agent.isolate_, this)) - { - } - - void V8NodeInspector::setupContext( - v8::Local context, - const char* context_name /*must be null terminated*/) - { - std::unique_ptr name_buffer = utils::Utf8ToStringView(context_name); - v8_inspector::V8ContextInfo info(context, 1, name_buffer->string()); - - std::unique_ptr aux_data_buffer = utils::Utf8ToStringView("{\"isDefault\":true}"); - info.auxData = aux_data_buffer->string(); - - inspector_->contextCreated(info); - } - - void V8NodeInspector::runMessageLoopOnPause(int /*context_group_id*/) override - { - waiting_for_resume_ = true; - if (running_nested_loop_) - return; - running_nested_loop_ = true; - while (waiting_for_resume_) - { - agent_.WaitForFrontendMessage(); - agent_.DispatchMessages(); - } - waiting_for_resume_ = false; - running_nested_loop_ = false; - } - - double V8NodeInspector::currentTimeMS() override - { - auto duration = std::chrono::system_clock::now().time_since_epoch(); - return static_cast(std::chrono::duration_cast(duration).count()); - } - - void V8NodeInspector::quitMessageLoopOnPause() override - { - waiting_for_resume_ = false; - } - - void V8NodeInspector::connectFrontend() - { - session_ = inspector_->connect( - 1, new ChannelImpl(agent_), v8_inspector::StringView()); - } - - void V8NodeInspector::disconnectFrontend() - { - session_.reset(); - } - - void V8NodeInspector::dispatchMessageFromFrontend(const v8_inspector::StringView& message) - { - std::string messagestr = utils::StringViewToUtf8(message); - - if (agent_.waiting_for_frontend_) - agent_.waiting_for_frontend_ = - messagestr.find("Runtime.runIfWaitingForDebugger") != - std::string::npos; - - session_->dispatchProtocolMessage(message); - } - - v8::Local V8NodeInspector::ensureDefaultContextInGroup(int /*contextGroupId*/) override - { - return v8::Isolate::GetCurrent()->GetCurrentContext(); - } -} \ No newline at end of file diff --git a/Dependencies/v8inspector/Source/V8InspectorClient.h b/Dependencies/v8inspector/Source/V8InspectorClient.h deleted file mode 100644 index 47dad4bb1..000000000 --- a/Dependencies/v8inspector/Source/V8InspectorClient.h +++ /dev/null @@ -1,49 +0,0 @@ -#pragma once - -#include - -namespace Babylon -{ - class AgentImpl; - - class V8NodeInspector : public v8_inspector::V8InspectorClient - { - public: - V8NodeInspector(AgentImpl& agent); - - void setupContext(v8::Local context, const char* context_name /*must be null terminated*/); - - void runMessageLoopOnPause(int /*context_group_id*/) override; - - double currentTimeMS() override; - - void quitMessageLoopOnPause() override; - - void connectFrontend(); - - void disconnectFrontend(); - - void dispatchMessageFromFrontend(const v8_inspector::StringView& message); - - v8::Local ensureDefaultContextInGroup(int /*contextGroupId*/) override; - - inline v8_inspector::V8Inspector* inspector() const - { - return inspector_.get(); - } - - inline bool isWaitingForResume() const - { - return waiting_for_resume_; - } - - std::unique_ptr session_; - - private: - AgentImpl& agent_; - v8::Platform* platform_; - std::atomic waiting_for_resume_{ false }; - bool running_nested_loop_; - std::unique_ptr inspector_; - }; -} \ No newline at end of file diff --git a/Dependencies/v8inspector/Source/V8InspectorSocket.cpp b/Dependencies/v8inspector/Source/V8InspectorSocket.cpp deleted file mode 100644 index 715425180..000000000 --- a/Dependencies/v8inspector/Source/V8InspectorSocket.cpp +++ /dev/null @@ -1,709 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. -// This code is based on the old node inspector implementation. See NOTICE.md for Node.js' project license details -#include "V8InspectorTCP.h" -#include "V8InspectorSocket.h" -#include "V8InspectorUtils.h" - -#include -#include -#include -#include -#include - -//#include - -typedef llhttp_type_t parser_type_t; -typedef llhttp_errno_t parser_errno_t; -typedef llhttp_settings_t parser_settings_t; -typedef llhttp_t parser_t; - -// The helper is for doing safe downcasts from base types to derived types. -template -class ContainerOfHelper { -public: - inline ContainerOfHelper(Inner Outer::*field, Inner* pointer); - template - inline operator TypeName*() const; -private: - Outer* const pointer_; -}; - -template -constexpr uintptr_t OffsetOf(Inner Outer::*field) { - return reinterpret_cast(&(static_cast(0)->*field)); -} - -template -ContainerOfHelper::ContainerOfHelper(Inner Outer::*field, - Inner* pointer) - : pointer_( - reinterpret_cast( - reinterpret_cast(pointer) - OffsetOf(field))) {} - -template -template -ContainerOfHelper::operator TypeName*() const { - return static_cast(pointer_); -} - -template -constexpr ContainerOfHelper ContainerOf(Inner Outer::*field, - Inner* pointer) { - return ContainerOfHelper(field, pointer); -} - -#include -#include - -#define ACCEPT_KEY_LENGTH Babylon::utils::base64_encoded_size(20) -#define BUFFER_GROWTH_CHUNK_SIZE 1024 - -#define DUMP_READS 0 -#define DUMP_WRITES 0 - -namespace Babylon { - -class TcpHolder : public std::enable_shared_from_this { - public: - void SetHandler(ProtocolHandler* handler); - int WriteRaw(const std::vector& buffer/*, uv_write_cb write_cb*/); - - void read_loop(); - - std::shared_ptr connection() { return connection_; }; - InspectorSocket::Delegate* delegate(); - - TcpHolder(std::shared_ptr connection, std::unique_ptr delegate); - ~TcpHolder(); - - private: - static void OnDataReceivedCb(std::vector&, bool iseof, void*data); - - std::shared_ptr connection_; - - const std::unique_ptr delegate_; - ProtocolHandler* handler_; - std::vector buffer_; -}; - - -class ProtocolHandler { - public: - ProtocolHandler(InspectorSocket* inspector, std::shared_ptr&& tcp); - virtual ~ProtocolHandler() = default; - - virtual void AcceptUpgrade(const std::string& accept_key) = 0; - virtual void OnData(std::vector* data) = 0; - virtual void OnEof() = 0; - virtual void Write(const std::vector data) = 0; - virtual void CancelHandshake() = 0; - - std::string GetHost() const; - - InspectorSocket* inspector() { - return inspector_; - } - - protected: - int WriteRaw(const std::vector& buffer/*, uv_write_cb write_cb*/); - InspectorSocket::Delegate* delegate(); - - InspectorSocket* const inspector_; - std::shared_ptr tcp_; -}; - -namespace { - -#if DUMP_READS || DUMP_WRITES -static void dump_hex(const char* buf, size_t len) { - const char* ptr = buf; - const char* end = ptr + len; - const char* cptr; - char c; - int i; - - while (ptr < end) { - cptr = ptr; - for (i = 0; i < 16 && ptr < end; i++) { - printf("%2.2X ", static_cast(*(ptr++))); - } - for (i = 72 - (i * 4); i > 0; i--) { - printf(" "); - } - for (i = 0; i < 16 && cptr < end; i++) { - c = *(cptr++); - printf("%c", (c > 0x19) ? c : '.'); - } - printf("\n"); - } - printf("\n\n"); -} -#endif - -static void remove_from_beginning(std::vector* buffer, size_t count) { - buffer->erase(buffer->begin(), buffer->begin() + count); -} - -static const char CLOSE_FRAME[] = {'\x88', '\x00'}; - -enum ws_decode_result { - FRAME_OK, FRAME_INCOMPLETE, FRAME_CLOSE, FRAME_ERROR -}; - -static void generate_accept_string(const std::string& client_key, - char (*buffer)[ACCEPT_KEY_LENGTH]) { - // Magic string from websockets spec. - static const char ws_magic[] = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; - std::string input(client_key + ws_magic); - - Babylon::utils::sha1_context ctx; - init(ctx); - update(ctx, input.data(), input.size()); - char digest[Babylon::utils::sha1_context::digest_size]; - finish(ctx, &digest[0]); - - Babylon::utils::base64_encode(digest, Babylon::utils::sha1_context::digest_size, *buffer, sizeof(*buffer)); -} - -static std::string TrimPort(const std::string& host) { - size_t last_colon_pos = host.rfind(":"); - if (last_colon_pos == std::string::npos) - return host; - size_t bracket = host.rfind("]"); - if (bracket == std::string::npos || last_colon_pos > bracket) - return host.substr(0, last_colon_pos); - return host; -} - -static bool IsIPAddress(const std::string& host) { - if (host.length() >= 4 && host.front() == '[' && host.back() == ']') - return true; - int quads = 0; - for (char c : host) { - if (c == '.') - quads++; - else if (!isdigit(c)) - return false; - } - return quads == 3; -} - -// Constants for hybi-10 frame format. - -typedef unsigned char OpCode; - -const OpCode kOpCodeContinuation = 0x0; -const OpCode kOpCodeText = 0x1; -const OpCode kOpCodeBinary = 0x2; -const OpCode kOpCodeClose = 0x8; -const OpCode kOpCodePing = 0x9; -const OpCode kOpCodePong = 0xA; - -const unsigned char kFinalBit = 0x80; -const unsigned char kReserved1Bit = 0x40; -const unsigned char kReserved2Bit = 0x20; -const unsigned char kReserved3Bit = 0x10; -const unsigned char kOpCodeMask = 0xF; -const unsigned char kMaskBit = 0x80; -const unsigned char kPayloadLengthMask = 0x7F; - -const size_t kMaxSingleBytePayloadLength = 125; -const size_t kTwoBytePayloadLengthField = 126; -const size_t kEightBytePayloadLengthField = 127; -const size_t kMaskingKeyWidthInBytes = 4; - -static std::vector encode_frame_hybi17(const std::vector& message) { - std::vector frame; - OpCode op_code = kOpCodeText; - frame.push_back(kFinalBit | op_code); - const size_t data_length = message.size(); - if (data_length <= kMaxSingleBytePayloadLength) { - frame.push_back(static_cast(data_length)); - } else if (data_length <= 0xFFFF) { - frame.push_back(kTwoBytePayloadLengthField); - frame.push_back((data_length & 0xFF00) >> 8); - frame.push_back(data_length & 0xFF); - } else { - frame.push_back(kEightBytePayloadLengthField); - char extended_payload_length[8]; - size_t remaining = data_length; - // Fill the length into extended_payload_length in the network byte order. - for (int i = 0; i < 8; ++i) { - extended_payload_length[7 - i] = remaining & 0xFF; - remaining >>= 8; - } - frame.insert(frame.end(), extended_payload_length, - extended_payload_length + 8); - CHECK_EQ(0, remaining); - } - frame.insert(frame.end(), message.begin(), message.end()); - return frame; -} - -static ws_decode_result decode_frame_hybi17(const std::vector& buffer, - bool client_frame, - size_t* bytes_consumed, - std::vector* output, - bool* compressed) { - *bytes_consumed = 0; - if (buffer.size() < 2) - return FRAME_INCOMPLETE; - - auto it = buffer.begin(); - - unsigned char first_byte = *it++; - unsigned char second_byte = *it++; - - bool final = (first_byte & kFinalBit) != 0; - bool reserved1 = (first_byte & kReserved1Bit) != 0; - bool reserved2 = (first_byte & kReserved2Bit) != 0; - bool reserved3 = (first_byte & kReserved3Bit) != 0; - int op_code = first_byte & kOpCodeMask; - bool masked = (second_byte & kMaskBit) != 0; - *compressed = reserved1; - if (!final || reserved2 || reserved3) - return FRAME_ERROR; // Only compression extension is supported. - - bool closed = false; - switch (op_code) { - case kOpCodeClose: - closed = true; - break; - case kOpCodeText: - break; - case kOpCodeBinary: // We don't support binary frames yet. - case kOpCodeContinuation: // We don't support binary frames yet. - case kOpCodePing: // We don't support binary frames yet. - case kOpCodePong: // We don't support binary frames yet. - default: - return FRAME_ERROR; - } - - // In Hybi-17 spec client MUST mask its frame. - if (client_frame && !masked) { - return FRAME_ERROR; - } - - uint64_t payload_length64 = second_byte & kPayloadLengthMask; - if (payload_length64 > kMaxSingleBytePayloadLength) { - int extended_payload_length_size; - if (payload_length64 == kTwoBytePayloadLengthField) { - extended_payload_length_size = 2; - } else if (payload_length64 == kEightBytePayloadLengthField) { - extended_payload_length_size = 8; - } else { - return FRAME_ERROR; - } - if ((buffer.end() - it) < extended_payload_length_size) - return FRAME_INCOMPLETE; - payload_length64 = 0; - for (int i = 0; i < extended_payload_length_size; ++i) { - payload_length64 <<= 8; - payload_length64 |= static_cast(*it++); - } - } - - static const uint64_t max_payload_length = 0x7FFFFFFFFFFFFFFFull; - static const size_t max_length = SIZE_MAX; - if (payload_length64 > max_payload_length || - payload_length64 > max_length - kMaskingKeyWidthInBytes) { - // WebSocket frame length too large. - return FRAME_ERROR; - } - size_t payload_length = static_cast(payload_length64); - - if (buffer.size() - kMaskingKeyWidthInBytes < payload_length) - return FRAME_INCOMPLETE; - - std::vector::const_iterator masking_key = it; - std::vector::const_iterator payload = it + kMaskingKeyWidthInBytes; - for (size_t i = 0; i < payload_length; ++i) // Unmask the payload. - output->insert(output->end(), - payload[i] ^ masking_key[i % kMaskingKeyWidthInBytes]); - - size_t pos = it + kMaskingKeyWidthInBytes + payload_length - buffer.begin(); - *bytes_consumed = pos; - return closed ? FRAME_CLOSE : FRAME_OK; -} - -// WS protocol -class WsHandler : public ProtocolHandler { - public: - WsHandler(InspectorSocket* inspector, std::shared_ptr tcp) - : ProtocolHandler(inspector, std::move(tcp)), - OnCloseSent(&WsHandler::WaitForCloseReply), - OnCloseRecieved(&WsHandler::CloseFrameReceived) { } - - ~WsHandler() { - if (tcp_) { - SendClose(); - } - } - - void AcceptUpgrade(const std::string& /*accept_key*/) override { } - void CancelHandshake() override {} - - void OnEof() override { - if (tcp_) - { - tcp_.reset(); - } - } - - void OnData(std::vector* data) override { - // 1. Parse. - size_t processed = 0; - do { - processed = ParseWsFrames(*data); - // 2. Fix the data size & length - if (processed > 0) { - remove_from_beginning(data, processed); - } - } while (processed > 0 && !data->empty()); - } - - void Write(const std::vector data) override { - std::vector output = encode_frame_hybi17(data); - WriteRaw(output/*, WriteRequest::Cleanup*/); - } - - private: - using Callback = void (WsHandler::*)(void); - - static void OnCloseFrameWritten(/*uv_write_t* req, */int /*status*/) { - /*WriteRequest* wr = WriteRequest::from_write_req(req); - WsHandler* handler = static_cast(wr->handler); - delete wr;*/ - /*Callback cb = handler->OnCloseSent; - (handler->*cb)();*/ - } - - void WaitForCloseReply() { - OnCloseRecieved = &WsHandler::OnEof; - } - - void SendClose() { - WriteRaw(std::vector(CLOSE_FRAME, CLOSE_FRAME + sizeof(CLOSE_FRAME))/*, - OnCloseFrameWritten*/); - } - - void CloseFrameReceived() { - OnCloseSent = &WsHandler::OnEof; - SendClose(); - } - - size_t ParseWsFrames(const std::vector& buffer) { - size_t bytes_consumed = 0; - std::vector output; - bool compressed = false; - - ws_decode_result r = decode_frame_hybi17(buffer, - true /* client_frame */, - &bytes_consumed, &output, - &compressed); - // Compressed frame means client is ignoring the headers and misbehaves - if (compressed || r == FRAME_ERROR) { - OnEof(); - bytes_consumed = 0; - } else if (r == FRAME_CLOSE) { - (this->*OnCloseRecieved)(); - bytes_consumed = 0; - } else if (r == FRAME_OK) { - delegate()->OnWsFrame(output); - } - return bytes_consumed; - } - - - Callback OnCloseSent; - Callback OnCloseRecieved; -}; - -// HTTP protocol -class HttpEvent { - public: - HttpEvent(const std::string& path, bool upgrade, bool isGET, - const std::string& ws_key, const std::string& host) - : path(path), upgrade(upgrade), isGET(isGET), ws_key(ws_key), - host(host) { } - - std::string path; - bool upgrade; - bool isGET; - std::string ws_key; - std::string host; -}; - -class HttpHandler : public ProtocolHandler { - public: - explicit HttpHandler(InspectorSocket* inspector, std::shared_ptr&& tcp) - : ProtocolHandler(inspector, std::move(tcp)), - parsing_value_(false) { - - llhttp_init(&parser_, HTTP_REQUEST, &parser_settings); - llhttp_settings_init(&parser_settings); - parser_settings.on_header_field = OnHeaderField; - parser_settings.on_header_value = OnHeaderValue; - parser_settings.on_message_complete = OnMessageComplete; - parser_settings.on_url = OnPath; - } - - void AcceptUpgrade(const std::string& accept_key) override { - char accept_string[ACCEPT_KEY_LENGTH]; - generate_accept_string(accept_key, &accept_string); - const char accept_ws_prefix[] = "HTTP/1.1 101 Switching Protocols\r\n" - "Upgrade: websocket\r\n" - "Connection: Upgrade\r\n" - "Sec-WebSocket-Accept: "; - const char accept_ws_suffix[] = "\r\n\r\n"; - std::vector reply(accept_ws_prefix, - accept_ws_prefix + sizeof(accept_ws_prefix) - 1); - reply.insert(reply.end(), accept_string, - accept_string + sizeof(accept_string)); - reply.insert(reply.end(), accept_ws_suffix, - accept_ws_suffix + sizeof(accept_ws_suffix) - 1); - if (WriteRaw(reply/*, WriteRequest::Cleanup*/) >= 0) { - inspector_->SwitchProtocol(std::make_unique(inspector_, std::move(tcp_))); - } else { - tcp_.reset(); - } - } - - void CancelHandshake() override { - const char HANDSHAKE_FAILED_RESPONSE[] = - "HTTP/1.0 400 Bad Request\r\n" - "Content-Type: text/html; charset=UTF-8\r\n\r\n" - "WebSockets request was expected\r\n"; - WriteRaw(std::vector(HANDSHAKE_FAILED_RESPONSE, - HANDSHAKE_FAILED_RESPONSE + sizeof(HANDSHAKE_FAILED_RESPONSE) - 1)/*, - ThenCloseAndReportFailure*/); - } - - - void OnEof() override { - tcp_.reset(); - } - - void OnData(std::vector* data) override { - parser_errno_t err; - err = llhttp_execute(&parser_, data->data(), data->size()); - - if (err == HPE_PAUSED_UPGRADE) { - err = HPE_OK; - llhttp_resume_after_upgrade(&parser_); - } - data->clear(); - if (err != HPE_OK) { - CancelHandshake(); - } - // Event handling may delete *this - std::vector events; - std::swap(events, events_); - for (const HttpEvent& event : events) { - if (!IsAllowedHost(event.host) || !event.isGET) { - CancelHandshake(); - return; - } else if (!event.upgrade) { - delegate()->OnHttpGet(event.host, event.path); - } else if (event.ws_key.empty()) { - CancelHandshake(); - return; - } else { - delegate()->OnSocketUpgrade(event.host, event.path, event.ws_key); - } - } - } - - void Write(const std::vector data) override { - WriteRaw(data/*, WriteRequest::Cleanup*/); - } - - private: - static void ThenCloseAndReportFailure(/*uv_write_t* req, */int /*status*/) { - /*ProtocolHandler* handler = WriteRequest::from_write_req(req)->handler; - WriteRequest::Cleanup(req, status); - handler->inspector()->SwitchProtocol(nullptr);*/ - } - - static int OnHeaderValue(parser_t* parser, const char* at, size_t length) { - HttpHandler* handler = From(parser); - handler->parsing_value_ = true; - handler->headers_[handler->current_header_].append(at, length); - return 0; - } - - static int OnHeaderField(parser_t* parser, const char* at, size_t length) { - HttpHandler* handler = From(parser); - if (handler->parsing_value_) { - handler->parsing_value_ = false; - handler->current_header_.clear(); - } - handler->current_header_.append(at, length); - return 0; - } - - static int OnPath(parser_t* parser, const char* at, size_t length) { - HttpHandler* handler = From(parser); - handler->path_.append(at, length); - return 0; - } - - static HttpHandler* From(parser_t* parser) { - return ContainerOf(&HttpHandler::parser_, parser); - } - - static int OnMessageComplete(parser_t* parser) { - // Event needs to be fired after the parser is done. - HttpHandler* handler = From(parser); - handler->events_.push_back( - HttpEvent(handler->path_, parser->upgrade, parser->method == HTTP_GET, - handler->HeaderValue("Sec-WebSocket-Key"), - handler->HeaderValue("Host"))); - handler->path_ = ""; - handler->parsing_value_ = false; - handler->headers_.clear(); - handler->current_header_ = ""; - return 0; - } - - std::string HeaderValue(const std::string& header) const { - bool header_found = false; - std::string value; - for (const auto& header_value : headers_) { - if (utils::StringEqualNoCaseN(header_value.first.data(), header.data(), - header.length())) { - if (header_found) - return ""; - value = header_value.second; - header_found = true; - } - } - return value; - } - - bool IsAllowedHost(const std::string& host_with_port) const { - std::string host = TrimPort(host_with_port); - return host.empty() || IsIPAddress(host) - || utils::StringEqualNoCase(host.data(), "localhost") - || utils::StringEqualNoCase(host.data(), "localhost6"); - } - - bool parsing_value_; - parser_t parser_; - parser_settings_t parser_settings; - std::vector events_; - std::string current_header_; - std::map headers_; - std::string path_; -}; - -} // namespace - -// Any protocol -ProtocolHandler::ProtocolHandler(InspectorSocket* inspector, - std::shared_ptr&& tcp) - : inspector_(inspector), tcp_(std::move(tcp)) { - CHECK_NOT_NULL(tcp_); - tcp_->SetHandler(this); -} - -int ProtocolHandler::WriteRaw(const std::vector& buffer/*, - uv_write_cb write_cb*/) { - return tcp_->WriteRaw(buffer/*, write_cb*/); -} - -InspectorSocket::Delegate* ProtocolHandler::delegate() { - return tcp_->delegate(); -} - -std::string ProtocolHandler::GetHost() const { - // TBD - return ""; -} - -// RAII uv_tcp_t wrapper -TcpHolder::TcpHolder(std::shared_ptr connection, std::unique_ptr delegate) - : delegate_(std::move(delegate)), - connection_(connection), handler_(nullptr) { - connection_->registerReadCallback(TcpHolder::OnDataReceivedCb, this); - connection_->read_loop_async(); -} - -TcpHolder::~TcpHolder() { - connection_->close(); -} - -void TcpHolder::read_loop() { - connection_->read_loop_async(); -} - -void TcpHolder::SetHandler(ProtocolHandler* handler) { - handler_ = handler; -} - -int TcpHolder::WriteRaw(const std::vector& buffer/*, uv_write_cb write_cb*/) { -#if DUMP_WRITES - printf("%s (%ld bytes):\n", __FUNCTION__, buffer.size()); - dump_hex(buffer.data(), buffer.size()); - printf("\n"); -#endif - - // Freed in write_request_cleanup - /*WriteRequest* wr = new WriteRequest(handler_, buffer); - uv_stream_t* stream = reinterpret_cast(&tcp_); - int err = uv_write(&wr->req, stream, &wr->buf, 1, write_cb); - if (err < 0) - delete wr; - return err < 0;*/ - connection_->write_async(buffer); - return 0; -} - -InspectorSocket::Delegate* TcpHolder::delegate() { - return delegate_.get(); -} - -void TcpHolder::OnDataReceivedCb(std::vector& wiredata, bool iseof, void*data) { - TcpHolder* holder = reinterpret_cast(data); - - if (iseof) { - holder->handler_->OnEof(); - } - else { - holder->handler_->OnData(&wiredata); - } -} - -InspectorSocket::~InspectorSocket() = default; - -// static -std::unique_ptr InspectorSocket::Accept(std::shared_ptr connection, std::unique_ptr&& delegate) { - auto tcp = std::make_shared(std::move(connection), std::move(delegate)); - - auto inspector = std::make_unique(); - inspector->SwitchProtocol(std::make_unique(inspector.get(), std::move(tcp))); - return inspector; -} - -void InspectorSocket::AcceptUpgrade(const std::string& ws_key) { - protocol_handler_->AcceptUpgrade(ws_key); -} - -void InspectorSocket::CancelHandshake() { - protocol_handler_->CancelHandshake(); -} - -std::string InspectorSocket::GetHost() { - return protocol_handler_->GetHost(); -} - -void InspectorSocket::SwitchProtocol(std::unique_ptr&& handler) { - protocol_handler_ = std::move(handler); -} - -void InspectorSocket::Write(const char* data, size_t len) { - protocol_handler_->Write(std::vector(data, data + len)); -} - -} // namespace inspector \ No newline at end of file diff --git a/Dependencies/v8inspector/Source/V8InspectorSocket.h b/Dependencies/v8inspector/Source/V8InspectorSocket.h deleted file mode 100644 index 075e7b296..000000000 --- a/Dependencies/v8inspector/Source/V8InspectorSocket.h +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. -// This code is based on the old node inspector implementation. See NOTICE.md for Node.js' project license details -#pragma once - -#include -#include -#include - -#include "V8InspectorTCP.h" - -namespace Babylon { - -class ProtocolHandler; - -// HTTP Wrapper around a uv_tcp_t -class InspectorSocket { - public: - InspectorSocket() = default; - ~InspectorSocket(); - - class Delegate { - public: - virtual void OnHttpGet(const std::string& host, - const std::string& path) = 0; - virtual void OnSocketUpgrade(const std::string& host, - const std::string& path, - const std::string& accept_key) = 0; - virtual void OnWsFrame(const std::vector& frame) = 0; - virtual ~Delegate() {} - }; - - static std::unique_ptr Accept(std::shared_ptr connection, std::unique_ptr&& delegate); - - void AcceptUpgrade(const std::string& accept_key); - void CancelHandshake(); - void Write(const char* data, size_t len); - void SwitchProtocol(std::unique_ptr&& handler); - std::string GetHost(); - - private: - std::unique_ptr protocol_handler_; - - InspectorSocket(const InspectorSocket&) = delete; - InspectorSocket& operator=(const InspectorSocket&) = delete; -}; - -} // namespace inspector \ No newline at end of file diff --git a/Dependencies/v8inspector/Source/V8InspectorSocketServer.cpp b/Dependencies/v8inspector/Source/V8InspectorSocketServer.cpp deleted file mode 100644 index a7f93feed..000000000 --- a/Dependencies/v8inspector/Source/V8InspectorSocketServer.cpp +++ /dev/null @@ -1,479 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. -// This code is based on the old node inspector implementation. See NOTICE.md for Node.js' project license details -#include "V8InspectorSocketServer.h" -#include "V8InspectorTCP.h" -#include "V8InspectorUtils.h" - -#include -#include -#include -#include - -namespace Babylon -{ - - namespace - { - - // We don't support protocol http end point. - static const uint8_t PROTOCOL_JSON[] = {0}; - // #include "v8_inspector_protocol_json.h" // NOLINT(build/include_order) - //}; - - void Escape(std::string* string) - { - for (char& c : *string) - { - c = (c == '\"' || c == '\\') ? '_' : c; - } - } - - std::string FormatWsAddress(const std::string& /*host*/, int /*port*/, - const std::string& /*target_id*/, - bool /*include_protocol*/) - { - // return FormatAddress(FormatHostPort(host, port), target_id, include_protocol); - return "formatted address!!"; - } - - std::string FormatHostPort(const std::string& host, int port) - { - // Host is valid (socket was bound) so colon means it's a v6 IP address - bool v6 = host.find(':') != std::string::npos; - std::ostringstream url; - if (v6) - { - url << '['; - } - url << host; - if (v6) - { - url << ']'; - } - url << ':' << port; - return url.str(); - } - - std::string FormatAddress(const std::string& host, - const std::string& target_id, - bool include_protocol) - { - std::ostringstream url; - if (include_protocol) - url << "ws://"; - url << host << '/' << target_id; - return url.str(); - } - - std::string MapToString(const std::map& object) - { - bool first = true; - std::ostringstream json; - json << "{\n"; - for (const auto& name_value : object) - { - if (!first) - json << ",\n"; - first = false; - json << " \"" << name_value.first << "\": \""; - json << name_value.second << "\""; - } - json << "\n} "; - return json.str(); - } - - std::string MapsToString( - const std::vector>& array) - { - bool first = true; - std::ostringstream json; - json << "[ "; - for (const auto& object : array) - { - if (!first) - json << ", "; - first = false; - json << MapToString(object); - } - json << "]\n\n"; - return json.str(); - } - - const char* MatchPathSegment(const char* path, const char* expected) - { - size_t len = strlen(expected); - if (utils::StringEqualNoCaseN(path, expected, len)) - { - if (path[len] == '/') - return path + len + 1; - if (path[len] == '\0') - return path + len; - } - return nullptr; - } - - void PrintDebuggerReadyMessage(const std::string& host, - int port, - const std::vector& ids, - FILE* out) - { - if (out == nullptr) - { - return; - } - for (const std::string& id : ids) - { - fprintf(out, "Debugger listening on %s\n", - FormatWsAddress(host, port, id, true).c_str()); - } - fprintf(out, "For help, see: %s\n", - "https://nodejs.org/en/docs/inspector"); - fflush(out); - } - - void SendHttpResponse(InspectorSocket* socket, const std::string& response) - { - const char HEADERS[] = "HTTP/1.0 200 OK\r\n" - "Content-Type: application/json; charset=UTF-8\r\n" - "Cache-Control: no-cache\r\n" - "Content-Length: %zu\r\n" - "\r\n"; - char header[sizeof(HEADERS) + 20]; - int header_len = snprintf(header, sizeof(header), HEADERS, response.size()); - socket->Write(header, header_len); - socket->Write(response.data(), response.size()); - } - - void SendVersionResponse(InspectorSocket* socket) - { - std::map response; - response["Browser"] = "node.js v12.0.0"; - response["Protocol-Version"] = "1.1"; - SendHttpResponse(socket, MapToString(response)); - } - - void SendProtocolJson(InspectorSocket* socket) - { - SendHttpResponse(socket, "TBD"); - } - } // namespace - - class SocketSession - { - public: - SocketSession(InspectorSocketServer* server, int id, int server_port); - void Close() - { - ws_socket_.reset(); - } - void Send(const std::string& message); - void Own(std::unique_ptr ws_socket) - { - ws_socket_ = std::move(ws_socket); - } - int id() const { return id_; } - int server_port() - { - return server_port_; - } - InspectorSocket* ws_socket() - { - return ws_socket_.get(); - } - void Accept(const std::string& ws_key) - { - ws_socket_->AcceptUpgrade(ws_key); - } - void Decline() - { - ws_socket_->CancelHandshake(); - } - - class Delegate : public InspectorSocket::Delegate - { - public: - Delegate(InspectorSocketServer* server, int session_id) - : server_(server) - , session_id_(session_id) - { - } - ~Delegate() - { - server_->SessionTerminated(session_id_); - } - void OnHttpGet(const std::string& host, const std::string& path) override; - void OnSocketUpgrade(const std::string& host, const std::string& path, - const std::string& ws_key) override; - void OnWsFrame(const std::vector& data) override; - - private: - SocketSession* Session() - { - return server_->Session(session_id_); - } - - InspectorSocketServer* server_; - int session_id_; - }; - - private: - const int id_; - std::unique_ptr ws_socket_; - const int server_port_; - }; - - InspectorSocketServer::InspectorSocketServer( - std::unique_ptr&& delegate, unsigned short port, FILE* out) - : delegate_(std::move(delegate)) - , port_(port) - , next_session_id_(0) - , out_(out) - { - state_ = ServerState::kNew; - } - - InspectorSocketServer::~InspectorSocketServer() = default; - - SocketSession* InspectorSocketServer::Session(int session_id) - { - auto it = connected_sessions_.find(session_id); - return it == connected_sessions_.end() ? nullptr : it->second.second.get(); - } - - void InspectorSocketServer::SessionStarted(int session_id, - const std::string& id, - const std::string& ws_key) - { - SocketSession* session = Session(session_id); - - //TODODO - //if (!TargetExists(id)) { - // session->Decline(); - // return; - // } - - //TODODO - // if (connected_session_) std::abort(); - //connected_session_.reset(session); - connected_sessions_[session_id].first = id; - session->Accept(ws_key); - delegate_->StartSession(session_id, id); - } - - void InspectorSocketServer::SessionTerminated(int session_id) - { - if (Session(session_id) == nullptr) - { - return; - } - bool was_attached = connected_sessions_[session_id].first != ""; - // bool was_attached = connected_session_ != nullptr; - if (was_attached) - { - delegate_->EndSession(session_id); - } - connected_sessions_.erase(session_id); - if (connected_sessions_.empty()) - { - if (was_attached && state_ == ServerState::kRunning) - { - } - if (state_ == ServerState::kStopped) - { - delegate_.reset(); - } - } - } - - bool InspectorSocketServer::HandleGetRequest(int session_id, - const std::string& host, - const std::string& path) - { - SocketSession* session = Session(session_id); - InspectorSocket* socket = session->ws_socket(); - const char* command = MatchPathSegment(path.c_str(), "/json"); - if (command == nullptr) - return false; - - if (MatchPathSegment(command, "list") || command[0] == '\0') - { - SendListResponse(socket, host, session); - return true; - } - else if (MatchPathSegment(command, "protocol")) - { - SendProtocolJson(socket); - return true; - } - else if (MatchPathSegment(command, "version")) - { - SendVersionResponse(socket); - return true; - } - return false; - } - - void InspectorSocketServer::SendListResponse(InspectorSocket* socket, - const std::string& host, - SocketSession* session) - { - std::vector> response; - for (const std::string& id : delegate_->GetTargetIds()) - { - response.push_back(std::map()); - std::map& target_map = response.back(); - target_map["description"] = "node.js instance"; - target_map["faviconUrl"] = "https://nodejs.org/static/favicon.ico"; - target_map["id"] = id; - target_map["title"] = delegate_->GetTargetTitle(id); - Escape(&target_map["title"]); - target_map["type"] = "node"; - // This attribute value is a "best effort" URL that is passed as a JSON - // string. It is not guaranteed to resolve to a valid resource. - target_map["url"] = delegate_->GetTargetUrl(id); - Escape(&target_map["url"]); - - std::string detected_host = host; - if (detected_host.empty()) - { - detected_host = FormatHostPort(socket->GetHost(), - session->server_port()); - } - std::string formatted_address = FormatAddress(detected_host, id, false); - target_map["devtoolsFrontendUrl"] = GetFrontendURL(false, - formatted_address); - // The compat URL is for Chrome browsers older than 66.0.3345.0 - target_map["devtoolsFrontendUrlCompat"] = GetFrontendURL(true, - formatted_address); - target_map["webSocketDebuggerUrl"] = FormatAddress(detected_host, id, true); - } - SendHttpResponse(socket, MapsToString(response)); - } - - std::string InspectorSocketServer::GetFrontendURL(bool is_compat, - const std::string& formatted_address) - { - std::ostringstream frontend_url; - frontend_url << "chrome-devtools://devtools/bundled/"; - frontend_url << (is_compat ? "inspector" : "js_app"); - frontend_url << ".html?experiments=true&v8only=true&ws="; - frontend_url << formatted_address; - return frontend_url.str(); - } - - /*static */ void InspectorSocketServer::SocketConnectedCallback(std::shared_ptr connection, void* callbackData_) - { - InspectorSocketServer* server = reinterpret_cast(callbackData_); - server->Accept(connection, server->port_); - } - - /*static */ void InspectorSocketServer::SocketClosedCallback(void* callbackData_) - { - InspectorSocketServer* server = reinterpret_cast(callbackData_); - server->Stop(); - } - - bool InspectorSocketServer::Start() - { - tcp_server_ = std::make_shared(port_, InspectorSocketServer::SocketConnectedCallback, this); - state_ = ServerState::kRunning; - tcp_server_->run(); - return true; - } - - void InspectorSocketServer::Stop() - { - if (state_ == ServerState::kStopped) - return; - CHECK_EQ(state_, ServerState::kRunning); - - state_ = ServerState::kStopped; - - tcp_server_->stop(); - - if (state_ == ServerState::kStopped) - { - delegate_.reset(); - } - } - - void InspectorSocketServer::TerminateConnections() - { - for (const auto& key_value : connected_sessions_) - key_value.second.second->Close(); - } - - bool InspectorSocketServer::TargetExists(const std::string& id) - { - const std::vector& target_ids = delegate_->GetTargetIds(); - const auto& found = std::find(target_ids.begin(), target_ids.end(), id); - return found != target_ids.end(); - } - - int InspectorSocketServer::Port() const - { - // return socket_->port(); - return port_; - } - - void InspectorSocketServer::Accept(std::shared_ptr connection, int server_port) - { - std::unique_ptr session( - new SocketSession(this, next_session_id_++, server_port)); - - auto delegate = std::make_unique(this, session->id()); - - std::unique_ptr inspector = - InspectorSocket::Accept(connection, std::move(delegate)); - if (inspector) - { - session->Own(std::move(inspector)); - connected_sessions_[session->id()].second = std::move(session); - } - } - - void InspectorSocketServer::Send(int session_id, const std::string& message) - { - SocketSession* session = Session(session_id); - if (session != nullptr) - { - session->Send(message); - } - } - - // InspectorSession tracking - SocketSession::SocketSession(InspectorSocketServer* /*server*/, int id, - int server_port) - : id_(id) - , server_port_(server_port) - { - } - - void SocketSession::Send(const std::string& message) - { - ws_socket_->Write(message.data(), message.length()); - } - - void SocketSession::Delegate::OnHttpGet(const std::string& host, - const std::string& path) - { - if (!server_->HandleGetRequest(session_id_, host, path)) - Session()->ws_socket()->CancelHandshake(); - } - - void SocketSession::Delegate::OnSocketUpgrade(const std::string& /*host*/, - const std::string& path, - const std::string& ws_key) - { - std::string id = path.empty() ? path : path.substr(1); - server_->SessionStarted(session_id_, id, ws_key); - } - - void SocketSession::Delegate::OnWsFrame(const std::vector& data) - { - server_->MessageReceived(session_id_, - std::string(data.data(), data.size())); - } - -} // namespace inspector \ No newline at end of file diff --git a/Dependencies/v8inspector/Source/V8InspectorSocketServer.h b/Dependencies/v8inspector/Source/V8InspectorSocketServer.h deleted file mode 100644 index feeb90778..000000000 --- a/Dependencies/v8inspector/Source/V8InspectorSocketServer.h +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. -// This code is based on the old node inspector implementation. See NOTICE.md for Node.js' project license details -#pragma once - -#include "V8InspectorAgent.h" -#include "V8InspectorSocket.h" - -#include -#include -#include - -namespace Babylon -{ - - class InspectorSocketServer; - class SocketSession; - class ServerSocket; - - class InspectorAgentDelegate - { - public: - InspectorAgentDelegate( - AgentImpl& agent, - const std::string& script_path, - const std::string& script_name, - bool wait); - void StartSession(int session_id, const std::string& target_id); - void MessageReceived(int session_id, const std::string& message); - void EndSession(int session_id); - std::vector GetTargetIds(); - std::string GetTargetTitle(const std::string& id); - std::string GetTargetUrl(const std::string& id); - bool IsConnected() - { - return connected_; - } - - private: - AgentImpl& agent_; - bool connected_; - int session_id_; - const std::string script_name_; - const std::string script_path_; - const std::string target_id_; - bool waiting_; - }; - - // HTTP Server, writes messages requested as TransportActions, and responds - // to HTTP requests and WS upgrades. - - class InspectorSocketServer - { - public: - InspectorSocketServer(std::unique_ptr&& delegate, unsigned short port, - FILE* out = stderr); - ~InspectorSocketServer(); - - // Start listening on host/port - bool Start(); - - void Stop(); - void Send(int session_id, const std::string& message); - void TerminateConnections(); - int Port() const; - - // Session connection lifecycle - void Accept(std::shared_ptr connection, int server_port /*, uv_stream_t* server_socket*/); - bool HandleGetRequest(int session_id, const std::string& host, const std::string& path); - void SessionStarted(int session_id, const std::string& target_id, const std::string& ws_id); - void SessionTerminated(int session_id); - void MessageReceived(int session_id, const std::string& message) - { - delegate_->MessageReceived(session_id, message); - } - bool IsConnected() - { - return delegate_->IsConnected(); - } - SocketSession* Session(int session_id); - //bool done() const { - // return server_sockets_.empty() && connected_sessions_.empty(); - //} - - static void SocketConnectedCallback(std::shared_ptr connection, void* callbackData_); - static void SocketClosedCallback(void* callbackData_); - - private: - static void CloseServerSocket(ServerSocket*); - - void SendListResponse(InspectorSocket* socket, const std::string& host, SocketSession* session); - std::string GetFrontendURL(bool is_compat, const std::string& formatted_address); - bool TargetExists(const std::string& id); - - enum class ServerState - { - kNew, - kRunning, - kStopping, - kStopped - }; - std::unique_ptr delegate_; - const std::string host_; - unsigned short port_; - - std::shared_ptr tcp_server_; - - int next_session_id_; - FILE* out_; - ServerState state_; - - std::map>> connected_sessions_; - }; - -} // namespace inspector \ No newline at end of file diff --git a/Dependencies/v8inspector/Source/V8InspectorTCP.cpp b/Dependencies/v8inspector/Source/V8InspectorTCP.cpp deleted file mode 100644 index 07f6c8911..000000000 --- a/Dependencies/v8inspector/Source/V8InspectorTCP.cpp +++ /dev/null @@ -1,167 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. -// This code is based on the old node inspector implementation. See NOTICE.md for Node.js' project license details -#include "V8InspectorTCP.h" - -#include - -namespace Babylon -{ - - tcp_server::tcp_server(unsigned short port, ConnectionCallback callback, void* data) - : io_service_() - , acceptor_(io_service_) - , socket_(io_service_) - , connectioncallback_(callback) - , callbackData_(data) - { - asio::ip::tcp::endpoint endpoint(asio::ip::tcp::v4(), port); - acceptor_.open(endpoint.protocol()); - acceptor_.set_option(asio::ip::tcp::acceptor::reuse_address(true)); - acceptor_.bind(endpoint); - acceptor_.listen(); - - do_accept(); - } - - void tcp_server::run() - { - io_service_.run(); - } - - void tcp_server::stop() - { - asio::error_code ec; - acceptor_.close(ec); - socket_.close(ec); - - io_service_.stop(); - } - - void tcp_server::do_accept() - { - std::shared_ptr self; - acceptor_.async_accept(socket_, - [this, self](asio::error_code ec) { - if (!ec) - { - connectioncallback_(std::make_shared(std::move(socket_)), callbackData_); - } - - do_accept(); - }); - } - - asio::ip::tcp::socket& tcp_connection::socket() - { - return socket_; - } - - void tcp_connection::read_loop_async() - { - auto self(shared_from_this()); - socket_.async_read_some(asio::buffer(buffer_), - [this, self](asio::error_code ec, std::size_t bytes_transferred) { - if (!ec) - { - std::vector vc; - //const char* start = boost::asio::buffer_cast(input_buffer_.data()); - vc.reserve(bytes_transferred); - for (size_t c = 0; c < bytes_transferred; c++) - { - vc.push_back(buffer_.data()[c]); - } - - std::string s((buffer_.data()), bytes_transferred); - - readcallback_(vc, false, callbackData_); - - self->read_loop_async(); - } - else if (ec == asio::error::eof) - { - std::vector vc; - readcallback_(vc, true, callbackData_); - } - else if (ec == asio::error::operation_aborted) - { - std::abort(); - } - else - { - return; - } - }); - } - - // !!COPY - void tcp_connection::write_async(std::vector message) - { - - { - std::lock_guard guard(queueAccessMutex); - outQueue.push(std::move(message)); - } - - do_write(false); - } - - void tcp_connection::do_write(bool cont) - { - - std::vector message; - { - std::lock_guard guard(queueAccessMutex); - - // New message but the last write is going on. - if (!cont && writing_) - return; - - if (outQueue.empty()) - { - writing_ = false; - return; - } - message = outQueue.front(); - outQueue.pop(); - - writing_ = true; - } - - auto self(shared_from_this()); - - messageToWrite_ = std::move(message); - - std::string str; - std::transform(messageToWrite_.begin(), messageToWrite_.end(), std::back_inserter(str), [](char c) { return c; }); - - socket_.async_send(asio::buffer(messageToWrite_), - [this, self](asio::error_code ec, std::size_t bytes_transferred) { - if (!ec) - { - std::ostringstream stream; - stream << "Writing completed .. " << bytes_transferred << " bytes."; - - self->do_write(true); - } - - if (ec == asio::error::operation_aborted) - { - std::abort(); - } - else - { - // TODO - } - }); - } - - void tcp_connection::close() - { - asio::error_code ec; - socket_.close(ec); - if (ec) - std::abort(); - } - -} \ No newline at end of file diff --git a/Dependencies/v8inspector/Source/V8InspectorTCP.h b/Dependencies/v8inspector/Source/V8InspectorTCP.h deleted file mode 100644 index 2f04a9293..000000000 --- a/Dependencies/v8inspector/Source/V8InspectorTCP.h +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. -// This code is based on the old node inspector implementation. See NOTICE.md for Node.js' project license details -#pragma once - -#include - -#include -#include - -namespace Babylon -{ - - class tcp_connection : public std::enable_shared_from_this - { - public: - asio::ip::tcp::socket& socket(); - - typedef void (*ReadCallback)(std::vector&, bool iseof, void* data); - inline void registerReadCallback(ReadCallback callback, void* data) - { - readcallback_ = callback; - callbackData_ = data; - } - - void read_loop_async(); - void write_async(std::vector); - void do_write(bool cont); - void close(); - - inline tcp_connection(asio::ip::tcp::socket socket) - : socket_(std::move(socket)) - { - } - - private: - int port_; - - asio::ip::tcp::socket socket_; - std::string message_; - - /// Buffer for incoming data. - std::array buffer_; - - void* callbackData_; - ReadCallback readcallback_; - - std::mutex queueAccessMutex; - std::queue> outQueue; - - std::vector messageToWrite_; - bool writing_{false}; - }; - - class tcp_server : public std::enable_shared_from_this - { - public: - typedef void (*ConnectionCallback)(std::shared_ptr connection, void* callbackData_); - - void run(); - void stop(); - - tcp_server(unsigned short port, ConnectionCallback callback, void* data); - void do_accept(); - - private: - asio::io_service io_service_; - asio::ip::tcp::acceptor acceptor_; - asio::ip::tcp::socket socket_; - - void* callbackData_; - ConnectionCallback connectioncallback_; - }; - -} \ No newline at end of file diff --git a/Dependencies/v8inspector/Source/V8InspectorUtils.cpp b/Dependencies/v8inspector/Source/V8InspectorUtils.cpp deleted file mode 100644 index 5a8969e18..000000000 --- a/Dependencies/v8inspector/Source/V8InspectorUtils.cpp +++ /dev/null @@ -1,245 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. -// This code is based on the old node inspector implementation. See NOTICE.md for Node.js' project license details - -#define _SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING -#include "V8InspectorUtils.h" -#include - -#include -#include -#include -#include - -namespace Babylon { -namespace utils { - -// These are copied from react-native code. -const uint16_t kUtf8OneByteBoundary = 0x80; -const uint16_t kUtf8TwoBytesBoundary = 0x800; -const uint16_t kUtf16HighSubLowBoundary = 0xD800; -const uint16_t kUtf16HighSubHighBoundary = 0xDC00; -const uint16_t kUtf16LowSubHighBoundary = 0xE000; - -size_t utf16toUTF8Length(const uint16_t* utf16String, size_t utf16StringLen) { - if (!utf16String || utf16StringLen == 0) { - return 0; - } - - uint32_t utf8StringLen = 0; - auto utf16StringEnd = utf16String + utf16StringLen; - auto idx16 = utf16String; - while (idx16 < utf16StringEnd) { - auto ch = *idx16++; - if (ch < kUtf8OneByteBoundary) { - utf8StringLen++; - } - else if (ch < kUtf8TwoBytesBoundary) { - utf8StringLen += 2; - } - else if ( - (ch >= kUtf16HighSubLowBoundary) && (ch < kUtf16HighSubHighBoundary) && - (idx16 < utf16StringEnd) && - (*idx16 >= kUtf16HighSubHighBoundary) && (*idx16 < kUtf16LowSubHighBoundary)) { - utf8StringLen += 4; - idx16++; - } - else { - utf8StringLen += 3; - } - } - - return utf8StringLen; -} - -std::string utf16toUTF8(const uint16_t* utf16String, size_t utf16StringLen) noexcept { - if (!utf16String || utf16StringLen <= 0) { - return ""; - } - - std::string utf8String(utf16toUTF8Length(utf16String, utf16StringLen), '\0'); - auto idx8 = utf8String.begin(); - auto idx16 = utf16String; - auto utf16StringEnd = utf16String + utf16StringLen; - while (idx16 < utf16StringEnd) { - auto ch = *idx16++; - if (ch < kUtf8OneByteBoundary) { - *idx8++ = (ch & 0x7F); - } - else if (ch < kUtf8TwoBytesBoundary) { -#ifdef _MSC_VER -#pragma warning(suppress: 4244) - *idx8++ = 0b11000000 | (ch >> 6); -#else - *idx8++ = 0b11000000 | (ch >> 6); -#endif - *idx8++ = 0b10000000 | (ch & 0x3F); - } - else if ( - (ch >= kUtf16HighSubLowBoundary) && (ch < kUtf16HighSubHighBoundary) && - (idx16 < utf16StringEnd) && - (*idx16 >= kUtf16HighSubHighBoundary) && (*idx16 < kUtf16LowSubHighBoundary)) { - auto ch2 = *idx16++; - uint8_t trunc_byte = (((ch >> 6) & 0x0F) + 1); - *idx8++ = 0b11110000 | (trunc_byte >> 2); - *idx8++ = 0b10000000 | ((trunc_byte & 0x03) << 4) | ((ch >> 2) & 0x0F); - *idx8++ = 0b10000000 | ((ch & 0x03) << 4) | ((ch2 >> 6) & 0x0F); - *idx8++ = 0b10000000 | (ch2 & 0x3F); - } - else { - *idx8++ = 0b11100000 | (ch >> 12); - *idx8++ = 0b10000000 | ((ch >> 6) & 0x3F); - *idx8++ = 0b10000000 | (ch & 0x3F); - } - } - - return utf8String; -} - -std::basic_string Utf8ToUtf16(const char* utf8, size_t utf8Len) -{ - std::wstring_convert, char16_t> converter; - return converter.from_bytes(utf8, utf8 + (utf8Len - 1)); -} - -std::string StringViewToUtf8(const v8_inspector::StringView& view) -{ - if (view.is8Bit()) - { - return std::string( - reinterpret_cast(view.characters8()), view.length()); - } - - return Babylon::utils::utf16toUTF8(view.characters16(), view.length()); -} - -std::unique_ptr Utf8ToStringView( - const std::string& message) -{ - auto wstr = - Babylon::utils::Utf8ToUtf16(message.data(), message.length() + 1); - v8_inspector::StringView view( - reinterpret_cast(wstr.c_str()), wstr.length()); - return v8_inspector::StringBuffer::create(view); -} - -char ToLower(char c) { - return c >= 'A' && c <= 'Z' ? c + ('a' - 'A') : c; -} - -std::string ToLower(const std::string& in) { - std::string out(in.size(), 0); - for (size_t i = 0; i < in.size(); ++i) - out[i] = ToLower(in[i]); - return out; -} - -bool StringEqualNoCase(const char* a, const char* b) { - do { - if (*a == '\0') - return *b == '\0'; - if (*b == '\0') - return *a == '\0'; - } while (ToLower(*a++) == ToLower(*b++)); - return false; -} - -bool StringEqualNoCaseN(const char* a, const char* b, size_t length) { - for (size_t i = 0; i < length; i++) { - if (ToLower(a[i]) != ToLower(b[i])) - return false; - if (a[i] == '\0') - return true; - } - return true; -} - -size_t base64_encode(const char* src, size_t slen, char* dst, size_t dlen) { - // We know how much we'll write, just make sure that there's space. - // CHECK(dlen >= base64_encoded_size(slen) && "not enough space provided for base64 encode"); - - dlen = base64_encoded_size(slen); - - unsigned a; - unsigned b; - unsigned c; - unsigned i; - unsigned k; - unsigned n; - - static const char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz" - "0123456789+/"; - - i = 0; - k = 0; - n = static_cast(slen) / 3 * 3; - - while (i < n) { - a = src[i + 0] & 0xff; - b = src[i + 1] & 0xff; - c = src[i + 2] & 0xff; - - dst[k + 0] = table[a >> 2]; - dst[k + 1] = table[((a & 3) << 4) | (b >> 4)]; - dst[k + 2] = table[((b & 0x0f) << 2) | (c >> 6)]; - dst[k + 3] = table[c & 0x3f]; - - i += 3; - k += 4; - } - - if (n != slen) { - switch (slen - n) { - case 1: - a = src[i + 0] & 0xff; - dst[k + 0] = table[a >> 2]; - dst[k + 1] = table[(a & 3) << 4]; - dst[k + 2] = '='; - dst[k + 3] = '='; - break; - - case 2: - a = src[i + 0] & 0xff; - b = src[i + 1] & 0xff; - dst[k + 0] = table[a >> 2]; - dst[k + 1] = table[((a & 3) << 4) | (b >> 4)]; - dst[k + 2] = table[(b & 0x0f) << 2]; - dst[k + 3] = '='; - break; - } - } - - return dlen; -} - -std::string GenerateUniqueID() -{ - static std::random_device rd; - static std::mt19937 mte(rd()); - - std::uniform_int_distribution dist; - - std::array buffer; - std::generate(buffer.begin(), buffer.end(), [&]() { return dist(mte); }); - - char uuid[256]; - snprintf(uuid, sizeof(uuid), "%04x%04x-%04x-%04x-%04x-%04x%04x%04x", - buffer[0], buffer[1], buffer[2], - (buffer[3] & 0x0fff) | 0x4000, - (buffer[4] & 0x3fff) | 0x8000, - buffer[5], buffer[6], buffer[7]); - return uuid; -} - -v8::Local OneByteString(v8::Isolate* isolate, const char* data, int length) -{ - return v8::String::NewFromOneByte( - isolate, - reinterpret_cast(data), - v8::NewStringType::kNormal, - length).ToLocalChecked(); -} - -} -} \ No newline at end of file diff --git a/Dependencies/v8inspector/Source/V8InspectorUtils.h b/Dependencies/v8inspector/Source/V8InspectorUtils.h deleted file mode 100644 index 5ea288a52..000000000 --- a/Dependencies/v8inspector/Source/V8InspectorUtils.h +++ /dev/null @@ -1,356 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. -// This code is based on the old node inspector implementation. See NOTICE.md for Node.js' project license details -#pragma once - -#include - -#include -#include - -#define CHECK(expr) \ - do \ - { \ - if (!(expr)) \ - std::abort(); \ - } while (0) -#define CHECK_EQ(expr1, expr2) \ - do \ - { \ - if ((expr1) != (expr2)) \ - std::abort(); \ - } while (0) -#define CHECK_NE(expr1, expr2) \ - do \ - { \ - if ((expr1) == (expr2)) \ - std::abort(); \ - } while (0) -#define CHECK_NOT_NULL(expr) \ - do \ - { \ - if (expr == nullptr) \ - std::abort(); \ - } while (0) - -namespace Babylon -{ - namespace utils - { - - inline constexpr size_t base64_encoded_size(size_t size) - { - return ((size + 2 - ((size + 2) % 3)) / 3 * 4); - } - - size_t base64_encode(const char* src, size_t slen, char* dst, size_t dlen); - - std::string GenerateUniqueID(); - - std::string utf16toUTF8(const uint16_t* utf16String, size_t utf16Len) noexcept; - std::basic_string Utf8ToUtf16(const char* utf8, size_t utf8Len); - - static char ToLower(char c); - std::string ToLower(const std::string& in); - bool StringEqualNoCase(const char* a, const char* b); - bool StringEqualNoCaseN(const char* a, const char* b, size_t length); - - std::string StringViewToUtf8(const v8_inspector::StringView& view); - std::unique_ptr Utf8ToStringView(const std::string& message); - - v8::Local OneByteString(v8::Isolate* isolate, const char* data, int length = -1); - - // This is a SHA implementation copied from BOOST BEAST. - - // - // Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com) - // - // Distributed under the Boost Software License, Version 1.0. (See accompanying - // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - // - // Official repository: https://github.com/boostorg/beast - // - - // Based on https://github.com/vog/sha1 - /* - Original authors: - Steve Reid (Original C Code) - Bruce Guenter (Small changes to fit into bglibs) - Volker Grabsch (Translation to simpler C++ Code) - Eugene Hopkinson (Safety improvements) - Vincent Falco (beast adaptation) -*/ - - namespace sha1 - { - - static std::size_t constexpr BLOCK_INTS = 16; - static std::size_t constexpr BLOCK_BYTES = 64; - static std::size_t constexpr DIGEST_BYTES = 20; - - inline std::uint32_t - rol(std::uint32_t value, std::size_t bits) - { - return (value << bits) | (value >> (32 - bits)); - } - - inline std::uint32_t - blk(std::uint32_t block[BLOCK_INTS], std::size_t i) - { - return rol( - block[(i + 13) & 15] ^ block[(i + 8) & 15] ^ - block[(i + 2) & 15] ^ block[i], - 1); - } - - inline void - R0(std::uint32_t block[BLOCK_INTS], std::uint32_t v, - std::uint32_t& w, std::uint32_t x, std::uint32_t y, - std::uint32_t& z, std::size_t i) - { - z += ((w & (x ^ y)) ^ y) + block[i] + 0x5a827999 + rol(v, 5); - w = rol(w, 30); - } - - inline void - R1(std::uint32_t block[BLOCK_INTS], std::uint32_t v, - std::uint32_t& w, std::uint32_t x, std::uint32_t y, - std::uint32_t& z, std::size_t i) - { - block[i] = blk(block, i); - z += ((w & (x ^ y)) ^ y) + block[i] + 0x5a827999 + rol(v, 5); - w = rol(w, 30); - } - - inline void - R2(std::uint32_t block[BLOCK_INTS], std::uint32_t v, - std::uint32_t& w, std::uint32_t x, std::uint32_t y, - std::uint32_t& z, std::size_t i) - { - block[i] = blk(block, i); - z += (w ^ x ^ y) + block[i] + 0x6ed9eba1 + rol(v, 5); - w = rol(w, 30); - } - - inline void - R3(std::uint32_t block[BLOCK_INTS], std::uint32_t v, - std::uint32_t& w, std::uint32_t x, std::uint32_t y, - std::uint32_t& z, std::size_t i) - { - block[i] = blk(block, i); - z += (((w | x) & y) | (w & x)) + block[i] + 0x8f1bbcdc + rol(v, 5); - w = rol(w, 30); - } - - inline void - R4(std::uint32_t block[BLOCK_INTS], std::uint32_t v, - std::uint32_t& w, std::uint32_t x, std::uint32_t y, - std::uint32_t& z, std::size_t i) - { - block[i] = blk(block, i); - z += (w ^ x ^ y) + block[i] + 0xca62c1d6 + rol(v, 5); - w = rol(w, 30); - } - - inline void - make_block(std::uint8_t const* p, - std::uint32_t block[BLOCK_INTS]) - { - for (std::size_t i = 0; i < BLOCK_INTS; i++) - block[i] = - (static_cast(p[4 * i + 3])) | - (static_cast(p[4 * i + 2])) << 8 | - (static_cast(p[4 * i + 1])) << 16 | - (static_cast(p[4 * i + 0])) << 24; - } - - template - void - transform( - std::uint32_t digest[], std::uint32_t block[BLOCK_INTS]) - { - std::uint32_t a = digest[0]; - std::uint32_t b = digest[1]; - std::uint32_t c = digest[2]; - std::uint32_t d = digest[3]; - std::uint32_t e = digest[4]; - - R0(block, a, b, c, d, e, 0); - R0(block, e, a, b, c, d, 1); - R0(block, d, e, a, b, c, 2); - R0(block, c, d, e, a, b, 3); - R0(block, b, c, d, e, a, 4); - R0(block, a, b, c, d, e, 5); - R0(block, e, a, b, c, d, 6); - R0(block, d, e, a, b, c, 7); - R0(block, c, d, e, a, b, 8); - R0(block, b, c, d, e, a, 9); - R0(block, a, b, c, d, e, 10); - R0(block, e, a, b, c, d, 11); - R0(block, d, e, a, b, c, 12); - R0(block, c, d, e, a, b, 13); - R0(block, b, c, d, e, a, 14); - R0(block, a, b, c, d, e, 15); - R1(block, e, a, b, c, d, 0); - R1(block, d, e, a, b, c, 1); - R1(block, c, d, e, a, b, 2); - R1(block, b, c, d, e, a, 3); - R2(block, a, b, c, d, e, 4); - R2(block, e, a, b, c, d, 5); - R2(block, d, e, a, b, c, 6); - R2(block, c, d, e, a, b, 7); - R2(block, b, c, d, e, a, 8); - R2(block, a, b, c, d, e, 9); - R2(block, e, a, b, c, d, 10); - R2(block, d, e, a, b, c, 11); - R2(block, c, d, e, a, b, 12); - R2(block, b, c, d, e, a, 13); - R2(block, a, b, c, d, e, 14); - R2(block, e, a, b, c, d, 15); - R2(block, d, e, a, b, c, 0); - R2(block, c, d, e, a, b, 1); - R2(block, b, c, d, e, a, 2); - R2(block, a, b, c, d, e, 3); - R2(block, e, a, b, c, d, 4); - R2(block, d, e, a, b, c, 5); - R2(block, c, d, e, a, b, 6); - R2(block, b, c, d, e, a, 7); - R3(block, a, b, c, d, e, 8); - R3(block, e, a, b, c, d, 9); - R3(block, d, e, a, b, c, 10); - R3(block, c, d, e, a, b, 11); - R3(block, b, c, d, e, a, 12); - R3(block, a, b, c, d, e, 13); - R3(block, e, a, b, c, d, 14); - R3(block, d, e, a, b, c, 15); - R3(block, c, d, e, a, b, 0); - R3(block, b, c, d, e, a, 1); - R3(block, a, b, c, d, e, 2); - R3(block, e, a, b, c, d, 3); - R3(block, d, e, a, b, c, 4); - R3(block, c, d, e, a, b, 5); - R3(block, b, c, d, e, a, 6); - R3(block, a, b, c, d, e, 7); - R3(block, e, a, b, c, d, 8); - R3(block, d, e, a, b, c, 9); - R3(block, c, d, e, a, b, 10); - R3(block, b, c, d, e, a, 11); - R4(block, a, b, c, d, e, 12); - R4(block, e, a, b, c, d, 13); - R4(block, d, e, a, b, c, 14); - R4(block, c, d, e, a, b, 15); - R4(block, b, c, d, e, a, 0); - R4(block, a, b, c, d, e, 1); - R4(block, e, a, b, c, d, 2); - R4(block, d, e, a, b, c, 3); - R4(block, c, d, e, a, b, 4); - R4(block, b, c, d, e, a, 5); - R4(block, a, b, c, d, e, 6); - R4(block, e, a, b, c, d, 7); - R4(block, d, e, a, b, c, 8); - R4(block, c, d, e, a, b, 9); - R4(block, b, c, d, e, a, 10); - R4(block, a, b, c, d, e, 11); - R4(block, e, a, b, c, d, 12); - R4(block, d, e, a, b, c, 13); - R4(block, c, d, e, a, b, 14); - R4(block, b, c, d, e, a, 15); - - digest[0] += a; - digest[1] += b; - digest[2] += c; - digest[3] += d; - digest[4] += e; - } - - } // sha1 - - struct sha1_context - { - static unsigned int constexpr block_size = sha1::BLOCK_BYTES; - static unsigned int constexpr digest_size = 20; - - std::size_t buflen; - std::size_t blocks; - std::uint32_t digest[5]; - std::uint8_t buf[block_size]; - }; - - template - void - init(sha1_context& ctx) noexcept - { - ctx.buflen = 0; - ctx.blocks = 0; - ctx.digest[0] = 0x67452301; - ctx.digest[1] = 0xefcdab89; - ctx.digest[2] = 0x98badcfe; - ctx.digest[3] = 0x10325476; - ctx.digest[4] = 0xc3d2e1f0; - } - - template - void - update(sha1_context& ctx, - void const* message, std::size_t size) noexcept - { - auto p = static_cast< - std::uint8_t const*>(message); - for (;;) - { - auto const n = (std::min)( - size, sizeof(ctx.buf) - ctx.buflen); - std::memcpy(ctx.buf + ctx.buflen, p, n); - ctx.buflen += n; - if (ctx.buflen != 64) - return; - p += n; - size -= n; - ctx.buflen = 0; - std::uint32_t block[sha1::BLOCK_INTS]; - sha1::make_block(ctx.buf, block); - sha1::transform(ctx.digest, block); - ++ctx.blocks; - } - } - - template - void - finish(sha1_context& ctx, void* digest) noexcept - { - using sha1::BLOCK_BYTES; - using sha1::BLOCK_INTS; - - std::uint64_t total_bits = - (ctx.blocks * 64 + ctx.buflen) * 8; - // pad - ctx.buf[ctx.buflen++] = 0x80; - auto const buflen = ctx.buflen; - while (ctx.buflen < 64) - ctx.buf[ctx.buflen++] = 0x00; - std::uint32_t block[BLOCK_INTS]; - sha1::make_block(ctx.buf, block); - if (buflen > BLOCK_BYTES - 8) - { - sha1::transform(ctx.digest, block); - for (size_t i = 0; i < BLOCK_INTS - 2; i++) - block[i] = 0; - } - - /* Append total_bits, split this uint64_t into two uint32_t */ - block[BLOCK_INTS - 1] = total_bits & 0xffffffff; - block[BLOCK_INTS - 2] = (total_bits >> 32); - sha1::transform(ctx.digest, block); - for (std::size_t i = 0; i < sha1::DIGEST_BYTES / 4; i++) - { - std::uint8_t* d = - static_cast(digest) + 4 * i; - d[3] = ctx.digest[i] & 0xff; - d[2] = (ctx.digest[i] >> 8) & 0xff; - d[1] = (ctx.digest[i] >> 16) & 0xff; - d[0] = (ctx.digest[i] >> 24) & 0xff; - } - } - - } -} \ No newline at end of file diff --git a/Dependencies/xr/CMakeLists.txt b/Dependencies/xr/CMakeLists.txt index bd7b5e69f..843f8fcb2 100644 --- a/Dependencies/xr/CMakeLists.txt +++ b/Dependencies/xr/CMakeLists.txt @@ -60,7 +60,7 @@ if (ANDROID) add_library(glm INTERFACE) set_target_properties(glm PROPERTIES INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR}/Dependencies/arcore-android-sdk/libraries/glm) - target_link_libraries(xr PRIVATE glm arcore GSL AndroidExtensions) + target_link_libraries(xr PRIVATE glm arcore AndroidExtensions) elseif (IOS) target_link_libraries(xr PRIVATE "-framework ARKit") else() diff --git a/Install/Install.cmake b/Install/Install.cmake index e2948b3db..731adfa97 100644 --- a/Install/Install.cmake +++ b/Install/Install.cmake @@ -75,12 +75,6 @@ endif() # ---------------- # Plugins # ---------------- - -if(TARGET ChromeDevTools) - install_targets(ChromeDevTools) - install_include(Plugins/ChromeDevTools/Include/Babylon) -endif() - if(TARGET ExternalTexture) install_targets(ExternalTexture) install_include(Plugins/ExternalTexture/Include/Babylon) diff --git a/Plugins/CMakeLists.txt b/Plugins/CMakeLists.txt index bcec27231..89d8982b2 100644 --- a/Plugins/CMakeLists.txt +++ b/Plugins/CMakeLists.txt @@ -1,7 +1,3 @@ -if(BABYLON_NATIVE_PLUGIN_CHROMEDEVTOOLS) - add_subdirectory(ChromeDevTools) -endif() - if(BABYLON_NATIVE_PLUGIN_EXTERNALTEXTURE) add_subdirectory(ExternalTexture) endif() diff --git a/Plugins/ChromeDevTools/CMakeLists.txt b/Plugins/ChromeDevTools/CMakeLists.txt deleted file mode 100644 index 86f64688f..000000000 --- a/Plugins/ChromeDevTools/CMakeLists.txt +++ /dev/null @@ -1,34 +0,0 @@ -set(SOURCES - "Include/Babylon/Plugins/ChromeDevTools.h") - -if (WIN32) - set(CHROME_DEVTOOLS_SUPPORTED_ENGINES ${CHROME_DEVTOOLS_SUPPORTED_ENGINES} "JSI") - if (NOT WINDOWS_STORE) - set(CHROME_DEVTOOLS_SUPPORTED_ENGINES ${CHROME_DEVTOOLS_SUPPORTED_ENGINES} "V8") - endif() -elseif(ANDROID) - set(CHROME_DEVTOOLS_SUPPORTED_ENGINES ${CHROME_DEVTOOLS_SUPPORTED_ENGINES} "V8") -endif() - -if (NAPI_JAVASCRIPT_ENGINE IN_LIST CHROME_DEVTOOLS_SUPPORTED_ENGINES) - set(SOURCES ${SOURCES} "Source/ChromeDevTools${NAPI_JAVASCRIPT_ENGINE}.cpp") -else() - set(SOURCES ${SOURCES} "Source/ChromeDevToolsNull.cpp") -endif() - -add_library(ChromeDevTools ${SOURCES}) -warnings_as_errors(ChromeDevTools) - -if (NAPI_JAVASCRIPT_ENGINE IN_LIST CHROME_DEVTOOLS_SUPPORTED_ENGINES AND NAPI_JAVASCRIPT_ENGINE STREQUAL "V8") - target_link_to_dependencies(ChromeDevTools PRIVATE v8inspector) -endif() - -target_include_directories(ChromeDevTools - PUBLIC "Include") - -target_link_to_dependencies(ChromeDevTools - PUBLIC napi - PRIVATE JsRuntime) - -set_property(TARGET ChromeDevTools PROPERTY FOLDER Plugins) -source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${SOURCES}) diff --git a/Plugins/ChromeDevTools/Include/Babylon/Plugins/ChromeDevTools.h b/Plugins/ChromeDevTools/Include/Babylon/Plugins/ChromeDevTools.h deleted file mode 100644 index ecd7b1ad5..000000000 --- a/Plugins/ChromeDevTools/Include/Babylon/Plugins/ChromeDevTools.h +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -#include - -namespace Babylon::Plugins -{ - class ChromeDevTools - { - public: - class Impl; - - ChromeDevTools(const ChromeDevTools&) = default; - ChromeDevTools& operator=(const ChromeDevTools&) = default; - - ChromeDevTools(ChromeDevTools&&) noexcept = default; - ChromeDevTools& operator=(ChromeDevTools&&) noexcept = default; - - bool SupportsInspector() const; - void StartInspector(const unsigned short port, const std::string& appName) const; - void StopInspector() const; - - static ChromeDevTools Initialize(Napi::Env env); - - private: - ChromeDevTools(std::shared_ptr impl); - std::shared_ptr m_impl; - }; -} diff --git a/Plugins/ChromeDevTools/Source/ChromeDevToolsJSI.cpp b/Plugins/ChromeDevTools/Source/ChromeDevToolsJSI.cpp deleted file mode 100644 index 6edeb1f7f..000000000 --- a/Plugins/ChromeDevTools/Source/ChromeDevToolsJSI.cpp +++ /dev/null @@ -1,76 +0,0 @@ -#include - -#include -#include - -namespace Babylon::Plugins -{ - class ChromeDevTools::Impl final : public std::enable_shared_from_this - { - public: - explicit Impl(Napi::Env env) - : m_env(env) - { - JsRuntime::GetFromJavaScript(env).Dispatch([this](Napi::Env env) { - m_runtime = JsRuntime::NativeObject::GetFromJavaScript(env).Get("_JSIRuntime").As>().Data(); - }); - } - - ~Impl() - { - } - - bool SupportsInspector() - { - return true; - } - - void StartInspector(const unsigned short, const std::string&) - { - JsRuntime::GetFromJavaScript(m_env).Dispatch([this](Napi::Env) { - if (m_runtime != nullptr) - { - v8runtime::openInspector(*m_runtime); - } - }); - } - - void StopInspector() - { - } - - private: - facebook::jsi::Runtime* m_runtime; - Napi::Env m_env; - }; - - ChromeDevTools ChromeDevTools::Initialize(Napi::Env env) - { - return {std::make_shared(env)}; - } - - ChromeDevTools::ChromeDevTools(std::shared_ptr impl) - : m_impl{std::move(impl)} - { - } - - bool ChromeDevTools::SupportsInspector() const - { - return m_impl->SupportsInspector(); - } - - /* - Note: V8JSI doesn't currently support setting the port or appName at runtime. - For now the port is set to 5643 in AppRuntimeJSI.cpp. - */ - void ChromeDevTools::StartInspector(const unsigned short port, const std::string& appName) const - { - m_impl->StartInspector(port, appName); - } - - /* Note: V8JSI doesn't currently have a method for stopping the inspector at runtime. */ - void ChromeDevTools::StopInspector() const - { - m_impl->StopInspector(); - } -} diff --git a/Plugins/ChromeDevTools/Source/ChromeDevToolsNull.cpp b/Plugins/ChromeDevTools/Source/ChromeDevToolsNull.cpp deleted file mode 100644 index c52c24af8..000000000 --- a/Plugins/ChromeDevTools/Source/ChromeDevToolsNull.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include - -#include - -namespace Babylon::Plugins -{ - class ChromeDevTools::Impl - { - }; - - ChromeDevTools ChromeDevTools::Initialize(Napi::Env) - { - return {nullptr}; - } - - ChromeDevTools::ChromeDevTools(std::shared_ptr impl) - : m_impl{std::move(impl)} - { - } - - bool ChromeDevTools::SupportsInspector() const - { - return false; - } - - void ChromeDevTools::StartInspector(const unsigned short, const std::string&) const - { - throw std::runtime_error{"This method is currently unsupported on this JavaScript engine."}; - } - - void ChromeDevTools::StopInspector() const - { - throw std::runtime_error{"This method is currently unsupported on this JavaScript engine."}; - } -} \ No newline at end of file diff --git a/Plugins/ChromeDevTools/Source/ChromeDevToolsV8.cpp b/Plugins/ChromeDevTools/Source/ChromeDevToolsV8.cpp deleted file mode 100644 index c4c479e3a..000000000 --- a/Plugins/ChromeDevTools/Source/ChromeDevToolsV8.cpp +++ /dev/null @@ -1,83 +0,0 @@ -#include - -#include -#include - -namespace Babylon::Plugins -{ - class ChromeDevTools::Impl final : public std::enable_shared_from_this - { - public: - explicit Impl(Napi::Env env) - : m_env(env) - { - JsRuntime::GetFromJavaScript(env).Dispatch([this](Napi::Env env) { - auto& v8Platform = *JsRuntime::NativeObject::GetFromJavaScript(env).Get("_V8Platform").As>().Data(); - auto v8Isolate = v8::Isolate::GetCurrent(); - auto v8Context = v8Isolate->GetCurrentContext(); - m_inspector = std::make_unique(v8Platform, v8Isolate, v8Context, "BabylonNative"); - }); - } - - ~Impl() - { - if (m_inspector != nullptr) - { - m_inspector->stop(); - } - } - - bool SupportsInspector() - { - return true; - } - - void StartInspector(const unsigned short port, const std::string& appName) - { - JsRuntime::GetFromJavaScript(m_env).Dispatch([this, port, appName](Napi::Env) { - if (m_inspector->IsStarted()) - { - m_inspector->stop(); - } - - m_inspector->start(port, appName); - }); - } - - void StopInspector() - { - JsRuntime::GetFromJavaScript(m_env).Dispatch([this](Napi::Env) { - m_inspector->stop(); - }); - } - - private: - std::unique_ptr m_inspector{}; - Napi::Env m_env; - }; - - ChromeDevTools ChromeDevTools::Initialize(Napi::Env env) - { - return {std::make_shared(env)}; - } - - ChromeDevTools::ChromeDevTools(std::shared_ptr impl) - : m_impl{std::move(impl)} - { - } - - bool ChromeDevTools::SupportsInspector() const - { - return m_impl->SupportsInspector(); - } - - void ChromeDevTools::StartInspector(const unsigned short port, const std::string& appName) const - { - m_impl->StartInspector(port, appName); - } - - void ChromeDevTools::StopInspector() const - { - m_impl->StopInspector(); - } -} diff --git a/Polyfills/CMakeLists.txt b/Polyfills/CMakeLists.txt index 9461c69b0..16c1b767f 100644 --- a/Polyfills/CMakeLists.txt +++ b/Polyfills/CMakeLists.txt @@ -1,15 +1,7 @@ -if(BABYLON_NATIVE_POLYFILL_CONSOLE) - add_subdirectory(Console) -endif() - if(BABYLON_NATIVE_POLYFILL_WINDOW) add_subdirectory(Window) endif() -if(BABYLON_NATIVE_POLYFILL_XMLHTTPREQUEST) - add_subdirectory(XMLHttpRequest) -endif() - if(BABYLON_NATIVE_POLYFILL_CANVAS) add_subdirectory(Canvas) endif() diff --git a/Polyfills/Console/CMakeLists.txt b/Polyfills/Console/CMakeLists.txt deleted file mode 100644 index 85fb85a91..000000000 --- a/Polyfills/Console/CMakeLists.txt +++ /dev/null @@ -1,15 +0,0 @@ -set(SOURCES - "Include/Babylon/Polyfills/Console.h" - "Source/Console.cpp") - -add_library(Console ${SOURCES}) -warnings_as_errors(Console) - -target_include_directories(Console - PUBLIC "Include") - -target_link_to_dependencies(Console - PUBLIC napi) - -set_property(TARGET Console PROPERTY FOLDER Polyfills) -source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${SOURCES}) diff --git a/Polyfills/Console/Include/Babylon/Polyfills/Console.h b/Polyfills/Console/Include/Babylon/Polyfills/Console.h deleted file mode 100644 index de800fe61..000000000 --- a/Polyfills/Console/Include/Babylon/Polyfills/Console.h +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once - -#include - -namespace Babylon::Polyfills::Console -{ - /** - * Importance level of messages sent via logging callbacks. - */ - enum class LogLevel - { - Log, - Warn, - Error, - }; - - using CallbackT = std::function; - - void Initialize(Napi::Env env, CallbackT callback); -} diff --git a/Polyfills/Console/Readme.md b/Polyfills/Console/Readme.md deleted file mode 100644 index e2fc5763a..000000000 --- a/Polyfills/Console/Readme.md +++ /dev/null @@ -1,14 +0,0 @@ -# Console -Implements parts of [`console`](https://developer.mozilla.org/en-US/docs/Web/API/console). Provides a way to output debug messages from JavaScript into C++. - -Currently supports: -* `log()` -* `warn()` -* `error()` - -When initializing, you should provide a callback which takes a message and a log level and outputs the message in whatever way you like. For example, you could initialize it like so: -```c++ -Babylon::Polyfills::Console::Initialize(env, [](const char* message, auto) { - printf("%s", message); - fflush(stdout); -}); diff --git a/Polyfills/Console/Source/Console.cpp b/Polyfills/Console/Source/Console.cpp deleted file mode 100644 index 322209b20..000000000 --- a/Polyfills/Console/Source/Console.cpp +++ /dev/null @@ -1,88 +0,0 @@ -#include - -#include -#include -#include - -namespace -{ - constexpr const char* JS_INSTANCE_NAME{"console"}; - - void Call(Napi::Function func, const Napi::CallbackInfo& info) - { - std::array staticArgs{}; - const size_t argc = info.Length(); - - if (info.Length() < std::size(staticArgs)) - { - for (size_t i = 0; i < argc; ++i) - { - staticArgs[i] = info[i]; - } - - func.Call(argc, staticArgs.data()); - } - else - { - std::vector args(argc); - for (size_t i = 0; i < argc; ++i) - { - args[i] = info[i]; - } - - func.Call(argc, args.data()); - } - } - - void InvokeCallback(Babylon::Polyfills::Console::CallbackT callback, const Napi::CallbackInfo& info, Babylon::Polyfills::Console::LogLevel logLevel) - { - std::stringstream ss{}; - for (size_t i = 0; i < info.Length(); i++) - { - if (i > 0) - { - ss << " "; - } - ss << info[i].ToString().Utf8Value().c_str(); - } - ss << std::endl; - - callback(ss.str().c_str(), logLevel); - } - - void AddMethod(Napi::Object& console, const char* functionName, Babylon::Polyfills::Console::LogLevel logLevel, Babylon::Polyfills::Console::CallbackT callback) - { - auto existingFunction = std::make_shared(Napi::Persistent(console.Get(functionName).As())); - console.Set(functionName, - Napi::Function::New( - console.Env(), - [callback, existingFunction = std::move(existingFunction), logLevel](const Napi::CallbackInfo& info) { - InvokeCallback(callback, info, logLevel); - - if (!existingFunction->Value().IsUndefined()) - { - Call(existingFunction->Value(), info); - } - }, - functionName)); - } -} - -namespace Babylon::Polyfills::Console -{ - void Initialize(Napi::Env env, CallbackT callback) - { - Napi::HandleScope scope{env}; - - auto console = env.Global().Get(JS_INSTANCE_NAME).As(); - if (console.IsUndefined()) - { - console = Napi::Object::New(env); - env.Global().Set(JS_INSTANCE_NAME, console); - } - - AddMethod(console, "log", LogLevel::Log, callback); - AddMethod(console, "warn", LogLevel::Warn, callback); - AddMethod(console, "error", LogLevel::Error, callback); - } -} diff --git a/Polyfills/XMLHttpRequest/CMakeLists.txt b/Polyfills/XMLHttpRequest/CMakeLists.txt deleted file mode 100644 index 4ce8e9d4e..000000000 --- a/Polyfills/XMLHttpRequest/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ -set(SOURCES - "Include/Babylon/Polyfills/XMLHttpRequest.h" - "Source/XMLHttpRequest.cpp" - "Source/XMLHttpRequest.h") - -add_library(XMLHttpRequest ${SOURCES}) -warnings_as_errors(XMLHttpRequest) - -target_include_directories(XMLHttpRequest - PUBLIC "Include") - -target_link_to_dependencies(XMLHttpRequest - PUBLIC napi - PRIVATE JsRuntimeInternal - PRIVATE arcana - PRIVATE UrlLib) - -set_property(TARGET XMLHttpRequest PROPERTY FOLDER Polyfills) -source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${SOURCES}) diff --git a/Polyfills/XMLHttpRequest/Include/Babylon/Polyfills/XMLHttpRequest.h b/Polyfills/XMLHttpRequest/Include/Babylon/Polyfills/XMLHttpRequest.h deleted file mode 100644 index f9cb46a01..000000000 --- a/Polyfills/XMLHttpRequest/Include/Babylon/Polyfills/XMLHttpRequest.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once - -#include - -namespace Babylon::Polyfills::XMLHttpRequest -{ - void Initialize(Napi::Env env); -} diff --git a/Polyfills/XMLHttpRequest/Readme.md b/Polyfills/XMLHttpRequest/Readme.md deleted file mode 100644 index 5c40c7476..000000000 --- a/Polyfills/XMLHttpRequest/Readme.md +++ /dev/null @@ -1,16 +0,0 @@ -# XMLHttpRequest -Minimal implementation of XMLHttpRequest required to support the Babylon.js RequestFile method. Under the hood, XMLHttpRequest is implemented using various platform-specific APIs in the UrlLib dependency. - -## Event listening -We do not support `onload`-style event listeners. Instead, you should listen to events using `addEventListener`. At the moment, we only support the following events: -* `loadend` -* `readystatechange` - -## Local files -Unlike the web, XMLHttpRequest supports loading local files using two schemes: -* `file:///` allows you to load from an absolute path -* `app:///` allows you to load from a relative path, either the current program or package depending on platform - -## Other things to be aware of: -* Only `GET` requests are currently supported -* For `readyState`, we only support `UNSENT`, `OPENED`, and `DONE` \ No newline at end of file diff --git a/Polyfills/XMLHttpRequest/Source/XMLHttpRequest.cpp b/Polyfills/XMLHttpRequest/Source/XMLHttpRequest.cpp deleted file mode 100644 index 972d8cf5d..000000000 --- a/Polyfills/XMLHttpRequest/Source/XMLHttpRequest.cpp +++ /dev/null @@ -1,257 +0,0 @@ -#include "XMLHttpRequest.h" -#include -#include -#include - -namespace Babylon::Polyfills::Internal -{ - namespace - { - namespace ResponseType - { - constexpr const char* Text = "text"; - constexpr const char* ArrayBuffer = "arraybuffer"; - - UrlLib::UrlResponseType StringToEnum(const std::string& value) - { - if (value == Text) - return UrlLib::UrlResponseType::String; - if (value == ArrayBuffer) - return UrlLib::UrlResponseType::Buffer; - - throw std::runtime_error{"Unsupported response type: " + value}; - } - - const char* EnumToString(UrlLib::UrlResponseType value) - { - switch (value) - { - case UrlLib::UrlResponseType::String: - return Text; - case UrlLib::UrlResponseType::Buffer: - return ArrayBuffer; - } - - throw std::runtime_error{"Invalid response type"}; - } - } - - namespace MethodType - { - constexpr const char* Get = "GET"; - - UrlLib::UrlMethod StringToEnum(const std::string& value) - { - if (value == Get) - return UrlLib::UrlMethod::Get; - - throw std::runtime_error{"Unsupported url method: " + value}; - } - } - - namespace EventType - { - constexpr const char* ReadyStateChange = "readystatechange"; - constexpr const char* LoadEnd = "loadend"; - } - } - - void XMLHttpRequest::Initialize(Napi::Env env) - { - Napi::HandleScope scope{env}; - - static constexpr auto JS_XML_HTTP_REQUEST_CONSTRUCTOR_NAME = "XMLHttpRequest"; - - Napi::Function func = DefineClass( - env, - JS_XML_HTTP_REQUEST_CONSTRUCTOR_NAME, - { - StaticValue("UNSENT", Napi::Value::From(env, 0)), - StaticValue("OPENED", Napi::Value::From(env, 1)), - StaticValue("HEADERS_RECEIVED", Napi::Value::From(env, 2)), - StaticValue("LOADING", Napi::Value::From(env, 3)), - StaticValue("DONE", Napi::Value::From(env, 4)), - InstanceAccessor("readyState", &XMLHttpRequest::GetReadyState, nullptr), - InstanceAccessor("response", &XMLHttpRequest::GetResponse, nullptr), - InstanceAccessor("responseText", &XMLHttpRequest::GetResponseText, nullptr), - InstanceAccessor("responseType", &XMLHttpRequest::GetResponseType, &XMLHttpRequest::SetResponseType), - InstanceAccessor("responseURL", &XMLHttpRequest::GetResponseURL, nullptr), - InstanceAccessor("status", &XMLHttpRequest::GetStatus, nullptr), - InstanceMethod("getResponseHeader", &XMLHttpRequest::GetResponseHeader), - InstanceMethod("addEventListener", &XMLHttpRequest::AddEventListener), - InstanceMethod("removeEventListener", &XMLHttpRequest::RemoveEventListener), - InstanceMethod("abort", &XMLHttpRequest::Abort), - InstanceMethod("open", &XMLHttpRequest::Open), - InstanceMethod("send", &XMLHttpRequest::Send), - }); - - if (env.Global().Get(JS_XML_HTTP_REQUEST_CONSTRUCTOR_NAME).IsUndefined()) - { - env.Global().Set(JS_XML_HTTP_REQUEST_CONSTRUCTOR_NAME, func); - } - - JsRuntime::NativeObject::GetFromJavaScript(env).Set(JS_XML_HTTP_REQUEST_CONSTRUCTOR_NAME, func); - } - - XMLHttpRequest::XMLHttpRequest(const Napi::CallbackInfo& info) - : Napi::ObjectWrap{info} - , m_runtimeScheduler{JsRuntime::GetFromJavaScript(info.Env())} - { - } - - Napi::Value XMLHttpRequest::GetReadyState(const Napi::CallbackInfo&) - { - return Napi::Value::From(Env(), arcana::underlying_cast(m_readyState)); - } - - Napi::Value XMLHttpRequest::GetResponse(const Napi::CallbackInfo&) - { - const gsl::span responseBuffer{m_request.ResponseBuffer()}; - const auto arrayBuffer{Napi::ArrayBuffer::New(Env(), responseBuffer.size())}; - std::memcpy(arrayBuffer.Data(), responseBuffer.data(), arrayBuffer.ByteLength()); - return std::move(arrayBuffer); - } - - Napi::Value XMLHttpRequest::GetResponseText(const Napi::CallbackInfo&) - { - return Napi::Value::From(Env(), m_request.ResponseString().data()); - } - - Napi::Value XMLHttpRequest::GetResponseType(const Napi::CallbackInfo&) - { - return Napi::Value::From(Env(), ResponseType::EnumToString(m_request.ResponseType())); - } - - void XMLHttpRequest::SetResponseType(const Napi::CallbackInfo&, const Napi::Value& value) - { - m_request.ResponseType(ResponseType::StringToEnum(value.As().Utf8Value())); - } - - Napi::Value XMLHttpRequest::GetResponseHeader(const Napi::CallbackInfo& info) - { - const auto headerName = info[0].As().Utf8Value(); - const auto header = m_request.GetResponseHeader(headerName); - return header ? Napi::Value::From(Env(), header.value()) : info.Env().Null(); - } - - Napi::Value XMLHttpRequest::GetResponseURL(const Napi::CallbackInfo&) - { - return Napi::Value::From(Env(), m_request.ResponseUrl().data()); - } - - Napi::Value XMLHttpRequest::GetStatus(const Napi::CallbackInfo&) - { - return Napi::Value::From(Env(), arcana::underlying_cast(m_request.StatusCode())); - } - - void XMLHttpRequest::AddEventListener(const Napi::CallbackInfo& info) - { - const std::string eventType = info[0].As().Utf8Value(); - const Napi::Function eventHandler = info[1].As(); - - const auto& eventHandlerRefs = m_eventHandlerRefs[eventType]; - for (auto it = eventHandlerRefs.begin(); it != eventHandlerRefs.end(); ++it) - { - if (it->Value() == eventHandler) - { - throw Napi::Error::New(info.Env(), "Cannot add the same event handler twice"); - } - } - - m_eventHandlerRefs[eventType].push_back(Napi::Persistent(eventHandler)); - } - - void XMLHttpRequest::RemoveEventListener(const Napi::CallbackInfo& info) - { - const std::string eventType = info[0].As().Utf8Value(); - const Napi::Function eventHandler = info[1].As(); - const auto itType = m_eventHandlerRefs.find(eventType); - if (itType != m_eventHandlerRefs.end()) - { - auto& eventHandlerRefs = itType->second; - for (auto it = eventHandlerRefs.begin(); it != eventHandlerRefs.end(); ++it) - { - if (it->Value() == eventHandler) - { - eventHandlerRefs.erase(it); - break; - } - } - } - } - - void XMLHttpRequest::Abort(const Napi::CallbackInfo&) - { - m_request.Abort(); - } - - void XMLHttpRequest::Open(const Napi::CallbackInfo& info) - { - const auto inputURL = info[1].As(); - - try - { - m_request.Open(MethodType::StringToEnum(info[0].As().Utf8Value()), inputURL); - } - catch (const std::exception& e) - { - throw Napi::Error::New(info.Env(), std::string{"Error opening URL: "} + e.what()); - } - catch (...) - { - throw Napi::Error::New(info.Env(), "Unknown error opening URL"); - } - - SetReadyState(ReadyState::Opened); - } - - void XMLHttpRequest::Send(const Napi::CallbackInfo& info) - { - if (m_readyState != ReadyState::Opened) - { - throw Napi::Error::New(info.Env(), "XMLHttpRequest must be opened before it can be sent"); - } - - m_request.SendAsync().then(m_runtimeScheduler, arcana::cancellation::none(), [env{info.Env()}, this](arcana::expected result) { - if (result.has_error()) - { - Napi::Error::New(env, result.error()).ThrowAsJavaScriptException(); - return; - } - - SetReadyState(ReadyState::Done); - RaiseEvent(EventType::LoadEnd); - - // Assume the XMLHttpRequest will only be used for a single request and clear the event handlers. - // Single use seems to be the standard pattern, and we need to release our strong refs to event handlers. - m_eventHandlerRefs.clear(); - }); - } - - void XMLHttpRequest::SetReadyState(ReadyState readyState) - { - m_readyState = readyState; - RaiseEvent(EventType::ReadyStateChange); - } - - void XMLHttpRequest::RaiseEvent(const char* eventType) - { - const auto it = m_eventHandlerRefs.find(eventType); - if (it != m_eventHandlerRefs.end()) - { - const auto& eventHandlerRefs = it->second; - for (const auto& eventHandlerRef : eventHandlerRefs) - { - eventHandlerRef.Call({}); - } - } - } -} - -namespace Babylon::Polyfills::XMLHttpRequest -{ - void Initialize(Napi::Env env) - { - Internal::XMLHttpRequest::Initialize(env); - } -} diff --git a/Polyfills/XMLHttpRequest/Source/XMLHttpRequest.h b/Polyfills/XMLHttpRequest/Source/XMLHttpRequest.h deleted file mode 100644 index c2e495a1f..000000000 --- a/Polyfills/XMLHttpRequest/Source/XMLHttpRequest.h +++ /dev/null @@ -1,49 +0,0 @@ -#pragma once - -#include - -#include -#include - -#include - -namespace Babylon::Polyfills::Internal -{ - class XMLHttpRequest final : public Napi::ObjectWrap - { - public: - static void Initialize(Napi::Env env); - - explicit XMLHttpRequest(const Napi::CallbackInfo& info); - - private: - enum class ReadyState - { - Unsent = 0, - Opened = 1, - Done = 4, - }; - - Napi::Value GetReadyState(const Napi::CallbackInfo& info); - Napi::Value GetResponse(const Napi::CallbackInfo& info); - Napi::Value GetResponseText(const Napi::CallbackInfo& info); - Napi::Value GetResponseType(const Napi::CallbackInfo& info); - Napi::Value GetResponseHeader(const Napi::CallbackInfo& info); - void SetResponseType(const Napi::CallbackInfo& info, const Napi::Value& value); - Napi::Value GetResponseURL(const Napi::CallbackInfo& info); - Napi::Value GetStatus(const Napi::CallbackInfo& info); - void AddEventListener(const Napi::CallbackInfo& info); - void RemoveEventListener(const Napi::CallbackInfo& info); - void Abort(const Napi::CallbackInfo& info); - void Open(const Napi::CallbackInfo& info); - void Send(const Napi::CallbackInfo& info); - - void SetReadyState(ReadyState readyState); - void RaiseEvent(const char* eventType); - - UrlLib::UrlRequest m_request{}; - JsRuntimeScheduler m_runtimeScheduler; - ReadyState m_readyState{ReadyState::Unsent}; - std::unordered_map> m_eventHandlerRefs; - }; -}