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.
Files changed (31) hide show
  1. package/android/src/main/java/com/margelo/nitro/NitroModules.kt +50 -42
  2. package/android/src/main/java/com/margelo/nitro/NitroModulesPackage.kt +26 -22
  3. package/android/src/main/java/com/margelo/nitro/core/AnyMap.kt +44 -7
  4. package/android/src/main/java/com/margelo/nitro/core/AnyValue.kt +145 -139
  5. package/android/src/main/java/com/margelo/nitro/core/ArrayBuffer.kt +162 -154
  6. package/android/src/main/java/com/margelo/nitro/core/HybridObject.kt +51 -51
  7. package/android/src/main/java/com/margelo/nitro/core/Promise.kt +9 -1
  8. package/android/src/main/java/com/margelo/nitro/utils/HardwareBuffer+updateFrom.kt +1 -2
  9. package/android/src/main/java/com/margelo/nitro/utils/HardwareBufferUtils.kt +33 -26
  10. package/android/src/main/java/com/margelo/nitro/views/HybridView.kt +20 -19
  11. package/cpp/jsi/{JSIConverter+HybridObject.hpp → JSIConverter+NativeState.hpp} +19 -13
  12. package/cpp/jsi/JSIConverter.hpp +1 -1
  13. package/cpp/threading/Dispatcher.cpp +16 -13
  14. package/cpp/utils/NitroDefines.hpp +1 -1
  15. package/ios/core/AnyMap.swift +12 -17
  16. package/ios/core/ArrayBuffer.swift +45 -36
  17. package/ios/core/HybridObject.swift +4 -6
  18. package/ios/core/Promise.swift +23 -25
  19. package/ios/core/RuntimeError.swift +6 -8
  20. package/ios/utils/Date+fromChrono.swift +4 -4
  21. package/ios/utils/SwiftClosure.swift +12 -16
  22. package/ios/views/HybridView.swift +30 -32
  23. package/lib/commonjs/turbomodule/NativeNitroModules.js +17 -0
  24. package/lib/commonjs/turbomodule/NativeNitroModules.js.map +1 -1
  25. package/lib/module/turbomodule/NativeNitroModules.js +17 -0
  26. package/lib/module/turbomodule/NativeNitroModules.js.map +1 -1
  27. package/lib/tsconfig.build.tsbuildinfo +1 -1
  28. package/lib/typescript/turbomodule/NativeNitroModules.d.ts +1 -0
  29. package/lib/typescript/turbomodule/NativeNitroModules.d.ts.map +1 -1
  30. package/package.json +3 -3
  31. package/src/turbomodule/NativeNitroModules.ts +19 -0
@@ -1,10 +1,9 @@
1
1
  //
2
- // Created by Marc Rousavy on 21.02.24.
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
- // HybridObject(NativeState) <> {}
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<TPointee>(runtime)) [[unlikely]] {
42
- if (!object.hasNativeState(runtime)) [[unlikely]] {
43
- std::string stringRepresentation = arg.toString(runtime).utf8(runtime);
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
- return std::dynamic_pointer_cast<TPointee>(nativeState);
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) {
@@ -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+HybridObject.hpp"
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::Object dispatcherHolder(runtime);
29
- dispatcherHolder.setNativeState(runtime, dispatcher);
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 dispatcherHolder = dispatcherHolderValue.getObject(runtime);
49
- std::shared_ptr<Dispatcher> dispatcher = dispatcherHolder.getNativeState<Dispatcher>(runtime);
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("Failed to get current Dispatcher - the global Dispatcher "
58
- "holder (`global." +
59
- std::string(GLOBAL_DISPATCHER_HOLDER_NAME) +
60
- "`) "
61
- "does not exist! Was `Dispatcher::installDispatcherIntoRuntime()` called "
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
 
@@ -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.30.0"
12
+ #define NITRO_VERSION "0.30.2"
13
13
 
14
14
  // Sets whether to use debug or optimized production build flags
15
15
  #ifdef DEBUG
@@ -7,18 +7,16 @@
7
7
 
8
8
  import Foundation
9
9
 
10
- /**
11
- * Represents any value representable by the `AnyMap`.
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(Array<AnyValue>)
21
- case object(Dictionary<String, AnyValue>)
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
- * Represents an `AnyMap`- an untyped map instance.
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) -> Dictionary<String, AnyValue> {
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: Dictionary<String, AnyValue>) {
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: Dictionary<String, AnyValue>) -> margelo.nitro.AnyValue {
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: Dictionary<String, AnyValue>) -> margelo.nitro.AnyObject {
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() -> Dictionary<String, AnyValue> {
343
+ func toSwift() -> [String: AnyValue] {
348
344
  let keys = margelo.nitro.AnyMapUtils.getAnyObjectKeys(self)
349
- var dictionary = Dictionary<String, AnyValue>(minimumCapacity: keys.size())
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
- * Holds instances of `std::shared_ptr<ArrayBuffer>`, which can be passed
12
- * between native and JS **without copy**.
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
- public extension ArrayBuffer {
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(dataWithoutCopy data: UnsafeMutablePointer<UInt8>,
31
- size: Int,
32
- onDelete delete: @escaping () -> Void) -> ArrayBuffer {
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(dataWithoutCopy data: UnsafeMutableRawPointer,
46
- size: Int,
47
- onDelete delete: @escaping () -> Void) -> ArrayBuffer {
48
- return ArrayBuffer.wrap(dataWithoutCopy: data.assumingMemoryBound(to: UInt8.self),
49
- size: size,
50
- onDelete: delete)
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
- public extension ArrayBuffer {
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
- public extension ArrayBuffer {
78
+ extension ArrayBuffer {
76
79
  /**
77
80
  * Copy the given `UnsafeMutablePointer<UInt8>` into a new **owning** `ArrayBuffer`.
78
81
  */
79
- static func copy(of other: UnsafeMutablePointer<UInt8>,
80
- size: Int) -> ArrayBuffer {
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(of other: UnsafeMutableRawPointer,
96
- size: Int) -> ArrayBuffer {
97
- return ArrayBuffer.copy(of: other.assumingMemoryBound(to: UInt8.self),
98
- size: size)
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
- public extension ArrayBuffer {
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(bytesNoCopy: self.data, count: self.size, deallocator: .custom({ buffer, size in
147
- // 3. Capture the std::shared_ptr<ArrayBuffer> in the deallocator lambda so it stays alive.
148
- // As soon as this lambda gets called, the `sharedPointer` gets deleted causing the
149
- // underlying `ArrayBuffer` to be freed.
150
- sharedPointer.reset()
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
- public extension HybridObject {
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
  }
@@ -7,16 +7,14 @@
7
7
 
8
8
  import Foundation
9
9
 
10
- /**
11
- * Represents a Promise that can be passed to JS.
12
- *
13
- * Create a new Promise with the following APIs:
14
- * - `Promise<T>.async { ... }` - Creates a new Promise that runs the given code in a Swift `async`/`await` Task.
15
- * - `Promise<T>.parallel { ... }` - Creates a new Promise that runs the given code in a parallel `DispatchQueue`.
16
- * - `Promise<T>.resolved(withResult:)` - Creates a new already resolved Promise.
17
- * - `Promise<T>.rejected(withError:)` - Creates a new already rejected Promise.
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("Failed to resolve promise with \(result) - it has already been resolved or rejected!")
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("Failed to reject promise with \(error) - it has already been resolved or rejected!")
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`(_ priority: TaskPriority? = nil,
95
- _ run: @escaping () async throws -> T) -> Promise {
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(_ queue: DispatchQueue = .global(),
112
- _ run: @escaping () throws -> T) -> Promise {
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
- * Represents an error that occured at any point during the application's runtime.
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
- case .error(let message): return message
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
- public extension Error {
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
- public extension Date {
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
- * Wraps a Swift closure in a Swift class.
12
- * This can be used to create unmanaged pointers (`void*`) and
13
- * passed to C-style function pointers via `void* context` parameters.
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
- public extension SwiftClosure {
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
  }