OR-1 dataflow CPU sketch
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_