node-addon-api 2.0.2 → 3.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.
Files changed (45) hide show
  1. package/.travis.yml +1 -4
  2. package/CHANGELOG.md +88 -30
  3. package/README.md +53 -7
  4. package/benchmark/README.md +47 -0
  5. package/benchmark/binding.gyp +25 -0
  6. package/benchmark/function_args.cc +153 -0
  7. package/benchmark/function_args.js +52 -0
  8. package/benchmark/index.js +34 -0
  9. package/benchmark/property_descriptor.cc +60 -0
  10. package/benchmark/property_descriptor.js +29 -0
  11. package/common.gypi +21 -0
  12. package/doc/async_worker.md +33 -4
  13. package/doc/{async_progress_worker.md → async_worker_variants.md} +115 -3
  14. package/doc/bigint.md +2 -1
  15. package/doc/class_property_descriptor.md +3 -3
  16. package/doc/creating_a_release.md +5 -5
  17. package/doc/env.md +14 -0
  18. package/doc/function.md +108 -1
  19. package/doc/object.md +40 -1
  20. package/doc/object_lifetime_management.md +1 -1
  21. package/doc/object_wrap.md +278 -2
  22. package/doc/property_descriptor.md +64 -9
  23. package/doc/setup.md +0 -1
  24. package/doc/string.md +1 -1
  25. package/doc/symbol.md +1 -1
  26. package/doc/value.md +1 -1
  27. package/except.gypi +16 -0
  28. package/index.js +5 -42
  29. package/napi-inl.h +727 -141
  30. package/napi.h +338 -83
  31. package/node_api.gyp +9 -0
  32. package/noexcept.gypi +16 -0
  33. package/{src/nothing.c → nothing.c} +0 -0
  34. package/package.json +33 -1
  35. package/tools/README.md +4 -4
  36. package/tools/conversion.js +0 -4
  37. package/external-napi/node_api.h +0 -7
  38. package/src/node_api.cc +0 -3655
  39. package/src/node_api.gyp +0 -21
  40. package/src/node_api.h +0 -588
  41. package/src/node_api_types.h +0 -115
  42. package/src/node_internals.cc +0 -142
  43. package/src/node_internals.h +0 -157
  44. package/src/util-inl.h +0 -38
  45. package/src/util.h +0 -7
package/napi-inl.h CHANGED
@@ -10,7 +10,6 @@
10
10
  // Note: Do not include this file directly! Include "napi.h" instead.
11
11
 
12
12
  #include <algorithm>
13
- #include <atomic>
14
13
  #include <cstring>
15
14
  #include <mutex>
16
15
  #include <type_traits>
@@ -20,8 +19,6 @@ namespace Napi {
20
19
  // Helpers to handle functions exposed from C++.
21
20
  namespace details {
22
21
 
23
- extern std::atomic_bool needs_objectwrap_destructor_fix;
24
-
25
22
  // Attach a data item to an object and delete it when the object gets
26
23
  // garbage-collected.
27
24
  // TODO: Replace this code with `napi_add_finalizer()` whenever it becomes
@@ -153,9 +150,6 @@ struct ThreadSafeFinalize {
153
150
  ThreadSafeFinalize* finalizeData =
154
151
  static_cast<ThreadSafeFinalize*>(rawFinalizeData);
155
152
  finalizeData->callback(Env(env));
156
- if (finalizeData->tsfn) {
157
- *finalizeData->tsfn = nullptr;
158
- }
159
153
  delete finalizeData;
160
154
  }
161
155
 
@@ -169,9 +163,6 @@ struct ThreadSafeFinalize {
169
163
  ThreadSafeFinalize* finalizeData =
170
164
  static_cast<ThreadSafeFinalize*>(rawFinalizeData);
171
165
  finalizeData->callback(Env(env), finalizeData->data);
172
- if (finalizeData->tsfn) {
173
- *finalizeData->tsfn = nullptr;
174
- }
175
166
  delete finalizeData;
176
167
  }
177
168
 
@@ -185,9 +176,6 @@ struct ThreadSafeFinalize {
185
176
  ThreadSafeFinalize* finalizeData =
186
177
  static_cast<ThreadSafeFinalize*>(rawFinalizeData);
187
178
  finalizeData->callback(Env(env), static_cast<ContextType*>(rawContext));
188
- if (finalizeData->tsfn) {
189
- *finalizeData->tsfn = nullptr;
190
- }
191
179
  delete finalizeData;
192
180
  }
193
181
 
@@ -202,15 +190,11 @@ struct ThreadSafeFinalize {
202
190
  static_cast<ThreadSafeFinalize*>(rawFinalizeData);
203
191
  finalizeData->callback(Env(env), finalizeData->data,
204
192
  static_cast<ContextType*>(rawContext));
205
- if (finalizeData->tsfn) {
206
- *finalizeData->tsfn = nullptr;
207
- }
208
193
  delete finalizeData;
209
194
  }
210
195
 
211
196
  FinalizerDataType* data;
212
197
  Finalizer callback;
213
- napi_threadsafe_function* tsfn;
214
198
  };
215
199
  #endif
216
200
 
@@ -254,16 +238,11 @@ struct AccessorCallbackData {
254
238
  // Module registration
255
239
  ////////////////////////////////////////////////////////////////////////////////
256
240
 
257
- #define NODE_API_MODULE(modname, regfunc) \
258
- namespace Napi { \
259
- namespace details { \
260
- std::atomic_bool needs_objectwrap_destructor_fix(false); \
261
- } \
262
- } \
263
- napi_value __napi_ ## regfunc(napi_env env, \
264
- napi_value exports) { \
265
- return Napi::RegisterModule(env, exports, regfunc); \
266
- } \
241
+ #define NODE_API_MODULE(modname, regfunc) \
242
+ napi_value __napi_ ## regfunc(napi_env env, \
243
+ napi_value exports) { \
244
+ return Napi::RegisterModule(env, exports, regfunc); \
245
+ } \
267
246
  NAPI_MODULE(modname, __napi_ ## regfunc)
268
247
 
269
248
  // Adapt the NAPI_MODULE registration function:
@@ -272,12 +251,6 @@ struct AccessorCallbackData {
272
251
  inline napi_value RegisterModule(napi_env env,
273
252
  napi_value exports,
274
253
  ModuleRegisterCallback registerCallback) {
275
- const napi_node_version* nver = Napi::VersionManagement::GetNodeVersion(env);
276
- Napi::details::needs_objectwrap_destructor_fix =
277
- (nver->major < 10 ||
278
- (nver->major == 10 && nver->minor < 15) ||
279
- (nver->major == 10 && nver->minor == 15 && nver->patch < 3));
280
-
281
254
  return details::WrapCallback([&] {
282
255
  return napi_value(registerCallback(Napi::Env(env),
283
256
  Napi::Object(env, exports)));
@@ -333,6 +306,64 @@ inline Error Env::GetAndClearPendingException() {
333
306
  return Error(_env, value);
334
307
  }
335
308
 
309
+ inline Value Env::RunScript(const char* utf8script) {
310
+ String script = String::New(_env, utf8script);
311
+ return RunScript(script);
312
+ }
313
+
314
+ inline Value Env::RunScript(const std::string& utf8script) {
315
+ return RunScript(utf8script.c_str());
316
+ }
317
+
318
+ inline Value Env::RunScript(String script) {
319
+ napi_value result;
320
+ napi_status status = napi_run_script(_env, script, &result);
321
+ NAPI_THROW_IF_FAILED(_env, status, Undefined());
322
+ return Value(_env, result);
323
+ }
324
+
325
+ #if NAPI_VERSION > 5
326
+ template <typename T, Env::Finalizer<T> fini>
327
+ inline void Env::SetInstanceData(T* data) {
328
+ napi_status status =
329
+ napi_set_instance_data(_env, data, [](napi_env env, void* data, void*) {
330
+ fini(env, static_cast<T*>(data));
331
+ }, nullptr);
332
+ NAPI_THROW_IF_FAILED_VOID(_env, status);
333
+ }
334
+
335
+ template <typename DataType,
336
+ typename HintType,
337
+ Napi::Env::FinalizerWithHint<DataType, HintType> fini>
338
+ inline void Env::SetInstanceData(DataType* data, HintType* hint) {
339
+ napi_status status =
340
+ napi_set_instance_data(_env, data,
341
+ [](napi_env env, void* data, void* hint) {
342
+ fini(env, static_cast<DataType*>(data), static_cast<HintType*>(hint));
343
+ }, hint);
344
+ NAPI_THROW_IF_FAILED_VOID(_env, status);
345
+ }
346
+
347
+ template <typename T>
348
+ inline T* Env::GetInstanceData() {
349
+ void* data = nullptr;
350
+
351
+ napi_status status = napi_get_instance_data(_env, &data);
352
+ NAPI_THROW_IF_FAILED(_env, status, nullptr);
353
+
354
+ return static_cast<T*>(data);
355
+ }
356
+
357
+ template <typename T> void Env::DefaultFini(Env, T* data) {
358
+ delete data;
359
+ }
360
+
361
+ template <typename DataType, typename HintType>
362
+ void Env::DefaultFiniWithHint(Env, DataType* data, HintType*) {
363
+ delete data;
364
+ }
365
+ #endif // NAPI_VERSION > 5
366
+
336
367
  ////////////////////////////////////////////////////////////////////////////////
337
368
  // Value class
338
369
  ////////////////////////////////////////////////////////////////////////////////
@@ -397,14 +428,11 @@ inline bool Value::IsNumber() const {
397
428
  return Type() == napi_number;
398
429
  }
399
430
 
400
- // Currently experimental guard with the definition of NAPI_EXPERIMENTAL.
401
- // Once it is no longer experimental guard with the NAPI_VERSION in which it is
402
- // released instead.
403
- #ifdef NAPI_EXPERIMENTAL
431
+ #if NAPI_VERSION > 5
404
432
  inline bool Value::IsBigInt() const {
405
433
  return Type() == napi_bigint;
406
434
  }
407
- #endif // NAPI_EXPERIMENTAL
435
+ #endif // NAPI_VERSION > 5
408
436
 
409
437
  #if (NAPI_VERSION > 4)
410
438
  inline bool Value::IsDate() const {
@@ -635,10 +663,7 @@ inline double Number::DoubleValue() const {
635
663
  return result;
636
664
  }
637
665
 
638
- // Currently experimental guard with the definition of NAPI_EXPERIMENTAL.
639
- // Once it is no longer experimental guard with the NAPI_VERSION in which it is
640
- // released instead.
641
- #ifdef NAPI_EXPERIMENTAL
666
+ #if NAPI_VERSION > 5
642
667
  ////////////////////////////////////////////////////////////////////////////////
643
668
  // BigInt Class
644
669
  ////////////////////////////////////////////////////////////////////////////////
@@ -699,7 +724,7 @@ inline void BigInt::ToWords(int* sign_bit, size_t* word_count, uint64_t* words)
699
724
  _env, _value, sign_bit, word_count, words);
700
725
  NAPI_THROW_IF_FAILED_VOID(_env, status);
701
726
  }
702
- #endif // NAPI_EXPERIMENTAL
727
+ #endif // NAPI_VERSION > 5
703
728
 
704
729
  #if (NAPI_VERSION > 4)
705
730
  ////////////////////////////////////////////////////////////////////////////////
@@ -1344,7 +1369,7 @@ inline ArrayBuffer ArrayBuffer::New(napi_env env, size_t byteLength) {
1344
1369
  napi_status status = napi_create_arraybuffer(env, byteLength, &data, &value);
1345
1370
  NAPI_THROW_IF_FAILED(env, status, ArrayBuffer());
1346
1371
 
1347
- return ArrayBuffer(env, value, data, byteLength);
1372
+ return ArrayBuffer(env, value);
1348
1373
  }
1349
1374
 
1350
1375
  inline ArrayBuffer ArrayBuffer::New(napi_env env,
@@ -1355,7 +1380,7 @@ inline ArrayBuffer ArrayBuffer::New(napi_env env,
1355
1380
  env, externalData, byteLength, nullptr, nullptr, &value);
1356
1381
  NAPI_THROW_IF_FAILED(env, status, ArrayBuffer());
1357
1382
 
1358
- return ArrayBuffer(env, value, externalData, byteLength);
1383
+ return ArrayBuffer(env, value);
1359
1384
  }
1360
1385
 
1361
1386
  template <typename Finalizer>
@@ -1378,7 +1403,7 @@ inline ArrayBuffer ArrayBuffer::New(napi_env env,
1378
1403
  NAPI_THROW_IF_FAILED(env, status, ArrayBuffer());
1379
1404
  }
1380
1405
 
1381
- return ArrayBuffer(env, value, externalData, byteLength);
1406
+ return ArrayBuffer(env, value);
1382
1407
  }
1383
1408
 
1384
1409
  template <typename Finalizer, typename Hint>
@@ -1402,38 +1427,28 @@ inline ArrayBuffer ArrayBuffer::New(napi_env env,
1402
1427
  NAPI_THROW_IF_FAILED(env, status, ArrayBuffer());
1403
1428
  }
1404
1429
 
1405
- return ArrayBuffer(env, value, externalData, byteLength);
1430
+ return ArrayBuffer(env, value);
1406
1431
  }
1407
1432
 
1408
- inline ArrayBuffer::ArrayBuffer() : Object(), _data(nullptr), _length(0) {
1433
+ inline ArrayBuffer::ArrayBuffer() : Object() {
1409
1434
  }
1410
1435
 
1411
1436
  inline ArrayBuffer::ArrayBuffer(napi_env env, napi_value value)
1412
- : Object(env, value), _data(nullptr), _length(0) {
1413
- }
1414
-
1415
- inline ArrayBuffer::ArrayBuffer(napi_env env, napi_value value, void* data, size_t length)
1416
- : Object(env, value), _data(data), _length(length) {
1437
+ : Object(env, value) {
1417
1438
  }
1418
1439
 
1419
1440
  inline void* ArrayBuffer::Data() {
1420
- EnsureInfo();
1421
- return _data;
1441
+ void* data;
1442
+ napi_status status = napi_get_arraybuffer_info(_env, _value, &data, nullptr);
1443
+ NAPI_THROW_IF_FAILED(_env, status, nullptr);
1444
+ return data;
1422
1445
  }
1423
1446
 
1424
1447
  inline size_t ArrayBuffer::ByteLength() {
1425
- EnsureInfo();
1426
- return _length;
1427
- }
1428
-
1429
- inline void ArrayBuffer::EnsureInfo() const {
1430
- // The ArrayBuffer instance may have been constructed from a napi_value whose
1431
- // length/data are not yet known. Fetch and cache these values just once,
1432
- // since they can never change during the lifetime of the ArrayBuffer.
1433
- if (_data == nullptr) {
1434
- napi_status status = napi_get_arraybuffer_info(_env, _value, &_data, &_length);
1435
- NAPI_THROW_IF_FAILED_VOID(_env, status);
1436
- }
1448
+ size_t length;
1449
+ napi_status status = napi_get_arraybuffer_info(_env, _value, nullptr, &length);
1450
+ NAPI_THROW_IF_FAILED(_env, status, 0);
1451
+ return length;
1437
1452
  }
1438
1453
 
1439
1454
  ////////////////////////////////////////////////////////////////////////////////
@@ -1649,6 +1664,10 @@ inline uint8_t TypedArray::ElementSize() const {
1649
1664
  case napi_float32_array:
1650
1665
  return 4;
1651
1666
  case napi_float64_array:
1667
+ #if (NAPI_VERSION > 5)
1668
+ case napi_bigint64_array:
1669
+ case napi_biguint64_array:
1670
+ #endif // (NAPI_VERSION > 5)
1652
1671
  return 8;
1653
1672
  default:
1654
1673
  return 0;
@@ -1780,6 +1799,51 @@ CreateFunction(napi_env env,
1780
1799
  return status;
1781
1800
  }
1782
1801
 
1802
+ template <Function::VoidCallback cb>
1803
+ inline Function Function::New(napi_env env, const char* utf8name, void* data) {
1804
+ napi_value result = nullptr;
1805
+ napi_status status = napi_create_function(
1806
+ env, utf8name, NAPI_AUTO_LENGTH,
1807
+ [](napi_env env, napi_callback_info info) {
1808
+ CallbackInfo callbackInfo(env, info);
1809
+ return details::WrapCallback([&] {
1810
+ cb(callbackInfo);
1811
+ return nullptr;
1812
+ });
1813
+ }, data, &result);
1814
+ NAPI_THROW_IF_FAILED(env, status, Function());
1815
+ return Function(env, result);
1816
+ }
1817
+
1818
+ template <Function::Callback cb>
1819
+ inline Function Function::New(napi_env env, const char* utf8name, void* data) {
1820
+ napi_value result = nullptr;
1821
+ napi_status status = napi_create_function(
1822
+ env, utf8name, NAPI_AUTO_LENGTH,
1823
+ [](napi_env env, napi_callback_info info) {
1824
+ CallbackInfo callbackInfo(env, info);
1825
+ return details::WrapCallback([&] {
1826
+ return cb(callbackInfo);
1827
+ });
1828
+ }, data, &result);
1829
+ NAPI_THROW_IF_FAILED(env, status, Function());
1830
+ return Function(env, result);
1831
+ }
1832
+
1833
+ template <Function::VoidCallback cb>
1834
+ inline Function Function::New(napi_env env,
1835
+ const std::string& utf8name,
1836
+ void* data) {
1837
+ return Function::New<cb>(env, utf8name.c_str(), data);
1838
+ }
1839
+
1840
+ template <Function::Callback cb>
1841
+ inline Function Function::New(napi_env env,
1842
+ const std::string& utf8name,
1843
+ void* data) {
1844
+ return Function::New<cb>(env, utf8name.c_str(), data);
1845
+ }
1846
+
1783
1847
  template <typename Callable>
1784
1848
  inline Function Function::New(napi_env env,
1785
1849
  Callable cb,
@@ -2051,12 +2115,19 @@ inline void Buffer<T>::EnsureInfo() const {
2051
2115
  inline Error Error::New(napi_env env) {
2052
2116
  napi_status status;
2053
2117
  napi_value error = nullptr;
2054
-
2118
+ bool is_exception_pending;
2055
2119
  const napi_extended_error_info* info;
2120
+
2121
+ // We must retrieve the last error info before doing anything else, because
2122
+ // doing anything else will replace the last error info.
2056
2123
  status = napi_get_last_error_info(env, &info);
2057
2124
  NAPI_FATAL_IF_FAILED(status, "Error::New", "napi_get_last_error_info");
2058
2125
 
2059
- if (info->error_code == napi_pending_exception) {
2126
+ status = napi_is_exception_pending(env, &is_exception_pending);
2127
+ NAPI_FATAL_IF_FAILED(status, "Error::New", "napi_is_exception_pending");
2128
+
2129
+ // A pending exception takes precedence over any internal error status.
2130
+ if (is_exception_pending) {
2060
2131
  status = napi_get_and_clear_last_exception(env, &error);
2061
2132
  NAPI_FATAL_IF_FAILED(status, "Error::New", "napi_get_and_clear_last_exception");
2062
2133
  }
@@ -2064,15 +2135,6 @@ inline Error Error::New(napi_env env) {
2064
2135
  const char* error_message = info->error_message != nullptr ?
2065
2136
  info->error_message : "Error in native callback";
2066
2137
 
2067
- bool isExceptionPending;
2068
- status = napi_is_exception_pending(env, &isExceptionPending);
2069
- NAPI_FATAL_IF_FAILED(status, "Error::New", "napi_is_exception_pending");
2070
-
2071
- if (isExceptionPending) {
2072
- status = napi_get_and_clear_last_exception(env, &error);
2073
- NAPI_FATAL_IF_FAILED(status, "Error::New", "napi_get_and_clear_last_exception");
2074
- }
2075
-
2076
2138
  napi_value message;
2077
2139
  status = napi_create_string_utf8(
2078
2140
  env,
@@ -2134,7 +2196,7 @@ inline Error& Error::operator =(Error&& other) {
2134
2196
  inline Error::Error(const Error& other) : ObjectReference(other) {
2135
2197
  }
2136
2198
 
2137
- inline Error& Error::operator =(Error& other) {
2199
+ inline Error& Error::operator =(const Error& other) {
2138
2200
  Reset();
2139
2201
 
2140
2202
  _env = other.Env();
@@ -2746,6 +2808,108 @@ inline void CallbackInfo::SetData(void* data) {
2746
2808
  // PropertyDescriptor class
2747
2809
  ////////////////////////////////////////////////////////////////////////////////
2748
2810
 
2811
+ template <typename PropertyDescriptor::GetterCallback Getter>
2812
+ PropertyDescriptor
2813
+ PropertyDescriptor::Accessor(const char* utf8name,
2814
+ napi_property_attributes attributes,
2815
+ void* data) {
2816
+ napi_property_descriptor desc = napi_property_descriptor();
2817
+
2818
+ desc.utf8name = utf8name;
2819
+ desc.getter = &GetterCallbackWrapper<Getter>;
2820
+ desc.attributes = attributes;
2821
+ desc.data = data;
2822
+
2823
+ return desc;
2824
+ }
2825
+
2826
+ template <typename PropertyDescriptor::GetterCallback Getter>
2827
+ PropertyDescriptor
2828
+ PropertyDescriptor::Accessor(const std::string& utf8name,
2829
+ napi_property_attributes attributes,
2830
+ void* data) {
2831
+ return Accessor<Getter>(utf8name.c_str(), attributes, data);
2832
+ }
2833
+
2834
+ template <typename PropertyDescriptor::GetterCallback Getter>
2835
+ PropertyDescriptor
2836
+ PropertyDescriptor::Accessor(Name name,
2837
+ napi_property_attributes attributes,
2838
+ void* data) {
2839
+ napi_property_descriptor desc = napi_property_descriptor();
2840
+
2841
+ desc.name = name;
2842
+ desc.getter = &GetterCallbackWrapper<Getter>;
2843
+ desc.attributes = attributes;
2844
+ desc.data = data;
2845
+
2846
+ return desc;
2847
+ }
2848
+
2849
+ template <
2850
+ typename PropertyDescriptor::GetterCallback Getter,
2851
+ typename PropertyDescriptor::SetterCallback Setter>
2852
+ PropertyDescriptor
2853
+ PropertyDescriptor::Accessor(const char* utf8name,
2854
+ napi_property_attributes attributes,
2855
+ void* data) {
2856
+
2857
+ napi_property_descriptor desc = napi_property_descriptor();
2858
+
2859
+ desc.utf8name = utf8name;
2860
+ desc.getter = &GetterCallbackWrapper<Getter>;
2861
+ desc.setter = &SetterCallbackWrapper<Setter>;
2862
+ desc.attributes = attributes;
2863
+ desc.data = data;
2864
+
2865
+ return desc;
2866
+ }
2867
+
2868
+ template <
2869
+ typename PropertyDescriptor::GetterCallback Getter,
2870
+ typename PropertyDescriptor::SetterCallback Setter>
2871
+ PropertyDescriptor
2872
+ PropertyDescriptor::Accessor(const std::string& utf8name,
2873
+ napi_property_attributes attributes,
2874
+ void* data) {
2875
+ return Accessor<Getter, Setter>(utf8name.c_str(), attributes, data);
2876
+ }
2877
+
2878
+ template <
2879
+ typename PropertyDescriptor::GetterCallback Getter,
2880
+ typename PropertyDescriptor::SetterCallback Setter>
2881
+ PropertyDescriptor
2882
+ PropertyDescriptor::Accessor(Name name,
2883
+ napi_property_attributes attributes,
2884
+ void* data) {
2885
+ napi_property_descriptor desc = napi_property_descriptor();
2886
+
2887
+ desc.name = name;
2888
+ desc.getter = &GetterCallbackWrapper<Getter>;
2889
+ desc.setter = &SetterCallbackWrapper<Setter>;
2890
+ desc.attributes = attributes;
2891
+ desc.data = data;
2892
+
2893
+ return desc;
2894
+ }
2895
+
2896
+ template <typename PropertyDescriptor::GetterCallback Getter>
2897
+ napi_value
2898
+ PropertyDescriptor::GetterCallbackWrapper(napi_env env,
2899
+ napi_callback_info info) {
2900
+ CallbackInfo cbInfo(env, info);
2901
+ return Getter(cbInfo);
2902
+ }
2903
+
2904
+ template <typename PropertyDescriptor::SetterCallback Setter>
2905
+ napi_value
2906
+ PropertyDescriptor::SetterCallbackWrapper(napi_env env,
2907
+ napi_callback_info info) {
2908
+ CallbackInfo cbInfo(env, info);
2909
+ Setter(cbInfo);
2910
+ return nullptr;
2911
+ }
2912
+
2749
2913
  template <typename Getter>
2750
2914
  inline PropertyDescriptor
2751
2915
  PropertyDescriptor::Accessor(Napi::Env env,
@@ -2999,16 +3163,6 @@ inline ObjectWrap<T>::~ObjectWrap() {
2999
3163
  // This happens e.g. during garbage collection.
3000
3164
  if (!object.IsEmpty() && _construction_failed) {
3001
3165
  napi_remove_wrap(Env(), object, nullptr);
3002
-
3003
- if (Napi::details::needs_objectwrap_destructor_fix) {
3004
- // If construction failed we delete the reference via
3005
- // `napi_remove_wrap()`, not via `napi_delete_reference()` in the
3006
- // `Reference<Object>` destructor. This will prevent the
3007
- // `Reference<Object>` destructor from doing a double delete of this
3008
- // reference.
3009
- _ref = nullptr;
3010
- _env = nullptr;
3011
- }
3012
3166
  }
3013
3167
  }
3014
3168
  }
@@ -3200,6 +3354,62 @@ inline ClassPropertyDescriptor<T> ObjectWrap<T>::StaticMethod(
3200
3354
  return desc;
3201
3355
  }
3202
3356
 
3357
+ template <typename T>
3358
+ template <typename ObjectWrap<T>::StaticVoidMethodCallback method>
3359
+ inline ClassPropertyDescriptor<T> ObjectWrap<T>::StaticMethod(
3360
+ const char* utf8name,
3361
+ napi_property_attributes attributes,
3362
+ void* data) {
3363
+ napi_property_descriptor desc = napi_property_descriptor();
3364
+ desc.utf8name = utf8name;
3365
+ desc.method = &ObjectWrap<T>::WrappedMethod<method>;
3366
+ desc.data = data;
3367
+ desc.attributes = static_cast<napi_property_attributes>(attributes | napi_static);
3368
+ return desc;
3369
+ }
3370
+
3371
+ template <typename T>
3372
+ template <typename ObjectWrap<T>::StaticVoidMethodCallback method>
3373
+ inline ClassPropertyDescriptor<T> ObjectWrap<T>::StaticMethod(
3374
+ Symbol name,
3375
+ napi_property_attributes attributes,
3376
+ void* data) {
3377
+ napi_property_descriptor desc = napi_property_descriptor();
3378
+ desc.name = name;
3379
+ desc.method = &ObjectWrap<T>::WrappedMethod<method>;
3380
+ desc.data = data;
3381
+ desc.attributes = static_cast<napi_property_attributes>(attributes | napi_static);
3382
+ return desc;
3383
+ }
3384
+
3385
+ template <typename T>
3386
+ template <typename ObjectWrap<T>::StaticMethodCallback method>
3387
+ inline ClassPropertyDescriptor<T> ObjectWrap<T>::StaticMethod(
3388
+ const char* utf8name,
3389
+ napi_property_attributes attributes,
3390
+ void* data) {
3391
+ napi_property_descriptor desc = napi_property_descriptor();
3392
+ desc.utf8name = utf8name;
3393
+ desc.method = &ObjectWrap<T>::WrappedMethod<method>;
3394
+ desc.data = data;
3395
+ desc.attributes = static_cast<napi_property_attributes>(attributes | napi_static);
3396
+ return desc;
3397
+ }
3398
+
3399
+ template <typename T>
3400
+ template <typename ObjectWrap<T>::StaticMethodCallback method>
3401
+ inline ClassPropertyDescriptor<T> ObjectWrap<T>::StaticMethod(
3402
+ Symbol name,
3403
+ napi_property_attributes attributes,
3404
+ void* data) {
3405
+ napi_property_descriptor desc = napi_property_descriptor();
3406
+ desc.name = name;
3407
+ desc.method = &ObjectWrap<T>::WrappedMethod<method>;
3408
+ desc.data = data;
3409
+ desc.attributes = static_cast<napi_property_attributes>(attributes | napi_static);
3410
+ return desc;
3411
+ }
3412
+
3203
3413
  template <typename T>
3204
3414
  inline ClassPropertyDescriptor<T> ObjectWrap<T>::StaticAccessor(
3205
3415
  const char* utf8name,
@@ -3238,6 +3448,38 @@ inline ClassPropertyDescriptor<T> ObjectWrap<T>::StaticAccessor(
3238
3448
  return desc;
3239
3449
  }
3240
3450
 
3451
+ template <typename T>
3452
+ template <typename ObjectWrap<T>::StaticGetterCallback getter,
3453
+ typename ObjectWrap<T>::StaticSetterCallback setter>
3454
+ inline ClassPropertyDescriptor<T> ObjectWrap<T>::StaticAccessor(
3455
+ const char* utf8name,
3456
+ napi_property_attributes attributes,
3457
+ void* data) {
3458
+ napi_property_descriptor desc = napi_property_descriptor();
3459
+ desc.utf8name = utf8name;
3460
+ desc.getter = This::WrapStaticGetter(This::StaticGetterTag<getter>());
3461
+ desc.setter = This::WrapStaticSetter(This::StaticSetterTag<setter>());
3462
+ desc.data = data;
3463
+ desc.attributes = static_cast<napi_property_attributes>(attributes | napi_static);
3464
+ return desc;
3465
+ }
3466
+
3467
+ template <typename T>
3468
+ template <typename ObjectWrap<T>::StaticGetterCallback getter,
3469
+ typename ObjectWrap<T>::StaticSetterCallback setter>
3470
+ inline ClassPropertyDescriptor<T> ObjectWrap<T>::StaticAccessor(
3471
+ Symbol name,
3472
+ napi_property_attributes attributes,
3473
+ void* data) {
3474
+ napi_property_descriptor desc = napi_property_descriptor();
3475
+ desc.name = name;
3476
+ desc.getter = This::WrapStaticGetter(This::StaticGetterTag<getter>());
3477
+ desc.setter = This::WrapStaticSetter(This::StaticSetterTag<setter>());
3478
+ desc.data = data;
3479
+ desc.attributes = static_cast<napi_property_attributes>(attributes | napi_static);
3480
+ return desc;
3481
+ }
3482
+
3241
3483
  template <typename T>
3242
3484
  inline ClassPropertyDescriptor<T> ObjectWrap<T>::InstanceMethod(
3243
3485
  const char* utf8name,
@@ -3304,6 +3546,62 @@ inline ClassPropertyDescriptor<T> ObjectWrap<T>::InstanceMethod(
3304
3546
  return desc;
3305
3547
  }
3306
3548
 
3549
+ template <typename T>
3550
+ template <typename ObjectWrap<T>::InstanceVoidMethodCallback method>
3551
+ inline ClassPropertyDescriptor<T> ObjectWrap<T>::InstanceMethod(
3552
+ const char* utf8name,
3553
+ napi_property_attributes attributes,
3554
+ void* data) {
3555
+ napi_property_descriptor desc = napi_property_descriptor();
3556
+ desc.utf8name = utf8name;
3557
+ desc.method = &ObjectWrap<T>::WrappedMethod<method>;
3558
+ desc.data = data;
3559
+ desc.attributes = attributes;
3560
+ return desc;
3561
+ }
3562
+
3563
+ template <typename T>
3564
+ template <typename ObjectWrap<T>::InstanceMethodCallback method>
3565
+ inline ClassPropertyDescriptor<T> ObjectWrap<T>::InstanceMethod(
3566
+ const char* utf8name,
3567
+ napi_property_attributes attributes,
3568
+ void* data) {
3569
+ napi_property_descriptor desc = napi_property_descriptor();
3570
+ desc.utf8name = utf8name;
3571
+ desc.method = &ObjectWrap<T>::WrappedMethod<method>;
3572
+ desc.data = data;
3573
+ desc.attributes = attributes;
3574
+ return desc;
3575
+ }
3576
+
3577
+ template <typename T>
3578
+ template <typename ObjectWrap<T>::InstanceVoidMethodCallback method>
3579
+ inline ClassPropertyDescriptor<T> ObjectWrap<T>::InstanceMethod(
3580
+ Symbol name,
3581
+ napi_property_attributes attributes,
3582
+ void* data) {
3583
+ napi_property_descriptor desc = napi_property_descriptor();
3584
+ desc.name = name;
3585
+ desc.method = &ObjectWrap<T>::WrappedMethod<method>;
3586
+ desc.data = data;
3587
+ desc.attributes = attributes;
3588
+ return desc;
3589
+ }
3590
+
3591
+ template <typename T>
3592
+ template <typename ObjectWrap<T>::InstanceMethodCallback method>
3593
+ inline ClassPropertyDescriptor<T> ObjectWrap<T>::InstanceMethod(
3594
+ Symbol name,
3595
+ napi_property_attributes attributes,
3596
+ void* data) {
3597
+ napi_property_descriptor desc = napi_property_descriptor();
3598
+ desc.name = name;
3599
+ desc.method = &ObjectWrap<T>::WrappedMethod<method>;
3600
+ desc.data = data;
3601
+ desc.attributes = attributes;
3602
+ return desc;
3603
+ }
3604
+
3307
3605
  template <typename T>
3308
3606
  inline ClassPropertyDescriptor<T> ObjectWrap<T>::InstanceAccessor(
3309
3607
  const char* utf8name,
@@ -3342,6 +3640,38 @@ inline ClassPropertyDescriptor<T> ObjectWrap<T>::InstanceAccessor(
3342
3640
  return desc;
3343
3641
  }
3344
3642
 
3643
+ template <typename T>
3644
+ template <typename ObjectWrap<T>::InstanceGetterCallback getter,
3645
+ typename ObjectWrap<T>::InstanceSetterCallback setter>
3646
+ inline ClassPropertyDescriptor<T> ObjectWrap<T>::InstanceAccessor(
3647
+ const char* utf8name,
3648
+ napi_property_attributes attributes,
3649
+ void* data) {
3650
+ napi_property_descriptor desc = napi_property_descriptor();
3651
+ desc.utf8name = utf8name;
3652
+ desc.getter = This::WrapGetter(This::GetterTag<getter>());
3653
+ desc.setter = This::WrapSetter(This::SetterTag<setter>());
3654
+ desc.data = data;
3655
+ desc.attributes = attributes;
3656
+ return desc;
3657
+ }
3658
+
3659
+ template <typename T>
3660
+ template <typename ObjectWrap<T>::InstanceGetterCallback getter,
3661
+ typename ObjectWrap<T>::InstanceSetterCallback setter>
3662
+ inline ClassPropertyDescriptor<T> ObjectWrap<T>::InstanceAccessor(
3663
+ Symbol name,
3664
+ napi_property_attributes attributes,
3665
+ void* data) {
3666
+ napi_property_descriptor desc = napi_property_descriptor();
3667
+ desc.name = name;
3668
+ desc.getter = This::WrapGetter(This::GetterTag<getter>());
3669
+ desc.setter = This::WrapSetter(This::SetterTag<setter>());
3670
+ desc.data = data;
3671
+ desc.attributes = attributes;
3672
+ return desc;
3673
+ }
3674
+
3345
3675
  template <typename T>
3346
3676
  inline ClassPropertyDescriptor<T> ObjectWrap<T>::StaticValue(const char* utf8name,
3347
3677
  Napi::Value value, napi_property_attributes attributes) {
@@ -3547,6 +3877,65 @@ inline void ObjectWrap<T>::FinalizeCallback(napi_env env, void* data, void* /*hi
3547
3877
  delete instance;
3548
3878
  }
3549
3879
 
3880
+ template <typename T>
3881
+ template <typename ObjectWrap<T>::StaticVoidMethodCallback method>
3882
+ inline napi_value ObjectWrap<T>::WrappedMethod(napi_env env, napi_callback_info info) noexcept {
3883
+ return details::WrapCallback([&] {
3884
+ method(CallbackInfo(env, info));
3885
+ return nullptr;
3886
+ });
3887
+ }
3888
+
3889
+ template <typename T>
3890
+ template <typename ObjectWrap<T>::StaticMethodCallback method>
3891
+ inline napi_value ObjectWrap<T>::WrappedMethod(napi_env env, napi_callback_info info) noexcept {
3892
+ return details::WrapCallback([&] {
3893
+ return method(CallbackInfo(env, info));
3894
+ });
3895
+ }
3896
+
3897
+ template <typename T>
3898
+ template <typename ObjectWrap<T>::InstanceVoidMethodCallback method>
3899
+ inline napi_value ObjectWrap<T>::WrappedMethod(napi_env env, napi_callback_info info) noexcept {
3900
+ return details::WrapCallback([&] {
3901
+ const CallbackInfo cbInfo(env, info);
3902
+ T* instance = Unwrap(cbInfo.This().As<Object>());
3903
+ (instance->*method)(cbInfo);
3904
+ return nullptr;
3905
+ });
3906
+ }
3907
+
3908
+ template <typename T>
3909
+ template <typename ObjectWrap<T>::InstanceMethodCallback method>
3910
+ inline napi_value ObjectWrap<T>::WrappedMethod(napi_env env, napi_callback_info info) noexcept {
3911
+ return details::WrapCallback([&] {
3912
+ const CallbackInfo cbInfo(env, info);
3913
+ T* instance = Unwrap(cbInfo.This().As<Object>());
3914
+ return (instance->*method)(cbInfo);
3915
+ });
3916
+ }
3917
+
3918
+ template <typename T>
3919
+ template <typename ObjectWrap<T>::StaticSetterCallback method>
3920
+ inline napi_value ObjectWrap<T>::WrappedMethod(napi_env env, napi_callback_info info) noexcept {
3921
+ return details::WrapCallback([&] {
3922
+ const CallbackInfo cbInfo(env, info);
3923
+ method(cbInfo, cbInfo[0]);
3924
+ return nullptr;
3925
+ });
3926
+ }
3927
+
3928
+ template <typename T>
3929
+ template <typename ObjectWrap<T>::InstanceSetterCallback method>
3930
+ inline napi_value ObjectWrap<T>::WrappedMethod(napi_env env, napi_callback_info info) noexcept {
3931
+ return details::WrapCallback([&] {
3932
+ const CallbackInfo cbInfo(env, info);
3933
+ T* instance = Unwrap(cbInfo.This().As<Object>());
3934
+ (instance->*method)(cbInfo, cbInfo[0]);
3935
+ return nullptr;
3936
+ });
3937
+ }
3938
+
3550
3939
  ////////////////////////////////////////////////////////////////////////////////
3551
3940
  // HandleScope class
3552
3941
  ////////////////////////////////////////////////////////////////////////////////
@@ -3744,8 +4133,8 @@ inline AsyncWorker::AsyncWorker(const Object& receiver,
3744
4133
  _env, resource_name, NAPI_AUTO_LENGTH, &resource_id);
3745
4134
  NAPI_THROW_IF_FAILED_VOID(_env, status);
3746
4135
 
3747
- status = napi_create_async_work(_env, resource, resource_id, OnExecute,
3748
- OnWorkComplete, this, &_work);
4136
+ status = napi_create_async_work(_env, resource, resource_id, OnAsyncWorkExecute,
4137
+ OnAsyncWorkComplete, this, &_work);
3749
4138
  NAPI_THROW_IF_FAILED_VOID(_env, status);
3750
4139
  }
3751
4140
 
@@ -3770,8 +4159,8 @@ inline AsyncWorker::AsyncWorker(Napi::Env env,
3770
4159
  _env, resource_name, NAPI_AUTO_LENGTH, &resource_id);
3771
4160
  NAPI_THROW_IF_FAILED_VOID(_env, status);
3772
4161
 
3773
- status = napi_create_async_work(_env, resource, resource_id, OnExecute,
3774
- OnWorkComplete, this, &_work);
4162
+ status = napi_create_async_work(_env, resource, resource_id, OnAsyncWorkExecute,
4163
+ OnAsyncWorkComplete, this, &_work);
3775
4164
  NAPI_THROW_IF_FAILED_VOID(_env, status);
3776
4165
  }
3777
4166
 
@@ -3858,40 +4247,51 @@ inline void AsyncWorker::SetError(const std::string& error) {
3858
4247
  inline std::vector<napi_value> AsyncWorker::GetResult(Napi::Env /*env*/) {
3859
4248
  return {};
3860
4249
  }
4250
+ // The OnAsyncWorkExecute method receives an napi_env argument. However, do NOT
4251
+ // use it within this method, as it does not run on the JavaScript thread and
4252
+ // must not run any method that would cause JavaScript to run. In practice,
4253
+ // this means that almost any use of napi_env will be incorrect.
4254
+ inline void AsyncWorker::OnAsyncWorkExecute(napi_env env, void* asyncworker) {
4255
+ AsyncWorker* self = static_cast<AsyncWorker*>(asyncworker);
4256
+ self->OnExecute(env);
4257
+ }
3861
4258
  // The OnExecute method receives an napi_env argument. However, do NOT
3862
- // use it within this method, as it does not run on the main thread and must
3863
- // not run any method that would cause JavaScript to run. In practice, this
3864
- // means that almost any use of napi_env will be incorrect.
3865
- inline void AsyncWorker::OnExecute(napi_env /*DO_NOT_USE*/, void* this_pointer) {
3866
- AsyncWorker* self = static_cast<AsyncWorker*>(this_pointer);
4259
+ // use it within this method, as it does not run on the JavaScript thread and
4260
+ // must not run any method that would cause JavaScript to run. In practice,
4261
+ // this means that almost any use of napi_env will be incorrect.
4262
+ inline void AsyncWorker::OnExecute(Napi::Env /*DO_NOT_USE*/) {
3867
4263
  #ifdef NAPI_CPP_EXCEPTIONS
3868
4264
  try {
3869
- self->Execute();
4265
+ Execute();
3870
4266
  } catch (const std::exception& e) {
3871
- self->SetError(e.what());
4267
+ SetError(e.what());
3872
4268
  }
3873
4269
  #else // NAPI_CPP_EXCEPTIONS
3874
- self->Execute();
4270
+ Execute();
3875
4271
  #endif // NAPI_CPP_EXCEPTIONS
3876
4272
  }
3877
4273
 
3878
- inline void AsyncWorker::OnWorkComplete(
3879
- napi_env /*env*/, napi_status status, void* this_pointer) {
3880
- AsyncWorker* self = static_cast<AsyncWorker*>(this_pointer);
4274
+ inline void AsyncWorker::OnAsyncWorkComplete(napi_env env,
4275
+ napi_status status,
4276
+ void* asyncworker) {
4277
+ AsyncWorker* self = static_cast<AsyncWorker*>(asyncworker);
4278
+ self->OnWorkComplete(env, status);
4279
+ }
4280
+ inline void AsyncWorker::OnWorkComplete(Napi::Env /*env*/, napi_status status) {
3881
4281
  if (status != napi_cancelled) {
3882
- HandleScope scope(self->_env);
4282
+ HandleScope scope(_env);
3883
4283
  details::WrapCallback([&] {
3884
- if (self->_error.size() == 0) {
3885
- self->OnOK();
4284
+ if (_error.size() == 0) {
4285
+ OnOK();
3886
4286
  }
3887
4287
  else {
3888
- self->OnError(Error::New(self->_env, self->_error));
4288
+ OnError(Error::New(_env, _error));
3889
4289
  }
3890
4290
  return nullptr;
3891
4291
  });
3892
4292
  }
3893
- if (!self->_suppress_destruct) {
3894
- self->Destroy();
4293
+ if (!_suppress_destruct) {
4294
+ Destroy();
3895
4295
  }
3896
4296
  }
3897
4297
 
@@ -4187,7 +4587,7 @@ inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env,
4187
4587
 
4188
4588
  ThreadSafeFunction tsfn;
4189
4589
  auto* finalizeData = new details::ThreadSafeFinalize<ContextType, Finalizer,
4190
- FinalizerDataType>({ data, finalizeCallback, &tsfn._tsfn });
4590
+ FinalizerDataType>({ data, finalizeCallback });
4191
4591
  napi_status status = napi_create_threadsafe_function(env, callback, resource,
4192
4592
  Value::From(env, resourceName), maxQueueSize, initialThreadCount,
4193
4593
  finalizeData, wrapper, context, CallJS, &tsfn._tsfn);
@@ -4230,9 +4630,89 @@ inline void ThreadSafeFunction::CallJS(napi_env env,
4230
4630
  }
4231
4631
 
4232
4632
  ////////////////////////////////////////////////////////////////////////////////
4233
- // Async Progress Worker class
4633
+ // Async Progress Worker Base class
4234
4634
  ////////////////////////////////////////////////////////////////////////////////
4635
+ template <typename DataType>
4636
+ inline AsyncProgressWorkerBase<DataType>::AsyncProgressWorkerBase(const Object& receiver,
4637
+ const Function& callback,
4638
+ const char* resource_name,
4639
+ const Object& resource,
4640
+ size_t queue_size)
4641
+ : AsyncWorker(receiver, callback, resource_name, resource) {
4642
+ // Fill all possible arguments to work around ambiguous ThreadSafeFunction::New signatures.
4643
+ _tsfn = ThreadSafeFunction::New(callback.Env(),
4644
+ callback,
4645
+ resource,
4646
+ resource_name,
4647
+ queue_size,
4648
+ /** initialThreadCount */ 1,
4649
+ /** context */ this,
4650
+ OnThreadSafeFunctionFinalize,
4651
+ /** finalizeData */ this);
4652
+ }
4653
+
4654
+ #if NAPI_VERSION > 4
4655
+ template <typename DataType>
4656
+ inline AsyncProgressWorkerBase<DataType>::AsyncProgressWorkerBase(Napi::Env env,
4657
+ const char* resource_name,
4658
+ const Object& resource,
4659
+ size_t queue_size)
4660
+ : AsyncWorker(env, resource_name, resource) {
4661
+ // TODO: Once the changes to make the callback optional for threadsafe
4662
+ // functions are available on all versions we can remove the dummy Function here.
4663
+ Function callback;
4664
+ // Fill all possible arguments to work around ambiguous ThreadSafeFunction::New signatures.
4665
+ _tsfn = ThreadSafeFunction::New(env,
4666
+ callback,
4667
+ resource,
4668
+ resource_name,
4669
+ queue_size,
4670
+ /** initialThreadCount */ 1,
4671
+ /** context */ this,
4672
+ OnThreadSafeFunctionFinalize,
4673
+ /** finalizeData */ this);
4674
+ }
4675
+ #endif
4676
+
4677
+ template<typename DataType>
4678
+ inline AsyncProgressWorkerBase<DataType>::~AsyncProgressWorkerBase() {
4679
+ // Abort pending tsfn call.
4680
+ // Don't send progress events after we've already completed.
4681
+ // It's ok to call ThreadSafeFunction::Abort and ThreadSafeFunction::Release duplicated.
4682
+ _tsfn.Abort();
4683
+ }
4684
+
4685
+ template <typename DataType>
4686
+ inline void AsyncProgressWorkerBase<DataType>::OnAsyncWorkProgress(Napi::Env /* env */,
4687
+ Napi::Function /* jsCallback */,
4688
+ void* data) {
4689
+ ThreadSafeData* tsd = static_cast<ThreadSafeData*>(data);
4690
+ tsd->asyncprogressworker()->OnWorkProgress(tsd->data());
4691
+ }
4692
+
4693
+ template <typename DataType>
4694
+ inline napi_status AsyncProgressWorkerBase<DataType>::NonBlockingCall(DataType* data) {
4695
+ auto tsd = new AsyncProgressWorkerBase::ThreadSafeData(this, data);
4696
+ return _tsfn.NonBlockingCall(tsd, OnAsyncWorkProgress);
4697
+ }
4698
+
4699
+ template <typename DataType>
4700
+ inline void AsyncProgressWorkerBase<DataType>::OnWorkComplete(Napi::Env /* env */, napi_status status) {
4701
+ _work_completed = true;
4702
+ _complete_status = status;
4703
+ _tsfn.Release();
4704
+ }
4235
4705
 
4706
+ template <typename DataType>
4707
+ inline void AsyncProgressWorkerBase<DataType>::OnThreadSafeFunctionFinalize(Napi::Env env, void* /* data */, AsyncProgressWorkerBase* context) {
4708
+ if (context->_work_completed) {
4709
+ context->AsyncWorker::OnWorkComplete(env, context->_complete_status);
4710
+ }
4711
+ }
4712
+
4713
+ ////////////////////////////////////////////////////////////////////////////////
4714
+ // Async Progress Worker class
4715
+ ////////////////////////////////////////////////////////////////////////////////
4236
4716
  template<class T>
4237
4717
  inline AsyncProgressWorker<T>::AsyncProgressWorker(const Function& callback)
4238
4718
  : AsyncProgressWorker(callback, "generic") {
@@ -4256,14 +4736,14 @@ inline AsyncProgressWorker<T>::AsyncProgressWorker(const Function& callback,
4256
4736
 
4257
4737
  template<class T>
4258
4738
  inline AsyncProgressWorker<T>::AsyncProgressWorker(const Object& receiver,
4259
- const Function& callback)
4739
+ const Function& callback)
4260
4740
  : AsyncProgressWorker(receiver, callback, "generic") {
4261
4741
  }
4262
4742
 
4263
4743
  template<class T>
4264
4744
  inline AsyncProgressWorker<T>::AsyncProgressWorker(const Object& receiver,
4265
- const Function& callback,
4266
- const char* resource_name)
4745
+ const Function& callback,
4746
+ const char* resource_name)
4267
4747
  : AsyncProgressWorker(receiver,
4268
4748
  callback,
4269
4749
  resource_name,
@@ -4275,10 +4755,9 @@ inline AsyncProgressWorker<T>::AsyncProgressWorker(const Object& receiver,
4275
4755
  const Function& callback,
4276
4756
  const char* resource_name,
4277
4757
  const Object& resource)
4278
- : AsyncWorker(receiver, callback, resource_name, resource),
4758
+ : AsyncProgressWorkerBase(receiver, callback, resource_name, resource),
4279
4759
  _asyncdata(nullptr),
4280
4760
  _asyncsize(0) {
4281
- _tsfn = ThreadSafeFunction::New(callback.Env(), callback, resource_name, 1, 1);
4282
4761
  }
4283
4762
 
4284
4763
  #if NAPI_VERSION > 4
@@ -4289,35 +4768,27 @@ inline AsyncProgressWorker<T>::AsyncProgressWorker(Napi::Env env)
4289
4768
 
4290
4769
  template<class T>
4291
4770
  inline AsyncProgressWorker<T>::AsyncProgressWorker(Napi::Env env,
4292
- const char* resource_name)
4771
+ const char* resource_name)
4293
4772
  : AsyncProgressWorker(env, resource_name, Object::New(env)) {
4294
4773
  }
4295
4774
 
4296
4775
  template<class T>
4297
4776
  inline AsyncProgressWorker<T>::AsyncProgressWorker(Napi::Env env,
4298
- const char* resource_name,
4299
- const Object& resource)
4300
- : AsyncWorker(env, resource_name, resource),
4777
+ const char* resource_name,
4778
+ const Object& resource)
4779
+ : AsyncProgressWorkerBase(env, resource_name, resource),
4301
4780
  _asyncdata(nullptr),
4302
4781
  _asyncsize(0) {
4303
- // TODO: Once the changes to make the callback optional for threadsafe
4304
- // functions are no longer optional we can remove the dummy Function here.
4305
- Function callback;
4306
- _tsfn = ThreadSafeFunction::New(env, callback, resource_name, 1, 1);
4307
4782
  }
4308
4783
  #endif
4309
4784
 
4310
4785
  template<class T>
4311
4786
  inline AsyncProgressWorker<T>::~AsyncProgressWorker() {
4312
- // Abort pending tsfn call.
4313
- // Don't send progress events after we've already completed.
4314
- _tsfn.Abort();
4315
4787
  {
4316
- std::lock_guard<std::mutex> lock(_mutex);
4788
+ std::lock_guard<std::mutex> lock(this->_mutex);
4317
4789
  _asyncdata = nullptr;
4318
4790
  _asyncsize = 0;
4319
4791
  }
4320
- _tsfn.Release();
4321
4792
  }
4322
4793
 
4323
4794
  template<class T>
@@ -4327,20 +4798,18 @@ inline void AsyncProgressWorker<T>::Execute() {
4327
4798
  }
4328
4799
 
4329
4800
  template<class T>
4330
- inline void AsyncProgressWorker<T>::WorkProgress_(Napi::Env /* env */, Napi::Function /* jsCallback */, void* _data) {
4331
- AsyncProgressWorker* self = static_cast<AsyncProgressWorker*>(_data);
4332
-
4801
+ inline void AsyncProgressWorker<T>::OnWorkProgress(void*) {
4333
4802
  T* data;
4334
4803
  size_t size;
4335
4804
  {
4336
- std::lock_guard<std::mutex> lock(self->_mutex);
4337
- data = self->_asyncdata;
4338
- size = self->_asyncsize;
4339
- self->_asyncdata = nullptr;
4340
- self->_asyncsize = 0;
4805
+ std::lock_guard<std::mutex> lock(this->_mutex);
4806
+ data = this->_asyncdata;
4807
+ size = this->_asyncsize;
4808
+ this->_asyncdata = nullptr;
4809
+ this->_asyncsize = 0;
4341
4810
  }
4342
4811
 
4343
- self->OnProgress(data, size);
4812
+ this->OnProgress(data, size);
4344
4813
  delete[] data;
4345
4814
  }
4346
4815
 
@@ -4351,19 +4820,19 @@ inline void AsyncProgressWorker<T>::SendProgress_(const T* data, size_t count) {
4351
4820
 
4352
4821
  T* old_data;
4353
4822
  {
4354
- std::lock_guard<std::mutex> lock(_mutex);
4823
+ std::lock_guard<std::mutex> lock(this->_mutex);
4355
4824
  old_data = _asyncdata;
4356
4825
  _asyncdata = new_data;
4357
4826
  _asyncsize = count;
4358
4827
  }
4359
- _tsfn.NonBlockingCall(this, WorkProgress_);
4828
+ this->NonBlockingCall(nullptr);
4360
4829
 
4361
4830
  delete[] old_data;
4362
4831
  }
4363
4832
 
4364
4833
  template<class T>
4365
4834
  inline void AsyncProgressWorker<T>::Signal() const {
4366
- _tsfn.NonBlockingCall(this, WorkProgress_);
4835
+ this->NonBlockingCall(static_cast<T*>(nullptr));
4367
4836
  }
4368
4837
 
4369
4838
  template<class T>
@@ -4376,6 +4845,123 @@ inline void AsyncProgressWorker<T>::ExecutionProgress::Send(const T* data, size_
4376
4845
  _worker->SendProgress_(data, count);
4377
4846
  }
4378
4847
 
4848
+ ////////////////////////////////////////////////////////////////////////////////
4849
+ // Async Progress Queue Worker class
4850
+ ////////////////////////////////////////////////////////////////////////////////
4851
+ template<class T>
4852
+ inline AsyncProgressQueueWorker<T>::AsyncProgressQueueWorker(const Function& callback)
4853
+ : AsyncProgressQueueWorker(callback, "generic") {
4854
+ }
4855
+
4856
+ template<class T>
4857
+ inline AsyncProgressQueueWorker<T>::AsyncProgressQueueWorker(const Function& callback,
4858
+ const char* resource_name)
4859
+ : AsyncProgressQueueWorker(callback, resource_name, Object::New(callback.Env())) {
4860
+ }
4861
+
4862
+ template<class T>
4863
+ inline AsyncProgressQueueWorker<T>::AsyncProgressQueueWorker(const Function& callback,
4864
+ const char* resource_name,
4865
+ const Object& resource)
4866
+ : AsyncProgressQueueWorker(Object::New(callback.Env()),
4867
+ callback,
4868
+ resource_name,
4869
+ resource) {
4870
+ }
4871
+
4872
+ template<class T>
4873
+ inline AsyncProgressQueueWorker<T>::AsyncProgressQueueWorker(const Object& receiver,
4874
+ const Function& callback)
4875
+ : AsyncProgressQueueWorker(receiver, callback, "generic") {
4876
+ }
4877
+
4878
+ template<class T>
4879
+ inline AsyncProgressQueueWorker<T>::AsyncProgressQueueWorker(const Object& receiver,
4880
+ const Function& callback,
4881
+ const char* resource_name)
4882
+ : AsyncProgressQueueWorker(receiver,
4883
+ callback,
4884
+ resource_name,
4885
+ Object::New(callback.Env())) {
4886
+ }
4887
+
4888
+ template<class T>
4889
+ inline AsyncProgressQueueWorker<T>::AsyncProgressQueueWorker(const Object& receiver,
4890
+ const Function& callback,
4891
+ const char* resource_name,
4892
+ const Object& resource)
4893
+ : AsyncProgressWorkerBase<std::pair<T*, size_t>>(receiver, callback, resource_name, resource, /** unlimited queue size */0) {
4894
+ }
4895
+
4896
+ #if NAPI_VERSION > 4
4897
+ template<class T>
4898
+ inline AsyncProgressQueueWorker<T>::AsyncProgressQueueWorker(Napi::Env env)
4899
+ : AsyncProgressQueueWorker(env, "generic") {
4900
+ }
4901
+
4902
+ template<class T>
4903
+ inline AsyncProgressQueueWorker<T>::AsyncProgressQueueWorker(Napi::Env env,
4904
+ const char* resource_name)
4905
+ : AsyncProgressQueueWorker(env, resource_name, Object::New(env)) {
4906
+ }
4907
+
4908
+ template<class T>
4909
+ inline AsyncProgressQueueWorker<T>::AsyncProgressQueueWorker(Napi::Env env,
4910
+ const char* resource_name,
4911
+ const Object& resource)
4912
+ : AsyncProgressWorkerBase<std::pair<T*, size_t>>(env, resource_name, resource, /** unlimited queue size */0) {
4913
+ }
4914
+ #endif
4915
+
4916
+ template<class T>
4917
+ inline void AsyncProgressQueueWorker<T>::Execute() {
4918
+ ExecutionProgress progress(this);
4919
+ Execute(progress);
4920
+ }
4921
+
4922
+ template<class T>
4923
+ inline void AsyncProgressQueueWorker<T>::OnWorkProgress(std::pair<T*, size_t>* datapair) {
4924
+ if (datapair == nullptr) {
4925
+ return;
4926
+ }
4927
+
4928
+ T *data = datapair->first;
4929
+ size_t size = datapair->second;
4930
+
4931
+ this->OnProgress(data, size);
4932
+ delete datapair;
4933
+ delete[] data;
4934
+ }
4935
+
4936
+ template<class T>
4937
+ inline void AsyncProgressQueueWorker<T>::SendProgress_(const T* data, size_t count) {
4938
+ T* new_data = new T[count];
4939
+ std::copy(data, data + count, new_data);
4940
+
4941
+ auto pair = new std::pair<T*, size_t>(new_data, count);
4942
+ this->NonBlockingCall(pair);
4943
+ }
4944
+
4945
+ template<class T>
4946
+ inline void AsyncProgressQueueWorker<T>::Signal() const {
4947
+ this->NonBlockingCall(nullptr);
4948
+ }
4949
+
4950
+ template<class T>
4951
+ inline void AsyncProgressQueueWorker<T>::OnWorkComplete(Napi::Env env, napi_status status) {
4952
+ // Draining queued items in TSFN.
4953
+ AsyncProgressWorkerBase<std::pair<T*, size_t>>::OnWorkComplete(env, status);
4954
+ }
4955
+
4956
+ template<class T>
4957
+ inline void AsyncProgressQueueWorker<T>::ExecutionProgress::Signal() const {
4958
+ _worker->Signal();
4959
+ }
4960
+
4961
+ template<class T>
4962
+ inline void AsyncProgressQueueWorker<T>::ExecutionProgress::Send(const T* data, size_t count) const {
4963
+ _worker->SendProgress_(data, count);
4964
+ }
4379
4965
  #endif
4380
4966
 
4381
4967
  ////////////////////////////////////////////////////////////////////////////////