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.
- package/NitroModules.podspec +2 -0
- package/README.md +3 -3
- package/android/src/main/cpp/core/JPromise.hpp +4 -2
- package/android/src/main/cpp/registry/JHybridObjectRegistry.cpp +17 -14
- package/android/src/main/cpp/turbomodule/JNitroModules.cpp +0 -2
- package/android/src/main/cpp/turbomodule/JNitroModules.hpp +1 -1
- package/android/src/main/java/com/margelo/nitro/core/HybridObject.kt +1 -1
- package/cpp/core/AnyMap.hpp +2 -1
- package/cpp/core/HybridFunction.hpp +8 -0
- package/cpp/core/HybridObject.hpp +2 -2
- package/cpp/core/Promise.hpp +19 -32
- package/cpp/jsi/JSIConverter+Exception.hpp +6 -0
- package/cpp/jsi/JSIConverter+Function.hpp +21 -14
- package/cpp/jsi/JSIConverter+Future.hpp +5 -4
- package/cpp/templates/PromiseType.hpp +32 -0
- package/cpp/threading/Dispatcher.hpp +9 -10
- package/cpp/utils/NitroDefines.hpp +13 -14
- package/cpp/utils/TypeInfo.hpp +1 -1
- package/ios/core/ArrayBufferHolder.hpp +1 -1
- package/ios/core/ArrayBufferHolder.swift +1 -1
- package/ios/core/HybridContext.hpp +2 -1
- package/ios/core/HybridObjectSpec.swift +3 -18
- package/ios/core/Promise.swift +10 -10
- package/ios/core/PromiseHolder.hpp +93 -0
- package/ios/utils/MemoryHelper.swift +21 -0
- package/ios/utils/Result.hpp +193 -0
- package/ios/utils/SwiftClosure.hpp +4 -4
- package/ios/utils/SwiftClosure.swift +3 -4
- package/lib/commonjs/Constructor.js +1 -1
- package/lib/module/Constructor.js +1 -1
- package/lib/tsconfig.build.tsbuildinfo +1 -1
- package/lib/typescript/Constructor.d.ts +1 -1
- package/package.json +4 -4
- package/src/Constructor.ts +1 -1
package/NitroModules.podspec
CHANGED
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...) => R</code></td>
|
|
180
|
-
<td><code>std::function<std::
|
|
181
|
-
<td
|
|
182
|
-
<td
|
|
180
|
+
<td><code>std::function<std::shared_ptr<<a href="./cpp/core/Promise.hpp">Promise<R></a>> (T...)></code></td>
|
|
181
|
+
<td><code>(T...) -> <a href="./ios/core/Promise.swift">Promise<T></a></code></td>
|
|
182
|
+
<td><code>(T...) -> <a href="./android/src/main/java/com/margelo/nitro/core/Promise.kt">Promise<T></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(
|
|
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(
|
|
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(
|
|
19
|
-
|
|
20
|
-
|
|
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
|
-
|
|
23
|
-
|
|
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
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
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() {
|
package/cpp/core/AnyMap.hpp
CHANGED
|
@@ -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) =
|
|
41
|
+
HybridObject(const HybridObject& copy) = delete;
|
|
42
42
|
/**
|
|
43
43
|
* HybridObjects cannot be moved.
|
|
44
44
|
*/
|
|
45
|
-
HybridObject(HybridObject&& move) =
|
|
45
|
+
HybridObject(HybridObject&& move) = delete;
|
|
46
46
|
/**
|
|
47
47
|
* HybridObjects cannot be default-constructed!
|
|
48
48
|
*/
|
package/cpp/core/Promise.hpp
CHANGED
|
@@ -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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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::
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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::
|
|
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
|
-
//
|
|
32
|
-
using ResultingType =
|
|
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
|
-
|
|
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,
|
|
70
|
-
jsi::HostFunctionType jsFunction = [function](jsi::Runtime& runtime, const jsi::Value& thisValue,
|
|
71
|
-
|
|
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),
|
|
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
|
|
30
|
-
|
|
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
|
|
41
|
-
|
|
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
|
|
45
|
+
* and return a `Promise<T>` that will hold the result of the function.
|
|
46
46
|
*/
|
|
47
47
|
template <typename T>
|
|
48
|
-
std::
|
|
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 =
|
|
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->
|
|
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->
|
|
63
|
+
promise->resolve(std::move(result));
|
|
65
64
|
}
|
|
66
65
|
} catch (...) {
|
|
67
66
|
// 5.b. Reject the Promise if the call failed
|
|
68
|
-
promise->
|
|
67
|
+
promise->reject(std::current_exception());
|
|
69
68
|
}
|
|
70
69
|
});
|
|
71
70
|
|
|
72
|
-
// 3. Return an open
|
|
73
|
-
return
|
|
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.
|
|
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 */
|
package/cpp/utils/TypeInfo.hpp
CHANGED
|
@@ -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
|
|
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>");
|
|
@@ -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
|
|
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
|
|