source: trip-planner-front/node_modules/node-addon-api/napi-inl.h@ 8d391a1

Last change on this file since 8d391a1 was e29cc2e, checked in by Ema <ema_spirova@…>, 3 years ago

primeNG components

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