react-native-nitro-modules 0.32.0-beta.0 → 0.32.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.
@@ -64,7 +64,7 @@ Pod::Spec.new do |s|
64
64
  xcconfig = {
65
65
  # Use C++ 20
66
66
  "CLANG_CXX_LANGUAGE_STANDARD" => "c++20",
67
- # Enables C++ <-> Swift interop (by default it's only C)
67
+ # Enables C++ <-> Swift interop (by default its only ObjC)
68
68
  "SWIFT_OBJC_INTEROP_MODE" => "objcxx",
69
69
  # Enables stricter modular headers
70
70
  "DEFINES_MODULE" => "YES",
@@ -7,7 +7,7 @@ buildscript {
7
7
  }
8
8
 
9
9
  dependencies {
10
- classpath "com.android.tools.build:gradle:8.13.1"
10
+ classpath "com.android.tools.build:gradle:8.13.2"
11
11
  }
12
12
  }
13
13
 
@@ -5,8 +5,6 @@
5
5
  // Created by Marc Rousavy on 14.07.24.
6
6
  //
7
7
 
8
- #pragma once
9
-
10
8
  #include "JAnyMap.hpp"
11
9
 
12
10
  namespace margelo::nitro {
@@ -117,4 +115,104 @@ jni::local_ref<jni::JHashMap<jni::JString, jni::JObject>> JAnyMap::anyObjectToJH
117
115
  return jMap;
118
116
  }
119
117
 
118
+ AnyValue JAnyMap::jObjectToAnyValue(jni::alias_ref<jni::JObject> jObject) {
119
+ if (!jObject) {
120
+ return nitro::null;
121
+ }
122
+
123
+ // Check for Double
124
+ if (jObject->isInstanceOf(jni::JDouble::javaClassStatic())) {
125
+ auto jDouble = jni::static_ref_cast<jni::JDouble>(jObject);
126
+ return jDouble->doubleValue();
127
+ }
128
+
129
+ // Check for Float
130
+ if (jObject->isInstanceOf(jni::JFloat::javaClassStatic())) {
131
+ auto jFloat = jni::static_ref_cast<jni::JFloat>(jObject);
132
+ return static_cast<double>(jFloat->floatValue());
133
+ }
134
+
135
+ // Check for Integer
136
+ if (jObject->isInstanceOf(jni::JInteger::javaClassStatic())) {
137
+ auto jInt = jni::static_ref_cast<jni::JInteger>(jObject);
138
+ return static_cast<double>(jInt->intValue());
139
+ }
140
+
141
+ // Check for Boolean
142
+ if (jObject->isInstanceOf(jni::JBoolean::javaClassStatic())) {
143
+ auto jBool = jni::static_ref_cast<jni::JBoolean>(jObject);
144
+ return jBool->booleanValue();
145
+ }
146
+
147
+ // Check for Long (bigint)
148
+ if (jObject->isInstanceOf(jni::JLong::javaClassStatic())) {
149
+ auto jLong = jni::static_ref_cast<jni::JLong>(jObject);
150
+ return jLong->longValue();
151
+ }
152
+
153
+ // Check for String
154
+ if (jObject->isInstanceOf(jni::JString::javaClassStatic())) {
155
+ auto jString = jni::static_ref_cast<jni::JString>(jObject);
156
+ return jString->toStdString();
157
+ }
158
+
159
+ // Check for List (array)
160
+ if (jObject->isInstanceOf(jni::JList<jni::JObject>::javaClassStatic())) {
161
+ auto jList = jni::static_ref_cast<jni::JList<jni::JObject>>(jObject);
162
+ return jListToAnyArray(jList);
163
+ }
164
+
165
+ // Check for Map (object)
166
+ if (jObject->isInstanceOf(jni::JMap<jni::JString, jni::JObject>::javaClassStatic())) {
167
+ auto jMap = jni::static_ref_cast<jni::JMap<jni::JString, jni::JObject>>(jObject);
168
+ return jHashMapToAnyObject(jMap);
169
+ }
170
+
171
+ throw std::runtime_error("Cannot convert JObject to AnyValue - unsupported type!");
172
+ }
173
+
174
+ AnyArray JAnyMap::jListToAnyArray(jni::alias_ref<jni::JList<jni::JObject>> jList) {
175
+ AnyArray array;
176
+ array.reserve(jList->size());
177
+ for (const auto& item : *jList) {
178
+ array.push_back(jObjectToAnyValue(item));
179
+ }
180
+ return array;
181
+ }
182
+
183
+ AnyObject JAnyMap::jHashMapToAnyObject(jni::alias_ref<jni::JMap<jni::JString, jni::JObject>> jMap) {
184
+ AnyObject object;
185
+ object.reserve(jMap->size());
186
+ for (const auto& entry : *jMap) {
187
+ object.emplace(entry.first->toStdString(), jObjectToAnyValue(entry.second));
188
+ }
189
+ return object;
190
+ }
191
+
192
+ jni::local_ref<JAnyMap::javaobject> JAnyMap::fromMap(jni::alias_ref<jclass>, jni::alias_ref<jni::JMap<jni::JString, jni::JObject>> javaMap,
193
+ bool ignoreIncompatible) {
194
+ size_t size = javaMap->size();
195
+ jni::local_ref<JAnyMap::javaobject> anyMap = JAnyMap::create(size);
196
+
197
+ auto& map = anyMap->cthis()->_map->getMap();
198
+
199
+ // Bulk convert all entries from Java to C++
200
+ for (const auto& entry : *javaMap) {
201
+ try {
202
+ std::string key = entry.first->toStdString();
203
+ AnyValue value = jObjectToAnyValue(entry.second);
204
+ map.emplace(std::move(key), std::move(value));
205
+ } catch (...) {
206
+ if (ignoreIncompatible) {
207
+ // encountered an incompatible key. Ignore it.
208
+ } else {
209
+ // encountered an incompatible key - we now throw!
210
+ throw;
211
+ }
212
+ }
213
+ }
214
+
215
+ return anyMap;
216
+ }
217
+
120
218
  } // namespace margelo::nitro
@@ -41,6 +41,18 @@ public:
41
41
  static jni::local_ref<JAnyMap::javaobject> create(const std::shared_ptr<AnyMap>& map) {
42
42
  return newObjectCxxArgs(map);
43
43
  }
44
+ /**
45
+ * Create a new `JAnyMap` from the given preallocated size.
46
+ */
47
+ static jni::local_ref<JAnyMap::javaobject> create(int preallocatedSize) {
48
+ return newObjectCxxArgs(preallocatedSize);
49
+ }
50
+ /**
51
+ * Create a new empty `JAnyMap`.
52
+ */
53
+ static jni::local_ref<JAnyMap::javaobject> create() {
54
+ return newObjectCxxArgs();
55
+ }
44
56
 
45
57
  private:
46
58
  JAnyMap() {
@@ -133,11 +145,24 @@ protected:
133
145
  */
134
146
  jni::local_ref<jni::JHashMap<jni::JString, jni::JObject>> toHashMap();
135
147
 
148
+ /**
149
+ * Bulk-converts a Java `Map<String, Object>` into this `JAnyMap` in a single JNI call.
150
+ *
151
+ * When `ignoreIncompatible` is `true`, this will drop keys that can't be converted.
152
+ * When `ignoreIncompatible` is `false`, this will throw when a key cannot be converted.
153
+ */
154
+ static jni::local_ref<JAnyMap::javaobject> fromMap(jni::alias_ref<jclass>, jni::alias_ref<jni::JMap<jni::JString, jni::JObject>> javaMap,
155
+ bool ignoreIncompatible);
156
+
136
157
  private:
137
158
  static jni::local_ref<jni::JObject> anyValueToJObject(const AnyValue& value);
138
159
  static jni::local_ref<jni::JArrayList<jni::JObject>> anyArrayToJList(const AnyArray& array);
139
160
  static jni::local_ref<jni::JHashMap<jni::JString, jni::JObject>> anyObjectToJHashMap(const AnyObject& object);
140
161
 
162
+ static AnyValue jObjectToAnyValue(jni::alias_ref<jni::JObject> jObject);
163
+ static AnyArray jListToAnyArray(jni::alias_ref<jni::JList<jni::JObject>> jList);
164
+ static AnyObject jHashMapToAnyObject(jni::alias_ref<jni::JMap<jni::JString, jni::JObject>> jMap);
165
+
141
166
  public:
142
167
  [[nodiscard]]
143
168
  std::shared_ptr<AnyMap> getMap() const {
@@ -189,6 +214,7 @@ public:
189
214
  makeNativeMethod("merge", JAnyMap::merge),
190
215
  // bulk conversion
191
216
  makeNativeMethod("toHashMap", JAnyMap::toHashMap),
217
+ makeNativeMethod("fromMap", JAnyMap::fromMap),
192
218
  });
193
219
  }
194
220
  };
@@ -39,29 +39,26 @@ class AnyMap {
39
39
  }
40
40
 
41
41
  companion object {
42
- fun fromMap(
42
+ /**
43
+ * Converts the given [map] to a new [AnyMap].
44
+ * @param map The map of keys/value types. Only a number of value types
45
+ * are supported in [AnyMap] - see Nitro docs for more information.
46
+ * @param ignoreIncompatible Whether to throw when an incompatible
47
+ * type is found, or not. If this is `false`, all incompatible key/value
48
+ * pairs will just be ignored.
49
+ */
50
+ @JvmStatic
51
+ external fun fromMap(
43
52
  map: Map<String, Any?>,
44
- ignoreIncompatible: Boolean = false,
45
- ): AnyMap {
46
- val anyMap = AnyMap(map.size)
47
- for ((key, value) in map) {
48
- try {
49
- anyMap.setAny(key, value)
50
- } catch (error: Throwable) {
51
- if (ignoreIncompatible) {
52
- continue
53
- } else {
54
- throw error
55
- }
56
- }
57
- }
58
- return anyMap
59
- }
53
+ ignoreIncompatible: Boolean,
54
+ ): AnyMap
60
55
  }
61
56
 
62
- fun toMap(): Map<String, Any?> {
63
- return toHashMap()
64
- }
57
+ /**
58
+ * Converts this [AnyMap] to a new [HashMap] by
59
+ * copying each key/value.
60
+ */
61
+ external fun toHashMap(): HashMap<String, Any?>
65
62
 
66
63
  fun setAny(
67
64
  key: String,
@@ -74,7 +71,10 @@ class AnyMap {
74
71
  return getAnyValue(key).toAny()
75
72
  }
76
73
 
77
- external fun toHashMap(): HashMap<String, Any?>
74
+ private external fun fromHashMap(
75
+ map: Map<String, Any?>,
76
+ ignoreIncompatible: Boolean,
77
+ )
78
78
 
79
79
  @FastNative
80
80
  external fun contains(key: String): Boolean
@@ -43,7 +43,7 @@ class ArrayBuffer {
43
43
  * - If the `ArrayBuffer` holds a `ByteBuffer`, `getBuffer(false)` can safely be called to
44
44
  * get shared access to the underlying data, without performing any copies.
45
45
  * - If the `ArrayBuffer` doesn't hold a `ByteBuffer`, it can still be accessed via `getBuffer(false)`,
46
- * but the returned `ByteBuffer` is only valid as long as it's parent `ArrayBuffer` is alive.
46
+ * but the returned `ByteBuffer` is only valid as long as its parent `ArrayBuffer` is alive.
47
47
  */
48
48
  val isByteBuffer: Boolean
49
49
  get() = getIsByteBuffer()
@@ -104,7 +104,7 @@ class ArrayBuffer {
104
104
  // The ByteBuffer is 1:1 mapped to a byte array - return as is!
105
105
  return array
106
106
  }
107
- // we had a CPU-backed array, but it's size differs from our ArrayBuffer size.
107
+ // we had a CPU-backed array, but its size differs from our ArrayBuffer size.
108
108
  // This might be because the ArrayBuffer has a smaller view of the data, so we need
109
109
  // to resort back to a good ol' copy.
110
110
  }
@@ -35,7 +35,7 @@ abstract class HybridObject {
35
35
  * Eagerly- (and manually-) dispose all native resources this `HybridObject` holds.
36
36
  * This method can only be manually called from JS using `dispose()`.
37
37
  *
38
- * If this method is never manually called, a `HybridObject` is expected to disposes it's
38
+ * If this method is never manually called, a `HybridObject` is expected to disposes its
39
39
  * resources as usual via the object's destructor (`~HybridObject()`, `deinit` or `finalize()`).
40
40
  *
41
41
  * By default, this method does nothing. It can be overridden to perform actual disposing/cleanup
@@ -58,13 +58,13 @@ abstract class HybridObject {
58
58
 
59
59
  /**
60
60
  * Holds the native C++ instance.
61
- * In `HybridObject`, the C++ instance is a sub-class of `JHybridObject`, such as one of it's specs.
61
+ * In `HybridObject`, the C++ instance is a sub-class of `JHybridObject`, such as one of its specs.
62
62
  * This is `null`, until `updateNative(..)` is called.
63
63
  */
64
64
  private var mHybridData: HybridData? = null
65
65
 
66
66
  /**
67
- * If `HybridObject` is subclassed, the sub-class needs to create it's own `HybridData`
67
+ * If `HybridObject` is subclassed, the sub-class needs to create its own `HybridData`
68
68
  * with a C++ `jni::HybridClass` representing the subclass directly.
69
69
  * Then, that `HybridData` must be passed upwards to `HybridObject` using `updateNative(..)`.
70
70
  *
@@ -189,7 +189,7 @@ void AnyMap::setAny(const std::string& key, const AnyValue& value) {
189
189
  }
190
190
 
191
191
  // C++ getter
192
- const std::unordered_map<std::string, AnyValue>& AnyMap::getMap() const {
192
+ std::unordered_map<std::string, AnyValue>& AnyMap::getMap() {
193
193
  return _map;
194
194
  }
195
195
 
@@ -201,7 +201,7 @@ public:
201
201
  /**
202
202
  * Get the actual C++ map that holds all keys and variant values.
203
203
  */
204
- const std::unordered_map<std::string, AnyValue>& getMap() const;
204
+ std::unordered_map<std::string, AnyValue>& getMap();
205
205
 
206
206
  public:
207
207
  /**
@@ -28,7 +28,7 @@ using DeleteFn = std::function<void()>;
28
28
  * - `NativeArrayBuffer`: Created from native (C++), and can either own the memory (`isOwner()`), or borrow it.
29
29
  * - `JSArrayBuffer`: Received from JS, and will only be alive for as long as the JS Runtime is actually alive.
30
30
  *
31
- * Also, an `ArrayBuffer` can either own it's memory, or just borrow it's memory.
31
+ * Also, an `ArrayBuffer` can either own its memory, or just borrow its memory.
32
32
  * - Owning = the `ArrayBuffer`'s `data()` is alive as long as the `ArrayBuffer` is alive.
33
33
  * When this `ArrayBuffer` gets deleted, it will free the memory.
34
34
  * - Borrowed = the `ArrayBuffer`'s `data()` might be deleted at any point from an external source (e.g. the JS garbage collector).
@@ -116,13 +116,13 @@ private:
116
116
  /**
117
117
  * Represents a JS-based `ArrayBuffer`.
118
118
  *
119
- * While it's underlying data might have been allocated on the native side (`NativeArrayBuffer`),
119
+ * While its underlying data might have been allocated on the native side (`NativeArrayBuffer`),
120
120
  * we only have a JS reference to the `ArrayBuffer` object so it is considered a "borrowed"-resource.
121
121
  *
122
122
  * `data()` and `size()` can only be accessed synchronously on the JS Runtime Thread.
123
123
  * If you want to access it elsewhere, copy the buffer first.
124
124
  *
125
- * If the JS ArrayBuffer (or it's JS Runtime) have already been deleted, `data()` returns `nullptr`.
125
+ * If the JS ArrayBuffer (or its JS Runtime) have already been deleted, `data()` returns `nullptr`.
126
126
  */
127
127
  class JSArrayBuffer final : public ArrayBuffer {
128
128
  public:
@@ -60,14 +60,14 @@ public:
60
60
  /**
61
61
  * Return the `jsi::Object` that holds this `HybridObject`. (boxed in a `jsi::Value`)
62
62
  * This properly assigns (or creates) the base prototype for this type,
63
- * and assigns it's NativeState.
63
+ * and assigns its NativeState.
64
64
  * Additionally, this sets the external memory pressure for proper GC memory management.
65
65
  */
66
66
  jsi::Value toObject(jsi::Runtime& runtime);
67
67
 
68
68
  public:
69
69
  /**
70
- * Get the `std::shared_ptr` instance of this HybridObject as it's concrete type.
70
+ * Get the `std::shared_ptr` instance of this HybridObject as its concrete type.
71
71
  * The HybridObject must be managed inside a `shared_ptr` already, otherwise this will fail.
72
72
  */
73
73
  template <typename Derived>
@@ -99,7 +99,7 @@ public:
99
99
  * Eagerly- (and manually-) dispose all native resources this `HybridObject` holds.
100
100
  * This method can only be manually called from JS using `dispose()`.
101
101
  *
102
- * If this method is never manually called, a `HybridObject` is expected to disposes it's
102
+ * If this method is never manually called, a `HybridObject` is expected to disposes its
103
103
  * resources as usual via the object's destructor (`~HybridObject()`, `deinit` or `finalize()`).
104
104
  *
105
105
  * By default, this method does nothing. It can be overridden to perform actual disposing/cleanup
@@ -71,7 +71,7 @@ jsi::Value HybridNitroModulesProxy::isHybridObject(jsi::Runtime& runtime, const
71
71
  }
72
72
 
73
73
  std::shared_ptr<HybridObject> HybridNitroModulesProxy::updateMemorySize(const std::shared_ptr<HybridObject>& hybridObject) {
74
- // If a hybridObject goes from Native -> JS, it will update it's memory size internally (in `HybridObject::toObject(..)`).
74
+ // If a hybridObject goes from Native -> JS, it will update its memory size internally (in `HybridObject::toObject(..)`).
75
75
  // This is all that function does.
76
76
  return hybridObject;
77
77
  }
@@ -50,7 +50,7 @@ struct JSIConverter<T, std::enable_if_t<is_shared_ptr_to_v<T, jsi::MutableBuffer
50
50
  if (!object.isArrayBuffer(runtime)) [[unlikely]] {
51
51
  throw std::invalid_argument("Object \"" + arg.toString(runtime).utf8(runtime) +
52
52
  "\" is not an ArrayBuffer! "
53
- "Are you maybe passing a TypedArray (e.g. Uint8Array)? Try to pass it's `.buffer` value.");
53
+ "Are you maybe passing a TypedArray (e.g. Uint8Array)? Try to pass its `.buffer` value.");
54
54
  }
55
55
  #endif
56
56
  if (object.hasNativeState<MutableBufferNativeState>(runtime)) {
@@ -69,7 +69,7 @@ struct JSIConverter<T, std::enable_if_t<is_shared_ptr_to_v<T, jsi::MutableBuffer
69
69
  }
70
70
  static inline jsi::Value toJSI(jsi::Runtime& runtime, const std::shared_ptr<jsi::MutableBuffer>& buffer) {
71
71
  if (auto jsBuffer = std::dynamic_pointer_cast<JSArrayBuffer>(buffer)) {
72
- // It already is a JSBuffer! Let's try to just get it's existing jsi::Value...
72
+ // It already is a JSBuffer! Let's try to just get its existing jsi::Value...
73
73
  auto jsValue = jsBuffer->getJSReference();
74
74
  if (jsValue != nullptr) [[likely]] {
75
75
  return jsi::Value(runtime, *jsValue);
@@ -65,7 +65,7 @@ struct JSIConverter<T, std::enable_if_t<is_shared_ptr_to_v<T, jsi::NativeState>>
65
65
  }
66
66
 
67
67
  if constexpr (std::is_base_of_v<HybridObject, TPointee>) {
68
- // It's a HybridObject - use it's internal constructor which caches jsi::Objects for proper memory management!
68
+ // It's a HybridObject - use its internal constructor which caches jsi::Objects for proper memory management!
69
69
  return arg->toObject(runtime);
70
70
  } else {
71
71
  // It's any other kind of jsi::NativeState - just create it as normal. This will not have a prototype then!
@@ -63,7 +63,7 @@ private:
63
63
  return node;
64
64
  } else {
65
65
  if (node->hasBase()) {
66
- // We didn't find a match in this prototype, let's recursively try it's parent!
66
+ // We didn't find a match in this prototype, let's recursively try its parent!
67
67
  return getOrExtendPrototype<Derived>(node->getBase());
68
68
  } else {
69
69
  // We didn't find `Derived` and we don't have a base- add a child and shift the tree by one.
@@ -27,7 +27,7 @@ public:
27
27
  public:
28
28
  /**
29
29
  * Registers the given HybridObject in the `HybridObjectRegistry`.
30
- * It will be uniquely identified via it's `hybridObjectName`, and can be initialized from
30
+ * It will be uniquely identified via its `hybridObjectName`, and can be initialized from
31
31
  * JS using `NitroModules.createHybridObject<T>(name)` - which will call the `constructorFn` here.
32
32
  */
33
33
  static void registerHybridObjectConstructor(const std::string& hybridObjectName, HybridObjectConstructorFn&& constructorFn);
@@ -15,7 +15,7 @@ namespace margelo::nitro {
15
15
  using namespace facebook;
16
16
 
17
17
  /**
18
- * A Dispatcher that uses react::CallInvoker for it's implementation
18
+ * A Dispatcher that uses react::CallInvoker for its implementation
19
19
  */
20
20
  class CallInvokerDispatcher final : public Dispatcher {
21
21
  public:
@@ -35,7 +35,7 @@ public:
35
35
  public:
36
36
  /**
37
37
  * Calls this `SyncJSCallback` synchronously, and
38
- * returns it's result (`R`).
38
+ * returns its result (`R`).
39
39
  * The callee is responsible for ensuring that the
40
40
  * underlying `jsi::Function` can actually be called from this Thread.
41
41
  * In Debug, sanity checks are made to ensure the `jsi::Function` is still alive.
@@ -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.32.0-beta.0"
12
+ #define NITRO_VERSION "0.32.0"
13
13
 
14
14
  // Sets whether to use debug or optimized production build flags
15
15
  #ifdef DEBUG
@@ -30,7 +30,7 @@ public protocol HybridObject: AnyObject {
30
30
  * Eagerly- (and manually-) dispose all native resources this `HybridObject` holds.
31
31
  * This method can only be manually called from JS using `dispose()`.
32
32
  *
33
- * If this method is never manually called, a `HybridObject` is expected to disposes it's
33
+ * If this method is never manually called, a `HybridObject` is expected to disposes its
34
34
  * resources as usual via the object's destructor (`~HybridObject()`, `deinit` or `finalize()`).
35
35
  *
36
36
  * By default, this method does nothing. It can be overridden to perform actual disposing/cleanup
@@ -31,7 +31,7 @@ extension SwiftClosure {
31
31
  * This can then be called from both C++ and Swift.
32
32
  */
33
33
  public init(wrappingClosure closure: @escaping () -> Void) {
34
- // Wrap closure in void*, and increment it's ref count so it stays alive.
34
+ // Wrap closure in void*, and increment its ref count so it stays alive.
35
35
  let context = Unmanaged.passRetained(ClosureWrapper(closure: closure)).toOpaque()
36
36
 
37
37
  // Create a C-style Function Pointer, which calls the actual Swift closure.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-nitro-modules",
3
- "version": "0.32.0-beta.0",
3
+ "version": "0.32.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",