OR-1 dataflow CPU sketch
at main 7033 lines 236 kB view raw
1#ifndef SRC_NAPI_INL_H_ 2#define SRC_NAPI_INL_H_ 3 4//////////////////////////////////////////////////////////////////////////////// 5// Node-API C++ Wrapper Classes 6// 7// Inline header-only implementations for "Node-API" ABI-stable C APIs for 8// Node.js. 9//////////////////////////////////////////////////////////////////////////////// 10 11// Note: Do not include this file directly! Include "napi.h" instead. 12// This should be a no-op and is intended for better IDE integration. 13#include "napi.h" 14 15#include <algorithm> 16#include <cstdarg> 17#include <cstring> 18#if NAPI_HAS_THREADS 19#include <mutex> 20#endif // NAPI_HAS_THREADS 21#include <type_traits> 22#include <utility> 23 24namespace Napi { 25 26#ifdef NAPI_CPP_CUSTOM_NAMESPACE 27namespace NAPI_CPP_CUSTOM_NAMESPACE { 28#endif 29 30// Helpers to handle functions exposed from C++ and internal constants. 31namespace details { 32 33// New napi_status constants not yet available in all supported versions of 34// Node.js releases. Only necessary when they are used in napi.h and napi-inl.h. 35constexpr int napi_no_external_buffers_allowed = 22; 36 37template <typename FreeType> 38inline void default_basic_finalizer(node_addon_api_basic_env /*env*/, 39 void* data, 40 void* /*hint*/) { 41 delete static_cast<FreeType*>(data); 42} 43 44// Attach a data item to an object and delete it when the object gets 45// garbage-collected. 46// TODO: Replace this code with `napi_add_finalizer()` whenever it becomes 47// available on all supported versions of Node.js. 48template < 49 typename FreeType, 50 node_addon_api_basic_finalize finalizer = default_basic_finalizer<FreeType>> 51inline napi_status AttachData(napi_env env, 52 napi_value obj, 53 FreeType* data, 54 void* hint = nullptr) { 55 napi_status status; 56#if (NAPI_VERSION < 5) 57 napi_value symbol, external; 58 status = napi_create_symbol(env, nullptr, &symbol); 59 if (status == napi_ok) { 60 status = napi_create_external(env, data, finalizer, hint, &external); 61 if (status == napi_ok) { 62 napi_property_descriptor desc = {nullptr, 63 symbol, 64 nullptr, 65 nullptr, 66 nullptr, 67 external, 68 napi_default, 69 nullptr}; 70 status = napi_define_properties(env, obj, 1, &desc); 71 } 72 } 73#else // NAPI_VERSION >= 5 74 status = napi_add_finalizer(env, obj, data, finalizer, hint, nullptr); 75#endif 76 return status; 77} 78 79// For use in JS to C++ callback wrappers to catch any Napi::Error exceptions 80// and rethrow them as JavaScript exceptions before returning from the callback. 81template <typename Callable> 82#ifdef NODE_ADDON_API_CPP_EXCEPTIONS_ALL 83inline napi_value WrapCallback(napi_env env, Callable callback) { 84#else 85inline napi_value WrapCallback(napi_env, Callable callback) { 86#endif 87#ifdef NODE_ADDON_API_CPP_EXCEPTIONS 88 try { 89 return callback(); 90 } catch (const Error& e) { 91 e.ThrowAsJavaScriptException(); 92 return nullptr; 93 } 94#ifdef NODE_ADDON_API_CPP_EXCEPTIONS_ALL 95 catch (const std::exception& e) { 96 Napi::Error::New(env, e.what()).ThrowAsJavaScriptException(); 97 return nullptr; 98 } catch (...) { 99 Napi::Error::New(env, "A native exception was thrown") 100 .ThrowAsJavaScriptException(); 101 return nullptr; 102 } 103#endif // NODE_ADDON_API_CPP_EXCEPTIONS_ALL 104#else // NODE_ADDON_API_CPP_EXCEPTIONS 105 // When C++ exceptions are disabled, errors are immediately thrown as JS 106 // exceptions, so there is no need to catch and rethrow them here. 107 return callback(); 108#endif // NODE_ADDON_API_CPP_EXCEPTIONS 109} 110 111// For use in JS to C++ void callback wrappers to catch any Napi::Error 112// exceptions and rethrow them as JavaScript exceptions before returning from 113// the callback. 114template <typename Callable> 115inline void WrapVoidCallback(Callable callback) { 116#ifdef NODE_ADDON_API_CPP_EXCEPTIONS 117 try { 118 callback(); 119 } catch (const Error& e) { 120 e.ThrowAsJavaScriptException(); 121 } 122#else // NAPI_CPP_EXCEPTIONS 123 // When C++ exceptions are disabled, errors are immediately thrown as JS 124 // exceptions, so there is no need to catch and rethrow them here. 125 callback(); 126#endif // NAPI_CPP_EXCEPTIONS 127} 128 129// For use in JS to C++ void callback wrappers to catch _any_ thrown exception 130// and rethrow them as JavaScript exceptions before returning from the callback, 131// wrapping in an Napi::Error as needed. 132template <typename Callable> 133#ifdef NODE_ADDON_API_CPP_EXCEPTIONS_ALL 134inline void WrapVoidCallback(napi_env env, Callable callback) { 135#else 136inline void WrapVoidCallback(napi_env, Callable callback) { 137#endif 138#ifdef NODE_ADDON_API_CPP_EXCEPTIONS 139 try { 140 callback(); 141 } catch (const Error& e) { 142 e.ThrowAsJavaScriptException(); 143 } 144#ifdef NODE_ADDON_API_CPP_EXCEPTIONS_ALL 145 catch (const std::exception& e) { 146 Napi::Error::New(env, e.what()).ThrowAsJavaScriptException(); 147 } catch (...) { 148 Napi::Error::New(env, "A native exception was thrown") 149 .ThrowAsJavaScriptException(); 150 } 151#endif // NODE_ADDON_API_CPP_EXCEPTIONS_ALL 152#else 153 // When C++ exceptions are disabled, there is no need to catch and rethrow C++ 154 // exceptions. JS errors should be thrown with 155 // `Error::ThrowAsJavaScriptException`. 156 callback(); 157#endif // NODE_ADDON_API_CPP_EXCEPTIONS 158} 159 160template <typename Callable, typename Return> 161struct CallbackData { 162 static inline napi_value Wrapper(napi_env env, napi_callback_info info) { 163 return details::WrapCallback(env, [&] { 164 CallbackInfo callbackInfo(env, info); 165 CallbackData* callbackData = 166 static_cast<CallbackData*>(callbackInfo.Data()); 167 callbackInfo.SetData(callbackData->data); 168 return callbackData->callback(callbackInfo); 169 }); 170 } 171 172 Callable callback; 173 void* data; 174}; 175 176template <typename Callable> 177struct CallbackData<Callable, void> { 178 static inline napi_value Wrapper(napi_env env, napi_callback_info info) { 179 return details::WrapCallback(env, [&] { 180 CallbackInfo callbackInfo(env, info); 181 CallbackData* callbackData = 182 static_cast<CallbackData*>(callbackInfo.Data()); 183 callbackInfo.SetData(callbackData->data); 184 callbackData->callback(callbackInfo); 185 return nullptr; 186 }); 187 } 188 189 Callable callback; 190 void* data; 191}; 192 193template <void (*Callback)(const CallbackInfo& info)> 194napi_value TemplatedVoidCallback(napi_env env, 195 napi_callback_info info) NAPI_NOEXCEPT { 196 return details::WrapCallback(env, [&] { 197 CallbackInfo cbInfo(env, info); 198 Callback(cbInfo); 199 return nullptr; 200 }); 201} 202 203template <Napi::Value (*Callback)(const CallbackInfo& info)> 204napi_value TemplatedCallback(napi_env env, 205 napi_callback_info info) NAPI_NOEXCEPT { 206 return details::WrapCallback(env, [&] { 207 CallbackInfo cbInfo(env, info); 208 // MSVC requires to copy 'Callback' function pointer to a local variable 209 // before invoking it. 210 auto callback = Callback; 211 return callback(cbInfo); 212 }); 213} 214 215template <typename T, 216 Napi::Value (T::*UnwrapCallback)(const CallbackInfo& info)> 217napi_value TemplatedInstanceCallback(napi_env env, 218 napi_callback_info info) NAPI_NOEXCEPT { 219 return details::WrapCallback(env, [&] { 220 CallbackInfo cbInfo(env, info); 221 T* instance = T::Unwrap(cbInfo.This().As<Object>()); 222 return instance ? (instance->*UnwrapCallback)(cbInfo) : Napi::Value(); 223 }); 224} 225 226template <typename T, void (T::*UnwrapCallback)(const CallbackInfo& info)> 227napi_value TemplatedInstanceVoidCallback(napi_env env, napi_callback_info info) 228 NAPI_NOEXCEPT { 229 return details::WrapCallback(env, [&] { 230 CallbackInfo cbInfo(env, info); 231 T* instance = T::Unwrap(cbInfo.This().As<Object>()); 232 if (instance) (instance->*UnwrapCallback)(cbInfo); 233 return nullptr; 234 }); 235} 236 237template <typename T, typename Finalizer, typename Hint = void> 238struct FinalizeData { 239#ifdef NODE_API_EXPERIMENTAL_HAS_POST_FINALIZER 240 template <typename F = Finalizer, 241 typename = std::enable_if_t< 242 std::is_invocable_v<F, node_addon_api_basic_env, T*>>> 243#endif 244 static inline void Wrapper(node_addon_api_basic_env env, 245 void* data, 246 void* finalizeHint) NAPI_NOEXCEPT { 247 WrapVoidCallback([&] { 248 FinalizeData* finalizeData = static_cast<FinalizeData*>(finalizeHint); 249 finalizeData->callback(env, static_cast<T*>(data)); 250 delete finalizeData; 251 }); 252 } 253 254#ifdef NODE_API_EXPERIMENTAL_HAS_POST_FINALIZER 255 template <typename F = Finalizer, 256 typename = std::enable_if_t< 257 !std::is_invocable_v<F, node_addon_api_basic_env, T*>>, 258 typename = void> 259 static inline void Wrapper(node_addon_api_basic_env env, 260 void* data, 261 void* finalizeHint) NAPI_NOEXCEPT { 262#ifdef NODE_ADDON_API_REQUIRE_BASIC_FINALIZERS 263 static_assert(false, 264 "NODE_ADDON_API_REQUIRE_BASIC_FINALIZERS defined: Finalizer " 265 "must be basic."); 266#endif 267 napi_status status = 268 node_api_post_finalizer(env, WrapperGC, data, finalizeHint); 269 NAPI_FATAL_IF_FAILED( 270 status, "FinalizeData::Wrapper", "node_api_post_finalizer failed"); 271 } 272#endif 273 274#ifdef NODE_API_EXPERIMENTAL_HAS_POST_FINALIZER 275 template <typename F = Finalizer, 276 typename = std::enable_if_t< 277 std::is_invocable_v<F, node_addon_api_basic_env, T*, Hint*>>> 278#endif 279 static inline void WrapperWithHint(node_addon_api_basic_env env, 280 void* data, 281 void* finalizeHint) NAPI_NOEXCEPT { 282 WrapVoidCallback([&] { 283 FinalizeData* finalizeData = static_cast<FinalizeData*>(finalizeHint); 284 finalizeData->callback(env, static_cast<T*>(data), finalizeData->hint); 285 delete finalizeData; 286 }); 287 } 288 289#ifdef NODE_API_EXPERIMENTAL_HAS_POST_FINALIZER 290 template <typename F = Finalizer, 291 typename = std::enable_if_t< 292 !std::is_invocable_v<F, node_addon_api_basic_env, T*, Hint*>>, 293 typename = void> 294 static inline void WrapperWithHint(node_addon_api_basic_env env, 295 void* data, 296 void* finalizeHint) NAPI_NOEXCEPT { 297#ifdef NODE_ADDON_API_REQUIRE_BASIC_FINALIZERS 298 static_assert(false, 299 "NODE_ADDON_API_REQUIRE_BASIC_FINALIZERS defined: Finalizer " 300 "must be basic."); 301#endif 302 napi_status status = 303 node_api_post_finalizer(env, WrapperGCWithHint, data, finalizeHint); 304 NAPI_FATAL_IF_FAILED( 305 status, "FinalizeData::Wrapper", "node_api_post_finalizer failed"); 306 } 307#endif 308 309 static inline void WrapperGCWithoutData(napi_env env, 310 void* /*data*/, 311 void* finalizeHint) NAPI_NOEXCEPT { 312 WrapVoidCallback(env, [&] { 313 FinalizeData* finalizeData = static_cast<FinalizeData*>(finalizeHint); 314 finalizeData->callback(env); 315 delete finalizeData; 316 }); 317 } 318 319 static inline void WrapperGC(napi_env env, 320 void* data, 321 void* finalizeHint) NAPI_NOEXCEPT { 322 WrapVoidCallback(env, [&] { 323 FinalizeData* finalizeData = static_cast<FinalizeData*>(finalizeHint); 324 finalizeData->callback(env, static_cast<T*>(data)); 325 delete finalizeData; 326 }); 327 } 328 329 static inline void WrapperGCWithHint(napi_env env, 330 void* data, 331 void* finalizeHint) NAPI_NOEXCEPT { 332 WrapVoidCallback(env, [&] { 333 FinalizeData* finalizeData = static_cast<FinalizeData*>(finalizeHint); 334 finalizeData->callback(env, static_cast<T*>(data), finalizeData->hint); 335 delete finalizeData; 336 }); 337 } 338 339 Finalizer callback; 340 Hint* hint; 341}; 342 343#if (NAPI_VERSION > 3 && NAPI_HAS_THREADS) 344template <typename ContextType = void, 345 typename Finalizer = std::function<void(Env, void*, ContextType*)>, 346 typename FinalizerDataType = void> 347struct ThreadSafeFinalize { 348 static inline void Wrapper(napi_env env, 349 void* rawFinalizeData, 350 void* /* rawContext */) { 351 if (rawFinalizeData == nullptr) return; 352 353 ThreadSafeFinalize* finalizeData = 354 static_cast<ThreadSafeFinalize*>(rawFinalizeData); 355 finalizeData->callback(Env(env)); 356 delete finalizeData; 357 } 358 359 static inline void FinalizeWrapperWithData(napi_env env, 360 void* rawFinalizeData, 361 void* /* rawContext */) { 362 if (rawFinalizeData == nullptr) return; 363 364 ThreadSafeFinalize* finalizeData = 365 static_cast<ThreadSafeFinalize*>(rawFinalizeData); 366 finalizeData->callback(Env(env), finalizeData->data); 367 delete finalizeData; 368 } 369 370 static inline void FinalizeWrapperWithContext(napi_env env, 371 void* rawFinalizeData, 372 void* rawContext) { 373 if (rawFinalizeData == nullptr) return; 374 375 ThreadSafeFinalize* finalizeData = 376 static_cast<ThreadSafeFinalize*>(rawFinalizeData); 377 finalizeData->callback(Env(env), static_cast<ContextType*>(rawContext)); 378 delete finalizeData; 379 } 380 381 static inline void FinalizeFinalizeWrapperWithDataAndContext( 382 napi_env env, void* rawFinalizeData, void* rawContext) { 383 if (rawFinalizeData == nullptr) return; 384 385 ThreadSafeFinalize* finalizeData = 386 static_cast<ThreadSafeFinalize*>(rawFinalizeData); 387 finalizeData->callback( 388 Env(env), finalizeData->data, static_cast<ContextType*>(rawContext)); 389 delete finalizeData; 390 } 391 392 FinalizerDataType* data; 393 Finalizer callback; 394}; 395 396template <typename ContextType, typename DataType, typename CallJs, CallJs call> 397inline typename std::enable_if<call != static_cast<CallJs>(nullptr)>::type 398CallJsWrapper(napi_env env, napi_value jsCallback, void* context, void* data) { 399 details::WrapVoidCallback(env, [&]() { 400 call(env, 401 Function(env, jsCallback), 402 static_cast<ContextType*>(context), 403 static_cast<DataType*>(data)); 404 }); 405} 406 407template <typename ContextType, typename DataType, typename CallJs, CallJs call> 408inline typename std::enable_if<call == static_cast<CallJs>(nullptr)>::type 409CallJsWrapper(napi_env env, 410 napi_value jsCallback, 411 void* /*context*/, 412 void* /*data*/) { 413 details::WrapVoidCallback(env, [&]() { 414 if (jsCallback != nullptr) { 415 Function(env, jsCallback).Call(0, nullptr); 416 } 417 }); 418} 419 420#if NAPI_VERSION > 4 421 422template <typename CallbackType, typename TSFN> 423napi_value DefaultCallbackWrapper(napi_env /*env*/, std::nullptr_t /*cb*/) { 424 return nullptr; 425} 426 427template <typename CallbackType, typename TSFN> 428napi_value DefaultCallbackWrapper(napi_env /*env*/, Napi::Function cb) { 429 return cb; 430} 431 432#else 433template <typename CallbackType, typename TSFN> 434napi_value DefaultCallbackWrapper(napi_env env, Napi::Function cb) { 435 if (cb.IsEmpty()) { 436 return TSFN::EmptyFunctionFactory(env); 437 } 438 return cb; 439} 440#endif // NAPI_VERSION > 4 441#endif // NAPI_VERSION > 3 && NAPI_HAS_THREADS 442 443template <typename Getter, typename Setter> 444struct AccessorCallbackData { 445 static inline napi_value GetterWrapper(napi_env env, 446 napi_callback_info info) { 447 return details::WrapCallback(env, [&] { 448 CallbackInfo callbackInfo(env, info); 449 AccessorCallbackData* callbackData = 450 static_cast<AccessorCallbackData*>(callbackInfo.Data()); 451 callbackInfo.SetData(callbackData->data); 452 return callbackData->getterCallback(callbackInfo); 453 }); 454 } 455 456 static inline napi_value SetterWrapper(napi_env env, 457 napi_callback_info info) { 458 return details::WrapCallback(env, [&] { 459 CallbackInfo callbackInfo(env, info); 460 AccessorCallbackData* callbackData = 461 static_cast<AccessorCallbackData*>(callbackInfo.Data()); 462 callbackInfo.SetData(callbackData->data); 463 callbackData->setterCallback(callbackInfo); 464 return nullptr; 465 }); 466 } 467 468 Getter getterCallback; 469 Setter setterCallback; 470 void* data; 471}; 472 473// Debugging-purpose C++-style variant of sprintf(). 474inline std::string StringFormat(const char* format, ...) { 475 std::string result; 476 va_list args; 477 va_start(args, format); 478 int len = vsnprintf(nullptr, 0, format, args); 479 result.resize(len); 480 vsnprintf(&result[0], len + 1, format, args); 481 va_end(args); 482 return result; 483} 484 485template <typename T> 486class HasExtendedFinalizer { 487 private: 488 template <typename U, void (U::*)(Napi::Env)> 489 struct SFINAE {}; 490 template <typename U> 491 static char test(SFINAE<U, &U::Finalize>*); 492 template <typename U> 493 static int test(...); 494 495 public: 496 static constexpr bool value = sizeof(test<T>(0)) == sizeof(char); 497}; 498 499template <typename T> 500class HasBasicFinalizer { 501 private: 502 template <typename U, void (U::*)(Napi::BasicEnv)> 503 struct SFINAE {}; 504 template <typename U> 505 static char test(SFINAE<U, &U::Finalize>*); 506 template <typename U> 507 static int test(...); 508 509 public: 510 static constexpr bool value = sizeof(test<T>(0)) == sizeof(char); 511}; 512 513} // namespace details 514 515#ifndef NODE_ADDON_API_DISABLE_DEPRECATED 516#include "napi-inl.deprecated.h" 517#endif // !NODE_ADDON_API_DISABLE_DEPRECATED 518 519//////////////////////////////////////////////////////////////////////////////// 520// Module registration 521//////////////////////////////////////////////////////////////////////////////// 522 523// Register an add-on based on an initializer function. 524#define NODE_API_MODULE(modname, regfunc) \ 525 static napi_value __napi_##regfunc(napi_env env, napi_value exports) { \ 526 return Napi::RegisterModule(env, exports, regfunc); \ 527 } \ 528 NAPI_MODULE(modname, __napi_##regfunc) 529 530// Register an add-on based on a subclass of `Addon<T>` with a custom Node.js 531// module name. 532#define NODE_API_NAMED_ADDON(modname, classname) \ 533 static napi_value __napi_##classname(napi_env env, napi_value exports) { \ 534 return Napi::RegisterModule(env, exports, &classname::Init); \ 535 } \ 536 NAPI_MODULE(modname, __napi_##classname) 537 538// Register an add-on based on a subclass of `Addon<T>` with the Node.js module 539// name given by node-gyp from the `target_name` in binding.gyp. 540#define NODE_API_ADDON(classname) \ 541 NODE_API_NAMED_ADDON(NODE_GYP_MODULE_NAME, classname) 542 543// Adapt the NAPI_MODULE registration function: 544// - Wrap the arguments in NAPI wrappers. 545// - Catch any NAPI errors and rethrow as JS exceptions. 546inline napi_value RegisterModule(napi_env env, 547 napi_value exports, 548 ModuleRegisterCallback registerCallback) { 549 return details::WrapCallback(env, [&] { 550 return napi_value( 551 registerCallback(Napi::Env(env), Napi::Object(env, exports))); 552 }); 553} 554 555//////////////////////////////////////////////////////////////////////////////// 556// Maybe class 557//////////////////////////////////////////////////////////////////////////////// 558 559template <class T> 560bool Maybe<T>::IsNothing() const { 561 return !_has_value; 562} 563 564template <class T> 565bool Maybe<T>::IsJust() const { 566 return _has_value; 567} 568 569template <class T> 570void Maybe<T>::Check() const { 571 NAPI_CHECK(IsJust(), "Napi::Maybe::Check", "Maybe value is Nothing."); 572} 573 574template <class T> 575T Maybe<T>::Unwrap() const { 576 NAPI_CHECK(IsJust(), "Napi::Maybe::Unwrap", "Maybe value is Nothing."); 577 return _value; 578} 579 580template <class T> 581T Maybe<T>::UnwrapOr(const T& default_value) const { 582 return _has_value ? _value : default_value; 583} 584 585template <class T> 586bool Maybe<T>::UnwrapTo(T* out) const { 587 if (IsJust()) { 588 *out = _value; 589 return true; 590 }; 591 return false; 592} 593 594template <class T> 595bool Maybe<T>::operator==(const Maybe& other) const { 596 return (IsJust() == other.IsJust()) && 597 (!IsJust() || Unwrap() == other.Unwrap()); 598} 599 600template <class T> 601bool Maybe<T>::operator!=(const Maybe& other) const { 602 return !operator==(other); 603} 604 605template <class T> 606Maybe<T>::Maybe() : _has_value(false) {} 607 608template <class T> 609Maybe<T>::Maybe(const T& t) : _has_value(true), _value(t) {} 610 611template <class T> 612inline Maybe<T> Nothing() { 613 return Maybe<T>(); 614} 615 616template <class T> 617inline Maybe<T> Just(const T& t) { 618 return Maybe<T>(t); 619} 620 621//////////////////////////////////////////////////////////////////////////////// 622// BasicEnv / Env class 623//////////////////////////////////////////////////////////////////////////////// 624 625inline BasicEnv::BasicEnv(node_addon_api_basic_env env) : _env(env) {} 626 627inline BasicEnv::operator node_addon_api_basic_env() const { 628 return _env; 629} 630 631inline Env::Env(napi_env env) : BasicEnv(env) {} 632 633inline Env::operator napi_env() const { 634 return const_cast<napi_env>(_env); 635} 636 637inline Object Env::Global() const { 638 napi_value value; 639 napi_status status = napi_get_global(*this, &value); 640 NAPI_THROW_IF_FAILED(*this, status, Object()); 641 return Object(*this, value); 642} 643 644inline Value Env::Undefined() const { 645 napi_value value; 646 napi_status status = napi_get_undefined(*this, &value); 647 NAPI_THROW_IF_FAILED(*this, status, Value()); 648 return Value(*this, value); 649} 650 651inline Value Env::Null() const { 652 napi_value value; 653 napi_status status = napi_get_null(*this, &value); 654 NAPI_THROW_IF_FAILED(*this, status, Value()); 655 return Value(*this, value); 656} 657 658inline bool Env::IsExceptionPending() const { 659 bool result; 660 napi_status status = napi_is_exception_pending(*this, &result); 661 if (status != napi_ok) 662 result = false; // Checking for a pending exception shouldn't throw. 663 return result; 664} 665 666inline Error Env::GetAndClearPendingException() const { 667 napi_value value; 668 napi_status status = napi_get_and_clear_last_exception(*this, &value); 669 if (status != napi_ok) { 670 // Don't throw another exception when failing to get the exception! 671 return Error(); 672 } 673 return Error(*this, value); 674} 675 676inline MaybeOrValue<Value> Env::RunScript(const char* utf8script) const { 677 String script = String::New(*this, utf8script); 678 return RunScript(script); 679} 680 681inline MaybeOrValue<Value> Env::RunScript(const std::string& utf8script) const { 682 return RunScript(utf8script.c_str()); 683} 684 685inline MaybeOrValue<Value> Env::RunScript(String script) const { 686 napi_value result; 687 napi_status status = napi_run_script(*this, script, &result); 688 NAPI_RETURN_OR_THROW_IF_FAILED( 689 *this, status, Napi::Value(*this, result), Napi::Value); 690} 691 692#if NAPI_VERSION > 2 693template <typename Hook, typename Arg> 694void BasicEnv::CleanupHook<Hook, Arg>::Wrapper(void* data) NAPI_NOEXCEPT { 695 auto* cleanupData = static_cast< 696 typename Napi::BasicEnv::CleanupHook<Hook, Arg>::CleanupData*>(data); 697 cleanupData->hook(); 698 delete cleanupData; 699} 700 701template <typename Hook, typename Arg> 702void BasicEnv::CleanupHook<Hook, Arg>::WrapperWithArg(void* data) 703 NAPI_NOEXCEPT { 704 auto* cleanupData = static_cast< 705 typename Napi::BasicEnv::CleanupHook<Hook, Arg>::CleanupData*>(data); 706 cleanupData->hook(static_cast<Arg*>(cleanupData->arg)); 707 delete cleanupData; 708} 709#endif // NAPI_VERSION > 2 710 711#if NAPI_VERSION > 5 712template <typename T, BasicEnv::Finalizer<T> fini> 713inline void BasicEnv::SetInstanceData(T* data) const { 714 napi_status status = napi_set_instance_data( 715 _env, 716 data, 717 [](napi_env env, void* data, void*) { fini(env, static_cast<T*>(data)); }, 718 nullptr); 719 NAPI_FATAL_IF_FAILED( 720 status, "BasicEnv::SetInstanceData", "invalid arguments"); 721} 722 723template <typename DataType, 724 typename HintType, 725 Napi::BasicEnv::FinalizerWithHint<DataType, HintType> fini> 726inline void BasicEnv::SetInstanceData(DataType* data, HintType* hint) const { 727 napi_status status = napi_set_instance_data( 728 _env, 729 data, 730 [](napi_env env, void* data, void* hint) { 731 fini(env, static_cast<DataType*>(data), static_cast<HintType*>(hint)); 732 }, 733 hint); 734 NAPI_FATAL_IF_FAILED( 735 status, "BasicEnv::SetInstanceData", "invalid arguments"); 736} 737 738template <typename T> 739inline T* BasicEnv::GetInstanceData() const { 740 void* data = nullptr; 741 742 napi_status status = napi_get_instance_data(_env, &data); 743 NAPI_FATAL_IF_FAILED( 744 status, "BasicEnv::GetInstanceData", "invalid arguments"); 745 746 return static_cast<T*>(data); 747} 748 749template <typename T> 750void BasicEnv::DefaultFini(Env, T* data) { 751 delete data; 752} 753 754template <typename DataType, typename HintType> 755void BasicEnv::DefaultFiniWithHint(Env, DataType* data, HintType*) { 756 delete data; 757} 758#endif // NAPI_VERSION > 5 759 760#if NAPI_VERSION > 8 761inline const char* BasicEnv::GetModuleFileName() const { 762 const char* result; 763 napi_status status = node_api_get_module_file_name(_env, &result); 764 NAPI_FATAL_IF_FAILED( 765 status, "BasicEnv::GetModuleFileName", "invalid arguments"); 766 return result; 767} 768#endif // NAPI_VERSION > 8 769//////////////////////////////////////////////////////////////////////////////// 770// Value class 771//////////////////////////////////////////////////////////////////////////////// 772 773inline Value::Value() : _env(nullptr), _value(nullptr) {} 774 775inline Value::Value(napi_env env, napi_value value) 776 : _env(env), _value(value) {} 777 778inline Value::operator napi_value() const { 779 return _value; 780} 781 782inline bool Value::operator==(const Value& other) const { 783 return StrictEquals(other); 784} 785 786inline bool Value::operator!=(const Value& other) const { 787 return !this->operator==(other); 788} 789 790inline bool Value::StrictEquals(const Value& other) const { 791 bool result; 792 napi_status status = napi_strict_equals(_env, *this, other, &result); 793 NAPI_THROW_IF_FAILED(_env, status, false); 794 return result; 795} 796 797inline Napi::Env Value::Env() const { 798 return Napi::Env(_env); 799} 800 801inline bool Value::IsEmpty() const { 802 return _value == nullptr; 803} 804 805inline napi_valuetype Value::Type() const { 806 if (IsEmpty()) { 807 return napi_undefined; 808 } 809 810 napi_valuetype type; 811 napi_status status = napi_typeof(_env, _value, &type); 812 NAPI_THROW_IF_FAILED(_env, status, napi_undefined); 813 return type; 814} 815 816inline bool Value::IsUndefined() const { 817 return Type() == napi_undefined; 818} 819 820inline bool Value::IsNull() const { 821 return Type() == napi_null; 822} 823 824inline bool Value::IsBoolean() const { 825 return Type() == napi_boolean; 826} 827 828inline bool Value::IsNumber() const { 829 return Type() == napi_number; 830} 831 832#if NAPI_VERSION > 5 833inline bool Value::IsBigInt() const { 834 return Type() == napi_bigint; 835} 836#endif // NAPI_VERSION > 5 837 838#if (NAPI_VERSION > 4) 839inline bool Value::IsDate() const { 840 if (IsEmpty()) { 841 return false; 842 } 843 844 bool result; 845 napi_status status = napi_is_date(_env, _value, &result); 846 NAPI_THROW_IF_FAILED(_env, status, false); 847 return result; 848} 849#endif 850 851inline bool Value::IsString() const { 852 return Type() == napi_string; 853} 854 855inline bool Value::IsSymbol() const { 856 return Type() == napi_symbol; 857} 858 859inline bool Value::IsArray() const { 860 if (IsEmpty()) { 861 return false; 862 } 863 864 bool result; 865 napi_status status = napi_is_array(_env, _value, &result); 866 NAPI_THROW_IF_FAILED(_env, status, false); 867 return result; 868} 869 870inline bool Value::IsArrayBuffer() const { 871 if (IsEmpty()) { 872 return false; 873 } 874 875 bool result; 876 napi_status status = napi_is_arraybuffer(_env, _value, &result); 877 NAPI_THROW_IF_FAILED(_env, status, false); 878 return result; 879} 880 881inline bool Value::IsTypedArray() const { 882 if (IsEmpty()) { 883 return false; 884 } 885 886 bool result; 887 napi_status status = napi_is_typedarray(_env, _value, &result); 888 NAPI_THROW_IF_FAILED(_env, status, false); 889 return result; 890} 891 892inline bool Value::IsObject() const { 893 return Type() == napi_object || IsFunction(); 894} 895 896inline bool Value::IsFunction() const { 897 return Type() == napi_function; 898} 899 900inline bool Value::IsPromise() const { 901 if (IsEmpty()) { 902 return false; 903 } 904 905 bool result; 906 napi_status status = napi_is_promise(_env, _value, &result); 907 NAPI_THROW_IF_FAILED(_env, status, false); 908 return result; 909} 910 911inline bool Value::IsDataView() const { 912 if (IsEmpty()) { 913 return false; 914 } 915 916 bool result; 917 napi_status status = napi_is_dataview(_env, _value, &result); 918 NAPI_THROW_IF_FAILED(_env, status, false); 919 return result; 920} 921 922inline bool Value::IsBuffer() const { 923 if (IsEmpty()) { 924 return false; 925 } 926 927 bool result; 928 napi_status status = napi_is_buffer(_env, _value, &result); 929 NAPI_THROW_IF_FAILED(_env, status, false); 930 return result; 931} 932 933inline bool Value::IsExternal() const { 934 return Type() == napi_external; 935} 936 937template <typename T> 938inline T Value::As() const { 939#ifdef NODE_ADDON_API_ENABLE_TYPE_CHECK_ON_AS 940 T::CheckCast(_env, _value); 941#endif 942 return T(_env, _value); 943} 944 945template <typename T> 946inline T Value::UnsafeAs() const { 947 return T(_env, _value); 948} 949 950// static 951inline void Value::CheckCast(napi_env /* env */, napi_value value) { 952 NAPI_CHECK(value != nullptr, "Value::CheckCast", "empty value"); 953} 954 955inline MaybeOrValue<Boolean> Value::ToBoolean() const { 956 napi_value result; 957 napi_status status = napi_coerce_to_bool(_env, _value, &result); 958 NAPI_RETURN_OR_THROW_IF_FAILED( 959 _env, status, Napi::Boolean(_env, result), Napi::Boolean); 960} 961 962inline MaybeOrValue<Number> Value::ToNumber() const { 963 napi_value result; 964 napi_status status = napi_coerce_to_number(_env, _value, &result); 965 NAPI_RETURN_OR_THROW_IF_FAILED( 966 _env, status, Napi::Number(_env, result), Napi::Number); 967} 968 969inline MaybeOrValue<String> Value::ToString() const { 970 napi_value result; 971 napi_status status = napi_coerce_to_string(_env, _value, &result); 972 NAPI_RETURN_OR_THROW_IF_FAILED( 973 _env, status, Napi::String(_env, result), Napi::String); 974} 975 976inline MaybeOrValue<Object> Value::ToObject() const { 977 napi_value result; 978 napi_status status = napi_coerce_to_object(_env, _value, &result); 979 NAPI_RETURN_OR_THROW_IF_FAILED( 980 _env, status, Napi::Object(_env, result), Napi::Object); 981} 982 983//////////////////////////////////////////////////////////////////////////////// 984// Boolean class 985//////////////////////////////////////////////////////////////////////////////// 986 987inline Boolean Boolean::New(napi_env env, bool val) { 988 napi_value value; 989 napi_status status = napi_get_boolean(env, val, &value); 990 NAPI_THROW_IF_FAILED(env, status, Boolean()); 991 return Boolean(env, value); 992} 993 994inline void Boolean::CheckCast(napi_env env, napi_value value) { 995 NAPI_CHECK(value != nullptr, "Boolean::CheckCast", "empty value"); 996 997 napi_valuetype type; 998 napi_status status = napi_typeof(env, value, &type); 999 NAPI_CHECK(status == napi_ok, "Boolean::CheckCast", "napi_typeof failed"); 1000 NAPI_INTERNAL_CHECK_EQ(type, napi_boolean, "%d", "Boolean::CheckCast"); 1001} 1002 1003inline Boolean::Boolean() : Napi::Value() {} 1004 1005inline Boolean::Boolean(napi_env env, napi_value value) 1006 : Napi::Value(env, value) {} 1007 1008inline Boolean::operator bool() const { 1009 return Value(); 1010} 1011 1012inline bool Boolean::Value() const { 1013 bool result; 1014 napi_status status = napi_get_value_bool(_env, _value, &result); 1015 NAPI_THROW_IF_FAILED(_env, status, false); 1016 return result; 1017} 1018 1019//////////////////////////////////////////////////////////////////////////////// 1020// Number class 1021//////////////////////////////////////////////////////////////////////////////// 1022 1023inline Number Number::New(napi_env env, double val) { 1024 napi_value value; 1025 napi_status status = napi_create_double(env, val, &value); 1026 NAPI_THROW_IF_FAILED(env, status, Number()); 1027 return Number(env, value); 1028} 1029 1030inline void Number::CheckCast(napi_env env, napi_value value) { 1031 NAPI_CHECK(value != nullptr, "Number::CheckCast", "empty value"); 1032 1033 napi_valuetype type; 1034 napi_status status = napi_typeof(env, value, &type); 1035 NAPI_CHECK(status == napi_ok, "Number::CheckCast", "napi_typeof failed"); 1036 NAPI_INTERNAL_CHECK_EQ(type, napi_number, "%d", "Number::CheckCast"); 1037} 1038 1039inline Number::Number() : Value() {} 1040 1041inline Number::Number(napi_env env, napi_value value) : Value(env, value) {} 1042 1043inline Number::operator int32_t() const { 1044 return Int32Value(); 1045} 1046 1047inline Number::operator uint32_t() const { 1048 return Uint32Value(); 1049} 1050 1051inline Number::operator int64_t() const { 1052 return Int64Value(); 1053} 1054 1055inline Number::operator float() const { 1056 return FloatValue(); 1057} 1058 1059inline Number::operator double() const { 1060 return DoubleValue(); 1061} 1062 1063inline int32_t Number::Int32Value() const { 1064 int32_t result; 1065 napi_status status = napi_get_value_int32(_env, _value, &result); 1066 NAPI_THROW_IF_FAILED(_env, status, 0); 1067 return result; 1068} 1069 1070inline uint32_t Number::Uint32Value() const { 1071 uint32_t result; 1072 napi_status status = napi_get_value_uint32(_env, _value, &result); 1073 NAPI_THROW_IF_FAILED(_env, status, 0); 1074 return result; 1075} 1076 1077inline int64_t Number::Int64Value() const { 1078 int64_t result; 1079 napi_status status = napi_get_value_int64(_env, _value, &result); 1080 NAPI_THROW_IF_FAILED(_env, status, 0); 1081 return result; 1082} 1083 1084inline float Number::FloatValue() const { 1085 return static_cast<float>(DoubleValue()); 1086} 1087 1088inline double Number::DoubleValue() const { 1089 double result; 1090 napi_status status = napi_get_value_double(_env, _value, &result); 1091 NAPI_THROW_IF_FAILED(_env, status, 0); 1092 return result; 1093} 1094 1095#if NAPI_VERSION > 5 1096//////////////////////////////////////////////////////////////////////////////// 1097// BigInt Class 1098//////////////////////////////////////////////////////////////////////////////// 1099 1100inline BigInt BigInt::New(napi_env env, int64_t val) { 1101 napi_value value; 1102 napi_status status = napi_create_bigint_int64(env, val, &value); 1103 NAPI_THROW_IF_FAILED(env, status, BigInt()); 1104 return BigInt(env, value); 1105} 1106 1107inline BigInt BigInt::New(napi_env env, uint64_t val) { 1108 napi_value value; 1109 napi_status status = napi_create_bigint_uint64(env, val, &value); 1110 NAPI_THROW_IF_FAILED(env, status, BigInt()); 1111 return BigInt(env, value); 1112} 1113 1114inline BigInt BigInt::New(napi_env env, 1115 int sign_bit, 1116 size_t word_count, 1117 const uint64_t* words) { 1118 napi_value value; 1119 napi_status status = 1120 napi_create_bigint_words(env, sign_bit, word_count, words, &value); 1121 NAPI_THROW_IF_FAILED(env, status, BigInt()); 1122 return BigInt(env, value); 1123} 1124 1125inline void BigInt::CheckCast(napi_env env, napi_value value) { 1126 NAPI_CHECK(value != nullptr, "BigInt::CheckCast", "empty value"); 1127 1128 napi_valuetype type; 1129 napi_status status = napi_typeof(env, value, &type); 1130 NAPI_CHECK(status == napi_ok, "BigInt::CheckCast", "napi_typeof failed"); 1131 NAPI_INTERNAL_CHECK_EQ(type, napi_bigint, "%d", "BigInt::CheckCast"); 1132} 1133 1134inline BigInt::BigInt() : Value() {} 1135 1136inline BigInt::BigInt(napi_env env, napi_value value) : Value(env, value) {} 1137 1138inline int64_t BigInt::Int64Value(bool* lossless) const { 1139 int64_t result; 1140 napi_status status = 1141 napi_get_value_bigint_int64(_env, _value, &result, lossless); 1142 NAPI_THROW_IF_FAILED(_env, status, 0); 1143 return result; 1144} 1145 1146inline uint64_t BigInt::Uint64Value(bool* lossless) const { 1147 uint64_t result; 1148 napi_status status = 1149 napi_get_value_bigint_uint64(_env, _value, &result, lossless); 1150 NAPI_THROW_IF_FAILED(_env, status, 0); 1151 return result; 1152} 1153 1154inline size_t BigInt::WordCount() const { 1155 size_t word_count; 1156 napi_status status = 1157 napi_get_value_bigint_words(_env, _value, nullptr, &word_count, nullptr); 1158 NAPI_THROW_IF_FAILED(_env, status, 0); 1159 return word_count; 1160} 1161 1162inline void BigInt::ToWords(int* sign_bit, 1163 size_t* word_count, 1164 uint64_t* words) { 1165 napi_status status = 1166 napi_get_value_bigint_words(_env, _value, sign_bit, word_count, words); 1167 NAPI_THROW_IF_FAILED_VOID(_env, status); 1168} 1169#endif // NAPI_VERSION > 5 1170 1171#if (NAPI_VERSION > 4) 1172//////////////////////////////////////////////////////////////////////////////// 1173// Date Class 1174//////////////////////////////////////////////////////////////////////////////// 1175 1176inline Date Date::New(napi_env env, double val) { 1177 napi_value value; 1178 napi_status status = napi_create_date(env, val, &value); 1179 NAPI_THROW_IF_FAILED(env, status, Date()); 1180 return Date(env, value); 1181} 1182 1183inline void Date::CheckCast(napi_env env, napi_value value) { 1184 NAPI_CHECK(value != nullptr, "Date::CheckCast", "empty value"); 1185 1186 bool result; 1187 napi_status status = napi_is_date(env, value, &result); 1188 NAPI_CHECK(status == napi_ok, "Date::CheckCast", "napi_is_date failed"); 1189 NAPI_CHECK(result, "Date::CheckCast", "value is not date"); 1190} 1191 1192inline Date::Date() : Value() {} 1193 1194inline Date::Date(napi_env env, napi_value value) : Value(env, value) {} 1195 1196inline Date::operator double() const { 1197 return ValueOf(); 1198} 1199 1200inline double Date::ValueOf() const { 1201 double result; 1202 napi_status status = napi_get_date_value(_env, _value, &result); 1203 NAPI_THROW_IF_FAILED(_env, status, 0); 1204 return result; 1205} 1206#endif 1207 1208//////////////////////////////////////////////////////////////////////////////// 1209// Name class 1210//////////////////////////////////////////////////////////////////////////////// 1211inline void Name::CheckCast(napi_env env, napi_value value) { 1212 NAPI_CHECK(value != nullptr, "Name::CheckCast", "empty value"); 1213 1214 napi_valuetype type; 1215 napi_status status = napi_typeof(env, value, &type); 1216 NAPI_CHECK(status == napi_ok, "Name::CheckCast", "napi_typeof failed"); 1217 NAPI_INTERNAL_CHECK(type == napi_string || type == napi_symbol, 1218 "Name::CheckCast", 1219 "value is not napi_string or napi_symbol, got %d.", 1220 type); 1221} 1222 1223inline Name::Name() : Value() {} 1224 1225inline Name::Name(napi_env env, napi_value value) : Value(env, value) {} 1226 1227//////////////////////////////////////////////////////////////////////////////// 1228// String class 1229//////////////////////////////////////////////////////////////////////////////// 1230 1231inline String String::New(napi_env env, const std::string& val) { 1232 return String::New(env, val.c_str(), val.size()); 1233} 1234 1235inline String String::New(napi_env env, const std::u16string& val) { 1236 return String::New(env, val.c_str(), val.size()); 1237} 1238 1239inline String String::New(napi_env env, const char* val) { 1240 // TODO(@gabrielschulhof) Remove if-statement when core's error handling is 1241 // available in all supported versions. 1242 if (val == nullptr) { 1243 // Throw an error that looks like it came from core. 1244 NAPI_THROW_IF_FAILED(env, napi_invalid_arg, String()); 1245 } 1246 napi_value value; 1247 napi_status status = 1248 napi_create_string_utf8(env, val, std::strlen(val), &value); 1249 NAPI_THROW_IF_FAILED(env, status, String()); 1250 return String(env, value); 1251} 1252 1253inline String String::New(napi_env env, const char16_t* val) { 1254 napi_value value; 1255 // TODO(@gabrielschulhof) Remove if-statement when core's error handling is 1256 // available in all supported versions. 1257 if (val == nullptr) { 1258 // Throw an error that looks like it came from core. 1259 NAPI_THROW_IF_FAILED(env, napi_invalid_arg, String()); 1260 } 1261 napi_status status = 1262 napi_create_string_utf16(env, val, std::u16string(val).size(), &value); 1263 NAPI_THROW_IF_FAILED(env, status, String()); 1264 return String(env, value); 1265} 1266 1267inline String String::New(napi_env env, const char* val, size_t length) { 1268 napi_value value; 1269 napi_status status = napi_create_string_utf8(env, val, length, &value); 1270 NAPI_THROW_IF_FAILED(env, status, String()); 1271 return String(env, value); 1272} 1273 1274inline String String::New(napi_env env, const char16_t* val, size_t length) { 1275 napi_value value; 1276 napi_status status = napi_create_string_utf16(env, val, length, &value); 1277 NAPI_THROW_IF_FAILED(env, status, String()); 1278 return String(env, value); 1279} 1280 1281inline void String::CheckCast(napi_env env, napi_value value) { 1282 NAPI_CHECK(value != nullptr, "String::CheckCast", "empty value"); 1283 1284 napi_valuetype type; 1285 napi_status status = napi_typeof(env, value, &type); 1286 NAPI_CHECK(status == napi_ok, "String::CheckCast", "napi_typeof failed"); 1287 NAPI_INTERNAL_CHECK_EQ(type, napi_string, "%d", "String::CheckCast"); 1288} 1289 1290inline String::String() : Name() {} 1291 1292inline String::String(napi_env env, napi_value value) : Name(env, value) {} 1293 1294inline String::operator std::string() const { 1295 return Utf8Value(); 1296} 1297 1298inline String::operator std::u16string() const { 1299 return Utf16Value(); 1300} 1301 1302inline std::string String::Utf8Value() const { 1303 size_t length; 1304 napi_status status = 1305 napi_get_value_string_utf8(_env, _value, nullptr, 0, &length); 1306 NAPI_THROW_IF_FAILED(_env, status, ""); 1307 1308 std::string value; 1309 value.reserve(length + 1); 1310 value.resize(length); 1311 status = napi_get_value_string_utf8( 1312 _env, _value, &value[0], value.capacity(), nullptr); 1313 NAPI_THROW_IF_FAILED(_env, status, ""); 1314 return value; 1315} 1316 1317inline std::u16string String::Utf16Value() const { 1318 size_t length; 1319 napi_status status = 1320 napi_get_value_string_utf16(_env, _value, nullptr, 0, &length); 1321 NAPI_THROW_IF_FAILED(_env, status, NAPI_WIDE_TEXT("")); 1322 1323 std::u16string value; 1324 value.reserve(length + 1); 1325 value.resize(length); 1326 status = napi_get_value_string_utf16( 1327 _env, _value, &value[0], value.capacity(), nullptr); 1328 NAPI_THROW_IF_FAILED(_env, status, NAPI_WIDE_TEXT("")); 1329 return value; 1330} 1331 1332//////////////////////////////////////////////////////////////////////////////// 1333// Symbol class 1334//////////////////////////////////////////////////////////////////////////////// 1335 1336inline Symbol Symbol::New(napi_env env, const char* description) { 1337 napi_value descriptionValue = description != nullptr 1338 ? String::New(env, description) 1339 : static_cast<napi_value>(nullptr); 1340 return Symbol::New(env, descriptionValue); 1341} 1342 1343inline Symbol Symbol::New(napi_env env, const std::string& description) { 1344 napi_value descriptionValue = String::New(env, description); 1345 return Symbol::New(env, descriptionValue); 1346} 1347 1348inline Symbol Symbol::New(napi_env env, String description) { 1349 napi_value descriptionValue = description; 1350 return Symbol::New(env, descriptionValue); 1351} 1352 1353inline Symbol Symbol::New(napi_env env, napi_value description) { 1354 napi_value value; 1355 napi_status status = napi_create_symbol(env, description, &value); 1356 NAPI_THROW_IF_FAILED(env, status, Symbol()); 1357 return Symbol(env, value); 1358} 1359 1360inline MaybeOrValue<Symbol> Symbol::WellKnown(napi_env env, 1361 const std::string& name) { 1362 // No need to check if the return value is a symbol or undefined. 1363 // Well known symbols are definite and it is an develop time error 1364 // if the symbol does not exist. 1365#if defined(NODE_ADDON_API_ENABLE_MAYBE) 1366 Value symbol_obj; 1367 Value symbol_value; 1368 if (Napi::Env(env).Global().Get("Symbol").UnwrapTo(&symbol_obj) && 1369 symbol_obj.As<Object>().Get(name).UnwrapTo(&symbol_value)) { 1370 return Just<Symbol>(symbol_value.UnsafeAs<Symbol>()); 1371 } 1372 return Nothing<Symbol>(); 1373#else 1374 return Napi::Env(env) 1375 .Global() 1376 .Get("Symbol") 1377 .As<Object>() 1378 .Get(name) 1379 .UnsafeAs<Symbol>(); 1380#endif 1381} 1382 1383inline MaybeOrValue<Symbol> Symbol::For(napi_env env, 1384 const std::string& description) { 1385 napi_value descriptionValue = String::New(env, description); 1386 return Symbol::For(env, descriptionValue); 1387} 1388 1389inline MaybeOrValue<Symbol> Symbol::For(napi_env env, const char* description) { 1390 napi_value descriptionValue = String::New(env, description); 1391 return Symbol::For(env, descriptionValue); 1392} 1393 1394inline MaybeOrValue<Symbol> Symbol::For(napi_env env, String description) { 1395 return Symbol::For(env, static_cast<napi_value>(description)); 1396} 1397 1398inline MaybeOrValue<Symbol> Symbol::For(napi_env env, napi_value description) { 1399#if defined(NODE_ADDON_API_ENABLE_MAYBE) 1400 Value symbol_obj; 1401 Value symbol_for_value; 1402 Value symbol_value; 1403 if (Napi::Env(env).Global().Get("Symbol").UnwrapTo(&symbol_obj) && 1404 symbol_obj.As<Object>().Get("for").UnwrapTo(&symbol_for_value) && 1405 symbol_for_value.As<Function>() 1406 .Call(symbol_obj, {description}) 1407 .UnwrapTo(&symbol_value)) { 1408 return Just<Symbol>(symbol_value.As<Symbol>()); 1409 } 1410 return Nothing<Symbol>(); 1411#else 1412 Object symbol_obj = Napi::Env(env).Global().Get("Symbol").As<Object>(); 1413 return symbol_obj.Get("for") 1414 .As<Function>() 1415 .Call(symbol_obj, {description}) 1416 .As<Symbol>(); 1417#endif 1418} 1419 1420inline void Symbol::CheckCast(napi_env env, napi_value value) { 1421 NAPI_CHECK(value != nullptr, "Symbol::CheckCast", "empty value"); 1422 1423 napi_valuetype type; 1424 napi_status status = napi_typeof(env, value, &type); 1425 NAPI_CHECK(status == napi_ok, "Symbol::CheckCast", "napi_typeof failed"); 1426 NAPI_INTERNAL_CHECK_EQ(type, napi_symbol, "%d", "Symbol::CheckCast"); 1427} 1428 1429inline Symbol::Symbol() : Name() {} 1430 1431inline Symbol::Symbol(napi_env env, napi_value value) : Name(env, value) {} 1432 1433//////////////////////////////////////////////////////////////////////////////// 1434// Automagic value creation 1435//////////////////////////////////////////////////////////////////////////////// 1436 1437namespace details { 1438template <typename T> 1439struct vf_number { 1440 static Number From(napi_env env, T value) { 1441 return Number::New(env, static_cast<double>(value)); 1442 } 1443}; 1444 1445template <> 1446struct vf_number<bool> { 1447 static Boolean From(napi_env env, bool value) { 1448 return Boolean::New(env, value); 1449 } 1450}; 1451 1452struct vf_utf8_charp { 1453 static String From(napi_env env, const char* value) { 1454 return String::New(env, value); 1455 } 1456}; 1457 1458struct vf_utf16_charp { 1459 static String From(napi_env env, const char16_t* value) { 1460 return String::New(env, value); 1461 } 1462}; 1463struct vf_utf8_string { 1464 static String From(napi_env env, const std::string& value) { 1465 return String::New(env, value); 1466 } 1467}; 1468 1469struct vf_utf16_string { 1470 static String From(napi_env env, const std::u16string& value) { 1471 return String::New(env, value); 1472 } 1473}; 1474 1475template <typename T> 1476struct vf_fallback { 1477 static Value From(napi_env env, const T& value) { return Value(env, value); } 1478}; 1479 1480template <typename...> 1481struct disjunction : std::false_type {}; 1482template <typename B> 1483struct disjunction<B> : B {}; 1484template <typename B, typename... Bs> 1485struct disjunction<B, Bs...> 1486 : std::conditional<bool(B::value), B, disjunction<Bs...>>::type {}; 1487 1488template <typename T> 1489struct can_make_string 1490 : disjunction<typename std::is_convertible<T, const char*>::type, 1491 typename std::is_convertible<T, const char16_t*>::type, 1492 typename std::is_convertible<T, std::string>::type, 1493 typename std::is_convertible<T, std::u16string>::type> {}; 1494} // namespace details 1495 1496template <typename T> 1497Value Value::From(napi_env env, const T& value) { 1498 using Helper = typename std::conditional< 1499 std::is_integral<T>::value || std::is_floating_point<T>::value, 1500 details::vf_number<T>, 1501 typename std::conditional<details::can_make_string<T>::value, 1502 String, 1503 details::vf_fallback<T>>::type>::type; 1504 return Helper::From(env, value); 1505} 1506 1507template <typename T> 1508String String::From(napi_env env, const T& value) { 1509 struct Dummy {}; 1510 using Helper = typename std::conditional< 1511 std::is_convertible<T, const char*>::value, 1512 details::vf_utf8_charp, 1513 typename std::conditional< 1514 std::is_convertible<T, const char16_t*>::value, 1515 details::vf_utf16_charp, 1516 typename std::conditional< 1517 std::is_convertible<T, std::string>::value, 1518 details::vf_utf8_string, 1519 typename std::conditional< 1520 std::is_convertible<T, std::u16string>::value, 1521 details::vf_utf16_string, 1522 Dummy>::type>::type>::type>::type; 1523 return Helper::From(env, value); 1524} 1525 1526//////////////////////////////////////////////////////////////////////////////// 1527// TypeTaggable class 1528//////////////////////////////////////////////////////////////////////////////// 1529 1530inline TypeTaggable::TypeTaggable() : Value() {} 1531 1532inline TypeTaggable::TypeTaggable(napi_env _env, napi_value _value) 1533 : Value(_env, _value) {} 1534 1535#if NAPI_VERSION >= 8 1536 1537inline void TypeTaggable::TypeTag(const napi_type_tag* type_tag) const { 1538 napi_status status = napi_type_tag_object(_env, _value, type_tag); 1539 NAPI_THROW_IF_FAILED_VOID(_env, status); 1540} 1541 1542inline bool TypeTaggable::CheckTypeTag(const napi_type_tag* type_tag) const { 1543 bool result; 1544 napi_status status = 1545 napi_check_object_type_tag(_env, _value, type_tag, &result); 1546 NAPI_THROW_IF_FAILED(_env, status, false); 1547 return result; 1548} 1549 1550#endif // NAPI_VERSION >= 8 1551 1552//////////////////////////////////////////////////////////////////////////////// 1553// Object class 1554//////////////////////////////////////////////////////////////////////////////// 1555 1556template <typename Key> 1557inline Object::PropertyLValue<Key>::operator Value() const { 1558 MaybeOrValue<Value> val = Object(_env, _object).Get(_key); 1559#ifdef NODE_ADDON_API_ENABLE_MAYBE 1560 return val.Unwrap(); 1561#else 1562 return val; 1563#endif 1564} 1565 1566template <typename Key> 1567template <typename ValueType> 1568inline Object::PropertyLValue<Key>& Object::PropertyLValue<Key>::operator=( 1569 ValueType value) { 1570#ifdef NODE_ADDON_API_ENABLE_MAYBE 1571 MaybeOrValue<bool> result = 1572#endif 1573 Object(_env, _object).Set(_key, value); 1574#ifdef NODE_ADDON_API_ENABLE_MAYBE 1575 result.Unwrap(); 1576#endif 1577 return *this; 1578} 1579 1580template <typename Key> 1581inline Value Object::PropertyLValue<Key>::AsValue() const { 1582 return Value(*this); 1583} 1584 1585template <typename Key> 1586inline Object::PropertyLValue<Key>::PropertyLValue(Object object, Key key) 1587 : _env(object.Env()), _object(object), _key(key) {} 1588 1589inline Object Object::New(napi_env env) { 1590 napi_value value; 1591 napi_status status = napi_create_object(env, &value); 1592 NAPI_THROW_IF_FAILED(env, status, Object()); 1593 return Object(env, value); 1594} 1595 1596inline void Object::CheckCast(napi_env env, napi_value value) { 1597 NAPI_CHECK(value != nullptr, "Object::CheckCast", "empty value"); 1598 1599 napi_valuetype type; 1600 napi_status status = napi_typeof(env, value, &type); 1601 NAPI_CHECK(status == napi_ok, "Object::CheckCast", "napi_typeof failed"); 1602 NAPI_INTERNAL_CHECK(type == napi_object || type == napi_function, 1603 "Object::CheckCast", 1604 "Expect napi_object or napi_function, but got %d.", 1605 type); 1606} 1607 1608inline Object::Object() : TypeTaggable() {} 1609 1610inline Object::Object(napi_env env, napi_value value) 1611 : TypeTaggable(env, value) {} 1612 1613inline Object::PropertyLValue<std::string> Object::operator[]( 1614 const char* utf8name) { 1615 return PropertyLValue<std::string>(*this, utf8name); 1616} 1617 1618inline Object::PropertyLValue<std::string> Object::operator[]( 1619 const std::string& utf8name) { 1620 return PropertyLValue<std::string>(*this, utf8name); 1621} 1622 1623inline Object::PropertyLValue<uint32_t> Object::operator[](uint32_t index) { 1624 return PropertyLValue<uint32_t>(*this, index); 1625} 1626 1627inline Object::PropertyLValue<Value> Object::operator[](Value index) const { 1628 return PropertyLValue<Value>(*this, index); 1629} 1630 1631inline MaybeOrValue<Value> Object::operator[](const char* utf8name) const { 1632 return Get(utf8name); 1633} 1634 1635inline MaybeOrValue<Value> Object::operator[]( 1636 const std::string& utf8name) const { 1637 return Get(utf8name); 1638} 1639 1640inline MaybeOrValue<Value> Object::operator[](uint32_t index) const { 1641 return Get(index); 1642} 1643 1644inline MaybeOrValue<bool> Object::Has(napi_value key) const { 1645 bool result; 1646 napi_status status = napi_has_property(_env, _value, key, &result); 1647 NAPI_RETURN_OR_THROW_IF_FAILED(_env, status, result, bool); 1648} 1649 1650inline MaybeOrValue<bool> Object::Has(Value key) const { 1651 bool result; 1652 napi_status status = napi_has_property(_env, _value, key, &result); 1653 NAPI_RETURN_OR_THROW_IF_FAILED(_env, status, result, bool); 1654} 1655 1656inline MaybeOrValue<bool> Object::Has(const char* utf8name) const { 1657 bool result; 1658 napi_status status = napi_has_named_property(_env, _value, utf8name, &result); 1659 NAPI_RETURN_OR_THROW_IF_FAILED(_env, status, result, bool); 1660} 1661 1662inline MaybeOrValue<bool> Object::Has(const std::string& utf8name) const { 1663 return Has(utf8name.c_str()); 1664} 1665 1666inline MaybeOrValue<bool> Object::HasOwnProperty(napi_value key) const { 1667 bool result; 1668 napi_status status = napi_has_own_property(_env, _value, key, &result); 1669 NAPI_RETURN_OR_THROW_IF_FAILED(_env, status, result, bool); 1670} 1671 1672inline MaybeOrValue<bool> Object::HasOwnProperty(Value key) const { 1673 bool result; 1674 napi_status status = napi_has_own_property(_env, _value, key, &result); 1675 NAPI_RETURN_OR_THROW_IF_FAILED(_env, status, result, bool); 1676} 1677 1678inline MaybeOrValue<bool> Object::HasOwnProperty(const char* utf8name) const { 1679 napi_value key; 1680 napi_status status = 1681 napi_create_string_utf8(_env, utf8name, std::strlen(utf8name), &key); 1682 NAPI_MAYBE_THROW_IF_FAILED(_env, status, bool); 1683 return HasOwnProperty(key); 1684} 1685 1686inline MaybeOrValue<bool> Object::HasOwnProperty( 1687 const std::string& utf8name) const { 1688 return HasOwnProperty(utf8name.c_str()); 1689} 1690 1691inline MaybeOrValue<Value> Object::Get(napi_value key) const { 1692 napi_value result; 1693 napi_status status = napi_get_property(_env, _value, key, &result); 1694 NAPI_RETURN_OR_THROW_IF_FAILED(_env, status, Value(_env, result), Value); 1695} 1696 1697inline MaybeOrValue<Value> Object::Get(Value key) const { 1698 napi_value result; 1699 napi_status status = napi_get_property(_env, _value, key, &result); 1700 NAPI_RETURN_OR_THROW_IF_FAILED(_env, status, Value(_env, result), Value); 1701} 1702 1703inline MaybeOrValue<Value> Object::Get(const char* utf8name) const { 1704 napi_value result; 1705 napi_status status = napi_get_named_property(_env, _value, utf8name, &result); 1706 NAPI_RETURN_OR_THROW_IF_FAILED(_env, status, Value(_env, result), Value); 1707} 1708 1709inline MaybeOrValue<Value> Object::Get(const std::string& utf8name) const { 1710 return Get(utf8name.c_str()); 1711} 1712 1713template <typename ValueType> 1714inline MaybeOrValue<bool> Object::Set(napi_value key, 1715 const ValueType& value) const { 1716 napi_status status = 1717 napi_set_property(_env, _value, key, Value::From(_env, value)); 1718 NAPI_RETURN_OR_THROW_IF_FAILED(_env, status, status == napi_ok, bool); 1719} 1720 1721template <typename ValueType> 1722inline MaybeOrValue<bool> Object::Set(Value key, const ValueType& value) const { 1723 napi_status status = 1724 napi_set_property(_env, _value, key, Value::From(_env, value)); 1725 NAPI_RETURN_OR_THROW_IF_FAILED(_env, status, status == napi_ok, bool); 1726} 1727 1728template <typename ValueType> 1729inline MaybeOrValue<bool> Object::Set(const char* utf8name, 1730 const ValueType& value) const { 1731 napi_status status = 1732 napi_set_named_property(_env, _value, utf8name, Value::From(_env, value)); 1733 NAPI_RETURN_OR_THROW_IF_FAILED(_env, status, status == napi_ok, bool); 1734} 1735 1736template <typename ValueType> 1737inline MaybeOrValue<bool> Object::Set(const std::string& utf8name, 1738 const ValueType& value) const { 1739 return Set(utf8name.c_str(), value); 1740} 1741 1742inline MaybeOrValue<bool> Object::Delete(napi_value key) const { 1743 bool result; 1744 napi_status status = napi_delete_property(_env, _value, key, &result); 1745 NAPI_RETURN_OR_THROW_IF_FAILED(_env, status, result, bool); 1746} 1747 1748inline MaybeOrValue<bool> Object::Delete(Value key) const { 1749 bool result; 1750 napi_status status = napi_delete_property(_env, _value, key, &result); 1751 NAPI_RETURN_OR_THROW_IF_FAILED(_env, status, result, bool); 1752} 1753 1754inline MaybeOrValue<bool> Object::Delete(const char* utf8name) const { 1755 return Delete(String::New(_env, utf8name)); 1756} 1757 1758inline MaybeOrValue<bool> Object::Delete(const std::string& utf8name) const { 1759 return Delete(String::New(_env, utf8name)); 1760} 1761 1762inline MaybeOrValue<bool> Object::Has(uint32_t index) const { 1763 bool result; 1764 napi_status status = napi_has_element(_env, _value, index, &result); 1765 NAPI_RETURN_OR_THROW_IF_FAILED(_env, status, result, bool); 1766} 1767 1768inline MaybeOrValue<Value> Object::Get(uint32_t index) const { 1769 napi_value value; 1770 napi_status status = napi_get_element(_env, _value, index, &value); 1771 NAPI_RETURN_OR_THROW_IF_FAILED(_env, status, Value(_env, value), Value); 1772} 1773 1774template <typename ValueType> 1775inline MaybeOrValue<bool> Object::Set(uint32_t index, 1776 const ValueType& value) const { 1777 napi_status status = 1778 napi_set_element(_env, _value, index, Value::From(_env, value)); 1779 NAPI_RETURN_OR_THROW_IF_FAILED(_env, status, status == napi_ok, bool); 1780} 1781 1782inline MaybeOrValue<bool> Object::Delete(uint32_t index) const { 1783 bool result; 1784 napi_status status = napi_delete_element(_env, _value, index, &result); 1785 NAPI_RETURN_OR_THROW_IF_FAILED(_env, status, result, bool); 1786} 1787 1788inline MaybeOrValue<Array> Object::GetPropertyNames() const { 1789 napi_value result; 1790 napi_status status = napi_get_property_names(_env, _value, &result); 1791 NAPI_RETURN_OR_THROW_IF_FAILED(_env, status, Array(_env, result), Array); 1792} 1793 1794inline MaybeOrValue<bool> Object::DefineProperty( 1795 const PropertyDescriptor& property) const { 1796 napi_status status = napi_define_properties( 1797 _env, 1798 _value, 1799 1, 1800 reinterpret_cast<const napi_property_descriptor*>(&property)); 1801 NAPI_RETURN_OR_THROW_IF_FAILED(_env, status, status == napi_ok, bool); 1802} 1803 1804inline MaybeOrValue<bool> Object::DefineProperties( 1805 const std::initializer_list<PropertyDescriptor>& properties) const { 1806 napi_status status = napi_define_properties( 1807 _env, 1808 _value, 1809 properties.size(), 1810 reinterpret_cast<const napi_property_descriptor*>(properties.begin())); 1811 NAPI_RETURN_OR_THROW_IF_FAILED(_env, status, status == napi_ok, bool); 1812} 1813 1814inline MaybeOrValue<bool> Object::DefineProperties( 1815 const std::vector<PropertyDescriptor>& properties) const { 1816 napi_status status = napi_define_properties( 1817 _env, 1818 _value, 1819 properties.size(), 1820 reinterpret_cast<const napi_property_descriptor*>(properties.data())); 1821 NAPI_RETURN_OR_THROW_IF_FAILED(_env, status, status == napi_ok, bool); 1822} 1823 1824inline MaybeOrValue<bool> Object::InstanceOf( 1825 const Function& constructor) const { 1826 bool result; 1827 napi_status status = napi_instanceof(_env, _value, constructor, &result); 1828 NAPI_RETURN_OR_THROW_IF_FAILED(_env, status, result, bool); 1829} 1830 1831template <typename Finalizer, typename T> 1832inline void Object::AddFinalizer(Finalizer finalizeCallback, T* data) const { 1833 details::FinalizeData<T, Finalizer>* finalizeData = 1834 new details::FinalizeData<T, Finalizer>( 1835 {std::move(finalizeCallback), nullptr}); 1836 napi_status status = 1837 details::AttachData<T, details::FinalizeData<T, Finalizer>::Wrapper>( 1838 _env, *this, data, finalizeData); 1839 if (status != napi_ok) { 1840 delete finalizeData; 1841 NAPI_THROW_IF_FAILED_VOID(_env, status); 1842 } 1843} 1844 1845template <typename Finalizer, typename T, typename Hint> 1846inline void Object::AddFinalizer(Finalizer finalizeCallback, 1847 T* data, 1848 Hint* finalizeHint) const { 1849 details::FinalizeData<T, Finalizer, Hint>* finalizeData = 1850 new details::FinalizeData<T, Finalizer, Hint>( 1851 {std::move(finalizeCallback), finalizeHint}); 1852 napi_status status = details:: 1853 AttachData<T, details::FinalizeData<T, Finalizer, Hint>::WrapperWithHint>( 1854 _env, *this, data, finalizeData); 1855 if (status != napi_ok) { 1856 delete finalizeData; 1857 NAPI_THROW_IF_FAILED_VOID(_env, status); 1858 } 1859} 1860 1861#ifdef NODE_ADDON_API_CPP_EXCEPTIONS 1862inline Object::const_iterator::const_iterator(const Object* object, 1863 const Type type) { 1864 _object = object; 1865 _keys = object->GetPropertyNames(); 1866 _index = type == Type::BEGIN ? 0 : _keys.Length(); 1867} 1868 1869inline Object::const_iterator Napi::Object::begin() const { 1870 const_iterator it(this, Object::const_iterator::Type::BEGIN); 1871 return it; 1872} 1873 1874inline Object::const_iterator Napi::Object::end() const { 1875 const_iterator it(this, Object::const_iterator::Type::END); 1876 return it; 1877} 1878 1879inline Object::const_iterator& Object::const_iterator::operator++() { 1880 ++_index; 1881 return *this; 1882} 1883 1884inline bool Object::const_iterator::operator==( 1885 const const_iterator& other) const { 1886 return _index == other._index; 1887} 1888 1889inline bool Object::const_iterator::operator!=( 1890 const const_iterator& other) const { 1891 return _index != other._index; 1892} 1893 1894inline const std::pair<Value, Object::PropertyLValue<Value>> 1895Object::const_iterator::operator*() const { 1896 const Value key = _keys[_index]; 1897 const PropertyLValue<Value> value = (*_object)[key]; 1898 return {key, value}; 1899} 1900 1901inline Object::iterator::iterator(Object* object, const Type type) { 1902 _object = object; 1903 _keys = object->GetPropertyNames(); 1904 _index = type == Type::BEGIN ? 0 : _keys.Length(); 1905} 1906 1907inline Object::iterator Napi::Object::begin() { 1908 iterator it(this, Object::iterator::Type::BEGIN); 1909 return it; 1910} 1911 1912inline Object::iterator Napi::Object::end() { 1913 iterator it(this, Object::iterator::Type::END); 1914 return it; 1915} 1916 1917inline Object::iterator& Object::iterator::operator++() { 1918 ++_index; 1919 return *this; 1920} 1921 1922inline bool Object::iterator::operator==(const iterator& other) const { 1923 return _index == other._index; 1924} 1925 1926inline bool Object::iterator::operator!=(const iterator& other) const { 1927 return _index != other._index; 1928} 1929 1930inline std::pair<Value, Object::PropertyLValue<Value>> 1931Object::iterator::operator*() { 1932 Value key = _keys[_index]; 1933 PropertyLValue<Value> value = (*_object)[key]; 1934 return {key, value}; 1935} 1936#endif // NODE_ADDON_API_CPP_EXCEPTIONS 1937 1938#if NAPI_VERSION >= 8 1939inline MaybeOrValue<bool> Object::Freeze() const { 1940 napi_status status = napi_object_freeze(_env, _value); 1941 NAPI_RETURN_OR_THROW_IF_FAILED(_env, status, status == napi_ok, bool); 1942} 1943 1944inline MaybeOrValue<bool> Object::Seal() const { 1945 napi_status status = napi_object_seal(_env, _value); 1946 NAPI_RETURN_OR_THROW_IF_FAILED(_env, status, status == napi_ok, bool); 1947} 1948#endif // NAPI_VERSION >= 8 1949 1950//////////////////////////////////////////////////////////////////////////////// 1951// External class 1952//////////////////////////////////////////////////////////////////////////////// 1953 1954template <typename T> 1955inline External<T> External<T>::New(napi_env env, T* data) { 1956 napi_value value; 1957 napi_status status = 1958 napi_create_external(env, data, nullptr, nullptr, &value); 1959 NAPI_THROW_IF_FAILED(env, status, External()); 1960 return External(env, value); 1961} 1962 1963template <typename T> 1964template <typename Finalizer> 1965inline External<T> External<T>::New(napi_env env, 1966 T* data, 1967 Finalizer finalizeCallback) { 1968 napi_value value; 1969 details::FinalizeData<T, Finalizer>* finalizeData = 1970 new details::FinalizeData<T, Finalizer>( 1971 {std::move(finalizeCallback), nullptr}); 1972 napi_status status = 1973 napi_create_external(env, 1974 data, 1975 details::FinalizeData<T, Finalizer>::Wrapper, 1976 finalizeData, 1977 &value); 1978 if (status != napi_ok) { 1979 delete finalizeData; 1980 NAPI_THROW_IF_FAILED(env, status, External()); 1981 } 1982 return External(env, value); 1983} 1984 1985template <typename T> 1986template <typename Finalizer, typename Hint> 1987inline External<T> External<T>::New(napi_env env, 1988 T* data, 1989 Finalizer finalizeCallback, 1990 Hint* finalizeHint) { 1991 napi_value value; 1992 details::FinalizeData<T, Finalizer, Hint>* finalizeData = 1993 new details::FinalizeData<T, Finalizer, Hint>( 1994 {std::move(finalizeCallback), finalizeHint}); 1995 napi_status status = napi_create_external( 1996 env, 1997 data, 1998 details::FinalizeData<T, Finalizer, Hint>::WrapperWithHint, 1999 finalizeData, 2000 &value); 2001 if (status != napi_ok) { 2002 delete finalizeData; 2003 NAPI_THROW_IF_FAILED(env, status, External()); 2004 } 2005 return External(env, value); 2006} 2007 2008template <typename T> 2009inline void External<T>::CheckCast(napi_env env, napi_value value) { 2010 NAPI_CHECK(value != nullptr, "External::CheckCast", "empty value"); 2011 2012 napi_valuetype type; 2013 napi_status status = napi_typeof(env, value, &type); 2014 NAPI_CHECK(status == napi_ok, "External::CheckCast", "napi_typeof failed"); 2015 NAPI_INTERNAL_CHECK_EQ(type, napi_external, "%d", "External::CheckCast"); 2016} 2017 2018template <typename T> 2019inline External<T>::External() : TypeTaggable() {} 2020 2021template <typename T> 2022inline External<T>::External(napi_env env, napi_value value) 2023 : TypeTaggable(env, value) {} 2024 2025template <typename T> 2026inline T* External<T>::Data() const { 2027 void* data; 2028 napi_status status = napi_get_value_external(_env, _value, &data); 2029 NAPI_THROW_IF_FAILED(_env, status, nullptr); 2030 return reinterpret_cast<T*>(data); 2031} 2032 2033//////////////////////////////////////////////////////////////////////////////// 2034// Array class 2035//////////////////////////////////////////////////////////////////////////////// 2036 2037inline Array Array::New(napi_env env) { 2038 napi_value value; 2039 napi_status status = napi_create_array(env, &value); 2040 NAPI_THROW_IF_FAILED(env, status, Array()); 2041 return Array(env, value); 2042} 2043 2044inline Array Array::New(napi_env env, size_t length) { 2045 napi_value value; 2046 napi_status status = napi_create_array_with_length(env, length, &value); 2047 NAPI_THROW_IF_FAILED(env, status, Array()); 2048 return Array(env, value); 2049} 2050 2051inline void Array::CheckCast(napi_env env, napi_value value) { 2052 NAPI_CHECK(value != nullptr, "Array::CheckCast", "empty value"); 2053 2054 bool result; 2055 napi_status status = napi_is_array(env, value, &result); 2056 NAPI_CHECK(status == napi_ok, "Array::CheckCast", "napi_is_array failed"); 2057 NAPI_CHECK(result, "Array::CheckCast", "value is not array"); 2058} 2059 2060inline Array::Array() : Object() {} 2061 2062inline Array::Array(napi_env env, napi_value value) : Object(env, value) {} 2063 2064inline uint32_t Array::Length() const { 2065 uint32_t result; 2066 napi_status status = napi_get_array_length(_env, _value, &result); 2067 NAPI_THROW_IF_FAILED(_env, status, 0); 2068 return result; 2069} 2070 2071//////////////////////////////////////////////////////////////////////////////// 2072// ArrayBuffer class 2073//////////////////////////////////////////////////////////////////////////////// 2074 2075inline ArrayBuffer ArrayBuffer::New(napi_env env, size_t byteLength) { 2076 napi_value value; 2077 void* data; 2078 napi_status status = napi_create_arraybuffer(env, byteLength, &data, &value); 2079 NAPI_THROW_IF_FAILED(env, status, ArrayBuffer()); 2080 2081 return ArrayBuffer(env, value); 2082} 2083 2084#ifndef NODE_API_NO_EXTERNAL_BUFFERS_ALLOWED 2085inline ArrayBuffer ArrayBuffer::New(napi_env env, 2086 void* externalData, 2087 size_t byteLength) { 2088 napi_value value; 2089 napi_status status = napi_create_external_arraybuffer( 2090 env, externalData, byteLength, nullptr, nullptr, &value); 2091 NAPI_THROW_IF_FAILED(env, status, ArrayBuffer()); 2092 2093 return ArrayBuffer(env, value); 2094} 2095 2096template <typename Finalizer> 2097inline ArrayBuffer ArrayBuffer::New(napi_env env, 2098 void* externalData, 2099 size_t byteLength, 2100 Finalizer finalizeCallback) { 2101 napi_value value; 2102 details::FinalizeData<void, Finalizer>* finalizeData = 2103 new details::FinalizeData<void, Finalizer>( 2104 {std::move(finalizeCallback), nullptr}); 2105 napi_status status = napi_create_external_arraybuffer( 2106 env, 2107 externalData, 2108 byteLength, 2109 details::FinalizeData<void, Finalizer>::Wrapper, 2110 finalizeData, 2111 &value); 2112 if (status != napi_ok) { 2113 delete finalizeData; 2114 NAPI_THROW_IF_FAILED(env, status, ArrayBuffer()); 2115 } 2116 2117 return ArrayBuffer(env, value); 2118} 2119 2120template <typename Finalizer, typename Hint> 2121inline ArrayBuffer ArrayBuffer::New(napi_env env, 2122 void* externalData, 2123 size_t byteLength, 2124 Finalizer finalizeCallback, 2125 Hint* finalizeHint) { 2126 napi_value value; 2127 details::FinalizeData<void, Finalizer, Hint>* finalizeData = 2128 new details::FinalizeData<void, Finalizer, Hint>( 2129 {std::move(finalizeCallback), finalizeHint}); 2130 napi_status status = napi_create_external_arraybuffer( 2131 env, 2132 externalData, 2133 byteLength, 2134 details::FinalizeData<void, Finalizer, Hint>::WrapperWithHint, 2135 finalizeData, 2136 &value); 2137 if (status != napi_ok) { 2138 delete finalizeData; 2139 NAPI_THROW_IF_FAILED(env, status, ArrayBuffer()); 2140 } 2141 2142 return ArrayBuffer(env, value); 2143} 2144#endif // NODE_API_NO_EXTERNAL_BUFFERS_ALLOWED 2145 2146inline void ArrayBuffer::CheckCast(napi_env env, napi_value value) { 2147 NAPI_CHECK(value != nullptr, "ArrayBuffer::CheckCast", "empty value"); 2148 2149 bool result; 2150 napi_status status = napi_is_arraybuffer(env, value, &result); 2151 NAPI_CHECK(status == napi_ok, 2152 "ArrayBuffer::CheckCast", 2153 "napi_is_arraybuffer failed"); 2154 NAPI_CHECK(result, "ArrayBuffer::CheckCast", "value is not arraybuffer"); 2155} 2156 2157inline ArrayBuffer::ArrayBuffer() : Object() {} 2158 2159inline ArrayBuffer::ArrayBuffer(napi_env env, napi_value value) 2160 : Object(env, value) {} 2161 2162inline void* ArrayBuffer::Data() { 2163 void* data; 2164 napi_status status = napi_get_arraybuffer_info(_env, _value, &data, nullptr); 2165 NAPI_THROW_IF_FAILED(_env, status, nullptr); 2166 return data; 2167} 2168 2169inline size_t ArrayBuffer::ByteLength() { 2170 size_t length; 2171 napi_status status = 2172 napi_get_arraybuffer_info(_env, _value, nullptr, &length); 2173 NAPI_THROW_IF_FAILED(_env, status, 0); 2174 return length; 2175} 2176 2177#if NAPI_VERSION >= 7 2178inline bool ArrayBuffer::IsDetached() const { 2179 bool detached; 2180 napi_status status = napi_is_detached_arraybuffer(_env, _value, &detached); 2181 NAPI_THROW_IF_FAILED(_env, status, false); 2182 return detached; 2183} 2184 2185inline void ArrayBuffer::Detach() { 2186 napi_status status = napi_detach_arraybuffer(_env, _value); 2187 NAPI_THROW_IF_FAILED_VOID(_env, status); 2188} 2189#endif // NAPI_VERSION >= 7 2190 2191//////////////////////////////////////////////////////////////////////////////// 2192// DataView class 2193//////////////////////////////////////////////////////////////////////////////// 2194inline DataView DataView::New(napi_env env, Napi::ArrayBuffer arrayBuffer) { 2195 return New(env, arrayBuffer, 0, arrayBuffer.ByteLength()); 2196} 2197 2198inline DataView DataView::New(napi_env env, 2199 Napi::ArrayBuffer arrayBuffer, 2200 size_t byteOffset) { 2201 if (byteOffset > arrayBuffer.ByteLength()) { 2202 NAPI_THROW(RangeError::New( 2203 env, "Start offset is outside the bounds of the buffer"), 2204 DataView()); 2205 } 2206 return New( 2207 env, arrayBuffer, byteOffset, arrayBuffer.ByteLength() - byteOffset); 2208} 2209 2210inline DataView DataView::New(napi_env env, 2211 Napi::ArrayBuffer arrayBuffer, 2212 size_t byteOffset, 2213 size_t byteLength) { 2214 if (byteOffset + byteLength > arrayBuffer.ByteLength()) { 2215 NAPI_THROW(RangeError::New(env, "Invalid DataView length"), DataView()); 2216 } 2217 napi_value value; 2218 napi_status status = 2219 napi_create_dataview(env, byteLength, arrayBuffer, byteOffset, &value); 2220 NAPI_THROW_IF_FAILED(env, status, DataView()); 2221 return DataView(env, value); 2222} 2223 2224inline void DataView::CheckCast(napi_env env, napi_value value) { 2225 NAPI_CHECK(value != nullptr, "DataView::CheckCast", "empty value"); 2226 2227 bool result; 2228 napi_status status = napi_is_dataview(env, value, &result); 2229 NAPI_CHECK( 2230 status == napi_ok, "DataView::CheckCast", "napi_is_dataview failed"); 2231 NAPI_CHECK(result, "DataView::CheckCast", "value is not dataview"); 2232} 2233 2234inline DataView::DataView() : Object() {} 2235 2236inline DataView::DataView(napi_env env, napi_value value) : Object(env, value) { 2237 napi_status status = napi_get_dataview_info(_env, 2238 _value /* dataView */, 2239 &_length /* byteLength */, 2240 &_data /* data */, 2241 nullptr /* arrayBuffer */, 2242 nullptr /* byteOffset */); 2243 NAPI_THROW_IF_FAILED_VOID(_env, status); 2244} 2245 2246inline Napi::ArrayBuffer DataView::ArrayBuffer() const { 2247 napi_value arrayBuffer; 2248 napi_status status = napi_get_dataview_info(_env, 2249 _value /* dataView */, 2250 nullptr /* byteLength */, 2251 nullptr /* data */, 2252 &arrayBuffer /* arrayBuffer */, 2253 nullptr /* byteOffset */); 2254 NAPI_THROW_IF_FAILED(_env, status, Napi::ArrayBuffer()); 2255 return Napi::ArrayBuffer(_env, arrayBuffer); 2256} 2257 2258inline size_t DataView::ByteOffset() const { 2259 size_t byteOffset; 2260 napi_status status = napi_get_dataview_info(_env, 2261 _value /* dataView */, 2262 nullptr /* byteLength */, 2263 nullptr /* data */, 2264 nullptr /* arrayBuffer */, 2265 &byteOffset /* byteOffset */); 2266 NAPI_THROW_IF_FAILED(_env, status, 0); 2267 return byteOffset; 2268} 2269 2270inline size_t DataView::ByteLength() const { 2271 return _length; 2272} 2273 2274inline void* DataView::Data() const { 2275 return _data; 2276} 2277 2278inline float DataView::GetFloat32(size_t byteOffset) const { 2279 return ReadData<float>(byteOffset); 2280} 2281 2282inline double DataView::GetFloat64(size_t byteOffset) const { 2283 return ReadData<double>(byteOffset); 2284} 2285 2286inline int8_t DataView::GetInt8(size_t byteOffset) const { 2287 return ReadData<int8_t>(byteOffset); 2288} 2289 2290inline int16_t DataView::GetInt16(size_t byteOffset) const { 2291 return ReadData<int16_t>(byteOffset); 2292} 2293 2294inline int32_t DataView::GetInt32(size_t byteOffset) const { 2295 return ReadData<int32_t>(byteOffset); 2296} 2297 2298inline uint8_t DataView::GetUint8(size_t byteOffset) const { 2299 return ReadData<uint8_t>(byteOffset); 2300} 2301 2302inline uint16_t DataView::GetUint16(size_t byteOffset) const { 2303 return ReadData<uint16_t>(byteOffset); 2304} 2305 2306inline uint32_t DataView::GetUint32(size_t byteOffset) const { 2307 return ReadData<uint32_t>(byteOffset); 2308} 2309 2310inline void DataView::SetFloat32(size_t byteOffset, float value) const { 2311 WriteData<float>(byteOffset, value); 2312} 2313 2314inline void DataView::SetFloat64(size_t byteOffset, double value) const { 2315 WriteData<double>(byteOffset, value); 2316} 2317 2318inline void DataView::SetInt8(size_t byteOffset, int8_t value) const { 2319 WriteData<int8_t>(byteOffset, value); 2320} 2321 2322inline void DataView::SetInt16(size_t byteOffset, int16_t value) const { 2323 WriteData<int16_t>(byteOffset, value); 2324} 2325 2326inline void DataView::SetInt32(size_t byteOffset, int32_t value) const { 2327 WriteData<int32_t>(byteOffset, value); 2328} 2329 2330inline void DataView::SetUint8(size_t byteOffset, uint8_t value) const { 2331 WriteData<uint8_t>(byteOffset, value); 2332} 2333 2334inline void DataView::SetUint16(size_t byteOffset, uint16_t value) const { 2335 WriteData<uint16_t>(byteOffset, value); 2336} 2337 2338inline void DataView::SetUint32(size_t byteOffset, uint32_t value) const { 2339 WriteData<uint32_t>(byteOffset, value); 2340} 2341 2342template <typename T> 2343inline T DataView::ReadData(size_t byteOffset) const { 2344 if (byteOffset + sizeof(T) > _length || 2345 byteOffset + sizeof(T) < byteOffset) { // overflow 2346 NAPI_THROW( 2347 RangeError::New(_env, "Offset is outside the bounds of the DataView"), 2348 0); 2349 } 2350 2351 return *reinterpret_cast<T*>(static_cast<uint8_t*>(_data) + byteOffset); 2352} 2353 2354template <typename T> 2355inline void DataView::WriteData(size_t byteOffset, T value) const { 2356 if (byteOffset + sizeof(T) > _length || 2357 byteOffset + sizeof(T) < byteOffset) { // overflow 2358 NAPI_THROW_VOID( 2359 RangeError::New(_env, "Offset is outside the bounds of the DataView")); 2360 } 2361 2362 *reinterpret_cast<T*>(static_cast<uint8_t*>(_data) + byteOffset) = value; 2363} 2364 2365//////////////////////////////////////////////////////////////////////////////// 2366// TypedArray class 2367//////////////////////////////////////////////////////////////////////////////// 2368inline void TypedArray::CheckCast(napi_env env, napi_value value) { 2369 NAPI_CHECK(value != nullptr, "TypedArray::CheckCast", "empty value"); 2370 2371 bool result; 2372 napi_status status = napi_is_typedarray(env, value, &result); 2373 NAPI_CHECK( 2374 status == napi_ok, "TypedArray::CheckCast", "napi_is_typedarray failed"); 2375 NAPI_CHECK(result, "TypedArray::CheckCast", "value is not typedarray"); 2376} 2377 2378inline TypedArray::TypedArray() 2379 : Object(), _type(napi_typedarray_type::napi_int8_array), _length(0) {} 2380 2381inline TypedArray::TypedArray(napi_env env, napi_value value) 2382 : Object(env, value), 2383 _type(napi_typedarray_type::napi_int8_array), 2384 _length(0) { 2385 if (value != nullptr) { 2386 napi_status status = 2387 napi_get_typedarray_info(_env, 2388 _value, 2389 &const_cast<TypedArray*>(this)->_type, 2390 &const_cast<TypedArray*>(this)->_length, 2391 nullptr, 2392 nullptr, 2393 nullptr); 2394 NAPI_THROW_IF_FAILED_VOID(_env, status); 2395 } 2396} 2397 2398inline TypedArray::TypedArray(napi_env env, 2399 napi_value value, 2400 napi_typedarray_type type, 2401 size_t length) 2402 : Object(env, value), _type(type), _length(length) {} 2403 2404inline napi_typedarray_type TypedArray::TypedArrayType() const { 2405 return _type; 2406} 2407 2408inline uint8_t TypedArray::ElementSize() const { 2409 switch (_type) { 2410 case napi_int8_array: 2411 case napi_uint8_array: 2412 case napi_uint8_clamped_array: 2413 return 1; 2414 case napi_int16_array: 2415 case napi_uint16_array: 2416 return 2; 2417 case napi_int32_array: 2418 case napi_uint32_array: 2419 case napi_float32_array: 2420 return 4; 2421 case napi_float64_array: 2422#if (NAPI_VERSION > 5) 2423 case napi_bigint64_array: 2424 case napi_biguint64_array: 2425#endif // (NAPI_VERSION > 5) 2426 return 8; 2427 default: 2428 return 0; 2429 } 2430} 2431 2432inline size_t TypedArray::ElementLength() const { 2433 return _length; 2434} 2435 2436inline size_t TypedArray::ByteOffset() const { 2437 size_t byteOffset; 2438 napi_status status = napi_get_typedarray_info( 2439 _env, _value, nullptr, nullptr, nullptr, nullptr, &byteOffset); 2440 NAPI_THROW_IF_FAILED(_env, status, 0); 2441 return byteOffset; 2442} 2443 2444inline size_t TypedArray::ByteLength() const { 2445 return ElementSize() * ElementLength(); 2446} 2447 2448inline Napi::ArrayBuffer TypedArray::ArrayBuffer() const { 2449 napi_value arrayBuffer; 2450 napi_status status = napi_get_typedarray_info( 2451 _env, _value, nullptr, nullptr, nullptr, &arrayBuffer, nullptr); 2452 NAPI_THROW_IF_FAILED(_env, status, Napi::ArrayBuffer()); 2453 return Napi::ArrayBuffer(_env, arrayBuffer); 2454} 2455 2456//////////////////////////////////////////////////////////////////////////////// 2457// TypedArrayOf<T> class 2458//////////////////////////////////////////////////////////////////////////////// 2459template <typename T> 2460inline void TypedArrayOf<T>::CheckCast(napi_env env, napi_value value) { 2461 TypedArray::CheckCast(env, value); 2462 napi_typedarray_type type; 2463 napi_status status = napi_get_typedarray_info( 2464 env, value, &type, nullptr, nullptr, nullptr, nullptr); 2465 NAPI_CHECK(status == napi_ok, 2466 "TypedArrayOf::CheckCast", 2467 "napi_is_typedarray failed"); 2468 2469 NAPI_INTERNAL_CHECK( 2470 (type == TypedArrayTypeForPrimitiveType<T>() || 2471 (type == napi_uint8_clamped_array && std::is_same<T, uint8_t>::value)), 2472 "TypedArrayOf::CheckCast", 2473 "Array type must match the template parameter, (Uint8 arrays may " 2474 "optionally have the \"clamped\" array type.), got %d.", 2475 type); 2476} 2477 2478template <typename T> 2479inline TypedArrayOf<T> TypedArrayOf<T>::New(napi_env env, 2480 size_t elementLength, 2481 napi_typedarray_type type) { 2482 Napi::ArrayBuffer arrayBuffer = 2483 Napi::ArrayBuffer::New(env, elementLength * sizeof(T)); 2484 return New(env, elementLength, arrayBuffer, 0, type); 2485} 2486 2487template <typename T> 2488inline TypedArrayOf<T> TypedArrayOf<T>::New(napi_env env, 2489 size_t elementLength, 2490 Napi::ArrayBuffer arrayBuffer, 2491 size_t bufferOffset, 2492 napi_typedarray_type type) { 2493 napi_value value; 2494 napi_status status = napi_create_typedarray( 2495 env, type, elementLength, arrayBuffer, bufferOffset, &value); 2496 NAPI_THROW_IF_FAILED(env, status, TypedArrayOf<T>()); 2497 2498 return TypedArrayOf<T>( 2499 env, 2500 value, 2501 type, 2502 elementLength, 2503 reinterpret_cast<T*>(reinterpret_cast<uint8_t*>(arrayBuffer.Data()) + 2504 bufferOffset)); 2505} 2506 2507template <typename T> 2508inline TypedArrayOf<T>::TypedArrayOf() : TypedArray(), _data(nullptr) {} 2509 2510template <typename T> 2511inline TypedArrayOf<T>::TypedArrayOf(napi_env env, napi_value value) 2512 : TypedArray(env, value), _data(nullptr) { 2513 napi_status status = napi_ok; 2514 if (value != nullptr) { 2515 void* data = nullptr; 2516 status = napi_get_typedarray_info( 2517 _env, _value, &_type, &_length, &data, nullptr, nullptr); 2518 _data = static_cast<T*>(data); 2519 } else { 2520 _type = TypedArrayTypeForPrimitiveType<T>(); 2521 _length = 0; 2522 } 2523 NAPI_THROW_IF_FAILED_VOID(_env, status); 2524} 2525 2526template <typename T> 2527inline TypedArrayOf<T>::TypedArrayOf(napi_env env, 2528 napi_value value, 2529 napi_typedarray_type type, 2530 size_t length, 2531 T* data) 2532 : TypedArray(env, value, type, length), _data(data) { 2533 if (!(type == TypedArrayTypeForPrimitiveType<T>() || 2534 (type == napi_uint8_clamped_array && 2535 std::is_same<T, uint8_t>::value))) { 2536 NAPI_THROW_VOID(TypeError::New( 2537 env, 2538 "Array type must match the template parameter. " 2539 "(Uint8 arrays may optionally have the \"clamped\" array type.)")); 2540 } 2541} 2542 2543template <typename T> 2544inline T& TypedArrayOf<T>::operator[](size_t index) { 2545 return _data[index]; 2546} 2547 2548template <typename T> 2549inline const T& TypedArrayOf<T>::operator[](size_t index) const { 2550 return _data[index]; 2551} 2552 2553template <typename T> 2554inline T* TypedArrayOf<T>::Data() { 2555 return _data; 2556} 2557 2558template <typename T> 2559inline const T* TypedArrayOf<T>::Data() const { 2560 return _data; 2561} 2562 2563//////////////////////////////////////////////////////////////////////////////// 2564// Function class 2565//////////////////////////////////////////////////////////////////////////////// 2566 2567template <typename CbData> 2568inline napi_status CreateFunction(napi_env env, 2569 const char* utf8name, 2570 napi_callback cb, 2571 CbData* data, 2572 napi_value* result) { 2573 napi_status status = 2574 napi_create_function(env, utf8name, NAPI_AUTO_LENGTH, cb, data, result); 2575 if (status == napi_ok) { 2576 status = Napi::details::AttachData(env, *result, data); 2577 } 2578 2579 return status; 2580} 2581 2582template <Function::VoidCallback cb> 2583inline Function Function::New(napi_env env, const char* utf8name, void* data) { 2584 napi_value result = nullptr; 2585 napi_status status = napi_create_function(env, 2586 utf8name, 2587 NAPI_AUTO_LENGTH, 2588 details::TemplatedVoidCallback<cb>, 2589 data, 2590 &result); 2591 NAPI_THROW_IF_FAILED(env, status, Function()); 2592 return Function(env, result); 2593} 2594 2595template <Function::Callback cb> 2596inline Function Function::New(napi_env env, const char* utf8name, void* data) { 2597 napi_value result = nullptr; 2598 napi_status status = napi_create_function(env, 2599 utf8name, 2600 NAPI_AUTO_LENGTH, 2601 details::TemplatedCallback<cb>, 2602 data, 2603 &result); 2604 NAPI_THROW_IF_FAILED(env, status, Function()); 2605 return Function(env, result); 2606} 2607 2608template <Function::VoidCallback cb> 2609inline Function Function::New(napi_env env, 2610 const std::string& utf8name, 2611 void* data) { 2612 return Function::New<cb>(env, utf8name.c_str(), data); 2613} 2614 2615template <Function::Callback cb> 2616inline Function Function::New(napi_env env, 2617 const std::string& utf8name, 2618 void* data) { 2619 return Function::New<cb>(env, utf8name.c_str(), data); 2620} 2621 2622template <typename Callable> 2623inline Function Function::New(napi_env env, 2624 Callable cb, 2625 const char* utf8name, 2626 void* data) { 2627 using ReturnType = decltype(cb(CallbackInfo(nullptr, nullptr))); 2628 using CbData = details::CallbackData<Callable, ReturnType>; 2629 auto callbackData = new CbData{std::move(cb), data}; 2630 2631 napi_value value; 2632 napi_status status = 2633 CreateFunction(env, utf8name, CbData::Wrapper, callbackData, &value); 2634 if (status != napi_ok) { 2635 delete callbackData; 2636 NAPI_THROW_IF_FAILED(env, status, Function()); 2637 } 2638 2639 return Function(env, value); 2640} 2641 2642template <typename Callable> 2643inline Function Function::New(napi_env env, 2644 Callable cb, 2645 const std::string& utf8name, 2646 void* data) { 2647 return New(env, cb, utf8name.c_str(), data); 2648} 2649 2650inline void Function::CheckCast(napi_env env, napi_value value) { 2651 NAPI_CHECK(value != nullptr, "Function::CheckCast", "empty value"); 2652 2653 napi_valuetype type; 2654 napi_status status = napi_typeof(env, value, &type); 2655 NAPI_CHECK(status == napi_ok, "Function::CheckCast", "napi_typeof failed"); 2656 NAPI_INTERNAL_CHECK_EQ(type, napi_function, "%d", "Function::CheckCast"); 2657} 2658 2659inline Function::Function() : Object() {} 2660 2661inline Function::Function(napi_env env, napi_value value) 2662 : Object(env, value) {} 2663 2664inline MaybeOrValue<Value> Function::operator()( 2665 const std::initializer_list<napi_value>& args) const { 2666 return Call(Env().Undefined(), args); 2667} 2668 2669inline MaybeOrValue<Value> Function::Call( 2670 const std::initializer_list<napi_value>& args) const { 2671 return Call(Env().Undefined(), args); 2672} 2673 2674inline MaybeOrValue<Value> Function::Call( 2675 const std::vector<napi_value>& args) const { 2676 return Call(Env().Undefined(), args); 2677} 2678 2679inline MaybeOrValue<Value> Function::Call( 2680 const std::vector<Value>& args) const { 2681 return Call(Env().Undefined(), args); 2682} 2683 2684inline MaybeOrValue<Value> Function::Call(size_t argc, 2685 const napi_value* args) const { 2686 return Call(Env().Undefined(), argc, args); 2687} 2688 2689inline MaybeOrValue<Value> Function::Call( 2690 napi_value recv, const std::initializer_list<napi_value>& args) const { 2691 return Call(recv, args.size(), args.begin()); 2692} 2693 2694inline MaybeOrValue<Value> Function::Call( 2695 napi_value recv, const std::vector<napi_value>& args) const { 2696 return Call(recv, args.size(), args.data()); 2697} 2698 2699inline MaybeOrValue<Value> Function::Call( 2700 napi_value recv, const std::vector<Value>& args) const { 2701 const size_t argc = args.size(); 2702 const size_t stackArgsCount = 6; 2703 napi_value stackArgs[stackArgsCount]; 2704 std::vector<napi_value> heapArgs; 2705 napi_value* argv; 2706 if (argc <= stackArgsCount) { 2707 argv = stackArgs; 2708 } else { 2709 heapArgs.resize(argc); 2710 argv = heapArgs.data(); 2711 } 2712 2713 for (size_t index = 0; index < argc; index++) { 2714 argv[index] = static_cast<napi_value>(args[index]); 2715 } 2716 2717 return Call(recv, argc, argv); 2718} 2719 2720inline MaybeOrValue<Value> Function::Call(napi_value recv, 2721 size_t argc, 2722 const napi_value* args) const { 2723 napi_value result; 2724 napi_status status = 2725 napi_call_function(_env, recv, _value, argc, args, &result); 2726 NAPI_RETURN_OR_THROW_IF_FAILED( 2727 _env, status, Napi::Value(_env, result), Napi::Value); 2728} 2729 2730inline MaybeOrValue<Value> Function::MakeCallback( 2731 napi_value recv, 2732 const std::initializer_list<napi_value>& args, 2733 napi_async_context context) const { 2734 return MakeCallback(recv, args.size(), args.begin(), context); 2735} 2736 2737inline MaybeOrValue<Value> Function::MakeCallback( 2738 napi_value recv, 2739 const std::vector<napi_value>& args, 2740 napi_async_context context) const { 2741 return MakeCallback(recv, args.size(), args.data(), context); 2742} 2743 2744inline MaybeOrValue<Value> Function::MakeCallback( 2745 napi_value recv, 2746 size_t argc, 2747 const napi_value* args, 2748 napi_async_context context) const { 2749 napi_value result; 2750 napi_status status = 2751 napi_make_callback(_env, context, recv, _value, argc, args, &result); 2752 NAPI_RETURN_OR_THROW_IF_FAILED( 2753 _env, status, Napi::Value(_env, result), Napi::Value); 2754} 2755 2756inline MaybeOrValue<Object> Function::New( 2757 const std::initializer_list<napi_value>& args) const { 2758 return New(args.size(), args.begin()); 2759} 2760 2761inline MaybeOrValue<Object> Function::New( 2762 const std::vector<napi_value>& args) const { 2763 return New(args.size(), args.data()); 2764} 2765 2766inline MaybeOrValue<Object> Function::New(size_t argc, 2767 const napi_value* args) const { 2768 napi_value result; 2769 napi_status status = napi_new_instance(_env, _value, argc, args, &result); 2770 NAPI_RETURN_OR_THROW_IF_FAILED( 2771 _env, status, Napi::Object(_env, result), Napi::Object); 2772} 2773 2774//////////////////////////////////////////////////////////////////////////////// 2775// Promise class 2776//////////////////////////////////////////////////////////////////////////////// 2777 2778inline Promise::Deferred Promise::Deferred::New(napi_env env) { 2779 return Promise::Deferred(env); 2780} 2781 2782inline Promise::Deferred::Deferred(napi_env env) : _env(env) { 2783 napi_status status = napi_create_promise(_env, &_deferred, &_promise); 2784 NAPI_THROW_IF_FAILED_VOID(_env, status); 2785} 2786 2787inline Promise Promise::Deferred::Promise() const { 2788 return Napi::Promise(_env, _promise); 2789} 2790 2791inline Napi::Env Promise::Deferred::Env() const { 2792 return Napi::Env(_env); 2793} 2794 2795inline void Promise::Deferred::Resolve(napi_value value) const { 2796 napi_status status = napi_resolve_deferred(_env, _deferred, value); 2797 NAPI_THROW_IF_FAILED_VOID(_env, status); 2798} 2799 2800inline void Promise::Deferred::Reject(napi_value value) const { 2801 napi_status status = napi_reject_deferred(_env, _deferred, value); 2802 NAPI_THROW_IF_FAILED_VOID(_env, status); 2803} 2804 2805inline void Promise::CheckCast(napi_env env, napi_value value) { 2806 NAPI_CHECK(value != nullptr, "Promise::CheckCast", "empty value"); 2807 2808 bool result; 2809 napi_status status = napi_is_promise(env, value, &result); 2810 NAPI_CHECK(status == napi_ok, "Promise::CheckCast", "napi_is_promise failed"); 2811 NAPI_CHECK(result, "Promise::CheckCast", "value is not promise"); 2812} 2813 2814inline Promise::Promise() : Object() {} 2815 2816inline Promise::Promise(napi_env env, napi_value value) : Object(env, value) {} 2817 2818inline MaybeOrValue<Promise> Promise::Then(napi_value onFulfilled) const { 2819 EscapableHandleScope scope(_env); 2820#ifdef NODE_ADDON_API_ENABLE_MAYBE 2821 Value thenMethod; 2822 if (!Get("then").UnwrapTo(&thenMethod)) { 2823 return Nothing<Promise>(); 2824 } 2825 MaybeOrValue<Value> result = 2826 thenMethod.As<Function>().Call(*this, {onFulfilled}); 2827 if (result.IsJust()) { 2828 return Just(scope.Escape(result.Unwrap()).As<Promise>()); 2829 } 2830 return Nothing<Promise>(); 2831#else 2832 Function thenMethod = Get("then").As<Function>(); 2833 MaybeOrValue<Value> result = thenMethod.Call(*this, {onFulfilled}); 2834 if (scope.Env().IsExceptionPending()) { 2835 return Promise(); 2836 } 2837 return scope.Escape(result).As<Promise>(); 2838#endif 2839} 2840 2841inline MaybeOrValue<Promise> Promise::Then(napi_value onFulfilled, 2842 napi_value onRejected) const { 2843 EscapableHandleScope scope(_env); 2844#ifdef NODE_ADDON_API_ENABLE_MAYBE 2845 Value thenMethod; 2846 if (!Get("then").UnwrapTo(&thenMethod)) { 2847 return Nothing<Promise>(); 2848 } 2849 MaybeOrValue<Value> result = 2850 thenMethod.As<Function>().Call(*this, {onFulfilled, onRejected}); 2851 if (result.IsJust()) { 2852 return Just(scope.Escape(result.Unwrap()).As<Promise>()); 2853 } 2854 return Nothing<Promise>(); 2855#else 2856 Function thenMethod = Get("then").As<Function>(); 2857 MaybeOrValue<Value> result = 2858 thenMethod.Call(*this, {onFulfilled, onRejected}); 2859 if (scope.Env().IsExceptionPending()) { 2860 return Promise(); 2861 } 2862 return scope.Escape(result).As<Promise>(); 2863#endif 2864} 2865 2866inline MaybeOrValue<Promise> Promise::Catch(napi_value onRejected) const { 2867 EscapableHandleScope scope(_env); 2868#ifdef NODE_ADDON_API_ENABLE_MAYBE 2869 Value catchMethod; 2870 if (!Get("catch").UnwrapTo(&catchMethod)) { 2871 return Nothing<Promise>(); 2872 } 2873 MaybeOrValue<Value> result = 2874 catchMethod.As<Function>().Call(*this, {onRejected}); 2875 if (result.IsJust()) { 2876 return Just(scope.Escape(result.Unwrap()).As<Promise>()); 2877 } 2878 return Nothing<Promise>(); 2879#else 2880 Function catchMethod = Get("catch").As<Function>(); 2881 MaybeOrValue<Value> result = catchMethod.Call(*this, {onRejected}); 2882 if (scope.Env().IsExceptionPending()) { 2883 return Promise(); 2884 } 2885 return scope.Escape(result).As<Promise>(); 2886#endif 2887} 2888 2889inline MaybeOrValue<Promise> Promise::Then(const Function& onFulfilled) const { 2890 return Then(static_cast<napi_value>(onFulfilled)); 2891} 2892 2893inline MaybeOrValue<Promise> Promise::Then(const Function& onFulfilled, 2894 const Function& onRejected) const { 2895 return Then(static_cast<napi_value>(onFulfilled), 2896 static_cast<napi_value>(onRejected)); 2897} 2898 2899inline MaybeOrValue<Promise> Promise::Catch(const Function& onRejected) const { 2900 return Catch(static_cast<napi_value>(onRejected)); 2901} 2902 2903//////////////////////////////////////////////////////////////////////////////// 2904// Buffer<T> class 2905//////////////////////////////////////////////////////////////////////////////// 2906 2907template <typename T> 2908inline Buffer<T> Buffer<T>::New(napi_env env, size_t length) { 2909 napi_value value; 2910 void* data; 2911 napi_status status = 2912 napi_create_buffer(env, length * sizeof(T), &data, &value); 2913 NAPI_THROW_IF_FAILED(env, status, Buffer<T>()); 2914 return Buffer(env, value); 2915} 2916 2917#ifndef NODE_API_NO_EXTERNAL_BUFFERS_ALLOWED 2918template <typename T> 2919inline Buffer<T> Buffer<T>::New(napi_env env, T* data, size_t length) { 2920 napi_value value; 2921 napi_status status = napi_create_external_buffer( 2922 env, length * sizeof(T), data, nullptr, nullptr, &value); 2923 NAPI_THROW_IF_FAILED(env, status, Buffer<T>()); 2924 return Buffer(env, value); 2925} 2926 2927template <typename T> 2928template <typename Finalizer> 2929inline Buffer<T> Buffer<T>::New(napi_env env, 2930 T* data, 2931 size_t length, 2932 Finalizer finalizeCallback) { 2933 napi_value value; 2934 details::FinalizeData<T, Finalizer>* finalizeData = 2935 new details::FinalizeData<T, Finalizer>( 2936 {std::move(finalizeCallback), nullptr}); 2937 napi_status status = 2938 napi_create_external_buffer(env, 2939 length * sizeof(T), 2940 data, 2941 details::FinalizeData<T, Finalizer>::Wrapper, 2942 finalizeData, 2943 &value); 2944 if (status != napi_ok) { 2945 delete finalizeData; 2946 NAPI_THROW_IF_FAILED(env, status, Buffer()); 2947 } 2948 return Buffer(env, value); 2949} 2950 2951template <typename T> 2952template <typename Finalizer, typename Hint> 2953inline Buffer<T> Buffer<T>::New(napi_env env, 2954 T* data, 2955 size_t length, 2956 Finalizer finalizeCallback, 2957 Hint* finalizeHint) { 2958 napi_value value; 2959 details::FinalizeData<T, Finalizer, Hint>* finalizeData = 2960 new details::FinalizeData<T, Finalizer, Hint>( 2961 {std::move(finalizeCallback), finalizeHint}); 2962 napi_status status = napi_create_external_buffer( 2963 env, 2964 length * sizeof(T), 2965 data, 2966 details::FinalizeData<T, Finalizer, Hint>::WrapperWithHint, 2967 finalizeData, 2968 &value); 2969 if (status != napi_ok) { 2970 delete finalizeData; 2971 NAPI_THROW_IF_FAILED(env, status, Buffer()); 2972 } 2973 return Buffer(env, value); 2974} 2975#endif // NODE_API_NO_EXTERNAL_BUFFERS_ALLOWED 2976 2977template <typename T> 2978inline Buffer<T> Buffer<T>::NewOrCopy(napi_env env, T* data, size_t length) { 2979#ifndef NODE_API_NO_EXTERNAL_BUFFERS_ALLOWED 2980 napi_value value; 2981 napi_status status = napi_create_external_buffer( 2982 env, length * sizeof(T), data, nullptr, nullptr, &value); 2983 if (status == details::napi_no_external_buffers_allowed) { 2984#endif // NODE_API_NO_EXTERNAL_BUFFERS_ALLOWED 2985 // If we can't create an external buffer, we'll just copy the data. 2986 return Buffer<T>::Copy(env, data, length); 2987#ifndef NODE_API_NO_EXTERNAL_BUFFERS_ALLOWED 2988 } 2989 NAPI_THROW_IF_FAILED(env, status, Buffer<T>()); 2990 return Buffer(env, value); 2991#endif // NODE_API_NO_EXTERNAL_BUFFERS_ALLOWED 2992} 2993 2994template <typename T> 2995template <typename Finalizer> 2996inline Buffer<T> Buffer<T>::NewOrCopy(napi_env env, 2997 T* data, 2998 size_t length, 2999 Finalizer finalizeCallback) { 3000 details::FinalizeData<T, Finalizer>* finalizeData = 3001 new details::FinalizeData<T, Finalizer>( 3002 {std::move(finalizeCallback), nullptr}); 3003#ifndef NODE_API_NO_EXTERNAL_BUFFERS_ALLOWED 3004 napi_value value; 3005 napi_status status = 3006 napi_create_external_buffer(env, 3007 length * sizeof(T), 3008 data, 3009 details::FinalizeData<T, Finalizer>::Wrapper, 3010 finalizeData, 3011 &value); 3012 if (status == details::napi_no_external_buffers_allowed) { 3013#endif // NODE_API_NO_EXTERNAL_BUFFERS_ALLOWED 3014 // If we can't create an external buffer, we'll just copy the data. 3015 Buffer<T> ret = Buffer<T>::Copy(env, data, length); 3016 details::FinalizeData<T, Finalizer>::WrapperGC(env, data, finalizeData); 3017 return ret; 3018#ifndef NODE_API_NO_EXTERNAL_BUFFERS_ALLOWED 3019 } 3020 if (status != napi_ok) { 3021 delete finalizeData; 3022 NAPI_THROW_IF_FAILED(env, status, Buffer()); 3023 } 3024 return Buffer(env, value); 3025#endif // NODE_API_NO_EXTERNAL_BUFFERS_ALLOWED 3026} 3027 3028template <typename T> 3029template <typename Finalizer, typename Hint> 3030inline Buffer<T> Buffer<T>::NewOrCopy(napi_env env, 3031 T* data, 3032 size_t length, 3033 Finalizer finalizeCallback, 3034 Hint* finalizeHint) { 3035 details::FinalizeData<T, Finalizer, Hint>* finalizeData = 3036 new details::FinalizeData<T, Finalizer, Hint>( 3037 {std::move(finalizeCallback), finalizeHint}); 3038#ifndef NODE_API_NO_EXTERNAL_BUFFERS_ALLOWED 3039 napi_value value; 3040 napi_status status = napi_create_external_buffer( 3041 env, 3042 length * sizeof(T), 3043 data, 3044 details::FinalizeData<T, Finalizer, Hint>::WrapperWithHint, 3045 finalizeData, 3046 &value); 3047 if (status == details::napi_no_external_buffers_allowed) { 3048#endif 3049 // If we can't create an external buffer, we'll just copy the data. 3050 Buffer<T> ret = Buffer<T>::Copy(env, data, length); 3051 details::FinalizeData<T, Finalizer, Hint>::WrapperGCWithHint( 3052 env, data, finalizeData); 3053 return ret; 3054#ifndef NODE_API_NO_EXTERNAL_BUFFERS_ALLOWED 3055 } 3056 if (status != napi_ok) { 3057 delete finalizeData; 3058 NAPI_THROW_IF_FAILED(env, status, Buffer()); 3059 } 3060 return Buffer(env, value); 3061#endif 3062} 3063 3064template <typename T> 3065inline Buffer<T> Buffer<T>::Copy(napi_env env, const T* data, size_t length) { 3066 napi_value value; 3067 napi_status status = 3068 napi_create_buffer_copy(env, length * sizeof(T), data, nullptr, &value); 3069 NAPI_THROW_IF_FAILED(env, status, Buffer<T>()); 3070 return Buffer<T>(env, value); 3071} 3072 3073template <typename T> 3074inline void Buffer<T>::CheckCast(napi_env env, napi_value value) { 3075 NAPI_CHECK(value != nullptr, "Buffer::CheckCast", "empty value"); 3076 3077 bool result; 3078 napi_status status = napi_is_buffer(env, value, &result); 3079 NAPI_CHECK(status == napi_ok, "Buffer::CheckCast", "napi_is_buffer failed"); 3080 NAPI_CHECK(result, "Buffer::CheckCast", "value is not buffer"); 3081} 3082 3083template <typename T> 3084inline Buffer<T>::Buffer() : Uint8Array() {} 3085 3086template <typename T> 3087inline Buffer<T>::Buffer(napi_env env, napi_value value) 3088 : Uint8Array(env, value) {} 3089 3090template <typename T> 3091inline size_t Buffer<T>::Length() const { 3092 return ByteLength() / sizeof(T); 3093} 3094 3095template <typename T> 3096inline T* Buffer<T>::Data() const { 3097 return reinterpret_cast<T*>(const_cast<uint8_t*>(Uint8Array::Data())); 3098} 3099 3100//////////////////////////////////////////////////////////////////////////////// 3101// Error class 3102//////////////////////////////////////////////////////////////////////////////// 3103 3104inline Error Error::New(napi_env env) { 3105 napi_status status; 3106 napi_value error = nullptr; 3107 bool is_exception_pending; 3108 napi_extended_error_info last_error_info_copy; 3109 3110 { 3111 // We must retrieve the last error info before doing anything else because 3112 // doing anything else will replace the last error info. 3113 const napi_extended_error_info* last_error_info; 3114 status = napi_get_last_error_info(env, &last_error_info); 3115 NAPI_FATAL_IF_FAILED(status, "Error::New", "napi_get_last_error_info"); 3116 3117 // All fields of the `napi_extended_error_info` structure gets reset in 3118 // subsequent Node-API function calls on the same `env`. This includes a 3119 // call to `napi_is_exception_pending()`. So here it is necessary to make a 3120 // copy of the information as the `error_code` field is used later on. 3121 memcpy(&last_error_info_copy, 3122 last_error_info, 3123 sizeof(napi_extended_error_info)); 3124 } 3125 3126 status = napi_is_exception_pending(env, &is_exception_pending); 3127 NAPI_FATAL_IF_FAILED(status, "Error::New", "napi_is_exception_pending"); 3128 3129 // A pending exception takes precedence over any internal error status. 3130 if (is_exception_pending) { 3131 status = napi_get_and_clear_last_exception(env, &error); 3132 NAPI_FATAL_IF_FAILED( 3133 status, "Error::New", "napi_get_and_clear_last_exception"); 3134 } else { 3135 const char* error_message = last_error_info_copy.error_message != nullptr 3136 ? last_error_info_copy.error_message 3137 : "Error in native callback"; 3138 3139 napi_value message; 3140 status = napi_create_string_utf8( 3141 env, error_message, std::strlen(error_message), &message); 3142 NAPI_FATAL_IF_FAILED(status, "Error::New", "napi_create_string_utf8"); 3143 3144 switch (last_error_info_copy.error_code) { 3145 case napi_object_expected: 3146 case napi_string_expected: 3147 case napi_boolean_expected: 3148 case napi_number_expected: 3149 status = napi_create_type_error(env, nullptr, message, &error); 3150 break; 3151 default: 3152 status = napi_create_error(env, nullptr, message, &error); 3153 break; 3154 } 3155 NAPI_FATAL_IF_FAILED(status, "Error::New", "napi_create_error"); 3156 } 3157 3158 return Error(env, error); 3159} 3160 3161inline Error Error::New(napi_env env, const char* message) { 3162 return Error::New<Error>( 3163 env, message, std::strlen(message), napi_create_error); 3164} 3165 3166inline Error Error::New(napi_env env, const std::string& message) { 3167 return Error::New<Error>( 3168 env, message.c_str(), message.size(), napi_create_error); 3169} 3170 3171inline NAPI_NO_RETURN void Error::Fatal(const char* location, 3172 const char* message) { 3173 napi_fatal_error(location, NAPI_AUTO_LENGTH, message, NAPI_AUTO_LENGTH); 3174} 3175 3176inline Error::Error() : ObjectReference() {} 3177 3178inline Error::Error(napi_env env, napi_value value) 3179 : ObjectReference(env, nullptr) { 3180 if (value != nullptr) { 3181 // Attempting to create a reference on the error object. 3182 // If it's not a Object/Function/Symbol, this call will return an error 3183 // status. 3184 napi_status status = napi_create_reference(env, value, 1, &_ref); 3185 3186 if (status != napi_ok) { 3187 napi_value wrappedErrorObj; 3188 3189 // Create an error object 3190 status = napi_create_object(env, &wrappedErrorObj); 3191 NAPI_FATAL_IF_FAILED(status, "Error::Error", "napi_create_object"); 3192 3193 // property flag that we attach to show the error object is wrapped 3194 napi_property_descriptor wrapObjFlag = { 3195 ERROR_WRAP_VALUE(), // Unique GUID identifier since Symbol isn't a 3196 // viable option 3197 nullptr, 3198 nullptr, 3199 nullptr, 3200 nullptr, 3201 Value::From(env, value), 3202 napi_enumerable, 3203 nullptr}; 3204 3205 status = napi_define_properties(env, wrappedErrorObj, 1, &wrapObjFlag); 3206#ifdef NODE_API_SWALLOW_UNTHROWABLE_EXCEPTIONS 3207 if (status == napi_pending_exception) { 3208 // Test if the pending exception was reported because the environment is 3209 // shutting down. We assume that a status of napi_pending_exception 3210 // coupled with the absence of an actual pending exception means that 3211 // the environment is shutting down. If so, we replace the 3212 // napi_pending_exception status with napi_ok. 3213 bool is_exception_pending = false; 3214 status = napi_is_exception_pending(env, &is_exception_pending); 3215 if (status == napi_ok && !is_exception_pending) { 3216 status = napi_ok; 3217 } else { 3218 status = napi_pending_exception; 3219 } 3220 } 3221#endif // NODE_API_SWALLOW_UNTHROWABLE_EXCEPTIONS 3222 NAPI_FATAL_IF_FAILED(status, "Error::Error", "napi_define_properties"); 3223 3224 // Create a reference on the newly wrapped object 3225 status = napi_create_reference(env, wrappedErrorObj, 1, &_ref); 3226 } 3227 3228 // Avoid infinite recursion in the failure case. 3229 NAPI_FATAL_IF_FAILED(status, "Error::Error", "napi_create_reference"); 3230 } 3231} 3232 3233inline Object Error::Value() const { 3234 if (_ref == nullptr) { 3235 return Object(_env, nullptr); 3236 } 3237 3238 napi_value refValue; 3239 napi_status status = napi_get_reference_value(_env, _ref, &refValue); 3240 NAPI_THROW_IF_FAILED(_env, status, Object()); 3241 3242 napi_valuetype type; 3243 status = napi_typeof(_env, refValue, &type); 3244 NAPI_THROW_IF_FAILED(_env, status, Object()); 3245 3246 // If refValue isn't a symbol, then we proceed to whether the refValue has the 3247 // wrapped error flag 3248 if (type != napi_symbol) { 3249 // We are checking if the object is wrapped 3250 bool isWrappedObject = false; 3251 3252 status = napi_has_property(_env, 3253 refValue, 3254 String::From(_env, ERROR_WRAP_VALUE()), 3255 &isWrappedObject); 3256 3257 // Don't care about status 3258 if (isWrappedObject) { 3259 napi_value unwrappedValue; 3260 status = napi_get_property(_env, 3261 refValue, 3262 String::From(_env, ERROR_WRAP_VALUE()), 3263 &unwrappedValue); 3264 NAPI_THROW_IF_FAILED(_env, status, Object()); 3265 3266 return Object(_env, unwrappedValue); 3267 } 3268 } 3269 3270 return Object(_env, refValue); 3271} 3272 3273inline Error::Error(Error&& other) : ObjectReference(std::move(other)) {} 3274 3275inline Error& Error::operator=(Error&& other) { 3276 static_cast<Reference<Object>*>(this)->operator=(std::move(other)); 3277 return *this; 3278} 3279 3280inline Error::Error(const Error& other) : ObjectReference(other) {} 3281 3282inline Error& Error::operator=(const Error& other) { 3283 Reset(); 3284 3285 _env = other.Env(); 3286 HandleScope scope(_env); 3287 3288 napi_value value = other.Value(); 3289 if (value != nullptr) { 3290 napi_status status = napi_create_reference(_env, value, 1, &_ref); 3291 NAPI_THROW_IF_FAILED(_env, status, *this); 3292 } 3293 3294 return *this; 3295} 3296 3297inline const std::string& Error::Message() const NAPI_NOEXCEPT { 3298 if (_message.size() == 0 && _env != nullptr) { 3299#ifdef NODE_ADDON_API_CPP_EXCEPTIONS 3300 try { 3301 _message = Get("message").As<String>(); 3302 } catch (...) { 3303 // Catch all errors here, to include e.g. a std::bad_alloc from 3304 // the std::string::operator=, because this method may not throw. 3305 } 3306#else // NODE_ADDON_API_CPP_EXCEPTIONS 3307#if defined(NODE_ADDON_API_ENABLE_MAYBE) 3308 Napi::Value message_val; 3309 if (Get("message").UnwrapTo(&message_val)) { 3310 _message = message_val.As<String>(); 3311 } 3312#else 3313 _message = Get("message").As<String>(); 3314#endif 3315#endif // NODE_ADDON_API_CPP_EXCEPTIONS 3316 } 3317 return _message; 3318} 3319 3320// we created an object on the &_ref 3321inline void Error::ThrowAsJavaScriptException() const { 3322 HandleScope scope(_env); 3323 if (!IsEmpty()) { 3324#ifdef NODE_API_SWALLOW_UNTHROWABLE_EXCEPTIONS 3325 bool pendingException = false; 3326 3327 // check if there is already a pending exception. If so don't try to throw a 3328 // new one as that is not allowed/possible 3329 napi_status status = napi_is_exception_pending(_env, &pendingException); 3330 3331 if ((status != napi_ok) || 3332 ((status == napi_ok) && (pendingException == false))) { 3333 // We intentionally don't use `NAPI_THROW_*` macros here to ensure 3334 // that there is no possible recursion as `ThrowAsJavaScriptException` 3335 // is part of `NAPI_THROW_*` macro definition for noexcept. 3336 3337 status = napi_throw(_env, Value()); 3338 3339#if (NAPI_VERSION >= 10) 3340 napi_status expected_failure_mode = napi_cannot_run_js; 3341#else 3342 napi_status expected_failure_mode = napi_pending_exception; 3343#endif 3344 if (status == expected_failure_mode) { 3345 // The environment must be terminating as we checked earlier and there 3346 // was no pending exception. In this case continuing will result 3347 // in a fatal error and there is nothing the author has done incorrectly 3348 // in their code that is worth flagging through a fatal error 3349 return; 3350 } 3351 } else { 3352 status = napi_pending_exception; 3353 } 3354#else 3355 // We intentionally don't use `NAPI_THROW_*` macros here to ensure 3356 // that there is no possible recursion as `ThrowAsJavaScriptException` 3357 // is part of `NAPI_THROW_*` macro definition for noexcept. 3358 3359 napi_status status = napi_throw(_env, Value()); 3360#endif 3361 3362#ifdef NODE_ADDON_API_CPP_EXCEPTIONS 3363 if (status != napi_ok) { 3364 throw Error::New(_env); 3365 } 3366#else // NODE_ADDON_API_CPP_EXCEPTIONS 3367 NAPI_FATAL_IF_FAILED( 3368 status, "Error::ThrowAsJavaScriptException", "napi_throw"); 3369#endif // NODE_ADDON_API_CPP_EXCEPTIONS 3370 } 3371} 3372 3373#ifdef NODE_ADDON_API_CPP_EXCEPTIONS 3374 3375inline const char* Error::what() const NAPI_NOEXCEPT { 3376 return Message().c_str(); 3377} 3378 3379#endif // NODE_ADDON_API_CPP_EXCEPTIONS 3380 3381inline const char* Error::ERROR_WRAP_VALUE() NAPI_NOEXCEPT { 3382 return "4bda9e7e-4913-4dbc-95de-891cbf66598e-errorVal"; 3383} 3384 3385template <typename TError> 3386inline TError Error::New(napi_env env, 3387 const char* message, 3388 size_t length, 3389 create_error_fn create_error) { 3390 napi_value str; 3391 napi_status status = napi_create_string_utf8(env, message, length, &str); 3392 NAPI_THROW_IF_FAILED(env, status, TError()); 3393 3394 napi_value error; 3395 status = create_error(env, nullptr, str, &error); 3396 NAPI_THROW_IF_FAILED(env, status, TError()); 3397 3398 return TError(env, error); 3399} 3400 3401inline TypeError TypeError::New(napi_env env, const char* message) { 3402 return Error::New<TypeError>( 3403 env, message, std::strlen(message), napi_create_type_error); 3404} 3405 3406inline TypeError TypeError::New(napi_env env, const std::string& message) { 3407 return Error::New<TypeError>( 3408 env, message.c_str(), message.size(), napi_create_type_error); 3409} 3410 3411inline TypeError::TypeError() : Error() {} 3412 3413inline TypeError::TypeError(napi_env env, napi_value value) 3414 : Error(env, value) {} 3415 3416inline RangeError RangeError::New(napi_env env, const char* message) { 3417 return Error::New<RangeError>( 3418 env, message, std::strlen(message), napi_create_range_error); 3419} 3420 3421inline RangeError RangeError::New(napi_env env, const std::string& message) { 3422 return Error::New<RangeError>( 3423 env, message.c_str(), message.size(), napi_create_range_error); 3424} 3425 3426inline RangeError::RangeError() : Error() {} 3427 3428inline RangeError::RangeError(napi_env env, napi_value value) 3429 : Error(env, value) {} 3430 3431#if NAPI_VERSION > 8 3432inline SyntaxError SyntaxError::New(napi_env env, const char* message) { 3433 return Error::New<SyntaxError>( 3434 env, message, std::strlen(message), node_api_create_syntax_error); 3435} 3436 3437inline SyntaxError SyntaxError::New(napi_env env, const std::string& message) { 3438 return Error::New<SyntaxError>( 3439 env, message.c_str(), message.size(), node_api_create_syntax_error); 3440} 3441 3442inline SyntaxError::SyntaxError() : Error() {} 3443 3444inline SyntaxError::SyntaxError(napi_env env, napi_value value) 3445 : Error(env, value) {} 3446#endif // NAPI_VERSION > 8 3447 3448//////////////////////////////////////////////////////////////////////////////// 3449// Reference<T> class 3450//////////////////////////////////////////////////////////////////////////////// 3451 3452template <typename T> 3453inline Reference<T> Reference<T>::New(const T& value, 3454 uint32_t initialRefcount) { 3455 napi_env env = value.Env(); 3456 napi_value val = value; 3457 3458 if (val == nullptr) { 3459 return Reference<T>(env, nullptr); 3460 } 3461 3462 napi_ref ref; 3463 napi_status status = napi_create_reference(env, value, initialRefcount, &ref); 3464 NAPI_THROW_IF_FAILED(env, status, Reference<T>()); 3465 3466 return Reference<T>(env, ref); 3467} 3468 3469template <typename T> 3470inline Reference<T>::Reference() 3471 : _env(nullptr), _ref(nullptr), _suppressDestruct(false) {} 3472 3473template <typename T> 3474inline Reference<T>::Reference(napi_env env, napi_ref ref) 3475 : _env(env), _ref(ref), _suppressDestruct(false) {} 3476 3477template <typename T> 3478inline Reference<T>::~Reference() { 3479 if (_ref != nullptr) { 3480 if (!_suppressDestruct) { 3481 // TODO(legendecas): napi_delete_reference should be invoked immediately. 3482 // Fix this when https://github.com/nodejs/node/pull/55620 lands. 3483#ifdef NODE_API_EXPERIMENTAL_HAS_POST_FINALIZER 3484 Env().PostFinalizer( 3485 [](Napi::Env env, napi_ref ref) { napi_delete_reference(env, ref); }, 3486 _ref); 3487#else 3488 napi_delete_reference(_env, _ref); 3489#endif 3490 } 3491 3492 _ref = nullptr; 3493 } 3494} 3495 3496template <typename T> 3497inline Reference<T>::Reference(Reference<T>&& other) 3498 : _env(other._env), 3499 _ref(other._ref), 3500 _suppressDestruct(other._suppressDestruct) { 3501 other._env = nullptr; 3502 other._ref = nullptr; 3503 other._suppressDestruct = false; 3504} 3505 3506template <typename T> 3507inline Reference<T>& Reference<T>::operator=(Reference<T>&& other) { 3508 Reset(); 3509 _env = other._env; 3510 _ref = other._ref; 3511 _suppressDestruct = other._suppressDestruct; 3512 other._env = nullptr; 3513 other._ref = nullptr; 3514 other._suppressDestruct = false; 3515 return *this; 3516} 3517 3518template <typename T> 3519inline Reference<T>::Reference(const Reference<T>& other) 3520 : _env(other._env), _ref(nullptr), _suppressDestruct(false) { 3521 HandleScope scope(_env); 3522 3523 napi_value value = other.Value(); 3524 if (value != nullptr) { 3525 // Copying is a limited scenario (currently only used for Error object) and 3526 // always creates a strong reference to the given value even if the incoming 3527 // reference is weak. 3528 napi_status status = napi_create_reference(_env, value, 1, &_ref); 3529 NAPI_FATAL_IF_FAILED( 3530 status, "Reference<T>::Reference", "napi_create_reference"); 3531 } 3532} 3533 3534template <typename T> 3535inline Reference<T>::operator napi_ref() const { 3536 return _ref; 3537} 3538 3539template <typename T> 3540inline bool Reference<T>::operator==(const Reference<T>& other) const { 3541 HandleScope scope(_env); 3542 return this->Value().StrictEquals(other.Value()); 3543} 3544 3545template <typename T> 3546inline bool Reference<T>::operator!=(const Reference<T>& other) const { 3547 return !this->operator==(other); 3548} 3549 3550template <typename T> 3551inline Napi::Env Reference<T>::Env() const { 3552 return Napi::Env(_env); 3553} 3554 3555template <typename T> 3556inline bool Reference<T>::IsEmpty() const { 3557 return _ref == nullptr; 3558} 3559 3560template <typename T> 3561inline T Reference<T>::Value() const { 3562 if (_ref == nullptr) { 3563 return T(_env, nullptr); 3564 } 3565 3566 napi_value value; 3567 napi_status status = napi_get_reference_value(_env, _ref, &value); 3568 NAPI_THROW_IF_FAILED(_env, status, T()); 3569 return T(_env, value); 3570} 3571 3572template <typename T> 3573inline uint32_t Reference<T>::Ref() const { 3574 uint32_t result; 3575 napi_status status = napi_reference_ref(_env, _ref, &result); 3576 NAPI_THROW_IF_FAILED(_env, status, 0); 3577 return result; 3578} 3579 3580template <typename T> 3581inline uint32_t Reference<T>::Unref() const { 3582 uint32_t result; 3583 napi_status status = napi_reference_unref(_env, _ref, &result); 3584 NAPI_THROW_IF_FAILED(_env, status, 0); 3585 return result; 3586} 3587 3588template <typename T> 3589inline void Reference<T>::Reset() { 3590 if (_ref != nullptr) { 3591 napi_status status = napi_delete_reference(_env, _ref); 3592 NAPI_THROW_IF_FAILED_VOID(_env, status); 3593 _ref = nullptr; 3594 } 3595} 3596 3597template <typename T> 3598inline void Reference<T>::Reset(const T& value, uint32_t refcount) { 3599 Reset(); 3600 _env = value.Env(); 3601 3602 napi_value val = value; 3603 if (val != nullptr) { 3604 napi_status status = napi_create_reference(_env, value, refcount, &_ref); 3605 NAPI_THROW_IF_FAILED_VOID(_env, status); 3606 } 3607} 3608 3609template <typename T> 3610inline void Reference<T>::SuppressDestruct() { 3611 _suppressDestruct = true; 3612} 3613 3614template <typename T> 3615inline Reference<T> Weak(T value) { 3616 return Reference<T>::New(value, 0); 3617} 3618 3619inline ObjectReference Weak(Object value) { 3620 return Reference<Object>::New(value, 0); 3621} 3622 3623inline FunctionReference Weak(Function value) { 3624 return Reference<Function>::New(value, 0); 3625} 3626 3627template <typename T> 3628inline Reference<T> Persistent(T value) { 3629 return Reference<T>::New(value, 1); 3630} 3631 3632inline ObjectReference Persistent(Object value) { 3633 return Reference<Object>::New(value, 1); 3634} 3635 3636inline FunctionReference Persistent(Function value) { 3637 return Reference<Function>::New(value, 1); 3638} 3639 3640//////////////////////////////////////////////////////////////////////////////// 3641// ObjectReference class 3642//////////////////////////////////////////////////////////////////////////////// 3643 3644inline ObjectReference::ObjectReference() : Reference<Object>() {} 3645 3646inline ObjectReference::ObjectReference(napi_env env, napi_ref ref) 3647 : Reference<Object>(env, ref) {} 3648 3649inline ObjectReference::ObjectReference(Reference<Object>&& other) 3650 : Reference<Object>(std::move(other)) {} 3651 3652inline ObjectReference& ObjectReference::operator=(Reference<Object>&& other) { 3653 static_cast<Reference<Object>*>(this)->operator=(std::move(other)); 3654 return *this; 3655} 3656 3657inline ObjectReference::ObjectReference(ObjectReference&& other) 3658 : Reference<Object>(std::move(other)) {} 3659 3660inline ObjectReference& ObjectReference::operator=(ObjectReference&& other) { 3661 static_cast<Reference<Object>*>(this)->operator=(std::move(other)); 3662 return *this; 3663} 3664 3665inline ObjectReference::ObjectReference(const ObjectReference& other) 3666 : Reference<Object>(other) {} 3667 3668inline MaybeOrValue<Napi::Value> ObjectReference::Get( 3669 const char* utf8name) const { 3670 EscapableHandleScope scope(_env); 3671 MaybeOrValue<Napi::Value> result = Value().Get(utf8name); 3672#ifdef NODE_ADDON_API_ENABLE_MAYBE 3673 if (result.IsJust()) { 3674 return Just(scope.Escape(result.Unwrap())); 3675 } 3676 return result; 3677#else 3678 if (scope.Env().IsExceptionPending()) { 3679 return Value(); 3680 } 3681 return scope.Escape(result); 3682#endif 3683} 3684 3685inline MaybeOrValue<Napi::Value> ObjectReference::Get( 3686 const std::string& utf8name) const { 3687 EscapableHandleScope scope(_env); 3688 MaybeOrValue<Napi::Value> result = Value().Get(utf8name); 3689#ifdef NODE_ADDON_API_ENABLE_MAYBE 3690 if (result.IsJust()) { 3691 return Just(scope.Escape(result.Unwrap())); 3692 } 3693 return result; 3694#else 3695 if (scope.Env().IsExceptionPending()) { 3696 return Value(); 3697 } 3698 return scope.Escape(result); 3699#endif 3700} 3701 3702inline MaybeOrValue<bool> ObjectReference::Set(const char* utf8name, 3703 napi_value value) const { 3704 HandleScope scope(_env); 3705 return Value().Set(utf8name, value); 3706} 3707 3708inline MaybeOrValue<bool> ObjectReference::Set(const char* utf8name, 3709 Napi::Value value) const { 3710 HandleScope scope(_env); 3711 return Value().Set(utf8name, value); 3712} 3713 3714inline MaybeOrValue<bool> ObjectReference::Set(const char* utf8name, 3715 const char* utf8value) const { 3716 HandleScope scope(_env); 3717 return Value().Set(utf8name, utf8value); 3718} 3719 3720inline MaybeOrValue<bool> ObjectReference::Set(const char* utf8name, 3721 bool boolValue) const { 3722 HandleScope scope(_env); 3723 return Value().Set(utf8name, boolValue); 3724} 3725 3726inline MaybeOrValue<bool> ObjectReference::Set(const char* utf8name, 3727 double numberValue) const { 3728 HandleScope scope(_env); 3729 return Value().Set(utf8name, numberValue); 3730} 3731 3732inline MaybeOrValue<bool> ObjectReference::Set(const std::string& utf8name, 3733 napi_value value) const { 3734 HandleScope scope(_env); 3735 return Value().Set(utf8name, value); 3736} 3737 3738inline MaybeOrValue<bool> ObjectReference::Set(const std::string& utf8name, 3739 Napi::Value value) const { 3740 HandleScope scope(_env); 3741 return Value().Set(utf8name, value); 3742} 3743 3744inline MaybeOrValue<bool> ObjectReference::Set(const std::string& utf8name, 3745 std::string& utf8value) const { 3746 HandleScope scope(_env); 3747 return Value().Set(utf8name, utf8value); 3748} 3749 3750inline MaybeOrValue<bool> ObjectReference::Set(const std::string& utf8name, 3751 bool boolValue) const { 3752 HandleScope scope(_env); 3753 return Value().Set(utf8name, boolValue); 3754} 3755 3756inline MaybeOrValue<bool> ObjectReference::Set(const std::string& utf8name, 3757 double numberValue) const { 3758 HandleScope scope(_env); 3759 return Value().Set(utf8name, numberValue); 3760} 3761 3762inline MaybeOrValue<Napi::Value> ObjectReference::Get(uint32_t index) const { 3763 EscapableHandleScope scope(_env); 3764 MaybeOrValue<Napi::Value> result = Value().Get(index); 3765#ifdef NODE_ADDON_API_ENABLE_MAYBE 3766 if (result.IsJust()) { 3767 return Just(scope.Escape(result.Unwrap())); 3768 } 3769 return result; 3770#else 3771 if (scope.Env().IsExceptionPending()) { 3772 return Value(); 3773 } 3774 return scope.Escape(result); 3775#endif 3776} 3777 3778inline MaybeOrValue<bool> ObjectReference::Set(uint32_t index, 3779 napi_value value) const { 3780 HandleScope scope(_env); 3781 return Value().Set(index, value); 3782} 3783 3784inline MaybeOrValue<bool> ObjectReference::Set(uint32_t index, 3785 Napi::Value value) const { 3786 HandleScope scope(_env); 3787 return Value().Set(index, value); 3788} 3789 3790inline MaybeOrValue<bool> ObjectReference::Set(uint32_t index, 3791 const char* utf8value) const { 3792 HandleScope scope(_env); 3793 return Value().Set(index, utf8value); 3794} 3795 3796inline MaybeOrValue<bool> ObjectReference::Set( 3797 uint32_t index, const std::string& utf8value) const { 3798 HandleScope scope(_env); 3799 return Value().Set(index, utf8value); 3800} 3801 3802inline MaybeOrValue<bool> ObjectReference::Set(uint32_t index, 3803 bool boolValue) const { 3804 HandleScope scope(_env); 3805 return Value().Set(index, boolValue); 3806} 3807 3808inline MaybeOrValue<bool> ObjectReference::Set(uint32_t index, 3809 double numberValue) const { 3810 HandleScope scope(_env); 3811 return Value().Set(index, numberValue); 3812} 3813 3814//////////////////////////////////////////////////////////////////////////////// 3815// FunctionReference class 3816//////////////////////////////////////////////////////////////////////////////// 3817 3818inline FunctionReference::FunctionReference() : Reference<Function>() {} 3819 3820inline FunctionReference::FunctionReference(napi_env env, napi_ref ref) 3821 : Reference<Function>(env, ref) {} 3822 3823inline FunctionReference::FunctionReference(Reference<Function>&& other) 3824 : Reference<Function>(std::move(other)) {} 3825 3826inline FunctionReference& FunctionReference::operator=( 3827 Reference<Function>&& other) { 3828 static_cast<Reference<Function>*>(this)->operator=(std::move(other)); 3829 return *this; 3830} 3831 3832inline FunctionReference::FunctionReference(FunctionReference&& other) 3833 : Reference<Function>(std::move(other)) {} 3834 3835inline FunctionReference& FunctionReference::operator=( 3836 FunctionReference&& other) { 3837 static_cast<Reference<Function>*>(this)->operator=(std::move(other)); 3838 return *this; 3839} 3840 3841inline MaybeOrValue<Napi::Value> FunctionReference::operator()( 3842 const std::initializer_list<napi_value>& args) const { 3843 EscapableHandleScope scope(_env); 3844 MaybeOrValue<Napi::Value> result = Value()(args); 3845#ifdef NODE_ADDON_API_ENABLE_MAYBE 3846 if (result.IsJust()) { 3847 return Just(scope.Escape(result.Unwrap())); 3848 } 3849 return result; 3850#else 3851 if (scope.Env().IsExceptionPending()) { 3852 return Value(); 3853 } 3854 return scope.Escape(result); 3855#endif 3856} 3857 3858inline MaybeOrValue<Napi::Value> FunctionReference::Call( 3859 const std::initializer_list<napi_value>& args) const { 3860 EscapableHandleScope scope(_env); 3861 MaybeOrValue<Napi::Value> result = Value().Call(args); 3862#ifdef NODE_ADDON_API_ENABLE_MAYBE 3863 if (result.IsJust()) { 3864 return Just(scope.Escape(result.Unwrap())); 3865 } 3866 return result; 3867#else 3868 if (scope.Env().IsExceptionPending()) { 3869 return Value(); 3870 } 3871 return scope.Escape(result); 3872#endif 3873} 3874 3875inline MaybeOrValue<Napi::Value> FunctionReference::Call( 3876 const std::vector<napi_value>& args) const { 3877 EscapableHandleScope scope(_env); 3878 MaybeOrValue<Napi::Value> result = Value().Call(args); 3879#ifdef NODE_ADDON_API_ENABLE_MAYBE 3880 if (result.IsJust()) { 3881 return Just(scope.Escape(result.Unwrap())); 3882 } 3883 return result; 3884#else 3885 if (scope.Env().IsExceptionPending()) { 3886 return Value(); 3887 } 3888 return scope.Escape(result); 3889#endif 3890} 3891 3892inline MaybeOrValue<Napi::Value> FunctionReference::Call( 3893 napi_value recv, const std::initializer_list<napi_value>& args) const { 3894 EscapableHandleScope scope(_env); 3895 MaybeOrValue<Napi::Value> result = Value().Call(recv, args); 3896#ifdef NODE_ADDON_API_ENABLE_MAYBE 3897 if (result.IsJust()) { 3898 return Just(scope.Escape(result.Unwrap())); 3899 } 3900 return result; 3901#else 3902 if (scope.Env().IsExceptionPending()) { 3903 return Value(); 3904 } 3905 return scope.Escape(result); 3906#endif 3907} 3908 3909inline MaybeOrValue<Napi::Value> FunctionReference::Call( 3910 napi_value recv, const std::vector<napi_value>& args) const { 3911 EscapableHandleScope scope(_env); 3912 MaybeOrValue<Napi::Value> result = Value().Call(recv, args); 3913#ifdef NODE_ADDON_API_ENABLE_MAYBE 3914 if (result.IsJust()) { 3915 return Just(scope.Escape(result.Unwrap())); 3916 } 3917 return result; 3918#else 3919 if (scope.Env().IsExceptionPending()) { 3920 return Value(); 3921 } 3922 return scope.Escape(result); 3923#endif 3924} 3925 3926inline MaybeOrValue<Napi::Value> FunctionReference::Call( 3927 napi_value recv, size_t argc, const napi_value* args) const { 3928 EscapableHandleScope scope(_env); 3929 MaybeOrValue<Napi::Value> result = Value().Call(recv, argc, args); 3930#ifdef NODE_ADDON_API_ENABLE_MAYBE 3931 if (result.IsJust()) { 3932 return Just(scope.Escape(result.Unwrap())); 3933 } 3934 return result; 3935#else 3936 if (scope.Env().IsExceptionPending()) { 3937 return Value(); 3938 } 3939 return scope.Escape(result); 3940#endif 3941} 3942 3943inline MaybeOrValue<Napi::Value> FunctionReference::MakeCallback( 3944 napi_value recv, 3945 const std::initializer_list<napi_value>& args, 3946 napi_async_context context) const { 3947 EscapableHandleScope scope(_env); 3948 MaybeOrValue<Napi::Value> result = Value().MakeCallback(recv, args, context); 3949#ifdef NODE_ADDON_API_ENABLE_MAYBE 3950 if (result.IsJust()) { 3951 return Just(scope.Escape(result.Unwrap())); 3952 } 3953 3954 return result; 3955#else 3956 if (scope.Env().IsExceptionPending()) { 3957 return Value(); 3958 } 3959 return scope.Escape(result); 3960#endif 3961} 3962 3963inline MaybeOrValue<Napi::Value> FunctionReference::MakeCallback( 3964 napi_value recv, 3965 const std::vector<napi_value>& args, 3966 napi_async_context context) const { 3967 EscapableHandleScope scope(_env); 3968 MaybeOrValue<Napi::Value> result = Value().MakeCallback(recv, args, context); 3969#ifdef NODE_ADDON_API_ENABLE_MAYBE 3970 if (result.IsJust()) { 3971 return Just(scope.Escape(result.Unwrap())); 3972 } 3973 return result; 3974#else 3975 if (scope.Env().IsExceptionPending()) { 3976 return Value(); 3977 } 3978 return scope.Escape(result); 3979#endif 3980} 3981 3982inline MaybeOrValue<Napi::Value> FunctionReference::MakeCallback( 3983 napi_value recv, 3984 size_t argc, 3985 const napi_value* args, 3986 napi_async_context context) const { 3987 EscapableHandleScope scope(_env); 3988 MaybeOrValue<Napi::Value> result = 3989 Value().MakeCallback(recv, argc, args, context); 3990#ifdef NODE_ADDON_API_ENABLE_MAYBE 3991 if (result.IsJust()) { 3992 return Just(scope.Escape(result.Unwrap())); 3993 } 3994 return result; 3995#else 3996 if (scope.Env().IsExceptionPending()) { 3997 return Value(); 3998 } 3999 return scope.Escape(result); 4000#endif 4001} 4002 4003inline MaybeOrValue<Object> FunctionReference::New( 4004 const std::initializer_list<napi_value>& args) const { 4005 EscapableHandleScope scope(_env); 4006 MaybeOrValue<Object> result = Value().New(args); 4007#ifdef NODE_ADDON_API_ENABLE_MAYBE 4008 if (result.IsJust()) { 4009 return Just(scope.Escape(result.Unwrap()).As<Object>()); 4010 } 4011 return result; 4012#else 4013 if (scope.Env().IsExceptionPending()) { 4014 return Object(); 4015 } 4016 return scope.Escape(result).As<Object>(); 4017#endif 4018} 4019 4020inline MaybeOrValue<Object> FunctionReference::New( 4021 const std::vector<napi_value>& args) const { 4022 EscapableHandleScope scope(_env); 4023 MaybeOrValue<Object> result = Value().New(args); 4024#ifdef NODE_ADDON_API_ENABLE_MAYBE 4025 if (result.IsJust()) { 4026 return Just(scope.Escape(result.Unwrap()).As<Object>()); 4027 } 4028 return result; 4029#else 4030 if (scope.Env().IsExceptionPending()) { 4031 return Object(); 4032 } 4033 return scope.Escape(result).As<Object>(); 4034#endif 4035} 4036 4037//////////////////////////////////////////////////////////////////////////////// 4038// CallbackInfo class 4039//////////////////////////////////////////////////////////////////////////////// 4040 4041inline CallbackInfo::CallbackInfo(napi_env env, napi_callback_info info) 4042 : _env(env), 4043 _info(info), 4044 _this(nullptr), 4045 _dynamicArgs(nullptr), 4046 _data(nullptr) { 4047 _argc = _staticArgCount; 4048 _argv = _staticArgs; 4049 napi_status status = 4050 napi_get_cb_info(env, info, &_argc, _argv, &_this, &_data); 4051 NAPI_THROW_IF_FAILED_VOID(_env, status); 4052 4053 if (_argc > _staticArgCount) { 4054 // Use either a fixed-size array (on the stack) or a dynamically-allocated 4055 // array (on the heap) depending on the number of args. 4056 _dynamicArgs = new napi_value[_argc]; 4057 _argv = _dynamicArgs; 4058 4059 status = napi_get_cb_info(env, info, &_argc, _argv, nullptr, nullptr); 4060 NAPI_THROW_IF_FAILED_VOID(_env, status); 4061 } 4062} 4063 4064inline CallbackInfo::~CallbackInfo() { 4065 if (_dynamicArgs != nullptr) { 4066 delete[] _dynamicArgs; 4067 } 4068} 4069 4070inline CallbackInfo::operator napi_callback_info() const { 4071 return _info; 4072} 4073 4074inline Value CallbackInfo::NewTarget() const { 4075 napi_value newTarget; 4076 napi_status status = napi_get_new_target(_env, _info, &newTarget); 4077 NAPI_THROW_IF_FAILED(_env, status, Value()); 4078 return Value(_env, newTarget); 4079} 4080 4081inline bool CallbackInfo::IsConstructCall() const { 4082 return !NewTarget().IsEmpty(); 4083} 4084 4085inline Napi::Env CallbackInfo::Env() const { 4086 return Napi::Env(_env); 4087} 4088 4089inline size_t CallbackInfo::Length() const { 4090 return _argc; 4091} 4092 4093inline const Value CallbackInfo::operator[](size_t index) const { 4094 return index < _argc ? Value(_env, _argv[index]) : Env().Undefined(); 4095} 4096 4097inline Value CallbackInfo::This() const { 4098 if (_this == nullptr) { 4099 return Env().Undefined(); 4100 } 4101 return Object(_env, _this); 4102} 4103 4104inline void* CallbackInfo::Data() const { 4105 return _data; 4106} 4107 4108inline void CallbackInfo::SetData(void* data) { 4109 _data = data; 4110} 4111 4112//////////////////////////////////////////////////////////////////////////////// 4113// PropertyDescriptor class 4114//////////////////////////////////////////////////////////////////////////////// 4115 4116template <typename PropertyDescriptor::GetterCallback Getter> 4117PropertyDescriptor PropertyDescriptor::Accessor( 4118 const char* utf8name, napi_property_attributes attributes, void* data) { 4119 napi_property_descriptor desc = napi_property_descriptor(); 4120 4121 desc.utf8name = utf8name; 4122 desc.getter = details::TemplatedCallback<Getter>; 4123 desc.attributes = attributes; 4124 desc.data = data; 4125 4126 return desc; 4127} 4128 4129template <typename PropertyDescriptor::GetterCallback Getter> 4130PropertyDescriptor PropertyDescriptor::Accessor( 4131 const std::string& utf8name, 4132 napi_property_attributes attributes, 4133 void* data) { 4134 return Accessor<Getter>(utf8name.c_str(), attributes, data); 4135} 4136 4137template <typename PropertyDescriptor::GetterCallback Getter> 4138PropertyDescriptor PropertyDescriptor::Accessor( 4139 Name name, napi_property_attributes attributes, void* data) { 4140 napi_property_descriptor desc = napi_property_descriptor(); 4141 4142 desc.name = name; 4143 desc.getter = details::TemplatedCallback<Getter>; 4144 desc.attributes = attributes; 4145 desc.data = data; 4146 4147 return desc; 4148} 4149 4150template <typename PropertyDescriptor::GetterCallback Getter, 4151 typename PropertyDescriptor::SetterCallback Setter> 4152PropertyDescriptor PropertyDescriptor::Accessor( 4153 const char* utf8name, napi_property_attributes attributes, void* data) { 4154 napi_property_descriptor desc = napi_property_descriptor(); 4155 4156 desc.utf8name = utf8name; 4157 desc.getter = details::TemplatedCallback<Getter>; 4158 desc.setter = details::TemplatedVoidCallback<Setter>; 4159 desc.attributes = attributes; 4160 desc.data = data; 4161 4162 return desc; 4163} 4164 4165template <typename PropertyDescriptor::GetterCallback Getter, 4166 typename PropertyDescriptor::SetterCallback Setter> 4167PropertyDescriptor PropertyDescriptor::Accessor( 4168 const std::string& utf8name, 4169 napi_property_attributes attributes, 4170 void* data) { 4171 return Accessor<Getter, Setter>(utf8name.c_str(), attributes, data); 4172} 4173 4174template <typename PropertyDescriptor::GetterCallback Getter, 4175 typename PropertyDescriptor::SetterCallback Setter> 4176PropertyDescriptor PropertyDescriptor::Accessor( 4177 Name name, napi_property_attributes attributes, void* data) { 4178 napi_property_descriptor desc = napi_property_descriptor(); 4179 4180 desc.name = name; 4181 desc.getter = details::TemplatedCallback<Getter>; 4182 desc.setter = details::TemplatedVoidCallback<Setter>; 4183 desc.attributes = attributes; 4184 desc.data = data; 4185 4186 return desc; 4187} 4188 4189template <typename Getter> 4190inline PropertyDescriptor PropertyDescriptor::Accessor( 4191 Napi::Env env, 4192 Napi::Object object, 4193 const char* utf8name, 4194 Getter getter, 4195 napi_property_attributes attributes, 4196 void* data) { 4197 using CbData = details::CallbackData<Getter, Napi::Value>; 4198 auto callbackData = new CbData({getter, data}); 4199 4200 napi_status status = AttachData(env, object, callbackData); 4201 if (status != napi_ok) { 4202 delete callbackData; 4203 NAPI_THROW_IF_FAILED(env, status, napi_property_descriptor()); 4204 } 4205 4206 return PropertyDescriptor({utf8name, 4207 nullptr, 4208 nullptr, 4209 CbData::Wrapper, 4210 nullptr, 4211 nullptr, 4212 attributes, 4213 callbackData}); 4214} 4215 4216template <typename Getter> 4217inline PropertyDescriptor PropertyDescriptor::Accessor( 4218 Napi::Env env, 4219 Napi::Object object, 4220 const std::string& utf8name, 4221 Getter getter, 4222 napi_property_attributes attributes, 4223 void* data) { 4224 return Accessor(env, object, utf8name.c_str(), getter, attributes, data); 4225} 4226 4227template <typename Getter> 4228inline PropertyDescriptor PropertyDescriptor::Accessor( 4229 Napi::Env env, 4230 Napi::Object object, 4231 Name name, 4232 Getter getter, 4233 napi_property_attributes attributes, 4234 void* data) { 4235 using CbData = details::CallbackData<Getter, Napi::Value>; 4236 auto callbackData = new CbData({getter, data}); 4237 4238 napi_status status = AttachData(env, object, callbackData); 4239 if (status != napi_ok) { 4240 delete callbackData; 4241 NAPI_THROW_IF_FAILED(env, status, napi_property_descriptor()); 4242 } 4243 4244 return PropertyDescriptor({nullptr, 4245 name, 4246 nullptr, 4247 CbData::Wrapper, 4248 nullptr, 4249 nullptr, 4250 attributes, 4251 callbackData}); 4252} 4253 4254template <typename Getter, typename Setter> 4255inline PropertyDescriptor PropertyDescriptor::Accessor( 4256 Napi::Env env, 4257 Napi::Object object, 4258 const char* utf8name, 4259 Getter getter, 4260 Setter setter, 4261 napi_property_attributes attributes, 4262 void* data) { 4263 using CbData = details::AccessorCallbackData<Getter, Setter>; 4264 auto callbackData = new CbData({getter, setter, data}); 4265 4266 napi_status status = AttachData(env, object, callbackData); 4267 if (status != napi_ok) { 4268 delete callbackData; 4269 NAPI_THROW_IF_FAILED(env, status, napi_property_descriptor()); 4270 } 4271 4272 return PropertyDescriptor({utf8name, 4273 nullptr, 4274 nullptr, 4275 CbData::GetterWrapper, 4276 CbData::SetterWrapper, 4277 nullptr, 4278 attributes, 4279 callbackData}); 4280} 4281 4282template <typename Getter, typename Setter> 4283inline PropertyDescriptor PropertyDescriptor::Accessor( 4284 Napi::Env env, 4285 Napi::Object object, 4286 const std::string& utf8name, 4287 Getter getter, 4288 Setter setter, 4289 napi_property_attributes attributes, 4290 void* data) { 4291 return Accessor( 4292 env, object, utf8name.c_str(), getter, setter, attributes, data); 4293} 4294 4295template <typename Getter, typename Setter> 4296inline PropertyDescriptor PropertyDescriptor::Accessor( 4297 Napi::Env env, 4298 Napi::Object object, 4299 Name name, 4300 Getter getter, 4301 Setter setter, 4302 napi_property_attributes attributes, 4303 void* data) { 4304 using CbData = details::AccessorCallbackData<Getter, Setter>; 4305 auto callbackData = new CbData({getter, setter, data}); 4306 4307 napi_status status = AttachData(env, object, callbackData); 4308 if (status != napi_ok) { 4309 delete callbackData; 4310 NAPI_THROW_IF_FAILED(env, status, napi_property_descriptor()); 4311 } 4312 4313 return PropertyDescriptor({nullptr, 4314 name, 4315 nullptr, 4316 CbData::GetterWrapper, 4317 CbData::SetterWrapper, 4318 nullptr, 4319 attributes, 4320 callbackData}); 4321} 4322 4323template <typename Callable> 4324inline PropertyDescriptor PropertyDescriptor::Function( 4325 Napi::Env env, 4326 Napi::Object /*object*/, 4327 const char* utf8name, 4328 Callable cb, 4329 napi_property_attributes attributes, 4330 void* data) { 4331 return PropertyDescriptor({utf8name, 4332 nullptr, 4333 nullptr, 4334 nullptr, 4335 nullptr, 4336 Napi::Function::New(env, cb, utf8name, data), 4337 attributes, 4338 nullptr}); 4339} 4340 4341template <typename Callable> 4342inline PropertyDescriptor PropertyDescriptor::Function( 4343 Napi::Env env, 4344 Napi::Object object, 4345 const std::string& utf8name, 4346 Callable cb, 4347 napi_property_attributes attributes, 4348 void* data) { 4349 return Function(env, object, utf8name.c_str(), cb, attributes, data); 4350} 4351 4352template <typename Callable> 4353inline PropertyDescriptor PropertyDescriptor::Function( 4354 Napi::Env env, 4355 Napi::Object /*object*/, 4356 Name name, 4357 Callable cb, 4358 napi_property_attributes attributes, 4359 void* data) { 4360 return PropertyDescriptor({nullptr, 4361 name, 4362 nullptr, 4363 nullptr, 4364 nullptr, 4365 Napi::Function::New(env, cb, nullptr, data), 4366 attributes, 4367 nullptr}); 4368} 4369 4370inline PropertyDescriptor PropertyDescriptor::Value( 4371 const char* utf8name, 4372 napi_value value, 4373 napi_property_attributes attributes) { 4374 return PropertyDescriptor({utf8name, 4375 nullptr, 4376 nullptr, 4377 nullptr, 4378 nullptr, 4379 value, 4380 attributes, 4381 nullptr}); 4382} 4383 4384inline PropertyDescriptor PropertyDescriptor::Value( 4385 const std::string& utf8name, 4386 napi_value value, 4387 napi_property_attributes attributes) { 4388 return Value(utf8name.c_str(), value, attributes); 4389} 4390 4391inline PropertyDescriptor PropertyDescriptor::Value( 4392 napi_value name, napi_value value, napi_property_attributes attributes) { 4393 return PropertyDescriptor( 4394 {nullptr, name, nullptr, nullptr, nullptr, value, attributes, nullptr}); 4395} 4396 4397inline PropertyDescriptor PropertyDescriptor::Value( 4398 Name name, Napi::Value value, napi_property_attributes attributes) { 4399 napi_value nameValue = name; 4400 napi_value valueValue = value; 4401 return PropertyDescriptor::Value(nameValue, valueValue, attributes); 4402} 4403 4404inline PropertyDescriptor::PropertyDescriptor(napi_property_descriptor desc) 4405 : _desc(desc) {} 4406 4407inline PropertyDescriptor::operator napi_property_descriptor&() { 4408 return _desc; 4409} 4410 4411inline PropertyDescriptor::operator const napi_property_descriptor&() const { 4412 return _desc; 4413} 4414 4415//////////////////////////////////////////////////////////////////////////////// 4416// InstanceWrap<T> class 4417//////////////////////////////////////////////////////////////////////////////// 4418 4419template <typename T> 4420inline void InstanceWrap<T>::AttachPropData( 4421 napi_env env, napi_value value, const napi_property_descriptor* prop) { 4422 napi_status status; 4423 if (!(prop->attributes & napi_static)) { 4424 if (prop->method == T::InstanceVoidMethodCallbackWrapper) { 4425 status = Napi::details::AttachData( 4426 env, value, static_cast<InstanceVoidMethodCallbackData*>(prop->data)); 4427 NAPI_THROW_IF_FAILED_VOID(env, status); 4428 } else if (prop->method == T::InstanceMethodCallbackWrapper) { 4429 status = Napi::details::AttachData( 4430 env, value, static_cast<InstanceMethodCallbackData*>(prop->data)); 4431 NAPI_THROW_IF_FAILED_VOID(env, status); 4432 } else if (prop->getter == T::InstanceGetterCallbackWrapper || 4433 prop->setter == T::InstanceSetterCallbackWrapper) { 4434 status = Napi::details::AttachData( 4435 env, value, static_cast<InstanceAccessorCallbackData*>(prop->data)); 4436 NAPI_THROW_IF_FAILED_VOID(env, status); 4437 } 4438 } 4439} 4440 4441template <typename T> 4442inline ClassPropertyDescriptor<T> InstanceWrap<T>::InstanceMethod( 4443 const char* utf8name, 4444 InstanceVoidMethodCallback method, 4445 napi_property_attributes attributes, 4446 void* data) { 4447 InstanceVoidMethodCallbackData* callbackData = 4448 new InstanceVoidMethodCallbackData({method, data}); 4449 4450 napi_property_descriptor desc = napi_property_descriptor(); 4451 desc.utf8name = utf8name; 4452 desc.method = T::InstanceVoidMethodCallbackWrapper; 4453 desc.data = callbackData; 4454 desc.attributes = attributes; 4455 return desc; 4456} 4457 4458template <typename T> 4459inline ClassPropertyDescriptor<T> InstanceWrap<T>::InstanceMethod( 4460 const char* utf8name, 4461 InstanceMethodCallback method, 4462 napi_property_attributes attributes, 4463 void* data) { 4464 InstanceMethodCallbackData* callbackData = 4465 new InstanceMethodCallbackData({method, data}); 4466 4467 napi_property_descriptor desc = napi_property_descriptor(); 4468 desc.utf8name = utf8name; 4469 desc.method = T::InstanceMethodCallbackWrapper; 4470 desc.data = callbackData; 4471 desc.attributes = attributes; 4472 return desc; 4473} 4474 4475template <typename T> 4476inline ClassPropertyDescriptor<T> InstanceWrap<T>::InstanceMethod( 4477 Symbol name, 4478 InstanceVoidMethodCallback method, 4479 napi_property_attributes attributes, 4480 void* data) { 4481 InstanceVoidMethodCallbackData* callbackData = 4482 new InstanceVoidMethodCallbackData({method, data}); 4483 4484 napi_property_descriptor desc = napi_property_descriptor(); 4485 desc.name = name; 4486 desc.method = T::InstanceVoidMethodCallbackWrapper; 4487 desc.data = callbackData; 4488 desc.attributes = attributes; 4489 return desc; 4490} 4491 4492template <typename T> 4493inline ClassPropertyDescriptor<T> InstanceWrap<T>::InstanceMethod( 4494 Symbol name, 4495 InstanceMethodCallback method, 4496 napi_property_attributes attributes, 4497 void* data) { 4498 InstanceMethodCallbackData* callbackData = 4499 new InstanceMethodCallbackData({method, data}); 4500 4501 napi_property_descriptor desc = napi_property_descriptor(); 4502 desc.name = name; 4503 desc.method = T::InstanceMethodCallbackWrapper; 4504 desc.data = callbackData; 4505 desc.attributes = attributes; 4506 return desc; 4507} 4508 4509template <typename T> 4510template <typename InstanceWrap<T>::InstanceVoidMethodCallback method> 4511inline ClassPropertyDescriptor<T> InstanceWrap<T>::InstanceMethod( 4512 const char* utf8name, napi_property_attributes attributes, void* data) { 4513 napi_property_descriptor desc = napi_property_descriptor(); 4514 desc.utf8name = utf8name; 4515 desc.method = details::TemplatedInstanceVoidCallback<T, method>; 4516 desc.data = data; 4517 desc.attributes = attributes; 4518 return desc; 4519} 4520 4521template <typename T> 4522template <typename InstanceWrap<T>::InstanceMethodCallback method> 4523inline ClassPropertyDescriptor<T> InstanceWrap<T>::InstanceMethod( 4524 const char* utf8name, napi_property_attributes attributes, void* data) { 4525 napi_property_descriptor desc = napi_property_descriptor(); 4526 desc.utf8name = utf8name; 4527 desc.method = details::TemplatedInstanceCallback<T, method>; 4528 desc.data = data; 4529 desc.attributes = attributes; 4530 return desc; 4531} 4532 4533template <typename T> 4534template <typename InstanceWrap<T>::InstanceVoidMethodCallback method> 4535inline ClassPropertyDescriptor<T> InstanceWrap<T>::InstanceMethod( 4536 Symbol name, napi_property_attributes attributes, void* data) { 4537 napi_property_descriptor desc = napi_property_descriptor(); 4538 desc.name = name; 4539 desc.method = details::TemplatedInstanceVoidCallback<T, method>; 4540 desc.data = data; 4541 desc.attributes = attributes; 4542 return desc; 4543} 4544 4545template <typename T> 4546template <typename InstanceWrap<T>::InstanceMethodCallback method> 4547inline ClassPropertyDescriptor<T> InstanceWrap<T>::InstanceMethod( 4548 Symbol name, napi_property_attributes attributes, void* data) { 4549 napi_property_descriptor desc = napi_property_descriptor(); 4550 desc.name = name; 4551 desc.method = details::TemplatedInstanceCallback<T, method>; 4552 desc.data = data; 4553 desc.attributes = attributes; 4554 return desc; 4555} 4556 4557template <typename T> 4558inline ClassPropertyDescriptor<T> InstanceWrap<T>::InstanceAccessor( 4559 const char* utf8name, 4560 InstanceGetterCallback getter, 4561 InstanceSetterCallback setter, 4562 napi_property_attributes attributes, 4563 void* data) { 4564 InstanceAccessorCallbackData* callbackData = 4565 new InstanceAccessorCallbackData({getter, setter, data}); 4566 4567 napi_property_descriptor desc = napi_property_descriptor(); 4568 desc.utf8name = utf8name; 4569 desc.getter = getter != nullptr ? T::InstanceGetterCallbackWrapper : nullptr; 4570 desc.setter = setter != nullptr ? T::InstanceSetterCallbackWrapper : nullptr; 4571 desc.data = callbackData; 4572 desc.attributes = attributes; 4573 return desc; 4574} 4575 4576template <typename T> 4577inline ClassPropertyDescriptor<T> InstanceWrap<T>::InstanceAccessor( 4578 Symbol name, 4579 InstanceGetterCallback getter, 4580 InstanceSetterCallback setter, 4581 napi_property_attributes attributes, 4582 void* data) { 4583 InstanceAccessorCallbackData* callbackData = 4584 new InstanceAccessorCallbackData({getter, setter, data}); 4585 4586 napi_property_descriptor desc = napi_property_descriptor(); 4587 desc.name = name; 4588 desc.getter = getter != nullptr ? T::InstanceGetterCallbackWrapper : nullptr; 4589 desc.setter = setter != nullptr ? T::InstanceSetterCallbackWrapper : nullptr; 4590 desc.data = callbackData; 4591 desc.attributes = attributes; 4592 return desc; 4593} 4594 4595template <typename T> 4596template <typename InstanceWrap<T>::InstanceGetterCallback getter, 4597 typename InstanceWrap<T>::InstanceSetterCallback setter> 4598inline ClassPropertyDescriptor<T> InstanceWrap<T>::InstanceAccessor( 4599 const char* utf8name, napi_property_attributes attributes, void* data) { 4600 napi_property_descriptor desc = napi_property_descriptor(); 4601 desc.utf8name = utf8name; 4602 desc.getter = details::TemplatedInstanceCallback<T, getter>; 4603 desc.setter = This::WrapSetter(This::SetterTag<setter>()); 4604 desc.data = data; 4605 desc.attributes = attributes; 4606 return desc; 4607} 4608 4609template <typename T> 4610template <typename InstanceWrap<T>::InstanceGetterCallback getter, 4611 typename InstanceWrap<T>::InstanceSetterCallback setter> 4612inline ClassPropertyDescriptor<T> InstanceWrap<T>::InstanceAccessor( 4613 Symbol name, napi_property_attributes attributes, void* data) { 4614 napi_property_descriptor desc = napi_property_descriptor(); 4615 desc.name = name; 4616 desc.getter = details::TemplatedInstanceCallback<T, getter>; 4617 desc.setter = This::WrapSetter(This::SetterTag<setter>()); 4618 desc.data = data; 4619 desc.attributes = attributes; 4620 return desc; 4621} 4622 4623template <typename T> 4624inline ClassPropertyDescriptor<T> InstanceWrap<T>::InstanceValue( 4625 const char* utf8name, 4626 Napi::Value value, 4627 napi_property_attributes attributes) { 4628 napi_property_descriptor desc = napi_property_descriptor(); 4629 desc.utf8name = utf8name; 4630 desc.value = value; 4631 desc.attributes = attributes; 4632 return desc; 4633} 4634 4635template <typename T> 4636inline ClassPropertyDescriptor<T> InstanceWrap<T>::InstanceValue( 4637 Symbol name, Napi::Value value, napi_property_attributes attributes) { 4638 napi_property_descriptor desc = napi_property_descriptor(); 4639 desc.name = name; 4640 desc.value = value; 4641 desc.attributes = attributes; 4642 return desc; 4643} 4644 4645template <typename T> 4646inline napi_value InstanceWrap<T>::InstanceVoidMethodCallbackWrapper( 4647 napi_env env, napi_callback_info info) { 4648 return details::WrapCallback(env, [&] { 4649 CallbackInfo callbackInfo(env, info); 4650 InstanceVoidMethodCallbackData* callbackData = 4651 reinterpret_cast<InstanceVoidMethodCallbackData*>(callbackInfo.Data()); 4652 callbackInfo.SetData(callbackData->data); 4653 T* instance = T::Unwrap(callbackInfo.This().As<Object>()); 4654 auto cb = callbackData->callback; 4655 if (instance) (instance->*cb)(callbackInfo); 4656 return nullptr; 4657 }); 4658} 4659 4660template <typename T> 4661inline napi_value InstanceWrap<T>::InstanceMethodCallbackWrapper( 4662 napi_env env, napi_callback_info info) { 4663 return details::WrapCallback(env, [&] { 4664 CallbackInfo callbackInfo(env, info); 4665 InstanceMethodCallbackData* callbackData = 4666 reinterpret_cast<InstanceMethodCallbackData*>(callbackInfo.Data()); 4667 callbackInfo.SetData(callbackData->data); 4668 T* instance = T::Unwrap(callbackInfo.This().As<Object>()); 4669 auto cb = callbackData->callback; 4670 return instance ? (instance->*cb)(callbackInfo) : Napi::Value(); 4671 }); 4672} 4673 4674template <typename T> 4675inline napi_value InstanceWrap<T>::InstanceGetterCallbackWrapper( 4676 napi_env env, napi_callback_info info) { 4677 return details::WrapCallback(env, [&] { 4678 CallbackInfo callbackInfo(env, info); 4679 InstanceAccessorCallbackData* callbackData = 4680 reinterpret_cast<InstanceAccessorCallbackData*>(callbackInfo.Data()); 4681 callbackInfo.SetData(callbackData->data); 4682 T* instance = T::Unwrap(callbackInfo.This().As<Object>()); 4683 auto cb = callbackData->getterCallback; 4684 return instance ? (instance->*cb)(callbackInfo) : Napi::Value(); 4685 }); 4686} 4687 4688template <typename T> 4689inline napi_value InstanceWrap<T>::InstanceSetterCallbackWrapper( 4690 napi_env env, napi_callback_info info) { 4691 return details::WrapCallback(env, [&] { 4692 CallbackInfo callbackInfo(env, info); 4693 InstanceAccessorCallbackData* callbackData = 4694 reinterpret_cast<InstanceAccessorCallbackData*>(callbackInfo.Data()); 4695 callbackInfo.SetData(callbackData->data); 4696 T* instance = T::Unwrap(callbackInfo.This().As<Object>()); 4697 auto cb = callbackData->setterCallback; 4698 if (instance) (instance->*cb)(callbackInfo, callbackInfo[0]); 4699 return nullptr; 4700 }); 4701} 4702 4703template <typename T> 4704template <typename InstanceWrap<T>::InstanceSetterCallback method> 4705inline napi_value InstanceWrap<T>::WrappedMethod( 4706 napi_env env, napi_callback_info info) NAPI_NOEXCEPT { 4707 return details::WrapCallback(env, [&] { 4708 const CallbackInfo cbInfo(env, info); 4709 T* instance = T::Unwrap(cbInfo.This().As<Object>()); 4710 if (instance) (instance->*method)(cbInfo, cbInfo[0]); 4711 return nullptr; 4712 }); 4713} 4714 4715//////////////////////////////////////////////////////////////////////////////// 4716// ObjectWrap<T> class 4717//////////////////////////////////////////////////////////////////////////////// 4718 4719template <typename T> 4720inline ObjectWrap<T>::ObjectWrap(const Napi::CallbackInfo& callbackInfo) { 4721 napi_env env = callbackInfo.Env(); 4722 napi_value wrapper = callbackInfo.This(); 4723 napi_status status; 4724 napi_ref ref; 4725 T* instance = static_cast<T*>(this); 4726 status = napi_wrap(env, wrapper, instance, FinalizeCallback, nullptr, &ref); 4727 NAPI_THROW_IF_FAILED_VOID(env, status); 4728 4729 Reference<Object>* instanceRef = instance; 4730 *instanceRef = Reference<Object>(env, ref); 4731} 4732 4733template <typename T> 4734inline ObjectWrap<T>::~ObjectWrap() { 4735 // If the JS object still exists at this point, remove the finalizer added 4736 // through `napi_wrap()`. 4737 if (!IsEmpty() && !_finalized) { 4738 Object object = Value(); 4739 // It is not valid to call `napi_remove_wrap()` with an empty `object`. 4740 // This happens e.g. during garbage collection. 4741 if (!object.IsEmpty() && _construction_failed) { 4742 napi_remove_wrap(Env(), object, nullptr); 4743 } 4744 } 4745} 4746 4747template <typename T> 4748inline T* ObjectWrap<T>::Unwrap(Object wrapper) { 4749 void* unwrapped; 4750 napi_status status = napi_unwrap(wrapper.Env(), wrapper, &unwrapped); 4751 NAPI_THROW_IF_FAILED(wrapper.Env(), status, nullptr); 4752 return static_cast<T*>(unwrapped); 4753} 4754 4755template <typename T> 4756inline Function ObjectWrap<T>::DefineClass( 4757 Napi::Env env, 4758 const char* utf8name, 4759 const size_t props_count, 4760 const napi_property_descriptor* descriptors, 4761 void* data) { 4762 napi_status status; 4763 std::vector<napi_property_descriptor> props(props_count); 4764 4765 // We copy the descriptors to a local array because before defining the class 4766 // we must replace static method property descriptors with value property 4767 // descriptors such that the value is a function-valued `napi_value` created 4768 // with `CreateFunction()`. 4769 // 4770 // This replacement could be made for instance methods as well, but V8 aborts 4771 // if we do that, because it expects methods defined on the prototype template 4772 // to have `FunctionTemplate`s. 4773 for (size_t index = 0; index < props_count; index++) { 4774 props[index] = descriptors[index]; 4775 napi_property_descriptor* prop = &props[index]; 4776 if (prop->method == T::StaticMethodCallbackWrapper) { 4777 status = 4778 CreateFunction(env, 4779 utf8name, 4780 prop->method, 4781 static_cast<StaticMethodCallbackData*>(prop->data), 4782 &(prop->value)); 4783 NAPI_THROW_IF_FAILED(env, status, Function()); 4784 prop->method = nullptr; 4785 prop->data = nullptr; 4786 } else if (prop->method == T::StaticVoidMethodCallbackWrapper) { 4787 status = 4788 CreateFunction(env, 4789 utf8name, 4790 prop->method, 4791 static_cast<StaticVoidMethodCallbackData*>(prop->data), 4792 &(prop->value)); 4793 NAPI_THROW_IF_FAILED(env, status, Function()); 4794 prop->method = nullptr; 4795 prop->data = nullptr; 4796 } 4797 } 4798 4799 napi_value value; 4800 status = napi_define_class(env, 4801 utf8name, 4802 NAPI_AUTO_LENGTH, 4803 T::ConstructorCallbackWrapper, 4804 data, 4805 props_count, 4806 props.data(), 4807 &value); 4808 NAPI_THROW_IF_FAILED(env, status, Function()); 4809 4810 // After defining the class we iterate once more over the property descriptors 4811 // and attach the data associated with accessors and instance methods to the 4812 // newly created JavaScript class. 4813 for (size_t idx = 0; idx < props_count; idx++) { 4814 const napi_property_descriptor* prop = &props[idx]; 4815 4816 if (prop->getter == T::StaticGetterCallbackWrapper || 4817 prop->setter == T::StaticSetterCallbackWrapper) { 4818 status = Napi::details::AttachData( 4819 env, value, static_cast<StaticAccessorCallbackData*>(prop->data)); 4820 NAPI_THROW_IF_FAILED(env, status, Function()); 4821 } else { 4822 // InstanceWrap<T>::AttachPropData is responsible for attaching the data 4823 // of instance methods and accessors. 4824 T::AttachPropData(env, value, prop); 4825 } 4826 } 4827 4828 return Function(env, value); 4829} 4830 4831template <typename T> 4832inline Function ObjectWrap<T>::DefineClass( 4833 Napi::Env env, 4834 const char* utf8name, 4835 const std::initializer_list<ClassPropertyDescriptor<T>>& properties, 4836 void* data) { 4837 return DefineClass( 4838 env, 4839 utf8name, 4840 properties.size(), 4841 reinterpret_cast<const napi_property_descriptor*>(properties.begin()), 4842 data); 4843} 4844 4845template <typename T> 4846inline Function ObjectWrap<T>::DefineClass( 4847 Napi::Env env, 4848 const char* utf8name, 4849 const std::vector<ClassPropertyDescriptor<T>>& properties, 4850 void* data) { 4851 return DefineClass( 4852 env, 4853 utf8name, 4854 properties.size(), 4855 reinterpret_cast<const napi_property_descriptor*>(properties.data()), 4856 data); 4857} 4858 4859template <typename T> 4860inline ClassPropertyDescriptor<T> ObjectWrap<T>::StaticMethod( 4861 const char* utf8name, 4862 StaticVoidMethodCallback method, 4863 napi_property_attributes attributes, 4864 void* data) { 4865 StaticVoidMethodCallbackData* callbackData = 4866 new StaticVoidMethodCallbackData({method, data}); 4867 4868 napi_property_descriptor desc = napi_property_descriptor(); 4869 desc.utf8name = utf8name; 4870 desc.method = T::StaticVoidMethodCallbackWrapper; 4871 desc.data = callbackData; 4872 desc.attributes = 4873 static_cast<napi_property_attributes>(attributes | napi_static); 4874 return desc; 4875} 4876 4877template <typename T> 4878inline ClassPropertyDescriptor<T> ObjectWrap<T>::StaticMethod( 4879 const char* utf8name, 4880 StaticMethodCallback method, 4881 napi_property_attributes attributes, 4882 void* data) { 4883 StaticMethodCallbackData* callbackData = 4884 new StaticMethodCallbackData({method, data}); 4885 4886 napi_property_descriptor desc = napi_property_descriptor(); 4887 desc.utf8name = utf8name; 4888 desc.method = T::StaticMethodCallbackWrapper; 4889 desc.data = callbackData; 4890 desc.attributes = 4891 static_cast<napi_property_attributes>(attributes | napi_static); 4892 return desc; 4893} 4894 4895template <typename T> 4896inline ClassPropertyDescriptor<T> ObjectWrap<T>::StaticMethod( 4897 Symbol name, 4898 StaticVoidMethodCallback method, 4899 napi_property_attributes attributes, 4900 void* data) { 4901 StaticVoidMethodCallbackData* callbackData = 4902 new StaticVoidMethodCallbackData({method, data}); 4903 4904 napi_property_descriptor desc = napi_property_descriptor(); 4905 desc.name = name; 4906 desc.method = T::StaticVoidMethodCallbackWrapper; 4907 desc.data = callbackData; 4908 desc.attributes = 4909 static_cast<napi_property_attributes>(attributes | napi_static); 4910 return desc; 4911} 4912 4913template <typename T> 4914inline ClassPropertyDescriptor<T> ObjectWrap<T>::StaticMethod( 4915 Symbol name, 4916 StaticMethodCallback method, 4917 napi_property_attributes attributes, 4918 void* data) { 4919 StaticMethodCallbackData* callbackData = 4920 new StaticMethodCallbackData({method, data}); 4921 4922 napi_property_descriptor desc = napi_property_descriptor(); 4923 desc.name = name; 4924 desc.method = T::StaticMethodCallbackWrapper; 4925 desc.data = callbackData; 4926 desc.attributes = 4927 static_cast<napi_property_attributes>(attributes | napi_static); 4928 return desc; 4929} 4930 4931template <typename T> 4932template <typename ObjectWrap<T>::StaticVoidMethodCallback method> 4933inline ClassPropertyDescriptor<T> ObjectWrap<T>::StaticMethod( 4934 const char* utf8name, napi_property_attributes attributes, void* data) { 4935 napi_property_descriptor desc = napi_property_descriptor(); 4936 desc.utf8name = utf8name; 4937 desc.method = details::TemplatedVoidCallback<method>; 4938 desc.data = data; 4939 desc.attributes = 4940 static_cast<napi_property_attributes>(attributes | napi_static); 4941 return desc; 4942} 4943 4944template <typename T> 4945template <typename ObjectWrap<T>::StaticVoidMethodCallback method> 4946inline ClassPropertyDescriptor<T> ObjectWrap<T>::StaticMethod( 4947 Symbol name, napi_property_attributes attributes, void* data) { 4948 napi_property_descriptor desc = napi_property_descriptor(); 4949 desc.name = name; 4950 desc.method = details::TemplatedVoidCallback<method>; 4951 desc.data = data; 4952 desc.attributes = 4953 static_cast<napi_property_attributes>(attributes | napi_static); 4954 return desc; 4955} 4956 4957template <typename T> 4958template <typename ObjectWrap<T>::StaticMethodCallback method> 4959inline ClassPropertyDescriptor<T> ObjectWrap<T>::StaticMethod( 4960 const char* utf8name, napi_property_attributes attributes, void* data) { 4961 napi_property_descriptor desc = napi_property_descriptor(); 4962 desc.utf8name = utf8name; 4963 desc.method = details::TemplatedCallback<method>; 4964 desc.data = data; 4965 desc.attributes = 4966 static_cast<napi_property_attributes>(attributes | napi_static); 4967 return desc; 4968} 4969 4970template <typename T> 4971template <typename ObjectWrap<T>::StaticMethodCallback method> 4972inline ClassPropertyDescriptor<T> ObjectWrap<T>::StaticMethod( 4973 Symbol name, napi_property_attributes attributes, void* data) { 4974 napi_property_descriptor desc = napi_property_descriptor(); 4975 desc.name = name; 4976 desc.method = details::TemplatedCallback<method>; 4977 desc.data = data; 4978 desc.attributes = 4979 static_cast<napi_property_attributes>(attributes | napi_static); 4980 return desc; 4981} 4982 4983template <typename T> 4984inline ClassPropertyDescriptor<T> ObjectWrap<T>::StaticAccessor( 4985 const char* utf8name, 4986 StaticGetterCallback getter, 4987 StaticSetterCallback setter, 4988 napi_property_attributes attributes, 4989 void* data) { 4990 StaticAccessorCallbackData* callbackData = 4991 new StaticAccessorCallbackData({getter, setter, data}); 4992 4993 napi_property_descriptor desc = napi_property_descriptor(); 4994 desc.utf8name = utf8name; 4995 desc.getter = getter != nullptr ? T::StaticGetterCallbackWrapper : nullptr; 4996 desc.setter = setter != nullptr ? T::StaticSetterCallbackWrapper : nullptr; 4997 desc.data = callbackData; 4998 desc.attributes = 4999 static_cast<napi_property_attributes>(attributes | napi_static); 5000 return desc; 5001} 5002 5003template <typename T> 5004inline ClassPropertyDescriptor<T> ObjectWrap<T>::StaticAccessor( 5005 Symbol name, 5006 StaticGetterCallback getter, 5007 StaticSetterCallback setter, 5008 napi_property_attributes attributes, 5009 void* data) { 5010 StaticAccessorCallbackData* callbackData = 5011 new StaticAccessorCallbackData({getter, setter, data}); 5012 5013 napi_property_descriptor desc = napi_property_descriptor(); 5014 desc.name = name; 5015 desc.getter = getter != nullptr ? T::StaticGetterCallbackWrapper : nullptr; 5016 desc.setter = setter != nullptr ? T::StaticSetterCallbackWrapper : nullptr; 5017 desc.data = callbackData; 5018 desc.attributes = 5019 static_cast<napi_property_attributes>(attributes | napi_static); 5020 return desc; 5021} 5022 5023template <typename T> 5024template <typename ObjectWrap<T>::StaticGetterCallback getter, 5025 typename ObjectWrap<T>::StaticSetterCallback setter> 5026inline ClassPropertyDescriptor<T> ObjectWrap<T>::StaticAccessor( 5027 const char* utf8name, napi_property_attributes attributes, void* data) { 5028 napi_property_descriptor desc = napi_property_descriptor(); 5029 desc.utf8name = utf8name; 5030 desc.getter = details::TemplatedCallback<getter>; 5031 desc.setter = This::WrapStaticSetter(This::StaticSetterTag<setter>()); 5032 desc.data = data; 5033 desc.attributes = 5034 static_cast<napi_property_attributes>(attributes | napi_static); 5035 return desc; 5036} 5037 5038template <typename T> 5039template <typename ObjectWrap<T>::StaticGetterCallback getter, 5040 typename ObjectWrap<T>::StaticSetterCallback setter> 5041inline ClassPropertyDescriptor<T> ObjectWrap<T>::StaticAccessor( 5042 Symbol name, napi_property_attributes attributes, void* data) { 5043 napi_property_descriptor desc = napi_property_descriptor(); 5044 desc.name = name; 5045 desc.getter = details::TemplatedCallback<getter>; 5046 desc.setter = This::WrapStaticSetter(This::StaticSetterTag<setter>()); 5047 desc.data = data; 5048 desc.attributes = 5049 static_cast<napi_property_attributes>(attributes | napi_static); 5050 return desc; 5051} 5052 5053template <typename T> 5054inline ClassPropertyDescriptor<T> ObjectWrap<T>::StaticValue( 5055 const char* utf8name, 5056 Napi::Value value, 5057 napi_property_attributes attributes) { 5058 napi_property_descriptor desc = napi_property_descriptor(); 5059 desc.utf8name = utf8name; 5060 desc.value = value; 5061 desc.attributes = 5062 static_cast<napi_property_attributes>(attributes | napi_static); 5063 return desc; 5064} 5065 5066template <typename T> 5067inline ClassPropertyDescriptor<T> ObjectWrap<T>::StaticValue( 5068 Symbol name, Napi::Value value, napi_property_attributes attributes) { 5069 napi_property_descriptor desc = napi_property_descriptor(); 5070 desc.name = name; 5071 desc.value = value; 5072 desc.attributes = 5073 static_cast<napi_property_attributes>(attributes | napi_static); 5074 return desc; 5075} 5076 5077template <typename T> 5078inline Value ObjectWrap<T>::OnCalledAsFunction( 5079 const Napi::CallbackInfo& callbackInfo) { 5080 NAPI_THROW( 5081 TypeError::New(callbackInfo.Env(), 5082 "Class constructors cannot be invoked without 'new'"), 5083 Napi::Value()); 5084} 5085 5086template <typename T> 5087inline void ObjectWrap<T>::Finalize(Napi::Env /*env*/) {} 5088 5089template <typename T> 5090inline void ObjectWrap<T>::Finalize(BasicEnv /*env*/) {} 5091 5092template <typename T> 5093inline napi_value ObjectWrap<T>::ConstructorCallbackWrapper( 5094 napi_env env, napi_callback_info info) { 5095 napi_value new_target; 5096 napi_status status = napi_get_new_target(env, info, &new_target); 5097 if (status != napi_ok) return nullptr; 5098 5099 bool isConstructCall = (new_target != nullptr); 5100 if (!isConstructCall) { 5101 return details::WrapCallback( 5102 env, [&] { return T::OnCalledAsFunction(CallbackInfo(env, info)); }); 5103 } 5104 5105 napi_value wrapper = details::WrapCallback(env, [&] { 5106 CallbackInfo callbackInfo(env, info); 5107 T* instance = new T(callbackInfo); 5108#ifdef NODE_ADDON_API_CPP_EXCEPTIONS 5109 instance->_construction_failed = false; 5110#else 5111 if (callbackInfo.Env().IsExceptionPending()) { 5112 // We need to clear the exception so that removing the wrap might work. 5113 Error e = callbackInfo.Env().GetAndClearPendingException(); 5114 delete instance; 5115 e.ThrowAsJavaScriptException(); 5116 } else { 5117 instance->_construction_failed = false; 5118 } 5119#endif // NODE_ADDON_API_CPP_EXCEPTIONS 5120 return callbackInfo.This(); 5121 }); 5122 5123 return wrapper; 5124} 5125 5126template <typename T> 5127inline napi_value ObjectWrap<T>::StaticVoidMethodCallbackWrapper( 5128 napi_env env, napi_callback_info info) { 5129 return details::WrapCallback(env, [&] { 5130 CallbackInfo callbackInfo(env, info); 5131 StaticVoidMethodCallbackData* callbackData = 5132 reinterpret_cast<StaticVoidMethodCallbackData*>(callbackInfo.Data()); 5133 callbackInfo.SetData(callbackData->data); 5134 callbackData->callback(callbackInfo); 5135 return nullptr; 5136 }); 5137} 5138 5139template <typename T> 5140inline napi_value ObjectWrap<T>::StaticMethodCallbackWrapper( 5141 napi_env env, napi_callback_info info) { 5142 return details::WrapCallback(env, [&] { 5143 CallbackInfo callbackInfo(env, info); 5144 StaticMethodCallbackData* callbackData = 5145 reinterpret_cast<StaticMethodCallbackData*>(callbackInfo.Data()); 5146 callbackInfo.SetData(callbackData->data); 5147 return callbackData->callback(callbackInfo); 5148 }); 5149} 5150 5151template <typename T> 5152inline napi_value ObjectWrap<T>::StaticGetterCallbackWrapper( 5153 napi_env env, napi_callback_info info) { 5154 return details::WrapCallback(env, [&] { 5155 CallbackInfo callbackInfo(env, info); 5156 StaticAccessorCallbackData* callbackData = 5157 reinterpret_cast<StaticAccessorCallbackData*>(callbackInfo.Data()); 5158 callbackInfo.SetData(callbackData->data); 5159 return callbackData->getterCallback(callbackInfo); 5160 }); 5161} 5162 5163template <typename T> 5164inline napi_value ObjectWrap<T>::StaticSetterCallbackWrapper( 5165 napi_env env, napi_callback_info info) { 5166 return details::WrapCallback(env, [&] { 5167 CallbackInfo callbackInfo(env, info); 5168 StaticAccessorCallbackData* callbackData = 5169 reinterpret_cast<StaticAccessorCallbackData*>(callbackInfo.Data()); 5170 callbackInfo.SetData(callbackData->data); 5171 callbackData->setterCallback(callbackInfo, callbackInfo[0]); 5172 return nullptr; 5173 }); 5174} 5175 5176template <typename T> 5177inline void ObjectWrap<T>::FinalizeCallback(node_addon_api_basic_env env, 5178 void* data, 5179 void* /*hint*/) { 5180 // If the child class does not override _any_ Finalize() method, `env` will be 5181 // unused because of the constexpr guards. Explicitly reference it here to 5182 // bypass compiler warnings. 5183 (void)env; 5184 T* instance = static_cast<T*>(data); 5185 5186 // Prevent ~ObjectWrap from calling napi_remove_wrap. 5187 // The instance->_ref should be deleted with napi_delete_reference in 5188 // ~Reference. 5189 instance->_finalized = true; 5190 5191 // If class overrides the basic finalizer, execute it. 5192 if constexpr (details::HasBasicFinalizer<T>::value) { 5193#ifndef NODE_API_EXPERIMENTAL_HAS_POST_FINALIZER 5194 HandleScope scope(env); 5195#endif 5196 5197 instance->Finalize(Napi::BasicEnv(env)); 5198 } 5199 5200 // If class overrides the (extended) finalizer, either schedule it or 5201 // execute it immediately (depending on experimental features enabled). 5202 if constexpr (details::HasExtendedFinalizer<T>::value) { 5203#ifdef NODE_API_EXPERIMENTAL_HAS_POST_FINALIZER 5204 // In experimental, attach via node_api_post_finalizer. 5205 // `PostFinalizeCallback` is responsible for deleting the `T* instance`, 5206 // after calling the user-provided finalizer. 5207 napi_status status = 5208 node_api_post_finalizer(env, PostFinalizeCallback, data, nullptr); 5209 NAPI_FATAL_IF_FAILED(status, 5210 "ObjectWrap<T>::FinalizeCallback", 5211 "node_api_post_finalizer failed"); 5212#else 5213 // In non-experimental, this `FinalizeCallback` already executes from a 5214 // non-basic environment. Execute the override directly. 5215 // `PostFinalizeCallback` is responsible for deleting the `T* instance`, 5216 // after calling the user-provided finalizer. 5217 HandleScope scope(env); 5218 PostFinalizeCallback(env, data, static_cast<void*>(nullptr)); 5219#endif 5220 } 5221 // If the instance does _not_ override the (extended) finalizer, delete the 5222 // `T* instance` immediately. 5223 else { 5224 delete instance; 5225 } 5226} 5227 5228template <typename T> 5229inline void ObjectWrap<T>::PostFinalizeCallback(napi_env env, 5230 void* data, 5231 void* /*hint*/) { 5232 T* instance = static_cast<T*>(data); 5233 instance->Finalize(Napi::Env(env)); 5234 delete instance; 5235} 5236 5237template <typename T> 5238template <typename ObjectWrap<T>::StaticSetterCallback method> 5239inline napi_value ObjectWrap<T>::WrappedMethod( 5240 napi_env env, napi_callback_info info) NAPI_NOEXCEPT { 5241 return details::WrapCallback(env, [&] { 5242 const CallbackInfo cbInfo(env, info); 5243 // MSVC requires to copy 'method' function pointer to a local variable 5244 // before invoking it. 5245 auto m = method; 5246 m(cbInfo, cbInfo[0]); 5247 return nullptr; 5248 }); 5249} 5250 5251//////////////////////////////////////////////////////////////////////////////// 5252// HandleScope class 5253//////////////////////////////////////////////////////////////////////////////// 5254 5255inline HandleScope::HandleScope(napi_env env, napi_handle_scope scope) 5256 : _env(env), _scope(scope) {} 5257 5258inline HandleScope::HandleScope(Napi::Env env) : _env(env) { 5259 napi_status status = napi_open_handle_scope(_env, &_scope); 5260 NAPI_THROW_IF_FAILED_VOID(_env, status); 5261} 5262 5263inline HandleScope::~HandleScope() { 5264 napi_status status = napi_close_handle_scope(_env, _scope); 5265 NAPI_FATAL_IF_FAILED( 5266 status, "HandleScope::~HandleScope", "napi_close_handle_scope"); 5267} 5268 5269inline HandleScope::operator napi_handle_scope() const { 5270 return _scope; 5271} 5272 5273inline Napi::Env HandleScope::Env() const { 5274 return Napi::Env(_env); 5275} 5276 5277//////////////////////////////////////////////////////////////////////////////// 5278// EscapableHandleScope class 5279//////////////////////////////////////////////////////////////////////////////// 5280 5281inline EscapableHandleScope::EscapableHandleScope( 5282 napi_env env, napi_escapable_handle_scope scope) 5283 : _env(env), _scope(scope) {} 5284 5285inline EscapableHandleScope::EscapableHandleScope(Napi::Env env) : _env(env) { 5286 napi_status status = napi_open_escapable_handle_scope(_env, &_scope); 5287 NAPI_THROW_IF_FAILED_VOID(_env, status); 5288} 5289 5290inline EscapableHandleScope::~EscapableHandleScope() { 5291 napi_status status = napi_close_escapable_handle_scope(_env, _scope); 5292 NAPI_FATAL_IF_FAILED(status, 5293 "EscapableHandleScope::~EscapableHandleScope", 5294 "napi_close_escapable_handle_scope"); 5295} 5296 5297inline EscapableHandleScope::operator napi_escapable_handle_scope() const { 5298 return _scope; 5299} 5300 5301inline Napi::Env EscapableHandleScope::Env() const { 5302 return Napi::Env(_env); 5303} 5304 5305inline Value EscapableHandleScope::Escape(napi_value escapee) { 5306 napi_value result; 5307 napi_status status = napi_escape_handle(_env, _scope, escapee, &result); 5308 NAPI_THROW_IF_FAILED(_env, status, Value()); 5309 return Value(_env, result); 5310} 5311 5312#if (NAPI_VERSION > 2) 5313//////////////////////////////////////////////////////////////////////////////// 5314// CallbackScope class 5315//////////////////////////////////////////////////////////////////////////////// 5316 5317inline CallbackScope::CallbackScope(napi_env env, napi_callback_scope scope) 5318 : _env(env), _scope(scope) {} 5319 5320inline CallbackScope::CallbackScope(napi_env env, napi_async_context context) 5321 : _env(env) { 5322 napi_status status = 5323 napi_open_callback_scope(_env, Object::New(env), context, &_scope); 5324 NAPI_THROW_IF_FAILED_VOID(_env, status); 5325} 5326 5327inline CallbackScope::~CallbackScope() { 5328 napi_status status = napi_close_callback_scope(_env, _scope); 5329 NAPI_FATAL_IF_FAILED( 5330 status, "CallbackScope::~CallbackScope", "napi_close_callback_scope"); 5331} 5332 5333inline CallbackScope::operator napi_callback_scope() const { 5334 return _scope; 5335} 5336 5337inline Napi::Env CallbackScope::Env() const { 5338 return Napi::Env(_env); 5339} 5340#endif 5341 5342//////////////////////////////////////////////////////////////////////////////// 5343// AsyncContext class 5344//////////////////////////////////////////////////////////////////////////////// 5345 5346inline AsyncContext::AsyncContext(napi_env env, const char* resource_name) 5347 : AsyncContext(env, resource_name, Object::New(env)) {} 5348 5349inline AsyncContext::AsyncContext(napi_env env, 5350 const char* resource_name, 5351 const Object& resource) 5352 : _env(env), _context(nullptr) { 5353 napi_value resource_id; 5354 napi_status status = napi_create_string_utf8( 5355 _env, resource_name, NAPI_AUTO_LENGTH, &resource_id); 5356 NAPI_THROW_IF_FAILED_VOID(_env, status); 5357 5358 status = napi_async_init(_env, resource, resource_id, &_context); 5359 NAPI_THROW_IF_FAILED_VOID(_env, status); 5360} 5361 5362inline AsyncContext::~AsyncContext() { 5363 if (_context != nullptr) { 5364 napi_async_destroy(_env, _context); 5365 _context = nullptr; 5366 } 5367} 5368 5369inline AsyncContext::AsyncContext(AsyncContext&& other) { 5370 _env = other._env; 5371 other._env = nullptr; 5372 _context = other._context; 5373 other._context = nullptr; 5374} 5375 5376inline AsyncContext& AsyncContext::operator=(AsyncContext&& other) { 5377 _env = other._env; 5378 other._env = nullptr; 5379 _context = other._context; 5380 other._context = nullptr; 5381 return *this; 5382} 5383 5384inline AsyncContext::operator napi_async_context() const { 5385 return _context; 5386} 5387 5388inline Napi::Env AsyncContext::Env() const { 5389 return Napi::Env(_env); 5390} 5391 5392//////////////////////////////////////////////////////////////////////////////// 5393// AsyncWorker class 5394//////////////////////////////////////////////////////////////////////////////// 5395 5396#if NAPI_HAS_THREADS 5397 5398inline AsyncWorker::AsyncWorker(const Function& callback) 5399 : AsyncWorker(callback, "generic") {} 5400 5401inline AsyncWorker::AsyncWorker(const Function& callback, 5402 const char* resource_name) 5403 : AsyncWorker(callback, resource_name, Object::New(callback.Env())) {} 5404 5405inline AsyncWorker::AsyncWorker(const Function& callback, 5406 const char* resource_name, 5407 const Object& resource) 5408 : AsyncWorker( 5409 Object::New(callback.Env()), callback, resource_name, resource) {} 5410 5411inline AsyncWorker::AsyncWorker(const Object& receiver, 5412 const Function& callback) 5413 : AsyncWorker(receiver, callback, "generic") {} 5414 5415inline AsyncWorker::AsyncWorker(const Object& receiver, 5416 const Function& callback, 5417 const char* resource_name) 5418 : AsyncWorker( 5419 receiver, callback, resource_name, Object::New(callback.Env())) {} 5420 5421inline AsyncWorker::AsyncWorker(const Object& receiver, 5422 const Function& callback, 5423 const char* resource_name, 5424 const Object& resource) 5425 : _env(callback.Env()), 5426 _receiver(Napi::Persistent(receiver)), 5427 _callback(Napi::Persistent(callback)), 5428 _suppress_destruct(false) { 5429 napi_value resource_id; 5430 napi_status status = napi_create_string_latin1( 5431 _env, resource_name, NAPI_AUTO_LENGTH, &resource_id); 5432 NAPI_THROW_IF_FAILED_VOID(_env, status); 5433 5434 status = napi_create_async_work(_env, 5435 resource, 5436 resource_id, 5437 OnAsyncWorkExecute, 5438 OnAsyncWorkComplete, 5439 this, 5440 &_work); 5441 NAPI_THROW_IF_FAILED_VOID(_env, status); 5442} 5443 5444inline AsyncWorker::AsyncWorker(Napi::Env env) : AsyncWorker(env, "generic") {} 5445 5446inline AsyncWorker::AsyncWorker(Napi::Env env, const char* resource_name) 5447 : AsyncWorker(env, resource_name, Object::New(env)) {} 5448 5449inline AsyncWorker::AsyncWorker(Napi::Env env, 5450 const char* resource_name, 5451 const Object& resource) 5452 : _env(env), _receiver(), _callback(), _suppress_destruct(false) { 5453 napi_value resource_id; 5454 napi_status status = napi_create_string_latin1( 5455 _env, resource_name, NAPI_AUTO_LENGTH, &resource_id); 5456 NAPI_THROW_IF_FAILED_VOID(_env, status); 5457 5458 status = napi_create_async_work(_env, 5459 resource, 5460 resource_id, 5461 OnAsyncWorkExecute, 5462 OnAsyncWorkComplete, 5463 this, 5464 &_work); 5465 NAPI_THROW_IF_FAILED_VOID(_env, status); 5466} 5467 5468inline AsyncWorker::~AsyncWorker() { 5469 if (_work != nullptr) { 5470 napi_delete_async_work(_env, _work); 5471 _work = nullptr; 5472 } 5473} 5474 5475inline void AsyncWorker::Destroy() { 5476 delete this; 5477} 5478 5479inline AsyncWorker::operator napi_async_work() const { 5480 return _work; 5481} 5482 5483inline Napi::Env AsyncWorker::Env() const { 5484 return Napi::Env(_env); 5485} 5486 5487inline void AsyncWorker::Queue() { 5488 napi_status status = napi_queue_async_work(_env, _work); 5489 NAPI_THROW_IF_FAILED_VOID(_env, status); 5490} 5491 5492inline void AsyncWorker::Cancel() { 5493 napi_status status = napi_cancel_async_work(_env, _work); 5494 NAPI_THROW_IF_FAILED_VOID(_env, status); 5495} 5496 5497inline ObjectReference& AsyncWorker::Receiver() { 5498 return _receiver; 5499} 5500 5501inline FunctionReference& AsyncWorker::Callback() { 5502 return _callback; 5503} 5504 5505inline void AsyncWorker::SuppressDestruct() { 5506 _suppress_destruct = true; 5507} 5508 5509inline void AsyncWorker::OnOK() { 5510 if (!_callback.IsEmpty()) { 5511 _callback.Call(_receiver.Value(), GetResult(_callback.Env())); 5512 } 5513} 5514 5515inline void AsyncWorker::OnError(const Error& e) { 5516 if (!_callback.IsEmpty()) { 5517 _callback.Call(_receiver.Value(), 5518 std::initializer_list<napi_value>{e.Value()}); 5519 } 5520} 5521 5522inline void AsyncWorker::SetError(const std::string& error) { 5523 _error = error; 5524} 5525 5526inline std::vector<napi_value> AsyncWorker::GetResult(Napi::Env /*env*/) { 5527 return {}; 5528} 5529// The OnAsyncWorkExecute method receives an napi_env argument. However, do NOT 5530// use it within this method, as it does not run on the JavaScript thread and 5531// must not run any method that would cause JavaScript to run. In practice, 5532// this means that almost any use of napi_env will be incorrect. 5533inline void AsyncWorker::OnAsyncWorkExecute(napi_env env, void* asyncworker) { 5534 AsyncWorker* self = static_cast<AsyncWorker*>(asyncworker); 5535 self->OnExecute(env); 5536} 5537// The OnExecute method receives an napi_env argument. However, do NOT 5538// use it within this method, as it does not run on the JavaScript thread and 5539// must not run any method that would cause JavaScript to run. In practice, 5540// this means that almost any use of napi_env will be incorrect. 5541inline void AsyncWorker::OnExecute(Napi::Env /*DO_NOT_USE*/) { 5542#ifdef NODE_ADDON_API_CPP_EXCEPTIONS 5543 try { 5544 Execute(); 5545 } catch (const std::exception& e) { 5546 SetError(e.what()); 5547 } 5548#else // NODE_ADDON_API_CPP_EXCEPTIONS 5549 Execute(); 5550#endif // NODE_ADDON_API_CPP_EXCEPTIONS 5551} 5552 5553inline void AsyncWorker::OnAsyncWorkComplete(napi_env env, 5554 napi_status status, 5555 void* asyncworker) { 5556 AsyncWorker* self = static_cast<AsyncWorker*>(asyncworker); 5557 self->OnWorkComplete(env, status); 5558} 5559inline void AsyncWorker::OnWorkComplete(Napi::Env env, napi_status status) { 5560 if (status != napi_cancelled) { 5561 HandleScope scope(_env); 5562 details::WrapCallback(env, [&] { 5563 if (_error.size() == 0) { 5564 OnOK(); 5565 } else { 5566 OnError(Error::New(_env, _error)); 5567 } 5568 return nullptr; 5569 }); 5570 } 5571 if (!_suppress_destruct) { 5572 Destroy(); 5573 } 5574} 5575 5576#endif // NAPI_HAS_THREADS 5577 5578#if (NAPI_VERSION > 3 && NAPI_HAS_THREADS) 5579//////////////////////////////////////////////////////////////////////////////// 5580// TypedThreadSafeFunction<ContextType,DataType,CallJs> class 5581//////////////////////////////////////////////////////////////////////////////// 5582 5583// Starting with NAPI 5, the JavaScript function `func` parameter of 5584// `napi_create_threadsafe_function` is optional. 5585#if NAPI_VERSION > 4 5586// static, with Callback [missing] Resource [missing] Finalizer [missing] 5587template <typename ContextType, 5588 typename DataType, 5589 void (*CallJs)(Napi::Env, Napi::Function, ContextType*, DataType*)> 5590template <typename ResourceString> 5591inline TypedThreadSafeFunction<ContextType, DataType, CallJs> 5592TypedThreadSafeFunction<ContextType, DataType, CallJs>::New( 5593 napi_env env, 5594 ResourceString resourceName, 5595 size_t maxQueueSize, 5596 size_t initialThreadCount, 5597 ContextType* context) { 5598 TypedThreadSafeFunction<ContextType, DataType, CallJs> tsfn; 5599 5600 napi_status status = 5601 napi_create_threadsafe_function(env, 5602 nullptr, 5603 nullptr, 5604 String::From(env, resourceName), 5605 maxQueueSize, 5606 initialThreadCount, 5607 nullptr, 5608 nullptr, 5609 context, 5610 CallJsInternal, 5611 &tsfn._tsfn); 5612 if (status != napi_ok) { 5613 NAPI_THROW_IF_FAILED( 5614 env, status, TypedThreadSafeFunction<ContextType, DataType, CallJs>()); 5615 } 5616 5617 return tsfn; 5618} 5619 5620// static, with Callback [missing] Resource [passed] Finalizer [missing] 5621template <typename ContextType, 5622 typename DataType, 5623 void (*CallJs)(Napi::Env, Napi::Function, ContextType*, DataType*)> 5624template <typename ResourceString> 5625inline TypedThreadSafeFunction<ContextType, DataType, CallJs> 5626TypedThreadSafeFunction<ContextType, DataType, CallJs>::New( 5627 napi_env env, 5628 const Object& resource, 5629 ResourceString resourceName, 5630 size_t maxQueueSize, 5631 size_t initialThreadCount, 5632 ContextType* context) { 5633 TypedThreadSafeFunction<ContextType, DataType, CallJs> tsfn; 5634 5635 napi_status status = 5636 napi_create_threadsafe_function(env, 5637 nullptr, 5638 resource, 5639 String::From(env, resourceName), 5640 maxQueueSize, 5641 initialThreadCount, 5642 nullptr, 5643 nullptr, 5644 context, 5645 CallJsInternal, 5646 &tsfn._tsfn); 5647 if (status != napi_ok) { 5648 NAPI_THROW_IF_FAILED( 5649 env, status, TypedThreadSafeFunction<ContextType, DataType, CallJs>()); 5650 } 5651 5652 return tsfn; 5653} 5654 5655// static, with Callback [missing] Resource [missing] Finalizer [passed] 5656template <typename ContextType, 5657 typename DataType, 5658 void (*CallJs)(Napi::Env, Napi::Function, ContextType*, DataType*)> 5659template <typename ResourceString, 5660 typename Finalizer, 5661 typename FinalizerDataType> 5662inline TypedThreadSafeFunction<ContextType, DataType, CallJs> 5663TypedThreadSafeFunction<ContextType, DataType, CallJs>::New( 5664 napi_env env, 5665 ResourceString resourceName, 5666 size_t maxQueueSize, 5667 size_t initialThreadCount, 5668 ContextType* context, 5669 Finalizer finalizeCallback, 5670 FinalizerDataType* data) { 5671 TypedThreadSafeFunction<ContextType, DataType, CallJs> tsfn; 5672 5673 auto* finalizeData = new details:: 5674 ThreadSafeFinalize<ContextType, Finalizer, FinalizerDataType>( 5675 {data, finalizeCallback}); 5676 auto fini = 5677 details::ThreadSafeFinalize<ContextType, Finalizer, FinalizerDataType>:: 5678 FinalizeFinalizeWrapperWithDataAndContext; 5679 napi_status status = 5680 napi_create_threadsafe_function(env, 5681 nullptr, 5682 nullptr, 5683 String::From(env, resourceName), 5684 maxQueueSize, 5685 initialThreadCount, 5686 finalizeData, 5687 fini, 5688 context, 5689 CallJsInternal, 5690 &tsfn._tsfn); 5691 if (status != napi_ok) { 5692 delete finalizeData; 5693 NAPI_THROW_IF_FAILED( 5694 env, status, TypedThreadSafeFunction<ContextType, DataType, CallJs>()); 5695 } 5696 5697 return tsfn; 5698} 5699 5700// static, with Callback [missing] Resource [passed] Finalizer [passed] 5701template <typename ContextType, 5702 typename DataType, 5703 void (*CallJs)(Napi::Env, Napi::Function, ContextType*, DataType*)> 5704template <typename ResourceString, 5705 typename Finalizer, 5706 typename FinalizerDataType> 5707inline TypedThreadSafeFunction<ContextType, DataType, CallJs> 5708TypedThreadSafeFunction<ContextType, DataType, CallJs>::New( 5709 napi_env env, 5710 const Object& resource, 5711 ResourceString resourceName, 5712 size_t maxQueueSize, 5713 size_t initialThreadCount, 5714 ContextType* context, 5715 Finalizer finalizeCallback, 5716 FinalizerDataType* data) { 5717 TypedThreadSafeFunction<ContextType, DataType, CallJs> tsfn; 5718 5719 auto* finalizeData = new details:: 5720 ThreadSafeFinalize<ContextType, Finalizer, FinalizerDataType>( 5721 {data, finalizeCallback}); 5722 auto fini = 5723 details::ThreadSafeFinalize<ContextType, Finalizer, FinalizerDataType>:: 5724 FinalizeFinalizeWrapperWithDataAndContext; 5725 napi_status status = 5726 napi_create_threadsafe_function(env, 5727 nullptr, 5728 resource, 5729 String::From(env, resourceName), 5730 maxQueueSize, 5731 initialThreadCount, 5732 finalizeData, 5733 fini, 5734 context, 5735 CallJsInternal, 5736 &tsfn._tsfn); 5737 if (status != napi_ok) { 5738 delete finalizeData; 5739 NAPI_THROW_IF_FAILED( 5740 env, status, TypedThreadSafeFunction<ContextType, DataType, CallJs>()); 5741 } 5742 5743 return tsfn; 5744} 5745#endif 5746 5747// static, with Callback [passed] Resource [missing] Finalizer [missing] 5748template <typename ContextType, 5749 typename DataType, 5750 void (*CallJs)(Napi::Env, Napi::Function, ContextType*, DataType*)> 5751template <typename ResourceString> 5752inline TypedThreadSafeFunction<ContextType, DataType, CallJs> 5753TypedThreadSafeFunction<ContextType, DataType, CallJs>::New( 5754 napi_env env, 5755 const Function& callback, 5756 ResourceString resourceName, 5757 size_t maxQueueSize, 5758 size_t initialThreadCount, 5759 ContextType* context) { 5760 TypedThreadSafeFunction<ContextType, DataType, CallJs> tsfn; 5761 5762 napi_status status = 5763 napi_create_threadsafe_function(env, 5764 callback, 5765 nullptr, 5766 String::From(env, resourceName), 5767 maxQueueSize, 5768 initialThreadCount, 5769 nullptr, 5770 nullptr, 5771 context, 5772 CallJsInternal, 5773 &tsfn._tsfn); 5774 if (status != napi_ok) { 5775 NAPI_THROW_IF_FAILED( 5776 env, status, TypedThreadSafeFunction<ContextType, DataType, CallJs>()); 5777 } 5778 5779 return tsfn; 5780} 5781 5782// static, with Callback [passed] Resource [passed] Finalizer [missing] 5783template <typename ContextType, 5784 typename DataType, 5785 void (*CallJs)(Napi::Env, Napi::Function, ContextType*, DataType*)> 5786template <typename ResourceString> 5787inline TypedThreadSafeFunction<ContextType, DataType, CallJs> 5788TypedThreadSafeFunction<ContextType, DataType, CallJs>::New( 5789 napi_env env, 5790 const Function& callback, 5791 const Object& resource, 5792 ResourceString resourceName, 5793 size_t maxQueueSize, 5794 size_t initialThreadCount, 5795 ContextType* context) { 5796 TypedThreadSafeFunction<ContextType, DataType, CallJs> tsfn; 5797 5798 napi_status status = 5799 napi_create_threadsafe_function(env, 5800 callback, 5801 resource, 5802 String::From(env, resourceName), 5803 maxQueueSize, 5804 initialThreadCount, 5805 nullptr, 5806 nullptr, 5807 context, 5808 CallJsInternal, 5809 &tsfn._tsfn); 5810 if (status != napi_ok) { 5811 NAPI_THROW_IF_FAILED( 5812 env, status, TypedThreadSafeFunction<ContextType, DataType, CallJs>()); 5813 } 5814 5815 return tsfn; 5816} 5817 5818// static, with Callback [passed] Resource [missing] Finalizer [passed] 5819template <typename ContextType, 5820 typename DataType, 5821 void (*CallJs)(Napi::Env, Napi::Function, ContextType*, DataType*)> 5822template <typename ResourceString, 5823 typename Finalizer, 5824 typename FinalizerDataType> 5825inline TypedThreadSafeFunction<ContextType, DataType, CallJs> 5826TypedThreadSafeFunction<ContextType, DataType, CallJs>::New( 5827 napi_env env, 5828 const Function& callback, 5829 ResourceString resourceName, 5830 size_t maxQueueSize, 5831 size_t initialThreadCount, 5832 ContextType* context, 5833 Finalizer finalizeCallback, 5834 FinalizerDataType* data) { 5835 TypedThreadSafeFunction<ContextType, DataType, CallJs> tsfn; 5836 5837 auto* finalizeData = new details:: 5838 ThreadSafeFinalize<ContextType, Finalizer, FinalizerDataType>( 5839 {data, finalizeCallback}); 5840 auto fini = 5841 details::ThreadSafeFinalize<ContextType, Finalizer, FinalizerDataType>:: 5842 FinalizeFinalizeWrapperWithDataAndContext; 5843 napi_status status = 5844 napi_create_threadsafe_function(env, 5845 callback, 5846 nullptr, 5847 String::From(env, resourceName), 5848 maxQueueSize, 5849 initialThreadCount, 5850 finalizeData, 5851 fini, 5852 context, 5853 CallJsInternal, 5854 &tsfn._tsfn); 5855 if (status != napi_ok) { 5856 delete finalizeData; 5857 NAPI_THROW_IF_FAILED( 5858 env, status, TypedThreadSafeFunction<ContextType, DataType, CallJs>()); 5859 } 5860 5861 return tsfn; 5862} 5863 5864// static, with: Callback [passed] Resource [passed] Finalizer [passed] 5865template <typename ContextType, 5866 typename DataType, 5867 void (*CallJs)(Napi::Env, Napi::Function, ContextType*, DataType*)> 5868template <typename CallbackType, 5869 typename ResourceString, 5870 typename Finalizer, 5871 typename FinalizerDataType> 5872inline TypedThreadSafeFunction<ContextType, DataType, CallJs> 5873TypedThreadSafeFunction<ContextType, DataType, CallJs>::New( 5874 napi_env env, 5875 CallbackType callback, 5876 const Object& resource, 5877 ResourceString resourceName, 5878 size_t maxQueueSize, 5879 size_t initialThreadCount, 5880 ContextType* context, 5881 Finalizer finalizeCallback, 5882 FinalizerDataType* data) { 5883 TypedThreadSafeFunction<ContextType, DataType, CallJs> tsfn; 5884 5885 auto* finalizeData = new details:: 5886 ThreadSafeFinalize<ContextType, Finalizer, FinalizerDataType>( 5887 {data, finalizeCallback}); 5888 auto fini = 5889 details::ThreadSafeFinalize<ContextType, Finalizer, FinalizerDataType>:: 5890 FinalizeFinalizeWrapperWithDataAndContext; 5891 napi_status status = napi_create_threadsafe_function( 5892 env, 5893 details::DefaultCallbackWrapper< 5894 CallbackType, 5895 TypedThreadSafeFunction<ContextType, DataType, CallJs>>(env, 5896 callback), 5897 resource, 5898 String::From(env, resourceName), 5899 maxQueueSize, 5900 initialThreadCount, 5901 finalizeData, 5902 fini, 5903 context, 5904 CallJsInternal, 5905 &tsfn._tsfn); 5906 if (status != napi_ok) { 5907 delete finalizeData; 5908 NAPI_THROW_IF_FAILED( 5909 env, status, TypedThreadSafeFunction<ContextType, DataType, CallJs>()); 5910 } 5911 5912 return tsfn; 5913} 5914 5915template <typename ContextType, 5916 typename DataType, 5917 void (*CallJs)(Napi::Env, Napi::Function, ContextType*, DataType*)> 5918inline TypedThreadSafeFunction<ContextType, DataType, CallJs>:: 5919 TypedThreadSafeFunction() 5920 : _tsfn() {} 5921 5922template <typename ContextType, 5923 typename DataType, 5924 void (*CallJs)(Napi::Env, Napi::Function, ContextType*, DataType*)> 5925inline TypedThreadSafeFunction<ContextType, DataType, CallJs>:: 5926 TypedThreadSafeFunction(napi_threadsafe_function tsfn) 5927 : _tsfn(tsfn) {} 5928 5929template <typename ContextType, 5930 typename DataType, 5931 void (*CallJs)(Napi::Env, Napi::Function, ContextType*, DataType*)> 5932inline TypedThreadSafeFunction<ContextType, DataType, CallJs>:: 5933operator napi_threadsafe_function() const { 5934 return _tsfn; 5935} 5936 5937template <typename ContextType, 5938 typename DataType, 5939 void (*CallJs)(Napi::Env, Napi::Function, ContextType*, DataType*)> 5940inline napi_status 5941TypedThreadSafeFunction<ContextType, DataType, CallJs>::BlockingCall( 5942 DataType* data) const { 5943 return napi_call_threadsafe_function(_tsfn, data, napi_tsfn_blocking); 5944} 5945 5946template <typename ContextType, 5947 typename DataType, 5948 void (*CallJs)(Napi::Env, Napi::Function, ContextType*, DataType*)> 5949inline napi_status 5950TypedThreadSafeFunction<ContextType, DataType, CallJs>::NonBlockingCall( 5951 DataType* data) const { 5952 return napi_call_threadsafe_function(_tsfn, data, napi_tsfn_nonblocking); 5953} 5954 5955template <typename ContextType, 5956 typename DataType, 5957 void (*CallJs)(Napi::Env, Napi::Function, ContextType*, DataType*)> 5958inline void TypedThreadSafeFunction<ContextType, DataType, CallJs>::Ref( 5959 napi_env env) const { 5960 if (_tsfn != nullptr) { 5961 napi_status status = napi_ref_threadsafe_function(env, _tsfn); 5962 NAPI_THROW_IF_FAILED_VOID(env, status); 5963 } 5964} 5965 5966template <typename ContextType, 5967 typename DataType, 5968 void (*CallJs)(Napi::Env, Napi::Function, ContextType*, DataType*)> 5969inline void TypedThreadSafeFunction<ContextType, DataType, CallJs>::Unref( 5970 napi_env env) const { 5971 if (_tsfn != nullptr) { 5972 napi_status status = napi_unref_threadsafe_function(env, _tsfn); 5973 NAPI_THROW_IF_FAILED_VOID(env, status); 5974 } 5975} 5976 5977template <typename ContextType, 5978 typename DataType, 5979 void (*CallJs)(Napi::Env, Napi::Function, ContextType*, DataType*)> 5980inline napi_status 5981TypedThreadSafeFunction<ContextType, DataType, CallJs>::Acquire() const { 5982 return napi_acquire_threadsafe_function(_tsfn); 5983} 5984 5985template <typename ContextType, 5986 typename DataType, 5987 void (*CallJs)(Napi::Env, Napi::Function, ContextType*, DataType*)> 5988inline napi_status 5989TypedThreadSafeFunction<ContextType, DataType, CallJs>::Release() const { 5990 return napi_release_threadsafe_function(_tsfn, napi_tsfn_release); 5991} 5992 5993template <typename ContextType, 5994 typename DataType, 5995 void (*CallJs)(Napi::Env, Napi::Function, ContextType*, DataType*)> 5996inline napi_status 5997TypedThreadSafeFunction<ContextType, DataType, CallJs>::Abort() const { 5998 return napi_release_threadsafe_function(_tsfn, napi_tsfn_abort); 5999} 6000 6001template <typename ContextType, 6002 typename DataType, 6003 void (*CallJs)(Napi::Env, Napi::Function, ContextType*, DataType*)> 6004inline ContextType* 6005TypedThreadSafeFunction<ContextType, DataType, CallJs>::GetContext() const { 6006 void* context; 6007 napi_status status = napi_get_threadsafe_function_context(_tsfn, &context); 6008 NAPI_FATAL_IF_FAILED(status, 6009 "TypedThreadSafeFunction::GetContext", 6010 "napi_get_threadsafe_function_context"); 6011 return static_cast<ContextType*>(context); 6012} 6013 6014// static 6015template <typename ContextType, 6016 typename DataType, 6017 void (*CallJs)(Napi::Env, Napi::Function, ContextType*, DataType*)> 6018void TypedThreadSafeFunction<ContextType, DataType, CallJs>::CallJsInternal( 6019 napi_env env, napi_value jsCallback, void* context, void* data) { 6020 details::CallJsWrapper<ContextType, DataType, decltype(CallJs), CallJs>( 6021 env, jsCallback, context, data); 6022} 6023 6024#if NAPI_VERSION == 4 6025// static 6026template <typename ContextType, 6027 typename DataType, 6028 void (*CallJs)(Napi::Env, Napi::Function, ContextType*, DataType*)> 6029Napi::Function 6030TypedThreadSafeFunction<ContextType, DataType, CallJs>::EmptyFunctionFactory( 6031 Napi::Env env) { 6032 return Napi::Function::New(env, [](const CallbackInfo& cb) {}); 6033} 6034 6035// static 6036template <typename ContextType, 6037 typename DataType, 6038 void (*CallJs)(Napi::Env, Napi::Function, ContextType*, DataType*)> 6039Napi::Function 6040TypedThreadSafeFunction<ContextType, DataType, CallJs>::FunctionOrEmpty( 6041 Napi::Env env, Napi::Function& callback) { 6042 if (callback.IsEmpty()) { 6043 return EmptyFunctionFactory(env); 6044 } 6045 return callback; 6046} 6047 6048#else 6049// static 6050template <typename ContextType, 6051 typename DataType, 6052 void (*CallJs)(Napi::Env, Napi::Function, ContextType*, DataType*)> 6053std::nullptr_t 6054TypedThreadSafeFunction<ContextType, DataType, CallJs>::EmptyFunctionFactory( 6055 Napi::Env /*env*/) { 6056 return nullptr; 6057} 6058 6059// static 6060template <typename ContextType, 6061 typename DataType, 6062 void (*CallJs)(Napi::Env, Napi::Function, ContextType*, DataType*)> 6063Napi::Function 6064TypedThreadSafeFunction<ContextType, DataType, CallJs>::FunctionOrEmpty( 6065 Napi::Env /*env*/, Napi::Function& callback) { 6066 return callback; 6067} 6068 6069#endif 6070 6071//////////////////////////////////////////////////////////////////////////////// 6072// ThreadSafeFunction class 6073//////////////////////////////////////////////////////////////////////////////// 6074 6075// static 6076template <typename ResourceString> 6077inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env, 6078 const Function& callback, 6079 ResourceString resourceName, 6080 size_t maxQueueSize, 6081 size_t initialThreadCount) { 6082 return New( 6083 env, callback, Object(), resourceName, maxQueueSize, initialThreadCount); 6084} 6085 6086// static 6087template <typename ResourceString, typename ContextType> 6088inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env, 6089 const Function& callback, 6090 ResourceString resourceName, 6091 size_t maxQueueSize, 6092 size_t initialThreadCount, 6093 ContextType* context) { 6094 return New(env, 6095 callback, 6096 Object(), 6097 resourceName, 6098 maxQueueSize, 6099 initialThreadCount, 6100 context); 6101} 6102 6103// static 6104template <typename ResourceString, typename Finalizer> 6105inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env, 6106 const Function& callback, 6107 ResourceString resourceName, 6108 size_t maxQueueSize, 6109 size_t initialThreadCount, 6110 Finalizer finalizeCallback) { 6111 return New(env, 6112 callback, 6113 Object(), 6114 resourceName, 6115 maxQueueSize, 6116 initialThreadCount, 6117 finalizeCallback); 6118} 6119 6120// static 6121template <typename ResourceString, 6122 typename Finalizer, 6123 typename FinalizerDataType> 6124inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env, 6125 const Function& callback, 6126 ResourceString resourceName, 6127 size_t maxQueueSize, 6128 size_t initialThreadCount, 6129 Finalizer finalizeCallback, 6130 FinalizerDataType* data) { 6131 return New(env, 6132 callback, 6133 Object(), 6134 resourceName, 6135 maxQueueSize, 6136 initialThreadCount, 6137 finalizeCallback, 6138 data); 6139} 6140 6141// static 6142template <typename ResourceString, typename ContextType, typename Finalizer> 6143inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env, 6144 const Function& callback, 6145 ResourceString resourceName, 6146 size_t maxQueueSize, 6147 size_t initialThreadCount, 6148 ContextType* context, 6149 Finalizer finalizeCallback) { 6150 return New(env, 6151 callback, 6152 Object(), 6153 resourceName, 6154 maxQueueSize, 6155 initialThreadCount, 6156 context, 6157 finalizeCallback); 6158} 6159 6160// static 6161template <typename ResourceString, 6162 typename ContextType, 6163 typename Finalizer, 6164 typename FinalizerDataType> 6165inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env, 6166 const Function& callback, 6167 ResourceString resourceName, 6168 size_t maxQueueSize, 6169 size_t initialThreadCount, 6170 ContextType* context, 6171 Finalizer finalizeCallback, 6172 FinalizerDataType* data) { 6173 return New(env, 6174 callback, 6175 Object(), 6176 resourceName, 6177 maxQueueSize, 6178 initialThreadCount, 6179 context, 6180 finalizeCallback, 6181 data); 6182} 6183 6184// static 6185template <typename ResourceString> 6186inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env, 6187 const Function& callback, 6188 const Object& resource, 6189 ResourceString resourceName, 6190 size_t maxQueueSize, 6191 size_t initialThreadCount) { 6192 return New(env, 6193 callback, 6194 resource, 6195 resourceName, 6196 maxQueueSize, 6197 initialThreadCount, 6198 static_cast<void*>(nullptr) /* context */); 6199} 6200 6201// static 6202template <typename ResourceString, typename ContextType> 6203inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env, 6204 const Function& callback, 6205 const Object& resource, 6206 ResourceString resourceName, 6207 size_t maxQueueSize, 6208 size_t initialThreadCount, 6209 ContextType* context) { 6210 return New(env, 6211 callback, 6212 resource, 6213 resourceName, 6214 maxQueueSize, 6215 initialThreadCount, 6216 context, 6217 [](Env, ContextType*) {} /* empty finalizer */); 6218} 6219 6220// static 6221template <typename ResourceString, typename Finalizer> 6222inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env, 6223 const Function& callback, 6224 const Object& resource, 6225 ResourceString resourceName, 6226 size_t maxQueueSize, 6227 size_t initialThreadCount, 6228 Finalizer finalizeCallback) { 6229 return New(env, 6230 callback, 6231 resource, 6232 resourceName, 6233 maxQueueSize, 6234 initialThreadCount, 6235 static_cast<void*>(nullptr) /* context */, 6236 finalizeCallback, 6237 static_cast<void*>(nullptr) /* data */, 6238 details::ThreadSafeFinalize<void, Finalizer>::Wrapper); 6239} 6240 6241// static 6242template <typename ResourceString, 6243 typename Finalizer, 6244 typename FinalizerDataType> 6245inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env, 6246 const Function& callback, 6247 const Object& resource, 6248 ResourceString resourceName, 6249 size_t maxQueueSize, 6250 size_t initialThreadCount, 6251 Finalizer finalizeCallback, 6252 FinalizerDataType* data) { 6253 return New(env, 6254 callback, 6255 resource, 6256 resourceName, 6257 maxQueueSize, 6258 initialThreadCount, 6259 static_cast<void*>(nullptr) /* context */, 6260 finalizeCallback, 6261 data, 6262 details::ThreadSafeFinalize<void, Finalizer, FinalizerDataType>:: 6263 FinalizeWrapperWithData); 6264} 6265 6266// static 6267template <typename ResourceString, typename ContextType, typename Finalizer> 6268inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env, 6269 const Function& callback, 6270 const Object& resource, 6271 ResourceString resourceName, 6272 size_t maxQueueSize, 6273 size_t initialThreadCount, 6274 ContextType* context, 6275 Finalizer finalizeCallback) { 6276 return New( 6277 env, 6278 callback, 6279 resource, 6280 resourceName, 6281 maxQueueSize, 6282 initialThreadCount, 6283 context, 6284 finalizeCallback, 6285 static_cast<void*>(nullptr) /* data */, 6286 details::ThreadSafeFinalize<ContextType, 6287 Finalizer>::FinalizeWrapperWithContext); 6288} 6289 6290// static 6291template <typename ResourceString, 6292 typename ContextType, 6293 typename Finalizer, 6294 typename FinalizerDataType> 6295inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env, 6296 const Function& callback, 6297 const Object& resource, 6298 ResourceString resourceName, 6299 size_t maxQueueSize, 6300 size_t initialThreadCount, 6301 ContextType* context, 6302 Finalizer finalizeCallback, 6303 FinalizerDataType* data) { 6304 return New( 6305 env, 6306 callback, 6307 resource, 6308 resourceName, 6309 maxQueueSize, 6310 initialThreadCount, 6311 context, 6312 finalizeCallback, 6313 data, 6314 details::ThreadSafeFinalize<ContextType, Finalizer, FinalizerDataType>:: 6315 FinalizeFinalizeWrapperWithDataAndContext); 6316} 6317 6318inline ThreadSafeFunction::ThreadSafeFunction() : _tsfn() {} 6319 6320inline ThreadSafeFunction::ThreadSafeFunction(napi_threadsafe_function tsfn) 6321 : _tsfn(tsfn) {} 6322 6323inline ThreadSafeFunction::operator napi_threadsafe_function() const { 6324 return _tsfn; 6325} 6326 6327inline napi_status ThreadSafeFunction::BlockingCall() const { 6328 return CallInternal(nullptr, napi_tsfn_blocking); 6329} 6330 6331template <> 6332inline napi_status ThreadSafeFunction::BlockingCall(void* data) const { 6333 return napi_call_threadsafe_function(_tsfn, data, napi_tsfn_blocking); 6334} 6335 6336template <typename Callback> 6337inline napi_status ThreadSafeFunction::BlockingCall(Callback callback) const { 6338 return CallInternal(new CallbackWrapper(callback), napi_tsfn_blocking); 6339} 6340 6341template <typename DataType, typename Callback> 6342inline napi_status ThreadSafeFunction::BlockingCall(DataType* data, 6343 Callback callback) const { 6344 auto wrapper = [data, callback](Env env, Function jsCallback) { 6345 callback(env, jsCallback, data); 6346 }; 6347 return CallInternal(new CallbackWrapper(wrapper), napi_tsfn_blocking); 6348} 6349 6350inline napi_status ThreadSafeFunction::NonBlockingCall() const { 6351 return CallInternal(nullptr, napi_tsfn_nonblocking); 6352} 6353 6354template <> 6355inline napi_status ThreadSafeFunction::NonBlockingCall(void* data) const { 6356 return napi_call_threadsafe_function(_tsfn, data, napi_tsfn_nonblocking); 6357} 6358 6359template <typename Callback> 6360inline napi_status ThreadSafeFunction::NonBlockingCall( 6361 Callback callback) const { 6362 return CallInternal(new CallbackWrapper(callback), napi_tsfn_nonblocking); 6363} 6364 6365template <typename DataType, typename Callback> 6366inline napi_status ThreadSafeFunction::NonBlockingCall( 6367 DataType* data, Callback callback) const { 6368 auto wrapper = [data, callback](Env env, Function jsCallback) { 6369 callback(env, jsCallback, data); 6370 }; 6371 return CallInternal(new CallbackWrapper(wrapper), napi_tsfn_nonblocking); 6372} 6373 6374inline void ThreadSafeFunction::Ref(napi_env env) const { 6375 if (_tsfn != nullptr) { 6376 napi_status status = napi_ref_threadsafe_function(env, _tsfn); 6377 NAPI_THROW_IF_FAILED_VOID(env, status); 6378 } 6379} 6380 6381inline void ThreadSafeFunction::Unref(napi_env env) const { 6382 if (_tsfn != nullptr) { 6383 napi_status status = napi_unref_threadsafe_function(env, _tsfn); 6384 NAPI_THROW_IF_FAILED_VOID(env, status); 6385 } 6386} 6387 6388inline napi_status ThreadSafeFunction::Acquire() const { 6389 return napi_acquire_threadsafe_function(_tsfn); 6390} 6391 6392inline napi_status ThreadSafeFunction::Release() const { 6393 return napi_release_threadsafe_function(_tsfn, napi_tsfn_release); 6394} 6395 6396inline napi_status ThreadSafeFunction::Abort() const { 6397 return napi_release_threadsafe_function(_tsfn, napi_tsfn_abort); 6398} 6399 6400inline ThreadSafeFunction::ConvertibleContext ThreadSafeFunction::GetContext() 6401 const { 6402 void* context; 6403 napi_status status = napi_get_threadsafe_function_context(_tsfn, &context); 6404 NAPI_FATAL_IF_FAILED(status, 6405 "ThreadSafeFunction::GetContext", 6406 "napi_get_threadsafe_function_context"); 6407 return ConvertibleContext({context}); 6408} 6409 6410// static 6411template <typename ResourceString, 6412 typename ContextType, 6413 typename Finalizer, 6414 typename FinalizerDataType> 6415inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env, 6416 const Function& callback, 6417 const Object& resource, 6418 ResourceString resourceName, 6419 size_t maxQueueSize, 6420 size_t initialThreadCount, 6421 ContextType* context, 6422 Finalizer finalizeCallback, 6423 FinalizerDataType* data, 6424 napi_finalize wrapper) { 6425 static_assert(details::can_make_string<ResourceString>::value || 6426 std::is_convertible<ResourceString, napi_value>::value, 6427 "Resource name should be convertible to the string type"); 6428 6429 ThreadSafeFunction tsfn; 6430 auto* finalizeData = new details:: 6431 ThreadSafeFinalize<ContextType, Finalizer, FinalizerDataType>( 6432 {data, finalizeCallback}); 6433 napi_status status = 6434 napi_create_threadsafe_function(env, 6435 callback, 6436 resource, 6437 Value::From(env, resourceName), 6438 maxQueueSize, 6439 initialThreadCount, 6440 finalizeData, 6441 wrapper, 6442 context, 6443 CallJS, 6444 &tsfn._tsfn); 6445 if (status != napi_ok) { 6446 delete finalizeData; 6447 NAPI_THROW_IF_FAILED(env, status, ThreadSafeFunction()); 6448 } 6449 6450 return tsfn; 6451} 6452 6453inline napi_status ThreadSafeFunction::CallInternal( 6454 CallbackWrapper* callbackWrapper, 6455 napi_threadsafe_function_call_mode mode) const { 6456 napi_status status = 6457 napi_call_threadsafe_function(_tsfn, callbackWrapper, mode); 6458 if (status != napi_ok && callbackWrapper != nullptr) { 6459 delete callbackWrapper; 6460 } 6461 6462 return status; 6463} 6464 6465// static 6466inline void ThreadSafeFunction::CallJS(napi_env env, 6467 napi_value jsCallback, 6468 void* /* context */, 6469 void* data) { 6470 if (env == nullptr && jsCallback == nullptr) { 6471 return; 6472 } 6473 6474 details::WrapVoidCallback(env, [&]() { 6475 if (data != nullptr) { 6476 auto* callbackWrapper = static_cast<CallbackWrapper*>(data); 6477 (*callbackWrapper)(env, Function(env, jsCallback)); 6478 delete callbackWrapper; 6479 } else if (jsCallback != nullptr) { 6480 Function(env, jsCallback).Call({}); 6481 } 6482 }); 6483} 6484 6485//////////////////////////////////////////////////////////////////////////////// 6486// Async Progress Worker Base class 6487//////////////////////////////////////////////////////////////////////////////// 6488template <typename DataType> 6489inline AsyncProgressWorkerBase<DataType>::AsyncProgressWorkerBase( 6490 const Object& receiver, 6491 const Function& callback, 6492 const char* resource_name, 6493 const Object& resource, 6494 size_t queue_size) 6495 : AsyncWorker(receiver, callback, resource_name, resource) { 6496 // Fill all possible arguments to work around ambiguous 6497 // ThreadSafeFunction::New signatures. 6498 _tsfn = ThreadSafeFunction::New(callback.Env(), 6499 callback, 6500 resource, 6501 resource_name, 6502 queue_size, 6503 /** initialThreadCount */ 1, 6504 /** context */ this, 6505 OnThreadSafeFunctionFinalize, 6506 /** finalizeData */ this); 6507} 6508 6509#if NAPI_VERSION > 4 6510template <typename DataType> 6511inline AsyncProgressWorkerBase<DataType>::AsyncProgressWorkerBase( 6512 Napi::Env env, 6513 const char* resource_name, 6514 const Object& resource, 6515 size_t queue_size) 6516 : AsyncWorker(env, resource_name, resource) { 6517 // TODO: Once the changes to make the callback optional for threadsafe 6518 // functions are available on all versions we can remove the dummy Function 6519 // here. 6520 Function callback; 6521 // Fill all possible arguments to work around ambiguous 6522 // ThreadSafeFunction::New signatures. 6523 _tsfn = ThreadSafeFunction::New(env, 6524 callback, 6525 resource, 6526 resource_name, 6527 queue_size, 6528 /** initialThreadCount */ 1, 6529 /** context */ this, 6530 OnThreadSafeFunctionFinalize, 6531 /** finalizeData */ this); 6532} 6533#endif 6534 6535template <typename DataType> 6536inline AsyncProgressWorkerBase<DataType>::~AsyncProgressWorkerBase() { 6537 // Abort pending tsfn call. 6538 // Don't send progress events after we've already completed. 6539 // It's ok to call ThreadSafeFunction::Abort and ThreadSafeFunction::Release 6540 // duplicated. 6541 _tsfn.Abort(); 6542} 6543 6544template <typename DataType> 6545inline void AsyncProgressWorkerBase<DataType>::OnAsyncWorkProgress( 6546 Napi::Env /* env */, Napi::Function /* jsCallback */, void* data) { 6547 ThreadSafeData* tsd = static_cast<ThreadSafeData*>(data); 6548 tsd->asyncprogressworker()->OnWorkProgress(tsd->data()); 6549 delete tsd; 6550} 6551 6552template <typename DataType> 6553inline napi_status AsyncProgressWorkerBase<DataType>::NonBlockingCall( 6554 DataType* data) { 6555 auto tsd = new AsyncProgressWorkerBase::ThreadSafeData(this, data); 6556 auto ret = _tsfn.NonBlockingCall(tsd, OnAsyncWorkProgress); 6557 if (ret != napi_ok) { 6558 delete tsd; 6559 } 6560 return ret; 6561} 6562 6563template <typename DataType> 6564inline void AsyncProgressWorkerBase<DataType>::OnWorkComplete( 6565 Napi::Env /* env */, napi_status status) { 6566 _work_completed = true; 6567 _complete_status = status; 6568 _tsfn.Release(); 6569} 6570 6571template <typename DataType> 6572inline void AsyncProgressWorkerBase<DataType>::OnThreadSafeFunctionFinalize( 6573 Napi::Env env, void* /* data */, AsyncProgressWorkerBase* context) { 6574 if (context->_work_completed) { 6575 context->AsyncWorker::OnWorkComplete(env, context->_complete_status); 6576 } 6577} 6578 6579//////////////////////////////////////////////////////////////////////////////// 6580// Async Progress Worker class 6581//////////////////////////////////////////////////////////////////////////////// 6582template <class T> 6583inline AsyncProgressWorker<T>::AsyncProgressWorker(const Function& callback) 6584 : AsyncProgressWorker(callback, "generic") {} 6585 6586template <class T> 6587inline AsyncProgressWorker<T>::AsyncProgressWorker(const Function& callback, 6588 const char* resource_name) 6589 : AsyncProgressWorker( 6590 callback, resource_name, Object::New(callback.Env())) {} 6591 6592template <class T> 6593inline AsyncProgressWorker<T>::AsyncProgressWorker(const Function& callback, 6594 const char* resource_name, 6595 const Object& resource) 6596 : AsyncProgressWorker( 6597 Object::New(callback.Env()), callback, resource_name, resource) {} 6598 6599template <class T> 6600inline AsyncProgressWorker<T>::AsyncProgressWorker(const Object& receiver, 6601 const Function& callback) 6602 : AsyncProgressWorker(receiver, callback, "generic") {} 6603 6604template <class T> 6605inline AsyncProgressWorker<T>::AsyncProgressWorker(const Object& receiver, 6606 const Function& callback, 6607 const char* resource_name) 6608 : AsyncProgressWorker( 6609 receiver, callback, resource_name, Object::New(callback.Env())) {} 6610 6611template <class T> 6612inline AsyncProgressWorker<T>::AsyncProgressWorker(const Object& receiver, 6613 const Function& callback, 6614 const char* resource_name, 6615 const Object& resource) 6616 : AsyncProgressWorkerBase(receiver, callback, resource_name, resource), 6617 _asyncdata(nullptr), 6618 _asyncsize(0), 6619 _signaled(false) {} 6620 6621#if NAPI_VERSION > 4 6622template <class T> 6623inline AsyncProgressWorker<T>::AsyncProgressWorker(Napi::Env env) 6624 : AsyncProgressWorker(env, "generic") {} 6625 6626template <class T> 6627inline AsyncProgressWorker<T>::AsyncProgressWorker(Napi::Env env, 6628 const char* resource_name) 6629 : AsyncProgressWorker(env, resource_name, Object::New(env)) {} 6630 6631template <class T> 6632inline AsyncProgressWorker<T>::AsyncProgressWorker(Napi::Env env, 6633 const char* resource_name, 6634 const Object& resource) 6635 : AsyncProgressWorkerBase(env, resource_name, resource), 6636 _asyncdata(nullptr), 6637 _asyncsize(0) {} 6638#endif 6639 6640template <class T> 6641inline AsyncProgressWorker<T>::~AsyncProgressWorker() { 6642 { 6643 std::lock_guard<std::mutex> lock(this->_mutex); 6644 _asyncdata = nullptr; 6645 _asyncsize = 0; 6646 } 6647} 6648 6649template <class T> 6650inline void AsyncProgressWorker<T>::Execute() { 6651 ExecutionProgress progress(this); 6652 Execute(progress); 6653} 6654 6655template <class T> 6656inline void AsyncProgressWorker<T>::OnWorkProgress(void*) { 6657 T* data; 6658 size_t size; 6659 bool signaled; 6660 { 6661 std::lock_guard<std::mutex> lock(this->_mutex); 6662 data = this->_asyncdata; 6663 size = this->_asyncsize; 6664 signaled = this->_signaled; 6665 this->_asyncdata = nullptr; 6666 this->_asyncsize = 0; 6667 this->_signaled = false; 6668 } 6669 6670 /** 6671 * The callback of ThreadSafeFunction is not been invoked immediately on the 6672 * callback of uv_async_t (uv io poll), rather the callback of TSFN is 6673 * invoked on the right next uv idle callback. There are chances that during 6674 * the deferring the signal of uv_async_t is been sent again, i.e. potential 6675 * not coalesced two calls of the TSFN callback. 6676 */ 6677 if (data == nullptr && !signaled) { 6678 return; 6679 } 6680 6681 this->OnProgress(data, size); 6682 delete[] data; 6683} 6684 6685template <class T> 6686inline void AsyncProgressWorker<T>::SendProgress_(const T* data, size_t count) { 6687 T* new_data = new T[count]; 6688 std::copy(data, data + count, new_data); 6689 6690 T* old_data; 6691 { 6692 std::lock_guard<std::mutex> lock(this->_mutex); 6693 old_data = _asyncdata; 6694 _asyncdata = new_data; 6695 _asyncsize = count; 6696 _signaled = false; 6697 } 6698 this->NonBlockingCall(nullptr); 6699 6700 delete[] old_data; 6701} 6702 6703template <class T> 6704inline void AsyncProgressWorker<T>::Signal() { 6705 { 6706 std::lock_guard<std::mutex> lock(this->_mutex); 6707 _signaled = true; 6708 } 6709 this->NonBlockingCall(static_cast<T*>(nullptr)); 6710} 6711 6712template <class T> 6713inline void AsyncProgressWorker<T>::ExecutionProgress::Signal() const { 6714 this->_worker->Signal(); 6715} 6716 6717template <class T> 6718inline void AsyncProgressWorker<T>::ExecutionProgress::Send( 6719 const T* data, size_t count) const { 6720 _worker->SendProgress_(data, count); 6721} 6722 6723//////////////////////////////////////////////////////////////////////////////// 6724// Async Progress Queue Worker class 6725//////////////////////////////////////////////////////////////////////////////// 6726template <class T> 6727inline AsyncProgressQueueWorker<T>::AsyncProgressQueueWorker( 6728 const Function& callback) 6729 : AsyncProgressQueueWorker(callback, "generic") {} 6730 6731template <class T> 6732inline AsyncProgressQueueWorker<T>::AsyncProgressQueueWorker( 6733 const Function& callback, const char* resource_name) 6734 : AsyncProgressQueueWorker( 6735 callback, resource_name, Object::New(callback.Env())) {} 6736 6737template <class T> 6738inline AsyncProgressQueueWorker<T>::AsyncProgressQueueWorker( 6739 const Function& callback, const char* resource_name, const Object& resource) 6740 : AsyncProgressQueueWorker( 6741 Object::New(callback.Env()), callback, resource_name, resource) {} 6742 6743template <class T> 6744inline AsyncProgressQueueWorker<T>::AsyncProgressQueueWorker( 6745 const Object& receiver, const Function& callback) 6746 : AsyncProgressQueueWorker(receiver, callback, "generic") {} 6747 6748template <class T> 6749inline AsyncProgressQueueWorker<T>::AsyncProgressQueueWorker( 6750 const Object& receiver, const Function& callback, const char* resource_name) 6751 : AsyncProgressQueueWorker( 6752 receiver, callback, resource_name, Object::New(callback.Env())) {} 6753 6754template <class T> 6755inline AsyncProgressQueueWorker<T>::AsyncProgressQueueWorker( 6756 const Object& receiver, 6757 const Function& callback, 6758 const char* resource_name, 6759 const Object& resource) 6760 : AsyncProgressWorkerBase<std::pair<T*, size_t>>( 6761 receiver, 6762 callback, 6763 resource_name, 6764 resource, 6765 /** unlimited queue size */ 0) {} 6766 6767#if NAPI_VERSION > 4 6768template <class T> 6769inline AsyncProgressQueueWorker<T>::AsyncProgressQueueWorker(Napi::Env env) 6770 : AsyncProgressQueueWorker(env, "generic") {} 6771 6772template <class T> 6773inline AsyncProgressQueueWorker<T>::AsyncProgressQueueWorker( 6774 Napi::Env env, const char* resource_name) 6775 : AsyncProgressQueueWorker(env, resource_name, Object::New(env)) {} 6776 6777template <class T> 6778inline AsyncProgressQueueWorker<T>::AsyncProgressQueueWorker( 6779 Napi::Env env, const char* resource_name, const Object& resource) 6780 : AsyncProgressWorkerBase<std::pair<T*, size_t>>( 6781 env, resource_name, resource, /** unlimited queue size */ 0) {} 6782#endif 6783 6784template <class T> 6785inline void AsyncProgressQueueWorker<T>::Execute() { 6786 ExecutionProgress progress(this); 6787 Execute(progress); 6788} 6789 6790template <class T> 6791inline void AsyncProgressQueueWorker<T>::OnWorkProgress( 6792 std::pair<T*, size_t>* datapair) { 6793 if (datapair == nullptr) { 6794 return; 6795 } 6796 6797 T* data = datapair->first; 6798 size_t size = datapair->second; 6799 6800 this->OnProgress(data, size); 6801 delete datapair; 6802 delete[] data; 6803} 6804 6805template <class T> 6806inline void AsyncProgressQueueWorker<T>::SendProgress_(const T* data, 6807 size_t count) { 6808 T* new_data = new T[count]; 6809 std::copy(data, data + count, new_data); 6810 6811 auto pair = new std::pair<T*, size_t>(new_data, count); 6812 this->NonBlockingCall(pair); 6813} 6814 6815template <class T> 6816inline void AsyncProgressQueueWorker<T>::Signal() const { 6817 this->SendProgress_(static_cast<T*>(nullptr), 0); 6818} 6819 6820template <class T> 6821inline void AsyncProgressQueueWorker<T>::OnWorkComplete(Napi::Env env, 6822 napi_status status) { 6823 // Draining queued items in TSFN. 6824 AsyncProgressWorkerBase<std::pair<T*, size_t>>::OnWorkComplete(env, status); 6825} 6826 6827template <class T> 6828inline void AsyncProgressQueueWorker<T>::ExecutionProgress::Signal() const { 6829 _worker->SendProgress_(static_cast<T*>(nullptr), 0); 6830} 6831 6832template <class T> 6833inline void AsyncProgressQueueWorker<T>::ExecutionProgress::Send( 6834 const T* data, size_t count) const { 6835 _worker->SendProgress_(data, count); 6836} 6837#endif // NAPI_VERSION > 3 && NAPI_HAS_THREADS 6838 6839//////////////////////////////////////////////////////////////////////////////// 6840// Memory Management class 6841//////////////////////////////////////////////////////////////////////////////// 6842 6843inline int64_t MemoryManagement::AdjustExternalMemory(BasicEnv env, 6844 int64_t change_in_bytes) { 6845 int64_t result; 6846 napi_status status = 6847 napi_adjust_external_memory(env, change_in_bytes, &result); 6848 NAPI_FATAL_IF_FAILED(status, 6849 "MemoryManagement::AdjustExternalMemory", 6850 "napi_adjust_external_memory"); 6851 return result; 6852} 6853 6854//////////////////////////////////////////////////////////////////////////////// 6855// Version Management class 6856//////////////////////////////////////////////////////////////////////////////// 6857 6858inline uint32_t VersionManagement::GetNapiVersion(BasicEnv env) { 6859 uint32_t result; 6860 napi_status status = napi_get_version(env, &result); 6861 NAPI_FATAL_IF_FAILED( 6862 status, "VersionManagement::GetNapiVersion", "napi_get_version"); 6863 return result; 6864} 6865 6866inline const napi_node_version* VersionManagement::GetNodeVersion( 6867 BasicEnv env) { 6868 const napi_node_version* result; 6869 napi_status status = napi_get_node_version(env, &result); 6870 NAPI_FATAL_IF_FAILED( 6871 status, "VersionManagement::GetNodeVersion", "napi_get_node_version"); 6872 return result; 6873} 6874 6875#if NAPI_VERSION > 5 6876//////////////////////////////////////////////////////////////////////////////// 6877// Addon<T> class 6878//////////////////////////////////////////////////////////////////////////////// 6879 6880template <typename T> 6881inline Object Addon<T>::Init(Env env, Object exports) { 6882 T* addon = new T(env, exports); 6883 env.SetInstanceData(addon); 6884 return addon->entry_point_; 6885} 6886 6887template <typename T> 6888inline T* Addon<T>::Unwrap(Object wrapper) { 6889 return wrapper.Env().GetInstanceData<T>(); 6890} 6891 6892template <typename T> 6893inline void Addon<T>::DefineAddon( 6894 Object exports, const std::initializer_list<AddonProp>& props) { 6895 DefineProperties(exports, props); 6896 entry_point_ = exports; 6897} 6898 6899template <typename T> 6900inline Napi::Object Addon<T>::DefineProperties( 6901 Object object, const std::initializer_list<AddonProp>& props) { 6902 const napi_property_descriptor* properties = 6903 reinterpret_cast<const napi_property_descriptor*>(props.begin()); 6904 size_t size = props.size(); 6905 napi_status status = 6906 napi_define_properties(object.Env(), object, size, properties); 6907 NAPI_THROW_IF_FAILED(object.Env(), status, object); 6908 for (size_t idx = 0; idx < size; idx++) 6909 T::AttachPropData(object.Env(), object, &properties[idx]); 6910 return object; 6911} 6912#endif // NAPI_VERSION > 5 6913 6914#if NAPI_VERSION > 2 6915template <typename Hook, typename Arg> 6916Env::CleanupHook<Hook, Arg> BasicEnv::AddCleanupHook(Hook hook, Arg* arg) { 6917 return CleanupHook<Hook, Arg>(*this, hook, arg); 6918} 6919 6920template <typename Hook> 6921Env::CleanupHook<Hook> BasicEnv::AddCleanupHook(Hook hook) { 6922 return CleanupHook<Hook>(*this, hook); 6923} 6924 6925template <typename Hook, typename Arg> 6926Env::CleanupHook<Hook, Arg>::CleanupHook() { 6927 data = nullptr; 6928} 6929 6930template <typename Hook, typename Arg> 6931Env::CleanupHook<Hook, Arg>::CleanupHook(Napi::BasicEnv env, Hook hook) 6932 : wrapper(Env::CleanupHook<Hook, Arg>::Wrapper) { 6933 data = new CleanupData{std::move(hook), nullptr}; 6934 napi_status status = napi_add_env_cleanup_hook(env, wrapper, data); 6935 if (status != napi_ok) { 6936 delete data; 6937 data = nullptr; 6938 } 6939} 6940 6941template <typename Hook, typename Arg> 6942Env::CleanupHook<Hook, Arg>::CleanupHook(Napi::BasicEnv env, 6943 Hook hook, 6944 Arg* arg) 6945 : wrapper(Env::CleanupHook<Hook, Arg>::WrapperWithArg) { 6946 data = new CleanupData{std::move(hook), arg}; 6947 napi_status status = napi_add_env_cleanup_hook(env, wrapper, data); 6948 if (status != napi_ok) { 6949 delete data; 6950 data = nullptr; 6951 } 6952} 6953 6954template <class Hook, class Arg> 6955bool Env::CleanupHook<Hook, Arg>::Remove(BasicEnv env) { 6956 napi_status status = napi_remove_env_cleanup_hook(env, wrapper, data); 6957 delete data; 6958 data = nullptr; 6959 return status == napi_ok; 6960} 6961 6962template <class Hook, class Arg> 6963bool Env::CleanupHook<Hook, Arg>::IsEmpty() const { 6964 return data == nullptr; 6965} 6966#endif // NAPI_VERSION > 2 6967 6968#ifdef NODE_API_EXPERIMENTAL_HAS_POST_FINALIZER 6969template <typename FinalizerType> 6970inline void BasicEnv::PostFinalizer(FinalizerType finalizeCallback) const { 6971 using T = void*; 6972 details::FinalizeData<T, FinalizerType>* finalizeData = 6973 new details::FinalizeData<T, FinalizerType>( 6974 {std::move(finalizeCallback), nullptr}); 6975 6976 napi_status status = node_api_post_finalizer( 6977 _env, 6978 details::FinalizeData<T, FinalizerType>::WrapperGCWithoutData, 6979 static_cast<void*>(nullptr), 6980 finalizeData); 6981 if (status != napi_ok) { 6982 delete finalizeData; 6983 NAPI_FATAL_IF_FAILED( 6984 status, "BasicEnv::PostFinalizer", "invalid arguments"); 6985 } 6986} 6987 6988template <typename FinalizerType, typename T> 6989inline void BasicEnv::PostFinalizer(FinalizerType finalizeCallback, 6990 T* data) const { 6991 details::FinalizeData<T, FinalizerType>* finalizeData = 6992 new details::FinalizeData<T, FinalizerType>( 6993 {std::move(finalizeCallback), nullptr}); 6994 6995 napi_status status = node_api_post_finalizer( 6996 _env, 6997 details::FinalizeData<T, FinalizerType>::WrapperGC, 6998 data, 6999 finalizeData); 7000 if (status != napi_ok) { 7001 delete finalizeData; 7002 NAPI_FATAL_IF_FAILED( 7003 status, "BasicEnv::PostFinalizer", "invalid arguments"); 7004 } 7005} 7006 7007template <typename FinalizerType, typename T, typename Hint> 7008inline void BasicEnv::PostFinalizer(FinalizerType finalizeCallback, 7009 T* data, 7010 Hint* finalizeHint) const { 7011 details::FinalizeData<T, FinalizerType, Hint>* finalizeData = 7012 new details::FinalizeData<T, FinalizerType, Hint>( 7013 {std::move(finalizeCallback), finalizeHint}); 7014 napi_status status = node_api_post_finalizer( 7015 _env, 7016 details::FinalizeData<T, FinalizerType, Hint>::WrapperGCWithHint, 7017 data, 7018 finalizeData); 7019 if (status != napi_ok) { 7020 delete finalizeData; 7021 NAPI_FATAL_IF_FAILED( 7022 status, "BasicEnv::PostFinalizer", "invalid arguments"); 7023 } 7024} 7025#endif // NODE_API_EXPERIMENTAL_HAS_POST_FINALIZER 7026 7027#ifdef NAPI_CPP_CUSTOM_NAMESPACE 7028} // namespace NAPI_CPP_CUSTOM_NAMESPACE 7029#endif 7030 7031} // namespace Napi 7032 7033#endif // SRC_NAPI_INL_H_