react-native-nitro-modules 0.2.0 → 0.4.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.
Files changed (53) hide show
  1. package/README.md +8 -2
  2. package/android/CMakeLists.txt +4 -4
  3. package/android/src/main/cpp/JNIOnLoad.cpp +7 -6
  4. package/android/src/main/java/com/margelo/nitro/HybridObject.kt +0 -11
  5. package/android/src/main/java/com/margelo/nitro/HybridObjectRegistry.java +2 -13
  6. package/android/src/main/java/com/margelo/nitro/NitroModulesPackage.java +12 -0
  7. package/cpp/core/AnyMap.hpp +12 -0
  8. package/cpp/core/HybridObject.cpp +0 -1
  9. package/cpp/jsi/JSICache.cpp +1 -3
  10. package/cpp/jsi/JSIConverter+Promise.hpp +2 -2
  11. package/cpp/jsi/{Promise.cpp → JSPromise.cpp} +6 -6
  12. package/cpp/jsi/{Promise.hpp → JSPromise.hpp} +10 -10
  13. package/cpp/registry/HybridObjectRegistry.cpp +22 -2
  14. package/cpp/registry/HybridObjectRegistry.hpp +6 -4
  15. package/cpp/turbomodule/NativeNitroModules.cpp +38 -2
  16. package/cpp/turbomodule/NativeNitroModules.hpp +2 -0
  17. package/cpp/utils/NitroDefines.hpp +6 -0
  18. package/ios/core/Promise.cpp +10 -0
  19. package/ios/core/Promise.hpp +43 -0
  20. package/ios/platform/ThreadUtils.cpp +1 -0
  21. package/lib/HybridObject.d.ts +13 -7
  22. package/lib/NativeNitroModules.d.ts +2 -0
  23. package/lib/NitroModules.d.ts +9 -1
  24. package/lib/NitroModules.js +15 -1
  25. package/lib/commonjs/NativeNitroModules.js.map +1 -1
  26. package/lib/commonjs/NitroModules.js +15 -1
  27. package/lib/commonjs/NitroModules.js.map +1 -1
  28. package/lib/module/NativeNitroModules.js.map +1 -1
  29. package/lib/module/NitroModules.js +15 -1
  30. package/lib/module/NitroModules.js.map +1 -1
  31. package/lib/tsconfig.tsbuildinfo +1 -1
  32. package/lib/typescript/AnyMap.d.ts +17 -0
  33. package/lib/typescript/AnyMap.d.ts.map +1 -0
  34. package/lib/typescript/HybridObject.d.ts +13 -7
  35. package/lib/typescript/HybridObject.d.ts.map +1 -1
  36. package/lib/typescript/ModuleNotFoundError.d.ts +7 -0
  37. package/lib/typescript/ModuleNotFoundError.d.ts.map +1 -0
  38. package/lib/typescript/NativeNitroModules.d.ts +15 -0
  39. package/lib/typescript/NativeNitroModules.d.ts.map +1 -0
  40. package/lib/typescript/NativeNitroModules.web.d.ts +5 -0
  41. package/lib/typescript/NativeNitroModules.web.d.ts.map +1 -0
  42. package/lib/typescript/NitroModules.d.ts +26 -0
  43. package/lib/typescript/NitroModules.d.ts.map +1 -1
  44. package/lib/typescript/__tests__/index.test.d.ts +1 -0
  45. package/lib/typescript/__tests__/index.test.d.ts.map +1 -0
  46. package/package.json +2 -2
  47. package/src/HybridObject.ts +13 -7
  48. package/src/NativeNitroModules.ts +2 -0
  49. package/src/NitroModules.ts +15 -1
  50. package/lib/NativeNitro.d.ts +0 -8
  51. package/lib/NativeNitro.js +0 -3
  52. package/lib/createTestObject.d.ts +0 -22
  53. package/lib/createTestObject.js +0 -7
package/README.md CHANGED
@@ -153,6 +153,10 @@ The following C++ / JS types are supported out of the box:
153
153
  <td><code>Promise&lt;T&gt;</code></td>
154
154
  <td><code>std::future&lt;T&gt;</code></td>
155
155
  </tr>
156
+ <tr>
157
+ <td><code>(TArgs...) =&gt; void</code></td>
158
+ <td><code>std::function&lt;void (TArgs...)&gt;</code></td>
159
+ </tr>
156
160
  <tr>
157
161
  <td><code>(TArgs...) =&gt; TReturn</code></td>
158
162
  <td><code>std::function&lt;std::future&lt;TReturn&gt; (TArgs...)&gt;</code></td>
@@ -174,7 +178,7 @@ The following C++ / JS types are supported out of the box:
174
178
 
175
179
  Since the `JSIConverter<T>` is just a template, you can extend it with any other custom types by overloading the interface.
176
180
 
177
- For example, to add support for an enum, overload `JSIConverter<YourEnum>`:
181
+ For example, to add support for an enum, overload `JSIConverter<MyEnum>`:
178
182
 
179
183
  ```cpp
180
184
  #include <NitroModules/JSIConverter.hpp>
@@ -199,7 +203,9 @@ namespace margelo::nitro {
199
203
  }
200
204
  ```
201
205
 
202
- ..and on the JS side, you can implicitly cast the `number` to an enum as well:
206
+ Once the `JSIConverter<T>` for `MyEnum` is defined, you can use the type `MyEnum` in C++ methods, getters and setters of `HybridObject`s.
207
+
208
+ And on the JS side, you can simply treat the returned `number` (int) as a `MyEnum`:
203
209
 
204
210
  ```js
205
211
  enum MyEnum {
@@ -5,11 +5,11 @@ set (CMAKE_VERBOSE_MAKEFILE ON)
5
5
  set (CMAKE_CXX_STANDARD 20)
6
6
 
7
7
  # Find all C++ files (shared and platform specifics)
8
- file(GLOB shared_files
9
- "../cpp/**/*.cpp"
8
+ file(GLOB_RECURSE shared_files RELATIVE ${CMAKE_SOURCE_DIR}
9
+ "../cpp/**.cpp"
10
10
  )
11
- file(GLOB android_files
12
- "src/main/cpp/**/*.cpp"
11
+ file(GLOB_RECURSE android_files RELATIVE ${CMAKE_SOURCE_DIR}
12
+ "src/main/cpp/**.cpp"
13
13
  )
14
14
 
15
15
  # Create library "NitroModules" and add all C++ files to it
@@ -2,16 +2,17 @@
2
2
 
3
3
  #include "JHybridObjectRegistry.hpp"
4
4
  #include "RegisterNativeNitroModules.hpp"
5
+ #include <fbjni/fbjni.h>
5
6
  #include <jni.h>
6
7
 
7
8
  using namespace margelo::nitro;
8
9
 
9
10
  JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void*) {
10
- // 1. Initialize the Nitro JSI Turbo Module
11
- RegisterNativeNitroModules::registerNativeNitroModules();
11
+ return facebook::jni::initialize(vm, [] {
12
+ // 1. Initialize the Nitro JSI Turbo Module
13
+ RegisterNativeNitroModules::registerNativeNitroModules();
12
14
 
13
- // 2. Initialize all Java bindings
14
- JHybridObjectRegistry::registerNatives();
15
-
16
- return JNI_VERSION_1_2;
15
+ // 2. Initialize all Java bindings
16
+ JHybridObjectRegistry::registerNatives();
17
+ });
17
18
  }
@@ -1,6 +1,5 @@
1
1
  package com.margelo.nitro
2
2
 
3
- import android.util.Log
4
3
  import androidx.annotation.Keep
5
4
  import com.facebook.jni.HybridData
6
5
  import com.facebook.proguard.annotations.DoNotStrip
@@ -47,15 +46,5 @@ abstract class HybridObject {
47
46
 
48
47
  companion object {
49
48
  private const val TAG = "HybridObject"
50
- init {
51
- try {
52
- Log.i(TAG, "Loading NitroModules C++ library...")
53
- System.loadLibrary("NitroModules")
54
- Log.i(TAG, "Successfully loaded NitroModules C++ library!")
55
- } catch (e: Error) {
56
- Log.e(TAG, "Failed to load NitroModules C++ library! Is it properly installed and linked?", e)
57
- throw e
58
- }
59
- }
60
49
  }
61
50
  }
@@ -1,30 +1,19 @@
1
1
  package com.margelo.nitro;
2
2
 
3
- import android.util.Log;
4
-
5
3
  import java.util.function.Supplier;
6
4
 
7
5
  /**
8
6
  * A registry that holds initializers for HybridObjects.
9
- * This will be used to initialize them from JS using `NitroModules.get<T>(name)`.
7
+ * This will be used to initialize them from JS using `NitroModules.createHybridObject<T>(name)`.
10
8
  * @noinspection JavaJniMissingFunction
11
9
  */
12
10
  public class HybridObjectRegistry {
13
11
  /**
14
12
  * Registers the given HybridObject in the `HybridObjectRegistry`.
15
13
  * It will be uniquely identified via it's `hybridObjectName`, and can be initialized from
16
- * JS using `NitroModules.get<T>(name)` - which will call the `constructorFn` here.
14
+ * JS using `NitroModules.createHybridObject<T>(name)` - which will call the `constructorFn` here.
17
15
  */
18
16
  public static native void registerHybridObjectConstructor(String hybridObjectName, HybridObjectInitializer initializer);
19
17
 
20
18
  private static final String TAG = "HybridObjectRegistry";
21
- static {
22
- Log.i(TAG, "Loading native NitroModules C++ library...");
23
- try {
24
- System.loadLibrary("NitroModules");
25
- Log.i(TAG, "Successfully loaded native NitroModules C++ library!");
26
- } catch (Throwable e) {
27
- Log.e(TAG, "Failed to load native NitroModules C++ library!", e);
28
- }
29
- }
30
19
  }
@@ -1,5 +1,6 @@
1
1
  package com.margelo.nitro;
2
2
 
3
+ import android.util.Log;
3
4
  import androidx.annotation.Nullable;
4
5
 
5
6
  import com.facebook.react.bridge.NativeModule;
@@ -10,6 +11,17 @@ import com.facebook.react.TurboReactPackage;
10
11
  import java.util.HashMap;
11
12
 
12
13
  public class NitroModulesPackage extends TurboReactPackage {
14
+ private static final String TAG = "NitroModules";
15
+ static {
16
+ try {
17
+ Log.i(TAG, "Loading NitroModules C++ library...");
18
+ System.loadLibrary("NitroModules");
19
+ Log.i(TAG, "Successfully loaded NitroModules C++ library!");
20
+ } catch (Throwable e) {
21
+ Log.e(TAG, "Failed to load NitroModules C++ library! Is it properly installed and linked?", e);
22
+ throw e;
23
+ }
24
+ }
13
25
 
14
26
  @Nullable
15
27
  @Override
@@ -40,6 +40,12 @@ public:
40
40
  * Create a new instance of AnyMap.
41
41
  */
42
42
  explicit AnyMap() {}
43
+ /**
44
+ * Create a new instance of AnyMap with the given amount of spaces pre-allocated.
45
+ */
46
+ explicit AnyMap(size_t size) {
47
+ _map.reserve(size);
48
+ }
43
49
 
44
50
  public:
45
51
  /**
@@ -48,6 +54,12 @@ public:
48
54
  static std::shared_ptr<AnyMap> make() {
49
55
  return std::make_shared<AnyMap>();
50
56
  }
57
+ /**
58
+ * Create a new shared_ptr instance of AnyMap with the given amount of spaces pre-allocated.
59
+ */
60
+ static std::shared_ptr<AnyMap> make(size_t size) {
61
+ return std::make_shared<AnyMap>(size);
62
+ }
51
63
 
52
64
  public:
53
65
  /**
@@ -3,7 +3,6 @@
3
3
  //
4
4
 
5
5
  #include "HybridObject.hpp"
6
- #include "HybridContext.hpp"
7
6
  #include "JSIConverter.hpp"
8
7
  #include "NitroLogger.hpp"
9
8
 
@@ -8,8 +8,6 @@
8
8
  #include "JSICache.hpp"
9
9
  #include "JSIHelpers.hpp"
10
10
 
11
- #define DOUBLE_CHECK_GLOBAL_CACHE 1
12
-
13
11
  namespace margelo::nitro {
14
12
 
15
13
  static constexpr auto CACHE_PROP_NAME = "__nitroModulesJSICache";
@@ -48,7 +46,7 @@ JSICacheReference JSICache::getOrCreateCache(jsi::Runtime& runtime) {
48
46
  Logger::log(TAG, "JSICache was created, but it is no longer strong!");
49
47
  }
50
48
 
51
- #if DOUBLE_CHECK_GLOBAL_CACHE
49
+ #if DEBUG
52
50
  if (runtime.global().hasProperty(runtime, CACHE_PROP_NAME)) [[unlikely]] {
53
51
  throw std::runtime_error("The Runtime \"" + getRuntimeId(runtime) + "\" already has a global cache! (\"" + CACHE_PROP_NAME + "\")");
54
52
  }
@@ -16,7 +16,7 @@ struct JSIConverter;
16
16
  #include "JSIConverter.hpp"
17
17
 
18
18
  #include "Dispatcher.hpp"
19
- #include "Promise.hpp"
19
+ #include "JSPromise.hpp"
20
20
  #include "ThreadPool.hpp"
21
21
  #include "TypeInfo.hpp"
22
22
  #include <future>
@@ -38,7 +38,7 @@ struct JSIConverter<std::future<TResult>> {
38
38
  std::shared_ptr<Dispatcher> strongDispatcher = Dispatcher::getRuntimeGlobalDispatcher(runtime);
39
39
  std::weak_ptr<Dispatcher> weakDispatcher = strongDispatcher;
40
40
 
41
- return Promise::createPromise(runtime, [sharedFuture, weakDispatcher](jsi::Runtime& runtime, std::shared_ptr<Promise> promise) {
41
+ return JSPromise::createPromise(runtime, [sharedFuture, weakDispatcher](jsi::Runtime& runtime, std::shared_ptr<JSPromise> promise) {
42
42
  // Spawn new async thread to synchronously wait for the `future<T>` to complete
43
43
  std::shared_ptr<ThreadPool> pool = ThreadPool::getSharedPool();
44
44
  pool->run([promise, &runtime, weakDispatcher, sharedFuture]() {
@@ -1,4 +1,4 @@
1
- #include "Promise.hpp"
1
+ #include "JSPromise.hpp"
2
2
  #include "JSICache.hpp"
3
3
  #include "NitroLogger.hpp"
4
4
  #include <jsi/jsi.h>
@@ -7,13 +7,13 @@ namespace margelo::nitro {
7
7
 
8
8
  using namespace facebook;
9
9
 
10
- Promise::Promise(jsi::Runtime& runtime, jsi::Function&& resolver, jsi::Function&& rejecter) {
10
+ JSPromise::JSPromise(jsi::Runtime& runtime, jsi::Function&& resolver, jsi::Function&& rejecter) {
11
11
  auto functionCache = JSICache::getOrCreateCache(runtime);
12
12
  _resolver = functionCache.makeShared(std::move(resolver));
13
13
  _rejecter = functionCache.makeShared(std::move(rejecter));
14
14
  }
15
15
 
16
- jsi::Value Promise::createPromise(jsi::Runtime& runtime, RunPromise&& run) {
16
+ jsi::Value JSPromise::createPromise(jsi::Runtime& runtime, RunPromise&& run) {
17
17
  // Get Promise ctor from global
18
18
  auto promiseCtor = runtime.global().getPropertyAsFunction(runtime, "Promise");
19
19
 
@@ -24,7 +24,7 @@ jsi::Value Promise::createPromise(jsi::Runtime& runtime, RunPromise&& run) {
24
24
  auto resolver = arguments[0].getObject(runtime).getFunction(runtime);
25
25
  auto rejecter = arguments[1].getObject(runtime).getFunction(runtime);
26
26
  // Create `Promise` type that wraps the JSI callbacks
27
- auto promise = std::make_shared<Promise>(runtime, std::move(resolver), std::move(rejecter));
27
+ auto promise = std::make_shared<JSPromise>(runtime, std::move(resolver), std::move(rejecter));
28
28
  // Call `run` callback
29
29
  run(runtime, promise);
30
30
 
@@ -34,7 +34,7 @@ jsi::Value Promise::createPromise(jsi::Runtime& runtime, RunPromise&& run) {
34
34
  return promiseCtor.callAsConstructor(runtime, promiseCallback);
35
35
  }
36
36
 
37
- void Promise::resolve(jsi::Runtime& runtime, jsi::Value&& result) {
37
+ void JSPromise::resolve(jsi::Runtime& runtime, jsi::Value&& result) {
38
38
  OwningLock<jsi::Function> lock = _resolver.lock();
39
39
 
40
40
  if (!_resolver) {
@@ -44,7 +44,7 @@ void Promise::resolve(jsi::Runtime& runtime, jsi::Value&& result) {
44
44
  _resolver->call(runtime, std::move(result));
45
45
  }
46
46
 
47
- void Promise::reject(jsi::Runtime& runtime, std::string message) {
47
+ void JSPromise::reject(jsi::Runtime& runtime, std::string message) {
48
48
  OwningLock<jsi::Function> lock = _rejecter.lock();
49
49
 
50
50
  if (!_rejecter) {
@@ -1,5 +1,5 @@
1
1
  //
2
- // Promise.hpp
2
+ // JSPromise.hpp
3
3
  // react-native-filament
4
4
  //
5
5
  // Created by Marc Rousavy on 11.03.24.
@@ -17,14 +17,14 @@ namespace margelo::nitro {
17
17
  using namespace facebook;
18
18
 
19
19
  /**
20
- Represents a JS Promise.
21
-
22
- `Promise` is not thread-safe: It has to be resolved/rejected
23
- on the same thread and Runtime as it was created on.
20
+ * Represents a JS Promise.
21
+ *
22
+ * `JSPromise` is not thread-safe: It has to be resolved/rejected
23
+ * on the same thread and Runtime as it was created on.
24
24
  */
25
- class Promise final {
25
+ class JSPromise final {
26
26
  public:
27
- Promise(jsi::Runtime& runtime, jsi::Function&& resolver, jsi::Function&& rejecter);
27
+ JSPromise(jsi::Runtime& runtime, jsi::Function&& resolver, jsi::Function&& rejecter);
28
28
 
29
29
  /**
30
30
  Resolve the Promise with the given `jsi::Value`.
@@ -43,10 +43,10 @@ private:
43
43
  static constexpr auto TAG = "Promise";
44
44
 
45
45
  public:
46
- using RunPromise = std::function<void(jsi::Runtime& runtime, std::shared_ptr<Promise> promise)>;
46
+ using RunPromise = std::function<void(jsi::Runtime& runtime, std::shared_ptr<JSPromise> promise)>;
47
47
  /**
48
- Create a new Promise using the JS `Promise` constructor and runs the given `run` function.
49
- The resulting Promise should be returned to JS so it can be awaited.
48
+ * Create a new Promise using the JS `Promise` constructor and runs the given `run` function.
49
+ * The resulting Promise should be returned to JS so it can be awaited.
50
50
  */
51
51
  static jsi::Value createPromise(jsi::Runtime& runtime, RunPromise&& run);
52
52
  };
@@ -15,9 +15,23 @@ std::unordered_map<std::string, HybridObjectRegistry::HybridObjectConstructorFn>
15
15
  return _constructorsMap;
16
16
  }
17
17
 
18
- void HybridObjectRegistry::registerHybridObjectConstructor(std::string hybridObjectName, HybridObjectConstructorFn&& constructorFn) {
18
+ bool HybridObjectRegistry::hasHybridObject(const std::string& name) {
19
+ return getRegistry().contains(name);
20
+ }
21
+
22
+ std::vector<std::string> HybridObjectRegistry::getAllHybridObjectNames() {
23
+ std::vector<std::string> keys;
24
+ keys.reserve(getRegistry().size());
25
+ for (const auto& entry : getRegistry()) {
26
+ keys.push_back(entry.first);
27
+ }
28
+ return keys;
29
+ }
30
+
31
+ void HybridObjectRegistry::registerHybridObjectConstructor(const std::string& hybridObjectName, HybridObjectConstructorFn&& constructorFn) {
19
32
  Logger::log(TAG, "Registering HybridObject \"%s\"...", hybridObjectName);
20
33
  auto& map = HybridObjectRegistry::getRegistry();
34
+ #if DEBUG
21
35
  if (map.contains(hybridObjectName)) [[unlikely]] {
22
36
  auto message =
23
37
  "HybridObject \"" + std::string(hybridObjectName) +
@@ -27,11 +41,12 @@ void HybridObjectRegistry::registerHybridObjectConstructor(std::string hybridObj
27
41
  "- If you just registered your own HybridObject, maybe you accidentally called `registerHybridObjectConstructor(...)` twice?";
28
42
  throw std::runtime_error(message);
29
43
  }
44
+ #endif
30
45
  map.insert({hybridObjectName, std::move(constructorFn)});
31
46
  Logger::log(TAG, "Successfully registered HybridObject \"%s\"!", hybridObjectName);
32
47
  }
33
48
 
34
- std::shared_ptr<HybridObject> HybridObjectRegistry::createHybridObject(std::string hybridObjectName) {
49
+ std::shared_ptr<HybridObject> HybridObjectRegistry::createHybridObject(const std::string& hybridObjectName) {
35
50
  auto& map = HybridObjectRegistry::getRegistry();
36
51
  auto fn = map.find(hybridObjectName);
37
52
  if (fn == map.end()) [[unlikely]] {
@@ -43,6 +58,11 @@ std::shared_ptr<HybridObject> HybridObjectRegistry::createHybridObject(std::stri
43
58
  std::shared_ptr<HybridObject> instance = fn->second();
44
59
 
45
60
  #if DEBUG
61
+ if (instance == nullptr) [[unlikely]] {
62
+ throw std::runtime_error("Failed to create HybridObject \"" + hybridObjectName +
63
+ "\" - "
64
+ "The constructor returned a nullptr!");
65
+ }
46
66
  if (instance->getName() != hybridObjectName) [[unlikely]] {
47
67
  throw std::runtime_error("HybridObject's name (\"" + instance->getName() +
48
68
  "\") does not match"
@@ -15,7 +15,7 @@ namespace margelo::nitro {
15
15
 
16
16
  /**
17
17
  * A registry that holds initializers for HybridObjects.
18
- * This will be used to initialize them from JS using `NitroModules.get<T>(name)`.
18
+ * This will be used to initialize them from JS using `NitroModules.createHybridObject<T>(name)`.
19
19
  */
20
20
  class HybridObjectRegistry {
21
21
  public:
@@ -28,11 +28,13 @@ public:
28
28
  /**
29
29
  * Registers the given HybridObject in the `HybridObjectRegistry`.
30
30
  * It will be uniquely identified via it's `hybridObjectName`, and can be initialized from
31
- * JS using `NitroModules.get<T>(name)` - which will call the `constructorFn` here.
31
+ * JS using `NitroModules.createHybridObject<T>(name)` - which will call the `constructorFn` here.
32
32
  */
33
- static void registerHybridObjectConstructor(std::string hybridObjectName, HybridObjectConstructorFn&& constructorFn);
33
+ static void registerHybridObjectConstructor(const std::string& hybridObjectName, HybridObjectConstructorFn&& constructorFn);
34
34
 
35
- static std::shared_ptr<HybridObject> createHybridObject(std::string hybridObjectName);
35
+ static std::shared_ptr<HybridObject> createHybridObject(const std::string& hybridObjectName);
36
+ static bool hasHybridObject(const std::string& hybridObjectName);
37
+ static std::vector<std::string> getAllHybridObjectNames();
36
38
 
37
39
  private:
38
40
  static std::unordered_map<std::string, HybridObjectConstructorFn>& getRegistry();
@@ -32,12 +32,14 @@ jsi::Value NativeNitroModules::get(jsi::Runtime& runtime, const jsi::PropNameID&
32
32
  }
33
33
  if (name == "createHybridObject") {
34
34
  return jsi::Function::createFromHostFunction(
35
- runtime, jsi::PropNameID::forUtf8(runtime, "install"), 2,
35
+ runtime, jsi::PropNameID::forUtf8(runtime, "createHybridObject"), 2,
36
36
  [=](jsi::Runtime& runtime, const jsi::Value& thisArg, const jsi::Value* args, size_t count) -> jsi::Value {
37
- if (count != 1 && count != 2) {
37
+ #if DEBUG
38
+ if (count != 1 && count != 2) [[unlikely]] {
38
39
  throw jsi::JSError(runtime, "NitroModules.createHybridObject(..) expects 1 or 2 arguments, but " + std::to_string(count) +
39
40
  " were supplied!");
40
41
  }
42
+ #endif
41
43
  jsi::String objectName = args[0].asString(runtime);
42
44
  std::optional<jsi::Object> optionalArgs = std::nullopt;
43
45
  if (count > 1) {
@@ -47,6 +49,25 @@ jsi::Value NativeNitroModules::get(jsi::Runtime& runtime, const jsi::PropNameID&
47
49
  return createHybridObject(runtime, objectName, optionalArgs);
48
50
  });
49
51
  }
52
+ if (name == "hasHybridObject") {
53
+ return jsi::Function::createFromHostFunction(
54
+ runtime, jsi::PropNameID::forUtf8(runtime, "hasHybridObject"), 1,
55
+ [=](jsi::Runtime& runtime, const jsi::Value& thisArg, const jsi::Value* args, size_t count) -> jsi::Value {
56
+ #if DEBUG
57
+ if (count != 1) [[unlikely]] {
58
+ throw jsi::JSError(runtime,
59
+ "NitroModules.hasHybridObject(..) expects 1 argument (name), but received " + std::to_string(count) + "!");
60
+ }
61
+ #endif
62
+ jsi::String objectName = args[0].asString(runtime);
63
+ return hasHybridObject(runtime, objectName);
64
+ });
65
+ }
66
+ if (name == "getAllHybridObjectNames") {
67
+ return jsi::Function::createFromHostFunction(runtime, jsi::PropNameID::forUtf8(runtime, "getAllHybridObjectNames"), 0,
68
+ [=](jsi::Runtime& runtime, const jsi::Value& thisArg, const jsi::Value* args,
69
+ size_t count) -> jsi::Value { return getAllHybridObjectNames(runtime); });
70
+ }
50
71
 
51
72
  return jsi::Value::undefined();
52
73
  }
@@ -66,4 +87,19 @@ jsi::Value NativeNitroModules::createHybridObject(jsi::Runtime& runtime, const j
66
87
  return hybridObject->toObject(runtime);
67
88
  }
68
89
 
90
+ jsi::Value NativeNitroModules::hasHybridObject(jsi::Runtime& runtime, const jsi::String& hybridObjectName) {
91
+ std::string name = hybridObjectName.utf8(runtime);
92
+ bool exists = HybridObjectRegistry::hasHybridObject(name);
93
+ return exists;
94
+ }
95
+
96
+ jsi::Value NativeNitroModules::getAllHybridObjectNames(jsi::Runtime& runtime) {
97
+ std::vector<std::string> keys = HybridObjectRegistry::getAllHybridObjectNames();
98
+ jsi::Array array(runtime, keys.size());
99
+ for (size_t i = 0; i < keys.size(); i++) {
100
+ array.setValueAtIndex(runtime, i, jsi::String::createFromUtf8(runtime, keys[i]));
101
+ }
102
+ return array;
103
+ }
104
+
69
105
  } // namespace facebook::react
@@ -24,6 +24,8 @@ public:
24
24
 
25
25
  void install(jsi::Runtime& runtime);
26
26
  jsi::Value createHybridObject(jsi::Runtime& runtime, const jsi::String& hybridObjectName, const std::optional<jsi::Object>& args);
27
+ jsi::Value hasHybridObject(jsi::Runtime& runtime, const jsi::String& hybridObjectName);
28
+ jsi::Value getAllHybridObjectNames(jsi::Runtime& runtime);
27
29
 
28
30
  public:
29
31
  constexpr static auto kModuleName = "NitroModulesCxx";
@@ -18,8 +18,14 @@
18
18
  #if _CXX_INTEROP_HAS_ATTRIBUTE(swift_attr)
19
19
  // Rename Type for Swift
20
20
  #define SWIFT_NAME(_name) __attribute__((swift_name(#_name)))
21
+ // Make Swift type private
22
+ #define SWIFT_PRIVATE __attribute__((swift_private))
23
+ // Make getter + setter a computed property
24
+ #define SWIFT_COMPUTED_PROPERTY __attribute__((swift_attr("import_computed_property")))
21
25
  #else
22
26
  #define SWIFT_NAME(_name)
27
+ #define SWIFT_PRIVATE
28
+ #define SWIFT_COMPUTED_PROPERTY
23
29
  #endif
24
30
 
25
31
  #if _CXX_INTEROP_HAS_ATTRIBUTE(enum_extensibility)
@@ -0,0 +1,10 @@
1
+ //
2
+ // Promise.cpp
3
+ // NitroModules
4
+ //
5
+ // Created by Marc Rousavy on 11.08.24.
6
+ //
7
+
8
+ #include "Promise.hpp"
9
+
10
+ namespace margelo::nitro {} // namespace margelo::nitro
@@ -0,0 +1,43 @@
1
+ //
2
+ // Promise.hpp
3
+ // NitroModules
4
+ //
5
+ // Created by Marc Rousavy on 11.08.24.
6
+ //
7
+
8
+ #pragma once
9
+
10
+ #include <future>
11
+ #include <memory>
12
+ #include <string>
13
+
14
+ namespace margelo::nitro {
15
+
16
+ class Promise {
17
+ public:
18
+ Promise(const Promise&) = delete;
19
+ Promise(Promise&&) = delete;
20
+
21
+ public:
22
+ void reject(const std::string& message) {
23
+ // TODO: reject()
24
+ }
25
+
26
+ void resolve(int result) {
27
+ // TODO: resolve()
28
+ }
29
+
30
+ private:
31
+ explicit Promise() {
32
+ // TODO: Init? From Future?
33
+ }
34
+
35
+ public:
36
+ static std::shared_ptr<Promise> run(void (*run)(std::shared_ptr<Promise> promise)) {
37
+ auto promise = std::shared_ptr<Promise>(new Promise());
38
+ run(promise);
39
+ return promise;
40
+ }
41
+ };
42
+
43
+ } // namespace margelo::nitro
@@ -7,6 +7,7 @@
7
7
 
8
8
  #include "ThreadUtils.hpp"
9
9
  #include <pthread.h>
10
+ #include <sstream>>
10
11
  #include <thread>
11
12
 
12
13
  namespace margelo::nitro {
@@ -1,19 +1,25 @@
1
1
  /**
2
2
  * Describes the languages this component will be implemented in.
3
+ *
4
+ * By default, everything has a C++ base, and can optionally be bridged down
5
+ * to platform-specific languages like Swift or Kotlin
3
6
  */
4
7
  export interface PlatformSpec {
5
8
  ios?: 'swift' | 'c++';
6
9
  android?: 'kotlin' | 'c++';
7
10
  }
8
11
  /**
9
- * Represents a Nitro `HybridObject` which is implemented natively in either C++,
10
- * or Swift/Kotlin.
12
+ * Represents a Nitro `HybridObject` which is implemented in a native language like
13
+ * C++, Swift or Kotlin.
14
+ * Every Nitro `HybridObject` has a C++ base, and can optionally be bridged down to Swift or Kotlin.
11
15
  *
12
16
  * `HybridObject`s use the Nitro Tunnel for efficient, low-overhead JS <-> Native communication.
13
17
  *
14
18
  * All `HybridObject`s are implemented using `NativeState`, and inherit their properties
15
19
  * and methods from their prototype, so the actual JS object is empty.
16
20
  *
21
+ * @type Platforms: The type of platforms this HybridObject will be implemented in. By default, it is
22
+ * a C++ `HybridObject`.
17
23
  * @example
18
24
  * ```ts
19
25
  * interface Photo extends HybridObject<{ ios: 'swift', android: 'kotlin' }> {
@@ -24,7 +30,7 @@ export interface PlatformSpec {
24
30
  * }
25
31
  * ```
26
32
  */
27
- export interface HybridObject<Spec extends PlatformSpec> {
33
+ export interface HybridObject<Platforms extends PlatformSpec = {}> {
28
34
  /**
29
35
  * Holds a type-name describing the native `HybridObject` instance.
30
36
  *
@@ -33,8 +39,8 @@ export interface HybridObject<Spec extends PlatformSpec> {
33
39
  *
34
40
  * Nitro prototypes also have a `__type`.
35
41
  *
36
- * For actual HybridObject instances, this is `NativeState<...>`, for
37
- * prototypes this is `Prototype<...>`.
42
+ * - For actual HybridObject instances, this is `NativeState<...>`
43
+ * - For prototypes this is `Prototype<...>`.
38
44
  *
39
45
  * @internal
40
46
  * @private
@@ -48,7 +54,7 @@ export interface HybridObject<Spec extends PlatformSpec> {
48
54
  /**
49
55
  * Returns a string representation of the given `HybridObject`.
50
56
  *
51
- * Unless overridden by the `HybridObject`, this will return a list of all properties.
57
+ * Unless overridden by the `HybridObject`, this will return the name of the object.
52
58
  *
53
59
  * @example
54
60
  * ```ts
@@ -72,5 +78,5 @@ export interface HybridObject<Spec extends PlatformSpec> {
72
78
  * console.log(hybridA.equals(hybridB)) // true
73
79
  * ```
74
80
  */
75
- equals(other: HybridObject<Spec>): boolean;
81
+ equals(other: HybridObject<Platforms>): boolean;
76
82
  }
@@ -3,6 +3,8 @@ import type { UnsafeObject } from 'react-native/Libraries/Types/CodegenTypes';
3
3
  export interface Spec extends TurboModule {
4
4
  install(): void;
5
5
  createHybridObject(name: string, args?: UnsafeObject): UnsafeObject;
6
+ hasHybridObject(name: string): boolean;
7
+ getAllHybridObjectNames(): string[];
6
8
  }
7
9
  export declare function getNativeNitroModules(): Spec;
8
10
  declare global {
@@ -13,5 +13,13 @@ export declare const NitroModules: {
13
13
  * @returns An instance of {@linkcode T}
14
14
  * @throws an Error if {@linkcode T} has not been registered under the name {@linkcode name}.
15
15
  */
16
- get<T extends HybridObject<any>>(name: string): T;
16
+ createHybridObject<T extends HybridObject<any>>(name: string): T;
17
+ /**
18
+ * Get a list of all registered Hybrid Objects.
19
+ */
20
+ getAllHybridObjectNames(): string[];
21
+ /**
22
+ * Returns whether a HybridObject under the given {@linkcode name} is registered, or not.
23
+ */
24
+ hasHybridObject(name: string): boolean;
17
25
  };
@@ -13,9 +13,23 @@ export const NitroModules = {
13
13
  * @returns An instance of {@linkcode T}
14
14
  * @throws an Error if {@linkcode T} has not been registered under the name {@linkcode name}.
15
15
  */
16
- get(name) {
16
+ createHybridObject(name) {
17
17
  const nitro = getNativeNitroModules();
18
18
  const instance = nitro.createHybridObject(name);
19
19
  return instance;
20
20
  },
21
+ /**
22
+ * Get a list of all registered Hybrid Objects.
23
+ */
24
+ getAllHybridObjectNames() {
25
+ const nitro = getNativeNitroModules();
26
+ return nitro.getAllHybridObjectNames();
27
+ },
28
+ /**
29
+ * Returns whether a HybridObject under the given {@linkcode name} is registered, or not.
30
+ */
31
+ hasHybridObject(name) {
32
+ const nitro = getNativeNitroModules();
33
+ return nitro.hasHybridObject(name);
34
+ },
21
35
  };