react-native-nitro-modules 0.18.2 → 0.20.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 (34) hide show
  1. package/NitroModules.podspec +2 -0
  2. package/README.md +3 -3
  3. package/android/src/main/cpp/core/JPromise.hpp +4 -2
  4. package/android/src/main/cpp/registry/JHybridObjectRegistry.cpp +17 -14
  5. package/android/src/main/cpp/turbomodule/JNitroModules.cpp +0 -2
  6. package/android/src/main/cpp/turbomodule/JNitroModules.hpp +1 -1
  7. package/android/src/main/java/com/margelo/nitro/core/HybridObject.kt +1 -1
  8. package/cpp/core/AnyMap.hpp +2 -1
  9. package/cpp/core/HybridFunction.hpp +8 -0
  10. package/cpp/core/HybridObject.hpp +2 -2
  11. package/cpp/core/Promise.hpp +19 -32
  12. package/cpp/jsi/JSIConverter+Exception.hpp +6 -0
  13. package/cpp/jsi/JSIConverter+Function.hpp +21 -14
  14. package/cpp/jsi/JSIConverter+Future.hpp +5 -4
  15. package/cpp/templates/PromiseType.hpp +32 -0
  16. package/cpp/threading/Dispatcher.hpp +9 -10
  17. package/cpp/utils/NitroDefines.hpp +13 -14
  18. package/cpp/utils/TypeInfo.hpp +1 -1
  19. package/ios/core/ArrayBufferHolder.hpp +1 -1
  20. package/ios/core/ArrayBufferHolder.swift +1 -1
  21. package/ios/core/HybridContext.hpp +2 -1
  22. package/ios/core/HybridObjectSpec.swift +3 -18
  23. package/ios/core/Promise.swift +10 -10
  24. package/ios/core/PromiseHolder.hpp +93 -0
  25. package/ios/utils/MemoryHelper.swift +21 -0
  26. package/ios/utils/Result.hpp +193 -0
  27. package/ios/utils/SwiftClosure.hpp +4 -4
  28. package/ios/utils/SwiftClosure.swift +3 -4
  29. package/lib/commonjs/Constructor.js +1 -1
  30. package/lib/module/Constructor.js +1 -1
  31. package/lib/tsconfig.build.tsbuildinfo +1 -1
  32. package/lib/typescript/Constructor.d.ts +1 -1
  33. package/package.json +4 -4
  34. package/src/Constructor.ts +1 -1
@@ -47,6 +47,8 @@ Pod::Spec.new do |s|
47
47
  "ios/core/ArrayBufferHolder.hpp",
48
48
  "ios/core/AnyMapHolder.hpp",
49
49
  "ios/core/HybridContext.hpp",
50
+ "ios/core/PromiseHolder.hpp",
51
+ "ios/utils/Result.hpp",
50
52
  "ios/utils/RuntimeError.hpp",
51
53
  "ios/utils/SwiftClosure.hpp",
52
54
  ]
package/README.md CHANGED
@@ -177,9 +177,9 @@ The following C++ / JS types are supported out of the box:
177
177
  </tr>
178
178
  <tr>
179
179
  <td><code>(T...) =&gt; R</code></td>
180
- <td><code>std::function&lt;std::future&lt;R&gt; (T...)&gt;</code></td>
181
- <td>❌</td>
182
- <td>❌</td>
180
+ <td><code>std::function&lt;std::shared_ptr&lt;<a href="./cpp/core/Promise.hpp">Promise&lt;R&gt;</a>&gt; (T...)&gt;</code></td>
181
+ <td><code>(T...) -&gt; <a href="./ios/core/Promise.swift">Promise&lt;T&gt;</a></code></td>
182
+ <td><code>(T...) -&gt; <a href="./android/src/main/java/com/margelo/nitro/core/Promise.kt">Promise&lt;T&gt;</a></code></td>
183
183
  </tr>
184
184
  <tr>
185
185
  <td><code>Error</code></td>
@@ -103,7 +103,8 @@ private:
103
103
  } else {
104
104
  // Promise is not yet resolved, put the listener in our queue.
105
105
  auto sharedCallback = jni::make_global(callback);
106
- _onResolvedListeners.emplace_back([=](const auto& result) { sharedCallback->onResolved(result); });
106
+ _onResolvedListeners.emplace_back(
107
+ [sharedCallback = std::move(sharedCallback)](const auto& result) { sharedCallback->onResolved(result); });
107
108
  }
108
109
  }
109
110
  void addOnRejectedListenerJava(jni::alias_ref<JOnRejectedCallback> callback) {
@@ -114,7 +115,8 @@ private:
114
115
  } else {
115
116
  // Promise is not yet rejected, put the listener in our queue.
116
117
  auto sharedCallback = jni::make_global(callback);
117
- _onRejectedListeners.emplace_back([=](const auto& error) { sharedCallback->onRejected(error); });
118
+ _onRejectedListeners.emplace_back(
119
+ [sharedCallback = std::move(sharedCallback)](const auto& error) { sharedCallback->onRejected(error); });
118
120
  }
119
121
  }
120
122
 
@@ -15,23 +15,26 @@ namespace margelo::nitro {
15
15
  void JHybridObjectRegistry::registerHybridObjectConstructor(jni::alias_ref<jni::JClass> clazz, std::string hybridObjectName,
16
16
  jni::alias_ref<JHybridObjectInitializer> constructorFn) {
17
17
  auto sharedInitializer = jni::make_global(constructorFn);
18
- HybridObjectRegistry::registerHybridObjectConstructor(hybridObjectName, [=]() -> std::shared_ptr<HybridObject> {
19
- // 1. Call the Java initializer function
20
- jni::local_ref<JHybridObject::javaobject> hybridObject = sharedInitializer->call();
18
+ HybridObjectRegistry::registerHybridObjectConstructor(
19
+ hybridObjectName,
20
+ [sharedInitializer = std::move(sharedInitializer),
21
+ hybridObjectName = std::move(hybridObjectName)]() -> std::shared_ptr<HybridObject> {
22
+ // 1. Call the Java initializer function
23
+ jni::local_ref<JHybridObject::javaobject> hybridObject = sharedInitializer->call();
21
24
  #ifdef NITRO_DEBUG
22
- if (hybridObject == nullptr) [[unlikely]] {
23
- throw std::runtime_error("Failed to create HybridObject \"" + hybridObjectName + "\" - the constructor returned null!");
24
- }
25
+ if (hybridObject == nullptr) [[unlikely]] {
26
+ throw std::runtime_error("Failed to create HybridObject \"" + hybridObjectName + "\" - the constructor returned null!");
27
+ }
25
28
  #endif
26
29
 
27
- // 2. Make the resulting HybridObject a global (shared) reference
28
- jni::global_ref<JHybridObject::javaobject> globalHybridObject = jni::make_global(hybridObject);
29
- // 3. Create a shared_ptr from the JNI global reference
30
- std::shared_ptr<JHybridObject> sharedCppPart = JNISharedPtr::make_shared_from_jni<JHybridObject>(globalHybridObject);
31
- // 4. Up-cast to a HybridObject (kinda unsafe)
32
- std::shared_ptr<HybridObject> cast = std::static_pointer_cast<HybridObject>(sharedCppPart);
33
- return cast;
34
- });
30
+ // 2. Make the resulting HybridObject a global (shared) reference
31
+ jni::global_ref<JHybridObject::javaobject> globalHybridObject = jni::make_global(hybridObject);
32
+ // 3. Create a shared_ptr from the JNI global reference
33
+ std::shared_ptr<JHybridObject> sharedCppPart = JNISharedPtr::make_shared_from_jni<JHybridObject>(globalHybridObject);
34
+ // 4. Up-cast to a HybridObject (kinda unsafe)
35
+ std::shared_ptr<HybridObject> cast = std::static_pointer_cast<HybridObject>(sharedCppPart);
36
+ return cast;
37
+ });
35
38
  }
36
39
 
37
40
  void JHybridObjectRegistry::registerNatives() {
@@ -10,8 +10,6 @@
10
10
 
11
11
  namespace margelo::nitro {
12
12
 
13
- JNitroModules::JNitroModules() = default;
14
-
15
13
  jni::local_ref<JNitroModules::jhybriddata> JNitroModules::initHybrid(jni::alias_ref<JNitroModules::jhybridobject>) {
16
14
  return makeCxxInstance();
17
15
  }
@@ -18,7 +18,7 @@ public:
18
18
  static auto constexpr kJavaDescriptor = "Lcom/margelo/nitro/NitroModules;";
19
19
 
20
20
  private:
21
- explicit JNitroModules();
21
+ explicit JNitroModules() = default;
22
22
 
23
23
  private:
24
24
  // JNI Methods
@@ -26,7 +26,7 @@ abstract class HybridObject: ExtendableHybridClass {
26
26
  * val memorySize: ULong
27
27
  * get() {
28
28
  * val imageSize = this.bitmap.bytesPerRow * this.bitmap.height
29
- * return getSizeOf(this) + imageSize
29
+ * return imageSize
30
30
  * }
31
31
  * ```
32
32
  */
@@ -4,6 +4,7 @@
4
4
 
5
5
  #pragma once
6
6
 
7
+ #include "NitroDefines.hpp"
7
8
  #include <map>
8
9
  #include <memory>
9
10
  #include <string>
@@ -199,6 +200,6 @@ public:
199
200
 
200
201
  private:
201
202
  std::unordered_map<std::string, AnyValue> _map;
202
- };
203
+ } SWIFT_NONCOPYABLE;
203
204
 
204
205
  } // namespace margelo::nitro
@@ -108,6 +108,14 @@ public:
108
108
  std::string funcName = getHybridFuncFullName<THybrid>(kind, name, hybridInstance.get());
109
109
  std::string message = exception.what();
110
110
  throw jsi::JSError(runtime, funcName + ": " + message);
111
+ #ifdef ANDROID
112
+ // Workaround for https://github.com/mrousavy/nitro/issues/382
113
+ } catch (const std::runtime_error& exception) {
114
+ // Some exception was thrown - add method name information and re-throw as `JSError`.
115
+ std::string funcName = getHybridFuncFullName<THybrid>(kind, name, hybridInstance.get());
116
+ std::string message = exception.what();
117
+ throw jsi::JSError(runtime, funcName + ": " + message);
118
+ #endif
111
119
  } catch (...) {
112
120
  // Some unknown exception was thrown - add method name information and re-throw as `JSError`.
113
121
  std::string funcName = getHybridFuncFullName<THybrid>(kind, name, hybridInstance.get());
@@ -38,11 +38,11 @@ public:
38
38
  /**
39
39
  * HybridObjects cannot be copied.
40
40
  */
41
- HybridObject(const HybridObject& copy) = default;
41
+ HybridObject(const HybridObject& copy) = delete;
42
42
  /**
43
43
  * HybridObjects cannot be moved.
44
44
  */
45
- HybridObject(HybridObject&& move) = default;
45
+ HybridObject(HybridObject&& move) = delete;
46
46
  /**
47
47
  * HybridObjects cannot be default-constructed!
48
48
  */
@@ -28,13 +28,9 @@ public:
28
28
  public:
29
29
  // Promise cannot be copied.
30
30
  Promise(const Promise&) = delete;
31
- // Promise can be moved.
32
- Promise(Promise&&) = default;
33
31
 
34
32
  private:
35
- Promise() {
36
- _mutex = std::make_unique<std::mutex>();
37
- }
33
+ Promise() {}
38
34
 
39
35
  public:
40
36
  /**
@@ -94,7 +90,7 @@ public:
94
90
  * Resolves this Promise with the given result, and calls any pending listeners.
95
91
  */
96
92
  void resolve(TResult&& result) {
97
- std::unique_lock lock(*_mutex);
93
+ std::unique_lock lock(_mutex);
98
94
  #ifdef NITRO_DEBUG
99
95
  assertPromiseState(*this, PromiseTask::WANTS_TO_RESOLVE);
100
96
  #endif
@@ -104,7 +100,7 @@ public:
104
100
  }
105
101
  }
106
102
  void resolve(const TResult& result) {
107
- std::unique_lock lock(*_mutex);
103
+ std::unique_lock lock(_mutex);
108
104
  #ifdef NITRO_DEBUG
109
105
  assertPromiseState(*this, PromiseTask::WANTS_TO_RESOLVE);
110
106
  #endif
@@ -121,7 +117,7 @@ public:
121
117
  throw std::runtime_error("Cannot reject Promise with a null exception_ptr!");
122
118
  }
123
119
 
124
- std::unique_lock lock(*_mutex);
120
+ std::unique_lock lock(_mutex);
125
121
  #ifdef NITRO_DEBUG
126
122
  assertPromiseState(*this, PromiseTask::WANTS_TO_REJECT);
127
123
  #endif
@@ -137,7 +133,7 @@ public:
137
133
  * If the Promise is already resolved, the listener will be immediately called.
138
134
  */
139
135
  void addOnResolvedListener(OnResolvedFunc&& onResolved) {
140
- std::unique_lock lock(*_mutex);
136
+ std::unique_lock lock(_mutex);
141
137
  if (std::holds_alternative<TResult>(_state)) {
142
138
  // Promise is already resolved! Call the callback immediately
143
139
  onResolved(std::get<TResult>(_state));
@@ -147,7 +143,7 @@ public:
147
143
  }
148
144
  }
149
145
  void addOnResolvedListener(const OnResolvedFunc& onResolved) {
150
- std::unique_lock lock(*_mutex);
146
+ std::unique_lock lock(_mutex);
151
147
  if (std::holds_alternative<TResult>(_state)) {
152
148
  // Promise is already resolved! Call the callback immediately
153
149
  onResolved(std::get<TResult>(_state));
@@ -156,15 +152,9 @@ public:
156
152
  _onResolvedListeners.push_back(onResolved);
157
153
  }
158
154
  }
155
+ [[deprecated("Upgrade Nitro to use PromiseHolder<T> instead.")]]
159
156
  void addOnResolvedListenerCopy(const std::function<void(TResult)>& onResolved) {
160
- std::unique_lock lock(*_mutex);
161
- if (std::holds_alternative<TResult>(_state)) {
162
- // Promise is already resolved! Call the callback immediately
163
- onResolved(std::get<TResult>(_state));
164
- } else {
165
- // Promise is not yet resolved, put the listener in our queue.
166
- _onResolvedListeners.push_back(onResolved);
167
- }
157
+ addOnResolvedListener([=](const TResult& value) { onResolved(value); });
168
158
  }
169
159
 
170
160
  /**
@@ -172,7 +162,7 @@ public:
172
162
  * If the Promise is already rejected, the listener will be immediately called.
173
163
  */
174
164
  void addOnRejectedListener(OnRejectedFunc&& onRejected) {
175
- std::unique_lock lock(*_mutex);
165
+ std::unique_lock lock(_mutex);
176
166
  if (std::holds_alternative<std::exception_ptr>(_state)) {
177
167
  // Promise is already rejected! Call the callback immediately
178
168
  onRejected(std::get<std::exception_ptr>(_state));
@@ -182,7 +172,7 @@ public:
182
172
  }
183
173
  }
184
174
  void addOnRejectedListener(const OnRejectedFunc& onRejected) {
185
- std::unique_lock lock(*_mutex);
175
+ std::unique_lock lock(_mutex);
186
176
  if (std::holds_alternative<std::exception_ptr>(_state)) {
187
177
  // Promise is already rejected! Call the callback immediately
188
178
  onRejected(std::get<std::exception_ptr>(_state));
@@ -252,7 +242,7 @@ private:
252
242
  std::variant<std::monostate, TResult, std::exception_ptr> _state;
253
243
  std::vector<OnResolvedFunc> _onResolvedListeners;
254
244
  std::vector<OnRejectedFunc> _onRejectedListeners;
255
- std::unique_ptr<std::mutex> _mutex;
245
+ std::mutex _mutex;
256
246
  };
257
247
 
258
248
  // Specialization for void
@@ -264,12 +254,9 @@ public:
264
254
 
265
255
  public:
266
256
  Promise(const Promise&) = delete;
267
- Promise(Promise&&) = default;
268
257
 
269
258
  private:
270
- Promise() {
271
- _mutex = std::make_unique<std::mutex>();
272
- }
259
+ Promise() {}
273
260
 
274
261
  public:
275
262
  static std::shared_ptr<Promise> create() {
@@ -309,7 +296,7 @@ public:
309
296
 
310
297
  public:
311
298
  void resolve() {
312
- std::unique_lock lock(*_mutex);
299
+ std::unique_lock lock(_mutex);
313
300
  #ifdef NITRO_DEBUG
314
301
  assertPromiseState(*this, PromiseTask::WANTS_TO_RESOLVE);
315
302
  #endif
@@ -323,7 +310,7 @@ public:
323
310
  throw std::runtime_error("Cannot reject Promise with a null exception_ptr!");
324
311
  }
325
312
 
326
- std::unique_lock lock(*_mutex);
313
+ std::unique_lock lock(_mutex);
327
314
  #ifdef NITRO_DEBUG
328
315
  assertPromiseState(*this, PromiseTask::WANTS_TO_REJECT);
329
316
  #endif
@@ -335,7 +322,7 @@ public:
335
322
 
336
323
  public:
337
324
  void addOnResolvedListener(OnResolvedFunc&& onResolved) {
338
- std::unique_lock lock(*_mutex);
325
+ std::unique_lock lock(_mutex);
339
326
  if (_isResolved) {
340
327
  onResolved();
341
328
  } else {
@@ -343,7 +330,7 @@ public:
343
330
  }
344
331
  }
345
332
  void addOnResolvedListener(const OnResolvedFunc& onResolved) {
346
- std::unique_lock lock(*_mutex);
333
+ std::unique_lock lock(_mutex);
347
334
  if (_isResolved) {
348
335
  onResolved();
349
336
  } else {
@@ -351,7 +338,7 @@ public:
351
338
  }
352
339
  }
353
340
  void addOnRejectedListener(OnRejectedFunc&& onRejected) {
354
- std::unique_lock lock(*_mutex);
341
+ std::unique_lock lock(_mutex);
355
342
  if (_error) {
356
343
  onRejected(_error);
357
344
  } else {
@@ -360,7 +347,7 @@ public:
360
347
  }
361
348
  }
362
349
  void addOnRejectedListener(const OnRejectedFunc& onRejected) {
363
- std::unique_lock lock(*_mutex);
350
+ std::unique_lock lock(_mutex);
364
351
  if (_error) {
365
352
  onRejected(_error);
366
353
  } else {
@@ -400,7 +387,7 @@ public:
400
387
  }
401
388
 
402
389
  private:
403
- std::unique_ptr<std::mutex> _mutex;
390
+ std::mutex _mutex;
404
391
  bool _isResolved = false;
405
392
  std::exception_ptr _error;
406
393
  std::vector<OnResolvedFunc> _onResolvedListeners;
@@ -39,6 +39,12 @@ struct JSIConverter<std::exception_ptr> final {
39
39
  } catch (const std::exception& e) {
40
40
  jsi::JSError error(runtime, e.what());
41
41
  return jsi::Value(runtime, error.value());
42
+ #ifdef ANDROID
43
+ // Workaround for https://github.com/mrousavy/nitro/issues/382
44
+ } catch (const std::runtime_error& e) {
45
+ jsi::JSError error(runtime, e.what());
46
+ return jsi::Value(runtime, error.value());
47
+ #endif
42
48
  } catch (...) {
43
49
  // Some unknown exception was thrown - maybe an Objective-C error?
44
50
  std::string errorName = TypeInfo::getCurrentExceptionName();
@@ -15,10 +15,9 @@ struct JSIConverter;
15
15
  #include "JSIConverter.hpp"
16
16
 
17
17
  #include "Dispatcher.hpp"
18
- #include "FutureType.hpp"
19
18
  #include "JSICache.hpp"
19
+ #include "PromiseType.hpp"
20
20
  #include <functional>
21
- #include <future>
22
21
  #include <jsi/jsi.h>
23
22
 
24
23
  namespace margelo::nitro {
@@ -28,8 +27,8 @@ using namespace facebook;
28
27
  // [](Args...) -> T {} <> (Args...) => T
29
28
  template <typename ReturnType, typename... Args>
30
29
  struct JSIConverter<std::function<ReturnType(Args...)>> final {
31
- // std::future<T> -> T
32
- using ResultingType = future_type_v<ReturnType>;
30
+ // Promise<T> -> T
31
+ using ResultingType = promise_type_v<ReturnType>;
33
32
 
34
33
  static inline std::function<ReturnType(Args...)> fromJSI(jsi::Runtime& runtime, const jsi::Value& arg) {
35
34
  // Make function global - it'll be managed by the Runtime's memory, and we only have a weak_ref to it.
@@ -42,7 +41,7 @@ struct JSIConverter<std::function<ReturnType(Args...)>> final {
42
41
 
43
42
  // Create a C++ function that can be called by the consumer.
44
43
  // This will call the jsi::Function if it is still alive.
45
- return [&runtime, weakDispatcher, sharedFunction = std::move(sharedFunction)](Args... args) -> ReturnType {
44
+ return [&runtime, weakDispatcher = std::move(weakDispatcher), sharedFunction = std::move(sharedFunction)](Args... args) -> ReturnType {
46
45
  // Try to get the JS Dispatcher if the Runtime is still alive
47
46
  std::shared_ptr<Dispatcher> dispatcher = weakDispatcher.lock();
48
47
  if (!dispatcher) {
@@ -56,26 +55,34 @@ struct JSIConverter<std::function<ReturnType(Args...)>> final {
56
55
  }
57
56
 
58
57
  if constexpr (std::is_void_v<ResultingType>) {
59
- dispatcher->runAsync(
60
- [&runtime, sharedFunction, ... args = std::move(args)]() { callJSFunction(runtime, sharedFunction, args...); });
61
- } else {
62
- return dispatcher->runAsyncAwaitable<ResultingType>([&runtime, sharedFunction, ... args = std::move(args)]() -> ResultingType {
63
- return callJSFunction(runtime, sharedFunction, args...);
58
+ dispatcher->runAsync([&runtime, sharedFunction = std::move(sharedFunction), ... args = std::move(args)]() {
59
+ callJSFunction(runtime, sharedFunction, args...);
64
60
  });
61
+ } else {
62
+ return dispatcher->runAsyncAwaitable<ResultingType>(
63
+ [&runtime, sharedFunction = std::move(sharedFunction), ... args = std::move(args)]() -> ResultingType {
64
+ return callJSFunction(runtime, sharedFunction, args...);
65
+ });
65
66
  }
66
67
  };
67
68
  }
68
69
 
69
- static inline jsi::Value toJSI(jsi::Runtime& runtime, const std::function<ReturnType(Args...)>& function) {
70
- jsi::HostFunctionType jsFunction = [function](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* args,
71
- size_t count) -> jsi::Value {
70
+ static inline jsi::Value toJSI(jsi::Runtime& runtime, std::function<ReturnType(Args...)>&& function) {
71
+ jsi::HostFunctionType jsFunction = [function = std::move(function)](jsi::Runtime& runtime, const jsi::Value& thisValue,
72
+ const jsi::Value* args, size_t count) -> jsi::Value {
72
73
  if (count != sizeof...(Args)) [[unlikely]] {
73
74
  throw jsi::JSError(runtime, "Function expected " + std::to_string(sizeof...(Args)) + " arguments, but received " +
74
75
  std::to_string(count) + "!");
75
76
  }
76
77
  return callHybridFunction(function, runtime, args, std::index_sequence_for<Args...>{});
77
78
  };
78
- return jsi::Function::createFromHostFunction(runtime, jsi::PropNameID::forUtf8(runtime, "hostFunction"), sizeof...(Args), jsFunction);
79
+ return jsi::Function::createFromHostFunction(runtime, jsi::PropNameID::forUtf8(runtime, "hostFunction"), sizeof...(Args),
80
+ std::move(jsFunction));
81
+ }
82
+
83
+ static inline jsi::Value toJSI(jsi::Runtime& runtime, const std::function<ReturnType(Args...)>& function) {
84
+ std::function<ReturnType(Args...)> copy = function;
85
+ return toJSI(runtime, std::move(copy));
79
86
  }
80
87
 
81
88
  static inline bool canConvert(jsi::Runtime& runtime, const jsi::Value& value) {
@@ -26,8 +26,9 @@ using namespace facebook;
26
26
  template <typename TResult>
27
27
  struct JSIConverter<std::future<TResult>> final {
28
28
  [[deprecated("Use JSIConverter<std::shared_ptr<Promise<T>>> instead.")]]
29
- static inline std::future<TResult> fromJSI(jsi::Runtime&, const jsi::Value&) {
30
- throw std::runtime_error("Promise cannot be converted to a native type - it needs to be awaited first!");
29
+ static inline std::future<TResult> fromJSI(jsi::Runtime& runtime, const jsi::Value& value) {
30
+ auto promise = JSIConverter<std::shared_ptr<Promise<TResult>>>::fromJSI(runtime, value);
31
+ return promise->await();
31
32
  }
32
33
 
33
34
  [[deprecated("Use JSIConverter<std::shared_ptr<Promise<T>>> instead.")]]
@@ -37,8 +38,8 @@ struct JSIConverter<std::future<TResult>> final {
37
38
  }
38
39
 
39
40
  [[deprecated("Use JSIConverter<std::shared_ptr<Promise<T>>> instead.")]]
40
- static inline bool canConvert(jsi::Runtime&, const jsi::Value&) {
41
- throw std::runtime_error("jsi::Value of type Promise cannot be converted to std::future yet!");
41
+ static inline bool canConvert(jsi::Runtime& runtime, const jsi::Value& value) {
42
+ return JSIConverter<std::shared_ptr<Promise<TResult>>>::canConvert(runtime, value);
42
43
  }
43
44
  };
44
45
 
@@ -0,0 +1,32 @@
1
+ //
2
+ // PromiseType.hpp
3
+ // NitroModules
4
+ //
5
+ // Created by Marc Rousavy on 09.12.24.
6
+ //
7
+
8
+ #pragma once
9
+
10
+ #include "Promise.hpp"
11
+ #include <type_traits>
12
+
13
+ namespace margelo::nitro {
14
+
15
+ // Gets the `T` in `Promise<T>`.
16
+ template <typename T>
17
+ struct promise_type {
18
+ using type = void;
19
+ };
20
+ template <typename T>
21
+ struct promise_type<Promise<T>> {
22
+ using type = T;
23
+ };
24
+ template <typename T>
25
+ struct promise_type<std::shared_ptr<Promise<T>>> {
26
+ using type = T;
27
+ };
28
+
29
+ template <typename T>
30
+ using promise_type_v = typename promise_type<std::remove_reference_t<T>>::type;
31
+
32
+ } // namespace margelo::nitro
@@ -4,8 +4,8 @@
4
4
 
5
5
  #pragma once
6
6
 
7
+ #include "Promise.hpp"
7
8
  #include <functional>
8
- #include <future>
9
9
  #include <jsi/jsi.h>
10
10
  #include <queue>
11
11
  #include <unordered_map>
@@ -42,13 +42,12 @@ public:
42
42
 
43
43
  /**
44
44
  * Run the given function asynchronously on the Thread this Dispatcher is managing,
45
- * and return a future that will hold the result of the function.
45
+ * and return a `Promise<T>` that will hold the result of the function.
46
46
  */
47
47
  template <typename T>
48
- std::future<T> runAsyncAwaitable(std::function<T()>&& function) {
48
+ std::shared_ptr<Promise<T>> runAsyncAwaitable(std::function<T()>&& function) {
49
49
  // 1. Create Promise that can be shared between this and dispatcher thread
50
- auto promise = std::make_shared<std::promise<T>>();
51
- std::future<T> future = promise->get_future();
50
+ auto promise = Promise<T>::create();
52
51
 
53
52
  runAsync([function = std::move(function), promise]() {
54
53
  try {
@@ -56,21 +55,21 @@ public:
56
55
  // 4. Call the actual function on the new Thread
57
56
  function();
58
57
  // 5.a. Resolve the Promise if we succeeded
59
- promise->set_value();
58
+ promise->resolve();
60
59
  } else {
61
60
  // 4. Call the actual function on the new Thread
62
61
  T result = function();
63
62
  // 5.a. Resolve the Promise if we succeeded
64
- promise->set_value(std::move(result));
63
+ promise->resolve(std::move(result));
65
64
  }
66
65
  } catch (...) {
67
66
  // 5.b. Reject the Promise if the call failed
68
- promise->set_exception(std::current_exception());
67
+ promise->reject(std::current_exception());
69
68
  }
70
69
  });
71
70
 
72
- // 3. Return an open future that gets resolved later by the dispatcher Thread
73
- return future;
71
+ // 3. Return an open `Promise<T>` that gets resolved later by the dispatcher Thread
72
+ return promise;
74
73
  }
75
74
 
76
75
  private:
@@ -9,7 +9,7 @@
9
9
  #define NitroDefines_h
10
10
 
11
11
  // Sets the version of the native Nitro core library
12
- #define NITRO_VERSION "0.18.2"
12
+ #define NITRO_VERSION "0.20.0"
13
13
 
14
14
  // Sets whether to use debug or optimized production build flags
15
15
  #ifdef DEBUG
@@ -31,19 +31,6 @@
31
31
  #define _CXX_INTEROP_HAS_ATTRIBUTE(x) 0
32
32
  #endif
33
33
 
34
- #if _CXX_INTEROP_HAS_ATTRIBUTE(swift_attr)
35
- // Rename Type for Swift
36
- #define SWIFT_NAME(_name) __attribute__((swift_name(#_name)))
37
- // Make Swift type private
38
- #define SWIFT_PRIVATE __attribute__((swift_private))
39
- // Make getter + setter a computed property
40
- #define SWIFT_COMPUTED_PROPERTY __attribute__((swift_attr("import_computed_property")))
41
- #else
42
- #define SWIFT_NAME(_name)
43
- #define SWIFT_PRIVATE
44
- #define SWIFT_COMPUTED_PROPERTY
45
- #endif
46
-
47
34
  #if _CXX_INTEROP_HAS_ATTRIBUTE(enum_extensibility)
48
35
  // Enum is marked as closed/not extensible
49
36
  #define CLOSED_ENUM __attribute__((enum_extensibility(closed)))
@@ -51,4 +38,16 @@
51
38
  #define CLOSED_ENUM
52
39
  #endif
53
40
 
41
+ #if __has_include(<swift/bridging>)
42
+ // Swift's bridging header defines those things
43
+ #include <swift/bridging>
44
+ #define SWIFT_PRIVATE __attribute__((swift_private))
45
+ #else
46
+ // If we don't have Swift bridging header, those macros do nothing
47
+ #define SWIFT_NAME(_name)
48
+ #define SWIFT_PRIVATE
49
+ #define SWIFT_COMPUTED_PROPERTY
50
+ #define SWIFT_NONCOPYABLE
51
+ #endif
52
+
54
53
  #endif /* NitroDefines_h */
@@ -48,7 +48,7 @@ public:
48
48
  #endif
49
49
 
50
50
  // Make a few edge-cases nicer.
51
- name = replaceRegex(name, R"(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>)", "std::string");
51
+ name = replaceRegex(name, R"(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> ?>)", "std::string");
52
52
  name = replaceRegex(name, R"(std::__1::vector<([^>]+), std::__1::allocator<\1>>)", "std::vector<$1>");
53
53
  name = replaceRegex(name, R"(std::__1::map<([^,]+), ([^>]+), std::__1::less<\1>, std::__1::allocator<std::__1::pair<const \1, \2>>>)",
54
54
  "std::map<$1, $2>");
@@ -8,9 +8,9 @@
8
8
  #pragma once
9
9
 
10
10
  #include "ArrayBuffer.hpp"
11
+ #include "NitroDefines.hpp"
11
12
  #include "SwiftClosure.hpp"
12
13
  #include <memory>
13
- #include <swift/bridging>
14
14
 
15
15
  namespace margelo::nitro {
16
16
 
@@ -50,7 +50,7 @@ public extension ArrayBufferHolder {
50
50
  /**
51
51
  * Copy the given `ArrayBufferHolder` into a new **owning** `ArrayBufferHolder`.
52
52
  */
53
- static func copy(of other: ArrayBufferHolder) -> ArrayBufferHolder {
53
+ static func copy(of other: borrowing ArrayBufferHolder) -> ArrayBufferHolder {
54
54
  let data = UnsafeMutablePointer<UInt8>.allocate(capacity: other.size)
55
55
  let pointer = other.data.assumingMemoryBound(to: UInt8.self)
56
56
  data.initialize(from: pointer, count: other.size)
@@ -24,7 +24,8 @@ namespace margelo::nitro {
24
24
  * This can be used in remote implementations, e.g. in a Swift implementation
25
25
  * to properly (weak-)reference the `HybridObject` instead of re-creating it each time.
26
26
  */
27
- struct HybridContext final {
27
+ struct [[deprecated("Update Nitrogen and re-generate your specs.")]]
28
+ HybridContext final {
28
29
  public:
29
30
  std::weak_ptr<HybridObject> cppPart;
30
31