react-native-nitro-modules 0.17.0 → 0.18.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 +6 -1
- package/cpp/core/Promise.hpp +89 -55
- package/cpp/jsi/JSIConverter+Exception.hpp +17 -7
- package/cpp/jsi/JSIConverter+Function.hpp +5 -7
- package/cpp/jsi/JSIConverter+Promise.hpp +4 -4
- package/cpp/platform/ThreadUtils.hpp +2 -0
- package/cpp/templates/IsSharedPtrTo.hpp +0 -1
- package/cpp/utils/AssertPromiseState.hpp +34 -0
- package/cpp/utils/BorrowingReference.hpp +1 -1
- package/cpp/utils/OwningReference.hpp +2 -2
- package/cpp/utils/TypeInfo.hpp +12 -11
- package/ios/core/RuntimeError.swift +11 -4
- package/ios/turbomodule/NativeNitroModules+OldArch.mm +1 -1
- package/ios/utils/RuntimeError.hpp +11 -4
- package/package.json +4 -2
package/NitroModules.podspec
CHANGED
|
@@ -12,7 +12,12 @@ Pod::Spec.new do |s|
|
|
|
12
12
|
s.license = package["license"]
|
|
13
13
|
s.authors = package["author"]
|
|
14
14
|
|
|
15
|
-
s.platforms = {
|
|
15
|
+
s.platforms = {
|
|
16
|
+
:ios => min_ios_version_supported,
|
|
17
|
+
:visionos => 1.0,
|
|
18
|
+
:macos => 10.13,
|
|
19
|
+
:tvos => 13.4,
|
|
20
|
+
}
|
|
16
21
|
s.source = { :git => "https://github.com/mrousavy/nitro.git", :tag => "#{s.version}" }
|
|
17
22
|
|
|
18
23
|
# VisionCamera Core C++ bindings
|
package/cpp/core/Promise.hpp
CHANGED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
#pragma once
|
|
6
6
|
|
|
7
|
+
#include "AssertPromiseState.hpp"
|
|
8
|
+
#include "NitroDefines.hpp"
|
|
7
9
|
#include "ThreadPool.hpp"
|
|
8
10
|
#include "TypeInfo.hpp"
|
|
9
11
|
#include <exception>
|
|
@@ -17,14 +19,14 @@ namespace margelo::nitro {
|
|
|
17
19
|
|
|
18
20
|
using namespace facebook;
|
|
19
21
|
|
|
20
|
-
template <typename TResult
|
|
22
|
+
template <typename TResult>
|
|
21
23
|
class Promise final {
|
|
22
24
|
public:
|
|
23
25
|
using OnResolvedFunc = std::function<void(const TResult&)>;
|
|
24
|
-
using OnRejectedFunc = std::function<void(const
|
|
26
|
+
using OnRejectedFunc = std::function<void(const std::exception_ptr&)>;
|
|
25
27
|
|
|
26
28
|
public:
|
|
27
|
-
// Promise cannot be
|
|
29
|
+
// Promise cannot be copied.
|
|
28
30
|
Promise(const Promise&) = delete;
|
|
29
31
|
// Promise can be moved.
|
|
30
32
|
Promise(Promise&&) = default;
|
|
@@ -53,13 +55,9 @@ public:
|
|
|
53
55
|
// Run the code, then resolve.
|
|
54
56
|
TResult result = run();
|
|
55
57
|
promise->resolve(std::move(result));
|
|
56
|
-
} catch (const TError& exception) {
|
|
57
|
-
// It threw an std::exception.
|
|
58
|
-
promise->reject(exception);
|
|
59
58
|
} catch (...) {
|
|
60
|
-
// It threw
|
|
61
|
-
std::
|
|
62
|
-
promise->reject(std::runtime_error("Unknown non-std error! Name: " + name));
|
|
59
|
+
// It threw an error.
|
|
60
|
+
promise->reject(std::current_exception());
|
|
63
61
|
}
|
|
64
62
|
});
|
|
65
63
|
return promise;
|
|
@@ -85,9 +83,9 @@ public:
|
|
|
85
83
|
/**
|
|
86
84
|
* Creates an immediately rejected Promise.
|
|
87
85
|
*/
|
|
88
|
-
static std::shared_ptr<Promise> rejected(
|
|
86
|
+
static std::shared_ptr<Promise> rejected(const std::exception_ptr& error) {
|
|
89
87
|
auto promise = create();
|
|
90
|
-
promise->reject(
|
|
88
|
+
promise->reject(error);
|
|
91
89
|
return promise;
|
|
92
90
|
}
|
|
93
91
|
|
|
@@ -97,33 +95,45 @@ public:
|
|
|
97
95
|
*/
|
|
98
96
|
void resolve(TResult&& result) {
|
|
99
97
|
std::unique_lock lock(*_mutex);
|
|
100
|
-
|
|
98
|
+
#ifdef NITRO_DEBUG
|
|
99
|
+
assertPromiseState(*this, PromiseTask::WANTS_TO_RESOLVE);
|
|
100
|
+
#endif
|
|
101
|
+
_state = std::move(result);
|
|
101
102
|
for (const auto& onResolved : _onResolvedListeners) {
|
|
102
|
-
onResolved(std::get<TResult>(
|
|
103
|
+
onResolved(std::get<TResult>(_state));
|
|
103
104
|
}
|
|
104
105
|
}
|
|
105
106
|
void resolve(const TResult& result) {
|
|
106
107
|
std::unique_lock lock(*_mutex);
|
|
107
|
-
|
|
108
|
+
#ifdef NITRO_DEBUG
|
|
109
|
+
assertPromiseState(*this, PromiseTask::WANTS_TO_RESOLVE);
|
|
110
|
+
#endif
|
|
111
|
+
_state = result;
|
|
108
112
|
for (const auto& onResolved : _onResolvedListeners) {
|
|
109
|
-
onResolved(std::get<TResult>(
|
|
113
|
+
onResolved(std::get<TResult>(_state));
|
|
110
114
|
}
|
|
111
115
|
}
|
|
112
116
|
/**
|
|
113
117
|
* Rejects this Promise with the given error, and calls any pending listeners.
|
|
114
118
|
*/
|
|
115
|
-
void reject(
|
|
119
|
+
void reject(const std::exception& exception) {
|
|
116
120
|
std::unique_lock lock(*_mutex);
|
|
117
|
-
|
|
121
|
+
#ifdef NITRO_DEBUG
|
|
122
|
+
assertPromiseState(*this, PromiseTask::WANTS_TO_REJECT);
|
|
123
|
+
#endif
|
|
124
|
+
_state = std::make_exception_ptr(exception);
|
|
118
125
|
for (const auto& onRejected : _onRejectedListeners) {
|
|
119
|
-
onRejected(std::get<
|
|
126
|
+
onRejected(std::get<std::exception_ptr>(_state));
|
|
120
127
|
}
|
|
121
128
|
}
|
|
122
|
-
void reject(const
|
|
129
|
+
void reject(const std::exception_ptr& exception) {
|
|
123
130
|
std::unique_lock lock(*_mutex);
|
|
124
|
-
|
|
131
|
+
#ifdef NITRO_DEBUG
|
|
132
|
+
assertPromiseState(*this, PromiseTask::WANTS_TO_REJECT);
|
|
133
|
+
#endif
|
|
134
|
+
_state = exception;
|
|
125
135
|
for (const auto& onRejected : _onRejectedListeners) {
|
|
126
|
-
onRejected(
|
|
136
|
+
onRejected(exception);
|
|
127
137
|
}
|
|
128
138
|
}
|
|
129
139
|
|
|
@@ -134,9 +144,9 @@ public:
|
|
|
134
144
|
*/
|
|
135
145
|
void addOnResolvedListener(OnResolvedFunc&& onResolved) {
|
|
136
146
|
std::unique_lock lock(*_mutex);
|
|
137
|
-
if (std::holds_alternative<TResult>(
|
|
147
|
+
if (std::holds_alternative<TResult>(_state)) {
|
|
138
148
|
// Promise is already resolved! Call the callback immediately
|
|
139
|
-
onResolved(std::get<TResult>(
|
|
149
|
+
onResolved(std::get<TResult>(_state));
|
|
140
150
|
} else {
|
|
141
151
|
// Promise is not yet resolved, put the listener in our queue.
|
|
142
152
|
_onResolvedListeners.push_back(std::move(onResolved));
|
|
@@ -144,9 +154,9 @@ public:
|
|
|
144
154
|
}
|
|
145
155
|
void addOnResolvedListener(const OnResolvedFunc& onResolved) {
|
|
146
156
|
std::unique_lock lock(*_mutex);
|
|
147
|
-
if (std::holds_alternative<TResult>(
|
|
157
|
+
if (std::holds_alternative<TResult>(_state)) {
|
|
148
158
|
// Promise is already resolved! Call the callback immediately
|
|
149
|
-
onResolved(std::get<TResult>(
|
|
159
|
+
onResolved(std::get<TResult>(_state));
|
|
150
160
|
} else {
|
|
151
161
|
// Promise is not yet resolved, put the listener in our queue.
|
|
152
162
|
_onResolvedListeners.push_back(onResolved);
|
|
@@ -154,9 +164,9 @@ public:
|
|
|
154
164
|
}
|
|
155
165
|
void addOnResolvedListenerCopy(const std::function<void(TResult)>& onResolved) {
|
|
156
166
|
std::unique_lock lock(*_mutex);
|
|
157
|
-
if (std::holds_alternative<TResult>(
|
|
167
|
+
if (std::holds_alternative<TResult>(_state)) {
|
|
158
168
|
// Promise is already resolved! Call the callback immediately
|
|
159
|
-
onResolved(std::get<TResult>(
|
|
169
|
+
onResolved(std::get<TResult>(_state));
|
|
160
170
|
} else {
|
|
161
171
|
// Promise is not yet resolved, put the listener in our queue.
|
|
162
172
|
_onResolvedListeners.push_back(onResolved);
|
|
@@ -169,9 +179,9 @@ public:
|
|
|
169
179
|
*/
|
|
170
180
|
void addOnRejectedListener(OnRejectedFunc&& onRejected) {
|
|
171
181
|
std::unique_lock lock(*_mutex);
|
|
172
|
-
if (std::holds_alternative<
|
|
182
|
+
if (std::holds_alternative<std::exception_ptr>(_state)) {
|
|
173
183
|
// Promise is already rejected! Call the callback immediately
|
|
174
|
-
onRejected(std::get<
|
|
184
|
+
onRejected(std::get<std::exception_ptr>(_state));
|
|
175
185
|
} else {
|
|
176
186
|
// Promise is not yet rejected, put the listener in our queue.
|
|
177
187
|
_onRejectedListeners.push_back(std::move(onRejected));
|
|
@@ -179,15 +189,26 @@ public:
|
|
|
179
189
|
}
|
|
180
190
|
void addOnRejectedListener(const OnRejectedFunc& onRejected) {
|
|
181
191
|
std::unique_lock lock(*_mutex);
|
|
182
|
-
if (std::holds_alternative<
|
|
192
|
+
if (std::holds_alternative<std::exception_ptr>(_state)) {
|
|
183
193
|
// Promise is already rejected! Call the callback immediately
|
|
184
|
-
onRejected(std::get<
|
|
194
|
+
onRejected(std::get<std::exception_ptr>(_state));
|
|
185
195
|
} else {
|
|
186
196
|
// Promise is not yet rejected, put the listener in our queue.
|
|
187
197
|
_onRejectedListeners.push_back(onRejected);
|
|
188
198
|
}
|
|
189
199
|
}
|
|
190
200
|
|
|
201
|
+
public:
|
|
202
|
+
/**
|
|
203
|
+
* Gets an awaitable `std::future<T>` for this `Promise<T>`.
|
|
204
|
+
*/
|
|
205
|
+
std::future<TResult> await() {
|
|
206
|
+
auto promise = std::make_shared<std::promise<TResult>>();
|
|
207
|
+
addOnResolvedListener([promise](const TResult& result) { promise->set_value(result); });
|
|
208
|
+
addOnRejectedListener([promise](const std::exception_ptr& error) { promise->set_exception(error); });
|
|
209
|
+
return promise->get_future();
|
|
210
|
+
}
|
|
211
|
+
|
|
191
212
|
public:
|
|
192
213
|
/**
|
|
193
214
|
* Get the result of the Promise if it has been resolved.
|
|
@@ -197,17 +218,17 @@ public:
|
|
|
197
218
|
if (!isResolved()) {
|
|
198
219
|
throw std::runtime_error("Cannot get result when Promise is not yet resolved!");
|
|
199
220
|
}
|
|
200
|
-
return std::get<TResult>(
|
|
221
|
+
return std::get<TResult>(_state);
|
|
201
222
|
}
|
|
202
223
|
/**
|
|
203
224
|
* Get the error of the Promise if it has been rejected.
|
|
204
225
|
* If the Promise is not rejected, this will throw.
|
|
205
226
|
*/
|
|
206
|
-
inline const
|
|
227
|
+
inline const std::exception_ptr& getError() {
|
|
207
228
|
if (!isRejected()) {
|
|
208
229
|
throw std::runtime_error("Cannot get error when Promise is not yet rejected!");
|
|
209
230
|
}
|
|
210
|
-
return std::get<
|
|
231
|
+
return std::get<std::exception_ptr>(_state);
|
|
211
232
|
}
|
|
212
233
|
|
|
213
234
|
public:
|
|
@@ -216,36 +237,36 @@ public:
|
|
|
216
237
|
*/
|
|
217
238
|
[[nodiscard]]
|
|
218
239
|
inline bool isResolved() const noexcept {
|
|
219
|
-
return std::holds_alternative<TResult>(
|
|
240
|
+
return std::holds_alternative<TResult>(_state);
|
|
220
241
|
}
|
|
221
242
|
/**
|
|
222
243
|
* Gets whether this Promise has been rejected with an error, or not.
|
|
223
244
|
*/
|
|
224
245
|
[[nodiscard]]
|
|
225
246
|
inline bool isRejected() const noexcept {
|
|
226
|
-
return std::holds_alternative<
|
|
247
|
+
return std::holds_alternative<std::exception_ptr>(_state);
|
|
227
248
|
}
|
|
228
249
|
/**
|
|
229
250
|
* Gets whether this Promise has not yet been resolved nor rejected.
|
|
230
251
|
*/
|
|
231
252
|
[[nodiscard]]
|
|
232
253
|
inline bool isPending() const noexcept {
|
|
233
|
-
return std::holds_alternative<std::monostate>(
|
|
254
|
+
return std::holds_alternative<std::monostate>(_state);
|
|
234
255
|
}
|
|
235
256
|
|
|
236
257
|
private:
|
|
237
|
-
std::variant<std::monostate, TResult,
|
|
258
|
+
std::variant<std::monostate, TResult, std::exception_ptr> _state;
|
|
238
259
|
std::vector<OnResolvedFunc> _onResolvedListeners;
|
|
239
260
|
std::vector<OnRejectedFunc> _onRejectedListeners;
|
|
240
261
|
std::unique_ptr<std::mutex> _mutex;
|
|
241
262
|
};
|
|
242
263
|
|
|
243
264
|
// Specialization for void
|
|
244
|
-
template
|
|
245
|
-
class Promise<void
|
|
265
|
+
template <>
|
|
266
|
+
class Promise<void> final {
|
|
246
267
|
public:
|
|
247
268
|
using OnResolvedFunc = std::function<void()>;
|
|
248
|
-
using OnRejectedFunc = std::function<void(const
|
|
269
|
+
using OnRejectedFunc = std::function<void(const std::exception_ptr&)>;
|
|
249
270
|
|
|
250
271
|
public:
|
|
251
272
|
Promise(const Promise&) = delete;
|
|
@@ -268,13 +289,9 @@ public:
|
|
|
268
289
|
// Run the code, then resolve.
|
|
269
290
|
run();
|
|
270
291
|
promise->resolve();
|
|
271
|
-
} catch (const TError& exception) {
|
|
272
|
-
// It threw an std::exception.
|
|
273
|
-
promise->reject(exception);
|
|
274
292
|
} catch (...) {
|
|
275
|
-
// It threw
|
|
276
|
-
std::
|
|
277
|
-
promise->reject(std::runtime_error("Unknown non-std error! Name: " + name));
|
|
293
|
+
// It threw an error.
|
|
294
|
+
promise->reject(std::current_exception());
|
|
278
295
|
}
|
|
279
296
|
});
|
|
280
297
|
return promise;
|
|
@@ -290,32 +307,41 @@ public:
|
|
|
290
307
|
promise->resolve();
|
|
291
308
|
return promise;
|
|
292
309
|
}
|
|
293
|
-
static std::shared_ptr<Promise> rejected(
|
|
310
|
+
static std::shared_ptr<Promise> rejected(const std::exception_ptr& error) {
|
|
294
311
|
auto promise = create();
|
|
295
|
-
promise->reject(
|
|
312
|
+
promise->reject(error);
|
|
296
313
|
return promise;
|
|
297
314
|
}
|
|
298
315
|
|
|
299
316
|
public:
|
|
300
317
|
void resolve() {
|
|
301
318
|
std::unique_lock lock(*_mutex);
|
|
319
|
+
#ifdef NITRO_DEBUG
|
|
320
|
+
assertPromiseState(*this, PromiseTask::WANTS_TO_RESOLVE);
|
|
321
|
+
#endif
|
|
302
322
|
_isResolved = true;
|
|
303
323
|
for (const auto& onResolved : _onResolvedListeners) {
|
|
304
324
|
onResolved();
|
|
305
325
|
}
|
|
306
326
|
}
|
|
307
|
-
void reject(
|
|
327
|
+
void reject(const std::exception& exception) {
|
|
308
328
|
std::unique_lock lock(*_mutex);
|
|
309
|
-
|
|
329
|
+
#ifdef NITRO_DEBUG
|
|
330
|
+
assertPromiseState(*this, PromiseTask::WANTS_TO_REJECT);
|
|
331
|
+
#endif
|
|
332
|
+
_error = std::make_exception_ptr(exception);
|
|
310
333
|
for (const auto& onRejected : _onRejectedListeners) {
|
|
311
334
|
onRejected(_error.value());
|
|
312
335
|
}
|
|
313
336
|
}
|
|
314
|
-
void reject(const
|
|
337
|
+
void reject(const std::exception_ptr& exception) {
|
|
315
338
|
std::unique_lock lock(*_mutex);
|
|
339
|
+
#ifdef NITRO_DEBUG
|
|
340
|
+
assertPromiseState(*this, PromiseTask::WANTS_TO_REJECT);
|
|
341
|
+
#endif
|
|
316
342
|
_error = exception;
|
|
317
343
|
for (const auto& onRejected : _onRejectedListeners) {
|
|
318
|
-
onRejected(
|
|
344
|
+
onRejected(exception);
|
|
319
345
|
}
|
|
320
346
|
}
|
|
321
347
|
|
|
@@ -356,7 +382,15 @@ public:
|
|
|
356
382
|
}
|
|
357
383
|
|
|
358
384
|
public:
|
|
359
|
-
|
|
385
|
+
std::future<void> await() {
|
|
386
|
+
auto promise = std::make_shared<std::promise<void>>();
|
|
387
|
+
addOnResolvedListener([promise]() { promise->set_value(); });
|
|
388
|
+
addOnRejectedListener([promise](const std::exception_ptr& error) { promise->set_exception(error); });
|
|
389
|
+
return promise->get_future();
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
public:
|
|
393
|
+
inline const std::exception_ptr& getError() {
|
|
360
394
|
if (!isRejected()) {
|
|
361
395
|
throw std::runtime_error("Cannot get error when Promise is not yet rejected!");
|
|
362
396
|
}
|
|
@@ -380,7 +414,7 @@ public:
|
|
|
380
414
|
private:
|
|
381
415
|
std::unique_ptr<std::mutex> _mutex;
|
|
382
416
|
bool _isResolved = false;
|
|
383
|
-
std::optional<
|
|
417
|
+
std::optional<std::exception_ptr> _error;
|
|
384
418
|
std::vector<OnResolvedFunc> _onResolvedListeners;
|
|
385
419
|
std::vector<OnRejectedFunc> _onRejectedListeners;
|
|
386
420
|
};
|
|
@@ -12,6 +12,7 @@ struct JSIConverter;
|
|
|
12
12
|
|
|
13
13
|
#include "JSIConverter.hpp"
|
|
14
14
|
|
|
15
|
+
#include "TypeInfo.hpp"
|
|
15
16
|
#include <exception>
|
|
16
17
|
#include <jsi/jsi.h>
|
|
17
18
|
|
|
@@ -19,18 +20,27 @@ namespace margelo::nitro {
|
|
|
19
20
|
|
|
20
21
|
using namespace facebook;
|
|
21
22
|
|
|
22
|
-
// std::
|
|
23
|
+
// std::exception_ptr <> Error
|
|
23
24
|
template <>
|
|
24
|
-
struct JSIConverter<std::
|
|
25
|
-
static inline std::
|
|
25
|
+
struct JSIConverter<std::exception_ptr> final {
|
|
26
|
+
static inline std::exception_ptr fromJSI(jsi::Runtime& runtime, const jsi::Value& error) {
|
|
26
27
|
jsi::Object object = error.asObject(runtime);
|
|
27
28
|
std::string name = object.getProperty(runtime, "name").asString(runtime).utf8(runtime);
|
|
28
29
|
std::string message = object.getProperty(runtime, "message").asString(runtime).utf8(runtime);
|
|
29
|
-
return std::runtime_error(name + ": " + message);
|
|
30
|
+
return std::make_exception_ptr(std::runtime_error(name + ": " + message));
|
|
30
31
|
}
|
|
31
|
-
static inline jsi::Value toJSI(jsi::Runtime& runtime, const std::
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
static inline jsi::Value toJSI(jsi::Runtime& runtime, const std::exception_ptr& exception) {
|
|
33
|
+
try {
|
|
34
|
+
std::rethrow_exception(exception);
|
|
35
|
+
} catch (const std::exception& e) {
|
|
36
|
+
jsi::JSError error(runtime, e.what());
|
|
37
|
+
return jsi::Value(runtime, error.value());
|
|
38
|
+
} catch (...) {
|
|
39
|
+
// Some unknown exception was thrown - maybe an Objective-C error?
|
|
40
|
+
std::string errorName = TypeInfo::getCurrentExceptionName();
|
|
41
|
+
jsi::JSError error(runtime, "Unknown " + errorName + " error.");
|
|
42
|
+
return jsi::Value(runtime, error.value());
|
|
43
|
+
}
|
|
34
44
|
}
|
|
35
45
|
static inline bool canConvert(jsi::Runtime& runtime, const jsi::Value& value) {
|
|
36
46
|
if (!value.isObject()) {
|
|
@@ -56,14 +56,12 @@ struct JSIConverter<std::function<ReturnType(Args...)>> final {
|
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
if constexpr (std::is_void_v<ResultingType>) {
|
|
59
|
-
dispatcher->runAsync(
|
|
60
|
-
|
|
61
|
-
});
|
|
59
|
+
dispatcher->runAsync(
|
|
60
|
+
[&runtime, sharedFunction, ... args = std::move(args)]() { callJSFunction(runtime, sharedFunction, args...); });
|
|
62
61
|
} else {
|
|
63
|
-
return dispatcher->runAsyncAwaitable<ResultingType>(
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
});
|
|
62
|
+
return dispatcher->runAsyncAwaitable<ResultingType>([&runtime, sharedFunction, ... args = std::move(args)]() -> ResultingType {
|
|
63
|
+
return callJSFunction(runtime, sharedFunction, args...);
|
|
64
|
+
});
|
|
67
65
|
}
|
|
68
66
|
};
|
|
69
67
|
}
|
|
@@ -37,8 +37,8 @@ struct JSIConverter<std::shared_ptr<Promise<TResult>>> final {
|
|
|
37
37
|
return JSIConverter<std::function<void(TResult)>>::toJSI(runtime, [=](const TResult& result) { promise->resolve(result); });
|
|
38
38
|
}
|
|
39
39
|
}();
|
|
40
|
-
auto catchCallback = JSIConverter<std::function<void(std::
|
|
41
|
-
runtime, [=](const std::
|
|
40
|
+
auto catchCallback = JSIConverter<std::function<void(std::exception_ptr)>>::toJSI(
|
|
41
|
+
runtime, [=](const std::exception_ptr& exception) { promise->reject(exception); });
|
|
42
42
|
|
|
43
43
|
// Chain .then listeners on JS Promise (onResolved and onRejected)
|
|
44
44
|
jsi::Object jsPromise = value.asObject(runtime);
|
|
@@ -65,7 +65,7 @@ struct JSIConverter<std::shared_ptr<Promise<TResult>>> final {
|
|
|
65
65
|
promise->addOnResolvedListener(std::move(resolver));
|
|
66
66
|
}
|
|
67
67
|
// Add rejecter listener
|
|
68
|
-
auto rejecter = JSIConverter<std::function<void(std::
|
|
68
|
+
auto rejecter = JSIConverter<std::function<void(std::exception_ptr)>>::fromJSI(runtime, arguments[1]);
|
|
69
69
|
promise->addOnRejectedListener(std::move(rejecter));
|
|
70
70
|
|
|
71
71
|
return jsi::Value::undefined();
|
|
@@ -89,7 +89,7 @@ struct JSIConverter<std::shared_ptr<Promise<TResult>>> final {
|
|
|
89
89
|
// Promise is already rejected - just return immediately
|
|
90
90
|
jsi::Object promiseObject = runtime.global().getPropertyAsObject(runtime, "Promise");
|
|
91
91
|
jsi::Function createRejectedPromise = promiseObject.getPropertyAsFunction(runtime, "reject");
|
|
92
|
-
jsi::Value error = JSIConverter<std::
|
|
92
|
+
jsi::Value error = JSIConverter<std::exception_ptr>::toJSI(runtime, promise->getError());
|
|
93
93
|
return createRejectedPromise.call(runtime, std::move(error));
|
|
94
94
|
} else {
|
|
95
95
|
throw std::runtime_error("Promise has invalid state!");
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
//
|
|
2
|
+
// AssertPromiseState.hpp
|
|
3
|
+
// NitroModules
|
|
4
|
+
//
|
|
5
|
+
// Created by Marc Rousavy on 20.11.24.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
#pragma once
|
|
9
|
+
|
|
10
|
+
namespace margelo::nitro {
|
|
11
|
+
template <typename TResult>
|
|
12
|
+
class Promise;
|
|
13
|
+
} // namespace margelo::nitro
|
|
14
|
+
|
|
15
|
+
#include "Promise.hpp"
|
|
16
|
+
#include "TypeInfo.hpp"
|
|
17
|
+
#include <exception>
|
|
18
|
+
#include <string>
|
|
19
|
+
|
|
20
|
+
namespace margelo::nitro {
|
|
21
|
+
|
|
22
|
+
enum PromiseTask { WANTS_TO_RESOLVE, WANTS_TO_REJECT };
|
|
23
|
+
|
|
24
|
+
template <typename TResult>
|
|
25
|
+
void assertPromiseState(Promise<TResult>& promise, PromiseTask task) {
|
|
26
|
+
if (!promise.isPending()) [[unlikely]] {
|
|
27
|
+
std::string taskString = task == WANTS_TO_RESOLVE ? "resolve" : "reject";
|
|
28
|
+
std::string state = promise.isResolved() ? "resolved" : "rejected";
|
|
29
|
+
throw std::runtime_error("Cannot " + taskString + " Promise<" + TypeInfo::getFriendlyTypename<TResult>() + "> - it is already " +
|
|
30
|
+
state + "!");
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
} // namespace margelo::nitro
|
|
@@ -34,7 +34,7 @@ public:
|
|
|
34
34
|
|
|
35
35
|
explicit OwningReference(T* value)
|
|
36
36
|
: _value(value), _isDeleted(new bool(false)), _strongRefCount(new std::atomic_size_t(1)), _weakRefCount(new std::atomic_size_t(0)),
|
|
37
|
-
_mutex(new std::
|
|
37
|
+
_mutex(new std::recursive_mutex()) {}
|
|
38
38
|
|
|
39
39
|
OwningReference(const OwningReference& ref)
|
|
40
40
|
: _value(ref._value), _isDeleted(ref._isDeleted), _strongRefCount(ref._strongRefCount), _weakRefCount(ref._weakRefCount),
|
|
@@ -229,7 +229,7 @@ private:
|
|
|
229
229
|
bool* _isDeleted;
|
|
230
230
|
std::atomic_size_t* _strongRefCount;
|
|
231
231
|
std::atomic_size_t* _weakRefCount;
|
|
232
|
-
std::
|
|
232
|
+
std::recursive_mutex* _mutex;
|
|
233
233
|
};
|
|
234
234
|
|
|
235
235
|
} // namespace margelo::nitro
|
package/cpp/utils/TypeInfo.hpp
CHANGED
|
@@ -24,17 +24,6 @@ struct TypeInfo final {
|
|
|
24
24
|
public:
|
|
25
25
|
TypeInfo() = delete;
|
|
26
26
|
|
|
27
|
-
/**
|
|
28
|
-
* Get the name of the currently thrown exception
|
|
29
|
-
*/
|
|
30
|
-
static inline const char* getCurrentExceptionName() {
|
|
31
|
-
#if __has_include(<cxxabi.h>)
|
|
32
|
-
return __cxxabiv1::__cxa_current_exception_type()->name();
|
|
33
|
-
#else
|
|
34
|
-
return "<unknown>";
|
|
35
|
-
#endif
|
|
36
|
-
}
|
|
37
|
-
|
|
38
27
|
static inline std::string replaceRegex(const std::string& original, const std::string& pattern, const std::string& replacement) {
|
|
39
28
|
std::regex re(pattern);
|
|
40
29
|
return std::regex_replace(original, re, replacement);
|
|
@@ -112,6 +101,18 @@ public:
|
|
|
112
101
|
std::string string = stream.str();
|
|
113
102
|
return string.substr(0, string.length() - 2);
|
|
114
103
|
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Get the name of the currently thrown exception
|
|
107
|
+
*/
|
|
108
|
+
static inline std::string getCurrentExceptionName() {
|
|
109
|
+
#if __has_include(<cxxabi.h>)
|
|
110
|
+
std::string name = __cxxabiv1::__cxa_current_exception_type()->name();
|
|
111
|
+
return demangleName(name);
|
|
112
|
+
#else
|
|
113
|
+
return "<unknown>";
|
|
114
|
+
#endif
|
|
115
|
+
}
|
|
115
116
|
};
|
|
116
117
|
|
|
117
118
|
} // namespace margelo::nitro
|
|
@@ -12,13 +12,20 @@ import Foundation
|
|
|
12
12
|
*
|
|
13
13
|
* Throw this error in Nitro Modules to provide clear and concise error messages to JS.
|
|
14
14
|
*/
|
|
15
|
-
|
|
15
|
+
@frozen
|
|
16
|
+
public enum RuntimeError: Error, CustomStringConvertible {
|
|
16
17
|
case error(withMessage: String)
|
|
17
|
-
|
|
18
|
+
|
|
19
|
+
public var description: String {
|
|
20
|
+
switch self {
|
|
21
|
+
case .error(let message): return message
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
18
25
|
/**
|
|
19
26
|
* Creates a new `RuntimeError` from the given C++ `std::exception`.
|
|
20
27
|
*/
|
|
21
|
-
public static func from(cppError: std.
|
|
28
|
+
public static func from(cppError: std.exception_ptr) -> RuntimeError {
|
|
22
29
|
let message = margelo.nitro.get_exception_message(cppError)
|
|
23
30
|
return .error(withMessage: String(message))
|
|
24
31
|
}
|
|
@@ -28,7 +35,7 @@ public extension Error {
|
|
|
28
35
|
/**
|
|
29
36
|
* Converts this `Error` to a C++ `std::exception`.
|
|
30
37
|
*/
|
|
31
|
-
func toCpp() -> std.
|
|
38
|
+
func toCpp() -> std.exception_ptr {
|
|
32
39
|
let message = String(describing: self)
|
|
33
40
|
return margelo.nitro.make_exception(std.string(message))
|
|
34
41
|
}
|
|
@@ -57,7 +57,7 @@ RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(install) {
|
|
|
57
57
|
// 5. Install Nitro
|
|
58
58
|
nitro::install(*runtime, dispatcher);
|
|
59
59
|
return nil;
|
|
60
|
-
} catch (std::exception& error) {
|
|
60
|
+
} catch (const std::exception& error) {
|
|
61
61
|
// ?. Any C++ error occurred (probably in nitro::install()?)
|
|
62
62
|
return [NSString stringWithCString:error.what() encoding:kCFStringEncodingUTF8];
|
|
63
63
|
} catch (...) {
|
|
@@ -12,12 +12,19 @@
|
|
|
12
12
|
|
|
13
13
|
namespace margelo::nitro {
|
|
14
14
|
|
|
15
|
-
static inline std::
|
|
16
|
-
return std::runtime_error(message);
|
|
15
|
+
static inline std::exception_ptr make_exception(const std::string& message) {
|
|
16
|
+
return std::make_exception_ptr(std::runtime_error(message));
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
static inline std::string get_exception_message(const std::
|
|
20
|
-
|
|
19
|
+
static inline std::string get_exception_message(const std::exception_ptr& exception) {
|
|
20
|
+
try {
|
|
21
|
+
std::rethrow_exception(exception);
|
|
22
|
+
} catch (const std::exception& error) {
|
|
23
|
+
return error.what();
|
|
24
|
+
} catch (...) {
|
|
25
|
+
std::string errorName = TypeInfo::getCurrentExceptionName();
|
|
26
|
+
return "Unknown " + errorName + " exception";
|
|
27
|
+
}
|
|
21
28
|
}
|
|
22
29
|
|
|
23
30
|
} // namespace margelo::nitro
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-nitro-modules",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.0",
|
|
4
4
|
"description": "Insanely fast native C++, Swift or Kotlin modules with a statically compiled binding layer to JSI.",
|
|
5
5
|
"main": "lib/commonjs/index",
|
|
6
6
|
"module": "lib/module/index",
|
|
@@ -28,6 +28,8 @@
|
|
|
28
28
|
"ios",
|
|
29
29
|
"android",
|
|
30
30
|
"visionOS",
|
|
31
|
+
"tvOS",
|
|
32
|
+
"macOS",
|
|
31
33
|
"cpp",
|
|
32
34
|
"framework",
|
|
33
35
|
"react",
|
|
@@ -70,7 +72,7 @@
|
|
|
70
72
|
"jest": "*",
|
|
71
73
|
"react": "*",
|
|
72
74
|
"react-native": "*",
|
|
73
|
-
"react-native-builder-bob": "^0.
|
|
75
|
+
"react-native-builder-bob": "^0.33.1"
|
|
74
76
|
},
|
|
75
77
|
"peerDependencies": {
|
|
76
78
|
"react": "*",
|