node-addon-api 1.6.3 → 2.0.0

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
@@ -9,7 +9,9 @@
9
9
 
10
10
  // Note: Do not include this file directly! Include "napi.h" instead.
11
11
 
12
+ #include <algorithm>
12
13
  #include <cstring>
14
+ #include <mutex>
13
15
  #include <type_traits>
14
16
 
15
17
  namespace Napi {
@@ -24,16 +26,23 @@ namespace details {
24
26
  template <typename FreeType>
25
27
  static inline napi_status AttachData(napi_env env,
26
28
  napi_value obj,
27
- FreeType* data) {
29
+ FreeType* data,
30
+ napi_finalize finalizer = nullptr,
31
+ void* hint = nullptr) {
32
+ napi_status status;
33
+ if (finalizer == nullptr) {
34
+ finalizer = [](napi_env /*env*/, void* data, void* /*hint*/) {
35
+ delete static_cast<FreeType*>(data);
36
+ };
37
+ }
38
+ #if (NAPI_VERSION < 5)
28
39
  napi_value symbol, external;
29
- napi_status status = napi_create_symbol(env, nullptr, &symbol);
40
+ status = napi_create_symbol(env, nullptr, &symbol);
30
41
  if (status == napi_ok) {
31
42
  status = napi_create_external(env,
32
43
  data,
33
- [](napi_env /*env*/, void* data, void* /*hint*/) {
34
- delete static_cast<FreeType*>(data);
35
- },
36
- nullptr,
44
+ finalizer,
45
+ hint,
37
46
  &external);
38
47
  if (status == napi_ok) {
39
48
  napi_property_descriptor desc = {
@@ -49,6 +58,9 @@ static inline napi_status AttachData(napi_env env,
49
58
  status = napi_define_properties(env, obj, 1, &desc);
50
59
  }
51
60
  }
61
+ #else // NAPI_VERSION >= 5
62
+ status = napi_add_finalizer(env, obj, data, finalizer, hint, nullptr);
63
+ #endif
52
64
  return status;
53
65
  }
54
66
 
@@ -125,6 +137,80 @@ struct FinalizeData {
125
137
  Hint* hint;
126
138
  };
127
139
 
140
+ #if (NAPI_VERSION > 3)
141
+ template <typename ContextType=void,
142
+ typename Finalizer=std::function<void(Env, void*, ContextType*)>,
143
+ typename FinalizerDataType=void>
144
+ struct ThreadSafeFinalize {
145
+ static inline
146
+ void Wrapper(napi_env env, void* rawFinalizeData, void* /* rawContext */) {
147
+ if (rawFinalizeData == nullptr)
148
+ return;
149
+
150
+ ThreadSafeFinalize* finalizeData =
151
+ static_cast<ThreadSafeFinalize*>(rawFinalizeData);
152
+ finalizeData->callback(Env(env));
153
+ if (finalizeData->tsfn) {
154
+ *finalizeData->tsfn = nullptr;
155
+ }
156
+ delete finalizeData;
157
+ }
158
+
159
+ static inline
160
+ void FinalizeWrapperWithData(napi_env env,
161
+ void* rawFinalizeData,
162
+ void* /* rawContext */) {
163
+ if (rawFinalizeData == nullptr)
164
+ return;
165
+
166
+ ThreadSafeFinalize* finalizeData =
167
+ static_cast<ThreadSafeFinalize*>(rawFinalizeData);
168
+ finalizeData->callback(Env(env), finalizeData->data);
169
+ if (finalizeData->tsfn) {
170
+ *finalizeData->tsfn = nullptr;
171
+ }
172
+ delete finalizeData;
173
+ }
174
+
175
+ static inline
176
+ void FinalizeWrapperWithContext(napi_env env,
177
+ void* rawFinalizeData,
178
+ void* rawContext) {
179
+ if (rawFinalizeData == nullptr)
180
+ return;
181
+
182
+ ThreadSafeFinalize* finalizeData =
183
+ static_cast<ThreadSafeFinalize*>(rawFinalizeData);
184
+ finalizeData->callback(Env(env), static_cast<ContextType*>(rawContext));
185
+ if (finalizeData->tsfn) {
186
+ *finalizeData->tsfn = nullptr;
187
+ }
188
+ delete finalizeData;
189
+ }
190
+
191
+ static inline
192
+ void FinalizeFinalizeWrapperWithDataAndContext(napi_env env,
193
+ void* rawFinalizeData,
194
+ void* rawContext) {
195
+ if (rawFinalizeData == nullptr)
196
+ return;
197
+
198
+ ThreadSafeFinalize* finalizeData =
199
+ static_cast<ThreadSafeFinalize*>(rawFinalizeData);
200
+ finalizeData->callback(Env(env), finalizeData->data,
201
+ static_cast<ContextType*>(rawContext));
202
+ if (finalizeData->tsfn) {
203
+ *finalizeData->tsfn = nullptr;
204
+ }
205
+ delete finalizeData;
206
+ }
207
+
208
+ FinalizerDataType* data;
209
+ Finalizer callback;
210
+ napi_threadsafe_function* tsfn;
211
+ };
212
+ #endif
213
+
128
214
  template <typename Getter, typename Setter>
129
215
  struct AccessorCallbackData {
130
216
  static inline
@@ -271,7 +357,7 @@ inline bool Value::IsEmpty() const {
271
357
  }
272
358
 
273
359
  inline napi_valuetype Value::Type() const {
274
- if (_value == nullptr) {
360
+ if (IsEmpty()) {
275
361
  return napi_undefined;
276
362
  }
277
363
 
@@ -297,14 +383,28 @@ inline bool Value::IsNumber() const {
297
383
  return Type() == napi_number;
298
384
  }
299
385
 
300
- // currently experimental guard with version of NAPI_VERSION that it is
301
- // released in once it is no longer experimental
302
- #if (NAPI_VERSION > 2147483646)
386
+ // Currently experimental guard with the definition of NAPI_EXPERIMENTAL.
387
+ // Once it is no longer experimental guard with the NAPI_VERSION in which it is
388
+ // released instead.
389
+ #ifdef NAPI_EXPERIMENTAL
303
390
  inline bool Value::IsBigInt() const {
304
391
  return Type() == napi_bigint;
305
392
  }
306
393
  #endif // NAPI_EXPERIMENTAL
307
394
 
395
+ #if (NAPI_VERSION > 4)
396
+ inline bool Value::IsDate() const {
397
+ if (IsEmpty()) {
398
+ return false;
399
+ }
400
+
401
+ bool result;
402
+ napi_status status = napi_is_date(_env, _value, &result);
403
+ NAPI_THROW_IF_FAILED(_env, status, false);
404
+ return result;
405
+ }
406
+ #endif
407
+
308
408
  inline bool Value::IsString() const {
309
409
  return Type() == napi_string;
310
410
  }
@@ -314,7 +414,7 @@ inline bool Value::IsSymbol() const {
314
414
  }
315
415
 
316
416
  inline bool Value::IsArray() const {
317
- if (_value == nullptr) {
417
+ if (IsEmpty()) {
318
418
  return false;
319
419
  }
320
420
 
@@ -325,7 +425,7 @@ inline bool Value::IsArray() const {
325
425
  }
326
426
 
327
427
  inline bool Value::IsArrayBuffer() const {
328
- if (_value == nullptr) {
428
+ if (IsEmpty()) {
329
429
  return false;
330
430
  }
331
431
 
@@ -336,7 +436,7 @@ inline bool Value::IsArrayBuffer() const {
336
436
  }
337
437
 
338
438
  inline bool Value::IsTypedArray() const {
339
- if (_value == nullptr) {
439
+ if (IsEmpty()) {
340
440
  return false;
341
441
  }
342
442
 
@@ -355,7 +455,7 @@ inline bool Value::IsFunction() const {
355
455
  }
356
456
 
357
457
  inline bool Value::IsPromise() const {
358
- if (_value == nullptr) {
458
+ if (IsEmpty()) {
359
459
  return false;
360
460
  }
361
461
 
@@ -366,7 +466,7 @@ inline bool Value::IsPromise() const {
366
466
  }
367
467
 
368
468
  inline bool Value::IsDataView() const {
369
- if (_value == nullptr) {
469
+ if (IsEmpty()) {
370
470
  return false;
371
471
  }
372
472
 
@@ -377,7 +477,7 @@ inline bool Value::IsDataView() const {
377
477
  }
378
478
 
379
479
  inline bool Value::IsBuffer() const {
380
- if (_value == nullptr) {
480
+ if (IsEmpty()) {
381
481
  return false;
382
482
  }
383
483
 
@@ -521,9 +621,10 @@ inline double Number::DoubleValue() const {
521
621
  return result;
522
622
  }
523
623
 
524
- // currently experimental guard with version of NAPI_VERSION that it is
525
- // released in once it is no longer experimental
526
- #if (NAPI_VERSION > 2147483646)
624
+ // Currently experimental guard with the definition of NAPI_EXPERIMENTAL.
625
+ // Once it is no longer experimental guard with the NAPI_VERSION in which it is
626
+ // released instead.
627
+ #ifdef NAPI_EXPERIMENTAL
527
628
  ////////////////////////////////////////////////////////////////////////////////
528
629
  // BigInt Class
529
630
  ////////////////////////////////////////////////////////////////////////////////
@@ -586,6 +687,37 @@ inline void BigInt::ToWords(int* sign_bit, size_t* word_count, uint64_t* words)
586
687
  }
587
688
  #endif // NAPI_EXPERIMENTAL
588
689
 
690
+ #if (NAPI_VERSION > 4)
691
+ ////////////////////////////////////////////////////////////////////////////////
692
+ // Date Class
693
+ ////////////////////////////////////////////////////////////////////////////////
694
+
695
+ inline Date Date::New(napi_env env, double val) {
696
+ napi_value value;
697
+ napi_status status = napi_create_date(env, val, &value);
698
+ NAPI_THROW_IF_FAILED(env, status, Date());
699
+ return Date(env, value);
700
+ }
701
+
702
+ inline Date::Date() : Value() {
703
+ }
704
+
705
+ inline Date::Date(napi_env env, napi_value value) : Value(env, value) {
706
+ }
707
+
708
+ inline Date::operator double() const {
709
+ return ValueOf();
710
+ }
711
+
712
+ inline double Date::ValueOf() const {
713
+ double result;
714
+ napi_status status = napi_get_date_value(
715
+ _env, _value, &result);
716
+ NAPI_THROW_IF_FAILED(_env, status, 0);
717
+ return result;
718
+ }
719
+ #endif
720
+
589
721
  ////////////////////////////////////////////////////////////////////////////////
590
722
  // Name class
591
723
  ////////////////////////////////////////////////////////////////////////////////
@@ -1052,6 +1184,40 @@ inline bool Object::InstanceOf(const Function& constructor) const {
1052
1184
  return result;
1053
1185
  }
1054
1186
 
1187
+ template <typename Finalizer, typename T>
1188
+ inline void Object::AddFinalizer(Finalizer finalizeCallback, T* data) {
1189
+ details::FinalizeData<T, Finalizer>* finalizeData =
1190
+ new details::FinalizeData<T, Finalizer>({ finalizeCallback, nullptr });
1191
+ napi_status status =
1192
+ details::AttachData(_env,
1193
+ *this,
1194
+ data,
1195
+ details::FinalizeData<T, Finalizer>::Wrapper,
1196
+ finalizeData);
1197
+ if (status != napi_ok) {
1198
+ delete finalizeData;
1199
+ NAPI_THROW_IF_FAILED_VOID(_env, status);
1200
+ }
1201
+ }
1202
+
1203
+ template <typename Finalizer, typename T, typename Hint>
1204
+ inline void Object::AddFinalizer(Finalizer finalizeCallback,
1205
+ T* data,
1206
+ Hint* finalizeHint) {
1207
+ details::FinalizeData<T, Finalizer, Hint>* finalizeData =
1208
+ new details::FinalizeData<T, Finalizer, Hint>({ finalizeCallback, finalizeHint });
1209
+ napi_status status =
1210
+ details::AttachData(_env,
1211
+ *this,
1212
+ data,
1213
+ details::FinalizeData<T, Finalizer, Hint>::WrapperWithHint,
1214
+ finalizeData);
1215
+ if (status != napi_ok) {
1216
+ delete finalizeData;
1217
+ NAPI_THROW_IF_FAILED_VOID(_env, status);
1218
+ }
1219
+ }
1220
+
1055
1221
  ////////////////////////////////////////////////////////////////////////////////
1056
1222
  // External class
1057
1223
  ////////////////////////////////////////////////////////////////////////////////
@@ -1876,47 +2042,43 @@ inline Error Error::New(napi_env env) {
1876
2042
  status = napi_get_last_error_info(env, &info);
1877
2043
  NAPI_FATAL_IF_FAILED(status, "Error::New", "napi_get_last_error_info");
1878
2044
 
1879
- if (status == napi_ok) {
1880
- if (info->error_code == napi_pending_exception) {
2045
+ if (info->error_code == napi_pending_exception) {
2046
+ status = napi_get_and_clear_last_exception(env, &error);
2047
+ NAPI_FATAL_IF_FAILED(status, "Error::New", "napi_get_and_clear_last_exception");
2048
+ }
2049
+ else {
2050
+ const char* error_message = info->error_message != nullptr ?
2051
+ info->error_message : "Error in native callback";
2052
+
2053
+ bool isExceptionPending;
2054
+ status = napi_is_exception_pending(env, &isExceptionPending);
2055
+ NAPI_FATAL_IF_FAILED(status, "Error::New", "napi_is_exception_pending");
2056
+
2057
+ if (isExceptionPending) {
1881
2058
  status = napi_get_and_clear_last_exception(env, &error);
1882
2059
  NAPI_FATAL_IF_FAILED(status, "Error::New", "napi_get_and_clear_last_exception");
1883
2060
  }
1884
- else {
1885
- const char* error_message = info->error_message != nullptr ?
1886
- info->error_message : "Error in native callback";
1887
-
1888
- bool isExceptionPending;
1889
- status = napi_is_exception_pending(env, &isExceptionPending);
1890
- NAPI_FATAL_IF_FAILED(status, "Error::New", "napi_is_exception_pending");
1891
-
1892
- if (isExceptionPending) {
1893
- status = napi_get_and_clear_last_exception(env, &error);
1894
- NAPI_FATAL_IF_FAILED(status, "Error::New", "napi_get_and_clear_last_exception");
1895
- }
1896
2061
 
1897
- napi_value message;
1898
- status = napi_create_string_utf8(
1899
- env,
1900
- error_message,
1901
- std::strlen(error_message),
1902
- &message);
1903
- NAPI_FATAL_IF_FAILED(status, "Error::New", "napi_create_string_utf8");
1904
-
1905
- if (status == napi_ok) {
1906
- switch (info->error_code) {
1907
- case napi_object_expected:
1908
- case napi_string_expected:
1909
- case napi_boolean_expected:
1910
- case napi_number_expected:
1911
- status = napi_create_type_error(env, nullptr, message, &error);
1912
- break;
1913
- default:
1914
- status = napi_create_error(env, nullptr, message, &error);
1915
- break;
1916
- }
1917
- NAPI_FATAL_IF_FAILED(status, "Error::New", "napi_create_error");
1918
- }
2062
+ napi_value message;
2063
+ status = napi_create_string_utf8(
2064
+ env,
2065
+ error_message,
2066
+ std::strlen(error_message),
2067
+ &message);
2068
+ NAPI_FATAL_IF_FAILED(status, "Error::New", "napi_create_string_utf8");
2069
+
2070
+ switch (info->error_code) {
2071
+ case napi_object_expected:
2072
+ case napi_string_expected:
2073
+ case napi_boolean_expected:
2074
+ case napi_number_expected:
2075
+ status = napi_create_type_error(env, nullptr, message, &error);
2076
+ break;
2077
+ default:
2078
+ status = napi_create_error(env, nullptr, message, &error);
2079
+ break;
1919
2080
  }
2081
+ NAPI_FATAL_IF_FAILED(status, "Error::New", "napi_create_error");
1920
2082
  }
1921
2083
 
1922
2084
  return Error(env, error);
@@ -2814,6 +2976,9 @@ inline ObjectWrap<T>::ObjectWrap(const Napi::CallbackInfo& callbackInfo) {
2814
2976
  *instanceRef = Reference<Object>(env, ref);
2815
2977
  }
2816
2978
 
2979
+ template<typename T>
2980
+ inline ObjectWrap<T>::~ObjectWrap() {}
2981
+
2817
2982
  template<typename T>
2818
2983
  inline T* ObjectWrap<T>::Unwrap(Object wrapper) {
2819
2984
  T* unwrapped;
@@ -3187,6 +3352,9 @@ inline ClassPropertyDescriptor<T> ObjectWrap<T>::InstanceValue(
3187
3352
  return desc;
3188
3353
  }
3189
3354
 
3355
+ template <typename T>
3356
+ inline void ObjectWrap<T>::Finalize(Napi::Env /*env*/) {}
3357
+
3190
3358
  template <typename T>
3191
3359
  inline napi_value ObjectWrap<T>::ConstructorCallbackWrapper(
3192
3360
  napi_env env,
@@ -3328,8 +3496,9 @@ inline napi_value ObjectWrap<T>::InstanceSetterCallbackWrapper(
3328
3496
  }
3329
3497
 
3330
3498
  template <typename T>
3331
- inline void ObjectWrap<T>::FinalizeCallback(napi_env /*env*/, void* data, void* /*hint*/) {
3499
+ inline void ObjectWrap<T>::FinalizeCallback(napi_env env, void* data, void* /*hint*/) {
3332
3500
  T* instance = reinterpret_cast<T*>(data);
3501
+ instance->Finalize(Napi::Env(env));
3333
3502
  delete instance;
3334
3503
  }
3335
3504
 
@@ -3347,7 +3516,10 @@ inline HandleScope::HandleScope(Napi::Env env) : _env(env) {
3347
3516
  }
3348
3517
 
3349
3518
  inline HandleScope::~HandleScope() {
3350
- napi_close_handle_scope(_env, _scope);
3519
+ napi_status status = napi_close_handle_scope(_env, _scope);
3520
+ NAPI_FATAL_IF_FAILED(status,
3521
+ "HandleScope::~HandleScope",
3522
+ "napi_close_handle_scope");
3351
3523
  }
3352
3524
 
3353
3525
  inline HandleScope::operator napi_handle_scope() const {
@@ -3372,7 +3544,10 @@ inline EscapableHandleScope::EscapableHandleScope(Napi::Env env) : _env(env) {
3372
3544
  }
3373
3545
 
3374
3546
  inline EscapableHandleScope::~EscapableHandleScope() {
3375
- napi_close_escapable_handle_scope(_env, _scope);
3547
+ napi_status status = napi_close_escapable_handle_scope(_env, _scope);
3548
+ NAPI_FATAL_IF_FAILED(status,
3549
+ "EscapableHandleScope::~EscapableHandleScope",
3550
+ "napi_close_escapable_handle_scope");
3376
3551
  }
3377
3552
 
3378
3553
  inline EscapableHandleScope::operator napi_escapable_handle_scope() const {
@@ -3408,7 +3583,10 @@ inline CallbackScope::CallbackScope(napi_env env, napi_async_context context)
3408
3583
  }
3409
3584
 
3410
3585
  inline CallbackScope::~CallbackScope() {
3411
- napi_close_callback_scope(_env, _scope);
3586
+ napi_status status = napi_close_callback_scope(_env, _scope);
3587
+ NAPI_FATAL_IF_FAILED(status,
3588
+ "CallbackScope::~CallbackScope",
3589
+ "napi_close_callback_scope");
3412
3590
  }
3413
3591
 
3414
3592
  inline CallbackScope::operator napi_callback_scope() const {
@@ -3468,6 +3646,10 @@ inline AsyncContext::operator napi_async_context() const {
3468
3646
  return _context;
3469
3647
  }
3470
3648
 
3649
+ inline Napi::Env AsyncContext::Env() const {
3650
+ return Napi::Env(_env);
3651
+ }
3652
+
3471
3653
  ////////////////////////////////////////////////////////////////////////////////
3472
3654
  // AsyncWorker class
3473
3655
  ////////////////////////////////////////////////////////////////////////////////
@@ -3522,6 +3704,32 @@ inline AsyncWorker::AsyncWorker(const Object& receiver,
3522
3704
  NAPI_THROW_IF_FAILED_VOID(_env, status);
3523
3705
  }
3524
3706
 
3707
+ inline AsyncWorker::AsyncWorker(Napi::Env env)
3708
+ : AsyncWorker(env, "generic") {
3709
+ }
3710
+
3711
+ inline AsyncWorker::AsyncWorker(Napi::Env env,
3712
+ const char* resource_name)
3713
+ : AsyncWorker(env, resource_name, Object::New(env)) {
3714
+ }
3715
+
3716
+ inline AsyncWorker::AsyncWorker(Napi::Env env,
3717
+ const char* resource_name,
3718
+ const Object& resource)
3719
+ : _env(env),
3720
+ _receiver(),
3721
+ _callback(),
3722
+ _suppress_destruct(false) {
3723
+ napi_value resource_id;
3724
+ napi_status status = napi_create_string_latin1(
3725
+ _env, resource_name, NAPI_AUTO_LENGTH, &resource_id);
3726
+ NAPI_THROW_IF_FAILED_VOID(_env, status);
3727
+
3728
+ status = napi_create_async_work(_env, resource, resource_id, OnExecute,
3729
+ OnWorkComplete, this, &_work);
3730
+ NAPI_THROW_IF_FAILED_VOID(_env, status);
3731
+ }
3732
+
3525
3733
  inline AsyncWorker::~AsyncWorker() {
3526
3734
  if (_work != nullptr) {
3527
3735
  napi_delete_async_work(_env, _work);
@@ -3529,6 +3737,10 @@ inline AsyncWorker::~AsyncWorker() {
3529
3737
  }
3530
3738
  }
3531
3739
 
3740
+ inline void AsyncWorker::Destroy() {
3741
+ delete this;
3742
+ }
3743
+
3532
3744
  inline AsyncWorker::AsyncWorker(AsyncWorker&& other) {
3533
3745
  _env = other._env;
3534
3746
  other._env = nullptr;
@@ -3583,18 +3795,29 @@ inline void AsyncWorker::SuppressDestruct() {
3583
3795
  }
3584
3796
 
3585
3797
  inline void AsyncWorker::OnOK() {
3586
- _callback.Call(_receiver.Value(), std::initializer_list<napi_value>{});
3798
+ if (!_callback.IsEmpty()) {
3799
+ _callback.Call(_receiver.Value(), GetResult(_callback.Env()));
3800
+ }
3587
3801
  }
3588
3802
 
3589
3803
  inline void AsyncWorker::OnError(const Error& e) {
3590
- _callback.Call(_receiver.Value(), std::initializer_list<napi_value>{ e.Value() });
3804
+ if (!_callback.IsEmpty()) {
3805
+ _callback.Call(_receiver.Value(), std::initializer_list<napi_value>{ e.Value() });
3806
+ }
3591
3807
  }
3592
3808
 
3593
3809
  inline void AsyncWorker::SetError(const std::string& error) {
3594
3810
  _error = error;
3595
3811
  }
3596
3812
 
3597
- inline void AsyncWorker::OnExecute(napi_env /*env*/, void* this_pointer) {
3813
+ inline std::vector<napi_value> AsyncWorker::GetResult(Napi::Env /*env*/) {
3814
+ return {};
3815
+ }
3816
+ // The OnExecute method receives an napi_env argument. However, do NOT
3817
+ // use it within this method, as it does not run on the main thread and must
3818
+ // not run any method that would cause JavaScript to run. In practice, this
3819
+ // means that almost any use of napi_env will be incorrect.
3820
+ inline void AsyncWorker::OnExecute(napi_env /*DO_NOT_USE*/, void* this_pointer) {
3598
3821
  AsyncWorker* self = static_cast<AsyncWorker*>(this_pointer);
3599
3822
  #ifdef NAPI_CPP_EXCEPTIONS
3600
3823
  try {
@@ -3623,10 +3846,493 @@ inline void AsyncWorker::OnWorkComplete(
3623
3846
  });
3624
3847
  }
3625
3848
  if (!self->_suppress_destruct) {
3626
- delete self;
3849
+ self->Destroy();
3627
3850
  }
3628
3851
  }
3629
3852
 
3853
+ #if (NAPI_VERSION > 3)
3854
+ ////////////////////////////////////////////////////////////////////////////////
3855
+ // ThreadSafeFunction class
3856
+ ////////////////////////////////////////////////////////////////////////////////
3857
+
3858
+ // static
3859
+ template <typename ResourceString>
3860
+ inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env,
3861
+ const Function& callback,
3862
+ ResourceString resourceName,
3863
+ size_t maxQueueSize,
3864
+ size_t initialThreadCount) {
3865
+ return New(env, callback, Object(), resourceName, maxQueueSize,
3866
+ initialThreadCount);
3867
+ }
3868
+
3869
+ // static
3870
+ template <typename ResourceString, typename ContextType>
3871
+ inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env,
3872
+ const Function& callback,
3873
+ ResourceString resourceName,
3874
+ size_t maxQueueSize,
3875
+ size_t initialThreadCount,
3876
+ ContextType* context) {
3877
+ return New(env, callback, Object(), resourceName, maxQueueSize,
3878
+ initialThreadCount, context);
3879
+ }
3880
+
3881
+ // static
3882
+ template <typename ResourceString, typename Finalizer>
3883
+ inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env,
3884
+ const Function& callback,
3885
+ ResourceString resourceName,
3886
+ size_t maxQueueSize,
3887
+ size_t initialThreadCount,
3888
+ Finalizer finalizeCallback) {
3889
+ return New(env, callback, Object(), resourceName, maxQueueSize,
3890
+ initialThreadCount, finalizeCallback);
3891
+ }
3892
+
3893
+ // static
3894
+ template <typename ResourceString, typename Finalizer,
3895
+ typename FinalizerDataType>
3896
+ inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env,
3897
+ const Function& callback,
3898
+ ResourceString resourceName,
3899
+ size_t maxQueueSize,
3900
+ size_t initialThreadCount,
3901
+ Finalizer finalizeCallback,
3902
+ FinalizerDataType* data) {
3903
+ return New(env, callback, Object(), resourceName, maxQueueSize,
3904
+ initialThreadCount, finalizeCallback, data);
3905
+ }
3906
+
3907
+ // static
3908
+ template <typename ResourceString, typename ContextType, typename Finalizer>
3909
+ inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env,
3910
+ const Function& callback,
3911
+ ResourceString resourceName,
3912
+ size_t maxQueueSize,
3913
+ size_t initialThreadCount,
3914
+ ContextType* context,
3915
+ Finalizer finalizeCallback) {
3916
+ return New(env, callback, Object(), resourceName, maxQueueSize,
3917
+ initialThreadCount, context, finalizeCallback);
3918
+ }
3919
+
3920
+ // static
3921
+ template <typename ResourceString, typename ContextType,
3922
+ typename Finalizer, typename FinalizerDataType>
3923
+ inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env,
3924
+ const Function& callback,
3925
+ ResourceString resourceName,
3926
+ size_t maxQueueSize,
3927
+ size_t initialThreadCount,
3928
+ ContextType* context,
3929
+ Finalizer finalizeCallback,
3930
+ FinalizerDataType* data) {
3931
+ return New(env, callback, Object(), resourceName, maxQueueSize,
3932
+ initialThreadCount, context, finalizeCallback, data);
3933
+ }
3934
+
3935
+ // static
3936
+ template <typename ResourceString>
3937
+ inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env,
3938
+ const Function& callback,
3939
+ const Object& resource,
3940
+ ResourceString resourceName,
3941
+ size_t maxQueueSize,
3942
+ size_t initialThreadCount) {
3943
+ return New(env, callback, resource, resourceName, maxQueueSize,
3944
+ initialThreadCount, static_cast<void*>(nullptr) /* context */);
3945
+ }
3946
+
3947
+ // static
3948
+ template <typename ResourceString, typename ContextType>
3949
+ inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env,
3950
+ const Function& callback,
3951
+ const Object& resource,
3952
+ ResourceString resourceName,
3953
+ size_t maxQueueSize,
3954
+ size_t initialThreadCount,
3955
+ ContextType* context) {
3956
+ return New(env, callback, resource, resourceName, maxQueueSize,
3957
+ initialThreadCount, context,
3958
+ [](Env, ContextType*) {} /* empty finalizer */);
3959
+ }
3960
+
3961
+ // static
3962
+ template <typename ResourceString, typename Finalizer>
3963
+ inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env,
3964
+ const Function& callback,
3965
+ const Object& resource,
3966
+ ResourceString resourceName,
3967
+ size_t maxQueueSize,
3968
+ size_t initialThreadCount,
3969
+ Finalizer finalizeCallback) {
3970
+ return New(env, callback, resource, resourceName, maxQueueSize,
3971
+ initialThreadCount, static_cast<void*>(nullptr) /* context */,
3972
+ finalizeCallback, static_cast<void*>(nullptr) /* data */,
3973
+ details::ThreadSafeFinalize<void, Finalizer>::Wrapper);
3974
+ }
3975
+
3976
+ // static
3977
+ template <typename ResourceString, typename Finalizer,
3978
+ typename FinalizerDataType>
3979
+ inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env,
3980
+ const Function& callback,
3981
+ const Object& resource,
3982
+ ResourceString resourceName,
3983
+ size_t maxQueueSize,
3984
+ size_t initialThreadCount,
3985
+ Finalizer finalizeCallback,
3986
+ FinalizerDataType* data) {
3987
+ return New(env, callback, resource, resourceName, maxQueueSize,
3988
+ initialThreadCount, static_cast<void*>(nullptr) /* context */,
3989
+ finalizeCallback, data,
3990
+ details::ThreadSafeFinalize<
3991
+ void, Finalizer, FinalizerDataType>::FinalizeWrapperWithData);
3992
+ }
3993
+
3994
+ // static
3995
+ template <typename ResourceString, typename ContextType, typename Finalizer>
3996
+ inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env,
3997
+ const Function& callback,
3998
+ const Object& resource,
3999
+ ResourceString resourceName,
4000
+ size_t maxQueueSize,
4001
+ size_t initialThreadCount,
4002
+ ContextType* context,
4003
+ Finalizer finalizeCallback) {
4004
+ return New(env, callback, resource, resourceName, maxQueueSize,
4005
+ initialThreadCount, context, finalizeCallback,
4006
+ static_cast<void*>(nullptr) /* data */,
4007
+ details::ThreadSafeFinalize<
4008
+ ContextType, Finalizer>::FinalizeWrapperWithContext);
4009
+ }
4010
+
4011
+ // static
4012
+ template <typename ResourceString, typename ContextType,
4013
+ typename Finalizer, typename FinalizerDataType>
4014
+ inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env,
4015
+ const Function& callback,
4016
+ const Object& resource,
4017
+ ResourceString resourceName,
4018
+ size_t maxQueueSize,
4019
+ size_t initialThreadCount,
4020
+ ContextType* context,
4021
+ Finalizer finalizeCallback,
4022
+ FinalizerDataType* data) {
4023
+ return New(env, callback, resource, resourceName, maxQueueSize,
4024
+ initialThreadCount, context, finalizeCallback, data,
4025
+ details::ThreadSafeFinalize<ContextType, Finalizer,
4026
+ FinalizerDataType>::FinalizeFinalizeWrapperWithDataAndContext);
4027
+ }
4028
+
4029
+ inline ThreadSafeFunction::ThreadSafeFunction()
4030
+ : _tsfn() {
4031
+ }
4032
+
4033
+ inline ThreadSafeFunction::ThreadSafeFunction(
4034
+ napi_threadsafe_function tsfn)
4035
+ : _tsfn(tsfn) {
4036
+ }
4037
+
4038
+ inline ThreadSafeFunction::operator napi_threadsafe_function() const {
4039
+ return _tsfn;
4040
+ }
4041
+
4042
+ inline napi_status ThreadSafeFunction::BlockingCall() const {
4043
+ return CallInternal(nullptr, napi_tsfn_blocking);
4044
+ }
4045
+
4046
+ template <>
4047
+ inline napi_status ThreadSafeFunction::BlockingCall(
4048
+ void* data) const {
4049
+ return napi_call_threadsafe_function(_tsfn, data, napi_tsfn_blocking);
4050
+ }
4051
+
4052
+ template <typename Callback>
4053
+ inline napi_status ThreadSafeFunction::BlockingCall(
4054
+ Callback callback) const {
4055
+ return CallInternal(new CallbackWrapper(callback), napi_tsfn_blocking);
4056
+ }
4057
+
4058
+ template <typename DataType, typename Callback>
4059
+ inline napi_status ThreadSafeFunction::BlockingCall(
4060
+ DataType* data, Callback callback) const {
4061
+ auto wrapper = [data, callback](Env env, Function jsCallback) {
4062
+ callback(env, jsCallback, data);
4063
+ };
4064
+ return CallInternal(new CallbackWrapper(wrapper), napi_tsfn_blocking);
4065
+ }
4066
+
4067
+ inline napi_status ThreadSafeFunction::NonBlockingCall() const {
4068
+ return CallInternal(nullptr, napi_tsfn_nonblocking);
4069
+ }
4070
+
4071
+ template <>
4072
+ inline napi_status ThreadSafeFunction::NonBlockingCall(
4073
+ void* data) const {
4074
+ return napi_call_threadsafe_function(_tsfn, data, napi_tsfn_nonblocking);
4075
+ }
4076
+
4077
+ template <typename Callback>
4078
+ inline napi_status ThreadSafeFunction::NonBlockingCall(
4079
+ Callback callback) const {
4080
+ return CallInternal(new CallbackWrapper(callback), napi_tsfn_nonblocking);
4081
+ }
4082
+
4083
+ template <typename DataType, typename Callback>
4084
+ inline napi_status ThreadSafeFunction::NonBlockingCall(
4085
+ DataType* data, Callback callback) const {
4086
+ auto wrapper = [data, callback](Env env, Function jsCallback) {
4087
+ callback(env, jsCallback, data);
4088
+ };
4089
+ return CallInternal(new CallbackWrapper(wrapper), napi_tsfn_nonblocking);
4090
+ }
4091
+
4092
+ inline void ThreadSafeFunction::Ref(napi_env env) const {
4093
+ if (_tsfn != nullptr) {
4094
+ napi_status status = napi_ref_threadsafe_function(env, _tsfn);
4095
+ NAPI_THROW_IF_FAILED_VOID(env, status);
4096
+ }
4097
+ }
4098
+
4099
+ inline void ThreadSafeFunction::Unref(napi_env env) const {
4100
+ if (_tsfn != nullptr) {
4101
+ napi_status status = napi_unref_threadsafe_function(env, _tsfn);
4102
+ NAPI_THROW_IF_FAILED_VOID(env, status);
4103
+ }
4104
+ }
4105
+
4106
+ inline napi_status ThreadSafeFunction::Acquire() const {
4107
+ return napi_acquire_threadsafe_function(_tsfn);
4108
+ }
4109
+
4110
+ inline napi_status ThreadSafeFunction::Release() {
4111
+ return napi_release_threadsafe_function(_tsfn, napi_tsfn_release);
4112
+ }
4113
+
4114
+ inline napi_status ThreadSafeFunction::Abort() {
4115
+ return napi_release_threadsafe_function(_tsfn, napi_tsfn_abort);
4116
+ }
4117
+
4118
+ inline ThreadSafeFunction::ConvertibleContext
4119
+ ThreadSafeFunction::GetContext() const {
4120
+ void* context;
4121
+ napi_status status = napi_get_threadsafe_function_context(_tsfn, &context);
4122
+ NAPI_FATAL_IF_FAILED(status, "ThreadSafeFunction::GetContext", "napi_get_threadsafe_function_context");
4123
+ return ConvertibleContext({ context });
4124
+ }
4125
+
4126
+ // static
4127
+ template <typename ResourceString, typename ContextType,
4128
+ typename Finalizer, typename FinalizerDataType>
4129
+ inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env,
4130
+ const Function& callback,
4131
+ const Object& resource,
4132
+ ResourceString resourceName,
4133
+ size_t maxQueueSize,
4134
+ size_t initialThreadCount,
4135
+ ContextType* context,
4136
+ Finalizer finalizeCallback,
4137
+ FinalizerDataType* data,
4138
+ napi_finalize wrapper) {
4139
+ static_assert(details::can_make_string<ResourceString>::value
4140
+ || std::is_convertible<ResourceString, napi_value>::value,
4141
+ "Resource name should be convertible to the string type");
4142
+
4143
+ ThreadSafeFunction tsfn;
4144
+ auto* finalizeData = new details::ThreadSafeFinalize<ContextType, Finalizer,
4145
+ FinalizerDataType>({ data, finalizeCallback, &tsfn._tsfn });
4146
+ napi_status status = napi_create_threadsafe_function(env, callback, resource,
4147
+ Value::From(env, resourceName), maxQueueSize, initialThreadCount,
4148
+ finalizeData, wrapper, context, CallJS, &tsfn._tsfn);
4149
+ if (status != napi_ok) {
4150
+ delete finalizeData;
4151
+ NAPI_THROW_IF_FAILED(env, status, ThreadSafeFunction());
4152
+ }
4153
+
4154
+ return tsfn;
4155
+ }
4156
+
4157
+ inline napi_status ThreadSafeFunction::CallInternal(
4158
+ CallbackWrapper* callbackWrapper,
4159
+ napi_threadsafe_function_call_mode mode) const {
4160
+ napi_status status = napi_call_threadsafe_function(
4161
+ _tsfn, callbackWrapper, mode);
4162
+ if (status != napi_ok && callbackWrapper != nullptr) {
4163
+ delete callbackWrapper;
4164
+ }
4165
+
4166
+ return status;
4167
+ }
4168
+
4169
+ // static
4170
+ inline void ThreadSafeFunction::CallJS(napi_env env,
4171
+ napi_value jsCallback,
4172
+ void* /* context */,
4173
+ void* data) {
4174
+ if (env == nullptr && jsCallback == nullptr) {
4175
+ return;
4176
+ }
4177
+
4178
+ if (data != nullptr) {
4179
+ auto* callbackWrapper = static_cast<CallbackWrapper*>(data);
4180
+ (*callbackWrapper)(env, Function(env, jsCallback));
4181
+ delete callbackWrapper;
4182
+ } else if (jsCallback != nullptr) {
4183
+ Function(env, jsCallback).Call({});
4184
+ }
4185
+ }
4186
+
4187
+ ////////////////////////////////////////////////////////////////////////////////
4188
+ // Async Progress Worker class
4189
+ ////////////////////////////////////////////////////////////////////////////////
4190
+
4191
+ template<class T>
4192
+ inline AsyncProgressWorker<T>::AsyncProgressWorker(const Function& callback)
4193
+ : AsyncProgressWorker(callback, "generic") {
4194
+ }
4195
+
4196
+ template<class T>
4197
+ inline AsyncProgressWorker<T>::AsyncProgressWorker(const Function& callback,
4198
+ const char* resource_name)
4199
+ : AsyncProgressWorker(callback, resource_name, Object::New(callback.Env())) {
4200
+ }
4201
+
4202
+ template<class T>
4203
+ inline AsyncProgressWorker<T>::AsyncProgressWorker(const Function& callback,
4204
+ const char* resource_name,
4205
+ const Object& resource)
4206
+ : AsyncProgressWorker(Object::New(callback.Env()),
4207
+ callback,
4208
+ resource_name,
4209
+ resource) {
4210
+ }
4211
+
4212
+ template<class T>
4213
+ inline AsyncProgressWorker<T>::AsyncProgressWorker(const Object& receiver,
4214
+ const Function& callback)
4215
+ : AsyncProgressWorker(receiver, callback, "generic") {
4216
+ }
4217
+
4218
+ template<class T>
4219
+ inline AsyncProgressWorker<T>::AsyncProgressWorker(const Object& receiver,
4220
+ const Function& callback,
4221
+ const char* resource_name)
4222
+ : AsyncProgressWorker(receiver,
4223
+ callback,
4224
+ resource_name,
4225
+ Object::New(callback.Env())) {
4226
+ }
4227
+
4228
+ template<class T>
4229
+ inline AsyncProgressWorker<T>::AsyncProgressWorker(const Object& receiver,
4230
+ const Function& callback,
4231
+ const char* resource_name,
4232
+ const Object& resource)
4233
+ : AsyncWorker(receiver, callback, resource_name, resource),
4234
+ _asyncdata(nullptr),
4235
+ _asyncsize(0) {
4236
+ _tsfn = ThreadSafeFunction::New(callback.Env(), callback, resource_name, 1, 1);
4237
+ }
4238
+
4239
+ #if NAPI_VERSION > 4
4240
+ template<class T>
4241
+ inline AsyncProgressWorker<T>::AsyncProgressWorker(Napi::Env env)
4242
+ : AsyncProgressWorker(env, "generic") {
4243
+ }
4244
+
4245
+ template<class T>
4246
+ inline AsyncProgressWorker<T>::AsyncProgressWorker(Napi::Env env,
4247
+ const char* resource_name)
4248
+ : AsyncProgressWorker(env, resource_name, Object::New(env)) {
4249
+ }
4250
+
4251
+ template<class T>
4252
+ inline AsyncProgressWorker<T>::AsyncProgressWorker(Napi::Env env,
4253
+ const char* resource_name,
4254
+ const Object& resource)
4255
+ : AsyncWorker(env, resource_name, resource),
4256
+ _asyncdata(nullptr),
4257
+ _asyncsize(0) {
4258
+ // TODO: Once the changes to make the callback optional for threadsafe
4259
+ // functions are no longer optional we can remove the dummy Function here.
4260
+ Function callback;
4261
+ _tsfn = ThreadSafeFunction::New(env, callback, resource_name, 1, 1);
4262
+ }
4263
+ #endif
4264
+
4265
+ template<class T>
4266
+ inline AsyncProgressWorker<T>::~AsyncProgressWorker() {
4267
+ // Abort pending tsfn call.
4268
+ // Don't send progress events after we've already completed.
4269
+ _tsfn.Abort();
4270
+ {
4271
+ std::lock_guard<std::mutex> lock(_mutex);
4272
+ _asyncdata = nullptr;
4273
+ _asyncsize = 0;
4274
+ }
4275
+ _tsfn.Release();
4276
+ }
4277
+
4278
+ template<class T>
4279
+ inline void AsyncProgressWorker<T>::Execute() {
4280
+ ExecutionProgress progress(this);
4281
+ Execute(progress);
4282
+ }
4283
+
4284
+ template<class T>
4285
+ inline void AsyncProgressWorker<T>::WorkProgress_(Napi::Env /* env */, Napi::Function /* jsCallback */, void* _data) {
4286
+ AsyncProgressWorker* self = static_cast<AsyncProgressWorker*>(_data);
4287
+
4288
+ T* data;
4289
+ size_t size;
4290
+ {
4291
+ std::lock_guard<std::mutex> lock(self->_mutex);
4292
+ data = self->_asyncdata;
4293
+ size = self->_asyncsize;
4294
+ self->_asyncdata = nullptr;
4295
+ self->_asyncsize = 0;
4296
+ }
4297
+
4298
+ self->OnProgress(data, size);
4299
+ delete[] data;
4300
+ }
4301
+
4302
+ template<class T>
4303
+ inline void AsyncProgressWorker<T>::SendProgress_(const T* data, size_t count) {
4304
+ T* new_data = new T[count];
4305
+ std::copy(data, data + count, new_data);
4306
+
4307
+ T* old_data;
4308
+ {
4309
+ std::lock_guard<std::mutex> lock(_mutex);
4310
+ old_data = _asyncdata;
4311
+ _asyncdata = new_data;
4312
+ _asyncsize = count;
4313
+ }
4314
+ _tsfn.NonBlockingCall(this, WorkProgress_);
4315
+
4316
+ delete[] old_data;
4317
+ }
4318
+
4319
+ template<class T>
4320
+ inline void AsyncProgressWorker<T>::Signal() const {
4321
+ _tsfn.NonBlockingCall(this, WorkProgress_);
4322
+ }
4323
+
4324
+ template<class T>
4325
+ inline void AsyncProgressWorker<T>::ExecutionProgress::Signal() const {
4326
+ _worker->Signal();
4327
+ }
4328
+
4329
+ template<class T>
4330
+ inline void AsyncProgressWorker<T>::ExecutionProgress::Send(const T* data, size_t count) const {
4331
+ _worker->SendProgress_(data, count);
4332
+ }
4333
+
4334
+ #endif
4335
+
3630
4336
  ////////////////////////////////////////////////////////////////////////////////
3631
4337
  // Memory Management class
3632
4338
  ////////////////////////////////////////////////////////////////////////////////