node-addon-api 1.7.1 → 2.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/napi-inl.h CHANGED
@@ -9,7 +9,10 @@
9
9
 
10
10
  // Note: Do not include this file directly! Include "napi.h" instead.
11
11
 
12
+ #include <algorithm>
13
+ #include <atomic>
12
14
  #include <cstring>
15
+ #include <mutex>
13
16
  #include <type_traits>
14
17
 
15
18
  namespace Napi {
@@ -17,6 +20,8 @@ namespace Napi {
17
20
  // Helpers to handle functions exposed from C++.
18
21
  namespace details {
19
22
 
23
+ extern std::atomic_bool needs_objectwrap_destructor_fix;
24
+
20
25
  // Attach a data item to an object and delete it when the object gets
21
26
  // garbage-collected.
22
27
  // TODO: Replace this code with `napi_add_finalizer()` whenever it becomes
@@ -24,16 +29,23 @@ namespace details {
24
29
  template <typename FreeType>
25
30
  static inline napi_status AttachData(napi_env env,
26
31
  napi_value obj,
27
- FreeType* data) {
32
+ FreeType* data,
33
+ napi_finalize finalizer = nullptr,
34
+ void* hint = nullptr) {
35
+ napi_status status;
36
+ if (finalizer == nullptr) {
37
+ finalizer = [](napi_env /*env*/, void* data, void* /*hint*/) {
38
+ delete static_cast<FreeType*>(data);
39
+ };
40
+ }
41
+ #if (NAPI_VERSION < 5)
28
42
  napi_value symbol, external;
29
- napi_status status = napi_create_symbol(env, nullptr, &symbol);
43
+ status = napi_create_symbol(env, nullptr, &symbol);
30
44
  if (status == napi_ok) {
31
45
  status = napi_create_external(env,
32
46
  data,
33
- [](napi_env /*env*/, void* data, void* /*hint*/) {
34
- delete static_cast<FreeType*>(data);
35
- },
36
- nullptr,
47
+ finalizer,
48
+ hint,
37
49
  &external);
38
50
  if (status == napi_ok) {
39
51
  napi_property_descriptor desc = {
@@ -49,6 +61,9 @@ static inline napi_status AttachData(napi_env env,
49
61
  status = napi_define_properties(env, obj, 1, &desc);
50
62
  }
51
63
  }
64
+ #else // NAPI_VERSION >= 5
65
+ status = napi_add_finalizer(env, obj, data, finalizer, hint, nullptr);
66
+ #endif
52
67
  return status;
53
68
  }
54
69
 
@@ -239,11 +254,16 @@ struct AccessorCallbackData {
239
254
  // Module registration
240
255
  ////////////////////////////////////////////////////////////////////////////////
241
256
 
242
- #define NODE_API_MODULE(modname, regfunc) \
243
- napi_value __napi_ ## regfunc(napi_env env, \
244
- napi_value exports) { \
245
- return Napi::RegisterModule(env, exports, regfunc); \
246
- } \
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
+ } \
247
267
  NAPI_MODULE(modname, __napi_ ## regfunc)
248
268
 
249
269
  // Adapt the NAPI_MODULE registration function:
@@ -252,6 +272,12 @@ struct AccessorCallbackData {
252
272
  inline napi_value RegisterModule(napi_env env,
253
273
  napi_value exports,
254
274
  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
+
255
281
  return details::WrapCallback([&] {
256
282
  return napi_value(registerCallback(Napi::Env(env),
257
283
  Napi::Object(env, exports)));
@@ -371,14 +397,28 @@ inline bool Value::IsNumber() const {
371
397
  return Type() == napi_number;
372
398
  }
373
399
 
374
- // currently experimental guard with version of NAPI_VERSION that it is
375
- // released in once it is no longer experimental
376
- #if (NAPI_VERSION > 2147483646)
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
377
404
  inline bool Value::IsBigInt() const {
378
405
  return Type() == napi_bigint;
379
406
  }
380
407
  #endif // NAPI_EXPERIMENTAL
381
408
 
409
+ #if (NAPI_VERSION > 4)
410
+ inline bool Value::IsDate() const {
411
+ if (IsEmpty()) {
412
+ return false;
413
+ }
414
+
415
+ bool result;
416
+ napi_status status = napi_is_date(_env, _value, &result);
417
+ NAPI_THROW_IF_FAILED(_env, status, false);
418
+ return result;
419
+ }
420
+ #endif
421
+
382
422
  inline bool Value::IsString() const {
383
423
  return Type() == napi_string;
384
424
  }
@@ -595,9 +635,10 @@ inline double Number::DoubleValue() const {
595
635
  return result;
596
636
  }
597
637
 
598
- // currently experimental guard with version of NAPI_VERSION that it is
599
- // released in once it is no longer experimental
600
- #if (NAPI_VERSION > 2147483646)
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
601
642
  ////////////////////////////////////////////////////////////////////////////////
602
643
  // BigInt Class
603
644
  ////////////////////////////////////////////////////////////////////////////////
@@ -660,6 +701,37 @@ inline void BigInt::ToWords(int* sign_bit, size_t* word_count, uint64_t* words)
660
701
  }
661
702
  #endif // NAPI_EXPERIMENTAL
662
703
 
704
+ #if (NAPI_VERSION > 4)
705
+ ////////////////////////////////////////////////////////////////////////////////
706
+ // Date Class
707
+ ////////////////////////////////////////////////////////////////////////////////
708
+
709
+ inline Date Date::New(napi_env env, double val) {
710
+ napi_value value;
711
+ napi_status status = napi_create_date(env, val, &value);
712
+ NAPI_THROW_IF_FAILED(env, status, Date());
713
+ return Date(env, value);
714
+ }
715
+
716
+ inline Date::Date() : Value() {
717
+ }
718
+
719
+ inline Date::Date(napi_env env, napi_value value) : Value(env, value) {
720
+ }
721
+
722
+ inline Date::operator double() const {
723
+ return ValueOf();
724
+ }
725
+
726
+ inline double Date::ValueOf() const {
727
+ double result;
728
+ napi_status status = napi_get_date_value(
729
+ _env, _value, &result);
730
+ NAPI_THROW_IF_FAILED(_env, status, 0);
731
+ return result;
732
+ }
733
+ #endif
734
+
663
735
  ////////////////////////////////////////////////////////////////////////////////
664
736
  // Name class
665
737
  ////////////////////////////////////////////////////////////////////////////////
@@ -1126,6 +1198,40 @@ inline bool Object::InstanceOf(const Function& constructor) const {
1126
1198
  return result;
1127
1199
  }
1128
1200
 
1201
+ template <typename Finalizer, typename T>
1202
+ inline void Object::AddFinalizer(Finalizer finalizeCallback, T* data) {
1203
+ details::FinalizeData<T, Finalizer>* finalizeData =
1204
+ new details::FinalizeData<T, Finalizer>({ finalizeCallback, nullptr });
1205
+ napi_status status =
1206
+ details::AttachData(_env,
1207
+ *this,
1208
+ data,
1209
+ details::FinalizeData<T, Finalizer>::Wrapper,
1210
+ finalizeData);
1211
+ if (status != napi_ok) {
1212
+ delete finalizeData;
1213
+ NAPI_THROW_IF_FAILED_VOID(_env, status);
1214
+ }
1215
+ }
1216
+
1217
+ template <typename Finalizer, typename T, typename Hint>
1218
+ inline void Object::AddFinalizer(Finalizer finalizeCallback,
1219
+ T* data,
1220
+ Hint* finalizeHint) {
1221
+ details::FinalizeData<T, Finalizer, Hint>* finalizeData =
1222
+ new details::FinalizeData<T, Finalizer, Hint>({ finalizeCallback, finalizeHint });
1223
+ napi_status status =
1224
+ details::AttachData(_env,
1225
+ *this,
1226
+ data,
1227
+ details::FinalizeData<T, Finalizer, Hint>::WrapperWithHint,
1228
+ finalizeData);
1229
+ if (status != napi_ok) {
1230
+ delete finalizeData;
1231
+ NAPI_THROW_IF_FAILED_VOID(_env, status);
1232
+ }
1233
+ }
1234
+
1129
1235
  ////////////////////////////////////////////////////////////////////////////////
1130
1236
  // External class
1131
1237
  ////////////////////////////////////////////////////////////////////////////////
@@ -1950,47 +2056,43 @@ inline Error Error::New(napi_env env) {
1950
2056
  status = napi_get_last_error_info(env, &info);
1951
2057
  NAPI_FATAL_IF_FAILED(status, "Error::New", "napi_get_last_error_info");
1952
2058
 
1953
- if (status == napi_ok) {
1954
- if (info->error_code == napi_pending_exception) {
2059
+ if (info->error_code == napi_pending_exception) {
2060
+ status = napi_get_and_clear_last_exception(env, &error);
2061
+ NAPI_FATAL_IF_FAILED(status, "Error::New", "napi_get_and_clear_last_exception");
2062
+ }
2063
+ else {
2064
+ const char* error_message = info->error_message != nullptr ?
2065
+ info->error_message : "Error in native callback";
2066
+
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) {
1955
2072
  status = napi_get_and_clear_last_exception(env, &error);
1956
2073
  NAPI_FATAL_IF_FAILED(status, "Error::New", "napi_get_and_clear_last_exception");
1957
2074
  }
1958
- else {
1959
- const char* error_message = info->error_message != nullptr ?
1960
- info->error_message : "Error in native callback";
1961
2075
 
1962
- bool isExceptionPending;
1963
- status = napi_is_exception_pending(env, &isExceptionPending);
1964
- NAPI_FATAL_IF_FAILED(status, "Error::New", "napi_is_exception_pending");
1965
-
1966
- if (isExceptionPending) {
1967
- status = napi_get_and_clear_last_exception(env, &error);
1968
- NAPI_FATAL_IF_FAILED(status, "Error::New", "napi_get_and_clear_last_exception");
1969
- }
1970
-
1971
- napi_value message;
1972
- status = napi_create_string_utf8(
1973
- env,
1974
- error_message,
1975
- std::strlen(error_message),
1976
- &message);
1977
- NAPI_FATAL_IF_FAILED(status, "Error::New", "napi_create_string_utf8");
1978
-
1979
- if (status == napi_ok) {
1980
- switch (info->error_code) {
1981
- case napi_object_expected:
1982
- case napi_string_expected:
1983
- case napi_boolean_expected:
1984
- case napi_number_expected:
1985
- status = napi_create_type_error(env, nullptr, message, &error);
1986
- break;
1987
- default:
1988
- status = napi_create_error(env, nullptr, message, &error);
1989
- break;
1990
- }
1991
- NAPI_FATAL_IF_FAILED(status, "Error::New", "napi_create_error");
1992
- }
2076
+ napi_value message;
2077
+ status = napi_create_string_utf8(
2078
+ env,
2079
+ error_message,
2080
+ std::strlen(error_message),
2081
+ &message);
2082
+ NAPI_FATAL_IF_FAILED(status, "Error::New", "napi_create_string_utf8");
2083
+
2084
+ switch (info->error_code) {
2085
+ case napi_object_expected:
2086
+ case napi_string_expected:
2087
+ case napi_boolean_expected:
2088
+ case napi_number_expected:
2089
+ status = napi_create_type_error(env, nullptr, message, &error);
2090
+ break;
2091
+ default:
2092
+ status = napi_create_error(env, nullptr, message, &error);
2093
+ break;
1993
2094
  }
2095
+ NAPI_FATAL_IF_FAILED(status, "Error::New", "napi_create_error");
1994
2096
  }
1995
2097
 
1996
2098
  return Error(env, error);
@@ -2880,14 +2982,37 @@ inline ObjectWrap<T>::ObjectWrap(const Napi::CallbackInfo& callbackInfo) {
2880
2982
  napi_value wrapper = callbackInfo.This();
2881
2983
  napi_status status;
2882
2984
  napi_ref ref;
2883
- T* instance = static_cast<T*>(this);
2884
- status = napi_wrap(env, wrapper, instance, FinalizeCallback, nullptr, &ref);
2985
+ status = napi_wrap(env, wrapper, this, FinalizeCallback, nullptr, &ref);
2885
2986
  NAPI_THROW_IF_FAILED_VOID(env, status);
2886
2987
 
2887
- Reference<Object>* instanceRef = instance;
2988
+ Reference<Object>* instanceRef = this;
2888
2989
  *instanceRef = Reference<Object>(env, ref);
2889
2990
  }
2890
2991
 
2992
+ 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);
3002
+
3003
+ if (Napi::details::needs_objectwrap_destructor_fix) {
3004
+ // If construction failed we delete the reference via
3005
+ // `napi_remove_wrap()`, not via `napi_delete_reference()` in the
3006
+ // `Reference<Object>` destructor. This will prevent the
3007
+ // `Reference<Object>` destructor from doing a double delete of this
3008
+ // reference.
3009
+ _ref = nullptr;
3010
+ _env = nullptr;
3011
+ }
3012
+ }
3013
+ }
3014
+ }
3015
+
2891
3016
  template<typename T>
2892
3017
  inline T* ObjectWrap<T>::Unwrap(Object wrapper) {
2893
3018
  T* unwrapped;
@@ -3261,6 +3386,9 @@ inline ClassPropertyDescriptor<T> ObjectWrap<T>::InstanceValue(
3261
3386
  return desc;
3262
3387
  }
3263
3388
 
3389
+ template <typename T>
3390
+ inline void ObjectWrap<T>::Finalize(Napi::Env /*env*/) {}
3391
+
3264
3392
  template <typename T>
3265
3393
  inline napi_value ObjectWrap<T>::ConstructorCallbackWrapper(
3266
3394
  napi_env env,
@@ -3275,10 +3403,21 @@ inline napi_value ObjectWrap<T>::ConstructorCallbackWrapper(
3275
3403
  return nullptr;
3276
3404
  }
3277
3405
 
3278
- T* instance;
3279
3406
  napi_value wrapper = details::WrapCallback([&] {
3280
3407
  CallbackInfo callbackInfo(env, info);
3281
- instance = new T(callbackInfo);
3408
+ T* instance = new T(callbackInfo);
3409
+ #ifdef NAPI_CPP_EXCEPTIONS
3410
+ instance->_construction_failed = false;
3411
+ #else
3412
+ if (callbackInfo.Env().IsExceptionPending()) {
3413
+ // We need to clear the exception so that removing the wrap might work.
3414
+ Error e = callbackInfo.Env().GetAndClearPendingException();
3415
+ delete instance;
3416
+ e.ThrowAsJavaScriptException();
3417
+ } else {
3418
+ instance->_construction_failed = false;
3419
+ }
3420
+ # endif // NAPI_CPP_EXCEPTIONS
3282
3421
  return callbackInfo.This();
3283
3422
  });
3284
3423
 
@@ -3402,8 +3541,9 @@ inline napi_value ObjectWrap<T>::InstanceSetterCallbackWrapper(
3402
3541
  }
3403
3542
 
3404
3543
  template <typename T>
3405
- inline void ObjectWrap<T>::FinalizeCallback(napi_env /*env*/, void* data, void* /*hint*/) {
3406
- T* instance = reinterpret_cast<T*>(data);
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));
3407
3547
  delete instance;
3408
3548
  }
3409
3549
 
@@ -3421,7 +3561,10 @@ inline HandleScope::HandleScope(Napi::Env env) : _env(env) {
3421
3561
  }
3422
3562
 
3423
3563
  inline HandleScope::~HandleScope() {
3424
- napi_close_handle_scope(_env, _scope);
3564
+ napi_status status = napi_close_handle_scope(_env, _scope);
3565
+ NAPI_FATAL_IF_FAILED(status,
3566
+ "HandleScope::~HandleScope",
3567
+ "napi_close_handle_scope");
3425
3568
  }
3426
3569
 
3427
3570
  inline HandleScope::operator napi_handle_scope() const {
@@ -3446,7 +3589,10 @@ inline EscapableHandleScope::EscapableHandleScope(Napi::Env env) : _env(env) {
3446
3589
  }
3447
3590
 
3448
3591
  inline EscapableHandleScope::~EscapableHandleScope() {
3449
- napi_close_escapable_handle_scope(_env, _scope);
3592
+ napi_status status = napi_close_escapable_handle_scope(_env, _scope);
3593
+ NAPI_FATAL_IF_FAILED(status,
3594
+ "EscapableHandleScope::~EscapableHandleScope",
3595
+ "napi_close_escapable_handle_scope");
3450
3596
  }
3451
3597
 
3452
3598
  inline EscapableHandleScope::operator napi_escapable_handle_scope() const {
@@ -3482,7 +3628,10 @@ inline CallbackScope::CallbackScope(napi_env env, napi_async_context context)
3482
3628
  }
3483
3629
 
3484
3630
  inline CallbackScope::~CallbackScope() {
3485
- napi_close_callback_scope(_env, _scope);
3631
+ napi_status status = napi_close_callback_scope(_env, _scope);
3632
+ NAPI_FATAL_IF_FAILED(status,
3633
+ "CallbackScope::~CallbackScope",
3634
+ "napi_close_callback_scope");
3486
3635
  }
3487
3636
 
3488
3637
  inline CallbackScope::operator napi_callback_scope() const {
@@ -3542,6 +3691,10 @@ inline AsyncContext::operator napi_async_context() const {
3542
3691
  return _context;
3543
3692
  }
3544
3693
 
3694
+ inline Napi::Env AsyncContext::Env() const {
3695
+ return Napi::Env(_env);
3696
+ }
3697
+
3545
3698
  ////////////////////////////////////////////////////////////////////////////////
3546
3699
  // AsyncWorker class
3547
3700
  ////////////////////////////////////////////////////////////////////////////////
@@ -3919,35 +4072,28 @@ inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env,
3919
4072
  }
3920
4073
 
3921
4074
  inline ThreadSafeFunction::ThreadSafeFunction()
3922
- : _tsfn(new napi_threadsafe_function(nullptr)) {
4075
+ : _tsfn() {
3923
4076
  }
3924
4077
 
3925
4078
  inline ThreadSafeFunction::ThreadSafeFunction(
3926
4079
  napi_threadsafe_function tsfn)
3927
- : _tsfn(new napi_threadsafe_function(tsfn)) {
4080
+ : _tsfn(tsfn) {
3928
4081
  }
3929
4082
 
3930
- inline ThreadSafeFunction::ThreadSafeFunction(ThreadSafeFunction&& other)
3931
- : _tsfn(std::move(other._tsfn)) {
3932
- other._tsfn.reset();
3933
- }
3934
-
3935
- inline ThreadSafeFunction& ThreadSafeFunction::operator =(
3936
- ThreadSafeFunction&& other) {
3937
- if (*_tsfn != nullptr) {
3938
- Error::Fatal("ThreadSafeFunction::operator =",
3939
- "You cannot assign a new TSFN because existing one is still alive.");
3940
- return *this;
3941
- }
3942
- _tsfn = std::move(other._tsfn);
3943
- other._tsfn.reset();
3944
- return *this;
4083
+ inline ThreadSafeFunction::operator napi_threadsafe_function() const {
4084
+ return _tsfn;
3945
4085
  }
3946
4086
 
3947
4087
  inline napi_status ThreadSafeFunction::BlockingCall() const {
3948
4088
  return CallInternal(nullptr, napi_tsfn_blocking);
3949
4089
  }
3950
4090
 
4091
+ template <>
4092
+ inline napi_status ThreadSafeFunction::BlockingCall(
4093
+ void* data) const {
4094
+ return napi_call_threadsafe_function(_tsfn, data, napi_tsfn_blocking);
4095
+ }
4096
+
3951
4097
  template <typename Callback>
3952
4098
  inline napi_status ThreadSafeFunction::BlockingCall(
3953
4099
  Callback callback) const {
@@ -3967,6 +4113,12 @@ inline napi_status ThreadSafeFunction::NonBlockingCall() const {
3967
4113
  return CallInternal(nullptr, napi_tsfn_nonblocking);
3968
4114
  }
3969
4115
 
4116
+ template <>
4117
+ inline napi_status ThreadSafeFunction::NonBlockingCall(
4118
+ void* data) const {
4119
+ return napi_call_threadsafe_function(_tsfn, data, napi_tsfn_nonblocking);
4120
+ }
4121
+
3970
4122
  template <typename Callback>
3971
4123
  inline napi_status ThreadSafeFunction::NonBlockingCall(
3972
4124
  Callback callback) const {
@@ -3982,22 +4134,37 @@ inline napi_status ThreadSafeFunction::NonBlockingCall(
3982
4134
  return CallInternal(new CallbackWrapper(wrapper), napi_tsfn_nonblocking);
3983
4135
  }
3984
4136
 
4137
+ inline void ThreadSafeFunction::Ref(napi_env env) const {
4138
+ if (_tsfn != nullptr) {
4139
+ napi_status status = napi_ref_threadsafe_function(env, _tsfn);
4140
+ NAPI_THROW_IF_FAILED_VOID(env, status);
4141
+ }
4142
+ }
4143
+
4144
+ inline void ThreadSafeFunction::Unref(napi_env env) const {
4145
+ if (_tsfn != nullptr) {
4146
+ napi_status status = napi_unref_threadsafe_function(env, _tsfn);
4147
+ NAPI_THROW_IF_FAILED_VOID(env, status);
4148
+ }
4149
+ }
4150
+
3985
4151
  inline napi_status ThreadSafeFunction::Acquire() const {
3986
- return napi_acquire_threadsafe_function(*_tsfn);
4152
+ return napi_acquire_threadsafe_function(_tsfn);
3987
4153
  }
3988
4154
 
3989
4155
  inline napi_status ThreadSafeFunction::Release() {
3990
- return napi_release_threadsafe_function(*_tsfn, napi_tsfn_release);
4156
+ return napi_release_threadsafe_function(_tsfn, napi_tsfn_release);
3991
4157
  }
3992
4158
 
3993
4159
  inline napi_status ThreadSafeFunction::Abort() {
3994
- return napi_release_threadsafe_function(*_tsfn, napi_tsfn_abort);
4160
+ return napi_release_threadsafe_function(_tsfn, napi_tsfn_abort);
3995
4161
  }
3996
4162
 
3997
4163
  inline ThreadSafeFunction::ConvertibleContext
3998
4164
  ThreadSafeFunction::GetContext() const {
3999
4165
  void* context;
4000
- napi_get_threadsafe_function_context(*_tsfn, &context);
4166
+ napi_status status = napi_get_threadsafe_function_context(_tsfn, &context);
4167
+ NAPI_FATAL_IF_FAILED(status, "ThreadSafeFunction::GetContext", "napi_get_threadsafe_function_context");
4001
4168
  return ConvertibleContext({ context });
4002
4169
  }
4003
4170
 
@@ -4020,10 +4187,10 @@ inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env,
4020
4187
 
4021
4188
  ThreadSafeFunction tsfn;
4022
4189
  auto* finalizeData = new details::ThreadSafeFinalize<ContextType, Finalizer,
4023
- FinalizerDataType>({ data, finalizeCallback, tsfn._tsfn.get() });
4190
+ FinalizerDataType>({ data, finalizeCallback, &tsfn._tsfn });
4024
4191
  napi_status status = napi_create_threadsafe_function(env, callback, resource,
4025
4192
  Value::From(env, resourceName), maxQueueSize, initialThreadCount,
4026
- finalizeData, wrapper, context, CallJS, tsfn._tsfn.get());
4193
+ finalizeData, wrapper, context, CallJS, &tsfn._tsfn);
4027
4194
  if (status != napi_ok) {
4028
4195
  delete finalizeData;
4029
4196
  NAPI_THROW_IF_FAILED(env, status, ThreadSafeFunction());
@@ -4036,7 +4203,7 @@ inline napi_status ThreadSafeFunction::CallInternal(
4036
4203
  CallbackWrapper* callbackWrapper,
4037
4204
  napi_threadsafe_function_call_mode mode) const {
4038
4205
  napi_status status = napi_call_threadsafe_function(
4039
- *_tsfn, callbackWrapper, mode);
4206
+ _tsfn, callbackWrapper, mode);
4040
4207
  if (status != napi_ok && callbackWrapper != nullptr) {
4041
4208
  delete callbackWrapper;
4042
4209
  }
@@ -4061,6 +4228,154 @@ inline void ThreadSafeFunction::CallJS(napi_env env,
4061
4228
  Function(env, jsCallback).Call({});
4062
4229
  }
4063
4230
  }
4231
+
4232
+ ////////////////////////////////////////////////////////////////////////////////
4233
+ // Async Progress Worker class
4234
+ ////////////////////////////////////////////////////////////////////////////////
4235
+
4236
+ template<class T>
4237
+ inline AsyncProgressWorker<T>::AsyncProgressWorker(const Function& callback)
4238
+ : AsyncProgressWorker(callback, "generic") {
4239
+ }
4240
+
4241
+ template<class T>
4242
+ inline AsyncProgressWorker<T>::AsyncProgressWorker(const Function& callback,
4243
+ const char* resource_name)
4244
+ : AsyncProgressWorker(callback, resource_name, Object::New(callback.Env())) {
4245
+ }
4246
+
4247
+ template<class T>
4248
+ inline AsyncProgressWorker<T>::AsyncProgressWorker(const Function& callback,
4249
+ const char* resource_name,
4250
+ const Object& resource)
4251
+ : AsyncProgressWorker(Object::New(callback.Env()),
4252
+ callback,
4253
+ resource_name,
4254
+ resource) {
4255
+ }
4256
+
4257
+ template<class T>
4258
+ inline AsyncProgressWorker<T>::AsyncProgressWorker(const Object& receiver,
4259
+ const Function& callback)
4260
+ : AsyncProgressWorker(receiver, callback, "generic") {
4261
+ }
4262
+
4263
+ template<class T>
4264
+ inline AsyncProgressWorker<T>::AsyncProgressWorker(const Object& receiver,
4265
+ const Function& callback,
4266
+ const char* resource_name)
4267
+ : AsyncProgressWorker(receiver,
4268
+ callback,
4269
+ resource_name,
4270
+ Object::New(callback.Env())) {
4271
+ }
4272
+
4273
+ template<class T>
4274
+ inline AsyncProgressWorker<T>::AsyncProgressWorker(const Object& receiver,
4275
+ const Function& callback,
4276
+ const char* resource_name,
4277
+ const Object& resource)
4278
+ : AsyncWorker(receiver, callback, resource_name, resource),
4279
+ _asyncdata(nullptr),
4280
+ _asyncsize(0) {
4281
+ _tsfn = ThreadSafeFunction::New(callback.Env(), callback, resource_name, 1, 1);
4282
+ }
4283
+
4284
+ #if NAPI_VERSION > 4
4285
+ template<class T>
4286
+ inline AsyncProgressWorker<T>::AsyncProgressWorker(Napi::Env env)
4287
+ : AsyncProgressWorker(env, "generic") {
4288
+ }
4289
+
4290
+ template<class T>
4291
+ inline AsyncProgressWorker<T>::AsyncProgressWorker(Napi::Env env,
4292
+ const char* resource_name)
4293
+ : AsyncProgressWorker(env, resource_name, Object::New(env)) {
4294
+ }
4295
+
4296
+ template<class T>
4297
+ inline AsyncProgressWorker<T>::AsyncProgressWorker(Napi::Env env,
4298
+ const char* resource_name,
4299
+ const Object& resource)
4300
+ : AsyncWorker(env, resource_name, resource),
4301
+ _asyncdata(nullptr),
4302
+ _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
+ }
4308
+ #endif
4309
+
4310
+ template<class T>
4311
+ inline AsyncProgressWorker<T>::~AsyncProgressWorker() {
4312
+ // Abort pending tsfn call.
4313
+ // Don't send progress events after we've already completed.
4314
+ _tsfn.Abort();
4315
+ {
4316
+ std::lock_guard<std::mutex> lock(_mutex);
4317
+ _asyncdata = nullptr;
4318
+ _asyncsize = 0;
4319
+ }
4320
+ _tsfn.Release();
4321
+ }
4322
+
4323
+ template<class T>
4324
+ inline void AsyncProgressWorker<T>::Execute() {
4325
+ ExecutionProgress progress(this);
4326
+ Execute(progress);
4327
+ }
4328
+
4329
+ 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
+
4333
+ T* data;
4334
+ size_t size;
4335
+ {
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;
4341
+ }
4342
+
4343
+ self->OnProgress(data, size);
4344
+ delete[] data;
4345
+ }
4346
+
4347
+ template<class T>
4348
+ inline void AsyncProgressWorker<T>::SendProgress_(const T* data, size_t count) {
4349
+ T* new_data = new T[count];
4350
+ std::copy(data, data + count, new_data);
4351
+
4352
+ T* old_data;
4353
+ {
4354
+ std::lock_guard<std::mutex> lock(_mutex);
4355
+ old_data = _asyncdata;
4356
+ _asyncdata = new_data;
4357
+ _asyncsize = count;
4358
+ }
4359
+ _tsfn.NonBlockingCall(this, WorkProgress_);
4360
+
4361
+ delete[] old_data;
4362
+ }
4363
+
4364
+ template<class T>
4365
+ inline void AsyncProgressWorker<T>::Signal() const {
4366
+ _tsfn.NonBlockingCall(this, WorkProgress_);
4367
+ }
4368
+
4369
+ template<class T>
4370
+ inline void AsyncProgressWorker<T>::ExecutionProgress::Signal() const {
4371
+ _worker->Signal();
4372
+ }
4373
+
4374
+ template<class T>
4375
+ inline void AsyncProgressWorker<T>::ExecutionProgress::Send(const T* data, size_t count) const {
4376
+ _worker->SendProgress_(data, count);
4377
+ }
4378
+
4064
4379
  #endif
4065
4380
 
4066
4381
  ////////////////////////////////////////////////////////////////////////////////