node-addon-api 1.6.2 → 1.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/napi-inl.h CHANGED
@@ -17,49 +17,6 @@ namespace Napi {
17
17
  // Helpers to handle functions exposed from C++.
18
18
  namespace details {
19
19
 
20
- #ifdef NAPI_CPP_EXCEPTIONS
21
-
22
- #define NAPI_THROW(e) throw e
23
-
24
- // When C++ exceptions are enabled, Errors are thrown directly. There is no need
25
- // to return anything after the throw statement. The variadic parameter is an
26
- // optional return value that is ignored.
27
- #define NAPI_THROW_IF_FAILED(env, status, ...) \
28
- if ((status) != napi_ok) throw Error::New(env);
29
-
30
- #define NAPI_THROW_IF_FAILED_VOID(env, status) \
31
- if ((status) != napi_ok) throw Error::New(env);
32
-
33
- #else // NAPI_CPP_EXCEPTIONS
34
-
35
- #define NAPI_THROW(e) (e).ThrowAsJavaScriptException();
36
-
37
- // When C++ exceptions are disabled, Errors are thrown as JavaScript exceptions,
38
- // which are pending until the callback returns to JS. The variadic parameter
39
- // is an optional return value; usually it is an empty result.
40
- #define NAPI_THROW_IF_FAILED(env, status, ...) \
41
- if ((status) != napi_ok) { \
42
- Error::New(env).ThrowAsJavaScriptException(); \
43
- return __VA_ARGS__; \
44
- }
45
-
46
- // We need a _VOID version of this macro to avoid warnings resulting from
47
- // leaving the NAPI_THROW_IF_FAILED `...` argument empty.
48
- #define NAPI_THROW_IF_FAILED_VOID(env, status) \
49
- if ((status) != napi_ok) { \
50
- Error::New(env).ThrowAsJavaScriptException(); \
51
- return; \
52
- }
53
-
54
- #endif // NAPI_CPP_EXCEPTIONS
55
-
56
- #define NAPI_FATAL_IF_FAILED(status, location, message) \
57
- do { \
58
- if ((status) != napi_ok) { \
59
- Error::Fatal((location), (message)); \
60
- } \
61
- } while (0)
62
-
63
20
  // Attach a data item to an object and delete it when the object gets
64
21
  // garbage-collected.
65
22
  // TODO: Replace this code with `napi_add_finalizer()` whenever it becomes
@@ -168,6 +125,80 @@ struct FinalizeData {
168
125
  Hint* hint;
169
126
  };
170
127
 
128
+ #if (NAPI_VERSION > 3)
129
+ template <typename ContextType=void,
130
+ typename Finalizer=std::function<void(Env, void*, ContextType*)>,
131
+ typename FinalizerDataType=void>
132
+ struct ThreadSafeFinalize {
133
+ static inline
134
+ void Wrapper(napi_env env, void* rawFinalizeData, void* /* rawContext */) {
135
+ if (rawFinalizeData == nullptr)
136
+ return;
137
+
138
+ ThreadSafeFinalize* finalizeData =
139
+ static_cast<ThreadSafeFinalize*>(rawFinalizeData);
140
+ finalizeData->callback(Env(env));
141
+ if (finalizeData->tsfn) {
142
+ *finalizeData->tsfn = nullptr;
143
+ }
144
+ delete finalizeData;
145
+ }
146
+
147
+ static inline
148
+ void FinalizeWrapperWithData(napi_env env,
149
+ void* rawFinalizeData,
150
+ void* /* rawContext */) {
151
+ if (rawFinalizeData == nullptr)
152
+ return;
153
+
154
+ ThreadSafeFinalize* finalizeData =
155
+ static_cast<ThreadSafeFinalize*>(rawFinalizeData);
156
+ finalizeData->callback(Env(env), finalizeData->data);
157
+ if (finalizeData->tsfn) {
158
+ *finalizeData->tsfn = nullptr;
159
+ }
160
+ delete finalizeData;
161
+ }
162
+
163
+ static inline
164
+ void FinalizeWrapperWithContext(napi_env env,
165
+ void* rawFinalizeData,
166
+ void* rawContext) {
167
+ if (rawFinalizeData == nullptr)
168
+ return;
169
+
170
+ ThreadSafeFinalize* finalizeData =
171
+ static_cast<ThreadSafeFinalize*>(rawFinalizeData);
172
+ finalizeData->callback(Env(env), static_cast<ContextType*>(rawContext));
173
+ if (finalizeData->tsfn) {
174
+ *finalizeData->tsfn = nullptr;
175
+ }
176
+ delete finalizeData;
177
+ }
178
+
179
+ static inline
180
+ void FinalizeFinalizeWrapperWithDataAndContext(napi_env env,
181
+ void* rawFinalizeData,
182
+ void* rawContext) {
183
+ if (rawFinalizeData == nullptr)
184
+ return;
185
+
186
+ ThreadSafeFinalize* finalizeData =
187
+ static_cast<ThreadSafeFinalize*>(rawFinalizeData);
188
+ finalizeData->callback(Env(env), finalizeData->data,
189
+ static_cast<ContextType*>(rawContext));
190
+ if (finalizeData->tsfn) {
191
+ *finalizeData->tsfn = nullptr;
192
+ }
193
+ delete finalizeData;
194
+ }
195
+
196
+ FinalizerDataType* data;
197
+ Finalizer callback;
198
+ napi_threadsafe_function* tsfn;
199
+ };
200
+ #endif
201
+
171
202
  template <typename Getter, typename Setter>
172
203
  struct AccessorCallbackData {
173
204
  static inline
@@ -176,6 +207,7 @@ struct AccessorCallbackData {
176
207
  CallbackInfo callbackInfo(env, info);
177
208
  AccessorCallbackData* callbackData =
178
209
  static_cast<AccessorCallbackData*>(callbackInfo.Data());
210
+ callbackInfo.SetData(callbackData->data);
179
211
  return callbackData->getterCallback(callbackInfo);
180
212
  });
181
213
  }
@@ -186,6 +218,7 @@ struct AccessorCallbackData {
186
218
  CallbackInfo callbackInfo(env, info);
187
219
  AccessorCallbackData* callbackData =
188
220
  static_cast<AccessorCallbackData*>(callbackInfo.Data());
221
+ callbackInfo.SetData(callbackData->data);
189
222
  callbackData->setterCallback(callbackInfo);
190
223
  return nullptr;
191
224
  });
@@ -193,6 +226,7 @@ struct AccessorCallbackData {
193
226
 
194
227
  Getter getterCallback;
195
228
  Setter setterCallback;
229
+ void* data;
196
230
  };
197
231
 
198
232
  } // namespace details
@@ -311,7 +345,7 @@ inline bool Value::IsEmpty() const {
311
345
  }
312
346
 
313
347
  inline napi_valuetype Value::Type() const {
314
- if (_value == nullptr) {
348
+ if (IsEmpty()) {
315
349
  return napi_undefined;
316
350
  }
317
351
 
@@ -354,7 +388,7 @@ inline bool Value::IsSymbol() const {
354
388
  }
355
389
 
356
390
  inline bool Value::IsArray() const {
357
- if (_value == nullptr) {
391
+ if (IsEmpty()) {
358
392
  return false;
359
393
  }
360
394
 
@@ -365,7 +399,7 @@ inline bool Value::IsArray() const {
365
399
  }
366
400
 
367
401
  inline bool Value::IsArrayBuffer() const {
368
- if (_value == nullptr) {
402
+ if (IsEmpty()) {
369
403
  return false;
370
404
  }
371
405
 
@@ -376,7 +410,7 @@ inline bool Value::IsArrayBuffer() const {
376
410
  }
377
411
 
378
412
  inline bool Value::IsTypedArray() const {
379
- if (_value == nullptr) {
413
+ if (IsEmpty()) {
380
414
  return false;
381
415
  }
382
416
 
@@ -395,7 +429,7 @@ inline bool Value::IsFunction() const {
395
429
  }
396
430
 
397
431
  inline bool Value::IsPromise() const {
398
- if (_value == nullptr) {
432
+ if (IsEmpty()) {
399
433
  return false;
400
434
  }
401
435
 
@@ -406,7 +440,7 @@ inline bool Value::IsPromise() const {
406
440
  }
407
441
 
408
442
  inline bool Value::IsDataView() const {
409
- if (_value == nullptr) {
443
+ if (IsEmpty()) {
410
444
  return false;
411
445
  }
412
446
 
@@ -417,7 +451,7 @@ inline bool Value::IsDataView() const {
417
451
  }
418
452
 
419
453
  inline bool Value::IsBuffer() const {
420
- if (_value == nullptr) {
454
+ if (IsEmpty()) {
421
455
  return false;
422
456
  }
423
457
 
@@ -1060,7 +1094,7 @@ inline bool Object::Delete(uint32_t index) {
1060
1094
  return result;
1061
1095
  }
1062
1096
 
1063
- inline Array Object::GetPropertyNames() {
1097
+ inline Array Object::GetPropertyNames() const {
1064
1098
  napi_value result;
1065
1099
  napi_status status = napi_get_property_names(_env, _value, &result);
1066
1100
  NAPI_THROW_IF_FAILED(_env, status, Array());
@@ -1309,8 +1343,8 @@ inline DataView DataView::New(napi_env env,
1309
1343
  size_t byteOffset) {
1310
1344
  if (byteOffset > arrayBuffer.ByteLength()) {
1311
1345
  NAPI_THROW(RangeError::New(env,
1312
- "Start offset is outside the bounds of the buffer"));
1313
- return DataView();
1346
+ "Start offset is outside the bounds of the buffer"),
1347
+ DataView());
1314
1348
  }
1315
1349
  return New(env, arrayBuffer, byteOffset,
1316
1350
  arrayBuffer.ByteLength() - byteOffset);
@@ -1321,8 +1355,8 @@ inline DataView DataView::New(napi_env env,
1321
1355
  size_t byteOffset,
1322
1356
  size_t byteLength) {
1323
1357
  if (byteOffset + byteLength > arrayBuffer.ByteLength()) {
1324
- NAPI_THROW(RangeError::New(env, "Invalid DataView length"));
1325
- return DataView();
1358
+ NAPI_THROW(RangeError::New(env, "Invalid DataView length"),
1359
+ DataView());
1326
1360
  }
1327
1361
  napi_value value;
1328
1362
  napi_status status = napi_create_dataview(
@@ -1448,8 +1482,7 @@ inline T DataView::ReadData(size_t byteOffset) const {
1448
1482
  if (byteOffset + sizeof(T) > _length ||
1449
1483
  byteOffset + sizeof(T) < byteOffset) { // overflow
1450
1484
  NAPI_THROW(RangeError::New(_env,
1451
- "Offset is outside the bounds of the DataView"));
1452
- return 0;
1485
+ "Offset is outside the bounds of the DataView"), 0);
1453
1486
  }
1454
1487
 
1455
1488
  return *reinterpret_cast<T*>(static_cast<uint8_t*>(_data) + byteOffset);
@@ -1459,9 +1492,8 @@ template <typename T>
1459
1492
  inline void DataView::WriteData(size_t byteOffset, T value) const {
1460
1493
  if (byteOffset + sizeof(T) > _length ||
1461
1494
  byteOffset + sizeof(T) < byteOffset) { // overflow
1462
- NAPI_THROW(RangeError::New(_env,
1495
+ NAPI_THROW_VOID(RangeError::New(_env,
1463
1496
  "Offset is outside the bounds of the DataView"));
1464
- return;
1465
1497
  }
1466
1498
 
1467
1499
  *reinterpret_cast<T*>(static_cast<uint8_t*>(_data) + byteOffset) = value;
@@ -1597,7 +1629,7 @@ inline TypedArrayOf<T>::TypedArrayOf(napi_env env,
1597
1629
  : TypedArray(env, value, type, length), _data(data) {
1598
1630
  if (!(type == TypedArrayTypeForPrimitiveType<T>() ||
1599
1631
  (type == napi_uint8_clamped_array && std::is_same<T, uint8_t>::value))) {
1600
- NAPI_THROW(TypeError::New(env, "Array type must match the template parameter. "
1632
+ NAPI_THROW_VOID(TypeError::New(env, "Array type must match the template parameter. "
1601
1633
  "(Uint8 arrays may optionally have the \"clamped\" array type.)"));
1602
1634
  }
1603
1635
  }
@@ -1657,7 +1689,11 @@ inline Function Function::New(napi_env env,
1657
1689
  CbData::Wrapper,
1658
1690
  callbackData,
1659
1691
  &value);
1660
- NAPI_THROW_IF_FAILED(env, status, Function());
1692
+ if (status != napi_ok) {
1693
+ delete callbackData;
1694
+ NAPI_THROW_IF_FAILED(env, status, Function());
1695
+ }
1696
+
1661
1697
  return Function(env, value);
1662
1698
  }
1663
1699
 
@@ -2031,8 +2067,20 @@ inline const std::string& Error::Message() const NAPI_NOEXCEPT {
2031
2067
  inline void Error::ThrowAsJavaScriptException() const {
2032
2068
  HandleScope scope(_env);
2033
2069
  if (!IsEmpty()) {
2070
+
2071
+ // We intentionally don't use `NAPI_THROW_*` macros here to ensure
2072
+ // that there is no possible recursion as `ThrowAsJavaScriptException`
2073
+ // is part of `NAPI_THROW_*` macro definition for noexcept.
2074
+
2034
2075
  napi_status status = napi_throw(_env, Value());
2035
- NAPI_THROW_IF_FAILED_VOID(_env, status);
2076
+
2077
+ #ifdef NAPI_CPP_EXCEPTIONS
2078
+ if (status != napi_ok) {
2079
+ throw Error::New(_env);
2080
+ }
2081
+ #else // NAPI_CPP_EXCEPTIONS
2082
+ NAPI_FATAL_IF_FAILED(status, "Error::ThrowAsJavaScriptException", "napi_throw");
2083
+ #endif // NAPI_CPP_EXCEPTIONS
2036
2084
  }
2037
2085
  }
2038
2086
 
@@ -2603,12 +2651,15 @@ PropertyDescriptor::Accessor(Napi::Env env,
2603
2651
  const char* utf8name,
2604
2652
  Getter getter,
2605
2653
  napi_property_attributes attributes,
2606
- void* /*data*/) {
2654
+ void* data) {
2607
2655
  typedef details::CallbackData<Getter, Napi::Value> CbData;
2608
- auto callbackData = new CbData({ getter, nullptr });
2656
+ auto callbackData = new CbData({ getter, data });
2609
2657
 
2610
2658
  napi_status status = AttachData(env, object, callbackData);
2611
- NAPI_THROW_IF_FAILED(env, status, napi_property_descriptor());
2659
+ if (status != napi_ok) {
2660
+ delete callbackData;
2661
+ NAPI_THROW_IF_FAILED(env, status, napi_property_descriptor());
2662
+ }
2612
2663
 
2613
2664
  return PropertyDescriptor({
2614
2665
  utf8name,
@@ -2638,12 +2689,15 @@ inline PropertyDescriptor PropertyDescriptor::Accessor(Napi::Env env,
2638
2689
  Name name,
2639
2690
  Getter getter,
2640
2691
  napi_property_attributes attributes,
2641
- void* /*data*/) {
2692
+ void* data) {
2642
2693
  typedef details::CallbackData<Getter, Napi::Value> CbData;
2643
- auto callbackData = new CbData({ getter, nullptr });
2694
+ auto callbackData = new CbData({ getter, data });
2644
2695
 
2645
2696
  napi_status status = AttachData(env, object, callbackData);
2646
- NAPI_THROW_IF_FAILED(env, status, napi_property_descriptor());
2697
+ if (status != napi_ok) {
2698
+ delete callbackData;
2699
+ NAPI_THROW_IF_FAILED(env, status, napi_property_descriptor());
2700
+ }
2647
2701
 
2648
2702
  return PropertyDescriptor({
2649
2703
  nullptr,
@@ -2664,12 +2718,15 @@ inline PropertyDescriptor PropertyDescriptor::Accessor(Napi::Env env,
2664
2718
  Getter getter,
2665
2719
  Setter setter,
2666
2720
  napi_property_attributes attributes,
2667
- void* /*data*/) {
2721
+ void* data) {
2668
2722
  typedef details::AccessorCallbackData<Getter, Setter> CbData;
2669
- auto callbackData = new CbData({ getter, setter });
2723
+ auto callbackData = new CbData({ getter, setter, data });
2670
2724
 
2671
2725
  napi_status status = AttachData(env, object, callbackData);
2672
- NAPI_THROW_IF_FAILED(env, status, napi_property_descriptor());
2726
+ if (status != napi_ok) {
2727
+ delete callbackData;
2728
+ NAPI_THROW_IF_FAILED(env, status, napi_property_descriptor());
2729
+ }
2673
2730
 
2674
2731
  return PropertyDescriptor({
2675
2732
  utf8name,
@@ -2701,12 +2758,15 @@ inline PropertyDescriptor PropertyDescriptor::Accessor(Napi::Env env,
2701
2758
  Getter getter,
2702
2759
  Setter setter,
2703
2760
  napi_property_attributes attributes,
2704
- void* /*data*/) {
2761
+ void* data) {
2705
2762
  typedef details::AccessorCallbackData<Getter, Setter> CbData;
2706
- auto callbackData = new CbData({ getter, setter });
2763
+ auto callbackData = new CbData({ getter, setter, data });
2707
2764
 
2708
2765
  napi_status status = AttachData(env, object, callbackData);
2709
- NAPI_THROW_IF_FAILED(env, status, napi_property_descriptor());
2766
+ if (status != napi_ok) {
2767
+ delete callbackData;
2768
+ NAPI_THROW_IF_FAILED(env, status, napi_property_descriptor());
2769
+ }
2710
2770
 
2711
2771
  return PropertyDescriptor({
2712
2772
  nullptr,
@@ -3524,7 +3584,34 @@ inline AsyncWorker::AsyncWorker(const Object& receiver,
3524
3584
  const Object& resource)
3525
3585
  : _env(callback.Env()),
3526
3586
  _receiver(Napi::Persistent(receiver)),
3527
- _callback(Napi::Persistent(callback)) {
3587
+ _callback(Napi::Persistent(callback)),
3588
+ _suppress_destruct(false) {
3589
+ napi_value resource_id;
3590
+ napi_status status = napi_create_string_latin1(
3591
+ _env, resource_name, NAPI_AUTO_LENGTH, &resource_id);
3592
+ NAPI_THROW_IF_FAILED_VOID(_env, status);
3593
+
3594
+ status = napi_create_async_work(_env, resource, resource_id, OnExecute,
3595
+ OnWorkComplete, this, &_work);
3596
+ NAPI_THROW_IF_FAILED_VOID(_env, status);
3597
+ }
3598
+
3599
+ inline AsyncWorker::AsyncWorker(Napi::Env env)
3600
+ : AsyncWorker(env, "generic") {
3601
+ }
3602
+
3603
+ inline AsyncWorker::AsyncWorker(Napi::Env env,
3604
+ const char* resource_name)
3605
+ : AsyncWorker(env, resource_name, Object::New(env)) {
3606
+ }
3607
+
3608
+ inline AsyncWorker::AsyncWorker(Napi::Env env,
3609
+ const char* resource_name,
3610
+ const Object& resource)
3611
+ : _env(env),
3612
+ _receiver(),
3613
+ _callback(),
3614
+ _suppress_destruct(false) {
3528
3615
  napi_value resource_id;
3529
3616
  napi_status status = napi_create_string_latin1(
3530
3617
  _env, resource_name, NAPI_AUTO_LENGTH, &resource_id);
@@ -3542,6 +3629,10 @@ inline AsyncWorker::~AsyncWorker() {
3542
3629
  }
3543
3630
  }
3544
3631
 
3632
+ inline void AsyncWorker::Destroy() {
3633
+ delete this;
3634
+ }
3635
+
3545
3636
  inline AsyncWorker::AsyncWorker(AsyncWorker&& other) {
3546
3637
  _env = other._env;
3547
3638
  other._env = nullptr;
@@ -3550,6 +3641,7 @@ inline AsyncWorker::AsyncWorker(AsyncWorker&& other) {
3550
3641
  _receiver = std::move(other._receiver);
3551
3642
  _callback = std::move(other._callback);
3552
3643
  _error = std::move(other._error);
3644
+ _suppress_destruct = other._suppress_destruct;
3553
3645
  }
3554
3646
 
3555
3647
  inline AsyncWorker& AsyncWorker::operator =(AsyncWorker&& other) {
@@ -3560,6 +3652,7 @@ inline AsyncWorker& AsyncWorker::operator =(AsyncWorker&& other) {
3560
3652
  _receiver = std::move(other._receiver);
3561
3653
  _callback = std::move(other._callback);
3562
3654
  _error = std::move(other._error);
3655
+ _suppress_destruct = other._suppress_destruct;
3563
3656
  return *this;
3564
3657
  }
3565
3658
 
@@ -3589,19 +3682,34 @@ inline FunctionReference& AsyncWorker::Callback() {
3589
3682
  return _callback;
3590
3683
  }
3591
3684
 
3685
+ inline void AsyncWorker::SuppressDestruct() {
3686
+ _suppress_destruct = true;
3687
+ }
3688
+
3592
3689
  inline void AsyncWorker::OnOK() {
3593
- _callback.Call(_receiver.Value(), std::initializer_list<napi_value>{});
3690
+ if (!_callback.IsEmpty()) {
3691
+ _callback.Call(_receiver.Value(), GetResult(_callback.Env()));
3692
+ }
3594
3693
  }
3595
3694
 
3596
3695
  inline void AsyncWorker::OnError(const Error& e) {
3597
- _callback.Call(_receiver.Value(), std::initializer_list<napi_value>{ e.Value() });
3696
+ if (!_callback.IsEmpty()) {
3697
+ _callback.Call(_receiver.Value(), std::initializer_list<napi_value>{ e.Value() });
3698
+ }
3598
3699
  }
3599
3700
 
3600
3701
  inline void AsyncWorker::SetError(const std::string& error) {
3601
3702
  _error = error;
3602
3703
  }
3603
3704
 
3604
- inline void AsyncWorker::OnExecute(napi_env /*env*/, void* this_pointer) {
3705
+ inline std::vector<napi_value> AsyncWorker::GetResult(Napi::Env /*env*/) {
3706
+ return {};
3707
+ }
3708
+ // The OnExecute method receives an napi_env argument. However, do NOT
3709
+ // use it within this method, as it does not run on the main thread and must
3710
+ // not run any method that would cause JavaScript to run. In practice, this
3711
+ // means that almost any use of napi_env will be incorrect.
3712
+ inline void AsyncWorker::OnExecute(napi_env /*DO_NOT_USE*/, void* this_pointer) {
3605
3713
  AsyncWorker* self = static_cast<AsyncWorker*>(this_pointer);
3606
3714
  #ifdef NAPI_CPP_EXCEPTIONS
3607
3715
  try {
@@ -3629,9 +3737,332 @@ inline void AsyncWorker::OnWorkComplete(
3629
3737
  return nullptr;
3630
3738
  });
3631
3739
  }
3632
- delete self;
3740
+ if (!self->_suppress_destruct) {
3741
+ self->Destroy();
3742
+ }
3743
+ }
3744
+
3745
+ #if (NAPI_VERSION > 3)
3746
+ ////////////////////////////////////////////////////////////////////////////////
3747
+ // ThreadSafeFunction class
3748
+ ////////////////////////////////////////////////////////////////////////////////
3749
+
3750
+ // static
3751
+ template <typename ResourceString>
3752
+ inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env,
3753
+ const Function& callback,
3754
+ ResourceString resourceName,
3755
+ size_t maxQueueSize,
3756
+ size_t initialThreadCount) {
3757
+ return New(env, callback, Object(), resourceName, maxQueueSize,
3758
+ initialThreadCount);
3759
+ }
3760
+
3761
+ // static
3762
+ template <typename ResourceString, typename ContextType>
3763
+ inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env,
3764
+ const Function& callback,
3765
+ ResourceString resourceName,
3766
+ size_t maxQueueSize,
3767
+ size_t initialThreadCount,
3768
+ ContextType* context) {
3769
+ return New(env, callback, Object(), resourceName, maxQueueSize,
3770
+ initialThreadCount, context);
3771
+ }
3772
+
3773
+ // static
3774
+ template <typename ResourceString, typename Finalizer>
3775
+ inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env,
3776
+ const Function& callback,
3777
+ ResourceString resourceName,
3778
+ size_t maxQueueSize,
3779
+ size_t initialThreadCount,
3780
+ Finalizer finalizeCallback) {
3781
+ return New(env, callback, Object(), resourceName, maxQueueSize,
3782
+ initialThreadCount, finalizeCallback);
3783
+ }
3784
+
3785
+ // static
3786
+ template <typename ResourceString, typename Finalizer,
3787
+ typename FinalizerDataType>
3788
+ inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env,
3789
+ const Function& callback,
3790
+ ResourceString resourceName,
3791
+ size_t maxQueueSize,
3792
+ size_t initialThreadCount,
3793
+ Finalizer finalizeCallback,
3794
+ FinalizerDataType* data) {
3795
+ return New(env, callback, Object(), resourceName, maxQueueSize,
3796
+ initialThreadCount, finalizeCallback, data);
3797
+ }
3798
+
3799
+ // static
3800
+ template <typename ResourceString, typename ContextType, typename Finalizer>
3801
+ inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env,
3802
+ const Function& callback,
3803
+ ResourceString resourceName,
3804
+ size_t maxQueueSize,
3805
+ size_t initialThreadCount,
3806
+ ContextType* context,
3807
+ Finalizer finalizeCallback) {
3808
+ return New(env, callback, Object(), resourceName, maxQueueSize,
3809
+ initialThreadCount, context, finalizeCallback);
3810
+ }
3811
+
3812
+ // static
3813
+ template <typename ResourceString, typename ContextType,
3814
+ typename Finalizer, typename FinalizerDataType>
3815
+ inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env,
3816
+ const Function& callback,
3817
+ ResourceString resourceName,
3818
+ size_t maxQueueSize,
3819
+ size_t initialThreadCount,
3820
+ ContextType* context,
3821
+ Finalizer finalizeCallback,
3822
+ FinalizerDataType* data) {
3823
+ return New(env, callback, Object(), resourceName, maxQueueSize,
3824
+ initialThreadCount, context, finalizeCallback, data);
3825
+ }
3826
+
3827
+ // static
3828
+ template <typename ResourceString>
3829
+ inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env,
3830
+ const Function& callback,
3831
+ const Object& resource,
3832
+ ResourceString resourceName,
3833
+ size_t maxQueueSize,
3834
+ size_t initialThreadCount) {
3835
+ return New(env, callback, resource, resourceName, maxQueueSize,
3836
+ initialThreadCount, static_cast<void*>(nullptr) /* context */);
3837
+ }
3838
+
3839
+ // static
3840
+ template <typename ResourceString, typename ContextType>
3841
+ inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env,
3842
+ const Function& callback,
3843
+ const Object& resource,
3844
+ ResourceString resourceName,
3845
+ size_t maxQueueSize,
3846
+ size_t initialThreadCount,
3847
+ ContextType* context) {
3848
+ return New(env, callback, resource, resourceName, maxQueueSize,
3849
+ initialThreadCount, context,
3850
+ [](Env, ContextType*) {} /* empty finalizer */);
3851
+ }
3852
+
3853
+ // static
3854
+ template <typename ResourceString, typename Finalizer>
3855
+ inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env,
3856
+ const Function& callback,
3857
+ const Object& resource,
3858
+ ResourceString resourceName,
3859
+ size_t maxQueueSize,
3860
+ size_t initialThreadCount,
3861
+ Finalizer finalizeCallback) {
3862
+ return New(env, callback, resource, resourceName, maxQueueSize,
3863
+ initialThreadCount, static_cast<void*>(nullptr) /* context */,
3864
+ finalizeCallback, static_cast<void*>(nullptr) /* data */,
3865
+ details::ThreadSafeFinalize<void, Finalizer>::Wrapper);
3866
+ }
3867
+
3868
+ // static
3869
+ template <typename ResourceString, typename Finalizer,
3870
+ typename FinalizerDataType>
3871
+ inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env,
3872
+ const Function& callback,
3873
+ const Object& resource,
3874
+ ResourceString resourceName,
3875
+ size_t maxQueueSize,
3876
+ size_t initialThreadCount,
3877
+ Finalizer finalizeCallback,
3878
+ FinalizerDataType* data) {
3879
+ return New(env, callback, resource, resourceName, maxQueueSize,
3880
+ initialThreadCount, static_cast<void*>(nullptr) /* context */,
3881
+ finalizeCallback, data,
3882
+ details::ThreadSafeFinalize<
3883
+ void, Finalizer, FinalizerDataType>::FinalizeWrapperWithData);
3884
+ }
3885
+
3886
+ // static
3887
+ template <typename ResourceString, typename ContextType, typename Finalizer>
3888
+ inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env,
3889
+ const Function& callback,
3890
+ const Object& resource,
3891
+ ResourceString resourceName,
3892
+ size_t maxQueueSize,
3893
+ size_t initialThreadCount,
3894
+ ContextType* context,
3895
+ Finalizer finalizeCallback) {
3896
+ return New(env, callback, resource, resourceName, maxQueueSize,
3897
+ initialThreadCount, context, finalizeCallback,
3898
+ static_cast<void*>(nullptr) /* data */,
3899
+ details::ThreadSafeFinalize<
3900
+ ContextType, Finalizer>::FinalizeWrapperWithContext);
3901
+ }
3902
+
3903
+ // static
3904
+ template <typename ResourceString, typename ContextType,
3905
+ typename Finalizer, typename FinalizerDataType>
3906
+ inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env,
3907
+ const Function& callback,
3908
+ const Object& resource,
3909
+ ResourceString resourceName,
3910
+ size_t maxQueueSize,
3911
+ size_t initialThreadCount,
3912
+ ContextType* context,
3913
+ Finalizer finalizeCallback,
3914
+ FinalizerDataType* data) {
3915
+ return New(env, callback, resource, resourceName, maxQueueSize,
3916
+ initialThreadCount, context, finalizeCallback, data,
3917
+ details::ThreadSafeFinalize<ContextType, Finalizer,
3918
+ FinalizerDataType>::FinalizeFinalizeWrapperWithDataAndContext);
3919
+ }
3920
+
3921
+ inline ThreadSafeFunction::ThreadSafeFunction()
3922
+ : _tsfn(new napi_threadsafe_function(nullptr)) {
3923
+ }
3924
+
3925
+ inline ThreadSafeFunction::ThreadSafeFunction(
3926
+ napi_threadsafe_function tsfn)
3927
+ : _tsfn(new napi_threadsafe_function(tsfn)) {
3928
+ }
3929
+
3930
+ inline ThreadSafeFunction::ThreadSafeFunction(ThreadSafeFunction&& other)
3931
+ : _tsfn(std::move(other._tsfn)) {
3932
+ other._tsfn.reset();
3933
+ }
3934
+
3935
+ inline ThreadSafeFunction& ThreadSafeFunction::operator =(
3936
+ ThreadSafeFunction&& other) {
3937
+ if (*_tsfn != nullptr) {
3938
+ Error::Fatal("ThreadSafeFunction::operator =",
3939
+ "You cannot assign a new TSFN because existing one is still alive.");
3940
+ return *this;
3941
+ }
3942
+ _tsfn = std::move(other._tsfn);
3943
+ other._tsfn.reset();
3944
+ return *this;
3945
+ }
3946
+
3947
+ inline napi_status ThreadSafeFunction::BlockingCall() const {
3948
+ return CallInternal(nullptr, napi_tsfn_blocking);
3949
+ }
3950
+
3951
+ template <typename Callback>
3952
+ inline napi_status ThreadSafeFunction::BlockingCall(
3953
+ Callback callback) const {
3954
+ return CallInternal(new CallbackWrapper(callback), napi_tsfn_blocking);
3955
+ }
3956
+
3957
+ template <typename DataType, typename Callback>
3958
+ inline napi_status ThreadSafeFunction::BlockingCall(
3959
+ DataType* data, Callback callback) const {
3960
+ auto wrapper = [data, callback](Env env, Function jsCallback) {
3961
+ callback(env, jsCallback, data);
3962
+ };
3963
+ return CallInternal(new CallbackWrapper(wrapper), napi_tsfn_blocking);
3964
+ }
3965
+
3966
+ inline napi_status ThreadSafeFunction::NonBlockingCall() const {
3967
+ return CallInternal(nullptr, napi_tsfn_nonblocking);
3968
+ }
3969
+
3970
+ template <typename Callback>
3971
+ inline napi_status ThreadSafeFunction::NonBlockingCall(
3972
+ Callback callback) const {
3973
+ return CallInternal(new CallbackWrapper(callback), napi_tsfn_nonblocking);
3974
+ }
3975
+
3976
+ template <typename DataType, typename Callback>
3977
+ inline napi_status ThreadSafeFunction::NonBlockingCall(
3978
+ DataType* data, Callback callback) const {
3979
+ auto wrapper = [data, callback](Env env, Function jsCallback) {
3980
+ callback(env, jsCallback, data);
3981
+ };
3982
+ return CallInternal(new CallbackWrapper(wrapper), napi_tsfn_nonblocking);
3983
+ }
3984
+
3985
+ inline napi_status ThreadSafeFunction::Acquire() const {
3986
+ return napi_acquire_threadsafe_function(*_tsfn);
3987
+ }
3988
+
3989
+ inline napi_status ThreadSafeFunction::Release() {
3990
+ return napi_release_threadsafe_function(*_tsfn, napi_tsfn_release);
3991
+ }
3992
+
3993
+ inline napi_status ThreadSafeFunction::Abort() {
3994
+ return napi_release_threadsafe_function(*_tsfn, napi_tsfn_abort);
3995
+ }
3996
+
3997
+ inline ThreadSafeFunction::ConvertibleContext
3998
+ ThreadSafeFunction::GetContext() const {
3999
+ void* context;
4000
+ napi_get_threadsafe_function_context(*_tsfn, &context);
4001
+ return ConvertibleContext({ context });
4002
+ }
4003
+
4004
+ // static
4005
+ template <typename ResourceString, typename ContextType,
4006
+ typename Finalizer, typename FinalizerDataType>
4007
+ inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env,
4008
+ const Function& callback,
4009
+ const Object& resource,
4010
+ ResourceString resourceName,
4011
+ size_t maxQueueSize,
4012
+ size_t initialThreadCount,
4013
+ ContextType* context,
4014
+ Finalizer finalizeCallback,
4015
+ FinalizerDataType* data,
4016
+ napi_finalize wrapper) {
4017
+ static_assert(details::can_make_string<ResourceString>::value
4018
+ || std::is_convertible<ResourceString, napi_value>::value,
4019
+ "Resource name should be convertible to the string type");
4020
+
4021
+ ThreadSafeFunction tsfn;
4022
+ auto* finalizeData = new details::ThreadSafeFinalize<ContextType, Finalizer,
4023
+ FinalizerDataType>({ data, finalizeCallback, tsfn._tsfn.get() });
4024
+ napi_status status = napi_create_threadsafe_function(env, callback, resource,
4025
+ Value::From(env, resourceName), maxQueueSize, initialThreadCount,
4026
+ finalizeData, wrapper, context, CallJS, tsfn._tsfn.get());
4027
+ if (status != napi_ok) {
4028
+ delete finalizeData;
4029
+ NAPI_THROW_IF_FAILED(env, status, ThreadSafeFunction());
4030
+ }
4031
+
4032
+ return tsfn;
4033
+ }
4034
+
4035
+ inline napi_status ThreadSafeFunction::CallInternal(
4036
+ CallbackWrapper* callbackWrapper,
4037
+ napi_threadsafe_function_call_mode mode) const {
4038
+ napi_status status = napi_call_threadsafe_function(
4039
+ *_tsfn, callbackWrapper, mode);
4040
+ if (status != napi_ok && callbackWrapper != nullptr) {
4041
+ delete callbackWrapper;
4042
+ }
4043
+
4044
+ return status;
3633
4045
  }
3634
4046
 
4047
+ // static
4048
+ inline void ThreadSafeFunction::CallJS(napi_env env,
4049
+ napi_value jsCallback,
4050
+ void* /* context */,
4051
+ void* data) {
4052
+ if (env == nullptr && jsCallback == nullptr) {
4053
+ return;
4054
+ }
4055
+
4056
+ if (data != nullptr) {
4057
+ auto* callbackWrapper = static_cast<CallbackWrapper*>(data);
4058
+ (*callbackWrapper)(env, Function(env, jsCallback));
4059
+ delete callbackWrapper;
4060
+ } else if (jsCallback != nullptr) {
4061
+ Function(env, jsCallback).Call({});
4062
+ }
4063
+ }
4064
+ #endif
4065
+
3635
4066
  ////////////////////////////////////////////////////////////////////////////////
3636
4067
  // Memory Management class
3637
4068
  ////////////////////////////////////////////////////////////////////////////////
@@ -3661,10 +4092,6 @@ inline const napi_node_version* VersionManagement::GetNodeVersion(Env env) {
3661
4092
  return result;
3662
4093
  }
3663
4094
 
3664
- // These macros shouldn't be useful in user code.
3665
- #undef NAPI_THROW
3666
- #undef NAPI_THROW_IF_FAILED
3667
-
3668
4095
  } // namespace Napi
3669
4096
 
3670
4097
  #endif // SRC_NAPI_INL_H_