react-native-wgpu 0.1.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 (208) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +31 -0
  3. package/android/CMakeLists.txt +74 -0
  4. package/android/build.gradle +166 -0
  5. package/android/cpp/cpp-adapter.cpp +12 -0
  6. package/android/gradle.properties +5 -0
  7. package/android/src/main/AndroidManifest.xml +3 -0
  8. package/android/src/main/AndroidManifestNew.xml +2 -0
  9. package/android/src/main/java/com/webgpu/WebGPUModule.java +39 -0
  10. package/android/src/main/java/com/webgpu/WebGPUView.java +24 -0
  11. package/android/src/main/java/com/webgpu/WebGPUViewManager.java +31 -0
  12. package/android/src/main/java/com/webgpu/WebGPUViewPackage.java +26 -0
  13. package/android/src/newarch/WgpuViewManagerSpec.java +24 -0
  14. package/android/src/oldarch/WebGPUViewManagerSpec.java +11 -0
  15. package/cpp/Logger.h +82 -0
  16. package/cpp/dawn/dawn_proc_table.h +308 -0
  17. package/cpp/dawn/webgpu.h +4201 -0
  18. package/cpp/dawn/webgpu_cpp.h +8985 -0
  19. package/cpp/dawn/webgpu_cpp_print.h +2460 -0
  20. package/cpp/dawn/wire/client/webgpu.h +339 -0
  21. package/cpp/dawn/wire/client/webgpu_cpp.h +9140 -0
  22. package/cpp/jsi/RNFEnumMapper.h +49 -0
  23. package/cpp/jsi/RNFHybridObject.cpp +145 -0
  24. package/cpp/jsi/RNFHybridObject.h +162 -0
  25. package/cpp/jsi/RNFJSIConverter.h +412 -0
  26. package/cpp/jsi/RNFJSIHelper.h +49 -0
  27. package/cpp/jsi/RNFPointerHolder.h +95 -0
  28. package/cpp/jsi/RNFPromise.cpp +45 -0
  29. package/cpp/jsi/RNFPromise.h +38 -0
  30. package/cpp/jsi/RNFRuntimeCache.cpp +57 -0
  31. package/cpp/jsi/RNFRuntimeCache.h +79 -0
  32. package/cpp/jsi/RNFWorkletRuntimeCollector.h +43 -0
  33. package/cpp/jsi/RNFWorkletRuntimeRegistry.cpp +11 -0
  34. package/cpp/jsi/RNFWorkletRuntimeRegistry.h +44 -0
  35. package/cpp/rnwgpu/MutableBuffer.h +48 -0
  36. package/cpp/rnwgpu/RNWebGPUManager.cpp +60 -0
  37. package/cpp/rnwgpu/RNWebGPUManager.h +30 -0
  38. package/cpp/rnwgpu/api/GPU.cpp +40 -0
  39. package/cpp/rnwgpu/api/GPU.h +43 -0
  40. package/cpp/rnwgpu/api/GPUAdapter.cpp +33 -0
  41. package/cpp/rnwgpu/api/GPUAdapter.h +40 -0
  42. package/cpp/rnwgpu/api/GPUAdapterInfo.h +33 -0
  43. package/cpp/rnwgpu/api/GPUBindGroup.h +38 -0
  44. package/cpp/rnwgpu/api/GPUBindGroupLayout.h +39 -0
  45. package/cpp/rnwgpu/api/GPUBuffer.cpp +16 -0
  46. package/cpp/rnwgpu/api/GPUBuffer.h +44 -0
  47. package/cpp/rnwgpu/api/GPUCanvasContext.h +33 -0
  48. package/cpp/rnwgpu/api/GPUCommandBuffer.h +38 -0
  49. package/cpp/rnwgpu/api/GPUCommandEncoder.h +38 -0
  50. package/cpp/rnwgpu/api/GPUCompilationInfo.h +33 -0
  51. package/cpp/rnwgpu/api/GPUCompilationMessage.h +33 -0
  52. package/cpp/rnwgpu/api/GPUComputePassEncoder.h +40 -0
  53. package/cpp/rnwgpu/api/GPUComputePipeline.h +39 -0
  54. package/cpp/rnwgpu/api/GPUDevice.cpp +12 -0
  55. package/cpp/rnwgpu/api/GPUDevice.h +45 -0
  56. package/cpp/rnwgpu/api/GPUDeviceLostInfo.h +33 -0
  57. package/cpp/rnwgpu/api/GPUExternalTexture.h +39 -0
  58. package/cpp/rnwgpu/api/GPUPipelineLayout.h +38 -0
  59. package/cpp/rnwgpu/api/GPUQuerySet.h +38 -0
  60. package/cpp/rnwgpu/api/GPUQueue.h +38 -0
  61. package/cpp/rnwgpu/api/GPURenderBundle.h +38 -0
  62. package/cpp/rnwgpu/api/GPURenderBundleEncoder.h +40 -0
  63. package/cpp/rnwgpu/api/GPURenderPassEncoder.h +40 -0
  64. package/cpp/rnwgpu/api/GPURenderPipeline.h +38 -0
  65. package/cpp/rnwgpu/api/GPUSampler.h +38 -0
  66. package/cpp/rnwgpu/api/GPUShaderModule.h +38 -0
  67. package/cpp/rnwgpu/api/GPUSupportedLimits.h +33 -0
  68. package/cpp/rnwgpu/api/GPUTexture.h +38 -0
  69. package/cpp/rnwgpu/api/GPUTextureView.h +38 -0
  70. package/cpp/rnwgpu/api/GPUUncapturedErrorEvent.h +33 -0
  71. package/cpp/rnwgpu/api/descriptors/GPUBindGroupDescriptor.h +81 -0
  72. package/cpp/rnwgpu/api/descriptors/GPUBindGroupEntry.h +67 -0
  73. package/cpp/rnwgpu/api/descriptors/GPUBindGroupLayoutDescriptor.h +69 -0
  74. package/cpp/rnwgpu/api/descriptors/GPUBindGroupLayoutEntry.h +95 -0
  75. package/cpp/rnwgpu/api/descriptors/GPUBlendComponent.h +56 -0
  76. package/cpp/rnwgpu/api/descriptors/GPUBlendState.h +65 -0
  77. package/cpp/rnwgpu/api/descriptors/GPUBufferBinding.h +72 -0
  78. package/cpp/rnwgpu/api/descriptors/GPUBufferBindingLayout.h +62 -0
  79. package/cpp/rnwgpu/api/descriptors/GPUBufferDescriptor.h +85 -0
  80. package/cpp/rnwgpu/api/descriptors/GPUBufferUsage.h +43 -0
  81. package/cpp/rnwgpu/api/descriptors/GPUCanvasConfiguration.h +93 -0
  82. package/cpp/rnwgpu/api/descriptors/GPUColorDict.h +81 -0
  83. package/cpp/rnwgpu/api/descriptors/GPUColorTargetState.h +69 -0
  84. package/cpp/rnwgpu/api/descriptors/GPUColorWrite.h +31 -0
  85. package/cpp/rnwgpu/api/descriptors/GPUComputePassDescriptor.h +62 -0
  86. package/cpp/rnwgpu/api/descriptors/GPUComputePassTimestampWrites.h +80 -0
  87. package/cpp/rnwgpu/api/descriptors/GPUComputePipelineDescriptor.h +82 -0
  88. package/cpp/rnwgpu/api/descriptors/GPUDepthStencilState.h +126 -0
  89. package/cpp/rnwgpu/api/descriptors/GPUDeviceDescriptor.h +69 -0
  90. package/cpp/rnwgpu/api/descriptors/GPUExtent3DDict.h +76 -0
  91. package/cpp/rnwgpu/api/descriptors/GPUExtent3DDictStrict.h +91 -0
  92. package/cpp/rnwgpu/api/descriptors/GPUExternalTextureBindingLayout.h +44 -0
  93. package/cpp/rnwgpu/api/descriptors/GPUExternalTextureDescriptor.h +75 -0
  94. package/cpp/rnwgpu/api/descriptors/GPUFragmentState.h +85 -0
  95. package/cpp/rnwgpu/api/descriptors/GPUImageCopyBuffer.h +83 -0
  96. package/cpp/rnwgpu/api/descriptors/GPUImageCopyExternalImage.h +66 -0
  97. package/cpp/rnwgpu/api/descriptors/GPUImageCopyTexture.h +74 -0
  98. package/cpp/rnwgpu/api/descriptors/GPUImageCopyTextureTagged.h +88 -0
  99. package/cpp/rnwgpu/api/descriptors/GPUImageDataLayout.h +70 -0
  100. package/cpp/rnwgpu/api/descriptors/GPUMapMode.h +25 -0
  101. package/cpp/rnwgpu/api/descriptors/GPUMultisampleState.h +68 -0
  102. package/cpp/rnwgpu/api/descriptors/GPUOrigin2DDict.h +61 -0
  103. package/cpp/rnwgpu/api/descriptors/GPUOrigin2DDictStrict.h +75 -0
  104. package/cpp/rnwgpu/api/descriptors/GPUOrigin3DDict.h +71 -0
  105. package/cpp/rnwgpu/api/descriptors/GPUPipelineErrorInit.h +54 -0
  106. package/cpp/rnwgpu/api/descriptors/GPUPipelineLayoutDescriptor.h +72 -0
  107. package/cpp/rnwgpu/api/descriptors/GPUPrimitiveState.h +66 -0
  108. package/cpp/rnwgpu/api/descriptors/GPUProgrammableStage.h +72 -0
  109. package/cpp/rnwgpu/api/descriptors/GPUQuerySetDescriptor.h +81 -0
  110. package/cpp/rnwgpu/api/descriptors/GPURenderBundleEncoderDescriptor.h +102 -0
  111. package/cpp/rnwgpu/api/descriptors/GPURenderPassColorAttachment.h +105 -0
  112. package/cpp/rnwgpu/api/descriptors/GPURenderPassDepthStencilAttachment.h +118 -0
  113. package/cpp/rnwgpu/api/descriptors/GPURenderPassDescriptor.h +100 -0
  114. package/cpp/rnwgpu/api/descriptors/GPURenderPassLayout.h +83 -0
  115. package/cpp/rnwgpu/api/descriptors/GPURenderPassTimestampWrites.h +80 -0
  116. package/cpp/rnwgpu/api/descriptors/GPURenderPipelineDescriptor.h +104 -0
  117. package/cpp/rnwgpu/api/descriptors/GPURequestAdapterOptions.h +56 -0
  118. package/cpp/rnwgpu/api/descriptors/GPUSamplerBindingLayout.h +48 -0
  119. package/cpp/rnwgpu/api/descriptors/GPUSamplerDescriptor.h +116 -0
  120. package/cpp/rnwgpu/api/descriptors/GPUShaderModuleCompilationHint.h +64 -0
  121. package/cpp/rnwgpu/api/descriptors/GPUShaderModuleDescriptor.h +88 -0
  122. package/cpp/rnwgpu/api/descriptors/GPUShaderStage.h +27 -0
  123. package/cpp/rnwgpu/api/descriptors/GPUStencilFaceState.h +61 -0
  124. package/cpp/rnwgpu/api/descriptors/GPUStorageTextureBindingLayout.h +67 -0
  125. package/cpp/rnwgpu/api/descriptors/GPUTextureBindingLayout.h +58 -0
  126. package/cpp/rnwgpu/api/descriptors/GPUTextureDescriptor.h +123 -0
  127. package/cpp/rnwgpu/api/descriptors/GPUTextureUsage.h +40 -0
  128. package/cpp/rnwgpu/api/descriptors/GPUTextureViewDescriptor.h +113 -0
  129. package/cpp/rnwgpu/api/descriptors/GPUUncapturedErrorEventInit.h +71 -0
  130. package/cpp/rnwgpu/api/descriptors/GPUVertexAttribute.h +80 -0
  131. package/cpp/rnwgpu/api/descriptors/GPUVertexBufferLayout.h +73 -0
  132. package/cpp/rnwgpu/api/descriptors/GPUVertexState.h +77 -0
  133. package/cpp/rnwgpu/api/descriptors/Unions.h +1645 -0
  134. package/cpp/webgpu/webgpu.h +33 -0
  135. package/cpp/webgpu/webgpu_cpp.h +33 -0
  136. package/cpp/webgpu/webgpu_cpp_chained_struct.h +55 -0
  137. package/cpp/webgpu/webgpu_enum_class_bitmasks.h +161 -0
  138. package/ios/RNFAppleLogger.mm +22 -0
  139. package/ios/Utils.h +5 -0
  140. package/ios/Utils.m +26 -0
  141. package/ios/WebGPUModule.h +18 -0
  142. package/ios/WebGPUModule.mm +77 -0
  143. package/ios/WebGPUView.h +15 -0
  144. package/ios/WebGPUView.mm +58 -0
  145. package/ios/WebGPUViewManager.mm +21 -0
  146. package/lib/commonjs/WebGPUNativeModule.js +10 -0
  147. package/lib/commonjs/WebGPUNativeModule.js.map +1 -0
  148. package/lib/commonjs/WebGPUViewNativeComponent.js +11 -0
  149. package/lib/commonjs/WebGPUViewNativeComponent.js.map +1 -0
  150. package/lib/commonjs/index.js +45 -0
  151. package/lib/commonjs/index.js.map +1 -0
  152. package/lib/module/WebGPUNativeModule.js +4 -0
  153. package/lib/module/WebGPUNativeModule.js.map +1 -0
  154. package/lib/module/WebGPUViewNativeComponent.js +4 -0
  155. package/lib/module/WebGPUViewNativeComponent.js.map +1 -0
  156. package/lib/module/index.js +9 -0
  157. package/lib/module/index.js.map +1 -0
  158. package/lib/typescript/babel.config.d.ts +2 -0
  159. package/lib/typescript/babel.config.d.ts.map +1 -0
  160. package/lib/typescript/jest.config.d.ts +5 -0
  161. package/lib/typescript/jest.config.d.ts.map +1 -0
  162. package/lib/typescript/lib/commonjs/WebGPUNativeModule.d.ts +5 -0
  163. package/lib/typescript/lib/commonjs/WebGPUNativeModule.d.ts.map +1 -0
  164. package/lib/typescript/lib/commonjs/WebGPUViewNativeComponent.d.ts +4 -0
  165. package/lib/typescript/lib/commonjs/WebGPUViewNativeComponent.d.ts.map +1 -0
  166. package/lib/typescript/lib/commonjs/index.d.ts +5 -0
  167. package/lib/typescript/lib/commonjs/index.d.ts.map +1 -0
  168. package/lib/typescript/lib/module/WebGPUNativeModule.d.ts +3 -0
  169. package/lib/typescript/lib/module/WebGPUNativeModule.d.ts.map +1 -0
  170. package/lib/typescript/lib/module/WebGPUViewNativeComponent.d.ts +4 -0
  171. package/lib/typescript/lib/module/WebGPUViewNativeComponent.d.ts.map +1 -0
  172. package/lib/typescript/lib/module/index.d.ts +5 -0
  173. package/lib/typescript/lib/module/index.d.ts.map +1 -0
  174. package/lib/typescript/scripts/build/copy-artifacts.d.ts +2 -0
  175. package/lib/typescript/scripts/build/copy-artifacts.d.ts.map +1 -0
  176. package/lib/typescript/scripts/build/dawn.d.ts +2 -0
  177. package/lib/typescript/scripts/build/dawn.d.ts.map +1 -0
  178. package/lib/typescript/scripts/build/util.d.ts +13 -0
  179. package/lib/typescript/scripts/build/util.d.ts.map +1 -0
  180. package/lib/typescript/scripts/codegen/codegen.d.ts +2 -0
  181. package/lib/typescript/scripts/codegen/codegen.d.ts.map +1 -0
  182. package/lib/typescript/scripts/codegen/model/dawn.d.ts +2 -0
  183. package/lib/typescript/scripts/codegen/model/dawn.d.ts.map +1 -0
  184. package/lib/typescript/scripts/codegen/model/model.d.ts +8 -0
  185. package/lib/typescript/scripts/codegen/model/model.d.ts.map +1 -0
  186. package/lib/typescript/scripts/codegen/templates/Descriptor.d.ts +4 -0
  187. package/lib/typescript/scripts/codegen/templates/Descriptor.d.ts.map +1 -0
  188. package/lib/typescript/scripts/codegen/templates/Enum.d.ts +3 -0
  189. package/lib/typescript/scripts/codegen/templates/Enum.d.ts.map +1 -0
  190. package/lib/typescript/scripts/codegen/templates/HybridObject.d.ts +3 -0
  191. package/lib/typescript/scripts/codegen/templates/HybridObject.d.ts.map +1 -0
  192. package/lib/typescript/scripts/codegen/templates/Unions.d.ts +6 -0
  193. package/lib/typescript/scripts/codegen/templates/Unions.d.ts.map +1 -0
  194. package/lib/typescript/scripts/codegen/templates/common.d.ts +9 -0
  195. package/lib/typescript/scripts/codegen/templates/common.d.ts.map +1 -0
  196. package/lib/typescript/scripts/codegen/util.d.ts +2 -0
  197. package/lib/typescript/scripts/codegen/util.d.ts.map +1 -0
  198. package/lib/typescript/src/WebGPUNativeModule.d.ts +7 -0
  199. package/lib/typescript/src/WebGPUNativeModule.d.ts.map +1 -0
  200. package/lib/typescript/src/WebGPUViewNativeComponent.d.ts +8 -0
  201. package/lib/typescript/src/WebGPUViewNativeComponent.d.ts.map +1 -0
  202. package/lib/typescript/src/index.d.ts +9 -0
  203. package/lib/typescript/src/index.d.ts.map +1 -0
  204. package/package.json +120 -0
  205. package/react-native-webgpu.podspec +56 -0
  206. package/src/WebGPUNativeModule.ts +9 -0
  207. package/src/WebGPUViewNativeComponent.ts +9 -0
  208. package/src/index.tsx +13 -0
@@ -0,0 +1,412 @@
1
+ //
2
+ // Created by Marc Rousavy on 21.02.24.
3
+ //
4
+
5
+ #pragma once
6
+
7
+ #include "RNFEnumMapper.h"
8
+ #include "RNFHybridObject.h"
9
+ #include "RNFJSIHelper.h"
10
+ #include "RNFPromise.h"
11
+ #include "RNFWorkletRuntimeRegistry.h"
12
+ #include <jsi/jsi.h>
13
+ #include <memory>
14
+ #include <array>
15
+ #include <future>
16
+ #include <vector>
17
+ #include <string>
18
+ #include <utility>
19
+ #include <type_traits>
20
+ #include <unordered_map>
21
+
22
+ #if __has_include(<cxxabi.h>)
23
+ #include <cxxabi.h>
24
+ #endif
25
+
26
+ namespace margelo {
27
+
28
+ namespace jsi = facebook::jsi;
29
+
30
+ // Unknown type (error)
31
+ template <typename ArgType, typename Enable = void> struct JSIConverter {
32
+ static ArgType fromJSI(jsi::Runtime&, const jsi::Value&, bool outOfBound) {
33
+ static_assert(always_false<ArgType>::value, "This type is not supported by the JSIConverter!");
34
+ return ArgType();
35
+ }
36
+ static jsi::Value toJSI(jsi::Runtime&, ArgType) {
37
+ static_assert(always_false<ArgType>::value, "This type is not supported by the JSIConverter!");
38
+ return jsi::Value::undefined();
39
+ }
40
+
41
+ private:
42
+ template <typename> struct always_false : std::false_type {};
43
+ };
44
+
45
+ // int <> number
46
+ template <> struct JSIConverter<int> {
47
+ static int fromJSI(jsi::Runtime&, const jsi::Value& arg, bool outOfBound) {
48
+ return static_cast<int>(arg.asNumber());
49
+ }
50
+ static jsi::Value toJSI(jsi::Runtime&, int arg) {
51
+ return jsi::Value(arg);
52
+ }
53
+ };
54
+
55
+ // double <> number
56
+ template <> struct JSIConverter<double> {
57
+ static double fromJSI(jsi::Runtime&, const jsi::Value& arg, bool outOfBound) {
58
+ return arg.asNumber();
59
+ }
60
+ static jsi::Value toJSI(jsi::Runtime&, double arg) {
61
+ return jsi::Value(arg);
62
+ }
63
+ };
64
+
65
+ // float <> number
66
+ template <> struct JSIConverter<float> {
67
+ static float fromJSI(jsi::Runtime&, const jsi::Value& arg, bool outOfBound) {
68
+ return static_cast<float>(arg.asNumber());
69
+ }
70
+ static jsi::Value toJSI(jsi::Runtime&, float arg) {
71
+ return jsi::Value(static_cast<double>(arg));
72
+ }
73
+ };
74
+
75
+ // uint64_t <> BigInt
76
+ template <> struct JSIConverter<uint64_t> {
77
+ static double fromJSI(jsi::Runtime& runtime, const jsi::Value& arg, bool outOfBound) {
78
+ return arg.asBigInt(runtime).asUint64(runtime);
79
+ }
80
+ static jsi::Value toJSI(jsi::Runtime& runtime, uint64_t arg) {
81
+ return jsi::BigInt::fromUint64(runtime, arg);
82
+ }
83
+ };
84
+
85
+ // int64_t <> BigInt
86
+ template <> struct JSIConverter<int64_t> {
87
+ static double fromJSI(jsi::Runtime& runtime, const jsi::Value& arg, bool outOfBound) {
88
+ return arg.asBigInt(runtime).asInt64(runtime);
89
+ }
90
+ static jsi::Value toJSI(jsi::Runtime& runtime, int64_t arg) {
91
+ return jsi::BigInt::fromInt64(runtime, arg);
92
+ }
93
+ };
94
+
95
+
96
+ // bool <> boolean
97
+ template <> struct JSIConverter<bool> {
98
+ static bool fromJSI(jsi::Runtime&, const jsi::Value& arg, bool outOfBound) {
99
+ return arg.asBool();
100
+ }
101
+ static jsi::Value toJSI(jsi::Runtime&, bool arg) {
102
+ return jsi::Value(arg);
103
+ }
104
+ };
105
+
106
+ // std::string <> string
107
+ template <> struct JSIConverter<std::string> {
108
+ static std::string fromJSI(jsi::Runtime& runtime, const jsi::Value& arg, bool outOfBound) {
109
+ return arg.asString(runtime).utf8(runtime);
110
+ }
111
+ static jsi::Value toJSI(jsi::Runtime& runtime, const std::string& arg) {
112
+ return jsi::String::createFromUtf8(runtime, arg);
113
+ }
114
+ };
115
+
116
+ // std::optional<T> <> T | undefined
117
+ template <typename TInner> struct JSIConverter<std::optional<TInner>> {
118
+ static std::optional<TInner> fromJSI(jsi::Runtime& runtime, const jsi::Value& arg, bool outOfBound) {
119
+ if (outOfBound || arg.isUndefined()) {
120
+ return {};
121
+ } else {
122
+ return JSIConverter<TInner>::fromJSI(runtime, std::move(arg), outOfBound);
123
+ }
124
+ }
125
+ static jsi::Value toJSI(jsi::Runtime& runtime, const std::optional<TInner>& arg) {
126
+ if (arg == std::nullopt) {
127
+ return jsi::Value::undefined();
128
+ } else {
129
+ return JSIConverter<TInner>::toJSI(runtime, arg.value());
130
+ }
131
+ }
132
+ };
133
+
134
+ // Enum <> Union
135
+ template <typename TEnum> struct JSIConverter<TEnum, std::enable_if_t<std::is_enum<TEnum>::value>> {
136
+ static TEnum fromJSI(jsi::Runtime& runtime, const jsi::Value& arg, bool outOfBound) {
137
+ std::string string = arg.asString(runtime).utf8(runtime);
138
+ TEnum outEnum;
139
+ EnumMapper::convertJSUnionToEnum(string, &outEnum);
140
+ return outEnum;
141
+ }
142
+ static jsi::Value toJSI(jsi::Runtime& runtime, const TEnum& arg) {
143
+ std::string outUnion;
144
+ EnumMapper::convertEnumToJSUnion(arg, &outUnion);
145
+ return jsi::String::createFromUtf8(runtime, outUnion);
146
+ }
147
+ };
148
+
149
+ // std::future<T> <> Promise<T>
150
+ template <typename TResult> struct JSIConverter<std::future<TResult>> {
151
+ static std::future<TResult> fromJSI(jsi::Runtime&, const jsi::Value&, bool outOfBound) {
152
+ throw std::runtime_error("Promise cannot be converted to a native type - it needs to be awaited first!");
153
+ }
154
+ static jsi::Value toJSI(jsi::Runtime& runtime, std::future<TResult>&& arg) {
155
+ auto sharedFuture = std::make_shared<std::future<TResult>>(std::move(arg));
156
+ return Promise::createPromise(runtime, [sharedFuture = std::move(sharedFuture)](jsi::Runtime& runtime,
157
+ std::shared_ptr<Promise> promise) {
158
+ try {
159
+ // wait until the future completes.
160
+ sharedFuture->wait();
161
+
162
+ if constexpr (std::is_same_v<TResult, void>) {
163
+ // it's returning void, just return undefined to JS
164
+ sharedFuture->get();
165
+ promise->resolve(jsi::Value::undefined());
166
+ } else {
167
+ // it's returning a custom type, convert it to a jsi::Value
168
+ TResult result = sharedFuture->get();
169
+ jsi::Value jsResult = JSIConverter<TResult>::toJSI(runtime, result);
170
+ promise->resolve(std::move(jsResult));
171
+ }
172
+ } catch (const std::exception& exception) {
173
+ // the async function threw an error, reject the promise
174
+ std::string what = exception.what();
175
+ promise->reject(what);
176
+ } catch (...) {
177
+ // the async function threw a non-std error, try getting it
178
+ #if __has_include(<cxxabi.h>)
179
+ std::string name = __cxxabiv1::__cxa_current_exception_type()->name();
180
+ #else
181
+ std::string name = "<unknown>";
182
+ #endif
183
+ promise->reject("Unknown non-std exception: " + name);
184
+ }
185
+
186
+ // This lambda owns the promise shared pointer, and we need to call its
187
+ // destructor correctly here - ensuring it's properly handled.
188
+ promise = nullptr;
189
+ });
190
+ }
191
+ };
192
+
193
+
194
+ // [](Args...) -> T {} <> (Args...) => T
195
+ template <typename ReturnType, typename... Args> struct JSIConverter<std::function<ReturnType(Args...)>> {
196
+ static std::function<ReturnType(Args...)> fromJSI(jsi::Runtime& runtime, const jsi::Value& arg, bool outOfBound) {
197
+ jsi::Function function = arg.asObject(runtime).asFunction(runtime);
198
+
199
+ std::shared_ptr<jsi::Function> sharedFunction = JSIHelper::createSharedJsiFunction(runtime, std::move(function));
200
+ return [&runtime, sharedFunction, outOfBound](Args... args) -> ReturnType {
201
+ jsi::Value result = sharedFunction->call(runtime, JSIConverter<std::decay_t<Args>>::toJSI(runtime, args)...);
202
+ if constexpr (std::is_same_v<ReturnType, void>) {
203
+ // it is a void function (returns undefined)
204
+ return;
205
+ } else {
206
+ // it returns a custom type, parse it from the JSI value.
207
+ return JSIConverter<ReturnType>::fromJSI(runtime, std::move(result), outOfBound);
208
+ }
209
+ };
210
+ }
211
+
212
+ template <size_t... Is>
213
+ static jsi::Value callHybridFunction(const std::function<ReturnType(Args...)>& function, jsi::Runtime& runtime, const jsi::Value* args,
214
+ std::index_sequence<Is...>, size_t count) {
215
+ if constexpr (std::is_same_v<ReturnType, void>) {
216
+ // it is a void function (will return undefined in JS)
217
+ function(JSIConverter<std::decay_t<Args>>::fromJSI(runtime, args[Is], Is >= count)...);
218
+ return jsi::Value::undefined();
219
+ } else {
220
+ // it is a custom type, parse it to a JS value
221
+ ReturnType result = function(JSIConverter<std::decay_t<Args>>::fromJSI(runtime, args[Is], Is >= count)...);
222
+ return JSIConverter<ReturnType>::toJSI(runtime, result);
223
+ }
224
+ }
225
+ static jsi::Value toJSI(jsi::Runtime& runtime, const std::function<ReturnType(Args...)>& function) {
226
+ jsi::HostFunctionType jsFunction = [function = std::move(function)](jsi::Runtime& runtime, const jsi::Value& thisValue,
227
+ const jsi::Value* args, size_t count) -> jsi::Value {
228
+ if (count != sizeof...(Args)) {
229
+ [[unlikely]];
230
+ throw jsi::JSError(runtime, "Function expected " + std::to_string(sizeof...(Args)) + " arguments, but received " +
231
+ std::to_string(count) + "!");
232
+ }
233
+ return callHybridFunction(function, runtime, args, std::index_sequence_for<Args...>{}, count);
234
+ };
235
+ return jsi::Function::createFromHostFunction(runtime, jsi::PropNameID::forUtf8(runtime, "hostFunction"), sizeof...(Args), jsFunction);
236
+ }
237
+ };
238
+
239
+ // std::vector<T> <> T[]
240
+ template <typename ElementType> struct JSIConverter<std::vector<ElementType>> {
241
+ static std::vector<ElementType> fromJSI(jsi::Runtime& runtime, const jsi::Value& arg, bool outOfBound) {
242
+ jsi::Array array = arg.asObject(runtime).asArray(runtime);
243
+ size_t length = array.size(runtime);
244
+
245
+ std::vector<ElementType> vector;
246
+ vector.reserve(length);
247
+ for (size_t i = 0; i < length; ++i) {
248
+ jsi::Value elementValue = array.getValueAtIndex(runtime, i);
249
+ vector.emplace_back(JSIConverter<ElementType>::fromJSI(runtime, elementValue, outOfBound));
250
+ }
251
+ return vector;
252
+ }
253
+ static jsi::Value toJSI(jsi::Runtime& runtime, const std::vector<ElementType>& vector) {
254
+ jsi::Array array(runtime, vector.size());
255
+ for (size_t i = 0; i < vector.size(); i++) {
256
+ jsi::Value value = JSIConverter<ElementType>::toJSI(runtime, vector[i]);
257
+ array.setValueAtIndex(runtime, i, std::move(value));
258
+ }
259
+ return array;
260
+ }
261
+ };
262
+
263
+ // std::unordered_map<std::string, T> <> Record<string, T>
264
+ template <typename ValueType> struct JSIConverter<std::unordered_map<std::string, ValueType>> {
265
+ static std::unordered_map<std::string, ValueType> fromJSI(jsi::Runtime& runtime, const jsi::Value& arg, bool outOfBound) {
266
+ jsi::Object object = arg.asObject(runtime);
267
+ jsi::Array propertyNames = object.getPropertyNames(runtime);
268
+ size_t length = propertyNames.size(runtime);
269
+
270
+ std::unordered_map<std::string, ValueType> map;
271
+ map.reserve(length);
272
+ for (size_t i = 0; i < length; ++i) {
273
+ std::string key = propertyNames.getValueAtIndex(runtime, i).asString(runtime).utf8(runtime);
274
+ jsi::Value value = object.getProperty(runtime, key.c_str());
275
+ map.emplace(key, JSIConverter<ValueType>::fromJSI(runtime, value, outOfBound));
276
+ }
277
+ return map;
278
+ }
279
+ static jsi::Value toJSI(jsi::Runtime& runtime, const std::unordered_map<std::string, ValueType>& map) {
280
+ jsi::Object object(runtime);
281
+ for (const auto& pair : map) {
282
+ jsi::Value value = JSIConverter<ValueType>::toJSI(runtime, pair.second);
283
+ jsi::String key = jsi::String::createFromUtf8(runtime, pair.first);
284
+ object.setProperty(runtime, key, std::move(value));
285
+ }
286
+ return object;
287
+ }
288
+ };
289
+
290
+ // HybridObject <> {}
291
+ template <typename T> struct is_shared_ptr_to_host_object : std::false_type {};
292
+
293
+ template <typename T> struct is_shared_ptr_to_host_object<std::shared_ptr<T>> : std::is_base_of<jsi::HostObject, T> {};
294
+
295
+ template <typename T> struct JSIConverter<T, std::enable_if_t<is_shared_ptr_to_host_object<T>::value>> {
296
+ using TPointee = typename T::element_type;
297
+
298
+ #if DEBUG
299
+ inline static std::string getFriendlyTypename() {
300
+ std::string name = std::string(typeid(TPointee).name());
301
+ #if __has_include(<cxxabi.h>)
302
+ int status = 0;
303
+ char* demangled_name = abi::__cxa_demangle(name.c_str(), NULL, NULL, &status);
304
+ if (status == 0) {
305
+ name = demangled_name;
306
+ std::free(demangled_name);
307
+ }
308
+ #endif
309
+ return name;
310
+ }
311
+
312
+ inline static std::string invalidTypeErrorMessage(const std::string& typeDescription, const std::string& reason) {
313
+ return "Cannot convert \"" + typeDescription + "\" to HostObject<" + getFriendlyTypename() + ">! " + reason;
314
+ }
315
+ #endif
316
+
317
+ static T fromJSI(jsi::Runtime& runtime, const jsi::Value& arg, bool outOfBound) {
318
+ #if DEBUG
319
+ if (arg.isUndefined()) {
320
+ [[unlikely]];
321
+ throw jsi::JSError(runtime, invalidTypeErrorMessage("undefined", "It is undefined!"));
322
+ }
323
+ if (!arg.isObject()) {
324
+ [[unlikely]];
325
+ std::string stringRepresentation = arg.toString(runtime).utf8(runtime);
326
+ throw jsi::JSError(runtime, invalidTypeErrorMessage(stringRepresentation, "It is not an object!"));
327
+ }
328
+ #endif
329
+ jsi::Object object = arg.getObject(runtime);
330
+ #if DEBUG
331
+ if (!object.isHostObject<TPointee>(runtime)) {
332
+ [[unlikely]];
333
+ std::string stringRepresentation = arg.toString(runtime).utf8(runtime);
334
+ throw jsi::JSError(runtime, invalidTypeErrorMessage(stringRepresentation, "It is a different HostObject<T>!"));
335
+ }
336
+ #endif
337
+ return object.getHostObject<TPointee>(runtime);
338
+ }
339
+ static jsi::Value toJSI(jsi::Runtime& runtime, const T& arg) {
340
+ #if DEBUG
341
+ if (arg == nullptr) {
342
+ [[unlikely]];
343
+ throw jsi::JSError(runtime, "Cannot convert nullptr to HostObject<" + getFriendlyTypename() + ">!");
344
+ }
345
+ #endif
346
+ return jsi::Object::createFromHostObject(runtime, arg);
347
+ }
348
+ };
349
+
350
+ // NativeState <> {}
351
+ template <typename T> struct is_shared_ptr_to_native_state : std::false_type {};
352
+
353
+ template <typename T> struct is_shared_ptr_to_native_state<std::shared_ptr<T>> : std::is_base_of<jsi::NativeState, T> {};
354
+
355
+ template <typename T> struct JSIConverter<T, std::enable_if_t<is_shared_ptr_to_native_state<T>::value>> {
356
+ using TPointee = typename T::element_type;
357
+
358
+ #if DEBUG
359
+ inline static std::string getFriendlyTypename() {
360
+ std::string name = std::string(typeid(TPointee).name());
361
+ #if __has_include(<cxxabi.h>)
362
+ int status = 0;
363
+ char* demangled_name = abi::__cxa_demangle(name.c_str(), NULL, NULL, &status);
364
+ if (status == 0) {
365
+ name = demangled_name;
366
+ std::free(demangled_name);
367
+ }
368
+ #endif
369
+ return name;
370
+ }
371
+
372
+ inline static std::string invalidTypeErrorMessage(const std::string& typeDescription, const std::string& reason) {
373
+ return "Cannot convert \"" + typeDescription + "\" to NativeState<" + getFriendlyTypename() + ">! " + reason;
374
+ }
375
+ #endif
376
+
377
+ static T fromJSI(jsi::Runtime& runtime, const jsi::Value& arg, bool outOfBound) {
378
+ #if DEBUG
379
+ if (arg.isUndefined()) {
380
+ [[unlikely]];
381
+ throw jsi::JSError(runtime, invalidTypeErrorMessage("undefined", "It is undefined!"));
382
+ }
383
+ if (!arg.isObject()) {
384
+ [[unlikely]];
385
+ std::string stringRepresentation = arg.toString(runtime).utf8(runtime);
386
+ throw jsi::JSError(runtime, invalidTypeErrorMessage(stringRepresentation, "It is not an object!"));
387
+ }
388
+ #endif
389
+ jsi::Object object = arg.getObject(runtime);
390
+ #if DEBUG
391
+ if (!object.hasNativeState<TPointee>(runtime)) {
392
+ [[unlikely]];
393
+ std::string stringRepresentation = arg.toString(runtime).utf8(runtime);
394
+ throw jsi::JSError(runtime, invalidTypeErrorMessage(stringRepresentation, "It is a different NativeState<T>!"));
395
+ }
396
+ #endif
397
+ return object.getNativeState<TPointee>(runtime);
398
+ }
399
+ static jsi::Value toJSI(jsi::Runtime& runtime, const T& arg) {
400
+ #if DEBUG
401
+ if (arg == nullptr) {
402
+ [[unlikely]];
403
+ throw jsi::JSError(runtime, "Cannot convert nullptr to HostObject<" + getFriendlyTypename() + ">!");
404
+ }
405
+ #endif
406
+ jsi::Object object(runtime);
407
+ object.setNativeState(runtime, arg);
408
+ return object;
409
+ }
410
+ };
411
+
412
+ } // namespace margelo
@@ -0,0 +1,49 @@
1
+ //
2
+ // Created by Hanno Gödecke on 15.05.24.
3
+ //
4
+
5
+ #pragma once
6
+
7
+ #include "RNFWorkletRuntimeRegistry.h"
8
+ #include <jsi/jsi.h>
9
+ #include <memory>
10
+ #include <utility>
11
+
12
+ namespace margelo {
13
+
14
+ namespace jsi = facebook::jsi;
15
+
16
+ class JSIHelper {
17
+ public:
18
+ /**
19
+ * Takes a jsi::Function and wraps it in a shared_ptr so its shareable.
20
+ * Every jsi::Function you intend to share or hold should be wrapped using this function.
21
+ */
22
+ static std::shared_ptr<jsi::Function> createSharedJsiFunction(jsi::Runtime& runtime, jsi::Function&& function) {
23
+ std::shared_ptr<jsi::Function> sharedFunction(new jsi::Function(std::move(function)), [&runtime](jsi::Function* ptr) {
24
+ if (RNFWorkletRuntimeRegistry::isRuntimeAlive(&runtime)) {
25
+ // Only delete the jsi::Function when the runtime it created is still alive.
26
+ // Otherwise leak memory. We do this on purpose, as sometimes we would keep
27
+ // references to JSI objects past the lifetime of its runtime (e.g.,
28
+ // shared values references from the RN VM holds reference to JSI objects
29
+ // on the UI runtime). When the runtime is terminated, the orphaned JSI
30
+ // objects would crash the app when their destructors are called, because
31
+ // they call into a memory that's managed by the terminated runtime. We
32
+ // accept the tradeoff of leaking memory here, as it has a limited impact.
33
+ // This scenario can only occur when the React instance is torn down which
34
+ // happens in development mode during app reloads, or in production when
35
+ // the app is being shut down gracefully by the system. An alternative
36
+ // solution would require us to keep track of all JSI values that are in
37
+ // use which would require additional data structure and compute spent on
38
+ // bookkeeping that only for the sake of destroying the values in time
39
+ // before the runtime is terminated. Note that the underlying memory that
40
+ // jsi::Value refers to is managed by the VM and gets freed along with the
41
+ // runtime.
42
+ delete ptr;
43
+ }
44
+ });
45
+
46
+ return sharedFunction;
47
+ }
48
+ };
49
+ } // namespace margelo
@@ -0,0 +1,95 @@
1
+ //
2
+ // Created by Marc Rousavy on 16.04.24.
3
+ //
4
+
5
+ #pragma once
6
+
7
+ #include "RNFHybridObject.h"
8
+ #include "RNFLogger.h"
9
+ #include <memory>
10
+ #include <mutex>
11
+ #include <utility>
12
+ #include <string>
13
+
14
+ namespace margelo {
15
+
16
+ namespace jsi = facebook::jsi;
17
+
18
+ template <typename T> class PointerHolder : public HybridObject {
19
+ protected:
20
+ // no default constructor
21
+ PointerHolder() = delete;
22
+
23
+ /**
24
+ * Create a new instance of a pointer holder which holds the given shared_ptr.
25
+ * @param name The name of the implementing class, for example "ViewWrapper".
26
+ * @param pointer The pointer this class will hold. It might be released from JS at any point via `release()`.
27
+ */
28
+ PointerHolder(const char* name, std::shared_ptr<T> pointer) : HybridObject(name), _name(name), _pointer(pointer) {
29
+ // eagerly initialize the release() method instead of putting it in `loadHybridMethods`
30
+ registerHybridMethod("release", &PointerHolder<T>::release, this);
31
+ registerHybridGetter("isValid", &PointerHolder<T>::getIsValid, this);
32
+ }
33
+
34
+ /**
35
+ * Create a new instance of a pointer holder which holds a shared_ptr of the given value.
36
+ * The shared_ptr will be move-constructed.
37
+ * @param name The name of the implementing class, for example "ViewWrapper".
38
+ * @param value The value this class will hold as a shared_ptr. It might be destroyed from JS at any point via `release()`.
39
+ */
40
+ PointerHolder(const char* name, T&& value) : PointerHolder(name, std::make_shared<T>(std::move(value))) {}
41
+
42
+ /**
43
+ * Called when the PointerHolder gets automatically destroyed (e.g. via GC) and the shared_ptr will be destroyed.
44
+ */
45
+ ~PointerHolder() {
46
+ if (_pointer != nullptr) {
47
+ Logger::log(TAG, "Automatically releasing %s... (~PointerHolder())", _name.c_str());
48
+ }
49
+ }
50
+
51
+ protected:
52
+ /**
53
+ * Manually release this reference to the pointer.
54
+ * If there are any other references to this pointer, no memory will be force-deleted.
55
+ */
56
+ virtual void release() {
57
+ std::unique_lock lock(_mutex);
58
+
59
+ if (_pointer == nullptr) {
60
+ throw std::runtime_error("Pointer " + _name + " has already been manually released!");
61
+ }
62
+ Logger::log(TAG, "Manually releasing %s... (PointerHolder::release())", _name.c_str());
63
+ _pointer = nullptr;
64
+ }
65
+
66
+ /**
67
+ * Get the shared_ptr this class is holding.
68
+ * If it has already been manually released from JS, this method will throw a runtime_error.
69
+ */
70
+ std::shared_ptr<T> pointee() {
71
+ std::unique_lock lock(_mutex);
72
+
73
+ if (_pointer == nullptr) {
74
+ throw std::runtime_error("Pointer " + _name + " has already been manually released!");
75
+ }
76
+ return _pointer;
77
+ }
78
+
79
+ /**
80
+ * Get if the pointer is still valid and strong.
81
+ */
82
+ bool getIsValid() {
83
+ std::unique_lock lock(_mutex);
84
+
85
+ return _pointer != nullptr;
86
+ }
87
+
88
+ private:
89
+ std::string _name;
90
+ std::shared_ptr<T> _pointer;
91
+ std::mutex _mutex;
92
+ static constexpr auto TAG = "PointerHolder";
93
+ };
94
+
95
+ } // namespace margelo
@@ -0,0 +1,45 @@
1
+ //
2
+ // Created by Marc Rousavy on 22.02.24.
3
+ //
4
+ #include "RNFPromise.h"
5
+ #include <future>
6
+ #include <jsi/jsi.h>
7
+ #include <utility>
8
+ #include <vector>
9
+
10
+ namespace margelo {
11
+
12
+ namespace jsi = facebook::jsi;
13
+
14
+ Promise::Promise(jsi::Runtime& runtime, jsi::Function&& resolver, jsi::Function&& rejecter)
15
+ : runtime(runtime), _resolver(std::move(resolver)), _rejecter(std::move(rejecter)) {}
16
+
17
+ jsi::Value Promise::createPromise(jsi::Runtime& runtime, RunPromise run) {
18
+ // Get Promise ctor from global
19
+ auto promiseCtor = runtime.global().getPropertyAsFunction(runtime, "Promise");
20
+
21
+ auto promiseCallback = jsi::Function::createFromHostFunction(
22
+ runtime, jsi::PropNameID::forUtf8(runtime, "PromiseCallback"), 2,
23
+ [=](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments, size_t count) -> jsi::Value {
24
+ // Call function
25
+ auto resolver = arguments[0].asObject(runtime).asFunction(runtime);
26
+ auto rejecter = arguments[1].asObject(runtime).asFunction(runtime);
27
+ auto promise = std::make_shared<Promise>(runtime, std::move(resolver), std::move(rejecter));
28
+ run(runtime, promise);
29
+
30
+ return jsi::Value::undefined();
31
+ });
32
+
33
+ return promiseCtor.callAsConstructor(runtime, promiseCallback);
34
+ }
35
+
36
+ void Promise::resolve(jsi::Value&& result) {
37
+ _resolver.call(runtime, std::move(result));
38
+ }
39
+
40
+ void Promise::reject(std::string message) {
41
+ jsi::JSError error(runtime, message);
42
+ _rejecter.call(runtime, error.value());
43
+ }
44
+
45
+ } // namespace margelo
@@ -0,0 +1,38 @@
1
+ //
2
+ // Created by Marc Rousavy on 22.02.24.
3
+ //
4
+ #pragma once
5
+
6
+ #include <jsi/jsi.h>
7
+ #include <utility>
8
+ #include <vector>
9
+ #include <string>
10
+ #include <memory>
11
+
12
+ namespace margelo {
13
+
14
+ namespace jsi = facebook::jsi;
15
+
16
+ class Promise {
17
+ public:
18
+ Promise(jsi::Runtime& runtime, jsi::Function&& resolver, jsi::Function&& rejecter);
19
+
20
+ void resolve(jsi::Value&& result);
21
+ void reject(std::string error);
22
+
23
+ public:
24
+ jsi::Runtime& runtime;
25
+
26
+ private:
27
+ jsi::Function _resolver;
28
+ jsi::Function _rejecter;
29
+
30
+ public:
31
+ using RunPromise = std::function<void(jsi::Runtime& runtime, std::shared_ptr<Promise> promise)>;
32
+ /**
33
+ Create a new Promise and runs the given `run` function.
34
+ */
35
+ static jsi::Value createPromise(jsi::Runtime& runtime, RunPromise run);
36
+ };
37
+
38
+ } // namespace margelo