react-native-nitro-modules 0.31.0 → 0.31.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.
@@ -90,11 +90,47 @@ class ArrayBuffer {
90
90
  return boxed as HardwareBuffer
91
91
  }
92
92
 
93
+ /**
94
+ * Copies the underlying data into a `ByteArray`.
95
+ * If this `ArrayBuffer` is backed by a GPU-HardwareBuffer,
96
+ * this performs a GPU-download.
97
+ */
98
+ fun toByteArray(): ByteArray {
99
+ val buffer = this.getBuffer(false)
100
+ if (buffer.hasArray()) {
101
+ // It's a CPU-backed array - we can return this directly if the size matches
102
+ val array = buffer.array()
103
+ if (array.size == this.size) {
104
+ // The ByteBuffer is 1:1 mapped to a byte array - return as is!
105
+ return array
106
+ }
107
+ // we had a CPU-backed array, but it's size differs from our ArrayBuffer size.
108
+ // This might be because the ArrayBuffer has a smaller view of the data, so we need
109
+ // to resort back to a good ol' copy.
110
+ }
111
+ // It's not a 1:1 mapped array (e.g. HardwareBuffer) - we need to copy to the CPU
112
+ val copy = ByteBuffer.allocate(buffer.capacity())
113
+ copy.put(buffer)
114
+ return copy.array()
115
+ }
116
+
117
+ /**
118
+ * Returns an **owning** version of this `ArrayBuffer`.
119
+ * If this `ArrayBuffer` already is **owning**, it is returned as-is.
120
+ * If this `ArrayBuffer` is **non-owning**, it is _copied_.
121
+ */
122
+ fun asOwning(): ArrayBuffer {
123
+ if (!isOwner) {
124
+ return ArrayBuffer.copy(this)
125
+ }
126
+ return this
127
+ }
128
+
93
129
  /**
94
130
  * Create a new **owning-** `ArrayBuffer` that holds the given `ByteBuffer`.
95
131
  * The `ByteBuffer` needs to remain valid for as long as the `ArrayBuffer` is alive.
96
132
  */
97
- constructor(byteBuffer: ByteBuffer) {
133
+ internal constructor(byteBuffer: ByteBuffer) {
98
134
  if (!byteBuffer.isDirect) {
99
135
  throw Error(
100
136
  "ArrayBuffers can only be created from direct ByteBuffers, " +
@@ -109,7 +145,7 @@ class ArrayBuffer {
109
145
  * The `HardwareBuffer` needs to remain valid for as long as the `ArrayBuffer` is alive.
110
146
  */
111
147
  @RequiresApi(Build.VERSION_CODES.O)
112
- constructor(hardwareBuffer: HardwareBuffer) {
148
+ internal constructor(hardwareBuffer: HardwareBuffer) {
113
149
  if (hardwareBuffer.isClosed) {
114
150
  throw Error("Cannot create ArrayBuffer from an already-closed HardwareBuffer!")
115
151
  }
@@ -187,6 +223,15 @@ class ArrayBuffer {
187
223
  return ArrayBuffer(newBuffer)
188
224
  }
189
225
 
226
+ /**
227
+ * Copy the given `ByteArray` into a new **owning** `ArrayBuffer`.
228
+ */
229
+ fun copy(byteArray: ByteArray): ArrayBuffer {
230
+ val byteBuffer = ByteBuffer.allocateDirect(byteArray.size)
231
+ byteBuffer.put(byteArray)
232
+ return ArrayBuffer.wrap(byteBuffer)
233
+ }
234
+
190
235
  /**
191
236
  * Copy the given `HardwareBuffer` into a new **owning** `ArrayBuffer`.
192
237
  */
@@ -32,6 +32,11 @@ std::shared_ptr<ArrayBuffer> ArrayBuffer::copy(const std::vector<uint8_t>& data)
32
32
  return ArrayBuffer::copy(data.data(), data.size());
33
33
  }
34
34
 
35
+ std::shared_ptr<ArrayBuffer> ArrayBuffer::move(std::vector<uint8_t>&& data) {
36
+ auto* vector = new std::vector<uint8_t>(std::move(data));
37
+ return ArrayBuffer::wrap(vector->data(), vector->size(), [=]() { delete vector; });
38
+ }
39
+
35
40
  std::shared_ptr<ArrayBuffer> ArrayBuffer::copy(const std::shared_ptr<ArrayBuffer>& buffer) {
36
41
  return ArrayBuffer::copy(buffer->data(), buffer->size());
37
42
  }
@@ -64,6 +64,10 @@ public:
64
64
  * Create a new `NativeArrayBuffer` that copies the given `std::vector`.
65
65
  */
66
66
  static std::shared_ptr<ArrayBuffer> copy(const std::vector<uint8_t>& data);
67
+ /**
68
+ * Create a new `NativeArrayBuffer` that moves the given `std::vector`.
69
+ */
70
+ static std::shared_ptr<ArrayBuffer> move(std::vector<uint8_t>&& data);
67
71
  /**
68
72
  * Create a new `NativeArrayBuffer` that copies the given `std::shared_ptr<ArrayBuffer>`.
69
73
  */
@@ -88,7 +88,8 @@ jsi::Value HybridObject::toObject(jsi::Runtime& runtime) {
88
88
  std::string typeName = "HybridObject<" + std::string(_name) + ">";
89
89
  ObjectUtils::defineProperty(runtime, object, "__type",
90
90
  PlainPropertyDescriptor{
91
- .configurable = false,
91
+ // .configurable has to be true because this property is non-frozen
92
+ .configurable = true,
92
93
  .enumerable = true,
93
94
  .value = jsi::String::createFromUtf8(runtime, typeName),
94
95
  .writable = false,
@@ -7,4 +7,130 @@
7
7
 
8
8
  #include "Promise.hpp"
9
9
 
10
- namespace margelo::nitro {} // namespace margelo::nitro
10
+ namespace margelo::nitro {
11
+
12
+ Promise<void>::~Promise() {
13
+ if (isPending()) [[unlikely]] {
14
+ std::runtime_error error("Timeouted: Promise<void> was destroyed!");
15
+ reject(std::make_exception_ptr(error));
16
+ }
17
+ }
18
+
19
+ std::shared_ptr<Promise<void>> Promise<void>::create() {
20
+ return std::shared_ptr<Promise<void>>(new Promise());
21
+ }
22
+
23
+ std::shared_ptr<Promise<void>> Promise<void>::async(std::function<void()>&& run) {
24
+ auto promise = create();
25
+ ThreadPool::shared().run([run = std::move(run), promise]() {
26
+ try {
27
+ // Run the code, then resolve.
28
+ run();
29
+ promise->resolve();
30
+ } catch (...) {
31
+ // It threw an error.
32
+ promise->reject(std::current_exception());
33
+ }
34
+ });
35
+ return promise;
36
+ }
37
+
38
+ std::shared_ptr<Promise<void>> Promise<void>::awaitFuture(std::future<void>&& future) {
39
+ auto sharedFuture = std::make_shared<std::future<void>>(std::move(future));
40
+ return async([sharedFuture = std::move(sharedFuture)]() { sharedFuture->get(); });
41
+ }
42
+
43
+ std::shared_ptr<Promise<void>> Promise<void>::resolved() {
44
+ auto promise = create();
45
+ promise->resolve();
46
+ return promise;
47
+ }
48
+ std::shared_ptr<Promise<void>> Promise<void>::rejected(const std::exception_ptr& error) {
49
+ auto promise = create();
50
+ promise->reject(error);
51
+ return promise;
52
+ }
53
+
54
+ void Promise<void>::resolve() {
55
+ std::unique_lock lock(_mutex);
56
+ #ifdef NITRO_DEBUG
57
+ assertPromiseState(*this, PromiseTask::WANTS_TO_RESOLVE);
58
+ #endif
59
+ _isResolved = true;
60
+ for (const auto& onResolved : _onResolvedListeners) {
61
+ onResolved();
62
+ }
63
+ didFinish();
64
+ }
65
+
66
+ void Promise<void>::reject(const std::exception_ptr& exception) {
67
+ if (exception == nullptr) [[unlikely]] {
68
+ throw std::runtime_error("Cannot reject Promise<void> with a null exception_ptr!");
69
+ }
70
+
71
+ std::unique_lock lock(_mutex);
72
+ #ifdef NITRO_DEBUG
73
+ assertPromiseState(*this, PromiseTask::WANTS_TO_REJECT);
74
+ #endif
75
+ _error = exception;
76
+ for (const auto& onRejected : _onRejectedListeners) {
77
+ onRejected(exception);
78
+ }
79
+ didFinish();
80
+ }
81
+
82
+ void Promise<void>::addOnResolvedListener(OnResolvedFunc&& onResolved) {
83
+ std::unique_lock lock(_mutex);
84
+ if (_isResolved) {
85
+ onResolved();
86
+ } else {
87
+ _onResolvedListeners.push_back(std::move(onResolved));
88
+ }
89
+ }
90
+ void Promise<void>::addOnResolvedListener(const OnResolvedFunc& onResolved) {
91
+ std::unique_lock lock(_mutex);
92
+ if (_isResolved) {
93
+ onResolved();
94
+ } else {
95
+ _onResolvedListeners.push_back(onResolved);
96
+ }
97
+ }
98
+ void Promise<void>::addOnRejectedListener(OnRejectedFunc&& onRejected) {
99
+ std::unique_lock lock(_mutex);
100
+ if (_error) {
101
+ onRejected(_error);
102
+ } else {
103
+ // Promise is not yet rejected, put the listener in our queue.
104
+ _onRejectedListeners.push_back(std::move(onRejected));
105
+ }
106
+ }
107
+ void Promise<void>::addOnRejectedListener(const OnRejectedFunc& onRejected) {
108
+ std::unique_lock lock(_mutex);
109
+ if (_error) {
110
+ onRejected(_error);
111
+ } else {
112
+ // Promise is not yet rejected, put the listener in our queue.
113
+ _onRejectedListeners.push_back(onRejected);
114
+ }
115
+ }
116
+
117
+ std::future<void> Promise<void>::await() {
118
+ auto promise = std::make_shared<std::promise<void>>();
119
+ addOnResolvedListener([promise]() { promise->set_value(); });
120
+ addOnRejectedListener([promise](const std::exception_ptr& error) { promise->set_exception(error); });
121
+ return promise->get_future();
122
+ }
123
+
124
+ const std::exception_ptr& Promise<void>::getError() {
125
+ if (!isRejected()) {
126
+ throw std::runtime_error("Cannot get error when Promise<void> is not yet rejected!");
127
+ }
128
+ return _error;
129
+ }
130
+
131
+ void Promise<void>::didFinish() noexcept {
132
+ _onResolvedListeners.clear();
133
+ _onRejectedListeners.clear();
134
+ }
135
+
136
+ } // namespace margelo::nitro
@@ -270,153 +270,48 @@ public:
270
270
 
271
271
  public:
272
272
  Promise(const Promise&) = delete;
273
+ Promise(Promise&&) = delete;
274
+ ~Promise();
273
275
 
274
276
  private:
275
277
  Promise() = default;
276
278
 
277
279
  public:
278
- ~Promise() {
279
- if (isPending()) [[unlikely]] {
280
- std::runtime_error error("Timeouted: Promise<void> was destroyed!");
281
- reject(std::make_exception_ptr(error));
282
- }
283
- }
280
+ static std::shared_ptr<Promise> create();
281
+ static std::shared_ptr<Promise> async(std::function<void()>&& run);
282
+ static std::shared_ptr<Promise> awaitFuture(std::future<void>&& future);
283
+ static std::shared_ptr<Promise> resolved();
284
+ static std::shared_ptr<Promise> rejected(const std::exception_ptr& error);
284
285
 
285
286
  public:
286
- static std::shared_ptr<Promise> create() {
287
- return std::shared_ptr<Promise>(new Promise());
288
- }
289
-
290
- static std::shared_ptr<Promise> async(std::function<void()>&& run) {
291
- auto promise = create();
292
- ThreadPool::shared().run([run = std::move(run), promise]() {
293
- try {
294
- // Run the code, then resolve.
295
- run();
296
- promise->resolve();
297
- } catch (...) {
298
- // It threw an error.
299
- promise->reject(std::current_exception());
300
- }
301
- });
302
- return promise;
303
- }
304
-
305
- static std::shared_ptr<Promise> awaitFuture(std::future<void>&& future) {
306
- auto sharedFuture = std::make_shared<std::future<void>>(std::move(future));
307
- return async([sharedFuture = std::move(sharedFuture)]() { sharedFuture->get(); });
308
- }
309
-
310
- static std::shared_ptr<Promise> resolved() {
311
- auto promise = create();
312
- promise->resolve();
313
- return promise;
314
- }
315
- static std::shared_ptr<Promise> rejected(const std::exception_ptr& error) {
316
- auto promise = create();
317
- promise->reject(error);
318
- return promise;
319
- }
287
+ void resolve();
288
+ void reject(const std::exception_ptr& exception);
320
289
 
321
290
  public:
322
- void resolve() {
323
- std::unique_lock lock(_mutex);
324
- #ifdef NITRO_DEBUG
325
- assertPromiseState(*this, PromiseTask::WANTS_TO_RESOLVE);
326
- #endif
327
- _isResolved = true;
328
- for (const auto& onResolved : _onResolvedListeners) {
329
- onResolved();
330
- }
331
- didFinish();
332
- }
333
- void reject(const std::exception_ptr& exception) {
334
- if (exception == nullptr) [[unlikely]] {
335
- throw std::runtime_error("Cannot reject Promise<void> with a null exception_ptr!");
336
- }
337
-
338
- std::unique_lock lock(_mutex);
339
- #ifdef NITRO_DEBUG
340
- assertPromiseState(*this, PromiseTask::WANTS_TO_REJECT);
341
- #endif
342
- _error = exception;
343
- for (const auto& onRejected : _onRejectedListeners) {
344
- onRejected(exception);
345
- }
346
- didFinish();
347
- }
348
-
349
- public:
350
- void addOnResolvedListener(OnResolvedFunc&& onResolved) {
351
- std::unique_lock lock(_mutex);
352
- if (_isResolved) {
353
- onResolved();
354
- } else {
355
- _onResolvedListeners.push_back(std::move(onResolved));
356
- }
357
- }
358
- void addOnResolvedListener(const OnResolvedFunc& onResolved) {
359
- std::unique_lock lock(_mutex);
360
- if (_isResolved) {
361
- onResolved();
362
- } else {
363
- _onResolvedListeners.push_back(onResolved);
364
- }
365
- }
366
- void addOnRejectedListener(OnRejectedFunc&& onRejected) {
367
- std::unique_lock lock(_mutex);
368
- if (_error) {
369
- onRejected(_error);
370
- } else {
371
- // Promise is not yet rejected, put the listener in our queue.
372
- _onRejectedListeners.push_back(std::move(onRejected));
373
- }
374
- }
375
- void addOnRejectedListener(const OnRejectedFunc& onRejected) {
376
- std::unique_lock lock(_mutex);
377
- if (_error) {
378
- onRejected(_error);
379
- } else {
380
- // Promise is not yet rejected, put the listener in our queue.
381
- _onRejectedListeners.push_back(onRejected);
382
- }
383
- }
291
+ void addOnResolvedListener(OnResolvedFunc&& onResolved);
292
+ void addOnResolvedListener(const OnResolvedFunc& onResolved);
293
+ void addOnRejectedListener(OnRejectedFunc&& onRejected);
294
+ void addOnRejectedListener(const OnRejectedFunc& onRejected);
384
295
 
385
296
  public:
386
- std::future<void> await() {
387
- auto promise = std::make_shared<std::promise<void>>();
388
- addOnResolvedListener([promise]() { promise->set_value(); });
389
- addOnRejectedListener([promise](const std::exception_ptr& error) { promise->set_exception(error); });
390
- return promise->get_future();
391
- }
297
+ std::future<void> await();
392
298
 
393
299
  public:
394
- inline const std::exception_ptr& getError() {
395
- if (!isRejected()) {
396
- throw std::runtime_error("Cannot get error when Promise<void> is not yet rejected!");
397
- }
398
- return _error;
399
- }
300
+ const std::exception_ptr& getError();
400
301
 
401
302
  public:
402
- [[nodiscard]]
403
303
  inline bool isResolved() const noexcept {
404
304
  return _isResolved;
405
305
  }
406
- [[nodiscard]]
407
306
  inline bool isRejected() const noexcept {
408
307
  return _error != nullptr;
409
308
  }
410
- [[nodiscard]]
411
309
  inline bool isPending() const noexcept {
412
310
  return !isResolved() && !isRejected();
413
311
  }
414
312
 
415
313
  private:
416
- void didFinish() noexcept {
417
- _onResolvedListeners.clear();
418
- _onRejectedListeners.clear();
419
- }
314
+ void didFinish() noexcept;
420
315
 
421
316
  private:
422
317
  std::mutex _mutex;
@@ -53,13 +53,16 @@ jsi::Value HybridObjectPrototype::createPrototype(jsi::Runtime& runtime, const s
53
53
  const std::string& name = getter.first;
54
54
  if (isReadonly) {
55
55
  // get
56
- ObjectUtils::defineProperty(
57
- runtime, object, name.c_str(),
58
- ComputedReadonlyPropertyDescriptor{.configurable = false, .enumerable = false, .get = getter.second.toJSFunction(runtime)});
56
+ ObjectUtils::defineProperty(runtime, object, name.c_str(),
57
+ ComputedReadonlyPropertyDescriptor{// readonly
58
+ .configurable = false,
59
+ .enumerable = true,
60
+ .get = getter.second.toJSFunction(runtime)});
59
61
  } else {
60
62
  // get + set
61
63
  ObjectUtils::defineProperty(runtime, object, name.c_str(),
62
- ComputedPropertyDescriptor{.configurable = false,
64
+ ComputedPropertyDescriptor{// readonly with setter
65
+ .configurable = false,
63
66
  .enumerable = false,
64
67
  .get = getter.second.toJSFunction(runtime),
65
68
  .set = setter->second.toJSFunction(runtime)});
@@ -21,6 +21,7 @@ namespace margelo::nitro {
21
21
  * the data will be bulk-memcopied.
22
22
  */
23
23
  template <typename T>
24
+ [[deprecated("FastVectorCopy is not safe for Swift - upgrade Nitro!")]]
24
25
  std::vector<T> FastVectorCopy(const T* CONTIGUOUS_MEMORY NON_NULL data, size_t size) {
25
26
  assert(data != nullptr && "FastVectoryCopy: data cannot be null!");
26
27
 
@@ -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.31.0"
12
+ #define NITRO_VERSION "0.31.2"
13
13
 
14
14
  // Sets whether to use debug or optimized production build flags
15
15
  #ifdef DEBUG
@@ -145,9 +145,12 @@ BorrowingReference<jsi::Function> ObjectUtils::getGlobalFunction(jsi::Runtime& r
145
145
  std::string stringKey = key;
146
146
  auto iterator = functionCache.find(stringKey);
147
147
  if (iterator != functionCache.end()) {
148
- // We found it! Copy & return the reference
148
+ // We found it! Let's check if the reference is still valid...
149
149
  BorrowingReference<jsi::Function> function = iterator->second;
150
- return function;
150
+ if (function != nullptr) [[likely]] {
151
+ // It's still alive - let's use it from cache!
152
+ return function;
153
+ }
151
154
  }
152
155
  }
153
156
  // We haven't found the function with the given key in cache - so let's get it:
@@ -10,7 +10,7 @@ import Foundation
10
10
  /// Holds instances of `std::shared_ptr<ArrayBuffer>`, which can be passed
11
11
  /// between native and JS **without copy**.
12
12
  ///
13
- /// See `data`, `size` and `isOwning`.
13
+ /// See `data`, `size` and `isOwner`.
14
14
  public typealias ArrayBuffer = margelo.nitro.ArrayBufferHolder
15
15
 
16
16
  @available(*, deprecated, renamed: "ArrayBuffer")
@@ -77,10 +77,10 @@ extension ArrayBuffer {
77
77
 
78
78
  extension ArrayBuffer {
79
79
  /**
80
- * Copy the given `UnsafeMutablePointer<UInt8>` into a new **owning** `ArrayBuffer`.
80
+ * Copy the given `UnsafePointer<UInt8>` into a new **owning** `ArrayBuffer`.
81
81
  */
82
82
  public static func copy(
83
- of other: UnsafeMutablePointer<UInt8>,
83
+ of other: UnsafePointer<UInt8>,
84
84
  size: Int
85
85
  ) -> ArrayBuffer {
86
86
  // 1. Create new `UnsafeMutablePointer<UInt8>`
@@ -94,18 +94,6 @@ extension ArrayBuffer {
94
94
  return ArrayBuffer.wrap(copy, size, deleteFunc)
95
95
  }
96
96
 
97
- /**
98
- * Copy the given `UnsafeMutableRawPointer` into a new **owning** `ArrayBuffer`.
99
- */
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)
107
- }
108
-
109
97
  /**
110
98
  * Copy the given `ArrayBuffer` into a new **owning** `ArrayBuffer`.
111
99
  */
@@ -161,3 +149,19 @@ extension ArrayBuffer {
161
149
  }
162
150
  }
163
151
  }
152
+
153
+ // pragma MARK: Helper
154
+
155
+ extension ArrayBuffer {
156
+ /**
157
+ * Returns an **owning** version of this `ArrayBuffer`.
158
+ * If this `ArrayBuffer` already is **owning**, it is returned as-is.
159
+ * If this `ArrayBuffer` is **non-owning**, it is _copied_.
160
+ */
161
+ public func asOwning() -> ArrayBuffer {
162
+ if !isOwner {
163
+ return ArrayBuffer.copy(of: self)
164
+ }
165
+ return self
166
+ }
167
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-nitro-modules",
3
- "version": "0.31.0",
3
+ "version": "0.31.2",
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",