node-addon-api 2.0.2 → 3.1.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 (82) hide show
  1. package/.clang-format +111 -0
  2. package/.github/workflows/ci.yml +55 -0
  3. package/.github/workflows/linter.yml +24 -0
  4. package/.github/workflows/stale.yml +18 -0
  5. package/.travis.yml +1 -5
  6. package/CHANGELOG.md +237 -23
  7. package/README.md +101 -31
  8. package/appveyor.yml +3 -14
  9. package/benchmark/README.md +47 -0
  10. package/benchmark/binding.gyp +25 -0
  11. package/benchmark/function_args.cc +217 -0
  12. package/benchmark/function_args.js +60 -0
  13. package/benchmark/index.js +34 -0
  14. package/benchmark/property_descriptor.cc +91 -0
  15. package/benchmark/property_descriptor.js +37 -0
  16. package/common.gypi +21 -0
  17. package/doc/addon.md +157 -0
  18. package/doc/array.md +81 -0
  19. package/doc/array_buffer.md +20 -0
  20. package/doc/async_context.md +1 -1
  21. package/doc/async_worker.md +34 -5
  22. package/doc/{async_progress_worker.md → async_worker_variants.md} +236 -23
  23. package/doc/bigint.md +7 -2
  24. package/doc/boolean.md +5 -1
  25. package/doc/buffer.md +4 -0
  26. package/doc/checker-tool.md +1 -1
  27. package/doc/class_property_descriptor.md +3 -3
  28. package/doc/creating_a_release.md +6 -6
  29. package/doc/dataview.md +4 -0
  30. package/doc/date.md +2 -2
  31. package/doc/env.md +69 -0
  32. package/doc/error.md +5 -0
  33. package/doc/escapable_handle_scope.md +1 -1
  34. package/doc/external.md +4 -0
  35. package/doc/function.md +111 -3
  36. package/doc/function_reference.md +1 -1
  37. package/doc/handle_scope.md +1 -1
  38. package/doc/hierarchy.md +91 -0
  39. package/doc/instance_wrap.md +408 -0
  40. package/doc/name.md +29 -0
  41. package/doc/number.md +1 -1
  42. package/doc/object.md +44 -1
  43. package/doc/object_lifetime_management.md +2 -2
  44. package/doc/object_reference.md +1 -1
  45. package/doc/object_wrap.md +220 -216
  46. package/doc/prebuild_tools.md +2 -2
  47. package/doc/promises.md +5 -0
  48. package/doc/property_descriptor.md +67 -12
  49. package/doc/setup.md +1 -2
  50. package/doc/string.md +5 -1
  51. package/doc/symbol.md +5 -1
  52. package/doc/threadsafe.md +121 -0
  53. package/doc/threadsafe_function.md +16 -46
  54. package/doc/typed_array.md +4 -0
  55. package/doc/typed_array_of.md +4 -0
  56. package/doc/typed_threadsafe_function.md +307 -0
  57. package/doc/value.md +166 -104
  58. package/doc/version_management.md +2 -2
  59. package/except.gypi +16 -0
  60. package/index.js +7 -41
  61. package/napi-inl.h +1685 -464
  62. package/napi.h +606 -141
  63. package/node_api.gyp +9 -0
  64. package/noexcept.gypi +16 -0
  65. package/{src/nothing.c → nothing.c} +0 -0
  66. package/package-support.json +21 -0
  67. package/package.json +106 -2
  68. package/tools/README.md +12 -6
  69. package/tools/clang-format.js +47 -0
  70. package/tools/conversion.js +4 -8
  71. package/doc/Doxyfile +0 -2450
  72. package/doc/basic_types.md +0 -423
  73. package/doc/working_with_javascript_values.md +0 -14
  74. package/external-napi/node_api.h +0 -7
  75. package/src/node_api.cc +0 -3655
  76. package/src/node_api.gyp +0 -21
  77. package/src/node_api.h +0 -588
  78. package/src/node_api_types.h +0 -115
  79. package/src/node_internals.cc +0 -142
  80. package/src/node_internals.h +0 -157
  81. package/src/util-inl.h +0 -38
  82. 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
@@ -85,6 +82,24 @@ inline napi_value WrapCallback(Callable callback) {
85
82
  #endif // NAPI_CPP_EXCEPTIONS
86
83
  }
87
84
 
85
+ // For use in JS to C++ void callback wrappers to catch any Napi::Error
86
+ // exceptions and rethrow them as JavaScript exceptions before returning from the
87
+ // callback.
88
+ template <typename Callable>
89
+ inline void WrapVoidCallback(Callable callback) {
90
+ #ifdef NAPI_CPP_EXCEPTIONS
91
+ try {
92
+ callback();
93
+ } catch (const Error& e) {
94
+ e.ThrowAsJavaScriptException();
95
+ }
96
+ #else // NAPI_CPP_EXCEPTIONS
97
+ // When C++ exceptions are disabled, errors are immediately thrown as JS
98
+ // exceptions, so there is no need to catch and rethrow them here.
99
+ callback();
100
+ #endif // NAPI_CPP_EXCEPTIONS
101
+ }
102
+
88
103
  template <typename Callable, typename Return>
89
104
  struct CallbackData {
90
105
  static inline
@@ -120,27 +135,73 @@ struct CallbackData<Callable, void> {
120
135
  void* data;
121
136
  };
122
137
 
138
+ template <void (*Callback)(const CallbackInfo& info)>
139
+ static napi_value
140
+ TemplatedVoidCallback(napi_env env, napi_callback_info info) NAPI_NOEXCEPT {
141
+ return details::WrapCallback([&] {
142
+ CallbackInfo cbInfo(env, info);
143
+ Callback(cbInfo);
144
+ return nullptr;
145
+ });
146
+ }
147
+
148
+ template <Napi::Value (*Callback)(const CallbackInfo& info)>
149
+ static napi_value
150
+ TemplatedCallback(napi_env env, napi_callback_info info) NAPI_NOEXCEPT {
151
+ return details::WrapCallback([&] {
152
+ CallbackInfo cbInfo(env, info);
153
+ return Callback(cbInfo);
154
+ });
155
+ }
156
+
157
+ template <typename T,
158
+ Napi::Value (T::*UnwrapCallback)(const CallbackInfo& info)>
159
+ static napi_value
160
+ TemplatedInstanceCallback(napi_env env, napi_callback_info info) NAPI_NOEXCEPT {
161
+ return details::WrapCallback([&] {
162
+ CallbackInfo cbInfo(env, info);
163
+ T* instance = T::Unwrap(cbInfo.This().As<Object>());
164
+ return (instance->*UnwrapCallback)(cbInfo);
165
+ });
166
+ }
167
+
168
+ template <typename T, void (T::*UnwrapCallback)(const CallbackInfo& info)>
169
+ static napi_value
170
+ TemplatedInstanceVoidCallback(napi_env env,
171
+ napi_callback_info info) NAPI_NOEXCEPT {
172
+ return details::WrapCallback([&] {
173
+ CallbackInfo cbInfo(env, info);
174
+ T* instance = T::Unwrap(cbInfo.This().As<Object>());
175
+ (instance->*UnwrapCallback)(cbInfo);
176
+ return nullptr;
177
+ });
178
+ }
179
+
123
180
  template <typename T, typename Finalizer, typename Hint = void>
124
181
  struct FinalizeData {
125
182
  static inline
126
- void Wrapper(napi_env env, void* data, void* finalizeHint) {
127
- FinalizeData* finalizeData = static_cast<FinalizeData*>(finalizeHint);
128
- finalizeData->callback(Env(env), static_cast<T*>(data));
129
- delete finalizeData;
183
+ void Wrapper(napi_env env, void* data, void* finalizeHint) noexcept {
184
+ WrapVoidCallback([&] {
185
+ FinalizeData* finalizeData = static_cast<FinalizeData*>(finalizeHint);
186
+ finalizeData->callback(Env(env), static_cast<T*>(data));
187
+ delete finalizeData;
188
+ });
130
189
  }
131
190
 
132
191
  static inline
133
- void WrapperWithHint(napi_env env, void* data, void* finalizeHint) {
134
- FinalizeData* finalizeData = static_cast<FinalizeData*>(finalizeHint);
135
- finalizeData->callback(Env(env), static_cast<T*>(data), finalizeData->hint);
136
- delete finalizeData;
192
+ void WrapperWithHint(napi_env env, void* data, void* finalizeHint) noexcept {
193
+ WrapVoidCallback([&] {
194
+ FinalizeData* finalizeData = static_cast<FinalizeData*>(finalizeHint);
195
+ finalizeData->callback(Env(env), static_cast<T*>(data), finalizeData->hint);
196
+ delete finalizeData;
197
+ });
137
198
  }
138
199
 
139
200
  Finalizer callback;
140
201
  Hint* hint;
141
202
  };
142
203
 
143
- #if (NAPI_VERSION > 3)
204
+ #if (NAPI_VERSION > 3 && !defined(__wasm32__))
144
205
  template <typename ContextType=void,
145
206
  typename Finalizer=std::function<void(Env, void*, ContextType*)>,
146
207
  typename FinalizerDataType=void>
@@ -153,9 +214,6 @@ struct ThreadSafeFinalize {
153
214
  ThreadSafeFinalize* finalizeData =
154
215
  static_cast<ThreadSafeFinalize*>(rawFinalizeData);
155
216
  finalizeData->callback(Env(env));
156
- if (finalizeData->tsfn) {
157
- *finalizeData->tsfn = nullptr;
158
- }
159
217
  delete finalizeData;
160
218
  }
161
219
 
@@ -169,9 +227,6 @@ struct ThreadSafeFinalize {
169
227
  ThreadSafeFinalize* finalizeData =
170
228
  static_cast<ThreadSafeFinalize*>(rawFinalizeData);
171
229
  finalizeData->callback(Env(env), finalizeData->data);
172
- if (finalizeData->tsfn) {
173
- *finalizeData->tsfn = nullptr;
174
- }
175
230
  delete finalizeData;
176
231
  }
177
232
 
@@ -185,9 +240,6 @@ struct ThreadSafeFinalize {
185
240
  ThreadSafeFinalize* finalizeData =
186
241
  static_cast<ThreadSafeFinalize*>(rawFinalizeData);
187
242
  finalizeData->callback(Env(env), static_cast<ContextType*>(rawContext));
188
- if (finalizeData->tsfn) {
189
- *finalizeData->tsfn = nullptr;
190
- }
191
243
  delete finalizeData;
192
244
  }
193
245
 
@@ -202,17 +254,52 @@ struct ThreadSafeFinalize {
202
254
  static_cast<ThreadSafeFinalize*>(rawFinalizeData);
203
255
  finalizeData->callback(Env(env), finalizeData->data,
204
256
  static_cast<ContextType*>(rawContext));
205
- if (finalizeData->tsfn) {
206
- *finalizeData->tsfn = nullptr;
207
- }
208
257
  delete finalizeData;
209
258
  }
210
259
 
211
260
  FinalizerDataType* data;
212
261
  Finalizer callback;
213
- napi_threadsafe_function* tsfn;
214
262
  };
215
- #endif
263
+
264
+ template <typename ContextType, typename DataType, typename CallJs, CallJs call>
265
+ typename std::enable_if<call != nullptr>::type static inline CallJsWrapper(
266
+ napi_env env, napi_value jsCallback, void* context, void* data) {
267
+ call(env,
268
+ Function(env, jsCallback),
269
+ static_cast<ContextType*>(context),
270
+ static_cast<DataType*>(data));
271
+ }
272
+
273
+ template <typename ContextType, typename DataType, typename CallJs, CallJs call>
274
+ typename std::enable_if<call == nullptr>::type static inline CallJsWrapper(
275
+ napi_env env, napi_value jsCallback, void* /*context*/, void* /*data*/) {
276
+ if (jsCallback != nullptr) {
277
+ Function(env, jsCallback).Call(0, nullptr);
278
+ }
279
+ }
280
+
281
+ #if NAPI_VERSION > 4
282
+
283
+ template <typename CallbackType, typename TSFN>
284
+ napi_value DefaultCallbackWrapper(napi_env /*env*/, std::nullptr_t /*cb*/) {
285
+ return nullptr;
286
+ }
287
+
288
+ template <typename CallbackType, typename TSFN>
289
+ napi_value DefaultCallbackWrapper(napi_env /*env*/, Napi::Function cb) {
290
+ return cb;
291
+ }
292
+
293
+ #else
294
+ template <typename CallbackType, typename TSFN>
295
+ napi_value DefaultCallbackWrapper(napi_env env, Napi::Function cb) {
296
+ if (cb.IsEmpty()) {
297
+ return TSFN::EmptyFunctionFactory(env);
298
+ }
299
+ return cb;
300
+ }
301
+ #endif // NAPI_VERSION > 4
302
+ #endif // NAPI_VERSION > 3 && !defined(__wasm32__)
216
303
 
217
304
  template <typename Getter, typename Setter>
218
305
  struct AccessorCallbackData {
@@ -254,30 +341,34 @@ struct AccessorCallbackData {
254
341
  // Module registration
255
342
  ////////////////////////////////////////////////////////////////////////////////
256
343
 
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
- } \
344
+ // Register an add-on based on an initializer function.
345
+ #define NODE_API_MODULE(modname, regfunc) \
346
+ napi_value __napi_ ## regfunc(napi_env env, \
347
+ napi_value exports) { \
348
+ return Napi::RegisterModule(env, exports, regfunc); \
349
+ } \
267
350
  NAPI_MODULE(modname, __napi_ ## regfunc)
268
351
 
352
+ // Register an add-on based on a subclass of `Addon<T>` with a custom Node.js
353
+ // module name.
354
+ #define NODE_API_NAMED_ADDON(modname, classname) \
355
+ static napi_value __napi_ ## classname(napi_env env, \
356
+ napi_value exports) { \
357
+ return Napi::RegisterModule(env, exports, &classname::Init); \
358
+ } \
359
+ NAPI_MODULE(modname, __napi_ ## classname)
360
+
361
+ // Register an add-on based on a subclass of `Addon<T>` with the Node.js module
362
+ // name given by node-gyp from the `target_name` in binding.gyp.
363
+ #define NODE_API_ADDON(classname) \
364
+ NODE_API_NAMED_ADDON(NODE_GYP_MODULE_NAME, classname)
365
+
269
366
  // Adapt the NAPI_MODULE registration function:
270
367
  // - Wrap the arguments in NAPI wrappers.
271
368
  // - Catch any NAPI errors and rethrow as JS exceptions.
272
369
  inline napi_value RegisterModule(napi_env env,
273
370
  napi_value exports,
274
371
  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
372
  return details::WrapCallback([&] {
282
373
  return napi_value(registerCallback(Napi::Env(env),
283
374
  Napi::Object(env, exports)));
@@ -333,6 +424,64 @@ inline Error Env::GetAndClearPendingException() {
333
424
  return Error(_env, value);
334
425
  }
335
426
 
427
+ inline Value Env::RunScript(const char* utf8script) {
428
+ String script = String::New(_env, utf8script);
429
+ return RunScript(script);
430
+ }
431
+
432
+ inline Value Env::RunScript(const std::string& utf8script) {
433
+ return RunScript(utf8script.c_str());
434
+ }
435
+
436
+ inline Value Env::RunScript(String script) {
437
+ napi_value result;
438
+ napi_status status = napi_run_script(_env, script, &result);
439
+ NAPI_THROW_IF_FAILED(_env, status, Undefined());
440
+ return Value(_env, result);
441
+ }
442
+
443
+ #if NAPI_VERSION > 5
444
+ template <typename T, Env::Finalizer<T> fini>
445
+ inline void Env::SetInstanceData(T* data) {
446
+ napi_status status =
447
+ napi_set_instance_data(_env, data, [](napi_env env, void* data, void*) {
448
+ fini(env, static_cast<T*>(data));
449
+ }, nullptr);
450
+ NAPI_THROW_IF_FAILED_VOID(_env, status);
451
+ }
452
+
453
+ template <typename DataType,
454
+ typename HintType,
455
+ Napi::Env::FinalizerWithHint<DataType, HintType> fini>
456
+ inline void Env::SetInstanceData(DataType* data, HintType* hint) {
457
+ napi_status status =
458
+ napi_set_instance_data(_env, data,
459
+ [](napi_env env, void* data, void* hint) {
460
+ fini(env, static_cast<DataType*>(data), static_cast<HintType*>(hint));
461
+ }, hint);
462
+ NAPI_THROW_IF_FAILED_VOID(_env, status);
463
+ }
464
+
465
+ template <typename T>
466
+ inline T* Env::GetInstanceData() {
467
+ void* data = nullptr;
468
+
469
+ napi_status status = napi_get_instance_data(_env, &data);
470
+ NAPI_THROW_IF_FAILED(_env, status, nullptr);
471
+
472
+ return static_cast<T*>(data);
473
+ }
474
+
475
+ template <typename T> void Env::DefaultFini(Env, T* data) {
476
+ delete data;
477
+ }
478
+
479
+ template <typename DataType, typename HintType>
480
+ void Env::DefaultFiniWithHint(Env, DataType* data, HintType*) {
481
+ delete data;
482
+ }
483
+ #endif // NAPI_VERSION > 5
484
+
336
485
  ////////////////////////////////////////////////////////////////////////////////
337
486
  // Value class
338
487
  ////////////////////////////////////////////////////////////////////////////////
@@ -397,14 +546,11 @@ inline bool Value::IsNumber() const {
397
546
  return Type() == napi_number;
398
547
  }
399
548
 
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
549
+ #if NAPI_VERSION > 5
404
550
  inline bool Value::IsBigInt() const {
405
551
  return Type() == napi_bigint;
406
552
  }
407
- #endif // NAPI_EXPERIMENTAL
553
+ #endif // NAPI_VERSION > 5
408
554
 
409
555
  #if (NAPI_VERSION > 4)
410
556
  inline bool Value::IsDate() const {
@@ -635,10 +781,7 @@ inline double Number::DoubleValue() const {
635
781
  return result;
636
782
  }
637
783
 
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
784
+ #if NAPI_VERSION > 5
642
785
  ////////////////////////////////////////////////////////////////////////////////
643
786
  // BigInt Class
644
787
  ////////////////////////////////////////////////////////////////////////////////
@@ -699,7 +842,7 @@ inline void BigInt::ToWords(int* sign_bit, size_t* word_count, uint64_t* words)
699
842
  _env, _value, sign_bit, word_count, words);
700
843
  NAPI_THROW_IF_FAILED_VOID(_env, status);
701
844
  }
702
- #endif // NAPI_EXPERIMENTAL
845
+ #endif // NAPI_VERSION > 5
703
846
 
704
847
  #if (NAPI_VERSION > 4)
705
848
  ////////////////////////////////////////////////////////////////////////////////
@@ -1344,7 +1487,7 @@ inline ArrayBuffer ArrayBuffer::New(napi_env env, size_t byteLength) {
1344
1487
  napi_status status = napi_create_arraybuffer(env, byteLength, &data, &value);
1345
1488
  NAPI_THROW_IF_FAILED(env, status, ArrayBuffer());
1346
1489
 
1347
- return ArrayBuffer(env, value, data, byteLength);
1490
+ return ArrayBuffer(env, value);
1348
1491
  }
1349
1492
 
1350
1493
  inline ArrayBuffer ArrayBuffer::New(napi_env env,
@@ -1355,7 +1498,7 @@ inline ArrayBuffer ArrayBuffer::New(napi_env env,
1355
1498
  env, externalData, byteLength, nullptr, nullptr, &value);
1356
1499
  NAPI_THROW_IF_FAILED(env, status, ArrayBuffer());
1357
1500
 
1358
- return ArrayBuffer(env, value, externalData, byteLength);
1501
+ return ArrayBuffer(env, value);
1359
1502
  }
1360
1503
 
1361
1504
  template <typename Finalizer>
@@ -1378,7 +1521,7 @@ inline ArrayBuffer ArrayBuffer::New(napi_env env,
1378
1521
  NAPI_THROW_IF_FAILED(env, status, ArrayBuffer());
1379
1522
  }
1380
1523
 
1381
- return ArrayBuffer(env, value, externalData, byteLength);
1524
+ return ArrayBuffer(env, value);
1382
1525
  }
1383
1526
 
1384
1527
  template <typename Finalizer, typename Hint>
@@ -1402,39 +1545,43 @@ inline ArrayBuffer ArrayBuffer::New(napi_env env,
1402
1545
  NAPI_THROW_IF_FAILED(env, status, ArrayBuffer());
1403
1546
  }
1404
1547
 
1405
- return ArrayBuffer(env, value, externalData, byteLength);
1548
+ return ArrayBuffer(env, value);
1406
1549
  }
1407
1550
 
1408
- inline ArrayBuffer::ArrayBuffer() : Object(), _data(nullptr), _length(0) {
1551
+ inline ArrayBuffer::ArrayBuffer() : Object() {
1409
1552
  }
1410
1553
 
1411
1554
  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) {
1555
+ : Object(env, value) {
1417
1556
  }
1418
1557
 
1419
1558
  inline void* ArrayBuffer::Data() {
1420
- EnsureInfo();
1421
- return _data;
1559
+ void* data;
1560
+ napi_status status = napi_get_arraybuffer_info(_env, _value, &data, nullptr);
1561
+ NAPI_THROW_IF_FAILED(_env, status, nullptr);
1562
+ return data;
1422
1563
  }
1423
1564
 
1424
1565
  inline size_t ArrayBuffer::ByteLength() {
1425
- EnsureInfo();
1426
- return _length;
1566
+ size_t length;
1567
+ napi_status status = napi_get_arraybuffer_info(_env, _value, nullptr, &length);
1568
+ NAPI_THROW_IF_FAILED(_env, status, 0);
1569
+ return length;
1427
1570
  }
1428
1571
 
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
- }
1572
+ #if NAPI_VERSION >= 7
1573
+ inline bool ArrayBuffer::IsDetached() const {
1574
+ bool detached;
1575
+ napi_status status = napi_is_detached_arraybuffer(_env, _value, &detached);
1576
+ NAPI_THROW_IF_FAILED(_env, status, false);
1577
+ return detached;
1578
+ }
1579
+
1580
+ inline void ArrayBuffer::Detach() {
1581
+ napi_status status = napi_detach_arraybuffer(_env, _value);
1582
+ NAPI_THROW_IF_FAILED_VOID(_env, status);
1437
1583
  }
1584
+ #endif // NAPI_VERSION >= 7
1438
1585
 
1439
1586
  ////////////////////////////////////////////////////////////////////////////////
1440
1587
  // DataView class
@@ -1649,6 +1796,10 @@ inline uint8_t TypedArray::ElementSize() const {
1649
1796
  case napi_float32_array:
1650
1797
  return 4;
1651
1798
  case napi_float64_array:
1799
+ #if (NAPI_VERSION > 5)
1800
+ case napi_bigint64_array:
1801
+ case napi_biguint64_array:
1802
+ #endif // (NAPI_VERSION > 5)
1652
1803
  return 8;
1653
1804
  default:
1654
1805
  return 0;
@@ -1721,8 +1872,14 @@ inline TypedArrayOf<T>::TypedArrayOf() : TypedArray(), _data(nullptr) {
1721
1872
  template <typename T>
1722
1873
  inline TypedArrayOf<T>::TypedArrayOf(napi_env env, napi_value value)
1723
1874
  : TypedArray(env, value), _data(nullptr) {
1724
- napi_status status = napi_get_typedarray_info(
1725
- _env, _value, &_type, &_length, reinterpret_cast<void**>(&_data), nullptr, nullptr);
1875
+ napi_status status = napi_ok;
1876
+ if (value != nullptr) {
1877
+ status = napi_get_typedarray_info(
1878
+ _env, _value, &_type, &_length, reinterpret_cast<void**>(&_data), nullptr, nullptr);
1879
+ } else {
1880
+ _type = TypedArrayTypeForPrimitiveType<T>();
1881
+ _length = 0;
1882
+ }
1726
1883
  NAPI_THROW_IF_FAILED_VOID(_env, status);
1727
1884
  }
1728
1885
 
@@ -1780,6 +1937,46 @@ CreateFunction(napi_env env,
1780
1937
  return status;
1781
1938
  }
1782
1939
 
1940
+ template <Function::VoidCallback cb>
1941
+ inline Function Function::New(napi_env env, const char* utf8name, void* data) {
1942
+ napi_value result = nullptr;
1943
+ napi_status status = napi_create_function(env,
1944
+ utf8name,
1945
+ NAPI_AUTO_LENGTH,
1946
+ details::TemplatedVoidCallback<cb>,
1947
+ data,
1948
+ &result);
1949
+ NAPI_THROW_IF_FAILED(env, status, Function());
1950
+ return Function(env, result);
1951
+ }
1952
+
1953
+ template <Function::Callback cb>
1954
+ inline Function Function::New(napi_env env, const char* utf8name, void* data) {
1955
+ napi_value result = nullptr;
1956
+ napi_status status = napi_create_function(env,
1957
+ utf8name,
1958
+ NAPI_AUTO_LENGTH,
1959
+ details::TemplatedCallback<cb>,
1960
+ data,
1961
+ &result);
1962
+ NAPI_THROW_IF_FAILED(env, status, Function());
1963
+ return Function(env, result);
1964
+ }
1965
+
1966
+ template <Function::VoidCallback cb>
1967
+ inline Function Function::New(napi_env env,
1968
+ const std::string& utf8name,
1969
+ void* data) {
1970
+ return Function::New<cb>(env, utf8name.c_str(), data);
1971
+ }
1972
+
1973
+ template <Function::Callback cb>
1974
+ inline Function Function::New(napi_env env,
1975
+ const std::string& utf8name,
1976
+ void* data) {
1977
+ return Function::New<cb>(env, utf8name.c_str(), data);
1978
+ }
1979
+
1783
1980
  template <typename Callable>
1784
1981
  inline Function Function::New(napi_env env,
1785
1982
  Callable cb,
@@ -2051,12 +2248,19 @@ inline void Buffer<T>::EnsureInfo() const {
2051
2248
  inline Error Error::New(napi_env env) {
2052
2249
  napi_status status;
2053
2250
  napi_value error = nullptr;
2054
-
2251
+ bool is_exception_pending;
2055
2252
  const napi_extended_error_info* info;
2253
+
2254
+ // We must retrieve the last error info before doing anything else, because
2255
+ // doing anything else will replace the last error info.
2056
2256
  status = napi_get_last_error_info(env, &info);
2057
2257
  NAPI_FATAL_IF_FAILED(status, "Error::New", "napi_get_last_error_info");
2058
2258
 
2059
- if (info->error_code == napi_pending_exception) {
2259
+ status = napi_is_exception_pending(env, &is_exception_pending);
2260
+ NAPI_FATAL_IF_FAILED(status, "Error::New", "napi_is_exception_pending");
2261
+
2262
+ // A pending exception takes precedence over any internal error status.
2263
+ if (is_exception_pending) {
2060
2264
  status = napi_get_and_clear_last_exception(env, &error);
2061
2265
  NAPI_FATAL_IF_FAILED(status, "Error::New", "napi_get_and_clear_last_exception");
2062
2266
  }
@@ -2064,15 +2268,6 @@ inline Error Error::New(napi_env env) {
2064
2268
  const char* error_message = info->error_message != nullptr ?
2065
2269
  info->error_message : "Error in native callback";
2066
2270
 
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
2271
  napi_value message;
2077
2272
  status = napi_create_string_utf8(
2078
2273
  env,
@@ -2134,7 +2329,7 @@ inline Error& Error::operator =(Error&& other) {
2134
2329
  inline Error::Error(const Error& other) : ObjectReference(other) {
2135
2330
  }
2136
2331
 
2137
- inline Error& Error::operator =(Error& other) {
2332
+ inline Error& Error::operator =(const Error& other) {
2138
2333
  Reset();
2139
2334
 
2140
2335
  _env = other.Env();
@@ -2746,6 +2941,91 @@ inline void CallbackInfo::SetData(void* data) {
2746
2941
  // PropertyDescriptor class
2747
2942
  ////////////////////////////////////////////////////////////////////////////////
2748
2943
 
2944
+ template <typename PropertyDescriptor::GetterCallback Getter>
2945
+ PropertyDescriptor
2946
+ PropertyDescriptor::Accessor(const char* utf8name,
2947
+ napi_property_attributes attributes,
2948
+ void* data) {
2949
+ napi_property_descriptor desc = napi_property_descriptor();
2950
+
2951
+ desc.utf8name = utf8name;
2952
+ desc.getter = details::TemplatedCallback<Getter>;
2953
+ desc.attributes = attributes;
2954
+ desc.data = data;
2955
+
2956
+ return desc;
2957
+ }
2958
+
2959
+ template <typename PropertyDescriptor::GetterCallback Getter>
2960
+ PropertyDescriptor
2961
+ PropertyDescriptor::Accessor(const std::string& utf8name,
2962
+ napi_property_attributes attributes,
2963
+ void* data) {
2964
+ return Accessor<Getter>(utf8name.c_str(), attributes, data);
2965
+ }
2966
+
2967
+ template <typename PropertyDescriptor::GetterCallback Getter>
2968
+ PropertyDescriptor
2969
+ PropertyDescriptor::Accessor(Name name,
2970
+ napi_property_attributes attributes,
2971
+ void* data) {
2972
+ napi_property_descriptor desc = napi_property_descriptor();
2973
+
2974
+ desc.name = name;
2975
+ desc.getter = details::TemplatedCallback<Getter>;
2976
+ desc.attributes = attributes;
2977
+ desc.data = data;
2978
+
2979
+ return desc;
2980
+ }
2981
+
2982
+ template <
2983
+ typename PropertyDescriptor::GetterCallback Getter,
2984
+ typename PropertyDescriptor::SetterCallback Setter>
2985
+ PropertyDescriptor
2986
+ PropertyDescriptor::Accessor(const char* utf8name,
2987
+ napi_property_attributes attributes,
2988
+ void* data) {
2989
+
2990
+ napi_property_descriptor desc = napi_property_descriptor();
2991
+
2992
+ desc.utf8name = utf8name;
2993
+ desc.getter = details::TemplatedCallback<Getter>;
2994
+ desc.setter = details::TemplatedVoidCallback<Setter>;
2995
+ desc.attributes = attributes;
2996
+ desc.data = data;
2997
+
2998
+ return desc;
2999
+ }
3000
+
3001
+ template <
3002
+ typename PropertyDescriptor::GetterCallback Getter,
3003
+ typename PropertyDescriptor::SetterCallback Setter>
3004
+ PropertyDescriptor
3005
+ PropertyDescriptor::Accessor(const std::string& utf8name,
3006
+ napi_property_attributes attributes,
3007
+ void* data) {
3008
+ return Accessor<Getter, Setter>(utf8name.c_str(), attributes, data);
3009
+ }
3010
+
3011
+ template <
3012
+ typename PropertyDescriptor::GetterCallback Getter,
3013
+ typename PropertyDescriptor::SetterCallback Setter>
3014
+ PropertyDescriptor
3015
+ PropertyDescriptor::Accessor(Name name,
3016
+ napi_property_attributes attributes,
3017
+ void* data) {
3018
+ napi_property_descriptor desc = napi_property_descriptor();
3019
+
3020
+ desc.name = name;
3021
+ desc.getter = details::TemplatedCallback<Getter>;
3022
+ desc.setter = details::TemplatedVoidCallback<Setter>;
3023
+ desc.attributes = attributes;
3024
+ desc.data = data;
3025
+
3026
+ return desc;
3027
+ }
3028
+
2749
3029
  template <typename Getter>
2750
3030
  inline PropertyDescriptor
2751
3031
  PropertyDescriptor::Accessor(Napi::Env env,
@@ -2973,90 +3253,400 @@ inline PropertyDescriptor::operator const napi_property_descriptor&() const {
2973
3253
  }
2974
3254
 
2975
3255
  ////////////////////////////////////////////////////////////////////////////////
2976
- // ObjectWrap<T> class
3256
+ // InstanceWrap<T> class
2977
3257
  ////////////////////////////////////////////////////////////////////////////////
2978
3258
 
2979
3259
  template <typename T>
2980
- inline ObjectWrap<T>::ObjectWrap(const Napi::CallbackInfo& callbackInfo) {
2981
- napi_env env = callbackInfo.Env();
2982
- napi_value wrapper = callbackInfo.This();
3260
+ inline void InstanceWrap<T>::AttachPropData(napi_env env,
3261
+ napi_value value,
3262
+ const napi_property_descriptor* prop) {
2983
3263
  napi_status status;
2984
- napi_ref ref;
2985
- status = napi_wrap(env, wrapper, this, FinalizeCallback, nullptr, &ref);
2986
- NAPI_THROW_IF_FAILED_VOID(env, status);
2987
-
2988
- Reference<Object>* instanceRef = this;
2989
- *instanceRef = Reference<Object>(env, ref);
3264
+ if (prop->method != nullptr && !(prop->attributes & napi_static)) {
3265
+ if (prop->method == T::InstanceVoidMethodCallbackWrapper) {
3266
+ status = Napi::details::AttachData(env,
3267
+ value,
3268
+ static_cast<InstanceVoidMethodCallbackData*>(prop->data));
3269
+ NAPI_THROW_IF_FAILED_VOID(env, status);
3270
+ } else if (prop->method == T::InstanceMethodCallbackWrapper) {
3271
+ status = Napi::details::AttachData(env,
3272
+ value,
3273
+ static_cast<InstanceMethodCallbackData*>(prop->data));
3274
+ NAPI_THROW_IF_FAILED_VOID(env, status);
3275
+ } else if (prop->getter == T::InstanceGetterCallbackWrapper ||
3276
+ prop->setter == T::InstanceSetterCallbackWrapper) {
3277
+ status = Napi::details::AttachData(env,
3278
+ value,
3279
+ static_cast<InstanceAccessorCallbackData*>(prop->data));
3280
+ NAPI_THROW_IF_FAILED_VOID(env, status);
3281
+ }
3282
+ }
2990
3283
  }
2991
3284
 
2992
3285
  template <typename T>
2993
- inline ObjectWrap<T>::~ObjectWrap() {
2994
- // If the JS object still exists at this point, remove the finalizer added
2995
- // through `napi_wrap()`.
2996
- if (!IsEmpty()) {
2997
- Object object = Value();
2998
- // It is not valid to call `napi_remove_wrap()` with an empty `object`.
2999
- // This happens e.g. during garbage collection.
3000
- if (!object.IsEmpty() && _construction_failed) {
3001
- napi_remove_wrap(Env(), object, nullptr);
3286
+ inline ClassPropertyDescriptor<T> InstanceWrap<T>::InstanceMethod(
3287
+ const char* utf8name,
3288
+ InstanceVoidMethodCallback method,
3289
+ napi_property_attributes attributes,
3290
+ void* data) {
3291
+ InstanceVoidMethodCallbackData* callbackData =
3292
+ new InstanceVoidMethodCallbackData({ method, data});
3002
3293
 
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
- }
3013
- }
3294
+ napi_property_descriptor desc = napi_property_descriptor();
3295
+ desc.utf8name = utf8name;
3296
+ desc.method = T::InstanceVoidMethodCallbackWrapper;
3297
+ desc.data = callbackData;
3298
+ desc.attributes = attributes;
3299
+ return desc;
3014
3300
  }
3015
3301
 
3016
- template<typename T>
3017
- inline T* ObjectWrap<T>::Unwrap(Object wrapper) {
3018
- T* unwrapped;
3019
- napi_status status = napi_unwrap(wrapper.Env(), wrapper, reinterpret_cast<void**>(&unwrapped));
3020
- NAPI_THROW_IF_FAILED(wrapper.Env(), status, nullptr);
3021
- return unwrapped;
3302
+ template <typename T>
3303
+ inline ClassPropertyDescriptor<T> InstanceWrap<T>::InstanceMethod(
3304
+ const char* utf8name,
3305
+ InstanceMethodCallback method,
3306
+ napi_property_attributes attributes,
3307
+ void* data) {
3308
+ InstanceMethodCallbackData* callbackData = new InstanceMethodCallbackData({ method, data });
3309
+
3310
+ napi_property_descriptor desc = napi_property_descriptor();
3311
+ desc.utf8name = utf8name;
3312
+ desc.method = T::InstanceMethodCallbackWrapper;
3313
+ desc.data = callbackData;
3314
+ desc.attributes = attributes;
3315
+ return desc;
3022
3316
  }
3023
3317
 
3024
3318
  template <typename T>
3025
- inline Function
3026
- ObjectWrap<T>::DefineClass(Napi::Env env,
3027
- const char* utf8name,
3028
- const size_t props_count,
3029
- const napi_property_descriptor* descriptors,
3030
- void* data) {
3031
- napi_status status;
3032
- std::vector<napi_property_descriptor> props(props_count);
3319
+ inline ClassPropertyDescriptor<T> InstanceWrap<T>::InstanceMethod(
3320
+ Symbol name,
3321
+ InstanceVoidMethodCallback method,
3322
+ napi_property_attributes attributes,
3323
+ void* data) {
3324
+ InstanceVoidMethodCallbackData* callbackData =
3325
+ new InstanceVoidMethodCallbackData({ method, data});
3033
3326
 
3034
- // We copy the descriptors to a local array because before defining the class
3035
- // we must replace static method property descriptors with value property
3036
- // descriptors such that the value is a function-valued `napi_value` created
3037
- // with `CreateFunction()`.
3038
- //
3039
- // This replacement could be made for instance methods as well, but V8 aborts
3040
- // if we do that, because it expects methods defined on the prototype template
3041
- // to have `FunctionTemplate`s.
3327
+ napi_property_descriptor desc = napi_property_descriptor();
3328
+ desc.name = name;
3329
+ desc.method = T::InstanceVoidMethodCallbackWrapper;
3330
+ desc.data = callbackData;
3331
+ desc.attributes = attributes;
3332
+ return desc;
3333
+ }
3334
+
3335
+ template <typename T>
3336
+ inline ClassPropertyDescriptor<T> InstanceWrap<T>::InstanceMethod(
3337
+ Symbol name,
3338
+ InstanceMethodCallback method,
3339
+ napi_property_attributes attributes,
3340
+ void* data) {
3341
+ InstanceMethodCallbackData* callbackData = new InstanceMethodCallbackData({ method, data });
3342
+
3343
+ napi_property_descriptor desc = napi_property_descriptor();
3344
+ desc.name = name;
3345
+ desc.method = T::InstanceMethodCallbackWrapper;
3346
+ desc.data = callbackData;
3347
+ desc.attributes = attributes;
3348
+ return desc;
3349
+ }
3350
+
3351
+ template <typename T>
3352
+ template <typename InstanceWrap<T>::InstanceVoidMethodCallback method>
3353
+ inline ClassPropertyDescriptor<T> InstanceWrap<T>::InstanceMethod(
3354
+ const char* utf8name,
3355
+ napi_property_attributes attributes,
3356
+ void* data) {
3357
+ napi_property_descriptor desc = napi_property_descriptor();
3358
+ desc.utf8name = utf8name;
3359
+ desc.method = details::TemplatedInstanceVoidCallback<T, method>;
3360
+ desc.data = data;
3361
+ desc.attributes = attributes;
3362
+ return desc;
3363
+ }
3364
+
3365
+ template <typename T>
3366
+ template <typename InstanceWrap<T>::InstanceMethodCallback method>
3367
+ inline ClassPropertyDescriptor<T> InstanceWrap<T>::InstanceMethod(
3368
+ const char* utf8name,
3369
+ napi_property_attributes attributes,
3370
+ void* data) {
3371
+ napi_property_descriptor desc = napi_property_descriptor();
3372
+ desc.utf8name = utf8name;
3373
+ desc.method = details::TemplatedInstanceCallback<T, method>;
3374
+ desc.data = data;
3375
+ desc.attributes = attributes;
3376
+ return desc;
3377
+ }
3378
+
3379
+ template <typename T>
3380
+ template <typename InstanceWrap<T>::InstanceVoidMethodCallback method>
3381
+ inline ClassPropertyDescriptor<T> InstanceWrap<T>::InstanceMethod(
3382
+ Symbol name,
3383
+ napi_property_attributes attributes,
3384
+ void* data) {
3385
+ napi_property_descriptor desc = napi_property_descriptor();
3386
+ desc.name = name;
3387
+ desc.method = details::TemplatedInstanceVoidCallback<T, method>;
3388
+ desc.data = data;
3389
+ desc.attributes = attributes;
3390
+ return desc;
3391
+ }
3392
+
3393
+ template <typename T>
3394
+ template <typename InstanceWrap<T>::InstanceMethodCallback method>
3395
+ inline ClassPropertyDescriptor<T> InstanceWrap<T>::InstanceMethod(
3396
+ Symbol name,
3397
+ napi_property_attributes attributes,
3398
+ void* data) {
3399
+ napi_property_descriptor desc = napi_property_descriptor();
3400
+ desc.name = name;
3401
+ desc.method = details::TemplatedInstanceCallback<T, method>;
3402
+ desc.data = data;
3403
+ desc.attributes = attributes;
3404
+ return desc;
3405
+ }
3406
+
3407
+ template <typename T>
3408
+ inline ClassPropertyDescriptor<T> InstanceWrap<T>::InstanceAccessor(
3409
+ const char* utf8name,
3410
+ InstanceGetterCallback getter,
3411
+ InstanceSetterCallback setter,
3412
+ napi_property_attributes attributes,
3413
+ void* data) {
3414
+ InstanceAccessorCallbackData* callbackData =
3415
+ new InstanceAccessorCallbackData({ getter, setter, data });
3416
+
3417
+ napi_property_descriptor desc = napi_property_descriptor();
3418
+ desc.utf8name = utf8name;
3419
+ desc.getter = getter != nullptr ? T::InstanceGetterCallbackWrapper : nullptr;
3420
+ desc.setter = setter != nullptr ? T::InstanceSetterCallbackWrapper : nullptr;
3421
+ desc.data = callbackData;
3422
+ desc.attributes = attributes;
3423
+ return desc;
3424
+ }
3425
+
3426
+ template <typename T>
3427
+ inline ClassPropertyDescriptor<T> InstanceWrap<T>::InstanceAccessor(
3428
+ Symbol name,
3429
+ InstanceGetterCallback getter,
3430
+ InstanceSetterCallback setter,
3431
+ napi_property_attributes attributes,
3432
+ void* data) {
3433
+ InstanceAccessorCallbackData* callbackData =
3434
+ new InstanceAccessorCallbackData({ getter, setter, data });
3435
+
3436
+ napi_property_descriptor desc = napi_property_descriptor();
3437
+ desc.name = name;
3438
+ desc.getter = getter != nullptr ? T::InstanceGetterCallbackWrapper : nullptr;
3439
+ desc.setter = setter != nullptr ? T::InstanceSetterCallbackWrapper : nullptr;
3440
+ desc.data = callbackData;
3441
+ desc.attributes = attributes;
3442
+ return desc;
3443
+ }
3444
+
3445
+ template <typename T>
3446
+ template <typename InstanceWrap<T>::InstanceGetterCallback getter,
3447
+ typename InstanceWrap<T>::InstanceSetterCallback setter>
3448
+ inline ClassPropertyDescriptor<T> InstanceWrap<T>::InstanceAccessor(
3449
+ const char* utf8name,
3450
+ napi_property_attributes attributes,
3451
+ void* data) {
3452
+ napi_property_descriptor desc = napi_property_descriptor();
3453
+ desc.utf8name = utf8name;
3454
+ desc.getter = details::TemplatedInstanceCallback<T, getter>;
3455
+ desc.setter = This::WrapSetter(This::SetterTag<setter>());
3456
+ desc.data = data;
3457
+ desc.attributes = attributes;
3458
+ return desc;
3459
+ }
3460
+
3461
+ template <typename T>
3462
+ template <typename InstanceWrap<T>::InstanceGetterCallback getter,
3463
+ typename InstanceWrap<T>::InstanceSetterCallback setter>
3464
+ inline ClassPropertyDescriptor<T> InstanceWrap<T>::InstanceAccessor(
3465
+ Symbol name,
3466
+ napi_property_attributes attributes,
3467
+ void* data) {
3468
+ napi_property_descriptor desc = napi_property_descriptor();
3469
+ desc.name = name;
3470
+ desc.getter = details::TemplatedInstanceCallback<T, getter>;
3471
+ desc.setter = This::WrapSetter(This::SetterTag<setter>());
3472
+ desc.data = data;
3473
+ desc.attributes = attributes;
3474
+ return desc;
3475
+ }
3476
+
3477
+ template <typename T>
3478
+ inline ClassPropertyDescriptor<T> InstanceWrap<T>::InstanceValue(
3479
+ const char* utf8name,
3480
+ Napi::Value value,
3481
+ napi_property_attributes attributes) {
3482
+ napi_property_descriptor desc = napi_property_descriptor();
3483
+ desc.utf8name = utf8name;
3484
+ desc.value = value;
3485
+ desc.attributes = attributes;
3486
+ return desc;
3487
+ }
3488
+
3489
+ template <typename T>
3490
+ inline ClassPropertyDescriptor<T> InstanceWrap<T>::InstanceValue(
3491
+ Symbol name,
3492
+ Napi::Value value,
3493
+ napi_property_attributes attributes) {
3494
+ napi_property_descriptor desc = napi_property_descriptor();
3495
+ desc.name = name;
3496
+ desc.value = value;
3497
+ desc.attributes = attributes;
3498
+ return desc;
3499
+ }
3500
+
3501
+ template <typename T>
3502
+ inline napi_value InstanceWrap<T>::InstanceVoidMethodCallbackWrapper(
3503
+ napi_env env,
3504
+ napi_callback_info info) {
3505
+ return details::WrapCallback([&] {
3506
+ CallbackInfo callbackInfo(env, info);
3507
+ InstanceVoidMethodCallbackData* callbackData =
3508
+ reinterpret_cast<InstanceVoidMethodCallbackData*>(callbackInfo.Data());
3509
+ callbackInfo.SetData(callbackData->data);
3510
+ T* instance = T::Unwrap(callbackInfo.This().As<Object>());
3511
+ auto cb = callbackData->callback;
3512
+ (instance->*cb)(callbackInfo);
3513
+ return nullptr;
3514
+ });
3515
+ }
3516
+
3517
+ template <typename T>
3518
+ inline napi_value InstanceWrap<T>::InstanceMethodCallbackWrapper(
3519
+ napi_env env,
3520
+ napi_callback_info info) {
3521
+ return details::WrapCallback([&] {
3522
+ CallbackInfo callbackInfo(env, info);
3523
+ InstanceMethodCallbackData* callbackData =
3524
+ reinterpret_cast<InstanceMethodCallbackData*>(callbackInfo.Data());
3525
+ callbackInfo.SetData(callbackData->data);
3526
+ T* instance = T::Unwrap(callbackInfo.This().As<Object>());
3527
+ auto cb = callbackData->callback;
3528
+ return (instance->*cb)(callbackInfo);
3529
+ });
3530
+ }
3531
+
3532
+ template <typename T>
3533
+ inline napi_value InstanceWrap<T>::InstanceGetterCallbackWrapper(
3534
+ napi_env env,
3535
+ napi_callback_info info) {
3536
+ return details::WrapCallback([&] {
3537
+ CallbackInfo callbackInfo(env, info);
3538
+ InstanceAccessorCallbackData* callbackData =
3539
+ reinterpret_cast<InstanceAccessorCallbackData*>(callbackInfo.Data());
3540
+ callbackInfo.SetData(callbackData->data);
3541
+ T* instance = T::Unwrap(callbackInfo.This().As<Object>());
3542
+ auto cb = callbackData->getterCallback;
3543
+ return (instance->*cb)(callbackInfo);
3544
+ });
3545
+ }
3546
+
3547
+ template <typename T>
3548
+ inline napi_value InstanceWrap<T>::InstanceSetterCallbackWrapper(
3549
+ napi_env env,
3550
+ napi_callback_info info) {
3551
+ return details::WrapCallback([&] {
3552
+ CallbackInfo callbackInfo(env, info);
3553
+ InstanceAccessorCallbackData* callbackData =
3554
+ reinterpret_cast<InstanceAccessorCallbackData*>(callbackInfo.Data());
3555
+ callbackInfo.SetData(callbackData->data);
3556
+ T* instance = T::Unwrap(callbackInfo.This().As<Object>());
3557
+ auto cb = callbackData->setterCallback;
3558
+ (instance->*cb)(callbackInfo, callbackInfo[0]);
3559
+ return nullptr;
3560
+ });
3561
+ }
3562
+
3563
+ template <typename T>
3564
+ template <typename InstanceWrap<T>::InstanceSetterCallback method>
3565
+ inline napi_value InstanceWrap<T>::WrappedMethod(napi_env env, napi_callback_info info) noexcept {
3566
+ return details::WrapCallback([&] {
3567
+ const CallbackInfo cbInfo(env, info);
3568
+ T* instance = T::Unwrap(cbInfo.This().As<Object>());
3569
+ (instance->*method)(cbInfo, cbInfo[0]);
3570
+ return nullptr;
3571
+ });
3572
+ }
3573
+
3574
+ ////////////////////////////////////////////////////////////////////////////////
3575
+ // ObjectWrap<T> class
3576
+ ////////////////////////////////////////////////////////////////////////////////
3577
+
3578
+ template <typename T>
3579
+ inline ObjectWrap<T>::ObjectWrap(const Napi::CallbackInfo& callbackInfo) {
3580
+ napi_env env = callbackInfo.Env();
3581
+ napi_value wrapper = callbackInfo.This();
3582
+ napi_status status;
3583
+ napi_ref ref;
3584
+ T* instance = static_cast<T*>(this);
3585
+ status = napi_wrap(env, wrapper, instance, FinalizeCallback, nullptr, &ref);
3586
+ NAPI_THROW_IF_FAILED_VOID(env, status);
3587
+
3588
+ Reference<Object>* instanceRef = instance;
3589
+ *instanceRef = Reference<Object>(env, ref);
3590
+ }
3591
+
3592
+ template <typename T>
3593
+ inline ObjectWrap<T>::~ObjectWrap() {
3594
+ // If the JS object still exists at this point, remove the finalizer added
3595
+ // through `napi_wrap()`.
3596
+ if (!IsEmpty()) {
3597
+ Object object = Value();
3598
+ // It is not valid to call `napi_remove_wrap()` with an empty `object`.
3599
+ // This happens e.g. during garbage collection.
3600
+ if (!object.IsEmpty() && _construction_failed) {
3601
+ napi_remove_wrap(Env(), object, nullptr);
3602
+ }
3603
+ }
3604
+ }
3605
+
3606
+ template<typename T>
3607
+ inline T* ObjectWrap<T>::Unwrap(Object wrapper) {
3608
+ T* unwrapped;
3609
+ napi_status status = napi_unwrap(wrapper.Env(), wrapper, reinterpret_cast<void**>(&unwrapped));
3610
+ NAPI_THROW_IF_FAILED(wrapper.Env(), status, nullptr);
3611
+ return unwrapped;
3612
+ }
3613
+
3614
+ template <typename T>
3615
+ inline Function
3616
+ ObjectWrap<T>::DefineClass(Napi::Env env,
3617
+ const char* utf8name,
3618
+ const size_t props_count,
3619
+ const napi_property_descriptor* descriptors,
3620
+ void* data) {
3621
+ napi_status status;
3622
+ std::vector<napi_property_descriptor> props(props_count);
3623
+
3624
+ // We copy the descriptors to a local array because before defining the class
3625
+ // we must replace static method property descriptors with value property
3626
+ // descriptors such that the value is a function-valued `napi_value` created
3627
+ // with `CreateFunction()`.
3628
+ //
3629
+ // This replacement could be made for instance methods as well, but V8 aborts
3630
+ // if we do that, because it expects methods defined on the prototype template
3631
+ // to have `FunctionTemplate`s.
3042
3632
  for (size_t index = 0; index < props_count; index++) {
3043
3633
  props[index] = descriptors[index];
3044
3634
  napi_property_descriptor* prop = &props[index];
3045
3635
  if (prop->method == T::StaticMethodCallbackWrapper) {
3046
3636
  status = CreateFunction(env,
3047
- utf8name,
3048
- prop->method,
3049
- static_cast<StaticMethodCallbackData*>(prop->data),
3637
+ utf8name,
3638
+ prop->method,
3639
+ static_cast<StaticMethodCallbackData*>(prop->data),
3050
3640
  &(prop->value));
3051
3641
  NAPI_THROW_IF_FAILED(env, status, Function());
3052
3642
  prop->method = nullptr;
3053
3643
  prop->data = nullptr;
3054
3644
  } else if (prop->method == T::StaticVoidMethodCallbackWrapper) {
3055
3645
  status = CreateFunction(env,
3056
- utf8name,
3057
- prop->method,
3058
- static_cast<StaticVoidMethodCallbackData*>(prop->data),
3059
- &(prop->value));
3646
+ utf8name,
3647
+ prop->method,
3648
+ static_cast<StaticVoidMethodCallbackData*>(prop->data),
3649
+ &(prop->value));
3060
3650
  NAPI_THROW_IF_FAILED(env, status, Function());
3061
3651
  prop->method = nullptr;
3062
3652
  prop->data = nullptr;
@@ -3086,24 +3676,10 @@ ObjectWrap<T>::DefineClass(Napi::Env env,
3086
3676
  value,
3087
3677
  static_cast<StaticAccessorCallbackData*>(prop->data));
3088
3678
  NAPI_THROW_IF_FAILED(env, status, Function());
3089
- } else if (prop->getter == T::InstanceGetterCallbackWrapper ||
3090
- prop->setter == T::InstanceSetterCallbackWrapper) {
3091
- status = Napi::details::AttachData(env,
3092
- value,
3093
- static_cast<InstanceAccessorCallbackData*>(prop->data));
3094
- NAPI_THROW_IF_FAILED(env, status, Function());
3095
- } else if (prop->method != nullptr && !(prop->attributes & napi_static)) {
3096
- if (prop->method == T::InstanceVoidMethodCallbackWrapper) {
3097
- status = Napi::details::AttachData(env,
3098
- value,
3099
- static_cast<InstanceVoidMethodCallbackData*>(prop->data));
3100
- NAPI_THROW_IF_FAILED(env, status, Function());
3101
- } else if (prop->method == T::InstanceMethodCallbackWrapper) {
3102
- status = Napi::details::AttachData(env,
3103
- value,
3104
- static_cast<InstanceMethodCallbackData*>(prop->data));
3105
- NAPI_THROW_IF_FAILED(env, status, Function());
3106
- }
3679
+ } else {
3680
+ // InstanceWrap<T>::AttachPropData is responsible for attaching the data
3681
+ // of instance methods and accessors.
3682
+ T::AttachPropData(env, value, prop);
3107
3683
  }
3108
3684
  }
3109
3685
 
@@ -3201,188 +3777,148 @@ inline ClassPropertyDescriptor<T> ObjectWrap<T>::StaticMethod(
3201
3777
  }
3202
3778
 
3203
3779
  template <typename T>
3204
- inline ClassPropertyDescriptor<T> ObjectWrap<T>::StaticAccessor(
3780
+ template <typename ObjectWrap<T>::StaticVoidMethodCallback method>
3781
+ inline ClassPropertyDescriptor<T> ObjectWrap<T>::StaticMethod(
3205
3782
  const char* utf8name,
3206
- StaticGetterCallback getter,
3207
- StaticSetterCallback setter,
3208
3783
  napi_property_attributes attributes,
3209
3784
  void* data) {
3210
- StaticAccessorCallbackData* callbackData =
3211
- new StaticAccessorCallbackData({ getter, setter, data });
3212
-
3213
3785
  napi_property_descriptor desc = napi_property_descriptor();
3214
3786
  desc.utf8name = utf8name;
3215
- desc.getter = getter != nullptr ? T::StaticGetterCallbackWrapper : nullptr;
3216
- desc.setter = setter != nullptr ? T::StaticSetterCallbackWrapper : nullptr;
3217
- desc.data = callbackData;
3787
+ desc.method = details::TemplatedVoidCallback<method>;
3788
+ desc.data = data;
3218
3789
  desc.attributes = static_cast<napi_property_attributes>(attributes | napi_static);
3219
3790
  return desc;
3220
3791
  }
3221
3792
 
3222
3793
  template <typename T>
3223
- inline ClassPropertyDescriptor<T> ObjectWrap<T>::StaticAccessor(
3794
+ template <typename ObjectWrap<T>::StaticVoidMethodCallback method>
3795
+ inline ClassPropertyDescriptor<T> ObjectWrap<T>::StaticMethod(
3224
3796
  Symbol name,
3225
- StaticGetterCallback getter,
3226
- StaticSetterCallback setter,
3227
3797
  napi_property_attributes attributes,
3228
3798
  void* data) {
3229
- StaticAccessorCallbackData* callbackData =
3230
- new StaticAccessorCallbackData({ getter, setter, data });
3231
-
3232
3799
  napi_property_descriptor desc = napi_property_descriptor();
3233
3800
  desc.name = name;
3234
- desc.getter = getter != nullptr ? T::StaticGetterCallbackWrapper : nullptr;
3235
- desc.setter = setter != nullptr ? T::StaticSetterCallbackWrapper : nullptr;
3236
- desc.data = callbackData;
3801
+ desc.method = details::TemplatedVoidCallback<method>;
3802
+ desc.data = data;
3237
3803
  desc.attributes = static_cast<napi_property_attributes>(attributes | napi_static);
3238
3804
  return desc;
3239
3805
  }
3240
3806
 
3241
3807
  template <typename T>
3242
- inline ClassPropertyDescriptor<T> ObjectWrap<T>::InstanceMethod(
3243
- const char* utf8name,
3244
- InstanceVoidMethodCallback method,
3245
- napi_property_attributes attributes,
3246
- void* data) {
3247
- InstanceVoidMethodCallbackData* callbackData =
3248
- new InstanceVoidMethodCallbackData({ method, data});
3249
-
3250
- napi_property_descriptor desc = napi_property_descriptor();
3251
- desc.utf8name = utf8name;
3252
- desc.method = T::InstanceVoidMethodCallbackWrapper;
3253
- desc.data = callbackData;
3254
- desc.attributes = attributes;
3255
- return desc;
3256
- }
3257
-
3258
- template <typename T>
3259
- inline ClassPropertyDescriptor<T> ObjectWrap<T>::InstanceMethod(
3808
+ template <typename ObjectWrap<T>::StaticMethodCallback method>
3809
+ inline ClassPropertyDescriptor<T> ObjectWrap<T>::StaticMethod(
3260
3810
  const char* utf8name,
3261
- InstanceMethodCallback method,
3262
3811
  napi_property_attributes attributes,
3263
3812
  void* data) {
3264
- InstanceMethodCallbackData* callbackData = new InstanceMethodCallbackData({ method, data });
3265
-
3266
3813
  napi_property_descriptor desc = napi_property_descriptor();
3267
3814
  desc.utf8name = utf8name;
3268
- desc.method = T::InstanceMethodCallbackWrapper;
3269
- desc.data = callbackData;
3270
- desc.attributes = attributes;
3271
- return desc;
3272
- }
3273
-
3274
- template <typename T>
3275
- inline ClassPropertyDescriptor<T> ObjectWrap<T>::InstanceMethod(
3276
- Symbol name,
3277
- InstanceVoidMethodCallback method,
3278
- napi_property_attributes attributes,
3279
- void* data) {
3280
- InstanceVoidMethodCallbackData* callbackData =
3281
- new InstanceVoidMethodCallbackData({ method, data});
3282
-
3283
- napi_property_descriptor desc = napi_property_descriptor();
3284
- desc.name = name;
3285
- desc.method = T::InstanceVoidMethodCallbackWrapper;
3286
- desc.data = callbackData;
3287
- desc.attributes = attributes;
3815
+ desc.method = details::TemplatedCallback<method>;
3816
+ desc.data = data;
3817
+ desc.attributes = static_cast<napi_property_attributes>(attributes | napi_static);
3288
3818
  return desc;
3289
3819
  }
3290
3820
 
3291
3821
  template <typename T>
3292
- inline ClassPropertyDescriptor<T> ObjectWrap<T>::InstanceMethod(
3822
+ template <typename ObjectWrap<T>::StaticMethodCallback method>
3823
+ inline ClassPropertyDescriptor<T> ObjectWrap<T>::StaticMethod(
3293
3824
  Symbol name,
3294
- InstanceMethodCallback method,
3295
3825
  napi_property_attributes attributes,
3296
3826
  void* data) {
3297
- InstanceMethodCallbackData* callbackData = new InstanceMethodCallbackData({ method, data });
3298
-
3299
3827
  napi_property_descriptor desc = napi_property_descriptor();
3300
3828
  desc.name = name;
3301
- desc.method = T::InstanceMethodCallbackWrapper;
3302
- desc.data = callbackData;
3303
- desc.attributes = attributes;
3829
+ desc.method = details::TemplatedCallback<method>;
3830
+ desc.data = data;
3831
+ desc.attributes = static_cast<napi_property_attributes>(attributes | napi_static);
3304
3832
  return desc;
3305
3833
  }
3306
3834
 
3307
3835
  template <typename T>
3308
- inline ClassPropertyDescriptor<T> ObjectWrap<T>::InstanceAccessor(
3836
+ inline ClassPropertyDescriptor<T> ObjectWrap<T>::StaticAccessor(
3309
3837
  const char* utf8name,
3310
- InstanceGetterCallback getter,
3311
- InstanceSetterCallback setter,
3838
+ StaticGetterCallback getter,
3839
+ StaticSetterCallback setter,
3312
3840
  napi_property_attributes attributes,
3313
3841
  void* data) {
3314
- InstanceAccessorCallbackData* callbackData =
3315
- new InstanceAccessorCallbackData({ getter, setter, data });
3842
+ StaticAccessorCallbackData* callbackData =
3843
+ new StaticAccessorCallbackData({ getter, setter, data });
3316
3844
 
3317
3845
  napi_property_descriptor desc = napi_property_descriptor();
3318
3846
  desc.utf8name = utf8name;
3319
- desc.getter = getter != nullptr ? T::InstanceGetterCallbackWrapper : nullptr;
3320
- desc.setter = setter != nullptr ? T::InstanceSetterCallbackWrapper : nullptr;
3847
+ desc.getter = getter != nullptr ? T::StaticGetterCallbackWrapper : nullptr;
3848
+ desc.setter = setter != nullptr ? T::StaticSetterCallbackWrapper : nullptr;
3321
3849
  desc.data = callbackData;
3322
- desc.attributes = attributes;
3850
+ desc.attributes = static_cast<napi_property_attributes>(attributes | napi_static);
3323
3851
  return desc;
3324
3852
  }
3325
3853
 
3326
3854
  template <typename T>
3327
- inline ClassPropertyDescriptor<T> ObjectWrap<T>::InstanceAccessor(
3855
+ inline ClassPropertyDescriptor<T> ObjectWrap<T>::StaticAccessor(
3328
3856
  Symbol name,
3329
- InstanceGetterCallback getter,
3330
- InstanceSetterCallback setter,
3857
+ StaticGetterCallback getter,
3858
+ StaticSetterCallback setter,
3331
3859
  napi_property_attributes attributes,
3332
3860
  void* data) {
3333
- InstanceAccessorCallbackData* callbackData =
3334
- new InstanceAccessorCallbackData({ getter, setter, data });
3861
+ StaticAccessorCallbackData* callbackData =
3862
+ new StaticAccessorCallbackData({ getter, setter, data });
3335
3863
 
3336
3864
  napi_property_descriptor desc = napi_property_descriptor();
3337
3865
  desc.name = name;
3338
- desc.getter = getter != nullptr ? T::InstanceGetterCallbackWrapper : nullptr;
3339
- desc.setter = setter != nullptr ? T::InstanceSetterCallbackWrapper : nullptr;
3866
+ desc.getter = getter != nullptr ? T::StaticGetterCallbackWrapper : nullptr;
3867
+ desc.setter = setter != nullptr ? T::StaticSetterCallbackWrapper : nullptr;
3340
3868
  desc.data = callbackData;
3341
- desc.attributes = attributes;
3869
+ desc.attributes = static_cast<napi_property_attributes>(attributes | napi_static);
3342
3870
  return desc;
3343
3871
  }
3344
3872
 
3345
3873
  template <typename T>
3346
- inline ClassPropertyDescriptor<T> ObjectWrap<T>::StaticValue(const char* utf8name,
3347
- Napi::Value value, napi_property_attributes attributes) {
3874
+ template <typename ObjectWrap<T>::StaticGetterCallback getter,
3875
+ typename ObjectWrap<T>::StaticSetterCallback setter>
3876
+ inline ClassPropertyDescriptor<T> ObjectWrap<T>::StaticAccessor(
3877
+ const char* utf8name,
3878
+ napi_property_attributes attributes,
3879
+ void* data) {
3348
3880
  napi_property_descriptor desc = napi_property_descriptor();
3349
3881
  desc.utf8name = utf8name;
3350
- desc.value = value;
3882
+ desc.getter = details::TemplatedCallback<getter>;
3883
+ desc.setter = This::WrapStaticSetter(This::StaticSetterTag<setter>());
3884
+ desc.data = data;
3351
3885
  desc.attributes = static_cast<napi_property_attributes>(attributes | napi_static);
3352
3886
  return desc;
3353
3887
  }
3354
3888
 
3355
3889
  template <typename T>
3356
- inline ClassPropertyDescriptor<T> ObjectWrap<T>::StaticValue(Symbol name,
3357
- Napi::Value value, napi_property_attributes attributes) {
3890
+ template <typename ObjectWrap<T>::StaticGetterCallback getter,
3891
+ typename ObjectWrap<T>::StaticSetterCallback setter>
3892
+ inline ClassPropertyDescriptor<T> ObjectWrap<T>::StaticAccessor(
3893
+ Symbol name,
3894
+ napi_property_attributes attributes,
3895
+ void* data) {
3358
3896
  napi_property_descriptor desc = napi_property_descriptor();
3359
3897
  desc.name = name;
3360
- desc.value = value;
3898
+ desc.getter = details::TemplatedCallback<getter>;
3899
+ desc.setter = This::WrapStaticSetter(This::StaticSetterTag<setter>());
3900
+ desc.data = data;
3361
3901
  desc.attributes = static_cast<napi_property_attributes>(attributes | napi_static);
3362
3902
  return desc;
3363
3903
  }
3364
3904
 
3365
3905
  template <typename T>
3366
- inline ClassPropertyDescriptor<T> ObjectWrap<T>::InstanceValue(
3367
- const char* utf8name,
3368
- Napi::Value value,
3369
- napi_property_attributes attributes) {
3906
+ inline ClassPropertyDescriptor<T> ObjectWrap<T>::StaticValue(const char* utf8name,
3907
+ Napi::Value value, napi_property_attributes attributes) {
3370
3908
  napi_property_descriptor desc = napi_property_descriptor();
3371
3909
  desc.utf8name = utf8name;
3372
3910
  desc.value = value;
3373
- desc.attributes = attributes;
3911
+ desc.attributes = static_cast<napi_property_attributes>(attributes | napi_static);
3374
3912
  return desc;
3375
3913
  }
3376
3914
 
3377
3915
  template <typename T>
3378
- inline ClassPropertyDescriptor<T> ObjectWrap<T>::InstanceValue(
3379
- Symbol name,
3380
- Napi::Value value,
3381
- napi_property_attributes attributes) {
3916
+ inline ClassPropertyDescriptor<T> ObjectWrap<T>::StaticValue(Symbol name,
3917
+ Napi::Value value, napi_property_attributes attributes) {
3382
3918
  napi_property_descriptor desc = napi_property_descriptor();
3383
3919
  desc.name = name;
3384
3920
  desc.value = value;
3385
- desc.attributes = attributes;
3921
+ desc.attributes = static_cast<napi_property_attributes>(attributes | napi_static);
3386
3922
  return desc;
3387
3923
  }
3388
3924
 
@@ -3479,74 +4015,23 @@ inline napi_value ObjectWrap<T>::StaticSetterCallbackWrapper(
3479
4015
  }
3480
4016
 
3481
4017
  template <typename T>
3482
- inline napi_value ObjectWrap<T>::InstanceVoidMethodCallbackWrapper(
3483
- napi_env env,
3484
- napi_callback_info info) {
3485
- return details::WrapCallback([&] {
3486
- CallbackInfo callbackInfo(env, info);
3487
- InstanceVoidMethodCallbackData* callbackData =
3488
- reinterpret_cast<InstanceVoidMethodCallbackData*>(callbackInfo.Data());
3489
- callbackInfo.SetData(callbackData->data);
3490
- T* instance = Unwrap(callbackInfo.This().As<Object>());
3491
- auto cb = callbackData->callback;
3492
- (instance->*cb)(callbackInfo);
3493
- return nullptr;
3494
- });
3495
- }
3496
-
3497
- template <typename T>
3498
- inline napi_value ObjectWrap<T>::InstanceMethodCallbackWrapper(
3499
- napi_env env,
3500
- napi_callback_info info) {
3501
- return details::WrapCallback([&] {
3502
- CallbackInfo callbackInfo(env, info);
3503
- InstanceMethodCallbackData* callbackData =
3504
- reinterpret_cast<InstanceMethodCallbackData*>(callbackInfo.Data());
3505
- callbackInfo.SetData(callbackData->data);
3506
- T* instance = Unwrap(callbackInfo.This().As<Object>());
3507
- auto cb = callbackData->callback;
3508
- return (instance->*cb)(callbackInfo);
3509
- });
3510
- }
3511
-
3512
- template <typename T>
3513
- inline napi_value ObjectWrap<T>::InstanceGetterCallbackWrapper(
3514
- napi_env env,
3515
- napi_callback_info info) {
3516
- return details::WrapCallback([&] {
3517
- CallbackInfo callbackInfo(env, info);
3518
- InstanceAccessorCallbackData* callbackData =
3519
- reinterpret_cast<InstanceAccessorCallbackData*>(callbackInfo.Data());
3520
- callbackInfo.SetData(callbackData->data);
3521
- T* instance = Unwrap(callbackInfo.This().As<Object>());
3522
- auto cb = callbackData->getterCallback;
3523
- return (instance->*cb)(callbackInfo);
3524
- });
4018
+ inline void ObjectWrap<T>::FinalizeCallback(napi_env env, void* data, void* /*hint*/) {
4019
+ HandleScope scope(env);
4020
+ T* instance = static_cast<T*>(data);
4021
+ instance->Finalize(Napi::Env(env));
4022
+ delete instance;
3525
4023
  }
3526
4024
 
3527
4025
  template <typename T>
3528
- inline napi_value ObjectWrap<T>::InstanceSetterCallbackWrapper(
3529
- napi_env env,
3530
- napi_callback_info info) {
4026
+ template <typename ObjectWrap<T>::StaticSetterCallback method>
4027
+ inline napi_value ObjectWrap<T>::WrappedMethod(napi_env env, napi_callback_info info) noexcept {
3531
4028
  return details::WrapCallback([&] {
3532
- CallbackInfo callbackInfo(env, info);
3533
- InstanceAccessorCallbackData* callbackData =
3534
- reinterpret_cast<InstanceAccessorCallbackData*>(callbackInfo.Data());
3535
- callbackInfo.SetData(callbackData->data);
3536
- T* instance = Unwrap(callbackInfo.This().As<Object>());
3537
- auto cb = callbackData->setterCallback;
3538
- (instance->*cb)(callbackInfo, callbackInfo[0]);
4029
+ const CallbackInfo cbInfo(env, info);
4030
+ method(cbInfo, cbInfo[0]);
3539
4031
  return nullptr;
3540
4032
  });
3541
4033
  }
3542
4034
 
3543
- template <typename T>
3544
- inline void ObjectWrap<T>::FinalizeCallback(napi_env env, void* data, void* /*hint*/) {
3545
- ObjectWrap<T>* instance = static_cast<ObjectWrap<T>*>(data);
3546
- instance->Finalize(Napi::Env(env));
3547
- delete instance;
3548
- }
3549
-
3550
4035
  ////////////////////////////////////////////////////////////////////////////////
3551
4036
  // HandleScope class
3552
4037
  ////////////////////////////////////////////////////////////////////////////////
@@ -3744,158 +4229,653 @@ inline AsyncWorker::AsyncWorker(const Object& receiver,
3744
4229
  _env, resource_name, NAPI_AUTO_LENGTH, &resource_id);
3745
4230
  NAPI_THROW_IF_FAILED_VOID(_env, status);
3746
4231
 
3747
- status = napi_create_async_work(_env, resource, resource_id, OnExecute,
3748
- OnWorkComplete, this, &_work);
4232
+ status = napi_create_async_work(_env, resource, resource_id, OnAsyncWorkExecute,
4233
+ OnAsyncWorkComplete, this, &_work);
4234
+ NAPI_THROW_IF_FAILED_VOID(_env, status);
4235
+ }
4236
+
4237
+ inline AsyncWorker::AsyncWorker(Napi::Env env)
4238
+ : AsyncWorker(env, "generic") {
4239
+ }
4240
+
4241
+ inline AsyncWorker::AsyncWorker(Napi::Env env,
4242
+ const char* resource_name)
4243
+ : AsyncWorker(env, resource_name, Object::New(env)) {
4244
+ }
4245
+
4246
+ inline AsyncWorker::AsyncWorker(Napi::Env env,
4247
+ const char* resource_name,
4248
+ const Object& resource)
4249
+ : _env(env),
4250
+ _receiver(),
4251
+ _callback(),
4252
+ _suppress_destruct(false) {
4253
+ napi_value resource_id;
4254
+ napi_status status = napi_create_string_latin1(
4255
+ _env, resource_name, NAPI_AUTO_LENGTH, &resource_id);
4256
+ NAPI_THROW_IF_FAILED_VOID(_env, status);
4257
+
4258
+ status = napi_create_async_work(_env, resource, resource_id, OnAsyncWorkExecute,
4259
+ OnAsyncWorkComplete, this, &_work);
4260
+ NAPI_THROW_IF_FAILED_VOID(_env, status);
4261
+ }
4262
+
4263
+ inline AsyncWorker::~AsyncWorker() {
4264
+ if (_work != nullptr) {
4265
+ napi_delete_async_work(_env, _work);
4266
+ _work = nullptr;
4267
+ }
4268
+ }
4269
+
4270
+ inline void AsyncWorker::Destroy() {
4271
+ delete this;
4272
+ }
4273
+
4274
+ inline AsyncWorker::AsyncWorker(AsyncWorker&& other) {
4275
+ _env = other._env;
4276
+ other._env = nullptr;
4277
+ _work = other._work;
4278
+ other._work = nullptr;
4279
+ _receiver = std::move(other._receiver);
4280
+ _callback = std::move(other._callback);
4281
+ _error = std::move(other._error);
4282
+ _suppress_destruct = other._suppress_destruct;
4283
+ }
4284
+
4285
+ inline AsyncWorker& AsyncWorker::operator =(AsyncWorker&& other) {
4286
+ _env = other._env;
4287
+ other._env = nullptr;
4288
+ _work = other._work;
4289
+ other._work = nullptr;
4290
+ _receiver = std::move(other._receiver);
4291
+ _callback = std::move(other._callback);
4292
+ _error = std::move(other._error);
4293
+ _suppress_destruct = other._suppress_destruct;
4294
+ return *this;
4295
+ }
4296
+
4297
+ inline AsyncWorker::operator napi_async_work() const {
4298
+ return _work;
4299
+ }
4300
+
4301
+ inline Napi::Env AsyncWorker::Env() const {
4302
+ return Napi::Env(_env);
4303
+ }
4304
+
4305
+ inline void AsyncWorker::Queue() {
4306
+ napi_status status = napi_queue_async_work(_env, _work);
4307
+ NAPI_THROW_IF_FAILED_VOID(_env, status);
4308
+ }
4309
+
4310
+ inline void AsyncWorker::Cancel() {
4311
+ napi_status status = napi_cancel_async_work(_env, _work);
3749
4312
  NAPI_THROW_IF_FAILED_VOID(_env, status);
3750
4313
  }
3751
4314
 
3752
- inline AsyncWorker::AsyncWorker(Napi::Env env)
3753
- : AsyncWorker(env, "generic") {
4315
+ inline ObjectReference& AsyncWorker::Receiver() {
4316
+ return _receiver;
4317
+ }
4318
+
4319
+ inline FunctionReference& AsyncWorker::Callback() {
4320
+ return _callback;
4321
+ }
4322
+
4323
+ inline void AsyncWorker::SuppressDestruct() {
4324
+ _suppress_destruct = true;
4325
+ }
4326
+
4327
+ inline void AsyncWorker::OnOK() {
4328
+ if (!_callback.IsEmpty()) {
4329
+ _callback.Call(_receiver.Value(), GetResult(_callback.Env()));
4330
+ }
4331
+ }
4332
+
4333
+ inline void AsyncWorker::OnError(const Error& e) {
4334
+ if (!_callback.IsEmpty()) {
4335
+ _callback.Call(_receiver.Value(), std::initializer_list<napi_value>{ e.Value() });
4336
+ }
4337
+ }
4338
+
4339
+ inline void AsyncWorker::SetError(const std::string& error) {
4340
+ _error = error;
4341
+ }
4342
+
4343
+ inline std::vector<napi_value> AsyncWorker::GetResult(Napi::Env /*env*/) {
4344
+ return {};
4345
+ }
4346
+ // The OnAsyncWorkExecute method receives an napi_env argument. However, do NOT
4347
+ // use it within this method, as it does not run on the JavaScript thread and
4348
+ // must not run any method that would cause JavaScript to run. In practice,
4349
+ // this means that almost any use of napi_env will be incorrect.
4350
+ inline void AsyncWorker::OnAsyncWorkExecute(napi_env env, void* asyncworker) {
4351
+ AsyncWorker* self = static_cast<AsyncWorker*>(asyncworker);
4352
+ self->OnExecute(env);
4353
+ }
4354
+ // The OnExecute method receives an napi_env argument. However, do NOT
4355
+ // use it within this method, as it does not run on the JavaScript thread and
4356
+ // must not run any method that would cause JavaScript to run. In practice,
4357
+ // this means that almost any use of napi_env will be incorrect.
4358
+ inline void AsyncWorker::OnExecute(Napi::Env /*DO_NOT_USE*/) {
4359
+ #ifdef NAPI_CPP_EXCEPTIONS
4360
+ try {
4361
+ Execute();
4362
+ } catch (const std::exception& e) {
4363
+ SetError(e.what());
4364
+ }
4365
+ #else // NAPI_CPP_EXCEPTIONS
4366
+ Execute();
4367
+ #endif // NAPI_CPP_EXCEPTIONS
4368
+ }
4369
+
4370
+ inline void AsyncWorker::OnAsyncWorkComplete(napi_env env,
4371
+ napi_status status,
4372
+ void* asyncworker) {
4373
+ AsyncWorker* self = static_cast<AsyncWorker*>(asyncworker);
4374
+ self->OnWorkComplete(env, status);
4375
+ }
4376
+ inline void AsyncWorker::OnWorkComplete(Napi::Env /*env*/, napi_status status) {
4377
+ if (status != napi_cancelled) {
4378
+ HandleScope scope(_env);
4379
+ details::WrapCallback([&] {
4380
+ if (_error.size() == 0) {
4381
+ OnOK();
4382
+ }
4383
+ else {
4384
+ OnError(Error::New(_env, _error));
4385
+ }
4386
+ return nullptr;
4387
+ });
4388
+ }
4389
+ if (!_suppress_destruct) {
4390
+ Destroy();
4391
+ }
4392
+ }
4393
+
4394
+ #if (NAPI_VERSION > 3 && !defined(__wasm32__))
4395
+ ////////////////////////////////////////////////////////////////////////////////
4396
+ // TypedThreadSafeFunction<ContextType,DataType,CallJs> class
4397
+ ////////////////////////////////////////////////////////////////////////////////
4398
+
4399
+ // Starting with NAPI 5, the JavaScript function `func` parameter of
4400
+ // `napi_create_threadsafe_function` is optional.
4401
+ #if NAPI_VERSION > 4
4402
+ // static, with Callback [missing] Resource [missing] Finalizer [missing]
4403
+ template <typename ContextType,
4404
+ typename DataType,
4405
+ void (*CallJs)(Napi::Env, Napi::Function, ContextType*, DataType*)>
4406
+ template <typename ResourceString>
4407
+ inline TypedThreadSafeFunction<ContextType, DataType, CallJs>
4408
+ TypedThreadSafeFunction<ContextType, DataType, CallJs>::New(
4409
+ napi_env env,
4410
+ ResourceString resourceName,
4411
+ size_t maxQueueSize,
4412
+ size_t initialThreadCount,
4413
+ ContextType* context) {
4414
+ TypedThreadSafeFunction<ContextType, DataType, CallJs> tsfn;
4415
+
4416
+ napi_status status =
4417
+ napi_create_threadsafe_function(env,
4418
+ nullptr,
4419
+ nullptr,
4420
+ String::From(env, resourceName),
4421
+ maxQueueSize,
4422
+ initialThreadCount,
4423
+ nullptr,
4424
+ nullptr,
4425
+ context,
4426
+ CallJsInternal,
4427
+ &tsfn._tsfn);
4428
+ if (status != napi_ok) {
4429
+ NAPI_THROW_IF_FAILED(
4430
+ env, status, TypedThreadSafeFunction<ContextType, DataType, CallJs>());
4431
+ }
4432
+
4433
+ return tsfn;
4434
+ }
4435
+
4436
+ // static, with Callback [missing] Resource [passed] Finalizer [missing]
4437
+ template <typename ContextType,
4438
+ typename DataType,
4439
+ void (*CallJs)(Napi::Env, Napi::Function, ContextType*, DataType*)>
4440
+ template <typename ResourceString>
4441
+ inline TypedThreadSafeFunction<ContextType, DataType, CallJs>
4442
+ TypedThreadSafeFunction<ContextType, DataType, CallJs>::New(
4443
+ napi_env env,
4444
+ const Object& resource,
4445
+ ResourceString resourceName,
4446
+ size_t maxQueueSize,
4447
+ size_t initialThreadCount,
4448
+ ContextType* context) {
4449
+ TypedThreadSafeFunction<ContextType, DataType, CallJs> tsfn;
4450
+
4451
+ napi_status status =
4452
+ napi_create_threadsafe_function(env,
4453
+ nullptr,
4454
+ resource,
4455
+ String::From(env, resourceName),
4456
+ maxQueueSize,
4457
+ initialThreadCount,
4458
+ nullptr,
4459
+ nullptr,
4460
+ context,
4461
+ CallJsInternal,
4462
+ &tsfn._tsfn);
4463
+ if (status != napi_ok) {
4464
+ NAPI_THROW_IF_FAILED(
4465
+ env, status, TypedThreadSafeFunction<ContextType, DataType, CallJs>());
4466
+ }
4467
+
4468
+ return tsfn;
4469
+ }
4470
+
4471
+ // static, with Callback [missing] Resource [missing] Finalizer [passed]
4472
+ template <typename ContextType,
4473
+ typename DataType,
4474
+ void (*CallJs)(Napi::Env, Napi::Function, ContextType*, DataType*)>
4475
+ template <typename ResourceString,
4476
+ typename Finalizer,
4477
+ typename FinalizerDataType>
4478
+ inline TypedThreadSafeFunction<ContextType, DataType, CallJs>
4479
+ TypedThreadSafeFunction<ContextType, DataType, CallJs>::New(
4480
+ napi_env env,
4481
+ ResourceString resourceName,
4482
+ size_t maxQueueSize,
4483
+ size_t initialThreadCount,
4484
+ ContextType* context,
4485
+ Finalizer finalizeCallback,
4486
+ FinalizerDataType* data) {
4487
+ TypedThreadSafeFunction<ContextType, DataType, CallJs> tsfn;
4488
+
4489
+ auto* finalizeData = new details::
4490
+ ThreadSafeFinalize<ContextType, Finalizer, FinalizerDataType>(
4491
+ {data, finalizeCallback});
4492
+ napi_status status = napi_create_threadsafe_function(
4493
+ env,
4494
+ nullptr,
4495
+ nullptr,
4496
+ String::From(env, resourceName),
4497
+ maxQueueSize,
4498
+ initialThreadCount,
4499
+ finalizeData,
4500
+ details::ThreadSafeFinalize<ContextType, Finalizer, FinalizerDataType>::
4501
+ FinalizeFinalizeWrapperWithDataAndContext,
4502
+ context,
4503
+ CallJsInternal,
4504
+ &tsfn._tsfn);
4505
+ if (status != napi_ok) {
4506
+ delete finalizeData;
4507
+ NAPI_THROW_IF_FAILED(
4508
+ env, status, TypedThreadSafeFunction<ContextType, DataType, CallJs>());
4509
+ }
4510
+
4511
+ return tsfn;
4512
+ }
4513
+
4514
+ // static, with Callback [missing] Resource [passed] Finalizer [passed]
4515
+ template <typename ContextType,
4516
+ typename DataType,
4517
+ void (*CallJs)(Napi::Env, Napi::Function, ContextType*, DataType*)>
4518
+ template <typename ResourceString,
4519
+ typename Finalizer,
4520
+ typename FinalizerDataType>
4521
+ inline TypedThreadSafeFunction<ContextType, DataType, CallJs>
4522
+ TypedThreadSafeFunction<ContextType, DataType, CallJs>::New(
4523
+ napi_env env,
4524
+ const Object& resource,
4525
+ ResourceString resourceName,
4526
+ size_t maxQueueSize,
4527
+ size_t initialThreadCount,
4528
+ ContextType* context,
4529
+ Finalizer finalizeCallback,
4530
+ FinalizerDataType* data) {
4531
+ TypedThreadSafeFunction<ContextType, DataType, CallJs> tsfn;
4532
+
4533
+ auto* finalizeData = new details::
4534
+ ThreadSafeFinalize<ContextType, Finalizer, FinalizerDataType>(
4535
+ {data, finalizeCallback});
4536
+ napi_status status = napi_create_threadsafe_function(
4537
+ env,
4538
+ nullptr,
4539
+ resource,
4540
+ String::From(env, resourceName),
4541
+ maxQueueSize,
4542
+ initialThreadCount,
4543
+ finalizeData,
4544
+ details::ThreadSafeFinalize<ContextType, Finalizer, FinalizerDataType>::
4545
+ FinalizeFinalizeWrapperWithDataAndContext,
4546
+ context,
4547
+ CallJsInternal,
4548
+ &tsfn._tsfn);
4549
+ if (status != napi_ok) {
4550
+ delete finalizeData;
4551
+ NAPI_THROW_IF_FAILED(
4552
+ env, status, TypedThreadSafeFunction<ContextType, DataType, CallJs>());
4553
+ }
4554
+
4555
+ return tsfn;
4556
+ }
4557
+ #endif
4558
+
4559
+ // static, with Callback [passed] Resource [missing] Finalizer [missing]
4560
+ template <typename ContextType,
4561
+ typename DataType,
4562
+ void (*CallJs)(Napi::Env, Napi::Function, ContextType*, DataType*)>
4563
+ template <typename ResourceString>
4564
+ inline TypedThreadSafeFunction<ContextType, DataType, CallJs>
4565
+ TypedThreadSafeFunction<ContextType, DataType, CallJs>::New(
4566
+ napi_env env,
4567
+ const Function& callback,
4568
+ ResourceString resourceName,
4569
+ size_t maxQueueSize,
4570
+ size_t initialThreadCount,
4571
+ ContextType* context) {
4572
+ TypedThreadSafeFunction<ContextType, DataType, CallJs> tsfn;
4573
+
4574
+ napi_status status =
4575
+ napi_create_threadsafe_function(env,
4576
+ callback,
4577
+ nullptr,
4578
+ String::From(env, resourceName),
4579
+ maxQueueSize,
4580
+ initialThreadCount,
4581
+ nullptr,
4582
+ nullptr,
4583
+ context,
4584
+ CallJsInternal,
4585
+ &tsfn._tsfn);
4586
+ if (status != napi_ok) {
4587
+ NAPI_THROW_IF_FAILED(
4588
+ env, status, TypedThreadSafeFunction<ContextType, DataType, CallJs>());
4589
+ }
4590
+
4591
+ return tsfn;
3754
4592
  }
3755
4593
 
3756
- inline AsyncWorker::AsyncWorker(Napi::Env env,
3757
- const char* resource_name)
3758
- : AsyncWorker(env, resource_name, Object::New(env)) {
4594
+ // static, with Callback [passed] Resource [passed] Finalizer [missing]
4595
+ template <typename ContextType,
4596
+ typename DataType,
4597
+ void (*CallJs)(Napi::Env, Napi::Function, ContextType*, DataType*)>
4598
+ template <typename ResourceString>
4599
+ inline TypedThreadSafeFunction<ContextType, DataType, CallJs>
4600
+ TypedThreadSafeFunction<ContextType, DataType, CallJs>::New(
4601
+ napi_env env,
4602
+ const Function& callback,
4603
+ const Object& resource,
4604
+ ResourceString resourceName,
4605
+ size_t maxQueueSize,
4606
+ size_t initialThreadCount,
4607
+ ContextType* context) {
4608
+ TypedThreadSafeFunction<ContextType, DataType, CallJs> tsfn;
4609
+
4610
+ napi_status status =
4611
+ napi_create_threadsafe_function(env,
4612
+ callback,
4613
+ resource,
4614
+ String::From(env, resourceName),
4615
+ maxQueueSize,
4616
+ initialThreadCount,
4617
+ nullptr,
4618
+ nullptr,
4619
+ context,
4620
+ CallJsInternal,
4621
+ &tsfn._tsfn);
4622
+ if (status != napi_ok) {
4623
+ NAPI_THROW_IF_FAILED(
4624
+ env, status, TypedThreadSafeFunction<ContextType, DataType, CallJs>());
4625
+ }
4626
+
4627
+ return tsfn;
3759
4628
  }
3760
4629
 
3761
- inline AsyncWorker::AsyncWorker(Napi::Env env,
3762
- const char* resource_name,
3763
- const Object& resource)
3764
- : _env(env),
3765
- _receiver(),
3766
- _callback(),
3767
- _suppress_destruct(false) {
3768
- napi_value resource_id;
3769
- napi_status status = napi_create_string_latin1(
3770
- _env, resource_name, NAPI_AUTO_LENGTH, &resource_id);
3771
- NAPI_THROW_IF_FAILED_VOID(_env, status);
4630
+ // static, with Callback [passed] Resource [missing] Finalizer [passed]
4631
+ template <typename ContextType,
4632
+ typename DataType,
4633
+ void (*CallJs)(Napi::Env, Napi::Function, ContextType*, DataType*)>
4634
+ template <typename ResourceString,
4635
+ typename Finalizer,
4636
+ typename FinalizerDataType>
4637
+ inline TypedThreadSafeFunction<ContextType, DataType, CallJs>
4638
+ TypedThreadSafeFunction<ContextType, DataType, CallJs>::New(
4639
+ napi_env env,
4640
+ const Function& callback,
4641
+ ResourceString resourceName,
4642
+ size_t maxQueueSize,
4643
+ size_t initialThreadCount,
4644
+ ContextType* context,
4645
+ Finalizer finalizeCallback,
4646
+ FinalizerDataType* data) {
4647
+ TypedThreadSafeFunction<ContextType, DataType, CallJs> tsfn;
4648
+
4649
+ auto* finalizeData = new details::
4650
+ ThreadSafeFinalize<ContextType, Finalizer, FinalizerDataType>(
4651
+ {data, finalizeCallback});
4652
+ napi_status status = napi_create_threadsafe_function(
4653
+ env,
4654
+ callback,
4655
+ nullptr,
4656
+ String::From(env, resourceName),
4657
+ maxQueueSize,
4658
+ initialThreadCount,
4659
+ finalizeData,
4660
+ details::ThreadSafeFinalize<ContextType, Finalizer, FinalizerDataType>::
4661
+ FinalizeFinalizeWrapperWithDataAndContext,
4662
+ context,
4663
+ CallJsInternal,
4664
+ &tsfn._tsfn);
4665
+ if (status != napi_ok) {
4666
+ delete finalizeData;
4667
+ NAPI_THROW_IF_FAILED(
4668
+ env, status, TypedThreadSafeFunction<ContextType, DataType, CallJs>());
4669
+ }
3772
4670
 
3773
- status = napi_create_async_work(_env, resource, resource_id, OnExecute,
3774
- OnWorkComplete, this, &_work);
3775
- NAPI_THROW_IF_FAILED_VOID(_env, status);
4671
+ return tsfn;
3776
4672
  }
3777
4673
 
3778
- inline AsyncWorker::~AsyncWorker() {
3779
- if (_work != nullptr) {
3780
- napi_delete_async_work(_env, _work);
3781
- _work = nullptr;
4674
+ // static, with: Callback [passed] Resource [passed] Finalizer [passed]
4675
+ template <typename ContextType,
4676
+ typename DataType,
4677
+ void (*CallJs)(Napi::Env, Napi::Function, ContextType*, DataType*)>
4678
+ template <typename CallbackType,
4679
+ typename ResourceString,
4680
+ typename Finalizer,
4681
+ typename FinalizerDataType>
4682
+ inline TypedThreadSafeFunction<ContextType, DataType, CallJs>
4683
+ TypedThreadSafeFunction<ContextType, DataType, CallJs>::New(
4684
+ napi_env env,
4685
+ CallbackType callback,
4686
+ const Object& resource,
4687
+ ResourceString resourceName,
4688
+ size_t maxQueueSize,
4689
+ size_t initialThreadCount,
4690
+ ContextType* context,
4691
+ Finalizer finalizeCallback,
4692
+ FinalizerDataType* data) {
4693
+ TypedThreadSafeFunction<ContextType, DataType, CallJs> tsfn;
4694
+
4695
+ auto* finalizeData = new details::
4696
+ ThreadSafeFinalize<ContextType, Finalizer, FinalizerDataType>(
4697
+ {data, finalizeCallback});
4698
+ napi_status status = napi_create_threadsafe_function(
4699
+ env,
4700
+ details::DefaultCallbackWrapper<
4701
+ CallbackType,
4702
+ TypedThreadSafeFunction<ContextType, DataType, CallJs>>(env,
4703
+ callback),
4704
+ resource,
4705
+ String::From(env, resourceName),
4706
+ maxQueueSize,
4707
+ initialThreadCount,
4708
+ finalizeData,
4709
+ details::ThreadSafeFinalize<ContextType, Finalizer, FinalizerDataType>::
4710
+ FinalizeFinalizeWrapperWithDataAndContext,
4711
+ context,
4712
+ CallJsInternal,
4713
+ &tsfn._tsfn);
4714
+ if (status != napi_ok) {
4715
+ delete finalizeData;
4716
+ NAPI_THROW_IF_FAILED(
4717
+ env, status, TypedThreadSafeFunction<ContextType, DataType, CallJs>());
3782
4718
  }
4719
+
4720
+ return tsfn;
3783
4721
  }
3784
4722
 
3785
- inline void AsyncWorker::Destroy() {
3786
- delete this;
4723
+ template <typename ContextType,
4724
+ typename DataType,
4725
+ void (*CallJs)(Napi::Env, Napi::Function, ContextType*, DataType*)>
4726
+ inline TypedThreadSafeFunction<ContextType, DataType, CallJs>::
4727
+ TypedThreadSafeFunction()
4728
+ : _tsfn() {}
4729
+
4730
+ template <typename ContextType,
4731
+ typename DataType,
4732
+ void (*CallJs)(Napi::Env, Napi::Function, ContextType*, DataType*)>
4733
+ inline TypedThreadSafeFunction<ContextType, DataType, CallJs>::
4734
+ TypedThreadSafeFunction(napi_threadsafe_function tsfn)
4735
+ : _tsfn(tsfn) {}
4736
+
4737
+ template <typename ContextType,
4738
+ typename DataType,
4739
+ void (*CallJs)(Napi::Env, Napi::Function, ContextType*, DataType*)>
4740
+ inline TypedThreadSafeFunction<ContextType, DataType, CallJs>::
4741
+ operator napi_threadsafe_function() const {
4742
+ return _tsfn;
3787
4743
  }
3788
4744
 
3789
- inline AsyncWorker::AsyncWorker(AsyncWorker&& other) {
3790
- _env = other._env;
3791
- other._env = nullptr;
3792
- _work = other._work;
3793
- other._work = nullptr;
3794
- _receiver = std::move(other._receiver);
3795
- _callback = std::move(other._callback);
3796
- _error = std::move(other._error);
3797
- _suppress_destruct = other._suppress_destruct;
4745
+ template <typename ContextType,
4746
+ typename DataType,
4747
+ void (*CallJs)(Napi::Env, Napi::Function, ContextType*, DataType*)>
4748
+ inline napi_status
4749
+ TypedThreadSafeFunction<ContextType, DataType, CallJs>::BlockingCall(
4750
+ DataType* data) const {
4751
+ return napi_call_threadsafe_function(_tsfn, data, napi_tsfn_blocking);
3798
4752
  }
3799
4753
 
3800
- inline AsyncWorker& AsyncWorker::operator =(AsyncWorker&& other) {
3801
- _env = other._env;
3802
- other._env = nullptr;
3803
- _work = other._work;
3804
- other._work = nullptr;
3805
- _receiver = std::move(other._receiver);
3806
- _callback = std::move(other._callback);
3807
- _error = std::move(other._error);
3808
- _suppress_destruct = other._suppress_destruct;
3809
- return *this;
4754
+ template <typename ContextType,
4755
+ typename DataType,
4756
+ void (*CallJs)(Napi::Env, Napi::Function, ContextType*, DataType*)>
4757
+ inline napi_status
4758
+ TypedThreadSafeFunction<ContextType, DataType, CallJs>::NonBlockingCall(
4759
+ DataType* data) const {
4760
+ return napi_call_threadsafe_function(_tsfn, data, napi_tsfn_nonblocking);
3810
4761
  }
3811
4762
 
3812
- inline AsyncWorker::operator napi_async_work() const {
3813
- return _work;
4763
+ template <typename ContextType,
4764
+ typename DataType,
4765
+ void (*CallJs)(Napi::Env, Napi::Function, ContextType*, DataType*)>
4766
+ inline void TypedThreadSafeFunction<ContextType, DataType, CallJs>::Ref(
4767
+ napi_env env) const {
4768
+ if (_tsfn != nullptr) {
4769
+ napi_status status = napi_ref_threadsafe_function(env, _tsfn);
4770
+ NAPI_THROW_IF_FAILED_VOID(env, status);
4771
+ }
3814
4772
  }
3815
4773
 
3816
- inline Napi::Env AsyncWorker::Env() const {
3817
- return Napi::Env(_env);
4774
+ template <typename ContextType,
4775
+ typename DataType,
4776
+ void (*CallJs)(Napi::Env, Napi::Function, ContextType*, DataType*)>
4777
+ inline void TypedThreadSafeFunction<ContextType, DataType, CallJs>::Unref(
4778
+ napi_env env) const {
4779
+ if (_tsfn != nullptr) {
4780
+ napi_status status = napi_unref_threadsafe_function(env, _tsfn);
4781
+ NAPI_THROW_IF_FAILED_VOID(env, status);
4782
+ }
3818
4783
  }
3819
4784
 
3820
- inline void AsyncWorker::Queue() {
3821
- napi_status status = napi_queue_async_work(_env, _work);
3822
- NAPI_THROW_IF_FAILED_VOID(_env, status);
4785
+ template <typename ContextType,
4786
+ typename DataType,
4787
+ void (*CallJs)(Napi::Env, Napi::Function, ContextType*, DataType*)>
4788
+ inline napi_status
4789
+ TypedThreadSafeFunction<ContextType, DataType, CallJs>::Acquire() const {
4790
+ return napi_acquire_threadsafe_function(_tsfn);
3823
4791
  }
3824
4792
 
3825
- inline void AsyncWorker::Cancel() {
3826
- napi_status status = napi_cancel_async_work(_env, _work);
3827
- NAPI_THROW_IF_FAILED_VOID(_env, status);
4793
+ template <typename ContextType,
4794
+ typename DataType,
4795
+ void (*CallJs)(Napi::Env, Napi::Function, ContextType*, DataType*)>
4796
+ inline napi_status
4797
+ TypedThreadSafeFunction<ContextType, DataType, CallJs>::Release() {
4798
+ return napi_release_threadsafe_function(_tsfn, napi_tsfn_release);
3828
4799
  }
3829
4800
 
3830
- inline ObjectReference& AsyncWorker::Receiver() {
3831
- return _receiver;
4801
+ template <typename ContextType,
4802
+ typename DataType,
4803
+ void (*CallJs)(Napi::Env, Napi::Function, ContextType*, DataType*)>
4804
+ inline napi_status
4805
+ TypedThreadSafeFunction<ContextType, DataType, CallJs>::Abort() {
4806
+ return napi_release_threadsafe_function(_tsfn, napi_tsfn_abort);
3832
4807
  }
3833
4808
 
3834
- inline FunctionReference& AsyncWorker::Callback() {
3835
- return _callback;
4809
+ template <typename ContextType,
4810
+ typename DataType,
4811
+ void (*CallJs)(Napi::Env, Napi::Function, ContextType*, DataType*)>
4812
+ inline ContextType*
4813
+ TypedThreadSafeFunction<ContextType, DataType, CallJs>::GetContext() const {
4814
+ void* context;
4815
+ napi_status status = napi_get_threadsafe_function_context(_tsfn, &context);
4816
+ NAPI_FATAL_IF_FAILED(status,
4817
+ "TypedThreadSafeFunction::GetContext",
4818
+ "napi_get_threadsafe_function_context");
4819
+ return static_cast<ContextType*>(context);
3836
4820
  }
3837
4821
 
3838
- inline void AsyncWorker::SuppressDestruct() {
3839
- _suppress_destruct = true;
4822
+ // static
4823
+ template <typename ContextType,
4824
+ typename DataType,
4825
+ void (*CallJs)(Napi::Env, Napi::Function, ContextType*, DataType*)>
4826
+ void TypedThreadSafeFunction<ContextType, DataType, CallJs>::CallJsInternal(
4827
+ napi_env env, napi_value jsCallback, void* context, void* data) {
4828
+ details::CallJsWrapper<ContextType, DataType, decltype(CallJs), CallJs>(
4829
+ env, jsCallback, context, data);
3840
4830
  }
3841
4831
 
3842
- inline void AsyncWorker::OnOK() {
3843
- if (!_callback.IsEmpty()) {
3844
- _callback.Call(_receiver.Value(), GetResult(_callback.Env()));
3845
- }
4832
+ #if NAPI_VERSION == 4
4833
+ // static
4834
+ template <typename ContextType,
4835
+ typename DataType,
4836
+ void (*CallJs)(Napi::Env, Napi::Function, ContextType*, DataType*)>
4837
+ Napi::Function
4838
+ TypedThreadSafeFunction<ContextType, DataType, CallJs>::EmptyFunctionFactory(
4839
+ Napi::Env env) {
4840
+ return Napi::Function::New(env, [](const CallbackInfo& cb) {});
3846
4841
  }
3847
4842
 
3848
- inline void AsyncWorker::OnError(const Error& e) {
3849
- if (!_callback.IsEmpty()) {
3850
- _callback.Call(_receiver.Value(), std::initializer_list<napi_value>{ e.Value() });
4843
+ // static
4844
+ template <typename ContextType,
4845
+ typename DataType,
4846
+ void (*CallJs)(Napi::Env, Napi::Function, ContextType*, DataType*)>
4847
+ Napi::Function
4848
+ TypedThreadSafeFunction<ContextType, DataType, CallJs>::FunctionOrEmpty(
4849
+ Napi::Env env, Napi::Function& callback) {
4850
+ if (callback.IsEmpty()) {
4851
+ return EmptyFunctionFactory(env);
3851
4852
  }
4853
+ return callback;
3852
4854
  }
3853
4855
 
3854
- inline void AsyncWorker::SetError(const std::string& error) {
3855
- _error = error;
4856
+ #else
4857
+ // static
4858
+ template <typename ContextType,
4859
+ typename DataType,
4860
+ void (*CallJs)(Napi::Env, Napi::Function, ContextType*, DataType*)>
4861
+ std::nullptr_t
4862
+ TypedThreadSafeFunction<ContextType, DataType, CallJs>::EmptyFunctionFactory(
4863
+ Napi::Env /*env*/) {
4864
+ return nullptr;
3856
4865
  }
3857
4866
 
3858
- inline std::vector<napi_value> AsyncWorker::GetResult(Napi::Env /*env*/) {
3859
- return {};
3860
- }
3861
- // 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);
3867
- #ifdef NAPI_CPP_EXCEPTIONS
3868
- try {
3869
- self->Execute();
3870
- } catch (const std::exception& e) {
3871
- self->SetError(e.what());
3872
- }
3873
- #else // NAPI_CPP_EXCEPTIONS
3874
- self->Execute();
3875
- #endif // NAPI_CPP_EXCEPTIONS
4867
+ // static
4868
+ template <typename ContextType,
4869
+ typename DataType,
4870
+ void (*CallJs)(Napi::Env, Napi::Function, ContextType*, DataType*)>
4871
+ Napi::Function
4872
+ TypedThreadSafeFunction<ContextType, DataType, CallJs>::FunctionOrEmpty(
4873
+ Napi::Env /*env*/, Napi::Function& callback) {
4874
+ return callback;
3876
4875
  }
3877
4876
 
3878
- inline void AsyncWorker::OnWorkComplete(
3879
- napi_env /*env*/, napi_status status, void* this_pointer) {
3880
- AsyncWorker* self = static_cast<AsyncWorker*>(this_pointer);
3881
- if (status != napi_cancelled) {
3882
- HandleScope scope(self->_env);
3883
- details::WrapCallback([&] {
3884
- if (self->_error.size() == 0) {
3885
- self->OnOK();
3886
- }
3887
- else {
3888
- self->OnError(Error::New(self->_env, self->_error));
3889
- }
3890
- return nullptr;
3891
- });
3892
- }
3893
- if (!self->_suppress_destruct) {
3894
- self->Destroy();
3895
- }
3896
- }
4877
+ #endif
3897
4878
 
3898
- #if (NAPI_VERSION > 3)
3899
4879
  ////////////////////////////////////////////////////////////////////////////////
3900
4880
  // ThreadSafeFunction class
3901
4881
  ////////////////////////////////////////////////////////////////////////////////
@@ -4187,7 +5167,7 @@ inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env,
4187
5167
 
4188
5168
  ThreadSafeFunction tsfn;
4189
5169
  auto* finalizeData = new details::ThreadSafeFinalize<ContextType, Finalizer,
4190
- FinalizerDataType>({ data, finalizeCallback, &tsfn._tsfn });
5170
+ FinalizerDataType>({ data, finalizeCallback });
4191
5171
  napi_status status = napi_create_threadsafe_function(env, callback, resource,
4192
5172
  Value::From(env, resourceName), maxQueueSize, initialThreadCount,
4193
5173
  finalizeData, wrapper, context, CallJS, &tsfn._tsfn);
@@ -4230,9 +5210,90 @@ inline void ThreadSafeFunction::CallJS(napi_env env,
4230
5210
  }
4231
5211
 
4232
5212
  ////////////////////////////////////////////////////////////////////////////////
4233
- // Async Progress Worker class
5213
+ // Async Progress Worker Base class
4234
5214
  ////////////////////////////////////////////////////////////////////////////////
5215
+ template <typename DataType>
5216
+ inline AsyncProgressWorkerBase<DataType>::AsyncProgressWorkerBase(const Object& receiver,
5217
+ const Function& callback,
5218
+ const char* resource_name,
5219
+ const Object& resource,
5220
+ size_t queue_size)
5221
+ : AsyncWorker(receiver, callback, resource_name, resource) {
5222
+ // Fill all possible arguments to work around ambiguous ThreadSafeFunction::New signatures.
5223
+ _tsfn = ThreadSafeFunction::New(callback.Env(),
5224
+ callback,
5225
+ resource,
5226
+ resource_name,
5227
+ queue_size,
5228
+ /** initialThreadCount */ 1,
5229
+ /** context */ this,
5230
+ OnThreadSafeFunctionFinalize,
5231
+ /** finalizeData */ this);
5232
+ }
5233
+
5234
+ #if NAPI_VERSION > 4
5235
+ template <typename DataType>
5236
+ inline AsyncProgressWorkerBase<DataType>::AsyncProgressWorkerBase(Napi::Env env,
5237
+ const char* resource_name,
5238
+ const Object& resource,
5239
+ size_t queue_size)
5240
+ : AsyncWorker(env, resource_name, resource) {
5241
+ // TODO: Once the changes to make the callback optional for threadsafe
5242
+ // functions are available on all versions we can remove the dummy Function here.
5243
+ Function callback;
5244
+ // Fill all possible arguments to work around ambiguous ThreadSafeFunction::New signatures.
5245
+ _tsfn = ThreadSafeFunction::New(env,
5246
+ callback,
5247
+ resource,
5248
+ resource_name,
5249
+ queue_size,
5250
+ /** initialThreadCount */ 1,
5251
+ /** context */ this,
5252
+ OnThreadSafeFunctionFinalize,
5253
+ /** finalizeData */ this);
5254
+ }
5255
+ #endif
5256
+
5257
+ template<typename DataType>
5258
+ inline AsyncProgressWorkerBase<DataType>::~AsyncProgressWorkerBase() {
5259
+ // Abort pending tsfn call.
5260
+ // Don't send progress events after we've already completed.
5261
+ // It's ok to call ThreadSafeFunction::Abort and ThreadSafeFunction::Release duplicated.
5262
+ _tsfn.Abort();
5263
+ }
5264
+
5265
+ template <typename DataType>
5266
+ inline void AsyncProgressWorkerBase<DataType>::OnAsyncWorkProgress(Napi::Env /* env */,
5267
+ Napi::Function /* jsCallback */,
5268
+ void* data) {
5269
+ ThreadSafeData* tsd = static_cast<ThreadSafeData*>(data);
5270
+ tsd->asyncprogressworker()->OnWorkProgress(tsd->data());
5271
+ delete tsd;
5272
+ }
5273
+
5274
+ template <typename DataType>
5275
+ inline napi_status AsyncProgressWorkerBase<DataType>::NonBlockingCall(DataType* data) {
5276
+ auto tsd = new AsyncProgressWorkerBase::ThreadSafeData(this, data);
5277
+ return _tsfn.NonBlockingCall(tsd, OnAsyncWorkProgress);
5278
+ }
5279
+
5280
+ template <typename DataType>
5281
+ inline void AsyncProgressWorkerBase<DataType>::OnWorkComplete(Napi::Env /* env */, napi_status status) {
5282
+ _work_completed = true;
5283
+ _complete_status = status;
5284
+ _tsfn.Release();
5285
+ }
5286
+
5287
+ template <typename DataType>
5288
+ inline void AsyncProgressWorkerBase<DataType>::OnThreadSafeFunctionFinalize(Napi::Env env, void* /* data */, AsyncProgressWorkerBase* context) {
5289
+ if (context->_work_completed) {
5290
+ context->AsyncWorker::OnWorkComplete(env, context->_complete_status);
5291
+ }
5292
+ }
4235
5293
 
5294
+ ////////////////////////////////////////////////////////////////////////////////
5295
+ // Async Progress Worker class
5296
+ ////////////////////////////////////////////////////////////////////////////////
4236
5297
  template<class T>
4237
5298
  inline AsyncProgressWorker<T>::AsyncProgressWorker(const Function& callback)
4238
5299
  : AsyncProgressWorker(callback, "generic") {
@@ -4256,14 +5317,14 @@ inline AsyncProgressWorker<T>::AsyncProgressWorker(const Function& callback,
4256
5317
 
4257
5318
  template<class T>
4258
5319
  inline AsyncProgressWorker<T>::AsyncProgressWorker(const Object& receiver,
4259
- const Function& callback)
5320
+ const Function& callback)
4260
5321
  : AsyncProgressWorker(receiver, callback, "generic") {
4261
5322
  }
4262
5323
 
4263
5324
  template<class T>
4264
5325
  inline AsyncProgressWorker<T>::AsyncProgressWorker(const Object& receiver,
4265
- const Function& callback,
4266
- const char* resource_name)
5326
+ const Function& callback,
5327
+ const char* resource_name)
4267
5328
  : AsyncProgressWorker(receiver,
4268
5329
  callback,
4269
5330
  resource_name,
@@ -4275,10 +5336,9 @@ inline AsyncProgressWorker<T>::AsyncProgressWorker(const Object& receiver,
4275
5336
  const Function& callback,
4276
5337
  const char* resource_name,
4277
5338
  const Object& resource)
4278
- : AsyncWorker(receiver, callback, resource_name, resource),
5339
+ : AsyncProgressWorkerBase(receiver, callback, resource_name, resource),
4279
5340
  _asyncdata(nullptr),
4280
5341
  _asyncsize(0) {
4281
- _tsfn = ThreadSafeFunction::New(callback.Env(), callback, resource_name, 1, 1);
4282
5342
  }
4283
5343
 
4284
5344
  #if NAPI_VERSION > 4
@@ -4289,35 +5349,27 @@ inline AsyncProgressWorker<T>::AsyncProgressWorker(Napi::Env env)
4289
5349
 
4290
5350
  template<class T>
4291
5351
  inline AsyncProgressWorker<T>::AsyncProgressWorker(Napi::Env env,
4292
- const char* resource_name)
5352
+ const char* resource_name)
4293
5353
  : AsyncProgressWorker(env, resource_name, Object::New(env)) {
4294
5354
  }
4295
5355
 
4296
5356
  template<class T>
4297
5357
  inline AsyncProgressWorker<T>::AsyncProgressWorker(Napi::Env env,
4298
- const char* resource_name,
4299
- const Object& resource)
4300
- : AsyncWorker(env, resource_name, resource),
5358
+ const char* resource_name,
5359
+ const Object& resource)
5360
+ : AsyncProgressWorkerBase(env, resource_name, resource),
4301
5361
  _asyncdata(nullptr),
4302
5362
  _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
5363
  }
4308
5364
  #endif
4309
5365
 
4310
5366
  template<class T>
4311
5367
  inline AsyncProgressWorker<T>::~AsyncProgressWorker() {
4312
- // Abort pending tsfn call.
4313
- // Don't send progress events after we've already completed.
4314
- _tsfn.Abort();
4315
5368
  {
4316
- std::lock_guard<std::mutex> lock(_mutex);
5369
+ std::lock_guard<std::mutex> lock(this->_mutex);
4317
5370
  _asyncdata = nullptr;
4318
5371
  _asyncsize = 0;
4319
5372
  }
4320
- _tsfn.Release();
4321
5373
  }
4322
5374
 
4323
5375
  template<class T>
@@ -4327,20 +5379,29 @@ inline void AsyncProgressWorker<T>::Execute() {
4327
5379
  }
4328
5380
 
4329
5381
  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
-
5382
+ inline void AsyncProgressWorker<T>::OnWorkProgress(void*) {
4333
5383
  T* data;
4334
5384
  size_t size;
4335
5385
  {
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;
5386
+ std::lock_guard<std::mutex> lock(this->_mutex);
5387
+ data = this->_asyncdata;
5388
+ size = this->_asyncsize;
5389
+ this->_asyncdata = nullptr;
5390
+ this->_asyncsize = 0;
4341
5391
  }
4342
5392
 
4343
- self->OnProgress(data, size);
5393
+ /**
5394
+ * The callback of ThreadSafeFunction is not been invoked immediately on the
5395
+ * callback of uv_async_t (uv io poll), rather the callback of TSFN is
5396
+ * invoked on the right next uv idle callback. There are chances that during
5397
+ * the deferring the signal of uv_async_t is been sent again, i.e. potential
5398
+ * not coalesced two calls of the TSFN callback.
5399
+ */
5400
+ if (data == nullptr) {
5401
+ return;
5402
+ }
5403
+
5404
+ this->OnProgress(data, size);
4344
5405
  delete[] data;
4345
5406
  }
4346
5407
 
@@ -4351,19 +5412,19 @@ inline void AsyncProgressWorker<T>::SendProgress_(const T* data, size_t count) {
4351
5412
 
4352
5413
  T* old_data;
4353
5414
  {
4354
- std::lock_guard<std::mutex> lock(_mutex);
5415
+ std::lock_guard<std::mutex> lock(this->_mutex);
4355
5416
  old_data = _asyncdata;
4356
5417
  _asyncdata = new_data;
4357
5418
  _asyncsize = count;
4358
5419
  }
4359
- _tsfn.NonBlockingCall(this, WorkProgress_);
5420
+ this->NonBlockingCall(nullptr);
4360
5421
 
4361
5422
  delete[] old_data;
4362
5423
  }
4363
5424
 
4364
5425
  template<class T>
4365
5426
  inline void AsyncProgressWorker<T>::Signal() const {
4366
- _tsfn.NonBlockingCall(this, WorkProgress_);
5427
+ this->NonBlockingCall(static_cast<T*>(nullptr));
4367
5428
  }
4368
5429
 
4369
5430
  template<class T>
@@ -4376,8 +5437,125 @@ inline void AsyncProgressWorker<T>::ExecutionProgress::Send(const T* data, size_
4376
5437
  _worker->SendProgress_(data, count);
4377
5438
  }
4378
5439
 
5440
+ ////////////////////////////////////////////////////////////////////////////////
5441
+ // Async Progress Queue Worker class
5442
+ ////////////////////////////////////////////////////////////////////////////////
5443
+ template<class T>
5444
+ inline AsyncProgressQueueWorker<T>::AsyncProgressQueueWorker(const Function& callback)
5445
+ : AsyncProgressQueueWorker(callback, "generic") {
5446
+ }
5447
+
5448
+ template<class T>
5449
+ inline AsyncProgressQueueWorker<T>::AsyncProgressQueueWorker(const Function& callback,
5450
+ const char* resource_name)
5451
+ : AsyncProgressQueueWorker(callback, resource_name, Object::New(callback.Env())) {
5452
+ }
5453
+
5454
+ template<class T>
5455
+ inline AsyncProgressQueueWorker<T>::AsyncProgressQueueWorker(const Function& callback,
5456
+ const char* resource_name,
5457
+ const Object& resource)
5458
+ : AsyncProgressQueueWorker(Object::New(callback.Env()),
5459
+ callback,
5460
+ resource_name,
5461
+ resource) {
5462
+ }
5463
+
5464
+ template<class T>
5465
+ inline AsyncProgressQueueWorker<T>::AsyncProgressQueueWorker(const Object& receiver,
5466
+ const Function& callback)
5467
+ : AsyncProgressQueueWorker(receiver, callback, "generic") {
5468
+ }
5469
+
5470
+ template<class T>
5471
+ inline AsyncProgressQueueWorker<T>::AsyncProgressQueueWorker(const Object& receiver,
5472
+ const Function& callback,
5473
+ const char* resource_name)
5474
+ : AsyncProgressQueueWorker(receiver,
5475
+ callback,
5476
+ resource_name,
5477
+ Object::New(callback.Env())) {
5478
+ }
5479
+
5480
+ template<class T>
5481
+ inline AsyncProgressQueueWorker<T>::AsyncProgressQueueWorker(const Object& receiver,
5482
+ const Function& callback,
5483
+ const char* resource_name,
5484
+ const Object& resource)
5485
+ : AsyncProgressWorkerBase<std::pair<T*, size_t>>(receiver, callback, resource_name, resource, /** unlimited queue size */0) {
5486
+ }
5487
+
5488
+ #if NAPI_VERSION > 4
5489
+ template<class T>
5490
+ inline AsyncProgressQueueWorker<T>::AsyncProgressQueueWorker(Napi::Env env)
5491
+ : AsyncProgressQueueWorker(env, "generic") {
5492
+ }
5493
+
5494
+ template<class T>
5495
+ inline AsyncProgressQueueWorker<T>::AsyncProgressQueueWorker(Napi::Env env,
5496
+ const char* resource_name)
5497
+ : AsyncProgressQueueWorker(env, resource_name, Object::New(env)) {
5498
+ }
5499
+
5500
+ template<class T>
5501
+ inline AsyncProgressQueueWorker<T>::AsyncProgressQueueWorker(Napi::Env env,
5502
+ const char* resource_name,
5503
+ const Object& resource)
5504
+ : AsyncProgressWorkerBase<std::pair<T*, size_t>>(env, resource_name, resource, /** unlimited queue size */0) {
5505
+ }
4379
5506
  #endif
4380
5507
 
5508
+ template<class T>
5509
+ inline void AsyncProgressQueueWorker<T>::Execute() {
5510
+ ExecutionProgress progress(this);
5511
+ Execute(progress);
5512
+ }
5513
+
5514
+ template<class T>
5515
+ inline void AsyncProgressQueueWorker<T>::OnWorkProgress(std::pair<T*, size_t>* datapair) {
5516
+ if (datapair == nullptr) {
5517
+ return;
5518
+ }
5519
+
5520
+ T *data = datapair->first;
5521
+ size_t size = datapair->second;
5522
+
5523
+ this->OnProgress(data, size);
5524
+ delete datapair;
5525
+ delete[] data;
5526
+ }
5527
+
5528
+ template<class T>
5529
+ inline void AsyncProgressQueueWorker<T>::SendProgress_(const T* data, size_t count) {
5530
+ T* new_data = new T[count];
5531
+ std::copy(data, data + count, new_data);
5532
+
5533
+ auto pair = new std::pair<T*, size_t>(new_data, count);
5534
+ this->NonBlockingCall(pair);
5535
+ }
5536
+
5537
+ template<class T>
5538
+ inline void AsyncProgressQueueWorker<T>::Signal() const {
5539
+ this->NonBlockingCall(nullptr);
5540
+ }
5541
+
5542
+ template<class T>
5543
+ inline void AsyncProgressQueueWorker<T>::OnWorkComplete(Napi::Env env, napi_status status) {
5544
+ // Draining queued items in TSFN.
5545
+ AsyncProgressWorkerBase<std::pair<T*, size_t>>::OnWorkComplete(env, status);
5546
+ }
5547
+
5548
+ template<class T>
5549
+ inline void AsyncProgressQueueWorker<T>::ExecutionProgress::Signal() const {
5550
+ _worker->Signal();
5551
+ }
5552
+
5553
+ template<class T>
5554
+ inline void AsyncProgressQueueWorker<T>::ExecutionProgress::Send(const T* data, size_t count) const {
5555
+ _worker->SendProgress_(data, count);
5556
+ }
5557
+ #endif // NAPI_VERSION > 3 && !defined(__wasm32__)
5558
+
4381
5559
  ////////////////////////////////////////////////////////////////////////////////
4382
5560
  // Memory Management class
4383
5561
  ////////////////////////////////////////////////////////////////////////////////
@@ -4407,6 +5585,49 @@ inline const napi_node_version* VersionManagement::GetNodeVersion(Env env) {
4407
5585
  return result;
4408
5586
  }
4409
5587
 
5588
+ #if NAPI_VERSION > 5
5589
+ ////////////////////////////////////////////////////////////////////////////////
5590
+ // Addon<T> class
5591
+ ////////////////////////////////////////////////////////////////////////////////
5592
+
5593
+ template <typename T>
5594
+ inline Object Addon<T>::Init(Env env, Object exports) {
5595
+ T* addon = new T(env, exports);
5596
+ env.SetInstanceData(addon);
5597
+ return addon->entry_point_;
5598
+ }
5599
+
5600
+ template <typename T>
5601
+ inline T* Addon<T>::Unwrap(Object wrapper) {
5602
+ return wrapper.Env().GetInstanceData<T>();
5603
+ }
5604
+
5605
+ template <typename T>
5606
+ inline void
5607
+ Addon<T>::DefineAddon(Object exports,
5608
+ const std::initializer_list<AddonProp>& props) {
5609
+ DefineProperties(exports, props);
5610
+ entry_point_ = exports;
5611
+ }
5612
+
5613
+ template <typename T>
5614
+ inline Napi::Object
5615
+ Addon<T>::DefineProperties(Object object,
5616
+ const std::initializer_list<AddonProp>& props) {
5617
+ const napi_property_descriptor* properties =
5618
+ reinterpret_cast<const napi_property_descriptor*>(props.begin());
5619
+ size_t size = props.size();
5620
+ napi_status status = napi_define_properties(object.Env(),
5621
+ object,
5622
+ size,
5623
+ properties);
5624
+ NAPI_THROW_IF_FAILED(object.Env(), status, object);
5625
+ for (size_t idx = 0; idx < size; idx++)
5626
+ T::AttachPropData(object.Env(), object, &properties[idx]);
5627
+ return object;
5628
+ }
5629
+ #endif // NAPI_VERSION > 5
5630
+
4410
5631
  } // namespace Napi
4411
5632
 
4412
5633
  #endif // SRC_NAPI_INL_H_