1 // Copyright © 2021-present 650 Industries, Inc. (aka Expo) 2 3 #pragma once 4 5 #include "CppType.h" 6 7 #include <jsi/jsi.h> 8 #include <fbjni/fbjni.h> 9 #include <ReactCommon/TurboModuleUtils.h> 10 #include <react/jni/ReadableNativeArray.h> 11 #include <memory> 12 #include <folly/dynamic.h> 13 #include <jsi/JSIDynamic.h> 14 15 namespace jni = facebook::jni; 16 namespace jsi = facebook::jsi; 17 namespace react = facebook::react; 18 19 namespace expo { 20 class JSIInteropModuleRegistry; 21 22 /** 23 * A class that holds information about the exported function. 24 */ 25 class MethodMetadata { 26 public: 27 /** 28 * Function name 29 */ 30 std::string name; 31 /** 32 * Number of arguments 33 */ 34 int args; 35 /* 36 * Whether this function is async 37 */ 38 bool isAsync; 39 40 std::unique_ptr<int[]> desiredTypes; 41 42 MethodMetadata( 43 std::string name, 44 int args, 45 bool isAsync, 46 std::unique_ptr<int[]> desiredTypes, 47 jni::global_ref<jobject> &&jBodyReference 48 ); 49 50 // We deleted the copy contractor to not deal with transforming the ownership of the `jBodyReference`. 51 MethodMetadata(const MethodMetadata &) = delete; 52 53 MethodMetadata(MethodMetadata &&other) = default; 54 55 /** 56 * MethodMetadata owns the only reference to the Kotlin function. 57 * We have to clean that, cause it's a `global_ref`. 58 */ 59 ~MethodMetadata() { 60 if (jBodyReference != nullptr) { 61 jBodyReference.release(); 62 } 63 } 64 65 /** 66 * Transforms metadata to a jsi::Function. 67 * 68 * @param runtime 69 * @param moduleRegistry 70 * @return shared ptr to the jsi::Function that wrapped the underlying Kotlin's function. 71 */ 72 std::shared_ptr<jsi::Function> toJSFunction( 73 jsi::Runtime &runtime, 74 JSIInteropModuleRegistry *moduleRegistry 75 ); 76 77 /** 78 * Calls the underlying Kotlin function. 79 */ 80 jsi::Value callSync( 81 jsi::Runtime &rt, 82 JSIInteropModuleRegistry *moduleRegistry, 83 const jsi::Value *args, 84 size_t count 85 ); 86 87 private: 88 /** 89 * Reference to one of two java objects - `JNIFunctionBody` or `JNIAsyncFunctionBody`. 90 * 91 * In case when `isAsync` is `true`, this variable will point to `JNIAsyncFunctionBody`. 92 * Otherwise to `JNIFunctionBody` 93 */ 94 jni::global_ref<jobject> jBodyReference; 95 96 /** 97 * To not create a jsi::Function always when we need it, we cached that value. 98 */ 99 std::shared_ptr<jsi::Function> body = nullptr; 100 101 jsi::Function toSyncFunction(jsi::Runtime &runtime, JSIInteropModuleRegistry *moduleRegistry); 102 103 jsi::Function toAsyncFunction(jsi::Runtime &runtime, JSIInteropModuleRegistry *moduleRegistry); 104 105 jsi::Function createPromiseBody( 106 jsi::Runtime &runtime, 107 JSIInteropModuleRegistry *moduleRegistry, 108 std::vector<jobject> &&args 109 ); 110 111 std::vector<jobject> convertJSIArgsToJNI( 112 JSIInteropModuleRegistry *moduleRegistry, 113 JNIEnv *env, 114 jsi::Runtime &rt, 115 const jsi::Value *args, 116 size_t count, 117 bool returnGlobalReferences 118 ); 119 }; 120 } // namespace expo 121