react-native-nitro-modules 0.0.2 → 0.0.6

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 (119) hide show
  1. package/NitroModules.podspec +49 -0
  2. package/android/CMakeLists.txt +44 -7
  3. package/android/build.gradle +28 -24
  4. package/cpp/core/AnyMap.cpp +181 -0
  5. package/cpp/core/AnyMap.hpp +191 -0
  6. package/cpp/core/HybridContext.hpp +51 -0
  7. package/cpp/core/HybridObject.cpp +220 -0
  8. package/cpp/core/HybridObject.hpp +241 -0
  9. package/cpp/core/PointerHolder.hpp +93 -0
  10. package/cpp/jsi/ArrayBuffer.hpp +79 -0
  11. package/cpp/jsi/JSICache.hpp +145 -0
  12. package/cpp/jsi/JSIConverter.hpp +610 -0
  13. package/cpp/jsi/Promise.cpp +54 -0
  14. package/cpp/jsi/Promise.hpp +54 -0
  15. package/cpp/platform/ThreadUtils.hpp +23 -0
  16. package/cpp/registry/HybridObjectRegistry.cpp +57 -0
  17. package/cpp/registry/HybridObjectRegistry.hpp +44 -0
  18. package/cpp/test-object/TestHybridObject.cpp +37 -0
  19. package/cpp/test-object/TestHybridObject.hpp +87 -0
  20. package/cpp/threading/CallInvokerDispatcher.hpp +33 -0
  21. package/cpp/threading/Dispatcher.cpp +56 -0
  22. package/cpp/threading/Dispatcher.hpp +82 -0
  23. package/cpp/turbomodule/NativeNitroModules.cpp +70 -0
  24. package/cpp/turbomodule/NativeNitroModules.h +7 -0
  25. package/cpp/turbomodule/NativeNitroModules.hpp +35 -0
  26. package/cpp/turbomodule/RegisterNativeNitroModules.cpp +33 -0
  27. package/cpp/turbomodule/RegisterNativeNitroModules.hpp +21 -0
  28. package/cpp/utils/BorrowingReference+Owning.hpp +34 -0
  29. package/cpp/utils/BorrowingReference.hpp +115 -0
  30. package/cpp/utils/DoesClassExist.hpp +23 -0
  31. package/cpp/utils/GetRuntimeID.hpp +28 -0
  32. package/cpp/utils/NitroDefines.hpp +32 -0
  33. package/cpp/utils/NitroHash.hpp +42 -0
  34. package/cpp/utils/NitroLogger.hpp +55 -0
  35. package/cpp/utils/OwningLock.hpp +54 -0
  36. package/cpp/utils/OwningReference.hpp +214 -0
  37. package/cpp/utils/TypeInfo.hpp +81 -0
  38. package/ios/core/HybridObjectSpec.swift +52 -0
  39. package/ios/core/RuntimeError.swift +17 -0
  40. package/ios/platform/ThreadUtils.cpp +28 -0
  41. package/ios/turbomodule/NitroModuleOnLoad.mm +31 -0
  42. package/lib/AnyMap.d.ts +16 -0
  43. package/lib/AnyMap.js +1 -0
  44. package/lib/HybridObject.d.ts +57 -0
  45. package/lib/HybridObject.js +1 -0
  46. package/lib/ModuleNotFoundError.d.ts +6 -0
  47. package/lib/ModuleNotFoundError.js +61 -0
  48. package/lib/NativeNitro.d.ts +8 -0
  49. package/lib/NativeNitro.js +3 -0
  50. package/lib/NativeNitroModules.d.ts +7 -0
  51. package/lib/NativeNitroModules.js +17 -0
  52. package/lib/NitroModules.d.ts +17 -0
  53. package/lib/NitroModules.js +21 -0
  54. package/lib/__tests__/index.test.d.ts +0 -0
  55. package/lib/__tests__/index.test.js +2 -0
  56. package/lib/commonjs/AnyMap.js +2 -0
  57. package/lib/commonjs/AnyMap.js.map +1 -0
  58. package/lib/commonjs/HybridObject.js +2 -0
  59. package/lib/commonjs/HybridObject.js.map +1 -0
  60. package/lib/commonjs/ModuleNotFoundError.js +72 -0
  61. package/lib/commonjs/ModuleNotFoundError.js.map +1 -0
  62. package/lib/commonjs/NativeNitroModules.js +24 -0
  63. package/lib/commonjs/NativeNitroModules.js.map +1 -0
  64. package/lib/commonjs/NitroModules.js +32 -0
  65. package/lib/commonjs/NitroModules.js.map +1 -0
  66. package/lib/commonjs/createTestObject.js +15 -0
  67. package/lib/commonjs/createTestObject.js.map +1 -0
  68. package/lib/commonjs/index.js +44 -5
  69. package/lib/commonjs/index.js.map +1 -1
  70. package/lib/createTestObject.d.ts +22 -0
  71. package/lib/createTestObject.js +7 -0
  72. package/lib/index.d.ts +4 -0
  73. package/lib/index.js +4 -0
  74. package/lib/module/AnyMap.js +2 -0
  75. package/lib/module/AnyMap.js.map +1 -0
  76. package/lib/module/HybridObject.js +2 -0
  77. package/lib/module/HybridObject.js.map +1 -0
  78. package/lib/module/ModuleNotFoundError.js +65 -0
  79. package/lib/module/ModuleNotFoundError.js.map +1 -0
  80. package/lib/module/NativeNitroModules.js +18 -0
  81. package/lib/module/NativeNitroModules.js.map +1 -0
  82. package/lib/module/NitroModules.js +27 -0
  83. package/lib/module/NitroModules.js.map +1 -0
  84. package/lib/module/createTestObject.js +8 -0
  85. package/lib/module/createTestObject.js.map +1 -0
  86. package/lib/module/index.js +4 -4
  87. package/lib/module/index.js.map +1 -1
  88. package/lib/tsconfig.tsbuildinfo +1 -0
  89. package/package.json +74 -50
  90. package/react-native.config.js +16 -0
  91. package/src/AnyMap.ts +22 -0
  92. package/src/HybridObject.ts +58 -0
  93. package/src/ModuleNotFoundError.ts +90 -0
  94. package/src/NativeNitroModules.ts +26 -0
  95. package/src/NitroModules.ts +30 -0
  96. package/src/createTestObject.ts +40 -0
  97. package/src/index.ts +4 -0
  98. package/LICENSE +0 -20
  99. package/README.md +0 -32
  100. package/android/cpp-adapter.cpp +0 -8
  101. package/android/src/main/AndroidManifest.xml +0 -3
  102. package/android/src/main/AndroidManifestNew.xml +0 -2
  103. package/android/src/main/java/com/nitro/NitroModule.java +0 -34
  104. package/android/src/main/java/com/nitro/NitroPackage.java +0 -44
  105. package/cpp/react-native-nitro.cpp +0 -7
  106. package/cpp/react-native-nitro.h +0 -8
  107. package/ios/Nitro.h +0 -15
  108. package/ios/Nitro.mm +0 -21
  109. package/lib/commonjs/NativeNitro.js +0 -9
  110. package/lib/commonjs/NativeNitro.js.map +0 -1
  111. package/lib/module/NativeNitro.js +0 -3
  112. package/lib/module/NativeNitro.js.map +0 -1
  113. package/lib/typescript/src/NativeNitro.d.ts +0 -7
  114. package/lib/typescript/src/NativeNitro.d.ts.map +0 -1
  115. package/lib/typescript/src/index.d.ts +0 -2
  116. package/lib/typescript/src/index.d.ts.map +0 -1
  117. package/react-native-nitro.podspec +0 -41
  118. package/src/NativeNitro.ts +0 -8
  119. package/src/index.tsx +0 -5
@@ -0,0 +1,115 @@
1
+ //
2
+ // BorrowingReference.hpp
3
+ // NitroModules
4
+ //
5
+ // Created by Marc Rousavy on 21.06.24.
6
+ //
7
+
8
+ #pragma once
9
+
10
+ #include <cstddef>
11
+ #include <mutex>
12
+ #include <atomic>
13
+
14
+ namespace margelo::nitro {
15
+
16
+ // forward-declaration to avoid duplicate symbols
17
+ template <typename T> class OwningReference;
18
+
19
+ /**
20
+ A `BorrowingReference<T>` is a weak reference to a pointer created by `OwningReference<T>`.
21
+ It can be locked to gain a strong `OwningReference<T>` again if it has not been deleted yet.
22
+ */
23
+ template <typename T> class BorrowingReference final {
24
+ private:
25
+ explicit BorrowingReference(const OwningReference<T>& ref);
26
+
27
+ public:
28
+ BorrowingReference() : _value(nullptr), _isDeleted(nullptr), _strongRefCount(nullptr), _weakRefCount(nullptr), _mutex(nullptr) {}
29
+
30
+ BorrowingReference(const BorrowingReference& ref)
31
+ : _value(ref._value), _isDeleted(ref._isDeleted), _strongRefCount(ref._strongRefCount), _weakRefCount(ref._weakRefCount),
32
+ _mutex(ref._mutex) {
33
+ // increment ref count after copy
34
+ (*_weakRefCount)++;
35
+ }
36
+
37
+ BorrowingReference(BorrowingReference&& ref)
38
+ : _value(ref._value), _isDeleted(ref._isDeleted), _strongRefCount(ref._strongRefCount), _weakRefCount(ref._weakRefCount),
39
+ _mutex(ref._mutex) {
40
+ ref._value = nullptr;
41
+ ref._isDeleted = nullptr;
42
+ ref._strongRefCount = nullptr;
43
+ ref._weakRefCount = nullptr;
44
+ }
45
+
46
+ BorrowingReference& operator=(const BorrowingReference& ref) {
47
+ if (this == &ref)
48
+ return *this;
49
+
50
+ if (_weakRefCount != nullptr) {
51
+ // destroy previous pointer
52
+ (*_weakRefCount)--;
53
+ maybeDestroy();
54
+ }
55
+
56
+ _value = ref._value;
57
+ _isDeleted = ref._isDeleted;
58
+ _strongRefCount = ref._strongRefCount;
59
+ _weakRefCount = ref._weakRefCount;
60
+ _mutex = ref._mutex;
61
+ if (_weakRefCount != nullptr) {
62
+ // increment new pointer
63
+ (*_weakRefCount)++;
64
+ }
65
+
66
+ return *this;
67
+ }
68
+
69
+ ~BorrowingReference() {
70
+ if (_weakRefCount == nullptr) {
71
+ // we are just a dangling nullptr.
72
+ return;
73
+ }
74
+
75
+ (*_weakRefCount)--;
76
+ maybeDestroy();
77
+ }
78
+
79
+ /**
80
+ Try to lock the borrowing reference to an owning reference, or `nullptr` if it has already been deleted.
81
+ */
82
+ [[nodiscard]]
83
+ OwningReference<T> lock();
84
+
85
+ public:
86
+ friend class OwningReference<T>;
87
+
88
+ private:
89
+ void maybeDestroy() {
90
+ _mutex->lock();
91
+
92
+ if (*_strongRefCount == 0 && *_weakRefCount == 0) {
93
+ // free the full memory if there are no more references at all
94
+ if (!(*_isDeleted)) {
95
+ delete _value;
96
+ }
97
+ delete _isDeleted;
98
+ delete _strongRefCount;
99
+ delete _weakRefCount;
100
+ _mutex->unlock();
101
+ return;
102
+ }
103
+
104
+ _mutex->unlock();
105
+ }
106
+
107
+ private:
108
+ T* _value;
109
+ bool* _isDeleted;
110
+ std::atomic_size_t* _strongRefCount;
111
+ std::atomic_size_t* _weakRefCount;
112
+ std::mutex* _mutex;
113
+ };
114
+
115
+ } // namespace margelo::nitro
@@ -0,0 +1,23 @@
1
+ //
2
+ // DoesClassExist.hpp
3
+ // Pods
4
+ //
5
+ // Created by Marc Rousavy on 17.07.24.
6
+ //
7
+
8
+ #pragma once
9
+
10
+ #include <type_traits>
11
+
12
+ namespace margelo::nitro {
13
+
14
+ // By default, it is false (class does not exist)
15
+ template <typename T, typename = std::void_t<>> struct does_class_exist : std::false_type {};
16
+
17
+ // If sizeof(T) can be a type (number), the type exists - so it is true
18
+ template <typename T> struct does_class_exist<T, std::void_t<decltype(sizeof(T))>> : std::true_type {};
19
+
20
+ // Direct value accessor for does_class_exist
21
+ template <typename T> inline constexpr bool does_class_exist_v = does_class_exist<T>::value;
22
+
23
+ } // namespace margelo::nitro
@@ -0,0 +1,28 @@
1
+ //
2
+ // GetRuntimeID.hpp
3
+ // NitroModules
4
+ //
5
+ // Created by Marc Rousavy on 20.06.24.
6
+ //
7
+
8
+ #pragma once
9
+
10
+ #include "ThreadUtils.hpp"
11
+ #include <jsi/jsi.h>
12
+
13
+ namespace margelo::nitro {
14
+
15
+ using namespace facebook;
16
+
17
+ /**
18
+ * Get an ID for the given Runtime.
19
+ *
20
+ * The ID usually consists of a Runtime description (e.g. "HermesRuntime"),
21
+ * and it's Thread (e.g. "com.facebook.react.runtime.JavaScript")
22
+ */
23
+ static inline std::string getRuntimeId(jsi::Runtime& runtime) {
24
+ std::string threadName = ThreadUtils::getThreadName();
25
+ return runtime.description() + std::string(" (") + threadName + std::string(")");
26
+ }
27
+
28
+ } // namespace margelo::nitro
@@ -0,0 +1,32 @@
1
+ //
2
+ // NitroDefines.hpp
3
+ // Pods
4
+ //
5
+ // Created by Marc Rousavy on 29.07.24.
6
+ //
7
+
8
+ #ifndef NitroDefines_h
9
+ #define NitroDefines_h
10
+
11
+ // Helper to find out if a C++ compiler attribute is available
12
+ #ifdef __has_attribute
13
+ #define _CXX_INTEROP_HAS_ATTRIBUTE(x) __has_attribute(x)
14
+ #else
15
+ #define _CXX_INTEROP_HAS_ATTRIBUTE(x) 0
16
+ #endif
17
+
18
+ #if _CXX_INTEROP_HAS_ATTRIBUTE(swift_attr)
19
+ // Rename Type for Swift
20
+ #define SWIFT_NAME(_name) __attribute__((swift_name(#_name)))
21
+ #else
22
+ #define SWIFT_NAME(_name)
23
+ #endif
24
+
25
+ #if _CXX_INTEROP_HAS_ATTRIBUTE(enum_extensibility)
26
+ // Enum is marked as closed/not extensible
27
+ #define CLOSED_ENUM __attribute__((enum_extensibility(closed)))
28
+ #else
29
+ #define CLOSED_ENUM
30
+ #endif
31
+
32
+ #endif /* NitroDefines_h */
@@ -0,0 +1,42 @@
1
+ //
2
+ // NitroHash.hpp
3
+ // react-native-nitro
4
+ //
5
+ // Created by Marc Rousavy on 14.07.24.
6
+ //
7
+
8
+ #pragma once
9
+
10
+ #include <cstddef>
11
+ #include <cstdint>
12
+
13
+ namespace margelo::nitro {
14
+
15
+ /**
16
+ * Hashes the given C-String using the FNV-1a hashing algorithm.
17
+ *
18
+ * This function can be used at compile time as a constexpr to build
19
+ * statically optimized switch statements.
20
+ */
21
+ constexpr uint64_t hashString(const char* str, size_t length) {
22
+ uint64_t hash = 14695981039346656037ull; // FNV offset basis
23
+ const uint64_t fnv_prime = 1099511628211ull;
24
+
25
+ for (size_t i = 0; i < length; ++i) {
26
+ hash ^= static_cast<uint64_t>(str[i]);
27
+ hash *= fnv_prime;
28
+ }
29
+
30
+ return hash;
31
+ }
32
+
33
+ /**
34
+ * Hashes the given constant C-String using the FNV-1a hashing algorithm.
35
+ *
36
+ * String length is known at compile time.
37
+ */
38
+ template <size_t N> constexpr uint64_t hashString(const char (&str)[N]) {
39
+ return hashString(str, N - 1); // N includes the null terminator, so subtract 1
40
+ }
41
+
42
+ } // namespace margelo::nitro
@@ -0,0 +1,55 @@
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 <string>
11
+ #include <vector>
12
+
13
+ namespace margelo::nitro {
14
+
15
+ class Logger final {
16
+ private:
17
+ Logger() = delete;
18
+
19
+ public:
20
+ template <typename... Args> static void log(const char* tag, const char* message, Args&&... args) {
21
+ std::string formattedMessage = format(message, std::forward<Args>(args)...);
22
+ std::cout << "[Nitro." << tag << "] " << formattedMessage << std::endl;
23
+ }
24
+
25
+ private:
26
+ template <typename... Args> static inline std::string format(const char* formatString, Args&&... args) {
27
+ #pragma clang diagnostic push
28
+ #pragma clang diagnostic ignored "-Wformat-security"
29
+ int size_s = std::snprintf(nullptr, 0, formatString, toCString(args)...) + 1; // Extra space for '\0'
30
+ if (size_s <= 0) [[unlikely]] {
31
+ throw std::runtime_error("Failed to format log message \"" + std::string(formatString) + "\"!");
32
+ }
33
+ auto size = static_cast<size_t>(size_s);
34
+ std::vector<char> buf(size);
35
+ std::snprintf(buf.data(), size, formatString, toCString(args)...);
36
+ return std::string(buf.data(), buf.data() + size - 1); // We don't want the '\0' inside
37
+ #pragma clang diagnostic pop
38
+ }
39
+
40
+ private:
41
+ // When the user passes an `std::string`, it will automatically be converted to a `const char*`
42
+ static inline const char* toCString(const std::string& s) {
43
+ return s.c_str();
44
+ }
45
+ // When the user passes a `const char*`, we don't want to implicitly convert to `std::string`, so block that
46
+ static inline const char* toCString(const char* s) {
47
+ return s;
48
+ }
49
+ // When the user passes any other type, just return that directly.
50
+ template <typename T> static inline T toCString(T value) {
51
+ return value;
52
+ }
53
+ };
54
+
55
+ } // namespace margelo::nitro
@@ -0,0 +1,54 @@
1
+ //
2
+ // OwningLock.hpp
3
+ // Pods
4
+ //
5
+ // Created by Marc Rousavy on 30.07.24.
6
+ //
7
+
8
+ #pragma once
9
+
10
+ namespace margelo::nitro {
11
+ template <typename T> class OwningReference;
12
+ }
13
+
14
+ #include "OwningReference.hpp"
15
+ #include <cstddef>
16
+ #include <mutex>
17
+
18
+ namespace margelo::nitro {
19
+
20
+ /**
21
+ * An `OwningLock<T>` is a RAII instance that locks the given caller thread guaranteed safe access
22
+ * to a `OwningReference<T>`.
23
+ * The `OwningReference<T>` cannot be deleted while an `OwningLock<T>` of it is alive.
24
+ *
25
+ * This is useful in JSI, because Hermes runs garbage collection on a separate Thread,
26
+ * and the separate Thread can delete an `OwningReference<T>` while it's still in use.
27
+ * The `OwningLock<T>` prevents exactly this problem by blocking the GC destructor until
28
+ * the `OwningLock<T>` is released.
29
+ *
30
+ * To create an `OwningLock<T>`, simply call `lock()` on an `OwningReference<T>`.
31
+ */
32
+ template <typename T> class OwningLock final {
33
+ public:
34
+ ~OwningLock() {
35
+ _reference._mutex->unlock();
36
+ }
37
+
38
+ OwningLock() = delete;
39
+ OwningLock(const OwningLock&) = delete;
40
+ OwningLock(OwningLock&&) = delete;
41
+
42
+ private:
43
+ explicit OwningLock(const OwningReference<T>& reference) : _reference(reference) {
44
+ _reference._mutex->lock();
45
+ }
46
+
47
+ private:
48
+ OwningReference<T> _reference;
49
+
50
+ private:
51
+ friend class OwningReference<T>;
52
+ };
53
+
54
+ } // namespace margelo::nitro
@@ -0,0 +1,214 @@
1
+ //
2
+ // OwningReference.hpp
3
+ // react-native-nitro
4
+ //
5
+ // Created by Marc Rousavy on 23.06.24.
6
+ //
7
+
8
+ #pragma once
9
+
10
+ #include "BorrowingReference.hpp"
11
+ #include "OwningLock.hpp"
12
+ #include <cstddef>
13
+ #include <mutex>
14
+ #include <atomic>
15
+
16
+ namespace margelo::nitro {
17
+
18
+ /**
19
+ An `OwningReference<T>` is a smart-pointer that holds a strong reference to a pointer.
20
+ You can have multiple `OwningReference<T>` instances point to the same pointer, as they internally keep a ref-count.
21
+ As opposed to a `shared_ptr<T>`, an `OwningReference<T>` can also be imperatively manually deleted, even if there
22
+ are multiple strong references still holding onto the pointer.
23
+
24
+ An `OwningReference<T>` can be weakified, which gives the user a `BorrowingReference<T>`.
25
+ A `BorrowingReference<T>` can be locked to get an `OwningReference<T>` again, assuming it has not been deleted yet.
26
+ */
27
+ template <typename T> class OwningReference final {
28
+ public:
29
+ using Pointee = T;
30
+
31
+ public:
32
+ OwningReference() : _value(nullptr), _isDeleted(nullptr), _strongRefCount(nullptr), _weakRefCount(nullptr), _mutex(nullptr) {}
33
+
34
+ explicit OwningReference(T* value)
35
+ : _value(value), _isDeleted(new bool(false)), _strongRefCount(new std::atomic_size_t(1)), _weakRefCount(new std::atomic_size_t(0)), _mutex(new std::mutex()) {
36
+ }
37
+
38
+ OwningReference(const OwningReference& ref)
39
+ : _value(ref._value), _isDeleted(ref._isDeleted), _strongRefCount(ref._strongRefCount), _weakRefCount(ref._weakRefCount),
40
+ _mutex(ref._mutex) {
41
+ // increment ref count after copy
42
+ (*_strongRefCount)++;
43
+ }
44
+
45
+ OwningReference(OwningReference&& ref)
46
+ : _value(ref._value), _isDeleted(ref._isDeleted), _strongRefCount(ref._strongRefCount), _weakRefCount(ref._weakRefCount),
47
+ _mutex(ref._mutex) {
48
+ ref._value = nullptr;
49
+ ref._isDeleted = nullptr;
50
+ ref._strongRefCount = nullptr;
51
+ ref._weakRefCount = nullptr;
52
+ }
53
+
54
+ OwningReference& operator=(const OwningReference& ref) {
55
+ if (this == &ref)
56
+ return *this;
57
+
58
+ if (_strongRefCount != nullptr) {
59
+ // destroy previous pointer
60
+ (*_strongRefCount)--;
61
+ maybeDestroy();
62
+ }
63
+
64
+ _value = ref._value;
65
+ _isDeleted = ref._isDeleted;
66
+ _strongRefCount = ref._strongRefCount;
67
+ _weakRefCount = ref._weakRefCount;
68
+ _mutex = ref._mutex;
69
+ if (_strongRefCount != nullptr) {
70
+ // increment new pointer
71
+ (*_strongRefCount)++;
72
+ }
73
+
74
+ return *this;
75
+ }
76
+
77
+ private:
78
+ OwningReference(const BorrowingReference<T>& ref)
79
+ : _value(ref._value), _isDeleted(ref._isDeleted), _strongRefCount(ref._strongRefCount), _weakRefCount(ref._weakRefCount),
80
+ _mutex(ref._mutex) {
81
+ (*_strongRefCount)++;
82
+ }
83
+
84
+ public:
85
+ ~OwningReference() {
86
+ if (_strongRefCount == nullptr) {
87
+ // we are just a dangling nullptr.
88
+ return;
89
+ }
90
+
91
+ // decrement strong ref count on destroy
92
+ --(*_strongRefCount);
93
+ maybeDestroy();
94
+ }
95
+
96
+ public:
97
+ /**
98
+ Creates an `OwningLock<T>` for the given `OwningReference<T>` to guarantee safe
99
+ safe access to `OwningReference<T>`.
100
+ Other threads (e.g. the Hermes garbage collector) cannot delete the `OwningReference<T>`
101
+ as long as the `OwningLock<T>` is still alive.
102
+ */
103
+ [[nodiscard]]
104
+ OwningLock<T> lock() const {
105
+ return OwningLock<T>(*this);
106
+ }
107
+
108
+ /**
109
+ Get whether the `OwningReference<T>` is still pointing to a valid value, or not.
110
+ */
111
+ inline bool hasValue() const {
112
+ return _value != nullptr && !(*_isDeleted);
113
+ }
114
+
115
+ /**
116
+ Get a borrowing (or "weak") reference to this owning reference
117
+ */
118
+ [[nodiscard]]
119
+ BorrowingReference<T> weak() const {
120
+ return BorrowingReference(*this);
121
+ }
122
+
123
+ /**
124
+ Delete and destroy the value this OwningReference is pointing to.
125
+ This can even be called if there are still multiple strong references to the value.
126
+
127
+ This will block as long as one or more `OwningLock<T>`s of this `OwningReference<T>` are still alive.
128
+ */
129
+ void destroy() {
130
+ std::unique_lock lock(*_mutex);
131
+
132
+ forceDestroy();
133
+ }
134
+
135
+ public:
136
+ explicit inline operator bool() const {
137
+ return hasValue();
138
+ }
139
+
140
+ inline T& operator*() const {
141
+ return *_value;
142
+ }
143
+
144
+ inline T* operator->() const {
145
+ return _value;
146
+ }
147
+
148
+ inline bool operator==(T* other) const {
149
+ std::unique_lock lock(*_mutex);
150
+
151
+ if (*_isDeleted) {
152
+ return other == nullptr;
153
+ } else {
154
+ return other == _value;
155
+ }
156
+ }
157
+
158
+ inline bool operator!=(T* other) const {
159
+ return !(this == other);
160
+ }
161
+
162
+ inline bool operator==(const OwningReference<T>& other) const {
163
+ return _value == other._value;
164
+ }
165
+
166
+ inline bool operator!=(const OwningReference<T>& other) const {
167
+ return !(this == other);
168
+ }
169
+
170
+ private:
171
+ void maybeDestroy() {
172
+ _mutex->lock();
173
+
174
+ if (*_strongRefCount == 0) {
175
+ // after no strong references exist anymore
176
+ forceDestroy();
177
+ }
178
+
179
+ if (*_strongRefCount == 0 && *_weakRefCount == 0) {
180
+ // free the full memory if there are no more references at all
181
+ delete _isDeleted;
182
+ delete _strongRefCount;
183
+ delete _weakRefCount;
184
+ _mutex->unlock();
185
+ return;
186
+ }
187
+
188
+ _mutex->unlock();
189
+ }
190
+
191
+ void forceDestroy() {
192
+ if (*_isDeleted) {
193
+ // it has already been destroyed.
194
+ return;
195
+ }
196
+ delete _value;
197
+ *_isDeleted = true;
198
+ }
199
+
200
+ public:
201
+ friend class BorrowingReference<T>;
202
+ friend class OwningLock<T>;
203
+
204
+ private:
205
+ T* _value;
206
+ bool* _isDeleted;
207
+ std::atomic_size_t* _strongRefCount;
208
+ std::atomic_size_t* _weakRefCount;
209
+ std::mutex* _mutex;
210
+ };
211
+
212
+ } // namespace margelo::nitro
213
+
214
+ #include "BorrowingReference+Owning.hpp"
@@ -0,0 +1,81 @@
1
+ //
2
+ // TypeInfo.hpp
3
+ // Pods
4
+ //
5
+ // Created by Marc Rousavy on 17.07.24.
6
+ //
7
+
8
+ #pragma once
9
+
10
+ #include <regex>
11
+ #include <sstream>
12
+ #include <string>
13
+ #include <type_traits>
14
+
15
+ #if __has_include(<cxxabi.h>)
16
+ #include <cxxabi.h>
17
+ #endif
18
+
19
+ namespace margelo::nitro {
20
+
21
+ struct TypeInfo final {
22
+ public:
23
+ TypeInfo() = delete;
24
+
25
+ /**
26
+ * Get the name of the currently thrown exception
27
+ */
28
+ static inline const char* getCurrentExceptionName() {
29
+ #if __has_include(<cxxabi.h>)
30
+ return __cxxabiv1::__cxa_current_exception_type()->name();
31
+ #else
32
+ return "<unknown>";
33
+ #endif
34
+ }
35
+
36
+ static inline std::string replaceRegex(const std::string& original, const std::string& pattern, const std::string& replacement) {
37
+ std::regex re(pattern);
38
+ return std::regex_replace(original, re, replacement);
39
+ }
40
+
41
+ /**
42
+ * Get a friendly name of the type `T` (if possible, demangled)
43
+ */
44
+ template <typename T> static inline std::string getFriendlyTypename() {
45
+ std::string name = typeid(T).name();
46
+ #if __has_include(<cxxabi.h>)
47
+ int status = 0;
48
+ char* demangled_name = abi::__cxa_demangle(name.c_str(), NULL, NULL, &status);
49
+ if (demangled_name != nullptr) {
50
+ name = demangled_name;
51
+ std::free(demangled_name);
52
+ }
53
+ #endif
54
+
55
+ // Make a few edge-cases nicer.
56
+ name = replaceRegex(name, R"(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>)", "std::string");
57
+ name = replaceRegex(name, R"(std::__1::vector<([^>]+), std::__1::allocator<\1>>)", "std::vector<$1>");
58
+ name = replaceRegex(name, R"(std::__1::map<([^,]+), ([^>]+), std::__1::less<\1>, std::__1::allocator<std::__1::pair<const \1, \2>>>)",
59
+ "std::map<$1, $2>");
60
+ name = replaceRegex(name, R"(std::__1::shared_ptr<([^>]+)>)", "std::shared_ptr<$1>");
61
+ name = replaceRegex(name, R"(std::__1::unique_ptr<([^>]+), std::__1::default_delete<\1>>)", "std::unique_ptr<$1>");
62
+ name = replaceRegex(
63
+ name,
64
+ R"(std::__1::unordered_map<([^,]+), ([^>]+), std::__1::hash<\1>, std::__1::equal_to<\1>, std::__1::allocator<std::__1::pair<const \1, \2>>>)",
65
+ "std::unordered_map<$1, $2>");
66
+ name = replaceRegex(name, R"(std::__1::unordered_set<([^>]+), std::__1::hash<\1>, std::__1::equal_to<\1>, std::__1::allocator<\1>>)",
67
+ "std::unordered_set<$1>");
68
+ name = replaceRegex(name, R"(std::__1::list<([^>]+), std::__1::allocator<\1>>)", "std::list<$1>");
69
+
70
+ return name;
71
+ }
72
+
73
+ template <typename... Types> static inline std::string getFriendlyTypenames() {
74
+ std::ostringstream stream;
75
+ ((stream << TypeInfo::getFriendlyTypename<Types>() << ", "), ...);
76
+ std::string string = stream.str();
77
+ return string.substr(0, string.length() - 2);
78
+ }
79
+ };
80
+
81
+ } // namespace margelo::nitro
@@ -0,0 +1,52 @@
1
+ //
2
+ // HybridObjectSpec.swift
3
+ // NitroModules
4
+ //
5
+ // Created by Marc Rousavy on 23.07.24.
6
+ //
7
+
8
+ import Foundation
9
+
10
+ /**
11
+ * A base protocol for all Swift-based Hybrid Objects.
12
+ */
13
+ public protocol HybridObjectSpec {
14
+ /**
15
+ * Holds the C++ HybridObject and it's context.
16
+ * Use the default initializer in your implementation, C++ will set and get this value.
17
+ *
18
+ * @example
19
+ * ```swift
20
+ * var hybridContext = margelo.nitro.HybridContext()
21
+ * ```
22
+ */
23
+ var hybridContext: margelo.nitro.HybridContext { get set }
24
+
25
+ /**
26
+ * Get the memory size of the Swift instance (plus any external heap allocations),
27
+ * in bytes.
28
+ *
29
+ * Override this to allow tracking heap allocations such as buffers or images,
30
+ * which will help the JS GC be more efficient in deleting large unused objects.
31
+ *
32
+ * @example
33
+ * ```swift
34
+ * var memorySize: Int {
35
+ * let imageSize = self.uiImage.bytesPerRow * self.uiImage.height
36
+ * return getSizeOf(self) + imageSize
37
+ * }
38
+ * ```
39
+ */
40
+ var memorySize: Int { get }
41
+ }
42
+
43
+ public extension HybridObjectSpec {
44
+ /**
45
+ * Get the memory size of the given instance.
46
+ * This only accounts for stack allocated member variables,
47
+ * not for externally allocated heap allocations like images or buffers.
48
+ */
49
+ func getSizeOf<T: AnyObject>(_ instance: T) -> Int {
50
+ return malloc_size(Unmanaged.passUnretained(instance).toOpaque())
51
+ }
52
+ }