source: imaps-frontend/node_modules/node-addon-api/napi-inl.h@ 0c6b92a

main
Last change on this file since 0c6b92a was 0c6b92a, checked in by stefan toskovski <stefantoska84@…>, 5 weeks ago

Pred finalna verzija

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