react-native-nitro-modules 0.5.0 → 0.7.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.
- package/NitroModules.podspec +3 -1
- package/README.md +33 -14
- package/android/gradle.properties +5 -5
- package/android/src/main/cpp/JNIOnLoad.cpp +8 -0
- package/android/src/main/cpp/core/ByteBufferArrayBuffer.hpp +47 -0
- package/android/src/main/cpp/core/JAnyMap.hpp +193 -0
- package/android/src/main/cpp/core/JAnyValue.hpp +191 -0
- package/android/src/main/cpp/core/JArrayBuffer.hpp +124 -0
- package/android/src/main/cpp/core/JHybridObject.hpp +11 -4
- package/android/src/main/cpp/core/JPromise.hpp +88 -0
- package/android/src/main/cpp/platform/NitroLogger.cpp +36 -0
- package/android/src/main/cpp/registry/JHybridObjectInitializer.hpp +1 -1
- package/android/src/main/cpp/registry/JHybridObjectRegistry.cpp +1 -1
- package/android/src/main/cpp/registry/JHybridObjectRegistry.hpp +1 -1
- package/android/src/main/cpp/utils/{JNISharedPtr.h → JNISharedPtr.hpp} +13 -1
- package/android/src/main/java/com/margelo/nitro/JNIOnLoad.java +27 -0
- package/android/src/main/java/com/margelo/nitro/NitroModulesPackage.java +1 -9
- package/android/src/main/java/com/margelo/nitro/core/AnyMap.kt +80 -0
- package/android/src/main/java/com/margelo/nitro/core/AnyValue.kt +164 -0
- package/android/src/main/java/com/margelo/nitro/core/ArrayBuffer.kt +115 -0
- package/android/src/main/java/com/margelo/nitro/{HybridObject.kt → core/HybridObject.kt} +12 -15
- package/android/src/main/java/com/margelo/nitro/{HybridObjectInitializer.java → core/HybridObjectInitializer.java} +1 -1
- package/android/src/main/java/com/margelo/nitro/{HybridObjectRegistry.java → core/HybridObjectRegistry.java} +6 -4
- package/android/src/main/java/com/margelo/nitro/core/Promise.kt +115 -0
- package/cpp/core/AnyMap.hpp +2 -2
- package/cpp/core/ArrayBuffer.cpp +5 -5
- package/cpp/core/ArrayBuffer.hpp +7 -9
- package/cpp/core/HybridFunction.hpp +120 -46
- package/cpp/core/HybridObject.cpp +17 -6
- package/cpp/core/HybridObject.hpp +32 -8
- package/cpp/jsi/JSICache.cpp +5 -5
- package/cpp/jsi/JSICache.hpp +1 -3
- package/cpp/jsi/JSIConverter+AnyMap.hpp +2 -2
- package/cpp/jsi/JSIConverter+ArrayBuffer.hpp +2 -2
- package/cpp/jsi/JSIConverter+Function.hpp +7 -6
- package/cpp/jsi/JSIConverter+HybridObject.hpp +6 -5
- package/cpp/jsi/JSIConverter+Optional.hpp +1 -1
- package/cpp/jsi/JSIConverter+Promise.hpp +5 -4
- package/cpp/jsi/JSIConverter+Tuple.hpp +1 -1
- package/cpp/jsi/JSIConverter+UnorderedMap.hpp +1 -1
- package/cpp/jsi/JSIConverter+Variant.hpp +1 -3
- package/cpp/jsi/JSIConverter+Vector.hpp +1 -1
- package/cpp/jsi/JSIConverter.hpp +11 -11
- package/cpp/jsi/JSPromise.cpp +2 -2
- package/cpp/platform/NitroLogger.hpp +67 -0
- package/cpp/prototype/HybridObjectPrototype.cpp +2 -2
- package/cpp/prototype/Prototype.hpp +43 -22
- package/cpp/registry/HybridObjectRegistry.cpp +4 -4
- package/cpp/threading/Dispatcher.cpp +4 -3
- package/cpp/threading/ThreadPool.cpp +2 -2
- package/cpp/turbomodule/NativeNitroModules.cpp +26 -8
- package/cpp/turbomodule/NativeNitroModules.h +1 -0
- package/cpp/turbomodule/NativeNitroModules.hpp +2 -0
- package/cpp/utils/TypeInfo.hpp +14 -0
- package/ios/core/AnyMapHolder.hpp +91 -0
- package/ios/core/AnyMapHolder.swift +316 -0
- package/ios/core/ArrayBufferHolder.hpp +7 -5
- package/ios/core/ArrayBufferHolder.swift +22 -7
- package/ios/core/HybridContext.hpp +3 -3
- package/ios/core/Promise.swift +20 -0
- package/ios/core/PromiseHolder.hpp +15 -11
- package/ios/platform/NitroLogger.mm +36 -0
- package/ios/platform/ThreadUtils.cpp +1 -1
- package/ios/turbomodule/NitroModuleOnLoad.mm +2 -1
- package/ios/utils/SwiftClosure.hpp +63 -0
- package/ios/utils/SwiftClosure.swift +58 -0
- package/lib/AnyMap.d.ts +3 -0
- package/lib/HybridObject.d.ts +15 -0
- package/lib/NativeNitroModules.d.ts +2 -0
- package/lib/NitroModules.d.ts +18 -0
- package/lib/NitroModules.js +24 -0
- package/lib/commonjs/NativeNitroModules.js.map +1 -1
- package/lib/commonjs/NitroModules.js +24 -0
- package/lib/commonjs/NitroModules.js.map +1 -1
- package/lib/commonjs/package.json +1 -0
- package/lib/module/AnyMap.js +1 -1
- package/lib/module/HybridObject.js +1 -1
- package/lib/module/ModuleNotFoundError.js +2 -0
- package/lib/module/ModuleNotFoundError.js.map +1 -1
- package/lib/module/NativeNitroModules.js +2 -0
- package/lib/module/NativeNitroModules.js.map +1 -1
- package/lib/module/NativeNitroModules.web.js +2 -0
- package/lib/module/NativeNitroModules.web.js.map +1 -1
- package/lib/module/NitroModules.js +26 -0
- package/lib/module/NitroModules.js.map +1 -1
- package/lib/module/index.js +2 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/package.json +1 -0
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +13 -12
- package/src/AnyMap.ts +3 -0
- package/src/HybridObject.ts +15 -0
- package/src/NativeNitroModules.ts +5 -0
- package/src/NitroModules.ts +24 -0
- package/android/src/main/cpp/core/JHybridObject.cpp +0 -8
- package/cpp/templates/IsInPack.hpp +0 -21
- package/cpp/utils/NitroLogger.hpp +0 -58
- package/ios/utils/ClosureWrapper.swift +0 -45
|
@@ -49,8 +49,8 @@ HybridObject::HybridObject(const char* name) : HybridObjectPrototype(), _name(na
|
|
|
49
49
|
_instanceId = getId(name);
|
|
50
50
|
uint32_t alive = incrementAliveInstancesAndGet(_name);
|
|
51
51
|
uint32_t totalObjects = getTotalAliveInstances();
|
|
52
|
-
Logger::log(TAG, "(MEMORY) ✅ Creating %s (#%i)... (Total %s(s): %i | Total HybridObjects: %i)", _name, _instanceId,
|
|
53
|
-
totalObjects);
|
|
52
|
+
Logger::log(LogLevel::Info, TAG, "(MEMORY) ✅ Creating %s (#%i)... (Total %s(s): %i | Total HybridObjects: %i)", _name, _instanceId,
|
|
53
|
+
_name, alive, totalObjects);
|
|
54
54
|
#endif
|
|
55
55
|
}
|
|
56
56
|
|
|
@@ -58,8 +58,8 @@ HybridObject::~HybridObject() {
|
|
|
58
58
|
#if LOG_MEMORY_ALLOCATIONS
|
|
59
59
|
uint32_t alive = decrementAliveInstancesAndGet(_name);
|
|
60
60
|
uint32_t totalObjects = getTotalAliveInstances();
|
|
61
|
-
Logger::log(TAG, "(MEMORY) ❌ Deleting %s (#%i)... (Total %s(s): %i | Total HybridObjects: %i) ", _name, _instanceId,
|
|
62
|
-
totalObjects);
|
|
61
|
+
Logger::log(LogLevel::Info, TAG, "(MEMORY) ❌ Deleting %s (#%i)... (Total %s(s): %i | Total HybridObjects: %i) ", _name, _instanceId,
|
|
62
|
+
_name, alive, totalObjects);
|
|
63
63
|
#endif
|
|
64
64
|
}
|
|
65
65
|
|
|
@@ -75,11 +75,22 @@ bool HybridObject::equals(std::shared_ptr<HybridObject> other) {
|
|
|
75
75
|
return this == other.get();
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
+
jsi::Value HybridObject::disposeRaw(jsi::Runtime& runtime, const jsi::Value& thisArg, const jsi::Value* args, size_t count) {
|
|
79
|
+
// 1. Dispose any resources - this might be overridden by child classes to perform manual cleanup.
|
|
80
|
+
dispose();
|
|
81
|
+
// 2. Remove the NativeState from `this`
|
|
82
|
+
jsi::Object thisObject = thisArg.asObject(runtime);
|
|
83
|
+
thisObject.setNativeState(runtime, nullptr);
|
|
84
|
+
|
|
85
|
+
return jsi::Value::undefined();
|
|
86
|
+
}
|
|
87
|
+
|
|
78
88
|
void HybridObject::loadHybridMethods() {
|
|
79
89
|
registerHybrids(this, [](Prototype& prototype) {
|
|
80
90
|
prototype.registerHybridGetter("name", &HybridObject::getName);
|
|
81
|
-
prototype.registerHybridMethod("toString", &HybridObject::toString);
|
|
82
91
|
prototype.registerHybridMethod("equals", &HybridObject::equals);
|
|
92
|
+
prototype.registerHybridMethod("toString", &HybridObject::toString);
|
|
93
|
+
prototype.registerRawHybridMethod("dispose", 0, &HybridObject::disposeRaw);
|
|
83
94
|
});
|
|
84
95
|
}
|
|
85
96
|
|
|
@@ -112,7 +123,7 @@ jsi::Value HybridObject::toObject(jsi::Runtime& runtime) {
|
|
|
112
123
|
// 6. Set memory size so Hermes GC knows about actual memory
|
|
113
124
|
object.setExternalMemoryPressure(runtime, getExternalMemorySize());
|
|
114
125
|
|
|
115
|
-
#
|
|
126
|
+
#ifndef NDEBUG
|
|
116
127
|
// 7. Assign a private __type property for debugging - this will be used so users know it's not just an empty object.
|
|
117
128
|
object.setProperty(runtime, "__type", jsi::String::createFromUtf8(runtime, "NativeState<" + std::string(_name) + ">"));
|
|
118
129
|
#endif
|
|
@@ -23,7 +23,7 @@ using namespace facebook;
|
|
|
23
23
|
*
|
|
24
24
|
* The new class can then be passed to JS using the `JSIConverter<HybridObject>`.
|
|
25
25
|
*/
|
|
26
|
-
class HybridObject : public jsi::NativeState, public HybridObjectPrototype, public std::enable_shared_from_this<HybridObject> {
|
|
26
|
+
class HybridObject : public virtual jsi::NativeState, public HybridObjectPrototype, public std::enable_shared_from_this<HybridObject> {
|
|
27
27
|
public:
|
|
28
28
|
/**
|
|
29
29
|
* Create a new instance of a `HybridObject`.
|
|
@@ -38,11 +38,17 @@ public:
|
|
|
38
38
|
/**
|
|
39
39
|
* HybridObjects cannot be copied.
|
|
40
40
|
*/
|
|
41
|
-
HybridObject(const HybridObject& copy) =
|
|
41
|
+
HybridObject(const HybridObject& copy) = default;
|
|
42
42
|
/**
|
|
43
43
|
* HybridObjects cannot be moved.
|
|
44
44
|
*/
|
|
45
|
-
HybridObject(HybridObject&& move) =
|
|
45
|
+
HybridObject(HybridObject&& move) = default;
|
|
46
|
+
/**
|
|
47
|
+
* HybridObjects cannot be default-constructed!
|
|
48
|
+
*/
|
|
49
|
+
HybridObject() {
|
|
50
|
+
throw std::runtime_error("Cannot default-construct HybridObject!");
|
|
51
|
+
}
|
|
46
52
|
|
|
47
53
|
public:
|
|
48
54
|
/**
|
|
@@ -60,7 +66,7 @@ public:
|
|
|
60
66
|
*/
|
|
61
67
|
template <typename Derived>
|
|
62
68
|
std::shared_ptr<Derived> shared() {
|
|
63
|
-
return std::
|
|
69
|
+
return std::dynamic_pointer_cast<Derived>(shared_from_this());
|
|
64
70
|
}
|
|
65
71
|
|
|
66
72
|
public:
|
|
@@ -68,10 +74,6 @@ public:
|
|
|
68
74
|
* Get the HybridObject's name
|
|
69
75
|
*/
|
|
70
76
|
std::string getName();
|
|
71
|
-
/**
|
|
72
|
-
* Get a string representation of this HostObject, useful for logging or debugging.
|
|
73
|
-
*/
|
|
74
|
-
virtual std::string toString();
|
|
75
77
|
/**
|
|
76
78
|
* Compare this HybridObject for reference equality to the other HybridObject.
|
|
77
79
|
*
|
|
@@ -79,6 +81,28 @@ public:
|
|
|
79
81
|
* they might still be the same `HybridObject` - in this case `equals(other)` will return true.
|
|
80
82
|
*/
|
|
81
83
|
bool equals(std::shared_ptr<HybridObject> other);
|
|
84
|
+
/**
|
|
85
|
+
* Get a string representation of this `HybridObject` - useful for logging or debugging.
|
|
86
|
+
*/
|
|
87
|
+
virtual std::string toString();
|
|
88
|
+
/**
|
|
89
|
+
* Eagerly- (and manually-) dispose all native resources this `HybridObject` holds.
|
|
90
|
+
* This method can only be manually called from JS using `dispose()`.
|
|
91
|
+
*
|
|
92
|
+
* If this method is never manually called, a `HybridObject` is expected to disposes it's
|
|
93
|
+
* resources as usual via the object's destructor (`~HybridObject()`, `deinit` or `finalize()`).
|
|
94
|
+
*
|
|
95
|
+
* By default, this method does nothing. It can be overridden to perform actual disposing/cleanup
|
|
96
|
+
* if required.
|
|
97
|
+
*/
|
|
98
|
+
virtual void dispose() {}
|
|
99
|
+
|
|
100
|
+
private:
|
|
101
|
+
/**
|
|
102
|
+
* The actual `dispose()` function from JS.
|
|
103
|
+
* This needs to be a raw JSI function as we remove the NativeState here.
|
|
104
|
+
*/
|
|
105
|
+
jsi::Value disposeRaw(jsi::Runtime& runtime, const jsi::Value& thisArg, const jsi::Value* args, size_t count);
|
|
82
106
|
|
|
83
107
|
protected:
|
|
84
108
|
/**
|
package/cpp/jsi/JSICache.cpp
CHANGED
|
@@ -24,7 +24,7 @@ inline void destroyReferences(const std::vector<BorrowingReference<T>>& referenc
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
JSICache::~JSICache() {
|
|
27
|
-
Logger::log(TAG, "Destroying JSICache...");
|
|
27
|
+
Logger::log(LogLevel::Info, TAG, "Destroying JSICache...");
|
|
28
28
|
std::unique_lock lock(_mutex);
|
|
29
29
|
|
|
30
30
|
destroyReferences(_objectCache);
|
|
@@ -43,19 +43,19 @@ JSICacheReference JSICache::getOrCreateCache(jsi::Runtime& runtime) {
|
|
|
43
43
|
// It's still alive! Return it
|
|
44
44
|
return JSICacheReference(strong);
|
|
45
45
|
}
|
|
46
|
-
Logger::log(TAG, "JSICache was created, but it is no longer strong!");
|
|
46
|
+
Logger::log(LogLevel::Warning, TAG, "JSICache was created, but it is no longer strong!");
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
#
|
|
49
|
+
#ifndef NDEBUG
|
|
50
50
|
if (runtime.global().hasProperty(runtime, CACHE_PROP_NAME)) [[unlikely]] {
|
|
51
51
|
throw std::runtime_error("The Runtime \"" + getRuntimeId(runtime) + "\" already has a global cache! (\"" + CACHE_PROP_NAME + "\")");
|
|
52
52
|
}
|
|
53
53
|
#endif
|
|
54
54
|
|
|
55
55
|
// Cache doesn't exist yet.
|
|
56
|
-
Logger::log(TAG, "Creating new JSICache<T> for runtime %s..", getRuntimeId(runtime));
|
|
56
|
+
Logger::log(LogLevel::Info, TAG, "Creating new JSICache<T> for runtime %s..", getRuntimeId(runtime).c_str());
|
|
57
57
|
// Create new cache
|
|
58
|
-
auto nativeState = std::shared_ptr<JSICache>(new JSICache(
|
|
58
|
+
auto nativeState = std::shared_ptr<JSICache>(new JSICache());
|
|
59
59
|
// Wrap it in a jsi::Value using NativeState
|
|
60
60
|
jsi::Object cache(runtime);
|
|
61
61
|
cache.setNativeState(runtime, nativeState);
|
package/cpp/jsi/JSICache.hpp
CHANGED
|
@@ -38,12 +38,11 @@ public:
|
|
|
38
38
|
~JSICache();
|
|
39
39
|
|
|
40
40
|
public:
|
|
41
|
-
JSICache() = delete;
|
|
42
41
|
JSICache(const JSICache&) = delete;
|
|
43
42
|
JSICache(JSICache&&) = delete;
|
|
44
43
|
|
|
45
44
|
private:
|
|
46
|
-
|
|
45
|
+
JSICache() = default;
|
|
47
46
|
|
|
48
47
|
public:
|
|
49
48
|
/**
|
|
@@ -59,7 +58,6 @@ private:
|
|
|
59
58
|
friend class JSICacheReference;
|
|
60
59
|
|
|
61
60
|
private:
|
|
62
|
-
jsi::Runtime* _runtime;
|
|
63
61
|
std::mutex _mutex;
|
|
64
62
|
std::vector<BorrowingReference<jsi::Object>> _objectCache;
|
|
65
63
|
std::vector<BorrowingReference<jsi::Function>> _functionCache;
|
|
@@ -27,7 +27,7 @@ using namespace facebook;
|
|
|
27
27
|
|
|
28
28
|
// AnyValue <> Record<K, V>
|
|
29
29
|
template <>
|
|
30
|
-
struct JSIConverter<AnyValue> {
|
|
30
|
+
struct JSIConverter<AnyValue> final {
|
|
31
31
|
static inline AnyValue fromJSI(jsi::Runtime& runtime, const jsi::Value& arg) {
|
|
32
32
|
return JSIConverter<AnyValue::variant>::fromJSI(runtime, arg);
|
|
33
33
|
}
|
|
@@ -41,7 +41,7 @@ struct JSIConverter<AnyValue> {
|
|
|
41
41
|
|
|
42
42
|
// AnyMap <> Record<K, V>
|
|
43
43
|
template <>
|
|
44
|
-
struct JSIConverter<std::shared_ptr<AnyMap>> {
|
|
44
|
+
struct JSIConverter<std::shared_ptr<AnyMap>> final {
|
|
45
45
|
static inline std::shared_ptr<AnyMap> fromJSI(jsi::Runtime& runtime, const jsi::Value& arg) {
|
|
46
46
|
jsi::Object object = arg.asObject(runtime);
|
|
47
47
|
jsi::Array propNames = object.getPropertyNames(runtime);
|
|
@@ -28,11 +28,11 @@ using namespace facebook;
|
|
|
28
28
|
|
|
29
29
|
// MutableBuffer <> ArrayBuffer
|
|
30
30
|
template <typename T>
|
|
31
|
-
struct JSIConverter<T, std::enable_if_t<is_shared_ptr_to_v<T, jsi::MutableBuffer>>> {
|
|
31
|
+
struct JSIConverter<T, std::enable_if_t<is_shared_ptr_to_v<T, jsi::MutableBuffer>>> final {
|
|
32
32
|
static inline std::shared_ptr<ArrayBuffer> fromJSI(jsi::Runtime& runtime, const jsi::Value& arg) {
|
|
33
33
|
jsi::Object object = arg.asObject(runtime);
|
|
34
34
|
|
|
35
|
-
#
|
|
35
|
+
#ifndef NDEBUG
|
|
36
36
|
if (!object.isArrayBuffer(runtime)) [[unlikely]] {
|
|
37
37
|
throw std::runtime_error("Object \"" + arg.toString(runtime).utf8(runtime) +
|
|
38
38
|
"\" is not an ArrayBuffer! "
|
|
@@ -27,7 +27,7 @@ using namespace facebook;
|
|
|
27
27
|
|
|
28
28
|
// [](Args...) -> T {} <> (Args...) => T
|
|
29
29
|
template <typename ReturnType, typename... Args>
|
|
30
|
-
struct JSIConverter<std::function<ReturnType(Args...)>> {
|
|
30
|
+
struct JSIConverter<std::function<ReturnType(Args...)>> final {
|
|
31
31
|
// std::future<T> -> T
|
|
32
32
|
using ResultingType = future_type_v<ReturnType>;
|
|
33
33
|
|
|
@@ -47,7 +47,8 @@ struct JSIConverter<std::function<ReturnType(Args...)>> {
|
|
|
47
47
|
std::shared_ptr<Dispatcher> dispatcher = weakDispatcher.lock();
|
|
48
48
|
if (!dispatcher) {
|
|
49
49
|
if constexpr (std::is_void_v<ResultingType>) {
|
|
50
|
-
Logger::log("JSIConverter",
|
|
50
|
+
Logger::log(LogLevel::Error, "JSIConverter",
|
|
51
|
+
"Tried calling void(..) function, but the JS Dispatcher has already been deleted by JS!");
|
|
51
52
|
return;
|
|
52
53
|
} else {
|
|
53
54
|
throw std::runtime_error("Cannot call the given Function - the JS Dispatcher has already been destroyed by the JS Runtime!");
|
|
@@ -68,8 +69,8 @@ struct JSIConverter<std::function<ReturnType(Args...)>> {
|
|
|
68
69
|
}
|
|
69
70
|
|
|
70
71
|
static inline jsi::Value toJSI(jsi::Runtime& runtime, const std::function<ReturnType(Args...)>& function) {
|
|
71
|
-
jsi::HostFunctionType jsFunction = [function](jsi::Runtime& runtime, const jsi::Value& thisValue,
|
|
72
|
-
|
|
72
|
+
jsi::HostFunctionType jsFunction = [function](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* args,
|
|
73
|
+
size_t count) -> jsi::Value {
|
|
73
74
|
if (count != sizeof...(Args)) [[unlikely]] {
|
|
74
75
|
throw jsi::JSError(runtime, "Function expected " + std::to_string(sizeof...(Args)) + " arguments, but received " +
|
|
75
76
|
std::to_string(count) + "!");
|
|
@@ -95,7 +96,7 @@ private:
|
|
|
95
96
|
if (!function) {
|
|
96
97
|
if constexpr (std::is_void_v<ResultingType>) {
|
|
97
98
|
// runtime has already been deleted. since this returns void, we can just ignore it being deleted.
|
|
98
|
-
Logger::log("JSIConverter", "Tried calling void(..) function, but it has already been deleted by JS!");
|
|
99
|
+
Logger::log(LogLevel::Error, "JSIConverter", "Tried calling void(..) function, but it has already been deleted by JS!");
|
|
99
100
|
return;
|
|
100
101
|
} else {
|
|
101
102
|
// runtime has already been deleted, but we are expecting a return value - throw an error in this case.
|
|
@@ -123,7 +124,7 @@ private:
|
|
|
123
124
|
} else {
|
|
124
125
|
// it is a custom type, parse it to a JS value
|
|
125
126
|
ReturnType result = function(JSIConverter<std::decay_t<Args>>::fromJSI(runtime, args[Is])...);
|
|
126
|
-
return JSIConverter<ReturnType>::toJSI(runtime, result);
|
|
127
|
+
return JSIConverter<ReturnType>::toJSI(runtime, std::forward<ReturnType>(result));
|
|
127
128
|
}
|
|
128
129
|
}
|
|
129
130
|
};
|
|
@@ -20,11 +20,11 @@ using namespace facebook;
|
|
|
20
20
|
|
|
21
21
|
// HybridObject(NativeState) <> {}
|
|
22
22
|
template <typename T>
|
|
23
|
-
struct JSIConverter<T, std::enable_if_t<is_shared_ptr_to_v<T, jsi::NativeState>>> {
|
|
23
|
+
struct JSIConverter<T, std::enable_if_t<is_shared_ptr_to_v<T, jsi::NativeState>>> final {
|
|
24
24
|
using TPointee = typename T::element_type;
|
|
25
25
|
|
|
26
26
|
static inline T fromJSI(jsi::Runtime& runtime, const jsi::Value& arg) {
|
|
27
|
-
#
|
|
27
|
+
#ifndef NDEBUG
|
|
28
28
|
if (!arg.isObject()) [[unlikely]] {
|
|
29
29
|
if (arg.isUndefined()) [[unlikely]] {
|
|
30
30
|
throw jsi::JSError(runtime, invalidTypeErrorMessage("undefined", "It is undefined!"));
|
|
@@ -36,7 +36,7 @@ struct JSIConverter<T, std::enable_if_t<is_shared_ptr_to_v<T, jsi::NativeState>>
|
|
|
36
36
|
#endif
|
|
37
37
|
jsi::Object object = arg.asObject(runtime);
|
|
38
38
|
|
|
39
|
-
#
|
|
39
|
+
#ifndef NDEBUG
|
|
40
40
|
if (!object.hasNativeState<TPointee>(runtime)) [[unlikely]] {
|
|
41
41
|
if (!object.hasNativeState(runtime)) [[unlikely]] {
|
|
42
42
|
std::string stringRepresentation = arg.toString(runtime).utf8(runtime);
|
|
@@ -47,7 +47,8 @@ struct JSIConverter<T, std::enable_if_t<is_shared_ptr_to_v<T, jsi::NativeState>>
|
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
49
|
#endif
|
|
50
|
-
|
|
50
|
+
std::shared_ptr<jsi::NativeState> nativeState = object.getNativeState(runtime);
|
|
51
|
+
return std::dynamic_pointer_cast<TPointee>(nativeState);
|
|
51
52
|
}
|
|
52
53
|
|
|
53
54
|
static inline jsi::Value toJSI(jsi::Runtime& runtime, const T& arg) {
|
|
@@ -60,7 +61,7 @@ struct JSIConverter<T, std::enable_if_t<is_shared_ptr_to_v<T, jsi::NativeState>>
|
|
|
60
61
|
// It's a HybridObject - use it's internal constructor which caches jsi::Objects for proper memory management!
|
|
61
62
|
return arg->toObject(runtime);
|
|
62
63
|
} else {
|
|
63
|
-
// It's any other kind of jsi::
|
|
64
|
+
// It's any other kind of jsi::NativeState - just create it as normal. This will not have a prototype then!
|
|
64
65
|
jsi::Object object(runtime);
|
|
65
66
|
object.setNativeState(runtime, arg);
|
|
66
67
|
return object;
|
|
@@ -21,7 +21,7 @@ using namespace facebook;
|
|
|
21
21
|
|
|
22
22
|
// std::optional<T> <> T | undefined
|
|
23
23
|
template <typename TInner>
|
|
24
|
-
struct JSIConverter<std::optional<TInner>> {
|
|
24
|
+
struct JSIConverter<std::optional<TInner>> final {
|
|
25
25
|
static inline std::optional<TInner> fromJSI(jsi::Runtime& runtime, const jsi::Value& arg) {
|
|
26
26
|
if (arg.isUndefined() || arg.isNull()) {
|
|
27
27
|
return std::nullopt;
|
|
@@ -30,7 +30,7 @@ using namespace facebook;
|
|
|
30
30
|
|
|
31
31
|
// std::future<T> <> Promise<T>
|
|
32
32
|
template <typename TResult>
|
|
33
|
-
struct JSIConverter<std::future<TResult>> {
|
|
33
|
+
struct JSIConverter<std::future<TResult>> final {
|
|
34
34
|
static inline std::future<TResult> fromJSI(jsi::Runtime&, const jsi::Value&) {
|
|
35
35
|
throw std::runtime_error("Promise cannot be converted to a native type - it needs to be awaited first!");
|
|
36
36
|
}
|
|
@@ -49,7 +49,8 @@ struct JSIConverter<std::future<TResult>> {
|
|
|
49
49
|
// the async function completed successfully, get a JS Dispatcher so we can resolve on JS Thread
|
|
50
50
|
std::shared_ptr<Dispatcher> dispatcher = weakDispatcher.lock();
|
|
51
51
|
if (!dispatcher) {
|
|
52
|
-
Logger::log("JSIConverter",
|
|
52
|
+
Logger::log(LogLevel::Error, "JSIConverter",
|
|
53
|
+
"Tried resolving Promise on JS Thread, but the `Dispatcher` has already been destroyed!");
|
|
53
54
|
return;
|
|
54
55
|
}
|
|
55
56
|
|
|
@@ -62,7 +63,7 @@ struct JSIConverter<std::future<TResult>> {
|
|
|
62
63
|
} else {
|
|
63
64
|
// it's returning a custom type, convert it to a jsi::Value
|
|
64
65
|
TResult result = sharedFuture->get();
|
|
65
|
-
jsi::Value jsResult = JSIConverter<TResult>::toJSI(runtime, result);
|
|
66
|
+
jsi::Value jsResult = JSIConverter<TResult>::toJSI(runtime, std::forward<TResult>(result));
|
|
66
67
|
promise->resolve(runtime, std::move(jsResult));
|
|
67
68
|
}
|
|
68
69
|
} catch (const std::exception& exception) {
|
|
@@ -84,7 +85,7 @@ struct JSIConverter<std::future<TResult>> {
|
|
|
84
85
|
});
|
|
85
86
|
}
|
|
86
87
|
|
|
87
|
-
static inline bool canConvert(jsi::Runtime
|
|
88
|
+
static inline bool canConvert(jsi::Runtime&, const jsi::Value&) {
|
|
88
89
|
throw std::runtime_error("jsi::Value of type Promise cannot be converted to std::future yet!");
|
|
89
90
|
}
|
|
90
91
|
};
|
|
@@ -23,7 +23,7 @@ using namespace facebook;
|
|
|
23
23
|
|
|
24
24
|
// std::tuple<A, B, C> <> [A, B, C]
|
|
25
25
|
template <typename... Types>
|
|
26
|
-
struct JSIConverter<std::tuple<Types...>> {
|
|
26
|
+
struct JSIConverter<std::tuple<Types...>> final {
|
|
27
27
|
static inline std::tuple<Types...> fromJSI(jsi::Runtime& runtime, const jsi::Value& value) {
|
|
28
28
|
jsi::Object object = value.asObject(runtime);
|
|
29
29
|
jsi::Array array = object.asArray(runtime);
|
|
@@ -23,7 +23,7 @@ using namespace facebook;
|
|
|
23
23
|
|
|
24
24
|
// std::unordered_map<std::string, T> <> Record<string, T>
|
|
25
25
|
template <typename ValueType>
|
|
26
|
-
struct JSIConverter<std::unordered_map<std::string, ValueType>> {
|
|
26
|
+
struct JSIConverter<std::unordered_map<std::string, ValueType>> final {
|
|
27
27
|
static inline std::unordered_map<std::string, ValueType> fromJSI(jsi::Runtime& runtime, const jsi::Value& arg) {
|
|
28
28
|
jsi::Object object = arg.asObject(runtime);
|
|
29
29
|
jsi::Array propertyNames = object.getPropertyNames(runtime);
|
|
@@ -18,7 +18,6 @@ struct JSIConverter;
|
|
|
18
18
|
#include "JSIConverter.hpp"
|
|
19
19
|
|
|
20
20
|
#include "AnyMap.hpp"
|
|
21
|
-
#include "IsInPack.hpp"
|
|
22
21
|
#include "TypeInfo.hpp"
|
|
23
22
|
#include <jsi/jsi.h>
|
|
24
23
|
#include <memory>
|
|
@@ -30,8 +29,7 @@ using namespace facebook;
|
|
|
30
29
|
|
|
31
30
|
// std::variant<A, B, C> <> A | B | C
|
|
32
31
|
template <typename... Types>
|
|
33
|
-
struct JSIConverter<std::variant<Types...>> {
|
|
34
|
-
|
|
32
|
+
struct JSIConverter<std::variant<Types...>> final {
|
|
35
33
|
static inline bool canConvert(jsi::Runtime& runtime, const jsi::Value& value) {
|
|
36
34
|
// Check each type in `Types...` to make sure we can convert `jsi::Value` to one of those.
|
|
37
35
|
return (JSIConverter<Types>::canConvert(runtime, value) || ...);
|
|
@@ -22,7 +22,7 @@ using namespace facebook;
|
|
|
22
22
|
|
|
23
23
|
// std::vector<T> <> T[]
|
|
24
24
|
template <typename ElementType>
|
|
25
|
-
struct JSIConverter<std::vector<ElementType>> {
|
|
25
|
+
struct JSIConverter<std::vector<ElementType>> final {
|
|
26
26
|
static inline std::vector<ElementType> fromJSI(jsi::Runtime& runtime, const jsi::Value& arg) {
|
|
27
27
|
jsi::Array array = arg.asObject(runtime).asArray(runtime);
|
|
28
28
|
size_t length = array.size(runtime);
|
package/cpp/jsi/JSIConverter.hpp
CHANGED
|
@@ -22,7 +22,7 @@ using namespace facebook;
|
|
|
22
22
|
* The JSIConverter<T> class can convert any type from and to a jsi::Value.
|
|
23
23
|
* It uses templates to statically create fromJSI/toJSI methods, and will throw compile-time errors
|
|
24
24
|
* if a given type is not convertable.
|
|
25
|
-
* Value types, custom types (
|
|
25
|
+
* Value types, custom types (HybridObject), and even functions with any number of arguments/types are supported.
|
|
26
26
|
* This type can be extended by just creating a new template for JSIConverter in a header.
|
|
27
27
|
*/
|
|
28
28
|
template <typename T, typename Enable = void>
|
|
@@ -61,7 +61,7 @@ private:
|
|
|
61
61
|
|
|
62
62
|
// int <> number
|
|
63
63
|
template <>
|
|
64
|
-
struct JSIConverter<int> {
|
|
64
|
+
struct JSIConverter<int> final {
|
|
65
65
|
static inline int fromJSI(jsi::Runtime&, const jsi::Value& arg) {
|
|
66
66
|
return static_cast<int>(arg.asNumber());
|
|
67
67
|
}
|
|
@@ -75,11 +75,11 @@ struct JSIConverter<int> {
|
|
|
75
75
|
|
|
76
76
|
// std::monostate <> null
|
|
77
77
|
template <>
|
|
78
|
-
struct JSIConverter<std::monostate> {
|
|
79
|
-
static inline std::monostate fromJSI(jsi::Runtime&, const jsi::Value&
|
|
78
|
+
struct JSIConverter<std::monostate> final {
|
|
79
|
+
static inline std::monostate fromJSI(jsi::Runtime&, const jsi::Value&) {
|
|
80
80
|
return std::monostate();
|
|
81
81
|
}
|
|
82
|
-
static inline jsi::Value toJSI(jsi::Runtime&, std::monostate
|
|
82
|
+
static inline jsi::Value toJSI(jsi::Runtime&, std::monostate) {
|
|
83
83
|
return jsi::Value::null();
|
|
84
84
|
}
|
|
85
85
|
static inline bool canConvert(jsi::Runtime&, const jsi::Value& value) {
|
|
@@ -89,7 +89,7 @@ struct JSIConverter<std::monostate> {
|
|
|
89
89
|
|
|
90
90
|
// double <> number
|
|
91
91
|
template <>
|
|
92
|
-
struct JSIConverter<double> {
|
|
92
|
+
struct JSIConverter<double> final {
|
|
93
93
|
static inline double fromJSI(jsi::Runtime&, const jsi::Value& arg) {
|
|
94
94
|
return arg.asNumber();
|
|
95
95
|
}
|
|
@@ -103,7 +103,7 @@ struct JSIConverter<double> {
|
|
|
103
103
|
|
|
104
104
|
// float <> number
|
|
105
105
|
template <>
|
|
106
|
-
struct JSIConverter<float> {
|
|
106
|
+
struct JSIConverter<float> final {
|
|
107
107
|
static inline float fromJSI(jsi::Runtime&, const jsi::Value& arg) {
|
|
108
108
|
return static_cast<float>(arg.asNumber());
|
|
109
109
|
}
|
|
@@ -117,7 +117,7 @@ struct JSIConverter<float> {
|
|
|
117
117
|
|
|
118
118
|
// int64_t <> BigInt
|
|
119
119
|
template <>
|
|
120
|
-
struct JSIConverter<int64_t> {
|
|
120
|
+
struct JSIConverter<int64_t> final {
|
|
121
121
|
static inline double fromJSI(jsi::Runtime& runtime, const jsi::Value& arg) {
|
|
122
122
|
return arg.asBigInt(runtime).asInt64(runtime);
|
|
123
123
|
}
|
|
@@ -135,7 +135,7 @@ struct JSIConverter<int64_t> {
|
|
|
135
135
|
|
|
136
136
|
// uint64_t <> BigInt
|
|
137
137
|
template <>
|
|
138
|
-
struct JSIConverter<uint64_t> {
|
|
138
|
+
struct JSIConverter<uint64_t> final {
|
|
139
139
|
static inline double fromJSI(jsi::Runtime& runtime, const jsi::Value& arg) {
|
|
140
140
|
return arg.asBigInt(runtime).asUint64(runtime);
|
|
141
141
|
}
|
|
@@ -153,7 +153,7 @@ struct JSIConverter<uint64_t> {
|
|
|
153
153
|
|
|
154
154
|
// bool <> boolean
|
|
155
155
|
template <>
|
|
156
|
-
struct JSIConverter<bool> {
|
|
156
|
+
struct JSIConverter<bool> final {
|
|
157
157
|
static inline bool fromJSI(jsi::Runtime&, const jsi::Value& arg) {
|
|
158
158
|
return arg.asBool();
|
|
159
159
|
}
|
|
@@ -167,7 +167,7 @@ struct JSIConverter<bool> {
|
|
|
167
167
|
|
|
168
168
|
// std::string <> string
|
|
169
169
|
template <>
|
|
170
|
-
struct JSIConverter<std::string> {
|
|
170
|
+
struct JSIConverter<std::string> final {
|
|
171
171
|
static inline std::string fromJSI(jsi::Runtime& runtime, const jsi::Value& arg) {
|
|
172
172
|
return arg.asString(runtime).utf8(runtime);
|
|
173
173
|
}
|
package/cpp/jsi/JSPromise.cpp
CHANGED
|
@@ -38,7 +38,7 @@ void JSPromise::resolve(jsi::Runtime& runtime, jsi::Value&& result) {
|
|
|
38
38
|
OwningLock<jsi::Function> lock = _resolver.lock();
|
|
39
39
|
|
|
40
40
|
if (!_resolver) {
|
|
41
|
-
Logger::log(TAG, "Promise resolver function has already been deleted! Ignoring call..");
|
|
41
|
+
Logger::log(LogLevel::Error, TAG, "Promise resolver function has already been deleted! Ignoring call..");
|
|
42
42
|
return;
|
|
43
43
|
}
|
|
44
44
|
_resolver->call(runtime, std::move(result));
|
|
@@ -48,7 +48,7 @@ void JSPromise::reject(jsi::Runtime& runtime, std::string message) {
|
|
|
48
48
|
OwningLock<jsi::Function> lock = _rejecter.lock();
|
|
49
49
|
|
|
50
50
|
if (!_rejecter) {
|
|
51
|
-
Logger::log(TAG, "Promise rejecter function has already been deleted! Ignoring call..");
|
|
51
|
+
Logger::log(LogLevel::Error, TAG, "Promise rejecter function has already been deleted! Ignoring call..");
|
|
52
52
|
return;
|
|
53
53
|
}
|
|
54
54
|
jsi::JSError error(runtime, message);
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Created by Marc Rousavy on 05.03.24.
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
#pragma once
|
|
6
|
+
|
|
7
|
+
#include <cstdarg>
|
|
8
|
+
#include <cstdio>
|
|
9
|
+
#include <iostream>
|
|
10
|
+
#include <sstream>
|
|
11
|
+
#include <string>
|
|
12
|
+
#include <type_traits>
|
|
13
|
+
|
|
14
|
+
namespace margelo::nitro {
|
|
15
|
+
|
|
16
|
+
enum class LogLevel { Debug, Info, Warning, Error };
|
|
17
|
+
|
|
18
|
+
class Logger final {
|
|
19
|
+
private:
|
|
20
|
+
Logger() = delete;
|
|
21
|
+
|
|
22
|
+
public:
|
|
23
|
+
template <typename... Args>
|
|
24
|
+
static void log(LogLevel level, const char* tag, const char* format, Args... args) {
|
|
25
|
+
#ifndef NDEBUG
|
|
26
|
+
// 1. Make sure args can be passed to sprintf(..)
|
|
27
|
+
static_assert(all_are_trivially_copyable<Args...>(), "All arguments passed to Logger::log(..) must be trivially copyable! "
|
|
28
|
+
"Did you try to pass a complex type, like std::string?");
|
|
29
|
+
|
|
30
|
+
// 2. Format all arguments in the message
|
|
31
|
+
std::string message = formatString(format, args...);
|
|
32
|
+
|
|
33
|
+
// 3. Call the platform specific log function
|
|
34
|
+
nativeLog(level, tag, message);
|
|
35
|
+
#endif
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
static void nativeLog(LogLevel level, const char* tag, const std::string& string);
|
|
39
|
+
|
|
40
|
+
private:
|
|
41
|
+
template <typename... Args>
|
|
42
|
+
static std::string formatString(const char* format, Args... args) {
|
|
43
|
+
#pragma clang diagnostic push
|
|
44
|
+
#pragma clang diagnostic ignored "-Wformat-security"
|
|
45
|
+
int size = snprintf(nullptr, 0, format, args...) + 1; // Extra space for '\0'
|
|
46
|
+
if (size <= 0) {
|
|
47
|
+
return "Error during formatting.";
|
|
48
|
+
}
|
|
49
|
+
std::unique_ptr<char[]> buf(new char[size]);
|
|
50
|
+
snprintf(buf.get(), size, format, args...);
|
|
51
|
+
return std::string(buf.get(), buf.get() + size - 1); // We don't want the '\0' inside
|
|
52
|
+
#pragma clang diagnostic pop
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Overloaded functions to convert std::string to C-style string
|
|
56
|
+
template <typename T>
|
|
57
|
+
static constexpr bool is_trivially_copyable() {
|
|
58
|
+
return std::is_trivially_copyable<T>::value;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
template <typename... Args>
|
|
62
|
+
static constexpr bool all_are_trivially_copyable() {
|
|
63
|
+
return (is_trivially_copyable<Args>() && ...);
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
} // namespace margelo::nitro
|
|
@@ -30,7 +30,7 @@ jsi::Value HybridObjectPrototype::createPrototype(jsi::Runtime& runtime, const s
|
|
|
30
30
|
|
|
31
31
|
// 2. We didn't find the given prototype in cache (either it's a new prototype, or a new runtime),
|
|
32
32
|
// so we need to create it. First, we need some helper methods from JS
|
|
33
|
-
Logger::log(TAG, "Creating new JS prototype for C++ instance type \"%s\"...", prototype->getNativeInstanceId().name());
|
|
33
|
+
Logger::log(LogLevel::Info, TAG, "Creating new JS prototype for C++ instance type \"%s\"...", prototype->getNativeInstanceId().name());
|
|
34
34
|
jsi::Object objectConstructor = runtime.global().getPropertyAsObject(runtime, "Object");
|
|
35
35
|
jsi::Function objectCreate = objectConstructor.getPropertyAsFunction(runtime, "create");
|
|
36
36
|
jsi::Function objectDefineProperty = objectConstructor.getPropertyAsFunction(runtime, "defineProperty");
|
|
@@ -69,7 +69,7 @@ jsi::Value HybridObjectPrototype::createPrototype(jsi::Runtime& runtime, const s
|
|
|
69
69
|
prototypeCache.emplace(prototype->getNativeInstanceId(), cachedObject);
|
|
70
70
|
|
|
71
71
|
// 7. In DEBUG, add a __type info to the prototype object.
|
|
72
|
-
#
|
|
72
|
+
#ifndef NDEBUG
|
|
73
73
|
auto typeName = "Prototype<" + std::string(prototype->getNativeInstanceId().name()) + ">";
|
|
74
74
|
cachedObject->setProperty(runtime, "__type", jsi::String::createFromUtf8(runtime, typeName));
|
|
75
75
|
#endif
|