react-native-nitro-modules 0.30.0 → 0.30.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/android/src/main/java/com/margelo/nitro/NitroModules.kt +50 -42
- package/android/src/main/java/com/margelo/nitro/NitroModulesPackage.kt +26 -22
- package/android/src/main/java/com/margelo/nitro/core/AnyMap.kt +44 -7
- package/android/src/main/java/com/margelo/nitro/core/AnyValue.kt +145 -139
- package/android/src/main/java/com/margelo/nitro/core/ArrayBuffer.kt +162 -154
- package/android/src/main/java/com/margelo/nitro/core/HybridObject.kt +51 -51
- package/android/src/main/java/com/margelo/nitro/core/Promise.kt +9 -1
- package/android/src/main/java/com/margelo/nitro/utils/HardwareBuffer+updateFrom.kt +1 -2
- package/android/src/main/java/com/margelo/nitro/utils/HardwareBufferUtils.kt +33 -26
- package/android/src/main/java/com/margelo/nitro/views/HybridView.kt +20 -19
- package/cpp/jsi/{JSIConverter+HybridObject.hpp → JSIConverter+NativeState.hpp} +19 -13
- package/cpp/jsi/JSIConverter.hpp +1 -1
- package/cpp/threading/Dispatcher.cpp +16 -13
- package/cpp/utils/NitroDefines.hpp +1 -1
- package/ios/core/AnyMap.swift +12 -17
- package/ios/core/ArrayBuffer.swift +45 -36
- package/ios/core/HybridObject.swift +4 -6
- package/ios/core/Promise.swift +23 -25
- package/ios/core/RuntimeError.swift +6 -8
- package/ios/utils/Date+fromChrono.swift +4 -4
- package/ios/utils/SwiftClosure.swift +12 -16
- package/ios/views/HybridView.swift +30 -32
- package/lib/commonjs/turbomodule/NativeNitroModules.js +17 -0
- package/lib/commonjs/turbomodule/NativeNitroModules.js.map +1 -1
- package/lib/module/turbomodule/NativeNitroModules.js +17 -0
- package/lib/module/turbomodule/NativeNitroModules.js.map +1 -1
- package/lib/tsconfig.build.tsbuildinfo +1 -1
- package/lib/typescript/turbomodule/NativeNitroModules.d.ts +1 -0
- package/lib/typescript/turbomodule/NativeNitroModules.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/turbomodule/NativeNitroModules.ts +19 -0
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
//
|
|
2
|
-
// Created by Marc Rousavy on
|
|
2
|
+
// Created by Marc Rousavy on 16.10.25.
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
#pragma once
|
|
6
6
|
|
|
7
|
-
// Forward declare a few of the common types that might have cyclic includes.
|
|
8
7
|
namespace margelo::nitro {
|
|
9
8
|
class HybridObject;
|
|
10
9
|
} // namespace margelo::nitro
|
|
@@ -19,7 +18,7 @@ namespace margelo::nitro {
|
|
|
19
18
|
|
|
20
19
|
using namespace facebook;
|
|
21
20
|
|
|
22
|
-
//
|
|
21
|
+
// NativeState <> {}
|
|
23
22
|
template <typename T>
|
|
24
23
|
struct JSIConverter<T, std::enable_if_t<is_shared_ptr_to_v<T, jsi::NativeState>>> final {
|
|
25
24
|
using TPointee = typename T::element_type;
|
|
@@ -35,21 +34,28 @@ struct JSIConverter<T, std::enable_if_t<is_shared_ptr_to_v<T, jsi::NativeState>>
|
|
|
35
34
|
}
|
|
36
35
|
}
|
|
37
36
|
#endif
|
|
38
|
-
jsi::Object object = arg.asObject(runtime);
|
|
39
37
|
|
|
38
|
+
jsi::Object object = arg.asObject(runtime);
|
|
40
39
|
#ifdef NITRO_DEBUG
|
|
41
|
-
if (!object.hasNativeState
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
throw jsi::JSError(runtime, invalidTypeErrorMessage(stringRepresentation, "It does not have a NativeState!"));
|
|
45
|
-
} else {
|
|
46
|
-
std::string stringRepresentation = arg.toString(runtime).utf8(runtime);
|
|
47
|
-
throw jsi::JSError(runtime, invalidTypeErrorMessage(stringRepresentation, "It has a different NativeState<T>!"));
|
|
48
|
-
}
|
|
40
|
+
if (!object.hasNativeState(runtime)) [[unlikely]] {
|
|
41
|
+
std::string stringRepresentation = arg.toString(runtime).utf8(runtime);
|
|
42
|
+
throw jsi::JSError(runtime, invalidTypeErrorMessage(stringRepresentation, "It does not have a NativeState!"));
|
|
49
43
|
}
|
|
50
44
|
#endif
|
|
45
|
+
|
|
51
46
|
std::shared_ptr<jsi::NativeState> nativeState = object.getNativeState(runtime);
|
|
52
|
-
|
|
47
|
+
std::shared_ptr<TPointee> result = std::dynamic_pointer_cast<TPointee>(nativeState);
|
|
48
|
+
if (result == nullptr) [[unlikely]] {
|
|
49
|
+
std::string stringRepresentation = arg.toString(runtime).utf8(runtime);
|
|
50
|
+
std::string typeName = TypeInfo::getFriendlyTypename<TPointee>();
|
|
51
|
+
throw jsi::JSError(runtime, invalidTypeErrorMessage(stringRepresentation, "Downcasting failed - It has a different NativeState<T>!\n"
|
|
52
|
+
"- Did you accidentally pass a different type?\n"
|
|
53
|
+
"- Is react-native-nitro-modules linked multiple times? "
|
|
54
|
+
"Ensure you don't have any duplicate symbols for `" +
|
|
55
|
+
typeName + "` in your app's binary."));
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return result;
|
|
53
59
|
}
|
|
54
60
|
|
|
55
61
|
static inline jsi::Value toJSI(jsi::Runtime& runtime, const T& arg) {
|
package/cpp/jsi/JSIConverter.hpp
CHANGED
|
@@ -187,7 +187,7 @@ struct JSIConverter<std::string> final {
|
|
|
187
187
|
#include "JSIConverter+Exception.hpp"
|
|
188
188
|
#include "JSIConverter+Function.hpp"
|
|
189
189
|
#include "JSIConverter+HostObject.hpp"
|
|
190
|
-
#include "JSIConverter+
|
|
190
|
+
#include "JSIConverter+NativeState.hpp"
|
|
191
191
|
#include "JSIConverter+Optional.hpp"
|
|
192
192
|
#include "JSIConverter+Promise.hpp"
|
|
193
193
|
#include "JSIConverter+Tuple.hpp"
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
//
|
|
7
7
|
|
|
8
8
|
#include "Dispatcher.hpp"
|
|
9
|
+
#include "JSIConverter.hpp"
|
|
9
10
|
#include "JSIHelpers.hpp"
|
|
10
11
|
#include "NitroDefines.hpp"
|
|
11
12
|
#include "NitroLogger.hpp"
|
|
@@ -16,6 +17,10 @@ using namespace facebook;
|
|
|
16
17
|
|
|
17
18
|
static constexpr auto GLOBAL_DISPATCHER_HOLDER_NAME = "__nitroDispatcher";
|
|
18
19
|
|
|
20
|
+
/**
|
|
21
|
+
* This map is only statically linked once to this library.
|
|
22
|
+
* If multiple versions of react-native-nitro-modules are linked, there would be multiple maps. We catch that issue later.
|
|
23
|
+
*/
|
|
19
24
|
std::unordered_map<jsi::Runtime * NON_NULL, std::weak_ptr<Dispatcher>> Dispatcher::_globalCache;
|
|
20
25
|
|
|
21
26
|
void Dispatcher::installRuntimeGlobalDispatcher(jsi::Runtime& runtime, std::shared_ptr<Dispatcher> dispatcher) {
|
|
@@ -25,9 +30,8 @@ void Dispatcher::installRuntimeGlobalDispatcher(jsi::Runtime& runtime, std::shar
|
|
|
25
30
|
_globalCache[&runtime] = dispatcher;
|
|
26
31
|
|
|
27
32
|
// Inject the dispatcher into Runtime global (runtime will hold a strong reference)
|
|
28
|
-
jsi::
|
|
29
|
-
|
|
30
|
-
runtime.global().setProperty(runtime, GLOBAL_DISPATCHER_HOLDER_NAME, dispatcherHolder);
|
|
33
|
+
jsi::Value dispatcherHolder = JSIConverter<std::shared_ptr<Dispatcher>>::toJSI(runtime, dispatcher);
|
|
34
|
+
runtime.global().setProperty(runtime, GLOBAL_DISPATCHER_HOLDER_NAME, std::move(dispatcherHolder));
|
|
31
35
|
}
|
|
32
36
|
|
|
33
37
|
std::shared_ptr<Dispatcher> Dispatcher::getRuntimeGlobalDispatcher(jsi::Runtime& runtime) {
|
|
@@ -44,24 +48,23 @@ std::shared_ptr<Dispatcher> Dispatcher::getRuntimeGlobalDispatcher(jsi::Runtime&
|
|
|
44
48
|
|
|
45
49
|
Logger::log(LogLevel::Warning, TAG, "Unknown Runtime (%s), looking for Dispatcher through JSI global lookup...",
|
|
46
50
|
getRuntimeId(runtime).c_str());
|
|
51
|
+
// 1. Get global.__nitroDispatcher
|
|
47
52
|
jsi::Value dispatcherHolderValue = getRuntimeGlobalDispatcherHolder(runtime);
|
|
48
|
-
jsi::Object
|
|
49
|
-
std::shared_ptr<Dispatcher> dispatcher =
|
|
53
|
+
// 2. Cast it to the jsi::Object
|
|
54
|
+
std::shared_ptr<Dispatcher> dispatcher = JSIConverter<std::shared_ptr<Dispatcher>>::fromJSI(runtime, dispatcherHolderValue);
|
|
55
|
+
// 3. Throw it in our cache and return
|
|
50
56
|
_globalCache[&runtime] = dispatcher;
|
|
51
57
|
return dispatcher;
|
|
52
58
|
}
|
|
53
59
|
|
|
54
60
|
jsi::Value Dispatcher::getRuntimeGlobalDispatcherHolder(jsi::Runtime& runtime) {
|
|
55
|
-
#ifdef NITRO_DEBUG
|
|
56
61
|
if (!runtime.global().hasProperty(runtime, GLOBAL_DISPATCHER_HOLDER_NAME)) [[unlikely]] {
|
|
57
|
-
throw std::runtime_error("
|
|
58
|
-
"
|
|
59
|
-
|
|
60
|
-
"`
|
|
61
|
-
"
|
|
62
|
-
"for this `jsi::Runtime`?");
|
|
62
|
+
throw std::runtime_error("The `jsi::Runtime` \"" + getRuntimeId(runtime) +
|
|
63
|
+
"\" does not support Callbacks or Promises because it does not have a `Dispatcher` installed!\n"
|
|
64
|
+
"To use Callbacks and Promises follow these steps;\n"
|
|
65
|
+
"1. Subclass `Dispatcher` with your implementation of `runAsync`/`runSync` for your Thread.\n"
|
|
66
|
+
"2. Call `Dispatcher::installRuntimeGlobalDispatcher(...)` with your `Runtime` and your `Dispatcher`.");
|
|
63
67
|
}
|
|
64
|
-
#endif
|
|
65
68
|
return runtime.global().getProperty(runtime, GLOBAL_DISPATCHER_HOLDER_NAME);
|
|
66
69
|
}
|
|
67
70
|
|
package/ios/core/AnyMap.swift
CHANGED
|
@@ -7,18 +7,16 @@
|
|
|
7
7
|
|
|
8
8
|
import Foundation
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
* Note: Arrays are currently not implemented due to a Swift compiler bug https://github.com/swiftlang/swift/issues/75994
|
|
13
|
-
*/
|
|
10
|
+
/// Represents any value representable by the `AnyMap`.
|
|
11
|
+
/// Note: Arrays are currently not implemented due to a Swift compiler bug https://github.com/swiftlang/swift/issues/75994
|
|
14
12
|
public indirect enum AnyValue {
|
|
15
13
|
case null
|
|
16
14
|
case number(Double)
|
|
17
15
|
case bool(Bool)
|
|
18
16
|
case bigint(Int64)
|
|
19
17
|
case string(String)
|
|
20
|
-
case array(
|
|
21
|
-
case object(
|
|
18
|
+
case array([AnyValue])
|
|
19
|
+
case object([String: AnyValue])
|
|
22
20
|
|
|
23
21
|
static func create(_ value: margelo.nitro.AnyValue) -> AnyValue {
|
|
24
22
|
if margelo.nitro.AnyMapUtils.is_AnyValue_null(value) {
|
|
@@ -41,10 +39,8 @@ public indirect enum AnyValue {
|
|
|
41
39
|
}
|
|
42
40
|
}
|
|
43
41
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
* See C++ `AnyMap.hpp` for more information.
|
|
47
|
-
*/
|
|
42
|
+
/// Represents an `AnyMap`- an untyped map instance.
|
|
43
|
+
/// See C++ `AnyMap.hpp` for more information.
|
|
48
44
|
public final class AnyMap: @unchecked Sendable {
|
|
49
45
|
public let cppPart: margelo.nitro.SharedAnyMap
|
|
50
46
|
|
|
@@ -150,7 +146,7 @@ public final class AnyMap: @unchecked Sendable {
|
|
|
150
146
|
* If no value exists at the given key, or if it is not a double,
|
|
151
147
|
* this function throws.
|
|
152
148
|
*/
|
|
153
|
-
public func getObject(key: String) ->
|
|
149
|
+
public func getObject(key: String) -> [String: AnyValue] {
|
|
154
150
|
let value = cppPart.pointee.getObject(std.string(key))
|
|
155
151
|
return value.toSwift()
|
|
156
152
|
}
|
|
@@ -202,7 +198,7 @@ public final class AnyMap: @unchecked Sendable {
|
|
|
202
198
|
/**
|
|
203
199
|
* Set the given key to the given object value.
|
|
204
200
|
*/
|
|
205
|
-
public func setObject(key: String, value:
|
|
201
|
+
public func setObject(key: String, value: [String: AnyValue]) {
|
|
206
202
|
cppPart.pointee.setObject(std.string(key), margelo.nitro.AnyObject.create(value))
|
|
207
203
|
}
|
|
208
204
|
|
|
@@ -297,7 +293,7 @@ extension margelo.nitro.AnyValue {
|
|
|
297
293
|
static func create(_ value: [AnyValue]) -> margelo.nitro.AnyValue {
|
|
298
294
|
return margelo.nitro.AnyMapUtils.create_AnyValue(margelo.nitro.AnyArray.create(value))
|
|
299
295
|
}
|
|
300
|
-
static func create(_ value:
|
|
296
|
+
static func create(_ value: [String: AnyValue]) -> margelo.nitro.AnyValue {
|
|
301
297
|
return margelo.nitro.AnyMapUtils.create_AnyValue(margelo.nitro.AnyObject.create(value))
|
|
302
298
|
}
|
|
303
299
|
}
|
|
@@ -335,7 +331,7 @@ extension margelo.nitro.AnyArray {
|
|
|
335
331
|
// pragma MARK: margelo.nitro.AnyObject extension
|
|
336
332
|
|
|
337
333
|
extension margelo.nitro.AnyObject {
|
|
338
|
-
static func create(_ dictionary:
|
|
334
|
+
static func create(_ dictionary: [String: AnyValue]) -> margelo.nitro.AnyObject {
|
|
339
335
|
var object = margelo.nitro.AnyObject()
|
|
340
336
|
object.reserve(dictionary.count)
|
|
341
337
|
for (key, value) in dictionary {
|
|
@@ -344,9 +340,9 @@ extension margelo.nitro.AnyObject {
|
|
|
344
340
|
return object
|
|
345
341
|
}
|
|
346
342
|
|
|
347
|
-
func toSwift() ->
|
|
343
|
+
func toSwift() -> [String: AnyValue] {
|
|
348
344
|
let keys = margelo.nitro.AnyMapUtils.getAnyObjectKeys(self)
|
|
349
|
-
var dictionary =
|
|
345
|
+
var dictionary = [String: AnyValue](minimumCapacity: keys.size())
|
|
350
346
|
for key in keys {
|
|
351
347
|
let value = margelo.nitro.AnyMapUtils.getAnyObjectValue(self, key)
|
|
352
348
|
dictionary[String(key)] = AnyValue.create(value)
|
|
@@ -355,6 +351,5 @@ extension margelo.nitro.AnyObject {
|
|
|
355
351
|
}
|
|
356
352
|
}
|
|
357
353
|
|
|
358
|
-
|
|
359
354
|
@available(*, deprecated, renamed: "AnyMap")
|
|
360
355
|
public typealias AnyMapHolder = AnyMap
|
|
@@ -7,12 +7,10 @@
|
|
|
7
7
|
|
|
8
8
|
import Foundation
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
* See `data`, `size` and `isOwning`.
|
|
15
|
-
*/
|
|
10
|
+
/// Holds instances of `std::shared_ptr<ArrayBuffer>`, which can be passed
|
|
11
|
+
/// between native and JS **without copy**.
|
|
12
|
+
///
|
|
13
|
+
/// See `data`, `size` and `isOwning`.
|
|
16
14
|
public typealias ArrayBuffer = margelo.nitro.ArrayBufferHolder
|
|
17
15
|
|
|
18
16
|
@available(*, deprecated, renamed: "ArrayBuffer")
|
|
@@ -20,16 +18,18 @@ public typealias ArrayBufferHolder = ArrayBuffer
|
|
|
20
18
|
|
|
21
19
|
// pragma MARK: Wrap
|
|
22
20
|
|
|
23
|
-
|
|
21
|
+
extension ArrayBuffer {
|
|
24
22
|
/**
|
|
25
23
|
* Create a new `ArrayBuffer` that wraps the given `data` of the given `size`
|
|
26
24
|
* without performing a copy.
|
|
27
25
|
* When the `ArrayBuffer` is no longer used, `onDelete` will be called, in which
|
|
28
26
|
* you as a caller are responsible for deleting `data`.
|
|
29
27
|
*/
|
|
30
|
-
static func wrap(
|
|
31
|
-
|
|
32
|
-
|
|
28
|
+
public static func wrap(
|
|
29
|
+
dataWithoutCopy data: UnsafeMutablePointer<UInt8>,
|
|
30
|
+
size: Int,
|
|
31
|
+
onDelete delete: @escaping () -> Void
|
|
32
|
+
) -> ArrayBuffer {
|
|
33
33
|
// Convert escaping Swift closure to a `void*`
|
|
34
34
|
let swiftClosure = SwiftClosure(wrappingClosure: delete)
|
|
35
35
|
// Create ArrayBuffer with our wrapped Swift closure to make it callable as a C-function pointer
|
|
@@ -42,23 +42,26 @@ public extension ArrayBuffer {
|
|
|
42
42
|
* When the `ArrayBuffer` is no longer used, `onDelete` will be called, in which
|
|
43
43
|
* you as a caller are responsible for deleting `data`.
|
|
44
44
|
*/
|
|
45
|
-
static func wrap(
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
45
|
+
public static func wrap(
|
|
46
|
+
dataWithoutCopy data: UnsafeMutableRawPointer,
|
|
47
|
+
size: Int,
|
|
48
|
+
onDelete delete: @escaping () -> Void
|
|
49
|
+
) -> ArrayBuffer {
|
|
50
|
+
return ArrayBuffer.wrap(
|
|
51
|
+
dataWithoutCopy: data.assumingMemoryBound(to: UInt8.self),
|
|
52
|
+
size: size,
|
|
53
|
+
onDelete: delete)
|
|
51
54
|
}
|
|
52
55
|
}
|
|
53
56
|
|
|
54
57
|
// pragma MARK: Allocate
|
|
55
58
|
|
|
56
|
-
|
|
59
|
+
extension ArrayBuffer {
|
|
57
60
|
/**
|
|
58
61
|
* Allocate a new buffer of the given `size`.
|
|
59
62
|
* If `initializeToZero` is `true`, all bytes are set to `0`, otherwise they are left untouched.
|
|
60
63
|
*/
|
|
61
|
-
static func allocate(size: Int, initializeToZero: Bool = false) -> ArrayBuffer {
|
|
64
|
+
public static func allocate(size: Int, initializeToZero: Bool = false) -> ArrayBuffer {
|
|
62
65
|
let data = UnsafeMutablePointer<UInt8>.allocate(capacity: size)
|
|
63
66
|
if initializeToZero {
|
|
64
67
|
data.initialize(repeating: 0, count: size)
|
|
@@ -72,12 +75,14 @@ public extension ArrayBuffer {
|
|
|
72
75
|
|
|
73
76
|
// pragma MARK: Copy
|
|
74
77
|
|
|
75
|
-
|
|
78
|
+
extension ArrayBuffer {
|
|
76
79
|
/**
|
|
77
80
|
* Copy the given `UnsafeMutablePointer<UInt8>` into a new **owning** `ArrayBuffer`.
|
|
78
81
|
*/
|
|
79
|
-
static func copy(
|
|
80
|
-
|
|
82
|
+
public static func copy(
|
|
83
|
+
of other: UnsafeMutablePointer<UInt8>,
|
|
84
|
+
size: Int
|
|
85
|
+
) -> ArrayBuffer {
|
|
81
86
|
// 1. Create new `UnsafeMutablePointer<UInt8>`
|
|
82
87
|
let copy = UnsafeMutablePointer<UInt8>.allocate(capacity: size)
|
|
83
88
|
// 2. Copy over data
|
|
@@ -92,23 +97,26 @@ public extension ArrayBuffer {
|
|
|
92
97
|
/**
|
|
93
98
|
* Copy the given `UnsafeMutableRawPointer` into a new **owning** `ArrayBuffer`.
|
|
94
99
|
*/
|
|
95
|
-
static func copy(
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
100
|
+
public static func copy(
|
|
101
|
+
of other: UnsafeMutableRawPointer,
|
|
102
|
+
size: Int
|
|
103
|
+
) -> ArrayBuffer {
|
|
104
|
+
return ArrayBuffer.copy(
|
|
105
|
+
of: other.assumingMemoryBound(to: UInt8.self),
|
|
106
|
+
size: size)
|
|
99
107
|
}
|
|
100
108
|
|
|
101
109
|
/**
|
|
102
110
|
* Copy the given `ArrayBuffer` into a new **owning** `ArrayBuffer`.
|
|
103
111
|
*/
|
|
104
|
-
static func copy(of other: ArrayBuffer) -> ArrayBuffer {
|
|
112
|
+
public static func copy(of other: ArrayBuffer) -> ArrayBuffer {
|
|
105
113
|
return ArrayBuffer.copy(of: other.data, size: other.size)
|
|
106
114
|
}
|
|
107
115
|
|
|
108
116
|
/**
|
|
109
117
|
* Copy the given `Data` into a new **owning** `ArrayBuffer`.
|
|
110
118
|
*/
|
|
111
|
-
static func copy(data: Data) throws -> ArrayBuffer {
|
|
119
|
+
public static func copy(data: Data) throws -> ArrayBuffer {
|
|
112
120
|
// 1. Create new `ArrayBuffer` of same size
|
|
113
121
|
let size = data.count
|
|
114
122
|
let arrayBuffer = ArrayBuffer.allocate(size: size)
|
|
@@ -123,17 +131,16 @@ public extension ArrayBuffer {
|
|
|
123
131
|
}
|
|
124
132
|
}
|
|
125
133
|
|
|
126
|
-
|
|
127
134
|
// pragma MARK: Data
|
|
128
135
|
|
|
129
|
-
|
|
136
|
+
extension ArrayBuffer {
|
|
130
137
|
/**
|
|
131
138
|
* Wrap this `ArrayBuffer` in a `Data` instance, without performing a copy.
|
|
132
139
|
* - `copyIfNeeded`: If this `ArrayBuffer` is **non-owning**, the foreign
|
|
133
140
|
* data may needs to be copied to be safely used outside of the scope of the caller function.
|
|
134
141
|
* This flag controls that.
|
|
135
142
|
*/
|
|
136
|
-
func toData(copyIfNeeded: Bool) -> Data {
|
|
143
|
+
public func toData(copyIfNeeded: Bool) -> Data {
|
|
137
144
|
let shouldCopy = copyIfNeeded && !self.isOwner
|
|
138
145
|
if shouldCopy {
|
|
139
146
|
// COPY DATA
|
|
@@ -143,12 +150,14 @@ public extension ArrayBuffer {
|
|
|
143
150
|
// 1. Get the std::shared_ptr<ArrayBuffer>
|
|
144
151
|
var sharedPointer = self.getArrayBuffer()
|
|
145
152
|
// 2. Create a Data object WRAPPING our pointer
|
|
146
|
-
return Data(
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
153
|
+
return Data(
|
|
154
|
+
bytesNoCopy: self.data, count: self.size,
|
|
155
|
+
deallocator: .custom({ buffer, size in
|
|
156
|
+
// 3. Capture the std::shared_ptr<ArrayBuffer> in the deallocator lambda so it stays alive.
|
|
157
|
+
// As soon as this lambda gets called, the `sharedPointer` gets deleted causing the
|
|
158
|
+
// underlying `ArrayBuffer` to be freed.
|
|
159
|
+
sharedPointer.reset()
|
|
160
|
+
}))
|
|
152
161
|
}
|
|
153
162
|
}
|
|
154
163
|
}
|
|
@@ -7,9 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
import Foundation
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
* A base protocol for all Swift-based Hybrid Objects.
|
|
12
|
-
*/
|
|
10
|
+
/// A base protocol for all Swift-based Hybrid Objects.
|
|
13
11
|
public protocol HybridObject: AnyObject {
|
|
14
12
|
/**
|
|
15
13
|
* Get the memory size of the Swift instance (plus any external heap allocations),
|
|
@@ -41,9 +39,9 @@ public protocol HybridObject: AnyObject {
|
|
|
41
39
|
func dispose()
|
|
42
40
|
}
|
|
43
41
|
|
|
44
|
-
|
|
42
|
+
extension HybridObject {
|
|
45
43
|
// By default, this returns `0`.
|
|
46
|
-
var memorySize: Int { return 0 }
|
|
44
|
+
public var memorySize: Int { return 0 }
|
|
47
45
|
// By default, this does nothing.
|
|
48
|
-
func dispose() {
|
|
46
|
+
public func dispose() {}
|
|
49
47
|
}
|
package/ios/core/Promise.swift
CHANGED
|
@@ -7,16 +7,14 @@
|
|
|
7
7
|
|
|
8
8
|
import Foundation
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
* - `Promise<T>()` - Creates a new Promise with fully manual control over the `resolve(..)`/`reject(..)` functions.
|
|
19
|
-
*/
|
|
10
|
+
/// Represents a Promise that can be passed to JS.
|
|
11
|
+
///
|
|
12
|
+
/// Create a new Promise with the following APIs:
|
|
13
|
+
/// - `Promise<T>.async { ... }` - Creates a new Promise that runs the given code in a Swift `async`/`await` Task.
|
|
14
|
+
/// - `Promise<T>.parallel { ... }` - Creates a new Promise that runs the given code in a parallel `DispatchQueue`.
|
|
15
|
+
/// - `Promise<T>.resolved(withResult:)` - Creates a new already resolved Promise.
|
|
16
|
+
/// - `Promise<T>.rejected(withError:)` - Creates a new already rejected Promise.
|
|
17
|
+
/// - `Promise<T>()` - Creates a new Promise with fully manual control over the `resolve(..)`/`reject(..)` functions.
|
|
20
18
|
public final class Promise<T>: @unchecked Sendable {
|
|
21
19
|
private enum State {
|
|
22
20
|
case result(T)
|
|
@@ -47,7 +45,8 @@ public final class Promise<T>: @unchecked Sendable {
|
|
|
47
45
|
*/
|
|
48
46
|
public func resolve(withResult result: T) {
|
|
49
47
|
guard state == nil else {
|
|
50
|
-
fatalError(
|
|
48
|
+
fatalError(
|
|
49
|
+
"Failed to resolve promise with \(result) - it has already been resolved or rejected!")
|
|
51
50
|
}
|
|
52
51
|
state = .result(result)
|
|
53
52
|
onResolvedListeners.forEach { listener in listener(result) }
|
|
@@ -58,16 +57,15 @@ public final class Promise<T>: @unchecked Sendable {
|
|
|
58
57
|
*/
|
|
59
58
|
public func reject(withError error: Error) {
|
|
60
59
|
guard state == nil else {
|
|
61
|
-
fatalError(
|
|
60
|
+
fatalError(
|
|
61
|
+
"Failed to reject promise with \(error) - it has already been resolved or rejected!")
|
|
62
62
|
}
|
|
63
63
|
state = .error(error)
|
|
64
64
|
onRejectedListeners.forEach { listener in listener(error) }
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
|
|
69
|
-
* Extensions to easily create new Promises.
|
|
70
|
-
*/
|
|
68
|
+
/// Extensions to easily create new Promises.
|
|
71
69
|
extension Promise {
|
|
72
70
|
/**
|
|
73
71
|
* Create a new `Promise<T>` already resolved with the given `T`.
|
|
@@ -91,8 +89,10 @@ extension Promise {
|
|
|
91
89
|
* Create a new `Promise<T>` that runs the given `async` code in a `Task`.
|
|
92
90
|
* This does not necessarily run the code in a different Thread, but supports Swift's `async`/`await`.
|
|
93
91
|
*/
|
|
94
|
-
public static func `async`(
|
|
95
|
-
|
|
92
|
+
public static func `async`(
|
|
93
|
+
_ priority: TaskPriority? = nil,
|
|
94
|
+
_ run: sending @escaping @isolated(any) () async throws -> T
|
|
95
|
+
) -> Promise {
|
|
96
96
|
let promise = Promise()
|
|
97
97
|
Task(priority: priority) {
|
|
98
98
|
do {
|
|
@@ -108,8 +108,10 @@ extension Promise {
|
|
|
108
108
|
/**
|
|
109
109
|
* Create a new `Promise<T>` that runs the given `run` function on a parallel Thread/`DispatchQueue`.
|
|
110
110
|
*/
|
|
111
|
-
public static func parallel(
|
|
112
|
-
|
|
111
|
+
public static func parallel(
|
|
112
|
+
_ queue: DispatchQueue = .global(),
|
|
113
|
+
_ run: @escaping @Sendable () throws -> T
|
|
114
|
+
) -> Promise {
|
|
113
115
|
let promise = Promise()
|
|
114
116
|
queue.async {
|
|
115
117
|
do {
|
|
@@ -123,9 +125,7 @@ extension Promise {
|
|
|
123
125
|
}
|
|
124
126
|
}
|
|
125
127
|
|
|
126
|
-
|
|
127
|
-
* Extensions to support then/catch syntax.
|
|
128
|
-
*/
|
|
128
|
+
/// Extensions to support then/catch syntax.
|
|
129
129
|
extension Promise {
|
|
130
130
|
/**
|
|
131
131
|
* Add a continuation listener to this `Promise<T>`.
|
|
@@ -162,9 +162,7 @@ extension Promise {
|
|
|
162
162
|
}
|
|
163
163
|
}
|
|
164
164
|
|
|
165
|
-
|
|
166
|
-
* Extensions to support await syntax.
|
|
167
|
-
*/
|
|
165
|
+
/// Extensions to support await syntax.
|
|
168
166
|
extension Promise {
|
|
169
167
|
/**
|
|
170
168
|
* Asynchronously await the result of the Promise.
|
|
@@ -7,18 +7,16 @@
|
|
|
7
7
|
|
|
8
8
|
import Foundation
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
* Throw this error in Nitro Modules to provide clear and concise error messages to JS.
|
|
14
|
-
*/
|
|
10
|
+
/// Represents an error that occured at any point during the application's runtime.
|
|
11
|
+
///
|
|
12
|
+
/// Throw this error in Nitro Modules to provide clear and concise error messages to JS.
|
|
15
13
|
@frozen
|
|
16
14
|
public enum RuntimeError: Error, CustomStringConvertible {
|
|
17
15
|
case error(withMessage: String)
|
|
18
16
|
|
|
19
17
|
public var description: String {
|
|
20
18
|
switch self {
|
|
21
|
-
|
|
19
|
+
case .error(let message): return message
|
|
22
20
|
}
|
|
23
21
|
}
|
|
24
22
|
|
|
@@ -31,11 +29,11 @@ public enum RuntimeError: Error, CustomStringConvertible {
|
|
|
31
29
|
}
|
|
32
30
|
}
|
|
33
31
|
|
|
34
|
-
|
|
32
|
+
extension Error {
|
|
35
33
|
/**
|
|
36
34
|
* Converts this `Error` to a C++ `std::exception`.
|
|
37
35
|
*/
|
|
38
|
-
func toCpp() -> std.exception_ptr {
|
|
36
|
+
public func toCpp() -> std.exception_ptr {
|
|
39
37
|
let message = String(describing: self)
|
|
40
38
|
return margelo.nitro.makeException(std.string(message))
|
|
41
39
|
}
|
|
@@ -7,19 +7,19 @@
|
|
|
7
7
|
|
|
8
8
|
import Foundation
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
extension Date {
|
|
11
11
|
/**
|
|
12
12
|
* Create a new `Date` object from the given `std::chrono::system_clock::time_point` value.
|
|
13
13
|
*/
|
|
14
|
-
init(fromChrono date: margelo.nitro.chrono_time) {
|
|
14
|
+
public init(fromChrono date: margelo.nitro.chrono_time) {
|
|
15
15
|
let millisecondsSinceEpoch = margelo.nitro.millisecondsSinceEpochFromChronoDate(date)
|
|
16
16
|
self = .init(timeIntervalSince1970: millisecondsSinceEpoch / 1_000)
|
|
17
17
|
}
|
|
18
|
-
|
|
18
|
+
|
|
19
19
|
/**
|
|
20
20
|
* Converts this `Date` object to a `std::chrono::system_clock::time_point` value.
|
|
21
21
|
*/
|
|
22
|
-
func toCpp() -> margelo.nitro.chrono_time {
|
|
22
|
+
public func toCpp() -> margelo.nitro.chrono_time {
|
|
23
23
|
let secondsSinceEpoch = self.timeIntervalSince1970
|
|
24
24
|
let millisecondsSinceEpoch = secondsSinceEpoch * 1_000
|
|
25
25
|
return margelo.nitro.chronoDateFromMillisecondsSinceEpoch(millisecondsSinceEpoch)
|
|
@@ -7,37 +7,33 @@
|
|
|
7
7
|
|
|
8
8
|
import Foundation
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
*/
|
|
15
|
-
fileprivate final class ClosureWrapper {
|
|
10
|
+
/// Wraps a Swift closure in a Swift class.
|
|
11
|
+
/// This can be used to create unmanaged pointers (`void*`) and
|
|
12
|
+
/// passed to C-style function pointers via `void* context` parameters.
|
|
13
|
+
private final class ClosureWrapper {
|
|
16
14
|
private let closure: () -> Void
|
|
17
|
-
|
|
15
|
+
|
|
18
16
|
init(closure: @escaping () -> Void) {
|
|
19
17
|
self.closure = closure
|
|
20
18
|
}
|
|
21
|
-
|
|
19
|
+
|
|
22
20
|
func invoke() {
|
|
23
21
|
closure()
|
|
24
22
|
}
|
|
25
23
|
}
|
|
26
24
|
|
|
27
|
-
|
|
28
|
-
* Represents a Swift Closure that can be called from both C++ and Swift.
|
|
29
|
-
*/
|
|
25
|
+
/// Represents a Swift Closure that can be called from both C++ and Swift.
|
|
30
26
|
public typealias SwiftClosure = margelo.nitro.SwiftClosure
|
|
31
27
|
|
|
32
|
-
|
|
28
|
+
extension SwiftClosure {
|
|
33
29
|
/**
|
|
34
30
|
* Create a new `SwiftClosure` wrapping the given Swift closure.
|
|
35
31
|
* This can then be called from both C++ and Swift.
|
|
36
32
|
*/
|
|
37
|
-
init(wrappingClosure closure: @escaping () -> Void) {
|
|
33
|
+
public init(wrappingClosure closure: @escaping () -> Void) {
|
|
38
34
|
// Wrap closure in void*, and increment it's ref count so it stays alive.
|
|
39
35
|
let context = Unmanaged.passRetained(ClosureWrapper(closure: closure)).toOpaque()
|
|
40
|
-
|
|
36
|
+
|
|
41
37
|
// Create a C-style Function Pointer, which calls the actual Swift closure.
|
|
42
38
|
func call(context: UnsafeMutableRawPointer) {
|
|
43
39
|
// Unwrap context from void* to closure again. We are assuming that it has not been deleted yet.
|
|
@@ -45,13 +41,13 @@ public extension SwiftClosure {
|
|
|
45
41
|
// Call it!
|
|
46
42
|
closure.invoke()
|
|
47
43
|
}
|
|
48
|
-
|
|
44
|
+
|
|
49
45
|
// Create a C-style Function Pointer, which deletes the `ClosureWrapper`.
|
|
50
46
|
func destroy(context: UnsafeMutableRawPointer) {
|
|
51
47
|
// Release the void* holding our `ClosureWrapper`
|
|
52
48
|
Unmanaged<ClosureWrapper>.fromOpaque(context).release()
|
|
53
49
|
}
|
|
54
|
-
|
|
50
|
+
|
|
55
51
|
self.init(context, call, destroy)
|
|
56
52
|
}
|
|
57
53
|
}
|